Skip to content

Write the work state from the skills #205

Closed

Description

@ToRvaLDz

Parent: 🗺 trailhead mod

Question

Make the skills write the work state, as decided in Where does the mod read the work state from? (#200):

  • a template helper trailhead-work-state.js (set --map --ticket --title --step --auto, clear): atomic write of .trailhead/work-state.json, field validation, session stamped from the host session id when exposed (CLAUDE_CODE_SESSION_ID), updatedAt stamped; unit-tested;
  • the skill prose calls it at work-start, at each step change (discuss | plan | execute | verify | resolve | paused), on auto start/stop, keeps it on pause and clears it at Resolve with session-ticket; resolved via the same three template dirs as the commit-msg sync, a missing helper never blocks the work;
  • .trailhead/work-state.json gitignored like session-ticket; session-ticket and the commit-msg hook unchanged;
  • the Codex projection carries the helper and the calls (host-neutral, no mod needed).
    Done when working a ticket on Claude Code and on Codex leaves an up-to-date work-state.json at every step and none after Resolve.

Activity

  1. self-assigned this
    on Oct 10, 2026
  2. ToRvaLDz commented on Oct 10, 2026

    @ToRvaLDz
    OwnerAuthor

    PLAN

    Goal. Every worked ticket leaves an up-to-date .trailhead/work-state.json at the working root at each step, on Claude Code and Codex alike, and none after Resolve. Implements the resolution of Where does the mod read the work state from? (#200). Commits land on feat/mod (this map's integration branch).

    Steps

    1. Helper, test first (TDD at the seam): plugins/trailhead/hooks/lib/work-state.test.js (RED), then plugins/trailhead/templates/trailhead-work-state.js (GREEN). Self-contained, same shape as trailhead-commit-msg-sync.js (pure functions exported, main(argv, {cwd, stdout, env}) injectable).
      • CLI: set [--repo <dir>] [--map <n>|none] [--ticket <n>] [--title <t>] [--step <step>] [--auto true|false] and clear [--repo <dir>]; --repo defaults to cwd.
      • set merges onto the existing file (a step change passes only --step), except when --ticket names a different ticket than the file holds: then it starts from an empty state (no carry-over of a stale title/map). A resulting state without a ticket or a step is a usage error.
      • Validation: map positive int or none (null, a whiteboard ticket); ticket positive int; step in discuss | plan | execute | verify | resolve | paused; title trimmed, control chars/newlines collapsed to spaces, capped at 200 chars; auto true|false (default false on a fresh state). Unknown flag, missing value, or an invalid value -> exit 2 with a stderr line, nothing written.
      • Stamps: session from CLAUDE_CODE_SESSION_ID when set and non-empty, else null; updatedAt ISO-8601 now. Shape exactly { map, ticket, title, step, auto, session, updatedAt } (matches types/index.d.ts WorkState).
      • Atomic write: mkdir -p <repo>/.trailhead, write a unique temp file in that dir, rename over work-state.json, temp cleaned on failure. A corrupt existing file is treated as empty (overwritten, never a crash).
      • clear: unlink if present. Output one JSON line {status, path, state?}, status written | cleared | absent | skipped (skipped = unexpected I/O error, message carried; exit 0 so it never blocks the caller).
      • Tests cover: fresh set, merge on step change, new ticket resets, none map, validation failures (exit 2, no file), title sanitising, session from env vs absent, atomic write leaves no temp files, corrupt file recovery, clear present/absent, JSON output line.
    2. Gitignore: add .trailhead/work-state.json to the repo .gitignore.
    3. Prose, one canonical paragraph + call sites (source docs, English, no em-dashes):
      • skills/_shared/teamwork.md: a Work state file paragraph beside the commit-msg hook one: what the file is, <templates> resolved by the same three-dir lookup as the commit-msg sync, the set/clear forms, gitignored like session-ticket, independent of session-ticket and the commit-msg hook, and that a missing helper or a non-zero exit is silent and never blocks the work (no user-facing line).
      • skills/trailhead-work/SKILL.md: Work the map step 2, a bullet after the session-ticket marker: set --map <n> --ticket <n> --title "<title>" --step discuss at the working root (add the gitignore entry if absent); quick bullet: same, --map none for a whiteboard ticket.
      • skills/trailhead-work/references/ticket-engines.md: one standing Work state (every type) paragraph near the top mapping steps: build Discuss/Plan/Execute/Verify/Resolve -> discuss/plan/execute/verify/resolve; bug Repro+Diagnose -> discuss, Fix -> execute, Verify -> verify, Resolve -> resolve; decision/prototype/task -> discuss until resolve; a loop back from Verify to Execute/Fix sets execute again.
      • skills/_shared/session-handoff.md: at the marker removal, also clear the work state.
      • skills/_shared/teamwork.md Pause/Resume: pause sets --step paused and keeps the file whether or not the claim is released; resume sets the recorded next step (re-creating the file if absent).
      • skills/trailhead-work/references/auto.md: during a run every set carries --auto true; at run end (drained or interrupt) a remaining file gets set --auto false.
    4. Codex projection: the helper rides templates/ wholesale and the prose is projected; add pins in bin/trailhead.test.js (helper projected byte-identical on --codex) and bin/lib/codex-projection.test.js (convertToCodex keeps trailhead-work-state.js and CLAUDE_CODE_SESSION_ID intact; the projected work skill carries the set/clear calls).

    Seams

    Helper CLI contract (main with injected cwd/env/stdout) and its pure mergeState/validate functions; the projection text transform.

    Files touched

    plugins/trailhead/templates/trailhead-work-state.js (new), plugins/trailhead/hooks/lib/work-state.test.js (new), .gitignore, plugins/trailhead/skills/_shared/{teamwork,session-handoff}.md, plugins/trailhead/skills/trailhead-work/SKILL.md, plugins/trailhead/skills/trailhead-work/references/{ticket-engines,auto}.md, bin/trailhead.test.js, bin/lib/codex-projection.test.js.

    Verification criteria

    • npm test green (the new suite is picked up by scripts/test.js under hooks/).
    • Manual run in a temp repo: set at work-start writes the full shape with session from CLAUDE_CODE_SESSION_ID; set --step plan updates only step + updatedAt; clear removes it; on a --codex install the projected helper behaves the same with session: null.
    • session-ticket handling and the commit-msg hook untouched (no diff in templates/trailhead-commit-msg, hooks/lib/commit-message-check.js).
    • Every prose call site names the same set/clear forms; no em-dashes introduced.
  3. ToRvaLDz commented on Oct 10, 2026

    @ToRvaLDz
    OwnerAuthor

    PLAN (revised after plan review)

    Goal. Every worked ticket leaves an up-to-date .trailhead/work-state.json at the working root at each step, on Claude Code and Codex alike, and none after Resolve. Implements the resolution of Where does the mod read the work state from? (#200). Commits land on feat/mod (this map's integration branch).

    Steps

    1. Helper, test first (TDD at the seam): plugins/trailhead/hooks/lib/work-state.test.js (RED), then plugins/trailhead/templates/trailhead-work-state.js (GREEN). Self-contained, same shape as trailhead-commit-msg-sync.js (pure functions exported, main(argv, {cwd, stdout, env}) injectable).
      • CLI: set [--repo <dir>] [--map <n>|none] [--ticket <n>] [--title <t>] [--step <step>] [--auto true|false] and clear [--repo <dir>]; --repo defaults to cwd.
      • set merges onto the existing file (a step change passes only --step), except when --ticket names a different ticket than the file holds: then it starts from an empty state (no carry-over of a stale title/map). The whole resulting state is validated and normalised after the merge: an existing field that fails validation is dropped (treated as absent), never carried over; a resulting state without a ticket or a step is a usage error.
      • Validation: map positive int or none (null, a whiteboard ticket); ticket positive int; step in discuss | plan | execute | verify | resolve | paused; title trimmed, control chars/newlines collapsed to spaces, capped at 200 chars; auto true|false (default false on a fresh state). Unknown flag, missing value, or an invalid value -> exit 2 with a stderr line, nothing written.
      • Stamps: session from CLAUDE_CODE_SESSION_ID when set and non-empty, else null; updatedAt ISO-8601 now. Shape exactly { map, ticket, title, step, auto, session, updatedAt } (matches types/index.d.ts WorkState).
      • Atomic write: mkdir -p <repo>/.trailhead, write a unique temp file in that dir, rename over work-state.json, temp cleaned on failure. A corrupt existing file is treated as empty (overwritten, never a crash).
      • clear: unlink if present. Output one JSON line {status, path, state?}, status written | cleared | absent | skipped (skipped = unexpected I/O error, message carried; exit 0 so it never blocks the caller).
      • Tests cover: fresh set, merge on step change, new ticket resets, none map, validation failures (exit 2, no file), title sanitising, session from env vs absent, corrupt file recovery, a malformed-but-valid-JSON existing file (bad fields dropped, not carried), clear present/absent, JSON output line, and failure injection (injected fs whose write or rename throws: the previous valid file survives byte-identical and no temp file is left).
    2. Gitignore: add .trailhead/work-state.json to the repo .gitignore.
    3. Prose, one canonical paragraph + call sites (source docs, English, no em-dashes):
      • skills/_shared/teamwork.md: a Work state file paragraph beside the commit-msg hook one: what the file is, <templates> resolved by the same three-dir lookup as the commit-msg sync, the set/clear forms, gitignored like session-ticket, independent of session-ticket and the commit-msg hook, and that a missing helper or a non-zero exit is silent and never blocks the work (no user-facing line).
      • skills/trailhead-work/SKILL.md: Work the map step 2, a last bullet, after the isolation workspace is set up (the working root is final only then): set --map <n> --ticket <n> --title "<title>" --step discuss at the working root (add the gitignore entry if absent); quick bullet: same, --map none for a whiteboard ticket.
      • skills/trailhead-work/references/ticket-engines.md: one standing Work state (every type) paragraph near the top mapping steps: build Discuss/Plan/Execute/Verify/Resolve -> discuss/plan/execute/verify/resolve; bug Repro+Diagnose -> discuss, Fix -> execute, Verify -> verify, Resolve -> resolve; decision/prototype/task -> discuss until resolve; a loop back from Verify to Execute/Fix sets execute again; a UAT follow-up (UAT of:) sets verify. research tickets never write it: they run AFK and possibly in parallel, so the single file tracks only the one ticket in play.
      • skills/_shared/session-handoff.md: at the marker removal, also clear the work state.
      • skills/_shared/teamwork.md Pause/Resume: pause sets --step paused and keeps the file whether or not the claim is released; resume sets the recorded next step (re-creating the file if absent).
      • skills/trailhead-work/references/auto.md: during a run every set carries --auto true; at run end (drained or interrupt) a remaining file gets set --auto false.
    4. Codex projection: the helper rides templates/ wholesale and the prose is projected; add pins in bin/trailhead.test.js (helper projected byte-identical on --codex) and bin/lib/codex-projection.test.js (convertToCodex keeps trailhead-work-state.js and CLAUDE_CODE_SESSION_ID intact; the projected work skill carries the set/clear calls).

    Seams

    Helper CLI contract (main with injected cwd/env/stdout) and its pure mergeState/validate functions; the projection text transform.

    Files touched

    plugins/trailhead/templates/trailhead-work-state.js (new), plugins/trailhead/hooks/lib/work-state.test.js (new), .gitignore, plugins/trailhead/skills/_shared/{teamwork,session-handoff}.md, plugins/trailhead/skills/trailhead-work/SKILL.md, plugins/trailhead/skills/trailhead-work/references/{ticket-engines,auto}.md, bin/trailhead.test.js, bin/lib/codex-projection.test.js.

    Verification criteria

    • npm test green (the new suite is picked up by scripts/test.js under hooks/).
    • Manual run in a temp repo: set at work-start writes the full shape with session from CLAUDE_CODE_SESSION_ID; set --step plan updates only step + updatedAt; clear removes it; on a --codex install the projected helper behaves the same with session: null.
    • session-ticket handling and the commit-msg hook untouched (no diff in templates/trailhead-commit-msg, hooks/lib/commit-message-check.js).
    • Every prose call site names the same set/clear forms; no em-dashes introduced.
  4. ToRvaLDz commented on Oct 10, 2026

    @ToRvaLDz
    OwnerAuthor

    PLAN-REVIEW

    Reviewer: codex (read-only, low effort), one round. The revised PLAN above resolves every blocking concern.

    • Blocking: initial write placed before the isolated workspace exists. Resolved: the initial set is the last work-start bullet, after the workspace is set up, so it lands at the final working root.
    • Blocking: parallel research tickets cannot share one file. Resolved: research never writes the work state; the file tracks only the one ticket in play.
    • Blocking: merged existing data not validated. Resolved: the whole post-merge state is validated; invalid existing fields are dropped, never carried.
    • Non-blocking: UAT follow-ups map to verify. Accepted.
    • Non-blocking: failure-injection test for atomic replacement. Accepted.
    • Non-blocking: prose lifecycle-ordering assertions. Deferred: ordering in prose is reviewed at Verify; string-order tests over Markdown would be brittle. Projection pins stay on the helper and the call forms.
  5. ToRvaLDz commented on Oct 10, 2026

    @ToRvaLDz
    OwnerAuthor

    VERIFY

    Tests. npm test: 23 ok/skipped, 0 failed (includes the new hooks/lib/work-state.test.js, 75 checks with failure injection, the Codex projection pins, claude plugin validate, claude plugin test).

    Code review (ticket diff: the Refs: #205 commits 7bc5850, 826242d, b3274ee, f03782c; fix round df51aa2, 4ddb6ab).
    critical: 0 · warning: 1 · info: 1

    Findings ledger:

    • W1 (warning): resume / pause in a fresh workspace used the step-only set, which exits 2 when no file exists, so the work state was silently never re-created. fixed in 4ddb6ab (Resume and the Work state file paragraph now pass the full work-start form where the file may be absent).
    • I1 (info): title defaulted to "" though the contract admits null. fixed in df51aa2 (no title -> null, tests updated).

    Goal-backward verification: met. Helper run in a temp repo through set / step changes / --auto / new ticket / clear, with and without CLAUDE_CODE_SESSION_ID; a --codex install into a temp dir carries the helper byte-identical (same behaviour, session: null) and the projected prose carries the calls at work-start, each step, pause, resume, auto and Resolve; .trailhead/work-state.json gitignored; session-ticket and the commit-msg hook untouched; no em-dashes introduced.

    Acceptance testing: not user-facing (local state file for tooling, no UI yet), so none owed.

  6. ToRvaLDz commented on Oct 10, 2026

    @ToRvaLDz
    OwnerAuthor

    Resolved. The skills now write the work state the mod will read.

    • New template helper plugins/trailhead/templates/trailhead-work-state.js (set / clear): atomic write of .trailhead/work-state.json with {map, ticket, title, step, auto, session, updatedAt}, whole-state validation (invalid existing fields dropped), session from CLAUDE_CODE_SESSION_ID, never blocks the caller (7bc5850, df51aa2).
    • .trailhead/work-state.json gitignored (826242d).
    • Skill prose: canonical Work state file paragraph in _shared/teamwork.md; calls at work-start (after workspace setup, --map none for whiteboard), at each step per the mapping in ticket-engines.md (UAT follow-ups -> verify, research excluded), on pause/resume, during auto (--auto true, --auto false at run end), and clear at Resolve with session-ticket (b3274ee, 4ddb6ab).
    • Codex: helper rides templates/ and the prose is projected; pinned by tests (f03782c).

    Verification and findings ledger: see the VERIFY comment above (all findings fixed).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

trailhead:buildtype: construct — discuss/plan/execute/verifytrailhead:map-198Tickets of map #198 (trailhead mod)trailhead:ticketa trailhead ticket

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions