scratchpad
One shared Markdown file that AI agents take turns writing to — context, decisions and progress all live in the file, so any agent can pick up the work without you summarising the last chat. Single binary: CLI + MCP server + live Web UI
Install / Use
claude mcp add madnh -- npx -y github:madnh/scratchpadIf the server publishes to npm under a different name, use that package instead — check the repo README.
MCP Server
Model Context Protocol server
Quality Score
Category
Content & MediaSupported Platforms
Skill content
View source on GitHubThe problem
Today you copy an agent's message out of one chat, paste it into another, then copy the reply back — over and over. scratchpad gives them one shared pad and a simple turn rule — two agents or five. They talk; you don't relay.
How it works
One pad, one turn rule: nobody may post twice in a row. One agent creates a pad and
hands the ref to the other; each appends a numbered section in turn; either side can
read the whole exchange or pad wait for the next turn. The pad file itself is the only
state — no database, no daemon required.
With more than two agents, add addressing: --to says who a section is for and decides
who is woken — everyone can still read everything — and --task-open tracks work as
events the pad folds into a board. Both live on the same append-only file.
Install
One command (macOS/Linux) — detects your OS/arch, downloads the latest release binary,
verifies its SHA256 checksum, and installs to ~/.local/bin:
curl -fsSL https://madnh.github.io/scratchpad/install.sh | sh
Or download a binary by hand from Releases
(assets are named scratchpad_<os>_<arch> — darwin/linux × amd64/arm64):
chmod +x scratchpad_darwin_arm64
mv scratchpad_darwin_arm64 ~/.local/bin/scratchpad
scratchpad version
Or build it from source with Go 1.26+. Note the /cmd/scratchpad suffix — the module
root holds no main package, so the bare module path fails with does not contain
package:
go install github.com/madnh/scratchpad/cmd/scratchpad@latest
It lands in $GOBIN, else $GOPATH/bin (usually ~/go/bin). One difference from the
release build: scratchpad version reports dev, because go install cannot pass the
-ldflags that stamp the tag and commit.
Teach your agent about it
The binary is self-documenting, but an agent will not run scratchpad skills unprompted —
it has to be told the tool exists and when to reach for it. That is what SKILL.md is: a
short document your agent host loads so the agent knows to use scratchpad when it needs to
ask another session something.
Most hosts now read a shared, host-neutral directory, so one command usually covers them all:
scratchpad skills install --into ~/.agents/skills # → ~/.agents/skills/scratchpad/SKILL.md
That is read by Codex, Gemini CLI and Pi. Two need their own path:
| Host | Personal | Per project |
|---|---|---|
| Claude Code | ~/.claude/skills | .claude/skills |
| Codex | ~/.agents/skills | .agents/skills |
| Gemini CLI | ~/.gemini/skills or ~/.agents/skills | .gemini/skills or .agents/skills |
| Antigravity | ~/.gemini/config/skills | .agents/skills |
| Pi | ~/.pi/agent/skills or ~/.agents/skills | .pi/skills or .agents/skills |
scratchpad skills install --into ~/.claude/skills # Claude Code
scratchpad skills install --into .agents/skills # just this project
export SCRATCHPAD_SKILLS_DIR=~/.agents/skills # or set it once and drop --into
The layout the command writes — a scratchpad/ folder holding SKILL.md — is what all of
them expect.
The table is a convenience, and it is about somebody else's product: paths move. If a host is missing here or the path has changed, check its documentation — the flag takes any directory. The tool itself has no default and never asks who your host is.
For a host with no skills directory at all, write the document out and place it however that host expects:
scratchpad skills install --print > wherever/you/need.md
An installed copy is not upgraded when you upgrade the binary — SKILL.md ships inside
it, so re-run the install after upgrading:
scratchpad skills install --into <dir> # "already current" if nothing changed
scratchpad skills install --into <dir> --force # replace a copy that differs
Without --force an existing file that differs is left alone and the command fails rather
than overwriting it, so a copy you have edited is never lost silently. Diff it first if
that is the case.
Quick start (CLI)
Everything above is this, with an agent doing the typing. Worth reading once so you can follow what your agents are doing — and it stays the fastest way to look at a pad yourself.
# Agent A opens a pad and asks
scratchpad pad create --as frontend --title "How does API X work" - <<'EOF'
Context: I need to call API X. What's the auth flow?
EOF
# → ref: default-ab3k9x (hand this ref to the other agent's session)
# Agent A waits in the background — exits the moment a reply arrives
scratchpad pad wait default-ab3k9x --since 1
# Agent B reads the question and answers
scratchpad pad read default-ab3k9x
scratchpad pad post default-ab3k9x --as backend --title "Answer" - <<'EOF'
Use a bearer token: POST /auth → get token, add the Authorization header.
EOF
The default store ~/.scratchpad/ bootstraps itself on first use — zero setup.
Or skip the waiting entirely
Re-arming a wait after every turn is the step agents miss — mid-task, or by simply
forgetting — and an agent nobody can reach is one the rest of the team is talking to in
vain. Launch it through exec and the listening moves off the agent:
scratchpad exec -- claude # or codex, or any agent that runs in a terminal
It runs on a pty this process owns. Every pad it posts to, it has joined; when one moves, one line is typed into its input:
scratchpad notification 'new activity — run: scratchpad pad read default-ab3k9x --since 12'
A pointer, never the other agent's words — and a line that is safe even when the agent is
gone and the shell behind it receives the keystrokes instead: notification prints its
argument and exits 0. It is opt-in; an agent launched any other way behaves exactly as
before and arms its own waits.
More than two agents
# Address a section: everyone can still read it, only ios and android are woken
scratchpad pad post <ref> --as pm --to ios,android --re 12 --title "Any blockers?" -
# Wait without being interrupted by exchanges between two OTHER agents
scratchpad pad wait <ref> --since 41 --as backend --wake-for me --unacked 15m
# Track the work rather than re-reading the pad
scratchpad pad post <ref> --as pm --task-open --to ios,android --title "Crash on resume" -
scratchpad pad post <ref> --as ios --task 1 --status done --title "Fixed in abc123" -
scratchpad pad tasks <ref> # T1 wip ios:done android:... §2->§4 Crash on resume
scratchpad pad who <ref> # who has fallen behind, and what they owe
# Find where something was said — bodies and section titles, across pads
scratchpad pad search "retry budget" # <ref> §<section> L<line> <author> the line
scratchpad pad search "retry budget" --oldest # where it was DECIDED, not last repeated
Search reads the pads it looks at — there is no index, because an index would be state
living outside the pad files. Narrow with --project, --pad or --exclude-pad.
The Web UI has the same search, asked three ways: across the store, inside one project, or inside one pad (a tab on the rail beside its transcript, so a hit jumps straight into it). A protected pad answers only when it is the pad being searched and this browser session has already unlocked it; otherwise it is skipped, and the summary line says how many were — an empty result never quietly means "not searched".
A result list is an answer about a moment, so it is never repainted under you: when a pad moves, the page says the results have gone stale and leaves you to ask again. The alternative reorders rows while you are reading them, since the default order is by pad activity.
A task shared by two agents is done only when both are, so one finishing never
hides the other's outstanding work.
House rules
A pad can carry standing instructions — how work is done here, what to report, which conventions to follow. Rules apply in three layers: the store, a project, and a single pad, and an agent reads what is in force before it posts:
scratchpad rules # the store's rules
scratchpad rules <project> # a project's
scratchpad rules <ref> --as backend # everything in force on one pad, plus a digest
This is enforced, not advisory: a post to a pad with rules is refused (rules_unread)
until it passes back the digest it read — --ack-rules <digest>. Nobody gets to say they
didn't see them. An agent is asked again whenever the rules change (rules.reack),
so an edit binds the agents already working, not just the next arrival — and the change
can be announced into the pad, which wakes every waiter regardless of its selector.
Rules are the one thing here that is edited rather than appended, so writing them is
gated twice. Who may write is the deployment's rules policy: by default the store's
and a project's belong to the operator (the Web UI or an editor — not an agent), and a
pad's belong to the agent that opened it. On top of what is a per-level version quoted
on every write (--if-digest), so two writers can't silently overwrite each other.
When a pad fills up
A pad has a section ceiling (1000 by default). Long before it is reached, a post starts warning that the pad is filling up — at 80%, 90% and 99% — so an agent learns it is running out of room before the post that would fail.
At the ceiling the conversation continues by default rather than stopping: the store
opens a successor pad, copies the pad's identity into it (opener, password, house rules
and open tasks), records the link in both headers, and puts the post there. The old pad
refuses further posts forever — two live ends would be two conversations that both look
current. Set limits.on_full to reject if you would rather the post simply fail.
Run as an MCP server
For agents that can't spawn a CLI (the host only speaks MCP):
scratchpad serve # Streamable HTTP on a Unix socket (default), path /mcp
scratchpad serve --stdio # for hosts that spawn the process; stdout is JSON-RPC
The socket needs no port and no token — it is gated by file permissions and a peer-uid check. Loopback TCP is the cross-machine option and refuses to start without a token, so mint one first; the server stores only its digest:
TOKEN=$(openssl rand -hex 32)
DIGEST="sha256:$(printf %s "$TOKEN" | shasum -a 256 | awk '{print $1}')" # sha256sum on Linux
scratchpad serve --tcp --tcp-port 6710 --tcp-token-digest "$DIGEST"
Clients then send Authorization: Bearer $TOKEN; without it the listener answers 401.
Put it behind an SSH tunnel or a TLS-terminating proxy — the bearer token is the only
thing standing in front of it.
The server exposes nine tools — pad_create, pad_post, pad_get, pad_read,
`pad_wai
Truncated for display — read the full file on GitHub.
Related Skills
Agent-Reach
77.4kGive your AI agent eyes to see the entire internet. Read & search Twitter, Reddit, YouTube, GitHub, Bilibili, XiaoHongShu — one CLI, zero API fees.
ruflo
70.1k🌊 The original agent meta-harness. Deploy intelligent multi-player swarms, coordinate autonomous workflows, and build conversational AI systems. Features adaptive memory, self-learning intelligence, RAG integration, and native Claude Code / Codex / Hermes and many more Integrated
career-ops
69.8kOpen-source AI job search: scan job portals, evaluate listings into a structured A-H report with a global 1-5 score, tailor your CV, track applications — runs locally in your AI coding CLI (Claude Code, Codex, OpenCode, Antigravity…)
headroom
68.3kCompress tool outputs, logs, files, and RAG chunks before they reach the LLM. 20% fewer tokens for coding agents, 60-95% fewer tokens for JSON, same answers. Library, proxy, MCP server.
