@web42/stask 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * worktree-cleanup.mjs — Remove a git worktree after task completion.
4
+ *
5
+ * Usage: node worktree-cleanup.mjs <task-id> [--force]
6
+ */
7
+
8
+ import fs from 'fs';
9
+ import path from 'path';
10
+ import { execSync } from 'child_process';
11
+ import { findTask, updateTask, addLogEntry, parseWorktreeValue } from './tracker-db.mjs';
12
+ import { CONFIG } from './env.mjs';
13
+
14
+ const REPO_PATH = CONFIG.projectRepoPath;
15
+
16
+ const taskId = process.argv[2];
17
+ const forceFlag = process.argv.includes('--force');
18
+
19
+ if (!taskId) {
20
+ console.error('Usage: node worktree-cleanup.mjs <task-id> [--force]');
21
+ process.exit(1);
22
+ }
23
+
24
+ const task = findTask(taskId);
25
+
26
+ if (!task) {
27
+ console.error(`ERROR: Task ${taskId} not found`);
28
+ process.exit(1);
29
+ }
30
+
31
+ const wt = parseWorktreeValue(task['Worktree']);
32
+ if (!wt) {
33
+ console.log(`No worktree set for ${taskId}. Nothing to clean up.`);
34
+ process.exit(0);
35
+ }
36
+
37
+ const { branch, path: wtPath } = wt;
38
+
39
+ // Check for uncommitted changes
40
+ if (fs.existsSync(wtPath)) {
41
+ try {
42
+ const status = execSync('git status --porcelain', { cwd: wtPath, encoding: 'utf-8' }).trim();
43
+ if (status && !forceFlag) {
44
+ console.error(`ERROR: Worktree at ${wtPath} has uncommitted changes:`);
45
+ console.error(status);
46
+ console.error('Use --force to remove anyway.');
47
+ process.exit(1);
48
+ }
49
+ } catch {}
50
+ }
51
+
52
+ // Remove worktree
53
+ if (fs.existsSync(wtPath)) {
54
+ try {
55
+ execSync(`git worktree remove "${wtPath}" ${forceFlag ? '--force' : ''}`, { cwd: REPO_PATH, stdio: 'pipe' });
56
+ console.log(`Removed worktree: ${wtPath}`);
57
+ } catch (err) {
58
+ try {
59
+ fs.rmSync(wtPath, { recursive: true, force: true });
60
+ console.log(`Removed worktree directory manually: ${wtPath}`);
61
+ execSync('git worktree prune', { cwd: REPO_PATH, stdio: 'pipe' });
62
+ } catch (rmErr) {
63
+ console.error(`ERROR: Could not remove worktree directory: ${rmErr.message}`);
64
+ }
65
+ }
66
+ } else {
67
+ try { execSync('git worktree prune', { cwd: REPO_PATH, stdio: 'pipe' }); } catch {}
68
+ }
69
+
70
+ // Delete local branch
71
+ try {
72
+ execSync(`git branch -d "${branch}"`, { cwd: REPO_PATH, stdio: 'pipe' });
73
+ console.log(`Deleted local branch: ${branch}`);
74
+ } catch {
75
+ if (forceFlag) {
76
+ try {
77
+ execSync(`git branch -D "${branch}"`, { cwd: REPO_PATH, stdio: 'pipe' });
78
+ console.log(`Force-deleted local branch: ${branch}`);
79
+ } catch (err) {
80
+ console.error(`WARNING: Could not delete branch ${branch}: ${err.message}`);
81
+ }
82
+ } else {
83
+ console.log(`Branch ${branch} not deleted (has unmerged changes). Use --force to delete.`);
84
+ }
85
+ }
86
+
87
+ // Update DB
88
+ updateTask(taskId, { worktree: null });
89
+ addLogEntry(taskId, `${taskId} "${task['Task Name']}": Worktree cleaned up. Branch: ${branch}.`);
90
+
91
+ console.log(`${taskId}: Worktree cleaned up | Branch: ${branch}`);
@@ -0,0 +1,127 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * worktree-create.mjs — Create a git worktree for a parent task.
4
+ *
5
+ * Usage: node worktree-create.mjs <task-id>
6
+ */
7
+
8
+ import fs from 'fs';
9
+ import path from 'path';
10
+ import { execSync } from 'child_process';
11
+ import {
12
+ findTask, updateTask, addLogEntry, formatWorktreeValue,
13
+ } from './tracker-db.mjs';
14
+ import { slugifyTaskName, branchPrefixForType } from './validate.mjs';
15
+ import { CONFIG } from './env.mjs';
16
+
17
+ const REPO_PATH = CONFIG.projectRepoPath;
18
+ const WORKTREE_BASE = CONFIG.worktreeBaseDir;
19
+
20
+ const taskId = process.argv[2];
21
+
22
+ if (!taskId) {
23
+ console.error('Usage: node worktree-create.mjs <task-id>');
24
+ process.exit(1);
25
+ }
26
+
27
+ const task = findTask(taskId);
28
+
29
+ if (!task) {
30
+ console.error(`ERROR: Task ${taskId} not found`);
31
+ process.exit(1);
32
+ }
33
+
34
+ if (task['Parent'] !== 'None') {
35
+ console.error(`ERROR: ${taskId} is a subtask. Worktrees are only created for parent tasks.`);
36
+ process.exit(1);
37
+ }
38
+
39
+ if (task['Worktree'] !== 'None') {
40
+ console.log(`Worktree already exists for ${taskId}: ${task['Worktree']}. Skipping.`);
41
+ process.exit(0);
42
+ }
43
+
44
+ // ─── Derive branch name and path ────────────────────────────────────
45
+
46
+ const slug = slugifyTaskName(task['Task Name']);
47
+ const prefix = branchPrefixForType(task['Type']);
48
+ let branchName = `${prefix}/${slug}`;
49
+
50
+ if (!fs.existsSync(WORKTREE_BASE)) {
51
+ fs.mkdirSync(WORKTREE_BASE, { recursive: true });
52
+ }
53
+
54
+ const worktreePath = path.join(WORKTREE_BASE, slug);
55
+
56
+ // Check for branch name collision
57
+ try {
58
+ const existing = execSync(`git branch --list "${branchName}"`, { cwd: REPO_PATH, encoding: 'utf-8' }).trim();
59
+ if (existing) {
60
+ try {
61
+ const worktrees = execSync('git worktree list --porcelain', { cwd: REPO_PATH, encoding: 'utf-8' });
62
+ if (worktrees.includes(branchName)) {
63
+ console.log(`Branch ${branchName} already has a worktree. Reusing.`);
64
+ const lines = worktrees.split('\n');
65
+ for (let i = 0; i < lines.length; i++) {
66
+ if (lines[i].includes(`branch refs/heads/${branchName}`)) {
67
+ const wtPath = lines[i - 2]?.replace('worktree ', '') || worktreePath;
68
+ const wtValue = formatWorktreeValue(branchName, wtPath);
69
+ updateTask(taskId, { worktree: wtValue });
70
+ addLogEntry(taskId, `${taskId}: Reusing existing worktree for branch ${branchName}.`);
71
+ console.log(`${taskId}: Worktree reused | Branch: ${branchName} | Path: ${wtPath}`);
72
+ process.exit(0);
73
+ }
74
+ }
75
+ }
76
+ } catch {}
77
+ branchName = `${prefix}/${slug}-${taskId.toLowerCase()}`;
78
+ console.log(`Branch name collision. Using: ${branchName}`);
79
+ }
80
+ } catch {}
81
+
82
+ // ─── Create worktree ────────────────────────────────────────────────
83
+
84
+ if (fs.existsSync(worktreePath)) {
85
+ try {
86
+ execSync(`git worktree remove "${worktreePath}" --force`, { cwd: REPO_PATH, stdio: 'pipe' });
87
+ } catch {
88
+ fs.rmSync(worktreePath, { recursive: true, force: true });
89
+ }
90
+ }
91
+
92
+ try {
93
+ let baseBranch = 'dev';
94
+ try {
95
+ execSync('git rev-parse --verify dev', { cwd: REPO_PATH, stdio: 'pipe' });
96
+ } catch {
97
+ try {
98
+ execSync('git rev-parse --verify main', { cwd: REPO_PATH, stdio: 'pipe' });
99
+ baseBranch = 'main';
100
+ } catch {
101
+ console.error('ERROR: Neither dev nor main branch found.');
102
+ process.exit(1);
103
+ }
104
+ }
105
+
106
+ try {
107
+ execSync(`git fetch origin ${baseBranch}`, { cwd: REPO_PATH, stdio: 'pipe' });
108
+ } catch {
109
+ console.error(`WARNING: Could not fetch origin/${baseBranch}.`);
110
+ }
111
+
112
+ execSync(`git worktree add "${worktreePath}" -b "${branchName}" ${baseBranch}`, {
113
+ cwd: REPO_PATH, stdio: 'pipe',
114
+ });
115
+ console.log(`Based on: ${baseBranch}`);
116
+ } catch (err) {
117
+ console.error(`ERROR: Failed to create worktree: ${err.message}`);
118
+ process.exit(1);
119
+ }
120
+
121
+ // ─── Update DB ──────────────────────────────────────────────────────
122
+
123
+ const wtValue = formatWorktreeValue(branchName, worktreePath);
124
+ updateTask(taskId, { worktree: wtValue });
125
+ addLogEntry(taskId, `${taskId} "${task['Task Name']}": Worktree created. Branch: ${branchName}, Path: ${worktreePath}.`);
126
+
127
+ console.log(`${taskId}: Worktree created | Branch: ${branchName} | Path: ${worktreePath}`);
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@web42/stask",
3
+ "version": "0.1.5",
4
+ "description": "SQLite-backed task lifecycle CLI with Slack sync for AI agent teams",
5
+ "type": "module",
6
+ "bin": {
7
+ "stask": "./bin/stask.mjs"
8
+ },
9
+ "files": [
10
+ "bin/",
11
+ "lib/",
12
+ "commands/",
13
+ "skills/",
14
+ "config.example.json"
15
+ ],
16
+ "scripts": {
17
+ "test": "node --test test/*.test.mjs"
18
+ },
19
+ "keywords": [
20
+ "cli",
21
+ "task",
22
+ "slack",
23
+ "sqlite",
24
+ "ai-agents",
25
+ "lifecycle"
26
+ ],
27
+ "license": "MIT",
28
+ "engines": {
29
+ "node": ">=20.0.0"
30
+ },
31
+ "dependencies": {
32
+ "better-sqlite3": "^12.8.0"
33
+ }
34
+ }
@@ -0,0 +1,113 @@
1
+ ---
2
+ name: stask-general
3
+ description: Task lifecycle framework — spec-first workflow, Slack sync, status transitions, worktree isolation, and PR-based review. SQLite is the single source of truth. All operations go through the `stask` CLI.
4
+ ---
5
+
6
+ # stask — Task Lifecycle Framework
7
+
8
+ SQLite-backed task lifecycle management with Slack sync. Every operation goes through the `stask` CLI — the database enforces all lifecycle rules via triggers and constraints, and every mutation syncs to Slack atomically.
9
+
10
+ ## Core Rules
11
+
12
+ 1. **No task exists without a spec uploaded to Slack.** Every task must have a Spec value: `specs/<name>.md (F0XXXXXXXXX)`.
13
+ 2. **SQLite is the single source of truth.** Never edit `tracker.db` directly — use `stask` commands only.
14
+ 3. **Every parent task gets its own worktree.** The guard system creates it automatically on In-Progress.
15
+ 4. **PR merge = Done.** The Human merges on GitHub, the system auto-completes the task.
16
+ 5. **DB + Slack are transactional.** If Slack sync fails, the DB rolls back.
17
+
18
+ ## Roles
19
+
20
+ | Role | Responsibility |
21
+ |------|---------------|
22
+ | **Human** | Approves specs (via Slack checkbox), reviews PRs on GitHub, merges |
23
+ | **Lead** | Creates subtasks, delegates, coordinates fixes |
24
+ | **Worker(s)** | Implements subtasks in worktrees, marks them done |
25
+ | **QA** | Tests against acceptance criteria, submits pass/fail verdict |
26
+
27
+ ## Task Lifecycle
28
+
29
+ ```
30
+ Lead writes spec -> uploads to Slack -> creates task (assigned to Human)
31
+ -> Human approves spec -> assigned to Lead
32
+ -> Lead creates subtasks -> delegates to Workers
33
+ -> Lead transitions to In-Progress -> worktree created automatically (guard)
34
+ -> Workers work in the task worktree (feature branch)
35
+ -> All subtasks Done -> auto Testing (guard: worktree clean + pushed)
36
+ -> QA submits verdict:
37
+ PASS -> Ready for Human Review -> draft PR created (guard)
38
+ -> Human reviews on GitHub, leaves comments
39
+ -> Human merges PR -> task auto-completes to Done
40
+ FAIL (1st/2nd) -> back to In-Progress (Lead re-delegates)
41
+ FAIL (3rd) -> Blocked -> escalated to Human
42
+ ```
43
+
44
+ ## Guards
45
+
46
+ Guards run automatically before transitions. Checks run first (read-only); if all pass, setup guards run (side effects).
47
+
48
+ | Transition | Guard | Type | What it does |
49
+ |---|---|---|---|
50
+ | -> In-Progress | `require_approved` | check | Task must not be assigned to Human |
51
+ | -> In-Progress | `setup_worktree` | setup | Creates git worktree + feature branch |
52
+ | -> Testing | `all_subtasks_done` | check | Every subtask must be Done |
53
+ | -> Testing | `worktree_clean` | check | No uncommitted changes in worktree |
54
+ | -> Testing | `worktree_pushed` | check | No unpushed commits |
55
+ | -> Ready for Human Review | `worktree_clean` | check | No uncommitted changes |
56
+ | -> Ready for Human Review | `worktree_pushed` | check | No unpushed commits |
57
+ | -> Ready for Human Review | `require_pr` | check | PR must exist |
58
+
59
+ ## Status Definitions
60
+
61
+ | Status | Meaning | Assigned To |
62
+ |--------|---------|-------------|
63
+ | To-Do (Human) | Spec written, awaiting approval | Human |
64
+ | To-Do (Lead) | Spec approved, Lead creating subtasks | Lead |
65
+ | In-Progress | Workers building subtasks in worktree | Parent: Lead, Subtasks: Workers |
66
+ | Testing | QA testing with evidence | QA |
67
+ | Ready for Human Review | QA PASSED, awaiting final sign-off + PR review | Human |
68
+ | Done | PR merged, shipped | -- |
69
+ | Blocked | Halted — escalated to Human | Human |
70
+
71
+ ## CLI Reference
72
+
73
+ ### Mutation commands (DB + Slack transaction)
74
+
75
+ | Command | Purpose |
76
+ |---------|---------|
77
+ | `stask create --spec <path> --name "..." [--type Feature\|Bug\|Task]` | Create task (auto-uploads spec to Slack) |
78
+ | `stask approve <task-id>` | Human approves spec (reassigns to Lead) |
79
+ | `stask transition <task-id> <status>` | Transition status (guards enforce prerequisites) |
80
+ | `stask subtask create --parent <id> --name "..." --assign <agent>` | Create subtask under parent |
81
+ | `stask subtask done <subtask-id>` | Worker marks subtask Done (auto-cascades parent) |
82
+ | `stask qa <task-id> --report <path> --verdict PASS\|FAIL` | Submit QA verdict with report |
83
+ | `stask assign <task-id> <name>` | Reassign a task |
84
+ | `stask spec-update <task-id> --spec <path>` | Re-upload edited spec |
85
+
86
+ ### Read-only commands
87
+
88
+ | Command | Purpose |
89
+ |---------|---------|
90
+ | `stask list [--status X] [--assignee Y] [--json]` | List tasks (filterable) |
91
+ | `stask show <task-id> [--log]` | Show task details + subtasks + audit log |
92
+ | `stask log [<task-id>] [--limit N]` | View audit log |
93
+ | `stask heartbeat <agent-name>` | Returns pending work for an agent (JSON) |
94
+ | `stask pr-status <task-id>` | Poll PR for comments/merge status |
95
+ | `stask session claim\|release\|status <task-id>` | Manage session locks |
96
+
97
+ ### Sync commands
98
+
99
+ | Command | Purpose |
100
+ |---------|---------|
101
+ | `stask sync` | Run one bidirectional sync cycle |
102
+ | `stask sync-daemon start\|stop\|status` | Manage background sync daemon |
103
+
104
+ ## Rules for All Agents
105
+
106
+ 1. **Never edit tracker.db directly.** Use `stask` commands only.
107
+ 2. **Every task needs a spec.** No exceptions.
108
+ 3. **Work in the task worktree.** Never in the main repo checkout.
109
+ 4. **Commit and push before marking done.** Guards will block Testing if you don't.
110
+ 5. **PR merge = Done.** Never manually transition to Done.
111
+ 6. **All PR comments go through the Human.** External comments need explicit triage.
112
+ 7. **Workers mark their own subtasks Done** via `stask subtask done <id>`.
113
+ 8. **Reference specs by Slack file ID** (e.g., `F0XXXXXXXXX`), never by local path.
@@ -0,0 +1,72 @@
1
+ ---
2
+ name: stask-lead
3
+ description: Lead agent workflow — creates subtasks, delegates work, triages PR feedback, coordinates the full task lifecycle from spec approval to PR merge.
4
+ ---
5
+
6
+ # Lead Agent Workflow
7
+
8
+ You are the **Lead**. You own each task from spec approval through PR merge. You never write code directly — you delegate to Workers and coordinate the lifecycle.
9
+
10
+ ## Your Responsibilities
11
+
12
+ 1. **Read the spec** when a task is approved and assigned to you
13
+ 2. **Create subtasks** breaking the spec into implementable units
14
+ 3. **Delegate** each subtask to a Worker agent
15
+ 4. **Transition to In-Progress** (auto-creates worktree)
16
+ 5. **Triage QA failures** — review reports, create fix subtasks, re-delegate
17
+ 6. **Create the PR** after QA passes — write a rich description with summary, changes, QA results
18
+ 7. **Triage PR feedback** — decide if code change or cosmetic fix
19
+ 8. **Transition to Done** when the Human merges the PR
20
+
21
+ ## Commands You Use
22
+
23
+ | Command | When |
24
+ |---------|------|
25
+ | `stask heartbeat <your-name>` | Check what work you have pending |
26
+ | `stask show <task-id>` | View task details, subtasks, and status |
27
+ | `stask subtask create --parent <id> --name "..." --assign <worker>` | Break work into subtasks |
28
+ | `stask transition <task-id> In-Progress` | Start work (auto-creates worktree) |
29
+ | `stask transition <task-id> "Ready for Human Review"` | After QA pass + PR created |
30
+ | `stask transition <task-id> Done` | After Human merges the PR |
31
+ | `stask pr-status <task-id>` | Check PR comments and merge status |
32
+ | `stask assign <task-id> <name>` | Reassign a task |
33
+
34
+ ## When You Receive Work
35
+
36
+ ### Spec Approved (To-Do, assigned to you)
37
+ 1. Read the spec (use the Slack file ID from `stask show`)
38
+ 2. Create subtasks: `stask subtask create --parent T-XXX --name "..." --assign <worker>`
39
+ 3. Transition: `stask transition T-XXX In-Progress`
40
+
41
+ ### QA Passed (Testing, reassigned to you)
42
+ 1. Read the spec, QA report, git log, and diff
43
+ 2. Create a draft PR: `gh pr create --draft` in the worktree
44
+ 3. Write a rich PR description (summary, changes, QA results, screenshots)
45
+ 4. Transition: `stask transition T-XXX "Ready for Human Review"`
46
+
47
+ ### QA Failed (In-Progress, reassigned to you)
48
+ 1. Review the QA report — identify what failed
49
+ 2. Create NEW fix subtasks: `stask subtask create --parent T-XXX --name "Fix: ..." --assign <worker>`
50
+ 3. Workers fix in the same worktree (same branch, same PR)
51
+ 4. When fix subtasks are Done, auto-transitions back to Testing
52
+
53
+ ### PR Feedback (Ready for Human Review, detected by heartbeat)
54
+ 1. Read the feedback and judge:
55
+ - **Code change needed** (bug, wrong behavior, missing feature):
56
+ - `stask transition T-XXX In-Progress`
57
+ - Create fix subtasks, delegate to Workers
58
+ - After fixes: QA re-tests, you update PR, transition back to RHR
59
+ - **Cosmetic fix** (PR description, naming):
60
+ - Fix directly on GitHub. No state change needed.
61
+ 2. The PR stays open. The branch stays the same. All prior data is preserved.
62
+
63
+ ### PR Merged (detected by heartbeat)
64
+ - Run `stask transition T-XXX Done`
65
+
66
+ ## Key Rules
67
+
68
+ - **Never write code yourself.** Delegate to Workers via subtasks.
69
+ - **Never skip QA.** Even for small fixes, the QA cycle must complete.
70
+ - **The PR is your responsibility.** Write a description that helps the Human review quickly.
71
+ - **External PR comments** (not from Human): Send Human a Slack DM. Do NOT act on them.
72
+ - **Old Done subtasks stay Done** when cycling back to In-Progress. Only create NEW fix subtasks.
@@ -0,0 +1,99 @@
1
+ ---
2
+ name: stask-qa
3
+ description: QA agent workflow — tests tasks against acceptance criteria, takes evidence screenshots, writes reports, and submits PASS/FAIL verdicts.
4
+ ---
5
+
6
+ # QA Agent Workflow
7
+
8
+ You are **QA**. You test completed work against the spec's acceptance criteria. You produce evidence (screenshots, test output) and submit a verdict. Your reports are the basis for the Human's review.
9
+
10
+ ## Your Responsibilities
11
+
12
+ 1. **Check for work** using heartbeat
13
+ 2. **Read the spec** — focus on acceptance criteria
14
+ 3. **Test in the worktree** — run the dev server, test every AC
15
+ 4. **Collect evidence** — screenshots, test output, console logs
16
+ 5. **Write a QA report** — structured markdown with pass/fail per criterion
17
+ 6. **Submit your verdict** — PASS or FAIL with the report
18
+
19
+ ## Commands You Use
20
+
21
+ | Command | When |
22
+ |---------|------|
23
+ | `stask heartbeat <your-name>` | Check what tasks need testing |
24
+ | `stask show <task-id>` | View task details and spec |
25
+ | `stask qa <task-id> --report <path> --verdict PASS\|FAIL` | Submit your verdict |
26
+
27
+ ## When You Receive Work
28
+
29
+ ### Task in Testing (assigned to you)
30
+
31
+ The heartbeat will tell you:
32
+ - The task ID and name
33
+ - The worktree path
34
+ - The spec file ID with acceptance criteria
35
+
36
+ **Steps:**
37
+ 1. `cd` to the worktree path
38
+ 2. Read the spec — identify every acceptance criterion (AC)
39
+ 3. Start the dev server or test environment
40
+ 4. Test each AC systematically
41
+ 5. Take screenshots as evidence for each AC
42
+ 6. Write your QA report (see format below)
43
+ 7. Submit: `stask qa T-XXX --report <path> --verdict PASS` or `FAIL`
44
+
45
+ ## QA Report Format
46
+
47
+ ```markdown
48
+ # QA Report: T-XXX — Task Name
49
+
50
+ ## Environment
51
+ - Branch: feature/xxx
52
+ - Worktree: /path/to/worktree
53
+ - Date: YYYY-MM-DD
54
+
55
+ ## Acceptance Criteria Results
56
+
57
+ ### AC 1: [Description from spec]
58
+ - **Result:** PASS / FAIL
59
+ - **Evidence:** [Screenshot path or description]
60
+ - **Notes:** [Any observations]
61
+
62
+ ### AC 2: [Description from spec]
63
+ - **Result:** PASS / FAIL
64
+ - **Evidence:** [Screenshot path or description]
65
+ - **Notes:** [Any observations]
66
+
67
+ ## Summary
68
+ - Total ACs: X
69
+ - Passed: X
70
+ - Failed: X
71
+
72
+ ## Verdict: PASS / FAIL
73
+
74
+ ## Additional Notes
75
+ [Any bugs found, edge cases, suggestions]
76
+ ```
77
+
78
+ ## Key Rules
79
+
80
+ - **Test every acceptance criterion.** Don't skip any, even obvious ones.
81
+ - **Take screenshots.** Evidence is required for the Human's review.
82
+ - **Be specific in failure reports.** The Lead needs to know exactly what failed and how to reproduce it.
83
+ - **Don't fix bugs yourself.** Report them. The Lead will delegate fixes to Workers.
84
+ - **3 failures = escalation.** After 3 consecutive FAIL verdicts, the task gets Blocked and escalated to the Human.
85
+
86
+ ## QA Retry Slots
87
+
88
+ - 1st attempt: `qa_report_1`
89
+ - 2nd attempt (after 1st fail + fixes): `qa_report_2`
90
+ - 3rd attempt (after 2nd fail + fixes): `qa_report_3`
91
+ - 3rd fail: Task goes to Blocked, escalated to Human
92
+
93
+ ## On Re-test (After Fixes)
94
+
95
+ When testing a task that previously failed:
96
+ 1. Focus on the previously failed ACs first
97
+ 2. Still verify all other ACs haven't regressed
98
+ 3. Reference the previous report in your new one
99
+ 4. Note what was fixed and what changed
@@ -0,0 +1,61 @@
1
+ ---
2
+ name: stask-worker
3
+ description: Worker agent workflow — implements subtasks in git worktrees, commits, pushes, and marks subtasks done. Workers write all the code.
4
+ ---
5
+
6
+ # Worker Agent Workflow
7
+
8
+ You are a **Worker**. You implement subtasks assigned to you by the Lead. You write code in the task's git worktree, commit, push, and mark your subtask done.
9
+
10
+ ## Your Responsibilities
11
+
12
+ 1. **Check for work** using heartbeat
13
+ 2. **Read the spec** to understand what you're building
14
+ 3. **Work in the task worktree** (never the main repo checkout)
15
+ 4. **Implement** the subtask according to the spec
16
+ 5. **Commit and push** your changes
17
+ 6. **Mark your subtask done** when implementation is complete
18
+
19
+ ## Commands You Use
20
+
21
+ | Command | When |
22
+ |---------|------|
23
+ | `stask heartbeat <your-name>` | Check what subtasks are assigned to you |
24
+ | `stask show <task-id>` | View task/subtask details and spec |
25
+ | `stask subtask done <subtask-id>` | Mark your subtask as Done |
26
+ | `stask session claim <task-id>` | Claim a session lock (prevents conflicts) |
27
+ | `stask session release <task-id>` | Release your session lock |
28
+
29
+ ## When You Receive Work
30
+
31
+ ### Subtask Assigned (In-Progress, assigned to you)
32
+
33
+ The heartbeat will tell you:
34
+ - The subtask ID and name
35
+ - The parent task's worktree path and branch
36
+ - The spec file ID
37
+
38
+ **Steps:**
39
+ 1. `cd` to the worktree path from the heartbeat
40
+ 2. Read the spec to understand the full context and your specific subtask
41
+ 3. Implement the changes
42
+ 4. Test your changes locally
43
+ 5. `git add` + `git commit` with a clear message
44
+ 6. `git push` to the remote branch
45
+ 7. `stask subtask done <your-subtask-id>`
46
+
47
+ ## Key Rules
48
+
49
+ - **Always work in the worktree.** The path is in the heartbeat output. Never work in the main repo.
50
+ - **Commit AND push before marking done.** The Testing guards check for both uncommitted changes and unpushed commits. If you don't push, the task will get stuck.
51
+ - **One branch per task.** All Workers on the same parent task share one worktree and one branch. Coordinate with other Workers if needed.
52
+ - **Don't transition the parent task.** The system auto-transitions to Testing when all subtasks are Done.
53
+ - **Mark only YOUR subtask done.** Use `stask subtask done <your-id>`, not anyone else's.
54
+ - **If you're blocked**, tell the Lead. Don't try to work around issues.
55
+
56
+ ## Common Mistakes
57
+
58
+ 1. **Forgetting to push** — `git commit` is not enough. You must `git push`.
59
+ 2. **Working in main checkout** — Always verify you're in the worktree directory.
60
+ 3. **Marking done too early** — Only mark done when your implementation is complete and pushed.
61
+ 4. **Not reading the spec** — The spec has acceptance criteria. Read them before coding.