@ainova-systems/intelligence 0.11.0-rc.7 → 0.11.0-rc.8

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 (50) hide show
  1. package/README.md +15 -16
  2. package/cli/commands/adapter.sh +153 -0
  3. package/cli/commands/init.sh +113 -22
  4. package/cli/commands/package.sh +30 -0
  5. package/cli/commands/registry.sh +4 -2
  6. package/cli/commands/status.sh +12 -4
  7. package/cli/commands/sync.sh +7 -20
  8. package/cli/commands/update.sh +76 -70
  9. package/cli/engine-package.yaml +2 -2
  10. package/cli/intelligence +10 -12
  11. package/cli/{commands/doctor.sh → internal/check.sh} +32 -14
  12. package/cli/{commands/migrate.sh → internal/migrate-v1.sh} +114 -25
  13. package/cli/{commands/add.sh → internal/package-add.sh} +3 -3
  14. package/cli/{commands/list.sh → internal/package-list.sh} +9 -4
  15. package/cli/{commands/remove.sh → internal/package-remove.sh} +3 -3
  16. package/cli/{commands/search.sh → internal/package-search.sh} +4 -4
  17. package/cli/internal/package-update.sh +97 -0
  18. package/cli/{commands/install.sh → internal/restore.sh} +3 -3
  19. package/cli/internal/target-state.sh +57 -0
  20. package/cli/{commands/upgrade.sh → internal/upgrade-v2.sh} +48 -8
  21. package/cli/lib/cli-common.sh +133 -7
  22. package/cli/lib/lockfile.sh +1 -1
  23. package/cli/lib/manifest.sh +86 -0
  24. package/cli/lib/registry.sh +4 -4
  25. package/engine/ENGINE_SHA +1 -1
  26. package/engine/adapters/_template.sh +10 -9
  27. package/engine/adapters/agents.sh +11 -11
  28. package/engine/adapters/opencode.sh +1 -1
  29. package/engine/lib/common.sh +14 -22
  30. package/engine/lib/contract.sh +14 -14
  31. package/engine/sync.sh +25 -20
  32. package/package.json +1 -1
  33. package/packages/sync/agents/intelligence-architect.md +5 -3
  34. package/packages/sync/agents/intelligence-operator.md +10 -13
  35. package/packages/sync/references/adapters.md +252 -0
  36. package/packages/sync/references/conventions.md +385 -0
  37. package/packages/sync/rules/intelligence-authoring.md +6 -6
  38. package/packages/sync/skills/intelligence-add-agent/SKILL.md +5 -5
  39. package/packages/sync/skills/intelligence-add-rule/SKILL.md +3 -3
  40. package/packages/sync/skills/intelligence-add-skill/SKILL.md +3 -3
  41. package/packages/sync/skills/intelligence-extract-skill/SKILL.md +2 -2
  42. package/packages/sync/skills/intelligence-install-adapter/SKILL.md +29 -22
  43. package/packages/sync/skills/intelligence-learn-from-context/SKILL.md +3 -3
  44. package/packages/sync/skills/intelligence-learn-from-repository/SKILL.md +55 -0
  45. package/packages/sync/skills/intelligence-review-skills/SKILL.md +6 -6
  46. package/packages/sync/skills/intelligence-sync/SKILL.md +13 -9
  47. package/packages/sync/skills/intelligence-uninstall-adapter/SKILL.md +19 -37
  48. package/packages/sync/skills/intelligence-update/SKILL.md +34 -156
  49. package/packages/sync/docs/ADAPTERS.md +0 -214
  50. package/packages/sync/docs/CONVENTIONS.md +0 -456
@@ -1,165 +1,43 @@
1
1
  ---
2
2
  name: intelligence-update
3
- description: "Update or migrate intelligence-sync: discover engine, read changelog, run migration chain, verify"
4
- argument-hint: "[--yes]"
3
+ description: "Interpret an update plan and verify breaking post-conditions"
4
+ argument-hint: "[@scope/name]"
5
5
  agent: intelligence-operator
6
6
  ---
7
7
 
8
- # Update intelligence-sync
8
+ # Update intelligence
9
9
 
10
- You are the **intelligent driver** of an update. The bash engine is
11
- deterministic and fail-closed — it never guesses; on any state it cannot
12
- resolve it prints `IS_STATUS=<code>` and stops. Your job: discover the engine,
13
- understand what is changing (read the CHANGELOG across the version gap), run
14
- the migration chain, branch on the status, and **verify afterward**. Ask the
15
- user only when genuinely ambiguous.
16
-
17
- Trigger: the user says something like *"update / migrate intelligence-sync"*.
18
- They never run shell commands by hand — you do.
19
-
20
- ## Key facts
21
-
22
- - **Umbrella** = whatever directory holds `config.yaml` (`intelligence/`,
23
- `Intelligence/`, …). Never assume the name — find it.
24
- - **Engine = a module discovered by ROLE, not by name**: a directory under
25
- the umbrella whose `scripts/sync.sh` **and** `scripts/VERSION` both exist
26
- (conventionally `sync/`, but never assume the folder name).
27
- - **Applied schema version** is the frozen contract key
28
- `sync_version` in `config.yaml` (a permanent top-level scalar;
29
- absent ⇒ pre-0.3.1). **Engine version** is `<module>/scripts/VERSION`.
30
- The gap between them is the set of breaking changes to apply.
31
- - Pre-0.3.1 projects have the engine flat at `<umbrella>/scripts/` and **no**
32
- `sync_version` key. Their frozen `update.sh` fails closed
33
- against the modular upstream (changes nothing) — you bootstrap the first hop.
34
- - The `intelligence-` skill prefix is **reserved** for upstream meta-skills.
10
+ The CLI owns planning and application. This skill interprets the plan, reads
11
+ the changelog across an engine-version gap, obtains approval, and verifies the
12
+ result.
35
13
 
36
14
  ## Steps
37
15
 
