Per-Task-File Mirror Design
Per-Task-File Mirror Design
Section titled “Per-Task-File Mirror Design”Status: Research / design-only — not yet promoted to a Task.
Session: kh-prod-readiness-S55.
Author: Claude (with Liam ratification: Q3 = “Design only this session”).
Context: Liam asked whether the KH task-list.json should be supplemented with per-Task Markdown mirror files (analogous to Taskmaster’s task_NNN_*.md pattern at /Users/liamj/Documents/development/propel-pathways-39761/.taskmaster/tasks/). Goal: enable browser-renderable per-Task view + Liam reading individual Tasks without loading the whole JSON into context.
This doc lays out the design space + open questions. No implementation here.
1. Problem statement
Section titled “1. Problem statement”docs/reference/task-list.json is the canonical traceability + observability surface for KH work. Active and recently-closed Tasks live here (per kh-sdlc-workflow.md §6.3). It is the only ingress path for workflow-orchestration (parseTaskListWithWarnings enforces schema + surfaces the 25-Subtask soft-ceiling).
Currently, the only way to read a single Task’s details + journal is to load and grep the whole JSON. That is fine for agents (they read targeted Subtasks via the dispatch brief) but suboptimal for Liam, who is the human-in-the-loop and frequently wants to view one Task’s full content in a renderable form (browser, editor, markdown viewer).
Taskmaster solves this with auto-generated per-Task .md mirrors at .taskmaster/tasks/task_NNN_*.md. Regen via task-master generate. The 319-file example dir at propel-pathways-39761/.taskmaster/tasks/ shows the pattern at scale.
2. Proposed shape
Section titled “2. Proposed shape”2.1 File layout
Section titled “2.1 File layout”docs/reference/├── task-list.json # canonical source (unchanged)└── tasks/ # NEW — auto-generated per-Task .md mirrors ├── ID-6.md ├── ID-7.md ├── ID-8.md ├── ... └── ID-N.mdFile naming: ID-{id}.md where {id} matches the integer id field in task-list.json. Canonical “ID-N” prefix everywhere except the JSON id field itself.
KH currently has 9 active Tasks (S55 baseline). At Taskmaster scale (~300 tasks) the dir would be larger but still manageable.
2.2 File content (per Task)
Section titled “2.2 File content (per Task)”Render the full Task object including all Subtasks + journal blocks:
# ID-{id}: {title}
| Field | Value || --- | --- || Status | {status} || Priority | {priority} || Effort estimate | {effort_estimate} || Owner | {owner} || Created | {createdAt or earliest session_refs entry} || Updated | {updatedAt} || Session refs | {session_refs[]} || Commit refs | {commit_refs[]} || Dependencies | {dependencies[]} || Cross-doc links | {cross_doc_links[]} |
## Description
{description}
{priority_note ? "**Priority note:** " + priority_note}{status_note ? "**Status note:** " + status_note}
## Subtasks
### ID-{id}.{subtask.id}: {subtask.title}
| Field | Value || --- | --- || Status | {subtask.status} || Dependencies | {subtask.dependencies[]} |
**Description:** {subtask.description}
**Test strategy:** {subtask.testStrategy}
**Details:**
{subtask.details}
---
(repeat per Subtask)2.3 Generator script
Section titled “2.3 Generator script”Path: scripts/generate-task-md.ts.
Signature: bun run gen:tasks (alias in package.json).
Behaviour:
- Reads
docs/reference/task-list.jsonviaparseTaskListWithWarningsfromlib/validation/task-list-schema.ts(canonical ingress). - For each Task: writes
docs/reference/tasks/ID-{id}.mdusing the template above. - Idempotent — same input produces byte-identical output across runs.
- Deletes orphan
tasks/ID-N.mdfiles for Tasks no longer in task-list.json (post-cancel / post-reclassification cleanup). - Optional
--checkmode (CI-friendly) — exits non-zero if regen would change any file, no writes.
Effort: ~1h authoring (mirror-file shape + script harness + tests).
2.4 Regen triggers
Section titled “2.4 Regen triggers”Three layered options (recommend deploying B + C; A is the always-available fallback):
| Option | Trigger | Pro | Con |
|---|---|---|---|
| A. Manual | Liam runs bun run gen:tasks | Zero automation surface | Easy to forget; drift accumulates silently |
| B. Local Stop hook | Fires after any Edit/Write to docs/reference/task-list.json | Local mirror always fresh; no PR friction | Adds a hook entry; need to scope correctly |
| C. CI guard | gen:tasks --check step in ci.yml | Catches drift on PR (mirror-file commits enforced) | Adds ~5s to CI |
Recommendation: B + C. Manual A is implicitly available regardless.
2.5 Workflow-file impact
Section titled “2.5 Workflow-file impact”The mirror is for humans, not agents. Existing workflow stays unchanged:
| File | Touched? | Why |
|---|---|---|
workflow-orchestration SKILL.md “Loading task-list.json” section | No | Canonical ingress remains parseTaskListWithWarnings(JSON) |
task-executor agent — dispatch-brief reading | No | Executor reads the details field passed in its brief; doesn’t ingest mirrors |
task-planner agent — Subtask population | No | Planner writes to JSON; mirror regenerates after |
task-checker agent — verification | No | Checker reads commit set + spec slice + JSON Subtask; not the mirror |
workflow-curator agent — triage | No | Curator’s update-roadmap-backlog writes to other JSON ledgers, not task-list.json |
start-session skill §2c “Task-list state inspection” | Optional | Could add a footnote: “Per-Task .md mirrors at docs/reference/tasks/ give a faster read for individual Tasks; JSON remains the parse target.” |
handoff skill — continuation prompt assembly | Optional | Could point to mirror paths in the “Read first” section for human-friendly opens |
claude-md-management:claude-md-improver, kpf:refresh-reference-docs etc. | No | Mirror is downstream; never the source |
Net: agent paths untouched. Only Liam-facing skills (start-session + handoff) optionally point to mirrors.
3. Open questions for Liam
Section titled “3. Open questions for Liam”These are the design judgement calls. Defaults proposed where possible.
| Q | Question | Default proposal |
|---|---|---|
| Q1 | Subtask details field journal blocks (<info added on …>) — render full verbose journal in per-Task .md or summarise? | Full verbose. Loses fidelity if summarised; mirror is the human-readable surface, fidelity matters there |
| Q2 | Counter padding: ID-1.md vs ID-01.md vs ID-001.md? | No padding (matches existing convention — ID-6.md, ID-19.md). Filesystem sort fine for current scale |
| Q3 | CI guard policy — block PR on drift, or warn only? | Block. Mirror drift = stale view; treat as test failure to keep them honest |
| Q4 | Include backlinks from per-Task .md to source spec docs (PRODUCT.md, TECH.md, PLAN.md) where they exist? | Yes. Each Subtask {N.2}/{N.3}/{N.4} should link to its written artefact for one-click navigation |
| Q5 | Render dependencies[] as plain text or as links to other ID-N.md mirrors? | Links. [ID-7] → ./ID-7.md (illustrative output format) — one-click navigation between Tasks |
| Q6 | Mirror for cancelled Tasks — keep, delete, or move to archive? | Delete. Per existing task-list.json rules (cancelled Tasks are removed), mirror follows |
| Q7 | Mirror for done Tasks — same as in_progress, or compact form? | Same as in_progress. Done Tasks are recently-closed records per §6.3; full content stays useful |
| Q8 | Should the Stop hook (option B) fire on every edit, or debounce (e.g. only on commit)? | Every edit. Cheap (~9 small files at current scale); deterministic |
4. Estimated effort if promoted to a Task
Section titled “4. Estimated effort if promoted to a Task”Treating this as a Task with PRODUCT + TECH + implementation Subtasks:
| Subtask | Scope | Effort |
|---|---|---|
{N.1} RESEARCH.md | Skip — this doc is the research | 0h |
{N.2} PRODUCT.md | Behaviour invariants for mirror file shape + regen triggers + Q1-Q8 answers | ~30min |
{N.3} TECH.md | Generator script + hook config + CI step + per-Task .md template | ~30min |
{N.4} PLAN.md | Probably skip — N.5+ Subtasks are linear | 0h |
{N.5} Generator script + tests | scripts/generate-task-md.ts + Vitest | ~1.5h |
{N.6} Initial mirror commit + add to .gitignore/CI | One-time generation + git add + gen:tasks package.json alias | ~30min |
{N.7} Stop hook configuration | .claude/settings.json PostToolUse hook on task-list.json edits | ~30min |
{N.8} CI guard | ci.yml step running bun run gen:tasks --check | ~30min |
{N.9} Optional start-session + handoff skill footnotes | Two small Edit ops | ~15min |
Total: ~4h. Comfortably one-Task scope.
5. What this design does NOT cover
Section titled “5. What this design does NOT cover”- Browser rendering surface. Liam mentioned “viewing a markdown version and rendering it to the UI or a browser” — that’s a separate concern (Astro-Starlight from ID-9, or a lightweight
docs.kh.phew.org.ukroute). Per-task .md files are render-ready by any markdown viewer; they don’t dictate which one - Bidirectional sync. Mirror is read-only; canonical writes still go to task-list.json
- Cross-Task aggregation views. A “next task to work on” view would need a separate index file (
docs/reference/tasks/INDEX.md) — outside this design’s scope; can add as a follow-up - Migration of any Taskmaster CLI behaviour. Per
workflow-orchestration§“What this skill is NOT” → “Not Taskmaster-coupled” — we adopt the per-file shape, not thetask-master generateinvocation or MCP tool
6. Recommended next action
Section titled “6. Recommended next action”Promoted to ID-20 at S55 close (per Liam ratification). Subtasks:
- 20.1 RESEARCH — this design doc (status: done at S55 close; awaits Liam OQ responses to mark complete)
- 20.2 RESEARCH — rendering-surface options (see §8 below)
- 20.3+ — spec chain (PRODUCT.md / TECH.md / PLAN.md if needed) authored after both research subtasks complete
7. Cross-project tooling constraint (important — affects file locations)
Section titled “7. Cross-project tooling constraint (important — affects file locations)”Per Liam at S55 close:
The task list tooling and setup, as well as our dev workflow eventually aren’t Knowledge Hub products. They’re the tooling that you and I use across multiple projects. So anything that we do create or build, we need to keep this in mind in terms of where we are storing tools/files etc.
Implication: the generator script + render surface + any supporting tooling MUST NOT live inside knowledge-hub/scripts/ or knowledge-hub/lib/ even though they will operate on knowledge-hub/docs/reference/task-list.json first. Reasonable target locations to evaluate during 20.2 / TECH.md:
~/.claude/plugins/task-list-mirror/— Claude plugin shape (skill + scripts + settings). Works cross-project; auto-discovered by Claude Code.~/.claude/tools/task-list-mirror/— bare scripts dir under global Claude config. Simpler; no plugin discovery semantics needed.- Separate
dev-toolingrepo — own git repo, installable via npm/bun link or symlink into each project. Highest ceremony; clearest project boundary. ~/.config/dev-workflow/— XDG-style; standalone CLI invoked by name.
What stays in KH: the canonical docs/reference/task-list.json (this is KH’s data, not the tool); the mirror output docs/reference/tasks/*.md (KH-rendered artefact); the Stop hook + CI guard wiring in .claude/settings.json + .github/workflows/ (per-project glue).
What moves out of KH: the generator script logic; the renderer (Plannotator fork or alternative); any shared schemas / TypeScript types describing the task-list shape.
The Q1-Q8 answers stay portable across this constraint — they describe the mirror file shape, not where the generator lives.
8. Rendering surface research (Subtask 20.2 scope)
Section titled “8. Rendering surface research (Subtask 20.2 scope)”Liam at S55 close: the per-Task .md mirror solves the storage problem (one file per Task, browser-renderable, editor-friendly). It does not solve the interaction problem — Liam wants to edit Task / Subtask state (text, status) from a UI, not just view.
Inputs to evaluate in 20.2:
Input A — Plannotator (Liam’s locally-forked candidate)
Section titled “Input A — Plannotator (Liam’s locally-forked candidate)”- Current capability: annotation UI on markdown files; takes filename as input
- Gap (per Liam): ability to update content (e.g. Subtask text or status), not just annotate
- Research questions:
- Does Plannotator already support edit mode that wasn’t surfaced in the README?
- If not, what’s the smallest fork delta to add: (a) edit-in-place for arbitrary text spans, (b) structured field edit for status (enum) + priority (enum)?
- Does the fork need a write-back path to
task-list.json(the canonical), or only to the.mdmirror (with the generator running in reverse)?
Input B — knowledge-hub-knowledge-platform repo legacy work
Section titled “Input B — knowledge-hub-knowledge-platform repo legacy work”- Path:
/Users/liamj/Documents/development/knowledge-hub-knowledge-platform/(worktree onkh-knowledge-platformbranch) - What was built: migrations + code that rendered state files (backlog, roadmap) to the platform’s UI
- Research questions:
- Catalogue the relevant files (likely
app/,components/,lib/, migrations) — what does it render, how, with what UI shape? - Which pieces are reusable as cross-project tooling vs. KH-coupled (assume most are KH-coupled given they’re in the KH repo)?
- Would the rendering approach work for per-Task .md mirrors with edit-back, or is it too coupled to the platform’s auth + Supabase setup?
- Catalogue the relevant files (likely
Recommendation framing for the 20.2 deliverable
Section titled “Recommendation framing for the 20.2 deliverable”A short doc (docs/research/per-task-render-surface.md) covering:
- Plannotator current edit capabilities (with link to fork)
- kh-knowledge-platform legacy work inventory (with file paths + what each does)
- Recommendation: build on Plannotator fork (with required deltas), build on kh-platform legacy (with caveats), or new minimal UI
- Cross-project tooling location implications (per §7) for whichever path wins
This research blocks 20.3 PRODUCT.md authoring. Once both 20.1 and 20.2 are ratified, the spec chain captures the unified design.