Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
f82aead
docs: plan daemon-first setup onboarding
Jun 30, 2026
a1002d4
feat(core): add add-mcp adapter contract
Jun 30, 2026
1248064
feat(core): support local daemon attach
Jun 30, 2026
ca49cce
feat(core): orchestrate daemon-first setup
Jun 30, 2026
2e309cf
feat(core): wire setup through add-mcp adapter
Jun 30, 2026
27afad2
feat(core): add native daemon defaults
Jun 30, 2026
2be2588
feat(core): polish daemon setup compatibility
Jun 30, 2026
c1e8df3
docs: promote daemon-first setup
Jun 30, 2026
0cb761a
fix(core): preserve loopback remote profiles
Jun 30, 2026
c00d066
fix(opencode): avoid native stdio warnings
Jun 30, 2026
af33f4a
chore: add daemon-first setup changeset
Jun 30, 2026
d48554c
fix(native): let env override setup defaults
Jun 30, 2026
fbb9c51
fix(setup): avoid remote auth for local daemon onboarding
Jun 30, 2026
6cde86b
docs(plan): add global serve config defaults plan
Jun 30, 2026
f441450
feat(config): add global serve config surface
Jun 30, 2026
68cba10
feat(serve): apply global serve defaults
Jun 30, 2026
680aff9
feat(serve): support multiple public origins
Jun 30, 2026
45bdbf2
feat(daemon): refresh serve defaults on restart
Jun 30, 2026
1bd35e0
test(setup): preserve local daemon safety with serve defaults
Jun 30, 2026
518782b
docs(config): document global serve defaults
Jun 30, 2026
5224e56
refactor(serve): share global defaults loader
Jun 30, 2026
f5607ec
fix(serve): honor secondary public origins for credentials
Jun 30, 2026
6b3c985
fix(setup): address daemon onboarding review feedback
Jun 30, 2026
6a2fe5e
fix(remote): trust persisted daemon before local attach
Jun 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .changeset/daemon-first-setup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
"@caplets/core": patch
"caplets": patch
"@caplets/opencode": patch
"@caplets/pi": patch
---

Promote daemon-first local setup. `caplets setup` now initializes config, starts or reuses the local daemon, verifies health before mutating integrations, and configures MCP clients as thin `caplets attach <local-daemon-url>` clients through the pinned `add-mcp` adapter.

Add explicit native daemon mode and setup-written daemon defaults for OpenCode and Pi, while keeping remote/cloud setup on Remote Login and secret-free attach paths.
6 changes: 6 additions & 0 deletions .changeset/global-serve-config.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@caplets/core": patch
"caplets": patch
---

Add top-level user `serve` config defaults for HTTP Caplets serving. Foreground `caplets serve --transport http` and daemon restarts can now reuse configured host, port, path, upstream URL, remote state path, public origins, proxy trust, and unauthenticated HTTP intent while project config ignores `serve` for security.
12 changes: 12 additions & 0 deletions CONCEPTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ A per-user native service managed by `caplets daemon` that runs local HTTP `capl

The Caplets Daemon is installed and updated through an install-time service contract. Runtime lifecycle commands operate on the installed service rather than changing its persisted serve or environment configuration.

### Daemon-First Setup

The local onboarding path where `caplets setup` prepares the user config and a healthy Caplets Daemon before configuring agent integrations.

Daemon-First Setup points MCP clients at `caplets attach <local-daemon-url>` and points native integrations at the local daemon runtime, so backend execution uses the daemon-owned environment instead of depending on MCP client environment passthrough.

### Caplets Vault

A runtime-owned encrypted string store whose values can be referenced from Caplets config with `$vault:NAME` or `${vault:NAME}`.
Expand Down Expand Up @@ -184,6 +190,12 @@ A local HTTP Caplets runtime that serves local Caplets while composing an upstre

Stacked Remote Runtime keeps project context session-scoped. `caplets attach` supplies the project root for a client session, while the long-running runtime owns env, Remote Profile, Project Binding, health, and composition behavior.

### Public Origin

An externally meaningful origin for a Caplets HTTP serve process.

Public Origins participate in host/audience identity for HTTP serve, Remote Login, and attach routes. They are not a project-controlled allowlist or a general network authorization policy.

### Remote Login

The provider-neutral flow that trusts a local Caplets client to a Caplets host, whether the host is self-hosted or Caplets Cloud.
Expand Down
81 changes: 57 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,19 +65,43 @@ caplets install
caplets update osv
```

