Skip to content

The bundled first-party sources

Plexus ships a set of first-party capability sources so an agent has something real to discover the moment you boot the gateway. This page covers each one: its capability ids, the grants it requires, how to enable and configure it, its prerequisites, and the honest read-only vs. write surface.

The sources:

SourceAccessPrereq
Obsidian (obsidian-fs)reada vault folder on disk
Obsidian (obsidian-rest)read + writeObsidian Local REST API plugin
Apple CalendarreadmacOS + Calendar TCC
Apple Remindersread + writemacOS + Reminders TCC
Things 3read + writeThings 3 installed
cc-masterexecute / write / readClaude Code (claude) on PATH
Workspace (workspace)read + writean authorized working directory on disk
Claude Code (claudecode)execute (sandbox-confined)claude on PATH + macOS sandbox-exec
Codex (codex)execute (sandbox-confined)codex CLI on PATH + macOS sandbox-exec

Two enablement shapes

The Apple sources, Things, cc-master, and the three sandbox-confined demo/agent sources (Workspace, Claude Code, Codex) are compiled in and auto-register — no add step. The Obsidian adapters are managed sources you add at runtime (CLI or /admin). Both shapes are covered below.

Safety posture (applies to all of them)

Default-deny: an agent holds zero call authority until it requests a grant. Reads on a first-party source auto-approve; writes are elevated-sensitivity and pend for human approval (the grant_pending_user dance — see Connect an agent). An agent can never self-grant a mutating call. See the project README and Get running for the trust model.


Obsidian

An Obsidian vault is just a folder of .md files. Plexus exposes it two ways; pick based on whether you need writes.

obsidian-fs — direct, read-only, path-confined

Capability idKindGrantsSurface
obsidian.vault.readcapabilityreadread-only by construction
obsidian.vault.how-to-citeskillusage guidance (read as context)

Read-only by construction — there is no write/execute path in the code — and path-confined: a ../ traversal, an absolute path, or a symlink escaping the vault is rejected, never served.

Prerequisites: a vault folder on disk. No Obsidian app, no plugin, no secret.

Enable it (a managed source — it persists to ~/.plexus/sources.json and hot-loads with no restart). From the repo root:

sh
# via the plexus CLI
bun run packages/cli/src/bin/plexus source add obsidian-fs --vault-path ~/Documents/MyVault

# or the launcher shortcut (persists the same managed source)
bun run start --vault ~/Documents/MyVault

You can also add it from the Sources tab in /admin. Confirm it hot-appeared:

sh
curl -s -H "Host: 127.0.0.1:7077" http://127.0.0.1:7077/.well-known/plexus | bun -e \
  'const d = await Bun.stdin.json(); console.log(d.capabilities.map(c => c.id).join("\n"))'
# → … obsidian.vault.read …

obsidian-restread + write via the Local REST API plugin

Capability idKindGrantsSurface
obsidian-rest.vault.listcapabilityreadlist vault entries
obsidian-rest.vault.readcapabilityreadread a note
obsidian-rest.vault.writecapabilitywritecreate/overwrite a note → PENDS
obsidian-rest.vault.how-to-useskillusage guidance

