Ships the MVP slice of spec 018 (dynamic agent spawning):
- 5 new SQLite migrations (021-025): goals + goal_tasks + agent_proposals
+ reputation_evidence + secrets + harness_runs.task_id. The legacy
`tasks` table (channel auctions) and `agent_trust` table (reactions
workflow) are left untouched — the new schema coexists.
- 4 new internal packages, fully tested:
- internal/goals: Goal struct + store + service, slug collision dedup,
backing-channel auto-create via ChannelCreator adapter
- internal/goaltasks: goal_tasks table with denormalized 16 KB
ancestry snapshots, single-statement optimistic-lock atomic claim,
recursive-CTE cost rollup, state machine, per-billing-code rollup
- internal/secrets: NaCl-secretbox encrypted blobs, user/agent/task
scope precedence, sanitized env injection, master-key bootstrap
- internal/trust additions: ConfigHash (deterministic SHA-256 of
model + prompt + tools + skills + mcp + subagents, sorted),
DelegationCap (tier + tool-scope + budget + depth enforcement),
append-only Ledger with exponential time-decay rolling score and
70%-of-parent child seeding. Existing trust package unchanged.
- Critical invariants under test:
- 50-goroutine concurrent claim race → exactly one winner per round
- ConfigHash stable under shuffled array inputs, sensitive to
capability changes
- DelegationCap full tier × tool-scope matrix
- Ledger time-decay + parent seed at 70 % ± 1 %
- Secret name sanitization, scope precedence, plaintext never
returned via MCP-equivalent paths
- internal/agents/types.go extended with dynamic-spawning columns
(config_hash, parent_agent_id, spawn_depth, system_prompt,
autonomy_tier, tool_scope_json, quarantined_at). Existing tests
still pass.
- cmd/docgardener: self-contained demo binary driving the end-to-end
flow. `docgardener run` creates a goal, builds a task tree with
denormalized ancestry, spawns 3 specialists (each going through
real delegation-cap validation and config-hash computation and
70 %-of-parent reputation seeding), claims tasks atomically, runs
them through the state machine, records reputation evidence.
`docgardener report` queries all of that back out and renders a
rich dark-mode HTML report (header, spend metrics, task tree,
spawned-agent cards with reputation bars, cost breakdown, artifacts,
timeline).
- examples/doc-gardener: start.sh / run_task.sh / report.sh / stop.sh
mirroring the cold-topic-explainer pattern. Launches an isolated
synapbus instance on port 18089, drives the demo, renders
report.html, cleans up. Full README documenting what's real vs
deferred, plus examples/README.md listing both examples.
- specs/018: tasks.md updated with MVP completion status; legacy tasks
naming collision noted.
Deferred (marked explicitly in example README):
- Real LLM-driven coordinator (needs MCP tool wiring + prompt
iteration)
- Real subprocess runs (needs reactor integration with task_id on
ExecRequest)
- Full MCP tool surface (contracts are written at
specs/018-dynamic-agent-spawning/contracts/mcp-tools.md)
- Svelte /goals UI (REST endpoints remain a follow-up)
- Full budget race + quarantine auto-trigger wiring
- Full resource-request → secrets fulfill reaction-workflow path
Cross-compiles clean for linux/amd64 and darwin/arm64 with no CGO
(SC-010). All new package tests pass (SC-004, SC-005, SC-007).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
55 lines
3.0 KiB
SQL
55 lines
3.0 KiB
SQL
-- 022: Agent proposals + resource requests.
|
|
--
|
|
-- Agent proposals: a pending request by an existing agent to spawn a new
|
|
-- specialist sub-agent. Delegation-cap and spawn-depth checks run at
|
|
-- propose time; approval via the reactions workflow on #approvals.
|
|
--
|
|
-- Resource requests: an agent asking the human owner for a missing
|
|
-- secret (API key, credential) via #requests.
|
|
|
|
CREATE TABLE agent_proposals (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
proposer_agent_id INTEGER NOT NULL REFERENCES agents(id) ON DELETE CASCADE,
|
|
goal_id INTEGER NOT NULL REFERENCES goals(id) ON DELETE CASCADE,
|
|
parent_task_id INTEGER REFERENCES goal_tasks(id) ON DELETE SET NULL,
|
|
proposed_name TEXT NOT NULL,
|
|
proposed_model TEXT NOT NULL,
|
|
proposed_system_prompt TEXT NOT NULL,
|
|
proposed_tool_scope_json TEXT NOT NULL DEFAULT '[]',
|
|
proposed_skills_json TEXT NOT NULL DEFAULT '[]',
|
|
proposed_mcp_servers_json TEXT NOT NULL DEFAULT '[]',
|
|
proposed_subagents_json TEXT NOT NULL DEFAULT '[]',
|
|
proposed_autonomy_tier TEXT NOT NULL
|
|
CHECK (proposed_autonomy_tier IN ('supervised','assisted','autonomous')),
|
|
reason TEXT NOT NULL DEFAULT '',
|
|
status TEXT NOT NULL DEFAULT 'pending'
|
|
CHECK (status IN ('pending','approved','rejected','materialized','cancelled')),
|
|
approval_message_id INTEGER REFERENCES messages(id) ON DELETE SET NULL,
|
|
materialized_agent_id INTEGER REFERENCES agents(id) ON DELETE SET NULL,
|
|
rejection_reason TEXT,
|
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
decided_at DATETIME
|
|
);
|
|
|
|
CREATE INDEX idx_proposals_goal ON agent_proposals(goal_id);
|
|
CREATE INDEX idx_proposals_parent ON agent_proposals(parent_task_id);
|
|
CREATE INDEX idx_proposals_status ON agent_proposals(status);
|
|
|
|
CREATE TABLE resource_requests (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
requester_agent_id INTEGER NOT NULL REFERENCES agents(id) ON DELETE CASCADE,
|
|
task_id INTEGER NOT NULL REFERENCES goal_tasks(id) ON DELETE CASCADE,
|
|
resource_name TEXT NOT NULL,
|
|
resource_type TEXT NOT NULL,
|
|
reason TEXT NOT NULL,
|
|
status TEXT NOT NULL DEFAULT 'pending'
|
|
CHECK (status IN ('pending','fulfilled','rejected','revoked')),
|
|
request_message_id INTEGER REFERENCES messages(id) ON DELETE SET NULL,
|
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
fulfilled_at DATETIME
|
|
);
|
|
|
|
CREATE INDEX idx_requests_task ON resource_requests(task_id);
|
|
CREATE INDEX idx_requests_requester ON resource_requests(requester_agent_id);
|
|
CREATE INDEX idx_requests_status ON resource_requests(status);
|