# capabilities.sh: full documentation Status: in development. Milestone M1 (the local hub) is in progress, 11 of 20 units merged as of 2026-11-06. Nothing is released yet. Generated from the same sources as https://capabilities.sh. Each section below is one page, with its canonical URL under its summary. --- # capabilities > One MCP endpoint for every tool your agents use. A local-first capability hub with three tools (search, describe, execute) where reads run, writes ask, only a person approves, and secrets never reach the model. Canonical page: https://capabilities.sh/ > [!STATUS] > In development. Milestone M1, the local hub, is in progress and nothing is released yet. capabilities is a hub for people who use agents. Put your MCP servers, HTTP APIs, credentials and skills in one hub, and every agent (Claude Code, Codex, Cursor) reaches all of them through one code-mode MCP endpoint. ## Three tools 1. **`search`** finds tools by intent and returns one-line TypeScript signatures. 2. **`describe`** returns exact types for the tools the model will call. 3. **`execute`** runs the model's code in a sandbox whose only way out is your tools. ## Four promises - **Reads run.** A tool that declares itself read-only runs without asking. - **Writes ask.** Everything else asks a person first, and asks again if the tool changes upstream. - **Only a person approves.** No path the model can reach records a decision. - **Secrets never reach the model.** Credentials stay in your keychain and are scrubbed from every result. ## Local first The local hub runs on your machine and will be free and open source (MIT). A hosted hub on Cloudflare, for cloud agents such as claude.ai and ChatGPT, is the planned paid product. ## Read next - [Overview](https://capabilities.sh/docs.md) - [Quickstart](https://capabilities.sh/docs/quickstart.md) - [The MCP surface](https://capabilities.sh/docs/mcp.md) - [Security and approvals](https://capabilities.sh/docs/security.md) - [Status and roadmap](https://capabilities.sh/status.md) - [For agents](https://capabilities.sh/agents.md) --- # Overview > What the capability hub is, how one MCP endpoint gives every agent your tools, and what exists today. Canonical page: https://capabilities.sh/docs Updated: 2026-11-06 > [!STATUS] > In development. The local hub (milestone M1) is being built now and nothing is released yet. Every page marks what is planned. See [Status](https://capabilities.sh/status.md) for what has landed. capabilities is a hub for people who use agents. Your MCP servers, HTTP APIs and skills, with their credentials and policies, live in one hub. Every agent reaches all of them through one MCP endpoint, and the model works through three tools instead of hundreds of tool definitions: - **`search`** finds your tools by what you want done and returns their addresses with one-line TypeScript signatures. - **`describe`** returns exact TypeScript declarations for the tools the model is about to call. - **`execute`** runs the model's JavaScript in a sandbox where each of your sources is a global object of async functions. You stay in control. Reads run. Writes ask. Only a person approves, never the model. Secrets never reach the model, the sandbox, a log or a result. ## Why one endpoint Each job below comes from the design spec, with the milestone that delivers it. - **Set it up once (M1).** Import what each agent harness already has, review it on one screen, then point every harness at the hub. - **Multi-step work without flooding context (M1).** The model searches, reads typed signatures, and writes code that chains calls across sources in one `execute`. - **Nothing you did not agree to (M1).** Reads run, writes ask, and a tool that changes upstream asks again before it runs. - **Reach from cloud agents (planned, M3).** The same hub, hosted on Cloudflare behind OAuth, for claude.ai, ChatGPT and phones. ## How a request flows ```text Claude Code ─┐ Codex ───────┼──▶ capabilities hub ──▶ search · describe · execute Cursor ──────┘ │ ├─ sources MCP servers over stdio or HTTP ├─ connections credentials in your OS keychain ├─ policy allow · ask · deny, per tool └─ sandbox QuickJS: no network, no files, no secrets ``` 1. The model calls `search("open bugs")` and gets back tool addresses such as `github.searchIssues` with their signatures. 2. It calls `describe("github.searchIssues")` for the exact input and output types. 3. It calls `execute` with code like `await github.searchIssues({ q: "is:open label:bug" })`, chaining as many calls as the task needs. 4. Each tool call inside the run is decided by policy. A write that needs a person pauses the run and asks. When the person decides, the run resumes from its journal, so no call that already happened is made twice. ## Local first, hosted later | | Local hub | Hosted hub | | ---------- | --------------------------------------------------- | ----------------------------------------------- | | Runs | On your machine, `capabilities hub serve` | On Cloudflare, `https://hub.capabilities.sh/mcp` | | Reaches | Agents on your machine, over stdio or loopback HTTP | Cloud agents: claude.ai, ChatGPT, phones | | Price | Free; open source under MIT when it ships | Paid; pricing is not decided | | Status | In progress: M1 now, M2 next | Planned: M3 alpha, M4 launch | Both run the same engine behind different ports, and shared conformance suites hold them to the same behavior. ## What exists today - The hub's contracts and most of the engine are merged: search, typed declarations, policy, the MCP source kind, the guest prelude, the QuickJS sandbox, runs with journal replay, and the CLI's local ports. The rest of M1 is listed on [Status](https://capabilities.sh/status.md). - The `capabilities` CLI exists in the repository with its census commands (`list`, `doctor`, `rollback`, `login`) and the `stack` preview. It is private and unreleased, and there is no `npx` install yet. - None of the `capabilities hub` commands on these pages runs yet. They land with M1. ## Read next - [Quickstart](https://capabilities.sh/docs/quickstart.md): the first local run, step by step. - [Concepts](https://capabilities.sh/docs/concepts.md): sources, namespaces, connections, policies, runs and journals. - [The MCP surface](https://capabilities.sh/docs/mcp.md): the three tools and what code can do inside the sandbox. - [Security and approvals](https://capabilities.sh/docs/security.md): who may approve, and what never leaves your machine. - [For agents](https://capabilities.sh/agents.md): llms.txt, Markdown twins and setup snippets. --- # Quickstart > The first local run, step by step. Build the CLI from a checkout, import what your agents already have, connect them, and approve a write. The hub steps are planned for M1. Canonical page: https://capabilities.sh/docs/quickstart Updated: 2026-11-06 > [!PLANNED] > This is the M1 quickstart, written ahead of the code. The `capabilities hub` commands arrive with plan units LH-13 (the commands), LH-14 (import and connect) and LH-15 (the approval page), and none of them is on `main` yet. M1 runs from a checkout build. An `npx` install comes in a later plan. The whole loop is one journey from the design spec (J1): on a machine with Claude Code and Codex, `hub init --import` finds their MCP servers, shows one review screen, and after `hub connect` both harnesses list one `capabilities` server. The target is under two minutes. ## Before you start - Node.js 22 or newer, and pnpm 11. - A checkout of the repository. It becomes public at the local alpha. - At least one agent: Claude Code, Codex, Cursor or Claude Desktop. ## 1. Build the CLI These commands work today. They build the CLI and its dependencies from the checkout. ```sh pnpm install pnpm exec turbo build --filter=capabilities... alias capabilities="node $PWD/packages/cli/dist/bin.js" ``` The alias is only a shortcut for this guide. The CLI is unreleased, so there is no global install. ## 2. Create the hub and import ```sh capabilities hub init --import ``` This creates `~/.capabilities/hub/` (directory mode 700, files 600) and runs the importer. The importer reads the configs of the harnesses you use (Claude Code, Codex, Cursor, Antigravity CLI, Hermes and pi), collects their MCP servers, and merges duplicates. It proposes a namespace for each server, such as `github` or `linear`. If a harness keeps a credential in plain text, the importer offers to copy it into your OS keychain for the hub. It leaves the harness config as it was, because a harness cannot read a keychain reference. In M1 the importer counts the skills it finds and says a later release imports them. ## 3. Review what the hub may do The review screen groups every new tool in three classes: | Class | Proposed policy | Why | | ----------- | --------------- | ------------------------------------------------------- | | Read-only | `allow` | The tool declares itself read-only | | Writes | `ask` | It changes something, or declares nothing about itself | | Destructive | `ask`, flagged | It says it deletes or overwrites | One keystroke accepts the proposal, or you adjust it. Accepting pins each tool's contract, so if a tool changes upstream it asks again. A local stdio server also asks for consent to run its exact command. ## 4. Connect your agents ```sh capabilities hub connect ``` `connect` writes one MCP entry named `capabilities` into Claude Code, Codex, Cursor and Claude Desktop. The entry runs `capabilities hub serve --stdio --profile default` by the CLI's absolute path, checked before it is written. For Antigravity, Hermes and pi, which the hub reads but does not write, it prints exact instructions instead. With `--replace`, `connect` also turns off the direct entries it imported, after taking a snapshot, and `capabilities rollback` restores them byte for byte. Entries your stack lock manages stay where they are, and `connect` prints the `capabilities stack uninstall` command for each. To write the entry yourself, use the [setup snippets](https://capabilities.sh/agents#connect-an-agent). ## 5. Ask for something that writes In Claude Code, try journey J2 from the spec: ```text Summarize my open bugs and post the top 3 to #eng. ``` The model searches, reads the two tools it needs, and runs one `execute` across both sources. The post is a write, so the run pauses and the hub asks you: - If your client supports MCP 2026-07-28 input requests with forms, it asks you itself. - Otherwise the hub opens an approval page in your browser, and the model is told only that a page opened. - From any terminal, you can always decide with the CLI: ```sh capabilities hub approve ``` You get four choices: **Allow once**, **Allow for this run**, **Always allow** (pinned to the tool's current contract), and **Deny**. Then the run resumes from its journal, and nothing that already ran runs twice. ## 6. Check health ```sh capabilities hub doctor ``` `doctor` reports each source's health and the tail of its error output, the store's schema version, the keychain status and the permissions on the HTTP token file. ## Add a source by hand ```sh capabilities hub add https://mcp.example.com/mcp capabilities hub auth example ``` `add` takes a URL or a command line for a local stdio server, fetches the tool list, and opens the same review screen. `auth` takes a credential at a masked prompt, never as an argument. OpenAPI documents, such as `capabilities hub add https://api.example.com/openapi.json`, arrive in M2. ## What's next - [Concepts](https://capabilities.sh/docs/concepts.md) explains sources, connections, policies, runs and journals. - [The CLI](https://capabilities.sh/docs/cli.md) lists every `capabilities hub` command and its milestone. - [Security and approvals](https://capabilities.sh/docs/security.md) covers the four choices and who may make them. --- # Concepts > The hub's vocabulary, from source and namespace to run, journal and decision. Generated from the project glossary so it always matches the code. Canonical page: https://capabilities.sh/docs/concepts Updated: 2026-11-06 These are the words the hub, its CLI and this site use, each with one meaning. They come straight from the project glossary (`CONTEXT.md`), copied into this site at a pinned commit and regenerated whenever that copy is refreshed. > [!STATUS] > The hub is in development, so these terms describe the design of record. Commands such as `capabilities hub serve` are planned for M1; see [Status](https://capabilities.sh/status.md) for what has landed. The two relationships that matter most: - A **source** yields a manifest of tools. Each tool has an **address** (`namespace.tool`) and a **contract** digest. The **index** is built from every manifest. - A tool call is decided by **policy** against the tool's address and the **connection** it uses, and recorded in the run's **journal** with that decision. ## The hub ### Hub The service that holds a person's sources, connections, policies and skills and serves them over one MCP endpoint. It runs locally (`capabilities hub serve`) or hosted (one tenant per account); both are the same engine behind different ports. Not to be called: gateway, proxy, executor. ### Source Where a hub's tools come from: a remote MCP server, a local stdio MCP server (local hub only), or an OpenAPI document. An MCP-server capability becomes a source when it is added to a hub. Not to be called: integration, plugin, connector. ### Namespace The identifier a source's tools appear under in code (`github`, `linear`). Unique per hub, chosen when the source is added, and stable across refreshes. ### Tool address `.`, how a run's code, policies and journals name a tool (`github.createIssue`). The tool part is the source's own name for it, normalized to a JavaScript identifier. ### Connection One named credential for one source (`github/work`). It holds references to secrets, never their values. A source has zero or more connections and at most one default; code picks another with a call option (`{ connection: "work" }`). Not to be called: account, binding, credential (the credential is the secret a connection points at). ### Policy The rule that decides a tool call: `allow`, `ask` (a person must approve) or `deny`. It attaches to a source or a tool, optionally narrowed to one connection. The most specific rule wins, except that a narrower rule can never loosen a `deny`. Not to be called: permission, guardrail. ### Tool contract The digest of what a tool claims to be (name, description, input and output schemas, annotations), recorded when a person approves the tool. A refresh that changes the digest puts the tool back to `ask` until it is reviewed, so the hub never widens its own authority. The tool-level counterpart of a Shape. ### Index The hub's searchable record of every tool and skill it can serve, built from each source's manifest. `search` reads it. Not to be called: catalog (that is the public listings repo), registry. ### Run One `execute` request's lifecycle: its code, status (`running`, `awaiting_input`, `completed`, `failed`, `cancelled`, `expired`), journal, result and logs. A run can take several sandbox attempts, one per resume. Its id is how the model and the person refer to it. Not to be called: session, job. ### Journal A run's append-only record of tool calls (address, connection, argument digest, outcome) and of the nondeterministic values its code read. Resuming a run replays its journal, so a call that already happened is never made twice. ### Profile A named, curated view of a hub: which namespaces, tools and skills are visible, and whether they are served in code mode or as direct tools. Each profile has its own endpoint. Profiles only curate; they grant nothing and carry no policy. Every hub has a `default` profile. Not to be called: toolkit, scope. ### Sandbox The isolated JavaScript runtime that runs a run's code: QuickJS compiled to WebAssembly on a local hub, a Worker Loader isolate on a hosted hub. It has no network, no filesystem and no secrets; its only way out is the tool bridge. ### Decision A person's answer to one pending tool call: `once`, `run`, `always` or `deny`, recorded with its channel (client prompt, approval page, CLI or dashboard). Never made by the model. Hub text calls asking for one "an approval"; it is distinct from a Shape **Approval**. Not to be called: consent, grant. ## Also used ### Capability One installable unit — an MCP server or a Skill. The Phase 0 contract accepts exactly three shapes: local MCP server (npm, stdio), remote MCP server (HTTP/SSE), and git-hosted skill pinned to a commit. Not to be called: plugin, extension, tool (a "tool" is what an MCP server exposes, not the capability itself). ### Client A coding agent whose config the stack workflow writes. Write-client coverage is defined in ADR-0002; the separate read registry follows ADR-0003. Not to be called: agent (ambiguous with the running LLM session), editor. ### Secret store Where secret values live on a machine: the OS keychain (macOS `security`, Linux Secret Service) with `~/.capabilities/.env` (mode 600) as fallback. Keyed by env var name, shared across capabilities. Values never enter the stack repo; the repo records names only. --- # The CLI > Every capabilities hub command and the milestone that brings it, plus the census and stack commands that exist in the repository today. Canonical page: https://capabilities.sh/docs/cli Updated: 2026-11-06 One binary, `capabilities`, holds three surfaces. `capabilities hub` runs the hub and is planned for M1. The census commands and the `capabilities stack` preview exist in the repository today, but the CLI is private and unreleased. > [!PLANNED] > No `capabilities hub` command runs yet. The M1 commands arrive with plan units LH-13, LH-14 and LH-15. Commands marked "later" wait for later plans. ## capabilities hub ### Setup | Command | What it does | Arrives | | ---------------------------------- | -------------------------------------------------------------------- | ------- | | `init [--import]` | Create the hub; with `--import`, run the importer too | M1 | | `import [--from …]` | Read harness configs and propose sources and credentials | M1 | | `add [--namespace ]` | Add one source from a URL or a stdio command line | M1 | | `list` | List sources | M1 | | `remove ` | Remove a source | M1 | | `refresh [namespace]` | Re-read tool lists and detect tools that changed upstream | M1 | | `review` | Decide new and changed tools | M1 | | `connect [--client …] [--replace]` | Point your harnesses at the hub | M1 | | `disconnect` | Undo `connect` | M1 | ### Credentials and access | Command | What it does | Arrives | | ---------------------------------------- | ------------------------------------------- | ------- | | `connections ` | List a source's connections | M1 | | `auth [--connection ]` | Enter a credential at a masked prompt | M1 | | `policy …` | Edit policy rules | Later | | `profiles …` | Manage profiles beyond `default` | Later | ### Serving and running | Command | What it does | Arrives | | ------------------------------------------ | ----------------------------------------------- | ------- | | `serve --stdio` | Serve the MCP endpoint to a harness | M1 | | `serve --http [--port ]` | Serve on loopback for clients that prefer HTTP | M1 | | `call
''` | Call one tool from the terminal | M1 | | `exec ''` | Run code from the terminal | M1 | | `runs [--status ]`, `runs show ` | List runs, or show one | M1 | | `approve ` | Decide a pending call and resume the run | M1 | | `cancel ` | Cancel a run | M1 | | `doctor` | Diagnose sources, the store and the keychain | M1 | `serve --stdio` is what harness configs launch: each harness session gets its own process, and all of them share the store under `~/.capabilities/hub/`. `serve --http` binds only to loopback, on port 4790 by default, and requires the bearer token in `~/.capabilities/hub/http-token` (mode 600). In M1, `--profile` accepts only `default`. ### Hosted | Command | What it does | Arrives | | ------------------ | --------------------------------------------------- | ------------ | | `login` | Sign in to the hosted hub | Later, M3 | | `push [--secrets]` | Send your local configuration to the hosted hub | Later, M3 | | `status` | Show the hosted hub's state | Later, M3 | `push` sends sources, policies, profiles, skill files and connection metadata, never secret values, unless you pass `--secrets` and consent to each one. The server answers with a plan and its hash, and applying needs that hash. ## Where the hub keeps its files ```text ~/.capabilities/hub/ mode 700; every file 600 hub.json settings, schema version, hub id sources/ manifests/ connections/ policies/ profiles/ skills/ runs/.json one record per run runs/.journal.jsonl append-only journal of the run's calls blobs/ locks/ http-token bearer token for serve --http ``` Writes go to a temporary file, are synced, and are renamed into place. Several `serve --stdio` processes share the store through per-record lock files, not a daemon. ## The CLI today These commands exist in the repository and run from a checkout build. They manage capabilities across your coding agents, and the hub builds on them. | Command | What it does | | ------------------------------------ | ------------------------------------------------------------- | | `capabilities list` | Show installed capabilities | | `capabilities doctor` | Check for missing secrets and broken client configs | | `capabilities rollback` | Restore client configs from the last snapshot | | `capabilities login` | Sign in with GitHub (device flow) | | `capabilities stack init` | Link the stack repository that syncs your capabilities | | `capabilities stack push` | Commit your stack and push it to the stack repository | | `capabilities stack pull` | Apply the stack repository's capabilities to this machine | | `capabilities stack install ` | Install a capability into your coding agents | | `capabilities stack uninstall ` | Remove a capability from your clients and the lock | Two global options go before the command: `--registry ` and `--no-input`. Secret values never enter the lockfile. They are read from your shell environment, then the OS keychain, then `~/.capabilities/.env`. ```sh pnpm --filter capabilities dev --help pnpm --filter capabilities dev list pnpm --filter capabilities dev doctor ``` --- # The MCP surface > The three tools a code-mode profile exposes, what the model's code can and cannot do inside the sandbox, how approvals travel over MCP, and the default limits. Canonical page: https://capabilities.sh/docs/mcp Updated: 2026-11-06 > [!PLANNED] > This surface is specified and partly built. Search (LH-07), typed declarations (LH-06), the QuickJS sandbox driver (LH-04) and runs with journal replay (LH-09) are merged. The code pipeline (LH-05) is in review, and the MCP server itself is LH-12. The model-facing wording below is the starting draft, and it changes only with evidence from the eval suite. A code-mode profile exposes exactly three tools. Nothing else is always loaded, so the fixed cost of the surface, tool definitions and server instructions together, has a target of 1,500 tokens or fewer. The server targets MCP 2026-07-28 (stateless requests, multi-round-trip input) and falls back for older clients. ## search Annotations: read-only, idempotent. > Find the user's tools and skills by what you want to do, for example "create a GitHub issue" or "recent Slack messages". Returns tool addresses with one-line TypeScript signatures, best match first. Read full types with `describe` before writing code. Pass `namespace` to search or list one source. | Field | Type | Notes | | ----------- | -------------- | ---------------------------------------- | | `query` | string, 1–200 | Empty lists a namespace | | `namespace` | string | Optional | | `limit` | integer, 1–25 | Default 8 | It returns plain text, best match first. A tool marked `[asks]` needs approval under your current policy, and tools your policy denies are hidden, with a count. ```text github (connections: personal*, work) github.createIssue(input: { owner: string; repo: string; title: string; body?: string; labels?: string[] }): Promise [asks] Create an issue in a repository. github.searchIssues(input: { q: string; perPage?: number; page?: number }): Promise Search issues and pull requests. 3 more matches. Narrow the query or pass namespace. ``` Ranking is BM25F over tool names, descriptions and parameter names, and never over connection names. ## describe Annotations: read-only, idempotent. > Get exact TypeScript declarations for tools: an address (`github.createIssue`), a whole namespace (`github`, budget permitting), or a type named in an earlier declaration (`github.Issue`). Write `execute` code against these types. It takes `targets`, a list of 1 to 10 strings, and returns one `declare const ` block per namespace, with required fields first and each field's description as JSDoc. Output stays within a token budget, 2,500 by default; deeper types become named interfaces you can describe on their own. ```ts declare const github: { /** Search issues and pull requests. */ searchIssues(input: { /** Search query, GitHub syntax. */ q: string; perPage?: number; page?: number; }, options?: CallOptions): Promise; }; ``` ## execute Annotations: not read-only, open world. It has an output schema. > Run JavaScript in a sandbox where each of the user's sources is a global object of async functions: `await github.createIssue({ owner, repo, title })`. TypeScript annotations are allowed and stripped. Write the body of an async function and `return` what you need; run independent calls in parallel with `Promise.all`. There is no network or filesystem besides these functions. If a call needs the user's approval or a connection, the result says so and a page opens on the user's screen; tell the user, then continue with `{ "resume": "" }` after they decide. Never ask the user for passwords or tokens in chat. Send exactly one of `code` (up to 64 KB) or `resume` (a run id). The result is an envelope, as structured content plus one compact line of text. Abridged, without the M2 fields: ```ts interface ExecuteEnvelope { runId: string; status: "completed" | "failed" | "awaiting_approval" | "awaiting_connection" | "cancelled"; result?: unknown; error?: { code: string; message: string; hint?: string }; logs?: string[]; calls: { address: string; ok: boolean; ms: number }[]; pending?: { id: string; kind: "approval" | "connection"; address?: string; summary: string; message?: string }[]; truncated?: { result?: boolean; logs?: boolean }; notices?: string[]; } ``` The hub forgives common code shapes. It takes the body of a fenced block, unwraps `export default`, calls a lone function, and returns a final expression, and each rewrite adds one line to `notices` so the model learns what changed. ```js const bugs = await github.searchIssues({ q: "repo:acme/app is:open label:bug" }); const top = bugs.items.slice(0, 3).map((i) => `• ${i.title} (#${i.number})`); await slack.postMessage({ channel: "#eng", text: top.join("\n") }); return top; ``` ## Inside the sandbox Both sandbox drivers load the same guest prelude, so this list holds everywhere. - **Your sources** as frozen global objects, one per namespace. Calling an unknown tool raises a `TypeError` that names the closest tools. - **`hub.search(query)`** and **`hub.describe(target)`**, the same lookups from inside code. - **`ToolError`** for expected tool failures, with `code`, `address`, `status`, `hint` and `retryable`. - **`console`**, captured within a log budget. - **Determinism:** `Date` runs on the run's logical clock, and `Math.random`, `crypto.randomUUID` and `crypto.getRandomValues` draw from a per-run seed. That is what lets a resumed run replay exactly. - **`setTimeout`** up to 30 seconds, plus `structuredClone`, `TextEncoder`, `TextDecoder`, `atob` and `btoa`. Not available: `fetch`, `import` and `require`, `process`, `Buffer`, `eval` and the `Function` constructor. `URL` and `URLSearchParams` are not in M1. A second connection is picked per call with `{ connection: "work" }`. ## Approvals over MCP When a call needs a person, the run records a pending input and stops. What the client receives depends on what it declared: 1. **A 2026-07-28 client with form elicitation** gets an input request with the call's address, connection, a redacted preview of the arguments and the reason, and four choices. The answer is accepted only with the state the server signed for that exact pending call, and only once. 2. **Every other client** gets `status: "awaiting_approval"`. A local hub opens its approval page in your browser and tells the model only that a page opened, with `capabilities hub approve ` as the fallback. It never hands the model a URL or a token. 3. **Always:** `capabilities hub approve ` from a terminal. The model then calls `execute({ resume: runId })`. Until a person decides, resume returns the same pending envelope and runs nothing. ## Default limits These are targets that prototypes and perf tests check. Hosts may lower them but not raise them. | Limit | Default | Meaning | | ------------------- | -------- | ---------------------------------------------------------------- | | `codeBytes` | 64 KB | Size of the code in one `execute` | | `computeMs` | 10,000 | Guest execution time, paused while tool calls are in flight | | `wallMs` | 90,000 | Ceiling for one attempt, tool calls included | | `memoryBytes` | 64 MB | Guest heap | | `maxCalls` | 500 | Tool calls per run, all attempts together | | `maxConcurrent` | 8 | Tool calls in flight at once | | `inlineResultBytes` | 24 KB | Result and logs returned inline, across every channel | | `upstreamTimeoutMs` | 30,000 | One upstream call | | `approvalTtlMs` | 24 h | How long a pending approval waits | ## Arriving in M2 M1 serves MCP sources, static credentials, the `default` code-mode profile and the `search` and `describe` helpers. M2 adds skills over MCP (the Skills extension, plus `describe("skill:")`), large results as handles read with `hub.read`, OpenAPI sources, OAuth connections, named profiles and direct mode, where each tool is exposed as its own MCP tool for clients and models that do better that way. --- # Security and approvals > The four control promises in detail. Policy decides every call, only a person records a decision, contracts pin what you approved, secrets stay in your keychain, and code runs with no network. Canonical page: https://capabilities.sh/docs/security Updated: 2026-11-06 > [!PLANNED] > These are design rules from the spec. Policy decisions (LH-08) are merged. The approval page (LH-15) and the invariant test suite that fails the build when a rule breaks (LH-18) are planned for M1. The hub makes four promises, and each one is a mechanism you can inspect. | Promise | Mechanism | | ------------------------------ | --------------------------------------------------------------------------- | | Reads run | Policy allows a tool that declares itself read-only, unless you say otherwise | | Writes ask | Every other tool, including one that declares nothing, asks a person | | Only a person approves | No MCP-reachable path can record a decision | | Secrets never reach the model | Credentials are resolved only at the moment of an upstream request | ## Policy decides every call A policy rule attaches to a source or a tool, optionally narrowed to one connection, and says `allow`, `ask` or `deny`. For each call: 1. Any matching `deny` wins. A narrower rule can never loosen a `deny`. 2. A tool that is new, or changed since you reviewed it, asks. 3. Otherwise the most specific rule decides: tool and connection, then tool, then source and connection, then source. 4. With no rule, a tool annotated `readOnly` runs and anything else asks. An unannotated tool counts as possibly destructive, as the MCP specification advises. A denied call never touches a credential. Policy is checked first, then approval, and only then is a secret resolved. ## Only a person approves When a call asks, the person sees the tool's address and connection, the first sentence of what the tool says it does, the arguments (redacted, capped at 4 KB), why it asks, and when the request expires. There are four choices: | Choice | Effect | | ------------------- | ------------------------------------------------------------------------- | | Allow once | This call runs | | Allow for this run | This tool runs for the rest of the run, so a loop of 20 posts asks once | | Always allow | A policy rule pinned to the tool's current contract | | Deny | The call fails with `approval_denied` inside the model's code | A decision can come only from host code that handles a person's input: - **Your client's own prompt**, for clients that support MCP 2026-07-28 input requests. The answer counts only with the state the server signed for that pending call, bound to the run, the call and a nonce, and only once. - **The approval page.** A local hub opens it in your browser itself, on loopback, with a one-time token the model never sees, a CSRF token, and `Host` and `Origin` checks against DNS rebinding. - **`capabilities hub approve `** in a terminal. - **The dashboard inbox**, behind a login, on the hosted hub (planned, M3). No MCP tool, no `execute` or `resume` argument, and no personal access token can record a decision. In the code, exactly one module may call the function that records one, and an import-graph test holds that line. Configuration is not a tool either. No MCP tool can add sources, change connections, edit policies or decide approvals, so a prompt-injected model cannot grant itself access. ## Contracts pin what you approved When you approve a tool, the hub records a digest of its name, description, input and output schemas and annotations. If a refresh finds that digest changed, the tool goes back to `ask`, rules pinned to the old contract stop applying, and the review shows what changed. New tools upstream also ask until you review them. The hub never widens its own authority. ## Secrets stay out of reach - On your machine, values live in the OS keychain under the service `capabilities.sh`. Without a keychain the hub falls back to a mode-600 file and says so every time it does. - A connection holds references to secrets, never their values. - Every string that crosses into the sandbox, a journal, a log, telemetry or a result is scrubbed. The run's secret values, and their base64 and URL-encoded forms, become `[secret]`, which covers an API that echoes a token. - Credentials are entered only by a person: at a masked prompt, on the connection page, or in the dashboard. Never in chat, and never through an MCP tool. ## Code runs with no way out The model's code runs in QuickJS compiled to WebAssembly, inside a worker thread that the hub can terminate. The sandbox has no network, no filesystem and no secrets. Its only way out is the tool bridge, and every call through it passes policy. Upstream traffic goes only to the hosts fixed when you reviewed the source. Credentials are never sent across a cross-origin redirect, and only a short allowlist of response headers reaches the code. ## Resume never repeats a call Every call is written to the run's journal when it settles. A run that pauses for approval waits for its in-flight calls to finish and records them first. Resuming replays the journal with the same seed and clock, so a call that already happened is never made twice, and a run whose code takes a different path fails with `divergence` instead of guessing. ## The invariants Each rule has a test that fails the build when it breaks. The local suite is plan unit LH-18. I5 belongs to the hosted hub. | # | Invariant | | --- | --------------------------------------------------------------------------------------------------------- | | I1 | A secret value never enters the sandbox, a journal, a log, telemetry or a result | | I2 | Only a person records a decision; no MCP-reachable path records one | | I3 | Authority never widens without a person | | I4 | The sandbox has no network; upstream traffic goes only to allowlisted hosts; credentials stay on their origin | | I5 | Tenants are isolated (hosted) | | I6 | Resume never repeats a call | | I7 | Every channel has a budget | | I8 | The model cannot change configuration | ## What the hub cannot protect against An agent with shell access on your own OS account can act as you. It could open the approval page, run `capabilities hub approve` or edit policy files. Your harness's own permission prompts are the boundary there. The hub never hands the model an approval token or a page URL, and opens the page itself. ## Telemetry The CLI's telemetry is on by default, announced on first run, and honors `DO_NOT_TRACK`. Events carry ids, counts, durations and error codes from a closed, published catalog. They never carry names, paths, code, arguments or results. --- # FAQ > Short answers about release status, code mode, approvals, secrets, supported agents, open source and pricing. Canonical page: https://capabilities.sh/docs/faq Updated: 2026-11-06 ## Can I install it today? Not yet. The local hub is milestone M1 and is being built now; [Status](https://capabilities.sh/status.md) shows what has landed. M1 runs from a checkout build, and an `npx` install comes in a later plan. ## How is this different from adding MCP servers to each agent? You set each server up once, in one place, with one set of credentials and one policy, and every agent sees all of it. The model does not load every tool definition up front. It searches, reads only the signatures it needs, and writes code that chains calls, so a multi-step task can run as one `execute`. ## Why code instead of tool calls? Hundreds of tool definitions cost context before the model does anything, and chaining calls one turn at a time costs round trips. Code mode keeps the fixed surface to three tools and lets one run filter, join and loop over results in the sandbox. Claims about how much better it is will come from the project's eval suite, which compares code mode with direct tools on Claude models. Two targets it checks: task success no worse than direct tools by more than two points, and at least 40% fewer input tokens on multi-step tasks. ## Can the model approve its own write? No. A decision comes only from a person, through the client's own prompt, the approval page the hub opens, the `capabilities hub approve` command, or the hosted dashboard. No MCP tool or argument can record one. See [Security and approvals](https://capabilities.sh/docs/security#approvals). ## Does the model ever see my API keys? No. Credentials stay in your OS keychain, are resolved only at the moment of an upstream request, and are scrubbed from everything that flows back. The sandbox that runs the model's code holds no secrets and has no network. ## What happens when a tool changes upstream? It asks again. The hub pins the contract you approved, a digest of the tool's description, schemas and annotations. When a refresh finds a different contract, the next call asks and says why. ## Which agents work with it? Any MCP client. `capabilities hub connect` writes the entry for Claude Code, Codex, Cursor and Claude Desktop, and prints exact instructions for Antigravity CLI, Hermes and pi. Cloud agents such as claude.ai and ChatGPT reach your hub through the hosted hub, planned for M3. The [setup snippets](https://capabilities.sh/agents#connect-an-agent) show the entry each agent needs. ## Does it run skills? In M1 the importer counts your skills and says a later release imports them. M2 adds skills to the hub: searchable, readable over MCP, and installed natively into each harness you connect. ## Is it open source? The local hub, its engine and the CLI will be published under the MIT license in a public repository at the local alpha. The hosted hub's Cloudflare app is proprietary at launch. ## What will it cost? The local hub is free. The hosted hub will be the paid product, and its price is not decided; it will be set with data from the alpha. ## Which operating systems? macOS and Linux first. The CLI's tests run on both. The sandbox on Windows is not yet proven. ## Where does my data live? On your machine, in `~/.capabilities/hub/` (directory mode 700, files 600), with secret values in your OS keychain. Runs, journals and their results are kept for 7 days by default. ## Who makes it? [DeepAura](https://deepaura.ai). --- # For agents > How this site serves agents (llms.txt, Markdown twins of every page, a JSON docs index, stable anchors, structured data) and the setup snippets that point Claude Code, Codex and Cursor at the hub. Canonical page: https://capabilities.sh/agents Updated: 2026-11-06 This site is written for two readers: the person deciding whether to use the hub, and the agent that person asks about it. Everything a person can read here, an agent can fetch as plain Markdown or JSON, without running JavaScript. ## Entry points | URL | What it holds | | --------------------------------------- | ---------------------------------------------------------------------- | | [`/llms.txt`](https://capabilities.sh/llms.txt) | A short index of the site in the llms.txt format, linking every page's Markdown | | [`/llms-full.txt`](https://capabilities.sh/llms-full.txt) | Every docs page in one Markdown file | | [`/docs.json`](https://capabilities.sh/docs.json) | A machine-readable index: titles, descriptions, URLs, headings, status | | Any page plus `.md` | That page as clean Markdown, for example [`/docs/quickstart.md`](https://capabilities.sh/docs/quickstart.md) | | Any page with a twin, sent `Accept: text/markdown` | The same Markdown at the page's own URL, with `Vary: Accept` | | [`/sitemap.xml`](https://capabilities.sh/sitemap.xml) | Every HTML page | | [`/robots.txt`](https://capabilities.sh/robots.txt) | The crawl policy, which welcomes AI crawlers by name | ## Conventions on every page - **A Markdown twin.** Each docs page links its twin with `` in the head, and a **Copy as Markdown** button copies it. In the twins, links to other pages point at their twins too. - **HTML that stands on its own.** Pages are static, semantic HTML (`header`, `nav`, `main`, `article`, `aside`, `footer`), and all content renders without JavaScript. Scripts only add the theme switch, copy buttons and the animated mark. - **Stable anchors.** Headings use GitHub's slug rules, and glossary terms carry fixed ids such as [`/docs/concepts#tool-address`](https://capabilities.sh/docs/concepts#tool-address), so a link you store keeps working. - **A description per page,** in ``, in the twin's summary line and in `docs.json`. - **Structured data.** The home page carries a schema.org `SoftwareApplication`, and each docs page a `TechArticle` whose `encoding` points at its Markdown twin. - **Honest status.** Anything not yet built is marked **Planned**, with the plan unit or milestone that brings it. ## Crawling `robots.txt` allows every crawler and names the AI crawlers explicitly, including GPTBot, ClaudeBot, PerplexityBot, Google-Extended and CCBot. There are no gated pages and no API keys. Please cite the canonical page URL, which every twin states under its summary. ## Connect an agent to the hub > [!PLANNED] > Available when the local hub ships. These entries run `capabilities hub serve --stdio`, which arrives with plan unit LH-13, and `capabilities hub connect` (LH-14) writes them for you. Until then they start nothing. Each snippet registers one stdio server named `capabilities`. M1 runs the CLI from a checkout build, so replace `/path/to/capabilities` with your checkout. `connect` writes the absolute path it verified. ### Claude Code Available when the local hub ships. Adds one user-scoped stdio server. `capabilities hub connect` writes the same entry to ~/.claude.json. ```sh title="terminal" claude mcp add --scope user capabilities -- node /path/to/capabilities/packages/cli/dist/bin.js hub serve --stdio --profile default ``` ### Codex Available when the local hub ships. Codex reads MCP servers from config.toml. `capabilities hub connect` writes this table for you. ```toml title="~/.codex/config.toml" [mcp_servers.capabilities] command = "node" args = ["/path/to/capabilities/packages/cli/dist/bin.js", "hub", "serve", "--stdio", "--profile", "default"] ``` ### Cursor Available when the local hub ships. Cursor reads global MCP servers from ~/.cursor/mcp.json. `capabilities hub connect` merges this entry in. ```json title="~/.cursor/mcp.json" { "mcpServers": { "capabilities": { "command": "node", "args": [ "/path/to/capabilities/packages/cli/dist/bin.js", "hub", "serve", "--stdio", "--profile", "default" ] } } } ``` Prefer to let the CLI do it: ```sh capabilities hub connect ``` ## The hosted endpoint > [!PLANNED] > Milestone M3. The hosted hub serves the same three tools at `https://hub.capabilities.sh/mcp`, behind OAuth, so claude.ai, ChatGPT and phones can reach your hub. You will add it as a connector and sign in. ## If you are an agent reading this - The hub is in development. Do not tell a person to run a `capabilities hub` command as if it works today. Check [Status](https://capabilities.sh/status.md) first. - Treat anything marked **Planned** as not available, and name the milestone when you mention it. - For exact tool contracts, read [The MCP surface](https://capabilities.sh/docs/mcp.md). For vocabulary, read [Concepts](https://capabilities.sh/docs/concepts.md), and use its terms. A "source" is not a "plugin", and a "connection" is not an "account". - Never ask a person to paste a password or token into chat. The hub takes credentials only through a masked prompt or a page it opens. --- # Status and roadmap > Where the hub stands. Milestone M1, the local hub, is in progress and nothing is released. The unit list is generated from the plan of record and the repository's history. Canonical page: https://capabilities.sh/status Updated: 2026-11-06 > [!STATUS] > **M1 is in progress.** As of 2026-11-06, 11 of the 20 M1 units are merged, 1 are in review and 8 have not started. Nothing is released yet. ## Milestones | Milestone | What it delivers | State | | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | ----------- | | M1 · Local hub | The engine and its approval page, run from a checkout: MCP sources, static credentials, the `default` code-mode profile, import, connect, review and the `hub` CLI | In progress | | M2 · Complete local | OpenAPI sources, OAuth, skills, large results as handles, the dashboard review inbox, named profiles, direct mode and run history | Planned | | M3 · Hosted alpha | The same engine on Cloudflare at `hub.capabilities.sh`, reachable from cloud agents behind OAuth | Planned | | M4 · Paid launch | The hosted hub as a paid product, priced with data from the alpha | Planned | M1 runs from a checkout build. An `npx` install waits for a later plan. ## M1, unit by unit M1 ships as twenty pull requests in dependency order. Each is verified by its own tests, live checks and a performance rule before it merges. | Unit | What it builds | State | | ---- | -------------- | ----- | | LH-01 | Freeze the hub contracts | Merged (#28) | | LH-16a | Add the eval harness, offline | Merged (#29) | | LH-02 | Add port conformance suites and memory stores | Merged (#30) | | LH-03 | Build the guest prelude | Merged (#32) | | LH-05 | Add the code pipeline | In review (#37) | | LH-06 | Add typegen | Merged (#35) | | LH-07 | Add the index and search | Merged (#36) | | LH-08 | Add the policy decision | Merged (#31) | | LH-10 | Add the MCP source kind | Merged (#33) | | LH-04 | Add the QuickJS sandbox driver | Merged (#38) | | LH-11 | Add the local ports | Merged (#39) | | LH-09 | Add runs with journal replay | Merged (#40) | | LH-12 | Add the MCP surface | Not started | | LH-17a | Run the early code-mode trial | Not started | | LH-13 | Add the hub CLI commands | Not started | | LH-14 | Add import and connect | Not started | | LH-15 | Add the local approval page | Not started | | LH-16b | Record the live eval baseline | Not started | | LH-17 | Run code-mode evals round 1 | Not started | | LH-18 | Add the local invariant suite | Not started | ## Journeys The design spec defines six journeys that version 1 must make work end to end. | # | Journey | Milestone | | --- | ------------------------------------------------------------------------------------------------------------------------------------- | --------- | | J1 | Import and connect: `hub init --import` finds your agents' MCP servers, and after `hub connect` each harness lists one `capabilities` server, in under two minutes | M1 | | J2 | A multi-step task, such as "summarize my open bugs and post the top 3 to #eng", runs as one `execute` over two sources with one approval for the post | M1 | | J3 | Add an API: `hub add https://api.example.com/openapi.json` asks for the key once, and the agent can call it | M2 | | J4 | A tool changes upstream: a refresh finds the new schema, and the next call asks again and says why | M1 | | J5 | Go hosted: `hub login` and `hub push`, then add `https://hub.capabilities.sh/mcp` as a claude.ai connector | M3 | | J6 | Skills everywhere: a skill in the hub appears natively in every connected harness and is readable over MCP | M2 | ## How this page is made The unit list comes from the plan of record (`docs/plans/2026-11-05-local-capability-hub.md`) and the commit history of `DeepAura/capabilities` `main`, through `scripts/sync-status.mjs`, which reads a copy of both pinned at one commit. A unit shows as merged only when a commit on `main` names it. Units in review come from the open pull requests on the day that copy was taken.