Survey
Ground-truth the roadmap's near-term candidates against the actual codebase — an Explore agent checks whether each candidate's touches/depends_on still match reality, then persists any real finding (hidden dependency, already-done, stale) back into ROADMAP.jsonl so future sessions pick it up automatically.From its SKILL.md
npx -y skills add V-Songbird/foreman --skill surveyAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
SKILL.md
9.0 KB, ~2.1k tokens by cl100k_base, as published. Nobody here has run it
foreman:survey — ground-truth the roadmap's near-term candidates
This is the one Foreman flow that deliberately investigates the codebase
against the roadmap. foreman:roadmap's pick-next-task branch explicitly
does not do this — see the 0.4.4-alpha changelog entry, where doing
exactly this at pick time burned ~100k tokens on every invocation. Keeping
it a separate, explicitly-triggered skill is what makes both halves cheap:
the fast path stays mechanical, and ground-truthing only runs when someone
actually asks for it.
All reads/writes to ROADMAP.jsonl go through
${CLAUDE_PLUGIN_ROOT}/scripts/roadmap.js — never Read/Edit the file
directly. Skim ${CLAUDE_PLUGIN_ROOT}/roadmap-schema.md for field semantics.
Pre-check: if ROADMAP.jsonl doesn't exist at the project root, tell
the user to run /foreman:init first and stop here.
1. Pick the scope
If args named specific task ids, list --ids <those ids> (validate they
exist and are planned). Otherwise:
node ${CLAUDE_PLUGIN_ROOT}/scripts/roadmap.js next-candidates
(default --limit 3) — candidates already include each one's own
depends_on, no separate call needed just to get that.
Survey the top candidates only — same 3 by default as foreman:roadmap
shows. This is deliberately not the whole backlog: a hidden dependency or
stale claim matters most for what's about to be picked, and checking every
planned entry every time would make this as expensive as the thing it's
trying to avoid. If total_unblocked is larger than what you surveyed,
say so when reporting back — don't imply full coverage silently.
Collect the exact set of dependency ids referenced across all candidates'
depends_on (dedup). If non-empty, resolve just those —
node ${CLAUDE_PLUGIN_ROOT}/scripts/roadmap.js list --ids <comma-joined ids>
— never the unfiltered list, which loads the whole file just to answer a
question about a handful of ids.
Mechanical pre-check, not an agent's job: for each resolved dependency
entry with status:"done", verify each of its commits actually exists —
git cat-file -e <sha> (Bash), exit code tells you, no reasoning involved.
Build a small per-commit exists: true/false map from this before moving
to step 2 — a dispatched agent re-deriving something a shell command
already answered for free is pure waste, one git cat-file call is
cheaper than N parallel agents each running their own git log.
Same reasoning applies to touches: collect every path named across the
candidates being surveyed (dedup), and check existence directly —
test -e <path> (Bash) / Test-Path <path> (PowerShell), relative to the
project root, one call per unique path (or a short loop in one call).
Build a path_exists: true/false map from this too — no agent needs a
Read/Glob round trip just to learn a file isn't there. A missing path
is a question, not a verdict: touches is a forward-looking best guess
written at add/init time and routinely names files the task will
create, so absence alone is expected on a healthy backlog and proves
nothing by itself.
2. Investigate each candidate in parallel
Dispatch one Agent (subagent_type: Explore) per candidate, in parallel
(single message, multiple tool calls). Each gets a self-contained prompt —
it has no memory of this conversation — built from the candidate's own
fields plus the resolved-dependency and exists-map context gathered in
step 1:
-
The candidate's
id,title,why,what,touches,depends_on. -
For each path in
touches: the pre-computedpath_existsflag from step 1 — the agent consumes this fact, it does not re-check it with its ownRead/Globcall. -
For each id in
depends_on: that entry'stitle,status,commits, and the pre-computedexistsflag for each of those commits — the agent consumes this fact, it does not re-derive it. -
Ask it to check, and report a verdict for each:
- Touches still real? A path step 1 flagged missing is
stale-touchesonly if it can be shown to have once existed and moved —git log --diff-filter=D -- <path>, or--followshowing a rename. Nothing found means the task simply hasn't created it yet: verdict staysvalid, nothing to annotate. For paths confirmed to exist, does their current content still match whatwhatdescribes? (git log --oneline -- <path>plus a read of the file's current state.) - Dependencies actually satisfied? If step 1's
existsmap already flags adoneentry's commit as missing, that alone is a red flag — no further check needed. Otherwise, for commits confirmed to exist, do they plausibly implement what that entry'stitle/whatclaims? (this half stays semantic — read the commit, judge the match) - Hidden dependency? Reading the code the candidate's
touchespoint to, does it already reference/import/call something that another not-done task'stouchesclaims to own, which isn't in this candidate'sdepends_on? Then the same question in reverse: does anything outside this candidate'stouchesconsume the code it changes, in a way that makes another not-done entry depend on this one? Only report either direction with a concrete file:line citation — no hunches. - Already done, or duplicate? Does the working tree already contain
what
whatdescribes, or does it closely overlap another entry?
Verdict per candidate:
valid(nothing found) |hidden-dependency|stale-touches|already-done|duplicate. Every non-validverdict must cite the file:line or commit that grounds it — refuse to report a finding it can't point to concretely. - Touches still real? A path step 1 flagged missing is
3. Confirm before writing anything
Present findings to the user — one line per candidate, valid ones need
no more than a mention. For anything else, ask before persisting
(AskUserQuestion) — a survey finding is Claude's read of the evidence,
not an automatic mutation:
hidden-dependency→ on confirm:echo '{"id":"<candidate>","add_depends_on":["<dep-id>"]}' | node ${CLAUDE_PLUGIN_ROOT}/scripts/roadmap.js update-depsThis is structural —next-candidateswill now correctly treat the candidate as blocked until<dep-id>isdone. This is the mechanism that makes a finding from this session visible to a completely different session later: it's baked into the graph the ranking algorithm reads, not a note someone has to remember to check.already-done/duplicate→ on confirm:echo '{"id":"<candidate>","status":"dropped","notes":"survey: <one-line evidence>"}' | node ${CLAUDE_PLUGIN_ROOT}/scripts/roadmap.js update-status(or"done"with the actualcommitif the evidence points to a specific commit that already did the work).stale-toucheswith no structural fix (the description just needs updating, nothing to block on) → notes-only, status untouched:echo '{"id":"<candidate>","notes":"survey: <one-line evidence>"}' | node ${CLAUDE_PLUGIN_ROOT}/scripts/roadmap.js annotate(the script date-stamps each appended note itself — don't write one in)annotateexists precisely for this write: unlikeupdate-status, it can't regress the entry to a status read before the survey ran (e.g. re-assertingplannedon an entry another session has since moved toin_progress). This is a soft signal, not a mechanical reorder —next-candidatesnow returns this candidate'snotes, so the nextforeman:roadmappick sees it as context, but ranking itself (unblocks_total, thenunblocks, then no-collision, thencreated_at) doesn't change. Say this explicitly if the user expects a guaranteed reorder — that would need a stored priority field this schema deliberately doesn't have (seeroadmap-schema.md's comment on why not).
Never write on an unconfirmed finding, and never touch ROADMAP.jsonl
directly — every write above goes through roadmap.js, same as every other
Foreman flow.
4. Report
Short summary: candidates surveyed (and how many were left unsurveyed, if any), verdicts, what got written. If nothing was confirmed, say the roadmap is unchanged — this skill running is not itself news.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.