Part of #1 and #6 (project bootstrap, v0.1, phase 5 split).
Phase 5 in issue #6 was originally one PR for core/loop + core/router + core/approval. Splitting into three PRs sequenced by dependency so each fits the local pre-commit gate's review window cleanly. This is part 5a (smallest, no inter-package deps).
Deliverables
core/approval/
Decision enum: Allow, Deny, AllowAll (allow-all-for-session).
Approver interface — Approve(ctx, event.ToolCallRequest) (Decision, error).
AutoAllow — trust MCP-declared permissions; always returns Allow.
Interactive — TTY prompt via injectable io.Reader / io.Writer for testability. Used by cmd/repl later.
Policy — rule-based: allow on prefix match (e.g. datahub_* reads), prompt on prefix match (e.g. trino_execute), deny on exact match (e.g. datahub_delete). Rules evaluated in order; first match wins.
- Sentinel errors:
ErrApprovalDenied (when caller wants to wrap a Deny).
Tests
- Table-driven unit tests for each implementation.
- Interactive uses a
bytes.Buffer for stdin and a bytes.Buffer for stdout; tests cover y/n/a (allow-all) responses, EOF, malformed input.
- Policy rule-precedence tests.
-race clean.
Out of scope
core/router (phase 5b, parallel branch)
core/loop (phase 5c, depends on 5a and 5b)
Branch
feat/bootstrap-approval
Spec: §6.7 of the bootstrap spec in #1.
Part of #1 and #6 (project bootstrap, v0.1, phase 5 split).
Phase 5 in issue #6 was originally one PR for
core/loop+core/router+core/approval. Splitting into three PRs sequenced by dependency so each fits the local pre-commit gate's review window cleanly. This is part 5a (smallest, no inter-package deps).Deliverables
core/approval/Decisionenum:Allow,Deny,AllowAll(allow-all-for-session).Approverinterface —Approve(ctx, event.ToolCallRequest) (Decision, error).AutoAllow— trust MCP-declared permissions; always returnsAllow.Interactive— TTY prompt via injectableio.Reader/io.Writerfor testability. Used bycmd/repllater.Policy— rule-based: allow on prefix match (e.g.datahub_*reads), prompt on prefix match (e.g.trino_execute), deny on exact match (e.g.datahub_delete). Rules evaluated in order; first match wins.ErrApprovalDenied(when caller wants to wrap a Deny).Tests
bytes.Bufferfor stdin and abytes.Bufferfor stdout; tests cover y/n/a (allow-all) responses, EOF, malformed input.-raceclean.Out of scope
core/router(phase 5b, parallel branch)core/loop(phase 5c, depends on 5a and 5b)Branch
feat/bootstrap-approvalSpec: §6.7 of the bootstrap spec in #1.