This repository is a typed agent harness (Agent = Model + Harness), not a chatbot wrapper.
Prefer clear architecture, strict typing, and tests over framework magic.
entrypoints/ → features/ + orchestration/ + tools/
↓
harness/ (loop, registry, compaction, guards)
↓
domain/ (models, ports, state — no I/O)
↑
adapters/ (LLM, SQLite, FS, HTTP, WS — implement ports)
| Package | Own |
|---|---|
domain/ |
Pure types, ports, ConversationState |
harness/ |
ReAct loop, ToolRegistry, compaction, validation |
features/ |
Product use-cases (brief, self_harness, evolve, harness_bank) |
adapters/ |
External systems |
orchestration/ |
Multi-agent runtime |
tools/ |
Agent-facing tools over ports |
support/ |
Shared helpers (console I/O) |
entrypoints/ |
CLI composition root |
Do not import adapters or entrypoints from domain.
Do not put I/O in domain or business policy in adapters.
- Python 3.12+,
mypywithdisallow_untyped_defsonsrc/ - Prefer explicit types on public functions; use
Protocolports for DI - Keep functions small; avoid deep nesting
- Failures of external deps are expected — log and return structured errors
- Never invent tool results in prompts; the harness observes tools
- Model proposes, harness executes — tools run only via
ToolRegistry.execute - Validate args before tool I/O (
validate_tool_arguments) - Bound loops with
max_tool_rounds - Context packing — full history stays in
ConversationState; wire view may be compacted (SummarizingCompactor). Prefer summarize over drop. - SQLite = durable session/memory retention across process restarts (not the same as provider “retained reasoning”)
- Self-Harness / HarnessBank patches are gated; evolver must not edit kernel (K) (
PathPolicy,MergePolicy, STOP, screening) run_pythonis deny-listed subprocess — not a multi-tenant sandbox- Evolve publishes via PR + HITL; Phase 2 auto-merge only under
MergePolicy+ CI + no STOP file
| Immutable kernel (K) | Mutable surface (X) |
|---|---|
| PathPolicy / MergePolicy / STOP | System prompts, tool descriptions |
| Eval / screening / Gene Bank bookkeeping | YAML configs, max_tool_rounds |
| Approval / CI merge rules | Recovery snippets, knowledge injects |
Mirror source layout under tests/:
tests/domain/ tests/harness/ tests/features/ tests/adapters/
tests/orchestration/ tests/tools/ tests/support/
- No live network in CI — use
ScriptedLLMand fakes - Mutation testing (
mutmut) targets pure high-value modules (tool_args,url_safety,compaction,diff_apply,path_policy,merge_policy, registry validation, workspace jail)
uv run pytest
uv run mypy src
uv run ruff check src tests
uv run mutmut run- Agent behavior lives in
config/**/*.yaml - Secrets only in
.env(OPENROUTER_API_KEY) — never commit - Optional compaction:
compaction:
enabled: true
max_context_chars: 48000
keep_recent_messages: 12
max_summary_chars: 4000- Match existing style; no drive-by refactors
- Add/adjust tests with behavior changes
- Update
README.md/DECISIONS.mdwhen architecture trade-offs change - Keep CLI thin; put logic in harness/features
uv sync --all-extras
uv run ai-agent -c config/agent_config.yaml
uv run ai-agent brief "topic"
uv run ai-agent evolve "add typed logging helpers"
# optional HITL gate: add --approve
uv run ai-agent evolve-goal add "tighten one evolve docstring"
uv run ai-agent evolve-worker --force-due
# continuous: uv run ai-agent evolve-worker --loop --hours 6
# halt: touch .ai_agent/evolve/STOP
uv run ai-agent harness-bank list
uv run ai-agent --server --host 0.0.0.0
docker compose up --build # WebSocket on :8765