nanobot/.agent/gotchas.md
chengyongru 6eef3d0f15 docs: add CLAUDE.md and .agent/ guides for AI contributors
Add CLAUDE.md at the repository root to orient future Claude Code
instances, and split detailed constraints into .agent/:

- .agent/design.md    — architectural constraints (core small, duplication
  over abstraction, minimal changes, explicit over magical)
- .agent/security.md  — workspace/SSRF/shell sandbox boundaries
- .agent/gotchas.md   — config ${VAR}, Windows compat, templates,
  heartbeat virtual tool call, atomic writes, ruff format warning,
  skills extension point

Also updates .gitignore to not ignore .agent/.
2026-05-09 14:00:32 +08:00

2.2 KiB

Common Gotchas

Do not use ruff format

CONTRIBUTING.md mentions ruff format, but do not run it — it destroys git blame history. Only ruff check should be used.

Config ${VAR} References

config/loader.py resolves ${VAR} patterns in config.json at load time. This is not a shell-like default-value syntax. If the environment variable is missing, load_config raises ValueError and the agent falls back to default configuration.

Example valid usage:

{ "providers": { "openrouter": { "apiKey": "${OPENROUTER_KEY}" } } }

Windows Compatibility

nanobot explicitly supports Windows. Key differences to keep in mind:

  • ExecTool uses cmd /c on Windows instead of sh -c (shell.py).
  • cli/commands.py forces sys.stdout/stderr to UTF-8 on startup to handle emoji and multilingual input.
  • MCP stdio server commands are normalized for Windows path separators (mcp.py).
  • Always use pathlib.Path for path manipulation; do not assume / separators.

Prompt Templates

Agent system prompts and scenario-specific instructions live in nanobot/templates/ as Jinja2 markdown files (identity.md, platform_policy.md, HEARTBEAT.md, SOUL.md, etc.). Changing these files alters agent behavior as directly as changing Python code. They are loaded by utils/prompt_templates.py.

Heartbeat Virtual Tool Call

The heartbeat service (heartbeat/service.py) does not parse free-text LLM output. Instead, it injects a virtual heartbeat tool with action: skip | run into the conversation. Phase 1 is a structured decision; Phase 2 executes only on run. When adding new periodic background checks, follow this virtual-tool-call pattern rather than string matching.

Skills as Extension Point

Built-in skills live in nanobot/skills/ (markdown + YAML frontmatter format). Agent capabilities that are "know-how" rather than code should be added as skills, not hardcoded into the agent loop. External skills can be published to and installed from ClawHub.

Atomic Session Writes

agent/memory.py writes history.jsonl atomically (temp file + fsync + rename + directory fsync). This guarantees durability across crashes. Do not replace this with a plain open(..., "w") write.