first-tree 0.0.3 → 0.0.4

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 (43) hide show
  1. package/README.md +69 -27
  2. package/dist/cli.js +28 -13
  3. package/dist/{help-xEI-s9iN.js → help-Dtdj91HJ.js} +1 -1
  4. package/dist/{init-DtOjj0wc.js → init--VepFe6N.js} +171 -21
  5. package/dist/{installer-rcZpGLnM.js → installer-cH7N4RNj.js} +2 -2
  6. package/dist/onboarding-C9cYSE6F.js +2 -0
  7. package/dist/onboarding-CPP8fF4D.js +10 -0
  8. package/dist/{repo-BTJG8BU1.js → repo-DY57bMqr.js} +143 -12
  9. package/dist/{upgrade-COGgI7Rj.js → upgrade-Cgx_K2HM.js} +46 -7
  10. package/dist/{verify-CxN6JiV9.js → verify-mC9ZTd1f.js} +66 -6
  11. package/package.json +1 -1
  12. package/skills/first-tree/SKILL.md +8 -4
  13. package/skills/first-tree/assets/framework/VERSION +1 -1
  14. package/skills/first-tree/assets/framework/helpers/run-review.ts +16 -2
  15. package/skills/first-tree/assets/framework/templates/{agent.md.template → agents.md.template} +1 -0
  16. package/skills/first-tree/assets/framework/templates/root-node.md.template +6 -3
  17. package/skills/first-tree/engine/commands/init.ts +1 -1
  18. package/skills/first-tree/engine/commands/upgrade.ts +1 -1
  19. package/skills/first-tree/engine/commands/verify.ts +1 -1
  20. package/skills/first-tree/engine/init.ts +285 -16
  21. package/skills/first-tree/engine/repo.ts +185 -9
  22. package/skills/first-tree/engine/rules/agent-instructions.ts +29 -7
  23. package/skills/first-tree/engine/runtime/asset-loader.ts +7 -0
  24. package/skills/first-tree/engine/upgrade.ts +66 -9
  25. package/skills/first-tree/engine/validators/nodes.ts +48 -3
  26. package/skills/first-tree/engine/verify.ts +61 -3
  27. package/skills/first-tree/references/maintainer-architecture.md +1 -1
  28. package/skills/first-tree/references/maintainer-build-and-distribution.md +3 -0
  29. package/skills/first-tree/references/maintainer-thin-cli.md +1 -1
  30. package/skills/first-tree/references/onboarding.md +32 -9
  31. package/skills/first-tree/references/source-map.md +3 -3
  32. package/skills/first-tree/references/upgrade-contract.md +14 -5
  33. package/skills/first-tree/scripts/check-skill-sync.sh +1 -1
  34. package/skills/first-tree/tests/helpers.ts +24 -4
  35. package/skills/first-tree/tests/init.test.ts +103 -6
  36. package/skills/first-tree/tests/repo.test.ts +87 -9
  37. package/skills/first-tree/tests/rules.test.ts +26 -7
  38. package/skills/first-tree/tests/skill-artifacts.test.ts +4 -0
  39. package/skills/first-tree/tests/thin-cli.test.ts +52 -7
  40. package/skills/first-tree/tests/upgrade.test.ts +19 -5
  41. package/skills/first-tree/tests/verify.test.ts +106 -7
  42. package/dist/onboarding-6Fr5Gkrk.js +0 -2
  43. package/dist/onboarding-B9zPGvvG.js +0 -10
@@ -1,11 +1,14 @@
1
1
  import { mkdirSync, rmSync, writeFileSync } from "node:fs";
2
- import { dirname, join } from "node:path";
2
+ import { dirname, join, resolve } from "node:path";
3
3
  import { Repo } from "#skill/engine/repo.js";
