@stdd/plugin 0.9.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 (80) hide show
  1. package/.claude-plugin/plugin.json +9 -0
  2. package/.codex-plugin/plugin.json +21 -0
  3. package/LICENSE +21 -0
  4. package/README.md +47 -0
  5. package/extensions/stdd.mjs +77 -0
  6. package/hooks/claude-hooks.json +28 -0
  7. package/hooks/codex-hooks.json +28 -0
  8. package/package.json +38 -0
  9. package/runtime/adapters/README.md +158 -0
  10. package/runtime/cli/check.mjs +555 -0
  11. package/runtime/cli/ci.mjs +190 -0
  12. package/runtime/cli/claude-hooks.mjs +689 -0
  13. package/runtime/cli/config.mjs +27 -0
  14. package/runtime/cli/evidence.mjs +249 -0
  15. package/runtime/cli/generated-files.mjs +1693 -0
  16. package/runtime/cli/held-fs.mjs +415 -0
  17. package/runtime/cli/init.mjs +883 -0
  18. package/runtime/cli/ledger.mjs +1470 -0
  19. package/runtime/cli/lib.mjs +909 -0
  20. package/runtime/cli/path-bytes.mjs +83 -0
  21. package/runtime/cli/policy.mjs +112 -0
  22. package/runtime/cli/recorders.mjs +188 -0
  23. package/runtime/cli/review-fs.mjs +825 -0
  24. package/runtime/cli/review.mjs +1065 -0
  25. package/runtime/cli/runtime.mjs +32 -0
  26. package/runtime/cli/scope.mjs +185 -0
  27. package/runtime/cli/snapshot.mjs +897 -0
  28. package/runtime/cli/state-validation.mjs +168 -0
  29. package/runtime/cli/status.mjs +580 -0
  30. package/runtime/cli/stdd.mjs +536 -0
  31. package/runtime/cli/worker-fs.mjs +971 -0
  32. package/runtime/cli/worker-metadata.mjs +139 -0
  33. package/runtime/cli/worker.mjs +779 -0
  34. package/runtime/method/README.md +634 -0
  35. package/runtime/method/reference-commands.md +147 -0
  36. package/runtime/method/reference-generated-state.md +151 -0
  37. package/runtime/method/reference-integration.md +233 -0
  38. package/runtime/package.json +65 -0
  39. package/runtime/playbooks/brainstorming.md +46 -0
  40. package/runtime/playbooks/debugging.md +36 -0
  41. package/runtime/playbooks/delegate-slice.md +129 -0
  42. package/runtime/playbooks/finish-change.md +46 -0
  43. package/runtime/playbooks/implement.md +26 -0
  44. package/runtime/playbooks/investigation.md +33 -0
  45. package/runtime/playbooks/managed-playbooks.json +14 -0
  46. package/runtime/playbooks/planning.md +177 -0
  47. package/runtime/playbooks/pr-green.md +50 -0
  48. package/runtime/playbooks/start-change.md +37 -0
  49. package/runtime/playbooks/worktrees.md +45 -0
  50. package/runtime/prebuilds/stdd-fs/darwin-arm64/stdd-fs +0 -0
  51. package/runtime/prebuilds/stdd-fs/darwin-x64/stdd-fs +0 -0
  52. package/runtime/prebuilds/stdd-fs/linux-arm64/stdd-fs +0 -0
  53. package/runtime/prebuilds/stdd-fs/linux-x64/stdd-fs +0 -0
  54. package/runtime/prebuilds/stdd-fs/manifest.json +47 -0
  55. package/runtime/prebuilds/stdd-fs/win32-arm64/stdd-fs.exe +0 -0
  56. package/runtime/prebuilds/stdd-fs/win32-x64/stdd-fs.exe +0 -0
  57. package/runtime/sdk/adapters.mjs +279 -0
  58. package/runtime/sdk/file-observation.mjs +12 -0
  59. package/runtime/sdk/index.d.ts +140 -0
  60. package/runtime/sdk/index.mjs +31 -0
  61. package/runtime/sdk/native-fs.mjs +1235 -0
  62. package/runtime/sdk/path.mjs +71 -0
  63. package/runtime/sdk/text.mjs +42 -0
  64. package/runtime/sdk/workflow.mjs +294 -0
  65. package/runtime/templates/deferred-design.md +47 -0
  66. package/runtime/templates/github-stdd.yml +42 -0
  67. package/runtime/templates/gitlab-stdd.yml +72 -0
  68. package/runtime/templates/pr-description.md +35 -0
  69. package/scripts/adopting-root.mjs +42 -0
  70. package/scripts/stdd-hook.mjs +72 -0
  71. package/skills/stdd-brainstorming/SKILL.md +48 -0
  72. package/skills/stdd-debugging/SKILL.md +38 -0
  73. package/skills/stdd-delegate-slice/SKILL.md +118 -0
  74. package/skills/stdd-finish-change/SKILL.md +40 -0
  75. package/skills/stdd-implement/SKILL.md +28 -0
  76. package/skills/stdd-investigation/SKILL.md +35 -0
  77. package/skills/stdd-planning/SKILL.md +165 -0
  78. package/skills/stdd-pr-green/SKILL.md +52 -0
  79. package/skills/stdd-start-change/SKILL.md +39 -0
  80. package/skills/stdd-worktrees/SKILL.md +46 -0
