first-tree 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +21 -7
  2. package/dist/cli.js +5 -5
  3. package/dist/{help-5-WG9QFm.js → help-DV9-AaFp.js} +1 -1
  4. package/dist/{init-CAq0Uhq6.js → init-BgGH2_yC.js} +41 -7
  5. package/dist/onboarding-D7fGGOMN.js +10 -0
  6. package/dist/onboarding-lASHHmgO.js +2 -0
  7. package/dist/{repo-DkR12VUv.js → repo-Cc5U4DWT.js} +22 -2
  8. package/dist/{installer-UgNasLjl.js → source-integration-CuKjoheT.js} +36 -3
  9. package/dist/{upgrade-DYzuvv1k.js → upgrade-BvA9oKmi.js} +26 -3
  10. package/dist/{verify-C0IUSkMZ.js → verify-G8gNXzDX.js} +5 -1
  11. package/package.json +2 -2
  12. package/skills/first-tree/SKILL.md +21 -5
  13. package/skills/first-tree/agents/openai.yaml +1 -1
  14. package/skills/first-tree/assets/framework/VERSION +1 -1
  15. package/skills/first-tree/engine/init.ts +75 -4
  16. package/skills/first-tree/engine/repo.ts +38 -7
  17. package/skills/first-tree/engine/runtime/asset-loader.ts +6 -0
  18. package/skills/first-tree/engine/runtime/source-integration.ts +80 -0
  19. package/skills/first-tree/engine/upgrade.ts +68 -1
  20. package/skills/first-tree/engine/verify.ts +7 -0
  21. package/skills/first-tree/references/maintainer-architecture.md +4 -0
  22. package/skills/first-tree/references/maintainer-thin-cli.md +3 -0
  23. package/skills/first-tree/references/onboarding.md +28 -3
  24. package/skills/first-tree/references/principles.md +97 -57
  25. package/skills/first-tree/references/source-map.md +1 -0
  26. package/skills/first-tree/references/source-workspace-installation.md +52 -0
  27. package/skills/first-tree/references/upgrade-contract.md +19 -4
  28. package/skills/first-tree/scripts/check-skill-sync.sh +2 -0
  29. package/skills/first-tree/tests/init.test.ts +61 -0
  30. package/skills/first-tree/tests/repo.test.ts +20 -0
  31. package/skills/first-tree/tests/skill-artifacts.test.ts +39 -0
  32. package/skills/first-tree/tests/upgrade.test.ts +38 -2
  33. package/skills/first-tree/tests/verify.test.ts +18 -0
  34. package/dist/onboarding-3zYUeYQb.js +0 -2
  35. package/dist/onboarding-Dd63N-V1.js +0 -10
@@ -0,0 +1,52 @@
1
+ ---
2
+ title: "Source/Workspace Installation Contract"
3
+ owners: []
4
+ ---
5
+
6
+ # Source/Workspace Installation Contract
7
+
8
+ This reference defines what it means to "install and use first-tree" in an
9
+ existing source or workspace repository.
10
+
11
+ ## Core Boundary
12
+
13
+ - The current source/workspace repo is **not** the Context Tree.
14
+ - The current source/workspace repo should carry only the installed
15
+ `.agents/skills/first-tree/` and `.claude/skills/first-tree/` skill roots
16
+ plus a single `FIRST-TREE-SOURCE-INTEGRATION:` line in root `AGENTS.md` and
17
+ `CLAUDE.md`.
18
+ - `NODE.md`, `members/`, and tree-scoped `AGENTS.md` content belong only in a
19
+ dedicated `*-context` repo.
20
+ - If a task changes decisions, rationale, ownership, or constraints, update
21
+ the dedicated tree repo rather than copying that material into the source
22
+ repo.
23
+
24
+ ## Default Agent Workflow
25
+
26
+ When an agent is asked to install first-tree for a source/workspace repo, the
27
+ default workflow is:
28
+
29
+ 1. Install the bundled first-tree skill into the current repo.
30
+ 2. Upsert the `FIRST-TREE-SOURCE-INTEGRATION:` line in root `AGENTS.md` and
31
+ `CLAUDE.md`.
32
+ 3. Create a sibling dedicated tree repo named `<repo>-context`.
33
+ 4. Prefer creating and pushing that repo in the same GitHub organization as
34
+ the source repo, matching the source repo's default visibility unless the
35
+ user asks for something else.
36
+ 5. Add the dedicated tree repo back to the source/workspace repo as a `git submodule`.
37
+ 6. Run `context-tree init --here` inside the dedicated tree repo.
38
+ 7. Draft the first tree version from the real codebase, docs, and ownership
39
+ signals.
40
+ 8. Open a PR against the source/workspace repo's default branch for the local
41
+ skill integration plus the new submodule pointer. Do not merge it
42
+ automatically.
43
+
44
+ ## Verification And Upgrade
45
+
46
+ - Do not run `context-tree verify` in the source/workspace repo. Verify the
47
+ dedicated tree repo instead, for example
48
+ `context-tree verify --tree-path ../my-repo-context`.
49
+ - Running `context-tree upgrade` in the source/workspace repo refreshes only
50
+ the local installed skill plus the `FIRST-TREE-SOURCE-INTEGRATION:` lines.
51
+ - Run `context-tree upgrade --tree-path ../my-repo-context` to upgrade the
52
+ dedicated tree repo itself.
@@ -16,7 +16,8 @@ rules we keep for legacy `skills/first-tree/`,
16
16
 
