Durable state
Let packages own state without making the gateway a database.
Packages can bring Turso, Neon, a package-owned HTTPS storage endpoint, or another provider while ExecWarden keeps workspace context, secrets, runtime isolation, policy, approvals, and audit boundaries.
What Belongs in Package Storage
Use package-owned storage when an integration needs durable state that belongs to the package, not to the gateway runtime. ExecWarden supplies the selected workspace id, package-local secrets, bounded HTTP, policy, approvals, and audit boundaries.
Runtime API
Package runtime code uses plain fetch(...) for outbound HTTPS and gateway.secrets.get(...) for declared package-local secrets. gateway.call(...) is a separate user-function bridge for gateway capabilities, not the package DBaaS/provider API.
const baseUrl = gateway.secrets.get("storage_api_url").replace(/\/+$/, "");
const token = gateway.secrets.get("storage_api_token");
const response = await fetch(baseUrl + "/mutation.stage", {
method: "POST",
headers: {
authorization: "Bearer " + token,
"content-type": "application/json"
},
body: JSON.stringify({
workspaceId: input.request.context.workspaceId,
kind: "linear.issue",
preview: { title: "Create issue" },
request: { title: "Create issue", teamId: "team-a" }
})
});
return { ok: true, data: await response.json() };Staged Mutation Lifecycle
Stage
Store the exact external API payload and a human-readable preview without sending it.
Approve
Review and approve the staged mutation id, so the approved payload is the payload that will be sent.
Commit
Claim the stored payload with an idempotency key, call the provider-specific API, and record the remote result. Active claims should be exclusive until their lease expires.
Discard
Finalize the staged mutation without calling the provider.
Register the Package
A storage-backed package still uses the normal package lifecycle: validate, create, configure secrets, test a draft action, publish, then grant the package actions explicitly.
gateway_capability_packages_validate({ manifest, runtime });
gateway_capability_packages_create({ manifest, runtime });
gateway_capability_packages_set_secret({
packageId: "staged-mutations-example",
secretName: "storage_api_url",
value: "https://storage.example.com/package-state"
});
gateway_capability_packages_set_secret({
packageId: "staged-mutations-example",
secretName: "storage_api_token",
value: "store_..."
});
gateway_capability_packages_test({
packageId: "staged-mutations-example",
action: "mutation.stage",
params: {
kind: "linear.issue",
preview: { title: "Create issue" },
request: { title: "Create issue", teamId: "team-a" }
}
});
gateway_capability_packages_publish({ packageId: "staged-mutations-example" });DBaaS Recipes
Worked Example
The MCP docs include a staged-mutation example that validates the manifest/runtime shape and demonstrates the storage action contract.
gateway_docs_get({ topic: "package-storage" });
gateway_examples_get({ id: "staged-mutations-libsql" });