Local hub
In progress · M1- Runs on your machine with
capabilities hub serve - Reaches agents over stdio or loopback HTTP
- Keys in your OS keychain, data in
~/.capabilities/hub - Free, and open source under MIT when it ships
Local-first capability hub · in development
Put your MCP servers, APIs, credentials and skills in one hub. Claude Code, Codex and Cursor reach all of them through three tools, and write typed code instead of loading hundreds of tool definitions.
01search
Finds your tools by what you want done, and returns their addresses with one-line TypeScript signatures.
02describe
Gives the exact TypeScript types for the tools the model is about to call, within a token budget.
03execute
Runs the model's code in a sandbox where each source is a global of async functions. Nothing else is reachable.
The model never loads your whole toolbox. It looks up what it needs, reads exact types, and writes one piece of code that chains the calls. When that code reaches a write, the run pauses until you answer.
1 · Find the tools
github (connections: personal*, work)
github.searchIssues(input: { q: string; perPage?: number; page?: number }): Promise<IssueSearchResult>
Search issues and pull requests.
slack (connections: work*)
slack.postMessage(input: { channel: string; text: string }): Promise<Message> [asks]
Post a message to a channel.2 · Read the types
declare const slack: {
/** Post a message to a channel. */
postMessage(input: {
/** Channel name or id, e.g. "#eng". */
channel: string;
text: string;
}, options?: CallOptions): Promise<slack.Message>;
};3 · Run the code
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;{
"runId": "01JD4Q8V…",
"status": "awaiting_approval",
"calls": [{ "address": "github.searchIssues", "ok": true, "ms": 412 }],
"pending": [{
"kind": "approval",
"address": "slack.postMessage",
"summary": "Post a message to #eng",
"message": "An approval page opened on the user's screen. Run `capabilities hub approve 01JD4Q8V…` if it did not."
}]
}Formats from the design spec. The surface ships with the local hub (M1); wording changes only with eval evidence.
Policy decides every call: allow, ask or deny, per source or per tool. Approving pins the tool's contract, so a tool that changes upstream asks again and says why.
slack.postMessage
Post a message to a channel. · connection work
{
"channel": "#eng",
"text": "• Login fails on Safari (#412)\n• …"
}Why it asks: writes ask by default.
The importer reads what your agents already have, you review it on one screen, and one command points them all at the hub. The target is under two minutes.
01 · Import
$ capabilities hub init --importReads Claude Code, Codex, Cursor, Antigravity CLI, Hermes and pi. Proposes a namespace per server and offers to move plain-text keys into your keychain.
02 · Review
$ capabilities hub reviewOne screen groups tools as read-only, writes and destructive. One keystroke accepts and pins each contract.
03 · Connect
$ capabilities hub connectWrites one capabilities entry into Claude Code, Codex, Cursor and Claude Desktop. Read-only harnesses get exact instructions.
Planned for M1 · LH-13, LH-14, LH-15
Setup snippets for each agentcapabilities hub serve~/.capabilities/hubhub.capabilities.sh/mcpThe local hub ships as 20 pull requests. As of 2026-11-06, 11 are merged and 1 are in review. Nothing is released yet, and every page here says what is planned.
curl -s https://capabilities.sh/llms.txt