nitm-ai-dev-toolkit 5.0.0 → 5.0.1
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.
- package/CHANGELOG.md +46 -0
- package/README.md +27 -7
- package/bin/cli.js +598 -88
- package/package.json +1 -1
- package/src/monorepo/.agents/skills/factory/SKILL.md +77 -27
- package/src/monorepo/.claude/commands/assign-tasks.md +1 -0
- package/src/monorepo/.claude/commands/factory.md +1 -1
- package/src/monorepo/.claude/commands/ponytail-review.md +1 -1
- package/src/monorepo/.claude/prompt-snippets/assign-tasks.md +13 -3
- package/src/monorepo/.claude/prompt-snippets/bootstrap-patch.md +31 -24
- package/src/monorepo/.claude/prompt-snippets/bootstrap-upgrade.md +12 -13
- package/src/monorepo/.claude/prompt-snippets/bootstrap.md +11 -11
- package/src/monorepo/.claude/prompt-snippets/factory.md +4 -4
- package/src/monorepo/.claude/prompt-snippets/implement-feature.md +3 -1
- package/src/monorepo/.claude/rules-snippets/subagent-workflow.md +2 -2
- package/src/monorepo/.cursor/commands/factory.md +1 -1
- package/src/monorepo/.github/prompts/factory.prompt.md +1 -1
- package/src/monorepo/.opencode/agents/admin-portal.md +1 -1
- package/src/monorepo/.opencode/agents/api-specialist.md +1 -1
- package/src/monorepo/.opencode/agents/backend-architect.md +1 -1
- package/src/monorepo/.opencode/agents/documenter.md +1 -1
- package/src/monorepo/.opencode/agents/factory-approver.md +1 -1
- package/src/monorepo/.opencode/agents/factory-builder.md +1 -1
- package/src/monorepo/.opencode/agents/factory-reviewer-code.md +1 -1
- package/src/monorepo/.opencode/agents/factory-reviewer-security.md +1 -1
- package/src/monorepo/.opencode/agents/factory-reviewer-ui.md +1 -1
- package/src/monorepo/.opencode/agents/factory-reviewer-ux.md +1 -1
- package/src/monorepo/.opencode/agents/factory-spec-writer.md +1 -1
- package/src/monorepo/.opencode/agents/feature-builder.md +1 -1
- package/src/monorepo/.opencode/agents/frontend-developer.md +1 -1
- package/src/monorepo/.opencode/agents/green.md +1 -1
- package/src/monorepo/.opencode/agents/implementer.md +1 -1
- package/src/monorepo/.opencode/agents/planner.md +1 -1
- package/src/monorepo/.opencode/agents/red.md +1 -1
- package/src/monorepo/.opencode/agents/refactor.md +1 -1
- package/src/monorepo/.opencode/agents/researcher.md +1 -1
- package/src/monorepo/.opencode/agents/reviewer.md +1 -1
- package/src/monorepo/.opencode/agents/tdd.md +1 -1
- package/src/monorepo/.opencode/commands/assign-tasks.md +1 -1
- package/src/monorepo/.opencode/commands/bootstrap-patch.md +1 -1
- package/src/monorepo/.opencode/commands/bootstrap-upgrade.md +1 -1
- package/src/monorepo/.opencode/commands/bootstrap.md +1 -1
- package/src/monorepo/.opencode/commands/commit-push.md +1 -1
- package/src/monorepo/.opencode/commands/constitution.md +1 -1
- package/src/monorepo/.opencode/commands/create-skill.md +1 -1
- package/src/monorepo/.opencode/commands/factory.md +1 -1
- package/src/monorepo/.opencode/commands/implement-feature.md +1 -1
- package/src/monorepo/.opencode/commands/implement-fixes.md +1 -1
- package/src/monorepo/.opencode/commands/implement.md +1 -1
- package/src/monorepo/.opencode/commands/plan.md +1 -1
- package/src/monorepo/.opencode/commands/playwright-test.md +1 -1
- package/src/monorepo/.opencode/commands/ponytail-audit.md +1 -1
- package/src/monorepo/.opencode/commands/ponytail-debt.md +1 -1
- package/src/monorepo/.opencode/commands/ponytail-gain.md +1 -1
- package/src/monorepo/.opencode/commands/ponytail-help.md +1 -1
- package/src/monorepo/.opencode/commands/ponytail-review.md +1 -1
- package/src/monorepo/.opencode/commands/ponytail.md +1 -1
- package/src/monorepo/.opencode/commands/release-notes.md +1 -1
- package/src/monorepo/.opencode/commands/review-pr.md +1 -1
- package/src/monorepo/.opencode/commands/review.md +1 -1
- package/src/monorepo/.opencode/commands/specify.md +1 -1
- package/src/monorepo/.opencode/commands/tasks.md +1 -1
- package/src/monorepo/.opencode/opencode.jsonc +1 -2
- package/src/monorepo/.opencode/rules/agent-conduct.md +1 -1
- package/src/monorepo/.opencode/rules/api-server.md +1 -1
- package/src/monorepo/.opencode/rules/coding-standards.md +1 -1
- package/src/monorepo/.opencode/rules/component-structure.md +1 -1
- package/src/monorepo/.opencode/rules/core-libraries.md +1 -1
- package/src/monorepo/.opencode/rules/environment-tooling.md +1 -1
- package/src/monorepo/.opencode/rules/logging-comments.md +1 -1
- package/src/monorepo/.opencode/rules/logging.md +1 -1
- package/src/monorepo/.opencode/rules/prisma-migrations.md +1 -1
- package/src/monorepo/.opencode/rules/project-context.md +1 -1
- package/src/monorepo/.opencode/rules/server-client-separation.md +1 -1
- package/src/monorepo/.opencode/rules/subagent-workflow.md +1 -1
- package/src/monorepo/.opencode/rules/testing-quality.md +1 -1
- package/src/monorepo/.opencode/rules/ui-accessibility.md +1 -1
- package/src/monorepo/.opencode/rules/version-control.md +1 -1
- package/src/monorepo/.opencode/rules/what-to-avoid.md +1 -1
- package/src/monorepo/AGENTS.md +3 -3
- package/src/monorepo/README.md +4 -4
- package/src/monorepo/factory/README.md +40 -15
- package/src/monorepo/factory/worktree-bootstrap.md +32 -0
- package/src/repo/.agents/skills/factory/SKILL.md +76 -26
- package/src/repo/.claude/commands/assign-tasks.md +1 -0
- package/src/repo/.claude/commands/factory.md +1 -1
- package/src/repo/.claude/commands/ponytail-review.md +1 -1
- package/src/repo/.claude/prompt-snippets/assign-tasks.md +13 -3
- package/src/repo/.claude/prompt-snippets/bootstrap-patch.md +31 -24
- package/src/repo/.claude/prompt-snippets/bootstrap-upgrade.md +16 -16
- package/src/repo/.claude/prompt-snippets/bootstrap.md +11 -11
- package/src/repo/.claude/prompt-snippets/factory.md +4 -4
- package/src/repo/.claude/prompt-snippets/implement-feature.md +3 -1
- package/src/repo/.claude/rules-snippets/subagent-workflow.md +2 -2
- package/src/repo/.cursor/commands/factory.md +1 -1
- package/src/repo/.github/prompts/factory.prompt.md +1 -1
- package/src/repo/.opencode/agents/admin-portal.md +1 -1
- package/src/repo/.opencode/agents/api-specialist.md +1 -1
- package/src/repo/.opencode/agents/backend-architect.md +1 -1
- package/src/repo/.opencode/agents/documenter.md +1 -1
- package/src/repo/.opencode/agents/factory-approver.md +1 -1
- package/src/repo/.opencode/agents/factory-builder.md +1 -1
- package/src/repo/.opencode/agents/factory-reviewer-code.md +1 -1
- package/src/repo/.opencode/agents/factory-reviewer-security.md +1 -1
- package/src/repo/.opencode/agents/factory-reviewer-ui.md +1 -1
- package/src/repo/.opencode/agents/factory-reviewer-ux.md +1 -1
- package/src/repo/.opencode/agents/factory-spec-writer.md +1 -1
- package/src/repo/.opencode/agents/feature-builder.md +1 -1
- package/src/repo/.opencode/agents/frontend-developer.md +1 -1
- package/src/repo/.opencode/agents/green.md +1 -1
- package/src/repo/.opencode/agents/implementer.md +1 -1
- package/src/repo/.opencode/agents/planner.md +1 -1
- package/src/repo/.opencode/agents/red.md +1 -1
- package/src/repo/.opencode/agents/refactor.md +1 -1
- package/src/repo/.opencode/agents/researcher.md +1 -1
- package/src/repo/.opencode/agents/reviewer.md +1 -1
- package/src/repo/.opencode/agents/tdd.md +1 -1
- package/src/repo/.opencode/commands/assign-tasks.md +1 -1
- package/src/repo/.opencode/commands/bootstrap-patch.md +1 -1
- package/src/repo/.opencode/commands/bootstrap-upgrade.md +1 -1
- package/src/repo/.opencode/commands/bootstrap.md +1 -1
- package/src/repo/.opencode/commands/commit-push.md +1 -1
- package/src/repo/.opencode/commands/constitution.md +1 -1
- package/src/repo/.opencode/commands/create-skill.md +1 -1
- package/src/repo/.opencode/commands/factory.md +1 -1
- package/src/repo/.opencode/commands/implement-feature.md +1 -1
- package/src/repo/.opencode/commands/implement-fixes.md +1 -1
- package/src/repo/.opencode/commands/implement.md +1 -1
- package/src/repo/.opencode/commands/plan.md +1 -1
- package/src/repo/.opencode/commands/playwright-test.md +1 -1
- package/src/repo/.opencode/commands/ponytail-audit.md +1 -1
- package/src/repo/.opencode/commands/ponytail-debt.md +1 -1
- package/src/repo/.opencode/commands/ponytail-gain.md +1 -1
- package/src/repo/.opencode/commands/ponytail-help.md +1 -1
- package/src/repo/.opencode/commands/ponytail-review.md +1 -1
- package/src/repo/.opencode/commands/ponytail.md +1 -1
- package/src/repo/.opencode/commands/release-notes.md +1 -1
- package/src/repo/.opencode/commands/review-pr.md +1 -1
- package/src/repo/.opencode/commands/review.md +1 -1
- package/src/repo/.opencode/commands/specify.md +1 -1
- package/src/repo/.opencode/commands/tasks.md +1 -1
- package/src/repo/.opencode/opencode.jsonc +1 -2
- package/src/repo/.opencode/rules/agent-conduct.md +1 -1
- package/src/repo/.opencode/rules/api-server.md +1 -1
- package/src/repo/.opencode/rules/coding-standards.md +1 -1
- package/src/repo/.opencode/rules/component-structure.md +1 -1
- package/src/repo/.opencode/rules/core-libraries.md +1 -1
- package/src/repo/.opencode/rules/environment-tooling.md +1 -1
- package/src/repo/.opencode/rules/logging-comments.md +1 -1
- package/src/repo/.opencode/rules/logging.md +1 -1
- package/src/repo/.opencode/rules/prisma-migrations.md +1 -1
- package/src/repo/.opencode/rules/project-context.md +1 -1
- package/src/repo/.opencode/rules/server-client-separation.md +1 -1
- package/src/repo/.opencode/rules/subagent-workflow.md +1 -1
- package/src/repo/.opencode/rules/testing-quality.md +1 -1
- package/src/repo/.opencode/rules/ui-accessibility.md +1 -1
- package/src/repo/.opencode/rules/version-control.md +1 -1
- package/src/repo/.opencode/rules/what-to-avoid.md +1 -1
- package/src/repo/AGENTS.md +3 -3
- package/src/repo/README.md +4 -4
- package/src/repo/factory/README.md +33 -14
- package/src/repo/factory/worktree-bootstrap.md +32 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: factory
|
|
3
|
-
description: Opt-in software factory for feature-sized work. Runs one job through intake questions, a spec gate, a plan gate, build in an isolated git worktree (or in place on request), parallel reviews by lens, approval, and a local merge. Feature docs live in
|
|
3
|
+
description: Opt-in software factory for feature-sized work. Runs one job through intake questions, a spec gate, a plan gate, build in an isolated git worktree (or in place on request), parallel reviews by lens, approval, and then a merge: local, or a merge request on the forge. Feature docs live in the feature folders, job state in factory/jobs/, and tickets (when the project tracks them) follow the job. Invoked as /factory with a request (intake), start, approve, rework, abandon, status, watch, archive, or prune. Quick fixes stay direct.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Factory (orchestrator)
|
|
7
7
|
|
|
8
|
-
One orchestrator session runs a feature through intake → spec → plan → build → review → approve → merge. Agents get their context from files and each agent writes only its own file. You are the orchestrator: you ask the intake questions, dispatch agents, read their files, rewrite `job.json`, run the gates with the operator, handle tickets, and run the merge. You never write code, specs, plans, reviews, or `qa.md` yourself. Exceptions: you write `intake.md` from the operator's answers, `spec-<k>.md` and `plan-<k>.md` from the operator's change requests, `tasks.md` ticket keys, the feature folder rename and copy, the feature docs commit on the job branch, worktree and branch removal, the moves and branch deletions in Archive, `decision.md` with `ESCALATE` when retries run out, `merge-conflict.md` on a merge conflict, and `rework-<k>.md` from the user's note.
|
|
8
|
+
One orchestrator session runs a feature through intake → spec → plan → build → review → approve → merge. Agents get their context from files and each agent writes only its own file. You are the orchestrator: you ask the intake questions, dispatch agents, read their files, rewrite `job.json`, run the gates with the operator, handle tickets, and run the merge. You never write code, specs, plans, reviews, or `qa.md` yourself. Exceptions: you write `intake.md` from the operator's answers, `spec-<k>.md` and `plan-<k>.md` from the operator's change requests, `tasks.md` ticket keys, the feature folder rename and copy, the feature docs commit on the job branch, worktree and branch removal, the moves and branch deletions in Archive, `decision.md` with `ESCALATE` when retries run out, `merge-conflict.md` on a merge conflict, `bootstrap.md` on a failed worktree bootstrap step, the push and merge request in `push-mr` mode (see Merge procedure), and `rework-<k>.md` from the user's note.
|
|
9
9
|
|
|
10
10
|
The factory is opt-in and sits alongside Feature Builder and TDD. Nothing runs unless the user invokes `/factory`.
|
|
11
11
|
|
|
@@ -19,6 +19,8 @@ Bootstrap replaces these when it adopts the template. The names below have no br
|
|
|
19
19
|
| FACTORY_PORT_BASE | Base dev-server port for job ports | `5100` |
|
|
20
20
|
| APPROVAL_MODE | `human` stops at `awaiting-human`; `auto` merges on `APPROVE` | `human` |
|
|
21
21
|
| FACTORY_REVIEW_LENSES | Comma list drawn from `code, security, ux, ui` | `code, security` |
|
|
22
|
+
| FACTORY_FEATURE_PATHS | Feature-folder roots, comma list, relative to the repo root. A `*` matches one folder name. Intake, Start, and Status search every root. A new feature goes to the first root without `*`, or to a `*` root when its code sits in exactly one app (see Feature folders) | monorepo: `apps/*/docs/features, docs/features`; repo: `docs/features` |
|
|
23
|
+
| MERGE_MODE | `local`: `--no-ff` merge on this machine, never pushed. `push-mr`: push `factory/<id>` and open a merge or pull request with the forge CLI; the forge merges. Any other value is `local` | `local` |
|
|
22
24
|
|
|
23
25
|
## When to use
|
|
24
26
|
|
|
@@ -32,20 +34,20 @@ Bootstrap replaces these when it adopts the template. The names below have no br
|
|
|
32
34
|
| --- | --- |
|
|
33
35
|
| `/factory [--in-place] <request>` | Intake (see Intake): read the project, ask only glaring questions, then continue as `start` |
|
|
34
36
|
| `/factory start [--in-place] <request \| KEY \| slug \| job-id>` | Resolve the feature folder, or resume its open job (see Start). `--in-place` applies only to a new job |
|
|
35
|
-
| `/factory approve <job-id>` | Merge a job in `awaiting-human` or `needs-human
|
|
37
|
+
| `/factory approve <job-id>` | Merge a job in `awaiting-human` or `needs-human` (`local`), or push it and open its merge request (`push-mr`, see Merge procedure). In `push-mr`, approving an `awaiting-human` job whose request is open finishes it once the forge has merged it. On a `merged` job, move its tickets to Done |
|
|
36
38
|
| `/factory rework <job-id> <note>` | Write a rework note, start a fresh builder, reset the retry budget |
|
|
37
39
|
| `/factory abandon <job-id>` | Close a job that will not continue. Nothing is merged. The worktree and branch are removed only when the branch has no unmerged commits (see Abandon) |
|
|
38
40
|
| `/factory status [--all]` | Summarize open jobs from their `job.json` (read-only). Closed jobs are hidden unless `--all` (see Status) |
|
|
39
41
|
| `/factory watch [--all]` | Show the status table, then the command for the live view to run in a terminal (read-only). `--all` as for status |
|
|
40
42
|
| `/factory archive [--all] [--dry-run]` | Move closed jobs to `factory/archive/` (see Archive). Open jobs never move |
|
|
41
|
-
| `/factory prune [--all] [--abandoned] [--dry-run]` | Permanently delete closed jobs from `factory/jobs/` and `factory/archive/` (see Prune). Open jobs and
|
|
43
|
+
| `/factory prune [--all] [--abandoned] [--dry-run]` | Permanently delete closed jobs from `factory/jobs/` and `factory/archive/` (see Prune). Open jobs and feature folders are never touched |
|
|
42
44
|
|
|
43
45
|
A first argument of `start`, `approve`, `rework`, `abandon`, `status`, `watch`, `archive`, or `prune` selects its row. Anything else is a request for intake. A bare job id that matches an existing `factory/jobs/<id>/` or `factory/archive/<id>/` is not a request: it goes to Start. An archived job is closed. `rework` and `abandon` refuse it. `approve` on an archived `merged` job only moves its tickets to Done, and merges nothing.
|
|
44
46
|
|
|
45
47
|
## Layout
|
|
46
48
|
|
|
47
49
|
```
|
|
48
|
-
|
|
50
|
+
<feature root>/<KEY>-<slug>/ tracked by the project; feature docs (roots: {{FACTORY_FEATURE_PATHS}})
|
|
49
51
|
spec.md spec-writer, spec mode (from the feature spec template)
|
|
50
52
|
plan.md spec-writer, plan mode: approach, steps, and the **Size:** line
|
|
51
53
|
tasks.md spec-writer, plan mode, large work only
|
|
@@ -53,6 +55,7 @@ docs/features/<KEY>-<slug>/ tracked by the project; feature docs
|
|
|
53
55
|
factory/
|
|
54
56
|
README.md setup and reference
|
|
55
57
|
.gitignore ignores jobs/ and archive/
|
|
58
|
+
worktree-bootstrap.md project-owned steps run in each new worktree (see Worktree)
|
|
56
59
|
jobs/ runtime state, ignored by git
|
|
57
60
|
<NNN-slug>/
|
|
58
61
|
job.json orchestrator only; rewrite the whole file
|
|
@@ -63,13 +66,25 @@ factory/
|
|
|
63
66
|
round-<N>/review-<lens>.md one per configured lens
|
|
64
67
|
decision.md approver (or you, on escalation)
|
|
65
68
|
merge-conflict.md you, on a merge conflict (blocks approve)
|
|
69
|
+
bootstrap.md you, on a failed worktree bootstrap step (blocks the build)
|
|
66
70
|
rework-<k>.md you, from the user's note
|
|
67
71
|
main-copies/ feature docs moved aside at merge (see Merge procedure)
|
|
68
72
|
archive/ closed jobs moved here by /factory archive, ignored by git
|
|
69
73
|
<NNN-slug>/ same layout as jobs/; never resumed
|
|
70
74
|
```
|
|
71
75
|
|
|
72
|
-
`<KEY>` is an issue key in the project's issue key format (`^[A-Z][A-Z0-9]+-\d+$`, as in `PROJ-1234`, the format `AGENTS.md` documents). Without a ticket, the folder is
|
|
76
|
+
`<KEY>` is an issue key in the project's issue key format (`^[A-Z][A-Z0-9]+-\d+$`, as in `PROJ-1234`, the format `AGENTS.md` documents). Without a ticket, the folder is `<root>/<slug>/` and gets its key later if tracking starts.
|
|
77
|
+
|
|
78
|
+
### Feature folders
|
|
79
|
+
|
|
80
|
+
Feature folders live under the roots in `{{FACTORY_FEATURE_PATHS}}`, relative to the repository root. Every root is searched. Where a new folder goes:
|
|
81
|
+
|
|
82
|
+
- **Literal root** (no `*`): the first literal root is the home for cross-cutting features. In a single-package repo, that is the only root.
|
|
83
|
+
- **Per-app root** (`apps/*/docs/features`): a new feature goes there when the request's code sits in exactly one app directory the glob matches. Intake or Start names that app, creates `apps/<app>/docs/features/` if it is missing, and says the chosen folder in chat before creating anything. Code in several apps, or none, goes to the first literal root.
|
|
84
|
+
- **Existing folders** keep their place, wherever they were created. A feature is found by its folder name, not by its root.
|
|
85
|
+
- **Feature-root excludes**: git pathspec excludes for the feature folders. For each root, `':(exclude,glob)<root>'`, so `apps/*/docs/features` becomes `':(exclude,glob)apps/*/docs/features'`. Wherever this skill says "feature-root excludes", use one per root.
|
|
86
|
+
|
|
87
|
+
`job.json` records the chosen folder in `feature_dir`.
|
|
73
88
|
|
|
74
89
|
### job.json
|
|
75
90
|
|
|
@@ -86,6 +101,7 @@ factory/
|
|
|
86
101
|
"branch": "factory/001-onboarding-bootstrap",
|
|
87
102
|
"worktree": true,
|
|
88
103
|
"worktree_path": "/abs/path/to/repo-factory/001-onboarding-bootstrap",
|
|
104
|
+
"mr": null,
|
|
89
105
|
"failed_stage": null,
|
|
90
106
|
"stage": "awaiting-plan",
|
|
91
107
|
"round": 1,
|
|
@@ -105,10 +121,11 @@ factory/
|
|
|
105
121
|
- `tracker_errors`: failed ticket transitions or creations, as short strings. Reported, never blocking.
|
|
106
122
|
- `worktree`: `true` (default) builds in a git worktree. `false` builds in place in the main checkout (see In-place mode). Set when the job is created; changed only at the plan gate.
|
|
107
123
|
- `worktree_path`: absolute path of the job's worktree, or `null` for an in-place job and before the build starts.
|
|
124
|
+
- `mr`: URL of the merge or pull request opened in `push-mr` mode, or `null`. Set once; later approvals read its state (see Merge procedure).
|
|
108
125
|
- `failed_stage`: `spec` or `plan` when the job is `needs-human` because its spec or plan agent failed, else `null`. `/factory start` reruns that stage (see Start).
|
|
109
126
|
- `reviews` values are `pending`, `PASS`, or `CHANGES`.
|
|
110
127
|
|
|
111
|
-
Stages, in order: `spec` (spec-writer running), `awaiting-spec` (spec gate), `plan` (plan writer running), `awaiting-plan` (plan gate), `build`, `review`, `approve`, `awaiting-human`, `merged`, `needs-human`. `abandoned` is set by `/factory abandon`, from any open stage. Set `updatedAt` on every write. Use `date -u +%Y-%m-%dT%H:%M:%SZ`.
|
|
128
|
+
Stages, in order: `spec` (spec-writer running), `awaiting-spec` (spec gate), `plan` (plan writer running), `awaiting-plan` (plan gate), `build`, `review`, `approve`, `awaiting-human`, `merged`, `needs-human`. In `push-mr` mode, `awaiting-human` with `mr` set means the request is open on the forge and waiting for its merge. `abandoned` is set by `/factory abandon`, from any open stage. Set `updatedAt` on every write. Use `date -u +%Y-%m-%dT%H:%M:%SZ`.
|
|
112
129
|
|
|
113
130
|
A job is **closed** when its stage is `merged` or `abandoned`. Every other job is **open**, and every open-job check in this skill uses that definition. Closed jobs that `/factory archive` moved to `factory/archive/` are archived (see Archive). A job **holds its build location** when it is open and has reached the build: its stage is `build`, `review`, `approve`, or `awaiting-human`, or `needs-human` with `failed_stage` `null`. A worktree job holds a worktree, and an in-place job holds the main checkout, for as long as it holds its build location.
|
|
114
131
|
|
|
@@ -116,10 +133,11 @@ A job is **closed** when its stage is `merged` or `abandoned`. Every other job i
|
|
|
116
133
|
|
|
117
134
|
`/factory <request>` starts here. Intake writes nothing until its questions are answered, so the operator can answer before any folder, job, or spec exists.
|
|
118
135
|
|
|
119
|
-
1. **Analyze, read-only.** Read the project's `AGENTS.md`. List `
|
|
136
|
+
1. **Analyze, read-only.** Read the project's `AGENTS.md`. List every feature root in `{{FACTORY_FEATURE_PATHS}}` (a `*` root expands to the app folders that exist) and read the title and Summary of each `spec.md` whose name or text matches the request's keywords, looking for related or overlapping features. Skim the code the request touches with glob and grep, and note which app directories it sits in. Work out the feature folder the way Start steps 1 and 2 would, without creating anything.
|
|
120
137
|
2. **Ask only glaring questions.** Ask at most five, in chat, as a numbered list, then wait. Ask only when one of these holds:
|
|
121
138
|
- The scope is ambiguous: two readings lead to different specs.
|
|
122
|
-
- The request conflicts with or duplicates an existing feature in
|
|
139
|
+
- The request conflicts with or duplicates an existing feature in a feature root.
|
|
140
|
+
- A `*` root in `{{FACTORY_FEATURE_PATHS}}` applies, and the request's code sits in several apps or none, so the folder is not clear (see Feature folders). Ask which folder.
|
|
123
141
|
- The target user, page, or system is missing.
|
|
124
142
|
- No acceptance is implied: there is no way to tell when it is done.
|
|
125
143
|
|
|
@@ -143,8 +161,8 @@ Strip a leading `--in-place` first. It is a flag, not part of the argument. Then
|
|
|
143
161
|
|
|
144
162
|
1. No argument: ask for a request, key, slug, or job id.
|
|
145
163
|
2. A job id (`^\d{3,}-[a-z0-9-]+$`) with a folder at `factory/jobs/<id>/`: resume that job, or report that it is closed (see the resume table). A job id with a folder at `factory/archive/<id>/` is archived: say so and stop. Archived jobs are not resumable. To work on the feature again, `/factory start <slug or KEY>` creates a new job.
|
|
146
|
-
3. An issue key (`^[A-Z][A-Z0-9]+-\d+$`): match
|
|
147
|
-
4. A kebab slug (`^[a-z0-9]+(-[a-z0-9]+)*$`): match
|
|
164
|
+
3. An issue key (`^[A-Z][A-Z0-9]+-\d+$`): match `<root>/<KEY>-*/` in every feature root of the main checkout.
|
|
165
|
+
4. A kebab slug (`^[a-z0-9]+(-[a-z0-9]+)*$`): match `<root>/<slug>/` or `<root>/<KEY>-<slug>/` in every feature root, where `<KEY>` has the key format in step 3.
|
|
148
166
|
5. Anything else is a free-text request. Derive a 2–4 word kebab slug from it, then match as in step 4.
|
|
149
167
|
|
|
150
168
|
### 2. Resolve the feature folder
|
|
@@ -154,8 +172,8 @@ Whichever way the folder was found, the job's key is the `<KEY>` in its name (`P
|
|
|
154
172
|
- **One match:** continue that feature. Its existing `spec.md`, `plan.md`, and `tasks.md` are inputs to the spec writer.
|
|
155
173
|
- **Several matches:** list them and ask which one.
|
|
156
174
|
- **None:**
|
|
157
|
-
- From a key: read the ticket title through the [issue-tracker](../issue-tracker/SKILL.md) skill (MCP first, CLI fallback). Derive a kebab slug from the title (lowercase, non-alphanumerics to `-`, at most 4 words). Create
|
|
158
|
-
- From a slug or free text: create
|
|
175
|
+
- From a key: read the ticket title through the [issue-tracker](../issue-tracker/SKILL.md) skill (MCP first, CLI fallback). Derive a kebab slug from the title (lowercase, non-alphanumerics to `-`, at most 4 words). Create `<target>/<KEY>-<slug>/`, where `<target>` is the new-feature folder (see Feature folders). If the ticket cannot be read, stop and ask for a slug. Do not guess.
|
|
176
|
+
- From a slug or free text: create `<target>/<slug>/`, with the same `<target>`.
|
|
159
177
|
|
|
160
178
|
### 3. Resume or create the job
|
|
161
179
|
|
|
@@ -179,7 +197,7 @@ Resume by stage:
|
|
|
179
197
|
| `awaiting-human` | Print the approver's rationale, the suggested checks from `qa.md` (see QA guidance), and the `/factory approve` command |
|
|
180
198
|
| `needs-human`, `failed_stage` `spec` | Rerun the spec stage (see Spec), then show the spec gate |
|
|
181
199
|
| `needs-human`, `failed_stage` `plan` | Rerun the plan stage (see Plan), then show the plan gate |
|
|
182
|
-
| `needs-human`, otherwise | Print the reason from `decision.md`, `merge-conflict.md`, or `build.md`, and the options: rework, approve, or abandon |
|
|
200
|
+
| `needs-human`, otherwise | Print the reason from `decision.md`, `merge-conflict.md`, `bootstrap.md`, or `build.md`, and the options: rework, approve, or abandon |
|
|
183
201
|
| `abandoned` | Closed. Say so and stop. To work on the feature again, run `/factory start <slug or KEY>`, which creates a new job |
|
|
184
202
|
| Archived (in `factory/archive/`, any stage) | Closed. Say so and stop (see Start step 1) |
|
|
185
203
|
|
|
@@ -267,7 +285,7 @@ Runs once, after the operator confirms the plan and before the build location is
|
|
|
267
285
|
2. **Parent.** If `issue_key` is set, that ticket is the parent. Otherwise create the parent ticket. Set `issue_key` to its key.
|
|
268
286
|
3. **Sub-tasks.** Run the `/assign-tasks` flow on the feature's `tasks.md`, with the issue-tracker skill's epic discovery and the flow's consolidation rules. Create one ticket per `tasks.md` line that has no key yet, under the parent.
|
|
269
287
|
4. **Write keys.** Append ` — <KEY>` to each line as its ticket is created. Lines that already have a key are skipped.
|
|
270
|
-
5. **Rename.** If the folder had no key, rename
|
|
288
|
+
5. **Rename.** If the folder had no key, rename `<parent>/<slug>/` to `<parent>/<KEY>-<slug>/`, where `<parent>` is the feature root that holds it (the parent of `feature_dir`). Use `git mv` when git tracks the folder, `mv` otherwise. Stop if the target exists. Then update `feature_dir` in `job.json`. The rename is committed on the job branch with the feature docs (see Feature docs commit).
|
|
271
289
|
|
|
272
290
|
If a ticket cannot be created, stop at `awaiting-plan`. Report the lines that have keys and the error, and record it in `tracker_errors`. The operator can fix the cause and run `/factory start <job-id>`, or switch tracking to `none`.
|
|
273
291
|
|
|
@@ -278,14 +296,23 @@ The default build location. Use the [using-git-worktrees](../using-git-worktrees
|
|
|
278
296
|
- Branch `factory/<id>` from `{{DEFAULT_BRANCH}}`.
|
|
279
297
|
- Path `../<repo-name>-factory/<id>/` relative to the main checkout, where `<repo-name>` is the basename of the main checkout. Record it in `worktree_path`.
|
|
280
298
|
- Create it at the start of the build stage, after the plan gate and tracking. Reuse it if it exists (rework and repair).
|
|
281
|
-
- Copy the job's `spec.md`, `plan.md`, and `tasks.md` (if any) from the main checkout's feature folder into the same relative path in the worktree. The builder ticks `tasks.md` there. Then make the feature docs commit
|
|
299
|
+
- Copy the job's `spec.md`, `plan.md`, and `tasks.md` (if any) from the main checkout's feature folder into the same relative path in the worktree. The builder ticks `tasks.md` there. Then run the bootstrap (next subsection) and make the feature docs commit.
|
|
282
300
|
- Job state stays in the main checkout's `factory/jobs/<id>/`, never in the worktree.
|
|
283
301
|
|
|
302
|
+
### Worktree bootstrap
|
|
303
|
+
|
|
304
|
+
Each new worktree needs its own setup: dependencies or vendored packages, local env files, and a database for the job. The project lists those steps in `factory/worktree-bootstrap.md`, one shell command per line, in order. Comment lines are notes, and the default file has no active steps. The project edits the file; this skill only runs it.
|
|
305
|
+
|
|
306
|
+
- Run each step from the worktree root, after the copy above and before the feature docs commit. A reused worktree (rework, repair) reruns the steps, so they must be safe to run again.
|
|
307
|
+
- Each step gets these variables: `FACTORY_JOB_ID` (the job id, for names such as a per-job database), `FACTORY_PORT_BUILDER` (the builder's dev-server port), `FACTORY_WORKTREE` (the worktree path), and `FACTORY_MAIN_CHECKOUT` (the main checkout, where ignored local files such as `.env` live).
|
|
308
|
+
- A step that fails stops the build before the builder is dispatched. Write `bootstrap.md` in the job folder with the step, its exit code, and the last lines of its output; set stage `needs-human`. The worktree stays. The operator fixes the cause, then runs `/factory rework <id>`, which reruns the bootstrap before the builder. Delete `bootstrap.md` once every step passes.
|
|
309
|
+
- In-place builds do not bootstrap. The main checkout is the environment, so run the steps by hand there if it lacks them.
|
|
310
|
+
|
|
284
311
|
## Feature docs commit
|
|
285
312
|
|
|
286
313
|
Runs once the job's branch exists, in its build location (the worktree, or the main checkout for an in-place job), before the builder is dispatched. It puts the job's feature docs on the branch, so the main checkout can stay clean and the merge carries them:
|
|
287
314
|
|
|
288
|
-
1. Remove the old unkeyed folder when the feature folder was renamed to its keyed name: `git rm -r -q --ignore-unmatch --
|
|
315
|
+
1. Remove the old unkeyed folder when the feature folder was renamed to its keyed name: `git rm -r -q --ignore-unmatch -- <parent>/<slug>`, where `<parent>` is the parent of `feature_dir`. Skip it when `feature_dir` is `<parent>/<slug>`.
|
|
289
316
|
2. `git add -A -- <feature_dir>`.
|
|
290
317
|
3. `git diff --cached --quiet || git commit -q -m "docs: feature docs for <id>"`. Nothing is committed when nothing is staged.
|
|
291
318
|
|
|
@@ -298,7 +325,7 @@ Used only when `worktree` is `false`: the operator asked for it with `--in-place
|
|
|
298
325
|
Create the branch at build start, after the plan gate and tracking, only when all four checks pass. If one fails, stay at `awaiting-plan` and tell the operator which one:
|
|
299
326
|
|
|
300
327
|
- The main checkout is on `{{DEFAULT_BRANCH}}`.
|
|
301
|
-
- `git status --porcelain --untracked-files=no -- .
|
|
328
|
+
- `git status --porcelain --untracked-files=no -- . <feature-root excludes>` is empty. The feature docs are excluded because the spec writer and tracking write there, and the feature docs commit carries them onto the branch.
|
|
302
329
|
- No other job with `worktree` `false` is open (not `merged` or `abandoned`).
|
|
303
330
|
- No job with `worktree` `true` holds its build location.
|
|
304
331
|
|
|
@@ -394,8 +421,9 @@ Tickets follow the job. The parent and every sub-task listed in `tasks.md` move
|
|
|
394
421
|
| --- | --- |
|
|
395
422
|
| Build starts, including rework | In Progress |
|
|
396
423
|
| Review round starts | In Review |
|
|
397
|
-
|
|
|
424
|
+
| The merge completes: the local merge, or in `push-mr` the finish step after the forge merged the request (`/factory approve`) | Done |
|
|
398
425
|
| `/factory approve` on a `merged` job (for example after `auto` merged it) | Done |
|
|
426
|
+
| `push-mr` opens or updates the request | In Review (no change) |
|
|
399
427
|
| `/factory abandon` | Left as they are. The report lists their keys |
|
|
400
428
|
|
|
401
429
|
Rules:
|
|
@@ -419,7 +447,7 @@ Rules:
|
|
|
419
447
|
<the user's note, verbatim>
|
|
420
448
|
```
|
|
421
449
|
|
|
422
|
-
4. Set `round` to `N`, stage `build`. Move tracked tickets to In Progress. For an in-place job, switch the main checkout to `factory/<id>` if needed (see In-place mode). Dispatch a fresh `factory-builder` in rework mode. It reads the latest `rework-<k>.md` and rewrites `qa.md`. Wait for it. Then continue from step 6's status check on `build.md` (do not dispatch the builder again), and run review round `N` from step 7.
|
|
450
|
+
4. Set `round` to `N`, stage `build`. Move tracked tickets to In Progress. For an in-place job, switch the main checkout to `factory/<id>` if needed (see In-place mode). For a worktree job, rerun the bootstrap first (see Worktree bootstrap); a failed step stops the rework the way it stops a build. Dispatch a fresh `factory-builder` in rework mode. It reads the latest `rework-<k>.md` and rewrites `qa.md`. Wait for it. Then continue from step 6's status check on `build.md` (do not dispatch the builder again), and run review round `N` from step 7.
|
|
423
451
|
|
|
424
452
|
The new cycle starts with a fresh repair budget. Old rounds and reviews are kept, not overwritten.
|
|
425
453
|
|
|
@@ -448,11 +476,11 @@ Rules:
|
|
|
448
476
|
3. Refuse unless the first line of `build.md` is exactly `STATUS: READY`. A job that failed before its build has no `build.md`: say so, and point to `/factory start <job-id>` (for a failed spec or plan step) or `/factory abandon <job-id>`.
|
|
449
477
|
4. Refuse while `merge-conflict.md` exists in the job folder. The user resolves the conflict on the branch, then removes that file.
|
|
450
478
|
5. Print the reason the job stopped before merging, so the user sees what they approve: the `ESCALATE` rationale in `decision.md`, the `Not verified` items, or the failed agent. For `awaiting-human`, print the approver's rationale.
|
|
451
|
-
6. Run the merge procedure.
|
|
479
|
+
6. Run the merge procedure for `{{MERGE_MODE}}`. In `push-mr`, a job with `mr` set takes the finish path there instead.
|
|
452
480
|
|
|
453
481
|
## Abandon
|
|
454
482
|
|
|
455
|
-
`/factory abandon <job-id>` closes a job that will not continue, such as one stopped before its build or one the operator no longer wants. It merges nothing and pushes nothing.
|
|
483
|
+
`/factory abandon <job-id>` closes a job that will not continue, such as one stopped before its build or one the operator no longer wants. It merges nothing and pushes nothing. If the job has `mr` set, the report gives its URL: abandon does not close the request, so the operator closes it on the forge.
|
|
456
484
|
|
|
457
485
|
1. Refuse if the stage is already `merged` or `abandoned`. If an agent for the job may still be running (stage `spec`, `plan`, `build`, `review`, or `approve`), confirm with the operator in chat first, because the agent may still write its file.
|
|
458
486
|
2. Set stage `abandoned`, `failed_stage` `null`, and `updatedAt`.
|
|
@@ -466,11 +494,15 @@ Rules:
|
|
|
466
494
|
|
|
467
495
|
## Merge procedure
|
|
468
496
|
|
|
497
|
+
Mode: `{{MERGE_MODE}}`. Exactly `push-mr` runs the forge procedure, after the local merge below. Any other value runs the local merge, the default and the only mode that never pushes.
|
|
498
|
+
|
|
499
|
+
### Local merge
|
|
500
|
+
|
|
469
501
|
Local only. **Never push.** Never force-delete a branch or worktree.
|
|
470
502
|
|
|
471
|
-
1. **Preconditions.** Worktree jobs: the main checkout is on `{{DEFAULT_BRANCH}}`. In-place jobs: the main checkout is on `factory/<id>`. For both, `git status --porcelain --untracked-files=no -- .
|
|
503
|
+
1. **Preconditions.** Worktree jobs: the main checkout is on `{{DEFAULT_BRANCH}}`. In-place jobs: the main checkout is on `factory/<id>`. For both, `git status --porcelain --untracked-files=no -- . <feature-root excludes>` is empty. Feature docs are excluded here, through the feature-root excludes, because step 3 reconciles them. Untracked files, including ignored `factory/jobs/**`, do not block. Worktree jobs also stop while another in-place job holds its build location (see Stages). Say which job it is: "In-place job `<id>` holds the main checkout; approve or abandon it first." If a precondition fails, stop and tell the user. Do not change the stage. For an in-place job, once the checks pass, run `git switch {{DEFAULT_BRANCH}}`. The branch stays in place.
|
|
472
504
|
2. Record `PRE=$(git rev-parse HEAD)`.
|
|
473
|
-
3. **Feature docs.** The branch already carries the job's feature docs (see Feature docs commit), so the main checkout's copies are set aside and its feature paths return to the `{{DEFAULT_BRANCH}}` state. Let `P` be `<feature_dir>`, plus
|
|
505
|
+
3. **Feature docs.** The branch already carries the job's feature docs (see Feature docs commit), so the main checkout's copies are set aside and its feature paths return to the `{{DEFAULT_BRANCH}}` state. Let `P` be `<feature_dir>`, plus `<parent>/<slug>` (the parent of `feature_dir`) when that differs:
|
|
474
506
|
- Copy each path that `git status --porcelain --untracked-files=all -- <P>` lists into `factory/jobs/<id>/main-copies/`, keeping its path. For a rename, copy the new path. Skip paths that no longer exist.
|
|
475
507
|
- `git reset -q -- <P>`, then `git clean -fdq -- <P>`. This removes only the untracked copies made above.
|
|
476
508
|
- If `git ls-tree -r --name-only {{DEFAULT_BRANCH}} -- <P>` lists files, `git checkout -- <P>` restores them.
|
|
@@ -483,6 +515,24 @@ Local only. **Never push.** Never force-delete a branch or worktree.
|
|
|
483
515
|
|
|
484
516
|
On any `needs-human` outcome, leave the branch and worktree in place so the user can inspect them.
|
|
485
517
|
|
|
518
|
+
### Push and merge request (`push-mr`)
|
|
519
|
+
|
|
520
|
+
Runs in place of the local merge, when `{{MERGE_MODE}}` is `push-mr` and the approval is an `/factory approve` or an `auto` APPROVE. It pushes the branch and opens one merge request (GitLab) or pull request (GitHub). The forge's review and merge are the final gate, so nothing merges locally, the main checkout is not touched, and force-push is never used.
|
|
521
|
+
|
|
522
|
+
1. **Forge and preconditions.** Pick the forge from `git remote get-url origin`: a GitHub host uses `gh`, a GitLab host uses `glab`. Stop and tell the operator if that CLI is missing or its auth check fails (`gh auth status` or `glab auth status`). The build location must have no tracked changes: `git -C <build location> status --porcelain --untracked-files=no` is empty. Do not change the stage on a failed precondition.
|
|
523
|
+
2. **Test gate.** Run the test commands of the local merge, step 5, in the build location on the branch, before any push. A failure sets stage `needs-human`, reports the output, and pushes nothing.
|
|
524
|
+
3. **Push.** `git -C <build location> push -u origin factory/<id>`. A rejected push stops here: set stage `needs-human` and report the message. Do not force.
|
|
525
|
+
4. **Open the request, once.** Skip this step when `mr` is already set. Otherwise:
|
|
526
|
+
- GitHub: `gh pr create --base {{DEFAULT_BRANCH}} --head factory/<id> --title "<feature>" --body-file <job folder>/decision.md`
|
|
527
|
+
- GitLab: `glab mr create --source-branch factory/<id> --target-branch {{DEFAULT_BRANCH}} --title "<feature>" --description-file <job folder>/decision.md --yes`
|
|
528
|
+
|
|
529
|
+
Record the URL the command prints in `mr`. A failed command sets stage `needs-human` and reports the error. Nothing is recorded, and rerunning approve retries from step 1.
|
|
530
|
+
5. **Stage.** Set stage `awaiting-human`. Tickets stay In Review. Print the request URL and say: "Review and merge it on the forge, then run `/factory approve <id>` to finish." Under `auto`, the same message applies: the forge merge stays the human gate.
|
|
531
|
+
6. **Finish (`/factory approve` with `mr` set).** Run `git fetch origin`, then read the request's state: `gh pr view <mr> --json state --jq .state`, or `glab mr view <mr> --output json` and its `state` field. If the CLI's flags differ, check its `--help` first.
|
|
532
|
+
- **Merged:** a worktree job runs `git worktree remove <worktree_path>`. An in-place job runs `git switch {{DEFAULT_BRANCH}}` in the main checkout when it is on `factory/<id>`. Then `git branch -D factory/<id>`. This is the one place the local merge's `-d` rule does not apply: `-d` refuses after a squash merge, and the forge's merge is the proof. If the removal fails, keep what remains and report the path. Then set the main checkout's feature copies aside with local merge step 3, so the default branch's merged docs can arrive on pull, and tell the operator to pull `{{DEFAULT_BRANCH}}`. Set stage `merged`, move tickets to Done (if tracked), and report.
|
|
533
|
+
- **Open:** if `git rev-parse factory/<id>` differs from `git rev-parse origin/factory/<id>`, the job has commits the request lacks (for example after a rework). Run steps 2 and 3 to update it, and report that the request was updated. Otherwise report that it is still open, and stop. Nothing else changes.
|
|
534
|
+
- **Closed without merge:** keep stage `awaiting-human`, report it, and offer rework, reopening the request on the forge, or abandon.
|
|
535
|
+
|
|
486
536
|
## Status
|
|
487
537
|
|
|
488
538
|
Read each `factory/jobs/*/job.json`. Print one row per open job: id, stage, round, reviews, issue key, size, tracking, updatedAt, and the next action for that stage. Write nothing.
|
|
@@ -496,7 +546,7 @@ Closed jobs (`merged` or `abandoned`) are hidden by default. Print one line in t
|
|
|
496
546
|
| `plan` | Wait, or `/factory start <id>` to resume if the session ended |
|
|
497
547
|
| `awaiting-plan` | `/factory start <id>` to review the plan and confirm it |
|
|
498
548
|
| `build`, `review`, `approve` | Wait, or `/factory start <id>` to resume if the session ended |
|
|
499
|
-
| `awaiting-human` | Review the branch and its `qa.md` (suggested checks, not a gate), then `/factory approve <id>` |
|
|
549
|
+
| `awaiting-human` | Review the branch and its `qa.md` (suggested checks, not a gate), then `/factory approve <id>`. In `push-mr` with `mr` set: merge the request on the forge, then `/factory approve <id>` to finish. Print the request URL |
|
|
500
550
|
| `needs-human` | Read the reason. A failed spec or plan step: `/factory start <id>` reruns it. After a build: `/factory rework <id> <note>` or `/factory approve <id>`. Either way, `/factory abandon <id>` closes the job |
|
|
501
551
|
| `abandoned` | Nothing: the job is closed. To work on the feature again, `/factory start <slug or KEY>` creates a new job |
|
|
502
552
|
| `merged` | Nothing, unless tickets are not Done yet: `/factory approve <id>` |
|
|
@@ -533,7 +583,7 @@ The live view needs an interactive terminal, which agent shells do not have, so
|
|
|
533
583
|
|
|
534
584
|
## Prune
|
|
535
585
|
|
|
536
|
-
`/factory prune [--all] [--abandoned] [--dry-run]` permanently deletes closed jobs from both `factory/jobs/` and `factory/archive/`. By default only `merged` jobs are deleted. `--abandoned` also deletes `abandoned` jobs. A pruned job cannot be recovered. It never deletes an open job, and it never touches
|
|
586
|
+
`/factory prune [--all] [--abandoned] [--dry-run]` permanently deletes closed jobs from both `factory/jobs/` and `factory/archive/`. By default only `merged` jobs are deleted. `--abandoned` also deletes `abandoned` jobs. A pruned job cannot be recovered. It never deletes an open job, and it never touches a feature folder.
|
|
537
587
|
|
|
538
588
|
The age rule is the same as Archive: by default only jobs whose `updatedAt` is more than 7 days ago, and `--all` drops the age limit. A job with no valid `updatedAt` is not selected. `--abandoned` adds `abandoned` jobs under the same rule. Without it, abandoned jobs are never selected, and the list counts the ones it kept.
|
|
539
589
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: "Run an opt-in factory job: intake, spec and plan gates, build in a worktree or in place, reviews, approval, local merge"
|
|
2
|
+
description: "Run an opt-in factory job: intake, spec and plan gates, build in a worktree or in place, reviews, approval, merge (local, or a merge request on the forge)"
|
|
3
3
|
allowed-tools: "Read, Grep, Glob, Write, Edit, Bash(*), agent"
|
|
4
4
|
argument-hint: "[--in-place] <feature request> | start [--in-place] <request | KEY | slug | job-id> | approve <job-id> | rework <job-id> <note> | abandon <job-id> | status [--all] | watch [--all] | archive [--all] [--dry-run] | prune [--all] [--abandoned] [--dry-run]"
|
|
5
5
|
---
|
|
@@ -50,11 +50,17 @@ When interacting with {{ISSUE_TRACKER}}, use MCP tools first (see the `issue-tra
|
|
|
50
50
|
1. **Parse Document**:
|
|
51
51
|
- Load the specified document (.md, .txt, .json)
|
|
52
52
|
- Detect document structure (headers, lists, task categories)
|
|
53
|
-
- For `tasks.md
|
|
53
|
+
- For `tasks.md`, detect the format first:
|
|
54
|
+
- **Slim** (has `- [ ] T<n>` or `- [x] T<n>` lines): each such line is one task. The text after the ID is the summary. Sub-bullets, if any, are subtasks. A line already has a ticket only when it ends with ` — {{PROJECT_KEY}}-<digits>`; skip it then. Any other ` — ` suffix (e.g. ` — depends on T3`) is a note, not a key: keep the line
|
|
55
|
+
- **Legacy** (no slim lines; has `#{2,4} T<n>` headings, e.g. `## T01`, `### T001`): each `T<n>` heading is one task. Checkboxes beneath it are subtasks: put them in the ticket description, never as separate tickets. Skip a heading that contains `{{PROJECT_KEY}}-<digits>` anywhere (e.g. `## T001 (PROJ-256): …`); it already has a ticket
|
|
56
|
+
- **Mixed** (slim lines and legacy headings): treat as slim and say in the report that the headings were ignored
|
|
57
|
+
- **Neither**: treat as a requirement document
|
|
58
|
+
- Keys are always `{{PROJECT_KEY}}-<digits>`. Nothing else counts as a key
|
|
54
59
|
- For requirement documents: extract task hierarchy: Epic → Story → Task → Subtask
|
|
55
60
|
|
|
56
61
|
2. **Consolidate First** (BEFORE creating tickets):
|
|
57
|
-
- **A `tasks.md` from `/tasks` is pre-consolidated**: one line = one ticket. Only merge lines that are clearly one deliverable; do not re-split them
|
|
62
|
+
- **A slim `tasks.md` from `/tasks` is pre-consolidated**: one line = one ticket. Only merge lines that are clearly one deliverable; do not re-split them
|
|
63
|
+
- **A legacy `tasks.md` is not pre-consolidated**: one heading = one ticket. Never merge or re-split headings. If the count exceeds the Maximum Ticket Counts, stop and ask before creating anything
|
|
58
64
|
- **Group related items** by component, feature area, or deliverable
|
|
59
65
|
- **Merge small tasks** (< 2 SP) into related larger tasks
|
|
60
66
|
- **Eliminate redundant subtasks** that are obvious steps
|
|
@@ -79,10 +85,12 @@ When interacting with {{ISSUE_TRACKER}}, use MCP tools first (see the `issue-tra
|
|
|
79
85
|
- Set assignees, labels, and story points
|
|
80
86
|
- Create dependency links where noted
|
|
81
87
|
- Ticket description: the task summary plus the acceptance criteria from `spec.md` for that deliverable
|
|
82
|
-
-
|
|
88
|
+
- **Slim `tasks.md`**: append ` — <KEY>` at the end of the task's line, after any notes (`- [ ] T1 Schema + migration — PROJ-124`)
|
|
89
|
+
- **Legacy `tasks.md`**: never write back. Record heading → ticket key in the report instead
|
|
83
90
|
|
|
84
91
|
6. **Generate Report**:
|
|
85
92
|
- List all created tickets with IDs
|
|
93
|
+
- **Legacy `tasks.md`**: heading → ticket key mapping, plus headings skipped because they already had a key
|
|
86
94
|
- Show hierarchy and relationships
|
|
87
95
|
- Report total story points
|
|
88
96
|
- **Consolidation summary**: "Merged X raw items into Y tickets"
|
|
@@ -153,6 +161,8 @@ Creating tickets...
|
|
|
153
161
|
|
|
154
162
|
## Document Format Support
|
|
155
163
|
|
|
164
|
+
**Legacy `tasks.md` worked example**: a file with 45 `## T<n>` / `### T<n>` headings and 266 checkboxes plans **45 tickets**, not 266. Each ticket's description lists that heading's checkboxes. If 2 headings already carry a `{{PROJECT_KEY}}-<digits>` key, plan 43. Do not modify the file; report the heading → key mapping.
|
|
165
|
+
|
|
156
166
|
**Markdown Headers**:
|
|
157
167
|
|
|
158
168
|
```markdown
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# Bootstrap Patch
|
|
2
2
|
|
|
3
|
-
Fetch
|
|
3
|
+
Fetch the published toolkit templates for the target version (4.0.0 or later) from npm or the ai-assisted-dev-toolkit repository's `<version>` git tag, and merge updated, new, or missing guidance into this project.
|
|
4
4
|
|
|
5
5
|
## OpenCode version preflight (before any changes)
|
|
6
6
|
|
|
7
7
|
- Confirm OpenCode use from actual session/runtime evidence or ask the user; directory presence alone is not proof. If only other harnesses are used, skip this preflight and all OpenCode steps.
|
|
8
|
-
- For confirmed OpenCode use, run `opencode --version` before any project writes. Trim output and parse numeric major/minor/patch components, accepting an optional leading `v`; toolkit 4.
|
|
9
|
-
- If OpenCode V1 (`major < 2`) is detected, **STOP** before customizing/migrating OpenCode files or writing `.toolkit-version` as
|
|
8
|
+
- For confirmed OpenCode use, run `opencode --version` before any project writes. Trim output and parse numeric major/minor/patch components, accepting an optional leading `v`; toolkit 4.0.0 and later require `major >= 2`.
|
|
9
|
+
- If OpenCode V1 (`major < 2`) is detected, **STOP** before customizing/migrating OpenCode files or writing `.toolkit-version` as 4.0.0 or later. Ask the user to upgrade OpenCode to V2 or remain on toolkit 3.x.
|
|
10
10
|
- If the CLI is missing, fails, or output is unparseable, **STOP OpenCode steps** and leave the version marker unchanged; ask the user to confirm/install a supported OpenCode version, then rerun this check. Never assume V2.
|
|
11
11
|
- If oh-my-opencode-slim >=3.0.0 is used or planned, require OpenCode >=2.0.7 (compare version components numerically); otherwise **STOP** before changes and ask to upgrade. Proceed only after this gate passes.
|
|
12
12
|
|
|
@@ -25,6 +25,8 @@ Fetch supported toolkit v4.x templates from the ai-assisted-dev-toolkit reposito
|
|
|
25
25
|
/bootstrap-patch --category commands,prompts
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
The CLI runs the same patch flow without an AI session: `npx nitm-ai-dev-toolkit patch --dry-run` previews changes, `--only <categories>` and `--exclude <categories>` narrow the scope, and `npx nitm-ai-dev-toolkit upgrade@<version>` (or `--version <version>`) pins the target version. Pinning a version does not skip the gates in Step 1.
|
|
29
|
+
|
|
28
30
|
## Process
|
|
29
31
|
|
|
30
32
|
**Codex invocation and scope:** `/bootstrap-patch` is not a native Codex command. Ask Codex to read and follow this snippet as a task document. Identify the actual harness from session/runtime evidence or ask; scaffold directories do not prove use. Codex targets `AGENTS.md`, relevant nested instructions, `.agents/skills/`, and optional `.codex/config.toml`. Include `.github/instructions/` and `.claude/rules-snippets/` solely as AGENTS-linked standards and their wrapper sources for Codex-scoped installs, not automatically loaded rules or evidence of Copilot/Claude use. Only include other harness command, agent, and config categories when those harnesses are confirmed in use.
|
|
@@ -33,33 +35,38 @@ Fetch supported toolkit v4.x templates from the ai-assisted-dev-toolkit reposito
|
|
|
33
35
|
|
|
34
36
|
1. **Fetch Latest Templates**:
|
|
35
37
|
|
|
36
|
-
|
|
38
|
+
**Resolve versions before any download.**
|
|
39
|
+
- **Installed version**: read `.toolkit-version` in the project root. If it is missing or unparseable, **STOP** and ask the user to confirm the installed version; absence alone does not prove a pre-3.0 installation.
|
|
40
|
+
- **Target version**: use the version the user pinned (`upgrade@<version>` or `--version <version>` in the CLI, or the version given to this task), validated as SemVer `X.Y.Z`. Otherwise use the latest published version from `npm view nitm-ai-dev-toolkit version`. If npm is unreachable or the output is unparseable, **STOP** and ask. Never guess a version.
|
|
41
|
+
|
|
42
|
+
**Fetch the matching release.** Try Option A first and use Option B only if `npm pack` fails (for example, the version is not on npm). Each download goes into a new, empty directory:
|
|
37
43
|
|
|
38
44
|
```bash
|
|
39
45
|
set -e
|
|
40
|
-
TOOLKIT_TEMP=$(mktemp -d)
|
|
41
|
-
|
|
46
|
+
TOOLKIT_TEMP=$(mktemp -d) # removed in step 6
|
|
47
|
+
mkdir "$TOOLKIT_TEMP/pack" "$TOOLKIT_TEMP/unpacked"
|
|
48
|
+
# Option A (preferred): the published package, the same artifact users install
|
|
49
|
+
if (cd "$TOOLKIT_TEMP/pack" && npm pack "nitm-ai-dev-toolkit@<version>"); then
|
|
50
|
+
tar -xzf "$TOOLKIT_TEMP/pack/nitm-ai-dev-toolkit-<version>.tgz" -C "$TOOLKIT_TEMP/unpacked"
|
|
51
|
+
SOURCE_ROOT="$TOOLKIT_TEMP/unpacked/package"
|
|
52
|
+
else
|
|
53
|
+
# Option B (fallback): the git tag for that release (tags have no "v" prefix)
|
|
54
|
+
git clone --depth 1 --branch "<version>" https://github.com/ninjasitm/ai-assisted-dev-toolkit.git "$TOOLKIT_TEMP/git"
|
|
55
|
+
SOURCE_ROOT="$TOOLKIT_TEMP/git"
|
|
56
|
+
fi
|
|
42
57
|
```
|
|
43
58
|
|
|
44
|
-
**Source availability gate:** If the clone
|
|
59
|
+
**Source availability gate:** If both `npm pack` and the tag clone fail (the version is unpublished and the tag is missing), **STOP** before diff/apply/version marking. Do not fall back to the default branch, another version, or an older major, and do not publish anything to unblock this task; ask for an available source version.
|
|
45
60
|
|
|
46
|
-
Determine the correct source path based on project structure
|
|
47
|
-
- **Single repo**:
|
|
48
|
-
- **Monorepo**:
|
|
61
|
+
Determine the correct source path based on project structure, under `$SOURCE_ROOT`:
|
|
62
|
+
- **Single repo**: `$SOURCE_ROOT/src/repo/`
|
|
63
|
+
- **Monorepo**: `$SOURCE_ROOT/src/monorepo/`
|
|
49
64
|
|
|
50
65
|
Detection heuristic:
|
|
51
66
|
- If `apps/` and `packages/` directories exist at root → monorepo
|
|
52
67
|
- Otherwise → single repo
|
|
53
68
|
|
|
54
|
-
**
|
|
55
|
-
|
|
56
|
-
Check for a `.toolkit-version` file in the project root:
|
|
57
|
-
- If exists: Read the version string (e.g., `2.0.10`, `3.0.0`)
|
|
58
|
-
- If missing: Verify the installed version or legacy state with the user; absence alone does not prove a pre-3.0 installation
|
|
59
|
-
|
|
60
|
-
Read the toolkit's version from the `version` field in `$TOOLKIT_TEMP/package.json` to compare; `.toolkit-version` tracks the target project's installed version.
|
|
61
|
-
|
|
62
|
-
**Source version guard (before diff/apply/version marking):** Parse source/target versions as SemVer and compare them (major/minor/patch numerically). If the fetched package's major is not `4`, or its version is older than the target `.toolkit-version`, **STOP** without diffing, applying changes, or updating the marker. Unknown/unparseable versions must also **STOP** and ask rather than guess. Never auto-downgrade.
|
|
69
|
+
**Source version gate (before diff/apply/version marking):** Read the `version` field in `$SOURCE_ROOT/package.json` and parse it as SemVer. The fetched version must equal the target version exactly, its major must be greater than or equal to the installed major from `.toolkit-version`, and it must not be older than the installed `.toolkit-version`. If any check fails, or a version is unknown or unparseable, **STOP** without diffing, applying changes, or updating the marker. Never auto-downgrade, and never hard-code a major.
|
|
63
70
|
|
|
64
71
|
**Version Comparison:**
|
|
65
72
|
- **Same version**: No structural changes expected
|
|
@@ -102,9 +109,9 @@ Fetch supported toolkit v4.x templates from the ai-assisted-dev-toolkit reposito
|
|
|
102
109
|
|
|
103
110
|
- Use `agents`/`system`, `request.body.temperature`, ordered `permissions` (`action`/`resource`/`effect`, `shell`/`subagent`, last match wins), `commands`/`subagent`, `plugins` with `{ "package": "…", "options": {} }`, skill-directory arrays, and `mcp.servers` with inverse `disabled` and `timeout.catalog`/`timeout.execution`.
|
|
104
111
|
- The version preflight must pass before changes. Back up V1 before native conversion (converted files are incompatible with V1). Preserve models/providers/user-global plugins. Only with approval, merge `"plugins": ["oh-my-opencode-slim@3.0.0"]` locally. Slim's separate strict schema keeps `prompt`/`permission`/`variant`; do not host-migrate it or silently upgrade the separate external starter.
|
|
105
|
-
- **Ponytail
|
|
106
|
-
- `instructions` entries
|
|
107
|
-
- `--env opencode` supplies minimal shared references without other harness activation. Activate on the next run/restart and report only installed-V2 checks actually run, not assumed runtime validation.
|
|
112
|
+
- **Obsolete Ponytail cleanup (plan here; apply after backup and approval in Step 5):** Remove only known obsolete toolkit-owned `.opencode/plugins/ponytail.js`, `.opencode/plugins/ponytail.mjs`, and `.opencode/plugins/ponytail.ts` copies. Preserve unrelated local plugins. The OpenCode Ponytail plugin is installed globally by the operator; never add it to project config. If it is not installed globally, tell the operator to install it globally. Do not edit global config. Keep `opentmux` commented as V1-only. Do not port local APIs or add bridges; runtime integration is untested.
|
|
113
|
+
- Ambient `AGENTS.md` works. `instructions` entries load only when the runtime injects them (OpenChamber does; other hosts may not), so do not rely on them: write explicit "Read and follow" wrappers regardless. `@refs` are ordinary text: explicitly read snippets. `request.body.temperature` remains in config, but the current runner does not send it. Preserve `lsp: true`; use project lint/typecheck/compiler commands (no V2 LSP tools/diagnostics currently).
|
|
114
|
+
- `--env opencode` supplies minimal shared references without other harness activation. Activate on the next run/restart and report only installed-V2 checks actually run, not assumed runtime validation.
|
|
108
115
|
|
|
109
116
|
3. **Diff Analysis** (parallelizable — dispatch one subagent per category):
|
|
110
117
|
|
|
@@ -175,8 +182,8 @@ Fetch supported toolkit v4.x templates from the ai-assisted-dev-toolkit reposito
|
|
|
175
182
|
a. **New files**: Copy directly from template
|
|
176
183
|
b. **Updated files (no customization)**: Replace with template version
|
|
177
184
|
c. **Updated files (customized)**: Apply structural additions while preserving project values
|
|
178
|
-
d. **OpenCode plugins**: Apply only the approved Ponytail
|
|
179
|
-
e. **Toolkit version**:
|
|
185
|
+
d. **OpenCode plugins**: Apply only the approved obsolete Ponytail cleanup above after backing up the known obsolete toolkit copies and local config; preserve all unrelated local/global plugins. Never add Ponytail to project config.
|
|
186
|
+
e. **Toolkit version**: Keep the `.toolkit-version` value the CLI writes for the verified target version (the installed package version, 4.0.0 or later; never hard-coded) only after the approved migration and OpenCode preflight pass (or OpenCode is confirmed out of scope).
|
|
180
187
|
f. **Git commit**: Stage and commit all changes with message:
|
|
181
188
|
```bash
|
|
182
189
|
git add -A
|