The sweeper
The sweeper keeps a project’s notes current without you having to. After each
of your chat turns in a project, a per-project, tool-less curation agent reads
what just happened and updates three files: OVERVIEW.md (the current state),
CHANGELOG.md (the running history), and the curated-notes section of
CLAUDE.md. It runs quietly, out of band — you never chat with it.
What it is
Section titled “What it is”- Per project. Each project has its own
sweeper-<slug>agent, whose working directory is the project’s metadata dir (agents bind to a cwd, so the sweeper can’t share one across projects). - Tool-less. The sweeper is configured with
allowed_tools: []and a small model (SWEEPER_DEFAULT_MODEL, Haiku by default,max_turns: 4). It cannot touch the working tree, run commands, or start other chats. It only returns text; Paddock’sSweepService(sweep.ts) parses that text and writes the files. This is a safety and cost property: a curation pass can never mutate your code and can never trigger another sweep.
When it runs
Section titled “When it runs”- Every completed, non-scratch turn — a human chat turn, a session-mode
wake, or a server-initiated agent turn — emits one
afterTurnlifecycle event, and its sole consumer enqueues the curation sweep. So the sweeper dispatches exactly once per turn (no double-curation), whatever drove it. - Sweeps are debounced/coalesced: at most one per project per
minIntervalMs(default 5 minutes,PADDOCK_SWEEP_MIN_INTERVAL_MS). Bursts of turns fold into a single trailing run. - An activity gate skips no-op sweeps:
SweepServicetracks the newest chat session mtime it last swept insweep-state.json, and does nothing if there’s been no new activity since. On failure, it retries the same activity next time rather than advancing past it.
Because it’s an afterTurn trigger with an enabled flag, a project can also
turn curation off — see below.
What it produces
Section titled “What it produces”The sweeper is prompted with a digest of recent activity — the last ~40 messages of every chat that’s been touched since the last sweep, capped at 6 chats so a burst of concurrent conversations can’t unbound the prompt — plus each of the three curated files.
Since v0.41 the sweeper is a full-file curator, not an appender. It is
shown each curated file in full and must return either that file’s complete
new contents or the literal NOCHANGE. It replies with marked sections as plain
text:
<<<OVERVIEW>>>…the FULL new OVERVIEW.md, or NOCHANGE…<<<CHANGELOG>>>…the FULL new CHANGELOG.md, or NOCHANGE…<<<CLAUDE>>>…the FULL new "## Curated notes" body, or NOCHANGE…<<<END>>>SweepService parses the markers and writes the files itself. A NOCHANGE (or
empty) section leaves that file untouched:
OVERVIEW.md— replaced wholesale. It’s a synthesized “what this project is, key decisions, open questions, next steps” written for an LLM to read at the start of a new chat (and offered as the optional preload context on a new chat).CHANGELOG.md— also replaced wholesale. The sweeper adds at most one bullet under a## YYYY-MM-DDheading at the top (newest-first), reusing today’s heading if it’s already there, coalesces near-duplicate recent bullets, and drops or summarizes the oldest entries to stay inside the file’s budget. A change-detection gate means an uneventful turn returnsNOCHANGErather than re-logging unchanged state. Paddock itself only stamps the# Changelog — <slug>title.CLAUDE.md— the body under the## Curated notesheading is replaced with a de-duplicated, pruned version; everything above that heading is preserved verbatim. Never curated for a repo-backed project (whoseCLAUDE.mdis upstream-owned).
If the markers are missing or unparseable, the sweep throws — the activity watermark doesn’t advance and no partial/garbage content is written. Every sweep failure is non-fatal to your chat.
Per-file token budgets
Section titled “Per-file token budgets”Each curated file has a token budget the sweeper is told to keep it under, and which Paddock enforces as a backstop at write time:
| File | Instance setting | Environment variable | Default |
|---|---|---|---|
OVERVIEW.md | curation.overviewMaxTokens | PADDOCK_CURATION_OVERVIEW_MAX_TOKENS | 2000 |
CHANGELOG.md | curation.changelogMaxTokens | PADDOCK_CURATION_CHANGELOG_MAX_TOKENS | 8000 |
CLAUDE.md | curation.claudeMaxTokens | PADDOCK_CURATION_CLAUDEMD_MAX_TOKENS | 6000 |
Precedence is the usual built-in default → paddock.config.yaml → environment
variable, and since v0.42 any project can override any subset of the three
in its project.yaml (or from its Settings tab):
# project.yaml — override two, inherit the thirdcuration: overviewMaxTokens: 800 changelogMaxTokens: 2400Resolution is field by field at sweep time: a field you don’t set tracks the instance default as you change it, and an invalid value degrades to “inherit” rather than failing the sweep. Lowering a budget shrinks the context a chatty project injects into every one of its chats. See Creating & organizing projects for the Settings-tab view.
When a file is already larger than its budget, the sweeper is shown a bounded
view that keeps the top of the file and truncates the older tail, with an
explicit marker telling it to preserve what it can’t see. Because CHANGELOG.md
is newest-first, that means the curator always sees the most recent history.
Customise or disable it
Section titled “Customise or disable it”The sweeper is the default curate-overview trigger, so you shape it the same
way you shape any trigger — by declaring one in the project’s project.yaml (or
from a keeper chat with the trigger-management tools). A project that declares
nothing behaves exactly as above; a declared curate-overview trigger only
customises the default via its run:
- A different model.
run.modeloverrides the sweeper’s model for this project — e.g. a larger model for a project whose notes need more synthesis. - Extra instructions.
run.prompt/run.promptFileare appended to the curator prompt under an=== EXTRA PROJECT-SPECIFIC CURATOR INSTRUCTIONS ===heading (the same slot as a project’s.paddock/hooks/sweep.mdfile) — so you can tell the sweeper what this project cares about without touching Paddock. - Off. Set the trigger
enabled: falseto switch curation off for a project entirely: no sweep runs, andOVERVIEW.md/CHANGELOG.mdare left to you.
Unlike every other event trigger, the curator is not run as its own
trigger-<slug>-<name> agent and is not fanned out to the generic event
dispatcher — it’s tool-less by nature (it returns marked text; Paddock writes the
files), so it keeps running through SweepService on the sweeper-<slug> agent.
Its run block therefore only tunes the sweep (model, prompt, enabled); trigger
fields that imply a scoped agent (a tool allow-list, a permission mode) don’t
apply to it.
Why it’s designed this way
Section titled “Why it’s designed this way”Splitting “decide what to write” (the agent, text-only) from “write the files”
(Paddock, deterministic) means the curation model is cheap, sandboxed, and
idempotent, and the file layout stays under Paddock’s control. It’s the mechanism
that keeps OVERVIEW.md a reliable “reload context at the start of a session”
document and CHANGELOG.md an honest history — the two files this very project
directory keeps.
See ../ARCHITECTURE.md#6-the-sweeper for the
code path and ../CONTRACT-v3.md for the original marker
contract.