Skip to content

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

SurfaceDirectionPurposeRequired for
POST /v1/leversyou → platformRegister each action a role may take, with owner + outcome assertionDepth 2
POST /v1/dutiesyou → platformDeclare each role’s job: triggers, expected outcomes, SLAsDepth 3 (optional at Depth 2)
POST /v1/actionsyou → platformRoute every agent action through the gauntletDepth 2
Occupant webhookplatform → youThe dispatcher wakes your agent when its duty firesDepth 3
Connector pair (execute/verify)platform → your systemCustom terminal edge for systems without a stock connectorAs 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-Key header; 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 idea

After — 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 | failed

One 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_role must exist and the lever lands in that role’s charter owns[] — a duty or action referencing a lever outside its role’s charter is rejected (coverage invariant C2).
  • pinned: true cannot 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:

StatusMeaningYour agent should
deliveredGate passed, side effect executed, outcome row verified; outcome_ref presentProceed
pending_approvalTiered action queued for a human; webhook fires on decisionWait or move on
request_filedLever not owned by this role — converted to a request to the owning roleNothing; that’s the system working
blockedGate failed; failed names the hard-block rule or lens; revision_hints presentRevise and resubmit (bounded)
failedExecuted but outcome could not be verified within SLA — escalated, never silently retriedDo 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 202 immediately; act by calling POST /v1/actions with the duty_run_id.
  • The platform — not your self-report — resolves the duty_run: delivered when the outcome assertion verifies, failed when the SLA lapses without a verified outcome.
  • If there is genuinely nothing to do after your own inspection, call POST /v1/duty_runs/{id}/skip with 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 thing
GET /verify?provider_ref=… → { exists: true|false } // prove it happened

verify 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):

  1. Enumerate every credential your agent holds that can reach a terminal edge (mail, CRM, repo, payment, filing).
  2. Move each behind a platform connector — or revoke it.
  3. Provide the egress evidence: the audit probe attempts direct actuation from the agent’s runtime and MUST fail.
  4. 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 delivered or 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).