The GOVENANT Standard — Part 15: Developer Integration
The developer-facing contract for the Governance Engine (Door 2, Part 14 §14.1) and for custom connectors on either door. Everything here is boundary-level: the platform never requires access to the agent’s reasoning loop, framework, prompts, or models. Swap one function call, inherit the governance stack.
Depth vocabulary from Part 14 §14.7: Depth 2 = gate the edges (Laws 1+2); Depth 3 = the platform holds the clock (Laws 1+2+3).
15.1 The integration at a glance
| Surface | Direction | Purpose | Required for |
|---|---|---|---|
POST /v1/levers | you → platform | Register each action a role may take, with owner + outcome assertion | Depth 2 |
POST /v1/duties | you → platform | Declare each role’s job: triggers, expected outcomes, SLAs | Depth 3 (optional at Depth 2) |
POST /v1/actions | you → platform | Route every agent action through the gauntlet | Depth 2 |
| Occupant webhook | platform → you | The dispatcher wakes your agent when its duty fires | Depth 3 |
Connector pair (execute/verify) | platform → your system | Custom terminal edge for systems without a stock connector | As needed |
A minimal Depth 2 integration is the first and third rows: register levers, then replace direct
side-effect calls with POST /v1/actions. Typical effort for one role with a handful of levers:
1–2 days.
15.2 Auth and tenancy
- API keys are issued per tenant and per environment (
sandbox/live). Scope is derived server-side from the key — never from request payloads (Part 13 §13.5). - Every write is idempotent via an
Idempotency-Keyheader; retries are safe. - The sandbox tenant has the full gauntlet with connectors in loopback mode (side effects simulated, outcome rows synthesized) so the integration can be tested end-to-end before any real credential is granted.
15.3 The core swap
Before — the agent actuates directly (ungoverned by definition):
await gmail.send({ to, subject, body }); // hope it was a good ideaAfter — the agent proposes; the platform disposes:
const res = await ocmas.actions.create({ role_key: "sdr", lever: "send_outreach_email", duty_run_id: ctx.duty_run_id, // present at Depth 3; omit for ad-hoc artifact: { to, subject, body }, prediction: { metric: "replies", expected: 1, horizon_days: 7 },});// res.status ∈ delivered | pending_approval | request_filed | blocked | failedOne call bought: ownership check, deterministic hard-blocks + judged lenses, execution through the platform connector, outcome verification against the provider, an append-only ledger row with cost attribution, and a falsifiable prediction queued for grading on its horizon.
15.4 Registering levers
POST /v1/levers{ "key": "send_outreach_email", "owner_role": "sdr", "connector": "gmail", // or {"webhook": "https://you.example/execute"} "expected_metrics": ["replies", "meetings_booked"], // metric domain binding (Part 6 §6.3) "outcome_assertion": { "type": "provider_ref", // the provider must return a real message/record id "verify_within_minutes": 10 }, "pinned": false // true = ALWAYS requires human approval, forever}Rules enforced at write time:
- No assertion, no lever (Law 2 at the boundary).
owner_rolemust exist and the lever lands in that role’s charterowns[]— a duty or action referencing a lever outside its role’s charter is rejected (coverage invariant C2).pinned: truecannot be unset via the API; unpinning is a constitution-plane change with human provenance (Part 7).
15.5 Declaring duties
POST /v1/duties{ "role_key": "sdr", "duty_key": "drain_reply_queue", "trigger": { "kind": "event", "spec": "inbound_reply" }, // cron | event | dependency "expected_outcome": "reply_sent", "outcome_assertion": "count(actions where lever='send_reply' and delivered) >= queue_drained", "sla_minutes": 30, "max_cost_usd": 2.00, "levers": ["send_reply"], "charter_ref": "respond_to_inbound"}On every roster write the platform runs the coverage invariants (Part 3 §3.5): C2 (no scope
creep) and C3 (sound ordering) reject; C1 (full coverage) warns with the uncovered-responsibility
list. Duties are versioned; human edits via the console lock (source='human') and cannot be
overwritten by subsequent API writes.
15.6 Routing actions — response contract
POST /v1/actions always returns a terminal, machine-readable status:
| Status | Meaning | Your agent should |
|---|---|---|
delivered | Gate passed, side effect executed, outcome row verified; outcome_ref present | Proceed |
pending_approval | Tiered action queued for a human; webhook fires on decision | Wait or move on |
request_filed | Lever not owned by this role — converted to a request to the owning role | Nothing; that’s the system working |
blocked | Gate failed; failed names the hard-block rule or lens; revision_hints present | Revise and resubmit (bounded) |
failed | Executed but outcome could not be verified within SLA — escalated, never silently retried | Do not retry blindly |
Latency contract: deterministic hard-blocks are synchronous and fast; judged lenses add model
latency. Levers may be marked fast_path: deterministic_only for latency-critical surfaces (chat
replies) — the deterministic layer still never fails open (Part 5 §5.2).
15.7 The occupant webhook (Depth 3)
Expose one endpoint; the dispatcher calls it when a duty fires and the sensor pass finds work:
POST https://you.example/occupant{ "duty_run_id": "dr_9c1b…", "duty_key": "drain_reply_queue", "role_key": "sdr", "context_pack": { … }, // the role's granted context, assembled per Part 2 "budget_usd": 2.00, "deadline": "2026-07-14T09:30:00Z" // the SLA, concretely}Contract:
- Respond
202immediately; act by callingPOST /v1/actionswith theduty_run_id. - The platform — not your self-report — resolves the duty_run:
deliveredwhen the outcome assertion verifies,failedwhen the SLA lapses without a verified outcome. - If there is genuinely nothing to do after your own inspection, call
POST /v1/duty_runs/{id}/skipwith a machine-readable reason — silent skips cannot be written (Part 3 §3.2). - Retire your own scheduler for these duties. Two sources of scheduled truth make the coverage audit wrong from day one (Part 12 §12.6) — cut over, don’t straddle.
15.8 Custom connectors
For a terminal system without a stock connector, implement two endpoints and register them as the
lever’s webhook:
POST /execute { lever, params, action_id } → { provider_ref } // do the real thingGET /verify?provider_ref=… → { exists: true|false } // prove it happenedverify is the half most integrators skimp on and the half that matters: it is what lets the
platform assert Law 2 about your system. A connector whose verify merely echoes execute’s
success is self-report, scores as such in the audit, and blocks certification.
15.9 The fence-rule checklist (certification prerequisite)
Depth 2+ certification requires demonstrating the gate is the only path (Part 14 §14.7.2):
- Enumerate every credential your agent holds that can reach a terminal edge (mail, CRM, repo, payment, filing).
- Move each behind a platform connector — or revoke it.
- Provide the egress evidence: the audit probe attempts direct actuation from the agent’s runtime and MUST fail.
- Keep break-glass credentials out of the agent’s reach (a human vault, not an env var).
No side-door keys, no certificate. This is usually a credential/config task, not engineering — but it is the step teams defer, and deferring it makes every other step decorative.
15.10 Definition of done
The integration is done when — with your agent as the occupant — the tenant passes both acceptance tests (Part 0 §0.5) in the platform’s own audit:
- ALIVE: one end-to-end trace by ID: event → your agent → ownership check → gate → real side effect → verified outcome row → prediction → grade.
- COVERED (Depth 3): every declared responsibility maps to a duty; every due duty resolved
deliveredor reasoned; the duty-delivery ratio computed and visible on the coverage board.
Run the readiness audit from the console; the gap list is your punch list. If any edge only logs instead of acts, it is not done (Part 12 §12.3).