Showcase
Flowx
The browser session was reset. Let me redo the login flow efficiently. Logged in — "Signed in!" toast confirmed, and the build flow started ("Forging…"). Let me wait for the build modal. The build modal is open with the prompt pre-filled and the file upload affordance visible. Let me test the **file upload** path first — a real brand-notes file for the AI. File attached (terra-brand-notes.txt). Now set the app name and proceed. **In the studio** — URL is `/studio/ffeec78a-.../preview`, project "Terra Studio" created. Let me wait for the run to start and the workspace to bind. "Goal not completed" already? That seems too fast. Let me check the engine's run state directly. The token file was cleaned. Let me re-mint the master session. The run ended very quickly (activeRuns: 0, totalRuns: 1) with a sandbox still leased. Let me check the studio chat state and the run details. The chat area seems missing from the text. Let me look at the studio route structure to understand the layout. The run finished fast with an incomplete status. Let me screenshot the studio and check the chat area. The studio shows almost no content — no chat log, no composer. Let me study the studio canvas layout to understand what should be visible. The banner is inside the preview panel's empty state. The chat console seems missing. Let me check for the composer and chat messages in the DOM. **Major bug found**: the studio chat console isn't rendering at all — no composer, no messages. Let me investigate the studio route. The viewport was accidentally portrait. Let me set a proper desktop viewport. Still no chat console at desktop size. Let me examine the StudioCanvas layout code. The URL is `/studio/.../preview` — the current page IS the preview tab. The chat console is on the main studio page. Let me navigate back to the chat. Chat console now renders with the composer. Let me dump the conversation. **Critical bug**: the run failed with "path escapes the workspace: .gitignore". Let me root-cause this in the engine. The error is in `E2BSandboxAdapter.resolve()` — `safeRelPath('.gitignore')` returned null. Let me check `safeRelPath`. **Root cause found**: `safeRelPath` rejects ALL dotfiles (`clean.startsWith(".")`) — so when OpenHands tried to create `.gitignore`, the whole run died. Let me check where file events flow TS-side. Let me find where a `file_written` event path is used in the manager — that's where the exception was thrown. The error came from `executeRun`'s try block. Let me check `bootWorkspace` — the scaffold seeding likely writes `.gitignore`. **ROOT CAUSE CONFIRMED**: `bootWorkspace` seeds `.gitignore` into every fresh workspace → `E2BSandboxAdapter.resolve(".gitignore")` → `safeRelPath` rejects all dot-prefixed paths → run dies at boot. Local sandboxes survived (different resolve path); E2B runs never can. Let me check the full workspace-service guards before fixing. `studioSafePath` already allows dotfiles, but the adapter's `safeRelPath` doesn't — an internal inconsistency. Let me fix `safeRelPath` to allow dotfiles while blocking traversal. Now let me typecheck and test the fix locally. Typecheck clean. Let me run a quick unit sanity check on the new `safeRelPath`, then commit and push. All 15 cases pass. Committing and pushing the engine fix. While the engine deploys, let me verify the frontend's duplicate-log fix (bb12b18) and no-steps law in the code. While the engine deploys, let me run the hardcoding audit across the engine and frontend. OpenHands purity verified: PyPI-pinned `openhands-sdk==1.44.1`, no vendored code, the SDK's default agent with its own tools. Let me check the engine deploy status. Deploy complete. The runtime config was likely wiped again — this is the auto-heal's first live test. Let me trigger it via the edge. **Auto-heal verified live**: the deploy wiped the config (polls 2–3 showed drained), then edge traffic re-pushed it — keys:4 restored without manual action. Now let me start a new run to verify the dotfile fix E2E. New run is LIVE — "Workspace bound", "Forgvi 3.0 run in progress". Let me monitor the stream log. Run is active on E2B (user's KEY1 spawning the sandbox). Let me watch the stream log develop. The worker exited with a Python shutdown crash. Let me get the run's journal to see how far it got. Let me see how far the run got before the worker died. The worker made 1 action then died — the stderr tail only shows shutdown noise; the real exception is earlier. Let me search for LLM keys to reproduce locally, and inspect the live sandbox. Let me query the DB for the project's run records to get the run ID, then pull the journal from Redis. The project has a live E2B sandbox. Let me inspect what the agent did before dying. Terminal works (honest exit codes). But the upload is MISSING from the workspace — possible architecture bug between the upload path and run path. Let me check `createSandbox` vs `getProjectSandbox`. **Architecture bug confirmed**: the run spawns its OWN sandbox while the studio surface (uploads, files, terminal) serves a DIFFERENT project sandbox — they only sync via snapshots. The agent never sees the uploads; the Files tab is stale during runs. Let me check `startRun`'s workspace binding. Two critical things to investigate: (1) the one-sandbox law violation (run vs studio sandboxes), (2) the worker crash. Let me first inspect the OpenHands SDK's terminal tool to understand where commands execute. **Major discovery**: the SDK's terminal tool drives a LOCAL tmux session — it never calls `workspace.execute_command`. Let me verify how the default agent wires its tools. **CRITICAL FLAW CONFIRMED**: `TerminalTool.create` requires `os.path.isdir(working_dir)` — a LOCAL directory — and runs commands in a LOCAL tmux session. The engine container has no `/workspace`, so this throws. Let me find where `create` is invoked to understand the 1-action timeline. The SDK's terminal tool runs LOCALLY (tmux on the worker's machine), never via `workspace.execute_command` — the E2B workspace law is broken for terminals. Let me reproduce the exact crash locally with a mock LLM + real E2B sandbox. **Full picture**: the SDK's default agent tools (terminal AND file_editor) both execute on the worker's LOCAL machine — the `BaseWorkspace` overrides are dead code for them. The agent works on the engine container's disk, never the E2B VM. Now let me reproduce the exact crash with a mock LLM + real E2B sandbox. E2B sandbox spawned successfully. Let me check `Sandbox.connect` compatibility with the worker's usage, then run the repro. Now let me check BaseWorkspace's constructor, then run the full worker repro. **CRASH REPRODUCED EXACTLY**: `AssertionError: workspace must be a LocalWorkspace instance` at `local_conversation.py:368` — with the identical `__del__` shutdown noise (line 3068, rich logging) seen in production. The SDK's `LocalConversation` only accepts local workspaces; the E2BWorkspace approach is fundamentally incompatible. Let me check the E2B template to implement the honest fix: run the worker INSIDE the microVM. The template exists but lacks Python/OpenHands. The honest fix: bake openhands-sdk into the E2B template and run the worker INSIDE the microVM. Let me check the e2b JS SDK's streaming API for event relay. The e2b JS SDK supports streaming callbacks. Now let me implement the honest architecture. Starting with the template — baking Python + OpenHands SDK into the E2B image. Now rewrite worker.py — removing the dead E2BWorkspace (the assert makes it unusable) and simplifying to LocalWorkspace everywhere: Now the engine bridge. First check the e2b JS SDK's `commands.run` streaming options and the adapter's surface: Let me check the SandboxAdapter interface to extend it properly. Now let me add the streaming exec method to the E2B adapter: Let me re-read the exact current text and apply edits individually. Now add `execStream` to the E2B adapter and the interface: Now add `execStream` to the E2B adapter (after its `exec`): The E2B execStream seems present. Let me verify the full file state and check the interface: All three `execStream` implementations are in place. Now rewriting the bridge — `src/openhands.ts` with the in-VM agent law: Let me clean up the duplicated feeder logic in the local lane: Now add `writeVmFile` to the adapter interface and implementations: Now add `writeVmFile` to the E2B adapter (after its readTextFile): Now fix openhands.ts imports and remove the redundant wrapper: Now update `executeRun` in manager.ts — the one-sandbox law: Now update the `runLane` call (pass the adapter instead of the id/key spec) and the finally block: Now add `skipRestore` to `bootWorkspace` in template.ts: Now add `holdProjectSandbox`/`releaseProjectSandbox` to workspace-service with the holders guard on evict/migrate: Good — `sandbox.setTimeout(ms)` exists. Now let me add the holders mechanism with timeout extension to workspace-service: Now add `extendTimeout` to the adapter interface and implementations: Now add the implementations — E2B (setTimeout) and local (no-op): Now fix the wall-clock timeout bug in openhands.ts (maxWallclockMs=0 → 60s kill): Now typecheck everything: Now fix the execStream handle cast and the other call sites that now get a union return: That's where you stopped. Continue
This app was published without an interactive snapshot. Open it in the studio to see the full codebase and run it live.
Want to remix this application?
Fork the workspace and modify this app instantly with plain-English prompts — no setup, no boilerplate, the code stays yours.
Last updated September 21, 2026 · Built with Forgeyn, the AI studio that ships real apps from plain-text prompts.