@wildorder/nightshift 0.1.0 → 0.3.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.
- package/dist/cli.js +252 -10
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +4 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +7 -0
- package/dist/config.js.map +1 -1
- package/dist/decision-ledger.d.ts +68 -0
- package/dist/decision-ledger.d.ts.map +1 -0
- package/dist/decision-ledger.js +108 -0
- package/dist/decision-ledger.js.map +1 -0
- package/dist/decision.d.ts +59 -0
- package/dist/decision.d.ts.map +1 -0
- package/dist/decision.js +0 -0
- package/dist/decision.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/init-project.d.ts +18 -0
- package/dist/init-project.d.ts.map +1 -0
- package/dist/init-project.js +259 -0
- package/dist/init-project.js.map +1 -0
- package/dist/install-prefs.d.ts +17 -0
- package/dist/install-prefs.d.ts.map +1 -0
- package/dist/install-prefs.js +55 -0
- package/dist/install-prefs.js.map +1 -0
- package/dist/install-skills.d.ts +83 -0
- package/dist/install-skills.d.ts.map +1 -0
- package/dist/install-skills.js +311 -0
- package/dist/install-skills.js.map +1 -0
- package/dist/install-wizard.d.ts +56 -0
- package/dist/install-wizard.d.ts.map +1 -0
- package/dist/install-wizard.js +166 -0
- package/dist/install-wizard.js.map +1 -0
- package/dist/manifest.d.ts +76 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +95 -0
- package/dist/manifest.js.map +1 -0
- package/dist/package-assets.d.ts +3 -0
- package/dist/package-assets.d.ts.map +1 -0
- package/dist/package-assets.js +13 -0
- package/dist/package-assets.js.map +1 -0
- package/dist/run-program.d.ts +72 -0
- package/dist/run-program.d.ts.map +1 -0
- package/dist/run-program.js +482 -0
- package/dist/run-program.js.map +1 -0
- package/dist/skill-roots.d.ts +51 -0
- package/dist/skill-roots.d.ts.map +1 -0
- package/dist/skill-roots.js +181 -0
- package/dist/skill-roots.js.map +1 -0
- package/package.json +3 -1
- package/skills/init-project/SKILL.md +196 -0
- package/skills/plan-program/SKILL.md +274 -0
- package/templates/AGENTS.md +29 -0
- package/templates/CLAUDE.md +7 -0
- package/templates/universal-directives.md +50 -0
- package/templates/vision.md +46 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { access } from "node:fs/promises";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join, resolve } from "node:path";
|
|
4
|
+
const SPECS = [
|
|
5
|
+
{
|
|
6
|
+
target: "claude",
|
|
7
|
+
label: "Claude Code",
|
|
8
|
+
configDir: ".claude",
|
|
9
|
+
homeEnv: "CLAUDE_CONFIG_DIR",
|
|
10
|
+
userSkills: (configHome) => join(configHome, "skills"),
|
|
11
|
+
projectSkills: join(".claude", "skills"),
|
|
12
|
+
extraScan: ({ home, projectRoot }) => [
|
|
13
|
+
{ kind: "command", scope: "project", root: join(projectRoot, ".claude", "commands") },
|
|
14
|
+
{ kind: "command", scope: "user", root: join(home, ".claude", "commands") },
|
|
15
|
+
],
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
target: "cursor",
|
|
19
|
+
label: "Cursor",
|
|
20
|
+
configDir: ".cursor",
|
|
21
|
+
userSkills: (configHome) => join(configHome, "skills"),
|
|
22
|
+
projectSkills: join(".cursor", "skills"),
|
|
23
|
+
// Cursor also reads the cross-tool .agents tree and Claude's skills dir,
|
|
24
|
+
// so a definition in either shadows what we install.
|
|
25
|
+
extraScan: ({ home, projectRoot }) => [
|
|
26
|
+
{ kind: "command", scope: "project", root: join(projectRoot, ".cursor", "commands") },
|
|
27
|
+
{ kind: "command", scope: "user", root: join(home, ".cursor", "commands") },
|
|
28
|
+
{ kind: "skill", scope: "project", root: join(projectRoot, ".agents", "skills") },
|
|
29
|
+
{ kind: "skill", scope: "project", root: join(projectRoot, ".claude", "skills") },
|
|
30
|
+
{ kind: "skill", scope: "user", root: join(home, ".agents", "skills") },
|
|
31
|
+
{ kind: "skill", scope: "user", root: join(home, ".claude", "skills") },
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
target: "codex",
|
|
36
|
+
label: "Codex",
|
|
37
|
+
configDir: ".codex",
|
|
38
|
+
homeEnv: "CODEX_HOME",
|
|
39
|
+
// Codex discovers skills in the cross-tool .agents directory, which does
|
|
40
|
+
// not move with CODEX_HOME — so detection and the write root diverge here
|
|
41
|
+
// on purpose.
|
|
42
|
+
userSkills: (_configHome, home) => join(home, ".agents", "skills"),
|
|
43
|
+
projectSkills: join(".agents", "skills"),
|
|
44
|
+
extraScan: ({ configHome }) => [
|
|
45
|
+
{ kind: "skill", scope: "user", root: join(configHome, "skills") },
|
|
46
|
+
],
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
target: "gemini",
|
|
50
|
+
label: "Gemini CLI",
|
|
51
|
+
configDir: ".gemini",
|
|
52
|
+
userSkills: (configHome) => join(configHome, "skills"),
|
|
53
|
+
projectSkills: join(".gemini", "skills"),
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
target: "openclaw",
|
|
57
|
+
label: "OpenClaw",
|
|
58
|
+
configDir: ".openclaw",
|
|
59
|
+
userSkills: (configHome) => join(configHome, "skills"),
|
|
60
|
+
projectSkills: "skills",
|
|
61
|
+
extraScan: ({ configHome }) => [
|
|
62
|
+
{ kind: "skill", scope: "user", root: join(configHome, "workspace", "skills") },
|
|
63
|
+
],
|
|
64
|
+
},
|
|
65
|
+
];
|
|
66
|
+
export const ALL_TARGETS = SPECS.map((spec) => spec.target);
|
|
67
|
+
export const DEFAULT_TARGETS = ALL_TARGETS.join(",");
|
|
68
|
+
export async function pathExists(path) {
|
|
69
|
+
try {
|
|
70
|
+
await access(path);
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/** The escape hatch for a layout this package does not know about. */
|
|
78
|
+
export function overrideEnvName(target) {
|
|
79
|
+
return `NIGHTSHIFT_SKILLS_ROOT_${target.toUpperCase()}`;
|
|
80
|
+
}
|
|
81
|
+
export function parseTargets(value) {
|
|
82
|
+
const values = value
|
|
83
|
+
.split(",")
|
|
84
|
+
.map((target) => target.trim().toLowerCase())
|
|
85
|
+
.filter(Boolean);
|
|
86
|
+
const invalid = values.filter((target) => !ALL_TARGETS.includes(target));
|
|
87
|
+
if (invalid.length > 0) {
|
|
88
|
+
throw new Error(`Unknown target(s): ${invalid.join(", ")}. Expected: ${ALL_TARGETS.join(", ")}.`);
|
|
89
|
+
}
|
|
90
|
+
return [...new Set(values)];
|
|
91
|
+
}
|
|
92
|
+
/** `--root claude=/path` entries into a per-target override map. */
|
|
93
|
+
export function parseRootOverrides(entries) {
|
|
94
|
+
const overrides = {};
|
|
95
|
+
for (const entry of entries) {
|
|
96
|
+
const separator = entry.indexOf("=");
|
|
97
|
+
if (separator < 1) {
|
|
98
|
+
throw new Error(`Invalid --root "${entry}"; expected <target>=<path>, e.g. claude=/opt/claude/skills.`);
|
|
99
|
+
}
|
|
100
|
+
const [target] = parseTargets(entry.slice(0, separator));
|
|
101
|
+
const path = entry.slice(separator + 1).trim();
|
|
102
|
+
if (!target || !path) {
|
|
103
|
+
throw new Error(`Invalid --root "${entry}"; expected <target>=<path>, e.g. claude=/opt/claude/skills.`);
|
|
104
|
+
}
|
|
105
|
+
overrides[target] = resolve(path);
|
|
106
|
+
}
|
|
107
|
+
return overrides;
|
|
108
|
+
}
|
|
109
|
+
function configHomeFor(spec, home, env) {
|
|
110
|
+
const override = spec.homeEnv ? env[spec.homeEnv]?.trim() : undefined;
|
|
111
|
+
return override ? resolve(override) : join(home, spec.configDir);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Resolve every target's roots and report which tools are actually present.
|
|
115
|
+
* Detection is what keeps an install from creating config directories for
|
|
116
|
+
* tools the developer does not use.
|
|
117
|
+
*/
|
|
118
|
+
export async function detectTargets(context = {}) {
|
|
119
|
+
const env = context.env ?? process.env;
|
|
120
|
+
const home = resolve(context.home ?? homedir());
|
|
121
|
+
return Promise.all(SPECS.map(async (spec) => {
|
|
122
|
+
const configHome = configHomeFor(spec, home, env);
|
|
123
|
+
const flag = context.roots?.[spec.target];
|
|
124
|
+
const envOverride = env[overrideEnvName(spec.target)]?.trim();
|
|
125
|
+
let userRoot;
|
|
126
|
+
let source;
|
|
127
|
+
if (flag) {
|
|
128
|
+
userRoot = resolve(flag);
|
|
129
|
+
source = "flag";
|
|
130
|
+
}
|
|
131
|
+
else if (envOverride) {
|
|
132
|
+
userRoot = resolve(envOverride);
|
|
133
|
+
source = "env";
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
userRoot = spec.userSkills(configHome, home);
|
|
137
|
+
// The tool's own home variable only counts as the source when it
|
|
138
|
+
// actually moved the skills root; for Codex it moves detection only.
|
|
139
|
+
const fromDefaultHome = spec.userSkills(join(home, spec.configDir), home);
|
|
140
|
+
source = userRoot === fromDefaultHome ? "default" : "env";
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
target: spec.target,
|
|
144
|
+
label: spec.label,
|
|
145
|
+
userRoot,
|
|
146
|
+
projectRoot: spec.projectSkills,
|
|
147
|
+
configHome,
|
|
148
|
+
detected: await pathExists(configHome),
|
|
149
|
+
source,
|
|
150
|
+
};
|
|
151
|
+
}));
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Every root worth scanning for a competing definition of a workflow: each
|
|
155
|
+
* target's own skills roots at both scopes, plus the command directories and
|
|
156
|
+
* cross-tool trees that shadow them.
|
|
157
|
+
*/
|
|
158
|
+
export function scanRoots(detected, projectRoot, home) {
|
|
159
|
+
const roots = [];
|
|
160
|
+
const byTarget = new Map(detected.map((entry) => [entry.target, entry]));
|
|
161
|
+
for (const spec of SPECS) {
|
|
162
|
+
const entry = byTarget.get(spec.target);
|
|
163
|
+
if (!entry)
|
|
164
|
+
continue;
|
|
165
|
+
roots.push({
|
|
166
|
+
target: spec.target,
|
|
167
|
+
kind: "skill",
|
|
168
|
+
scope: "project",
|
|
169
|
+
root: join(projectRoot, entry.projectRoot),
|
|
170
|
+
}, { target: spec.target, kind: "skill", scope: "user", root: entry.userRoot });
|
|
171
|
+
for (const extra of spec.extraScan?.({
|
|
172
|
+
home,
|
|
173
|
+
projectRoot,
|
|
174
|
+
configHome: entry.configHome,
|
|
175
|
+
}) ?? []) {
|
|
176
|
+
roots.push({ target: spec.target, ...extra });
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return roots;
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=skill-roots.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-roots.js","sourceRoot":"","sources":["../src/skill-roots.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wildorder/nightshift",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "The crew that builds while you're gone: walk-away, CI-dispatched engineering programs with a decision ledger instead of gates",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
},
|
|
21
21
|
"files": [
|
|
22
22
|
"dist",
|
|
23
|
+
"skills",
|
|
24
|
+
"templates",
|
|
23
25
|
"README.md",
|
|
24
26
|
"LICENSE"
|
|
25
27
|
],
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: init-project
|
|
3
|
+
description: Initialize a new repository or adopt an existing one into the nightshift structure, including deriving the vision and as-built docs from existing code. Use when a user asks to set up, initialize, or onboard a project for nightshift.
|
|
4
|
+
argument-hint: "[project-root]"
|
|
5
|
+
disable-model-invocation: true
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Initialize or adopt a project
|
|
9
|
+
|
|
10
|
+
Use the supplied argument as the project root. When omitted, use the current
|
|
11
|
+
working directory.
|
|
12
|
+
|
|
13
|
+
## Step 1 — Detect project type
|
|
14
|
+
|
|
15
|
+
Inspect the root. If it contains source code, a populated README, or other
|
|
16
|
+
project documentation, treat this as a **brownfield adoption**. An empty or
|
|
17
|
+
near-empty directory is a **greenfield initialization**.
|
|
18
|
+
|
|
19
|
+
## Step 2 — Ask about version control upfront
|
|
20
|
+
|
|
21
|
+
Check whether the root is inside a git repository
|
|
22
|
+
(`git rev-parse --is-inside-work-tree`). Ask these questions now, alongside
|
|
23
|
+
the project questions — never defer them to a suggested next step:
|
|
24
|
+
|
|
25
|
+
1. If it is **not** a repository: "Initialize a git repository here?" If yes,
|
|
26
|
+
run `git init` before any scaffolding so everything that follows is
|
|
27
|
+
tracked from the start.
|
|
28
|
+
2. In all cases: "Commit the nightshift setup when finished?" If yes, plan to
|
|
29
|
+
commit at the end of this workflow.
|
|
30
|
+
3. Brownfield with uncommitted changes: point out the dirty tree and confirm
|
|
31
|
+
that the final commit should include only the files this setup created or
|
|
32
|
+
modified, keeping the user's in-progress work out of it.
|
|
33
|
+
|
|
34
|
+
Record the answers and apply them in Step 6. Git is not optional decoration
|
|
35
|
+
for nightshift: the decision ledger tags commits and replays roll back to
|
|
36
|
+
them, so if the user declines a repository entirely, warn that decision
|
|
37
|
+
replay, rollback, and per-workstream checkpoints will all be unavailable,
|
|
38
|
+
then proceed.
|
|
39
|
+
|
|
40
|
+
## Step 3 — Gather project information
|
|
41
|
+
|
|
42
|
+
The initializer resolves defaults on its own: name and description from
|
|
43
|
+
`package.json`, and the stack by scanning manifests (package.json,
|
|
44
|
+
tsconfig.json, pyproject.toml, go.mod, Cargo.toml).
|
|
45
|
+
|
|
46
|
+
- Greenfield: ask for the project name, stack, and one-line description, and
|
|
47
|
+
wait for the response.
|
|
48
|
+
- Brownfield: state the values you expect detection to produce and ask only
|
|
49
|
+
about gaps or corrections. Do not re-ask for what the repository already
|
|
50
|
+
declares.
|
|
51
|
+
|
|
52
|
+
### Agent roles
|
|
53
|
+
|
|
54
|
+
Also ask which agent CLI (and model) fills each of nightshift's roles. Never
|
|
55
|
+
leave this implicit — it is the most consequential configuration in the
|
|
56
|
+
project. Each block in `nightshift.config.json` declares a command, args, and
|
|
57
|
+
prompt mode, spelled in that CLI's own vocabulary:
|
|
58
|
+
|
|
59
|
+
1. **Implementer** (`agent`) — executes each workstream. A cheaper model is
|
|
60
|
+
usually the right call, for example
|
|
61
|
+
`{ "command": "claude", "args": ["-p", "--model", "sonnet"], "promptMode": "stdin" }`.
|
|
62
|
+
2. **Decider** (`deciderAgent`) — makes, ratifies, or escalates the decisions
|
|
63
|
+
agents surface during a run, and composes the human notification when one
|
|
64
|
+
is warranted. Decisions are the highest-leverage, lowest-token work in a
|
|
65
|
+
run, so recommend the most capable model available here — and a
|
|
66
|
+
**different provider than the implementer**, because ratifying the
|
|
67
|
+
implementer's own choices with the implementer's own model re-creates the
|
|
68
|
+
self-grading conflict this role exists to remove. If the user picks the
|
|
69
|
+
same provider anyway, note the tradeoff and respect the choice.
|
|
70
|
+
3. **Reviewer** (`reviewerAgent`) — the independent second opinion: spec
|
|
71
|
+
critique before build, test critique after each workstream, whole-program
|
|
72
|
+
review at the end. Recommend a different provider than the implementer.
|
|
73
|
+
Leave the model flag out of its args and let the external CLI run its own
|
|
74
|
+
default — the role wants an uncorrelated second opinion, which that
|
|
75
|
+
default already is, and a named model is one more thing to go stale.
|
|
76
|
+
4. **Recovery** (`recoveryAgent`, optional) — retries failed workstreams. A
|
|
77
|
+
distinct provider also lets a run survive a primary quota, token, or
|
|
78
|
+
session failure. Skip it if the user has no second implementer available.
|
|
79
|
+
|
|
80
|
+
An absent `deciderAgent` does not break runs — implementer defaults simply
|
|
81
|
+
stand unratified, and the run report says so — but recommend configuring it:
|
|
82
|
+
it is the difference between "decisions were made" and "decisions were
|
|
83
|
+
reviewed". An absent `reviewerAgent` disables the review passes entirely and
|
|
84
|
+
is reported, never silently substituted.
|
|
85
|
+
|
|
86
|
+
If the user has no preference, record the host's current model for the
|
|
87
|
+
implementer and recommend a distinct decider and reviewer. Roles can be
|
|
88
|
+
filled in later, but say so explicitly in the report — a run started before
|
|
89
|
+
`agent` is set aborts immediately.
|
|
90
|
+
|
|
91
|
+
Ask the Step 2 and Step 3 questions together in one message when possible.
|
|
92
|
+
|
|
93
|
+
## Step 4 — Run the deterministic initializer
|
|
94
|
+
|
|
95
|
+
```sh
|
|
96
|
+
npx --yes @wildorder/nightshift init --cwd "{project-root}"
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Always invoke the CLI by its full package name. The executable is named
|
|
100
|
+
`nightshift`, but the package is `@wildorder/nightshift` — a bare
|
|
101
|
+
`npm exec nightshift` only resolves when the *shell's* working directory
|
|
102
|
+
already has the package installed, and otherwise queries the registry for the
|
|
103
|
+
unscoped name, which is not this package. That is the common case here,
|
|
104
|
+
because `init` usually targets a project root that has no `node_modules` yet.
|
|
105
|
+
|
|
106
|
+
Add `--name`, `--stack`, or `--description` only for values the user supplied
|
|
107
|
+
or detection cannot provide. Do not manually reproduce the templates; the CLI
|
|
108
|
+
is the canonical write path. It:
|
|
109
|
+
|
|
110
|
+
- creates the standard directories and any missing starter files without
|
|
111
|
+
overwriting existing ones;
|
|
112
|
+
- merges the universal directives into an existing `AGENTS.md` by adding or
|
|
113
|
+
refreshing only the marked `BEGIN/END UNIVERSAL` block, leaving all other
|
|
114
|
+
content untouched;
|
|
115
|
+
- prefills `verify` commands from `package.json` scripts and records existing
|
|
116
|
+
markdown documentation as `contextDocs` in `nightshift.config.json`.
|
|
117
|
+
|
|
118
|
+
The universal directives come from the packaged template by default; a user
|
|
119
|
+
override is honored from `~/.nightshift/universal-directives.md`, or pass
|
|
120
|
+
`--directives <path>` when the user names a directives file.
|
|
121
|
+
|
|
122
|
+
After the initializer runs, write the role decisions from Step 3 into
|
|
123
|
+
`nightshift.config.json`, for example:
|
|
124
|
+
|
|
125
|
+
```json
|
|
126
|
+
"agent": { "command": "claude", "args": ["-p", "--model", "sonnet"], "promptMode": "stdin" },
|
|
127
|
+
"deciderAgent": { "command": "codex", "args": ["exec", "--model", "gpt-5.4"], "promptMode": "stdin" },
|
|
128
|
+
"reviewerAgent": { "command": "codex", "args": ["exec"] }
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Before moving on, re-read the file and confirm the blocks the user chose are
|
|
132
|
+
all present. When adopting a project whose `nightshift.config.json` already
|
|
133
|
+
existed, check it for the same blocks and add whichever the user asked for.
|
|
134
|
+
|
|
135
|
+
## Step 5 — Confirm workflow skills are present
|
|
136
|
+
|
|
137
|
+
Check whether the project already contains installed nightshift skills
|
|
138
|
+
(`.cursor/skills/`, `.claude/skills/`, `skills/`, `.agents/skills/`, or
|
|
139
|
+
`.gemini/skills/`). If any target is present, the team has already chosen
|
|
140
|
+
its targets — do not install more, and do not re-run the installer.
|
|
141
|
+
|
|
142
|
+
Only when no target is installed at all (for example, when initializing a
|
|
143
|
+
different project root than the one this skill is running from), ask the
|
|
144
|
+
user which targets they want and run:
|
|
145
|
+
|
|
146
|
+
```sh
|
|
147
|
+
npx --yes @wildorder/nightshift install --cwd "{project-root}" --targets {chosen}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Never use `--force` unless the user explicitly approves replacing a reported
|
|
151
|
+
skill conflict.
|
|
152
|
+
|
|
153
|
+
## Step 6 — Brownfield enrichment
|
|
154
|
+
|
|
155
|
+
Skip this step for greenfield projects.
|
|
156
|
+
|
|
157
|
+
1. **Snapshot reality.** Scan the codebase — entry points, schema files,
|
|
158
|
+
route registrations, shared contracts, infrastructure config — and write
|
|
159
|
+
`docs/as-built.md`, noting it as the initial adoption snapshot. This
|
|
160
|
+
grounds all later planning in what actually exists.
|
|
161
|
+
2. **Author the vision.** The CLI scaffolded `docs/vision.md` as a template.
|
|
162
|
+
Draft its real content from the as-built snapshot plus a short interview:
|
|
163
|
+
what the product is for, target users, where it is heading, and what is
|
|
164
|
+
explicitly out of scope. Write the draft directly to `docs/vision.md` —
|
|
165
|
+
the file is the review surface; do not paste the content into the
|
|
166
|
+
conversation for approval. Summarize briefly and invite edits, applying
|
|
167
|
+
them to the file in place.
|
|
168
|
+
3. **Complete `AGENTS.md`.** Fill the project Conventions section from
|
|
169
|
+
observed practice — lint and formatter configs, test layout, naming
|
|
170
|
+
patterns — and confirm the generated dependency table reflects the
|
|
171
|
+
packages that matter.
|
|
172
|
+
4. **Curate `contextDocs`.** Review the detected list in
|
|
173
|
+
`nightshift.config.json`: remove documents that are stale or irrelevant
|
|
174
|
+
and add any the user names. Planning reads every listed document, so the
|
|
175
|
+
list should be signal, not bulk.
|
|
176
|
+
|
|
177
|
+
## Step 7 — Apply the version-control decisions
|
|
178
|
+
|
|
179
|
+
Execute what the user approved in Step 2:
|
|
180
|
+
|
|
181
|
+
- If a commit was approved, stage exactly the files this setup created or
|
|
182
|
+
modified and commit with a message like `chore: adopt nightshift`.
|
|
183
|
+
Do not stage unrelated in-progress changes.
|
|
184
|
+
- If the user declined, leave the working tree as is.
|
|
185
|
+
|
|
186
|
+
## Step 8 — Report
|
|
187
|
+
|
|
188
|
+
Report:
|
|
189
|
+
|
|
190
|
+
1. Files created, updated, and skipped.
|
|
191
|
+
2. Skill conflicts, if any.
|
|
192
|
+
3. Warnings from the initializer.
|
|
193
|
+
4. The configured agent roles, and which roles were deferred.
|
|
194
|
+
5. Brownfield: the as-built and vision drafts produced and any assumptions.
|
|
195
|
+
6. Git actions taken (repository initialized, setup committed) or declined.
|
|
196
|
+
7. Next step: invoke `/plan-program` for the first program.
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: plan-program
|
|
3
|
+
description: Plan a new engineering program or product phase, define architecture changes and workstreams, and produce the canonical program document and manifest. Use when turning a feature set into an executable program plan.
|
|
4
|
+
argument-hint: "[program-id] [feature-set-or-phase]"
|
|
5
|
+
disable-model-invocation: true
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Plan a program
|
|
9
|
+
|
|
10
|
+
Plan a new feature set or phase for the current project. This is one of the
|
|
11
|
+
two places a human exercises judgment in nightshift; everything downstream is
|
|
12
|
+
a walk-away run, so the plan you produce here is the last routine chance to
|
|
13
|
+
shape the work interactively. Write every artifact for a human reader first —
|
|
14
|
+
the run's trust surface is its artifacts.
|
|
15
|
+
|
|
16
|
+
## 1. Load project context
|
|
17
|
+
|
|
18
|
+
Read:
|
|
19
|
+
|
|
20
|
+
- The vision document at `visionPath` from `nightshift.config.json`, the
|
|
21
|
+
anchor product vision. Use `docs/vision.md` only when no configuration
|
|
22
|
+
exists.
|
|
23
|
+
- `docs/as-built.md`, when present, for current system state.
|
|
24
|
+
- `AGENTS.md` for repository directives and conventions.
|
|
25
|
+
- Every document listed in `contextDocs` from `nightshift.config.json`, when
|
|
26
|
+
present.
|
|
27
|
+
- When re-planning after a run, the program's run report and decision ledger
|
|
28
|
+
under `docs/programs/` — a prior run's parked workstreams, risk-accepted
|
|
29
|
+
findings, and recorded decisions are planning input, not noise. Plan from
|
|
30
|
+
the repository state that exists now, not from the original pre-program
|
|
31
|
+
design; treat work a prior run verified and committed as current
|
|
32
|
+
architecture rather than scheduling it again, and give replacement work new
|
|
33
|
+
workstream IDs and task-file paths so nothing overwrites the historical
|
|
34
|
+
record.
|
|
35
|
+
|
|
36
|
+
If no vision document exists at the resolved path, stop. Explain that it
|
|
37
|
+
should contain the product description, architecture, target users, API
|
|
38
|
+
surface, data model, phase scope, and technology stack. For a new repository,
|
|
39
|
+
suggest the `init-project` skill.
|
|
40
|
+
|
|
41
|
+
If `docs/as-built.md` is absent, note that this is likely the first program
|
|
42
|
+
and proceed.
|
|
43
|
+
|
|
44
|
+
## 2. Gather requirements
|
|
45
|
+
|
|
46
|
+
Resolve these values from the arguments or ask for anything missing:
|
|
47
|
+
|
|
48
|
+
1. The feature set or phase to build.
|
|
49
|
+
2. A lowercase, hyphenated program ID, such as `phase-2-durable`.
|
|
50
|
+
|
|
51
|
+
Wait for the user's response when questions are required.
|
|
52
|
+
|
|
53
|
+
### Select the execution mode
|
|
54
|
+
|
|
55
|
+
Choose the mode before decomposing the work and record the decision in both
|
|
56
|
+
artifacts. Default to `atomic` unless there is positive causal evidence that
|
|
57
|
+
orchestration is necessary.
|
|
58
|
+
|
|
59
|
+
- **`atomic`** — one cohesive agent working set, one implementation brief,
|
|
60
|
+
and one green commit. Choose this when a capable coding agent can own the
|
|
61
|
+
whole change coherently and intermediate checkpoints add no material safety
|
|
62
|
+
or parallelism.
|
|
63
|
+
- **`orchestrated`** — multiple independently-green workstreams executed as a
|
|
64
|
+
dependency graph. Choose this when the minimum static context physically
|
|
65
|
+
cannot fit one agent session, independent work provides material
|
|
66
|
+
parallelism, independently deployable service boundaries matter, or a
|
|
67
|
+
shared-contract migration requires expand → migrate consumers →
|
|
68
|
+
contract/delete ordering.
|
|
69
|
+
|
|
70
|
+
Do not choose orchestrated merely because the feature is important, spans
|
|
71
|
+
many files, or has a high estimated token count. State the concrete evidence
|
|
72
|
+
in `program.executionModeReason`. In atomic mode create exactly one
|
|
73
|
+
workstream covering the entire program, with no dependencies and task file
|
|
74
|
+
`tasks/{program-id}/implementation.md`. In orchestrated mode use the
|
|
75
|
+
decomposition and checkpoint rules below.
|
|
76
|
+
|
|
77
|
+
## 3. Draft the program document
|
|
78
|
+
|
|
79
|
+
Inspect `docs/programs/` for an existing `*-program.md`. Match its structure
|
|
80
|
+
when one exists. Otherwise use:
|
|
81
|
+
|
|
82
|
+
```markdown
|
|
83
|
+
# {Project Name} — Program Plan ({Program Name})
|
|
84
|
+
|
|
85
|
+
## Program Overview
|
|
86
|
+
**Product:** [From the vision.]
|
|
87
|
+
**Program scope:** [What this program delivers.]
|
|
88
|
+
|
|
89
|
+
## Execution Mode
|
|
90
|
+
**Mode:** atomic | orchestrated
|
|
91
|
+
**Reason:** [Concrete causal evidence for the choice.]
|
|
92
|
+
|
|
93
|
+
## Strategic Goals
|
|
94
|
+
[Three to five outcome-focused bullets.]
|
|
95
|
+
|
|
96
|
+
## Architecture Changes
|
|
97
|
+
[Changes from the system in as-built.md. For the first program, describe the full architecture.]
|
|
98
|
+
|
|
99
|
+
## Technology Choices
|
|
100
|
+
[Only new choices. If none: "No new technology — uses existing stack."]
|
|
101
|
+
|
|
102
|
+
## Anticipated Decisions
|
|
103
|
+
[Choices you can already see the run will face — API shapes, data-model
|
|
104
|
+
tradeoffs, library picks — with your leaning and why. The decider reads
|
|
105
|
+
these; a decision anticipated here is a decision the run handles better.]
|
|
106
|
+
|
|
107
|
+
## Risk Register
|
|
108
|
+
| Risk | Impact | Mitigation |
|
|
109
|
+
|------|--------|------------|
|
|
110
|
+
[Key risks.]
|
|
111
|
+
|
|
112
|
+
## Success Criteria, Workstreams, and Scope
|
|
113
|
+
Canonical in `docs/programs/{program-id}-manifest.json`: success-criteria
|
|
114
|
+
text, the workstream roster, dependencies, sizes, scope, and exclusions live
|
|
115
|
+
there and only there. This document refers to them by id (`SC-xx`, `WS-xx`)
|
|
116
|
+
and never restates their text.
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
The program document carries only what the manifest cannot: narrative
|
|
120
|
+
architecture, causal reasoning, anticipated decisions, and risks. Success
|
|
121
|
+
criteria, the workstream table, the dependency graph, and scope in/out lists
|
|
122
|
+
are manifest data — do not reproduce them here. Two copies of the same fact
|
|
123
|
+
drift apart; one canonical home per fact is a founding rule of this system.
|
|
124
|
+
When this section's rule and an older program document's structure conflict,
|
|
125
|
+
this rule wins: delete the duplicated sections rather than matching them.
|
|
126
|
+
|
|
127
|
+
Write the draft directly to `docs/programs/{program-id}-program.md`. Do not
|
|
128
|
+
paste the document into the conversation or ask for approval before saving —
|
|
129
|
+
the file is the review surface, not the chat window.
|
|
130
|
+
|
|
131
|
+
## 4. Generate the manifest
|
|
132
|
+
|
|
133
|
+
If `docs/programs/` contains an existing `*-manifest.json`, match its schema
|
|
134
|
+
exactly. Otherwise use:
|
|
135
|
+
|
|
136
|
+
```json
|
|
137
|
+
{
|
|
138
|
+
"program": {
|
|
139
|
+
"id": "{program-id}",
|
|
140
|
+
"name": "{Program Name}",
|
|
141
|
+
"description": "{one-line description}",
|
|
142
|
+
"status": "planning",
|
|
143
|
+
"created": "{YYYY-MM-DD}",
|
|
144
|
+
"executionMode": "atomic|orchestrated",
|
|
145
|
+
"executionModeReason": "{concrete causal evidence}"
|
|
146
|
+
},
|
|
147
|
+
"technology": {},
|
|
148
|
+
"successCriteria": [
|
|
149
|
+
{ "id": "SC-01", "description": "{verifiable outcome}" }
|
|
150
|
+
],
|
|
151
|
+
"packages": [
|
|
152
|
+
{
|
|
153
|
+
"name": "{package-name}",
|
|
154
|
+
"path": "{relative-path}",
|
|
155
|
+
"description": "{purpose}"
|
|
156
|
+
}
|
|
157
|
+
],
|
|
158
|
+
"workstreams": [
|
|
159
|
+
{
|
|
160
|
+
"id": "WS-01",
|
|
161
|
+
"name": "{Workstream Name}",
|
|
162
|
+
"taskFile": "tasks/{program-id}/{ws-id}-{slug}.md",
|
|
163
|
+
"status": "not_started",
|
|
164
|
+
"size": "S|M|L",
|
|
165
|
+
"scope": {
|
|
166
|
+
"summary": "{one line: what this workstream owns}",
|
|
167
|
+
"includes": ["{specific thing it covers}"],
|
|
168
|
+
"excludes": ["{specific thing it deliberately does not cover}"]
|
|
169
|
+
},
|
|
170
|
+
"dependencies": [],
|
|
171
|
+
"packages": []
|
|
172
|
+
}
|
|
173
|
+
],
|
|
174
|
+
"outOfScope": []
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Save it directly to `docs/programs/{program-id}-manifest.json`.
|
|
179
|
+
Keep the manifest, program document, and every referenced `taskFile`
|
|
180
|
+
trackable by Git — nightshift tags decisions to commits and replays roll back
|
|
181
|
+
to them, so a plan that exists only in an ignored working tree is neither
|
|
182
|
+
reproducible nor replayable. If the repository ignores `tasks/` or
|
|
183
|
+
`docs/programs/`, remove those ignore rules or explicitly force-add these
|
|
184
|
+
canonical artifacts.
|
|
185
|
+
|
|
186
|
+
For `atomic`, the `workstreams` array contains exactly one whole-program
|
|
187
|
+
workstream (`WS-01`) whose `taskFile` is
|
|
188
|
+
`tasks/{program-id}/implementation.md`. For `orchestrated`, it contains the
|
|
189
|
+
dependency graph described in the program document.
|
|
190
|
+
|
|
191
|
+
### Scope is load-bearing, not decoration
|
|
192
|
+
|
|
193
|
+
`scope` is required on every workstream, and the reason is worth
|
|
194
|
+
understanding before you write them.
|
|
195
|
+
|
|
196
|
+
Authoring spawns one clean agent per workstream, and every one of those
|
|
197
|
+
agents is handed the roster of the whole program — each workstream's id,
|
|
198
|
+
name, and scope, and nothing else. That roster is how an author discovers
|
|
199
|
+
that another workstream already owns something it was about to build, or
|
|
200
|
+
produces something it needs. An author that cannot tell what `WS-12` covers
|
|
201
|
+
will not merely omit a dependency; it will reimplement WS-12's work.
|
|
202
|
+
|
|
203
|
+
So write these for a reader who has no other information about that
|
|
204
|
+
workstream:
|
|
205
|
+
|
|
206
|
+
- **`summary`** — one line naming what it owns. "Auth improvements" tells an
|
|
207
|
+
author nothing. "Issues, rotates, and validates auth tokens" tells it
|
|
208
|
+
everything it needs to decide whether to depend on this.
|
|
209
|
+
- **`includes`** — the specific capabilities inside the boundary.
|
|
210
|
+
- **`excludes`** — the specific capabilities deliberately outside it. These
|
|
211
|
+
carry more weight than they look. An exclusion tells every other author
|
|
212
|
+
that something is *not* covered here, which prevents both duplicated work
|
|
213
|
+
and a requirement that silently belongs to nobody. If a workstream's
|
|
214
|
+
neighbors might reasonably assume it handles something, say that it does
|
|
215
|
+
not.
|
|
216
|
+
|
|
217
|
+
### Every orchestrated workstream is an independently green checkpoint
|
|
218
|
+
|
|
219
|
+
Design the roster so that, starting from a green repository containing only
|
|
220
|
+
its declared dependencies, each workstream can finish with every configured
|
|
221
|
+
build, typecheck, test, and lint command still green. A later workstream must
|
|
222
|
+
never be required to repair an earlier checkpoint — and in nightshift this
|
|
223
|
+
matters doubly, because a failed workstream is parked while everything
|
|
224
|
+
outside its downstream cone still builds; a roster whose checkpoints lean on
|
|
225
|
+
later repair work turns one parked workstream into a broken partial build.
|
|
226
|
+
|
|
227
|
+
For a shared contract migration, prefer an explicit sequence:
|
|
228
|
+
|
|
229
|
+
1. **Expand** — introduce the new contract while preserving compatibility.
|
|
230
|
+
2. **Migrate** — move bounded consumer groups in independently green batches.
|
|
231
|
+
3. **Contract/delete** — remove the compatibility surface only after every
|
|
232
|
+
consumer migration is complete.
|
|
233
|
+
|
|
234
|
+
The destructive cleanup depends on every migration workstream. Do not place
|
|
235
|
+
foundational deletion first merely because it is conceptually central.
|
|
236
|
+
|
|
237
|
+
## 5. Hand off for review
|
|
238
|
+
|
|
239
|
+
Both files now exist on disk. Reply with a short summary only — program
|
|
240
|
+
scope in a sentence, selected execution mode and reason, workstream count,
|
|
241
|
+
critical path, and links to the two file paths — and invite the user to
|
|
242
|
+
review the files and request changes. Apply any requested edits to the files
|
|
243
|
+
in place.
|
|
244
|
+
|
|
245
|
+
Do not create workstream specs in this workflow, and do not offer to. Specs
|
|
246
|
+
are written by the packaged runner, one clean agent per workstream, as
|
|
247
|
+
narrative documents a human can review. Point the user at the run command
|
|
248
|
+
and stop:
|
|
249
|
+
|
|
250
|
+
```sh
|
|
251
|
+
npx --yes @wildorder/nightshift run "{program-id}"
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Authoring a spec inside this session would write it in a context already
|
|
255
|
+
carrying the whole planning conversation, compose its own instructions, and
|
|
256
|
+
then grade its own output — which is what the command exists to prevent.
|
|
257
|
+
|
|
258
|
+
## Rules
|
|
259
|
+
|
|
260
|
+
- Describe only new behavior. Reference `docs/as-built.md` for unchanged
|
|
261
|
+
capabilities.
|
|
262
|
+
- Keep each workstream completable in one agent session and independently
|
|
263
|
+
green; use causal boundaries instead of hard line-count or file-count
|
|
264
|
+
rules.
|
|
265
|
+
- List every package or directory each workstream touches.
|
|
266
|
+
- Use stable `SC-xx` success-criteria IDs for downstream traceability.
|
|
267
|
+
- The manifest is the single source of truth for success criteria,
|
|
268
|
+
workstreams, dependencies, and scope. The program document references them
|
|
269
|
+
by id and never restates their text.
|
|
270
|
+
- Give every workstream a `scope` with a specific `summary`, and state
|
|
271
|
+
`excludes` wherever a neighbor might reasonably assume coverage.
|
|
272
|
+
- Record anticipated decisions in the program document — the decider reads
|
|
273
|
+
them, and a decision anticipated at planning time is handled better at run
|
|
274
|
+
time.
|