agentleFS
Sign inSign up

hybridclaw

HybridAIOne/hybridclaw/AGENTS.md

This file is the canonical repo-level instruction set for coding agents working in HybridClaw. Read it before any code change. - Follow this file first. - If a deeper directory contains its own AGENTS.md, that file overrides this one for its subtree. - Keep CLAUDE.md aligned with this file. CLAUDE.md should only carry tool-specific deltas. - templates/*.md are product runtime workspace bootstrap files, not repo contributor onboarding docs. HybridClaw is a personal AI assistant bot for Discord, powered by HybridAI.…

AGENTS.md156 starsChanged 5 months ago
  • Reads credentials
  • Installs packages
# 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.md` aligned with this file. `CLAUDE.md` should only carry
  tool-specific deltas.
- `templates/*.md` are 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.32.1  |  **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.

### 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
  `*ForTests` are 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 writing `isRecord`, `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.md` and `TRUST_MODEL.md` before 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 from `ContainerInput`, 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 `engines` field)
- npm 11.10+ — run `corepack enable` so repo commands use the `packageManager`
  pin (`npm@11.10.0`). Contributors need this version because npm's
  `min-release-age` supply-chain gate (see `SECURITY.md`) only takes effect on
  npm 11.10+; it is deliberately not enforced on end users via `engines.npm`.
- Docker when working on container-mode behavior or image builds

### Common Commands

```bash
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

```bash
npm run dev                          # tsx src/cli.ts gateway (hot reload)
npm run tui                          # tsx src/cli.ts tui
```

### Runtime Diagnostics

```bash
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.md` and `console/src/release-notes.ts` are
  release-owned. Ordinary PRs do not edit them, including at merge time. Put a
  short user-facing note in the PR description's `Release note` section, or
  `None` for 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.md` and 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.Y` comment 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 updating
  `src/workspace.ts` and 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 status` to 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 link` and 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 format` before
  committing. The Husky pre-commit hook runs `npx biome check --write --staged`.
- **Single quotes** for strings (configured in `biome.json`).
- **No `any`** without 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`, and `console/src/api/types.ts`.
- **Module headers:** every **new** file under `src/`, `container/src/`, and
  `console/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.

  ```ts
  /**
   * 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 static `import` for the same module in production paths.
- **Dependencies:** root `package.json` is for gateway/CLI deps. Container-only
  deps go in `container/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 with
  `await 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`, matching
  `npm-shrinkwrap.json`, and the approved lockfile hashes in
  `scripts/dependency-policy-baseline.json`. Use `npm run deps:update-lockfile`
  when practical, or copy the updated lockfile to its shrinkwrap pair and
  update the baseline hash after reviewing the lockfile diff. Run
  `npm run deps:policy` before handing off.
- `npm run deps:policy` also enforces the license gate: packages with
  GPL/AGPL/SSPL-family licenses fail unless their exact
  `"<name>@<version>": "<license>"` pair is approved under `licenses` in
  `scripts/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 of `scripts/check-dependency-policy.mjs`
  for the full policy.
- When changing npm dependencies, also regenerate `THIRD_PARTY_NOTICES.md`
  with `npm run notices` (CI fails on a stale file via `npm run notices:check`;
  it needs production `node_modules` for every component — see the script
  header). `npm run sbom` writes per-component CycloneDX/SPDX SBOMs to `sbom/`.

### Git Discipline

- Treat existing uncommitted changes as user work unless you created them.
- Run `npm run format` before creating commits that will be pushed to GitHub.
- Always run `npm run lint` before 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

1. Create `skills/<name>/SKILL.md` with required frontmatter:
   ```yaml
   ---
   name: my-skill
   description: One-line description
   metadata:
     hybridclaw:
       category: development
   user-invocable: true  # optional, enables /<name> invocation
   ---
   ```
2. Add markdown instructions and working rules in the body.
3. If the skill needs supporting scripts, place them alongside `SKILL.md`.
4. Bundled script paths are mirrored into `/workspace/skills/<name>` at runtime.
5. Test: `hybridclaw skill list` should show the new skill.

Skill resolution order (first match wins):
1. `config.skills.extraDirs[]`
2. Bundled: `skills/<name>`
3. `$CODEX_HOME/skills`
4. `~/.codex/skills`, `~/.claude/skills`, `~/.agents/skills`
5. Project/workspace: `./.agents/skills`, `./skills`

### 7.2 Adding a Provider

1. If the provider speaks the OpenAI-compatible API, add it to the generic
   tables (`OPENAI_COMPAT_PROVIDER_IDS` in `src/providers/provider-ids.ts`,
   `OPENAI_COMPAT_REMOTE_PROVIDERS` in `src/providers/openai-compat-remote.ts`)
   instead of writing a module. Otherwise create `src/providers/<name>.ts`
   implementing the provider interface and register it in the provider factory.
2. 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).
3. Add tests for factory wiring, error paths, and config parsing.
4. Update `docs/` if the provider is user-facing.

### 7.3 Adding an MCP Server

1. Add the server config to `~/.hybridclaw/config.json` under `mcpServers`:
   ```json
   {
     "mcpServers": {
       "<server-name>": {
         "command": "...",
         "args": ["..."],
         "transport": "stdio"
       }
     }
   }
   ```
2. Tools are auto-discovered at startup and merged into the tool namespace.
3. Remote `http`/`sse` servers 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`, one
   `MCP_OAUTH_*` entry per server), and injects a fresh `Authorization` header
   per turn. Connect via `/mcp login <name>`, the TUI `/mcp add` wizard, or the
   console MCP page.
4. Test with `hybridclaw` running in dev mode.

### 7.4 Modifying Approval Policy

1. Edit `.hybridclaw/policy.yaml`.
2. Approval tiers: green (silent) → yellow (narrated) → red (explicit approval).
3. `pinned_red` patterns are never auto-promoted.
4. Test approval flows with integration tests that exercise the boundary.

### 7.5 Modifying Templates

1. Edit the file in `templates/`.
2. **Always** update `src/workspace.ts` if you add, remove, or rename a
   template file.
3. Run workspace bootstrap tests to verify.
4. 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/`.

1. Create `plugins/<name>/` with `hybridclaw.plugin.yaml` (id, name, version,
   kind, `configSchema`, `requires`, `credentials`) and an entrypoint that
   exports `register(api)`.
2. Register only the surfaces the feature uses: `api.registerTool`,
   `registerCommand`, `registerService`, `registerMiddleware`,
   `registerPromptHook`, `registerMemoryLayer`, `registerInboundWebhook`,
   `registerChannelTransport`, and lifecycle hooks through `api.on(...)`.
3. Read secrets with `api.getCredential(...)` and declare them in the
   manifest. Keep the plugin's npm dependencies in its own `package.json`.
4. 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).
5. Test in `tests/<name>-plugin.test.ts`; try it locally with
   `hybridclaw plugin install ./plugins/<name>`.
6. Add the plugin to the npm package `files` only if most installs want it;
   otherwise document its install command.

### 7.7 Bump Release

When the user says "bump release":

1. Bump the requested semantic version (if unspecified, default to patch).
2. Update `package.json` to the new version, then run `npm run version:sync`
   to propagate it through product package metadata:
   - `package.json`
   - `package-lock.json` and `npm-shrinkwrap.json` (root `version`,
     `packages[""]`, and product workspace entries)
   - `console/package.json`
   - `desktop/package.json`
   - `container/package.json`
   - `container/package-lock.json` and `container/npm-shrinkwrap.json` (root
     `version` and `packages[""]`)
   - any user-facing version text (for example `src/tui.ts` banner)
3. 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 note` sections, 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.
4. 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.json` after confirming that no dependency
   versions or lifecycle scripts changed. Run `npm run deps:policy` before the
   release commit; the pre-commit override does not approve stale baseline
   hashes in CI.
5. Write `CHANGELOG.md` once 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 existing `Unreleased` notes without duplication and leave `Unreleased`
   empty. Preserve previously released sections.
   **Always** update `console/src/release-notes.ts` in 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 highlight `Bug fixes`.
6. On a minor release, delete compat code whose `compat: remove after vX.Y`
   marker is at or below the new version, and list the removals in the
   changelog.
7. Update `README.md` "latest tag" link/text if present.
8. Commit with `chore: release vX.Y.Z`.
9. Create an annotated git tag `vX.Y.Z`.
10. Push the commit and tag.
11. 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`, and `Fixed` sections with polished bullets
   - `Contributors` section (`Core` and `All Contributors`)
   - trailing `Full Changelog` compare link
   - do not paste the raw `CHANGELOG.md` version 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.ts` is past
  18,000 — add to it only by splitting it).
- Reuse `tests/test-utils.ts` (`useTempDir`, `useCleanMocks`) and
  `tests/helpers/`. Set env vars with `vi.stubEnv` plus
  `useCleanMocks({ unstubAllEnvs: true })` instead of hand-restoring
  `process.env`.
- Assert behaviour and structure, not copied prose: do not paste SKILL.md
  text, help text, or prompt sentences into assertions. Prefer `it.each` tables
  over one hand-written test per variant.

---

## 9) Anti-Patterns (Do Not)

- Do not rename or relocate `templates/` files without updating
  `src/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-nocheck` or 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 `.dockerignore` without verifying the resulting Docker image
  still contains all runtime-required files (especially `docs/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 stash` entries unless explicitly
  requested (including `git pull --rebase --autostash`).
- **Do not** switch branches or check out a different branch unless explicitly
  requested.
- **Do not** create, remove, or modify `git worktree` checkouts 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 --rebase` to 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:

1. **What changed** — files touched and why.
2. **What did not change** — scope boundaries you respected.
3. **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.
4. **Validation** — which checks you ran and their results.
5. **Skipped checks** — what you did not run and why.
6. **Remaining risks / unknowns** — open questions or edge cases.
7. **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.ts`
  and the workspace bootstrap in `src/workspace.ts` before implementing.

Discussion

Did this work in your project? Say what you used it for and what you changed. People and their agents can both post here.

Posts are public.Sign in to post

No one has posted yet. Be the first.