Install
$ agentstack add mcp-edspencer-paddock ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
🐎 Paddock
Your Claude Code chats, hosted and organized by project. Persistent, resumable Claude Code sessions with a web UI — from your desk or your phone.
Docs • Quickstart • Management API • Configuration • How it works • herdctl • Issues
Why Paddock
Paddock is a project-first launchpad for herdctl. It turns Claude Code into something you run on a server and reach from a browser: long-lived chats, grouped by project, that persist and resume — instead of a laptop full of terminal tabs you can't get back to from your phone.
A project is a directory plus a project.yaml. Paddock runs Claude Code in that directory, and the project is the collection of chats you start there — each one a Claude Code session, persisted on disk and resumable across reloads, reconnects, and devices — together with per-project settings and an OVERVIEW.md and CHANGELOG.md that a post-turn sweeper keeps current out of band. There are two kinds:
- Notebook — a directory in your data repo for planning, notes, and light work.
- Repo-backed — an external git repo cloned as the project's working directory,
so the repo's own CLAUDE.md, branches, and PR flow apply. The natural unit for doing real engineering.
The instance root is a workspace too, so a chat that belongs to no particular project just lives there — and can be promoted into a project later, keeping its history. The whole UI is responsive — the same launchpad works from a phone.
It also runs without you watching. Turns are fired by schedules, lifecycle events and other chats; background work a chat starts survives the turn that started it and wakes Claude when it lands. And the boundary now opens the other way: an instance exposes itself as an MCP server, so Claude Code on your laptop — or CI, or a peer Paddock — can drive it from outside. Less an app you visit, more a service your other tools talk to.
Highlights
- 🗂️ Project-first — every project is a set of chats, with its own files, settings, and generated changelog
- 💬 Persistent, resumable chats — server-hosted sessions survive reloads, reconnects, and devices
- ⌨️ Token-by-token streaming — replies, real tool calls, and subagents render live as they run, with rich tool cards (Edit diffs, Bash exit codes, Grep counts)
- 🛰️ Drive it from outside — an [external Management API](#drive-it-from-outside) serves the management tools as MCP at
/mcp, so Claude Code on your laptop, CI, or a peer Paddock can list projects, read chats, and (with the scope for it) start turns - ⏰ Triggers & automation — run a turn on a schedule, on a lifecycle event, or on demand; each trigger can carry its own scoped toolset
- 🤖 Self-driving — an opt-in, depth-gated in-process MCP lets Claude list projects, read chats, spawn and fork chats to fan work out across parallel sessions, manage a project's triggers, and — behind a further flag — provision new projects
- ⏳ Background work outlives the turn — a build, deploy, or sub-agent Claude backgrounds keeps running after the turn ends and wakes it with the result
- 📎 Send files & images — pick, drag-drop, or paste into the composer; Claude reads images and PDFs natively
- 📁 Files & Changes — browse rendered project files and review Claude's work as git diffs
- 🧩 Two project types — notebook (data-repo subdir) or repo-backed (clone an external repo as cwd)
- 📱 Works from your phone — the same launchpad, fully responsive
- 🔀 Chat ergonomics — star to pin, mark unread, fork or rewind from any message, queue-while-streaming, stop, search, archive; spawned chats nest under the chat that created them
- 🎛️ Settings, per project and per instance — model, permission mode, curation budgets and more per project; an instance-wide Config screen edits
paddock.config.yamlfrom the UI - 🧠 Claude Opus 5 by default — with Opus 4.8, Fable 5, Sonnet 5 and Haiku 4.5 selectable, and an allow-list if you'd rather offer fewer
- 📈 Token & cost tracking — per-chat context meter and estimated API cost, live
- 🎙️ Voice dictation & slash commands — mic-to-text in the composer,
/-autocomplete for skills - 🔌 Built on herdctl — anything the fleet engine can do, Paddock can wire in
Quickstart
One command, from anywhere:
npx @edspencer/paddock -o
That starts the server on http://127.0.0.1:7233 and opens a browser at it. Data lives in ~/.paddock; the directory you run it from makes no difference.
A new instance opens on Discover. It reads your Claude Code history, works out which directories on this machine you have actually been using claude in, and offers them as projects — with conversation counts, last-used dates and git remotes, so you can tell them apart. Tick the ones you want, press Import, and instead of an empty instance you are looking at your own work, resumable. It stays in the sidebar afterwards.
Nothing is written into your directories. No .paddock/, no .chats/, no .gitignore edit, no CLAUDE.md — the project record and the copied transcripts both live in ~/.paddock, and the project just points at the path. Your ~/.claude transcripts are copied, never moved or deleted, so your terminal claude keeps working exactly as before.
Needs Node 22+. First run downloads ~250 MB — Paddock drives Claude Code, and the Agent SDK ships a per-platform binary of that size; later runs reuse the npm cache. For repeated use, npm i -g @edspencer/paddock beats bare npx.
There are two subcommands, and both are optional detail: bare paddock starts the server, paddock start is the same thing said out loud, and paddock service registers it as a background service that comes back at login. Anything else in leading position is an error.
The full flag set — they parse the same after a subcommand as without one, and --help is the canonical short-form reference:
| Flag | Purpose | |---|---| | -p, --port | Listen port. Overrides PORT and port:. Use this when 7233 is taken. | | --host | Bind address. Overrides HOST. | | -d, --data-dir | Data root. Overrides PADDOCK_DATA_DIR. The only flag that picks which instance you get. | | -o, --open | Open a browser once the server is listening. | | --verbose | Restore normal logging; the CLI is quiet by default. | | -h, --help / -v, --version | Usage / version. |
Port 7233 already in use? npx @edspencer/paddock --port 7234. (7233 is also Temporal's default frontend port, which is the usual collision. The failure is loud — Paddock names the port and the flag and exits.)
Always-on: your own laptop
npx is a terminal tab. To keep the same ~/.paddock instance running in the background instead:
npm i -g @edspencer/paddock
paddock service install # uninstall | status
A launchd LaunchAgent on macOS, a systemd --user unit on Linux. It starts at login, not at boot — a per-user agent is what lets it read the Claude login you already have, and on macOS a boot-time daemon structurally cannot (the login Keychain is unlocked by your password at login). On Linux you also want loginctl enable-linger $USER, or logging out stops it. Full detail, including what the generated unit contains and what is still unverified: Keeping Paddock running on your laptop.
Always-on: Docker
For a server rather than a laptop, run the published image, point it at a data volume, and give it a Claude token:
docker run -d --name paddock -p 127.0.0.1:7233:7233 \
-e CLAUDE_CODE_OAUTH_TOKEN=… `# Claude Max/Pro plan (OAuth)` \
-e PADDOCK_DATA_DIR=/data \
-e PADDOCK_DANGEROUSLY_ALLOW_OPEN=1 `# see below — required inside a container` \
-v paddock-data:/data \
ghcr.io/edspencer/paddock:latest
PADDOCK_DANGEROUSLY_ALLOW_OPEN=1 is required here and the container will refuse to start without it. The image binds 0.0.0.0 (it has to, to be reachable from outside the container) and Paddock's default auth mode is none, and Paddock will not bind a routable interface unauthenticated without being told to. It is safe in this command because -p 127.0.0.1:7233:7233 publishes the port on loopback only — the container namespace is the boundary. Drop the 127.0.0.1: and you have handed an unauthenticated, code-executing Paddock to your whole network, so put an auth mode or a reverse proxy in front of it first.
Then open http://127.0.0.1:7233 and click New Project.
Two images ship from the same source: :latest is the lean base (app plus git, gh, and the claude CLI), and :devbox layers on a coding-agent toolbox — PM2-backed preview servers, ffmpeg, a headless Playwright browser, the Docker CLI, kubectl, python3/uv, jq, rsync. Same app and same /data layout, so you can swap tags against one volume. Ready-made self-hosting recipes (Compose, Kubernetes, Proxmox, a Basic Auth sidecar) live in paddock-deploy.
docker-compose
services:
paddock:
image: ghcr.io/edspencer/paddock:latest # or :devbox for the coding-agent toolbox
ports:
- "127.0.0.1:7233:7233"
environment:
CLAUDE_CODE_OAUTH_TOKEN: ${CLAUDE_CODE_OAUTH_TOKEN} # Claude Max/Pro (OAuth); or ANTHROPIC_API_KEY for API-key billing
PADDOCK_DATA_DIR: /data
PADDOCK_DANGEROUSLY_ALLOW_OPEN: "1" # required in a container; safe because the port is published on loopback
volumes:
- paddock-data:/data
volumes:
paddock-data:
> The web UI has no login of its own — run it behind a reverse proxy / auth > layer you trust (see [AUTH.md](AUTH.md)). Paddock reads credentials from the > environment and from files the host provides; it never stores secrets itself. > It also fails closed: an npx, source or tarball run binds loopback by default, > and refuses to start on a routable interface with PADDOCK_AUTH_MODE=none unless > you explicitly set PADDOCK_DANGEROUSLY_ALLOW_OPEN. None of that is a concern for > a local npx run, which is reachable only from your own machine. (The > [Management API](#drive-it-from-outside) is the one surface that authenticates > itself rather than delegating to your proxy.)
A tour
These are real screenshots — Paddock is dogfooded on its own dev stack: Paddock, herdctl (the engine underneath it), and Warren (an agentic PR reviewer) all live here as projects that build one another.
Every project is a set of chats, organized on one page.
Each project keeps dozens of persistent, resumable chats — searchable, forkable, archivable.
Chat with Claude — real tool calls and subagents stream in, with a live context + cost meter.
Built for real, long-running work — persistent sessions track their own context window and estimated cost as they grow (this one's 42% of a 1M-token window):
Repo-backed projectsClone an external repo as the project's working directory — its own CLAUDE.md, branches, and PR flow apply. Rendered project filesMarkdown, Mermaid, code, images, PDF and video render inline; pin files as tabs.
Slash-command autocompleteType / to discover and run the project's skills. Per-project settingsIdentity, model, permission mode, links, curation budgets, and drive mode — deep-linkable.
…and it all works from your phone.
Drive it from outside
Paddock isn't only something you open in a browser. An instance can expose its Management API as an MCP server over streamable HTTP at /mcp — so a Claude Code session on your laptop, a CI job, or a peer Paddock can list projects, read chats, and, if you grant it, start turns. External callers get the same toolset Claude receives in-process, so the two surfaces can't drift.
Clients are declared in paddock.config.yaml, and their tokens are referenced, never inlined — a literal secret in the config file is a hard error:
managementApi:
instanceId: my-paddock
publicUrl: https://paddock.example.com
clients:
my-laptop:
auth:
ref: env:PADDOCK_MCP_TOKEN_MY_LAPTOP # value lives in the environment
# no scope ⇒ read-only, across all projects
claude mcp add --transport http --scope user paddock \
https://paddock.example.com/mcp \
--header "Authorization: Bearer $PADDOCK_MCP_TOKEN_MY_LAPTOP"
A few things worth knowing before you widen that scope:
- Read-only is the default, and it should usually stay that way. A client
configured without an explicit scope gets list_projects, list_chats, list_triggers and read_chat — nothing else. This is not timidity: any write scope can start a turn, and Claude has Bash. Granting write access to the Management API is equivalent to granting remote code execution on the host. Treat such a token like an SSH key, scope it to specific projects, and expect the boot log to warn you by name when a client holds one.
- Static bearer tokens are the only credential that works today. OAuth is
not implemented — auth.type accepts only "token", and anything else is a config error. Paddock will publish RFC 9728 protected-resource metadata once an authorization server is configured, but there is no OAuth path to configure one against yet, so mint a token and use it.
- It authenticates itself.
/mcpis credential-gated independently of
PADDOCK_AUTH_MODE and of any reverse proxy, so it stays closed even on an instance running auth.mode: none, and a bad token gets a 401 rather than a login redirect no MCP client could follow.
- It fails closed. The endpoint
404s entirely until you've configured both
clients and a publicUrl; if every client's token resolves to nothing, it goes back to 404ing rather than opening up.
Full setup, the scope grammar, and the per-tool reference: Management API and the self-management MCP.
Configuration
An instance is configured by a single paddock.config.yaml, with per-project overrides in each project's project.yaml. The file lives at /paddock.config.yaml (or wherever PADDOCK_CONFIG points), and it is entirely optional — every key has a built-in default, so an instance with no file at all is a working instance.
# /paddock.config.yaml — every key below is optional.
schemaVersion: 1 # the version of THIS format the file is written in
# --- Core ---
port: 7233
host: 127.0.0.1 # loopback by default; a routable bind needs the opt-in below
logLevel: info # trace | debug | info | warn | error | fatal | silent
# --- How turns run ---
driveMode: session # session = SDK runtime (streaming + cross-turn autonomy)
# batch = legacy one-shot CLI runtime
nativeSystemPrompt: true # use Claude Code's native prompt + CLAUDE.md hierarchy
models: # which catalog models the picker offers; omit to offer all
- claude-opus-5
- claude-sonnet-5
# --- Capabilities & safety gates (every switch defaults OFF; maxSpawnDepth to 1) ---
selfMcpEnabled: true # let Claude list/read projects and other chats
selfMcpWriteEnabled: true # + create, fork, message and archive chats
selfMcpProjectsEnabled: false # + provision whole new projects
maxSpawnDepth: 1 # how deep a spawn tree may grow before children lose the self-MCP
hooksMcpEnabled: false # let chats declare and edit their own triggers
browserMcp: false # give chats a headless Chromium browser MCP
# --- The post-turn sweeper that curates OVERVIEW.md and CHANGELOG.md ---
sweepMinIntervalMs: 3
…
## Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [edspencer](https://github.com/edspencer)
- **Source:** [edspencer/paddock](https://github.com/edspencer/paddock)
- **License:** MIT
- **Homepage:** https://paddock.edspencer.net
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.