38
- ### 0. Vendored setups only
39
- If the project has a root `intelligence.yaml` (a CLI setup), **stop** — this
40
- flow is vendored-only. There the engine ships inside the CLI package: run
41
- `npm i -g @ainova-systems/intelligence@latest`, then `intelligence upgrade`,
42
- and verify with `intelligence doctor`.
43
-
44
- ### 1. Locate the umbrella & discover the engine
45
- Find the dir containing `config.yaml` → `<umbrella>`. Then find the engine by
46
- role: search `<umbrella>` (one level deep) for a directory `<M>` with both
47
- `<M>/scripts/sync.sh` and `<M>/scripts/VERSION`.
48
-
49
- - Several candidates → pick the one with the highest `scripts/VERSION`.
50
- - A module engine exists → use it; **never** fall back to a flat
51
- `<umbrella>/scripts/` even if present (that's stale legacy).
52
- - No module engine, only flat `<umbrella>/scripts/` (or nothing) → this is a
53
- pre-0.3.1 / un-bootstrapped project; go to step 2's bootstrap.
54
- - No `config.yaml` at all → not bootstrapped; point the user at upstream
55
- `INIT.md` and stop.
56
-
57
- ### 2. Fetch upstream (read-only) — do NOT write into the project yet
58
- Clone upstream into a temp dir (default
59
- `https://github.com/ainova-systems/intelligence-sync`, or the user's
60
- `REPO_URL`/fork). The upstream module is always `intelligence/sync/`.
61
-
62
- ```
63
- git clone --depth=1 <repo> <tmp>
64
- ```
65
-
66
- **Make no changes to the project before step 3's confirmation.** In
67
- particular do not copy anything into `<umbrella>/sync` yet — that would
68
- modify (and could downgrade) an already-modular project even if the user then
69
- declines. The temp clone is only for reading the CHANGELOG and as the source
70
- for the eventual write.
71
-
72
- ### 3. Understand what is changing (changelog-aware)
73
- Determine the project's current version = the `sync_version`
74
- value in `config.yaml`, or `0.0.0` if the key is absent (pre-0.3.1). The
75
- engine version = `<tmp>/intelligence/sync/scripts/VERSION`.
76
-
77
- Read `<tmp>/CHANGELOG.md`. For every release in the range
78
- **`current < release <= engine`** (inclusive of the target release — its
79
- entry holds the destination's breaking post-conditions), read its entry. Pay
80
- special attention to any **`### Breaking`** subsection (the
81
- machine-distinguishable marker). Build a short list of breaking items, new
82
- migrations, and anything to verify afterward. Surface it to the user; without
83
- `--yes`, let them confirm before any write.
84
-
85
- ### 3a. Ensure the engine to run (only now, post-confirmation)
86
- - **Modular project** (a module engine was discovered in step 1): run *its*
87
- `update.sh` — at the discovered module dir, whatever its name. `update.sh`
88
- re-clones upstream internally, shows the diff, and is authoritative; do not
89
- hand-copy over the module.
90
- - **No module engine** (pre-0.3.1 flat or un-bootstrapped): only here create
91
- the module from the temp clone, and only after confirmation:
92
- ```
93
- mkdir -p <umbrella>/sync
94
- cp -r <tmp>/intelligence/sync/. <umbrella>/sync/
95
- ```
96
- then run `<umbrella>/sync/scripts/update.sh`.
97
-
98
- ### 4. Run the engine
99
- Run the `update.sh` of the engine determined in 3a — the **discovered module
100
- dir** for a modular project (whatever its name), or the just-created
101
- `<umbrella>/sync` for the legacy bootstrap path:
102
-
103
- ```
104
- bash <engine-module>/scripts/update.sh --yes # omit --yes to confirm the diff
105
- ```
106
- Capture stdout; find the last `IS_STATUS=<code> [IS_DETAIL=...]` line.
107
-
108
- ### 5. Branch on `IS_STATUS`
109
-
110
- | Code | Meaning | Action |
111
- |---|---|---|
112
- | `ok` | Already current | Go to step 6. |
113
- | `migrated` | Migration chain applied | Go to step 6; note the relocation/changes. |
114
- | `aborted-incomplete` | Staged module incomplete; legacy intact (safe) | Re-run step 2–4 once (clone hiccup). Persists → show output, stop, don't hand-fix. |
115
- | `ahead-of-engine` | Project schema newer than this engine | Do **not** downgrade. Point `REPO_URL` at the correct/newer upstream, or accept it's already ahead. Stop. |
116
- | `needs-update` | Pending breaking changes (sync refused) | Expected pre-migration; proceed — `update.sh` is the migrator. If it persists *after* update, investigate. |
117
- | `config-missing` | No `config.yaml` | Not bootstrapped — direct user to `<umbrella>/sync/INIT.md`. Stop. |
118
- | `error` | Engine couldn't proceed | Show message; check `REPO_URL`. Stop. |
119
- | *(no status)* | Engine crashed before contract | Show full output; don't modify the tree. Stop. |
120
-
121
- On any failure code, first re-read the upstream `CHANGELOG.md` entries for `current < release <= engine` (esp. `### Breaking`) — the breaking change usually explains the error and what the user must do — before retrying or escalating.
122
-
123
- Genuinely **ambiguous** tree (e.g. both a legacy flat `<umbrella>/scripts/`
124
- and a populated module, no clear `sync_version`): inspect both,
125
- summarize the difference, ask the user which is authoritative, apply their
126
- choice. Never guess.
127
-
128
- ### 6. Verify (always, after `ok`/`migrated`)
129
-
130
- Structural — always:
131
- - No `intelligence-*` directory directly under `<umbrella>/skills/`
132
- (meta-skills live only in the module's `skills/`).
133
- - Project content intact: `<umbrella>/{rules,agents}/` and any
134
- non-`intelligence-` skills untouched.
135
- - `config.yaml` has `sync_version` equal to the engine
136
- `scripts/VERSION`, and `sources.skills` includes the module skills path
137
- exactly once.
138
-
139
- Changelog-driven — per release crossed:
140
- - For each **`### Breaking`** item in the crossed range, verify its stated
141
- post-condition actually holds (e.g. a removed/renamed file is gone, a
142
- config-schema change is reflected). If a breaking item has no verifiable
143
- post-condition, state that you could not auto-verify it.
144
-
145
- Then regenerate IDE outputs:
146
- ```
147
- bash <umbrella>/sync/scripts/sync.sh
148
- ```
149
- Relay any model-drift report. Finally summarize: versions before→after, the
150
- breaking changes applied, verification result, anything the user must act on.
151
- Clean up the temp clone.
152
-
153
- ## Notes
154
-
155
- - Everything is **idempotent**. Re-running on a current project is a safe
156
- no-op (`IS_STATUS=ok`).
157
- - Correctness rests on the engine's idempotent structural preconditions, not
158
- on the version stamp — a missing/wrong `sync_version` cannot
159
- cause a needed migration to be skipped; it only weakens the
160
- `ahead-of-engine` guard until re-stamped.
161
- - Never touch `config.yaml` beyond what the engine does (the idempotent
162
- `sources.skills` line and the `sync_version` key). Never
163
- move/delete project skills, rules, or agents.
164
- - Sibling modules beside the engine module are independent — only operate on
165
- the discovered engine module.
16
+ 1. Run `intelligence update --preview` (or
17
+ `intelligence update $ARGUMENTS --preview` for one named package). Use its
18
+ CLI, project, and package sections as the complete plan; do not re-resolve
19
+ versions independently.
20
+
21
+ 2. If the CLI or project engine version would change, read the authoritative
22
+ `CHANGELOG.md` at `https://github.com/ainova-systems/intelligence` for every
23
+ release in **`current < release <= target`**. If it is unavailable, stop
24
+ before changing versions. Turn every crossed `### Breaking` item into a
25
+ post-condition to verify.
26
+
27
+ 3. Show the plan and breaking checklist to the user. The command without a
28
+ mode also shows the plan and prompts; after approval, use `--apply` for an
29
+ unambiguous non-interactive execution.
30
+
31
+ 4. If the plan reports a newer global CLI, run exactly the npm command it
32
+ prints after approval, then rerun `intelligence update --preview` with the
33
+ new executable. Apply the resulting plan with `intelligence update --apply`,
34
+ or `intelligence update $ARGUMENTS --apply` when one package was requested.
35
+
36
+ 5. An applied update that renders must finish with `IS_STATUS=ok`; preserve and
37
+ stop on any other status. Then run `intelligence status --check`. Do not run
38
+ a duplicate sync after `update --apply`. Verify every crossed breaking
39
+ post-condition directly and report any item that cannot be machine-verified.
40
+
41
+ Report versions before and after, the applied plan, post-condition results,
42
+ and any remaining action. On a refusal, preserve the full error and stop
43
+ instead of invoking hidden lifecycle operations.
@@ -1,214 +0,0 @@
1
- # intelligence-sync: Writing a New Adapter
2
-
3
- ## Overview
4
-
5
- An adapter transforms source prompts (from `intelligence/`) into an IDE-specific format. Each adapter is a single bash file, discovered by filename.
6
-
7
- ## Where adapters live
8
-
9
- `sync.sh` scans two directories, in this order:
10
-
11
- | Location | Owner | Survives `update.sh`? |
12
- |---|---|---|
13
- | `intelligence/sync/scripts/adapters/` | **upstream** — the built-ins shipped with the engine | No — the engine replaces this directory wholesale on every update |
14
- | `intelligence/adapters/` (beside `config.yaml`) | **the project** | Yes — updates never touch project content |
15
-
16
- Write custom adapters in the project's `intelligence/adapters/`. A file placed in the engine's own `adapters/` is deleted by the next `update.sh`, silently and without a diff to notice. A project adapter whose name matches a built-in **overrides** it (sync prints a `NOTE:` line saying so) — an escape hatch for patching a built-in without forking the engine. An adapter that would serve every project is worth contributing upstream instead.
17
-
18
- The umbrella folder is not hardcoded anywhere — `intelligence/` above means "whatever directory holds `config.yaml`".
19
-
20
- ## Quick Start
21
-
22
- 1. Copy `intelligence/sync/scripts/adapters/_template.sh` to `intelligence/adapters/<name>.sh`
23
- 2. Replace `<name>` placeholders with your adapter name
24
- 3. Implement the `sync_to_<name>()` function
25
- 4. Add target to `config.yaml`:
26
- ```yaml
27
- targets:
28
- <name>: { enabled: true, output: ".<name>" }
29
- ```
30
- 5. Run `bash intelligence/sync/scripts/sync.sh <name>` to test
31
-
32
- ## Adapter Contract
33
-
34
- ### Required Function
35
-
36
- ```bash
37
- sync_to_<name>(repo_root, config_file, output_dir)
38
- ```
39
-
40
- This is called by `sync.sh` for each enabled target.
41
-
42
- Parameters:
43
- - `repo_root` -- absolute path to the project root
44
- - `config_file` -- absolute path to `config.yaml`
45
- - `output_dir` -- absolute path to output directory (e.g., `/project/.cursor`)
46
-
47
- ### Available Library Functions
48
-
49
- Source `lib/common.sh` for these utilities:
50
-
51
- | Function | Description |
52
- |----------|-------------|
53
- | `finalize_output_file(file)` | **Call this on every file you write.** Expands layout tokens (`<umbrella>`, `<module>`) and converts CRLF to LF |
54
- | `normalize_file_to_lf(file)` | LF conversion only — for intermediate files that are not adapter output |
55
- | `lint_frontmatter(file)` | Warn about unquoted colons, leading tabs, and literal double quotes inside unquoted values (stderr) |
56
- | `get_frontmatter_value(key, file)` | Extract YAML frontmatter value |
57
- | `has_frontmatter(file)` | Check for `---` header |
58
- | `has_paths(file)` | Check for `paths:` field |
59
- | `get_model(config, ide, tier)` | Resolve model from `models:` override or default |
60
- | `get_model_default(ide, tier)` | Hardcoded default for `<ide>:<tier>` |
61
- | `map_access_to_claude_tools(access)` | Tool string for access level |
62
- | `map_access_to_claude_disallowed(access)` | Disallowed tools string |
63
- | `read_yaml_list(config, section)` | Read list from `config.yaml` |
64
- | `resolve_source_dir(repo_root, src)` | Map a source entry to a local dir — `"$repo_root/$src"` for a path, or a shallow clone for a pack reference (`@<name>[/<subpath>]`) or an inline `git+<url>` spec |
65
- | `source_is_local_path(src)` | True (0) if a source entry is a plain repo-relative path — i.e. neither of the two below. Use this, not a negated `source_is_remote`, whenever a token is about to be pattern-matched against a real directory |
66
- | `source_is_pack(src)` | True (0) if a source entry references a pack declared under `packs:` (`@<name>`) |
67
- | `source_is_remote(src)` | True (0) if a source entry is an inline remote `git+` spec |
68
- | `get_target_field(config, target, field)` | Read a field from a target's config block |
69
-
70
- ### Transformation Patterns
71
-
72
- Each adapter handles three prompt types. Here's how the built-in adapters approach each:
73
-
74
- **Rules:**
75
-
76
- intelligence-sync routes rule content based on **scope** (always-on vs path-scoped) and on which channels each IDE actually reads, to avoid duplicating content into multiple places.
77
-
78
- | Source | `agents` (AGENTS.md) | `claude` | `cursor` | `copilot` | `codex` | `pi` | `opencode` |
79
- |--------|----------------------|----------|----------|-----------|---------|------|------------|
80
- | Always-on (no `paths:`) | inlined as canonical | copied as-is | skipped (Cursor reads AGENTS.md) | skipped (Copilot reads AGENTS.md) | skipped (Codex reads AGENTS.md) | skipped (Pi reads AGENTS.md) | skipped (opencode reads AGENTS.md) |
81
- | Path-scoped (with `paths:`) | listed by name only | copied as-is | `paths:` → `globs:` in `.mdc` | `paths:` → `applyTo:` in `.instructions.md` | not supported by Codex | copied to `.pi/intelligence-sync/rules/` + surfaced by generated extension | not supported (opencode has no native scoping; users may opt in via `instructions:` globs in `opencode.json`) |
82
- | Listing | full table in AGENTS.md | n/a | n/a | n/a | n/a | extension prompt snippet | n/a |
83
-
84
- **Skills:**
85
-
86
- Skills follow the [Agent Skills open standard](https://agentskills.io). All supported tools read `SKILL.md` directly — no semantic transformation needed. Skill directories are copied **in full** via `copy_skill_bundle` in `lib/common.sh`: bundled resources (`references/`, `scripts/`, `assets/`) ship alongside `SKILL.md`, because skill bodies point at them by relative path and a copy without them is broken at runtime. Markdown files are LF-normalized; everything else is copied byte-for-byte.
87
-
88
- `copy_skill_bundle` also quotes free-text `SKILL.md` frontmatter (`description`, `argument-hint`) for **every** target, not just the strict-YAML ones: `argument-hint: [pr-number]` is a YAML flow *sequence* unquoted, and Claude Code rejects the skill with "argument-hint must be a string" — it vanishes from the picker with no other signal. Adapters must therefore copy skills through this helper rather than plain `cp`.
89
-
90
- | Pattern | Used by | Output location |
91
- |---------|---------|-----------------|
92
- | Copy skill dirs in full (SKILL.md + bundled resources) | Claude, Cursor, Copilot, Codex, Pi, opencode | `.claude/skills/`, `.cursor/skills/`, `.github/skills/`, `.agents/skills/` (shared by Codex, Pi, opencode) |
93
-
94
- **Agents:**
95
-
96
- | Pattern | Used by |
97
- |---------|---------|
98
- | Transform frontmatter | Claude (`tier`→`model` via `get_model`, `access`→`tools`/`disallowedTools`), Cursor (`tier`→`model` via `get_model`, `access: readonly`→`readonly: true`) |
99
- | Transform to `.agent.md` | Copilot (`tier`→`model`, `access: readonly`→restricted `tools` array) |
100
- | Transform to `.toml` | Codex (`name`, `description`, `model`, `model_reasoning_effort` from tier, `sandbox_mode` from access, `developer_instructions`) |
101
- | Transform to prompt template | Pi (`.pi/prompts/intelligence-agent-<name>.md`; `readonly` becomes prompt guidance, `full` stays implicit) |
102
- | Transform to markdown subagent | opencode (`.opencode/agents/<name>.md`; `mode: subagent`, `model` from tier via `get_model`, `permission.edit`/`permission.bash` from access) |
103
-
104
- Model names come from `get_model(config_file, ide, tier)` in `lib/common.sh`. Defaults are baked into `get_model_default()`; users override per-IDE/tier under `models:` in `config.yaml`. Sync prints a drift report when an override no longer matches the current default.
105
-
106
- ### Layout tokens (required)
107
-
108
- The engine ships artifacts of its own — the `intelligence-authoring` rule and the `intelligence-architect` agent — and they cannot hardcode the umbrella's folder name, because the project chooses it. They write `<umbrella>` and `<module>` instead, and **every adapter must expand them by calling `finalize_output_file` on each file it writes** (it also does the LF normalization that `normalize_file_to_lf` used to do):
109
-
110
- | Token | Expands to |
111
- |---|---|
112
- | `<umbrella>` | repo-relative umbrella dir (e.g. `Intelligence`) |
113
- | `<module>` | repo-relative engine module (e.g. `Intelligence/sync`; CLI setup: `.intelligence/packages/@ainova-systems/sync`) |
114
- | `<manifest>` | the project's config file name — vendored: `config.yaml`, CLI setup: `intelligence.yaml` (`IS_MANIFEST_NAME`) |
115
- | `<sync-cmd>` | the sync invocation — vendored: `bash <module>/scripts/sync.sh`, CLI setup: `intelligence sync` (`IS_SYNC_CMD`) |
116
-
117
- Values are exported by `sync.sh` (`IS_UMBRELLA_REL`, `IS_MODULE_REL`; `IS_SYNC_CMD` comes from the CLI in CLI mode), derived from the detected layout. Expansion covers frontmatter and body, so `paths: ["<umbrella>/**"]` reaches Claude's `paths:`, Cursor's `globs:` and Copilot's `applyTo:` carrying the project's real folder name. A file written without `finalize_output_file` ships a literal `<umbrella>` into an IDE — CI fails the build if any generated output still contains a token.
118
-
119
- ### Cleanup Contract
120
-
121
- Every adapter MUST follow these rules to stay safe alongside others:
122
-
123
- 1. **Clean only adapter-owned subpaths.** Never `rm -rf "$output_dir"` — users hand-author siblings (`.claude/settings.json`, `.cursor/settings.json`, `.pi/settings.json`, `.opencode/opencode.json`, `.github/workflows/`, project-specific commands and extensions). Mirror `claude.sh` (deletes only `rules/`, `agents/`, and per-skill subdirs), `pi.sh` (deletes only `.pi/intelligence-sync/`, the named extension file, and `intelligence-agent-*.md` prompt files), or `opencode.sh` (deletes only `.opencode/agents/` wholesale, and inside `.opencode/commands/` only files that carry the `<!-- Generated by intelligence-sync. Do not edit manually. -->` marker — hand-authored sibling commands survive).
124
- 2. **The cleanup block defines what the adapter owns.** It is the same set `/intelligence-uninstall-adapter` removes when the target is turned off: whatever `sync_to_<name>()` deletes on every re-sync, and nothing more. Keep it obvious in the source — an uninstall reads it.
125
- 3. **Use shared helpers for shared dirs.** `.agents/skills/` is read by Codex, Pi, opencode, and any tool implementing the [Agent Skills open standard](https://agentskills.io). All adapters writing there must call `sync_open_skill_dirs`, which owns the full lifecycle (clean per-skill subfolders, recreate the dir, populate). Do NOT duplicate the clean / `mkdir -p` in the adapter — calling sites become divergent and one adapter inevitably drifts. It is also *shared*: an uninstall removes it only when no other open-standard target remains enabled.
126
- 4. **Document owned paths in `.gitignore`.** Each adapter's INIT.md `.gitignore` block lists exactly the paths it writes — no broader. This lets users keep hand-authored content under the same root tracked.
127
- 5. **The output path is validated before you run.** `sync.sh` calls `validate_output_path` for every adapter (including `agents`): the resolved output must stay inside the repo, and must not be the repo root, the intelligence source tree, or any configured source. `..` is canonicalized away first, so a config line cannot walk out of the repository. Adapters never need to re-check this — but they must not write outside the `output_dir` they are handed.
128
-
129
- ## Example: Minimal Adapter
130
-
131
- ```bash
132
- #!/bin/bash
133
- source "$(dirname "$0")/../lib/common.sh"
134
-
135
- sync_to_myide() {
136
- local repo_root="$1"
137
- local config_file="$2"
138
- local output_dir="$3"
139
-
140
- echo "=== MyIDE ==="
141
- mkdir -p "$output_dir/rules"
142
-
143
- # Copy rules, strip frontmatter
144
- while IFS= read -r src; do
145
- [ -z "$src" ] && continue
146
- # resolve_source_dir maps a source entry to a local dir: "$repo_root/$src"
147
- # for a local path, or a shallow clone for a pack reference (`@<name>`)
148
- # or an inline `git+<url>` spec. A pack's url/ref/mirror are read from
149
- # config.yaml, which it takes from $IS_CONFIG_FILE (exported by sync.sh)
150
- # unless you pass the config as a third argument.
151
- local dir
152
- dir="$(resolve_source_dir "$repo_root" "$src")"
153
- [ -d "$dir" ] || continue
154
- for f in "$dir"/*.md; do
155
- [ -f "$f" ] || continue
156
- awk '
157
- BEGIN { in_fm=0; past_fm=0 }
158
- { sub(/\r$/, "") }
159
- /^---$/ {
160
- if (!past_fm) { in_fm = !in_fm; if (!in_fm) { past_fm=1 }; next }
161
- }
162
- past_fm || !in_fm { print }
163
- ' "$f" > "$output_dir/rules/$(basename "$f")"
164
- # Every written file goes through finalize_output_file: it expands
165
- # the <umbrella> / <module> layout tokens and normalizes CRLF -> LF.
166
- finalize_output_file "$output_dir/rules/$(basename "$f")"
167
- done
168
- done < <(read_yaml_list "$config_file" "rules")
169
- }
170
- ```
171
-
172
- ## Testing
173
-
174
- Test your adapter by creating a temporary project with `config.yaml` and running:
175
-
176
- ```bash
177
- REPO_ROOT=/path/to/test/project bash intelligence/sync/scripts/sync.sh <name>
178
- ```
179
-
180
- Verify the output directory contains correctly transformed files. The sync entry point also runs `lint_frontmatter` over every source file before adapters fire — unquoted YAML colons and leading tabs surface as warnings on stderr.
181
-
182
- ## Distributing changes
183
-
184
- When you ship a new adapter, downstream projects pick it up by running:
185
-
186
- ```bash
187
- bash intelligence/sync/scripts/update.sh
188
- ```
189
-
190
- `update.sh` clones the upstream repo into a `mktemp -d` directory, shows the diff for `intelligence/sync/scripts/` and `intelligence/sync/INIT.md`, and prompts before overwriting. Project content (`config.yaml`, `rules/`, `agents/`, `skills/`, `adapters/`) is never touched. Pass `--yes` for non-interactive runs; set `REPO_URL=<fork>` to use a fork.
191
-
192
- This is exactly why a project's own adapter belongs in `intelligence/adapters/` and not in the engine's `scripts/adapters/`: the first is project content, the second is overwritten by the command above.
193
-
194
- ## Built-in Adapters Reference
195
-
196
- | Adapter | Output | Rules | Skills | Agents |
197
- |---------|--------|-------|--------|--------|
198
- | `agents.sh` | `AGENTS.md` (committed) | Always-on inlined; scoped listed | Listed in table | Listed in table |
199
- | `claude.sh` | `.claude/` | Copy as-is (Claude does not read AGENTS.md) | SKILL.md dirs | tier/access → model/tools |
200
- | `cursor.sh` | `.cursor/` | Scoped only → `.mdc` + globs | Copy as-is | tier → model |
201
- | `copilot.sh` | `.github/` | Scoped only → `.instructions.md` | SKILL.md dirs | `.agent.md` |
202
- | `codex.sh` | `.codex/` + `.agents/skills/` | None (AGENTS.md handles) | SKILL.md dirs in `.agents/skills/` | `.toml` in `.codex/agents/` |
203
- | `pi.sh` | `.pi/` + `.agents/skills/` | Scoped rules copied + listed by generated extension; always-on via AGENTS.md | SKILL.md dirs in `.agents/skills/` | prompt templates in `.pi/prompts/` |
204
- | `opencode.sh` | `.opencode/` + `.agents/skills/` | None (AGENTS.md handles always-on; opencode has no native scoping) | SKILL.md dirs in `.agents/skills/`; one slash command per skill in `.opencode/commands/<name>.md` (marker-protected) | markdown subagents in `.opencode/agents/` |
205
-
206
- ### Notes on `agents.sh`
207
-
208
- Unlike IDE adapters, `agents.sh` emits a single committed markdown file intended for humans and generic LLM tooling. It reads a static `header` block from `config.yaml` (under `targets.agents.header`) and appends auto-generated tables (agents, skills) and a list of rules derived from frontmatter. The output carries a "do not edit manually" marker and is regenerated on every sync.
209
-
210
- #### Why AGENTS.md inlines always-on rules
211
-
212
- AGENTS.md is the canonical project doc — Cursor, Copilot, Codex, Pi, and opencode read it natively. Always-on rule content is inlined automatically so all five tools see the same context from one source. Path-scoped rules are NOT inlined (would balloon AGENTS.md in monorepos); they live in tool-specific channels with native scoping (`.cursor/rules/*.mdc` with `globs:`, `.github/instructions/*.instructions.md` with `applyTo:`) or, for Pi, in generated on-demand rule files surfaced by a small extension. opencode has no first-class path-scoped channel; users who need scoped rules can opt into them via `instructions:` globs in `opencode.json`.
213
-
214
- Claude Code does not read AGENTS.md natively (per [open feature request](https://github.com/anthropics/claude-code/issues/6235)) — its adapter copies all rules into `.claude/rules/`. There is no duplication because Claude does not consume AGENTS.md.