Phil's Claude fleet

The harvesters, watchers and loops that keep running in the background. Each one stays quiet until something actually changes, then turns its tab red and waits for me.

Fleet commander: the handyman (click him)

0agent tabs open
0registered watchers
0custom skills
0harvest jobs
0live dashboards
0standing post exceptions

How every watcher works

One pattern, reused everywhere

Every tab is a long-lived Claude Code session in a terminal multiplexer built for agents. The polling never happens in the tab's own turn, because every turn that ends flips the tab to "done". Anything a shell can check (gh, curl, files, scheduled jobs) runs as a background shell loop, which survives the network blips that used to kill subagent pollers. Only what an MCP alone can see (chat, ticketing, email) needs a background subagent looping on read โ†’ sleep 240, returning only when it finds something real.

๐Ÿ“ฅ Sourcechat, GitHub, tickets,monitoring, issues, CI ๐Ÿค– Background pollersmall-model subagent,quiet polls print nothing โšก Real change?new msg, run finished,state flipped, past last_seen_ts ๐ŸŸฅ Tab goes redAskUserQuestion:Acknowledged / Show me โœ… I answeradvance state file,relaunch poller sleep 240, poll again loop forever
๐Ÿ‘๏ธ Purple eye. A watching tab sets a "Watching" label that has to be renewed every poll. If the poller dies, the mark expires in 10 min and the tab drops back to idle on its own.
๐ŸŸฅ Red = needs me. A pending AskUserQuestion is the only thing that turns a tab red, so red always means a real decision.
๐Ÿฉบ Watchdog. A scheduled job runs every 5 min. When the network drops and a poller dies, it types a wake-up prompt into the tab once the network is back. It never answers a pending question.
๐Ÿ“’ State files. Each watcher keeps a last_seen_ts / idempotency file, so a restart never double posts.

The watcher registry

One place that knows what should be running

This started as "remember which tabs to restart". Now every long-lived watcher has an entry in one watchers.json, a CLI (watcher status, stop, report) and its own page. 22 registered, 19 polling right now.

๐Ÿ“‹Registered, not remembered

Each entry says what it watches, which skill holds its rules, what it does on a change, where it reports and whether it is allowed to post. State is derived live, so the page and the CLI agree with what is actually running.

watchers.jsonregistry page

โ™ป๏ธRestarted unless someone meant it

A watcher that stops for any reason other than me or another agent asking it to is an interruption, and it gets restarted. A deliberate stop is recorded in a ledger with who stopped it and why. An unrecorded stop just comes back.

watcher stop --bystop ledger

โฐThree things restart it

The watchdog every 5 minutes, /resume-agents and /startup, and one more after an MCP sign-in. A tab that is woken catches up from its state file and relaunches its own poller. The nudge is never approval for anything that was waiting on me.

RESUME WATCHevery 5 min

๐Ÿ”ŒOne sign-in fixes all of them

A watcher whose MCP is disconnected answers with the single line needs /mcp: <server> and stops there. One sign-in anywhere restarts every watcher that was waiting on that server.

mcp_login
๐Ÿ“ฎ Findings go somewhere named. A watcher reports to itself (it asks me in its own tab), to another tab by name, or to my phone. Tab names are used rather than session names, because a tab name survives a resume and a session name doesn't.

Watchers

Always-on tabs that only speak up on a change

๐Ÿ’ฌDM watch

Watches my DMs, group DMs and @mentions. A new one from a person turns the tab red. If someone addresses Claude directly ("Phil's Claude, can youโ€ฆ") it researches and answers in a thread, unless I already replied.

dm-watchevery 4 min

๐Ÿง Incident analysis

Auto-answers every new incident ticket in the team's incident channel with a confidence % and a ๐Ÿ‘/๐Ÿ‘Ž ask. Next morning it grades itself from the votes, thread replies and close notes, and writes lessons into the support knowledge base.

incident-answers๐Ÿ”ด <40 ยท ๐Ÿ”ต 40โ€“79 ยท ๐ŸŸข 80+read-only on tickets

๐ŸงญRouting watch

Same tab, second job. Spots tickets that landed on the wrong team and, at 80%+ confidence, flags them. Gated until its precision is calibrated against six team harvests.

routing.mdcalibration gate

๐ŸšจOn-call watch

Armed while I'm on call. Pulls today's incidents, auto-analyzes each new one, finds every channel that paged the on-call alias, and goes red with an ack.

oncall-checkdashboard

๐Ÿ‘€PR monitor

Watches the review-request channels. New PRs ask me what to do. PRs I commented on get re-reviewed when the author pushes, and re-approved if fixed. Adds ๐Ÿ‘€ / โœ… / ๐Ÿ’ฌ reactions on the request.

