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

PackagePurpose
@b4run/sdkThe author-facing TypeScript SDK — agent(), defineMiddleware(), allow()/reject(), and the type primitives the CLI consumes.
@b4run/coreFilesystem-based route discovery, app config loading, state-field resolution, and typegen primitives that the B4.run CLI builds on.
@b4run/cliThe b4 CLI — local HMR dev runtime, route execution, validation, typegen, and the build step that produces LangSmith deployment artifacts.
@b4run/langgraphLangGraph runtime adapters and route module contracts (graphAdapter, workflowAdapter, defineEntry) used by the CLI.
@b4run/langchainLangChain backend adapters — materializes chain routes and provider-aware agent routes (tool conversion, streaming, retry).

Capabilities & integrations

PackagePurpose
@b4run/ag-uiAG-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/permissionsPermission and access-control primitives for B4.run agents — gating tool and resource access at runtime.
@b4run/workspaceFilesystem-backed workspace utilities for B4.run agents — reading, writing, and managing files in an agent's working directory.
@b4run/sandboxReference 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-pluginVite plugin for B4.run's typegen pipeline (extracts tool types and generates route ambient declarations).

Storage & memory

PackagePurpose
@b4run/memoryDeterministic long-term memory storage and recall for B4.run's typed memory.ts capability — the storage/ranking layer under @b4run/core.
@b4run/memory-pgvectorPostgres + 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-storageSQLite-backed storage adapter for B4.run — durable persistence for agent state and runtime data.
@b4run/postgres-storagePostgres 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

PackagePurpose
@b4run/testingTesting utilities for B4.run apps — helpers for exercising routes, tools, and agent behavior in unit and scenario tests.
@b4run/evalsEvaluation harness for B4.run agents — running and scoring agent behavior against datasets and scenarios.

Scaffolding & tooling

PackagePurpose
create-b4-appScaffold 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/devkitInternal scaffold templates and dev-time tooling shared between @b4run/cli and create-b4-app.
@b4run/config-typescriptShared TypeScript compiler configurations (base, library, node, nextjs) for B4.run workspace packages.
@b4run/config-biomeShared Biome lint/format configuration used by B4.run workspace packages.

Apps

PackagePurpose
@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)

PackagePurpose
@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)

ChartPurpose
charts/b4-appRuns 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-infraCluster-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:

  1. pnpm test:release-integrity — early content pins and recovery-policy checks
  2. pnpm lint
  3. pnpm check:build-cache
  4. pnpm build
  5. pnpm typecheck
  6. pnpm test
  7. pnpm check:release-inventory
  8. node 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's fixed group). On a 0.x train a minor bump takes every package to 1.0.0 — use patch unless 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. Use pnpm lint (or pnpm lint:fix to 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 sibling src/*.ts modules with a .js extension; 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; no gpt-4o, though it stays in the provider registry, validation tests, and recorded fixtures). This is a project convention, not currently enforced by scripts/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 compile src/*.ts to a gitignored dist/, and consumers import the built output — a stale or skewed dist/ (from a branch switch or a per-package filtered build) produces false negatives in ad-hoc scripts. Run pnpm build first; see CONTRIBUTING.md's "Build before running anything against dist/".
  • Banned doc phrases. scripts/check-docs.mjs greps README.md, CONTRIBUTING.md, CONTRIBUTORS.md, SECURITY.md, CODE_OF_CONDUCT.md, apps/web/app, apps/web/content, docs/ (excluding docs/superpowers/), and packages/ for stale or overstated wording — e.g. the retired b4.run domain, provider-prefixed model ids (openai:gpt...), the old agent.bindTools / .b4/generated / auto-bound/auto-registered phrasing, 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 the forbiddenContent list in scripts/check-docs.mjs for 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 fails pnpm test:release-controller until the reviewed fixture is regenerated in the same commit. Reachability is re-derived from workflow run: steps, package-script expansion, and action with: inputs, and then closed transitively over each entrypoint's repository-local module loads — static import/export ... from, dynamic import() with a literal specifier, and the new 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 in REVIEWED_DYNAMIC_IMPORT_SEAMS. Files a pinned module reads off disk instead of importing are declared in RELEASE_DATA_FILES and anchored to a reader. This is deliberately limited to release ownership; ordinary CI-only scripts are not pinned. See CONTRIBUTORS.md's "Release Integrity Coverage" for the boundary.

Where things live

  • Docs site content: apps/web/content/docs/*.mdx (nav registered in apps/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.
  • CONTRIBUTING.md — the public PR path: setup, issues, PRs, CLA/DCO, code of conduct.
  • CONTRIBUTORS.md — internal monorepo guide: local setup, the --mode internal scaffold path, and verification lanes. Its per-package responsibilities point back at the workspace map above.
  • README.md — project overview and quickstart.