Align the agent instruction files with the current CLAUDE.md guidance: keep only what a session cannot derive from the tree, and load package-specific rules on demand. - Replace the workspace table and the docs table with pointers to `ls packages/` and docs/README.md, which already indexes every page. - Split the dependency-pinning rule into rule and rationale, and reflow the run-store invariant onto one line. - Move the architecture entry points, the examples lint exclusion, and the adapter checklist into packages/core/AGENTS.md, with a CLAUDE.md shim that imports it.
11 KiB
AGENTS.md
This file is the canonical working agreement for AI agents editing this repository. It holds the execution rules, high-risk invariants, and verification expectations that apply across workspaces. Conceptual architecture lives in packages/core/README.md, subsystem behavior in docs/, and package-specific traps in each package's own AGENTS.md, so this file stays concise and accurate.
Repository layout
This is a private npm-workspaces root. Run the commands below from the repository root unless a workspace-specific -w form is shown. Discover the workspaces with ls packages/ and read each package.json for its scripts; the facts below are the ones that listing cannot tell you.
@open-multi-agent/release-botis private and never published. It drives.github/workflows/release-bot.ymlandpublish.yml.@open-multi-agent/otelis versioned independently from core.bench/is the A/B benchmark harness: not a workspace, never published, runs throughnpx tsx, and everything it produces is gitignored.- Paths in this file are repository-relative. An unprefixed
src/ortests/is ambiguous across workspaces, so name the package. - Package-specific rules live in nested
AGENTS.mdfiles (ls packages/*/AGENTS.md), each beside aCLAUDE.mdthat only imports it. They load when you work inside that package; read them before editing there.
Commands
npm run build # Compile every workspace
npm run lint # Type-check every workspace; core lint also covers packages/core/examples/
npm test # Unit tests in every workspace; mocks provider SDKs, needs no network or API keys
npm run test:scaffold # End-to-end create-oma-app scaffold smoke test
npm run test:example-catalog # Validate example catalog metadata and coverage
npm run test:e2e # Core provider E2E; needs real API keys, as do most examples
node packages/core/dist/cli/oma.js help # After build; `oma` when installed from npm
Working rules
- Use strict TypeScript and ESM imports with
.jsextensions:import { X } from './foo.js'even when the source file is TypeScript. There is no eslint/prettier configuration; match nearby style. - Change source files, tests, templates, or docs rather than generated
dist/output. - Add or update tests for behavior changes. Update user-facing docs and examples when public behavior changes, or state why they are not applicable.
- Keep dependency ownership explicit. Core must remain importable and runnable without optional integrations.
- Pin what stays in the repository; keep ranges on what a consumer installs.
devDependencieseverywhere and the release bot's dependencies are exact; the root.npmrcsetssave-exact=trueso a new one arrives pinned. The published blocks stay semver ranges: core'sdependencies, everypeerDependencies, and otel's@open-multi-agent/core. save-exactalso pins a new entry in a published block, so widen it by hand. An exact version there overrides the consumer's own resolution and blocks theirnpm audit fixuntil we cut a release; thepackagejob in.github/workflows/ci.ymlfails when one is left exact.- Add optional provider SDKs as peer dependencies and load them lazily with dynamic
import(). Do not maintain a fixed dependency or adapter count in documentation. - OpenTelemetry APIs, SDKs, semantic-convention packages, and exporters belong in
@open-multi-agent/otel, never in the core root import. The application owns its tracer/provider lifecycle unless an API explicitly says otherwise. docs/is the source of truth for subsystem behavior. docs/README.md indexes every page with the question it answers; runls docs/before concluding a topic is undocumented. Keep this file to rules and concise invariants, and link to docs instead of copying explanations.- The package READMEs are landing pages, not guides. A new feature earns at most one short paragraph plus a link to its
docs/page inpackages/core/README.md; anything longer belongs indocs/. Updatepackages/core/README_zh.mdin the same change or the translation drifts. Per-contributor credits live inCONTRIBUTORS.md, not in a README. - Follow conventional commits when a commit is requested. Reference a PR or issue when one exists. The full contribution flow is in
.github/CONTRIBUTING.md. - Publishing spans three packages with independent version tracks, a fixed publish order, and template pins that must move with the core version. Do not infer any of that from this file:
.github/RELEASING.mdis the source of truth. - Managed Git worktrees share repository metadata. Never repair access by changing
.gitownership or permissions. Use the current tool's normal Git and approval flow. - Keep worktree dependencies isolated. Run
npm ciin each worktree and never symlinknode_modulesfrom another checkout.
Validation by change type
Always inspect the focused diff and run git diff --check. Run the smallest relevant checks first, then broaden in proportion to the change.
- Documentation-only:
git diff --check; tests are not required unless commands, generated artifacts, or executable examples changed. - Core code: relevant core tests, then
npm run lint -w @open-multi-agent/coreandnpm run test -w @open-multi-agent/core. Runnpm run build -w @open-multi-agent/corewhen public entry points, declarations, package output, or CLI output may be affected. - OpenTelemetry adapter: relevant tests, then
npm run lint -w @open-multi-agent/otel,npm run test -w @open-multi-agent/otel, and build when package output or public types may be affected. - Release bot: relevant tests, then
npm run lint -w @open-multi-agent/release-botandnpm run test -w @open-multi-agent/release-bot; both build core first through theirprescripts, so they also catch a core API change that breaks the bot. Workflow changes follow.github/RELEASING.md. - Scaffolder or templates: relevant tests, then
npm run lint -w create-oma-app,npm run test -w create-oma-app, andnpm run typecheck:template -w create-oma-app. Runnpm run test:scaffold -w create-oma-appwhen generated-project behavior changes. - Examples or catalog metadata:
npm run test:example-catalogandnpm run lint -w @open-multi-agent/core; add a runnable example smoke test when executable behavior changes. Which examples core lint excludes, and why, is inpackages/core/AGENTS.md. - Cross-workspace or dependency changes:
npm run lint,npm test, andnpm run build; add the package/import/template smoke checks relevant to the changed surface. - Provider E2E: run only when the changed surface requires real-provider verification and the necessary credentials are safely available. Never expose credential values.
Before finishing, report every command run and its outcome. If a relevant check was skipped or could not run, state the reason and residual risk. CI remains the source of truth for the complete Node 20/22/24 pre-merge matrix.
Non-obvious invariants
These constraints span multiple files and packages and can cause behavioral or compatibility bugs when missed. Each links to the docs/ page that owns the full contract.
- Tool errors are values: tool failures are returned as
ToolResultwithisError: true; they do not throw through the runner. LLM API failures propagate. Task failures cascade to dependents while independent tasks may continue. - Built-in tools are default-deny: a built-in is granted only through
AgentConfig.tools,toolPreset, orOrchestratorConfig.defaultToolPreset. Registered custom/runtime tools are granted by registration but still honordisallowedTools. Ungranted calls return an error rather than executing. See tool configuration. - Per-call gates run below grants:
onToolCallruns after Zod validation and before execution. Denial returns an errorToolResult; throwing or invalid gates fail closed. Ungranted tools never reach the gate.AgentConfig.onToolCalloverrides the orchestrator default. The optional shell classifier is exported from/classifiers. - Delegation is orchestration-only and separately granted:
delegate_to_agentexists only inrunTeam()andrunTasks()workers and must be explicitly granted. StandalonerunAgent()and the simple-goal short circuit do not register it. Self-delegation, cycles, unknown targets, excess depth, and unavailable pool capacity are rejected; delegated usage counts against the parent budget. - Filesystem tools are sandboxed;
bashis not: filesystem built-ins resolve paths and symlinks withinAgentConfig.cwdorOrchestratorConfig.defaultCwd, defaulting to<cwd>/.agent-workspace.nulldisables that sandbox andprocess.cwd()widens it. Shell execution has no equivalent filesystem boundary. See sandbox and shell. - Reasoning is dropped unless opted in: provider-native reasoning blocks that the target adapter cannot echo are discarded unless
preserveReasoningAsTextis enabled. Inline<thinking>text is never reconstructed into a signed reasoning block. See context management. - Native tool calls win: the local-model text extractor runs only when a server emits no native tool calls.
- External backends replace the LLM runner: process and ACP backends perform their own work in
cwd; the runner tool loop, sandbox, and context strategy do not apply, while queue, scheduler, memory, and budget behavior remain backend-agnostic. ACP permissions default to auto-approve and its cumulative context usage is recorded as per-turn deltas when updates exist. See external agents. - Ownership is opt-in, and its writes fail closed: without a
runStorea checkpoint is recovery state with no owner, so two processes can restore the same snapshot and both advance it. With one, a run acquires a lease before it dispatches, checkpoint writes fence against its token, and lifecycle writes reject rather than degrade to best-effort. A worker that lost its lease writes no terminal status and never reports success. See run store. - Telemetry is not execution state: losing telemetry must not roll back a durable run. Deleting traces must not delete checkpoints, shared memory, or remotely exported OpenTelemetry data. Observability delivery/export failures do not become agent, task, or run failures. See observability.
- Evaluation observes results: offline evaluation is separate; online sampling, scoring, and persistence are best-effort and isolated from the business response. Scorer failures become
scorer_errorand are excluded from score aggregates rather than converted to zero. See evaluation. - Secrets and PII are redacted best-effort: traces, shell output, and dashboard payloads pass through redaction, but callers must still avoid deliberately persisting or logging secrets.