Agent System
The Society is not one agent. It is specialists who know when to call each other.
Overview
The Agenthood uses a multi-agent architecture where a central Orchestrator
coordinates all specialized members. No member tries to do everything.
Each receives only the tools and context relevant to their specialty.
This design avoids the failure mode of monolithic agents: an agent given every
tool and every responsibility becomes unpredictable, slow, and hard to debug.
The Orchestrator
The Orchestrator is the Society's dispatch system. It:
- Receives incoming requests and classifies them by type
- Routes work to the appropriate member(s)
- Manages the publish/subscribe event bus between members
- Tracks the state of multi-step tasks across member handoffs
- Never does the work itself — it only coordinates
Key principle: Every member communicates through the Orchestrator,
never directly to each other. This decouples the system and makes behavior
predictable and auditable.
User Request
↓
Orchestrator
↙ ↓ ↓ ↘
Scribe Reviewer Tester Doorman ...
The Members as Subagents
Each member is a subagent with:
| Property | Description |
|---|---|
| Role | A single, well-defined specialty |
| Tool scope | Only the tools needed for their role |
| Permission profile | Restricted / Standard / Trusted |
| Handoff protocol | How they signal completion to the Orchestrator |
| Escalation path | What to do when they can't proceed alone |
Member → Tool Scope
Full tool-scope definitions live in built-in-tools.md and are
implemented in src/members/MemberRegistry.ts.
| Member | Permission Profile | Key Tools |
|---|---|---|
| The Scribe | standard | file.write, code.write, code.refactor |
| The Architect | standard | file.write, code.write, code.refactor |
| The Builder | standard | file.write, code.write, code.refactor |
| The Reviewer | restricted | file.read, file.search, code.explain |
| The Tester | standard | file.write, code.write, code.refactor |
| The Debugger | standard | file.write, code.write, code.refactor |
| The Auditor | restricted | file.read, file.search, code.explain |
| The Herald | standard | file.write, code.write, code.refactor |
| The Librarian | standard | file.write, code.write, code.refactor |
| The Doorman | restricted | file.read, file.search, code.explain |
| The Oracle | restricted | file.read, file.search, code.explain |
| The Envoy | restricted | file.read, file.search, code.explain |
| The Sentinel | restricted | file.read, file.search, code.explain |
| The Warden | restricted | file.read, file.search, code.explain |
| The Strategist | restricted | file.read, file.search, code.explain |
| The Steward | restricted | file.read, file.search, code.explain |
| The Operator | restricted | file.read, file.search, code.explain |
| The Mailman | standard | file.write, code.write, code.refactor |
| The Inspector | standard | file.write, code.write, code.refactor |
Core Agents (Runtime)
The standalone core-agent classes carry narrower tool sets than the member
profile grants below — a deliberate fail-closed choice from the agent lifecycle
hardening wave. They only receive what their executor path needs: Developer,
Architect, QA, and Reviewer are wired in ApplicationContext.setupAgents,
Oracle in setupOracle, and Strategist/Operator are not wired into the
ApplicationContext at all — they are instantiated by tests or callers directly.
| Agent | Tools |
|---|---|
| DeveloperAgent | ReadFileSkill, WriteFileSkill, WriteCodeSkill, RefactorSkill, SearchCodebaseSkill, ExplainCodeSkill, SubagentTaskSkill (delegation, opt-in) |
| ArchitectAgent | ReadFileSkill, WriteFileSkill, WriteCodeSkill |
| QAAgent | ReadFileSkill, WriteFileSkill, WriteCodeSkill |
| ReviewerAgent | ReadFileSkill (read-only) |
| OracleAgent | ReadFileSkill, SearchCodebaseSkill (read-only) |
| StrategistAgent / OperatorAgent | none — pure reasoning, output rendered against a fixed format |
Member execution (via MemberAgent) remains governed by MemberRegistry profile
grants. delegate_task for members is opt-in per spec via canDelegate;
DeveloperAgent's SubagentTaskSkill is a separate core-agent delegation path,
not governed by member profile grants — it is also opt-in viaDeveloperAgentOptions.canDelegate (enabled in ApplicationContext.setupAgents).
Delegation is bounded at two levels. First, the role allowlist (DELEGATION_ALLOWED_ROLES)
admits only read-only analysis roles — never write-capable agents. Second, tool
isolation: every agent and each member run constructs its own ToolRegistry +ReActLoop (ApplicationContext.setupAgents, runMemberTask), so a delegated
subagent's tool schemas are always its own load-out and never the caller's write
tools. The delegated task itself travels inside an untrusted <delegated_task>
boundary, and the only surface genuinely shared is the ExecutionContext
(memory, tracer, artifacts). A compromise of the caller therefore cannot reach
writes through delegation that the caller could not already reach with its own
tools.
The Reason → Act → Observe Loop
Each member operates on a three-step cycle:
REASON → Read context, form a plan, identify tools needed
↓
ACT → Execute tools, make changes, call external services
↓
OBSERVE → Read output, assess result, decide next step
↓
(repeat until task complete or escalation needed)
The loop continues until:
- The task is complete (success)
- A safety limit is reached (see built-in-tools.md)
- Human approval is required (destructive action gate)
- The member escalates to the Orchestrator for handoff
Self-Healing
When a member encounters an error during execution:
- Read the full error output — not just the first line
- Classify: is this recoverable or not?
- If recoverable: apply correction and retry
- If not recoverable: escalate with a clear description of what failed and why
- Never silently swallow errors or add empty catch blocks to proceed
Multi-Member Tasks
Some tasks span multiple members. The Orchestrator manages the handoff:
Example: "Review and ship this PR"
Orchestrator
→ The Doorman (validate commit messages on the branch)
→ The Reviewer (five-axis code review)
→ The Tester (verify test coverage)
→ The Auditor (security pass)
→ The Scribe (generate PR description)
→ The Herald (prepare release notes if merging to main)
Each member signals done → Orchestrator routes to next → human approves final output.
Persistent Memory
The Society remembers across sessions:
- Project scope — conventions, rules, recurring patterns in this codebase
- User scope — preferences, feedback, workflow patterns
- Session scope — current task state, in-progress work
Memory is backed by a tiered store: LanceDB for vector storage (.agenthood/memory/), ResidualMemory (.agenthood/residual.json), KnowledgeGraphStore (.agenthood/society-graph.json), and ShortTermMemory (in-memory ring buffer). Multiple namespaces — shortTerm, longTerm, episodic, project — keep concerns separated.
On top of the tiers sit the decision and provenance records. Every member run
writes one entry to the decision log (.agenthood/decisions/) and one to the
provenance store (.agenthood/provenance/), linked by the run'sexecutionId. Decisions connect with causal edges (CAUSED, INFLUENCED,PRECEDENT_FOR) in edges.json, and the provenance chain is tamper-evident
(SHA-256 hash chain, verifyChain()). See
decision-intelligence.md.
Runtime Implementation
The architecture described in this document is implemented as a TypeScript CLI in
this repo (src/), per ADR-008.
| This doc | Implemented as | Status |
|---|---|---|
| Members (skill files) | skills/<name>/SKILL.md | ✅ Shipped |
| Core agent roles (runtime) | developer → The Builder, qa → The Tester, architect → The Architect, reviewer → The Reviewer, the-oracle → The Oracle (src/agents/) | ✅ Shipped |
| Member subagent specs (tools, permissions) | src/members/MemberRegistry.ts | ✅ v2.0.0 |
| Tool scoping per member | MemberSpec.tools in MemberRegistry | ✅ v2.0.0 |
| Permission profiles | MemberSpec.permissions in MemberRegistry | ✅ v2.0.0 |
| Per-member preferred LLM provider | MemberSpec.preferredProvider | ✅ v2.0.0 |
| ReAct loop | src/reasoning/ReActLoop.ts | ✅ Shipped |
| BaseAgent | src/agents/base/BaseAgent.ts | ✅ Shipped |
| Concurrency queue | src/core/ConcurrencyQueue.ts | ✅ v2.0.0 |
| Safety caps | src/core/SafetyGuard.ts | ✅ v2.0.0 |
| Provider failover + circuit breaker | src/llm/ProviderFailover.ts | ✅ v2.0.0 |
| Persistent memory (IMemoryStore, ResidualMemory, InMemoryStore, VectorStore, ShortTerm, LongTerm, Episodic, Project) | src/memory/ | ✅ Shipped |
| Decision intelligence (DecisionLog + causal chains, ProvenanceStore, DecisionSearch, GraphSnapshot) | src/memory/ | ✅ ADR-015 |
| RAG pipeline (ChunkStrategy (FixedSize + MarkdownHierarchical), Indexer, Retriever, AgenticRAG, TreeSitterParser, ProjectIngestion) | src/rag/ | ✅ Shipped |
| Society index (members, ADRs, conventions → KGS + VectorStore) | src/project/SocietyIndexer.ts | ✅ Shipped |
| MemberOrchestrator Phase 1 — detection | src/reasoning/MemberOrchestrator.ts | ✅ v2.6.0 |
| Orchestrator (event bus, multi-step handoff) | src/orchestrator/ | 📋 Planned — Phase 3 |
| Member → Member direct handoff (today) | SubagentTaskSkill | ✅ Shipped (no bus) |
The Markdown skill files in skills/ are never modified — each is parsed at runtime
by MemberRegistry and used as the system prompt for the corresponding BaseAgent.