17
17
  ## Installed Layout
18
18
 
19
- The current installed layout in a user repo is:
19
+ The current installed layout in a source/workspace repo or dedicated tree repo
20
+ is:
20
21
 
21
22
  ```text
22
23
  .agents/
@@ -50,7 +51,11 @@ The current installed layout in a user repo is:
50
51
  helpers/
51
52
  ```
52
53
 
53
- The tree content still lives outside the skill:
54
+ For a source/workspace repo, the local integration stops there. It should also
55
+ carry a single `FIRST-TREE-SOURCE-INTEGRATION:` line in root `AGENTS.md` and
56
+ `CLAUDE.md`, but it must not contain tree content.
57
+
58
+ For a dedicated tree repo, the tree content still lives outside the skill:
54
59
 
55
60
  - `NODE.md`
56
61
  - `AGENTS.md`
@@ -66,17 +71,25 @@ skill discovery and hooks.
66
71
  - `context-tree init`
67
72
  - when run in a source/workspace repo, creates or reuses a sibling dedicated
68
73
  tree repo by default
74
+ - installs the skill into the source/workspace repo without creating tree
75
+ files there
76
+ - upserts the `FIRST-TREE-SOURCE-INTEGRATION:` line in root `AGENTS.md` and
77
+ `CLAUDE.md`
69
78
  - installs the skill into the target tree repo
70
- - renders top-level tree scaffolding from the skill templates
71
- - writes progress state to `.agents/skills/first-tree/progress.md`
79
+ - renders top-level tree scaffolding only in the target tree repo
80
+ - writes progress state only to the dedicated tree repo at
81
+ `.agents/skills/first-tree/progress.md`
72
82
  - `context-tree verify`
73
83
  - checks progress state from the installed skill
74
84
  - validates root/frontmatter/agent markers
75
85
  - runs node and member validators
86
+ - must reject source/workspace repos that carry only local integration
76
87
  - `context-tree upgrade`
77
88
  - compares the installed skill payload version to the skill bundled with the
78
89
  currently running `first-tree` package
79
90
  - refreshes the installed skill payload without overwriting tree content
91
+ - when run in a source/workspace repo, refreshes only the local installed
92
+ skill plus the `FIRST-TREE-SOURCE-INTEGRATION:` lines
80
93
  - migrates repos that still use the previous `skills/first-tree/` path onto
81
94
  `.agents/skills/first-tree/` and `.claude/skills/first-tree/`
82
95
  - migrates repos that still use the previous
@@ -93,6 +106,8 @@ skill discovery and hooks.
93
106
  - Default dedicated-tree-repo creation is local-only. The CLI may create a new
94
107
  sibling git repo on disk, but it must not clone the source repo or depend on
95
108
  network access.
109
+ - Source/workspace repos must never receive `NODE.md`, `members/`, or
110
+ tree-scoped `AGENTS.md` from default init flows.
96
111
  - Normal `context-tree init` and `context-tree upgrade` flows do not clone the
97
112
  source repo or require network access.
98
113
  - `context-tree verify` may still read a legacy
@@ -39,6 +39,7 @@ require_file "$SOURCE_DIR/SKILL.md"
39
39
  require_file "$SOURCE_DIR/agents/openai.yaml"
