@theglitchking/babel-fish 2.5.0 → 2.6.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.
@@ -0,0 +1,76 @@
1
+ # Layout: monorepo -- several apps and shared packages in one repo, dev (localhost) -> stg -> prod (cloud).
2
+ #
3
+ # A reference, not a rule. `structure-check.py --bootstrap --layout monorepo` copies it,
4
+ # marks each folder active (exists) or planned (not yet), adds a folder for anything
5
+ # it doesn't cover, and lists the remaining differences in `exceptions` by exact
6
+ # path -- adopting it blocks nothing. The
7
+ # structure-bootstrap skill reads it to suggest purposes and changes.
8
+ mode = "monorepo"
9
+ env_file = "infra/env/.env.example" # the ONE committed env template (every key, every env and app)
10
+ root_files = [
11
+ "README.md", "LICENSE", "CHANGELOG.md", "CLAUDE.md", "AGENTS.md",
12
+ ".gitignore", ".gitattributes", ".editorconfig", ".dockerignore", ".mcp.json",
13
+ "package.json", "package-lock.json", "*.lock", "tsconfig*.json", "*.config.js", "*.config.ts",
14
+ "pyproject.toml", "requirements*.txt", "go.mod", "go.sum", "Cargo.toml",
15
+ "Makefile", "Dockerfile",
16
+ "pnpm-workspace.yaml", "turbo.json", "nx.json", "lerna.json", "go.work",
17
+ ]
18
+
19
+ [[folder]]
20
+ path = "apps"
21
+ purpose = "One folder per deployable app: apps/<name>/ with its own source, tests, manifest and migrations"
22
+ holds = ["*/**", "README.md"]
23
+
24
+ [[folder]]
25
+ path = "packages"
26
+ purpose = "Shared libraries: packages/<name>/, imported by apps, never deployed alone"
27
+ holds = ["*/**", "README.md"]
28
+
29
+ [[folder]]
30
+ path = "tests"
31
+ purpose = "Cross-app tests (end-to-end, contract); unit tests live with each app"
32
+
33
+ [[folder]]
34
+ path = "scripts"
35
+ purpose = "Repo-wide developer and ops scripts"
36
+
37
+ [[folder]]
38
+ path = "infra/compose"
39
+ purpose = "Compose files: base.yml shared, dev.yml for localhost, remote.yml for the cloud environments"
40
+ holds = ["*.yml", "*.yaml"]
41
+
42
+ [[folder]]
43
+ path = "infra/env"
44
+ purpose = "Env config: .env.example is the one template (every key, placeholders) and your local .env sits beside it, gitignored. Stg/prod values come from the secret manager or CI, never from files here; <env>/ holds only non-secret per-env deltas"
45
+ holds = [".env.example", "README.md", "*/**"]
46
+
47
+ [[folder]]
48
+ path = "infra/deploy"
49
+ purpose = "Cloud deploy config: base/ shared, <env>/ holds only what differs (Terraform, k8s, platform files)"
50
+
51
+ [[folder]]
52
+ path = ".github"
53
+ purpose = "CI workflows -- one deploy workflow that takes the environment as input"
54
+
55
+ [[folder]]
56
+ path = ".claude"
57
+ purpose = "Claude Code config: rules, skills, the project map and this manifest"
58
+
59
+ [[folder]]
60
+ path = ".documentation"
61
+ purpose = "Prose docs (hit-em-with-the-docs)"
62
+
63
+ [[environment]]
64
+ name = "dev"
65
+ target = "local"
66
+ promotes_to = "stg"
67
+
68
+ [[environment]]
69
+ name = "stg"
70
+ target = "cloud"
71
+ promotes_to = "prod"
72
+ mirrors = "prod"
73
+
74
+ [[environment]]
75
+ name = "prod"
76
+ target = "cloud"
@@ -0,0 +1,85 @@
1
+ # Layout: multi-repo -- this repo is one of several. Same flat layout as `single`;
2
+ # [[repo]] entries point at the others. Each of those runs its own babel-fish (map,
3
+ # drift, structure check) -- nothing here reaches into them.
4
+ #
5
+ # Environments: dev (localhost) -> stg -> prod (cloud).
6
+ #
7
+ # A reference, not a rule. `structure-check.py --bootstrap --layout multi-repo` copies it,
8
+ # marks each folder active (exists) or planned (not yet), adds a folder for anything
9
+ # it doesn't cover, and lists the remaining differences in `exceptions` by exact
10
+ # path -- adopting it blocks nothing. The
11
+ # structure-bootstrap skill reads it to suggest purposes and changes.
12
+ mode = "multi-repo"
13
+ env_file = "infra/env/.env.example" # the ONE committed env template (every key, every env and app)
14
+ root_files = [
15
+ "README.md", "LICENSE", "CHANGELOG.md", "CLAUDE.md", "AGENTS.md",
16
+ ".gitignore", ".gitattributes", ".editorconfig", ".dockerignore", ".mcp.json",
17
+ "package.json", "package-lock.json", "*.lock", "tsconfig*.json", "*.config.js", "*.config.ts",
18
+ "pyproject.toml", "requirements*.txt", "go.mod", "go.sum", "Cargo.toml",
19
+ "Makefile", "Dockerfile",
20
+ ]
21
+
22
+ [[folder]]
23
+ path = "src"
24
+ purpose = "Application source"
25
+
26
+ [[folder]]
27
+ path = "tests"
28
+ purpose = "Tests"
29
+
30
+ [[folder]]
31
+ path = "scripts"
32
+ purpose = "Developer and ops scripts"
33
+
34
+ [[folder]]
35
+ path = "migrations"
36
+ purpose = "Database migrations -- one folder, the same path forward in every environment"
37
+
38
+ [[folder]]
39
+ path = "infra/compose"
40
+ purpose = "Compose files: base.yml shared, dev.yml for localhost, remote.yml for the cloud environments"
41
+ holds = ["*.yml", "*.yaml"]
42
+
43
+ [[folder]]
44
+ path = "infra/env"
45
+ purpose = "Env config: .env.example is the one template (every key, placeholders) and your local .env sits beside it, gitignored. Stg/prod values come from the secret manager or CI, never from files here; <env>/ holds only non-secret per-env deltas"
46
+ holds = [".env.example", "README.md", "*/**"]
47
+
48
+ [[folder]]
49
+ path = "infra/deploy"
50
+ purpose = "Cloud deploy config: base/ shared, <env>/ holds only what differs (Terraform, k8s, platform files)"
51
+
52
+ [[folder]]
53
+ path = ".github"
54
+ purpose = "CI workflows -- one deploy workflow that takes the environment as input"
55
+
56
+ [[folder]]
57
+ path = ".claude"
58
+ purpose = "Claude Code config: rules, skills, the project map and this manifest"
59
+
60
+ [[folder]]
61
+ path = ".documentation"
62
+ purpose = "Prose docs (hit-em-with-the-docs)"
63
+
64
+ [[environment]]
65
+ name = "dev"
66
+ target = "local"
67
+ promotes_to = "stg"
68
+
69
+ [[environment]]
70
+ name = "stg"
71
+ target = "cloud"
72
+ promotes_to = "prod"
73
+ mirrors = "prod"
74
+
75
+ [[environment]]
76
+ name = "prod"
77
+ target = "cloud"
78
+
79
+ # One entry per repo this one works with. `path` is a local checkout (warned if
80
+ # missing), `url` the remote; at least one is required.
81
+ # [[repo]]
82
+ # name = "api"
83
+ # path = "../api"
84
+ # url = "https://github.com/<org>/api"
85
+ # purpose = "Backend API"
@@ -0,0 +1,73 @@
1
+ # Layout: single -- one project, flat layout, dev (localhost) -> stg -> prod (cloud).
2
+ #
3
+ # A reference, not a rule. `structure-check.py --bootstrap --layout single` copies it,
4
+ # marks each folder active (exists) or planned (not yet), adds a folder for anything
5
+ # it doesn't cover, and lists the remaining differences in `exceptions` by exact
6
+ # path -- adopting it blocks nothing. The
7
+ # structure-bootstrap skill reads it to suggest purposes and changes.
8
+ mode = "single"
9
+ env_file = "infra/env/.env.example" # the ONE committed env template (every key, every env and app)
10
+ root_files = [
11
+ "README.md", "LICENSE", "CHANGELOG.md", "CLAUDE.md", "AGENTS.md",
12
+ ".gitignore", ".gitattributes", ".editorconfig", ".dockerignore", ".mcp.json",
13
+ "package.json", "package-lock.json", "*.lock", "tsconfig*.json", "*.config.js", "*.config.ts",
14
+ "pyproject.toml", "requirements*.txt", "go.mod", "go.sum", "Cargo.toml",
15
+ "Makefile", "Dockerfile",
16
+ ]
17
+
18
+ [[folder]]
19
+ path = "src"
20
+ purpose = "Application source"
21
+
22
+ [[folder]]
23
+ path = "tests"
24
+ purpose = "Tests"
25
+
26
+ [[folder]]
27
+ path = "scripts"
28
+ purpose = "Developer and ops scripts"
29
+
30
+ [[folder]]
31
+ path = "migrations"
32
+ purpose = "Database migrations -- one folder, the same path forward in every environment"
33
+
34
+ [[folder]]
35
+ path = "infra/compose"
36
+ purpose = "Compose files: base.yml shared, dev.yml for localhost, remote.yml for the cloud environments"
37
+ holds = ["*.yml", "*.yaml"]
38
+
39
+ [[folder]]
40
+ path = "infra/env"
41
+ purpose = "Env config: .env.example is the one template (every key, placeholders) and your local .env sits beside it, gitignored. Stg/prod values come from the secret manager or CI, never from files here; <env>/ holds only non-secret per-env deltas"
42
+ holds = [".env.example", "README.md", "*/**"]
43
+
44
+ [[folder]]
45
+ path = "infra/deploy"
46
+ purpose = "Cloud deploy config: base/ shared, <env>/ holds only what differs (Terraform, k8s, platform files)"
47
+
48
+ [[folder]]
49
+ path = ".github"
50
+ purpose = "CI workflows -- one deploy workflow that takes the environment as input"
51
+
52
+ [[folder]]
53
+ path = ".claude"
54
+ purpose = "Claude Code config: rules, skills, the project map and this manifest"
55
+
56
+ [[folder]]
57
+ path = ".documentation"
58
+ purpose = "Prose docs (hit-em-with-the-docs)"
59
+
60
+ [[environment]]
61
+ name = "dev"
62
+ target = "local"
63
+ promotes_to = "stg"
64
+
65
+ [[environment]]
66
+ name = "stg"
67
+ target = "cloud"
68
+ promotes_to = "prod"
69
+ mirrors = "prod"
70
+
71
+ [[environment]]
72
+ name = "prod"
73
+ target = "cloud"
@@ -6,13 +6,13 @@
6
6
  },
