feat(emdash-bot): hybrid computer/sandbox execution layer + investigation skills (bot next-gen 3/5) - #2381
Conversation
|
Scope checkThis PR changes 1,893 lines across 19 files. Large PRs are harder to review and more likely to be closed without review. If this scope is intentional, no action needed. A maintainer will review it. If not, please consider splitting this into smaller PRs. See CONTRIBUTING.md for contribution guidelines. |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
emdash-playground | 89ef4d6 | Aug 09 2026, 11:24 AM |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
emdash-demo-cache | 89ef4d6 | Aug 09 2026, 11:25 AM |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
View logs |
emdash-demo-do | 78e4b0e | Aug 09 2026, 09:17 AM |
@emdash-cms/admin
@emdash-cms/auth
@emdash-cms/auth-atproto
@emdash-cms/blocks
@emdash-cms/cloudflare
@emdash-cms/contentful-to-portable-text
emdash
create-emdash
@emdash-cms/gutenberg-to-portable-text
@emdash-cms/plugin-cli
@emdash-cms/plugin-types
@emdash-cms/registry-client
@emdash-cms/registry-lexicons
@emdash-cms/registry-verification
@emdash-cms/sandbox-workerd
@emdash-cms/x402
@emdash-cms/plugin-ai-moderation
@emdash-cms/plugin-atproto
@emdash-cms/plugin-audit-log
@emdash-cms/plugin-color
@emdash-cms/plugin-embeds
@emdash-cms/plugin-field-kit
@emdash-cms/plugin-forms
@emdash-cms/plugin-webhook-notifier
commit: |
207faf1 to
3b16598
Compare
97757a9 to
3b16598
Compare
There was a problem hiding this comment.
Pull request overview
This PR upgrades infra/emdash-bot to a hybrid execution model, introducing an isolate/VFS substrate (via @cloudflare/computer) alongside the existing container-based sandbox, and lands the next-gen “investigation” skill set used by the bot’s maintainer-triggered workflow.
Changes:
- Add
@cloudflare/computer@0.1.1and wire a newWorkspaceDO(SQLite-backed VFS + worker-shell exec via Dynamic Worker Loader) into the bot Worker. - Introduce an
ExecEnvabstraction that routes commands to isolate vs container and re-materializes VFS changes into the container fromgit status --porcelain -z. - Add the investigation skill directory set (repro/diagnose/verify/fix/investigate), update the investigate agent to use them, and add targeted unit tests for the execEnv seam.
Reviewed changes
Copilot reviewed 17 out of 19 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| pnpm-lock.yaml | Locks @cloudflare/computer@0.1.1 and related dependency graph adjustments. |
| infra/emdash-bot/package.json | Adds @cloudflare/computer dependency for isolate/VFS execution. |
| infra/emdash-bot/wrangler.jsonc | Enables experimental compat flag, adds worker_loaders, and registers WorkspaceDO as sqlite-enabled (v4). |
| infra/emdash-bot/vitest.workers.config.ts | Adds a Vite plugin stub for SKILL.md imports to keep worker-pool bundles parseable in tests. |
| infra/emdash-bot/tests/unit/sandbox-deadline.test.ts | Removes tests for the deleted withSandboxDeadlines wrapper; keeps withDeadline coverage. |
| infra/emdash-bot/tests/unit/exec-env.test.ts | New unit test suite covering exec routing, deadlines, container reuse, VFS→container materialization, artifact containment, and clone behavior. |
| infra/emdash-bot/.flue/raw.d.ts | Adds a module declaration for */SKILL.md imports as Flue SkillReferences. |
| infra/emdash-bot/.flue/lib/sandbox-deadline.ts | Removes withSandboxDeadlines, leaving withDeadline as the shared deadline primitive. |
| infra/emdash-bot/.flue/lib/exec-env.ts | New hybrid execution layer (ExecEnv) bridging isolate VFS + sandbox container; includes porcelain parsing + artifact egress hardening. |
| infra/emdash-bot/.flue/cloudflare.ts | Adds WorkspaceDO based on withWorkspace, configures worker-shell backend using the LOADER binding. |
| infra/emdash-bot/.flue/agents/investigate.ts | Replaces sandbox-only plumbing with ExecEnv, registers skills, and exposes isolate/container tools to the agent. |
| infra/emdash-bot/.flue/skills/investigate/SKILL.md | New “spine” skill defining the end-to-end investigation pipeline and execution discipline. |
| infra/emdash-bot/.flue/skills/diagnose/SKILL.md | New diagnose leaf skill (isolate-only inspection + evidence-carrying output). |
| infra/emdash-bot/.flue/skills/verify/SKILL.md | New verify leaf skill that gates fixes on intended vs bug behavior with citations. |
| infra/emdash-bot/.flue/skills/repro-admin/SKILL.md | New admin repro leaf skill (container + agent-browser + dev-bypass flow). |
| infra/emdash-bot/.flue/skills/repro-public/SKILL.md | New public-site repro leaf skill (container + agent-browser against public routes). |
| infra/emdash-bot/.flue/skills/repro-api/SKILL.md | New API/CLI repro leaf skill (prefer failing vitest test in container). |
| infra/emdash-bot/.flue/skills/fix/SKILL.md | New fix leaf skill (implements diagnose fix when verify says bug; enforces repo conventions). |
| infra/emdash-bot/.flue/skills/investigate/instructions.md | Removes the legacy freeform instructions doc in favor of SKILL-based workflow. |
Files not reviewed (1)
- pnpm-lock.yaml: Generated file
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| { | ||
| name: "git-push-capability", | ||
| command: `cd ${REPO_DIR} && git config http.https://github.com/.extraHeader '${PUSH_CAPABILITY_HEADER}: ${pushCapability}'`, | ||
| command: `cd ${REPO_DIR} && git checkout '${branch}' && git reset --hard 'origin/${branch}'`, | ||
| }, |
Overlapping PRsThis PR modifies files that are also changed by other open PRs:
This may cause merge conflicts or duplicated work. A maintainer will coordinate. |
There was a problem hiding this comment.
This PR is the right next slice for emdash-bot: it replaces the previous all-container setup with an isolate-first/computer VFS layer plus a sandbox fallback, and lands the Flue 2 investigation skill set. The stateless VFS→container materialization design fixes the coherence problem described in the PR (edits are re-derived from git status on every container exec instead of tracked in memory), and the test coverage for rename, non-ASCII, and cross-isolate materialization is good.
I checked the new exec-env.ts seam, the refactored Investigate agent, the WorkspaceDO plumbing, the wrangler migration, the deadline helpers, and the tests. I also searched for remaining references to the removed withSandboxDeadlines/useSandbox/defineSkill patterns and for stale call sites of the old sandbox setup. No user-facing routes were touched, so AGENTS concerns about Lingui, RTL Tailwind, SQL safety, locale filtering, and logged-out query counts do not apply here.
I did find a few concrete issues that should be addressed before merge:
- A transient
getWorkspace()failure is cached as a rejected promise forever, so the run can never recover. useSkill(fixSkill)is called conditionally, which is unsafe if the Flue runtime uses React-style hook ordering.wrangler.test.jsoncand the workers-pool test entry still only listSandbox/OrchestratorDO; they need to reflect the newWorkspaceDOandLOADERbinding and theexperimentalflag so tests mirror production.- Several top-of-file comments repeat PR rationale / rejected alternatives, which violates AGENTS.md comment discipline.
None of these are catastrophic, but #1 and #3 are real regressions/footguns.
Findings
-
[needs fixing]
infra/emdash-bot/.flue/agents/investigate.ts:284-290The
clientPromiseinfromWorkspaceClientLazyis set with??= getWorkspace(stub). If that first RPC call rejects, the rejected promise is cached forever and every subsequentreadFile/execcall will rethrow it, even if the DO has recovered. A single transient failure on the first call poisons the entire run.function fromWorkspaceClientLazy(getClient: () => ReturnType<typeof getWorkspace>) { let backend: ReturnType<typeof fromWorkspaceClient> | undefined; const resolve = async () => { if (backend) return backend; const client = await getClient(); backend = fromWorkspaceClient(client); return backend; }; -
[needs fixing]
infra/emdash-bot/.flue/agents/investigate.ts:91-92Calling
useSkillinside a conditional breaks React-style hook ordering. If the Flue runtime tracks hook position, a re-render with a differentinput.mode(or even just a future code path) will corrupt persisted hook state. The skill should be registered unconditionally, or you should use a Flue API that explicitly supports conditional registration.useSkill(reproPublicSkill); useSkill(fixSkill); -
[needs fixing]
infra/emdash-bot/wrangler.test.jsonc:38-53wrangler.test.jsoncstill only declaresSandboxandOrchestratorDO. The file's own comment says to keep it in sync with production bindings, but the PR addsWorkspaceDO, theLOADERworker loader, and theexperimentalcompatibility flag inwrangler.jsonc. Without them, the workers-pool tests are not exercising the same shapes as the deployed Worker."compatibility_flags": ["nodejs_compat", "experimental"], // ... existing containers / ai / durable_objects additions ... "worker_loaders": [ { "binding": "LOADER", }, ],Also add
WorkspaceDOto the durable-object bindings and the test-only migrationnew_sqlite_classes, and re-export it fromtests/integration/_entry.ts. -
[needs fixing]
infra/emdash-bot/tests/integration/_entry.ts:16-17The test entry re-exports the DO classes declared in
wrangler.test.jsonc. SinceWorkspaceDOwas added to production, it needs to be re-exported here as well oncewrangler.test.jsoncis updated.export { Sandbox, ContainerProxy, WorkspaceDO } from "../../.flue/cloudflare.js"; -
[suggestion]
infra/emdash-bot/.flue/lib/exec-env.ts:1-22This header comment contains PR-style rationale and rejected alternatives ("computerd is not shippable yet", "Swapping to computer's CloudflareContainerBackend later", "GitHub reads: emdash is public"). AGENTS.md says comments should address future readers, not summarize the PR or justify decisions. Trim it to the invariants a reader needs to know, and move the architecture rationale to the PR description.
// exec-env: single seam over the investigation's two execution substrates. // Every @cloudflare/computer and @cloudflare/sandbox touchpoint lives here. // VFS is authoritative for source; container checkout is re-synced from git status before each container exec. // Only the container side performs pnpm/astro/vitest/agent-browser work. -
[suggestion]
infra/emdash-bot/.flue/cloudflare.ts:124-133This block repeats the architecture rationale from
exec-env.ts("computerd is not shippable yet", "the flip-point when it becomes so"). Per AGENTS.md, comments should explain invariants, not restate the PR rationale or reference rejected alternatives. Keep only what is needed to understand the class boundaries.// Isolate + VFS substrate for execEnv's IsolateBackend. // WorkspaceDO hosts the SQLite-backed filesystem and the worker-shell isolate backend. // See exec-env.ts for the agent-side seam.
84a7f8e to
e771ab5
Compare
|
Addressed in e771ab5: a failed workspace connection is no longer cached as a rejected promise (the next call retries), The conditional ~ 🤖 Claude Fable 5 |
28da451 to
0873a1c
Compare
113e7ea to
d0b0af0
Compare
78e4b0e to
64afe94
Compare
64afe94 to
2b8b15f
Compare
Thin, testable seam wrapping the two investigation substrates: computer 0.1.1 Workspace (isolate/fs/git) and @cloudflare/sandbox (container). Routes exec by target, bounds every op with a deadline, bridges VFS edits into the container checkout, and confines every @cloudflare/computer touchpoint to one module so the future computerd flip is a single-adapter change.
emdash is public, so the VFS read-clone needs no auth and runs via an isolate git command; fs+runtime reach the DO through their RPC stubs, so the seam lives agent-side. Drops the in-DO typed-git dependency and keeps token minting confined to the container push path.
Ports the repro-public/repro-admin/repro-api/diagnose/verify/fix leaf skills and the investigate spine from the gen-1 .flue/skills content onto computer's tool model, as flat SKILL.md directories the agent loads per mode. Replaces the single investigate/instructions.md.
Adds the WorkspaceDO (computer Workspace + worker-shell isolate backend via a LOADER binding) and swaps the investigate agent off useSandbox onto execEnv: read/write/edit/ls/grep + an exec tool the model routes isolate-vs-container, skills loaded per mode, VFS clone at setup. Container stays @cloudflare/sandbox. Bindings: experimental flag, worker_loaders, WorkspaceDO DO + append-only v4 migration. Build + 107 unit + 35 integration green; typecheck at baseline.
withSandboxDeadlines wrapped Flue's useSandbox SessionEnv, which the execEnv swap removed. withDeadline (still used by the classifier, orchestrator, and execEnv) stays.
…F4/F9) F1: derive the container sync set from the VFS itself (git status against the checkout) before every container exec, instead of tracking dirty paths in memory. Materializing before each exec -- not only at attach -- closes the edit-after-attach gap (stale container source, and a fix push that omits post-attach edits) and survives an isolate resume, since the VFS is the only source consulted. Removes #dirtyPaths and the write-through path; the one-time base checkout stays in the injected attachContainer. F4: readArtifact takes a bare filename under .bot-artifacts/ -- rejects path separators, '.'/'..', absolute forms, and a symlinked target. F9: rewrite the module header to operative facts; the coherence claim is now true because every container exec re-derives from the VFS.
Non-z porcelain C-escapes and quotes special-character paths, so a delete of such a path silently no-opped in the container (surviving stale file), and the ' -> ' rename heuristic misfired on paths containing that literal. Switch to 'git status --porcelain -z': NUL-delimited, never quoted or escaped, with rename/copy old paths in a trailing NUL field (new-then-old). Adds rename and non-ASCII regression tests.
… mirror WorkspaceDO bindings in the test config
…gated push capability; align skill docs with agent-owned pushes
2b8b15f to
89ef4d6
Compare
What does this PR do?
Slice 3 of the bot next-gen stack (on #2376). Replaces emdash-bot's execution plumbing with a hybrid
execEnvand lands the investigation skills.@cloudflare/computer0.1.1 (pinned exact) provides the isolate surface — durable SQLite VFS on a newWorkspaceDO(append-only migration v4), in-VFS isomorphic-git (clone/status/diff without a container), andjust-bashisolate exec via the Worker Loader. The existing@cloudflare/sandboxcontainer keeps the real-Linux work (pnpm install,astro build, vitest, agent-browser). computer's own container backend requirescomputerd, which Cloudflare has not published (private in their monorepo; verified against the tarball and repo) — theexec-env.tsmodule is the single flip-point when that changes.git status --porcelain -zand materialized into the container checkout. No in-memory bookkeeping — correctness survives isolate eviction/resume in both directions (adversarial review found the stateful version lost edits across isolate restarts; the stateless design eliminates the class).readArtifactaccepts bare filenames only (traversal/absolute/symlink rejected); every exec is deadline-bounded across both substrates.Investigation model stays
@cf/moonshotai/kimi-k2.7-code(verified id); classifier unchanged.Closes #
Type of change
Checklist
pnpm typecheckpasses — n/a-with-note: same pre-existinginfra/emdash-botred baseline as chore(emdash-bot): port to Flue 2.0.3 with Workers traces (bot next-gen 1/5) #2375/feat(emdash-bot): maintainer-triggered investigation + fix-loop states (bot next-gen 2/5) #2376; zero new error classespnpm lintpasses — oxlint--type-aware --deny-warningsexit 0pnpm testpasses — unit 111/111, integration 35/35 (workers pool)pnpm formathas been runAI-generated code disclosure
Screenshots / test output
Known live-validation items deferred to the slice-5 eval harness (cannot be exercised in CI): isolate exec + VFS git clone against real bindings, container attach round-trip, bundle headroom watch.
Try this PR
Open a fresh playground →
A full working EmDash site, deployed from this branch. Each visit gets its own session-scoped sandbox: no login needed and no shared state. Try the admin, edit content, hit the public site.
Tracks
bot-nextgen/03-computer-exec. Updated automatically when the playground redeploys.