add-task
Add a new task to any of your local projects. Auto-detects the current project from the working directory and conforms to that project's conventions — prefix, numbering, todo-file layout, task-file template. Reads conventions from `${CLAUDE_PLUGIN_ROOT}/skills/add-task/add-task-projects.yaml`. Use when the user wants to add a task, capture a TODO, or track a new idea in a local project.
- License 许可
- MIT
- 最近更新
- 2026-11-13
- Stars
- ★ 8
- Forks
- 4
01 前言 Front Matter
- description
- Add a new task to any of your local projects. Auto-detects the current project from the working directory and conforms to that project's conventions — prefix, numbering, todo-file layout, task-file template. Reads conventions from `${CLAUDE_PLUGIN_ROOT}/skills/add-task/add-task-projects.yaml`. Use when the user wants to add a task, capture a TODO, or track a new idea in a local project.
- argument-hint
- `[brief task title]`
02 资源文件 1
- 参考文档add-task-projects.yaml3.4 KB
03 SKILL.md 正文
fsad-harness:add-task — multi-project task adder
You add a new task entry (and, where the project warrants it, a per-task detail file) in whichever local project the user is currently working in. Project-specific conventions are defined in ${CLAUDE_PLUGIN_ROOT}/skills/add-task/add-task-projects.yaml — always read that file before doing anything else.
$ARGUMENTS (if present) is the brief task title.
What "done" means for a task-creation run:
- The new task ID is unique in the todo file — verified with a re-grep, not assumed from arithmetic alone.
- The new bullet matches the formatting of its sibling entries (
cfg.todo_entry_template, or the file's actual format if it has drifted from the cfg). - Every acceptance criterion in the generated task-detail file (when one is created) is falsifiable — a future reader can check it against the codebase and get a clear pass/fail, not a vague judgment call.
The steps below exist to satisfy these criteria, not just to move mechanically from prefix to written bullet.
Asking the user
This rule covers every question this skill asks the user: a confirmation, a choice, a missing value, a numbered decision list, or a stop-and-ask. It applies even where a later step says "ask the user" or "ask exactly once". The user may watch the decisions pane rather than the chat, so a question that only goes to chat can go unanswered.
- When
mcp__decision-tracker__decisionis in your tool list (loaded, or named as a deferred tool; load a deferred one withToolSearchfirst), log each question before you ask it:- Call it with
action: "open", the question (ending in?), andoptionswhen the answers are a closed set. Setrequired: falsewhen the work can go on without an answer. A numbered list of questions opens one decision per item. Keep each returnedid. - Ask the question in chat as this skill says. The open call does not replace the chat question.
- When the user answers, in chat or as a
Decision Dn: <answer>message from the plugin, call the tool withaction: "close", theidand the answer. - When the change the answer asked for is in place, call it with
action: "implement", theidand apath:line.
- Call it with
- When the tool is absent, ask in chat only.
- An
AskUserQuestioncall is logged on its own. Do not open it again. - This rule changes where a question is logged. It does not change when this skill asks, or how many times.
Step 0 — Detect the project
- Determine the current working directory.
- Read
${CLAUDE_PLUGIN_ROOT}/skills/add-task/add-task-projects.yaml. - Match cwd against each project's
match_paths(expand~). The cwd may be a descendant of a match path. If multiple match, prefer the longest (most specific) match. - If a project matches, refer to its entry as
cfgand proceed. - If no project matches in
add-task-projects.yaml:- Tell the user the project is not registered.
- Show the values you'd use from the
defaultblock. - Ask whether to (a) proceed using the defaults this once, (b) register the project now, or (c) abort.
- If (b), collect the following fields one at a time, showing the suggested default for each:
name— project key in the YAML (e.g.my_project)match_paths— root path (default: current working directory)prefix— task identifier prefix (e.g.MYP)number_digits— zero-pad width (default:3)todo_file— relative path to the todo file (default:planning/to do/todo.md)task_dir— relative path to the task detail directory (default:planning/to do)use_full_template— whether to create per-task detail files (default:true)version_scheme— versioning convention:semver,integer,calver, ornone(default:semver)version_files— file(s) that carry the version string (default:README.md; user may specifypackage.jsonor others)
- Write all collected fields as a new entry under
projects:in the YAML before continuing.
Step 0.4 — Skill routing
Resolve which skill should actually handle this task-creation run for cfg's project:
desired_skill=cfg.skills.add_task(if set) → else the YAML's top-leveldefaults.skills.add_task(if set) → else"fsad-harness:add-task".- If
desired_skilldiffers from"fsad-harness:add-task": invoke theSkilltool with that skill name, passing$ARGUMENTSunchanged, and stop — none of this skill's remaining steps run in this invocation. - Otherwise continue to Step 1.
Step 1 — Compute the next number
Success criteria for this step: the computed ID must be numerically correct (the highest existing number for {prefix} in the todo file, plus one) regardless of whether {prefix} itself contains a hyphen (e.g. KHB-Todo), and must be verified as unique in the todo file — not merely assumed — before it is ever written. Uniqueness is protected two ways: mutual exclusion (Step 1.0's lock — only one add-task invocation can be computing/writing an ID at a time) and detection (Step 1.6's pre-write check and Step 3's post-write re-grep, which catch stale arithmetic if the lock is ever bypassed or a lock file is manually removed).
Step 1.0 — Acquire the allocation lock
Before touching the todo file, acquire an exclusive lock so two concurrent add-task invocations (two CLI sessions, an autonomous agent running alongside an interactive one, etc.) can never compute the same ID at once — this closes the race that Step 1.6/Step 3's checks can only detect after the fact.
- Lock path:
{lock_dir} = "{dirname(todo_file_path)}/.add-task.lock"— the lock lives next to the project'stodo_file, so it's naturally scoped per-project; two different projects'add-taskruns never contend for the same lock. - Attempt
mkdir "{lock_dir}"and check the exit code.mkdiris atomic on POSIX filesystems — if the directory already exists, the command fails, so exactly one concurrent caller can ever succeed.- Exit 0 (acquired) — continue to Step 1.1.
- Nonzero (lock already held):
a. Check the lock directory's age:
find "{lock_dir}" -maxdepth 0 -mmin +1.- Non-empty output (older than 60s, stale) — a prior run crashed or was killed before releasing its lock. Remove it (
rmdir "{lock_dir}") and retrymkdironce. If that retry also fails, treat the lock as fresh and fall through to (b). - Empty output (60s or newer, fresh) — another
add-taskinvocation is genuinely in progress; go to (b). b. Fresh lock — poll and retry. Wait ~2s, retrymkdir, up to 5 attempts (~10s total). If still unacquired after 5 attempts, stop and tell the user anotheradd-taskrun appears to be in progress; ask whether to keep waiting (repeat the poll) or abort. Do notrmdirthe lock on this abort path — this invocation never acquired it, so it isn't this invocation's to release; the directory the retries were failing against belongs to whichever session is still holding it. Do not proceed to Step 1.1 without the lock.
- Non-empty output (older than 60s, stale) — a prior run crashed or was killed before releasing its lock. Remove it (
- Release discipline. The lock must be released on every exit path where this invocation held it — never left held by this invocation when control leaves Steps 1–3, whether by success or by a stop-and-ask. The specific release points are called out inline at each exit below: the happy-path release after Step 3's post-write re-grep, and a release immediately before the two stop-and-asks that can only be reached after this invocation has the lock (Step 1.6's second collision, Step 3's retry-fails). The poll-timeout abort above is the one exit path with nothing to release, precisely because the lock was never acquired.
Step 1.1 — Find every existing ID
Do not read the full todo file. Use targeted Bash commands instead:
grep -oE '{prefix}-[0-9]+' "{todo_file_path}"
Substitute the literal prefix (e.g. CBP, TBS, KHB-Todo, FSD_Train) for {prefix} and the resolved absolute path for {todo_file_path}. Quote the path to handle spaces. If the output is empty, no tasks exist yet — start at 1 and skip to Step 1.3.
Step 1.2 — Parse the numeric suffix yourself — do not pipe through sort
sort -t- -k2 -n | tail -1 assumes the number always lands in field 2 when splitting on -. That assumption breaks the moment the prefix itself contains a hyphen: for KHB-Todo-0010, splitting on - gives fields KHB / Todo / 0010, so field 2 is the literal string "Todo" on every matched line — sort -n can't numerically order a constant string, and tail -1 just returns whichever line happens to sort last (effectively grep/file order), not the actual highest number. Instead, for each line grep returned, split on the last - (not a fixed field position) to isolate the trailing digits regardless of how many hyphens the prefix contains, parse each as an integer, and take the max. This is you reasoning over the grep output directly — not another shell pipeline.
Step 1.3 — Clean up empty placeholder entries
grep -nE '^- \[ \] `{prefix}-[0-9]+`\s*$' "{todo_file_path}"
If any lines are returned, remove each with Edit using the exact line text as old_string. If the only entry removed was the last real line, treat the file as empty and start numbering from 1.
Step 1.4 — Increment
Increment the highest-seen number by 1; zero-pad to cfg.number_digits digits → nnn.
Step 1.5 — Build the ID
ID = "{prefix}-{nnn}"(e.g.CBP-031,KHB-Todo-0010,FSD_Train-012).prefix_lower=cfg.prefix_in_filenameif set, otherwise the prefix lowercased.slug(only if the filename template uses it) = title lowercased, non-alphanumerics →_, collapsed runs of_, trimmed.
Step 1.6 — Pre-write uniqueness check
Before ID is used anywhere else, derive a format-agnostic match string from cfg.todo_entry_template rather than assuming a backtick wrapper. The template varies per project — most backtick-wrap the ID (`{ID}`), but e.g. KHB's bolds it instead (**{ID}**) — and a hardcoded backtick produces a false "0 hits" (spurious retry, or a silently-skipped uniqueness check) on every run for any project whose format differs. Take the substring of cfg.todo_entry_template from its start through the delimiter(s) that immediately close {ID} (e.g. - [ ] `{ID}` for a backtick template, - [ ] **{ID}** for a bold template), substitute {ID} with the literal ID, and grep for that exact literal string:
grep -cF "{id_pattern}" "{todo_file_path}"
- 0 hits —
IDis confirmed unique; continue to Step 2. - ≥1 hit — a collision (stale arithmetic, or the lock was bypassed). Increment
nnnby 1, rebuildID, and re-run the check exactly once more. - Second collision — release the lock (
rmdir "{lock_dir}"), then stop and ask the user how to proceed. Do not keep incrementing and guessing.
Step 2 — Get the title
If $ARGUMENTS is non-empty, use it. Otherwise ask:
What's the task title? (one-liner — I'll prompt for details next.)
Before adding, check for an existing entry with a similar title using:
grep -i "{keyword_from_title}" "{todo_file_path}"
Pick 2–3 distinctive words from the title as the keyword. If any lines are returned, surface them and ask whether to proceed, edit the existing one, or abandon.
Step 3 — Add the bullet to the todo file
Render cfg.todo_entry_template by substituting {ID}, {title}, {nnn}, {prefix_lower}.
Insertion point — use grep to find the right location without a full-file read:
- If
cfg.insert_before_sectionis set → rungrep -n "{section_heading}" "{todo_file_path}"to get the line number. ThenReadwithoffsetset to ~5 lines before that line number andlimitof ~10 lines to get enough context for a uniqueEditmatch. - Else if
cfg.insert_under_sectionis set → rungrep -n "^##" "{todo_file_path}"to find section boundaries. Read ~10 lines around the target section's end to locate the last bullet. - Else → run
grep -c "" "{todo_file_path}"to get the total line count, thenReadwithoffsetset to the last ~10 lines to find the final bullet.
Use the Edit tool with enough surrounding context to be unique. Don't rewrite the whole file.
If you must append through Bash instead (for example, a main-tree write from a worktree session), first add a newline when the file does not end with one. Otherwise the new bullet joins the last line. Use a quoted heredoc, because the bullet holds backticks that double quotes would run as commands:
[ -n "$(tail -c1 "{todo_file_path}")" ] && printf '\n' >> "{todo_file_path}"
cat >> "{todo_file_path}" <<'EOF'
{rendered bullet}
EOF
Post-write uniqueness re-grep — immediately after the Edit completes, re-use the same {id_pattern} derived in Step 1.6 (do not fall back to a hardcoded backtick here either):
grep -cF "{id_pattern}" "{todo_file_path}"
- Exactly 1 hit — the write is confirmed clean. Release the lock (
rmdir "{lock_dir}") — this is the happy-path release from Step 1.0 — then continue to Step 4. - 0 hits — the
Editdidn't land where expected (badold_stringmatch, wrong file, etc.). Retry the insertion once. If the retry also fails to produce exactly 1 hit, release the lock (rmdir "{lock_dir}"), then stop and ask the user. - ≥2 hits — the ID already existed elsewhere in the file (the pre-write check in Step 1.6 missed it, or the lock was bypassed and a concurrent write landed in between). Release the lock (
rmdir "{lock_dir}"), then stop and ask the user how to resolve the duplicate rather than silently leaving two entries with the same ID.
Step 4 — Gather task details
Skip this step if cfg.use_full_template is false.
Ask one question at a time (don't dump a form):
- Source — Where did this task come from? (release note, feedback, bug report, own idea). Omit the section if not applicable.
- Summary — What's changing and why? 1-3 sentences.
- Assessment — Current state? Where does the relevant content live? File paths and line numbers if you have them.
- Plan — Step-by-step implementation.
- Acceptance Criteria —
- [ ]checkbox list of verification steps.
If the user says "use your best judgment", "fill it in", or similar, proceed without blocking — infer from the title and project context.
Step 5 — Write the task-detail file
Skip this step if cfg.use_full_template is false.
Resolve the path:
{project_root}/{cfg.task_dir}/{rendered cfg.task_filename_template}
Write this content (em-dash, not hyphen, in the H1):
# {ID} — {title}
## Source
[Where this came from — or omit this section if not applicable]
## Summary
[1-3 sentences: what's changing and why]
## Assessment
[Current state of the relevant content. Does it exist? Where? What needs to change?]
**Location:** `[file path]` — [section/line reference]
## Plan
[Step-by-step implementation]
1. [Step one]
2. [Step two]
## Acceptance Criteria
- [ ] [Verification step 1]
- [ ] [Verification step 2]
If cfg.notes mentions style cues (e.g. "reference task-cbp-030.md"), peek at that file first and match its tone.
Step 6 — Confirm completion
In one short response, report:
- The project that was matched (and its root path).
- The new
ID. - That the bullet was appended to
cfg.todo_file. - The task-detail file path (if one was created).
Conventions to honour
- Number format: always zero-pad to
cfg.number_digitsdigits. - Filename casing: lowercase the prefix unless
cfg.prefix_in_filenameoverrides. - Heading separator: em-dash (
—), not hyphen. - Identifier casing in IDs: preserve
cfg.prefixexactly (e.g.FSD_Train-012,KHB-Todo-0010). - One question at a time when gathering details.
Guardrails
- Never duplicate titles — scan existing entries before creating.
- Trust the file over the cfg. If the file's existing entries clearly use a different format than
cfg.todo_entry_template, follow the file and flag the drift to the user (the cfg may be stale). - Don't modify other projects. Only touch the matched project's files.
- Don't implement the task. Only create planning artifacts; the user will do the work separately.
- Don't add a task-detail file when
cfg.use_full_templateis false. Lightweight projects (e.g. hangman) intentionally keep the bullet alone.
04 同仓库更多 Skills
sync
Pre-flight sync check for registered projects. Fetches from remote, reports uncommitted changes, and handles four states — up-to-date, ahead, behind (warns + pulls), or diverged (warns, no pull). Supports single-project (cwd detection), named-project (fsad-harness:sync key1 key2), and full-sync (fsad-harness:sync ALL) modes.
spec-review
Run a detailed, adversarial multi-agent review of a written proposal or specification (spec.md, PRD, RFC, design doc, architecture proposal, business case) — reviews the document, not code. Runs a steelman/inventory pass, then up to 10 specialist lenses (logic, assumptions, evidence, completeness, feasibility, alternatives, consistency, stakeholders, testability, risk), then adversarial validation that defaults to refuting each finding unless it survives, then a loop-until-dry completeness pass. Writes a single severity-ranked SPEC-REVIEW.md next to the document. Use when the user says "review this spec", "adversarial review", "poke holes in this proposal", "red team this PRD", "critique this design doc", "what's wrong with this RFC", "stress test this plan", or similar. Review-only — never edits the document.
ship
Short alias for /fsad-harness:ship-it. Wrap up finished work, cut a version, commit, push, and open a PR.
ship-it
Wrap up a finished round of work — verify README and CHANGELOG are current, cut a version if warranted, move completed task files into the completed/ folder, then create a feature branch if needed, commit, push, and open a PR. Run after `/fsad-harness:do-task` has marked one or more tasks done. Takes no arguments.
set-context
Gather codebase and initiative context before planning starts — runs a graphify build or query when graphify is available locally, falls back to a manual repo sweep otherwise, then asks targeted questions and writes a single context.md. Invocable standalone or as fsad-harness:plan's mandatory Phase 0. Use when the user says "set context", "gather context", or as the first step of fsad-harness:plan.
sec-review-team
Run a multi-agent security review TEAM over a codebase or recent diff. Picks a specialist roster based on detected stack signals (webapp / desktop / iac / llm-agent / container / backend / mobile / etc.) from a library of 13 specialists. Each specialist writes structured JSONL + prose findings in parallel; input-validation-auditor and auth-authz-auditor run a loop-until-dry consensus fan-out (2-8 passes); every deduped finding is adversarially verified by a dedicated validator agent before it can appear in the report. Orchestrator consolidates into a single severity-ranked REPORT.md with deduped root issues, archived per-run under a known-findings.jsonl ledger that drives auto re-review. Distinct from the built-in `/security-review` (which is a single-pass branch review). Use when the user says "multi-agent security review", "security review team", "sec-review team", "audit this branch with a team", "pre-release hardening team pass", or similar. Review-only — no fixes.