A local capability gateway for AI agents. Plexus is a user-installed, open-source gateway that exposes one AI-native self-describe endpoint, so any AI agent can DISCOVER → UNDERSTAND → be GRANTED → CALL the capabilities of the software on your machine — under a trust model you can see, scope, and revoke.
Five agents, one wall — reads flow, writes pend, execute is per-call, off-subset bounces, revoke is surgical. Watch it live on the site →
Open Claude Code (or any coding agent) in this repo and say:
"read docs/getting-started.md and set Plexus up for me." It installs, starts
Plexus, configures everything (asking you for the folder to expose), connects itself as
an agent, and demonstrates one read and one write — while you approve each grant in the
Plexus UI. You'll watch an agent reach your Mac's capabilities with no shell, locked to
what you exposed, every powerful move approved by you.
→ docs/getting-started.md — the end-to-end runbook (also
a fine copy-paste guide if you'd rather drive by hand).
| You want to… | Go to |
|---|---|
| See what Plexus is and why | you're on the right page — read on |
| Run it (hand the repo to your agent) | docs/getting-started.md |
| Understand the model + build (install, connect an agent, author a source) | docs/README.md — the developer reading path |
This page is the product landing page. It won't repeat the getting-started steps —
follow docs/README.md for those.
MCP answers "what functions do I have?" Plexus answers "how should you use me?" — it wraps the functions in usage knowledge, a legible trust model, and an audit trail, then brokers them to agents over a stable, AI-native protocol.
The point isn't another tool registry. It's the surface no vendor ships a server for: the local macOS software you already use. Plexus turns your Obsidian vault, your Apple Calendar, Reminders, Notes, Mail, Contacts and Photos, your browser, your Shortcuts, and your Claude Code orchestration into capabilities an agent can discover and call — without you handing over a blanket key, and without an agent ever self-granting a mutating action.
Transparency is the product. Default-deny, per-capability, scoped, revocable, audited — that trust story is the value, not a tax on it.
Plexus runs on Bun (≥ 1.3.0). Install Bun if you don't have it
(curl -fsSL https://bun.sh/install | bash), then:
# 1. Install dependencies (workspace monorepo)
bun install
# 2. Boot the gateway — loopback only (127.0.0.1:7077). Prints the URL, then stays
# running (Ctrl-C to stop).
bun run start
# Optionally open an Obsidian vault read-only at boot (persists as a managed source):
bun run start --vault ~/Documents/MyVault
# Print the ADMIN connection-key (the management credential — you use it to reach
# /admin; NEVER hand it to an agent). Read from ~/.plexus/, no server needed:
bun run start --print-key
# Prove the whole DISCOVER → GRANT → CALL loop end-to-end (self-contained, no setup):
bun run demoFirst run is automatic: the gateway creates ~/.plexus/ (connection-key, signing
secret, audit log) on first boot — nothing to configure. Open the management UI at
http://127.0.0.1:7077/admin to add sources, approve grants, and read the audit
trail. It's served same-origin from the gateway, so the page's HTML/assets load
key-free — but every /admin/api/* call still needs the connection-key. The SPA
resolves it desktop-IPC inject → cached → one-time paste: the Electron desktop
app injects it over IPC (no paste), while a plain browser uses a cached key or
prompts you to paste it once.
Desktop app (Electron, macOS): a developer-run tray shell supervises the runtime as a sidecar and hosts the same admin UI, with native approval notifications. Signed/notarized distribution and auto-update are deferred (the current build is unsigned). Run it from the desktop package:
bun run --cwd packages/desktop start→ Full walkthrough: docs/README.md — the developer reading
path: install, start, add a source, connect an agent (mint a one-time code + grant a
starting cap-set), and approve a grant with the trust-window picker.
Two credentials, never conflated. This is the whole trust story:
- connection-key (
plx_live_…) — the admin / management credential, and the trust boundary. The owner-as-admin holds it; rotating it revokes everything at once. Agents never see or use it. - per-agent PAT (
plx_agent_…) — each agent's own durable credential. It is redeemed once from a one-time enrollment code, hashed at rest, and revocable per agent. The PAT-authenticated handshake binds the real agentId — an agent can't self-assert someone else's identity.
The flow is admin → agent, not agent-helps-itself:
- The admin connects an agent. In the console's Connect an agent wizard (or
POST /admin/api/agents/connect) you name the agent, grant it a starting cap-set, and Plexus mints a one-time enrollment code (plx_enroll_…, 15-min, single-use). You hand the agent one command — never the connection-key. - The agent installs once. It runs the one-command install
(
curl -fsSL <gateway>/integration/<agentId>/install.sh | …), which redeems the code → stores its PAT (0600) → drops a compiled plugin exposing a per-agent launcherplexus-<agentId>on its PATH. - The agent discovers + calls through its launcher.
plexus-<agentId> listshows what it can call right now (standing-granted) vs what needs approval;plexus-<agentId> <capabilityId>invokes. That launcher is the agent's complete and only interface — it never hand-rolls HTTP and never guesses auth.
What you expose is modeled as Connector → Source → Capability: a managed source
(e.g. an Obsidian vault) registers capabilities (e.g. obsidian.vault.read) live with
no restart — they appear immediately in the admin surface, and an agent discovers
them once the owner adds them to that agent's authorized subset. What you trust
is a unified model:
per-capability scoped grants, trust-windows (once / 1h / 1d / 7d /
until-revoked), 3-class provenance (first-party / managed / extension), a
sensitivity rating, and the GET /grants ledger where every standing grant is
visible and revocable.
Standing is decided by sensitivity, not origin. A read capability lands
standing (frictionless re-use, 1d/7d) at connect. A side-effecting capability
(write / execute, e.g. claudecode.run) is approved per use by default — a
posture the agent can never lift itself. Only the owner can lift it, per agent +
per capability: the standing opt-in at connect (default off, double-confirmed —
the only path for execute), or, for a write, approving its pending request with a
real trust window or granting it directly; once lifted, it rides a real trust-window /
until-revoked.
The agent interface is compiled, not bolted on. The per-agent launcher ships inside
a Claude Code plugin that is a projection over the always-present self-describing
floor (.well-known + requestShapes + how-to-use). The floor works for any agent
with no plugin at all; the plugin is a cache/shortcut that makes the same capabilities
feel more native per agent — never a replacement, and never a place a durable secret is
baked in.
→ Deep dive: docs/concepts.md ·
Security model: docs/design/security-model.md ·
Protocol contract: docs/protocol/PLEXUS-PROTOCOL.md
First-party sources (macOS-first; code + hermetic-test verified — live E2E against real macOS TCC apps was not run this round, see KNOWN-LIMITATIONS):
- Obsidian — read-only path-confined filesystem read (
obsidian.vault.read), or read-write via the Obsidian Local REST API plugin (obsidian-rest.vault.{list,read,write}). - Apple Calendar — read-only (
grants:["read"]by construction). - Apple Reminders — read and write.
- Apple Notes — read + a create-only write (
apple-notes.notes.create; no update/delete exists). - Apple Mail — strictly read-only (mailboxes, bounded search, read one message; no draft/send exists).
- Apple Contacts — read-only search + full-card read.
- Apple Photos — read posture: albums, metadata-only search, and a jailed export
(
~/.plexus/exports/photos/). - Shortcuts — list (read) + run (execute → pends; record-mode by default, real launch is owner opt-in).
- Browser — read-only Safari/Chrome tabs, bookmarks, history (per-browser graceful degradation).
- Browser control (
browser-control) — drive a real Chrome over the DevTools Protocol, no Puppeteer/Playwright dependency. The owner's decision is which browser: a fresh empty profile (launch, the default — no cookies, no sessions) or the browser they are logged into (attach, opt-in). The page surface is fully open, arbitrary JavaScript included, because inside an authorized pageclick+typealready equal full user agency; what is withheld is the browser-global half of CDP (Target,Browser,Storage, the cookie jar), which is what keeps a domain allowlist meaningful. File upload is jailed to an owner-named directory. - Workspace (
workspace) — one authorized working directory as a path-confined filesystem: read (workspace.{list,read}) and write (workspace.write→ pends). - Claude Code (
claudecode) — headless Claude Code under macOSsandbox-execconfinement (claudecode.run,execute→ pends). - Codex (
codex) — headlesscodex execunder the same sandbox confinement, a mirror ofclaudecode.run(codex.run,execute→ pends).
Each source reports its own health (agent-facing field + the admin dashboard via
GET /admin/api/health), so an agent — and you — can see when a backing app is
unreachable before a call fails.
User extensions — author a manifest, preview the security surface (cli bins, rest hosts, cross-source attaches, per-capability verbs), then install it live:
plexus extension preview ./my-source.json # validate + show the security surface (no commit)
plexus extension add ./my-source.json # install live (you are the human approver)
plexus extension list
plexus extension remove my-sourceOr do all of it from the /admin UI. An authoring guide for coding agents is
served at GET /admin/api/extensions/authoring-guide.
→ Tutorials: connect an agent · create an extension · first-party sources
Overview — the dashboard: what's exposed, what needs you, recent activity.
What I expose — the Connector → Source → Capability surface, with the dynamic config form for adding a source.
Create an extension — author a manifest and preview its security surface before it ever goes live.
- Loopback by default. The gateway binds
127.0.0.1only. Binding to a chosen NIC or0.0.0.0is opt-in (~/.plexus/network.json), and when you do, every/admin/api/*route is connection-key gated — the connection-key becomes the trust boundary for the LAN. - Host/Origin guard on every endpoint before auth (DNS-rebinding defense); a
request without the matching
Hostis rejected (host_forbidden, 403). - Default-deny, scoped invoke. A grant is per-capability and verb-scoped; tokens
are short-lived. Mutating (
write/execute) grants pend for a human — an agent cannot self-grant them. - Re-gating on change. Reconfiguring a source's endpoint/secret purges its grants, so a prior approval can't silently carry over to a new target.
- Secrets are stored under
~/.plexus/secrets/and referenced by name — never written into config files, never echoed back.
→ Full write-up: docs/security.md
Plexus is a Bun + TypeScript + Hono workspace monorepo:
packages/
protocol/ the keystone — the compiler-enforced wire contract (frozen at 0.1.3)
runtime/ the headless loopback gateway (discovery, grants, invoke, audit, sources)
cli/ the `plexus` CLI (discover / manifest / skills / call / source / extension / bundle)
web-admin/ the same-origin React management UI
desktop/ the Electron shell (macOS) — supervisor + tray + native notifications
The OS surface lives behind a single PlatformServices seam: macOS is the shipped,
fully-implemented target, and Linux is implemented and end-to-end verified — the
headless portable gateway runs on a real Linux kernel in Docker (Ubuntu + Bun; see
docs/deploy-linux.md), auto-gating first-party sources to the
portable {workspace, sysinfo} set. Windows is implemented behind the same seam
but not yet validated on a real Windows host — so cross-platform is a fill-in, not a
rewrite.
The protocol is frozen at PLEXUS_PROTOCOL_VERSION = 0.1.3 and evolves
additive-only — new optional fields, never a breaking change to the wire.
Plexus carries two independent version numbers, and the distinction matters:
| What it is | How it moves | Who depends on it | |
|---|---|---|---|
Software version (PLEXUS_VERSION, e.g. 0.9.1) |
the product release — the gateway, desktop app, sources, UI | fast — every feature/fix bumps it | nobody on the wire; it's informational (shown in the admin UI as running · v0.9.1) |
Protocol version (PLEXUS_PROTOCOL_VERSION, 0.1.3) |
the agent-facing wire contract — the shapes of discover / handshake / grant / invoke | rarely — frozen, additive-only (a new optional field bumps the patch) | agents integrate against this, never the software version |
They are decoupled by design: the product can ship 0.6 → 0.7 → 1.0 … while the
protocol stays 0.1.x, because the wire is stable under a fast-moving app. An agent
that integrated at protocol 0.1.0 keeps working across every software release — it only
needs to care when the protocol version changes (and even then, additively). The admin
UI surfaces both, distinctly: running · v<software> · protocol <protocol>.
Tags/releases track the software version (
v0.9.1). The protocol version lives in code (@plexus/protocol) and.well-known/plexus, and bumps on its own schedule.
bash run-tests.sh # the canonical gate: bunx tsc --noEmit (strict) + bun test
bunx tsc --noEmit # typecheck only
bun test # tests onlySee CONTRIBUTING.md for the monorepo layout, the additive-only
protocol rule, and how to author a source module or an extension.
| Doc | What it covers |
|---|---|
| Developer reading path | Start here to understand + build — the spine that orders the docs below. |
| Getting started (macOS) | Install → start → connect an agent (mint a code + grant a cap-set), end to end. |
| Concepts | The self-describe protocol, the trust model, sources & extensions. |
| Security | Loopback boundary, connection-key, Host/Origin guard, re-gating. |
| Connect an agent | Drive Plexus from a coding agent. |
| Create an extension | Author + preview + install a manifest. |
| First-party sources | Obsidian, Apple Calendar/Reminders/Notes/Mail/Contacts/Photos, Shortcuts, browser, Claude Code. |
| Protocol contract | The frozen wire spec + the ADRs. |
| Known limitations | Honest pre-1.0 state: MCP ingestion, io.input scope, desktop/cross-platform not E2E-verified. |
Contributions welcome — see CONTRIBUTING.md. This project follows
the Contributor Covenant.
MIT © 2026 Plexus contributors.