Or add Caplets manually to any MCP client:
`caplets setup` is the recommended local path. It creates or reuses your Caplets config,
starts the local Caplets daemon, and configures the agent as a thin client that runs
`caplets attach <local-daemon-url>`. The daemon owns backend execution, environment,
Vault values, reloads, and health while the agent config stays stable and secret-free.

Manual daemon-backed MCP config looks like this:

```json
{
"mcpServers": {
"caplets": {
"command": "caplets",
"args": ["serve"]
"args": ["attach", "<local-daemon-url>"]
}
}
}
```

You can put HTTP serve defaults in your user Caplets config when you run a foreground
HTTP server or want daemon restarts to reuse a non-default port, path, upstream, or public
origin. These defaults live under top-level `serve`, are ignored from project config for
security, and lose to command flags and environment variables:

```json
{
"serve": {
"host": "127.0.0.1",
"port": 5387,
"publicOrigins": ["https://caplets.example.com"]
}
}
```

`serve.publicOrigins` are full origins used for public request identity, not host-only
allowlists. `caplets setup` still prepares a credential-free loopback daemon before
mutating agent config, even if your user `serve` defaults describe a broader HTTP runtime.

## Use Caplets

Add your own capability sources:
Expand Down Expand Up @@ -107,32 +131,40 @@ handles so discovery, execution, filtering, and synthesis can happen in one call

## Agent Surfaces

Caplets works as a regular MCP server through `caplets serve`. By default, that server exposes
Code Mode for the configured backends. Caplets also has native integrations for agents that can
load packages directly:
Caplets' default local agent setup is daemon-first. `caplets setup` initializes user
configuration, installs or starts the local Caplets daemon, checks health, and then
configures the selected agent as a thin attach/native client. This avoids relying on
each MCP client to inherit the same shell environment as your terminal; backend
execution happens in the Caplets daemon instead.

