A real dsh Cordis bundle with an Agent Apps manager shown inside the dsh UI, alongside the agent tools. It registers no new top-level route (dsh has none for plugins); the manager appears as a global panel: an icon in the left sidebar whose click shows the manager in the centre column.
- Agent tools (src/index.ts) —
apply(ctx)registers the build+operate tools viactx.tools.register(defineTool(...)), each shelling a framework CLI verb through the shared engine. They include the task tools (agent_app_next_task,agent_app_task_progress,agent_app_complete_task) an agent takes and closes work an app queued with. - Bridge route —
apply(ctx)also registers dsh withagent-app <dir> bridge, the service that starts a harness when an app queues work, as adshprofile in$A2APP_HOME/harnesses.json:dsh --profile headless {prompt}, one turn in the app's directory. Its default sandbox confines writes, not network, so the agent reaches the app through the a2app CLI. The framework has no built-in dsh profile, so without this the bridge cannot see dsh. Written once; an existingdshentry (your own) is kept. - The six skills (src/skills.ts) — registered as a
ctx.skillsprovider over theskills/directory the build stages beside the bundle. dsh has no per-bundle skill discovery: its only filesystem provider (skill-filesystem) isdisabled: truein the shippedwebprofile, so a provider is the only way a bundle's skills reach an agent's catalog. - Agent Apps manager (src/manager.ts + src/ui.ts) — mounted once dsh's
webServeris available. Browser-style tabs (one per app, status dot, greyed when offline) plus a New + build form; an app tab embeds the running app in an iframe; each app has a resizable session side panel (transcript + composer); the ⋯ menu launches/pauses/deletes. Build and chat drive a dedicated dsh session (ctx.agents.create, orctx.agents.resumewhen that session already exists); the agent is created with the deployment's default model selection and the default agent preset mounted throughsetup, because{{model}}readsagent.options.modeland a preset is what composes an agent's persona and tool rows. The transcript is read back withsession.deriveMessages(); lifecycle shells the CLIs (serve/stop/remove). - Client half (src/client/index.ts) — claims two seats with one id (
agent-apps): amainkeyed entry renders the manager in the centre column, and asidebar.panellistlist entry contributes the left-sidebar icon that selects it (the sidebar owns the button, label and tooltip; the same id addresses the main panel). Selecting a Session or Workspace returns the centre column to the Conversation, so the panel is never a trap. The manager itself is an iframe of the host half's page — same origin as the dsh server, so its fetches and any embedded app need no CORS — told the theme through the route (?light=1) because an iframe cannot inherit--dsw-*tokens. Both registrations go throughctx.slots.inject, never a barectx.slots.register: the client creates every entry concurrently, somain(declared by ui-layout) andsidebar.panellist(declared by ui-sidebar) may not exist yet, andSlotCore.registerthrows on an undeclared slot.
dsh loads a bundle as a normally-resolvable npm package whose dsh.bundle.patch manifest points at cordis.patch.yml, with a host half (main → lib/index.js) and a browser half (./client → lib/client.js). scripts/build.mjs stages a self-contained dist/: the host bundle (engine inlined; cordis + @deepseek-ai/* external), the browser bundle wrapped in dsh's module-loader closure (the frozen platform module table — react, cordis, ui-slots — external, everything else inlined), a generated package.json with the dsh.bundle + dsh.client manifest, the patch, and the six skills.
From npm (the published package is this dist/; web is dsh's browser-UI profile, where the manager panel shows):
dsh plugin --profile web add @craftos/agent-app-dshFrom a cloned repo:
pnpm install
pnpm --filter @a2app/integration-starter build # the engine the host bundle inlines
pnpm --filter @craftos/agent-app-dsh build # stages dist/
dsh plugin --profile <name> add ./harness-plugins/dsh/distRequires the framework CLIs on PATH (npm i -g agent-app-framework; from a cloned repo, pnpm -r build then npm link in framework/cli). Set A2APP_CLI (operate, default a2app) and AGENT_APP_CLI (build/evolve, default agent-app) to override which binaries are shelled; a value ending in .js/.mjs/.cjs is run with Node directly.