Imported from HybridAIOne/hybridclaw (
AGENTS.md). Install upstream withnpx skills add HybridAIOne/hybridclaw. Copyright stays with the author.
AGENTS.md — HybridClaw Engineering Protocol
This file is the canonical repo-level instruction set for coding agents working in HybridClaw. Read it before any code change.
Scope
- Follow this file first.
- If a deeper directory contains its own
AGENTS.md, that file overrides this one for its subtree. - Keep
CLAUDE.mdaligned with this file.CLAUDE.mdshould only carry tool-specific deltas. templates/*.mdare product runtime workspace bootstrap files, not repo contributor onboarding docs.
1) Project Snapshot
HybridClaw is a personal AI assistant bot for Discord, powered by HybridAI. Enterprise-grade Node.js 22 application with gateway service, TUI client, and Docker-sandboxed container runtime.
Version: 0.35.3 | Package: @hybridaione/hybridclaw
| License: see LICENSE
Architecture: gateway (core runtime, SQLite persistence, REST API, Discord
integration) → container (Docker-sandboxed tool execution via file-based IPC) →
TUI (thin HTTP client). Agent workspaces are bootstrapped from templates/ and
seeded with identity, memory, and context files managed by src/workspace.ts.
2) Project Map
src/
cli.ts CLI entry point and command dispatch
types.ts Core type definitions (ChatMessage, ContainerInput, ToolExecution, etc.)
workspace.ts Workspace bootstrap (SOUL.md, IDENTITY.md, USER.md, etc.)
logger.ts Structured logging (pino)
tui.ts Terminal UI
onboarding.ts Interactive onboarding
model-selection.ts Model selection logic
agent/ Agent execution: conversation loop, tool executor, prompt hooks, delegation
audit/ Append-only audit trail, approval tracking, hash-chain integrity
auth/ HybridAI and OpenAI Codex authentication flows
channels/ Channel transports (discord, slack, telegram, email, whatsapp, msteams, voice, imessage)
config/ CLI flag parsing, runtime config management
doctor/ Doctor checks and resource hygiene maintenance
gateway/ Core gateway service: HTTP APIs, health, session mgmt, approvals
infra/ Container setup, IPC (file-based), worker signatures, runners
memory/ SQLite database, semantic memory, compaction, consolidation, chunking
providers/ Model providers (HybridAI, Anthropic, OpenAI, Ollama, LM Studio, vLLM)
scheduler/ Scheduled task execution and cron management
security/ Mount allowlists, approval policies, secret redaction, instruction audit
session/ Session transcripts, token tracking, compaction, export
skills/ Skill resolution, installation, trust-aware guard
utils/ Shared utilities
media/ Media handling and context management
container/ Sandboxed runtime (separate npm package)
src/ Container agent runtime, tool execution, provider adapters, MCP client
Dockerfile Container build definition
package.json Container-specific deps (Playwright, agent-browser, PDF, MCP SDK)
skills/ Bundled SKILL.md skills (pdf, docx, xlsx, pptx, office, personality, etc.)
templates/ Runtime workspace bootstrap files seeded into agent workspaces
tests/ Vitest suites: unit, integration, e2e, live
docs/ Static site assets, development reference docs
console/ Web console workspace package
eval-harness/ Benchmark/eval harness (unshipped; `npm run eval -- <suite>`)
Key Data Flows
User message → Gateway (HTTP/Discord) → ContainerInput (JSON)
→ Container spawns (Docker sandbox, file-based IPC)
→ Agent loop (tool calls, approvals, MCP)
→ ContainerOutput (JSON) → Gateway → User
→ Session persisted (SQLite), audit logged (wire.jsonl, hash-chained)
Extension Points
| Extension | Interface / Registration | Playbook |
|---|---|---|
| Skill | skills/<name>/SKILL.md frontmatter |
§7.1 |
| Provider | src/providers/<name>.ts + factory |
§7.2 |
| MCP Server | ~/.hybridclaw/config.json (mcpServers.*) → tool namespace |
§7.3 |
| Approval rule | .hybridclaw/policy.yaml |
§7.4 |
| Template | templates/<name>.md + src/workspace.ts |
§7.5 |
| Plugin | plugins/<name>/hybridclaw.plugin.yaml + register(api) |
§7.6 |
OpenTelemetry (Distributed Tracing)
Optional and off by default: the SDK is imported only when OTEL_ENABLED=true
or OTEL_EXPORTER_OTLP_ENDPOINT is set. Implementation in
src/observability/otel.ts; env vars and emitted spans are documented in
docs/content/developer-guide/runtime.md.
3) Engineering Principles
These are implementation constraints, not suggestions. Lean is the default: a change leaves the codebase smaller or says why it can't (owner call, 2026-09-24: the bloat is copies of the same fact and optional features in core, not dead code).
3.1 KISS
- Prefer straightforward control flow over abstraction.
- Keep error paths obvious and localized.
- Call a function directly. Do not route a direct call through an event bus, queue, or registry that has a single consumer.
- Dispatch from a table, not an if-chain with a fall-through default. An unknown key must fail, not run another key's branch.
- Three similar lines of code is better than a premature helper.
- Do not infer task intent from keyword or language-specific regexes over user prose (owner instruction, 2026-09-29). The model chooses search queries and relevant content through tool arguments; deterministic code validates those arguments and enforces access and resource limits.
3.2 YAGNI
- Do not add config keys, interfaces, hooks, registries, plugin API members, transports, or feature flags without a production caller in the same change.
- Do not add error handling for scenarios that cannot happen.
- Do not design for hypothetical future requirements.
- Code that only tests call is dead; delete it. Test reset hooks named
*ForTestsare the exception. - When a change replaces a mechanism (a router, client, runner, parser, or guard), delete the old one in the same change. No parallel implementations.
3.3 DRY — One Source per Fact, Rule of Three for Logic
- Facts are defined once, from day one. A list or map of channels, providers, tools, routes and their permissions, or config keys and defaults, and any type that crosses the gateway / container / console boundary, has exactly one definition. Before writing one, search for it and derive from it: import it, generate from it, or look it up. If a second copy is unavoidable, generate it and add a test that fails when the two diverge.
- Logic: duplicate small local logic when it preserves clarity; extract a
helper on the third copy. Reusing a helper that already exists is never
premature: check
src/utils/,container/shared/, and the owning module before writingisRecord,sleep,parseJsonObject, a base-URL normalizer, or a private-network check. - When extracting, preserve module boundaries. Code both the gateway and the
container need lives in
container/shared/.
3.4 Core Is for What Every Install Needs
- A feature belongs in core only if every install needs it or it is part of the security boundary (sandbox, approvals, secrets, audit). Everything else ships as a plugin (§7.6), a skill (§7.1), or an unshipped workspace: vendor and single-service integrations, channel SDKs, eval and benchmark harnesses, labs features, and optional heavy or native dependencies.
- If the plugin API lacks a hook the feature needs, add the smallest generic
hook to
src/plugins/with the feature as its first caller, rather than putting the feature in core. - Do not add a table, config section, or module to core that only one channel or vendor uses. Make it channel-agnostic, or keep it in the plugin.
3.5 Fail Fast
- Prefer explicit errors for unsupported or unsafe states.
- Never silently broaden permissions or capabilities.
- Validate at system boundaries (user input, external APIs, IPC); trust internal code.
3.6 Secure by Default
- LLM output is untrusted by default.
- Defaults are deny-by-default (mount allowlists, approval tiers, sandbox).
- Never log secrets, raw tokens, or sensitive payloads.
- Read
SECURITY.mdandTRUST_MODEL.mdbefore touching security surfaces. - Extend the existing private-network (SSRF) guard, pinned-path matcher, approval-policy parser, or secret redactor; never add another copy.
3.7 Workers Are Disposable
- A worker (agent container or host agent process) can die between any two turns: the 5-minute idle timeout, a provider or credential switch, eviction under pool pressure, a crash, or a gateway restart.
- Anything that must outlive a worker lives on the gateway side: SQLite and
the data dir, or the host-mounted workspace. Per-session facts go in the
session state dir (
container/src/session-state.ts). - Worker memory, worker
/tmp, and worker processes hold only caches the next worker rebuilds fromContainerInput, and live handles (running commands, open browser pages, MCP connections) that die with it. - Never promise the model or the user session-long behavior that only the worker remembers. A guard that depends on earlier calls persists what it remembered instead of failing open, and a tool whose live handle is gone says so on its next call.
- Adding worker state? Update "Worker State" in
docs/content/developer-guide/runtime.md.
4) Risk Tiers by Path
Classify changes by blast radius. When uncertain, classify higher.
| Tier | Paths |
|---|---|
| High | src/security/, src/gateway/, src/infra/, src/audit/, container/src/approval-policy.ts, container/src/extensions.ts, .hybridclaw/policy.yaml |
| Medium | src/agent/, src/providers/, src/session/, src/memory/, src/skills/, container/src/, templates/ |
| Low | docs/, skills/ (bundled SKILL.md), test additions, comments, formatting |
High-risk changes must include threat/risk notes and boundary/failure-mode tests. Medium-risk changes need targeted test coverage. Low-risk changes should verify no broken references.
5) Setup and Commands
Prerequisites
- Node.js 22 (matches CI and the
enginesfield) - npm 11.10+ — run
corepack enableso repo commands use thepackageManagerpin (npm@11.10.0). Contributors need this version because npm'smin-release-agesupply-chain gate (seeSECURITY.md) only takes effect on npm 11.10+; it is deliberately not enforced on end users viaengines.npm. - Docker when working on container-mode behavior or image builds
Common Commands
npm install # install deps + Husky hooks
npm run setup # install container/ deps
npm run build # compile root + container TypeScript
npm run typecheck # tsc --noEmit
npm run lint # tsc --noEmit with unused detection
npm run check # biome check src
npm run format # biome check --write src
npm run test:unit # vitest unit suite
npm run test:integration # integration tests
npm run test:e2e # end-to-end tests
npm run test:live # live tests (requires credentials)
npm run release:check # verify release readiness
npm --prefix container run lint # container lint
npm --prefix container run release:check # container release check
npm run build:container # build Docker image
Dev Mode
npm run dev # tsx src/cli.ts gateway (hot reload)
npm run tui # tsx src/cli.ts tui
Runtime Diagnostics
hybridclaw gateway status # gateway liveness, PID, build/version diagnostics
6) Working Rules
Code Changes
- Keep changes focused. Prefer targeted fixes over broad refactors unless the task requires wider movement.
- Match the existing TypeScript + ESM patterns in the touched area.
- Update tests and docs when behavior, commands, or repo workflows change.
- Release notes:
CHANGELOG.mdandconsole/src/release-notes.tsare release-owned. Ordinary PRs do not edit them, including at merge time. Put a short user-facing note in the PR description'sRelease notesection, orNonefor internal-only changes. Breaking changes must include migration instructions. Assemble the changelog during §7.7 instead. - Before creating, editing, or optimizing a skill, read
docs/content/extensibility/skills.mdand follow its helper, command-surface, approval, credential, gateway, and testing guidance. - When implementing a new feature, ask before keeping any compatibility shim, migration fallback, legacy alias, or feature flag solely for backward compatibility.
- Do not preserve compatibility for previous internal states of a new, unreleased feature. Remove provisional names, aliases, and workflows instead of carrying them forward.
- Compat code for released behaviour (a shim, alias, fallback, or data
migration) carries a
compat: remove after vX.Ycomment naming the release that deletes it; §7.7 removes expired ones. A data migration runs once: gate it on the schema version or clear its source after importing. Never re-import on every start. - Do not rename or relocate files in
templates/without updatingsrc/workspace.tsand the workspace bootstrap tests. - Do not mix container and gateway changes in one commit unless they are tightly coupled.
- README tone: Describe the current state of the product, not changes relative to a prior version. Avoid "now", "no longer", "deprecated … for now", "recently added". The changelog is the place for transition language.
Diagnostics
- Before diagnosing gateway/runtime issues, inspect the actual checkout, the
running process, runtime state, logs, and
hybridclaw gateway status. - The coding agent's shell Node version is not evidence about the gateway runtime. If the CLI bootstrap rejects the shell's Node version, invoke the installed CLI with the live gateway's Node 22 binary (discovered from the running process) and continue silently. Report a Node runtime mismatch only when the live gateway process itself is using the wrong version.
- Use
hybridclaw gateway statusto compare the PID file, API-reported PID, entrypoint, package root, Node version, Git commit/branch, and source-vs-build freshness before concluding that a gateway is stale. - Never change a linked binary or global CLI target without asking the user
first and receiving explicit approval. This includes
npm linkand creating or replacing executable/package symlinks. For branch or worktree testing, invoke the checkout-local CLI by its explicit path instead. - Do not restart the gateway unless the user explicitly requests or approves a restart. If a restart would help, report the exact reason and command instead.
Coding Style
-
Language: TypeScript (strict mode, ES2022 target, NodeNext modules, ESM).
-
Formatting: Biome is authoritative. Run
npm run formatbefore committing. The Husky pre-commit hook runsnpx biome check --write --staged. -
Single quotes for strings (configured in
biome.json). -
No
anywithout strong justification. No@ts-nocheck. -
File size (owner call, 2026-09-24): aim for ~500 lines; a new file stays under 800. Files over 1,000 lines are closed to feature growth: put new routes, commands, handlers, config sections, and types in a new module and wire it in with a line or two. Bug fixes may touch them but should not grow them; if a fix needs more than a few lines there, extract first. The most-edited ones:
src/gateway/gateway-service.ts,gateway-http-server.ts,gateway.ts,gateway-chat-service.ts,src/config/runtime-config.ts,src/command-registry.ts,container/src/tools.ts,container/src/index.ts,container/src/approval-policy.ts, andconsole/src/api/types.ts. -
Module headers: every new file under
src/,container/src/, andconsole/src/opens with a short block comment (2–6 lines) stating the contract, not the mechanics. Name the invariant the module guarantees, the neighbour it is most often confused with, and what it deliberately does not do. "What it does" is already readable from the exports; write down what a reader cannot infer./** * Pending-approval registry — the store of record for prompts awaiting a human. * * Each prompt is `pending → resolved` exactly once, idempotent and * first-responder-wins, so answering from Slack, Discord, the TUI, or the * console is safe under a race. Channel button handlers are transports of * these records, never a second registry. * * NOT the escalation router (`approval-presentation.ts` decides *where* a * prompt is shown); this module only decides *whether it is still open*. */When you materially change an existing file's contract, add or update its header in the same PR. Backfill headers only for files whose invariants cross module boundaries (approvals, policy, A2A, gateway routing, secrets) — do not open drive-by header-only PRs across the tree.
-
Decision provenance: when a value, list, or threshold exists because someone made a call rather than because it is derivable, record the call in the comment: date, who decided, and what was deliberately deferred. Applies to curated model lists, default tiers, timeouts, and pinned-red defaults. Example:
// 120s (owner call, 2026-07-24): matches the inline prompt window; queued-approval TTL semantics deferred to approvals-v2 phase 2.5. -
Comments: brief inline comments for tricky or non-obvious logic only. Do not add inline comments or type annotations to code you did not change; the module-header rule above is the exception and applies to new or contract-changed files.
-
Imports: let Biome organize imports. Do not mix dynamic
await import()and staticimportfor the same module in production paths. -
Dependencies: root
package.jsonis for gateway/CLI deps. Container-only deps go incontainer/package.json. Never add container deps to root. A dependency that serves one optional feature (a channel or vendor SDK, an ML runtime, a native binary) belongs to that feature's plugin, or is loaded withawait import()on the feature's own path — never statically from the gateway or CLI startup graph. -
When changing npm dependencies, update every generated dependency artifact in the same change: the relevant
package-lock.json, matchingnpm-shrinkwrap.json, and the approved lockfile hashes inscripts/dependency-policy-baseline.json. Usenpm run deps:update-lockfilewhen practical, or copy the updated lockfile to its shrinkwrap pair and update the baseline hash after reviewing the lockfile diff. Runnpm run deps:policybefore handing off. -
npm run deps:policyalso enforces the license gate: packages with GPL/AGPL/SSPL-family licenses fail unless their exact"<name>@<version>": "<license>"pair is approved underlicensesinscripts/dependency-policy-baseline.json(add entries only after license review). Weak-copyleft (LGPL/MPL/EPL/…) and unknown licenses are reported but allowed; dual-licensed(X OR Y)packages count as their most permissive option. See the header ofscripts/check-dependency-policy.mjsfor the full policy. -
When changing npm dependencies, also regenerate
THIRD_PARTY_NOTICES.mdwithnpm run notices(CI fails on a stale file vianpm run notices:check; it needs productionnode_modulesfor every component — see the script header).npm run sbomwrites per-component CycloneDX/SPDX SBOMs tosbom/.
Git Discipline
- Treat existing uncommitted changes as user work unless you created them.
- Run
npm run formatbefore creating commits that will be pushed to GitHub. - Always run
npm run lintbefore creating any commit. - Sign off every commit (
git commit -s). CI enforces the Developer Certificate of Origin on pull requests; see CONTRIBUTING.md "Licensing And Sign-Off (DCO)". - Conventional Commits preferred:
feat:,fix:,test:,refactor:,chore:,docs:. - Group related changes; avoid bundling unrelated refactors.
- Never commit real API keys, tokens, credentials, or personal data. Use
neutral placeholders in tests:
"test-key","example.com","user_a".
7) Change Playbooks
7.1 Adding a Skill
- Create
skills/<name>/SKILL.mdwith required frontmatter:--- name: my-skill description: One-line description metadata: hybridclaw: category: development user-invocable: true # optional, enables /<name> invocation --- - Add markdown instructions and working rules in the body.
- If the skill needs supporting scripts, place them alongside
SKILL.md. - Bundled script paths are mirrored into
/workspace/skills/<name>at runtime. - Test:
hybridclaw skill listshould show the new skill.
Skill resolution order (first match wins):
config.skills.extraDirs[]- Bundled:
skills/<name> $CODEX_HOME/skills~/.codex/skills,~/.claude/skills,~/.agents/skills- Project/workspace:
./.agents/skills,./skills
7.2 Adding a Provider
- If the provider speaks the OpenAI-compatible API, add it to the generic
tables (
OPENAI_COMPAT_PROVIDER_IDSinsrc/providers/provider-ids.ts,OPENAI_COMPAT_REMOTE_PROVIDERSinsrc/providers/openai-compat-remote.ts) instead of writing a module. Otherwise createsrc/providers/<name>.tsimplementing the provider interface and register it in the provider factory. - Add config in
src/config/only for credentials or endpoints the tables can't express. A provider id is still hand-copied into about ten files; do not add another copy, and fold the ones you touch into the tables (§3.3). - Add tests for factory wiring, error paths, and config parsing.
- Update
docs/if the provider is user-facing.
7.3 Adding an MCP Server
- Add the server config to
~/.hybridclaw/config.jsonundermcpServers:{ "mcpServers": { "<server-name>": { "command": "...", "args": ["..."], "transport": "stdio" } } } - Tools are auto-discovered at startup and merged into the tool namespace.
- Remote
http/sseservers can set"auth": "oauth"; the gateway runs the OAuth 2.1 flow (src/mcp/mcp-oauth.ts), stores credentials in the encrypted runtime secret store (~/.hybridclaw/credentials.json, oneMCP_OAUTH_*entry per server), and injects a freshAuthorizationheader per turn. Connect via/mcp login <name>, the TUI/mcp addwizard, or the console MCP page. - Test with
hybridclawrunning in dev mode.
7.4 Modifying Approval Policy
- Edit
.hybridclaw/policy.yaml. - Approval tiers: green (silent) → yellow (narrated) → red (explicit approval).
pinned_redpatterns are never auto-promoted.- Test approval flows with integration tests that exercise the boundary.
7.5 Modifying Templates
- Edit the file in
templates/. - Always update
src/workspace.tsif you add, remove, or rename a template file. - Run workspace bootstrap tests to verify.
- Remember: templates are seeded into agent workspaces at runtime — changes only apply to new sessions or after workspace reset.
7.6 Adding an Optional Feature as a Plugin
Use this for anything §3.4 keeps out of core. Reference:
docs/content/extensibility/plugins.md; working examples live in plugins/.
- Create
plugins/<name>/withhybridclaw.plugin.yaml(id, name, version, kind,configSchema,requires,credentials) and an entrypoint that exportsregister(api). - Register only the surfaces the feature uses:
api.registerTool,registerCommand,registerService,registerMiddleware,registerPromptHook,registerMemoryLayer,registerInboundWebhook,registerChannelTransport, and lifecycle hooks throughapi.on(...). - Read secrets with
api.getCredential(...)and declare them in the manifest. Keep the plugin's npm dependencies in its ownpackage.json. - If a needed hook is missing, add the smallest generic one to
src/plugins/in the same change, with this plugin as its caller (§3.2). - Test in
tests/<name>-plugin.test.ts; try it locally withhybridclaw plugin install ./plugins/<name>. - Add the plugin to the npm package
filesonly if most installs want it; otherwise document its install command.
7.7 Bump Release
When the user says "bump release":
- Bump the requested semantic version (if unspecified, default to patch).
- Update
package.jsonto the new version, then runnpm run version:syncto propagate it through product package metadata:package.jsonpackage-lock.jsonandnpm-shrinkwrap.json(rootversion,packages[""], and product workspace entries)console/package.jsondesktop/package.jsoncontainer/package.jsoncontainer/package-lock.jsonandcontainer/npm-shrinkwrap.json(rootversionandpackages[""])- any user-facing version text (for example
src/tui.tsbanner)
- Collect release-note context from the previous published release tag on
the target branch through the intended release commit. Review merged PRs
and their
Release notesections, and inspect the commit range for direct commits, missing notes, reverts, and follow-up fixes. Use the actual changes to fill gaps; do not rely on PR notes or merge dates alone. - Review the generated lockfile diff. Even a version-only release changes the
lockfile bytes, so update the matching SHA-256 entries in
scripts/dependency-policy-baseline.jsonafter confirming that no dependency versions or lifecycle scripts changed. Runnpm run deps:policybefore the release commit; the pre-commit override does not approve stale baseline hashes in CI. - Write
CHANGELOG.mdonce for the release: curate the collected changes into the new version heading, group related changes, omit internal-only noise, and include migration instructions for breaking changes. Incorporate any existingUnreleasednotes without duplication and leaveUnreleasedempty. Preserve previously released sections. Always updateconsole/src/release-notes.tsin the same release commit with the new version and up to four ultra-short highlights derived from that changelog for the What's New dialog. Do not carry the previous release's version or highlights forward. For a patch release whose changes are only technical or internal, use the single highlightBug fixes. - On a minor release, delete compat code whose
compat: remove after vX.Ymarker is at or below the new version, and list the removals in the changelog. - Update
README.md"latest tag" link/text if present. - Commit with
chore: release vX.Y.Z. - Create an annotated git tag
vX.Y.Z. - Push the commit and tag.
- Create or publish a GitHub Release entry for the tag using the same curated
format as
v0.9.2:
- title:
HybridClaw vX.Y.Z Release Date:line with the calendar date- short blockquote summary paragraph
Highlights,Changed, andFixedsections with polished bulletsContributorssection (CoreandAll Contributors)- trailing
Full Changelogcompare link - do not paste the raw
CHANGELOG.mdversion heading/body verbatim
8) Testing Expectations
What to Run
| Change scope | Required checks |
|---|---|
| Docs only | Verify links, commands, examples |
src/ changes |
npm run typecheck, npm run lint, targeted Vitest suites |
container/ changes |
npm --prefix container run lint, npm run build, IPC boundary tests |
skills/ changes |
hybridclaw skill list, targeted skill tests |
| Release/packaging | Both release:check scripts, verify versioned docs |
| Security surfaces | Include boundary and failure-mode tests |
Conventions
- Test files:
tests/*.test.ts,*.integration.test.ts,*.e2e.test.ts,*.live.test.ts. - Live tests require credentials. Skip them unless your change needs them, and state that explicitly in your handoff.
- If you skip a relevant check, state what you skipped and why.
- Never hardcode real credentials in tests. Use env vars or test fixtures.
- Put new tests in a focused file per module or route group; do not grow a
test file past 2,000 lines (
tests/gateway-http-server.test.tsis past 18,000 — add to it only by splitting it). - Reuse
tests/test-utils.ts(useTempDir,useCleanMocks) andtests/helpers/. Set env vars withvi.stubEnvplususeCleanMocks({ unstubAllEnvs: true })instead of hand-restoringprocess.env. - Assert behaviour and structure, not copied prose: do not paste SKILL.md
text, help text, or prompt sentences into assertions. Prefer
it.eachtables over one hand-written test per variant.
9) Anti-Patterns (Do Not)
- Do not rename or relocate
templates/files without updatingsrc/workspace.ts. - Do not add container-only deps to root
package.json. - Do not grow files over 1,000 lines with features, hand-copy a list or type that already exists, add a second implementation of a mechanism, or put an optional feature in core (§3, §6).
- Do not use
@ts-nocheckor disable lint rules without strong justification. - Do not silently weaken security policy, approval tiers, or mount allowlists.
- Do not log secrets, tokens, or sensitive payloads — even at debug level.
- Do not modify unrelated modules "while here".
- Do not include personal identity, real phone numbers, or live config values in tests, examples, docs, or commits.
- Do not edit
.dockerignorewithout verifying the resulting Docker image still contains all runtime-required files (especiallydocs/content/). Build the image and confirm the affected paths exist inside it before marking the change complete. - Do not edit
node_modules/or vendored files. - Do not break prompt caching: do not alter past context, change toolsets, or rebuild system prompts mid-conversation.
- Do not return stale or mocked data for security/audit paths.
10) Multi-Agent Safety
When multiple agents may be working on this repo concurrently:
- Do not create, apply, or drop
git stashentries unless explicitly requested (includinggit pull --rebase --autostash). - Do not switch branches or check out a different branch unless explicitly requested.
- Do not create, remove, or modify
git worktreecheckouts unless explicitly requested. - When the user says "commit", scope to your changes only. When the user says "commit all", commit everything in grouped chunks.
- When the user says "push", you may
git pull --rebaseto integrate latest changes. Never discard other agents' work. - When you see unrecognized files, keep going. Focus on your changes and commit only those.
- Focus reports on your edits. End with a brief "other files present" note only if relevant.
- Lint/format churn: if diffs are formatting-only, auto-resolve without asking. Only ask when changes are semantic (logic/data/behavior).
11) Documentation Hierarchy
| Document | Audience | Purpose |
|---|---|---|
README.md |
End users | Product overview, setup |
AGENTS.md (this file) |
Coding agents | Canonical repo instructions |
CLAUDE.md |
Claude Code | Shim that imports AGENTS.md |
CONTRIBUTING.md |
Human contributors | Quickstart, PR workflow |
SECURITY.md |
Security reviewers | Runtime security controls |
TRUST_MODEL.md |
Operators | Trust acceptance policy |
docs/content/ |
Maintainers | User docs, developer guide, reference |
templates/*.md |
Product runtime | Agent workspace bootstrap |
12) Handoff Template
When handing off work (agent → agent or agent → maintainer), include:
- What changed — files touched and why.
- What did not change — scope boundaries you respected.
- Size — net production lines (without tests, docs, lockfiles), lines added to files over 1,000 lines, and copies of a fact removed or added. A feature that grows core by more than ~500 lines says why it isn't a plugin.
- Validation — which checks you ran and their results.
- Skipped checks — what you did not run and why.
- Remaining risks / unknowns — open questions or edge cases.
- Next recommended action — what to do next.
13) Vibe Coding Guardrails
When working in fast iterative mode:
- Keep each iteration reversible (small commits, clear rollback path).
- Search before you write: find the function, type, list, route, or helper you are about to create, and reuse or extend it instead (§3.3).
- Prefer deterministic behavior over clever shortcuts.
- Do not "ship and hope" on security-sensitive paths.
- If uncertain about an internal API, search
src/for existing usage patterns before guessing. - If uncertain about architecture, read the type definitions in
src/types.tsand the workspace bootstrap insrc/workspace.tsbefore implementing.
