ntcoding/lightweight-task-workflow
FOLLOW THE STATE MACHINE IN SKILL.MD. When user says 'continue': (1) FIRST: Run pwd, (2) Announce STATE: CHECK_STATUS, (3) Read .claude/session.md to check Status field, (4) Route based on Status. NEVER auto-advance tasks. NEVER use TodoWrite. NEVER create git commits.
npx skills add https://github.com/NTCoding/claude-skillz --skill lightweight-task-workflow
🚨 CRITICAL: YOU MUST FOLLOW THE STATE MACHINE BELOW 🚨
🚨 EVERY SINGLE MESSAGE MUST START WITH: 🔵 STATE: [STATE_NAME] 🚨
NOT JUST THE FIRST MESSAGE. EVERY. SINGLE. MESSAGE.
When you read a file - prefix with state.
When you run a command - prefix with state.
When you explain something - prefix with state.
When you ask a question - prefix with state.
Example:
🔵 STATE: WORKING
Reading requirements.md...
🔵 STATE: WORKING
I can see the requirements specify...
🔵 STATE: WORKING
Now running tests...
🔵 STATE: WORKING
Test results show...
This skill is a persistent todo list based on 3 files in .claude/: tasks.md (checklist), requirements.md (specs), session.md (current state).
When user says "continue", you MUST:
pwd to check current working directory🔵 STATE: CHECK_STATUS.claude/session.md from the current project directorySTATE MACHINE:
user: "continue"
↓
┌────────────────┐
┌───│ CHECK_STATUS │←──────────┬──────────┐
│ │ Read session.md│ │ │
│ └────────┬───────┘ │ │
│ │ │ │
Status= │ │ Status= │ │
"Complete" │ │ "in progress" │ │
│ │ │ │
↓ ↓ │ │
┌───────────┐ ┌──────────────┐ │ │
│ AWAITING_ │ │ WORKING │←────┐ │ │
│ COMMIT │ │ │ │ │ │
│ │ │ Read: │ │ │ │
│ Ask │ │ requirements │ │ │ │
│ permission│ │ tasks.md │ │ │ │
│ STOP │ │ │ │ │ │
└─────┬─────┘ │ Write: │ │ │ │
│ │ session.md │ │ │ │
user: yes │ └──────┬───────┘ │ │ │
│ │ │ │ │
│ │ task done │ │ │
│ │ │ │ │
│ ↓ │ │ │
│ ┌──────────────┐ │ │ │
│ │ VERIFY │ │ │ │
│ │ │ │ │ │
│ │ Run steps │ │ │ │
│ │ from │─────┘ │ │
│ │ requirements │ fail │ │
│ └──────┬───────┘ │ │
│ │ │ │
│ │ pass │ │
│ │ │ │
│ ↓ │ │
│ ┌──────────────┐ │ │
│ │ COMPLETE │ │ │
│ │ │ │ │
│ │ Write: │ │ │
│ │ session.md │ │ │
│ │ Status= │─────────┘ │
│ │ "Complete" │ │
│ └──────────────┘ │
│ │
↓ │
┌──────────────────┐ │
│ MARK_TASK_ │ │
│ COMPLETE │ │
│ │ │
│ Write: tasks [x] │ │
│ Write: session.md│──────────────────────────────┘
│ (next task) │
└──────────────────┘
🚨 STATE DEFINITIONS - FOLLOW EXACTLY 🚨
CHECK_STATUS:
ACTIONS:
1. Run pwd
2. Read .claude/session.md
3. Look at Status field
4. IF Status="Complete" OR "ready to commit" → Go to AWAITING_COMMIT
5. IF Status="in progress" OR missing → Go to WORKING
DO NOT: Read other files, launch agents, do anything except route
IF ERROR: STOP and tell user what failed
AWAITING_COMMIT:
ACTIONS:
1. Say: "Task X is complete. May I mark Task X as complete in tasks.md?"
2. STOP - wait for user response
3. IF user says yes → Go to MARK_TASK_COMPLETE
4. IF user says no → STOP, await further instruction
DO NOT: Read files, launch agents, work on next task, do anything except ask permission and STOP
IF ERROR: STOP and tell user what failed
MARK_TASK_COMPLETE:
ACTIONS:
1. Write tasks.md: Change [ ] to [x] for current task
2. Write session.md: Update to next task with Status="in progress"
3. Go to CHECK_STATUS
DO NOT: Read other files, launch agents, research next task
IF ERROR (e.g., plan mode, can't write): Say "I cannot edit files: [reason]" and STOP
NEVER try alternative actions if write fails
WORKING:
REMINDER: EVERY message in this state must start with: 🔵 STATE: WORKING
ACTIONS:
1. Read requirements.md
2. Read tasks.md
3. Work on current task
4. Update session.md after TDD cycles
5. When task done → Go to VERIFY
EVERY message you send while WORKING must have the state prefix.
When you read a file → prefix with state
When you run tests → prefix with state
When you explain results → prefix with state
DO NOT: Skip to next task, work on multiple tasks
IF ERROR: Document in session.md as blocker, STOP
VERIFY:
REMINDER: EVERY message in this state must start with: 🔵 STATE: VERIFY
ACTIONS:
1. Read Verification section from requirements.md
2. Run all verification commands
3. IF all pass → Go to COMPLETE
4. IF any fail → Go to WORKING (treat as blocker)
EVERY message you send while VERIFYING must have the state prefix.
DO NOT: Skip verification, claim complete without running checks
IF ERROR running verification: STOP and tell user
COMPLETE:
ACTIONS:
1. Write session.md: Set Status="Complete"
2. Go to CHECK_STATUS
DO NOT: Read files, launch agents, ask permission (that happens in AWAITING_COMMIT)
IF ERROR writing: STOP and tell user
CRITICAL: State Announcements
ALL messages MUST be prefixed with your current state.
Format:
**🔵 STATE: [STATE_NAME]**
[Your message here]
When transitioning:
**🟢 TRANSITION: [STATE_A] → [STATE_B]**
Example:
**🔵 STATE: CHECK_STATUS**
Reading session.md to check current task status...
**🟢 TRANSITION: CHECK_STATUS → AWAITING_COMMIT**
**🔵 STATE: AWAITING_COMMIT**
Task 2 is complete and ready for you to commit. May I mark Task 2 as complete in tasks.md?
Activate when the user:
THIS SKILL REPLACES Claude Code's built-in TodoWrite functionality.
NEVER use the following tools:
ALWAYS use this skill's files instead:
.claude/tasks.md for task checklists.claude/requirements.md for plans and implementation specs.claude/session.md for session context and recoveryWhy this matters: Using TodoWrite creates workflow conflicts. The built-in todo system stores tasks in internal state (not visible as files), causing the plan to be lost in chat history instead of persisted in .claude/requirements.md. This prevents session continuity and defeats the purpose of this skill.
If you find yourself wanting to use TodoWrite, STOP and use this skill's files instead.
IMPORTANT PATH GUIDANCE:
~/.claude/skills/lightweight-task-workflow/<project-root>/, task files go in <project-root>/.claude/./.claude/tasks.md, ./.claude/requirements.md, ./.claude/session.md~/.claude/skills/lightweight-task-workflow/tasks.md (that's the skill directory, not the project directory).claude/tasks.md - the task checklist (in the PROJECT directory)
- [ ] Task 1: Extract UserService
- [x] Task 2: Add tests
.claude/requirements.md - implementation specs and guidelines
## Global Guidelines
- Preserve existing API contracts - no breaking changes
- Add logging for error cases
- Follow repository's existing code style
## Verification & Definition of Done
Before marking any task complete, the following must pass:
- `npm test` - all tests must pass
- `npm run lint` - no lint errors
- `npm run build` - build must succeed
## Task 1: Extract UserService
- Move all user-related methods from AppService to new UserService
- Keep existing method signatures for backward compatibility
- Update dependency injection in app.module.ts
## Task 2: Add tests
- Cover happy path and error cases
- Include edge cases for null/undefined inputs
- Mock external dependencies
.claude/session.md - session recovery context
**Current Task:** Task 3
**Status:** in progress
## What's Done
- Task 1: Extracted UserService (commit a1b2c3d)
- Task 2: Added tests (commit e4f5g6h)
## Next Steps
1. Finish Task 3: Update documentation
## Context
- Using yarn for builds
- Commands: ./verify.sh
FIRST: Remember you are NOT using TodoWrite. Use this skill's .claude/ files exclusively.
.claude/tasks.md with numbered checklist - format: - [ ] Task 1: [exact user wording], - [ ] Task 2: [exact user wording], etc..claude/requirements.md with:.claude/session.md initialized to Task 1 with Status="in progress"After setup: You enter the state machine at CHECK_STATUS with session.md showing Task 1 Status="in progress"
Start at CHECK_STATUS state: Read session.md and route based on Status field. Follow the state machine at the top of this file.
Include: Global guidelines, Verification & Definition of Done (user can edit anytime), per-task requirements, learnings/edge cases discovered.
NOT for: Progress notes, debugging notes, code changes (that's git).
Update at 4 triggers: (1) Start task, (2) End of TDD cycle (one line), (3) Hit blocker, (4) Complete task.
Include: Current task/status, completed tasks with commits, brief progress notes, blockers, next steps.
NOT for: Every change, file paths, verbose explanations.
User: "continue"
Claude: *Reads tasks.md*
Claude: "Let me investigate the codebase to understand what's already been done"
Claude: *Searches through 10+ files, runs git log, checks test files*
Claude: *Wastes 2 minutes and 5000 tokens figuring out current state*
Claude: "I can see Task 1 was completed, let me start on Task 2..."
Problem: Wasted time and tokens. All that information was already in session.md.
User: "continue"
Claude: *Runs pwd*
Claude: "🔵 STATE: CHECK_STATUS"
Claude: *Reads session.md FIRST*
Claude: "Status shows 'in progress'. Routing to WORKING."
Claude: "🟢 TRANSITION: CHECK_STATUS → WORKING"
Claude: "🔵 STATE: WORKING"
Claude: "Continuing Task 2: Add email validation..."
Result: Instant context, no wasted time, exactly where to resume. That's the whole point of session.md.
Claude: *Completes task implementation*
Claude: "Task 1 is complete and ready for you to commit"
Claude: "May I mark this task as complete?"
*User commits and deploys*
*Build breaks in CI - test failures, lint errors discovered*
Problem: Introduced regressions, broken build, wasted time debugging issues that should have been caught before claiming "complete."
Claude: *Completes task implementation*
Claude: *Reads requirements.md Verification section*
Claude: *Runs npm test* → All pass ✅
Claude: *Runs npm run lint* → All pass ✅
Claude: *Runs npm run build* → Success ✅
Claude: *Updates session.md: "Task 1 complete - all verification passed"*
Claude: "Task 1 is complete, all verification passed (tests/lint/build), ready for you to commit"
Result: Confidence that task is truly complete, no regressions introduced, ready for production.
Claude: *Completes task implementation*
Claude: *Runs git add .*
Claude: *Runs git commit -m "Add UTF-8 correction table"*
Claude: "I've committed the changes"
Problem: User loses control over commits - can't review changes, adjust commit message, or stage selectively.
Claude: *Completes task implementation*
Claude: *Updates .claude/session.md: "Task 1 complete - UTF-8 correction ready for commit"*
Claude: "Task 1 is complete and ready for you to commit. The changes include..."
Claude: "May I mark this task as complete in tasks.md?"
Result: User reviews changes, creates commit with their preferred message and staging, maintains full git control.
Claude: "Task 1 is complete, verification passed, ready for you to commit"
Claude: "May I mark this task as complete?"
Claude: "Let me explore the codebase to understand Task 2: Add email validation..."
Claude: *Launches Plan agent for Task 2*
Problem: User doesn't have time to review Task 1, commit changes, or decide when to proceed. Claude rushes ahead without permission.
Claude: "Task 1 is complete, verification passed, ready for you to commit"
Claude: "May I mark this task as complete in tasks.md?"
Claude: *Waits for user response*
User: *Reviews changes, creates commit*
User: "continue"
Claude: *Reads session.md, sees Status="Complete", routes to AWAITING_COMMIT*
Claude: "Task 1 is complete. May I mark it [x]?"
User: "yes"
Claude: *Updates tasks.md, updates session.md to Task 2 Status="in progress"*
User: "continue"
Claude: *Reads session.md, sees Task 2 Status="in progress", routes to WORKING*
Result: User controls the pace, reviews and commits when ready, decides when to proceed to next task.
Symptom: "Error reading file" when trying to continue tasks
Likely cause: You're looking in the skill directory instead of the project directory
Fix:
pwd to check current working directory.claude/ subdirectory in the project root./.claude/tasks.md, NOT ~/.claude/skills/lightweight-task-workflow/tasks.mdExample:
~/.claude/skills/lightweight-task-workflow/tasks.md (skill directory)./.claude/tasks.md or <project-root>/.claude/tasks.md (project directory)🔵 STATE: [STATE_NAME].claude/ directory, not skill directoryTake ntcoding/lightweight-task-workflow from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.