strikethroo 3.0.0

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.
Files changed (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +79 -0
  3. package/dist/cli.d.ts +9 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +187 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/conflict-detector.d.ts +24 -0
  8. package/dist/conflict-detector.d.ts.map +1 -0
  9. package/dist/conflict-detector.js +130 -0
  10. package/dist/conflict-detector.js.map +1 -0
  11. package/dist/index.d.ts +22 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +344 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/metadata.d.ts +40 -0
  16. package/dist/metadata.d.ts.map +1 -0
  17. package/dist/metadata.js +121 -0
  18. package/dist/metadata.js.map +1 -0
  19. package/dist/plan-utils.d.ts +35 -0
  20. package/dist/plan-utils.d.ts.map +1 -0
  21. package/dist/plan-utils.js +123 -0
  22. package/dist/plan-utils.js.map +1 -0
  23. package/dist/plan.d.ts +27 -0
  24. package/dist/plan.d.ts.map +1 -0
  25. package/dist/plan.js +279 -0
  26. package/dist/plan.js.map +1 -0
  27. package/dist/prompts.d.ts +21 -0
  28. package/dist/prompts.d.ts.map +1 -0
  29. package/dist/prompts.js +132 -0
  30. package/dist/prompts.js.map +1 -0
  31. package/dist/status.d.ts +73 -0
  32. package/dist/status.d.ts.map +1 -0
  33. package/dist/status.js +375 -0
  34. package/dist/status.js.map +1 -0
  35. package/dist/types.d.ts +274 -0
  36. package/dist/types.d.ts.map +1 -0
  37. package/dist/types.js +9 -0
  38. package/dist/types.js.map +1 -0
  39. package/dist/utils.d.ts +53 -0
  40. package/dist/utils.d.ts.map +1 -0
  41. package/dist/utils.js +158 -0
  42. package/dist/utils.js.map +1 -0
  43. package/package.json +94 -0
  44. package/templates/harness/agents/plan-creator.md +95 -0
  45. package/templates/harness/skills/st-create-plan/SKILL.md +120 -0
  46. package/templates/harness/skills/st-create-plan/scripts/find-strikethroo-root.cjs +116 -0
  47. package/templates/harness/skills/st-create-plan/scripts/get-next-plan-id.cjs +197 -0
  48. package/templates/harness/skills/st-execute-blueprint/SKILL.md +147 -0
  49. package/templates/harness/skills/st-execute-blueprint/scripts/create-feature-branch.cjs +359 -0
  50. package/templates/harness/skills/st-execute-blueprint/scripts/find-strikethroo-root.cjs +116 -0
  51. package/templates/harness/skills/st-execute-blueprint/scripts/validate-plan-blueprint.cjs +358 -0
  52. package/templates/harness/skills/st-execute-task/SKILL.md +195 -0
  53. package/templates/harness/skills/st-execute-task/scripts/check-task-dependencies.cjs +420 -0
  54. package/templates/harness/skills/st-execute-task/scripts/find-strikethroo-root.cjs +116 -0
  55. package/templates/harness/skills/st-execute-task/scripts/validate-plan-blueprint.cjs +358 -0
  56. package/templates/harness/skills/st-full-workflow/SKILL.md +413 -0
  57. package/templates/harness/skills/st-full-workflow/scripts/create-feature-branch.cjs +359 -0
  58. package/templates/harness/skills/st-full-workflow/scripts/find-strikethroo-root.cjs +116 -0
  59. package/templates/harness/skills/st-full-workflow/scripts/get-next-plan-id.cjs +197 -0
  60. package/templates/harness/skills/st-full-workflow/scripts/get-next-task-id.cjs +295 -0
  61. package/templates/harness/skills/st-full-workflow/scripts/validate-plan-blueprint.cjs +358 -0
  62. package/templates/harness/skills/st-generate-tasks/SKILL.md +244 -0
  63. package/templates/harness/skills/st-generate-tasks/scripts/find-strikethroo-root.cjs +116 -0
  64. package/templates/harness/skills/st-generate-tasks/scripts/get-next-task-id.cjs +295 -0
  65. package/templates/harness/skills/st-generate-tasks/scripts/validate-plan-blueprint.cjs +358 -0
  66. package/templates/harness/skills/st-refine-plan/SKILL.md +205 -0
  67. package/templates/harness/skills/st-refine-plan/scripts/find-strikethroo-root.cjs +116 -0
  68. package/templates/harness/skills/st-refine-plan/scripts/validate-plan-blueprint.cjs +358 -0
  69. package/templates/strikethroo/README.md +7 -0
  70. package/templates/strikethroo/config/STRIKETHROO.md +76 -0
  71. package/templates/strikethroo/config/hooks/POST_ERROR_DETECTION.md +46 -0
  72. package/templates/strikethroo/config/hooks/POST_EXECUTION.md +25 -0
  73. package/templates/strikethroo/config/hooks/POST_PHASE.md +24 -0
  74. package/templates/strikethroo/config/hooks/POST_PLAN.md +5 -0
  75. package/templates/strikethroo/config/hooks/POST_TASK_GENERATION_ALL.md +41 -0
  76. package/templates/strikethroo/config/hooks/PRE_PHASE.md +21 -0
  77. package/templates/strikethroo/config/hooks/PRE_PLAN.md +42 -0
  78. package/templates/strikethroo/config/hooks/PRE_TASK_ASSIGNMENT.md +32 -0
  79. package/templates/strikethroo/config/hooks/PRE_TASK_EXECUTION.md +1 -0
  80. package/templates/strikethroo/config/templates/BLUEPRINT_TEMPLATE.md +24 -0
  81. package/templates/strikethroo/config/templates/EXECUTION_SUMMARY_TEMPLATE.md +13 -0
  82. package/templates/strikethroo/config/templates/PLAN_TEMPLATE.md +109 -0
  83. package/templates/strikethroo/config/templates/TASK_TEMPLATE.md +36 -0
@@ -0,0 +1,358 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/skill-scripts/validate-plan-blueprint.ts
31
+ var validate_plan_blueprint_exports = {};
32
+ __export(validate_plan_blueprint_exports, {
33
+ main: () => main
34
+ });
35
+ module.exports = __toCommonJS(validate_plan_blueprint_exports);
36
+ var fs4 = __toESM(require("fs"));
37
+ var path4 = __toESM(require("path"));
38
+
39
+ // src/skill-scripts/shared/root.ts
40
+ var fs = __toESM(require("fs"));
41
+ var path = __toESM(require("path"));
42
+ var EXPECTED_SCHEMA = true ? 1 : 1;
43
+ var isValidStrikethrooRoot = (strikethrooPath) => {
44
+ try {
45
+ if (!fs.existsSync(strikethrooPath)) return false;
46
+ if (!fs.lstatSync(strikethrooPath).isDirectory()) return false;
47
+ const metadataPath = path.join(strikethrooPath, ".init-metadata.json");
48
+ if (!fs.existsSync(metadataPath)) return false;
49
+ const metadata = JSON.parse(fs.readFileSync(metadataPath, "utf8"));
50
+ return metadata && typeof metadata === "object" && "version" in metadata;
51
+ } catch (_err) {
52
+ return false;
53
+ }
54
+ };
55
+ var getStrikethrooAt = (directory) => {
56
+ const strikethrooPath = path.join(directory, ".ai", "strikethroo");
57
+ return isValidStrikethrooRoot(strikethrooPath) ? strikethrooPath : null;
58
+ };
59
+ var getParentPaths = (currentPath, acc = []) => {
60
+ const absolutePath = path.resolve(currentPath);
61
+ const nextAcc = [...acc, absolutePath];
62
+ const parentPath = path.dirname(absolutePath);
63
+ if (parentPath === absolutePath) return nextAcc;
64
+ return getParentPaths(parentPath, nextAcc);
65
+ };
66
+ var checkWorkspaceSchema = (metadataPath) => {
67
+ let metadata;
68
+ try {
69
+ metadata = JSON.parse(fs.readFileSync(metadataPath, "utf8"));
70
+ } catch {
71
+ return;
72
+ }
73
+ const actual = typeof metadata.workspaceSchemaVersion === "number" ? metadata.workspaceSchemaVersion : 1;
74
+ if (actual === EXPECTED_SCHEMA) return;
75
+ if (actual < EXPECTED_SCHEMA) {
76
+ process.stderr.write(
77
+ `Workspace schema v${actual} is older than this skill requires (v${EXPECTED_SCHEMA}). Re-run \`npx strikethroo init\` with the latest CLI to update.
78
+ `
79
+ );
80
+ } else {
81
+ process.stderr.write(
82
+ `This skill (built for workspace schema v${EXPECTED_SCHEMA}) is older than the workspace (v${actual}). Re-run \`npx skills add e0ipso/strikethroo\` to update skills.
83
+ `
84
+ );
85
+ }
86
+ process.exit(1);
87
+ };
88
+ var findStrikethrooRoot = (startPath = process.cwd()) => {
89
+ const paths = getParentPaths(startPath);
90
+ const found = paths.find((p) => getStrikethrooAt(p));
91
+ if (!found) return null;
92
+ const root = getStrikethrooAt(found);
93
+ if (root) checkWorkspaceSchema(path.join(root, ".init-metadata.json"));
94
+ return root;
95
+ };
96
+
97
+ // src/skill-scripts/shared/plan-scan.ts
98
+ var fs2 = __toESM(require("fs"));
99
+ var path2 = __toESM(require("path"));
100
+
101
+ // src/skill-scripts/shared/frontmatter.ts
102
+ var ID_PATTERNS = [
103
+ /^\s*["']?id["']?\s*:\s*["']?([+-]?\d+)["']?\s*(?:#.*)?$/im,
104
+ /^\s*id\s*:\s*([+-]?\d+)\s*(?:#.*)?$/im,
105
+ /^\s*["']?id["']?\s*:\s*"([+-]?\d+)"\s*(?:#.*)?$/im,
106
+ /^\s*["']?id["']?\s*:\s*'([+-]?\d+)'\s*(?:#.*)?$/im,
107
+ /^\s*["']id["']\s*:\s*([+-]?\d+)\s*(?:#.*)?$/im,
108
+ /^\s*id\s*:\s*[|>]\s*([+-]?\d+)\s*$/im
109
+ ];
110
+ var validateId = (rawId) => {
111
+ const id = parseInt(rawId, 10);
112
+ if (Number.isNaN(id) || id < 0 || id > Number.MAX_SAFE_INTEGER) return null;
113
+ return id;
114
+ };
115
+ var extractIdFromMarkdown = (content) => {
116
+ const frontmatterMatch = content.match(/^---\s*\r?\n([\s\S]*?)\r?\n---/);
117
+ if (!frontmatterMatch || !frontmatterMatch[1]) return null;
118
+ const block = frontmatterMatch[1];
119
+ for (const pattern of ID_PATTERNS) {
120
+ const match = block.match(pattern);
121
+ if (match && match[1]) {
122
+ const id = validateId(match[1]);
123
+ if (id !== null) return id;
124
+ }
125
+ }
126
+ return null;
127
+ };
128
+ var extractPlanId = (content, _filePath) => {
129
+ return extractIdFromMarkdown(content);
130
+ };
131
+
132
+ // src/skill-scripts/shared/plan-scan.ts
133
+ var PLAN_EXTENSIONS = [".md"];
134
+ var scanPlanDir = (planDirPath, dirName, isArchive) => {
135
+ let entries;
136
+ try {
137
+ entries = fs2.readdirSync(planDirPath, { withFileTypes: true });
138
+ } catch (_err) {
139
+ return [];
140
+ }
141
+ return entries.filter((e) => e.isFile() && PLAN_EXTENSIONS.some((ext) => e.name.endsWith(ext))).flatMap((e) => {
142
+ const filePath = path2.join(planDirPath, e.name);
143
+ try {
144
+ const content = fs2.readFileSync(filePath, "utf8");
145
+ const id = extractPlanId(content, filePath);
146
+ if (id === null) return [];
147
+ return [{ id, file: filePath, dir: planDirPath, isArchive, name: dirName }];
148
+ } catch (_err) {
149
+ return [];
150
+ }
151
+ });
152
+ };
153
+ var getAllPlans = (taskManagerRoot) => {
154
+ const sources = [
155
+ { dir: path2.join(taskManagerRoot, "plans"), isArchive: false },
156
+ { dir: path2.join(taskManagerRoot, "archive"), isArchive: true }
157
+ ];
158
+ return sources.flatMap(({ dir, isArchive }) => {
159
+ if (!fs2.existsSync(dir)) return [];
160
+ let entries;
161
+ try {
162
+ entries = fs2.readdirSync(dir, { withFileTypes: true });
163
+ } catch (_err) {
164
+ return [];
165
+ }
166
+ return entries.filter((e) => e.isDirectory()).flatMap((e) => scanPlanDir(path2.join(dir, e.name), e.name, isArchive));
167
+ });
168
+ };
169
+
170
+ // src/skill-scripts/shared/plan-resolve.ts
171
+ var fs3 = __toESM(require("fs"));
172
+ var path3 = __toESM(require("path"));
173
+ var isValidRootDir = (strikethrooPath) => {
174
+ try {
175
+ if (!fs3.existsSync(strikethrooPath)) return false;
176
+ if (!fs3.lstatSync(strikethrooPath).isDirectory()) return false;
177
+ const metadataPath = path3.join(strikethrooPath, ".init-metadata.json");
178
+ if (!fs3.existsSync(metadataPath)) return false;
179
+ const metadata = JSON.parse(fs3.readFileSync(metadataPath, "utf8"));
180
+ return metadata && typeof metadata === "object" && "version" in metadata;
181
+ } catch (_err) {
182
+ return false;
183
+ }
184
+ };
185
+ var checkStandardRootShortcut = (filePath) => {
186
+ const planDir = path3.dirname(filePath);
187
+ const parentDir = path3.dirname(planDir);
188
+ const possibleRoot = path3.dirname(parentDir);
189
+ const parentBase = path3.basename(parentDir);
190
+ if (parentBase !== "plans" && parentBase !== "archive") return null;
191
+ if (path3.basename(possibleRoot) !== "strikethroo") return null;
192
+ const dotAiDir = path3.dirname(possibleRoot);
193
+ if (path3.basename(dotAiDir) !== ".ai") return null;
194
+ return isValidRootDir(possibleRoot) ? possibleRoot : null;
195
+ };
196
+ var resolveByPath = (absolutePath) => {
197
+ let content;
198
+ try {
199
+ content = fs3.readFileSync(absolutePath, "utf8");
200
+ } catch (_err) {
201
+ return null;
202
+ }
203
+ const planId = extractPlanId(content, absolutePath);
204
+ if (planId === null) return null;
205
+ const tmRoot = checkStandardRootShortcut(absolutePath) || findStrikethrooRoot(path3.dirname(absolutePath));
206
+ if (!tmRoot) return null;
207
+ return {
208
+ planFile: absolutePath,
209
+ planDir: path3.dirname(absolutePath),
210
+ strikethrooRoot: tmRoot,
211
+ planId
212
+ };
213
+ };
214
+ var resolveByIdInAncestry = (planId, startPath, searched = /* @__PURE__ */ new Set()) => {
215
+ const tmRoot = findStrikethrooRoot(startPath);
216
+ if (!tmRoot) return null;
217
+ const normalized = path3.normalize(tmRoot);
218
+ if (searched.has(normalized)) return null;
219
+ searched.add(normalized);
220
+ const plans = getAllPlans(tmRoot);
221
+ const match = plans.find((p) => p.id === planId);
222
+ if (match) {
223
+ return {
224
+ planFile: match.file,
225
+ planDir: match.dir,
226
+ strikethrooRoot: tmRoot,
227
+ planId
228
+ };
229
+ }
230
+ const parentOfRoot = path3.dirname(path3.dirname(tmRoot));
231
+ if (parentOfRoot === tmRoot) return null;
232
+ return resolveByIdInAncestry(planId, parentOfRoot, searched);
233
+ };
234
+ var resolvePlan = (input, startPath = process.cwd()) => {
235
+ if (input === null || input === void 0 || input === "") return null;
236
+ const inputStr = String(input);
237
+ if (inputStr.startsWith("/")) {
238
+ return resolveByPath(inputStr);
239
+ }
240
+ const planId = parseInt(inputStr, 10);
241
+ if (Number.isNaN(planId)) return null;
242
+ return resolveByIdInAncestry(planId, startPath);
243
+ };
244
+
245
+ // src/skill-scripts/validate-plan-blueprint.ts
246
+ var VALID_FIELDS = [
247
+ "planFile",
248
+ "planDir",
249
+ "taskCount",
250
+ "blueprintExists",
251
+ "strikethrooRoot",
252
+ "planId"
253
+ ];
254
+ var countTasks = (planDir) => {
255
+ const tasksDir = path4.join(planDir, "tasks");
256
+ if (!fs4.existsSync(tasksDir)) return 0;
257
+ try {
258
+ const stat = fs4.lstatSync(tasksDir);
259
+ if (!stat.isDirectory()) return 0;
260
+ return fs4.readdirSync(tasksDir).filter((f) => f.endsWith(".md")).length;
261
+ } catch (_err) {
262
+ return 0;
263
+ }
264
+ };
265
+ var checkBlueprintExists = (planFile) => {
266
+ try {
267
+ const content = fs4.readFileSync(planFile, "utf8");
268
+ return /^## Execution Blueprint/m.test(content);
269
+ } catch (_err) {
270
+ return false;
271
+ }
272
+ };
273
+ var usage = () => {
274
+ const lines = [
275
+ "Plan ID or absolute path is required",
276
+ "",
277
+ "Usage: node validate-plan-blueprint.cjs <plan-id-or-path> [field-name]",
278
+ "",
279
+ "Examples:",
280
+ " node validate-plan-blueprint.cjs 47",
281
+ " node validate-plan-blueprint.cjs /path/to/plan.md",
282
+ " node validate-plan-blueprint.cjs 47 planFile",
283
+ " node validate-plan-blueprint.cjs 47 blueprintExists"
284
+ ];
285
+ lines.forEach((l) => process.stderr.write(`[ERROR] ${l}
286
+ `));
287
+ };
288
+ var listAvailablePlans = (startPath) => {
289
+ const tmRoot = findStrikethrooRoot(startPath);
290
+ if (!tmRoot) return [];
291
+ const plans = getAllPlans(tmRoot);
292
+ return plans.map((p) => p.name).sort((a, b) => {
293
+ const aMatch = a.match(/^(\d+)--/);
294
+ const bMatch = b.match(/^(\d+)--/);
295
+ if (!aMatch || !bMatch || !aMatch[1] || !bMatch[1]) return 0;
296
+ return parseInt(aMatch[1], 10) - parseInt(bMatch[1], 10);
297
+ });
298
+ };
299
+ var main = () => {
300
+ const inputId = process.argv[2];
301
+ const fieldName = process.argv[3];
302
+ if (!inputId) {
303
+ usage();
304
+ process.exit(1);
305
+ }
306
+ const numericInput = parseInt(inputId, 10);
307
+ const isNumeric = !Number.isNaN(numericInput);
308
+ const isAbsolutePath = inputId.startsWith("/");
309
+ if (!isNumeric && !isAbsolutePath) {
310
+ process.stderr.write(`[ERROR] Invalid plan ID: "${inputId}" is not a valid number
311
+ `);
312
+ process.exit(1);
313
+ }
314
+ const resolved = resolvePlan(inputId);
315
+ if (!resolved) {
316
+ process.stderr.write(`[ERROR] Plan ID ${inputId} not found or invalid
317
+ `);
318
+ process.stderr.write("[ERROR] \n");
319
+ const available = listAvailablePlans(process.cwd());
320
+ if (available.length > 0) {
321
+ process.stderr.write("[ERROR] Available plans:\n");
322
+ available.forEach((name) => process.stderr.write(`[ERROR] ${name}
323
+ `));
324
+ }
325
+ process.exit(1);
326
+ }
327
+ const result = {
328
+ planFile: resolved.planFile,
329
+ planDir: resolved.planDir,
330
+ strikethrooRoot: resolved.strikethrooRoot,
331
+ planId: resolved.planId,
332
+ taskCount: countTasks(resolved.planDir),
333
+ blueprintExists: checkBlueprintExists(resolved.planFile) ? "yes" : "no"
334
+ };
335
+ if (fieldName) {
336
+ if (!VALID_FIELDS.includes(fieldName)) {
337
+ process.stderr.write(`[ERROR] Invalid field name: ${fieldName}
338
+ `);
339
+ process.stderr.write(`[ERROR] Valid fields: ${VALID_FIELDS.join(", ")}
340
+ `);
341
+ process.exit(1);
342
+ }
343
+ const value = result[fieldName];
344
+ process.stdout.write(`${String(value)}
345
+ `);
346
+ } else {
347
+ process.stdout.write(`${JSON.stringify(result, null, 2)}
348
+ `);
349
+ }
350
+ process.exit(0);
351
+ };
352
+ if (require.main === module) {
353
+ main();
354
+ }
355
+ // Annotate the CommonJS export names for ESM import in node:
356
+ 0 && (module.exports = {
357
+ main
358
+ });
@@ -0,0 +1,7 @@
1
+ # Strikethroo
2
+
3
+ This directory contains AI-assisted task management files for this project.
4
+
5
+ Managed by the [Strikethroo](https://www.github.com/e0ipso/strikethroo) project.
6
+
7
+ **Documentation**: https://mateuaguilo.com/strikethroo
@@ -0,0 +1,76 @@
1
+ # Strikethroo General Information
2
+
3
+ This document contains important information that is common to all the
4
+ Strikethroo skills your AI assistant uses to plan, decompose, and execute work.
5
+
6
+ ## Types of Documents
7
+
8
+ Work orders (abbreviated as WO) are complex prompts for programming,
9
+ organizational, or management tasks created by a user. Work orders are
10
+ independent of each other and cannot share any context. By definition
11
+ different work orders can be worked on independently.
12
+
13
+ Each work order has plan associated to it. The plan is a comprehensive document
14
+ highlighting all the aspects of the work necessary to accomplish the goals from
15
+ the work order.
16
+
17
+ Each plan will be broken into tasks. Each task is a logical unit of work that
18
+ has a single purpose, and is solved using a single skill. All tasks exist as
19
+ part of a plan. Tasks can have dependencies on other tasks. This happens when a
20
+ task cannot be worked on (or completed) before some other task(s) are completed.
21
+
22
+ ## Directory Structure
23
+
24
+ To find a plan document from its ID use the following command (replace {planId} with the ID, like 06):
25
+ ```shell
26
+ find .ai/strikethroo/{plans,archive} -name "plan-[0-9][0-9]*--*.md" -type f -exec grep -l "^id: \?{planId}$" {} \;
27
+ ```
28
+
29
+ Plans, and tasks are stored as MarkDown files with a YAML front-matter. They are
30
+ all filed under the `.ai/strikethroo/` folder at the root of the repository.
31
+
32
+ Plans are organized as follows:
33
+
34
+ ```
35
+ .ai/
36
+ strikethroo/
37
+ plans/ # Active plans (work in progress)
38
+ 01--authentication-provider/
39
+ plan-01--authentication-provider.md
40
+ tasks/
41
+ 01--create-project-structure.md
42
+ 02--implement-authorization.md
43
+ 03--this-example-task.md
44
+ 04--create-tests.md
45
+ 05--update-documentation.md
46
+ archive/ # Completed plans (successfully executed)
47
+ 05--user-management/
48
+ plan-05--user-management.md
49
+ tasks/
50
+ 01--create-user-model.md
51
+ 02--implement-crud-operations.md
52
+ 03--add-validation.md
53
+ ```
54
+
55
+ Note how in the `.ai/strikethroo/plans/` folder we have a sub-folder per plan.
56
+ Each sub-folder will contain the plan document and has a name following a naming
57
+ pattern `[ID]--[plan-short-name]`. Where the ID is auto-incremental. The plan
58
+ document has a name following the pattern `plan-[ID]--[plan-short-name].md`.
59
+ Finally, all tasks are under a `tasks` sub-folder. Each task has a name
60
+ according to the pattern `[incremental-ID]--[task-short-name].md`. IDs for tasks
61
+ are auto-incremental within a plan. Each plan starts their tasks' IDs from 01.
62
+
63
+ ## Plan Lifecycle and Archive System
64
+
65
+ Plans follow a lifecycle that maintains workspace organization:
66
+
67
+ 1. **Active Plans**: When created, plans are placed in the `plans/` directory where they remain while being worked on.
68
+
69
+ 2. **Completed Plans**: Upon successful execution of a blueprint (via the `st-execute-blueprint` skill), the entire plan directory is automatically moved from `plans/` to `archive/`.
70
+
71
+ 3. **Archive Directory**: The `archive/` directory serves as permanent storage for completed work. This separation keeps the active workspace clean while preserving completed plans for reference.
72
+
73
+ The archive system provides several benefits:
74
+ - **Workspace Organization**: Active plans remain easily accessible while completed work doesn't clutter the workspace
75
+ - **Historical Reference**: Completed plans and their tasks remain available for future reference or learning
76
+ - **Automatic Management**: No manual intervention required - archival happens automatically upon successful completion
@@ -0,0 +1,46 @@
1
+ # POST_ERROR_DETECTION Hook
2
+
3
+ ## Task Execution Error Handling
4
+
5
+ If task execution fails:
6
+
7
+ ```bash
8
+ # On execution failure, update status to failed
9
+ echo "Task execution failed - updating status..."
10
+
11
+ TEMP_FILE=$(mktemp)
12
+ awk '
13
+ /^---$/ {
14
+ if (++delim == 1) {
15
+ print
16
+ next
17
+ } else if (delim == 2) {
18
+ print "status: \"failed\""
19
+ print
20
+ next
21
+ }
22
+ }
23
+ /^status:/ && delim == 1 {
24
+ print "status: \"failed\""
25
+ next
26
+ }
27
+ { print }
28
+ ' "$TASK_FILE" > "$TEMP_FILE"
29
+
30
+ mv "$TEMP_FILE" "$TASK_FILE"
31
+
32
+ echo "Task ${TASK_ID} marked as failed"
33
+ echo "Check the task requirements and try again"
34
+ exit 1
35
+ ```
36
+
37
+ ## Validation Gate Failure Handling
38
+
39
+ #### Validation Gate Failures
40
+ If validation gates fail:
41
+ 1. Document which specific validations failed
42
+ 2. Identify which tasks may have caused the failure
43
+ 3. Generate remediation plan
44
+ 4. Re-execute affected tasks after fixes
45
+ 5. Re-run validation gates
46
+ 6. If errors persist, escalate to the user
@@ -0,0 +1,25 @@
1
+ # POST_EXECUTION Hook
2
+
3
+ ## Validation Gates
4
+
5
+ Before marking the blueprint as complete, verify:
6
+
7
+ - [ ] All linting rules must pass without errors. If no linter is configured, skip this step
8
+ - [ ] All tests must pass successfully. If no test suite is configured, skip this step
9
+ - [ ] Verify all tasks in the plan have `status: "completed"` in their frontmatter
10
+ - [ ] Verify that the AGENTS.md documentation or related documentes are still correct after this plan execution
11
+ - [ ] Execute the **Self Validation** steps defined in the plan document. These are concrete verification procedures (e.g., Playwright browser checks, database CLI queries, screenshots) that confirm the implementation works in the real system. If any step fails, treat it as a validation gate failure
12
+
13
+ ## Cleanup
14
+ Assess weather the current plan has left tech debt behind or if it has created dead code. None of those are acceptable. Fix them and leave behind the most maintainable code change possible.
15
+
16
+ Backwards compatibility and legacy support are only tolerated if explicitly expressed by the user. Unless it is called out in the plan, you are to assume that backwards compatibility layers are tech debt that should be eliminated.
17
+
18
+ ## Failure Behavior
19
+
20
+ If any validation gate fails:
21
+
22
+ - **Halt execution immediately** - do not proceed to summary generation or archival
23
+ - **Leave plan in `plans/` directory** for debugging and correction
24
+ - **Document the failure** in the plan file with details about which gate failed
25
+ - **Provide actionable next steps** for resolving the failure
@@ -0,0 +1,24 @@
1
+ # POST_PHASE Hook
2
+
3
+ Ensure that:
4
+
5
+ - The code base is passing the linting requirements
6
+ - A descriptive commit (using conventional commits with a subject and a description) for the phase was successfully created.
7
+
8
+ ### Execution Monitoring
9
+
10
+ #### Progress Tracking
11
+
12
+ Update the list of tasks from the plan document to add the status of each task
13
+ and phase. Once a phase has been completed and validated, and before you move to
14
+ the next phase, update the blueprint and add a ✅ emoji in front of its title.
15
+ Add ✔️ emoji in front of all the tasks in that phase, and update their status to
16
+ `completed`.
17
+
18
+ #### Task Status Updates
19
+ Valid status transitions:
20
+ - `pending` → `in-progress` (when agent starts)
21
+ - `in-progress` → `completed` (successful execution)
22
+ - `in-progress` → `failed` (execution error)
23
+ - `failed` → `in-progress` (retry attempt)
24
+
@@ -0,0 +1,5 @@
1
+ # POST_PLAN Hook
2
+
3
+ Ensure the plan includes a _Self Validation_ section describing the steps the LLM will take to validate that the plan was completed successfully.
4
+
5
+ Also, answer the question _Does this plan need to update the documentation, or the AGENTS.md_.
@@ -0,0 +1,41 @@
1
+ # POST_TASK_GENERATION_ALL Hook
2
+
3
+ After all tasks have been generated, perform these two steps:
4
+
5
+ ## 1. Review Task Complexity
6
+
7
+ For each generated task, do a quick sanity check:
8
+
9
+ - **Too complex?** If a task spans 3+ technologies or requires 3+ skills, split it.
10
+ - **Too vague?** If acceptance criteria are unclear, sharpen them.
11
+ - **Too trivial?** If two tasks could be one without adding complexity, merge them.
12
+
13
+ Target: every task should be completable with 1-2 skills and have clear acceptance criteria.
14
+
15
+ ## 2. Update Plan with Blueprint
16
+
17
+ After finalizing tasks, append to the plan document:
18
+
19
+ ### Dependency Diagram
20
+
21
+ If tasks have dependencies, add a Mermaid graph:
22
+
23
+ ```mermaid
24
+ graph TD
25
+ 001[Task 001: Description] --> 002[Task 002: Description]
26
+ ```
27
+
28
+ Verify there are no circular dependencies.
29
+
30
+ ### Execution Phases
31
+
32
+ Group tasks into phases:
33
+ - **Phase 1**: Tasks with no dependencies (run in parallel)
34
+ - **Phase N**: Tasks whose dependencies are all in earlier phases
35
+
36
+ Use the template in `.ai/strikethroo/config/templates/BLUEPRINT_TEMPLATE.md` for structure.
37
+
38
+ Before finalizing, verify:
39
+ - Every task is in exactly one phase
40
+ - No task runs before its dependencies complete
41
+ - Phase 1 has only zero-dependency tasks
@@ -0,0 +1,21 @@
1
+ # PRE_PHASE Hook
2
+
3
+ ## Phase Pre-Execution
4
+
5
+ ### Feature Branch Creation
6
+
7
+ Create a feature branch for this plan execution:
8
+
9
+ - From `main`/`master` with a clean working tree: create a branch named `feature/{planId}--{plan-name}` and switch to it.
10
+ - From `main`/`master` with uncommitted changes: halt with an error — do not proceed.
11
+ - Already on a feature branch: proceed without creating a new branch.
12
+ - Branch already exists: switch to it and proceed normally.
13
+
14
+ ## Phase Execution Workflow
15
+
16
+ 1. **Phase Initialization**
17
+ - Identify current phase from the execution blueprint
18
+ - List all tasks scheduled for parallel execution in this phase
19
+ - **Validate Task Dependencies**: For each task in the current phase, verify that all declared dependencies (from the task's YAML frontmatter `dependencies` array) have status `completed`. If any dependency is unresolved, halt the phase and report the blocking dependencies before continuing.
20
+ - Confirm no tasks are marked "needs-clarification"
21
+ - If any phases are marked as completed, verify they are actually completed and continue from the next phase.
@@ -0,0 +1,42 @@
1
+ # PRE_PLAN Hook
2
+
3
+ ## Scope Control Guidelines
4
+
5
+ **Critical: Implement ONLY what is explicitly requested**
6
+
7
+ - **Minimal Viable Implementation**: Build exactly what the user asked for, nothing more
8
+ - **Question Everything Extra**: If not directly mentioned by the user, don't add it
9
+ - **Avoid Feature Creep**: Resist the urge to add "helpful" features or "nice-to-have" additions
10
+ - **YAGNI Principle**: _You Aren't Gonna Need It_ - don't build for hypothetical future needs
11
+ - **Do NOT add backwards compatibility, unless requested**: If there is a potential BC break, ask the user if they want to BC support. Do not assume the want it.
12
+
13
+ **Common Scope Creep Anti-Patterns to Avoid:**
14
+ 1. Adding extra commands or features "for completeness"
15
+ 2. Creating infrastructure for future features that weren't requested
16
+ 3. Building abstractions or frameworks when simple solutions suffice
17
+ 4. Adding configuration options not specifically mentioned
18
+ 5. Implementing error handling beyond what's necessary for the core request
19
+ 6. Creating documentation or help systems unless explicitly requested
20
+
21
+ **When in doubt, ask**: "Is this feature explicitly mentioned in the user's request?"
22
+
23
+ ## Simplicity Principles
24
+
25
+ **Favor maintainability over cleverness**
26
+
27
+ - **Simple Solutions First**: Choose the most straightforward approach that meets requirements
28
+ - **Avoid Over-Engineering**: Don't create complex systems when simple ones work
29
+ - **Readable Code**: Write code that others can easily understand and modify
30
+ - **Standard Patterns**: Use established patterns rather than inventing new ones
31
+ - **Minimal Dependencies**: Add external dependencies only when essential, but do not re-invent the wheel
32
+ - **Clear Structure**: Organize code in obvious, predictable ways
33
+
34
+ **Remember**: A working simple solution is better than a complex "perfect" one.
35
+
36
+ ## Critical Notes
37
+
38
+ - Never generate a partial or assumed plan without adequate context
39
+ - Prioritize accuracy over speed
40
+ - Consider both technical and non-technical aspects
41
+ - Use the plan template in .ai/strikethroo/config/templates/PLAN_TEMPLATE.md
42
+ - DO NOT create or list any tasks or phases during the plan creation. This will be done in a later step. Stick to writing the PRD (Project Requirements Document).