@@ -0,0 +1,147 @@
1
+ # Reference: review and worker command internals
2
+
3
+ The mechanics behind `stdd review` and the worker commands: how a request is
4
+ stored and settled, what each dispatch route does, and what a managed sandbox
5
+ copies and collects. The method states the contract; this document states the
6
+ implementation.
7
+
8
+ ## Brief construction
9
+
10
+ The brief carries a complete changed-file manifest (the diff body
11
+ may truncate beyond a size bound; the manifest never does, and it names
12
+ every untracked path too — symlinks and other non-regular files carry a
13
+ skipped marker, so nothing the reviewer was not told about can exist),
14
+ the diff, the contents of untracked regular files
15
+ (a new file is part of the change even before `git add`; symlinks are
16
+ skipped and large files are read only up to a bound), and a **governing
17
+ docs** section (the canonical docs are the standing spec: docs changed
18
+ in this branch are named as the spec delta to read first, and when none
19
+ changed the configured `canonicalDocs` globs are named instead — the
20
+ reviewer is read-only in the repository and reads them itself; contents
21
+ are never inlined).
22
+
23
+ ## The review result contract
24
+
25
+ The reviewer's output is a single JSON object with required `summary` and
26
+ `findings` fields. `summary` and every finding's required `message` must be
27
+ non-empty printable single lines; ordinary Unicode, including ZWNJ/ZWJ and
28
+ emoji, remains valid. Each finding has `severity: blocking | advisory`,
29
+ `path` absent or null or a non-empty printable single line, and `line`
30
+ absent or null or a positive safe integer. An absent location field is
31
+ normalized to null for findings not tied to one location. For a
32
+ control-bearing repository path that cannot cross this inline boundary, the
33
+ reviewer omits `path` rather than emitting unsafe text. Any wrong field type
34
+ or output shape rejects the whole result.
35
+
36
+ ## Brief storage and settlement
37
+
38
+ The brief is written outside the repository, in a
39
+ private temporary directory with owner-only permissions — it can carry
40
+ source contents and must not be world-readable. A `review-request` event
41
+ records the route, snapshot, brief hash, and a versioned, lossless identity
42
+ for the OS temp root, private directory, and every owned artifact. Codex's
43
+ `last-message.txt` is created owner-only before that event and read only
44
+ through a descriptor whose identity still matches the request. If the branch
45
+ or active task changes
46
+ while a CLI reviewer runs, the command records a terminal cancellation
47
+ against the captured original request rather than attaching a verdict to
48
+ the new context or leaving an orphan request. The cancellation and verdict
49
+ paths share the ledger lock, so exactly one terminal outcome wins.
50
+
51
+ Private-artifact settlement verifies the recorded directory and artifact
52
+ identities, including that every artifact's recorded and observed owner equals
53
+ the recorded review-directory owner, then overwrites each captured file through a helper-held writable
54
+ capability, flushes it, truncates it to zero, and flushes again. It then moves
55
+ the zeroed directory into an owner-private, non-loadable OS-temp quarantine.
56
+ After the terminal ledger outcome is durable, that identity-bound zeroed tree
57
+ remains for explicit operator removal. A crash leaves the quarantine
58
+ recoverable by `review --cleanup`; unknown siblings, changed identities, or
59
+ legacy requests without complete identity provenance fail closed before
60
+ mutation and require explicit operator remediation. Settlement never follows
61
+ or recursively deletes a replaceable final basename.
62
+
63
+ ## Dispatch routes
64
+
65
+ - `--via codex` dispatches `codex exec --sandbox read-only` itself —
66
+ stdin closed, wall-clock bounded (`--timeout <seconds>`, default
67
+ 600) — parses the reviewer's final message, and recomputes the
68
+ snapshot once the runner returns: a checkout that changed while the
69
+ reviewer ran records stale, the same as on submit.
70
+ - `--via claude` dispatches `claude -p --safe-mode --tools Read,Glob,Grep --permission-mode dontAsk`
71
+ headless in the same way — brief over stdin, bounded, and tool-enforced read-only — for
72
+ repositories driven from Codex, or as a second perspective; like codex it
73
+ requires the `crossCli` capability.
74
+ - `--via subagent` prints the brief path for the orchestrating agent to
75
+ hand to a fresh read-only subagent; the reviewer's JSON comes back via
76
+ `stdd review --result <file|->`, which grades it against the **open
77
+ subagent request**: a snapshot mismatch with the current checkout
78
+ records the result as stale and rejects it, and a CLI-dispatched
79
+ request (codex or claude) can never be completed by `--result` — its
80
+ runner is its only mouth, so a hand-fed file cannot forge its provenance.
81
+ Submitting a result securely settles the private temporary artifacts. An
82
+ abandoned request is cancelled and settled with `stdd review --cleanup`;
83
+ cleanup also reaches an interrupted CLI request and retries settlement
84
+ when a terminal cancellation outlived its private-artifact move.
85
+
86
+ ## Declaring a scope
87
+
88
+ `stdd slice new` declares a scope inside the existing checkout;
89
+ `stdd worker create <directory>` declares the same scope and builds a managed
90
+ filesystem snapshot without `.git`. Both accept `--frozen` (globs the slice
91
+ must not touch) and `--allowed` (globs the slice may touch — anything outside
92
+ is a violation), and both record a `scope` event carrying the globs and a
93
+ baseline. Every glob crosses the same printable-single-line
94
+ boundary as other persisted identifiers; control, bidi, and invisible
95
+ formatting characters are rejected before durable state is written.
96
+
97
+ ## Managed worker sandboxes
98
+
99
+ A managed worker sandbox created by `stdd worker create` requires an active
100
+ task and an already recorded docs
101
+ decision. Its destination must not exist. Managed create and collect use the
102
+ native mutation helper and fail before mutation when the destination
103
+ filesystem cannot provide the required capability guarantees. Creation copies
104
+ the checkout's tracked and non-ignored untracked files at
105
+ current bytes, excluding Git metadata and the private ledger/plan. Ignored dependencies, credentials, and
106
+ build output are deliberately absent; run the repository's readiness setup in
107
+ the sandbox before trusting tests. `.stdd/worker.json` binds the sandbox ID,
108
+ source task and branch, scope, source HEAD, and every copied path fingerprint;
109
+ the parent ledger records the metadata hash. The sandbox receives a minimal
110
+ local ledger for the same task, so `status --local`, `red`, `verify`, `note`,
111
+ `scope`, and `doctor --readiness` work without source Git authority. Task boundaries, docs decisions, nested worker
112
+ creation, review, evidence, and delivery commands are rejected there.
113
+
114
+ `stdd worker collect <directory>` runs only from the source checkout. It
115
+ rejects a missing or changed metadata binding, any non-ignored `.git` entry,
116
+ unsafe file type, scope violation, source task/branch/HEAD drift, or concurrent source
117
+ edit to a worker-touched path before applying anything. A complete preflight
118
+ then imports only worker-introduced file changes and the worker's red/verify/
119
+ note evidence. Collection never stages, commits, switches branches, pushes, or
120
+ otherwise changes Git history. Import is idempotent: a rerun accepts paths
121
+ already at the sandbox result and completes any remaining paths after an
122
+ interruption; any third state is a conflict. Deleted source bytes move into an
123
+ owner-private, Git-ignored `.stdd/worker-deletions/` recovery quarantine.
124
+ Interrupted collection reuses exact deletion baselines for the next idempotent
125
+ run; completed baselines remain recognizable for explicit operator removal.
126
+ A readable metadata-v1 sandbox may replace file content while retaining its
127
+ exact validated baseline mode, including a legacy mode such as `0664`; this
128
+ compatibility authority never permits a sandbox-selected mode change and does
129
+ not relax metadata-v2 creation modes. The orchestrator still runs fresh
130
+ verification and review in the source checkout. STDD never removes the
131
+ sandbox automatically; the orchestrator deletes it explicitly only after
132
+ reviewing the collected result.
133
+
134
+ ## The scope postflight
135
+
136
+ `stdd scope` is the postflight check against the recorded baseline rather than
137
+ a ref: Git checkouts compare HEAD plus dirty paths, while managed sandboxes
138
+ compare their bound file manifest. Only **worker-introduced** changes count — a
139
+ change to a frozen path, or outside the allowed paths, fails. Dirt inherited
140
+ from before the slice (a file already modified at baseline, byte-identical
141
+ now) is reported separately and never blamed on the slice. A declared slice
142
+ exempts only the ledger, plan, and exact shape-validated private internal
143
+ transaction names;
144
+ tracked config, generated files, and reset-name near misses under `.stdd/`
145
+ remain ordinary scope inputs. The same exact exemption boundary applies to
146
+ checkout and review snapshots. A declared slice appears in `stdd status`,
147
+ which names the postflight as the next step once the loop is complete.
@@ -0,0 +1,151 @@
1
+ # Reference: generated state and durable mutation
2
+
3
+ How STDD proves that its generated files are the ones it wrote, and how it
4
+ mutates a namespace without losing state to a crash. The method summarizes the
5
+ guarantee; this document holds the mechanism.
6
+
7
+ ## Manifest hashes and generated-file cleanup
8
+
9
+ Manifest hashes prove that generated bytes have not changed since init; for
10
+ the installed method, `check` and `doctor` also compare those bytes with the
11
+ canonical method shipped by the running CLI, so a stale method and a matching
12
+ stale manifest cannot authenticate each other. Generated-looking method,
13
+ snippet, and native-skill files without a manifest are a partial install and
14
+ also fail the check, even when an exact generated path is occupied by a
15
+ directory, symlink, or other unsafe object. A malformed manifest — including a wrong generator or
16
+ version shape, a non-object document, an invalid generated path or exact
17
+ `sha256:<64 lowercase hex>` file hash, or malformed present target metadata —
18
+ is an actionable adoption finding in both `check` and `doctor`, never an
19
+ uncaught runtime error. Legacy manifests may omit target metadata; when
20
+ present, it must contain the complete known target schema. Every listed
21
+ output is inspected as a readable regular file without following symlinks;
22
+ directories, non-regular files, unreadable paths, and paths replaced during
23
+ inspection are stale findings rather than runtime errors. Profile cleanup
24
+ uses the same inspection boundary and never deletes an output it cannot
25
+ safely identify. Retirement is confined to a filesystem capability held by
26
+ the native mutation helper: the verified inode is moved out of its agent or
27
+ CI load path to an unpredictable quarantine name. That quarantine is a
28
+ durable safety and crash-recovery boundary; STDD never turns a final basename
29
+ check into automatic recursive deletion. Before the first quarantine rename,
30
+ init atomically publishes and fsyncs `.stdd/cleanup-transaction.json`
31
+ with each output's original and quarantine paths, expected hash, and captured
32
+ parent and file identities. Every later phase is durably recorded. A
33
+ manifest-publish failure rolls back all quarantines; after a durable manifest
34
+ commit the exact quarantined trees remain hash-accounted outside their former
35
+ load paths for explicit operator removal. A crash leaves the journal
36
+ authoritative, and the next init reconstructs whether to resume or roll back.
37
+ If recovery cannot prove the exact identities, it blocks without forgetting
38
+ an orphan. `check` and `doctor` report pending or malformed cleanup journals;
39
+ `doctor` also inventories recognized retained quarantines and gives manual
40
+ removal guidance. Neither treats a quarantine as active generated output. A hand-edited formerly generated file is preserved and
41
+ remains listed and reported stale until its owner removes or relocates it.
42
+ The journal is repo-local, single-linked, owner-private, and replaced
43
+ atomically. Journal reads bind metadata, bytes, and the final pathname to one
44
+ helper-held file capability. Recovery rollback and retirement use captured
45
+ parent capabilities, so a concurrent logical-parent swap cannot redirect
46
+ either operation. The replacement manifest is committed in durable order:
47
+ held-parent temp creation, file flush, held-parent atomic rename, directory
48
+ flush, then logical-parent and manifest-identity verification. Only after
49
+ that proof may the zeroed journal itself move to a retained, non-loadable
50
+ quarantine. An indeterminate post-rename failure leaves all state for
51
+ deterministic recovery.
52
+
53
+ ## The bundled `stdd-fs` helper
54
+
55
+ Namespace mutations that require a stable parent run through one bundled
56
+ `stdd-fs` helper session per CLI command. The helper exposes a versioned JSONL
57
+ capability protocol; opaque handles and expected identity tokens, not logical
58
+ pathnames, authorize mutation. STDD's JavaScript runtime retains policy, WAL
59
+ schemas, operation ordering, and user-facing diagnostics. The helper binaries
60
+ for Linux x64/arm64, macOS x64/arm64, and Windows x64/arm64 are included in
61
+ both `@stdd/cli` and the universal plugin. Release CI builds every target and
62
+ verifies the packaged artifact manifest. Before spawning one, STDD verifies
63
+ the exact platform/architecture selection, regular non-symlinked file shape,
64
+ SHA-256, and protocol handshake. The installed package tree is part of the
65
+ trusted code boundary, like the JavaScript runtime itself; integrity checks
66
+ detect static corruption but do not claim to defeat a same-user process that
67
+ can rewrite executing package code. Target-repository namespace races remain
68
+ untrusted after the helper session starts. A missing, damaged, or incompatible
69
+ helper fails before target mutation; read-only commands do not require it except
70
+ when `doctor` capability-inspects exact ledger-proven retained review or worker
71
+ quarantine locations. Those inspections use only read operations through the
72
+ verified helper session; discovery or helper failures become doctor findings.
73
+
74
+ The helper preflights the target filesystem metadata and OS primitive set for stable file identities,
75
+ no-follow traversal, same-volume atomic rename, and durable file and directory
76
+ flushes. Unix binds owner and mode through descriptor-relative operations.
77
+ Windows binds volume/file IDs, rejects reparse points, and creates private
78
+ state with a protected current-user DACL. Symbolic-link inspection is a
79
+ protocol-v1, capability-relative `read-link` operation over a held parent and
80
+ one validated child name: it never follows the link, requires the caller's
81
+ expected symlink identity, returns bounded raw target bytes as base64, and
82
+ rejects an identity change across the read. Unix uses bounded `readlinkat`
83
+ retries with an identity postflight. Windows accepts only recognized symbolic
84
+ link reparse tags and binds the exact reparse identity before and after parsing.
85
+ Symbolic-link creation uses the same held-parent authority and no-replace
86
+ publication. On Windows it selects file or directory link semantics without
87
+ following an external target, applies the exact owner and protected DACL,
88
+ verifies the published reparse identity, and flushes and postflights the
89
+ parent. Missing privilege or developer-mode support fails with a structured
90
+ unsupported or access error before partial publication. Probe evidence covers
91
+ both link operations consistently. Managed-worker creation performs that
92
+ preflight against the held, probed destination parent after preparing the
93
+ complete source snapshot and before creating the destination root whenever the
94
+ snapshot contains a symbolic link; regular-only snapshots skip it.
95
+ Protocol-v1 also exposes an expected-identity-bound `set-mode` mutation for a
96
+ held regular file on Unix. It uses descriptor-relative `fchmod`, rejects type
97
+ or special bits outside the legacy metadata-v1 mode range, and returns a stat
98
+ postflight with committed mutation reporting after the syscall. Windows
99
+ returns a structured unsupported result because managed metadata-v1 workers
100
+ are Linux-only. Collection may use this operation only to restore the exact
101
+ mode inherited from the validated metadata-v1 baseline for that file; a worker
102
+ cannot select a different mode. Metadata-v2 and new file creation remain
103
+ restricted to `0600`, `0644`, and `0755`. A filesystem without those
104
+ capabilities fails closed; there is no best-effort pathname fallback. New
105
+ quarantines always record enough provenance for deterministic recovery and
106
+ operator inventory. Existing manifest, journal, worker, review, ledger, and
107
+ plugin quarantines are never discovered by a broad temp-directory scan;
108
+ recognized locations are reported, while provenance-less leftovers remain
109
+ untouched.
110
+
111
+ ## The printable-text boundary
112
+
113
+ Inline identifiers and adapter metadata share one printable-text boundary
114
+ before they reach task state, logs, or generated files. It accepts ordinary
115
+ Unicode, including ZWNJ/ZWJ and emoji sequences, but rejects line/control
116
+ characters, unpaired surrogate code units, Unicode `Bidi_Control` code points,
117
+ and a fixed denylist of invisible or deprecated formatting controls. The
118
+ denylist includes soft-hyphen/grapheme-joiner controls, zero-width space,
119
+ word/invisible-operator controls, interlinear/shorthand/music formatting
120
+ controls, and BOM, so visually identical or reordered text cannot spoof those
121
+ outputs without broadly rejecting Unicode format characters.
122
+
123
+ ## Ledger transactions and retained quarantines
124
+
125
+ Reset publishes its two task
126
+ boundaries with one same-directory atomic rename. Its exact internal
127
+ active transaction names (`.ledger-reset-` and `.ledger-prepared-`, each
128
+ followed by 32 lowercase hex characters and `.tmp`) are owner-only. A trusted
129
+ stranded active temp moves under the next ledger lock to
130
+ `.stdd/ledger-quarantines/.ledger-recovered-<same-token>.tmp/`, an owner-private
131
+ retained directory containing a single-linked `0600` payload and matching
132
+ `0600` `inventory.json`. Active temps and those two retained files are ignored
133
+ by checkout/review snapshots only after their complete shape, token-bound
134
+ provenance, and exact directory contents are verified. Unix recognition also
135
+ binds uid and exact modes; Windows relies on the protected current-user DACL
136
+ and owner check enforced by the native creator because Node exposes only
137
+ synthetic POSIX uid/mode values there. They are deliberately not hidden by
138
+ `.gitignore`, so a symlink, non-regular or hard-linked file, extra sibling,
139
+ malformed inventory, near-miss name, or (on Unix) foreign owner/non-private
140
+ mode remains visible and is rejected rather than trusted. `stdd doctor` inventories verified retained ledger quarantines with
141
+ manual-removal guidance. Repository transaction-temp recovery, reset commit,
142
+ and settlement use
143
+ one native-helper session with held `.stdd` capabilities for the snapshot,
144
+ active and prepared temps, final ledger publication, and identity-conditioned
145
+ quarantine retirement. A crash leaves the exact temp recoverable; a completed
146
+ transaction moves it out of every active transaction namespace but does not
147
+ recursively delete its final quarantine basename. Ordinary task start, finish, and
148
+ recorder appends use the same portable publication boundary when they need a
149
+ namespace mutation. A SIGKILL-stranded active temp is a non-authoritative copy
150
+ recovered under the next ledger lock only after its owner-only, single-link
151
+ regular-file shape is validated, which is why a review snapshot may exempt it.
@@ -0,0 +1,233 @@
1
+ # Reference: installation, agent hosts, and automation
2
+
3
+ What `stdd init` and `stdd configure` write, what each agent host receives,
4
+ and how the optional CI and lifecycle-hook adapters behave. The method states
5
+ that these surfaces exist; this document states what they do.
6
+
7
+ ## Choosing the profile: `init` and `configure`
8
+
9
+ `stdd init
10
+ --capabilities <list>` writes the profile without hand-editing JSON
11
+ (named capabilities on, the rest off), and `stdd init --interview` asks
12
+ one question at a time — recommended answer first — then runs the same
13
+ init. The interview also picks the reviewer route (`review.via`) and,
14
+ for the selected native agents (Claude Code, Codex, and Pi), offers the
15
+ lifecycle integration.
16
+ When `crossCli` is selected, the first selected native host is the driver for
17
+ the repository-level reviewer default and its opposite CLI is recorded:
18
+ Claude → codex, Codex → claude, Pi → claude. Per-host generated skills use the
19
+ same opposite-host rule explicitly, so a repository compiling multiple hosts
20
+ never teaches Claude Code or Codex to review itself; Pi is a driver host, not a
21
+ `stdd review --via` runner. With no dispatch capability, generated skills omit
22
+ the `[review:]` claim and review commands entirely; manual self-review is never
23
+ presented as an independent-review fallback.
24
+
25
+ `stdd configure` re-runs the interview over an existing install, with
26
+ the **current** values as the defaults. It edits only the capability
27
+ profile and the review route — every other config key is preserved —
28
+ and recompiles the same generated targets the last init produced (the
29
+ manifest remembers them). It does not install or remove CI workflows,
30
+ change CI target selection, or remove lifecycle hooks. Stop hooks are the
31
+ explicit exception: a remembered Stop-hook target is maintained (and restored
32
+ if missing), while `--stop-hook` opts in and may install it for the selected
33
+ agents. Configure never adds pre-push or session hooks. Flag forms skip the
34
+ questions: `--capabilities <list>`,
35
+ `--review-via subagent|codex|claude`, `--max-rounds <n>` (the review
36
+ budget; 0 = unlimited), `--stop-hook`. When the profile has a dispatch
37
+ capability, an incompatible route (codex or claude without `crossCli`,
38
+ subagent without `subagents`) is an error, never a silent downgrade to
39
+ self-review. A profile with no dispatch capability may retain a dormant
40
+ route because it emits no review claim; invoking or claiming review still
41
+ requires an available route.
42
+
43
+ ## Agent host outputs
44
+
45
+ For Codex (`--tools codex`), init compiles every active playbook to
46
+ `.agents/skills/<name>/SKILL.md`, where Codex can select it implicitly from
47
+ its description or the user can invoke it explicitly as `$<name>`. Init also
48
+ maintains the repo's `AGENTS.md`: the short STDD section is written between
49
+ `stdd:begin`/`stdd:end` marker comments. The file is created when absent, the
50
+ marked section is replaced in place when present, and content outside the
51
+ markers is never touched. The section is also saved to
52
+ `.stdd/AGENTS-snippet.md` for manual composition.
53
+
54
+ For Claude Code (`--tools claude`), the same playbooks compile to
55
+ `.claude/skills/<name>/SKILL.md`, invocable as `/<name>` or selected
56
+ implicitly. Init maintains the same short invariant block in `CLAUDE.md`,
57
+ between the same managed markers, and saves it as
58
+ `.stdd/CLAUDE-snippet.md`. `AGENTS.md` and `CLAUDE.md` stay user-owned and
59
+ are never manifest-tracked; the generated snippets and native skills are
60
+ manifest-tracked. The full method is never injected into every prompt:
61
+ always-on files point to `.stdd/method.md`, while skills load their detailed
62
+ workflow only when used.
63
+
64
+ For Pi (`--tools pi`), init uses the Agent Skills standard registry at
65
+ `.agents/skills/<name>/SKILL.md`, which Pi discovers natively and invokes as
66
+ `/skill:<name>`. That output is byte-identical to Codex's skill files, so a
67
+ repository selecting both hosts has one shared generated copy rather than
68
+ duplicate skill names. Pi's short router lives in `.pi/APPEND_SYSTEM.md`, not
69
+ `AGENTS.md`: this keeps Pi's `/skill:` syntax from overwriting Codex's `$`
70
+ syntax when both hosts are selected. The append-system file is user-owned;
71
+ init maintains only its marked STDD section and saves the generated source as
72
+ `.stdd/PI-snippet.md`.
73
+
74
+ ## Adoption modes and the universal bundle
75
+
76
+ STDD has three cumulative adoption modes. **Personal plugin** use installs the
77
+ universal STDD bundle once through Codex, Claude Code, or Pi and changes no
78
+ repository; its lazy skills remain available, while lifecycle integrations stay
79
+ dormant outside a checkout containing `.stdd/`.
80
+ **Shared repository contract** use runs `init` once and commits `.stdd/`, native
81
+ agent routing, and repository policy. **Enforced contract** use explicitly adds
82
+ repository-owned hooks or a CI adapter; ordinary `init` never creates CI, and
83
+ CI reads checkout and review-request facts rather than the private ledger or
84
+ agent state.
85
+
86
+ Repo-local generated skills remain a valid team contract and need no plugin.
87
+ The optional universal bundle at `plugins/stdd/` distributes one generated set
88
+ of conservative-profile skills and one CLI runtime through native Codex and
89
+ Claude Code plugin manifests or the `@stdd/plugin` Pi package. The runtime is
90
+ generated from the same source and version as `@stdd/cli`; the adopting
91
+ repository does not install that CLI package. The bundle never owns repository
92
+ state: its lifecycle integration acts only when the checkout contains
93
+ `.stdd/`; init, task state, policy, and optional CI stay with the repository.
94
+
95
+ Codex and Claude Code use the bundle's fail-open SessionStart and Stop command
96
+ hooks. If the bundled runtime cannot read an adopting checkout, SessionStart
97
+ reports fixed update-or-reinitialize guidance and exits successfully; Stop
98
+ returns the host's allow response without forwarding runtime output. Pi loads
99
+ the same skills plus a package extension. On `session_start` and
100
+ `session_compact`, that extension queues successful local status output for
101
+ the next model turn; on `agent_settled`, it queues at most one corrective
102
+ follow-up when the gate blocks. Runtime errors remain fail-open and are never
103
+ sent into a model turn. The installed bundle version governs all three hosts'
104
+ lifecycle commands.
105
+
106
+ Repository-generated pre-push/session/stop hooks are a separate integration and continue to require the exact project-local package
107
+ for pinned offline execution. The source-checkout command
108
+ `npm run build:plugin` validates every host manifest and publishes the shared
109
+ skills, Pi extension, runtime, and all six native mutation helpers through the
110
+ same capability boundary as the CLI. Retired stale skills move to an
111
+ identity-bound, non-loadable quarantine that remains available for explicit
112
+ operator removal; subsequent builds keep recognized quarantines stable.
113
+
114
+ ## Project-local recipes
115
+
116
+ Project-specific recipes live in `.stdd/playbooks/local/` — markdown
117
+ playbooks with the same frontmatter contract (`name`, `description`,
118
+ `when`, optional `requires`), owned by the repository and never
119
+ overwritten by `stdd init`. They compile through the same pipeline as
120
+ the kit's playbooks — capability blocks included — into each selected host's
121
+ native skill registry. Always-on AGENTS/CLAUDE blocks remain a fixed, minimal
122
+ router: they name the method, the project-local runner, and `.stdd/policy.md`,
123
+ and do not enumerate either kit or project skills. A local recipe that
124
+ reuses a kit playbook's `name` replaces it: project knowledge outranks the kit.
125
+ Local recipe names must otherwise be unique; init rejects duplicates before
126
+ writing generated state and names both conflicting source files.
127
+ The three skills named by that router (`stdd-start-change`, `stdd-implement`,
128
+ and `stdd-finish-change`) are mandatory; init rejects a profile or local
129
+ override that would make one inactive. Other inactive local overrides still
130
+ shadow their kit playbook intentionally.
131
+
132
+ ## CI adapters
133
+
134
+ CI integration is an explicit, optional transport adapter around
135
+ provider-neutral CLI contracts. `init` without `--ci` creates no provider file;
136
+ a team may instead place the printed generic commands in an existing quality
137
+ job. Every configured provider runs `stdd check`; a review pipeline pipes its
138
+ live PR/MR description to `stdd check-pr - --base <ref>`. CI uses read-only
139
+ repository and review-request access. It never attempts to prove the agent's
140
+ reasoning, consume the ignored ledger, dispatch workers, or mutate Git: it
141
+ grades only facts derivable from the checkout and review request.
142
+
143
+ On GitHub, `stdd init --ci github` writes the canonical workflow for these
144
+ gates and installs an explicit supported Node runtime. It fetches the PR body
145
+ live from the API and re-runs on body edits —
146
+ a workflow reading `github.event.pull_request.body` validates a payload
147
+ frozen at trigger time, so an edited body is never re-checked and a re-run
148
+ replays the stale text. The fetch uses node, not the gh CLI — node is
149
+ already required to run stdd, while self-hosted runners often lack gh —
150
+ and the step sets `pipefail`, so a failed fetch fails the gate as a fetch
151
+ error instead of feeding check-pr an empty body that misreports as a
152
+ missing evidence line. `stdd doctor` flags the frozen-payload form, and flags a PR
153
+ template carrying an unquoted evidence label at the start of a line, since
154
+ its placeholder residue would pass the gate on every PR.
155
+
156
+ On GitLab, `stdd init --ci gitlab` writes an includeable
157
+ `.gitlab/stdd.gitlab-ci.yml` job. It uses the merge-request API to fetch the
158
+ live description, pipes it to `check-pr -`, and passes
159
+ `CI_MERGE_REQUEST_DIFF_BASE_SHA` as the base. The job enables `pipefail`, so
160
+ an API failure fails the gate instead of being mistaken for an empty body.
161
+ Same-project pipelines authenticate with the short-lived `CI_JOB_TOKEN`.
162
+ Because fork merge-request pipelines normally run in the source project, the
163
+ target must allowlist that source for job-token access. A controlled trusted
164
+ fork may instead supply a masked and hidden target-project
165
+ `STDD_GITLAB_READ_API_TOKEN` with only `read_api`; target credentials are
166
+ never safe in an untrusted fork pipeline. Authentication failure names the
167
+ required setup instead of pretending fork access is automatic.
168
+ `stdd init --ci generic` writes no provider file; it prints and records the
169
+ portable command contract for teams to compose into Jenkins, Buildkite, or an
170
+ existing pipeline. Provider templates are adapters, never dependencies of
171
+ the method or public SDK.
172
+
173
+ ## Local hooks
174
+
175
+ Locally, `stdd init --hooks` writes a pre-push hook that runs exactly one
176
+ fast, offline command: `stdd check`. Nothing network-bound belongs in a
177
+ hook — a flaky gate's false positives train `--no-verify`. The hook file
178
+ is user-owned after generation (like `config.json`, it is not
179
+ manifest-tracked and never overwritten), so teams append their own steps.
180
+ stdd never touches `.git/`: install it via
181
+ `git config core.hooksPath .stdd/hooks`, or call `stdd check` from an
182
+ existing hook manager. `stdd doctor` reports whether the hook is wired
183
+ up — informationally, never as a failure.
184
+
185
+ Generated hooks invoke the project-local package offline and name the scoped
186
+ package explicitly:
187
+ `npm exec --offline --package=@stdd/cli@<generated-version> -- stdd`. They
188
+ never ask npm to resolve the unrelated unscoped package `stdd`. Install
189
+ `@stdd/cli` as an exact development dependency before wiring hooks. The
190
+ `@stdd/cli` source repository is the one dogfood exception: its generated
191
+ automation invokes `node "$(git rev-parse --show-toplevel)/cli/stdd.mjs"`
192
+ directly, because the checkout being tested is the package source and may not
193
+ exist in npm's offline cache yet.
194
+
195
+ For selected native agents, `stdd init --session-hook` wires the session-start
196
+ ritual mechanically. Claude Code and Codex each get one `SessionStart` hook
197
+ (`startup|resume|clear|compact`) in their native settings. Pi gets a
198
+ project-local `.pi/extensions/stdd.js` extension that runs the same command on
199
+ `session_start` and `session_compact`, then queues its output for the next
200
+ model turn. The `compact` source is the single context-restoration path;
201
+ re-init removes older managed Claude `PostCompact` entries to avoid running the
202
+ ritual twice, while preserving unrelated user hooks. Each integration runs
203
+ `stdd status --local`, which never calls a forge or the network, so every fresh
204
+ context opens with local loop state and the next step already in it — recorded
205
+ state instead of recall. Hook entries are merged into existing valid files
206
+ without duplication. A conflicting Pi extension or invalid JSON settings are
207
+ left untouched and a manual instruction is printed instead. Codex hooks and
208
+ Pi project extensions remain subject to their host's repository trust review.
209
+
210
+ `stdd init --stop-hook` (opt-in, also offered by the interview and
211
+ `stdd configure`) wires the other end of the selected native agents. Claude
212
+ Code and Codex receive a `Stop` hook running the agent-specific
213
+ `stdd stop-hook` protocol, which applies the same judgment as `status --gate`
214
+ when the agent tries to finish. Pi has no pre-stop veto event; its project
215
+ extension checks the same gate at `agent_settled` and queues at most one
216
+ corrective follow-up turn when blocked. It then fails open rather than creating
217
+ an unbounded feedback loop, so this is visible corrective continuation, not a
218
+ hard stop guarantee. Broken claims — a
219
+ checked-but-unproven `[review:]` item, a changes-requested or stale
220
+ verdict — block the stop with the reasons fed back; unfinished work
221
+ never does, the same as the gate. The command respects
222
+ `stop_hook_active` (a blocked stop is never re-blocked into a loop) and
223
+ fails open: an internal error exits zero, because a broken hook must
224
+ not trap the session. Claude blocks with exit 2 and stderr; Codex exits 0
225
+ with its documented `Stop` continuation JSON (`decision: "block"` plus
226
+ `reason`); an empty JSON object allows a clean stop. The Codex boundary accepts
227
+ exactly `{}`, or exactly the two keys `decision` and `reason`, where the
228
+ decision is `"block"` and the reason is a string with non-whitespace content.
229
+ It emits compact JSON without changing valid reason text. Extra or missing
230
+ keys, whitespace-only reasons, arrays, primitives, malformed or empty output,
231
+ and nonzero child results all fail open as `{}`.
232
+ Pi treats command failures as fail-open and never sends their output into a
233
+ model turn. Merging rules match the session hook.
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "@stdd/cli",
3
+ "version": "0.9.0",
4
+ "description": "Spec + Test Driven Development — a markdown-first methodology kit for teams building software with AI coding agents",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "types": "./sdk/index.d.ts",
9
+ "import": "./sdk/index.mjs"
10
+ }
11
+ },
12
+ "types": "./sdk/index.d.ts",
13
+ "bin": {
14
+ "stdd": "cli/stdd.mjs"
15
+ },
16
+ "files": [
17
+ "cli/",
18
+ "sdk/",
19
+ "method/",
20
+ "playbooks/",
21
+ "templates/",
22
+ "adapters/",
23
+ "prebuilds/"
24
+ ],
25
+ "scripts": {
26
+ "test": "node --test",
27
+ "test:harness": "node scripts/agent-contract.mjs",
28
+ "build:plugin": "node scripts/build-plugin.mjs",
29
+ "check": "biome ci .",
30
+ "format": "biome check --fix .",
31
+ "selfcheck": "node cli/stdd.mjs check ."
32
+ },
33
+ "engines": {
34
+ "node": ">=20"
35
+ },
36
+ "keywords": [
37
+ "sdd",
38
+ "tdd",
39
+ "stdd",
40
+ "spec-driven-development",
41
+ "test-driven-development",
42
+ "ai-agents",
43
+ "claude-code",
44
+ "codex",
45
+ "pi-coding-agent",
46
+ "methodology",
47
+ "workflow"
48
+ ],
49
+ "repository": {
50
+ "type": "git",
51
+ "url": "git+https://github.com/vsem-azamat/stdd.git"
52
+ },
53
+ "bugs": {
54
+ "url": "https://github.com/vsem-azamat/stdd/issues"
55
+ },
56
+ "homepage": "https://github.com/vsem-azamat/stdd#readme",
57
+ "author": "Azamat Almazbek uulu",
58
+ "license": "MIT",
59
+ "devDependencies": {
60
+ "@biomejs/biome": "^2.3.8"
61
+ },
62
+ "directories": {
63
+ "test": "test"
64
+ }
65
+ }
@@ -0,0 +1,46 @@
1
+ ---
2
+ name: stdd-brainstorming
3
+ description: Shape a fuzzy idea into an agreed behavior contract before any plan or code
4
+ when: A non-trivial change is requested and the requirements, scope, or approach are not yet pinned down.
5
+ ---
6
+
7
+ # Brainstorming
8
+
9
+ The goal is agreement on **what** and **why** before anyone invests in **how**.
10
+ The output is not a document — it is a shared understanding that becomes a
11
+ docs edit and a PR description.
12
+
13
+ ## Process
14
+
15
+ 1. **Understand the current state first.** Read the relevant docs and the code
16
+ the change will touch. Questions asked from ignorance waste the other
17
+ side's time; questions asked from knowledge sharpen the idea.
18
+ 2. **Ask one question at a time.** Prefer questions that eliminate whole
19
+ branches of the design space: who is it for, what triggers it, what must
20
+ never happen, what is explicitly out of scope. When the answer space is
21
+ enumerable, offer it as a closed choice with your recommendation first —
22
+ a closed question costs the other side seconds, an open one minutes.
23
+ Keep open questions for genuinely open design space.
24
+ 3. **Challenge scope creep in both directions.** If the idea is bigger than
25
+ the need, say so and propose the smaller version. If the stated need hides
26
+ a larger real problem, surface it.
27
+ 4. **Propose 2–3 approaches with a recommendation.** For each: one paragraph,
28
+ the trade-off that actually matters, and what it costs later. Recommend
29
+ one; do not present a menu without an opinion.
30
+ 5. **Converge on the behavior contract.** State the agreed behavior as rules
31
+ precise enough to test. Confirm them explicitly.
32
+
33
+ ## Output
34
+
35
+ - The agreed rules become the **docs edit** (the spec) — the first commit of
36
+ the branch.
37
+ - The rationale, rejected alternatives, and scope decisions go into the
38
+ **PR description** when the branch opens.
39
+ - Nothing from this conversation is committed as a standalone file.
40
+
41
+ ## Anti-patterns
42
+
43
+ - Jumping to implementation detail while behavior is still unsettled.
44
+ - Asking multiple stacked questions at once.
45
+ - Writing a "spec document" instead of editing the real docs.
46
+ - Agreeing silently: if you disagree with the direction, say so with reasons.