@ainova-systems/intelligence 0.11.0-rc.7 → 0.11.0-rc.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -16
- package/cli/commands/adapter.sh +153 -0
- package/cli/commands/init.sh +113 -22
- package/cli/commands/package.sh +30 -0
- package/cli/commands/registry.sh +4 -2
- package/cli/commands/status.sh +12 -4
- package/cli/commands/sync.sh +7 -20
- package/cli/commands/update.sh +76 -70
- package/cli/engine-package.yaml +2 -2
- package/cli/intelligence +10 -12
- package/cli/{commands/doctor.sh → internal/check.sh} +30 -23
- package/cli/{commands/migrate.sh → internal/migrate-v1.sh} +117 -30
- package/cli/{commands/add.sh → internal/package-add.sh} +11 -16
- package/cli/{commands/list.sh → internal/package-list.sh} +9 -4
- package/cli/{commands/remove.sh → internal/package-remove.sh} +3 -3
- package/cli/{commands/search.sh → internal/package-search.sh} +4 -4
- package/cli/internal/package-update.sh +103 -0
- package/cli/{commands/install.sh → internal/restore.sh} +7 -18
- package/cli/internal/target-state.sh +57 -0
- package/cli/internal/upgrade-v2.sh +133 -0
- package/cli/lib/cli-common.sh +142 -12
- package/cli/lib/lockfile.sh +1 -1
- package/cli/lib/manifest.sh +109 -0
- package/cli/lib/registry.sh +4 -4
- package/engine/ENGINE_SHA +1 -1
- package/engine/adapters/_template.sh +10 -9
- package/engine/adapters/agents.sh +11 -11
- package/engine/adapters/opencode.sh +1 -1
- package/engine/lib/common.sh +14 -22
- package/engine/lib/contract.sh +14 -14
- package/engine/sync.sh +25 -20
- package/package.json +1 -1
- package/packages/sync/agents/intelligence-architect.md +5 -3
- package/packages/sync/agents/intelligence-operator.md +10 -13
- package/packages/sync/references/adapters.md +252 -0
- package/packages/sync/references/conventions.md +385 -0
- package/packages/sync/rules/intelligence-authoring.md +6 -6
- package/packages/sync/skills/intelligence-add-agent/SKILL.md +5 -5
- package/packages/sync/skills/intelligence-add-rule/SKILL.md +3 -3
- package/packages/sync/skills/intelligence-add-skill/SKILL.md +3 -3
- package/packages/sync/skills/intelligence-extract-skill/SKILL.md +2 -2
- package/packages/sync/skills/intelligence-install-adapter/SKILL.md +29 -22
- package/packages/sync/skills/intelligence-learn-from-context/SKILL.md +3 -3
- package/packages/sync/skills/intelligence-learn-from-repository/SKILL.md +55 -0
- package/packages/sync/skills/intelligence-review-skills/SKILL.md +6 -6
- package/packages/sync/skills/intelligence-sync/SKILL.md +13 -9
- package/packages/sync/skills/intelligence-uninstall-adapter/SKILL.md +19 -37
- package/packages/sync/skills/intelligence-update/SKILL.md +34 -156
- package/cli/commands/upgrade.sh +0 -68
- package/packages/sync/docs/ADAPTERS.md +0 -214
- package/packages/sync/docs/CONVENTIONS.md +0 -456
package/engine/sync.sh
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
#
|
|
8
8
|
# CONFIG_FILE the project's manifest (intelligence.yaml at the root)
|
|
9
9
|
# REPO_ROOT the project root
|
|
10
|
-
#
|
|
10
|
+
# IS_CONTENT_REL the project's content dir, repo-relative
|
|
11
11
|
# IS_MODULE_REL the installed sync package, repo-relative
|
|
12
12
|
# IS_PROTECTED_DIRS dirs an adapter output may never overlap
|
|
13
13
|
#
|
|
@@ -35,21 +35,21 @@ _vc_rc=0
|
|
|
35
35
|
check_version_compat "$_cf" || _vc_rc=$?
|
|
36
36
|
if [ "$_vc_rc" -ne 0 ]; then exit "$_vc_rc"; fi
|
|
37
37
|
|
|
38
|
-
# Schema gap → refuse. sync is a PURE synchronizer: it never
|
|
39
|
-
#
|
|
40
|
-
#
|
|
41
|
-
# `
|
|
42
|
-
_stamp="$(
|
|
38
|
+
# Schema gap → refuse. sync is a PURE synchronizer: it never changes schemas,
|
|
39
|
+
# so the CLI lifecycle preflight must align the project first. An ABSENT stamp
|
|
40
|
+
# means the same thing — a manifest with no
|
|
41
|
+
# `schema_version` must not silently sync past a schema change.
|
|
42
|
+
_stamp="$(read_schema_version "$_cf")"
|
|
43
43
|
_eng="$(engine_version)"
|
|
44
44
|
if [ -z "$_stamp" ]; then
|
|
45
|
-
is_status needs-update "stamped= engine=$_eng (no
|
|
46
|
-
echo "ERROR: the manifest has no
|
|
47
|
-
echo " Run: intelligence
|
|
45
|
+
is_status needs-update "stamped= engine=$_eng (no schema_version)"
|
|
46
|
+
echo "ERROR: the manifest has no schema_version — schema un-applied." >&2
|
|
47
|
+
echo " Run: intelligence init --apply" >&2
|
|
48
48
|
exit "$IS_RC_NEEDS_UPDATE"
|
|
49
49
|
elif [ -n "$_eng" ] && _ver_gt "$_eng" "$_stamp"; then
|
|
50
50
|
is_status needs-update "stamped=$_stamp engine=$_eng"
|
|
51
51
|
echo "ERROR: project at $_stamp but engine is $_eng — pending schema changes." >&2
|
|
52
|
-
echo " Run: intelligence
|
|
52
|
+
echo " Run: intelligence init --apply" >&2
|
|
53
53
|
exit "$IS_RC_NEEDS_UPDATE"
|
|
54
54
|
fi
|
|
55
55
|
|
|
@@ -64,19 +64,19 @@ CONFIG_FILE="$(cd "$(dirname "$CONFIG_FILE")" && pwd)/$(basename "$CONFIG_FILE")
|
|
|
64
64
|
|
|
65
65
|
# Layout tokens for generated output (see finalize_output_file in common.sh).
|
|
66
66
|
# Package-shipped rules/agents cannot hardcode the content dir's name — the
|
|
67
|
-
# project chooses it — so they write `<
|
|
67
|
+
# project chooses it — so they write `<content-dir>` / `<module>` and every adapter
|
|
68
68
|
# expands them on the way out.
|
|
69
|
-
|
|
69
|
+
IS_CONTENT_REL="${IS_CONTENT_REL:-intelligence}"
|
|
70
70
|
# No vendor default: the CLI always exports the package path (derived from its
|
|
71
71
|
# distribution data), so a bare invocation must say so rather than guess.
|
|
72
72
|
if [ -z "${IS_MODULE_REL:-}" ]; then
|
|
73
73
|
echo "ERROR: the engine needs IS_MODULE_REL (exported by the intelligence CLI)." >&2
|
|
74
74
|
exit 1
|
|
75
75
|
fi
|
|
76
|
-
export
|
|
76
|
+
export IS_CONTENT_REL IS_MODULE_REL
|
|
77
77
|
|
|
78
|
-
# Project-owned adapters live in the content dir: <
|
|
79
|
-
INTELLIGENCE_DIR="$REPO_ROOT/$
|
|
78
|
+
# Project-owned adapters live in the content dir: <content-dir>/adapters/.
|
|
79
|
+
INTELLIGENCE_DIR="$REPO_ROOT/$IS_CONTENT_REL"
|
|
80
80
|
|
|
81
81
|
TARGET_FILTER="${1:-}"
|
|
82
82
|
|
|
@@ -132,8 +132,8 @@ done
|
|
|
132
132
|
# Adapters come from two places, discovered by filename (minus `.sh`,
|
|
133
133
|
# `_template` excluded):
|
|
134
134
|
#
|
|
135
|
-
# 1. Built-in — shipped inside the CLI, replaced
|
|
136
|
-
# 2. Project — <
|
|
135
|
+
# 1. Built-in — shipped inside the CLI, replaced with each CLI installation
|
|
136
|
+
# 2. Project — <content-dir>/adapters/, owned by the project and never touched
|
|
137
137
|
#
|
|
138
138
|
# A custom adapter therefore belongs in the content dir's `adapters/`; the
|
|
139
139
|
# built-in directory lives inside the installed CLI and is not the project's to
|
|
@@ -183,7 +183,12 @@ while [ "$adapter_idx" -lt "$adapter_count" ]; do
|
|
|
183
183
|
|
|
184
184
|
# Check if target is enabled in config
|
|
185
185
|
enabled=$(is_target_enabled "$CONFIG_FILE" "$adapter")
|
|
186
|
-
if [ "$enabled" != "1" ]
|
|
186
|
+
if [ "$enabled" != "1" ]; then
|
|
187
|
+
if [ -n "$TARGET_FILTER" ]; then
|
|
188
|
+
echo "ERROR: Adapter '$TARGET_FILTER' is disabled in $CONFIG_FILE." >&2
|
|
189
|
+
echo " Enable it first: intelligence adapter enable $TARGET_FILTER" >&2
|
|
190
|
+
exit 1
|
|
191
|
+
fi
|
|
187
192
|
continue
|
|
188
193
|
fi
|
|
189
194
|
|
|
@@ -227,7 +232,7 @@ warn_unsynced "$REPO_ROOT" "$CONFIG_FILE"
|
|
|
227
232
|
report_model_drift "$CONFIG_FILE"
|
|
228
233
|
|
|
229
234
|
echo ""
|
|
230
|
-
# sync.sh never
|
|
231
|
-
# always ok.
|
|
235
|
+
# sync.sh never changes project schemas (the CLI preflight owns that), so
|
|
236
|
+
# success is always ok.
|
|
232
237
|
is_status ok "synced=$synced"
|
|
233
238
|
echo "=== Done: $synced target(s) synced ==="
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ainova-systems/intelligence",
|
|
3
|
-
"version": "0.11.0-rc.
|
|
3
|
+
"version": "0.11.0-rc.9",
|
|
4
4
|
"description": "Build, version and distribute AI agent intelligence across your organization — one CLI, versioned Intelligence Packages, and a sync engine for Claude Code, Cursor, Copilot, Codex, Pi and OpenCode.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"intelligence": "bin/intelligence.js"
|
|
@@ -9,12 +9,13 @@ skills:
|
|
|
9
9
|
- intelligence-add-skill
|
|
10
10
|
- intelligence-extract-skill
|
|
11
11
|
- intelligence-review-skills
|
|
12
|
+
- intelligence-learn-from-repository
|
|
12
13
|
- intelligence-learn-from-context
|
|
13
14
|
---
|
|
14
15
|
|
|
15
16
|
# Intelligence architect
|
|
16
17
|
|
|
17
|
-
Owns `<
|
|
18
|
+
Owns `<content-dir>/` itself: what the layer is made of, and what it is allowed to grow into. Not the project's code — the instructions that shape how everyone else writes it.
|
|
18
19
|
|
|
19
20
|
## Expertise
|
|
20
21
|
|
|
@@ -45,9 +46,10 @@ The per-artifact checks are procedure, so they live in the meta-skills rather th
|
|
|
45
46
|
| `intelligence-add-rule` / `intelligence-add-agent` / `intelligence-add-skill` | author one artifact |
|
|
46
47
|
| `intelligence-extract-skill` | turn an observed workflow into a skill |
|
|
47
48
|
| `intelligence-review-skills` | audit the layer for duplication, drift, size, hardcoded paths |
|
|
49
|
+
| `intelligence-learn-from-repository` | propose the initial project-owned layer from repository evidence |
|
|
48
50
|
| `intelligence-learn-from-context` | fold a session's lessons back into the layer |
|
|
49
51
|
| `intelligence-sync` | project the source to every tool channel |
|
|
50
|
-
| `intelligence-update` |
|
|
51
|
-
| `intelligence-install-adapter` / `intelligence-uninstall-adapter` |
|
|
52
|
+
| `intelligence-update` | interpret and apply the CLI's unified update plan |
|
|
53
|
+
| `intelligence-install-adapter` / `intelligence-uninstall-adapter` | research and manage a tool adapter |
|
|
52
54
|
|
|
53
55
|
A change is done when the sync is green and the skill you invoked reports clean. Size is a separate judgement: the caps are ceilings, not quotas, and a short artifact is not a defect.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: intelligence-operator
|
|
3
|
-
description: "
|
|
3
|
+
description: "Interpret CLI plans and operate sync, update, and adapter flows"
|
|
4
4
|
tier: standard
|
|
5
5
|
access: full
|
|
6
6
|
skills:
|
|
@@ -12,20 +12,17 @@ skills:
|
|
|
12
12
|
|
|
13
13
|
# Intelligence operator
|
|
14
14
|
|
|
15
|
-
Operates the
|
|
16
|
-
|
|
15
|
+
Operates the CLI: projects the source tree to every enabled tool channel, interprets and applies update
|
|
16
|
+
plans, and manages adapters. What the layer contains - which rules, agents and skills
|
|
17
17
|
exist and what they say - is `intelligence-architect`'s judgement; this agent runs the machinery
|
|
18
18
|
that ships it.
|
|
19
19
|
|
|
20
20
|
## Expertise
|
|
21
21
|
|
|
22
|
-
The status contract
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
what that code says - including stopping. The guards carry the decisions, which is why this agent
|
|
27
|
-
runs on the standard tier: the failure mode is a loud refusal and a retry, not a plausible wrong
|
|
28
|
-
answer.
|
|
22
|
+
The CLI and engine status contract. Mechanical flows are deterministic and
|
|
23
|
+
fail-closed; the agent reads their result, selects the next supported command,
|
|
24
|
+
checks changelog post-conditions, and stops on a refusal instead of recreating
|
|
25
|
+
the operation in prose.
|
|
29
26
|
|
|
30
27
|
## Boundaries
|
|
31
28
|
|
|
@@ -35,7 +32,7 @@ answer.
|
|
|
35
32
|
- **Operating is not authoring.** A change to what an artifact says - a rule body, an agent persona,
|
|
36
33
|
a skill's steps - belongs to `intelligence-architect` and the authoring meta-skills. This agent
|
|
37
34
|
ships what exists and never decides what should exist.
|
|
38
|
-
- **A state the
|
|
35
|
+
- **A state the CLI refuses to resolve goes to a human.** `ambiguous` and every other non-ok
|
|
39
36
|
status exists so that nobody guesses past a refusal; report the code and its detail, do the one
|
|
40
37
|
thing the contract names for it, and stop rather than force a way through.
|
|
41
38
|
|
|
@@ -45,5 +42,5 @@ answer.
|
|
|
45
42
|
<sync-cmd> # expect IS_STATUS=ok
|
|
46
43
|
```
|
|
47
44
|
|
|
48
|
-
Done is the invoked skill reporting its own success criteria met: `IS_STATUS=ok
|
|
49
|
-
|
|
45
|
+
Done is the invoked skill reporting its own success criteria met: `IS_STATUS=ok`,
|
|
46
|
+
per-target counts matching the sources, and no warning left unhandled.
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# Writing an Intelligence Adapter
|
|
2
|
+
|
|
3
|
+
An adapter transforms tool-neutral rules, agents and skills into one tool's native files. The sync engine discovers adapters by filename and calls one shell function for each enabled target.
|
|
4
|
+
|
|
5
|
+
## Built-in and project adapters
|
|
6
|
+
|
|
7
|
+
| Location | Owner | Upgrade behavior |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| Installed CLI's `engine/adapters/` | Intelligence | Replaced when the CLI is upgraded |
|
|
10
|
+
| `<content-dir>/adapters/` | Project | Never changed by CLI upgrades |
|
|
11
|
+
|
|
12
|
+
The default content directory is `intelligence/`; `project.intelligence_dir` in `intelligence.yaml` may choose another. A project adapter with the same name as a built-in overrides it, and sync reports the override.
|
|
13
|
+
|
|
14
|
+
Contribute broadly useful integrations as built-ins. Keep organization-specific or experimental formats in the project.
|
|
15
|
+
|
|
16
|
+
## Create and enable an adapter
|
|
17
|
+
|
|
18
|
+
Choose a lowercase shell-safe name matching `[a-z][a-z0-9_]*`, then scaffold from the template bundled with the installed engine:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
intelligence adapter create mytool
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
This creates `<content-dir>/adapters/mytool.sh` and refuses to overwrite an existing file. Implement the generated functions, then enable its target:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
intelligence adapter enable mytool
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`adapter enable` adds or updates this manifest entry when the adapter exists, then runs a full sync so shared outputs such as `AGENTS.md` remain current:
|
|
31
|
+
|
|
32
|
+
```yaml
|
|
33
|
+
targets:
|
|
34
|
+
mytool: { enabled: true, output: ".mytool" }
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Change `output` in `intelligence.yaml` if the tool expects another location. The engine validates the resolved path before calling the adapter.
|
|
38
|
+
|
|
39
|
+
To stop syncing a target:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
intelligence adapter disable mytool
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Disabling changes only target state. Generated output is deliberately kept because a generic command cannot know which paths a custom adapter owns. Remove only documented owned paths after reviewing them. A disabled project adapter can be deleted with `intelligence adapter remove mytool`; removal prompts by default, accepts `--apply` for explicit non-interactive use, and also keeps generated output. Built-in adapter source cannot be removed. Use `intelligence adapter list` to inspect source, state and output.
|
|
46
|
+
|
|
47
|
+
## Required function
|
|
48
|
+
|
|
49
|
+
The file name and function name form the adapter's identity:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# <content-dir>/adapters/mytool.sh
|
|
53
|
+
sync_to_mytool() {
|
|
54
|
+
local repo_root="$1"
|
|
55
|
+
local config_file="$2"
|
|
56
|
+
local output_dir="$3"
|
|
57
|
+
|
|
58
|
+
# transform sources into output_dir
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The engine calls:
|
|
63
|
+
|
|
64
|
+
```text
|
|
65
|
+
sync_to_<name> <repo-root> <absolute-intelligence.yaml> <absolute-output-path>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The engine has already loaded `engine/lib/common.sh` before it sources the adapter, so project adapters use its functions directly.
|
|
69
|
+
|
|
70
|
+
## Source model
|
|
71
|
+
|
|
72
|
+
`sources.rules`, `sources.agents` and `sources.skills` contain repo-relative directory paths. Packages have already been resolved, fetched and pinned by the CLI, so package content appears as an ordinary path under `.intelligence/packages/`. Adapters never perform network access or parse `packages:`.
|
|
73
|
+
|
|
74
|
+
Iterate a source section in manifest order:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
while IFS= read -r src; do
|
|
78
|
+
[ -n "$src" ] || continue
|
|
79
|
+
dir="$(resolve_source_dir "$repo_root" "$src")"
|
|
80
|
+
[ -d "$dir" ] || continue
|
|
81
|
+
|
|
82
|
+
for file in "$dir"/*.md; do
|
|
83
|
+
[ -f "$file" ] || continue
|
|
84
|
+
# transform file
|
|
85
|
+
done
|
|
86
|
+
done < <(read_yaml_list "$config_file" "rules")
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Later sources intentionally overwrite same-named artifacts from earlier sources. Package sources are wired before project sources, so project content can override a package artifact by name.
|
|
90
|
+
|
|
91
|
+
## Shared functions
|
|
92
|
+
|
|
93
|
+
Use the engine library instead of copying parsers or file-handling logic.
|
|
94
|
+
|
|
95
|
+
| Function | Purpose |
|
|
96
|
+
|---|---|
|
|
97
|
+
| `resolve_source_dir(repo_root, source)` | Resolve a manifest source to its local directory. |
|
|
98
|
+
| `read_yaml_list(config, section)` | Stream entries from `sources.<section>`. |
|
|
99
|
+
| `get_frontmatter_value(key, file)` | Read a scalar from the first frontmatter block. |
|
|
100
|
+
| `has_frontmatter(file)` / `has_paths(file)` | Inspect source shape. |
|
|
101
|
+
| `strip_frontmatter(file)` | Emit the body without its first frontmatter block. |
|
|
102
|
+
| `get_model(config, tool, tier)` | Resolve a `heavy`, `standard` or `light` model, including manifest overrides. |
|
|
103
|
+
| `get_model_default(tool, tier)` | Read the built-in model default. |
|
|
104
|
+
| `copy_skill_bundle(src, dest)` | Copy `SKILL.md` and all resources safely, normalize Markdown and quote free-text frontmatter. |
|
|
105
|
+
| `sync_open_skill_dirs(root, config, dest)` | Own and populate a shared Agent Skills directory such as `.agents/skills/`. |
|
|
106
|
+
| `finalize_output_file(file)` | Expand layout tokens and normalize line endings; required for every emitted text file. |
|
|
107
|
+
| `get_target_field(config, target, field)` | Read another field from the target configuration. |
|
|
108
|
+
| `repo_rel_link(root, path)` | Produce a stable repo-relative link for a committed output. |
|
|
109
|
+
|
|
110
|
+
`lint_frontmatter` is run across all inputs by the engine before adapters execute. It warns about common YAML hazards; adapters should not duplicate that pass.
|
|
111
|
+
|
|
112
|
+
## Rules, skills and agents
|
|
113
|
+
|
|
114
|
+
### Rules
|
|
115
|
+
|
|
116
|
+
Rules without `paths:` are always-on. Rules with `paths:` are scoped.
|
|
117
|
+
|
|
118
|
+
Intelligence routes always-on rules once through `AGENTS.md` for tools that consume it. An adapter for such a tool should not copy those rules again. If the tool has a native scoped-rule channel, transform `paths:` to the tool's equivalent.
|
|
119
|
+
|
|
120
|
+
| Built-in | Always-on rules | Scoped rules |
|
|
121
|
+
|---|---|---|
|
|
122
|
+
| `agents` | Inline in `AGENTS.md` | List with links |
|
|
123
|
+
| `claude` | Copy | Copy with `paths:` preserved |
|
|
124
|
+
| `cursor` | Omit; reads `AGENTS.md` | `.mdc` with `globs:` |
|
|
125
|
+
| `copilot` | Omit; reads `AGENTS.md` | `.instructions.md` with `applyTo:` |
|
|
126
|
+
| `codex` | Omit; reads `AGENTS.md` | No native channel |
|
|
127
|
+
| `pi` | Omit; reads `AGENTS.md` | Generated on-demand files and extension |
|
|
128
|
+
| `opencode` | Omit; reads `AGENTS.md` | No native channel |
|
|
129
|
+
|
|
130
|
+
If a new adapter relies on `AGENTS.md` for always-on rules, its target must require `agents`. Add that invariant to `engine/sync.sh` when contributing the adapter upstream.
|
|
131
|
+
|
|
132
|
+
### Skills
|
|
133
|
+
|
|
134
|
+
Skills follow the [Agent Skills standard](https://agentskills.io). Copy each skill directory as a complete bundle—not only `SKILL.md`—because its body may reference `references/`, `scripts/` or `assets/` beside it.
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
copy_skill_bundle "$source_skill_dir" "$output_dir/skills/$skill_name"
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Do not use plain `cp` for skill bundles. `copy_skill_bundle` preserves non-Markdown assets, avoids materializing symlink targets, normalizes Markdown, expands layout tokens and quotes `description` and `argument-hint` where strict YAML readers require strings.
|
|
141
|
+
|
|
142
|
+
Codex, Pi and OpenCode share `.agents/skills/`. Any adapter writing that open-standard directory must call `sync_open_skill_dirs`; it is the single lifecycle owner for immediate skill subdirectories.
|
|
143
|
+
|
|
144
|
+
### Agents
|
|
145
|
+
|
|
146
|
+
Source agents use tool-neutral fields:
|
|
147
|
+
|
|
148
|
+
```yaml
|
|
149
|
+
---
|
|
150
|
+
name: backend-developer
|
|
151
|
+
description: "Implements backend features"
|
|
152
|
+
tier: heavy
|
|
153
|
+
access: full
|
|
154
|
+
---
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Map `tier` through `get_model`, not a hardcoded model name. Transform `access: full|readonly` into the target tool's native permission model. Preserve the body as the agent's instructions.
|
|
158
|
+
|
|
159
|
+
Built-ins currently emit Claude and Cursor Markdown, Copilot `.agent.md`, Codex TOML, Pi prompt templates and OpenCode Markdown subagents. Read the closest built-in adapter before implementing a new transformation.
|
|
160
|
+
|
|
161
|
+
## Layout tokens
|
|
162
|
+
|
|
163
|
+
Content shipped in `@ainova-systems/sync` cannot assume the project's content-directory name or package-store location. It uses these tokens:
|
|
164
|
+
|
|
165
|
+
| Token | v2 expansion |
|
|
166
|
+
|---|---|
|
|
167
|
+
| `<content-dir>` | Project content directory, usually `intelligence` |
|
|
168
|
+
| `<module>` | Installed sync package, usually `.intelligence/packages/@ainova-systems/sync` |
|
|
169
|
+
| `<manifest>` | `intelligence.yaml` |
|
|
170
|
+
| `<sync-cmd>` | `intelligence sync` |
|
|
171
|
+
|
|
172
|
+
Call `finalize_output_file` on every text file after transformation. It expands the tokens literally and converts CRLF to LF. A generated file containing an unexpanded token is an adapter bug.
|
|
173
|
+
|
|
174
|
+
`copy_skill_bundle` already finalizes Markdown within a skill; do not run a second custom token pass.
|
|
175
|
+
|
|
176
|
+
## Cleanup and safety contract
|
|
177
|
+
|
|
178
|
+
Adapters regenerate output, so cleanup is part of their public contract.
|
|
179
|
+
|
|
180
|
+
1. Delete only paths the adapter owns. Preserve sibling settings, commands, extensions, workflows and hand-authored files.
|
|
181
|
+
2. Make ownership obvious in `sync_to_<name>()`; the same list is what a user removes after disabling or uninstalling the adapter.
|
|
182
|
+
3. Use marker-based cleanup when generated and hand-authored files share a directory. The OpenCode adapter is the reference implementation.
|
|
183
|
+
4. Use `sync_open_skill_dirs` for `.agents/skills/`; multiple adapters share it.
|
|
184
|
+
5. Write only beneath the supplied `output_dir`, except for an explicitly shared standard path handled by a shared helper.
|
|
185
|
+
6. Make repeated syncs idempotent.
|
|
186
|
+
|
|
187
|
+
Before an adapter runs, the engine canonicalizes and validates its configured output. It refuses the repository root, paths outside the repository, symlink escapes, the project content directory, `.intelligence/` and configured source paths. This guard does not make broad cleanup safe: an adapter must still avoid deleting unrelated files within a valid tool directory.
|
|
188
|
+
|
|
189
|
+
## Minimal example
|
|
190
|
+
|
|
191
|
+
This example copies rules without frontmatter. A real adapter must decide how the target represents scoping and should also implement agents and skills.
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
#!/bin/bash
|
|
195
|
+
|
|
196
|
+
sync_mytool_rules() {
|
|
197
|
+
local repo_root="$1" config_file="$2" output_dir="$3"
|
|
198
|
+
mkdir -p "$output_dir/rules"
|
|
199
|
+
|
|
200
|
+
while IFS= read -r src; do
|
|
201
|
+
[ -n "$src" ] || continue
|
|
202
|
+
local dir
|
|
203
|
+
dir="$(resolve_source_dir "$repo_root" "$src")"
|
|
204
|
+
[ -d "$dir" ] || continue
|
|
205
|
+
|
|
206
|
+
for file in "$dir"/*.md; do
|
|
207
|
+
[ -f "$file" ] || continue
|
|
208
|
+
strip_frontmatter "$file" > "$output_dir/rules/$(basename "$file")"
|
|
209
|
+
finalize_output_file "$output_dir/rules/$(basename "$file")"
|
|
210
|
+
done
|
|
211
|
+
done < <(read_yaml_list "$config_file" "rules")
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
sync_to_mytool() {
|
|
215
|
+
local repo_root="$1" config_file="$2" output_dir="$3"
|
|
216
|
+
|
|
217
|
+
rm -rf "$output_dir/rules"
|
|
218
|
+
sync_mytool_rules "$repo_root" "$config_file" "$output_dir"
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Testing
|
|
223
|
+
|
|
224
|
+
Use a disposable Git repository with a v2 manifest and representative always-on/scoped rules, agents, skills and bundled skill resources.
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
intelligence sync mytool
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Verify:
|
|
231
|
+
|
|
232
|
+
- native file names, frontmatter and model/permission mappings;
|
|
233
|
+
- scoped and always-on routing without duplicated context;
|
|
234
|
+
- skill resources are present;
|
|
235
|
+
- no literal layout tokens remain;
|
|
236
|
+
- hand-authored siblings under the tool root survive;
|
|
237
|
+
- output paths cannot overlap sources or escape the repository;
|
|
238
|
+
- a second sync produces no Git diff.
|
|
239
|
+
|
|
240
|
+
For a built-in adapter, add the same assertions to the repository's smoke or lifecycle tests and run all five CLI suites before submitting the change.
|
|
241
|
+
|
|
242
|
+
## Built-in outputs
|
|
243
|
+
|
|
244
|
+
| Adapter | Primary output |
|
|
245
|
+
|---|---|
|
|
246
|
+
| `agents` | `AGENTS.md` |
|
|
247
|
+
| `claude` | `.claude/rules`, `.claude/agents`, `.claude/skills` |
|
|
248
|
+
| `cursor` | `.cursor/rules`, `.cursor/agents`, `.cursor/skills` |
|
|
249
|
+
| `copilot` | `.github/instructions`, `.github/agents`, `.github/skills` |
|
|
250
|
+
| `codex` | `.codex/agents`, `.agents/skills` |
|
|
251
|
+
| `pi` | `.pi/intelligence-sync`, `.pi/extensions`, `.pi/prompts`, `.agents/skills` |
|
|
252
|
+
| `opencode` | `.opencode/agents`, marker-owned `.opencode/commands`, `.agents/skills` |
|