| Agent | Setup |
| ----------------------------------------- | ----------------------------------------------------------------------------------------------- |
| Codex, Claude Code, and other MCP clients | `caplets setup` or `caplets serve` |
| OpenCode | [`@caplets/opencode`](https://github.com/spiritledsoftware/caplets/tree/main/packages/opencode) |
| Pi | [`@caplets/pi`](https://github.com/spiritledsoftware/caplets/tree/main/packages/pi) |
| Agent | Recommended local setup |
| ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| Codex, Claude Code, and other MCP clients | `caplets setup` or `caplets setup mcp-client --client codex` for an explicit add-mcp client target |
| OpenCode | `caplets setup opencode` or [`@caplets/opencode`](https://github.com/spiritledsoftware/caplets/tree/main/packages/opencode) |
| Pi | `caplets setup pi` or [`@caplets/pi`](https://github.com/spiritledsoftware/caplets/tree/main/packages/pi) |

`caplets setup` uses each harness's MCP configuration command:

```sh
codex mcp add caplets -- caplets serve
claude mcp add --transport stdio --scope user caplets -- caplets serve
```

Equivalent local Codex config:
For MCP clients, setup uses the `add-mcp` client catalog under the hood and writes a
Caplets server command shaped like this:

```toml
[mcp_servers.caplets]
command = "caplets"
args = ["serve"]
args = ["attach", "<local-daemon-url>"]
```

```json
{
"mcpServers": {
"caplets": {
"command": "caplets",
"args": ["attach", "<local-daemon-url>"]
}
}
}
```

For a remote or Cloud-backed MCP server, point the client at `caplets attach` instead:
For a remote or Cloud-backed MCP server, keep the same thin-client shape and point
`caplets attach` at the remote URL after Remote Login:

```toml
[mcp_servers.caplets]
Expand All @@ -151,9 +183,9 @@ args = ["attach", "https://caplets.example.com/caplets"]
}
```

`caplets attach <url>` is always the stdio client command for MCP configs. To run a
long-lived local HTTP runtime that composes local and project Caplets with an upstream
host, start the runtime separately:
`caplets attach <url>` is always the stdio client command for MCP configs. As an
advanced manual fallback, you can still run a foreground HTTP runtime yourself, for
example to compose local/project Caplets with an upstream host:

```sh
caplets serve --transport http --upstream-url https://caplets.example.com/caplets
Expand All @@ -163,7 +195,8 @@ Then point agents at that local runtime with `caplets attach <local-runtime-url>

Native integrations expose `caplets__code_mode` for multi-step TypeScript workflows over
generated `caplets.<id>` handles. Progressive exposure adds `caplets__<id>` tools; direct
exposure adds operation-level tools such as `caplets__<id>__<operation>`.
exposure adds operation-level tools such as `caplets__<id>__<operation>`. `caplets setup`
writes non-secret daemon defaults for OpenCode and Pi; explicit plugin settings still win.

Remote mode uses Remote Login for both self-hosted Caplets and Caplets Cloud. Trust the
host once, then launch attach or a native integration with only non-secret selectors:
Expand Down
57 changes: 44 additions & 13 deletions apps/docs/src/content/docs/agent-integrations.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,83 +6,114 @@ description: Use Caplets with Codex, Claude, OpenCode, and Pi.
Caplets works with Codex, Claude, OpenCode, Pi, and other MCP clients. Code Mode is the
default surface for configured capabilities.

Local setup is daemon-first: `caplets setup` initializes user Caplets config, installs or
starts the local Caplets daemon, verifies daemon health, and then configures the selected
agent as a thin `caplets attach <local-daemon-url>` or native client. This solves the
environment passthrough problem in clients that do not launch MCP servers with the same
shell environment as your terminal; backend execution happens in the Caplets daemon.

## Codex

Run setup:

```sh
caplets setup
caplets setup codex
```

Manual local MCP config:
Equivalent daemon-backed local MCP config:

```toml
[mcp_servers.caplets]
command = "caplets"
args = ["serve"]
args = ["attach", "<local-daemon-url>"]
```

## Claude

Run setup:

```sh
caplets setup
caplets setup claude-code
```

Manual setup uses Claude's MCP command:
Manual setup should still point Claude at the daemon-backed attach client:

```sh
claude mcp add --transport stdio --scope user caplets -- caplets serve
claude mcp add --transport stdio --scope user caplets -- caplets attach http://127.0.0.1:5387/
```

## OpenCode

OpenCode can use Caplets through MCP or the native OpenCode integration. Native mode exposes
`caplets__code_mode` for Code Mode, plus progressive or direct tools only when configured.

```sh
caplets setup opencode
```

Local setup installs the native plugin and writes non-secret daemon defaults. Explicit
OpenCode plugin config still wins over those defaults.

Native integrations use the shared anonymous telemetry controls and do not send telemetry on a
native-first run until a visible CLI telemetry notice has already been recorded.

Remote native usage:

```sh
caplets remote login https://caplets.example.com/caplets
CAPLETS_MODE=remote CAPLETS_REMOTE_URL=https://caplets.example.com/caplets opencode
```

## Pi

Pi can use Caplets through MCP or the native Pi integration. Native mode uses the same local
and remote selection rules as OpenCode.
Pi can use Caplets through MCP or the native Pi integration. Native mode uses the same local,
daemon, remote, and Cloud selection rules as OpenCode.

```sh
caplets setup pi
```

Local setup installs the Pi extension and writes non-secret daemon defaults. Explicit Pi
settings still win over those defaults.

Native integrations use the shared anonymous telemetry controls and do not send telemetry on a
native-first run until a visible CLI telemetry notice has already been recorded.

Remote native usage:

```sh
caplets remote login https://caplets.example.com/caplets
CAPLETS_MODE=remote CAPLETS_REMOTE_URL=https://caplets.example.com/caplets pi
```

## Other MCP clients

Use:
Use the `add-mcp` client catalog through Caplets setup:

```sh
caplets setup mcp-client --client <client-id>
```

If you write config manually, keep the agent as a thin daemon client:

```json
{
"mcpServers": {
"caplets": {
"command": "caplets",
"args": ["serve"]
"args": ["attach", "<local-daemon-url>"]
}
}
}
```

For remote-backed MCP, use `caplets attach` instead of `caplets serve`.
For remote-backed MCP, use `caplets attach <remote-url>` after `caplets remote login
<remote-url>`. Agent configs should not contain Caplets remote tokens, passwords, or
provider environment variables.

`caplets attach <url>` is stdio-only. If you want one local HTTP runtime to own environment,
Vault, Remote Login, reloads, and logs while still composing an upstream host, run:
As an advanced manual fallback, `caplets serve` can still run a foreground HTTP or stdio
runtime. If you want one local HTTP runtime to own environment, Vault, Remote Login,
reloads, and logs while composing an upstream host, run:

```sh
caplets serve --transport http --upstream-url https://caplets.example.com/caplets
Expand Down
35 changes: 35 additions & 0 deletions apps/docs/src/content/docs/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,41 @@ CAPLETS_CONFIG=/path/to/caplets.json caplets doctor
`CAPLETS_CONFIG` is useful in CI, tests, or temporary sessions where you want a different
user config file.

### HTTP serve defaults

User config can define optional HTTP `serve` defaults for foreground `caplets serve
--transport http` and the managed local daemon:

```json
{
"$schema": "https://caplets.dev/config.schema.json",
"serve": {
"host": "127.0.0.1",
"port": 5387,
"path": "/",
"publicOrigins": ["https://caplets.example.com"]
},
"mcpServers": {}
}
```

Precedence is command flags, then environment variables, then user `serve` config, then
built-in defaults. `caplets daemon restart` re-resolves user `serve` defaults for daemon
fields that were not set explicitly at daemon install time.

`serve.publicOrigins` entries are full origins, not host-only allowlists. They are used for
public request identity such as DNS rebinding checks and remote credential audiences. The
config surface intentionally has no transport field under `serve`; choose transport on the
command line.

Keep `serve` in user config only. Project config ignores `serve` and warns because project
repositories should not control a developer's local HTTP bind address, auth posture, or
public origins.

`caplets setup` remains safer than a hand-written MCP server. Local setup always prepares a
credential-free loopback daemon before writing agent config, even if user `serve` defaults
describe a broader foreground or self-hosted HTTP runtime.

## Project config

Project config lives at:
Expand Down
20 changes: 10 additions & 10 deletions apps/docs/src/content/docs/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,8 @@ stdio server.

## Quick Start

Run a known-good no-auth setup first. OSV is public, so it is the fastest way to prove
your agent can see and call a Caplet.

```sh
npx caplets setup
npx caplets install spiritledsoftware/caplets osv
npx caplets doctor
```

Or install it globally:
Install the CLI, then run a known-good no-auth setup first. OSV is public, so it is the
fastest way to prove your agent can see and call a Caplet.

```sh
npm install -g caplets
Expand All @@ -30,6 +22,14 @@ caplets install spiritledsoftware/caplets osv
caplets doctor
```

Use `npx caplets ...` only for temporary foreground commands; daemon-backed agent setup
expects a stable installed `caplets` binary on `PATH`.

`caplets setup` is daemon-first: it initializes Caplets config, starts or reuses the
local Caplets daemon, and configures your agent as a thin `caplets attach
<local-daemon-url>` or native client. The daemon owns backend execution and environment
passthrough, so agent configs do not need secrets or provider-specific environment values.

Comment thread
coderabbitai[bot] marked this conversation as resolved.
`doctor` should identify the active Caplets config path and report the checks it can run
for your configured integrations. Fix any failed check before testing through an agent.

Expand Down
Loading
Loading