Guide: generated Koerper discipline
Status: design guidance. This page is the rule set an AI-driven code generator (Claude Code, Cursor, an in-house agent) must preserve when it produces application code that talks to Gestalt. It exists so a competent generator can produce a correct Koerper without the founding team interpreting every output.
A Koerper is the mutable operational body around a Geist. See concepts/geist-and-koerper.md. When a generator produces a Koerper, the same discipline applies — it is just easier to violate by accident at scale.
These are the rules. They are short on purpose.
What the generated code must do
Section titled “What the generated code must do”1. Cross the membrane through the SDK or HTTP
Section titled “1. Cross the membrane through the SDK or HTTP”Every act that should become company reality goes through the cloud
membrane. Use GestaltClient for the routes it covers. For the small
set of routes that do not yet have an SDK wrapper (see
../sdk/typescript.md), call HTTP directly with
the bearer token. Never reach into a database, a queue, or a connector
endpoint.
2. Keep the receipt with the UI state
Section titled “2. Keep the receipt with the UI state”Every membrane response carries a receipt (or at minimum a receipt
ref). Persist it alongside the rendered fact. A list row that shows an
invoice should be able to surface the invoice’s receipt.ref,
outcome, reasons, and fixture flag.
3. Render outcomes, not exceptions
Section titled “3. Render outcomes, not exceptions”refused, pending, and projected are real outcomes. Treat them as
data:
switch (response.outcome) { case "admitted": case "verified": case "executed": // success break; case "refused": // structured finding — render reasons and remedy hints break; case "pending": // act needs more — store the pending ref, ask the user for what is missing break; case "projected": // admitted into a projection, not into record break; case "queued": case "failed": // effect outbox states — see effect.intent / effect.dispatch break;}Throw only on transport errors (non-2xx HTTP, network failure). A
refused 200 OK is not an error.
4. Surface fixture and production-admission markers
Section titled “4. Surface fixture and production-admission markers”Until production admission lands, every receipt carries fixture: true
and most bodies carry productionAdmission: false. Show this on every
surface that displays admitted state. A Koerper that hides the fixture
flag is a Koerper that lies to its user.
5. Use read models for read surfaces
Section titled “5. Use read models for read surfaces”For lists, dashboards, and detail panels, prefer the read models over reconstructing state from raw atoms:
readActiveStandings durable active standingreadActiveMandates durable active mandatereadPeriodCloseReadiness derived close readinessreadConnectorEvidenceGaps evidence gap summaryreadProofHistory proof bundle manifest historycommitRecent remains the journal view; the read models are the
projection-shaped views the Koerper renders against.
6. Treat local state as cache, draft, or projection
Section titled “6. Treat local state as cache, draft, or projection”Local state is fine, as long as it is one of:
- Cache of a recent membrane projection, invalidated by re-fetching.
- Draft of an intent the user has not yet submitted.
- Projection of a forked reality that has not been promoted.
Local state is never the canonical version of company truth. If a fact would be relied on by an audit, an advisor, a regulator, or a counterparty, it crosses the membrane.
7. Route sensitive effects through effect.intent
Section titled “7. Route sensitive effects through effect.intent”External-world effects (sending an email, debiting an account, posting
to a webhook, calling an API) go through effectIntent followed by
effectDispatch. Always supply a stable idempotency_key derived from
the user-intended action. Reuse the same key on retry.
8. Request HumanAuth presence where required
Section titled “8. Request HumanAuth presence where required”Sensitive acts (signing, granting, revoking) require fresh HumanAuth
presence. The generator should produce code that calls
m13PresenceApproval and attaches the receipt ref to the proposing
call. Always pass create_standing_from_presence: false.
9. Distinguish presence, session, standing, and mandate
Section titled “9. Distinguish presence, session, standing, and mandate”These are four different things:
session a signed bearer context for a vesselHumanAuth presence a fresh receipt that a human is at the keyboardstanding a grant of capacity to bind a subjectmandate a scoped delegationGenerated data models, render trees, and authorization checks must keep them separate. None of the four can be derived from another client-side.
10. Show refusal reasons and remedy hints
Section titled “10. Show refusal reasons and remedy hints”A refusal is a finding. The body usually carries refusalReason,
optional missingEvidence, and an optional remedyHint. Surface all
three. A refusal panel without remedy is a bug.
What the generated code must not do
Section titled “What the generated code must not do”write directly to a databaseread directly from a databasehold canonical company truth in local statehide the fixture flagmint standing, mandate, package trust, or proof refs locallytreat HumanAuth presence as standing or mandatetreat a bearer session as standingexpose raw connector payloadsexpose raw biometric material or credential bytesexpose raw register / ID payloadsflatten refused, pending, and projected into a generic errorimply production admission before the production gate is satisfiedIf any of the above appears in generated code, the generator has lost the discipline. Reject the output.
A worked test
Section titled “A worked test”Before a Koerper ships, run this sanity walk against the fixture cloud:
- Call
tenantSelf. Confirm the response hasfixture: true. - Call
precheckIntentforcapability:issue_invoice_fixture_v1with empty evidence. Confirm the UI renders a structured refusal with reasons and remedy hint, not a 500. - Call
economicInvoicewithevidence_bundle:invoice_payload. Confirm the UI renders the admitted invoice with the receipt ref and the fixture marker. - Call
economicPeriodClosewith no clearance evidence. Confirm the UI renders theeconomic_closure_surface_openrefusal cleanly. - Inspect the network panel: every authenticated call carries the bearer token; no call goes anywhere except the membrane base URL.
A Koerper that passes these five steps satisfies the floor of this guide.
Where to read next
Section titled “Where to read next”- Building a Koerper — the broader pattern.
- SDK: TypeScript — every method and the routes without wrappers.
- Reference: outcomes
- Reference: refusal codes
- Reference: capability state