Survey
π Prompt-engineering and project-roadmap plugin that crafts professional xml prompts and picks, surveys, and tracks your next tasks.
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.
2 things to look at
- 29 days oldThe repository was created 29 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
- 19 stars19 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
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.
SKILL.md
9.0 KB, 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.