# Features overview Source: https://docs.corbits.dev/about-corbits/features The capabilities that make Corbits a platform for deploying secure, auditable agents. [**Corbits**](/getting-started/intro) is a platform for deploying secure, auditable agents with organizational guardrails: control, audit, and observability over what your agents can do. It gives teams the run, audit, and manage layer that turns a promising agent into something they can put in front of real work. ## What Corbits gives you Grant agents exactly the capabilities they need and nothing more. Access is fail-closed by default. See [Credentials & Grants](/platform/guardrails). The control plane commits each agent's conversation context and audit records to a cryptographically signed git history, and exposes logs, metrics, and traces for how an agent is behaving right now. The signed history is verifiable with standard git, though it is not retained past a run and there is no route for querying it. Secrets are resolved and scoped by the platform at launch. Agents never look them up, and they act only within the grants they were given. Organize agents and policy across an organizational hierarchy, with inheritance and restrictions that never leak authority downward. Run agents on Anthropic, Google Gemini, OpenAI, or any OpenAI-compatible endpoint. Choose on cost and capability, and switch without re-platforming. ## Built for two buyers Corbits is written for the builders shipping agents and the security and compliance teams accountable for them. Developers get permissions, secrets handling, and audit logging without hand-rolling them for every deployment. Evaluators get proof that an agent can be granted exactly what it needs, and that every action is accountable. ## Apps on the platform A standalone coding-agent CLI that applies the same guardrail discipline in its own process rather than on the control plane. The multiplayer workspace for humans and agents, sharing benches and conversations. # Legal Source: https://docs.corbits.dev/about-corbits/legal The policies that govern your use of Corbits. The terms that govern your use of Corbits. How Corbits collects, uses, and protects your data. # Glossary Source: https://docs.corbits.dev/getting-started/glossary Plain-language definitions of the core Corbits terms: the layers, the authorization model, the runtime, and the signed commit history. The Corbits docs use a compact, precise vocabulary. This page collects the core terms in one place, grouped by what they describe, so a term you meet mid-page has a definition you can jump to. Each entry links to the page that covers it in depth. Where one of these words also carries an app-specific meaning inside a product, the definitions here are the platform ones. Many terms belong to a specific layer. Corbits is three layers: **apps** on top, a **control plane** that runs and governs agents, and an **agent runtime** beneath. The definitions below say which layer each term belongs to. See [The Corbits Platform](/platform/overview) for the layered picture. ## Layers and products **Corbits.** The platform for deploying secure, auditable agents with organizational guardrails: the run, audit, and manage layer you run agents on. See [Overview](/platform/overview). **Control plane.** The layer that runs, governs, and audits agents. It resolves credentials, materializes grants, gates the API, and keeps a signed record of what an agent did. It does not decide everything: some checks run in the agent runtime while an agent is going. Most terms in this glossary belong to the control plane. **Agent runtime (Interchange).** The execution engine beneath the control plane. It runs the agents and handles model choice, speaking to the major model providers natively. It also evaluates grants itself: whether a running agent may invoke a given tool is decided here, against the grants that deployment holds, rather than in the control plane. **Agent.** A defined set of capabilities, instructions, and goals that runs as a loop within a durable workflow. An agent can run locally, built directly on the Interchange libraries, or be deployed on the control plane and provisioned onto a sidecar for managed use. See [Overview](/platform/overview). **Apps.** The finished products people use, built on the stack. Corbits ships two: Workbench and Corbits Code. **Workbench.** The first-party multiplayer workspace for humans and agents, sharing benches and conversations. It runs on the control plane and inherits its credentials and grants. See [Workbench](/platform/workbench). **Corbits Code.** A standalone coding-agent CLI that applies the same guardrail discipline in its own process rather than on the control plane. See [Corbits Code](/platform/corbits-code). **Bench.** In Workbench, the shared space a team works in, holding its members, its agents, and its history. A bench is a control-plane tenant underneath, so belonging to one is a principal record and what you may do in it is decided by grants. See [Workbench](/platform/workbench). **Channel.** In Workbench, a conversation inside a bench. A channel is minted as its own control-plane tenant parented under that bench, which gives it an identity and a place to hang membership, though the routes serving it authorize against the bench above. See [Workbench](/platform/workbench). ## Authorization These are the credential and grant terms. The **control plane** resolves credentials and materializes grants; the **agent runtime** decides some of what an agent may do while it runs, and a few decisions consult no grant at all. See [Guardrails](/platform/guardrails) for which is which. **Principal.** An entity within the control plane, joined to a tenant. A principal is a user or a workflow. Grants attach to principals, either directly or through a role. **Tenant.** An organizational scope that owns credentials, roles, and grants. Tenants nest into a hierarchy of sub-tenants. **Inheritance and shadowing.** Credentials resolve up the tenant hierarchy: the control plane checks the current tenant, then walks up the parent chain, so a child tenant can resolve a credential defined at a parent. A child can shadow a parent's credential by defining one with the same name, since names are unique within a tenant. Grants do not inherit at all: authorization evaluates only the grants held in the acting tenant. **Role.** A named bundle of grants scoped to a tenant. Every tenant has the system roles owner, admin, and member. Roles carry authority when a person calls the control-plane API; a running workflow's authority comes from the grants on its own principal. **Grant.** A row saying that some principal may take some action on some resource, carrying three fields: resource, action, and effect. Most of what a principal may do is decided by evaluating grants, though not all of it: a model-provider credential is authorized by tenant ownership with no grant involved. **Resource.** The part of a grant that names what is authorized, as a glob pattern: `tool:bash`, `credential:crd_gdrive`, `tool:*`. **Action.** The part of a grant that names the operation, as a verb: `invoke`, `read`, `use`. **Effect.** The decision a grant carries: `allow`, `deny`, or `ask`. When more than one grant matches, the most specific wins, and at equal specificity deny beats ask beats allow. **Fail-closed.** Where either layer decides from grants, an action proceeds on the strength of a grant that permits it, and on nothing else. There is no implicit allow. Which decisions are made that way, and which are not, is set out on [Guardrails](/platform/guardrails). **Credential.** A runtime secret an agent uses to authenticate with an outside provider: an API key, an OAuth token, or a certificate. Owned and stored by your organization, and delivered to a deployment by the control plane rather than looked up by the agent. **Provider.** The outside service a credential authenticates to, such as GitHub, Slack, or a model provider like OpenAI. Every credential belongs to a provider. **Organizational vs. personal credential.** An organizational credential has no principal owner and is shared across the tenant. A personal credential is owned by a specific user. **Git token.** A bearer secret a caller presents to reach the durable state described on [Guardrails](/platform/guardrails), minted by the control plane as either a personal access token or a service token. It is a separate concept from a credential: a credential is what an agent authenticates to an outside provider with, while a git token is what a caller authenticates to us with. Its claims narrow the actions a holder may take, the refs they may touch, and how long the token lives, and the control plane intersects them with a grant verdict on every repository operation. **Requirement.** What a deployed definition declares it needs, rather than a live grant. The control plane resolves credential requirements when a definition is deployed and grant requirements when it first triggers, rather than letting an agent look anything up while it runs. Credential requirements and grant requirements are declared separately, and the two accept different sources. **Source.** A field on a requirement that names where its authority comes from. A credential requirement draws from `tenant` (the organization's), `creator` (the definition author's), or `invoker` (the user launching the agent). A grant requirement draws from `creator` or `invoker` only; there is no tenant-sourced grant requirement. Source is about the provenance of authority, not about sharing. **Tool.** A capability a principal can invoke. The agent runtime checks every invocation against a `tool:` grant that the control plane froze when the deployment was created, taken from what the workflow declared rather than from a set an operator chose. The effect that grant carries comes from the tool's own declaration in the same way: a tool declaring an approval mark carries `ask`. Not every tool reaching an outside provider needs a credential. ## Execution These terms name the agent-runtime pieces involved in running the code you deploy. See [Isolation](/platform/isolation) for the full treatment. **Sidecar.** The managed host that runs deployed agents and workflows. The control plane provisions work onto sidecars, tracks their health, and routes to the deployments each one hosts. See [Isolation](/platform/isolation). **Deployment.** A workflow or agent placed onto a sidecar and made addressable, carrying its own mail address and signing key. It is the unit the control plane provisions, routes to, and tears down. **Supervisor.** The trusted half of a running deployment. It holds the deployment's identity, meaning its signing key, its address on the message bus, and the credentials it was granted, and it starts and oversees the process that runs your code. See [Isolation](/platform/isolation). **Workflow process.** The other half: where the code you deployed actually runs, meaning your tools, prompts, and agent logic. It is treated as the untrusted side of the pair, and it cannot act as the deployment or reach its signing key. See [Isolation](/platform/isolation). **Harness.** The agent-runtime component that drives an agent's loop and mediates everything it touches: tools, messages, inference, and storage. It is what keeps grants, keys, and audit records out of the agent's reach. See [Isolation](/platform/isolation). ## Approvals These terms belong to workflow runs. The control plane evaluates the `ask` decision, and the run is what suspends and resumes. See [Approvals](/platform/approvals). **Suspend and park.** When a tool call in a workflow run resolves to the `ask` effect, the call is suspended and parked durably to await a human decision, and the exact call is resumed once approved. **Approval.** A parked decision awaiting a human: approve-once or reject, resolved through the API by whoever holds the grant to resolve it. **Snapshot.** The record captured when a call is parked: the tool's name, its description and input schema, and the actual call arguments, so an approver reviews the real operation rather than an opaque id. ## Provenance These are control-plane terms, covering the agents the control plane runs. [Workbench](/platform/workbench) runs on the control plane and its agents are recorded this way. [Corbits Code](/platform/corbits-code) does not: it persists conversation context to a git-backed store of its own and does not sign it. **Signed commit history.** Conversation context and audit records for an agent running on the control plane are committed to that agent's own git repository and cryptographically signed, so a commit altered after the fact no longer verifies. The signing keys belong to the hub and to each sidecar rather than to individual agents. Treat this as a verifiable record of what was written, not as an audit trail you can query: a run's audit records are deleted when the run ends, and the control plane exposes no route for reading them. See [Guardrails](/platform/guardrails). # Intro to Corbits Source: https://docs.corbits.dev/getting-started/intro Corbits is a platform for deploying secure, auditable agents with organizational guardrails: control, audit, and observability over what your agents can do. ## What is Corbits? Corbits is a platform for **deploying secure, auditable agents with organizational guardrails**. It's the run, audit, and manage layer that turns a promising agent into something you can put in front of real work, with control over what agents can do, an audit trail of what they did, and observability into how they're behaving right now. Building an agent is the easy part. Running it safely is where Corbits comes in: the right permissions, a record you can hand to security, and the ability to shut it down when it goes wrong. ## Start here The layered platform (apps, control plane, and agent runtime) and how they fit together. How guardrails work: what authorizes a credential, a tool, or your data, decided separately for each. Start here if you're evaluating for security or compliance. The standalone coding-agent CLI, built on the platform's runtime primitives and guarded by the same enforcement discipline in its own process. The multiplayer workspace for humans and agents, sharing benches and conversations. *** ## Support Join hundreds of developers building with Corbits and speak with the team directly. # Durable approvals Source: https://docs.corbits.dev/platform/approvals How the control plane suspends an agent when an action needs human approval, parks the call durably, and resumes the exact call once approved, surviving process crashes and reconnects. When a grant resolves to `ask`, the agent does not fail and it does not guess. The control plane suspends the call, parks it durably, waits for a human decision, and then resumes the exact call that was paused. This is the durable approval substrate: the mechanism a human-in-the-loop control needs to stay trustworthy under real conditions, including process crashes and network reconnects. This page describes the **control plane** and the agent runtime beneath it: the layers that evaluate the `ask` decision, park the call, and resume it. [Workbench](/platform/workbench) surfaces the pending ones in its Activity band, where an approver resolves them once each, but the parking and resuming described here are not app features. The `ask` decision itself, and who may resolve it, are covered in [Guardrails](/platform/guardrails). ## The `ask` decision suspends the call The grant engine's effect decides what happens to a tool call: | Effect | Outcome | | -------- | -------------------------------------------------- | | `allow` | The call proceeds. | | `deny` | The call is blocked. | | `ask` | The call is **suspended** and parked for approval. | | no match | The call is blocked, fail-closed. | `ask` is the effect that suspends. The call is parked and the agent's turn pauses cleanly, and the model is never handed a refusal it could try to work around. ## The lifecycle of an approval At the moment of suspension the control plane captures an approval snapshot: the tool's name, its description, its input schema, and the **actual arguments** of the call being made. The approver reviews the real operation, not an opaque id. These fields are captured at suspension and stored with the approval, so the record is complete the instant it exists. The suspended call is persisted, not held in memory. Two records are written in one transaction: an `approval` row and a correlation that ties the eventual decision back to the exact parked call. An approval's status is `pending`, and resolves to one of `approved`, `rejected`, `timeout`, or `expired`. Because the park is durable, the pending approval outlives the process that created it. A decision is made through the API: approve or reject. Two properties keep this correct. It is **exactly once**: the resolver claims the correlation and flips the approval status in a single transaction, so a redelivered decision cannot resolve the same approval twice. And it **leaks no ids**: an approval id from another tenant is reported as not found before authorization runs, so a caller never learns a foreign id exists by getting a different error. Approval does not ask the model to try again. The run **re-dispatches the exact call it parked**, with the snapshot arguments, so the approved operation is the one that runs. A one-shot, in-memory token lets that call clear its own gate once and only once. The agent keeps its place rather than re-inferring and hoping to reissue the same call. Who may resolve an approval, and how visibility is scoped, is part of the grant model: resolving is itself a grant-gated action, it is pull-based, and nothing is pushed to a human. That is covered under the `ask` effect in [Guardrails](/platform/guardrails). ### Rejection and timeout do not strand the agent A rejected or timed-out call does not leave a dangling request in the conversation. The control plane closes the open tool call with a synthetic error result and lets the model infer once more, so the agent continues from a coherent history instead of a stranded one. ## Durable under failure The substrate is built to survive the failures a long-running approval will actually meet. * **Child crash.** If the process running the agent dies while a call is parked, a fresh run re-drives its durable log and re-offers the same park. The pending approval is not lost with the process. * **Hub reconnect.** When a supervisor reconnects, it re-queries its durably parked correlations and re-registers them. The hub deduplicates on a unique constraint, so a reconnect cannot create a second copy of the same pending approval. ## Resolving through the API Approvals are resolved through the tenant-scoped API under `/api/tenants/:tenantId/approvals`: | Method and path | Purpose | | --------------------------- | ------------------------------------------------------ | | `GET /` | List pending approvals (scoped by the caller's grant). | | `GET /:approvalId` | Read one approval and its snapshot. | | `POST /:approvalId/approve` | Approve the parked call. | | `POST /:approvalId/reject` | Reject it. | The admin UI has a list view and a detail view, and **the detail view is read-only by design**: it shows the snapshot and status but carries no approve or reject control. Resolving is API-only. ## What this substrate does not do Documenting the control means documenting its edges. Today, on the agent-step path: * **There is no standing "approve always."** The control plane resolves an approval as approve-once or reject; the API rejects `scope: "always"`. No app supplies a durable auto-approval over this path. [Corbits Code](/platform/corbits-code)'s persistent "always allow" is its own in-process gate against locally stored approvals, not a resolution of anything parked here. * **Approvals are pull, not push.** Nothing is routed, assigned, or notified to a human. Approvers find pending work by reading the list, and the appropriate approver is defined by who holds the resolve grant. No app adds an inbox or notifications over this queue. * **There is no approval deadline.** An agent-step suspend parks with no timeout and holds indefinitely. The reactor's own in-process gate has a one-hour default, but that governs an in-process wait, not the durable park, and nothing populates a per-approval deadline on this path. * **The UI cannot resolve.** The detail page is read-only; resolution is API-only. * **It carries approvals only.** The correlation machinery currently supports a single kind of signal, the approval. It is a durable approval substrate, not yet a general signal system. * **A failed decision delivery is not retried.** The decision is persisted, but redelivering it to a parked run after a failed push is deferred. **"What if nobody approves?"** The call holds. An agent-step approval parks indefinitely and waits: it is never silently allowed, and it is not auto-expired on this path. It stays pending until a human approves or rejects it. # Corbits Code Source: https://docs.corbits.dev/platform/corbits-code Corbits Code is a terminal-based coding agent built on the Corbits agentic platform: the flagship example app that proves the runtime primitives in production. Corbits Code is a single-process, terminal-based coding agent that plans, writes, and tests code locally on your machine. You give it a task in plain English and it works autonomously, reading files, writing code, running tests, and driving a feature to completion. It runs on the model of your choice: Claude, GPT, Gemini, or any other model served over an OpenAI-compatible endpoint. It is deeply extensible, through MCP servers, hooks, plugins, skills, and a fleet of specialist sub-agents. It is also the clearest proof that the Corbits agentic platform holds up under real load. Corbits Code is not a demo stub: it is a production coding agent assembled entirely from the platform's runtime primitives, then layered with the discipline, safety, and UX that make an agent trustworthy. If you want to see what you can build on the platform, this is the reference. Corbits Code is built on the same Corbits/Interchange **runtime primitives** documented across the [platform overview](/platform/overview): the agent loop, inference, tools, and persistence. It is a **consumer** of those primitives, not a fork, and the same building blocks are available to you. Its guardrails, though, are **layered by Corbits Code**: a permission, secret, and authorization system enforced as tool middleware in its own process. They are not the control plane's credentials and grants. ## Install Homebrew, on macOS and Linux: ```bash theme={null} brew install corbitsdev/tap/corbits-code ``` The CLI binary is `corbits`. Upgrade later with `brew update && brew upgrade corbits-code`. To run from source you need [Bun](https://bun.sh) 1.2 or newer: ```bash theme={null} git clone https://github.com/corbitsdev/corbits-code.git cd corbits-code bun install bun run start ``` `bun run build:bin` produces a standalone `dist/corbits` you can put on your PATH. ## Run it Point Corbits Code at a repository and describe the work. It launches a full-screen terminal UI seeded with your task and starts implementing. ```bash theme={null} corbits "Add JWT auth to the API" ``` From there you steer in chat: answer the agent's clarifying questions, approve consequential actions, and follow along in the live event log as it edits files and runs commands. ## What makes it different Most coding agents stall. They re-read the same files, drift from their own plan, or never signal that they are done. Corbits Code replaces the open-ended chat loop with a deterministic **event loop** governed by a custom reactor director, a policy layer that watches every turn and decides what happens next. When the agent tries to end a turn with tasks still open, the director rewrites that ending into another inference pass carrying a pointed reminder, up to three times, instead of letting a run stop half-done without saying so. The shared [Interchange runtime](/platform/overview) spills oversized tool results to the session blob store and leaves a URI in their place. Corbits Code makes that spill usable: it wires a blob reader into `read_file`, rejects the URI on tools that cannot resolve it, and instructs the model to re-open a prior result by reference rather than re-reading the file it came from. The agent tracks its own work as a task list through a dedicated tool. That list lives in director state rather than only in the chat transcript, so it survives context shifts across a long run. The Interchange reactor processes one event at a time and yields a single next action. Corbits Code supplies the policy that picks it: a director written in code, not a suggestion buried in a prompt. ## Safety you can't talk it out of Corbits Code enforces safety at the tool layer, as middleware wrapped around every tool call, not as advisory text in a prompt the model can reason around. One layer owns each constraint, and the agent cannot evade a constraint by rewording its request. Read-only tools (reading files, searching, listing directories) run freely. Every consequential tool (file writes, edits, shell commands) is gated. You approve with **Allow Once** or **Allow Always**, scoped to a file, a directory, or a command shape. "Allow Always" choices persist per repository, so repeat actions stop interrupting your flow. Sensitive files are protected by a single hard deny covering two surfaces: path-keyed tool arguments and shell command strings. Both are blocked outright, and the deny runs *before* the permission gate, so it holds even under `--dangerously-skip-permissions`. **Path arguments.** A tool call whose path argument names a sensitive file is denied: `.env` and its variants, `.dev.vars`, anything under `.ssh` or `.gnupg`, `id_rsa` and its ecdsa / ed25519 / dsa siblings, `.pem` / `.p12` / `.pfx` certificates, `.netrc`, `.npmrc`, `.pgpass`, `.htpasswd`, `.git-credentials`, `.aws/credentials`, and Corbits Code's own `.corbits/settings.json`. This covers reads, writes, edits, deletes, and searches pointed at one of those files. Template files like `.env.example` are exempt. **Shell.** A `run_shell` command is tokenized and every path-like token is checked against the same denylist, so `cat .env`, `bun --env-file=.env run …`, and `FILE=.env cat $FILE` are all denied the same as a direct read. There is no operator approval and no "Allow Always" for a secret-path shell command: it is refused. Detection here is token matching, not sandboxing. It defeats quoting and the common assignment and redirection forms, but a path assembled at runtime (for example `F=.en; cat ${F}v`) is not recognized as one. **What the deny does not do.** It keys on the path token, not on file contents, so it is not a content filter. A search scoped at a surrounding directory can still surface matching lines from a sensitive file inside it, such as a `.pem` under `certs/`, because the search argument names the directory, not the secret file. It also does not cover the Codex and xAI OAuth token files described under Configuration and credentials below: only the literal `settings.json` filename is matched. A curated set of unrecoverable commands is blocked before it runs: filesystem creation (`mkfs`), raw disk writes (`dd` to a device), recursive deletes that target the filesystem root, your home directory, or a system tree, writes that clobber system paths like `/etc`, privilege escalation (`sudo`), power-state changes (`shutdown`, `reboot`), fork bombs, and piping a network download straight into a shell (`curl … | bash`). Like the secret guard, this cannot be overridden, not even with `--dangerously-skip-permissions`. Everyday destructive commands like `rm -rf ./build` aren't hard-denied here; they go through the permission gate like any other consequential command. Path arguments are resolved against the working directory; paths that escape it are blocked. After every write or edit, the file is re-read and compared to confirm the change actually landed. Consequential actions run through an ask/auto behavior at the permission gate, so you decide how much to approve interactively versus let run. That setting never downgrades the secret guard or the catastrophic-command guard: both are hard denies that hold regardless of how much you choose to auto-approve. ## Resume where you left off Conversation context persists to a git-backed store, and director state (turns used, plan, tasks, files read) is snapshotted alongside it. When you relaunch in a repository, Corbits Code can present a **session picker** in the TUI so you pick up a prior run from exactly where it stopped: no lost context after a `Ctrl+C`, a crash, or a walk away from the desk. ## The sub-agent fleet Corbits Code dispatches specialist sub-agents for self-contained work, each on its own inference source. They form a **fleet**: a live tree of worker sessions the lead agent spawns, waits on, interrupts, and resumes while they run. The fleet is layered by Corbits Code rather than inherited, implemented under the app's own `src/subagent/` tree. ### Authority is a tier, not a prompt Every profile carries one of three tiers, and the tier decides what it may do to the rest of the tree. Tier 1, the primary agent. Full fleet control over the whole tree. Tier 2. May manage only its own descendants, never a sibling and never anything above it. Tier 3, the workers. Each carries an explicit tool allowlist sized to its job, finishes with the report envelope, and mounts no fleet verbs at all. The check runs where tools are assembled, not in prompt wording, so a leaf is never handed a fleet verb it could be talked into using. This is the same pattern as the safety middleware above: one layer owns the constraint, and rewording the request does not move it. ### Picking a specialist Dispatch by intent and take the default, or name a profile directly. The intent defaults are `implement` to **build**, `explore` to **explore**, `plan` to **plan**, and `review` to **critique**. Naming an id that is not registered fails with the list of valid ones rather than quietly falling back to a general agent. The registry holds sixteen profiles at `v0.3.1`. Most are leaves with a narrow tool envelope and a distinct lens: **critique** reviews for correctness against the brief and cannot finish a run without having read the code it judged, while **greybeard** judges soundness, constraint ownership, and backward compatibility, and is the one profile besides the primary that can manage a subtree of its own. You can add your own profiles in the project tree or through plugins, and the agent picks the right specialist for the job. ### Working a live fleet Workers are sessions you can steer, not fire-and-forget calls. | Verb | What it does | | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | | `spawn_agent` / `wait_agents` | Start workers and collect them. These replace the older fused `task()` call, which still works but is deprecated. | | `interrupt_agent` | Stop waiting on a worker's turn and mark the session interrupted, keeping its context for a follow-up. A tool call already in flight keeps running. | | `followup_task` | Send new work into an existing session, reusing its prior context and tool output. | | `resume_agent` | Make a finished, retained worker addressable again so `followup_task` can send it new work. | | `close_agent` | Tear a session down, under a cleanup deadline so a wedged worker cannot hang the call. | | `read_agent_trace` | Read a worker's trace to see what it actually did. | ### How a run ends A worker runs until it produces a **report envelope**: a structured Summary, Findings, Blockers, and Paths. Short of that, it stops for one of four recorded reasons: it was cancelled by the operator, it hit an opt-in wall-clock deadline, it stalled after a long silence with no tool activity, or it narrated an answer instead of writing an envelope. None of those is a turn count. `v0.3.0` removed turn budgets outright, including the `maxTurns` setting, the per-profile cap, and the argument on the dispatch tools. A worker is bounded by the clock, by its own completion, or by you, and never by a number of inference passes it was allowed to spend. ## Integrations Connect Model Context Protocol servers over stdio (launched as a subprocess) or HTTP (a remote Streamable-HTTP endpoint, authorized via OAuth). Configure them per repo and inspect connected servers with `/mcp`. Config-driven `postTurn` and `postRun` hooks (shell or TypeScript) run automatically. `postTurn` receives aggregated turn context; `postRun` receives a run summary. Discovered per repo and globally, and toggled with `/hooks`. Opt-in capabilities: web search, additional tools, workflow recipes. Plugins are discovered per repo, from `.corbits/plugins/`, and globally, from `~/.corbits/plugins/`. Enabling one is a global choice rather than a per-repo one, because the enable flag travels with any credentials the plugin declares and those live only in the global settings file. Skills are Markdown capability packages the model loads on demand rather than commands you invoke, resolved from enabled plugins first and then from the repo you are working in. An extensible in-TUI command surface: `/model`, `/settings`, `/permissions`, `/plugins`, `/hooks`, `/mcp`, `/cost`, `/status`, `/clear`, and more. Plugins can register their own. ## Configuration and credentials Corbits Code can run on any OpenAI-compatible endpoint, so you bring the model you want: OpenAI, a local Ollama or vLLM server, or an OpenAI-compatible gateway like OpenRouter that fronts Claude, Gemini, and hundreds more. The Corbits runtime speaks to the major model providers natively; Corbits Code reaches models through the OpenAI-compatible protocol. Corbits Code reads its provider and credential configuration from settings files, plus a per-provider token file for OAuth-based providers: Global settings live in `~/.corbits/settings.json` (providers and credentials). A per-repo `.corbits/settings.json` handles **selection only**: it chooses a provider and model and **rejects** stored secrets. Codex tokens live in `~/.corbits/codex-auth.json` and xAI tokens live in `~/.corbits/xai-auth.json`; neither is ever written to `settings.json`. There is no environment-variable override and `.env` files are not loaded, so a stale or exported key can never silently shadow the configured provider. The two `settings.json` files sit on the secret-guard denylist, so the agent cannot read its own API-key credentials through a file tool or a shell command; the OAuth token files are not on that denylist. ## Built on the platform Corbits Code is the honest test of the platform: everything the runtime provides, it composes; everything it adds sits cleanly on top. That layering is the story. * **Agent loop**: the event-driven reactor and agent lifecycle * **Inference**: the runtime's inference primitive, run here over OpenAI-compatible sources * **Tools**: POSIX shell, file read/write/edit, grep, and search * **Persistence**: git-backed context and state storage for resume * Custom **reactor directors** for stall detection, plan adherence, and completion discipline * A **permission, secret, and authorization** system enforced as tool middleware * A **tiered sub-agent fleet** with authority enforced at the tool-mount point * An **Ink-based terminal UI** with a live event log, diff view, and modals * Workflows, hooks, plugins, and skills The same primitives that make Corbits Code fast, safe, and resumable are the ones the platform exposes to you. The runtime primitives Corbits Code is built on, and how they fit together. The platform's Credentials and Grants model: how the control plane keeps agents in bounds. The multiplayer workspace for humans and agents, where a team authors and runs its agents together. # Organizational guardrails: Credentials & Grants Source: https://docs.corbits.dev/platform/guardrails What authorizes an agent to reach a credential, a tool, or your data, decided separately for each: the credential and grant model behind enterprise control and audit. When you run agents across an organization, two questions never stop mattering: what can each agent reach, and who authorized it to reach that. Corbits answers both, but not with a single rule. What may use a credential, what may invoke a tool, and what may read your durable state are decided by different machinery, in different places, at different moments. This page is where each of those is written down. If you lead an AI org, it shows you how to hand agents real power without handing over the keys. If you own security or compliance, it shows you where authority comes from, where it stops, and which controls do not exist. This page spans two layers, so read it as a signpost rather than a scope: nothing here inherits a layer, and each section names the one it describes. The **control plane** resolves credentials, materializes grants, and gates the API. The **agent runtime** decides, while an agent is running, whether a given call may proceed. [Workbench](/platform/workbench) runs on both and inherits what they enforce. [Corbits Code](/platform/corbits-code) does not run on the control plane, so the credential and grant model described here does not govern it, though it builds on the same agent runtime. Both layers are described at `v0.3.0`. ## The vocabulary A few nouns carry the rest of the page. The secrets an agent uses to authenticate with an outside service: an API key, an OAuth token, a certificate. Owned and stored by your organization, and delivered to a deployment by the control plane rather than looked up by the agent. A row saying that some principal may take some action on some resource, and whether the answer is allow, deny, or ask. Grants are what most, though not all, of the decisions below are made from. A **principal** is an identity within a tenant: the join between an entity and that tenant. An entity is either a person or a workflow, and what this page calls an agent is deployed and launched as a workflow. The API still reports a third kind, `agent`, left over from a retired model; nothing creates one, and any that survive hold no authority. A person's principal is their user account in that tenant. A running workflow has a principal of its own, and that is the identity its authority is resolved against. A principal by itself grants nothing; it only establishes that the entity exists in the tenant. A **tenant** is the isolation boundary. It has a nullable `parent_id`, so tenants form a hierarchy of parents and **sub-tenants**. Credentials and grants behave differently across that hierarchy, and the difference is the one piece of vocabulary readers most often get backwards: a credential is reachable from a tenant up its ancestor chain, so a child can use one its parent owns, while grants are collected within a single tenant and do not inherit in either direction. ## How the hierarchy carries each one The walk-up is worth stating concretely, because it is the mechanism behind every "a child tenant can use this" claim below. When the control plane resolves a credential, it accepts one that sits anywhere on the launching tenant's ancestor chain. Store an organizational credential at the parent tenant and every descendant can use it. Define your integrations once for the whole org. A child tenant can **shadow** a parent's credential by creating one with the same name; the child's takes precedence within its scope. Names are unique within a tenant, which is what makes name-based shadowing work. Grants do not walk the hierarchy in either direction. The control plane collects a principal's grants **within a single tenant**, so a grant stamped at a parent tenant does not reach a child, and a parent tenant's policies do not bound what a child tenant can grant. Inheritance therefore spreads credential *availability* only. Authority must be granted in the tenant where it is used. ## Credentials A credential is a runtime secret an agent uses to authenticate with a **provider**: GitHub, OpenAI, Slack, Google Drive, an internal deployment service, an SSH bastion. Every credential belongs to a provider; there are no provider-less credentials. The provider definition is what tells the control plane how to handle the credential: its refresh behavior, its authentication method, its scope model. The credential's type (API key, OAuth token, certificate) is a property of the credential, **not** something the agent chooses. From the agent's side, it needs "access to service X," and the control plane figures out the authentication mechanism. Agents do not select or negotiate credential types. A credential can optionally be owned by a specific principal. One with no principal owner is **organizational**: shared across the tenant and managed by administrators, the company's OpenAI key or its deploy token. One with an owner is **personal**, typically created through an OAuth flow. That distinction is not cosmetic; it is the whole authorization rule for two of the classes below. **Agents never look a credential up.** The control plane resolves the credentials a deployment needs and delivers them to the process that runs it. The agent cannot reach into a store and pull a secret it was not given. Resolution is confined to deploy in practice. A rotation or a catalog edit does re-resolve model-provider credentials and push them, but only to a single-agent shape this release does not launch, and no equivalent producer exists for tool credentials, so a deployed workflow keeps the material it was given until it is redeployed. Deleting a credential removes the grants written against that exact credential in the same transaction. A coarse `credential:*` role grant is untouched, and it matches every credential in the tenant, including any created later. That grant reaches the control-plane API, where roles are consulted; it does not reach a running agent, whose grant set is read from its own principal. A credential a model provider still references is refused rather than deleted, which stops an operator removing one out from under a running catalog by accident. Read that alongside the model-provider class below, because the two combine badly. Deletion is blocked while a provider references the credential, setting its status to `revoked` does not stop that path resolving it, and a credential's owner cannot be changed after it is created. Withdrawing one takes two steps in order: repoint or remove the model provider that references it, then delete the credential. Credential secrets are encrypted at rest. The control plane seals a secret on every write path before it reaches the database, and each ciphertext is bound to its own row and column, so a value lifted from one row will not decrypt in another. Today that binding is AES-256-GCM under a single operator-provided key. It is not KMS-managed or envelope-encrypted, and we do not claim it is; the encryption seam is pluggable so a KMS implementation replaces it without touching a call site. ## Grants A grant carries three fields: | Field | What it is | Examples | | ---------- | ------------------------------------------- | -------------------------------------------------------------- | | `resource` | A glob pattern for what is being authorized | `tool:acme-tools:bash`, `credential:crd_gdrive`, `tool:*`, `*` | | `action` | The operation verb | `invoke`, `read`, `use`, `*` | | `effect` | The decision | `allow`, `deny`, `ask` | A grant attaches either to a **role** (a named bundle of grants scoped to a tenant) or directly to a **principal**. System roles (owner, admin, member) are created with every tenant; admins can define custom roles on top. ### How a grant set resolves Given a set of grants and an operation, the evaluator ranks them the same way everywhere it runs. What differs between the classes below is *which* grants are in the set, not how they are ranked. Drop expired grants, then keep only those whose `resource` and `action` patterns match the operation. A grant carrying conditions is skipped unless the caller supplied a registry that can evaluate them. Specificity is the count of non-wildcard characters, with a large bonus for a pattern containing no wildcard at all. The most specific matching grant wins outright. Between two grants of the same specificity, **deny beats ask beats allow**. If nothing matches, the evaluator returns no decision and the enforcing layer fails closed. Specificity is decided before effect, so **a specific `allow` overrides a broader `deny`**. A blanket `*`/`*` deny does not revoke a grant written against an exact resource. To withdraw access, remove or override the specific grant; adding a broad deny above it will not do it. An `ask` effect does not deny and does not prompt in line. The agent runtime suspends the call, with a one-hour default deadline, and the control plane records a pending approval against it. The control plane pushes no prompt and assigns no one: resolving an approval is itself a grant-gated action, evaluated like any other. An approver is any principal whose grant allows `resolve` on the approval. That grant's breadth sets what they can reach: a tenant-wide `approval:*` grant lists the whole pending queue, while a grant covering just one agent's approvals cannot list and instead fetches each one by its id. A control-plane approval is one-time: it authorizes that action, not future ones. How the blocked call is parked durably, resolved exactly once, and resumed without re-running the agent is covered in [Approvals](/platform/approvals). Durable "approve always" is not one of those outcomes today: the control plane's approval path is approve-once-or-reject and does not yet support `scope: "always"` (it returns `unsupported_scope`). No app supplies a durable auto-approval over that path either. [Corbits Code](/platform/corbits-code) does offer an "always allow" that survives a restart, but it is a different mechanism at a different layer: its gate runs in its own process against approvals it persists locally, and it never resolves a control-plane approval. Nothing routes or notifies an approval parked here either: the queue is pull-only, and an approver finds pending work by reading it. ## What is protected Six things are governed, and they are not governed the same way. The table is the summary; the sections below it carry the detail, and each one states what it does **not** check. | What | Layer | Decided from | Can an operator deny it? | | -------------------------- | ------------- | ------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | | Tool invocation | Agent runtime | The run's grant set, frozen at deploy from the workflow's own declaration | Not at deploy, and not the effect; only by editing the run's grants; see below | | Workflow effects | Agent runtime | The run's grant set | Yes | | Tool credentials | Both | Tenant ownership, then a `use` grant at the point of use | Only if the grant exists; see below | | Model-provider credentials | Control plane | Nothing, for a deployed workflow: the deploy request carries the key | No; see below | | API surfaces | Control plane | The caller's grants plus the grants of every role they hold | Yes | | Durable state | Control plane | Bearer-token claims intersected with a resolved grant verdict | Yes | ### Tool invocation **Layer:** agent runtime. **Decided from:** the run's grant set, evaluated in the process running the workflow, materialized from the snapshot frozen when the deployment was created. **When:** on every invocation. **Withdrawal:** remove or override the tool's grant on the run's principal, which reaches the deployment at its next trigger. See the warning below. Every tool call is checked against `tool:` with action `invoke`, and a call with no matching grant is blocked. The three outcomes are allow, block, and `ask`, which suspends the call for approval rather than refusing it. **What it does not check:** attachment. Nothing filters which tools a step may load; the check happens when a tool is called, not when it is attached. **No operator input enters this decision.** Deploying a workflow probes what it declares and freezes exactly that surface as the run's grant set. There is no approval set to supply and no route that accepts one, so the grants a deployment holds are the ones the workflow asked for. The effect on each `tool:` row is taken from the tool's own static declaration in the same way: a tool declaring an approval mark carries `ask`, and every other tool carries `allow`. Read the fail-closed rule with that in mind. A definition with no frozen snapshot does fail closed at its next trigger, and a call with no matching grant is blocked, so the mechanism is real. What it is measured against is the workflow's own declaration rather than a policy your organization wrote. The levers you have are not deploying the workflow, and editing the grant rows on the run's principal afterwards, which reach the deployment at its next trigger rather than the call in flight. ### Workflow effects **Layer:** agent runtime. **Decided from:** the run's grant set, using the same evaluator as tool invocation. **When:** at each action. **Withdrawal:** removing the grant reaches the deployment at its next trigger. A workflow action declaring a capability is checked in two places: that the capability is in the step's declared set, and that a grant allows `invoke` on `effect:`. Both fail closed. **What it does not check:** whether those two agree. Both read the same declaration, since the control plane mints the `effect:` grant from the same `requires` set the runtime later checks against, and the minted effect is always `allow`. Treat this as one declaration enforced at two points rather than as two independent controls. An operator can still deny a specific effect, because a `deny` at the same specificity beats the minted `allow`. ### Tool credentials **Layer:** the control plane resolves and delivers; the agent runtime decides whether a tool may open the handle. **Decided from:** tenant ownership first, then a `use` grant at the point of use. **When:** ownership at deploy, when the binding is resolved and the material delivered; the grant when a tool opens the handle. **Withdrawal:** remove the `use` grant, which reaches the deployment at its next trigger. The control plane matches a definition's binding against the tenant's **active** credentials for the named provider, anywhere on the ancestor chain, and delivers the material. That delivery carries no authority. A tool package then cannot open the handle unless the run holds a `use` grant matching the credential resource, and a grant may carry a condition naming the package entitled to resolve it. Read that condition as scoping which package may ask, not as isolation between packages: the delivered material is deployment-wide, and one package's code can reach another's secret without going through the gate at all. **What it does not check:** scopes. A binding carries no scope field, so the scope-matching machinery is never reached on this path. Two limits worth sizing your trust against. Nothing mints the `use` grant automatically from a binding, so unless an operator or a definition author creates it, a tool-credential resolve fails closed. And the gate is not a confidentiality boundary. A tool package that clears it receives a mediated handle rather than the raw secret, but credential material also reaches tool code by routes in the agent runtime that no grant governs. Treat any tool package you deploy as trusted with every credential in its deployment, and see [Isolation](/platform/isolation) for the boundary you have to supply yourself. ### Model-provider credentials **Layer:** control plane. **Decided from:** for a deployed workflow, nothing at all. The request that creates the deployment carries the key. **When:** at deploy. **Withdrawal:** redeploy with a different key, or rotate at the provider. This is the class where the shape of the rest of this page does not apply, so it is worth stating flatly. Creating a deployment supplies the inference sources it will use, and each one carries its API key in the request body. Nothing resolves that key against the organization's credentials, because it never was one of them. The only check it passes is that its provider and model appear in the deployment's approved set, and that set is the deployment's own declaration. The control plane does keep a tenant credential catalog, with the ownership rules you would expect: a credential the organization owns is reachable from the owning tenant and every descendant along the ancestor chain, no grant of any kind is consulted, and a credential owned by a principal rather than the tenant is refused. Those rules are real. They are not what governs a deployed workflow's model access. **What it does not check:** on the deploy path, anything. There is no credential row, so there is no status, no expiry, and no owner to check. On the catalog path, status and expiry are unread, so a credential marked `revoked` still resolves. ### API surfaces **Layer:** control plane. **Decided from:** the calling principal's own grants plus the grants of every role they hold, collected within a single tenant. **When:** on every request. **Withdrawal:** immediate, since grants are collected per request. This is the one class where roles carry authority. Route groups across the control-plane API are gated on a grant for the resource and verb they expose, and two surfaces that mint no grants at all are mounted as a default deny. Acting principals here are people: the tenant middleware resolves the caller to a user principal, so a workflow does not reach the API this way. **What it does not check:** this is the class where a missing gate is a route that simply lacks one, rather than a rule with an exception. Treat the grant model as what the control-plane API is *designed* around rather than as a proof that every route is covered. ### Durable state **Layer:** control plane and agent runtime, since the same substrate is constructed in the sidecar too. **Decided from:** for a bearer-token holder, the token's claims intersected with a grant verdict; for the platform's own components, the principal's kind alone. **When:** on most repository operations. **Withdrawal:** revoke the token, or remove the grant behind the verdict. Both are read per request, so both are immediate. Run event logs, agent state, workflow assets, skills, and the package registry live in a git substrate with its own authorization model, layered over the same grant evaluator the control-plane API uses rather than a separate one. A bearer-token holder reaching an agent-state, skill, workflow, or workflow-run repo has the token's permitted actions, its ref pattern, and its expiry intersected with that verdict. The platform's own principals skip that intersection: a hub write is allowed outright, and a sidecar, supervisor, or workflow process is decided by principal kind and action alone. **What it does not check:** the resource a token was minted for. A token narrows the verbs, the refs, and the lifetime a holder may use, but not which object they may use them on. Push-time handlers do add some scoping, though less than the shape suggests: a workflow process is confined to its deployment rather than to one run within it, and the check that a pushed event's origin matches its pusher covers cancellation events only. ## Where requirement-sourced authority comes from This section describes one control-plane mechanism only: how a definition's declared **grant requirements** become rows on a run's principal. Tool invocation, workflow effects, model-provider credentials, durable state, and the control-plane API are all decided without reference to any of it. An agent definition does not ship live grants. It ships requirements. A definition declares credential requirements and grant requirements separately, and a grant requirement can name only `creator` or `invoker`; any other source is refused. The definition author delegates authority they themselves hold. This is the setuid model: the author's authority travels with the definition, and they cannot delegate what they do not have. The person triggering the deployment supplies it, and they cannot pass along authority that was itself delegated to them by an invoker. Materialized as a grant that expires 24 hours later. **Requirements resolve once per deployment, not once per launch.** The first trigger materializes the grant set; every later trigger reuses it rather than recomputing from the new caller. Three consequences a compliance reader should plan around. Revoking a creator's or invoker's authority does not narrow what an already-deployed agent holds. A later trigger by a different person runs under the first invoker's delegation, not their own. And an invoker-sourced grant expires 24 hours after that first materialization and is not renewed automatically, so a long-lived deployment quietly loses its invoker-delegated capability a day in. Redeploying does re-resolve, because a redeploy mints a new run. That, rather than a later trigger, is what picks up a revocation. The control plane re-reads and re-ships the grant rows themselves on every trigger, so deleting a row does reach the deployment at its next one. What does not re-run is the check against the delegating party's live authority. ## Grant strings that gate nothing, and one that does The control plane records grant-shaped strings for everything a workflow declares it will touch. Four of them constrain nothing afterwards: `director:`, `capability:`, `mail.address:` and `mail.send:`. The membership gate that would check them has no caller, and the one check that does sit on the deploy path skips the comparison, since with no operator set to measure against the probe's own surface would stand on both sides of it. Those four are a description of what a workflow said it would touch, and not a control. `inference.source:` is the exception, and what it does is narrow. When the control plane pins a step's model it refuses a `(provider, model)` pair absent from the frozen set. For a source the workflow declared that always holds, so the check never shows. It bites on the fallback path, where a step with no resolvable preference would otherwise pin to a default the workflow never named. Of the strings recorded at deploy, `tool:`, `effect:` and `credential:` are the ones consulted again at the point of use, alongside the control-plane resource prefixes. ## A worked example One agent in the **marketing** sub-tenant of an org: written by Ali, deployed by Dana, triggered later by Sam. It has an HTTP tool, a Google Drive credential bound to that tool and stored at the parent tenant, an inference model drawn from the org catalog, and a step that sends mail. Grouped by when each decision is made, because that is what decides whether you can change it later. **At deploy.** Dana's call is gated on a control-plane grant, and her roles count toward it. What the deploy then freezes is what the workflow declares, not a set Dana chooses. The Drive credential resolves here, matched against active tenant-owned credentials on marketing's ancestor chain, settled by ownership with no grant consulted. The inference source does not resolve at all: Dana's deploy request carries the model's API key, and marketing's credential catalog is not consulted for it. **At the first trigger.** Sam triggers the deployment, and the definition's grant requirements resolve: creator-sourced ones against Ali's live authority, invoker-sourced ones against Sam's, written onto the run's principal. Every later trigger reuses that set. If Priya triggers it tomorrow, the run still holds what Sam delegated. **At each call.** The agent runtime checks the HTTP tool against `tool:`, and the row that decides is the one Dana's deploy froze from the workflow's own declaration, carrying whatever effect that tool's author asked for. Opening the Drive handle needs a `use` grant on the run. The mail step is checked against its `effect:` resource. Writing the run's audit record is decided against the process's bearer claims and path scope instead, by different machinery again. Four kinds of decision, three moments, and not one of them turns on a policy your organization authored. Now try to withdraw something. Revoke Ali's authority and the running deployment keeps what it materialized, because requirements resolved at Sam's trigger and are not recomputed. Set the Drive credential to `revoked` and nothing changes for this deployment either: its material was resolved at deploy, and no push replaces it. Add a blanket `deny` and the HTTP tool still runs, because the specific row the deploy froze outranks a broad one; a `deny` naming that exact resource on the run's principal does reach it. For a deployed workflow, the lever that reliably works is redeploying it. That is the honest summary of everything above: inheritance spreads credential availability, most permissions are decided from grants, and the grants a deployment holds are the ones it asked for. ## Audit and provenance Authorization decides what an agent may do. Provenance records what it did and makes that record verifiable rather than something you take on trust. For an agent running on the control plane, the runtime commits conversation context and audit records on its behalf. All of it lands in a git repository on the sidecar host, keyed per agent for a warm single-step deployment and per run, step and attempt otherwise, and every commit the runtime writes is signed using the standard SSH signature format. An agent repository's initial commit is the exception, created before a signer is attached. The result is a tamper-evident history: any commit altered after the fact no longer verifies, so a recorded action cannot be rewritten without breaking its signature. Two keys do that signing, and neither is per-agent. The hub holds one key and signs the commits it writes, such as an agent's deployed state. A sidecar holds one key per data directory and signs the run commits produced by the workflows it executes. So a signature identifies the component that wrote the commit, not the individual agent behind it, and the agent's own key is used to authenticate it to the hub rather than to author commits. Verification uses standard git. `git verify-commit` checks a commit against the public key that signed it, so you can confirm authenticity yourself, outside the platform. Be precise about where that check runs today: a sidecar verifies the deploy packs the hub sends it, against a hub key it learned from that same deploy rather than an independent anchor, while asset packs and run-restore packs are not verified. Nothing on the hub verifies a commit it receives, and its ingest path takes no verifier at all. Tamper-evidence here is a property you can check after the fact with git, not a gate the control plane enforces on the way in. Two limits matter if you are evaluating this for compliance. The hub mints its signing key at startup, holds it in memory only, and keeps no key history, so a restart permanently orphans the signatures on everything it signed before: no code path can check them again. And the audit records themselves are scratch: a multi-step run's storage is deleted when the run reaches `completed`, `failed` or `cancelled`, while a single-step workflow is kept warm automatically and its records are written somewhere else entirely, a per-agent directory that undeploy does not sweep and nothing else deletes. The durable copy kept by the hub carries turns and metadata rather than the audit records. The control plane exposes no route for reading audit records, sets no retention window, and offers no export. That gap is narrower than it sounds: the hub keeps its own committed, append-only log of a workflow run's orchestration events, separate from the deleted audit records, and a route exists to read it back after the run ends. What has no query surface is the per-call authorization record, not the run itself. ## Transport and supply chain Two controls sit underneath the credential and grant model. Neither decides what an agent may do; both bound who can present themselves as part of the system and what code can enter it. **The sidecar connection is authenticated.** Agent execution happens in a sidecar that connects back to the control plane over a WebSocket. That connection is authenticated on the handshake against the sidecar's own identity token, which is a distinct secret from any credential the sidecar is later given to work with. The control plane stores only an unsalted SHA-256 digest of that identity token, never the token itself. A token the control plane mints carries 256 bits of entropy, so its digest is not searchable; the provisioning script also accepts an operator-supplied token and does not check its entropy, and for that path the property rests on the token you choose. A handshake that does not resolve to a known sidecar is rejected rather than trusted on the strength of what the connecting party claims about itself. This is a per-sidecar bearer secret rather than mutual TLS, layered with per-connection checks that bind a sidecar to the addresses it was allocated and to the repositories it may push. **Tool packages are integrity-checked.** Third-party tool packages ship as npm tarballs and land in a content-addressable cache keyed by the tarball's SRI digest, sha512 in what npm and the control plane produce. That digest is verified rather than merely used as a key: a mismatch throws when the tarball is written and again when it is read back, before anything is unpacked, so a tampered or substituted tarball is never loaded. A tool package shipped as source rather than a tarball is checked against a git tree object instead. This is a property of the **agent runtime's** packaging layer, documented across the [platform overview](/platform/overview), rather than a control-plane authorization decision: it governs which tool-package code can be loaded, while grants continue to govern what that code is allowed to do once loaded. It does not reach the operator-configured adapters the sidecar imports by its own configuration. ## Controls that do not exist Stated plainly, because a reader who infers a control from silence is worse off than one who knows it is absent. * **No rate limiting** anywhere in the control plane. * **No containment of credentials from tool code** by the agent runtime. A tool package can reach credential material the credential gate does not govern, so treat any package you deploy as trusted with every credential in its deployment. * **No secret redaction** by either layer, on agent output, tool results, audit records, run events, or logs. A secret an agent prints is recorded as printed. * **No retention limit on a single-step deployment's audit records.** They are written to a per-agent directory on the sidecar host that survives run termination, survives undeploy, and has no sweeper. Nothing in the control plane can read or delete them. * **No operator approval of a deployment's capability surface.** Creating a deployment freezes what the workflow declares. The control plane exposes no route that accepts an approved set, so nothing narrows a workflow to less than it asked for. * **No permissioning for MCP tools** in the agent runtime, which does not support them today. * **No confinement of your workflow code** by the agent runtime: no filesystem jail, no network policy, no syscall filtering. A tool that reaches the network needs only a grant to be invoked, and neither layer narrows where it may reach. [Isolation](/platform/isolation) covers this in full and is the page to read before a security review. ## How this shows up Where credentials and grants sit in the control plane, harness, and agent lifecycle. The guardrails discipline in a real coding agent: tiered permissions and hard-deny secret guards. The multiplayer workspace for humans and agents, running on control-plane-governed credentials and grants. # Isolation boundaries Source: https://docs.corbits.dev/platform/isolation What separates one agent from another on Corbits: what is on by default, what you set up yourself, and what is not available today. "How does isolation work?" is several questions wearing one word. A running agent is separated from other tenants' data, from the credentials it spends, and from the code you deploy alongside it. Those are different boundaries with different answers, and they are not equally strong. This page states what each one gives you, and what is not on the list. This page covers the **agent runtime** and the **control plane** above it, and describes the current released version. [Workbench](/platform/workbench) and [Corbits Code](/platform/corbits-code) add controls of their own, which are not covered here. ## What you get | What you want | Status today | | ------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | | Your data, credentials, and permissions separated from other tenants | On by default | | Deployed code that cannot act as your deployment or reach its signing key | On by default | | An agent that cannot read your policy, keys, or audit records | On by default | | A container or VM around the machine your agents run on | Yours to run. Treat as required if workflows have shell or filesystem access | | Filesystem, network, syscall, or memory confinement of your workflow code | Not available | The rest of this page explains each row. If you are evaluating Corbits against a security review, the last two rows are the ones to read first. **Run the host isolated. This is the one deployment decision that matters most.** If your workflows use shell or filesystem tools, run the machine hosting them inside a container, VM, or sandbox. Do not run it directly on a host you care about. Those tools hand deployed code the full reach of the account the host runs as, and Corbits does not narrow that reach. The host boundary is the only thing bounding it. Without one, a workflow can read any file that account can read, reach any network the host can reach, and consume whatever the host has. This is a deployment responsibility, not a setting to switch on. Nothing in Corbits enforces it for you. ## The tenant boundary: who can reach it A tenant is the control plane's isolation boundary. Agents, credentials, grants, and roles are scoped to a tenant, and tenants nest into a hierarchy. Credentials resolve up that hierarchy, so a child tenant can use one defined at a parent. Grants do not inherit: authorization evaluates the grants held in the acting tenant. This is the boundary the rest of the docs already cover. See [Guardrails](/platform/guardrails) for the grant model and the [Glossary](/getting-started/glossary) for the vocabulary. ## The trust boundary: what the agent can observe The agent is treated as the untrusted party. It sees its tools, their results, its messages, and model responses. Of its own machinery, the agent runtime exposes none of the following to the agent: * **Your policy.** A blocked tool call returns a generic refusal, not the rule that stopped it, so the agent cannot reason about routing around a control it cannot see. * **Key material.** The agent's keys are held and used on its behalf. The agent cannot export or influence them. * **Audit records.** The agent has no read or write path to the record of what it did. * **Its own history.** Conversation context and audit records live in a store the runtime owns. The agent cannot inspect, branch, or rewrite it. ## The process boundary: what deployed code can reach A running deployment is split in two. A **supervisor** holds the deployment's identity: its signing key, its address on the message bus, and the credentials it was granted. A separate **workflow process** runs the code you deployed, meaning your tools, prompts, and agent logic. The supervisor is the trusted half and the workflow process is not. The channel between them is authenticated in both directions, so neither half can impersonate the other, and a message that does not verify is rejected rather than acted on. What this buys you: if the code you deployed is compromised, it still cannot sign records as your deployment, take over its address, or issue instructions to the half that holds the keys. One limit worth stating, because it is the question a security reviewer asks next. Provider API keys do reach the workflow process. It is what calls your model and tool providers, so the keys for those providers are in its memory while it runs. What stays out of its reach is the deployment's own signing key and its address on the bus. ## What is not available today Corbits does not confine your workflow code at the operating-system level. Specifically, there is no filesystem jail, no network policy, no syscall filtering, and no memory or CPU limit applied to the process running your code. If your workflow spawns a shell, that shell has the reach of the account the machine runs as. This is why the deployment recommendation above is not optional in practice. The only host-level confinement available today is the one you bring: run the machine hosting your agents inside a container, VM, or sandbox. If workflows have shell or filesystem access, treat that as a requirement of running Corbits rather than a hardening step to get to later. Note the granularity when you do. An isolated host confines everything on it as a group, rather than drawing a boundary around each workflow, so workflows sharing a host are not isolated from each other. Corbits is built so a per-process boundary can be added later without redesigning the runtime around it. Treat that as an architectural affordance rather than a commitment, and plan against what the table above says is available now. One clarification, because it is a common source of confusion: [Corbits Code](/platform/corbits-code) applies path controls of its own, including a secret-path denylist on file reads and shell commands. Those are Corbits Code features, not runtime features, and they do not extend to workflows you deploy yourself. **"So is my agent sandboxed?"** Not by Corbits, and you should sandbox it yourself. What Corbits gives you is a separation of authority: your code runs somewhere that cannot act as your deployment, cannot reach its signing key, and cannot instruct the half that holds it. The operating-system boundary is yours to supply, by running the host inside a container, VM, or sandbox. If your workflows have shell or filesystem access, do that before you run anything you would not hand the host account to. # The Corbits Platform Source: https://docs.corbits.dev/platform/overview Corbits is a platform for deploying secure, auditable agents with organizational guardrails: run, govern, and audit agents your whole organization can trust. ## Ship agents your organization can trust Corbits is a platform for **deploying secure, auditable agents with organizational guardrails**. You get the run, audit, and manage layer that turns a promising agent into something you can put in front of real work: control over what agents can do, an audit trail of what they did, and observability into how they're behaving right now. This is the part of the agent stack most teams are missing. Building an agent is the easy 20%. Running it safely is the other 80%: the right permissions, a record you can hand to security, and the ability to shut it down when it goes wrong. Corbits owns that 80%. It is not a general agentic toolkit; it's the control plane you run agents *on*. That serves two readers at once: * **Builders and developers** who want to ship capable agents without hand-rolling permissions, secrets handling, and audit logging for every deployment. * **Enterprise evaluators** (a head of AI, plus the compliance and security teams standing behind them) who need to know an agent can be granted exactly what it needs, nothing more, and that every action is accountable. **Control and audit** is the whole point. ## The platform in one view Corbits is layered. Apps sit on top. A control plane runs, governs, and audits the agents that run on it. An agent runtime does the work. Finished products people use every day: **Corbits Code** and **Workbench**. **Workbench** runs on the control plane below; the same credentials and grants described here govern its agents. **Corbits Code** is a standalone CLI that applies the same guardrail discipline in its own process rather than on the control plane. For a local tool, in-process is the right boundary. This is the layer that runs, governs, and audits agents. It resolves the credentials a principal can use, materializes its grants, gates the API, and keeps a cryptographically signed record of what it does while it runs. The execution engine underneath, **powered by Interchange**. It runs the agents; the control plane decides what the ones deployed on it are permitted to do while they run. We build on this stack ourselves. **Workbench** is a first-party app running on the same control plane we offer you: the credentials and grants described here are the ones it depends on. **Corbits Code** is a standalone CLI that applies the same guardrail discipline (enforcement as tool middleware, hard-deny guards) in its own process rather than on the control plane. ## The apps Two flagship apps show what the platform makes possible. A standalone coding-agent CLI. Bring agentic coding into your workflow, guarded by the same enforcement discipline (tool middleware and hard-deny guards), enforced in-process. The multiplayer workspace for humans and agents, running on control-plane credentials and grants. ## Guardrails: control what agents can do The heart of the platform is how it governs agents. Corbits separates **Credentials**, the secrets and identities an agent can act with, from **Grants**, the specific, scoped permissions that say what it's allowed to do. Where a decision is made from grants it is **fail-closed**: nothing explicitly permitting an action means it is denied. That's what lets an organization hand an agent real capability without handing it the keys to everything. How organizational guardrails work: what authorizes a credential, a tool, or your data, decided separately for each. Start here if you're evaluating for security or compliance. ## Bring any major model, no lock-in Model choice is a property of the **Interchange runtime** at the base of the platform: it speaks to the major model providers natively, so you pick models on cost and capability rather than on what your platform happens to support. **Anthropic** (with extended thinking and prompt caching), **Google Gemini**, and **OpenAI** are first-class, alongside any OpenAI-compatible endpoint (OpenRouter, self-hosted, or local). Run several models side by side, or move a workload to a cheaper one, without re-platforming. No single-vendor lock-in, and no waiting on us to add the model you need. ## Durable, resumable workflows A single agent turn is not the unit of real work. The jobs teams actually want to automate run for hours, hand work across several agents, and have to survive a process dying partway through. Multi-step orchestration is a property of the **Interchange runtime** at the base of the platform, which runs a workflow as a declared graph of steps rather than an open-ended agent loop. Declaring the graph up front is what makes the run bounded and recoverable: * **Loops are bounded.** A loop declares its maximum iteration count as part of the definition, and a definition that omits it is rejected. A rework loop cannot spin past its declared ceiling. * **Actions are checkpointed and replayable.** An action step is a host-effect node rather than a model call. Its external effects run through a capability-checked, deduplicating effect ledger, so a replayed handler sees the results already recorded instead of re-firing work the run had committed. * **One stage, many items.** A map step runs the same agent step once per item in its input and gathers the results in order. * **Cycles are caught at definition time.** The step graph is validated when the workflow is defined, so a dependency cycle fails then rather than in production. * **Crashes do not double-fire effects.** A run that dies mid-loop resumes without repeating effects it already committed, and an agent step interrupted mid-invocation refuses to re-invoke rather than risk running its side effects a second time. The practical result is that a long multi-step run leaves a durable record rather than living only in a process: you can see how far it got, restart it against that record without re-firing the effects it already committed, and audit every step it took. ## Where to go next Credentials, grants, and what each one actually decides. The standalone coding-agent CLI, built on the platform's runtime primitives. The multiplayer workspace for humans and agents. # Workbench Source: https://docs.corbits.dev/platform/workbench The multiplayer workspace for humans and agents: a team and its agents share benches, conversations, and the material they work from, built on the Corbits agentic platform. Workbench is a workspace where a team and its agents work in the same place. People and agents share a bench and take part in the same conversations, over the same material, rather than each agent living in a tab of its own. This page describes the **Workbench app**. Where it reaches into the layers underneath, it names them: the [control plane](/platform/guardrails) owns tenancy, credentials, and grants, and the [agent runtime](/platform/isolation) executes agents. Neither layer's guarantees are restated here. Workbench is open source, and it runs from a source checkout today: there is no single-command install. ## What you get today | What you want | Status today | | ----------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | | A shared space where people and agents hold the same conversation | Available | | Agents you author yourself, from a prompt and a model | Available | | A place to keep files the team refers back to | Available | | Work that runs on a schedule | Available. A routine runs a conversation's own agent, or any deployed one if you ask the assistant | | An outside service that can start a run | Available, by webhook, over the API only | | Approving what an agent is waiting on | Available, and the assistant in every bench already carries tools that park for one | | Seeing what a routine or an agent has done | Available. A routine keeps its own run history, and the agents page lists instances including stopped and errored ones | | Agents that reach into your CRM, tracker, or publishing tools | Available for a service you connect, and a write through a connected server waits for you | | One place to see everything that has run | Not available. The Insights page reports only work that is running now, not a history of it | | Usage and cost reporting, or a view of the audit trail | Not available | | A reusable library of skills you upload and version | Not available. The section appears in the interface and stores nothing | | An install that is one command | Not available | ## Benches and channels A **bench** is the shared space a team works in, holding its members, its agents, and its history. Underneath, a bench is a [control plane](/platform/guardrails) tenant. Belonging to one is a principal record the control plane resolves before a Workbench route runs, and what you may do once you are in is decided by control-plane grants, rather than by a membership or permission model Workbench invents alongside them. A **channel** is a conversation inside a bench, and it is minted as its own control-plane tenant parented under that bench, with its own roles and grants seeded when it is created. If you are evaluating the tenancy model, be precise about what that buys today: it gives a channel its own identity and somewhere to hang membership, but the routes serving a channel authorize against the bench above it, and the agents running in a channel draw their inference and credential context from that bench too. Treat a channel as an identity boundary rather than an enforcement one. A channel's timeline is its mailbox, read back in order. People and agents post into the same timeline, and mentioning an agent by its handle delivers that agent a copy of the message, addressed from the channel rather than from you, so its reply lands back in the shared timeline rather than in a side thread. What a mentioned agent reads as context is that message plus a configurable number of preceding ones, not the channel's whole history. A channel is the broadcast kind, meant for a whole bench. It starts with no agents in it: you invite one in, and it joins the timeline from then on. The dialog that creates a channel also creates a chat, which starts with the single agent you pick when you create it. A fresh bench opens into a channel named Myra with nothing invited into it yet, though the bench itself is seeded with three deployed workflows you can invite: a general-purpose assistant, an echo test agent, and the channel-digest automation. The invite dialog lists them under their asset names, `assistant`, `echo`, and `channel-digest`, and the assistant is the one the channel is named after. An agent in a channel that goes quiet is put to sleep rather than left running, and the next message addressed to it brings it back before delivery. Several senders arriving at once coalesce onto a single wake instead of racing each other. Each bench also keeps a **library** of uploaded files. You add files to it and then browse and search them, so a team has one place to put the material it keeps referring back to. The interface offers no download, export, or publish action, though the API will return a file's content to a caller holding a [control plane](/platform/guardrails) grant to read that bench's stored files. ## Agents and routines An **agent definition** is a reusable template: a name, a handle, a system prompt, and optionally a description and the model it should run on. Launching a definition produces an **instance**, a running agent with its own mailbox address you can write to. One definition backs as many instances as you launch from it. A **routine** runs a workflow on a schedule. It names the workflow to launch and a trigger, which is an interval, a time of day, a day and time of the week, or a cron expression when the presets do not fit; a routine with no trigger is one you run by hand. When more than one hub replica is running, each due fire is claimed atomically, so a routine fires once rather than once per replica, and a launch that keeps failing backs off and is eventually dead-lettered instead of retrying indefinitely. The routine panel gives you no way to choose what a routine runs. Opened with the `/routine` command, it binds the routine to the first agent in that channel or chat and delivers back into it, and it refuses to create one at all where no agent has been invited yet. Opened any other way, it falls back to the bench's own assistant conversation and the first agent in it. Asking Myra is how you pick, since she creates a routine against any definition deployed in the bench, including the agents you author. Nothing afterwards moves a routine onto a different one: not the panel, not Myra, not the update path either of them takes. Agents here are not confined to the bench's own material. The assistant seeded into every bench carries Model Context Protocol tools, so a server you connect becomes callable from a conversation. Attio for a CRM and Linear for a tracker are among the servers offered. Other shipped workflows reach GitHub and web search through native connectors rather than a server you connect. An agent can list a connected server's tools and read through the ones its listing marks read-only on its own authority; invoking anything else there waits for a person to approve that call. What goes unchecked is whether a tool marked read-only behaves that way. A bench's connected servers are Workbench's own records, while the [control plane](/platform/guardrails) holds each server's credential and resolves it per bench. The code review workflow posts its review to GitHub with no approval gate on it, so no prompt interrupts that write. A service outside Workbench can start a run by posting to a signed webhook endpoint. ## Approving what an agent is waiting on When a run parks on a human decision, it surfaces in the Activity band, naming the agent that is asking and the bench it is asking in rather than the identifiers underneath. You approve or reject it from there, and rejecting takes an optional message. There is no separate approvals page. Approving covers that one call and nothing more. There is no durable "always allow this tool" that Workbench records on your behalf, and the [control plane](/platform/guardrails) does not yet support approving with that scope. The assistant seeded into every bench produces approvals with no server connected at all. Asking it for a capability it lacks stops for a person, as do running a routine on demand and pinning a skill. ## What Workbench builds on Workbench does not reimplement the hard parts of running agents. It composes them from the layers below, which is also why the guarantees on those layers are the ones to read when you evaluate it. A definition is a workflow definition and an instance is a workflow run, both of them [agent runtime](/platform/isolation) objects. The runtime owns a run's lifecycle, its suspension and resumption, and its event log, and Workbench hosts that machinery in a sidecar process that dials in to its hub. What Workbench adds is the authoring surface that turns a prompt and a model into a definition, and the policy that decides when an instance should be running at all. A channel is not a chat system built beside the [agent runtime](/platform/isolation). It is a long-lived agent run whose job is to hold a mailbox, and a message is mail delivered to that run's address. Reading a timeline lists that mailbox. Workbench adds the structure carried over that transport: how a message's parts are encoded, the participants and handles a channel knows about, and the fan-out that copies a mentioned agent in. Benches and channels are [control plane](/platform/guardrails) tenants. Belonging to a bench is a control-plane principal record, and what a member may do is control-plane grants; both are resolved before a Workbench route runs. Model access is bring-your-own-key: first-run setup has a credential step that asks for a provider key and proves it with a real call before storing it, and the control plane holds and resolves it from then on. See [Credentials and guardrails](/platform/guardrails) for how that resolution works. ## Running it Workbench is open source under the GNU General Public License version 2, with an AI Exception. It runs from a source checkout against a local Postgres, with a setup and a seed step to run once the hub is up before a bench and its workflows exist. Its README says the single-command install it is aiming for does not exist yet, so a source checkout is the way to try it: the code and the instructions are at [corbitsdev/workbench](https://github.com/corbitsdev/workbench). The agentic platform Workbench is built on. How credentials, grants, and delivery capabilities are governed.