Chat
September 8, 2026 · View on GitHub
Status: foundational harness primitives (filesystem + bash) plus the planning, skills, subagents, workspace, and HITL permissions capabilities. Pluggable backend implementations (in-memory, remote sandbox) are available — see
b4.config.ts. Tool-output offloading is supported for workspace-backed routes, and conversation summarization is available as an opt-in config.
What this shows
- B4.run route discovery and the
tools/convention - Workspace capability — when a route's working directory contains
workspace/, B4.run auto-contributesreadFile/writeFile/listDir/runBashtools wired through pluggable backends. The filesystem and exec backends default to local node:fs / child_process; swap them inb4.config.tsfor in-memory storage, remote sandboxes, etc. AGENTS.mdmemory autoload — B4.run auto-injectsworkspace/AGENTS.mdinto the system prompt on every turn; the agent updates it viawriteFile- Planning —
plan.mdin the route directory opts the agent into the built-inwriteTodostool, atodosstate channel, and aplan_updateAgent Protocol stream event. The AG-UI adapter maps valid root updates to standard replacementb4.planactivity snapshots. - Skills —
src/app/chat/skills/<name>/SKILL.mdfiles are auto-listed in the agent's system prompt (name + description). The agent callsreadSkill({ name })to load a skill's full body on demand. Two example skills ship with the demo:workspace-conventionsandrecover-from-failure. - Subagents —
/coordinatordispatches to specialist subagents (research,summarizer) via an auto-generatedtask({ subagent, input })tool. Subagent runs bubblesubagent.*Agent Protocol stream events withcall_idcorrelation, and the AG-UI adapter maps matching lifecycles to bounded replacementb4.subagentsnapshots. The basic web client registersb4ActivityRenderersfrom@b4run/ag-ui/react, but drives only/chatand does not expose/coordinator, so drive coordinator runs through Agent Protocol instead. - HITL permissions —
b4.config.tsseeds allow/deny lists forrunBash. Unknown commands in interactive mode emit an interrupt; resume the thread withonce,always, ordenyto continue. See Permissions for the interrupt/resume flow. - End-to-end streaming to a CopilotKit V2 web client over
B4.run's AG-UI endpoint (
POST /agui/{routeId}, see@b4run/ag-ui) for basic/chatmessages. The browser uses CopilotKit's same-origin multi-route runtime under/api/copilotkit/*; the runtime'sHttpAgentowns the server-to-server B4.run call. The client presents plan/subagent activities and the standard permission decision control.
Model choice
This example uses gpt-5 with reasoning: { effort: "high" }. In live testing, smaller models (gpt-5-mini, gpt-5-nano) tend to ignore explicit tool-use directives and produce generic "what can I help you with?" responses on the first turn — they don't reliably exercise the planning + memory capabilities. gpt-5 engages with tools and actually drives an agent loop. The tradeoff: each turn costs more.
If you swap to a smaller model, expect to do more prompt-engineering work to get tool calls to fire.
Quickstart
Run these commands from the repository root:
cd examples/chat
cp server/.env.example server/.env # add OPENAI_API_KEY
cp web/.env.example web/.env.local
pnpm install
pnpm dev
# open http://localhost:3000
Layout
examples/chat/
├── server/ # @b4-example/chat-server (B4.run routes)
│ ├── b4.config.ts # appDir + optional backends config
│ ├── workspace/ # shared workspace (AGENTS.md lives here)
│ └── src/app/
│ ├── chat/ # /chat route
│ │ ├── index.ts # agent({ model, systemPrompt })
│ │ ├── state.ts
│ │ ├── system-prompt.ts
│ │ ├── plan.md # presence enables planning
│ │ └── skills/ # SKILL.md files per skill
│ └── coordinator/ # /coordinator route + subagents
│ ├── index.ts
│ └── subagents/
│ ├── research/index.ts
│ └── summarizer/index.ts
└── web/ # @b4-example/chat-web (CopilotKit v2 web client)
└── app/
├── layout.tsx # imports @copilotkit/react-core/v2/styles.css
├── page.tsx # CopilotKit + CopilotSidebar
└── api/copilotkit/[...path]/route.ts # V2 runtime + HttpAgent → B4.run /agui/%2Fchat%23agent
Security caveats
runBash executes shell commands on your machine with cwd: workspace/ and a timeout.
This is NOT a sandbox. Network calls, package installs, file ops outside workspace/ via
shell expansion — all possible. Do not point untrusted users at this example.
Current capability notes
- HITL permission gating is active in this demo. The example config pre-approves a
few read-only shell commands and denies destructive patterns; any other
runBashcommand pauses the run for a human decision in interactive mode. Path escapes outsideworkspace/are also permission-gated by the workspace capability. See Permissions and the configuration reference. The basic web client renders CopilotKit's standard interrupt decision control. - Tool-output offloading is supported by the runtime and is active whenever the app
root has a
workspace/directory. Large tool results are written underworkspace/tool-outputs/and replaced in context with a preview plus areadFilehandle. Tune thresholds and retention with thetoolOutputconfig. See Context Management and the configuration reference. - Conversation summarization is supported but opt-in. This example leaves it disabled
by default; enable
summarization.enabledinb4.config.tswhen you want older message history compacted after a token threshold. See Context Management and the configuration reference.
The remaining limitations are scoped to this example's surface, not missing runtime capabilities:
- Nested-object tool inputs (e.g.,
edit_file({ edits: [{ old, new }] })) — typegen extension - The web client only drives
/chat;/coordinatoris outside this basic client's UI.