Skip to content

nemori-ai/plexus

Repository files navigation

Plexus

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.

License: MIT Protocol 0.1.2 Runtime: Bun + TypeScript Platform: macOS-first


▶︎ Try it in 5 minutes — hand it to your AI

Open Claude Code (or any coding agent) in this repo and say: "read START-HERE.md and set up the pomodoro demo for me." It installs, starts Plexus, configures everything (asking you for a folder and an LLM key), and runs both acts — while you approve each grant in the Plexus UI. You'll watch a remote agent build a real app on your Mac with no shell, locked to one folder, every powerful move approved by you. The onboarding is Plexus's thesis, compiled into your agent's native form.

START-HERE.md — the agent-executable runbook (also a fine copy-paste guide if you'd rather drive by hand).

Where to start

You want to… Go to
See what Plexus is and why you're on the right page — read on
Run the demo (hand the repo to your agent) START-HERE.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.


Why Plexus

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 and Reminders, your Things 3 inbox, 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.


Quick start (macOS)

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 demo

First 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.


Concepts (the 60-second model)

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:

  1. 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.
  2. 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 launcher plexus-<agentId> on its PATH.
  3. The agent discovers + calls through its launcher. plexus-<agentId> list shows 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) that hot-appear in discovery with no restart. 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 can be standing (frictionless re-use, 1d/7d) once approved. An execute or otherwise high-sensitivity capability (e.g. claudecode.run) can never be standing — it is approved per use with a once ceiling, even under an admin trust-window.

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


What's exposed

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.
  • Things 3 — AppleScript read + a narrow URL-scheme write ("append a to-do").
  • cc-master — Claude Code long-horizon orchestration, launched headless with an embedded plugin (it never touches your ~/.claude/).
  • 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 macOS sandbox-exec confinement (claudecode.run, execute → pends).
  • Codex (codex) — headless codex exec under the same sandbox confinement, a mirror of claudecode.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-source

Or 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


Screenshots

Overview — the dashboard: what's exposed, what needs you, recent activity.

Plexus overview

What I expose — the Connector → Source → Capability surface, with the dynamic config form for adding a source.

What I expose

Create an extension — author a manifest and preview its security surface before it ever goes live.

Create an extension


Security posture

  • Loopback by default. The gateway binds 127.0.0.1 only. Binding to a chosen NIC or 0.0.0.0 is 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 Host is 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


macOS-first, with a real cross-platform seam

Plexus is a Bun + TypeScript + Hono workspace monorepo:

packages/
  protocol/    the keystone — the compiler-enforced wire contract (frozen at 0.1.2)
  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; the Windows/Linux implementations are typed stubs behind the same seam, so cross-platform is a fill-in, not a rewrite.

The protocol is frozen at PLEXUS_PROTOCOL_VERSION = 0.1.2 and evolves additive-only — new optional fields, never a breaking change to the wire.


Versioning — two numbers, two clocks

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.7.0-rc.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.7.0-rc.1)
Protocol version (PLEXUS_PROTOCOL_VERSION, 0.1.2) 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.7.0-rc.1). The protocol version lives in code (@plexus/protocol) and .well-known/plexus, and bumps on its own schedule.


Build, test, typecheck

bash run-tests.sh    # the canonical gate: bunx tsc --noEmit (strict) + bun test
bunx tsc --noEmit    # typecheck only
bun test             # tests only

See CONTRIBUTING.md for the monorepo layout, the additive-only protocol rule, and how to author a source module or an extension.


Docs

Doc What it covers
Developer reading path Start here to understand + build — the spine that orders the docs below.
Start here (AI-native onboarding) Hand the repo to Claude Code: it sets up + runs the pomodoro demo while you approve grants.
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, Things 3, cc-master.
Pomodoro demo (Plexus × DeepAgents) A remote agent builds real software on your Mac — no shell, one folder, every powerful move approved.
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.

Contributing & conduct

Contributions welcome — see CONTRIBUTING.md. This project follows the Contributor Covenant.

License

MIT © 2026 Plexus contributors.

About

No description, website, or topics provided.

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors