AGENTS.md
September 8, 2026 · View on GitHub
Standards for anyone — human or coding agent — working in this repository: the workspace map, the Definition of Done, and the conventions that keep changes consistent.
What this is (and isn't)
This is the repo-root contributor/agent standards doc — how to find your
way around the B4.run monorepo, what "done" means for a change, and the rules
that keep the codebase consistent. It's the canonical entrypoint; see
Cross-links for how it relates to CONTRIBUTING.md and
CONTRIBUTORS.md.
This is not the runtime workspace/AGENTS.md capability. B4.run ships a
built-in capability
(packages/core/src/capabilities/built-in/agents-md.ts) that auto-injects the
contents of an app's <appRoot>/workspace/AGENTS.md into that agent's
system prompt as its persistent "# Memory" — re-read every turn, updated by
the agent itself via writeFile. That's an end-user B4.run app feature,
documented at b4.run/docs/memory. The
name collision is real: this file (repo root, for contributors) and that file
(inside a generated app's workspace/, for the agent at runtime) share a
filename but nothing else. If you're looking for the runtime feature, this
isn't it.
Workspace map
Every packages/* directory is a pnpm workspace member (verify: pnpm -r list --depth -1). One-line purpose is each package's own README.md first line.
Core framework
| Package | Purpose |
|---|---|
@b4run/sdk | The author-facing TypeScript SDK — agent(), defineMiddleware(), allow()/reject(), and the type primitives the CLI consumes. |
@b4run/core | Filesystem-based route discovery, app config loading, state-field resolution, and typegen primitives that the B4.run CLI builds on. |
@b4run/cli | The b4 CLI — local HMR dev runtime, route execution, validation, typegen, and the build step that produces LangSmith deployment artifacts. |
@b4run/langgraph | LangGraph runtime adapters and route module contracts (graphAdapter, workflowAdapter, defineEntry) used by the CLI. |
@b4run/langchain | LangChain backend adapters — materializes chain routes and provider-aware agent routes (tool conversion, streaming, retry). |
Capabilities & integrations
| Package | Purpose |
|---|---|
@b4run/ag-ui | AG-UI protocol translation for B4.run's local runtime — maps runtime stream chunks to AG-UI events and back, so CopilotKit and other AG-UI clients can drive B4.run agents. |
@b4run/permissions | Permission and access-control primitives for B4.run agents — gating tool and resource access at runtime. |
@b4run/workspace | Filesystem-backed workspace utilities for B4.run agents — reading, writing, and managing files in an agent's working directory. |
@b4run/sandbox | Reference sandbox providers for B4.run workspace execution — a Docker-backed SandboxProvider that redirects the workspace filesystem and shell tools into a per-thread isolated environment. |
@b4run/vite-plugin | Vite plugin for B4.run's typegen pipeline (extracts tool types and generates route ambient declarations). |
Storage & memory
| Package | Purpose |
|---|---|
@b4run/memory | Deterministic long-term memory storage and recall for B4.run's typed memory.ts capability — the storage/ranking layer under @b4run/core. |
@b4run/memory-pgvector | Postgres + pgvector backend for B4.run's typed long-term memory store, for deployments where SQLite is too local (multiple instances, shared DB, HNSW retrieval at scale). |
@b4run/sqlite-storage | SQLite-backed storage adapter for B4.run — durable persistence for agent state and runtime data. |
@b4run/postgres-storage | Postgres backend for B4.run's durable runtime state — checkpointer, Agent Protocol threads store, and permissions store over one pg pool, for deployments where the .b4/ files are too local (multiple instances, shared DB, ephemeral filesystem). |
Testing & evals
| Package | Purpose |
|---|---|
@b4run/testing | Testing utilities for B4.run apps — helpers for exercising routes, tools, and agent behavior in unit and scenario tests. |
@b4run/evals | Evaluation harness for B4.run agents — running and scoring agent behavior against datasets and scenarios. |
Scaffolding & tooling
| Package | Purpose |
|---|---|
create-b4-app | Scaffold a new B4.run app — generates a working application from the supported starter templates with B4.run's canonical layout wired for local development. |
@b4run/devkit | Internal scaffold templates and dev-time tooling shared between @b4run/cli and create-b4-app. |
@b4run/config-typescript | Shared TypeScript compiler configurations (base, library, node, nextjs) for B4.run workspace packages. |
@b4run/config-biome | Shared Biome lint/format configuration used by B4.run workspace packages. |
Apps
| Package | Purpose |
|---|---|
@b4run/web (apps/web) | The documentation website (b4.run) and its content/nav. |
Examples (examples/*, pnpm workspace members; consume B4.run via workspace:* and are typechecked in CI)
| Package | Purpose |
|---|---|
@b4-example/chat-server / @b4-example/chat-web (examples/chat) | Foundational agent-harness primitives (filesystem + bash) end-to-end, plus planning, skills, subagents, workspace, and HITL permissions, with a disposable smoke-test web client. |
@b4-example/memory (examples/memory/server) | Long-term memory with a backend-switchable store — zero-setup SQLite by default, Postgres + pgvector via DATABASE_URL, hybrid keyword + vector recall via OPENAI_API_KEY. |
@b4-example/research-server / @b4-example/research-web (examples/research) | The flagship deep-research assistant example — routes, tools, subagents, memory, planning, offloading, HITL permissions, and an optional Docker sandbox. |
Note: examples/chat/package.json and examples/research/package.json are
orchestration-only (private: true, one level above server/web) and are
not themselves pnpm workspace members — the actual members are the
server/web subdirectories, matched by the examples/*/* glob in
pnpm-workspace.yaml.
Charts (Helm charts under charts/, not pnpm workspace members)
| Chart | Purpose |
|---|---|
charts/b4-app | Runs a built B4.run app image on Kubernetes as a Deployment + Service, with optional Ingress, HorizontalPodAutoscaler, and PodDisruptionBudget, with an application-owned ServiceAccount in the chart release namespace. Sandbox access is bound cross-namespace to the b4-sandbox-infra orchestrator Role. |
charts/b4-sandbox-infra | Cluster-side infrastructure for the B4.run kubernetesSandbox provider — namespace, least-privilege RBAC, default-deny egress, quotas/limits, Pod Security Standards, and a PVC reaper. |
test/ and scripts/ are repo-level (verification lanes and workspace
scripts respectively) — not workspace packages.
Definition of Done
The required validate job in .github/workflows/ci.yml aggregates four
independent lanes and succeeds only when all four succeed. Failure, cancellation,
or a skipped lane blocks it.
The source-validate lane runs these gates in order after installation:
pnpm test:release-integrity— early content pins and recovery-policy checkspnpm lintpnpm check:build-cachepnpm buildpnpm typecheckpnpm testpnpm check:release-inventorynode scripts/check-docs.mjs
The release-controller lane installs dependencies, runs the early integrity
checks, and runs the complete pnpm test:release-controller suite from an unbuilt
checkout. The pack-smoke lane runs pnpm pack:check and
pnpm verify:typescript-tooling-pack. The harness-verify lane runs
pnpm verify:harness:self-test and the framework, runtime, and smoke harnesses.
These gates remain part of repository validation.
On pull requests, a separate changesets job also runs
node scripts/check-changesets.mjs to require a changeset for user-facing
package changes.
Run pnpm ci:validate locally to run the validation commands sequentially.
The script in the root package.json runs release-integrity → lint → build-cache →
build → typecheck → source-test → release-inventory → release-controller-test →
docs-check → pack-check → TypeScript-tooling-pack → harness sequence, plus
the local-only test:sync-chart-appversion release-script unit test, which is
not a separate CI step. The former publish, upload, and backfill unit-test
commands were removed with their legacy release owners; their replacement
coverage is part of test:release-controller.
Gated lanes — these run as separate CI jobs behind env flags or dedicated
infrastructure, not part of validate, and aren't required for most PRs:
sandbox-docker (B4_TEST_DOCKER=1), pgvector-docker
(B4_TEST_PGVECTOR=1), postgres-storage-docker (B4_TEST_PGSTORAGE=1,
Testcontainers postgres:16), sandbox-k8s (B4_TEST_K8S=1, kind + Calico),
sandbox-k8s-e2e / sandbox-docker-e2e (B4_TEST_SMOKE_E2E=1, full-arc
deployed-app smoke), chart-validate (Helm lint + kubeconform), and
chart-apply-smoke (kind install smoke).
Release-bearing changes must also leave the separate copilotkit-examples-e2e
and real vercel-native production-boundary jobs green. The CopilotKit examples
exercise the v2 integration surface, and the Vercel job creates, verifies, and
removes real preview resources through the pinned Vercel CLI; neither lane is a
substitute for the other or optional release cleanup.
Conventions
- Changesets are a fixed group, patch on 0.x. All publishable packages
release together (
.changeset/config.json'sfixedgroup). On a 0.x train aminorbump takes every package to1.0.0— usepatchunless you intend a real 1.0 release. exactOptionalPropertyTypes: true. Never assign{ x: undefined }to an optional field; use a conditional spread (...(x !== undefined ? { x } : {})) instead, or the type checker will reject it.- Never run bare
biome check --write. It mass-reformats the whole workspace. Usepnpm lint(orpnpm lint:fixto auto-fix), or scope Biome to the files you changed. - Import specifiers:
src/uses.js,test/uses.ts. This is NodeNext ESM — source files import siblingsrc/*.tsmodules with a.jsextension; test files import with.ts. Follow the existing pattern in the package you're editing. - Examples/docs/scaffolds use gpt-5-family models only (canonical default
gpt-5-mini; nogpt-4o, though it stays in the provider registry, validation tests, and recorded fixtures). This is a project convention, not currently enforced byscripts/check-docs.mjs— check it by eye when touching examples. - Branch per PR; pin before dispatching parallel/subagent work. In a multi-worktree setup, a subagent's commits can land on a detached HEAD tracking the wrong branch if the feature branch isn't checked out first.
- Build before running anything against
dist/. Packages compilesrc/*.tsto a gitignoreddist/, and consumers import the built output — a stale or skeweddist/(from a branch switch or a per-package filtered build) produces false negatives in ad-hoc scripts. Runpnpm buildfirst; seeCONTRIBUTING.md's "Build before running anything againstdist/". - Banned doc phrases.
scripts/check-docs.mjsgrepsREADME.md,CONTRIBUTING.md,CONTRIBUTORS.md,SECURITY.md,CODE_OF_CONDUCT.md,apps/web/app,apps/web/content,docs/(excludingdocs/superpowers/), andpackages/for stale or overstated wording — e.g. the retiredb4.rundomain, provider-prefixed model ids (openai:gpt...), the oldagent.bindTools/.b4/generated/auto-bound/auto-registeredphrasing, and claims like "byte-identical" or "speaks the LangSmith protocol natively" that overstate local/prod parity. This file (AGENTS.md) isn't in that scanned set, but keep it honest anyway — see theforbiddenContentlist inscripts/check-docs.mjsfor the exact patterns. - Always run commands from the repo root. Turbo and workspace-package resolution assume it.
- Every final-workflow-reachable release script is content-pinned. The
audited SHA256 and exact command line for each repository script reachable
from the final release-owner workflows are recorded in
scripts/release/test/fixtures/release-script-hashes.json. Editing a reachable script, adding an unpinned entrypoint, or retaining a stale pin failspnpm test:release-controlleruntil the reviewed fixture is regenerated in the same commit. Reachability is re-derived from workflowrun:steps, package-script expansion, and actionwith:inputs, and then closed transitively over each entrypoint's repository-local module loads — staticimport/export ... from, dynamicimport()with a literal specifier, and thenew URL("./sibling.mjs", import.meta.url)form the release CLI hands to its injected loader. A load whose specifier cannot be resolved statically fails the check rather than being skipped; the reviewed exceptions live inREVIEWED_DYNAMIC_IMPORT_SEAMS. Files a pinned module reads off disk instead of importing are declared inRELEASE_DATA_FILESand anchored to a reader. This is deliberately limited to release ownership; ordinary CI-only scripts are not pinned. SeeCONTRIBUTORS.md's "Release Integrity Coverage" for the boundary.
Where things live
- Docs site content:
apps/web/content/docs/*.mdx(nav registered inapps/web/app/components/docs/nav.ts). - Specs, plans, audits, runbooks:
docs/superpowers/. - CI:
.github/workflows/ci.yml. - Changeset config (fixed group, patch-on-0.x):
.changeset/config.json.
Cross-links
CONTRIBUTING.md— the public PR path: setup, issues, PRs, CLA/DCO, code of conduct.CONTRIBUTORS.md— internal monorepo guide: local setup, the--mode internalscaffold path, and verification lanes. Its per-package responsibilities point back at the workspace map above.README.md— project overview and quickstart.