@skyf0xx/hedgehog 6.0.5 → 6.1.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/bin/cli.mjs CHANGED
@@ -281,19 +281,6 @@ function corePayload(core, h, { hostOnly = false } = {}) {
281
281
  // than generating it live. A core that scaffolds nothing (its
282
282
  // workspace is designed during planning) declares no `workspace`.
283
283
  ...(manifest.workspace ? [{ type: 'dir', root, from: manifest.workspace, to: '.' }] : []),
284
- // A second CLAUDE.md section for cores whose path fills
285
- // {{CORE_SECTION}} after install rather than at it — adoption reads
286
- // it from the project instead of the package it ships in.
287
- ...(manifest.template_adopted
288
- ? [
289
- {
290
- type: 'file',
291
- root,
292
- from: manifest.template_adopted,
293
- to: `.hedgehog/${manifest.template_adopted}`,
294
- },
295
- ]
296
- : []),
297
284
  ];
298
285
  }
299
286
 
@@ -526,7 +513,7 @@ ${bold('Usage')}
526
513
  npx @skyf0xx/hedgehog init --pwa-app scaffold the pwa-app core now
527
514
  npx @skyf0xx/hedgehog init --landing-page scaffold the landing-page core now
528
515
  npx @skyf0xx/hedgehog cores list every core this release can install
529
- npx @skyf0xx/hedgehog core record-adopted land the authored core's agents/skills and record
516
+ npx @skyf0xx/hedgehog core record-adopted land the adopted core's agents/skills and record
530
517
  this project as adopted (hedgehog-adopt calls this
531
518
  after writing .hedgehog/core.yaml; not for other cores)
532
519
  npx @skyf0xx/hedgehog init --cursor install for Cursor (default: Claude Code)
@@ -1046,10 +1033,10 @@ async function resolveInstalledCore() {
1046
1033
  }
1047
1034
 
1048
1035
  // `hedgehog core record-adopted` — the record path for `hedgehog-adopt`
1049
- // (shipped in @skyf0xx/hedgehog-core-authored), which brings the
1036
+ // (shipped in @skyf0xx/hedgehog-core-adopted), which brings the
1050
1037
  // discipline to an existing repo by writing `.hedgehog/core.yaml` and
1051
1038
  // `.hedgehog/adoption.md` directly. That path has no `init` step and so
1052
- // never fetches the `authored` package or calls `recordCore` — a no-flag
1039
+ // never fetches the `adopted` package or calls `recordCore` — a no-flag
1053
1040
  // `init` (what the offer skill actually runs before adoption) installs
1054
1041
  // only the shared engine payload, never a core's own agents/skills, and
1055
1042
  // `bootstrap` (the only other place a core package gets fetched) is
