Concept: The membrane
Status: fixture-rehearsed. The membrane is the contract
contracts/gestalt-cloud-membrane.v0.jsonserved by the Axum runtime incrates/gestalt-cloud. Production admission across the membrane is gated.
The line
Section titled “The line”Gestalt’s central architectural decision is a line called the membrane. On one side of the line is mutable work. On the other side is governed company reality. Every crossing is explicit, typed, and produces a receipt.
Koerper membrane Geist (mutable) (intent envelope (governed) in, receipt out)
UI state standing drafts atoms local tables realities imports capabilities agent scratchpads ─── intent ───> evidence bundles generated workflows effects caches closure surfaces AI scratchpads <─── receipt ─── tensions fixtures receiptsThe membrane is not an API convenience. It is the place where ordinary computation asks to become consequential.
Why a membrane at all
Section titled “Why a membrane at all”Most software does not have one. A typical app calls a function, the function writes a row, the row is now company truth. Gestalt refuses this because it makes a single layer responsible for two incompatible jobs:
- navigation (showing operators paths through possibility), and
- admission (binding a fact into company history).
Navigation wants to be opinionated, fast-moving, replaceable, and context-rich. Admission wants to be slow-moving, narrow, signed, and durable. When they share a layer, admission gets corrupted by navigation’s velocity and navigation gets choked by admission’s ceremony.
Gestalt splits them. The Koerper does navigation. The Geist does admission. The membrane is where they talk.
What crosses the membrane
Section titled “What crosses the membrane”The thing that crosses is an intent envelope. It carries:
who is asking actor refunder what surface vessel id + signing posturefor which company subject refin which reality record / projected:<id>under which capability capability refwith which content payload conforming to capability schemaciting which evidence evidence bundle refsexpecting which effects declared effect intentwith which signing posture how the vessel is willing to commitThis shape is consistent across every operation in the membrane contract. Operations vary in their bodies and outcomes; the envelope discipline is universal.
What comes back
Section titled “What comes back”Every crossing returns a MembraneResponse:
interface MembraneResponse<T> { operation: string; // "intent.commit", "reality.fork", ... outcome: MembraneOutcome; // "admitted" | "refused" | "pending" | ... body: T; // operation-specific payload receipt?: MembraneReceipt;}The outcome is one of:
admitted serious atom committedrefused structured refusalpending awaiting signing / evidence / advisorprojected admitted into a projected reality onlyverified a non-mutating call (probe, query, verify) succeededqueued accepted into a durable outboxexecuted dispatchedfailed dispatched but failed (idempotent record)The receipt is shape-correct on every crossing. Today it is not
cryptographically signed against canonical bytes (see
022 gap report
item 17), but the discipline of “every crossing leaves a verifiable
receipt” is enforced. See receipts-and-proofs.md.
What the membrane refuses
Section titled “What the membrane refuses”The membrane is structured to refuse, not to forgive. A refusal is not an error. It is a structured finding about why an act could not enter reality.
A refusal carries:
failed_gate which structural check failedcapability_ref which capability was being citedsource_atoms what was being cited as causelocus where in the envelope it failedreason human-readable coderemedy_hint what could fix itrequired_evidence what evidence would unblock itrequired_intervention what professional act would unblockpossible_projection_path could this work in a projectionwhether_failure_is_recordable does the company need to rememberSome failures are themselves company reality: an employee tried to bind a contract without standing, an agent attempted a risky production-continuity message. These get recorded. See reference/refusal-codes.md.
Open SDK boundary vs closed runtime boundary
Section titled “Open SDK boundary vs closed runtime boundary”The membrane contract is explicit about who owns what.
Open to the SDK:
typed request envelopestyped response envelopeslocal receipt verificationfixture simulationproof disclosure request constructionClosed — owned by the cloud runtime:
production admissiontenant key custodyauthority package activationpendulum evaluator dispatchproof issuanceoperator audit policyForbidden — no surface ever touches:
raw database accessprivate signing keyscross-tenant graph traversalproduction package mutationunscoped proof bundle disclosureThese boundaries are part of the contract, not folklore. They show up
literally in
contracts/gestalt-cloud-membrane.v0.json.
Vessels and signing postures
Section titled “Vessels and signing postures”The thing on the Koerper side of the membrane is called a vessel. A vessel may be:
- a CLI session,
- a native desktop app (e.g. macos-workbench),
- a browser surface (e.g. react-workbench),
- an MCP tool wired into an LLM,
- an HSM-backed signer,
- a hosted operator delegate (for shop-origin actions).
Each vessel has a declared signing posture:
dev_full_signing dev key against fixture substratelocal_fixture_signing fixture key, fixture substrateproposal_only cannot sign; can only proposepaired_native_signing proposes via app; signs via paired native vesselhsm_backed_signing signs through HSMread_only can verify and inspect; cannot proposeGravity uses the posture to decide whether the vessel can complete a serious act or only propose one. The same command from the same actor can produce a committed atom from one vessel and only a pending action from another.
This means: the CLI is not a backdoor. It crosses the membrane the same way a browser or a Steuerberater console does.
Pending actions
Section titled “Pending actions”If a vessel cannot complete an act, the membrane does not error. It creates a pending action:
intent_envelope the original enveloperequired_standing what standing the act needsrequired_evidence what evidence is missingrequired_channels how it can be completed (paired vessel, HSM)expires_at deadlineorigin_vessel who proposedcorrelation_id ties the pending to its eventual completionpreview what would have happenedgravity_precheck which gates passed and which did notA separate signing vessel — a phone, a hardware key, a paired native app — can later complete the pending action. The completion produces either an admitted atom or a refusal, citing the original origin.
This is how Gestalt avoids the worst dark pattern of governance software: silently downgrading a serious act to a casual one because the user happened to click from the wrong device.
Dry run vs projection
Section titled “Dry run vs projection”A dry run asks: would this proposal pass Gravity against today’s record reality? It returns a structured evaluation. It does not bind anything.
A projection says: create a bounded possible worldline in which proposed atoms may have effects, closure surfaces, tensions, fibers, and receipts. A projection is governed; it is not a “test mode” or a “draft folder.”
Both are first-class. They are not the same. See realities.md.
Receipts everywhere
Section titled “Receipts everywhere”Every serious crossing leaves a receipt. The CLI prints them
aggressively. The SDK exposes them in MembraneResponse.receipt. The
verification path is supposed to let any downstream party (auditor,
counterparty, advisor) confirm what happened.
Today, receipt verification is shape-only — it checks the receipt fields are present and the outcome is from the known set. Real cryptographic verification against the runtime signer is on the roadmap. See receipts-and-proofs.md and 022 item 17.
What the membrane looks like in code
Section titled “What the membrane looks like in code”In the contract:
{ "operation": "intent.commit", "method": "POST", "path": "/v1/intents/commit", "runtime_owner": "cloud_geist", "sdk_role": "submit standing-bound intent", "request_record": "CloudIntentCommitRequest", "responses": ["atom", "refusal", "pending_action", "receipt"]}In the TypeScript SDK:
const response = await client.precheckIntent({ tenant: "tenant_node:rheinwerk_calibration", capability: "capability:issue_invoice_fixture_v1", action: "issue", evidence: ["evidence_bundle:invoice_payload"],});
if (response.outcome === "refused") { console.log("refused:", response.body.failedGate);} else if (response.outcome === "admitted") { console.log("atom committed:", response.body.atomRef);}In the Rust SDK (today: local fixture client):
let client = GestaltClient::fixture();let response = client.precheck_intent(IntentPrecheckRequest { intent_kind: "invoice.issue".into(), actor_ref: "human_person:anna".into(), effect_class: "economic_action".into(), evidence_refs: vec!["evidence_bundle:invoice_payload".into()],});What the membrane is not
Section titled “What the membrane is not”- Not an audit log. An audit log records “X happened.” Gestalt records “X became admissible under standing S, evidence E, capability C, in reality R, citing prior atoms P, with effects F, signed by signer K.”
- Not a workflow engine. Workflows live in Koerpers. The membrane doesn’t sequence steps; it admits acts.
- Not a permission system. Permissions ask “can this user call this function?” The membrane asks “can this actor, under this mandate, in this situation, citing these facts, with this evidence, cause this act to become company reality?”
- Not an event bus. Events are emitted from the Geist (effects, closure-surface changes), but the membrane is not a pub/sub.
Where to read next
Section titled “Where to read next”- Geist and Koerper — what each side of the line is for.
- Atoms and capabilities — what crosses in detail.
- Receipts and proofs — what comes back.
- Realities — record vs projected.
- API reference — every operation.