@pilotspace/add 1.16.0 → 1.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/README.md +2 -2
- package/package.json +1 -1
- package/skill/add/phases/0-setup.md +1 -1
- package/tooling/add.py +17 -0
- package/tooling/add_engine/constants.py +9 -0
- package/tooling/add_engine/io_state.py +14 -0
- package/tooling/templates/personas/_template.md.tmpl +22 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,24 @@ All notable changes to the ADD method (`@pilotspace/add` on npm,
|
|
|
4
4
|
`pilotspace-add` on PyPI) are documented here. The format follows
|
|
5
5
|
[Keep a Changelog](https://keepachangelog.com/); versions follow semver.
|
|
6
6
|
|
|
7
|
+
## [1.16.1] — 2026-07-04
|
|
8
|
+
|
|
9
|
+
Patch: two loose, additive persona-loop improvements found while dogfooding
|
|
10
|
+
ADD in a real consumer project. No engine validation changed; no CLI
|
|
11
|
+
behavior changed; nothing removed or renamed.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
- **Persona seed nudge is project-scoped.** The setup/status/check/new-milestone
|
|
15
|
+
hint to draft a project's missing personas now names the project by scope
|
|
16
|
+
instead of a generic reminder, so it fires once per genuinely-uncovered
|
|
17
|
+
project rather than repeating a one-size-fits-all message.
|
|
18
|
+
- **Persona schema template recommends `flow:` + `## Abilities`.** A seeded
|
|
19
|
+
persona can now state which ADD apply-surface (design/build/advisor) loads
|
|
20
|
+
it and what it can concretely do, distinct from `## Critical Rules`
|
|
21
|
+
(always-enforced constraints) and the optional `## Playbook`. Recommended,
|
|
22
|
+
not engine-checked — existing personas anywhere stay schema-conformant
|
|
23
|
+
with no forced re-seed.
|
|
24
|
+
|
|
7
25
|
## [1.16.0] — 2026-07-03
|
|
8
26
|
|
|
9
27
|
Closes the **install-update-hardening** milestone: `add.py init`/`update` (both
|
package/README.md
CHANGED
|
@@ -39,7 +39,7 @@ pip install pilotspace-add && pilotspace-add init
|
|
|
39
39
|
|
|
40
40
|
Then, in your coding agent, say what you want to build:
|
|
41
41
|
|
|
42
|
-
> `/add` — *"
|
|
42
|
+
> `/add` — *"Let users log in with email + password / SSO, and keep them signed in for 30 days unless they explicitly log out."*
|
|
43
43
|
|
|
44
44
|
The agent sizes it into a milestone (you confirm the shape), drafts the spec →
|
|
45
45
|
scenarios → contract → tests as one bundle (you approve once, at the frozen
|
|
@@ -182,7 +182,7 @@ exactly what that means, so there are no surprises:
|
|
|
182
182
|
ADD is AI-first: you talk to the agent; it drives the method. In Claude Code, run
|
|
183
183
|
**`/add`** and say what you want to build:
|
|
184
184
|
|
|
185
|
-
> `/add` — *"
|
|
185
|
+
> `/add` — *"Let users log in with email + password / SSO, and keep them signed in for 30 days unless they explicitly log out."*
|
|
186
186
|
|
|
187
187
|
**Works with your agent.** The installer detects which coding agent you're in and
|
|
188
188
|
drops the context file it reads — so ADD drives through the CLI under **Claude Code,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pilotspace/add",
|
|
3
|
-
"version": "1.16.
|
|
3
|
+
"version": "1.16.1",
|
|
4
4
|
"description": "ADD (AI-Driven Development). One skill. Eight steps. Five disciplines. Every feature ships through the loop — a minimal, state-tracked Claude Code skill that ships the AIDD book as its trust layer.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"add": "bin/cli.js"
|
|
@@ -52,7 +52,7 @@ Capture each surfaced decision as an **ADR** in `PROJECT.md` **Key Decisions** a
|
|
|
52
52
|
## 3 · Draft to the lock (both paths)
|
|
53
53
|
|
|
54
54
|
1. **Fill the living documentation**: `.add/PROJECT.md` (Domain · Spec · UI/UX · Key Decisions), `CONVENTIONS.md`, `GLOSSARY.md`, `MODEL_REGISTRY.md`, `dependencies.allowlist`, and — for a UI project — `DESIGN.md` (delete if no UI; `design.md`). Brownfield: from code. Greenfield: from interview, gaps flagged `guessed`.
|
|
55
|
-
- **Seed personas** (`.add/personas/`): `init` scaffolds `_template.md` (the schema). **Author one per role** from PROJECT.md + the vendored teacher library `.add/personas-teacher/` (read off-build; engine never fetches) — citing the teacher in `source:` and carrying its top `## Playbook` are the two optional parts, not the authoring. Covered by the **baseline approval**; `add.py check` validates; never clobber.
|
|
55
|
+
- **Seed personas** (`.add/personas/`): `init` scaffolds `_template.md` (the schema). **Author one per role** from PROJECT.md + the vendored teacher library `.add/personas-teacher/` (read off-build; engine never fetches) — citing the teacher in `source:` and carrying its top `## Playbook` are the two optional parts, not the authoring. Covered by the **baseline approval**; `add.py check` validates; never clobber. Still unseeded later? `status`/`check`/`new-milestone`'s hint means: return here, draft every missing project persona — not just one.
|
|
56
56
|
2. **Propose, then size it.** Float a **kickoff suggestion** for the first milestone: a **goal** (one sentence), a **flow** (task order), **scenarios** (examples of what ships). Not the frozen `MILESTONE.md`. On their reaction, draft `MILESTONE.md` (read `scope.md`).
|
|
57
57
|
3. **Create the first task and draft its candidate specification bundle.** `new-task` is allowed pre-lock:
|
|
58
58
|
```bash
|
package/tooling/add.py
CHANGED
|
@@ -100,6 +100,7 @@ from add_engine.io_state import ( # re-exported as module globals: callers use
|
|
|
100
100
|
_CONFLICT_MARKER_RE, # conflict-marker re
|
|
101
101
|
_load_state_for_json, # --json state loader
|
|
102
102
|
_md5_text, _md5_file, # md5 hashing helpers
|
|
103
|
+
_personas_unseeded, # persona-seed-nudge predicate
|
|
103
104
|
)
|
|
104
105
|
|
|
105
106
|
|
|
@@ -1886,6 +1887,11 @@ def cmd_status(args: argparse.Namespace) -> None:
|
|
|
1886
1887
|
# Existence-only: no open/parse, so the pointer adds no IO failure path (a non-file is no voice).
|
|
1887
1888
|
if (root / "SOUL.md").exists():
|
|
1888
1889
|
print("voice : .add/SOUL.md (how I sound & what keeps your trust — read each session)")
|
|
1890
|
+
# persona pointer (persona-seed-nudge v2): project-wide, read every session like context/voice
|
|
1891
|
+
# above — fires until >=1 REAL persona is seeded, self-clears once one lands. Advisory only;
|
|
1892
|
+
# never gates, never touches the --json branch (human-readable orientation surface only).
|
|
1893
|
+
if _personas_unseeded(root):
|
|
1894
|
+
print(f"persona : {PERSONA_HINT}")
|
|
1889
1895
|
# wave resume hint — a live ledger outranks memory (streams.md "Wave ledger").
|
|
1890
1896
|
# Existence-only: no open/read/parse, so the hint adds no IO failure path; a
|
|
1891
1897
|
# non-file at the path is not a ledger. One line PER live ledger — more than
|
|
@@ -2930,6 +2936,11 @@ def cmd_check(args: argparse.Namespace) -> None:
|
|
|
2930
2936
|
"persona_schema_incomplete: missing " + ", ".join(missing)))
|
|
2931
2937
|
else:
|
|
2932
2938
|
infos.append((f"persona '{slug}'", "schema-conformant"))
|
|
2939
|
+
# persona-seed-nudge: surface the SAME "no real persona" gap `new-milestone` nudges on, so
|
|
2940
|
+
# it is also visible on a plain `check`/`status` sweep — an INFO affirmation-of-absence,
|
|
2941
|
+
# never a WARN (measure-not-block; a project with no personas behaves exactly as before).
|
|
2942
|
+
if _personas_unseeded(root):
|
|
2943
|
+
infos.append(("personas", f"unseeded — {PERSONA_HINT}"))
|
|
2933
2944
|
|
|
2934
2945
|
# drift: a done milestone must have no unfinished tasks
|
|
2935
2946
|
for mslug, m in milestones.items():
|
|
@@ -3431,6 +3442,12 @@ def cmd_new_milestone(args: argparse.Namespace) -> None:
|
|
|
3431
3442
|
else:
|
|
3432
3443
|
print("active milestone set." + ("" if not await_confirm else
|
|
3433
3444
|
" (unconfirmed — show the MILESTONE.md, then: add.py milestone-confirm " + slug + ")"))
|
|
3445
|
+
# persona-seed-nudge: a non-blocking hint (never a gate) when this project has no
|
|
3446
|
+
# REAL project-fit persona yet — points at the cross-cutting selection/drafting
|
|
3447
|
+
# service rather than inventing a second mechanism. Fires only on the ACTIVE arm
|
|
3448
|
+
# (a queued milestone isn't yet in flight, so the nudge would be premature there).
|
|
3449
|
+
if _personas_unseeded(root):
|
|
3450
|
+
print(f"note: {PERSONA_HINT}")
|
|
3434
3451
|
print(_next_footer(root, state)) # converges the old "Decompose it into tasks: …" hint
|
|
3435
3452
|
|
|
3436
3453
|
|
|
@@ -24,6 +24,7 @@ __all__ = [
|
|
|
24
24
|
"SETUP_FILES",
|
|
25
25
|
"PERSONA_FRONTMATTER_KEYS",
|
|
26
26
|
"PERSONA_REQUIRED_SECTIONS",
|
|
27
|
+
"PERSONA_HINT",
|
|
27
28
|
"GUIDELINE_FILES",
|
|
28
29
|
"RULES_FILE_REL",
|
|
29
30
|
"WORKFLOW_HEADINGS",
|
|
@@ -99,6 +100,14 @@ SETUP_FILES = ("PROJECT.md", "CONVENTIONS.md", "GLOSSARY.md", "MODEL_REGISTRY.md
|
|
|
99
100
|
PERSONA_FRONTMATTER_KEYS = ("name", "vibe")
|
|
100
101
|
PERSONA_REQUIRED_SECTIONS = ("## Identity", "## Critical Rules", "## Default Requirement", "## Success Metrics")
|
|
101
102
|
|
|
103
|
+
# persona-seed-nudge v2: ONE hint, single-sourced — `new-milestone`/`check`/`status` all print
|
|
104
|
+
# THIS constant (not their own copy) so the wording can never drift across the three surfaces.
|
|
105
|
+
# Project-scoped (not "this milestone's domain") per the confirmed v2 amendment: the AI should
|
|
106
|
+
# catch up ALL of a project's missing personas, not draft a single milestone-fit one.
|
|
107
|
+
PERSONA_HINT = ("no project-fit persona seeded yet under .add/personas/ — spawn the add-persona "
|
|
108
|
+
"agent (or read docs/18-personas.md) to seed the project's persona(s) from "
|
|
109
|
+
"PROJECT.md's domain")
|
|
110
|
+
|
|
102
111
|
# Scaffolded into .add/.gitignore at init so the engine's transient LOCAL artifacts
|
|
103
112
|
# never reach git. Bare-filename patterns match at any depth under .add/ (tasks/,
|
|
104
113
|
# milestones/, archive/). These are working state, not records: scope-snapshot.json
|
|
@@ -199,3 +199,17 @@ def _md5_file(p: Path) -> str | None:
|
|
|
199
199
|
return hashlib.md5(p.read_bytes()).hexdigest()
|
|
200
200
|
except OSError:
|
|
201
201
|
return None
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def _personas_unseeded(root: Path) -> bool:
|
|
205
|
+
"""True when `.add/personas/` has no REAL (non-template) authored persona: the
|
|
206
|
+
directory is absent, empty, or holds only the seeded `_template.md` scaffold
|
|
207
|
+
(persona-seed-nudge). Fail-soft: an unreadable directory counts as unseeded
|
|
208
|
+
rather than raising — this feeds a `note:`/INFO hint, never a gate."""
|
|
209
|
+
d = root / "personas"
|
|
210
|
+
if not d.is_dir():
|
|
211
|
+
return True
|
|
212
|
+
try:
|
|
213
|
+
return not any(p.stem != "_template" for p in d.glob("*.md"))
|
|
214
|
+
except OSError:
|
|
215
|
+
return True
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: <persona name — e.g. Frontend Engineer, UX Researcher>
|
|
3
3
|
vibe: <one-line essence — what this persona keeps true>
|
|
4
|
+
flow: <RECOMMENDED — which of the three apply-surfaces this persona is loaded at (see
|
|
5
|
+
docs/18-personas.md "Apply — three surfaces"): design (the UDD requirements lens) | build
|
|
6
|
+
(the domain-identity overlay on SOUL.md) | advisor (subagent/streams delegation, incl. the
|
|
7
|
+
verify refute-read) — comma-separate if more than one, e.g. `build, advisor`>
|
|
4
8
|
source: <OPTIONAL — the teacher file(s) this was distilled from, e.g. `.add/personas-teacher/engineering/engineering-software-architect.md` (provenance; omit if hand-authored)>
|
|
5
9
|
---
|
|
6
10
|
<!-- A PERSONA is a project-fit requirements persona, distilled from the vendored teacher
|
|
@@ -9,8 +13,11 @@ source: <OPTIONAL — the teacher file(s) this was distilled from, e.g. `.add/pe
|
|
|
9
13
|
the teacher; the engine only seeds + validates this schema (presence-based). This
|
|
10
14
|
`_template.md` is the schema reference — copy it to `<slug>.md` and fill it.
|
|
11
15
|
|
|
12
|
-
REQUIRED: `name` + `vibe` frontmatter and the Identity / Critical Rules /
|
|
16
|
+
REQUIRED (engine-checked): `name` + `vibe` frontmatter and the Identity / Critical Rules /
|
|
13
17
|
Default Requirement / Success Metrics sections.
|
|
18
|
+
RECOMMENDED (not engine-checked, but expected on every persona for consistency): `flow:`
|
|
19
|
+
frontmatter and the `## Abilities` section — a persona with no stated flow or abilities is
|
|
20
|
+
hard for the design/build/advisor surfaces to actually pick up and use.
|
|
14
21
|
OPTIONAL (recommended for a faithful distillation): `source:` frontmatter, and the
|
|
15
22
|
`## Anti-patterns` + `## Playbook` sections. The engine never requires the optional
|
|
16
23
|
parts; absence is conformant.
|
|
@@ -23,12 +30,25 @@ source: <OPTIONAL — the teacher file(s) this was distilled from, e.g. `.add/pe
|
|
|
23
30
|
3. TAG provenance honestly. In `## Playbook`, mark each item teacher-derived vs
|
|
24
31
|
ADD-native. Never credit home-grown project scaffolding to the teacher.
|
|
25
32
|
4. METRICS are rules, not snapshots. Prefer an invariant ("suite matches the last
|
|
26
|
-
green run") over a volatile literal ("2491/0") that rots as the project grows.
|
|
33
|
+
green run") over a volatile literal ("2491/0") that rots as the project grows.
|
|
34
|
+
5. NAME the flow. State which apply-surface(s) actually load this persona — a persona
|
|
35
|
+
that fits none of design/build/advisor is dead weight nobody will ever pick up.
|
|
36
|
+
6. ABILITIES are checkable skills, not aspirations. Anchor each to a real file, tool, or
|
|
37
|
+
command this project already has — the same anchoring discipline as Critical Rules
|
|
38
|
+
and Success Metrics, applied to "what this persona can concretely do." -->
|
|
27
39
|
|
|
28
40
|
## Identity
|
|
29
41
|
<who this persona is — role, domain depth, and the EARNED perspective it brings (what it has
|
|
30
42
|
seen succeed/fail that shapes its judgement). One short paragraph.>
|
|
31
43
|
|
|
44
|
+
## Abilities
|
|
45
|
+
<concrete, checkable things this persona can actually DO — a capability list, distinct from
|
|
46
|
+
Critical Rules (always-enforced constraints) and Playbook (optional step-by-step scaffolding).
|
|
47
|
+
State each as something the agent can perform right now, anchored to a real file/tool/command
|
|
48
|
+
where possible — not an aspiration.>
|
|
49
|
+
- <a concrete capability — e.g. "can diff two response fixtures byte-for-byte to prove passthrough">
|
|
50
|
+
- <another concrete capability>
|
|
51
|
+
|
|
32
52
|
## Critical Rules
|
|
33
53
|
<non-negotiables this persona ALWAYS enforces. Lead with 1–2 carried from the teacher (its
|
|
34
54
|
signature stance), then add project-specific ones.>
|