40
40
  require_file "$SOURCE_DIR/references/about.md"
41
41
  require_file "$SOURCE_DIR/references/onboarding.md"
42
+ require_file "$SOURCE_DIR/references/source-workspace-installation.md"
42
43
  require_file "$SOURCE_DIR/references/principles.md"
43
44
  require_file "$SOURCE_DIR/references/ownership-and-naming.md"
44
45
  require_file "$SOURCE_DIR/references/source-map.md"
@@ -59,6 +60,7 @@ require_file "$SOURCE_DIR/engine/commands/verify.ts"
59
60
  require_file "$SOURCE_DIR/engine/rules/index.ts"
60
61
  require_file "$SOURCE_DIR/engine/runtime/asset-loader.ts"
61
62
  require_file "$SOURCE_DIR/engine/runtime/installer.ts"
63
+ require_file "$SOURCE_DIR/engine/runtime/source-integration.ts"
62
64
  require_file "$SOURCE_DIR/engine/runtime/upgrader.ts"
63
65
  require_file "$SOURCE_DIR/engine/runtime/adapters.ts"
64
66
  require_file "$SOURCE_DIR/engine/validators/members.ts"
@@ -10,11 +10,13 @@ import {
10
10
  import { Repo } from "#skill/engine/repo.js";
11
11
  import {
12
12
  AGENT_INSTRUCTIONS_FILE,
13
+ CLAUDE_INSTRUCTIONS_FILE,
13
14
  FRAMEWORK_VERSION,
14
15
  INSTALLED_PROGRESS,
15
16
  LEGACY_AGENT_INSTRUCTIONS_FILE,
16
17
  LEGACY_PROGRESS,
17
18
  } from "#skill/engine/runtime/asset-loader.js";
19
+ import { buildSourceIntegrationLine } from "#skill/engine/runtime/source-integration.js";
18
20
  import {
19
21
  makeGitRepo,
20
22
  useTmpDir,
@@ -124,6 +126,10 @@ const fakeGitInitializer = (root: string): void => {
124
126
  makeGitRepo(root);
125
127
  };
126
128
 
129
+ function escapeRegExp(text: string): string {
130
+ return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
131
+ }
132
+
127
133
  describe("runInit", () => {
128
134
  it("errors when not a git repo", () => {
129
135
  const tmp = useTmpDir();
@@ -205,6 +211,18 @@ describe("runInit", () => {
205
211
  );
206
212
 
207
213
  expect(ret).toBe(0);
214
+ expect(
215
+ existsSync(join(sourceRepoDir.path, ".agents", "skills", "first-tree", "SKILL.md")),
216
+ ).toBe(true);
217
+ expect(
218
+ existsSync(join(sourceRepoDir.path, ".claude", "skills", "first-tree", "SKILL.md")),
219
+ ).toBe(true);
220
+ expect(
221
+ readFileSync(join(sourceRepoDir.path, AGENT_INSTRUCTIONS_FILE), "utf-8"),
222
+ ).toContain(buildSourceIntegrationLine(basename(treeRepo)));
223
+ expect(
224
+ readFileSync(join(sourceRepoDir.path, CLAUDE_INSTRUCTIONS_FILE), "utf-8"),
225
+ ).toContain(buildSourceIntegrationLine(basename(treeRepo)));
208
226
  expect(
209
227
  existsSync(join(treeRepo, ".agents", "skills", "first-tree", "SKILL.md")),
210
228
  ).toBe(true);
@@ -220,6 +238,49 @@ describe("runInit", () => {
220
238
  expect(existsSync(join(sourceRepoDir.path, INSTALLED_PROGRESS))).toBe(false);
221
239
  });
222
240
 
241
+ it("updates existing AGENTS.md and CLAUDE.md without duplicating the source integration line", () => {
242
+ const sourceRepoDir = useTmpDir();
243
+ const sourceSkillDir = useTmpDir();
244
+ makeSourceRepo(sourceRepoDir.path);
245
+ makeSourceSkill(sourceSkillDir.path, "0.2.0");
246
+ writeFileSync(join(sourceRepoDir.path, AGENT_INSTRUCTIONS_FILE), "# Repo Notes\n");
247
+ writeFileSync(join(sourceRepoDir.path, CLAUDE_INSTRUCTIONS_FILE), "# Claude Notes\n");
248
+
249
+ expect(
250
+ runInit(new Repo(sourceRepoDir.path), {
251
+ sourceRoot: sourceSkillDir.path,
252
+ gitInitializer: fakeGitInitializer,
253
+ }),
254
+ ).toBe(0);
255
+ expect(
256
+ runInit(new Repo(sourceRepoDir.path), {
257
+ sourceRoot: sourceSkillDir.path,
258
+ gitInitializer: fakeGitInitializer,
259
+ }),
260
+ ).toBe(0);
261
+
262
+ const treeRepo = join(
263
+ dirname(sourceRepoDir.path),
264
+ `${basename(sourceRepoDir.path)}-context`,
265
+ );
266
+ const expectedLine = buildSourceIntegrationLine(basename(treeRepo));
267
+ const agentText = readFileSync(
268
+ join(sourceRepoDir.path, AGENT_INSTRUCTIONS_FILE),
269
+ "utf-8",
270
+ );
271
+ const claudeText = readFileSync(
272
+ join(sourceRepoDir.path, CLAUDE_INSTRUCTIONS_FILE),
273
+ "utf-8",
274
+ );
275
+
276
+ expect(
277
+ agentText.match(new RegExp(escapeRegExp(expectedLine), "g")),
278
+ ).toHaveLength(1);
279
+ expect(
280
+ claudeText.match(new RegExp(escapeRegExp(expectedLine), "g")),
281
+ ).toHaveLength(1);
282
+ });
283
+
223
284
  it("keeps supporting in-place init with --here", () => {
224
285
  const sourceRepoDir = useTmpDir();
225
286
  const sourceSkillDir = useTmpDir();
@@ -5,6 +5,7 @@ import { Repo } from "#skill/engine/repo.js";
5
5
  import {
6
6
  AGENT_INSTRUCTIONS_FILE,
7
7
  CLAUDE_INSTALLED_PROGRESS,
8
+ CLAUDE_INSTRUCTIONS_FILE,
8
9
  FRAMEWORK_VERSION,
9
10
  INSTALLED_PROGRESS,
10
11
  LEGACY_AGENT_INSTRUCTIONS_FILE,
@@ -14,6 +15,7 @@ import {
14
15
  LEGACY_SKILL_VERSION,
15
16
  LEGACY_PROGRESS,
16
17
  LEGACY_VERSION,
18
+ SOURCE_INTEGRATION_MARKER,
17
19
  } from "#skill/engine/runtime/asset-loader.js";
18
20
  import {
19
21
  useTmpDir,
@@ -454,6 +456,24 @@ describe("init heuristics", () => {
454
456
  expect(repo.isLikelySourceRepo()).toBe(false);
455
457
  });
456
458
 
459
+ it("treats a source repo with installed skill and integration markers as a source repo", () => {
460
+ const tmp = useTmpDir();
461
+ makeSourceRepo(tmp.path);
462
+ makeFramework(tmp.path);
463
+ writeFileSync(
464
+ join(tmp.path, AGENT_INSTRUCTIONS_FILE),
465
+ `${SOURCE_INTEGRATION_MARKER} Use the installed \`first-tree\` skill here.\n`,
466
+ );
467
+ writeFileSync(
468
+ join(tmp.path, CLAUDE_INSTRUCTIONS_FILE),
469
+ `${SOURCE_INTEGRATION_MARKER} Use the installed \`first-tree\` skill here.\n`,
470
+ );
471
+ const repo = new Repo(tmp.path);
472
+ expect(repo.hasSourceWorkspaceIntegration()).toBe(true);
473
+ expect(repo.looksLikeTreeRepo()).toBe(false);
474
+ expect(repo.isLikelySourceRepo()).toBe(true);
475
+ });
476
+
457
477
  it("does not mistake the framework source repo for a user tree repo", () => {
458
478
  const tmp = useTmpDir();
459
479
  makeSourceRepo(tmp.path);
@@ -20,6 +20,17 @@ describe("skill artifacts", () => {
20
20
  it("keeps only the canonical skill in the source repo", () => {
21
21
  expect(existsSync(join(ROOT, "skills", "first-tree", "SKILL.md"))).toBe(true);
22
22
  expect(existsSync(join(ROOT, "skills", "first-tree", "references", "onboarding.md"))).toBe(true);
23
+ expect(
24
+ existsSync(
25
+ join(
26
+ ROOT,
27
+ "skills",
28
+ "first-tree",
29
+ "references",
30
+ "source-workspace-installation.md",
31
+ ),
32
+ ),
33
+ ).toBe(true);
23
34
  expect(existsSync(join(ROOT, "skills", "first-tree", "assets", "framework", "manifest.json"))).toBe(true);
24
35
  expect(existsSync(join(ROOT, "skills", "first-tree", "engine", "init.ts"))).toBe(true);
25
36
  expect(existsSync(join(ROOT, "AGENTS.md"))).toBe(true);
@@ -43,6 +54,18 @@ describe("skill artifacts", () => {
43
54
  ),
44
55
  ),
45
56
  ).toBe(true);
57
+ expect(
58
+ existsSync(
59
+ join(
60
+ ROOT,
61
+ "skills",
62
+ "first-tree",
63
+ "engine",
64
+ "runtime",
65
+ "source-integration.ts",
66
+ ),
67
+ ),
68
+ ).toBe(true);
46
69
  expect(
47
70
  existsSync(
48
71
  join(
@@ -200,13 +223,16 @@ describe("skill artifacts", () => {
200
223
  expect(read("README.md")).toContain("Package Name vs Command");
201
224
  expect(read("README.md")).toContain("Canonical Documentation");
202
225
  expect(read("README.md")).toContain("references/source-map.md");
226
+ expect(read("README.md")).toContain("source-workspace-installation.md");
203
227
  expect(read("README.md")).toContain("skills/first-tree/");
204
228
  expect(read("README.md")).toContain(".agents/skills/first-tree/");
205
229
  expect(read("README.md")).toContain(".claude/skills/first-tree/");
206
230
  expect(read("README.md")).toContain("bundled canonical");
207
231
  expect(read("README.md")).toContain("dedicated tree repo");
232
+ expect(read("README.md")).toContain("FIRST-TREE-SOURCE-INTEGRATION:");
208
233
  expect(read("README.md")).toContain("`first-tree` skill");
209
234
  expect(read("AGENTS.md")).toContain("references/source-map.md");
235
+ expect(read("AGENTS.md")).toContain("source-workspace-installation.md");
210
236
  expect(read("AGENTS.md")).toContain("bundled skill path");
211
237
  expect(read("AGENTS.md")).not.toContain("### Running evals");
212
238
  expect(read("AGENTS.md")).not.toContain("EVALS_TREE_REPO");
@@ -222,6 +248,9 @@ describe("skill artifacts", () => {
222
248
  expect(onboarding).toContain("npx first-tree@latest upgrade");
223
249
  expect(onboarding).toContain(".agents/skills/first-tree/");
224
250
  expect(onboarding).toContain(".claude/skills/first-tree/");
251
+ expect(onboarding).toContain("FIRST-TREE-SOURCE-INTEGRATION:");
252
+ expect(onboarding).toContain("source/workspace repo");
253
+ expect(onboarding).toContain("git submodule");
225
254
  expect(onboarding).not.toContain("This clones the framework into `.context-tree/`");
226
255
  expect(onboarding).not.toContain("from upstream");
227
256
 
@@ -234,11 +263,14 @@ describe("skill artifacts", () => {
234
263
  expect(skillMd).toContain("so it is not confused with the `first-tree`");
235
264
  expect(skillMd).toContain(".agents/skills/first-tree/");
236
265
  expect(skillMd).toContain(".claude/skills/first-tree/");
266
+ expect(skillMd).toContain("source-workspace-installation.md");
267
+ expect(skillMd).toContain("FIRST-TREE-SOURCE-INTEGRATION:");
237
268
  expect(skillMd).not.toContain("canonical eval harness");
238
269
 
239
270
  const sourceMap = read("skills/first-tree/references/source-map.md");
240
271
  expect(sourceMap).not.toContain("repo-snapshot");
241
272
  expect(sourceMap).not.toContain("sync-skill-artifacts.sh");
273
+ expect(sourceMap).toContain("source-workspace-installation.md");
242
274
  expect(sourceMap).toContain("maintainer-architecture.md");
243
275
  expect(sourceMap).toContain("maintainer-thin-cli.md");
244
276
  expect(sourceMap).toContain("maintainer-build-and-distribution.md");
@@ -252,6 +284,13 @@ describe("skill artifacts", () => {
252
284
  expect(sourceMap).not.toContain("vitest.eval.config.ts");
253
285
  expect(sourceMap).toContain(".github/workflows/ci.yml");
254
286
 
287
+ const sourceWorkspaceInstall = read(
288
+ "skills/first-tree/references/source-workspace-installation.md",
289
+ );
290
+ expect(sourceWorkspaceInstall).toContain("FIRST-TREE-SOURCE-INTEGRATION:");
291
+ expect(sourceWorkspaceInstall).toContain("git submodule");
292
+ expect(sourceWorkspaceInstall).toContain("Do not run `context-tree verify`");
293
+
255
294
  const maintainerArchitecture = read(
256
295
  "skills/first-tree/references/maintainer-architecture.md",
257
296
  );
@@ -1,14 +1,17 @@
1
- import { existsSync, readFileSync } from "node:fs";
2
- import { join } from "node:path";
1
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { basename, join } from "node:path";
3
3
  import { describe, expect, it } from "vitest";
4
4
  import { Repo } from "#skill/engine/repo.js";
5
5
  import { runUpgrade } from "#skill/engine/upgrade.js";
6
6
  import {
7
7
  AGENT_INSTRUCTIONS_FILE,
8
+ CLAUDE_INSTRUCTIONS_FILE,
8
9
  FRAMEWORK_VERSION,
9
10
  INSTALLED_PROGRESS,
10
11
  LEGACY_AGENT_INSTRUCTIONS_FILE,
12
+ SOURCE_INTEGRATION_MARKER,
11
13
  } from "#skill/engine/runtime/asset-loader.js";
14
+ import { buildSourceIntegrationLine } from "#skill/engine/runtime/source-integration.js";
12
15
  import {
13
16
  makeAgentsMd,
14
17
  makeFramework,
@@ -119,4 +122,37 @@ describe("runUpgrade", () => {
119
122
  const result = runUpgrade(new Repo(repoDir.path));
120
123
  expect(result).toBe(1);
121
124
  });
125
+
126
+ it("refreshes source/workspace integration without writing tree progress", () => {
127
+ const repoDir = useTmpDir();
128
+ const sourceDir = useTmpDir();
129
+ makeSourceRepo(repoDir.path);
130
+ makeFramework(repoDir.path, "0.1.0");
131
+ writeFileSync(
132
+ join(repoDir.path, AGENT_INSTRUCTIONS_FILE),
133
+ `${SOURCE_INTEGRATION_MARKER} old text\n`,
134
+ );
135
+ writeFileSync(
136
+ join(repoDir.path, CLAUDE_INSTRUCTIONS_FILE),
137
+ `${SOURCE_INTEGRATION_MARKER} old text\n`,
138
+ );
139
+ makeSourceSkill(sourceDir.path, "0.2.0");
140
+
141
+ const result = runUpgrade(new Repo(repoDir.path), {
142
+ sourceRoot: sourceDir.path,
143
+ });
144
+
145
+ const expectedLine = buildSourceIntegrationLine(
146
+ `${basename(repoDir.path)}-context`,
147
+ );
148
+ expect(result).toBe(0);
149
+ expect(readFileSync(join(repoDir.path, FRAMEWORK_VERSION), "utf-8").trim()).toBe("0.2.0");
150
+ expect(readFileSync(join(repoDir.path, AGENT_INSTRUCTIONS_FILE), "utf-8")).toContain(
151
+ expectedLine,
152
+ );
153
+ expect(readFileSync(join(repoDir.path, CLAUDE_INSTRUCTIONS_FILE), "utf-8")).toContain(
154
+ expectedLine,
155
+ );
156
+ expect(existsSync(join(repoDir.path, INSTALLED_PROGRESS))).toBe(false);
157
+ });
122
158
  });
@@ -6,8 +6,10 @@ import { check, checkProgress, runVerify } from "#skill/engine/verify.js";
6
6
  import { Repo } from "#skill/engine/repo.js";
7
7
  import {
8
8
  AGENT_INSTRUCTIONS_FILE,
9
+ CLAUDE_INSTRUCTIONS_FILE,
9
10
  INSTALLED_PROGRESS,
10
11
  LEGACY_PROGRESS,
12
+ SOURCE_INTEGRATION_MARKER,
11
13
  } from "#skill/engine/runtime/asset-loader.js";
12
14
  import {
13
15
  useTmpDir,
@@ -238,4 +240,20 @@ describe("runVerify failing", () => {
238
240
  const ret = runVerify(repo, passValidator);
239
241
  expect(ret).toBe(1);
240
242
  });
243
+
244
+ it("refuses to verify a source/workspace repo that only has local first-tree integration", () => {
245
+ const tmp = useTmpDir();
246
+ makeSourceRepo(tmp.path);
247
+ makeFramework(tmp.path);
248
+ writeFileSync(
249
+ join(tmp.path, AGENT_INSTRUCTIONS_FILE),
250
+ `${SOURCE_INTEGRATION_MARKER} Use the installed \`first-tree\` skill here.\n`,
251
+ );
252
+ writeFileSync(
253
+ join(tmp.path, CLAUDE_INSTRUCTIONS_FILE),
254
+ `${SOURCE_INTEGRATION_MARKER} Use the installed \`first-tree\` skill here.\n`,
255
+ );
256
+ const repo = new Repo(tmp.path);
257
+ expect(runVerify(repo, passValidator)).toBe(1);
258
+ });
241
259
  });
@@ -1,2 +0,0 @@
1
- import { t as runOnboarding } from "./onboarding-Dd63N-V1.js";
2
- export { runOnboarding };
@@ -1,10 +0,0 @@
1
- //#region skills/first-tree/references/onboarding.md
2
- var onboarding_default = "# Context Tree Onboarding\n\nYou are setting up a **Context Tree** — the living source of truth for an organization. This document tells you what it is and how to bootstrap one.\n\n---\n\n## What Is a Context Tree\n\nA Context Tree is a Git repository where every directory is a **domain** and every file is a **node**. Each node captures decisions, designs, and cross-domain relationships — the knowledge that would otherwise scatter across PRs, documents, and people's heads.\n\nKey properties:\n\n- **Nodes are markdown files.** Each directory has a `NODE.md` that describes the domain. Leaf `.md` files capture specific decisions or designs.\n- **Every node has an owner.** Declared in YAML frontmatter. Owners approve changes to their nodes.\n- **Organized by concern, not by repo or team.** An agent working on \"add SSO\" finds all auth context in one place — not split across 4 repos.\n- **The tree is never a snapshot — it's the current state.** When decisions change, the tree updates. Stale nodes are bugs.\n\n### Frontmatter Format\n\nEvery node has frontmatter:\n\n```yaml\n---\ntitle: \"Auth Architecture\"\nowners: [alice, bob]\nsoft_links: [/infrastructure/deployments]\n---\n```\n\n- `owners` — who can approve changes. `owners: []` inherits from parent. `owners: [*]` means anyone.\n- `soft_links` — cross-references to related nodes in other domains.\n\n### What Belongs in the Tree\n\nInformation an agent needs to **decide** on an approach — not to execute it.\n\n**Yes:** \"Auth spans 4 repos: backend issues JWTs, frontend uses Better Auth, extension uses OAuth popup, desktop uses localhost callback.\"\n\n**No:** The function signature of `auth_service.verify()` — that's in the code.\n\n---\n\n## Four Principles\n\n1. **Source of truth for decisions, not execution.** The tree captures the *what* and *why*. Execution details stay in source systems.\n2. **Agents are first-class participants.** The tree is designed for agents to navigate and update.\n3. **Transparency by default.** Reading is open to all. Writing requires owner approval.\n4. **Git-native.** Nodes are files, domains are directories. History, ownership, and review follow Git conventions.\n\n---\n\n## How to Set Up a Context Tree\n\n### Prerequisites\n\n- A source/workspace Git repository, or an already-created dedicated tree repo\n- Node.js 18+\n- The npm package is `first-tree`, the installed CLI command is\n `context-tree`.\n- `context-tree init` installs the framework skill into\n `.agents/skills/first-tree/` and `.claude/skills/first-tree/`.\n- Use `npx first-tree init` for one-off runs, or `npm install -g first-tree`\n to add the `context-tree` command to your PATH\n\n### Step 1: Initialize\n\nRecommended workflow: run `context-tree init` from your source or workspace repo.\nThe CLI will create a sibling dedicated tree repo named `<repo>-context` by\ndefault and install the framework there.\n\n```bash\ncd my-org\ncontext-tree init\ncd ../my-org-context\n```\n\nIf you already created a dedicated tree repo manually, initialize it in place:\n\n```bash\nmkdir my-org-context && cd my-org-context\ngit init\ncontext-tree init --here\n```\n\nEither way, the framework installs into `.agents/skills/first-tree/` and\n`.claude/skills/first-tree/`, renders scaffolding (`NODE.md`, `AGENTS.md`,\n`members/NODE.md`), and generates a task list in\n`.agents/skills/first-tree/progress.md`.\n\nPublishing tip: keep the tree repo in the same GitHub organization as the\nsource repo unless you have a reason not to.\n\n### Step 2: Work Through the Task List\n\nRead `.agents/skills/first-tree/progress.md`. It contains a checklist tailored\nto the current state of the repo. Complete each task:\n\n- Fill in `NODE.md` with your organization name, owners, and domains\n- Add project-specific instructions to `AGENTS.md` below the framework markers\n- Create member nodes under `members/`\n- Optionally configure agent integration (for Claude Code, the installed hook\n assets live under `.claude/skills/first-tree/`)\n- Copy validation workflows from\n `.agents/skills/first-tree/assets/framework/workflows/` to\n `.github/workflows/`\n\nAs you complete each task, check it off in\n`.agents/skills/first-tree/progress.md` by changing `- [ ]` to `- [x]`.\n\n### Step 3: Verify\n\n```bash\ncontext-tree verify\n```\n\nOr, from your source/workspace repo:\n\n```bash\ncontext-tree verify --tree-path ../my-org-context\n```\n\nThis fails if any items in `.agents/skills/first-tree/progress.md` remain\nunchecked, and runs deterministic checks (valid frontmatter, node structure,\nmember nodes exist).\n\n### Step 4: Design Your Domains\n\nCreate top-level directories for your organization's primary concerns. Each needs a `NODE.md`:\n\n```\nmy-org-tree/\n NODE.md # root — lists all domains\n engineering/\n NODE.md # decisions about architecture, infra, tooling\n product/\n NODE.md # strategy, roadmap, user research\n marketing/\n NODE.md # positioning, campaigns\n members/\n NODE.md # team members and agents\n alice/\n NODE.md # individual member node\n```\n\n### Step 5: Populate from Existing Work\n\nFor each domain, extract knowledge from existing repos, docs, and systems:\n\n- Decisions and their rationale\n- Cross-domain relationships and dependencies\n- Constraints that aren't obvious from the code\n\nThe tree doesn't duplicate source code — it captures what connects things and why they were built that way.\n\n---\n\n## CLI Reference\n\n| Command | Description |\n|---------|-------------|\n| `context-tree init` | Create or refresh a dedicated tree repo. By default, running in a source/workspace repo creates a sibling `<repo>-context`; use `--here` to initialize the current repo in place. |\n| `context-tree verify` | Check the installed progress file for unchecked items + run deterministic validation. Use `--tree-path` when invoking from another working directory. |\n| `context-tree upgrade` | Refresh the installed framework skill from the currently running `first-tree` npm package and generate follow-up tasks. Use `--tree-path` when invoking from another working directory. |\n| `context-tree help onboarding` | Print this onboarding guide. |\n\n---\n\n## Upgrading the Framework\n\nWhen the framework updates:\n\n```bash\ncontext-tree upgrade\n```\n\n`context-tree upgrade` refreshes `.agents/skills/first-tree/` and\n`.claude/skills/first-tree/` from the skill bundled with the currently running\n`first-tree` npm package, preserves your tree content, and generates follow-up\ntasks in `.agents/skills/first-tree/progress.md`.\n\nIf your repo still uses the older `skills/first-tree/`,\n`skills/first-tree-cli-framework/`, or `.context-tree/` layouts,\n`context-tree upgrade` will migrate it to the current installed layout first.\n\nTo pick up a newer framework release, first run a newer package version, for\nexample `npx first-tree@latest upgrade`, or update your global `first-tree`\ninstall before running `context-tree upgrade`.\n\n---\n\n## Further Reading\n\n- `.agents/skills/first-tree/references/principles.md` — Core principles with detailed examples\n- `.agents/skills/first-tree/references/ownership-and-naming.md` — How nodes are named and owned\n- `AGENTS.md` in your tree — The before/during/after workflow for every task\n";
3
- //#endregion
4
- //#region skills/first-tree/engine/onboarding.ts
5
- function runOnboarding(output = console.log) {
6
- output(onboarding_default);
7
- return 0;
8
- }
9
- //#endregion
10
- export { onboarding_default as n, runOnboarding as t };