Prerequisites: the Obsidian Local REST API plugin installed and running in the Obsidian app on the same Mac. The plugin serves HTTPS on loopback (default https://127.0.0.1:27124) and authenticates with a Bearer API key from its settings. Plexus accepts the plugin's self-signed cert only because the host resolves to loopback; the transport re-checks loopback before every call.

Enable it. The API key is read from STDIN only — never argv, which would leak via ps — and stored by name in ~/.plexus/secrets/, never echoed back:

sh
printf %s "$OBSIDIAN_KEY" | bun run packages/cli/src/bin/plexus source add obsidian-rest \
    --base-url https://127.0.0.1:27124 --secret-name obsidian-local-rest-api-key --api-key-stdin

obsidian-rest.vault.write carries a write grant, so granting it pends for a human: the agent gets grant_pending_user, you approve in the Approvals tab. The two reads auto-approve. Reconfiguring a source's --base-url or secret purges its grants, so a prior approval can't carry over to a new endpoint. Full source management: docs/sources/MANAGING-SOURCES.md.


Apple Calendar — read-only

Capability idKindGrantsSurface
apple-calendar.calendars.listcapabilityreadlist calendars
apple-calendar.events.listcapabilityreadlist events in a window
apple-calendar.how-to-useskillusage guidance

Read-only by construction — the provider exposes only listCalendars() / listEvents(); there is no write path. Auto-registers (compiled-in, first-party); no add step.

Prerequisites (real macOS): the Calendar app, and a one-time macOS TCC grant. The first live call shells out to osascript -l JavaScript (JXA) and triggers the macOS consent dialog — System Settings ▸ Privacy & Security ▸ Automation (and Calendars). If you deny, the call fails with a precise "enable it in System Settings" message; Plexus cannot re-prompt for you, so you re-grant in System Settings.

Hermetic mode (no macOS, no TCC): set PLEXUS_FAKE_APPLE=1 and the source resolves a fake provider with deterministic in-memory fixtures (sample calendars Home / Work / Birthdays and sample events). This is how the acceptance playbook and the test gate run.

sh
PLEXUS_FAKE_APPLE=1 bun run start     # fake providers — no TCC, deterministic fixtures

Apple Reminders — read + write

Capability idKindGrantsSurface
apple-reminders.lists.listcapabilityreadlist reminder lists
apple-reminders.reminders.listcapabilityreadlist reminders
apple-reminders.reminders.createcapabilitywritecreate a reminder → PENDS
apple-reminders.reminders.completecapabilitywritemark a reminder done → PENDS
apple-reminders.skill.how-to-useskillusage guidance

The two write capabilities mutate the user's Reminders — their describe says so — and both carry a write grant, so they pend for approval. The two reads auto-approve. Auto-registers (compiled-in, first-party).

Prerequisites (real macOS): the Reminders app, and a one-time TCC grant (System Settings ▸ Privacy & Security ▸ Automation + Reminders). The real provider shells osascript (AppleScript) against tell application "Reminders"; the first live use prompts. Hermetic mode: PLEXUS_FAKE_APPLE=1 (seed lists Reminders / Groceries; create/complete mutate the in-memory store).


Things 3 — read + write

Capability idKindGrantsSurface
things.todos.listcapabilityreadlist to-dos (AppleScript)
things.projects.listcapabilityreadlist projects (AppleScript)
things.todos.addcapabilitywriteappend a to-do → PENDS
things.how-to-useskillusage guidance

A surface split worth knowing: reads go through the AppleScript dictionary (tell application "Things3"), but the write (things.todos.add) uses the Things URL-scheme (things:///add?title=…&notes=…&when=…&list=…). That makes the write a well-bounded append — not arbitrary mutation — but it still carries a write grant and pends for approval. Auto-registers (compiled-in, first-party).

Prerequisites (real macOS): Things 3 installed (detected via an osascript version probe). The write opens the things:// URL via the open binary. Hermetic mode: PLEXUS_FAKE_APPLE=1 (seed to-dos + projects; add mutates the in-memory store).

The injectable-provider / TCC story (all three Apple sources)

Each source selects its provider through one env check: process.env.PLEXUS_FAKE_APPLE === "1" → the fake provider with fixtures, otherwise the real macOS provider (which drives osascript/JXA or the Things URL-scheme and is gated by macOS TCC on first use). The selection is also injectable for unit tests. PLEXUS_FAKE_APPLE=1 is therefore the single switch for a hermetic, TCC-free run — used by bash run-tests.sh, the tests/harnesses/acceptance-apple playbook, and CI.

osascript performance, honestly

The Apple providers drive Calendar / Reminders through osascript, which is slow on very large stores — listing hundreds or thousands of items can take noticeable seconds. Scope queries to a window or a specific list rather than asking for everything.


cc-master — Claude Code orchestration

cc-master is a managed launcher for the Claude Code long-horizon orchestration plugin. It spawns claude --plugin-dir <embedded cc-master> -p … headless and never mutates your ~/.claude — the plugin is auto-loaded into the managed session via --plugin-dir injection.

Capability idKindGrantsNotes
cc-master.session.launchcapabilityexecutelaunch a headless Claude Code session (always exposed)
cc-master.orchestration.runworkflowexecutethe flagship orchestration workflow
cc-master.board.createcapabilitywritecreate an orchestration board
cc-master.agent.dispatchcapabilityexecutedispatch a managed sub-agent
cc-master.board.statuscapabilityreadread board status
cc-master.skill.orchestrating-to-completionskillusage guidance
cc-master.skill.authoring-workflowsskillusage guidance
cc-master.skill.as-master-orchestratorskillusage guidance
cc-master.skill.statusskillusage guidance

All the execute / write capabilities pend for approval (default-deny per capability); board.status is a read. The orchestration surface beyond session.launch is gated by a config flag (below); when off, only cc-master.session.launch is exposed.

Prerequisites: the claude binary on PATH, with the plugin installed under ~/.claude/. Plexus auto-detects cc-master when both are present and surfaces the capabilities.

Enable / configure:

  • If cc-master isn't enabled yet, use the Install cc-master action in /admin. It performs an idempotent, audited install — it only adds the two settings keys that enable the plugin and register its marketplace, never rewriting unrelated settings. Already enabled ⇒ safe no-op.
  • The exposure gate persists to ~/.plexus/cc-master.json as { "loadCcMaster": <bool> } (default true); the /admin cc-master config toggles it (GET/POST /admin/api/cc-master/config).

Confirm detection from discovery:

sh
curl -s -H "Host: 127.0.0.1:7077" http://127.0.0.1:7077/.well-known/plexus | bun -e \
  'const d = await Bun.stdin.json();
   console.log(d.capabilities.filter(c => c.id.startsWith("cc-master")).map(c => c.id).join("\n"))'

Launch is gated for safety

A bare bun run start (and the whole test gate) runs cc-master in record-only mode: cc-master.agent.dispatch records the dispatch on a real board and returns the argv it would run, without spawning claude. The shipped desktop app flips the gate on (PLEXUS_CC_HEADLESS_LAUNCH=1) so launch executes for real; set that env var manually to make a bare runtime launch. See tests/harnesses/acceptance/README.md.


Workspace — sandboxed working directory (read + write)

workspace exposes one authorized working directory on disk as a path-confined filesystem surface — the agent's scratch/output folder for the demo flows. It is the companion read/write surface to the two sandboxed runners below: an agent lists and reads files here, has Claude Code or Codex build inside the same jail, then reads the products back.

Capability idKindGrantsSurface
workspace.listcapabilityreadlist a directory (read-only)
workspace.readcapabilityreadread a file (read-only)
workspace.writecapabilitywritecreate/overwrite a file → PENDS
workspace.how-to-useskillusage guidance

Path-confined like the Obsidian vault reader: every path resolves under the workspace root and is rejected if it escapes (.., absolute, or symlink-out). The two reads (list/read) auto-approve; workspace.write carries a write grant on a first-party source, so it pends for the owner. Auto-registers (compiled-in, first-party); availability — does the authorized directory exist? — is reported via health, never by hiding the entries.


Claude Code — headless, sandbox-confined (execute)

claudecode exposes the Claude Code CLI as one sensitive capability: launch headless Claude Code to do real coding work, confined by macOS sandbox-exec to the authorized directory. The agent never sees a shell or the launch command — only a { prompt }. Reads and writes outside the jail fail at the kernel.

Capability idKindGrantsSurface
claudecode.runcapabilityexecutelaunch headless Claude Code in the jail → PENDS
claudecode.how-to-useskillusage guidance

claudecode.run is an execute on a first-party source, so it is elevated and pends for the owner: issue the call and wait for approval. Verify the products between calls via workspace.read. Auto-registers (compiled-in, first-party); whether claude + sandbox-exec are present surfaces via health, not by hiding the entry.


Codex — headless, sandbox-confined (execute)

codex is the mirror of claudecode: it runs the local Codex CLI (codex exec) headless to do real coding work, confined by macOS sandbox-exec to the authorized directory. Same posture — only a { prompt } (plus an optional in-jail cwd), and reads and writes outside the jail fail at the kernel.

Capability idKindGrantsSurface
codex.runcapabilityexecutelaunch headless codex exec in the jail → PENDS
codex.how-to-useskillusage guidance

codex.run is an execute on a first-party source, so it pends for the owner: issue the call and wait. If the local codex CLI is absent, the call reports source_unavailable rather than failing the session. Auto-registers (compiled-in, first-party); presence of codex + sandbox-exec surfaces via health.


Where to go next