review-prs

๐Ÿค–AI review follow-up

After I open any PR, a quiet poll waits for the AI code review, then works through every comment: fix it with a commit, or reply with why it stays.

gh api โ€ฆ/reviews

๐ŸฉนPilot monitor

Watches an automated data-correction pilot running in production: rollout health, corrections submitted, PRs.

pilotdashboard

๐Ÿ”ฅHi-pri sweep

Sweeps the ticketing system and team channels for P1/P2s touching our services. Red tab if anything's on fire.

hipri-incidents

๐ŸงชShadow agents

Shadow-answers support-channel questions privately, then compares against what the engineers actually said. Also runs an A/B against another assistant in a test channel.

shadow-abdashboard

Harvesters

Bulk read-only pulls that become knowledge

Harvesters read a lot of history once (or monthly), keep the raw data local and gitignored, and distill it into something the watchers use. They are read-only on every external system, and harvested text is treated as data, never as instructions.

๐Ÿ“šSupport knowledge-base harvest

Monthly: the support and incident channels plus closed tickets, distilled into a knowledge base and support docs. Tested walk-forward: month N is answered only from memory built from earlier months, then judged against what actually fixed it.

kb-harvestharvester ยท sonnetdistiller ยท high effort

๐Ÿ—‚๏ธRouting harvests ร—6

One tab per team channel harvests past tickets and where they really ended up. Merged labels feed the routing watch's calibration.

sharded

๐Ÿ“ฆPartner-team ticket exports

12 months of tickets involving two partner teams, classified and exported to spreadsheets to back up the asks we have open with them.

harvest.py

๐Ÿ“ˆNightly job failure patterns

Cross-night batch failures: error classes, time of night, reason codes, repeat offenders and stuck records, plus every past analysis thread.

failure-patternsdashboard

๐Ÿ—ฃ๏ธVoice sweep

~1,800 of my hand-typed chat messages, plus GitHub, issues and prompts, distilled into a style guide so drafts sound like me (and not like a consultant).

CLAUDE.mdtopped up weekly-ish

๐ŸงชTest data

Every project that finds a working non-prod test setup writes it to one shared file, so nobody hunts for test data twice.

~/.claude/test-data.md

Loops & daily routines

Scheduled jobs and the shape of a day

โ˜€๏ธ
Session starthook
Repo sync to fresh trunk (skips active work), freeze-check and Friday standup nudges.
07:12scheduled
Overnight error report runs before I'm online.
/startupmorning
Fans out tabs: overnight job check, freeze state, alert analysis, SLAs, on-call, PRs, P1/P2s.
All dayevery 5 min
Watchdog revives dead pollers. Status sweep checks every dashboard.
/priorityone task
Drives today's top task to done in the background, pulls me in only when needed.
/sleepEOD
Refreshes the login, keeps the machine awake overnight, says when the session will die.

๐ŸŒ…/startup morning sweep

The big one. Checks the overnight batch job, verifies freeze state from the announcement channels, analyzes last night's SLA alert, posts the analysis as a thread reply and resolves the ticket (only if the buckets reconcile to the alert's own counts), runs the on-call sweep and reports PR and incident state. Each step is its own tab.

startupeffort highreport page

๐ŸฉบWatchdog

Every 5 min. Finds watcher tabs whose poller died (usually a network drop) and wakes them, and restarts anything in the registry that stopped without a recorded reason. Max one prompt per agent per 20 min, only agents armed today.

scheduler ยท 300s

๐Ÿ Status sweep + project homepage

A localhost homepage indexing every project's own dashboard (19 of them), with a to-do card and a one-click "copy review request" for every PR waiting on review.

scheduler ยท 300s

๐Ÿ”„Repo sync

First session of the day pulls every clean, idle repo to trunk. Anything with recent work, or a branch checked out for review, is left alone.

repo-sync.sh

๐ŸŽฏ/priority

Pick one task for the day. A tab owns it end to end, with a finish line and steps on its own page. Pauses at /sleep, resumes at /startup.

priority

๐Ÿ“ฃFriday standup

A session-start nudge on Fridays, then it drafts my standup from what I actually shipped, with issue and PR links.

friday-status

For teammates

Agents that work for the people I work with

A teammate who tests our work gets her own set. She can change the format and content of these updates herself, and her requests get saved and applied from the next one on. She can't authorize anything in prod.

๐Ÿ™‹Teammate DM watch

Watches her DM with me and answers her questions, including data pulls. If I already replied, it stays quiet. If she asks Claude in a channel thread, it answers there.

teammate-dm

