nikos 0.0.0-stage → 0.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/LICENSE +21 -0
- package/README.md +32 -2
- package/dist/cli.js +60 -0
- package/dist/commands/bet.js +97 -0
- package/dist/commands/clear.js +100 -0
- package/dist/commands/decide.js +60 -0
- package/dist/commands/decisions.js +71 -0
- package/dist/commands/init.js +72 -0
- package/dist/commands/next.js +35 -0
- package/dist/commands/plan.js +64 -0
- package/dist/commands/show.js +82 -0
- package/dist/commands/state.js +104 -0
- package/dist/commands/validate.js +206 -0
- package/dist/commands/verify.js +95 -0
- package/dist/lib/project.js +42 -0
- package/dist/lint/constitution.js +40 -0
- package/dist/lint/gherkin.js +99 -0
- package/dist/lint/portable.js +66 -0
- package/dist/verify/detect.js +21 -0
- package/docs/format.md +296 -0
- package/docs/gherkin.md +81 -0
- package/docs/install.md +72 -0
- package/docs/intentdocs-mapping.md +117 -0
- package/package.json +44 -4
- package/schemas/bet.schema.json +23 -0
- package/schemas/state.schema.json +34 -0
- package/schemas/storymap.schema.json +43 -0
- package/skills/clear/SKILL.md +55 -0
- package/skills/clear-review/SKILL.md +45 -0
- package/skills/decisions/SKILL.md +45 -0
- package/skills/intent/SKILL.md +39 -0
- package/skills/nikos-mode/SKILL.md +61 -0
- package/skills/nikos-mode/playbooks/answer.md +9 -0
- package/skills/nikos-mode/playbooks/bet.md +14 -0
- package/skills/nikos-mode/playbooks/build-a-story.md +14 -0
- package/skills/nikos-mode/playbooks/change.md +12 -0
- package/skills/nikos-mode/playbooks/idea-to-blueprint.md +16 -0
- package/skills/nikos-mode/playbooks/index.md +13 -0
- package/skills/nikos-mode/playbooks/validate.md +17 -0
- package/skills/nikos-mode/principles/index.md +14 -0
- package/skills/verify/SKILL.md +49 -0
- package/templates/intent/constitution.md +19 -0
- package/templates/intent/decisions.md +12 -0
- package/templates/intent/features/getting-started/first-story.feature +12 -0
- package/templates/intent/plans/.gitkeep +0 -0
- package/templates/intent/state.yaml +4 -0
- package/templates/intent/storymap.yaml +10 -0
- package/templates/plan.md +13 -0
- package/templates/verify/js/cucumber.mjs +6 -0
- package/templates/verify/js/test/steps/first-story.steps.mjs +16 -0
- package/templates/verify/python/behave.ini +4 -0
- package/templates/verify/python/steps/first_story_steps.py +19 -0
- package/templates/verify/ts/cucumber.mjs +6 -0
- package/templates/verify/ts/test/steps/first-story.steps.ts +16 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { readdirSync, readFileSync, statSync } from "node:fs";
|
|
2
|
+
import { join, relative } from "node:path";
|
|
3
|
+
import { parse } from "yaml";
|
|
4
|
+
/** The only frontmatter keys every harness (Claude Code, Cursor, Codex) understands. */
|
|
5
|
+
const ALLOWED_KEYS = ["name", "description"];
|
|
6
|
+
/** Tool names that exist in one harness only. A portable skill describes the action instead. */
|
|
7
|
+
const HARNESS_TOOLS = [
|
|
8
|
+
"TodoWrite", "TodoRead", "TaskCreate", "TaskUpdate", "TaskList", "AskUserQuestion",
|
|
9
|
+
"EnterPlanMode", "ExitPlanMode", "NotebookEdit", "SlashCommand", "todo_write", "update_plan",
|
|
10
|
+
"apply_patch", "$ARGUMENTS", "allowed-tools",
|
|
11
|
+
];
|
|
12
|
+
/** Lint one SKILL.md (or a file it links to) for harness-specific features. */
|
|
13
|
+
export function lintSkill(text, { isEntry = true } = {}) {
|
|
14
|
+
const issues = [];
|
|
15
|
+
let body = text;
|
|
16
|
+
if (isEntry) {
|
|
17
|
+
const m = /^---\n([\s\S]*?)\n---\n/.exec(text);
|
|
18
|
+
if (!m) {
|
|
19
|
+
issues.push({ level: "error", message: "has no frontmatter", hint: "start with ---, name: and description:, then ---" });
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
body = text.slice(m[0].length);
|
|
23
|
+
let meta = {};
|
|
24
|
+
try {
|
|
25
|
+
meta = parse(m[1]) ?? {};
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
issues.push({ level: "error", message: `frontmatter isn't valid YAML: ${err.message.split("\n")[0]}` });
|
|
29
|
+
}
|
|
30
|
+
for (const key of Object.keys(meta)) {
|
|
31
|
+
if (!ALLOWED_KEYS.includes(key)) {
|
|
32
|
+
issues.push({ level: "error", message: `frontmatter key '${key}' isn't portable`, hint: "use only name and description" });
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
for (const key of ALLOWED_KEYS) {
|
|
36
|
+
if (typeof meta[key] !== "string" || !meta[key].trim()) {
|
|
37
|
+
issues.push({ level: "error", message: `frontmatter is missing '${key}'` });
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
for (const tool of HARNESS_TOOLS) {
|
|
43
|
+
if (body.includes(tool)) {
|
|
44
|
+
issues.push({ level: "error", message: `names the harness-only tool '${tool}'`, hint: "describe the action (\"your task list\") instead" });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return issues;
|
|
48
|
+
}
|
|
49
|
+
/** Lint every Markdown file under a skills/ folder. SKILL.md files are entry points and need frontmatter. */
|
|
50
|
+
export function lintSkills(dir) {
|
|
51
|
+
const issues = [];
|
|
52
|
+
const walk = (d) => {
|
|
53
|
+
for (const name of readdirSync(d)) {
|
|
54
|
+
const path = join(d, name);
|
|
55
|
+
if (statSync(path).isDirectory())
|
|
56
|
+
walk(path);
|
|
57
|
+
else if (name.endsWith(".md")) {
|
|
58
|
+
const file = relative(dir, path);
|
|
59
|
+
for (const i of lintSkill(readFileSync(path, "utf8"), { isEntry: name === "SKILL.md" }))
|
|
60
|
+
issues.push({ ...i, file });
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
walk(dir);
|
|
65
|
+
return issues;
|
|
66
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
const PYTHON_MARKERS = ["pyproject.toml", "requirements.txt", "setup.py", "setup.cfg", "Pipfile"];
|
|
4
|
+
/** Pick the Cucumber runner's stack from the files at the repo root. Undefined means ask the person. */
|
|
5
|
+
export function detectStack(root) {
|
|
6
|
+
const pkgPath = join(root, "package.json");
|
|
7
|
+
if (existsSync(pkgPath)) {
|
|
8
|
+
let pkg = {};
|
|
9
|
+
try {
|
|
10
|
+
pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
// An unreadable package.json is still a JS project.
|
|
14
|
+
}
|
|
15
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
16
|
+
return existsSync(join(root, "tsconfig.json")) || "typescript" in deps ? "ts" : "js";
|
|
17
|
+
}
|
|
18
|
+
if (PYTHON_MARKERS.some((f) => existsSync(join(root, f))))
|
|
19
|
+
return "python";
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
package/docs/format.md
ADDED
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
# The intent/ format
|
|
2
|
+
|
|
3
|
+
Format version: **1**
|
|
4
|
+
|
|
5
|
+
nikOS keeps a project's intent — what it's for, what to build, how it's going —
|
|
6
|
+
in an `intent/` folder at the root of the repo. Everything is plain text, so
|
|
7
|
+
agents, humans, git and code review all see the same thing.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
intent/
|
|
11
|
+
constitution.md the project's vision
|
|
12
|
+
storymap.yaml activities, releases and story order
|
|
13
|
+
features/
|
|
14
|
+
<activity>/
|
|
15
|
+
<story-slug>.feature one story, its criteria as scenarios
|
|
16
|
+
plans/
|
|
17
|
+
<story-id>.v<N>.md versioned implementation plans
|
|
18
|
+
decisions.md append-only decision log
|
|
19
|
+
state.yaml status, blockers and the run queue
|
|
20
|
+
outreach/ optional, drafts from the validate playbook
|
|
21
|
+
<date>-<channel>.md
|
|
22
|
+
bets/ optional, time-boxed bets (see Bets)
|
|
23
|
+
<bet-id>.md
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Two rules hold across every file:
|
|
27
|
+
|
|
28
|
+
1. **Specs describe intent, not implementation.** Feature files and the
|
|
29
|
+
constitution say what and why. File paths, frameworks and code belong in
|
|
30
|
+
plans and decisions.
|
|
31
|
+
2. **Changing state never edits a spec.** Status, owners, blockers and dates
|
|
32
|
+
live in `state.yaml`, so a spec's diff only changes when the intent does.
|
|
33
|
+
|
|
34
|
+
Every file below is listed with its **purpose**, **path** and **format**.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## constitution.md
|
|
39
|
+
|
|
40
|
+
**Purpose:** the project's vision, answered once and refined as you learn.
|
|
41
|
+
Every story should trace back to it.
|
|
42
|
+
|
|
43
|
+
**Path:** `intent/constitution.md`
|
|
44
|
+
|
|
45
|
+
**Format:** Markdown with YAML front matter and exactly these five `##`
|
|
46
|
+
sections, in this order:
|
|
47
|
+
|
|
48
|
+
```markdown
|
|
49
|
+
---
|
|
50
|
+
name: Hello Todo
|
|
51
|
+
idea: A todo list that only shows today's three most important tasks.
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Users
|
|
55
|
+
Who it's for.
|
|
56
|
+
|
|
57
|
+
## Problem
|
|
58
|
+
What hurts today, in their words.
|
|
59
|
+
|
|
60
|
+
## Switch
|
|
61
|
+
What makes them switch now, and from what.
|
|
62
|
+
|
|
63
|
+
## First
|
|
64
|
+
The smallest first version that proves it.
|
|
65
|
+
|
|
66
|
+
## Proof
|
|
67
|
+
How you'll know it's working.
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Further `##` sections may follow the five required ones. The
|
|
71
|
+
idea-to-blueprint playbook writes `## Jobs to be done` and
|
|
72
|
+
`## Founding hypothesis`; the validate playbook writes `## Validation`, one entry per round of
|
|
73
|
+
outreach, and keeps its drafts in `intent/outreach/`. A draft is marked
|
|
74
|
+
`Status: draft, not sent` until the founder signs it off; the founder sends it.
|
|
75
|
+
`nikos validate` checks the front matter has `name` and `idea`, and that the
|
|
76
|
+
five vision sections come first, in order, and aren't empty.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## storymap.yaml
|
|
81
|
+
|
|
82
|
+
**Purpose:** the shape of the product: activities (columns), releases (rows)
|
|
83
|
+
and the order stories should be built in. It is an index; the stories
|
|
84
|
+
themselves live in feature files.
|
|
85
|
+
|
|
86
|
+
**Path:** `intent/storymap.yaml`
|
|
87
|
+
|
|
88
|
+
**Format:** YAML.
|
|
89
|
+
|
|
90
|
+
```yaml
|
|
91
|
+
format_version: 1
|
|
92
|
+
project: hello-todo
|
|
93
|
+
key: HT # story id prefix: HT-1, HT-2 …
|
|
94
|
+
activities:
|
|
95
|
+
- id: tasks # slug, matches the features/<activity>/ folder
|
|
96
|
+
title: Manage tasks
|
|
97
|
+
releases:
|
|
98
|
+
- number: 1
|
|
99
|
+
title: MVP
|
|
100
|
+
stories: [HT-1, HT-2] # build order within the release
|
|
101
|
+
- number: 2
|
|
102
|
+
title: Enhancements
|
|
103
|
+
stories: [HT-3]
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Rules:
|
|
107
|
+
|
|
108
|
+
- Every story id appears in exactly one release.
|
|
109
|
+
- Every story id has exactly one feature file and one `state.yaml` entry.
|
|
110
|
+
- Release numbers start at 1 and have no gaps.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## features/<activity>/<story-slug>.feature
|
|
115
|
+
|
|
116
|
+
**Purpose:** one user story and its acceptance criteria, written so they
|
|
117
|
+
run as tests.
|
|
118
|
+
|
|
119
|
+
**Path:** `intent/features/<activity-id>/<story-slug>.feature`, where the
|
|
120
|
+
activity id matches `storymap.yaml` and the slug is the story title in
|
|
121
|
+
kebab-case.
|
|
122
|
+
|
|
123
|
+
**Format:** Gherkin. One `Feature` per file. The description holds the user
|
|
124
|
+
story; each acceptance criterion is a `Scenario` (or `Scenario Outline`)
|
|
125
|
+
titled with its label. Full rules are in [gherkin.md](gherkin.md).
|
|
126
|
+
|
|
127
|
+
```gherkin
|
|
128
|
+
@HT-1 @release-1 @must @activity-tasks
|
|
129
|
+
Feature: Add a task
|
|
130
|
+
|
|
131
|
+
As a busy person
|
|
132
|
+
I want to add a task in one step
|
|
133
|
+
So that capturing it is faster than forgetting it
|
|
134
|
+
|
|
135
|
+
@AC1 @must
|
|
136
|
+
Scenario: AC1 — Adding a task shows it at the top
|
|
137
|
+
Given my list is empty
|
|
138
|
+
When I add the task "Call the bank"
|
|
139
|
+
Then I see "Call the bank" at the top of my list
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## plans/<story-id>.v<N>.md
|
|
145
|
+
|
|
146
|
+
**Purpose:** how a story will be built. Plans are versioned: a new approach
|
|
147
|
+
is a new file, so history is never lost.
|
|
148
|
+
|
|
149
|
+
**Path:** `intent/plans/<story-id>.v<N>.md`, for example
|
|
150
|
+
`intent/plans/HT-1.v2.md`. `N` starts at 1 and increases by one.
|
|
151
|
+
|
|
152
|
+
**Format:** Markdown with front matter, then one `##` section per step:
|
|
153
|
+
|
|
154
|
+
```markdown
|
|
155
|
+
---
|
|
156
|
+
story: HT-1
|
|
157
|
+
version: 2
|
|
158
|
+
created: 2026-11-03
|
|
159
|
+
supersedes: 1 # omit for v1
|
|
160
|
+
summary: One to three plain sentences on the approach.
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## 1. Store tasks locally
|
|
164
|
+
**Why:** tasks survive a refresh.
|
|
165
|
+
**Criteria:** AC1
|
|
166
|
+
**Files:** src/store.ts
|
|
167
|
+
|
|
168
|
+
Notes for the agent.
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
These fields match intentdocs plans one to one (see the mapping doc).
|
|
172
|
+
|
|
173
|
+
Start a new version with `nikos plan new <story-id>`. It writes the next
|
|
174
|
+
`v<N>` from a template, sets `supersedes`, and refuses to overwrite an
|
|
175
|
+
existing file.
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## decisions.md
|
|
180
|
+
|
|
181
|
+
**Purpose:** why things are the way they are. Append-only; never rewrite an
|
|
182
|
+
entry, add a new one that supersedes it.
|
|
183
|
+
|
|
184
|
+
**Path:** `intent/decisions.md`
|
|
185
|
+
|
|
186
|
+
**Format:** Markdown. One `##` entry per decision, newest last:
|
|
187
|
+
|
|
188
|
+
```markdown
|
|
189
|
+
## 2026-11-03 — Store tasks in localStorage (HT-1)
|
|
190
|
+
**Category:** architecture
|
|
191
|
+
**Supersedes:** none
|
|
192
|
+
|
|
193
|
+
Why this, and what we rejected.
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
The heading is `date — title (story id)`; the story id is optional for
|
|
197
|
+
project-wide decisions. Category is one of `product`, `architecture`,
|
|
198
|
+
`design`, `process`.
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## state.yaml
|
|
203
|
+
|
|
204
|
+
**Purpose:** everything that changes as work happens: status, who's on it,
|
|
205
|
+
blockers, and the run queue. Kept apart so specs stay clean.
|
|
206
|
+
|
|
207
|
+
**Path:** `intent/state.yaml`
|
|
208
|
+
|
|
209
|
+
**Format:** YAML.
|
|
210
|
+
|
|
211
|
+
```yaml
|
|
212
|
+
format_version: 1
|
|
213
|
+
stories:
|
|
214
|
+
HT-1:
|
|
215
|
+
status: done # todo | in_progress | needs_rework | done
|
|
216
|
+
claimed_by: claude-code # optional
|
|
217
|
+
plan_version: 2 # optional, the plan in use
|
|
218
|
+
blockers: [] # optional, plain sentences
|
|
219
|
+
updated: 2026-11-03
|
|
220
|
+
HT-2:
|
|
221
|
+
status: todo
|
|
222
|
+
run: # optional, an ordered build queue
|
|
223
|
+
queue: [HT-2]
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Status moves `todo → in_progress → done`, or `in_progress → needs_rework →
|
|
227
|
+
in_progress`. Only a passing verification can set `done` (see the
|
|
228
|
+
build-a-story playbook).
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## outreach/<date>-<channel>.md (optional)
|
|
233
|
+
|
|
234
|
+
**Purpose:** outreach drafted to test the idea with real people, kept so the
|
|
235
|
+
founder can review it and the results can be traced back to it.
|
|
236
|
+
|
|
237
|
+
**Path:** `intent/outreach/<yyyy-mm-dd>-<channel>.md`
|
|
238
|
+
|
|
239
|
+
**Format:** Markdown. The first line is the status: `Status: draft, not sent`
|
|
240
|
+
until the founder signs it off, then `Status: signed off <date>, for the
|
|
241
|
+
person to send`. Then who it's for, the message, the questions to ask and,
|
|
242
|
+
optionally, a demo or reel script. Written by the validate playbook; the
|
|
243
|
+
founder sends it, never the agent.
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## bets/<bet-id>.md (optional)
|
|
248
|
+
|
|
249
|
+
**Purpose:** a time-boxed bet that a set of stories will move a measure.
|
|
250
|
+
|
|
251
|
+
**Path:** `intent/bets/<bet-id>.md`, where `<bet-id>` is lowercase words
|
|
252
|
+
joined by hyphens.
|
|
253
|
+
|
|
254
|
+
**Format:** Markdown with YAML front matter, then free-form notes. Create one
|
|
255
|
+
with `nikos bet new`; the bet playbook frames and closes it.
|
|
256
|
+
|
|
257
|
+
```markdown
|
|
258
|
+
---
|
|
259
|
+
id: faster-reorder
|
|
260
|
+
hypothesis: We believe drag to reorder will make people plan their day in the app because they reorder on paper today.
|
|
261
|
+
key_result: Share of daily users who reorder at least once
|
|
262
|
+
expected_uplift: from 10% to 30%
|
|
263
|
+
time_box: 2026-12-01
|
|
264
|
+
blockers: []
|
|
265
|
+
stories: [HT-3]
|
|
266
|
+
status: open
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## Why we think so
|
|
270
|
+
The evidence behind the hypothesis.
|
|
271
|
+
|
|
272
|
+
## Outcome
|
|
273
|
+
Filled in when the time box ends.
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
| Field | Required | Meaning |
|
|
277
|
+
| --- | --- | --- |
|
|
278
|
+
| `id` | yes | Matches the file name |
|
|
279
|
+
| `hypothesis` | yes | What you believe and why |
|
|
280
|
+
| `key_result` | yes | The one measure that says whether it worked |
|
|
281
|
+
| `expected_uplift` | yes | How far you expect it to move, from what to what |
|
|
282
|
+
| `time_box` | yes | End date, `YYYY-MM-DD` |
|
|
283
|
+
| `blockers` | yes | What stands in the way; `[]` if nothing |
|
|
284
|
+
| `stories` | yes | At least one story id; each must be in `storymap.yaml` |
|
|
285
|
+
| `status` | yes | `open \| won \| lost \| killed` |
|
|
286
|
+
|
|
287
|
+
`nikos validate` checks every field against `schemas/bet.schema.json`, that
|
|
288
|
+
the id matches the file name, and that every linked story exists.
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## Versioning this format
|
|
293
|
+
|
|
294
|
+
`format_version` in `storymap.yaml` and `state.yaml` is the version of this
|
|
295
|
+
document. Breaking changes bump it; `nikos validate` reads it and explains
|
|
296
|
+
any migration needed.
|
package/docs/gherkin.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Writing stories as feature files
|
|
2
|
+
|
|
3
|
+
Every story is one Gherkin `.feature` file in
|
|
4
|
+
`intent/features/<activity>/<story-slug>.feature`. The file is both the spec
|
|
5
|
+
and the test: each acceptance criterion is a scenario that Cucumber can run.
|
|
6
|
+
`nikos validate` checks all the rules on this page.
|
|
7
|
+
|
|
8
|
+
## The shape of a story
|
|
9
|
+
|
|
10
|
+
```gherkin
|
|
11
|
+
@HT-1 @release-1 @must @activity-tasks @effort-S
|
|
12
|
+
Feature: Add a task
|
|
13
|
+
|
|
14
|
+
As a busy person
|
|
15
|
+
I want to add a task in one step
|
|
16
|
+
So that capturing it is faster than forgetting it
|
|
17
|
+
|
|
18
|
+
@AC1 @must
|
|
19
|
+
Scenario: AC1 — Adding a task shows it at the top
|
|
20
|
+
Given my list is empty
|
|
21
|
+
When I add the task "Call the bank"
|
|
22
|
+
Then I see "Call the bank" at the top of my list
|
|
23
|
+
|
|
24
|
+
@AC2 @should
|
|
25
|
+
Scenario: AC2 — Blank tasks are ignored
|
|
26
|
+
Given my list is empty
|
|
27
|
+
When I add the task ""
|
|
28
|
+
Then my list is still empty
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Rules
|
|
32
|
+
|
|
33
|
+
**One story per file.** Exactly one `Feature`, and exactly one story id tag.
|
|
34
|
+
|
|
35
|
+
**The user story goes in the Feature description.** Three lines under
|
|
36
|
+
`Feature:`, starting `As a`, `I want` and `So that`.
|
|
37
|
+
|
|
38
|
+
**Each acceptance criterion is a scenario.** Tag it `@AC1`, `@AC2` … and
|
|
39
|
+
start its title with the same label (`AC1 — …`). Labels are unique within
|
|
40
|
+
the file. A `Scenario Outline` counts as one criterion. Scenarios may sit
|
|
41
|
+
inside a `Rule:` block.
|
|
42
|
+
|
|
43
|
+
**Every scenario has a When and a Then.** `Given` is optional.
|
|
44
|
+
|
|
45
|
+
**Priority is a tag.** Exactly one of `@must`, `@should` or `@could` on the
|
|
46
|
+
Feature (the story's priority), and optionally one on each scenario (the
|
|
47
|
+
criterion's priority).
|
|
48
|
+
|
|
49
|
+
## Allowed Feature tags
|
|
50
|
+
|
|
51
|
+
| Tag | Meaning | Required |
|
|
52
|
+
|---|---|---|
|
|
53
|
+
| `@HT-1` | story id, using the project key | yes |
|
|
54
|
+
| `@release-N` | release the story is in | yes |
|
|
55
|
+
| `@must` / `@should` / `@could` | story priority | yes |
|
|
56
|
+
| `@activity-<id>` | activity, matching the folder name | no |
|
|
57
|
+
| `@effort-XS` … `@effort-XL` | size estimate | no |
|
|
58
|
+
|
|
59
|
+
Anything else is a warning, so you notice typos.
|
|
60
|
+
|
|
61
|
+
## Never put status in a feature
|
|
62
|
+
|
|
63
|
+
Tags like `@todo`, `@wip`, `@in-progress`, `@done`, `@blocked` or `@ready`
|
|
64
|
+
are errors. Status, owners, blockers and dates live in `intent/state.yaml`,
|
|
65
|
+
so a feature file only changes when the intent changes and its git history
|
|
66
|
+
reads as a history of decisions about the product.
|
|
67
|
+
|
|
68
|
+
## Keep it about behaviour, not implementation
|
|
69
|
+
|
|
70
|
+
Write steps the way a user would describe what happens: "When I add the task
|
|
71
|
+
'Call the bank'", not "When I POST to /api/tasks". Implementation detail
|
|
72
|
+
belongs in the story's plan. `nikos clear` flags file paths, endpoints and
|
|
73
|
+
framework names in feature text.
|
|
74
|
+
|
|
75
|
+
## Checking your work
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
npx nikos validate
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Errors block (exit code 1); warnings are shown but don't fail.
|
package/docs/install.md
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Installing nikOS in your agent tool
|
|
2
|
+
|
|
3
|
+
nikOS is one set of skills in `skills/`. Each tool reads its own small
|
|
4
|
+
manifest, and every manifest points at that same folder, so no skill file is
|
|
5
|
+
copied per tool.
|
|
6
|
+
|
|
7
|
+
| Tool | Manifest | Install |
|
|
8
|
+
| --- | --- | --- |
|
|
9
|
+
| Claude Code | `.claude-plugin/plugin.json`, `.claude-plugin/marketplace.json` | `/plugin install nikos --marketplace nikovijay/NikOS` |
|
|
10
|
+
| Codex | `.codex-plugin/plugin.json`, `.agents/plugins/marketplace.json` | `codex plugin marketplace add nikovijay/NikOS` |
|
|
11
|
+
| Cursor | `.cursor-plugin/plugin.json` | Add the repo as a marketplace (below) |
|
|
12
|
+
|
|
13
|
+
After installing, ask the agent to plan, build or check a story. The
|
|
14
|
+
`nikos-mode` skill picks the playbook.
|
|
15
|
+
|
|
16
|
+
## Claude Code
|
|
17
|
+
|
|
18
|
+
In a session:
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
/plugin install nikos --marketplace nikovijay/NikOS
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
That works in one step on Claude Code 2.1.275 or later. On older versions,
|
|
25
|
+
add the marketplace first, then install:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
/plugin marketplace add nikovijay/NikOS
|
|
29
|
+
/plugin install nikos@nikos
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
From a terminal, the same commands are `claude plugin marketplace add
|
|
33
|
+
nikovijay/NikOS` and `claude plugin install nikos@nikos`.
|
|
34
|
+
|
|
35
|
+
## Codex
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
codex plugin marketplace add nikovijay/NikOS
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Then install nikOS from the Plugins directory. Update it later with `codex
|
|
42
|
+
plugin marketplace upgrade`.
|
|
43
|
+
|
|
44
|
+
## Cursor
|
|
45
|
+
|
|
46
|
+
Cursor installs plugins from a marketplace in its settings rather than a
|
|
47
|
+
command. Add `https://github.com/nikovijay/NikOS` as a marketplace (Plugins,
|
|
48
|
+
then Add Marketplace, then Import from Repo), and install nikOS from it.
|
|
49
|
+
|
|
50
|
+
To try it without a marketplace, copy the repo to
|
|
51
|
+
`~/.cursor/plugins/local/nikos` and run "Developer: Reload Window".
|
|
52
|
+
|
|
53
|
+
## The command-line tool
|
|
54
|
+
|
|
55
|
+
The skills run the `nikos` command. When it isn't installed, they run it
|
|
56
|
+
through `npx -y nikos`, so nothing has to be installed globally. To install
|
|
57
|
+
it anyway: `npm install -g nikos`.
|
|
58
|
+
|
|
59
|
+
## Formats checked
|
|
60
|
+
|
|
61
|
+
Plugin formats change often. These were read on 2026-11-04 (no page showed a
|
|
62
|
+
version):
|
|
63
|
+
|
|
64
|
+
- Claude Code: https://code.claude.com/docs/en/plugins-reference and
|
|
65
|
+
https://code.claude.com/docs/en/plugins/marketplace-reference. Checked with
|
|
66
|
+
`claude plugin validate .` on Claude Code 2.1.318.
|
|
67
|
+
- Cursor: https://cursor.com/docs/reference/plugins
|
|
68
|
+
- Codex: https://developers.openai.com/plugins/build/plugins
|
|
69
|
+
|
|
70
|
+
All three find skills as `skills/<name>/SKILL.md` at the plugin root.
|
|
71
|
+
`test/install.test.ts` checks the manifests agree with each other and with
|
|
72
|
+
the skills folder. `evals/install.md` records each install tried.
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Mapping intent/ to intentdocs
|
|
2
|
+
|
|
3
|
+
`intentdocs push` and `intentdocs pull` translate between the local
|
|
4
|
+
`intent/` folder and an intentdocs project. This table is the contract: every
|
|
5
|
+
local field maps to an intentdocs field, or is marked **local-only**.
|
|
6
|
+
Fields that exist only in intentdocs are listed at the end.
|
|
7
|
+
|
|
8
|
+
## Project and vision
|
|
9
|
+
|
|
10
|
+
| Local | intentdocs | Notes |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| `constitution.md` front matter `name` | project name | |
|
|
13
|
+
| `constitution.md` front matter `idea` | project idea | |
|
|
14
|
+
| `## Users` | vision `users` | |
|
|
15
|
+
| `## Problem` | vision `problem` | |
|
|
16
|
+
| `## Switch` | vision `switch` | |
|
|
17
|
+
| `## First` | vision `first` | |
|
|
18
|
+
| `## Proof` | vision `proof` | |
|
|
19
|
+
| extra `##` sections (e.g. `## Validation`) | **local-only** | pushed as a project note in a later format version |
|
|
20
|
+
| `storymap.yaml` `key` | project story key prefix | e.g. `HT` → `HT-1` |
|
|
21
|
+
| `storymap.yaml` `project` | **local-only** | slug used for paths |
|
|
22
|
+
| `storymap.yaml` `format_version` | **local-only** | |
|
|
23
|
+
|
|
24
|
+
## Activities and releases
|
|
25
|
+
|
|
26
|
+
| Local | intentdocs | Notes |
|
|
27
|
+
|---|---|---|
|
|
28
|
+
| `activities[].title` | story `activity` | intentdocs groups by activity name |
|
|
29
|
+
| `activities[].id` | **local-only** | folder slug under `features/` |
|
|
30
|
+
| `releases[].number` | release order | |
|
|
31
|
+
| `releases[].title` | release label | |
|
|
32
|
+
| `releases[].stories` order | build sequence within the release | |
|
|
33
|
+
|
|
34
|
+
## Stories (feature files)
|
|
35
|
+
|
|
36
|
+
| Local | intentdocs | Notes |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| story id tag, e.g. `@HT-1` | story `key` | |
|
|
39
|
+
| `Feature:` title | story `title` | |
|
|
40
|
+
| description `As a …` | `as_a` | |
|
|
41
|
+
| description `I want …` | `i_want` | |
|
|
42
|
+
| description `So that …` | `so_that` | |
|
|
43
|
+
| `@must` / `@should` / `@could` on the Feature | story `priority` | |
|
|
44
|
+
| `@release-N` | story `release` | must agree with `storymap.yaml` |
|
|
45
|
+
| `@activity-<id>` | story `activity` | resolved to the activity title |
|
|
46
|
+
| `@effort-XS` … `@effort-XL` (optional) | story `effort` | |
|
|
47
|
+
| file path | **local-only** | |
|
|
48
|
+
|
|
49
|
+
## Acceptance criteria (scenarios)
|
|
50
|
+
|
|
51
|
+
| Local | intentdocs | Notes |
|
|
52
|
+
|---|---|---|
|
|
53
|
+
| `@AC<n>` tag and scenario title prefix | criterion `label` | |
|
|
54
|
+
| scenario title after the label + its steps | criterion `text` | pushed as one Given/When/Then sentence |
|
|
55
|
+
| `@must` / `@should` / `@could` on the Scenario | criterion `priority` | |
|
|
56
|
+
| scenario pass/fail from `nikos verify` | criterion `last_result` | sent via report_criteria |
|
|
57
|
+
| step definition file and test name | linked tests | sent via save_tests |
|
|
58
|
+
|
|
59
|
+
## Plans
|
|
60
|
+
|
|
61
|
+
| Local | intentdocs | Notes |
|
|
62
|
+
|---|---|---|
|
|
63
|
+
| file `plans/<id>.v<N>.md` | plan `version` N | |
|
|
64
|
+
| front matter `summary` | plan `summary` | |
|
|
65
|
+
| `## <n>. <title>` | step `title` | |
|
|
66
|
+
| `**Why:**` | step `why` | |
|
|
67
|
+
| `**Criteria:**` | step `criteria` | labels resolved to criterion ids |
|
|
68
|
+
| `**Files:**` | step `files` | |
|
|
69
|
+
| `**Tests:**` (optional) | step `tests` | |
|
|
70
|
+
| `**Needs you:**` (optional) | step `needs_you.question` | |
|
|
71
|
+
| body text | step `agent_notes` | |
|
|
72
|
+
| front matter `risk` (optional) | plan `risk` | |
|
|
73
|
+
| front matter `introduces` (optional) | plan `introduces` | new dependencies |
|
|
74
|
+
| front matter `supersedes`, `created` | **local-only** | intentdocs keeps its own history |
|
|
75
|
+
|
|
76
|
+
## Decisions
|
|
77
|
+
|
|
78
|
+
| Local | intentdocs | Notes |
|
|
79
|
+
|---|---|---|
|
|
80
|
+
| entry heading title | decision `title` | |
|
|
81
|
+
| entry body | decision `description` | |
|
|
82
|
+
| `**Category:**` | decision `category` | |
|
|
83
|
+
| entry date | decision created date | |
|
|
84
|
+
| story id in heading | decision linked story | |
|
|
85
|
+
| `**Supersedes:**` | **local-only** | intentdocs amends instead |
|
|
86
|
+
|
|
87
|
+
## State
|
|
88
|
+
|
|
89
|
+
Status isn't pushed: intentdocs sets it. New stories start as To do,
|
|
90
|
+
existing ones keep theirs, and they move through build and acceptance in
|
|
91
|
+
intentdocs. `intentdocs push` still sends the local status, and says how
|
|
92
|
+
many it ignored.
|
|
93
|
+
|
|
94
|
+
| Local | intentdocs | Notes |
|
|
95
|
+
|---|---|---|
|
|
96
|
+
| `status: todo` | **not pushed** | intentdocs sets status |
|
|
97
|
+
| `status: in_progress` | **not pushed** | intentdocs sets status |
|
|
98
|
+
| `status: needs_rework` | **not pushed** | intentdocs sets status |
|
|
99
|
+
| `status: done` | **not pushed** | intentdocs sets status; its own done needs acceptance after build |
|
|
100
|
+
| `blockers` | raised blockers | |
|
|
101
|
+
| `plan_version` | current plan version | |
|
|
102
|
+
| `claimed_by` | story claim | |
|
|
103
|
+
| `run.queue` | build run story order | |
|
|
104
|
+
| `updated` | **local-only** | |
|
|
105
|
+
|
|
106
|
+
## Bets
|
|
107
|
+
|
|
108
|
+
| Local | intentdocs | Notes |
|
|
109
|
+
|---|---|---|
|
|
110
|
+
| `outreach/*.md`, `## Validation` | **local-only** | intentdocs keeps the vision answers, not outreach drafts or results |
|
|
111
|
+
| `bets/*.md` | **local-only** | intentdocs has no bet object yet |
|
|
112
|
+
|
|
113
|
+
## intentdocs-only (not pulled into files)
|
|
114
|
+
|
|
115
|
+
Comments, design references, plan approvals, story approval after build,
|
|
116
|
+
founder to-dos, releases readiness checks, collaborators and workspace
|
|
117
|
+
settings stay in intentdocs. `intentdocs pull` never writes them to the repo.
|