4
4
  import {
5
+ AGENT_INSTRUCTIONS_FILE,
6
+ AGENT_INSTRUCTIONS_TEMPLATE,
5
7
  FRAMEWORK_WORKFLOWS_DIR,
6
8
  FRAMEWORK_TEMPLATES_DIR,
7
9
  FRAMEWORK_VERSION,
8
10
  INSTALLED_PROGRESS,
11
+ LEGACY_AGENT_INSTRUCTIONS_FILE,
9
12
  LEGACY_FRAMEWORK_ROOT,
10
13
  LEGACY_SKILL_ROOT,
11
14
  SKILL_ROOT,
@@ -20,6 +23,13 @@ import {
20
23
  readSourceVersion,
21
24
  } from "#skill/engine/runtime/upgrader.js";
22
25
 
26
+ export const UPGRADE_USAGE = `usage: context-tree upgrade [--tree-path PATH]
27
+
28
+ Options:
29
+ --tree-path PATH Upgrade a tree repo from another working directory
30
+ --help Show this help message
31
+ `;
32
+
23
33
  function writeProgress(repo: Repo, content: string): void {
24
34
  const progressPath = join(repo.root, repo.preferredProgressPath());
25
35
  mkdirSync(dirname(progressPath), { recursive: true });
@@ -41,26 +51,37 @@ function formatUpgradeTaskList(
41
51
  "",
42
52
  ];
43
53
 
54
+ const migrationTasks: string[] = [];
44
55
  if (layout === "legacy") {
45
- lines.push(
46
- "## Migration",
56
+ migrationTasks.push(
47
57
  "- [ ] Remove any stale `.context-tree/` references from repo-specific docs, scripts, or workflow files",
48
- "",
49
58
  );
50
59
  }
51
60
 
52
61
  if (layout === "legacy-skill") {
53
- lines.push(
54
- "## Migration",
62
+ migrationTasks.push(
55
63
  `- [ ] Remove any stale \`${LEGACY_SKILL_ROOT}/\` references from repo-specific docs, scripts, workflow files, or agent config`,
56
- "",
57
64
  );
58
65
  }
59
66
 
60
- if (repo.hasAgentMdMarkers()) {
67
+ if (repo.hasCanonicalAgentInstructionsFile() && repo.hasLegacyAgentInstructionsFile()) {
68
+ migrationTasks.push(
69
+ `- [ ] Merge any remaining user-authored content from \`${LEGACY_AGENT_INSTRUCTIONS_FILE}\` into \`${AGENT_INSTRUCTIONS_FILE}\`, then delete the legacy file`,
70
+ );
71
+ } else if (repo.hasLegacyAgentInstructionsFile()) {
72
+ migrationTasks.push(
73
+ `- [ ] Rename \`${LEGACY_AGENT_INSTRUCTIONS_FILE}\` to \`${AGENT_INSTRUCTIONS_FILE}\` to use the canonical agent instructions filename`,
74
+ );
75
+ }
76
+
77
+ if (migrationTasks.length > 0) {
78
+ lines.push("## Migration", ...migrationTasks, "");
79
+ }
80
+
81
+ if (repo.hasAgentInstructionsMarkers()) {
61
82
  lines.push(
62
83
  "## Agent Instructions",
63
- `- [ ] Compare the framework section in \`AGENT.md\` with \`${FRAMEWORK_TEMPLATES_DIR}/agent.md.template\` and update the content between the markers if needed`,
84
+ `- [ ] Compare the framework section in \`${AGENT_INSTRUCTIONS_FILE}\` with \`${FRAMEWORK_TEMPLATES_DIR}/${AGENT_INSTRUCTIONS_TEMPLATE}\` and update the content between the markers if needed`,
64
85
  "",
65
86
  );
66
87
  }
@@ -89,6 +110,13 @@ export interface UpgradeOptions {
89
110
  export function runUpgrade(repo?: Repo, options?: UpgradeOptions): number {
90
111
  const workingRepo = repo ?? new Repo();
91
112
 
113
+ if (workingRepo.isLikelySourceRepo() && !workingRepo.looksLikeTreeRepo()) {
114
+ console.error(
115
+ "Error: no installed framework skill found here. This looks like a source/workspace repo. Run `context-tree init` to create a dedicated tree repo, or pass `--tree-path` to upgrade an existing tree repo.",
116
+ );
117
+ return 1;
118
+ }
119
+
92
120
  if (!workingRepo.hasFramework()) {
93
121
  console.error(
94
122
  "Error: no installed framework skill found. Run `context-tree init` first.",
@@ -174,3 +202,32 @@ export function runUpgrade(repo?: Repo, options?: UpgradeOptions): number {
174
202
  console.log(`Progress file written to ${workingRepo.preferredProgressPath()}`);
175
203
  return 0;
176
204
  }
205
+
206
+ export function runUpgradeCli(args: string[] = []): number {
207
+ if (args.includes("--help") || args.includes("-h")) {
208
+ console.log(UPGRADE_USAGE);
209
+ return 0;
210
+ }
211
+
212
+ let treePath: string | undefined;
213
+ for (let index = 0; index < args.length; index += 1) {
214
+ const arg = args[index];
215
+ if (arg === "--tree-path") {
216
+ const value = args[index + 1];
217
+ if (!value) {
218
+ console.error("Missing value for --tree-path");
219
+ console.log(UPGRADE_USAGE);
220
+ return 1;
221
+ }
222
+ treePath = value;
223
+ index += 1;
224
+ continue;
225
+ }
226
+
227
+ console.error(`Unknown upgrade option: ${arg}`);
228
+ console.log(UPGRADE_USAGE);
229
+ return 1;
230
+ }
231
+
232
+ return runUpgrade(treePath ? new Repo(resolve(process.cwd(), treePath)) : undefined);
233
+ }
@@ -1,5 +1,13 @@
1
1
  import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
2
2
  import { join, relative, posix } from "node:path";
3
+ import {
4
+ AGENT_INSTRUCTIONS_FILE,
5
+ LEGACY_AGENT_INSTRUCTIONS_FILE,
6
+ LEGACY_SKILL_NAME,
7
+ LEGACY_SKILL_ROOT,
8
+ SKILL_NAME,
9
+ SKILL_ROOT,
10
+ } from "#skill/engine/runtime/asset-loader.js";
3
11
 
4
12
  const FRONTMATTER_RE = /^---\s*\n(.*?)\n---/s;
5
13
  const OWNERS_RE = /^owners:\s*\[([^\]]*)\]/m;
@@ -11,7 +19,11 @@ const MD_LINK_RE = /\[.*?\]\(([^)]+\.md)\)/g;
11
19
  const DOMAIN_LINK_RE = /\[(\w[\w-]*)\/?\]\((\w[\w-]*)\/NODE\.md\)/g;
12
20
 
13
21
  const SKIP = new Set(["node_modules", "__pycache__"]);
14
- const SKIP_FILES = new Set(["AGENT.md", "CLAUDE.md"]);
22
+ const SKIP_FILES = new Set([
23
+ AGENT_INSTRUCTIONS_FILE,
24
+ LEGACY_AGENT_INSTRUCTIONS_FILE,
25
+ "CLAUDE.md",
26
+ ]);
15
27
  const MIN_BODY_LENGTH = 20;
16
28
 
17
29
  export class Findings {
@@ -75,9 +87,42 @@ function rel(path: string): string {
75
87
  return relative(treeRoot, path);
76
88
  }
77
89
 
90
+ function isInstalledSkillPath(relPath: string): boolean {
91
+ return (
92
+ relPath === SKILL_ROOT ||
93
+ relPath.startsWith(`${SKILL_ROOT}/`) ||
94
+ relPath === LEGACY_SKILL_ROOT ||
95
+ relPath.startsWith(`${LEGACY_SKILL_ROOT}/`)
96
+ );
97
+ }
98
+
99
+ function isFrameworkContainerDir(relPath: string, fullPath: string): boolean {
100
+ if (relPath !== "skills") {
101
+ return false;
102
+ }
103
+
104
+ try {
105
+ const entries = readdirSync(fullPath).filter((entry) => !entry.startsWith("."));
106
+ if (entries.length === 0) {
107
+ return false;
108
+ }
109
+ return entries.every(
110
+ (entry) => entry === SKILL_NAME || entry === LEGACY_SKILL_NAME,
111
+ );
112
+ } catch {
113
+ return false;
114
+ }
115
+ }
116
+
78
117
  function shouldSkip(path: string): boolean {
79
- const parts = relative(treeRoot, path).split("/");
80
- return parts.some((part) => SKIP.has(part) || part.startsWith("."));
118
+ const relPath = relative(treeRoot, path);
119
+ const parts = relPath.split("/");
120
+
121
+ if (parts.some((part) => SKIP.has(part) || part.startsWith("."))) {
122
+ return true;
123
+ }
124
+
125
+ return isInstalledSkillPath(relPath) || isFrameworkContainerDir(relPath, path);
81
126
  }
82
127
 
83
128
  function readText(path: string): string | null {
@@ -1,8 +1,19 @@
1
+ import { resolve } from "node:path";
1
2
  import { Repo } from "#skill/engine/repo.js";
3
+ import {
4
+ AGENT_INSTRUCTIONS_FILE,
5
+ LEGACY_AGENT_INSTRUCTIONS_FILE,
6
+ } from "#skill/engine/runtime/asset-loader.js";
2
7
  import { runValidateMembers } from "#skill/engine/validators/members.js";
3
8
  import { runValidateNodes } from "#skill/engine/validators/nodes.js";
4
9
 
5
10
  const UNCHECKED_RE = /^- \[ \] (.+)$/gm;
11
+ export const VERIFY_USAGE = `usage: context-tree verify [--tree-path PATH]
12
+
13
+ Options:
14
+ --tree-path PATH Verify a tree repo from another working directory
15
+ --help Show this help message
16
+ `;
6
17
 
7
18
  export function check(label: string, passed: boolean): boolean {
8
19
  const icon = passed ? "\u2713" : "\u2717";
@@ -38,6 +49,14 @@ function defaultNodeValidator(root: string): ValidateNodesResult {
38
49
  export function runVerify(repo?: Repo, nodeValidator?: NodeValidator): number {
39
50
  const r = repo ?? new Repo();
40
51
  const validate = nodeValidator ?? defaultNodeValidator;
52
+
53
+ if (r.isLikelySourceRepo() && !r.looksLikeTreeRepo()) {
54
+ console.error(
55
+ "Error: no installed framework skill found here. This looks like a source/workspace repo. Run `context-tree init` to create a dedicated tree repo, or pass `--tree-path` to verify an existing tree repo.",
56
+ );
57
+ return 1;
58
+ }
59
+
41
60
  let allPassed = true;
42
61
  const progressPath = r.progressPath() ?? r.preferredProgressPath();
43
62
  const frameworkVersionPath = r.frameworkVersionPath();
@@ -73,10 +92,20 @@ export function runVerify(repo?: Repo, nodeValidator?: NodeValidator): number {
73
92
  hasValidNode,
74
93
  ) && allPassed;
75
94
 
76
- // 3. AGENT.md exists with framework markers
95
+ // 3. AGENTS.md is canonical and contains framework markers
96
+ const hasCanonicalAgentInstructions = r.hasCanonicalAgentInstructionsFile();
97
+ const hasLegacyAgentInstructions = r.hasLegacyAgentInstructionsFile();
98
+ if (hasLegacyAgentInstructions) {
99
+ const followUp = hasCanonicalAgentInstructions
100
+ ? `Remove legacy \`${LEGACY_AGENT_INSTRUCTIONS_FILE}\` after confirming its contents are in \`${AGENT_INSTRUCTIONS_FILE}\`.`
101
+ : `Rename \`${LEGACY_AGENT_INSTRUCTIONS_FILE}\` to \`${AGENT_INSTRUCTIONS_FILE}\`.`;
102
+ console.log(` Legacy agent instructions detected. ${followUp}\n`);
103
+ }
77
104
  allPassed = check(
78
- "AGENT.md exists with framework markers",
79
- r.hasAgentMdMarkers(),
105
+ `${AGENT_INSTRUCTIONS_FILE} is the only agent instructions file and has framework markers`,
106
+ hasCanonicalAgentInstructions &&
107
+ !hasLegacyAgentInstructions &&
108
+ r.hasAgentInstructionsMarkers(),
80
109
  ) && allPassed;
81
110
 
82
111
  // 4. Node validation
@@ -95,3 +124,32 @@ export function runVerify(repo?: Repo, nodeValidator?: NodeValidator): number {
95
124
  }
96
125
  return allPassed ? 0 : 1;
97
126
  }
127
+
128
+ export function runVerifyCli(args: string[] = []): number {
129
+ if (args.includes("--help") || args.includes("-h")) {
130
+ console.log(VERIFY_USAGE);
131
+ return 0;
132
+ }
133
+
134
+ let treePath: string | undefined;
135
+ for (let index = 0; index < args.length; index += 1) {
136
+ const arg = args[index];
137
+ if (arg === "--tree-path") {
138
+ const value = args[index + 1];
139
+ if (!value) {
140
+ console.error("Missing value for --tree-path");
141
+ console.log(VERIFY_USAGE);
142
+ return 1;
143
+ }
144
+ treePath = value;
145
+ index += 1;
146
+ continue;
147
+ }
148
+
149
+ console.error(`Unknown verify option: ${arg}`);
150
+ console.log(VERIFY_USAGE);
151
+ return 1;
152
+ }
153
+
154
+ return runVerify(treePath ? new Repo(resolve(process.cwd(), treePath)) : undefined);
155
+ }
@@ -33,7 +33,7 @@ that install the framework.
33
33
  - Treat `skills/first-tree/` as the only canonical source.
34
34
  - If a maintainer needs information to safely change behavior, move that
35
35
  information into `references/`; do not leave it only in root `README.md`,
36
- `AGENT.md`, CI comments, or PR descriptions.
36
+ `AGENTS.md`, CI comments, or PR descriptions.
37
37
  - Keep runtime assets generic. They are copied into every user tree.
38
38
  - Keep the CLI thin. Command semantics, upgrade rules, layout contracts, and
39
39
  maintainer guidance should belong to the skill.
@@ -50,6 +50,9 @@ another skill reference, not only in the files themselves.
50
50
  with the package rather than copying that information into root docs.
51
51
  - Normal `context-tree init` / `context-tree upgrade` flows must install from
52
52
  the skill bundled in the running package, not by cloning the source repo.
53
+ - Default dedicated-tree-repo creation must stay local-only. It may create a
54
+ sibling git repo on disk, but it must not require remote repo creation or
55
+ source-repo cloning.
53
56
  - If you change anything that gets copied into user repos, bump
54
57
  `assets/framework/VERSION` and keep the upgrade task text in sync.
55
58
  - If packaging changes alter what gets installed into user repos, update
@@ -26,7 +26,7 @@ These root files are shell code, not canonical knowledge stores:
26
26
  - `vitest.config.ts`
27
27
  - `vitest.eval.config.ts` (repo-only maintainer eval entrypoint)
28
28
  - `.github/workflows/ci.yml`
29
- - root `README.md` and `AGENT.md`
29
+ - root `README.md` and `AGENTS.md`
30
30
 
31
31
  ## Rules For Shell Changes
32
32
 
@@ -53,7 +53,7 @@ Information an agent needs to **decide** on an approach — not to execute it.
53
53
 
54
54
  ### Prerequisites
55
55
 
56
- - A Git repository for your tree (separate from your code repos)
56
+ - A source/workspace Git repository, or an already-created dedicated tree repo
57
57
  - Node.js 18+
58
58
  - The npm package is `first-tree`, the installed CLI command is
59
59
  `context-tree`, and the installed skill directory in the tree is
@@ -63,20 +63,37 @@ Information an agent needs to **decide** on an approach — not to execute it.
63
63
 
64
64
  ### Step 1: Initialize
65
65
 
66
+ Recommended workflow: run `context-tree init` from your source or workspace repo.
67
+ The CLI will create a sibling dedicated tree repo named `<repo>-context` by
68
+ default and install the framework there.
69
+
66
70
  ```bash
67
- mkdir my-org-tree && cd my-org-tree
68
- git init
71
+ cd my-org
69
72
  context-tree init
73
+ cd ../my-org-context
74
+ ```
75
+
76
+ If you already created a dedicated tree repo manually, initialize it in place:
77
+
78
+ ```bash
79
+ mkdir my-org-context && cd my-org-context
80
+ git init
81
+ context-tree init --here
70
82
  ```
71
83
 
72
- This installs the framework skill into `skills/first-tree/`, renders scaffolding (`NODE.md`, `AGENT.md`, `members/NODE.md`), and generates a task list in `skills/first-tree/progress.md`.
84
+ Either way, the framework installs into `skills/first-tree/`, renders
85
+ scaffolding (`NODE.md`, `AGENTS.md`, `members/NODE.md`), and generates a task
86
+ list in `skills/first-tree/progress.md`.
87
+
88
+ Publishing tip: keep the tree repo in the same GitHub organization as the
89
+ source repo unless you have a reason not to.
73
90
 
74
91
  ### Step 2: Work Through the Task List
75
92
 
76
93
  Read `skills/first-tree/progress.md`. It contains a checklist tailored to the current state of the repo. Complete each task:
77
94
 
78
95
  - Fill in `NODE.md` with your organization name, owners, and domains
79
- - Add project-specific instructions to `AGENT.md` below the framework markers
96
+ - Add project-specific instructions to `AGENTS.md` below the framework markers
80
97
  - Create member nodes under `members/`
81
98
  - Optionally configure agent integration (e.g., Claude Code session hooks)
82
99
  - Copy validation workflows from `skills/first-tree/assets/framework/workflows/` to `.github/workflows/`
@@ -89,6 +106,12 @@ As you complete each task, check it off in `skills/first-tree/progress.md` by ch
89
106
  context-tree verify
90
107
  ```
91
108
 
109
+ Or, from your source/workspace repo:
110
+
111
+ ```bash
112
+ context-tree verify --tree-path ../my-org-context
113
+ ```
114
+
92
115
  This fails if any items in `skills/first-tree/progress.md` remain unchecked, and runs deterministic checks (valid frontmatter, node structure, member nodes exist).
93
116
 
94
117
  ### Step 4: Design Your Domains
@@ -126,9 +149,9 @@ The tree doesn't duplicate source code — it captures what connects things and
126
149
 
127
150
  | Command | Description |
128
151
  |---------|-------------|
129
- | `context-tree init` | Bootstrap a new tree. Installs the framework skill, renders templates, generates a task list. |
130
- | `context-tree verify` | Check the installed progress file for unchecked items + run deterministic validation. |
131
- | `context-tree upgrade` | Refresh the installed framework skill from the currently running `first-tree` npm package and generate follow-up tasks. |
152
+ | `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. |
153
+ | `context-tree verify` | Check the installed progress file for unchecked items + run deterministic validation. Use `--tree-path` when invoking from another working directory. |
154
+ | `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. |
132
155
  | `context-tree help onboarding` | Print this onboarding guide. |
133
156
 
134
157
  ---
@@ -159,4 +182,4 @@ install before running `context-tree upgrade`.
159
182
 
160
183
  - `skills/first-tree/references/principles.md` — Core principles with detailed examples
161
184
  - `skills/first-tree/references/ownership-and-naming.md` — How nodes are named and owned
162
- - `AGENT.md` in your tree — The before/during/after workflow for every task
185
+ - `AGENTS.md` in your tree — The before/during/after workflow for every task
@@ -43,7 +43,7 @@ These skill-owned files implement the framework behavior.
43
43
  | `engine/commands/` | Stable command entrypoints that the thin CLI imports |
44
44
  | `engine/init.ts` / `engine/verify.ts` / `engine/upgrade.ts` | Command implementations for install, verify, and upgrade |
45
45
  | `engine/onboarding.ts` | Canonical onboarding text loader |
46
- | `engine/repo.ts` | Repo inspection and layout helpers |
46
+ | `engine/repo.ts` | Repo inspection, source-vs-tree heuristics, and worktree-aware git-root helpers |
47
47
  | `engine/rules/` | Situation-aware task generation after `init` |
48
48
  | `engine/validators/` | Deterministic tree and member validation |
49
49
  | `engine/runtime/asset-loader.ts` | Path constants plus legacy-layout detection |
@@ -66,7 +66,7 @@ not become the only place important maintainer knowledge lives.
66
66
  | `vitest.config.ts` | Unit-test entrypoints |
67
67
  | `.github/workflows/ci.yml` | Thin CI shell |
68
68
  | `README.md` | Thin distribution overview |
69
- | `AGENT.md` | Thin maintainer pointer for agent sessions |
69
+ | `AGENTS.md` | Thin maintainer pointer for agent sessions |
70
70
 
71
71
  ## Validation
72
72
 
@@ -89,6 +89,6 @@ not become the only place important maintainer knowledge lives.
89
89
  - Legacy `.context-tree/...` paths still matter only for migrating existing
90
90
  user repos; the compatibility logic lives in
91
91
  `engine/runtime/asset-loader.ts` and `engine/upgrade.ts`.
92
- - Root `README.md` and `AGENT.md` are intentionally brief. Important
92
+ - Root `README.md` and `AGENTS.md` are intentionally brief. Important
93
93
  information must live in the skill references instead.
94
94
  - If you change `references/` or `assets/framework/`, run `pnpm validate:skill`.
@@ -38,13 +38,15 @@ skills/
38
38
  The tree content still lives outside the skill:
39
39
 
40
40
  - `NODE.md`
41
- - `AGENT.md`
41
+ - `AGENTS.md`
42
42
  - `members/`
43
43
 
44
44
  ## Command Intent
45
45
 
46
46
  - `context-tree init`
47
- - installs the skill into the target repo
47
+ - when run in a source/workspace repo, creates or reuses a sibling dedicated
48
+ tree repo by default
49
+ - installs the skill into the target tree repo
48
50
  - renders top-level tree scaffolding from the skill templates
49
51
  - writes progress state to `skills/first-tree/progress.md`
50
52
  - `context-tree verify`
@@ -58,12 +60,16 @@ The tree content still lives outside the skill:
58
60
  - migrates repos that still use the previous
59
61
  `skills/first-tree-cli-framework/` path onto `skills/first-tree/`
60
62
  - migrates legacy `.context-tree/` repos onto the installed skill layout
61
- - preserves user-authored sections such as the editable part of `AGENT.md`
63
+ - preserves user-authored sections such as the editable part of `AGENTS.md`
62
64
 
63
65
  ## Compatibility Rules For Legacy Trees
64
66
 
65
- - `context-tree init` only installs the skill layout; it never creates a new
66
- `.context-tree/`.
67
+ - `context-tree init` never creates a new `.context-tree/`.
68
+ - `context-tree init --here` preserves the explicit in-place bootstrap path for
69
+ already-created tree repos.
70
+ - Default dedicated-tree-repo creation is local-only. The CLI may create a new
71
+ sibling git repo on disk, but it must not clone the source repo or depend on
72
+ network access.
67
73
  - Normal `context-tree init` and `context-tree upgrade` flows do not clone the
68
74
  source repo or require network access.
69
75
  - `context-tree verify` may still read a legacy
@@ -72,6 +78,9 @@ The tree content still lives outside the skill:
72
78
  - `context-tree upgrade` must migrate either legacy layout onto
73
79
  `skills/first-tree/` and remove the old directory afterward.
74
80
  - When both layouts are present, prefer the installed skill layout.
81
+ - Existing repos may still have a legacy `AGENT.md`; `init` and `upgrade`
82
+ must not silently overwrite it, and follow-up tasks should direct users to
83
+ rename it to `AGENTS.md`.
75
84
 
76
85
  ## Invariants
77
86
 
@@ -70,7 +70,7 @@ require_file "$SOURCE_DIR/assets/framework/manifest.json"
70
70
  require_file "$SOURCE_DIR/assets/framework/VERSION"
71
71
  require_file "$SOURCE_DIR/assets/framework/prompts/pr-review.md"
72
72
  require_file "$SOURCE_DIR/assets/framework/templates/root-node.md.template"
73
- require_file "$SOURCE_DIR/assets/framework/templates/agent.md.template"
73
+ require_file "$SOURCE_DIR/assets/framework/templates/agents.md.template"
74
74
  require_file "$SOURCE_DIR/assets/framework/templates/members-domain.md.template"
75
75
  require_file "$SOURCE_DIR/assets/framework/templates/member-node.md.template"
76
76
  require_file "$SOURCE_DIR/assets/framework/workflows/validate.yml"
@@ -3,7 +3,10 @@ import { join } from "node:path";
3
3
  import { tmpdir } from "node:os";
4
4
  import { afterEach } from "vitest";
5
5
  import {
6
+ AGENT_INSTRUCTIONS_FILE,
7
+ AGENT_INSTRUCTIONS_TEMPLATE,
6
8
  FRAMEWORK_VERSION,
9
+ LEGACY_AGENT_INSTRUCTIONS_FILE,
7
10
  LEGACY_SKILL_VERSION,
8
11
  LEGACY_VERSION,
9
12
  } from "#skill/engine/runtime/asset-loader.js";
@@ -27,6 +30,20 @@ export function makeFramework(root: string, version = "0.1.0"): void {
27
30
  writeFileSync(join(root, FRAMEWORK_VERSION), `${version}\n`);
28
31
  }
29
32
 
33
+ export function makeGitRepo(root: string): void {
34
+ mkdirSync(join(root, ".git"), { recursive: true });
35
+ }
36
+
37
+ export function makeSourceRepo(root: string): void {
38
+ makeGitRepo(root);
39
+ mkdirSync(join(root, "src"), { recursive: true });
40
+ writeFileSync(
41
+ join(root, "package.json"),
42
+ JSON.stringify({ name: "example-source-repo" }, null, 2),
43
+ );
44
+ writeFileSync(join(root, "src", "index.ts"), "export const ready = true;\n");
45
+ }
46
+
30
47
  export function makeLegacyFramework(root: string, version = "0.1.0"): void {
31
48
  const ct = join(root, ".context-tree");
32
49
  mkdirSync(ct, { recursive: true });
@@ -85,7 +102,7 @@ export function makeSourceSkill(root: string, version = "0.2.0"): void {
85
102
  "assets",
86
103
  "framework",
87
104
  "templates",
88
- "agent.md.template",
105
+ AGENT_INSTRUCTIONS_TEMPLATE,
89
106
  ),
90
107
  "<!-- BEGIN CONTEXT-TREE FRAMEWORK -->\nframework text\n<!-- END CONTEXT-TREE FRAMEWORK -->\n",
91
108
  );
@@ -114,12 +131,15 @@ export function makeNode(
114
131
  );
115
132
  }
116
133
 
117
- export function makeAgentMd(
134
+ export function makeAgentsMd(
118
135
  root: string,
119
- opts?: { markers?: boolean; userContent?: boolean },
136
+ opts?: { markers?: boolean; userContent?: boolean; legacyName?: boolean },
120
137
  ): void {
121
138
  const markers = opts?.markers ?? true;
122
139
  const userContent = opts?.userContent ?? false;
140
+ const fileName = opts?.legacyName
141
+ ? LEGACY_AGENT_INSTRUCTIONS_FILE
142
+ : AGENT_INSTRUCTIONS_FILE;
123
143
  const parts: string[] = [];
124
144
  if (markers) {
125
145
  parts.push(
@@ -131,7 +151,7 @@ export function makeAgentMd(
131
151
  if (userContent) {
132
152
  parts.push("\n# Project-specific\nThis is real user content.\n");
133
153
  }
134
- writeFileSync(join(root, "AGENT.md"), parts.join("\n"));
154
+ writeFileSync(join(root, fileName), parts.join("\n"));
135
155
  }
136
156
 
137
157
  export function makeMembers(root: string, count = 1): void {