Concepts
The publish pipeline
Publishing isn't deployment. It's a pipeline that classifies your code, rewrites it to fit Ellivate's contract, pauses if configuration is missing, deploys the container, and verifies the result — with loud, specific errors at every stage.
The stages
Every ellivate publish runs the same pipeline. You see each stage as it happens — in the CLI as streamed status events, in the dashboard as a progress card. The stages are:
- Upload. The CLI bundles your project folder and POSTs it to the API (the dashboard does the same when you drag a folder in). Files in
.gitignore/.ellivateignoreare excluded. Large binaries should live in a blob store, not the upload. - Classify. The API inspects your files and picks a framework (Next.js, Flask, FastAPI, Streamlit, vanilla HTML, Playwright, ...). Sets the app shape, runtime, detected entry file, data-storage patterns, and auth requirements.
- Translate — persistence. Rewrites
localStorage,sqlite3, JSON file reads/writes,shelve,pickle, and other user-data patterns to the Ellivate KV SDK. Idempotent — re-runs skip already- converted code. - Translate — Supabase data. If your code uses Supabase as a CRUD data store (
supabase.from(...).select/insert/update/delete), it gets rewritten toellivate.collection(...)automatically. Your new tool starts with no data; the app detail page shows what changed and offers a one-click switch back to Supabase if you'd rather keep your real DB. Apps that use Supabase realtime, storage buckets, edge functions, or RPC fall outside the rewrite — those need real Supabase, and the pipeline says so loudly instead of half-migrating. - Translate — auth. For frameworks with server-side gates (Next.js, Flask, FastAPI), writes the handoff route and middleware. Removes third-party auth libraries if present.
- Translate — framework-specific. Playwright apps get Chrome-channel scrubbed. Flask/ FastAPI get the contextvar-based per-viewer wiring. Each rewriter is safe-fail — errors become warnings on the manifest, not aborts.
- Inject the SDK. The
ellivate-client.js/ellivate_client.py/ellivate-client.global.jsfile is written to project root. This stage runs unconditionally — any reference in user code to the SDK must resolve. - Invariant check. The pipeline verifies the translated code meets the Ellivate contract — SDK file exists, imports are shaped correctly, no forbidden auth libraries snuck through, host binding is correct. Violations become Class 1 blockers.
- Gate. If your app declared env vars it needs (a third-party API key, a toggle), or the classifier detected missing configuration, the status moves to
NEEDS_CONFIG. Publish pauses until you fill in the gate form (in the dashboard) or confirm via the CLI. - Deploy. Railway builds the container, starts the app, and assigns a URL. Host binding is verified (
0.0.0.0:$PORT). - Verify. Ellivate warms the app with an HTTP request. Either the app responds on the expected route(s) or the status flips to
FAILEDwith a specific error pointing at the Railway logs.
Status values
The app's status drives both the dashboard UI and the CLI's progress display:
CREATED→ upload succeeded, pipeline queued.CLASSIFYING,TRANSLATING,DEPLOYING→ intermediate stages. Each has sub-steps surfaced in the status card.NEEDS_CONFIG→ gate paused. Your action required.LIVE→ deployed and responding.FAILED→ a Class 1 blocker caught the publish before deploy, or the deploy itself errored. Dashboard shows the specific file + line that needs fixing.
Class 1 vs Class 2 failures
Ellivate classifies publish failures into two kinds. The distinction matters because the fix pattern is different:
Class 1 — Ellivate generated bad config
The classifier picked the wrong framework, the rewriter leaked prose into a file, the injector put a statement in the wrong position. These are 100% preventable because we control the code path. They get fixed on Ellivate's side — patch the translator, reproduce in a test fixture, ship the fix.
Class 2 — User code doesn't fit the container
Hardcoded Chrome channel in a Playwright app, persistent browser profile requirement, requires-GPU code, reads files outside the project directory. Publish fails loudly with the exact reason. The fix is either to change your code or to pick a different app shape Ellivate supports.
Republishing an existing app
Running ellivate publish from the same project directory a second time updates the existing app in place:
- Same app ID, same URL, same share settings.
- Same data — KV keys persist across publishes. Your users don't lose state on an update.
- Same Railway project. The deploy reuses the existing infrastructure; containers are rebuilt but domains and env vars stay.
If you want to start fresh (new app, new data, new URL), pass --new to publish.
The end-to-end test harness
Every supported app shape has a fixture in Ellivate's test harness that publishes through the real pipeline, makes HTTP requests, and asserts the response matches expectations. When a new publish regression is caught, it gets a fixture — so the same bug can't reach users twice.
This matters for you because when your Flask / FastAPI / Next.js app publishes, the shape has been proven green by the harness. If it fails anyway, that's a regression Ellivate needs to fix, not a configuration you missed.
What's next
- Fix common errors — specific failure modes and their resolutions.
- The Ellivate contract — what the invariant check enforces.