From coding-toolkit
Project task management for any coding repo: epics, milestones, and feature-sized tasks tracked as one markdown note per task in a local Obsidian vault, queried via Obsidian Bases. This is the durable layer ABOVE a single implementation — it owns what work exists and where it stands, then hands each task into the superpowers brainstorm → spec → plan → execute loop and records the spec/plan links. Use it whenever the user is choosing or prioritising what to work on next, grooming or triaging the backlog, adding a feature/epic/milestone, or starting any new feature-sized piece of work. Also applies when a repo already tracks work in an informal tracker (project.md, ROADMAP.md, TODO.md, KNOWN_ISSUES.md, etc.) but has no pm/ vault. Invoke this skill to handle these — do not read tracker files or probe pm/ yourself; the skill owns detection, ranking, and migration. NOT for a one-off typo or single-file bugfix, a two-minute tweak, or ticking an in-flight plan checkbox — those stay in the plan.
How this skill is triggered — by the user, by Claude, or both
Slash command
/coding-toolkit:task-workflowThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
The **durable** project-management layer for a repo. It tracks *what work
scripts/tw.shtemplates/backlog.basetemplates/board.basetemplates/by-epic.basetemplates/by-milestone.basetemplates/epic.mdtemplates/milestone.mdtemplates/pm-task.mdtemplates/vendor/README.mdtemplates/vendor/kanban-bases-view/LICENSEtemplates/vendor/kanban-bases-view/main.jstemplates/vendor/kanban-bases-view/manifest.jsontemplates/vendor/kanban-bases-view/styles.cssThe durable project-management layer for a repo. It tracks what work exists and where it stands across many features over time. It is distinct from — and feeds into — the ephemeral superpowers implementation loop.
A PM task is a feature-sized story (1–N days). A superpowers plan step is a 2–5 minute checkbox. They are different layers. Never create a PM note per plan step. One PM task → one spec file → one plan file containing 10–30 steps. Getting this wrong floods the vault with dozens of notes per feature and makes Bases useless.
| Layer | Unit | Lives in | Tracked by | Durable |
|---|---|---|---|---|
| PM (this skill) | feature-sized task / epic / milestone | one Obsidian note + YAML frontmatter | Obsidian Bases | yes |
| Implementation (superpowers) | 2–5 min step | docs/superpowers/plans/*.md checkbox | TodoWrite | no |
Ownership contract — do not duplicate content across layers:
status, and links out.docs/superpowers/specs/…) owns: the design.docs/superpowers/plans/…) owns: the how (steps).The PM note links forward via spec_file: / plan_file:. Spec/plan files may
back-reference pm_task: for provenance. The PM note's status is the single
field the agent advances as it walks the superpowers loop.
A local Obsidian vault lives at pm/ in the repo root:
pm/
.obsidian/ # vault config + the vendored kanban plugin
plugins/kanban-bases-view/ # bundled by tw init (MIT) — real kanban board
community-plugins.json # enables the kanban plugin: ["kanban-bases-view"]
tasks/ # one note per PM task: T-NNN-<slug>.md
epics/ # one note per epic: epic-<slug>.md
milestones/ # one note per milestone: m-<slug>.md
archive/ # done tasks moved here after they settle
board.base # Kanban + table over tasks/, grouped by status
backlog.base # status=backlog, priority column first (sort in UI)
by-epic.base # Kanban + table, columns = epic
by-milestone.base # Kanban + table, columns = milestone
Task filenames are T-NNN-<slug>.md (e.g. T-007-csv-export.md) so a folder
listing is self-describing, but T-NNN is still the only lookup key — every
tw command takes the bare id (tw status T-007 done), and the slug is cosmetic.
If a vault ever has two files for one id (a stale slug left beside a renamed one),
tw errors and you run tw rename-files to repair filenames from frontmatter.
archive/ exists from day one: move a task note here once it has been done
for a while. Bases editing performance degrades past several hundred notes, so
keep tasks/ to live work only.
A PM task's status advances through the superpowers loop:
backlog → speccing → planning → in-progress → review → done
backlog — captured, not started.speccing — running superpowers brainstorming; produces the spec file.planning — running superpowers writing-plans; produces the plan file.in-progress — running executing-plans / subagent-driven-development.review — code green, running adversarial review / finishing the branch.done — merged. Eligible for archive/.blocked and cancelled are terminal/holding states usable from any point.
The helper lives at ${CLAUDE_PLUGIN_ROOT}/skills/task-workflow/scripts/tw.sh
(same path the /tw command uses; resolves wherever the plugin is installed).
Examples below abbreviate it as tw; run it with that full path (or alias it).
It operates on the pm/ vault under the current repo, so run it from inside
the target repo.
Do not hand-detect vault state. Do not run test -d pm/... yourself and do
not scan the repo for tracker files yourself. The tw.sh script is the gate: it
detects the vault, detects a foreign tracker, and prints the directive that tells
you what to do. If you reimplement that detection in your own Bash, you skip the
gate and freelance a backlog — the exact failure this preflight exists to stop.
tw.sh next; for a capture
it is the tw.sh new … the user asked for. Run it and branch on the result:
tw: run 'tw.sh init' first (no vault, no foreign
tracker) → go to step 2.tw init will do
(creates pm/{tasks,epics,milestones,archive}, the .base views, and bundles
the vendored kanban-bases-view plugin so the board is a real drag-and-drop
Kanban — not just a grouped table).
Wait for a yes — do not scaffold files unasked. On yes: run tw.sh init
yourself, then re-run the original subcommand. On no: stop; don't run
PM commands that would fail.tw init is idempotent (mkdir -p, cp -n) — safe to run if unsure whether a
partial vault exists. It does not launch Obsidian or require it to be
running; the vault is plain files. Opening it in Obsidian (and enabling the
Bases core plugin on first open) is a manual, human-side step.
When step 2 finds a foreign tracker and no opt-out flag, offer to migrate it into the PM vault. Migration is propose → approve → run: nothing touches the vault until the user signs off, and the source tracker file is never modified (it stays as the audit trail).
Tell the user what you found (which tracker file) and offer to migrate it
into a pm/ vault. Ask how much control they want — adapt to the answer:
tw new … command list, run
it only after the user approves.On confirm: scaffold first. Run tw init to create the empty vault.
Dispatch a migration sub-agent. Use the Agent tool with
subagent_type: general-purpose and model: opus — migration is a one-shot
that defines the vault's whole epic/milestone structure, so classification
errors propagate into every downstream link. Use the strongest model; do not
let it inherit a weaker one. Dispatch it with this prompt (fill in the source
path and the tw.sh path):
Read
<source tracker path>. Classify each work item as a task, epic, or milestone. Output a list of shell commands. Order matters: emit everynew epic/new milestoneline BEFORE any task that references it.
- Epics:
<tw.sh path> new epic "Title" --slug epic-<short-slug>- Milestones:
<tw.sh path> new milestone "Title" --slug m-<short-slug>- Tasks:
<tw.sh path> new task "Title" [--epic epic-<short-slug>] [--milestone m-<short-slug>] [--priority N]The
--slugyou give an epic/milestone is its full id; reference that exact string in each task's--epic/--milestone. Choose short, stable slugs (epic-rpc-shape, not the whole title) and use them consistently — this is what keeps task links from dangling. Infer grouping and priority from the source structure. Output ONLY the command list as your final message — do NOT run any command and do NOT edit the source file. Preserve source ordering within each kind.
It returns the command list as its final message.
Main thread applies the result per the chosen control level: show the
command list (propose-confirm/interactive) or just run it (auto). Run each
command from the repo root, epics/milestones first so task --epic
references resolve. Then tw check to confirm the vault parses with no
dangling links.
Offer to open the vault in Obsidian (always — even in Auto). Once
tw check is clean, before you write the migration summary or answer the
original question, stop and ask the user whether to open the new pm/
vault in Obsidian now. A migration is not complete until this offer is made;
do not roll straight from tw check into the backlog answer. On no,
leave it — the files are already on disk. On yes, register and open it
correctly:
open -a Obsidian "<path>"does NOT register or switch to a new vault — it only re-focuses Obsidian on whatever vault was last active. A vault Obsidian has never seen must be added to its registry first. Do not loop onopen -a; it will keep landing on the wrong vault.
osascript -e 'quit app "Obsidian"', then pkill -x Obsidian if needed) so it doesn't overwrite the file on exit.~/Library/Application Support/obsidian/obsidian.json, add an entry under vaults: a fresh random hex id → { "path": "<abs vault path>", "ts": <epoch-ms>, "open": true }, and set open: false on every other vault so the new one is the one that opens.open -a Obsidian.Bases ships enabled by default in current Obsidian, so the table views in
board.base / backlog.base render on first open with no action. The Kanban
views need the bundled kanban-bases-view community plugin, and Obsidian
opens any vault with community plugins in restricted mode: it shows "Do you
trust the authors of this vault?" on first open. Tell the user explicitly to
click Trust (then, if prompted, Enable community plugins) — until they do,
the Kanban columns fall back to the table view and the board looks plugin-less.
There is no filesystem way to pre-trust the vault; the click is required once.
Offer to archive the migrated source tracker (optional). The source file was never modified during migration and stays as the audit trail — but it is now superseded by the vault, and a future session may read the stale tracker instead of the vault. After the user has the vault open, offer to tidy it. Only on yes, and never deleting:
git mv <tracker> docs/legacy/<tracker> (a move preserves git history; do
not rm). Move only the trackers that were actually migrated — leave
design/spec/brand docs (DESIGN.md, PRODUCT.md, …) where they are.docs/legacy/README.md stub: one line saying these files are a frozen
audit trail, the date migrated, and that pm/ is now the source of truth.docs/legacy/ to the
Obsidian userIgnoreFilters so the archived trackers don't clutter the view.
If the user prefers the tracker visible at root for history, skip this — it is
a convenience, not a requirement.Vault at pm/ (default) vs. the repo root. This skill defaults to a vault
scoped to pm/ — bounded, so Obsidian never treats stray repo .md as PM notes
and no exclude filters are needed. Some users instead want the whole repo as
the vault (to browse all project notes in Obsidian). That works, but it is a
manual reconfiguration, not a tw mode: move .obsidian/ from pm/ up to the
repo root, and in .obsidian/app.json set userIgnoreFilters to hide noise
(node_modules/, dist/, build/, out/, coverage/, .git/,
.claude/worktrees/) and showUnsupportedFiles: false. tw.sh is unaffected —
it only touches pm/tasks and pm/*.base, wherever the vault config lives. Gitignore
the root .obsidian/workspace* / cache local state but commit app.json /
core-plugins.json.
Stored in .claude/coding-toolkit.local.md at the target repo root (shared
across this plugin's skills, so use a scoped key). It is a local preference, not
shared state: when you write it, also ensure the repo ignores it — add
.claude/*.local.md to the repo's .gitignore if not already present (create
.gitignore with that line if the repo has none). It silences the prompt,
not the detection.
Read: before pitching migration, check the file for
task_workflow.migrate_declined: true in its YAML frontmatter (Read the file,
or grep). If set → do not pitch migration; proceed with the bare-init offer.
Write on decline: if the user says they don't want to migrate, create or
update .claude/coding-toolkit.local.md with:
---
task_workflow.migrate_declined: true
---
Preserve any existing frontmatter keys other skills wrote — merge, don't clobber.
If the user later asks how to migrate (explicitly), tell them: delete that key (or run migration directly via the steps above). Do not volunteer this reminder unprompted on every PM call — the whole point of the flag is silence.
Run tw next — prints the highest-priority backlog task (ties broken by oldest
created). Or open backlog.base in Obsidian.
tw status T-042 speccingbrainstorming. When it writes the spec to
docs/superpowers/specs/…, record it: tw link T-042 spec <path>.tw status T-042 planning; invoke superpowers writing-plans;
record the plan: tw link T-042 plan <path>.tw status T-042 in-progress; invoke superpowers
executing-plans (or subagent-driven-development).tw status T-042 review; finish the branch + adversarial review
per the coding-principles skill.tw status T-042 done.tw new task "CSV export" --epic epic-export --milestone m1-ga --priority 2tw new epic "Data export"tw new milestone "GA"tw check — flags malformed frontmatter, unknown status values,
and dangling epic: / milestone: wikilinks. Run after bulk edits; Bases
silently drops rows whose frontmatter doesn't parse.
Bases reads YAML frontmatter one note = one row. Get the types right or the row vanishes from views:
status — one of the lifecycle values above, unquoted bare word is fine
but stay exact (in-progress, not In Progress).priority — number 1–3 (1 highest), unquoted.created — ISO 8601 date YYYY-MM-DD, unquoted.epic / milestone — wikilink inside quotes: "[[epic-export]]".spec_file / plan_file — repo-relative path string, may be empty.Use the templates in templates/ rather than writing frontmatter from memory.
kepano/obsidian-skills plugin (Bases,
markdown, frontmatter). Adopt it for .base authoring details rather than
re-deriving Bases YAML here.brainstorming, writing-plans,
executing-plans, finishing-a-development-branch). This skill only manages
the PM layer and the handoff; it does not re-implement planning.tw.sh needs only git plus POSIX awk/sed — no yq. The frontmatter
schema is flat, so a line-oriented reader suffices and stays portable.Guides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.
npx claudepluginhub adeanima/coding-toolkit --plugin coding-toolkit