@@ -1061,24 +1048,27 @@ async function resolveInstalledCore() {
1061
1048
  // `core.yaml` (the shipped-core workspace marker) and finds nothing for
1062
1049
  // an adopted repo's `.hedgehog/core.yaml`, so it would read as "no core
1063
1050
  // yet" and update would silently rewrite `.claude/agents`/`.claude/skills`
1064
- // down to just the shared payload, deleting the authored package's files
1051
+ // down to just the shared payload, deleting the adopted package's files
1065
1052
  // with nothing put back.
1066
1053
  //
1067
- // This command is both fixes at once: it fetches the `authored` package
1054
+ // This command is both fixes at once: it fetches the `adopted` package
1068
1055
  // and lands its agents/skills for every host this project already has
1069
- // installed (never its workspace, template, or vendor_skills — adoption
1070
- // already wrote its own CLAUDE.md section and root workspace is the one
1071
- // thing adoption must never touch), then records the core with
1072
- // `adopted: true` so `update` refreshes it correctly from here on.
1073
- // Idempotent and safe to re-run e.g. from a later `hedgehog-adopt` pass
1074
- // adding new change-work since it always overwrites from the current
1075
- // package rather than merging.
1056
+ // installed (never its workspace or vendor_skills — root workspace is
1057
+ // the one thing adoption must never touch), plus a local copy of its
1058
+ // `CLAUDE.core.md` at `.hedgehog/CLAUDE.core.md` `hedgehog-adopt`'s own
1059
+ // Confirm & Lock step reads that file from there to merge into root
1060
+ // `CLAUDE.md`, since a no-flag `init` never ran the normal
1061
+ // `{{CORE_SECTION}}` merge this project's core would otherwise get then
1062
+ // records the core the same as any other, naming `adopted`, so `update`
1063
+ // refreshes it correctly from here on. Idempotent and safe to re-run —
1064
+ // e.g. from a later `hedgehog-adopt` pass adding new change-work — since
1065
+ // it always overwrites from the current package rather than merging.
1076
1066
  async function recordAdoptedCommand() {
1077
1067
  const entry = await resolveCore(ADOPTED_CORE_NAME);
1078
1068
  if (!entry) {
1079
1069
  console.error(
1080
- `${red('authored core not in this release.')} This Hedgehog release's registry has no\n` +
1081
- `entry named "authored" — nothing to install. Update Hedgehog and retry.\n`,
1070
+ `${red('adopted core not in this release.')} This Hedgehog release's registry has no\n` +
1071
+ `entry named "adopted" — nothing to install. Update Hedgehog and retry.\n`,
1082
1072
  );
1083
1073
  process.exitCode = 1;
1084
1074
  return;
@@ -1106,7 +1096,19 @@ async function recordAdoptedCommand() {
1106
1096
  }
1107
1097
  }
1108
1098
 
1109
- await recordCore(DEST_ROOT, { name: core.manifest.name, version: core.version, adopted: true });
1099
+ const templateFile = (
1100
+ await plannedFiles({
1101
+ type: 'file',
1102
+ root: core.root,
1103
+ from: core.manifest.template,
1104
+ to: '.hedgehog/CLAUDE.core.md',
1105
+ })
1106
+ )[0];
1107
+ await writePlannedFile(templateFile);
1108
+ written++;
1109
+ console.log(` ${green('install')} ${relative(DEST_ROOT, templateFile.dest)}`);
1110
+
1111
+ await recordCore(DEST_ROOT, { name: core.manifest.name, version: core.version });
1110
1112
 
1111
1113
  console.log(
1112
1114
  `\n${green(bold('Adopted core recorded.'))} ${dim(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skyf0xx/hedgehog",
3
- "version": "6.0.5",
3
+ "version": "6.1.0",
4
4
  "description": "Install the Hedgehog build discipline (agents + skills) into a repo, for Claude Code, Cursor, or Gemini CLI.",
5
5
  "type": "module",
6
6
  "repository": {
@@ -31,7 +31,8 @@ You run on two paths, and Workflow step 2 decides which:
31
31
  scope into additional intents without re-running the BMAD shelf.
32
32
  Landing-page has no module axis, so this path doesn't apply to it — see
33
33
  the landing-page constraint below for where its new scope actually
34
- goes.
34
+ goes. New change-work on an **adopted** core is a separate case again —
35
+ see "An existing repo, ongoing adoption" below.
35
36
 
36
37
  Either path is entered when the user says "plan", "scope", "break down",
37
38
  asks for something that's new scope rather than a tweak (routed here by
@@ -200,14 +201,14 @@ none of them is a description matching a `when` paragraph:
200
201
  repo", "add Hedgehog to my existing project", "I want scope/verify
201
202
  enforcement on my changes here"). This is a distinct question from
202
203
  everything above: it's not about which core fits new work, because no
203
- new workspace gets built at all. Route straight to `hedgehog-adopt`
204
- bootstrap and every other Phase 0 outcome are skipped entirely, since
205
- there is no workspace to scaffold and no shipped stack to adopt toward.
206
- `hedgehog-adopt` runs its own read-only intake and writes its own
207
- `.hedgehog/core.yaml`; don't run `hedgehog-planning-intake`'s BMAD shelf
208
- first the drivers that skill elicits (persistence, stack, deployment
209
- target) are already settled facts of the existing repo, not open
210
- decisions.
204
+ new workspace gets built at all. This project gets the **adopted
205
+ core**. Route straight to `hedgehog-adopt` bootstrap and every other
206
+ Phase 0 outcome are skipped entirely, since there is no workspace to
207
+ scaffold and no shipped stack to adopt toward. `hedgehog-adopt` runs
208
+ its own read-only intake and writes its own `.hedgehog/core.yaml`;
209
+ don't run `hedgehog-planning-intake`'s BMAD shelf first the drivers
210
+ that skill elicits (persistence, stack, deployment target) are already
211
+ settled facts of the existing repo, not open decisions.
211
212
 
212
213
  State the decision plainly before Phase 1 begins, with the one-line
213
214
  reason it landed there — this is cheap to correct now and expensive once
@@ -375,7 +376,7 @@ as full-stack-app's Auth/Queue/Mobile trio.
375
376
  the build graph.
376
377
  - **landing-page**: owns `.hedgehog/BMAD/` and
377
378
  `.hedgehog/chain/00-brief.md` as artifacts.
378
- - **brownfield adoption**: owns nothing here — `hedgehog-adopt` owns
379
+ - **adopted**: owns nothing here — `hedgehog-adopt` owns
379
380
  `.hedgehog/core.yaml` and `.hedgehog/adoption.md`, the same way an
380
381
  authored core's design is `hedgehog-core-design`'s.
381
382
 
@@ -30,7 +30,8 @@ Everything the commit gate already enforces — the layer's own `verify`
30
30
  command, and whatever typecheck/lint/test it runs — is out of scope;
31
31
  don't re-report a green gate. Read the core's own design first: its loop
32
32
  skill for a shipped core, `.hedgehog/core.yaml` and
33
- `.hedgehog/core-design.md` for an authored one. That is where the layer
33
+ `.hedgehog/core-design.md` for an authored one, `.hedgehog/core.yaml` and
34
+ `.hedgehog/adoption.md` for an adopted one. That is where the layer
34
35
  boundaries, the interface between them, and this core's own conventions
35
36
  are stated. Your checklist is derived from it, not from a stack you
36
37
  recognize.
@@ -96,7 +97,7 @@ Check what the gate structurally cannot:
96
97
  - Don't nitpick style. Focus on structural correctness relative to the
97
98
  stack and build order the core's own design fixed — its loop and
98
99
  bootstrap skills on a shipped core, `.hedgehog/core-design.md` on an
99
- authored one.
100
+ authored one, `.hedgehog/adoption.md` on an adopted one.
100
101
  - 3 real findings beats 20 suggestions. This review sits at a phase or
101
102
  layer boundary, not mid-Loop — don't slow the Loop down for anything
102
103
  that isn't load-bearing for the work that comes next.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: tweaker
3
- description: Use once a core's build is complete (every task in the build graph `complete`) and the user is offered a fresh-context session to iterate. Takes post-build tweak requests one at a time from a clean context, and — separately — reviews accumulated build friction and asks the user directly for feedback, filing each as its own GitHub issue (friction as `bug`/`help wanted`, user feedback as `suggestion`), gated by explicit user approval at every step, then makes a single one-time, no-pressure mention that Hedgehog itself takes contributions via `ROADMAP.md`. Shared by every core with a Stop Condition — not an adopted repo (`hedgehog-adopt`), which has none; there, new change-work goes straight through `hedgehog-adopt` and `hedgehog-authored-loop` instead.
3
+ description: Use once a core's build is complete (every task in the build graph `complete`) and the user is offered a fresh-context session to iterate. Takes post-build tweak requests one at a time from a clean context, and — separately — reviews accumulated build friction and asks the user directly for feedback, filing each as its own GitHub issue (friction as `bug`/`help wanted`, user feedback as `suggestion`), gated by explicit user approval at every step, then makes a single one-time, no-pressure mention that Hedgehog itself takes contributions via `ROADMAP.md`. Shared by every core with a Stop Condition — not the `adopted` core, which has none; there, new change-work goes straight through `hedgehog-adopt` and `hedgehog-authored-loop` instead.
4
4
  model: sonnet
5
5
  color: green
6
6
  tools: Read, Glob, Grep, Edit, Write, Bash
@@ -15,7 +15,7 @@ conversation. You start from a cleared context on purpose. Re-read the
15
15
  friction log (`hedgehog friction list`) and the commit log rather than
16
16
  expecting anything to be remembered.
17
17
 
18
- **Not for an adopted repo (`.hedgehog/core.yaml` written by
18
+ **Not for the `adopted` core (`.hedgehog/core.yaml` written by
19
19
  `hedgehog-adopt`).** That core has no Stop Condition and no "build
20
20
  finished" moment for you to follow — adoption is the permanent way
21
21
  change lands, not a project with an end. A request there is just the
@@ -44,8 +44,8 @@ straight to job 1.
44
44
 
45
45
  None of its own — you work inside whichever core's stack is already
46
46
  installed (a shipped core's, or the stack an authored core's
47
- `.hedgehog/core-design.md` names — an adopted repo never reaches you, per
48
- the note above), editing the same files the core's own build agents
47
+ `.hedgehog/core-design.md` names — the `adopted` core never reaches you,
48
+ per the note above), editing the same files the core's own build agents
49
49
  would. `gh` (GitHub CLI) for issue creation only, and only against
50
50
  `skyf0xx/hedgehog`, never the project's own remote.
51
51
 
@@ -13,7 +13,7 @@
13
13
  // instead of substituting into one.
14
14
  //
15
15
  // Referenced by name (not substance) from hedgehog-adopt's own SKILL.md
16
- // in the @skyf0xx/hedgehog-core-authored package — that skill invokes
16
+ // in the @skyf0xx/hedgehog-core-adopted package — that skill invokes
17
17
  // `appendCoreSection` the same way it already invokes `loadCore` from
18
18
  // src/db/core.mjs, via `node -e "import('<path-to-hedgehog-install>/
19
19
  // src/hosts/claude-md-merge.mjs')..."`.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hedgehog",
3
- "version": "6.0.5",
3
+ "version": "6.1.0",
4
4
  "description": "Hedgehog build discipline: ordered, tested, verified build steps.",
5
5
  "contextFileName": "GEMINI.md"
6
6
  }
@@ -39,10 +39,18 @@
39
39
  {
40
40
  "name": "authored",
41
41
  "package": "@skyf0xx/hedgehog-core-authored",
42
- "version": "^1.0.2",
42
+ "version": "^1.1.0",
43
43
  "language": "typescript",
44
44
  "repository": "https://github.com/skyf0xx/hedgehog-core-authored",
45
- "selects_when": "Neither shipped core fits, but the description names a real artifact a Builder step would produce — just not in either shipped core's shape. This core is designed by the planner rather than chosen from a fixed set: hedgehog-planning-intake's Phase 0 elicits the drivers first, then hedgehog-core-design names the system shape, picks the stack, derives the layers, and writes .hedgehog/core.yaml. It carries the same enforcement as a shipped core — ordered layers, scoped file access, verification before completion — but the sequence is designed for this project rather than battle-tested across many."
45
+ "selects_when": "Neither shipped core fits, but the description names a real artifact a Builder step would produce — just not in either shipped core's shape. This core is designed by the planner rather than chosen from a fixed set: hedgehog-planning-intake's Phase 0 elicits the drivers first, then hedgehog-core-design names the system shape, picks the stack, derives the layers, and writes .hedgehog/core.yaml. It carries the same enforcement as a shipped core — ordered layers, scoped file access, verification before completion — but the sequence is designed for this project rather than battle-tested across many. This is the core most often confused with adopted: authored designs a workspace from scratch for a project being built new, while adopted brings Hedgehog's discipline to a repo that already exists — route here only when there is no existing codebase this work is being added to."
46
+ },
47
+ {
48
+ "name": "adopted",
49
+ "package": "@skyf0xx/hedgehog-core-adopted",
50
+ "version": "^1.0.0",
51
+ "language": "typescript",
52
+ "repository": "https://github.com/skyf0xx/hedgehog-core-adopted",
53
+ "selects_when": "The description is about bringing Hedgehog's discipline to a codebase that already exists, rather than building something new — the repo already has real source files, or the user says so explicitly: \"adopt this repo\", \"add Hedgehog to my existing project\", \"I want scope/verify enforcement on my changes here\". Not chosen by matching a `when` paragraph the way a shipped core is: hedgehog-adopt reads the repo read-only, proposes a linear-chain .hedgehog/core.yaml whose verify commands are the repo's own, and writes only .hedgehog/ — never a workspace, never a stack migration. This is the core most often confused with authored: adopted brings discipline to an existing repo, while authored designs and scaffolds a workspace from scratch for something being built new — route here only when the work is landing on a codebase that already exists."
46
54
  }
47
55
  ]
48
56
  }