7
7
  "metadata": {
8
8
  "description": "Official marketplace for babel-fish - Codebase introspection and vocabulary translation for AI coding assistants",
9
- "version": "2.5.0"
9
+ "version": "2.6.0"
10
10
  },
11
11
  "plugins": [
12
12
  {
13
13
  "name": "babel-fish",
14
14
  "description": "Auto-generates a project map, vocabulary translation layer, and developer skill for any codebase. Introspects routes, models, services, features, infrastructure, and session history to give Claude instant full-stack context. Self-updates via pre-commit hook.",
15
- "version": "2.5.0",
15
+ "version": "2.6.0",
16
16
  "author": {
17
17
  "name": "TheGlitchKing"
18
18
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "babel-fish",
3
3
  "description": "Auto-generates a project map, vocabulary translation layer, and developer skill for any codebase. Introspects routes, models, services, features, infrastructure, and session history to give Claude instant full-stack context. Self-updates via pre-commit hook.",
4
- "version": "2.5.0",
4
+ "version": "2.6.0",
5
5
  "author": {
6
6
  "name": "TheGlitchKing",
7
7
  "email": "theglitchking@users.noreply.github.com"
@@ -38,3 +38,21 @@ if git diff --cached --name-only 2>/dev/null | grep -qE '^(\.claude/)?CLAUDE(\.l
38
38
  fi
39
39
  fi
40
40
  # ── End Context Check ────────────────────────────────────────────────────────
41
+
42
+ # ── Structure Check: files land where .claude/structure.toml says (#22) ──────
43
+ # Opt-in: runs only once the repo has a manifest. On Python < 3.11 it warns and passes.
44
+ if [ -f ".claude/structure.toml" ]; then
45
+ CHECK_SCRIPT=".claude/project-map/structure-check.py"
46
+ if [ -f "$CHECK_SCRIPT" ]; then
47
+ PYTHON=""
48
+ if [ -f ".venv/bin/python3" ]; then PYTHON=".venv/bin/python3"
49
+ elif command -v python3 &>/dev/null; then PYTHON="python3"
50
+ elif command -v python &>/dev/null; then PYTHON="python"
51
+ fi
52
+ if [ -n "$PYTHON" ] && ! $PYTHON "$CHECK_SCRIPT" --staged; then
53
+ echo "[structure-check] Commit blocked. Each FAIL above has a fix: line -- or change .claude/structure.toml if the structure should change." >&2
54
+ exit 1
55
+ fi
56
+ fi
57
+ fi
58
+ # ── End Structure Check ──────────────────────────────────────────────────────
package/CHANGELOG.md CHANGED
@@ -2,6 +2,63 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [2.6.0] - 2026-09-30
6
+
7
+ ### Added
8
+
9
+ - **`structure-check.py`: files land where the repo says they go**
10
+ ([#22](https://github.com/the-glitch-kingdom/babel-fish/issues/22)). The project map
11
+ describes where things *are*. The new, opt-in `.claude/structure.toml` says where
12
+ they *should go*, and the check enforces it at commit time and in CI.
13
+
14
+ **Manifest.** Each approved folder declares a `purpose`, optional `holds` globs and
15
+ a lifecycle status: `planned` (approved, may be created), `active`, or `deprecated`
16
+ (new files blocked while existing ones move out). The manifest also lists
17
+ `root_files`, an `exceptions` baseline so adopting the check blocks nothing (only
18
+ *new* violations fail), and `[[repo]]` pointers for multi-repo setups. Each pointed-to
19
+ repo runs its own babel-fish; nothing crosses repos. The mode is `single`,
20
+ `monorepo` or `multi-repo`.
21
+
22
+ **Environment lifecycle.** Declared `[[environment]]`s (`target` local or cloud,
23
+ `promotes_to`, `mirrors`) enforce dev → stg → prod: undeclared environment folders
24
+ fail, stg must hold the same files as prod, local-only files (Compose, seeds, certs)
25
+ stay out of cloud environments and deploy config stays out of local ones,
26
+ environment folders hold deltas only (an identical copy of a shared file fails),
27
+ migrations are never per-environment, and per-app environment folders outside
28
+ `env_roots` fail. A tracked `.env` fails in every mode. Only an exact-path
29
+ exception, added by hand for a committed test fixture, can allow one.
30
+
31
+ **One `.env`, as close as the structure allows.** A single committed template
32
+ (`env_file`, default `infra/env/.env.example`) holds every key for every
33
+ environment and app; the one real `.env` sits beside it, gitignored; stg/prod values
34
+ come from the secret manager. Any other template (per-app, per-environment,
35
+ `.env.sample`, `example.env`) fails with "merge its keys into env_file". A real
36
+ env file that git would commit fails before it is staged, and scattered local ones
37
+ warn. Bootstrap keeps an existing single template where it is and puts extra
38
+ templates in the backlog.
39
+
40
+ **Detection and adoption.** `--detect [--json]` reports facts: best-guess mode with
41
+ reasons, environments seen, top-level folders, sibling repos, and whether the repo is
42
+ new. `--bootstrap [--layout single|monorepo|multi-repo]` writes a starting manifest
43
+ and never overwrites an existing one. Uncovered top-level folders become their own
44
+ entries, leftover violations seed `exceptions` as exact paths, and tracked secrets
45
+ are never seeded. With
46
+ no manifest, running the script explains the options and exits 0. Flags for commit
47
+ and CI: `--staged` and `--since REF`.
48
+
49
+ **`structure-bootstrap` skill.** It makes the judgment calls the script can't:
50
+ folder purposes and `holds` from real contents, which layout fits, planning a new
51
+ repo from a project description, recipes for adding and retiring folders, apps and
52
+ environments, and, only on request, for Flow C, or for a new repo, a rules file and
53
+ a procedure doc.
54
+
55
+ The pre-commit hook gets a `Structure Check` block (own marker, so re-running
56
+ `bash .claude/install.sh` adds it to existing hooks). It runs only when the manifest
57
+ exists. The installer copies the script and the layouts and never touches
58
+ `structure.toml`. On Python < 3.11 (no `tomllib`) the check prints a readable warning
59
+ and passes; the rest of babel-fish still runs on 3.8. When a manifest exists,
60
+ `PROJECT_MAP.md` gets a one-line pointer to it plus the related repos.
61
+
5
62
  ## [2.5.0] - 2026-09-25
6
63
 
7
64
  ### Added
package/README.md CHANGED
@@ -242,6 +242,31 @@ python .claude/project-map/context-check.py --budget 80000 --map-style
242
242
 
243
243
  ---
244
244
 
245
+ ## Repo Structure Check *(2.6.0+)*
246
+
247
+ The map shows where things **are**. An opt-in `.claude/structure.toml` says where they **should go**, and `structure-check.py` blocks the commit (and fails CI) when a file lands somewhere else.
248
+
249
+ - **Folders with a lifecycle:** each approved folder has a purpose, optional `holds` globs, and a status of `planned`, `active` or `deprecated`. A deprecated folder takes no new files while the old ones move out.
250
+ - **dev → stg → prod:** declared environments must stay separate:
251
+ - stg holds the same files as prod
252
+ - environment folders hold only what differs
253
+ - local tooling stays out of the cloud environments, and deploy config out of local ones
254
+ - migrations are shared across environments
255
+ - a real `.env` is never committed
256
+ - **One `.env`, not twenty:** a single committed `.env.example` holds every key for every environment and app, and the one real `.env` sits beside it, gitignored. Stray templates, per-app `.env` files and a `.env` that git would commit all get caught.
257
+ - **Modes:** `single`, `monorepo`, or `multi-repo`. In multi-repo, `[[repo]]` entries point at sibling repos, each running its own babel-fish.
258
+ - **Adoption blocks nothing:** `--bootstrap` seeds an `exceptions` baseline from today's tree, so only *new* violations fail.
259
+
260
+ ```bash
261
+ python .claude/project-map/structure-check.py --detect # mode, environments, folders
262
+ python .claude/project-map/structure-check.py --bootstrap --layout monorepo # start a manifest (never overwrites)
263
+ python .claude/project-map/structure-check.py --since origin/main # CI
264
+ ```
265
+
266
+ Or ask Claude to *"set up the repo structure"*. The `structure-bootstrap` skill reads the tree, fills in each folder's purpose, can plan a new repo from a description, and asks only what it can't infer. Needs Python 3.11+ (on older Python it warns and passes). See [repo structure check](./.documentation/standards/repo-structure-check.md) and [changing repo structure](./.documentation/procedures/changing-repo-structure.md).
267
+
268
+ ---
269
+
245
270
  ## File Structure
246
271
 
247
272
  ```
@@ -251,11 +276,14 @@ python .claude/project-map/context-check.py --budget 80000 --map-style
251
276
  │ ├── grader.py # Quality grader
252
277
  │ ├── mine-sessions.py # Session vocabulary miner
253
278
  │ ├── context-check.py # Budget + pointer check for auto-loaded files
279
+ │ ├── structure-check.py # Files vs .claude/structure.toml (opt-in)
254
280
  │ ├── PROJECT_MAP.md # TOC + quick routing guide
255
281
  │ ├── sections/ # 19 focused section files
256
282
  │ ├── reports/ # Install and iteration reports
257
283
  │ ├── checksums.json # Skip regeneration if unchanged
258
284
  │ └── learned-vocabulary.json # Persisted session aliases
285
+ ├── structure.toml # Your repo's structure manifest (you own it; never overwritten)
286
+ ├── templates/structure/ # Layouts: single, monorepo, multi-repo
259
287
  ├── rules/
260
288
  │ ├── project-vocabulary.md # Auto-loaded every session
261
289
  │ └── operational-runbook.md # Auto-loaded every session
@@ -263,7 +291,7 @@ python .claude/project-map/context-check.py --budget 80000 --map-style
263
291
  └── <project>-developer-skill/
264
292
  └── SKILL.md
265
293
  .githooks/
266
- ├── pre-commit # Regenerates map; runs the context check
294
+ ├── pre-commit # Regenerates map; runs the context + structure checks
267
295
  └── install.sh # Register hooks: bash .githooks/install.sh
268
296
  ```
269
297
 
@@ -284,7 +312,7 @@ python .claude/project-map/context-check.py --budget 80000 --map-style
284
312
  ## Requirements
285
313
 
286
314
  - AI coding assistant (Claude Code, Cursor, or compatible)
287
- - Python ≥ 3.8 (auto-installed if missing)
315
+ - Python ≥ 3.8 (auto-installed if missing); the structure check needs ≥ 3.11
288
316
  - Bash
289
317
  - Optional: `pip install pyyaml` for docker-compose YAML parsing (regex fallback included)
290
318
 
@@ -298,6 +326,7 @@ python .claude/project-map/context-check.py --budget 80000 --map-style
298
326
  | `python .claude/project-map/grader.py` | Grade map quality (0–100%) |
299
327
  | `python .claude/project-map/mine-sessions.py` | Mine session vocabulary |
300
328
  | `python .claude/project-map/context-check.py` | Check auto-loaded context: budget, pointers |
329
+ | `python .claude/project-map/structure-check.py` | Check files against `.claude/structure.toml` (`--detect`, `--bootstrap`) |
301
330
  | `bash .githooks/install.sh` | (Re)install git hooks |
302
331
  | `bash .claude/install.sh` | Re-run full plugin installer |
303
332
 
package/checksums.json CHANGED
@@ -1,4 +1,4 @@
1
1
  {
2
- "install_sh": "eb3a15ddeaf969b3b0e609fe6cde7792efd7c60ef2305d8593cb761fe812c1aa",
2
+ "install_sh": "a60cc1de663517c86ec4f6aa35f4171c2e32f2d0c43001202583039d9b7d847a",
3
3
  "note": "SHA256 of .claude/install.sh \u2014 verified by the remote installer before execution"
4
4
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@theglitchking/babel-fish",
3
- "version": "2.5.0",
3
+ "version": "2.6.0",
4
4
  "description": "Gives your AI coding assistant instant, accurate knowledge of every route, model, service, feature, and infrastructure element in your codebase.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -8,7 +8,7 @@
8
8
  },
9
9
  "scripts": {
10
10
  "postinstall": "node scripts/link-skills.js",
11
- "test": "python3 .claude/project-map/test_generate.py && python3 .claude/project-map/test_mine_sessions.py && python3 .claude/project-map/test_grader.py && python3 .claude/project-map/test_context_check.py"
11
+ "test": "python3 .claude/project-map/test_generate.py && python3 .claude/project-map/test_mine_sessions.py && python3 .claude/project-map/test_grader.py && python3 .claude/project-map/test_context_check.py && python3 .claude/project-map/test_structure_check.py"
12
12
  },
13
13
  "files": [
14
14
  "bin/",
@@ -23,10 +23,12 @@
23
23
  ".claude/project-map/grader.py",
24
24
  ".claude/project-map/mine-sessions.py",
25
25
  ".claude/project-map/context-check.py",
26
+ ".claude/project-map/structure-check.py",
26
27
  ".claude/project-map/test_generate.py",
27
28
  ".claude/project-map/test_mine_sessions.py",
28
29
  ".claude/project-map/test_grader.py",
29
30
  ".claude/project-map/test_context_check.py",
31
+ ".claude/project-map/test_structure_check.py",
30
32
  ".githooks/",
31
33
  "skills/",
32
34
  "install.sh",
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  // Postinstall — delegates to @theglitchking/claude-plugin-runtime.
3
- // babel-fish ships one skill (skills/babel-fish-developer-skill/) which
4
- // the runtime symlinks into <project>/.claude/skills/ so Claude Code
5
- // can discover it. Runtime also writes the default update-policy config
3
+ // babel-fish ships two skills (skills/babel-fish-developer-skill/ and
4
+ // skills/structure-bootstrap/) which the runtime symlinks into
5
+ // <project>/.claude/skills/ so Claude Code can discover them. Runtime also writes the default update-policy config
6
6
  // and registers the SessionStart hook (with plugin-vs-npm dedup).
7
7
  //
8
8
  // NOTE: npm install only handles the skill + update policy. To get the