--- id: BINKY-WP-0007 type: workplan title: "Qonto Governed Assistant: policy kernel + REST (Phase 1)" domain: infotech repo: binky-control status: active owner: claude topic_slug: the-custodian created: "2026-07-22" updated: "2026-07-22" state_hub_workstream_id: "8a691acb-3500-4f17-84fe-dcfc7a979fdc" --- Follow-on from BINKY-WP-0005 (custody lane + first read-only pull, finished). Blueprint: `integrations/qonto-governed-assistant/ArchitectureBlueprint.md`. **Recommendation being executed:** build a small **Qonto Governed Assistant** service — the only component allowed to hold the bank API key — exposing a default-deny policy-shaped MCP server and thin REST API, so every harness (Claude Code, Codex, Cursor, Grok, agent-harness sessions, scripts) is a dumb client of one governed endpoint instead of each wiring vendor MCP + local allow-lists directly. **No spend / no volume-cost tools in v1** — payments, transfers, card ops, and plan changes stay Red lane (human in the Qonto app). This workplan tracks **Phase 1 only** (policy kernel + REST — minimum useful product, per blueprint §6). Phase 2 (MCP surface), Phase 3 (flex-auth/fleet), and Phase 4 (productization) are follow-on work, opened as residuals or a new workplan once Phase 1 lands. ## Task: Ratify architecture decisions (blueprint §9) ```task id: BINKY-WP-0007-T01 status: todo priority: high state_hub_task_id: "34474d61-0238-4321-a6c0-27c3ad3b8fe3" ``` Bring the five decision requests from the blueprint to the founder via DecisionQueue.md: 1. Adopt the domain-assistant architecture (option B) for Qonto. 2. Repo home: new dedicated `qonto-assistant` repo (already present in the state-hub repo registry) vs. waiting for a generic `finance-connect`. 3. v1 policy freeze: hard deny on all spend / volume-cost tools. 4. MCP transport: remote streamable-HTTP only for production clients. 5. Whether to ever run vendor `qonto-mcp-server` as an internal-only backend (blueprint default: no). Done when: DEC entry filed, founder decision recorded, blueprint updated with the ratified answers. ## Task: Service skeleton — decision function + custody wiring ```task id: BINKY-WP-0007-T02 status: todo priority: high state_hub_task_id: "8978dbd9-c7a1-4b5b-9c0c-acf3e08c74bf" ``` In the `qonto-assistant` repo (per T01 decision): shared `decide(tool, args, claims) -> Allow|Deny` module backed by `policy/qonto-v1.yaml` (blueprint §4.6); OpenBao fetch of `tenants/binky/qonto-api` only inside this service (AppRole/OIDC role, short TTL) — never in harness env. Hard deny list for every write/spend path, even unimplemented ones. Green lane (no live traffic yet). Done when: policy module has unit tests for allow/deny cases including the deny-classes (`spend`, `volume_cost`, `credential_exfil`). ## Task: REST surface + CostRunRate consumer cutover ```task id: BINKY-WP-0007-T03 status: todo priority: medium state_hub_task_id: "a35e2565-e520-491e-8587-8ec4961f898c" ``` Implement `GET /v1/accounts`, `GET /v1/transactions`, `GET /v1/snapshot` behind the policy gate from T02. Replace the ad-hoc first-pull script used for `finance/CostRunRate.md` with a call through this REST surface. Blue lane (reads live account data; no writes). Done when: CostRunRate refresh runs via the assistant end-to-end at least once, with call metadata (actor, tool, decision) logged to evidence, not the raw account data. ## Task: Smoke tests and closure ```task id: BINKY-WP-0007-T04 status: todo priority: medium state_hub_task_id: "a16ef7df-ddd7-474b-8327-0eca5c89ede7" ``` CI smoke against a mocked Qonto backend (deny-path and allow-path cases); one manual live read against the dogfood account through the deployed assistant. Close this workplan when Phase 1 is proven; hand off Phase 2 (MCP surface for all harnesses) as a residual intake or new workplan. Done when: `statehub fix-consistency` run clean; Phase 2 scope captured either as an AutopilotWorkQueue residual or a follow-on workplan file.