@@ -7,21 +7,19 @@
7
7
  // the core — `installedCore` returns null until then, and `update` limits
8
8
  // itself to the shared payload.
9
9
  //
10
- // `authored` has a second entry point with no `init` step at all:
11
- // `hedgehog-adopt` brings the discipline to a repo that already exists by
12
- // writing `.hedgehog/core.yaml` itself, directly, and never calls
13
- // `recordCore` (see that skill, shipped in
14
- // @skyf0xx/hedgehog-core-authored adoption has no npm package of its
15
- // own to fetch, just a core.yaml and adoption.md derived from the
16
- // existing repo). `hedgehog core record-adopted` (bin/cli.mjs) is the
17
- // record path for that case instead: it lands the authored package's
18
- // agents/skills otherwise never installed, since adoption's `init` runs
19
- // with no `--core` flag and `bootstrap` is skipped entirely for adoption
20
- // and calls `recordCore` with `adopted: true`. That flag is the one
21
- // thing distinguishing an adopted record from a normal one: `update`'s
22
- // resolveInstalledCore refreshes an adopted project's payload the same as
23
- // any other (same package, same agents/skills, kept current) but must
24
- // never treat `record.name` changing upstream, or the record going
10
+ // `adopted` has no `init` step at all: `hedgehog-adopt` (shipped in
11
+ // @skyf0xx/hedgehog-core-adopted) brings the discipline to a repo that
12
+ // already exists by writing `.hedgehog/core.yaml` itself, directly, and
13
+ // never calls `recordCore`. `hedgehog core record-adopted` (bin/cli.mjs)
14
+ // is the record path for that case instead: it fetches the `adopted`
15
+ // package and lands its agents/skills otherwise never installed, since
16
+ // adoption's `init` runs with no `--core` flag and `bootstrap` is skipped
17
+ // entirely for adoption and calls `recordCore` the same as any other
18
+ // core, naming `adopted`. That name is the one thing distinguishing an
19
+ // adopted record from a normal one: `update`'s resolveInstalledCore
20
+ // refreshes an adopted project's payload the same as any other (same
21
+ // package, same agents/skills, kept current) but must never treat
22
+ // `record.name === 'adopted'` changing upstream, or the record going
25
23
  // missing, as license to fetch and install a *different* core the way it