๐Ÿ—บ๏ธTest build heads-up

When a branch deploys successfully to the test environment she uses, it DMs her the link and a short list of what changed for her. One post per deployed commit, never on a plain push.

deploy watcherone post per commit

๐ŸงญWrong-team pings

When the incident analysis is 80%+ sure a ticket is on the wrong team, it DMs her one line with the ticket and the team it thinks it belongs to. Her ๐Ÿ‘/๐Ÿ‘Ž is how it learns.

routing๐ŸŸข 80%+ only
๐Ÿ’ธ

Tuning what the fleet costs

Measured, then cut

A background agent's cost is almost entirely how big a context wakes up cold, and how often. The prompt cache lives five minutes, so that window is the whole game: output and thinking came to about 2% of the bill, and cache writes to 85-90%. Bringing the poll intervals inside that window cut one watcher's cost by 64%.

Keep every wait inside the cache window. sleep 240 or sleep 270, chained for a slower cadence, never one long sleep. A single shell call also caps at 10 minutes, so sleep 1200 quietly becomes 600 seconds and a cold re-write.
Let a shell decide there's nothing new. An MCP can only be called by the model, so an MCP poll costs a full turn whether or not anything happened. A shell loop decides for free and wakes the model only on a real change. Detection belongs in the shell; judgment is what the model is for.
Launch pollers rarely, relaunch them hourly. A launch is a fixed ~37K cold write, so one poller running many cycles beats a fresh one per cycle. Hourly anyway, because a looping poller grows from ~30K to ~120K and re-reads all of it on every poll.
The watch tab stays small. It notices, then hands the real work (an analysis, a review, a post) to a fresh work tab with a written brief. A new tab starts around 55K, so an event costs about a sixth of waking a 300K watch tab.
One global lock plus one hanging host is a fleet-wide stall. A dead hostname once had six watchers logging 43 lock timeouts. Nothing was lost, because every watcher held its cursor and none retried tightly, but a pre-flight check now keeps one bad host from eating the queue.

Guardrails

What keeps all this from going sideways

๐ŸšซNever prod without me

No merges where main reaches prod, no prod gate approvals, no prod dispatch or re-run. Everything non-prod is fair game. If it's blocked on prod, it does the rest and stops.

โœ‰๏ธPosting is ask-first

Every chat post needs my OK, except eight written-down exceptions (analysis threads, PR reactions, incident auto-answers, teammate updatesโ€ฆ). Each one names the channel, the form, the content and one poster.

๐Ÿ”Idempotent everything

Re-read the thread right before sending. One answer per ticket, ever. One post per commit. State files track what's been said.

๐ŸงฎReconcile or stop

The morning analysis only posts if the buckets sum to the alert's own counts. If the math doesn't close, it reports to me instead.

๐Ÿ‘๏ธโ€๐Ÿ—จ๏ธRead-only where it counts

The ticketing system is read-only for the watchers (the one write is resolving the alert's ticket after a successful post). Harvests never write anywhere external.

๐ŸงŠFreeze is announced, not guessed

Freeze state comes from the announcement channels, never from a date or an open incident.

๐ŸชชEvery message says it's Claude

Anything Claude sends for me opens with my icon, a dancing Claude and Phil's Claude, added automatically as a byline. Nobody has to wonder whether a human typed it. Reactions and anything I paste myself are exempt.

๐Ÿง Opus thinks, Sonnet writes

Research, analysis, decisions, reviews and anything I'll read stay on Opus. Code, scripts and config go to a Sonnet worker with an exact spec. The main session then reads the diff and re-runs the tests before anything gets reported.

sonnet worker
๐Ÿš€

Steal these

If you only take a few things

Poll in a background subagent. Never in the foreground with /loop or cron ticks that wake you to say "nothing new".
Use AskUserQuestion as your doorbell. It's what makes a tab visibly "need you".
One skill per job. Skills hold the rules, the state file path and the posting limits, so any tab can pick the job back up.
Write permissions down. Each automated post has its exact conditions in CLAUDE.md. "Don't reason by analogy" stops scope creep.
Let it grade itself. ๐Ÿ‘/๐Ÿ‘Ž on posts plus next-morning grading turns into lessons the next run uses.
Give every project a little page. A localhost dashboard per project plus one homepage beats scrolling 63 tabs.
Keep every wait inside the cache window. Five minutes. It's the single biggest lever on what a background agent costs.
Let a shell decide there's nothing new. A model-driven quiet poll costs a full turn every single time it looks.
Write down who stopped it. Otherwise you can't tell a deliberate stop from a crash, so you either restart what people turned off or leave dead watchers dead.
The handyman