AGENTS.md · git:20260912.c730120 · 2026-09-12 · sha256 5268bb7a1dae76c3

AGENTS.md git:20260912.c730120A

Immutable. This exact content is served forever at /api/v1/blob/5268bb7a1dae76c3.

# AGENTS.md — clawagents (Python)

Operational guide for AI/automation agents working *on* the `clawagents` Python
codebase. This file is intentionally short. It captures the conventions that
are easy to violate accidentally and hard to fix retroactively.

## 1. Prompt-cache policy

Every long-running agent session relies on the LLM provider's **prompt
prefix cache**. A handful of slash-commands and tools mutate state that lives
in the system prompt (skills, permission mode, persona, model routing, …).
If those mutations apply *immediately*, the cached prefix is invalidated and
the next turn pays the full re-prefill cost. For multi-turn tool runs this
typically dominates latency and cost.

The policy mirrors the one we adopted from Hermes:

- **`cache_impact = "none"`** — read-only commands. Always safe mid-run.
  Examples: `/help`, `/status`, `/version`, `/tools`, `/models`, `/trace`,
  `/profile`, `/redact`, `/history`.
- **`cache_impact = "deferred"`** — *default* for any command that mutates
  system-prompt state. The change is staged for the **next session** so the
  current prefix cache survives. Pass `--now` to opt into immediate
  invalidation. Examples: `/plan`, `/accept-edits`, `/default`, `/bypass`,
  and any future `/skills install`, `/model`, `/personality` commands.
- **`cache_impact = "immediate"`** — commands that *cannot* be deferred
  because they rewrite history or start a fresh context. Examples: `/new`,
  `/clear`, `/compress`, `/undo`.

Implementation lives in `src/clawagents/commands.py`:

- `CommandDef.cache_impact: CacheImpact` (declared per command).
- `ResolvedCommand.apply_now: bool` (computed by `resolve_command()`,
  combining `cache_impact` with the `--now` flag).
- The `--now` token is recognised in any position in the argument list and
  is stripped from `ResolvedCommand.args` so consumers never see it.
- The bare word `now` is **not** a flag, so steer/queue prompts like
  `/q now do the next thing` round-trip cleanly.

When you add a new slash-command or skill that touches system-prompt state,
default to `"deferred"`. Use `"immediate"` only when correctness requires
a cache flush (history rewrites, persona swaps that must take effect on the
very next turn).

## 2. User-facing paths

Tool descriptions and user-visible messages must render configuration paths
through `display_clawagents_home()` / `display_clawagents_workspace_dir()`
instead of hardcoding `~/.clawagents/...`. This keeps the message correct
when the user is on a non-default profile (`CLAWAGENTS_PROFILE`) or has
relocated home (`CLAWAGENTS_HOME`).

```python
from clawagents.paths import display_clawagents_home

description = f"Read a memory file from {display_clawagents_home()}/memories/"
```

## 3. Subagent boundaries (do not violate)

- Subagent depth is capped at **2**. The `task` tool refuses to spawn a
  subagent from inside a subagent. This prevents recursive blowup and
  protects the iteration / token budget.
- Subagents run with `skip_memory=True`. They do **not** load the parent's
  memory directory, lessons, or skill state. Pass anything they need
  explicitly via the prompt or a tool argument.
- Agent loops respect a per-agent `IterationBudget` (default 50). The
  delegating agent must reserve at least one iteration for itself.

## 4. Parallel tool execution

The agent loop will run independent read-only tools in parallel when their
**path scopes do not overlap**. Two `read_file` calls on different paths
go in parallel; a `read_file` and `write_file` on overlapping paths do not.
If you add a new tool, declare its path scope with the standard helper so
the scheduler can reason about it; otherwise it will be treated as
"unknown scope" and run serially.

## 5. Tests

Always run the hermetic test entry point before shipping:

```bash
scripts/run_tests.sh
```

This pins xdist worker count, scrubs `CLAWAGENTS_*` env vars, and runs both
the unit suite and the typed parity checks against `clawagents/` (TS).
Don't run `pytest` directly when validating a release — the worker count
and env scrubbing matter.

## 6. Plugin hooks

Plugins can implement:

- `pre_tool_call(name, args)` — return `{"veto": True, "reason": "..."}` to
  block a call. Plain raises are also caught and surfaced as veto reasons.
- `post_tool_call(name, args, result)` — observation only.
- `transform_tool_result(name, args, result)` — *return* a replacement
  result (or `None` to leave it unchanged). Use this for redaction,
  summarisation, or schema migration.

`pre_tool_call` runs first, then the tool itself, then `transform_tool_result`,
then `post_tool_call`. Hooks must be deterministic-ish; if a hook is slow,
the entire agent loop is slow.

## 7. Context transformer fallback

Any output reducer, artifact projection, or other context transformer must
preserve the original observation when transformation or evidence validation
fails. Archive the exact source before replacing it with a recoverable view;
never silently replace failure evidence with a clean-looking summary. Diagnostic
receipts are untrusted evidence, not instructions or pass/fail adjudication.