26
24
  // would for a project that chose one at `init` — adoption's core is a
27
25
  // fixed fact of the repo (its `.hedgehog/core.yaml`), not a choice
@@ -30,38 +28,34 @@
30
28
  import { readFile, writeFile, mkdir } from 'node:fs/promises';
31
29
  import { dirname, join } from 'node:path';
32
30
 
33
- export const ADOPTED_CORE_NAME = 'authored';
31
+ export const ADOPTED_CORE_NAME = 'adopted';
34
32
 
35
33
  const CORE_PATH = '.hedgehog/core.json';
36
34
 
37
35
  /**
38
36
  * Record the core a project installed and the exact version resolved for
39
37
  * it. Written after the core's files land, so the record describes what
40
- * is on disk. `adopted: true` marks a record written by `hedgehog core
41
- * record-adopted` rather than by `init` — see the module comment above.
38
+ * is on disk.
42
39
  */
43
- export async function recordCore(root, { name, version, adopted = false }) {
40
+ export async function recordCore(root, { name, version }) {
44
41
  const path = join(root, CORE_PATH);
45
42
  await mkdir(dirname(path), { recursive: true });
46
43
  await writeFile(
47
44
  path,
48
- `${JSON.stringify(
49
- { core: name, version, installedAt: new Date().toISOString(), ...(adopted ? { adopted: true } : {}) },
50
- null,
51
- 2,
52
- )}\n`,
45
+ `${JSON.stringify({ core: name, version, installedAt: new Date().toISOString() }, null, 2)}\n`,
53
46
  );
54
47
  }
55
48
 
56
49
  /**
57
- * The core `update` should refresh — `{ name, version, adopted }` — or
58
- * null when this project has no core installed yet. `adopted` is always a
59
- * boolean, `false` for every record `init` writes.
50
+ * The core `update` should refresh — `{ name, version }` — or null when
51
+ * this project has no core installed yet. `name === 'adopted'` marks a
52
+ * record written by `hedgehog core record-adopted` rather than by `init`
53
+ * — see the module comment above.
60
54
  */
61
55
  export async function installedCore(root) {
62
56
  try {
63
- const { core, version, adopted } = JSON.parse(await readFile(join(root, CORE_PATH), 'utf8'));
64
- return core ? { name: core, version, adopted: adopted === true } : null;
57
+ const { core, version } = JSON.parse(await readFile(join(root, CORE_PATH), 'utf8'));
58
+ return core ? { name: core, version } : null;
65
59
  } catch {
66
60
  return null;
67
61
  }
@@ -11,7 +11,6 @@
11
11
  // engine: "^<major>.<minor>.<patch>" which CLI versions can install it
12
12
  // workspace: workspace/ omitted by a core that scaffolds nothing
13
13
  // template: CLAUDE.core.md fills the CLAUDE.md shell's core section
14
- // template_adopted: <path> optional second section, for adoption
15
14
  // agents: [<name>, ...] agents/<name>.md in the package
16
15
  // skills: [<name>, ...] skills/<name>/ in the package
17
16
  // vendor_skills: [<name>, ...] vendor-skills/<name>/ in the package