@ainova-systems/intelligence 0.11.0-rc.1
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/LICENSE +21 -0
- package/README.md +46 -0
- package/bin/intelligence.js +59 -0
- package/cli/commands/add.sh +133 -0
- package/cli/commands/doctor.sh +100 -0
- package/cli/commands/init.sh +96 -0
- package/cli/commands/install.sh +84 -0
- package/cli/commands/list.sh +28 -0
- package/cli/commands/migrate.sh +251 -0
- package/cli/commands/registry.sh +51 -0
- package/cli/commands/remove.sh +39 -0
- package/cli/commands/status.sh +34 -0
- package/cli/commands/sync.sh +22 -0
- package/cli/commands/update.sh +59 -0
- package/cli/commands/upgrade.sh +27 -0
- package/cli/intelligence +71 -0
- package/cli/lib/cli-common.sh +149 -0
- package/cli/lib/lockfile.sh +97 -0
- package/cli/lib/manifest.sh +211 -0
- package/cli/lib/registry.sh +141 -0
- package/cli/lib/semver.sh +127 -0
- package/engine/INIT.md +498 -0
- package/engine/agents/intelligence-architect.md +53 -0
- package/engine/agents/intelligence-operator.md +49 -0
- package/engine/docs/ADAPTERS.md +212 -0
- package/engine/docs/CLI.md +91 -0
- package/engine/docs/CONVENTIONS.md +440 -0
- package/engine/rules/intelligence-authoring.md +114 -0
- package/engine/scripts/VERSION +1 -0
- package/engine/scripts/adapters/_template.sh +86 -0
- package/engine/scripts/adapters/agents.sh +299 -0
- package/engine/scripts/adapters/claude.sh +136 -0
- package/engine/scripts/adapters/codex.sh +118 -0
- package/engine/scripts/adapters/copilot.sh +193 -0
- package/engine/scripts/adapters/cursor.sh +146 -0
- package/engine/scripts/adapters/opencode.sh +200 -0
- package/engine/scripts/adapters/pi.sh +256 -0
- package/engine/scripts/lib/common.sh +1602 -0
- package/engine/scripts/lib/layout.sh +51 -0
- package/engine/scripts/lib/migrations.sh +708 -0
- package/engine/scripts/sync.sh +311 -0
- package/engine/scripts/update.sh +237 -0
- package/engine/skills/intelligence-add-agent/SKILL.md +62 -0
- package/engine/skills/intelligence-add-rule/SKILL.md +54 -0
- package/engine/skills/intelligence-add-skill/SKILL.md +53 -0
- package/engine/skills/intelligence-extract-skill/SKILL.md +47 -0
- package/engine/skills/intelligence-install-adapter/SKILL.md +31 -0
- package/engine/skills/intelligence-learn-from-context/SKILL.md +69 -0
- package/engine/skills/intelligence-review-skills/SKILL.md +86 -0
- package/engine/skills/intelligence-sync/SKILL.md +18 -0
- package/engine/skills/intelligence-uninstall-adapter/SKILL.md +42 -0
- package/engine/skills/intelligence-update/SKILL.md +159 -0
- package/package.json +39 -0
- package/registry/index.yaml +15 -0
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
# intelligence-sync: Conventions
|
|
2
|
+
|
|
3
|
+
## Choosing artifact type
|
|
4
|
+
|
|
5
|
+
Three artifact types — each has a different intent and loading mechanism. Picking the right one is the first authoring decision.
|
|
6
|
+
|
|
7
|
+
| Type | Intent | Loading | Content |
|
|
8
|
+
|---|---|---|---|
|
|
9
|
+
| **Rule** | LLM **respects** a constraint or convention in the background | Auto (path-scoped or always-on) | Required patterns, invariants, architecture, examples |
|
|
10
|
+
| **Skill** | LLM **performs** a multi-step procedure on invocation | Explicit (`/skill-name`) | Numbered steps with verification |
|
|
11
|
+
| **Agent** | LLM **adopts** a persona / domain expertise | Explicit (via agent picker) | Expertise scope, before-any-task checklist, build/verify |
|
|
12
|
+
|
|
13
|
+
Plain rule of thumb:
|
|
14
|
+
- "AI should consider X across any work in scope" → **rule**
|
|
15
|
+
- "AI should execute a defined sequence of steps" → **skill**
|
|
16
|
+
- "AI should think as an X-domain expert with these tools" → **agent**
|
|
17
|
+
|
|
18
|
+
Common mistakes to avoid:
|
|
19
|
+
- Conventions / standards embedded in an agent body → belongs in a **rule** (auto-loaded, shared across all agents working in scope)
|
|
20
|
+
- A workflow embedded in a rule body → belongs in a **skill** (explicit invocation, not always-loaded context)
|
|
21
|
+
- Expertise scope embedded in a skill body → belongs in an **agent** (persona reusable across many skills)
|
|
22
|
+
|
|
23
|
+
## Source Structure
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
intelligence/ # Umbrella — name NOT hardcoded (whatever holds config.yaml)
|
|
27
|
+
├── config.yaml # Sync config + `sync_version` schema key (committed)
|
|
28
|
+
├── rules/ # Path-based rules (auto-loaded by context)
|
|
29
|
+
│ ├── context.md # Always-loaded (no paths:)
|
|
30
|
+
│ ├── backend.md # paths: ["src/backend/**"]
|
|
31
|
+
│ └── frontend.md # paths: ["src/frontend/**"]
|
|
32
|
+
├── agents/ # Specialized agent definitions
|
|
33
|
+
│ ├── backend-developer.md # tier: heavy, access: full
|
|
34
|
+
│ └── backend-code-reviewer.md # tier: standard, access: readonly
|
|
35
|
+
├── skills/ # Reusable project skill commands
|
|
36
|
+
│ ├── backend-add-endpoint/SKILL.md
|
|
37
|
+
│ └── frontend-add-component/SKILL.md
|
|
38
|
+
├── adapters/ # OPTIONAL — project-owned adapters (survive updates)
|
|
39
|
+
│ └── myide.sh # sync_to_myide(); overrides a built-in of the same name
|
|
40
|
+
└── sync/ # intelligence-sync MODULE (upstream-owned)
|
|
41
|
+
├── INIT.md docs/ scripts/(+VERSION)
|
|
42
|
+
├── rules/intelligence-authoring.md # authoring discipline for this layer
|
|
43
|
+
├── agents/intelligence-architect.md # designs and prunes this layer
|
|
44
|
+
├── agents/intelligence-operator.md # runs sync, update, adapter flows
|
|
45
|
+
└── skills/intelligence-* # meta-skills
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Everything project-authored lives at the umbrella level (`rules/ agents/ skills/ adapters/`); everything upstream-owned lives in the self-contained module `sync/`, updated independently via `sync/scripts/update.sh`. Additional modules (e.g. `domain/`) sit beside `sync/`. The umbrella folder name is derived at runtime as "the directory holding `config.yaml`" — never hardcoded. The `intelligence-` prefix is **reserved** for upstream artifacts; project rules, agents and skills must not use it (the updater prunes what matches it).
|
|
49
|
+
|
|
50
|
+
The module ships three kinds of artifact, and `config.yaml` must list all three under `sources` for them to reach the IDEs — `<umbrella>/sync/rules`, `<umbrella>/sync/agents`, `<umbrella>/sync/skills`. INIT emits those entries on bootstrap; the `0.7.0` migration adds them to existing projects.
|
|
51
|
+
|
|
52
|
+
### Layout tokens in engine-shipped artifacts
|
|
53
|
+
|
|
54
|
+
An artifact shipped *by the engine* cannot write the umbrella's name down — the project chooses it (`intelligence/`, `Intelligence/`, a codename). So engine artifacts spell it with tokens, and every adapter expands them on the way out (`finalize_output_file` in `lib/common.sh`):
|
|
55
|
+
|
|
56
|
+
| Token | Expands to | Example |
|
|
57
|
+
|---|---|---|
|
|
58
|
+
| `<umbrella>` | repo-relative umbrella dir | `Intelligence` |
|
|
59
|
+
| `<module>` | repo-relative engine module | `Intelligence/sync` |
|
|
60
|
+
|
|
61
|
+
Expansion covers frontmatter and body alike, so `paths: ["<umbrella>/**"]` reaches Claude's `paths:`, Cursor's `globs:` and Copilot's `applyTo:` already carrying the project's real folder name. Project-authored artifacts may use the tokens too, but they have no reason to — they can simply name their own folders.
|
|
62
|
+
|
|
63
|
+
A custom adapter belongs in the umbrella's `adapters/`, never in the module's `sync/scripts/adapters/` — the module is replaced wholesale on every update, so an adapter written there disappears at the next one. See `docs/ADAPTERS.md`.
|
|
64
|
+
|
|
65
|
+
Rule filenames, agent names, and skill names all share the same **domain prefix** (`backend-`, `frontend-`, `devops-`, `core-`, `tests-`, project codename, or monorepo component name). Pick the domain once from repo structure and reuse it — do not invent new domains without clear need.
|
|
66
|
+
|
|
67
|
+
### Packs (remote sources)
|
|
68
|
+
|
|
69
|
+
A `sources.{rules,agents,skills}` entry is normally a **local path** relative to the repo root. It may instead reference a **pack** — a remote git repo that `sync` shallow-clones and treats exactly like a local source directory — so a team can keep shared intelligence in one repo and pull it into many projects.
|
|
70
|
+
|
|
71
|
+
A pack is **declared once** under `packs:` and referenced by name from as many sections as need it:
|
|
72
|
+
|
|
73
|
+
```yaml
|
|
74
|
+
packs:
|
|
75
|
+
shared-intel:
|
|
76
|
+
url: https://github.com/org/shared-intel.git
|
|
77
|
+
ref: v1.2.0 # the pin — one place, not one per section
|
|
78
|
+
mirror: "intelligence/external/shared-intel" # optional; see below
|
|
79
|
+
|
|
80
|
+
sources:
|
|
81
|
+
rules:
|
|
82
|
+
- "intelligence/rules" # local
|
|
83
|
+
- "@shared-intel/rules" # pack
|
|
84
|
+
skills:
|
|
85
|
+
- "@shared-intel/skills" # same pack, same clone, same pin
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Declaring the pack is what keeps the url and the ref in one place. Repeating them per section is how the two drift, and nothing catches it: rules pinned at one commit and skills at another is a config that looks fine and reads wrong.
|
|
89
|
+
|
|
90
|
+
Reference format: `@<pack>[/<subpath>]`
|
|
91
|
+
|
|
92
|
+
- `<pack>` — a key under `packs:`. It is a **reference handle, never a path component**, so it needs no sanitizing; it must simply contain no `/`.
|
|
93
|
+
- `/<subpath>` — optional directory inside the pack repo holding the rules / agents / skills. Omit to use the repo root. The subpath is preserved in the mirror, so `@shared-intel/packs/core/rules` lands at `<mirror>/packs/core/rules`.
|
|
94
|
+
- **An undeclared pack fails the run** (exit 1, naming the pack and listing the declared ones). This is deliberately unlike a missing local path, which only warns: the config claims to know that name, so a typo must not quietly drop a whole rule set.
|
|
95
|
+
|
|
96
|
+
Pack fields:
|
|
97
|
+
|
|
98
|
+
- `url:` — must carry an explicit scheme: `https://`, `http://`, `ssh://`, `git://`, or `file://`. Other transports (notably the command-executing `ext::` / `fd::`) are **rejected** with a warning and skipped.
|
|
99
|
+
- `ref:` — optional tag, branch, or commit SHA. Omit for the default branch.
|
|
100
|
+
- `mirror:` — optional; see [Mirroring a pack into the repo](#mirroring-a-pack-into-the-repo).
|
|
101
|
+
|
|
102
|
+
#### Inline specs (`git+…`)
|
|
103
|
+
|
|
104
|
+
A source entry may still carry the whole spec inline: `git+<url>[@<ref>][#<subpath>]`. This is an **anonymous pack** — it has no declared name and no mirror, so it is always transient and cannot be referenced from elsewhere. Declare the pack under `packs:` to pin it once or to commit it.
|
|
105
|
+
|
|
106
|
+
The inline `@<ref>` is parsed as the segment after the last `@`, accepted as a ref only when it contains no `/` (so `ssh://git@host/...` userinfo is not mistaken for a ref). Branch names containing `/` (e.g. `feature/x`) can't be expressed this way — use `packs:` with a plain `ref:`, which has no such limit.
|
|
107
|
+
|
|
108
|
+
Behavior and trust:
|
|
109
|
+
|
|
110
|
+
- **Fresh every sync.** Each `sync` run clones into a run-scoped temp dir and removes it on exit, so branch refs always pick up the latest. Within one run the same `url@ref` is cloned only once, even when several entries (different subpaths) reference it.
|
|
111
|
+
- **Reproducibility / supply chain.** A remote's content becomes rules, agents, and skills the LLM reads as project context. Pin to a tag or SHA so an upstream change can't silently alter behavior, and only reference repos you trust.
|
|
112
|
+
- **Containment.** The clone can't be made to read outside itself: `..` in `#subpath` is refused, remote repos are checked out with `core.symlinks=false` (a hostile `skills -> /etc` link becomes an inert text file, not a path the copy step follows), and the resolved directory is verified to sit inside the clone.
|
|
113
|
+
- **Line endings are the pack's, not the host's.** The clone pins `core.autocrlf=false` and `core.eol=lf`, so a pack that declares no `.gitattributes` still materializes the bytes it has stored. Without it, Git for Windows' `core.autocrlf=true` default would rewrite the checkout to CRLF and a `mirror:` — copied verbatim — would land CRLF in your repo, showing up as a whole-pack diff after every sync.
|
|
114
|
+
- **Private repos** rely on ambient credentials (an SSH agent or git credential helper). `sync` runs git with `GIT_TERMINAL_PROMPT=0`, so a missing credential fails fast with a warning instead of hanging; local sources still sync.
|
|
115
|
+
- **Best-effort.** A clone failure (offline, bad URL, missing subpath) warns on stderr and skips that one source — the rest of the sync proceeds and still reports `IS_STATUS=ok`.
|
|
116
|
+
|
|
117
|
+
#### Mirroring a pack into the repo
|
|
118
|
+
|
|
119
|
+
Without `mirror:` a pack exists only inside the run cache, so the only trace of an upstream change is a shifted diff in the *generated* output, mixed in with your own content. Give the pack a `mirror:` and it is additionally materialized there, which makes a version bump readable as an ordinary diff:
|
|
120
|
+
|
|
121
|
+
```yaml
|
|
122
|
+
packs:
|
|
123
|
+
shared-intel:
|
|
124
|
+
url: https://github.com/org/shared-intel.git
|
|
125
|
+
ref: v1.2.0
|
|
126
|
+
mirror: "intelligence/external/shared-intel" # omit to keep the pack transient
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
intelligence/external/
|
|
131
|
+
└── shared-intel/ # the path you declared — nothing is derived
|
|
132
|
+
├── .pack # url + ref + resolved SHA, written by sync
|
|
133
|
+
├── rules/ # only the subpaths your sources reference
|
|
134
|
+
└── skills/
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Commit that directory — being able to review `git diff` after bumping a pin is the entire point. `<umbrella>/external/<pack>` is the recommended location, but the value is a plain path, so packs can live wherever suits the repo, one per pack.
|
|
138
|
+
|
|
139
|
+
- **The directory is declared, never derived.** `mirror:` says exactly where the pack goes, so there is no name to sanitize and no collision to resolve.
|
|
140
|
+
- **`.pack` is output, not config.** sync writes it; nothing reads it as configuration and it is not meant to be hand-edited. The pin lives in `config.yaml`.
|
|
141
|
+
- **Only the referenced subpaths are copied**, so a pack's `README`, CI config and tests never enter your repo. A reference with no subpath copies the whole repo.
|
|
142
|
+
- **`.git` is never copied.** A nested repository would be recorded as a gitlink, whose contents git does not track — precisely the state this avoids.
|
|
143
|
+
- **Cleared once per run.** The first entry to touch a pack clears its mirror, so content left by a previous ref (or by a source entry you have since deleted) does not linger; later entries only replace their own subpath.
|
|
144
|
+
- **Never destructive.** The `.pack` stamp marks the directory as sync's to manage: a non-empty directory *without* one is left alone (with a warning) rather than deleted, so a directory of your own at that path is safe. A stamped directory stays the pack's even after you edit its `url:` — a moved or renamed upstream refreshes the mirror, which is the whole point of committing it. To hand a mirror path back to the project, delete the directory. A mirror that resolves to the repo root, escapes the repo, or sits inside a configured `sources.*` directory is refused outright — `sync` exits 1 before anything is written.
|
|
145
|
+
- Mirrored files have committed paths, so `AGENTS.md` and the Pi adapter link to them like any local source instead of naming them bare. A transient pack has no such path and is still named bare.
|
|
146
|
+
|
|
147
|
+
## Agent Frontmatter
|
|
148
|
+
|
|
149
|
+
```yaml
|
|
150
|
+
---
|
|
151
|
+
name: agent-name # Kebab-case identifier
|
|
152
|
+
description: When to use this agent # Shown in IDE agent picker
|
|
153
|
+
tier: heavy|standard|light # Model capability (tool-agnostic)
|
|
154
|
+
access: full|readonly # Tool permissions (tool-agnostic)
|
|
155
|
+
skills: # Optional: linked skills
|
|
156
|
+
- skill-name-1
|
|
157
|
+
- skill-name-2
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
Agent instructions in markdown...
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### An agent is thin — it never restates the rules
|
|
164
|
+
|
|
165
|
+
Body sections: **Expertise** → **Boundaries** (where it stops) → **Build & Verify**. What belongs to the agent is its role, its limits, and how it proves the work is done.
|
|
166
|
+
|
|
167
|
+
**Do not instruct an agent to read the rules.** They reach it on their own: Claude Code loads `.claude/rules/` into every custom subagent's startup context alongside `CLAUDE.md` (*Subagents → What loads at startup*), and Cursor, Copilot, Codex, Pi and opencode receive always-on rules inlined in `AGENTS.md`. A `Read intelligence/rules/<domain>.md before starting` line is duplication: it doubles the tokens and creates a second copy that drifts from the rule it copied. Point at a rule by name if you must; never restate it. The urge to copy a rule into an agent means the rule is in the wrong place — move it.
|
|
168
|
+
|
|
169
|
+
### Tier Mappings
|
|
170
|
+
|
|
171
|
+
| Tier | Claude | Cursor | Copilot / Codex | opencode | Use for |
|
|
172
|
+
|------|--------|--------|-----------------|----------|---------|
|
|
173
|
+
| heavy | opus | (default) | gpt-5.6-sol | claude-opus-4-8 | Developers, complex reasoning, migration |
|
|
174
|
+
| standard | sonnet | fast | gpt-5.6-terra | claude-sonnet-5 | Reviewers, validators, analysis |
|
|
175
|
+
| light | haiku | fast | gpt-5.6-luna | claude-haiku-4-5 | Simple lookups, formatting |
|
|
176
|
+
|
|
177
|
+
The vocabulary is tool-agnostic on purpose: the source says `tier: heavy`, and each adapter resolves it through `get_model()`. Defaults move forward as vendors ship new models — pin one per IDE/tier under `models:` in `config.yaml` only when you must, and expect a drift report on every sync once the default overtakes the pin.
|
|
178
|
+
|
|
179
|
+
### Access Mappings
|
|
180
|
+
|
|
181
|
+
| Access | Claude | Cursor | Description |
|
|
182
|
+
|--------|--------|--------|-------------|
|
|
183
|
+
| full | (no `tools:` field - inherits every session tool, MCP servers included) | (default) | Full edit access |
|
|
184
|
+
| readonly | tools: Read,Grep,Glob,Bash + disallowedTools: Write,Edit | readonly: true | Analysis only |
|
|
185
|
+
|
|
186
|
+
## Rule Frontmatter
|
|
187
|
+
|
|
188
|
+
```yaml
|
|
189
|
+
---
|
|
190
|
+
paths: # Optional: path-based activation
|
|
191
|
+
- "src/backend/**" # Glob patterns from repo root
|
|
192
|
+
- "config/**"
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
Rule content in markdown...
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
- **With paths:** Rule auto-loads when user edits matching files
|
|
199
|
+
- **Without paths:** Rule applies always (context rules)
|
|
200
|
+
|
|
201
|
+
### Sync Transformations (Rules)
|
|
202
|
+
|
|
203
|
+
| Source | Claude | Cursor | Copilot | Codex / Pi / opencode / AGENTS.md |
|
|
204
|
+
|--------|--------|--------|---------|------------------------|
|
|
205
|
+
| `paths:` (scoped) | copied | `globs:` in `.mdc` | `applyTo:` in `.instructions.md` | listed in AGENTS.md; Pi also gets generated on-demand rule files + extension |
|
|
206
|
+
| no `paths:` (always-on) | copied | skipped | skipped | inlined into AGENTS.md |
|
|
207
|
+
| extension | `.md` | `.mdc` | `.instructions.md` | inline / generated extension / n/a |
|
|
208
|
+
|
|
209
|
+
Always-on rule content is inlined once into AGENTS.md (which Cursor, Copilot, Codex, Pi, and opencode read natively); the per-IDE rule channels carry only path-scoped rules to preserve monorepo glob targeting without duplicating context. Claude Code does not read AGENTS.md, so its adapter receives the full rule set. opencode has no first-class path-scoped channel (users may opt in via `instructions:` globs in `opencode.json`), so the opencode adapter does not generate scoped-rule files.
|
|
210
|
+
|
|
211
|
+
## Skill Frontmatter
|
|
212
|
+
|
|
213
|
+
Skills follow the [Agent Skills open standard](https://agentskills.io) (adopted by Claude Code, Cursor, GitHub Copilot, OpenAI Codex, Pi, Gemini CLI, OpenCode, Goose, Junie, and 30+ others). Required fields: `name` + `description`.
|
|
214
|
+
|
|
215
|
+
```yaml
|
|
216
|
+
---
|
|
217
|
+
name: <domain>-<verb>-<noun> # e.g., backend-add-endpoint
|
|
218
|
+
description: What the skill does # Shown in IDE skill picker
|
|
219
|
+
argument-hint: <arg1> [arg2] # Optional: usage hint
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
# Skill Title
|
|
223
|
+
|
|
224
|
+
## Steps
|
|
225
|
+
1. First step...
|
|
226
|
+
2. Second step...
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Standard optional fields (`license`, `compatibility`, `metadata`, `allowed-tools`) and IDE-specific extensions (Claude's `disable-model-invocation`, `model`, `effort`, `agent`, `context: fork`, `hooks`, `paths`, `shell`) pass through unchanged — adapters do not strip them. The engine's own flow skills declare `agent:` (`intelligence-review-skills` → `intelligence-architect`, the four sync/update/adapter flows → `intelligence-operator`); the binding takes effect where a tool honors it, and a skill invoked directly runs on the session model unless it also sets `context: fork`, as `intelligence-sync` does — the flows that can need the user mid-run (update, adapter install/removal) deliberately do not. Each tool ignores fields it does not understand.
|
|
230
|
+
|
|
231
|
+
**Limits that reject the skill outright** (it does not degrade — it disappears from the picker):
|
|
232
|
+
|
|
233
|
+
| Field | Limit | Failure |
|
|
234
|
+
|---|---|---|
|
|
235
|
+
| `description` | 1024 chars | *"Skill description must be at most 1024 characters"* |
|
|
236
|
+
| `name` | 64 chars | rejected at load |
|
|
237
|
+
| `argument-hint` | must be a **string** | `argument-hint: [pr-number]` is a YAML flow *sequence* unquoted → *"argument-hint must be a string"* |
|
|
238
|
+
|
|
239
|
+
Sync quotes `description` and `argument-hint` for every target on the way out, so an unquoted hint is fixed automatically; the length limits it can only warn about (`lint_frontmatter` prints the file, line and actual length) — shortening the text is the author's call.
|
|
240
|
+
|
|
241
|
+
### Naming Conventions
|
|
242
|
+
|
|
243
|
+
Skill names are `<domain>-<verb>-<noun>`. Both parts are required.
|
|
244
|
+
|
|
245
|
+
**Domain prefix** (the scope — required, never omit):
|
|
246
|
+
|
|
247
|
+
| Source | Domain |
|
|
248
|
+
|--------|--------|
|
|
249
|
+
| Single / root project | Project codename from `config.yaml` → `project.name` |
|
|
250
|
+
| Backend service / API | `backend-` |
|
|
251
|
+
| Frontend / web / UI | `frontend-` |
|
|
252
|
+
| Infrastructure / IaC / CI/CD | `devops-` |
|
|
253
|
+
| Shared library / common code | `core-` |
|
|
254
|
+
| Test suites (e2e, integration) | `tests-` |
|
|
255
|
+
| Monorepo named components | Component name (e.g., `billing-`, `auth-`) |
|
|
256
|
+
| Tool-internal (intelligence-sync) | `intelligence-` |
|
|
257
|
+
|
|
258
|
+
Reuse an existing domain whenever possible. Do not invent new domains without clear need.
|
|
259
|
+
|
|
260
|
+
**Verb prefix** (the action):
|
|
261
|
+
|
|
262
|
+
| Verb | Type | Description |
|
|
263
|
+
|------|------|-------------|
|
|
264
|
+
| `add-` | Append | Puts one new member into a set that already exists |
|
|
265
|
+
| `create-` | Originate | Brings into existence the container nothing hosted before |
|
|
266
|
+
| `update-` | Revise | Changes what is already there, selectively |
|
|
267
|
+
| `run-` | Execution | Runs an operation (tests, sync, build) |
|
|
268
|
+
| `review-` | Read-only | Analyzes code without changes |
|
|
269
|
+
| `test-` | Testing | Manual or automated test verification |
|
|
270
|
+
| `remove-` | Deletion | Safely removes an artifact |
|
|
271
|
+
|
|
272
|
+
Agents follow the same domain prefix rule: `<domain>-<role>` (e.g., `backend-developer`, `frontend-code-reviewer`). Rule filenames use the domain without a verb: `<domain>.md` (e.g., `backend.md`).
|
|
273
|
+
|
|
274
|
+
### How much a skill body carries
|
|
275
|
+
|
|
276
|
+
A skill that does the work itself carries the detail: the patterns, the code, the examples. A skill that dispatches to other skills stays thin — it names them and adds only what it alone knows (the discovery, the order, the check between steps), and it never restates their content, because two copies of a procedure disagree at the first edit.
|
|
277
|
+
|
|
278
|
+
Which of the two a skill is has nothing to do with its verb. An `add-` skill may dispatch, and a `create-` skill may do the work itself: the verb answers what already existed (Verb prefix, above), not how the skill is built inside.
|
|
279
|
+
|
|
280
|
+
## Authoring Discipline
|
|
281
|
+
|
|
282
|
+
### Writing description fields
|
|
283
|
+
|
|
284
|
+
Each skill, rule, and agent has a `description` field in frontmatter. This field is loaded into every IDE's available-skills context. **Total description tokens across all artifacts compete for a shared budget** — with a large registry, longer descriptions push other skills out of reach.
|
|
285
|
+
|
|
286
|
+
Two cases:
|
|
287
|
+
|
|
288
|
+
| Case | Format | Length target |
|
|
289
|
+
|---|---|---|
|
|
290
|
+
| **Unique skill** (no siblings doing similar action) | Plain verb-noun phrase | 4-8 words |
|
|
291
|
+
| **Skill with siblings** (multiple similar skills in registry) | verb-noun + distinct trigger phrase | 10-20 words, ~250 chars |
|
|
292
|
+
|
|
293
|
+
Two different numbers, do not confuse them: **~250 chars is the house budget** (what keeps the shared registry affordable), while **1024 chars is a wall** — Claude Code and the Agent Skills standard reject a longer `description` outright and the artifact disappears from the picker. Sync warns at the wall (`lint_frontmatter`); staying near the budget is the author's job.
|
|
294
|
+
|
|
295
|
+
Examples:
|
|
296
|
+
|
|
297
|
+
```yaml
|
|
298
|
+
# Unique skill — short is fine
|
|
299
|
+
description: "Create new intelligence rule"
|
|
300
|
+
|
|
301
|
+
# Sibling skill — needs distinguishing trigger
|
|
302
|
+
description: "Run weekly check-up: retrospective + strategic analysis + next week planning"
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
When the registry grows past comfortable budget, prefer **curation** (merge duplicates, archive orphans via `intelligence-review-skills`) over truncating descriptions individually.
|
|
306
|
+
|
|
307
|
+
### Size discipline — the backstop, not the goal
|
|
308
|
+
|
|
309
|
+
The goal is **subtraction** (see the `intelligence-authoring` rule the engine ships): every line is loaded into someone's context out of a shared, finite budget, so the default answer to "should this be a rule?" is no. These caps are only the line past which something is definitely wrong.
|
|
310
|
+
|
|
311
|
+
| Type | Hard cap | Over the cap |
|
|
312
|
+
|---|---|---|
|
|
313
|
+
| SKILL.md body | 1000 lines | Move detail into `references/<topic>.md` and point at it |
|
|
314
|
+
| Reference file (`references/*.md`) | 500 lines | Add a table of contents past 300 lines |
|
|
315
|
+
| Rule | 500 lines | Split by sub-scope, or move pattern detail to `references/` |
|
|
316
|
+
| Agent | 200 lines | Refactor — agents stay thin; heavy content lives in skills and rules |
|
|
317
|
+
|
|
318
|
+
**Ceilings, not quotas.** An artifact that says everything it needs to is finished, not underweight. Over the cap means it is doing two jobs, or the detail belongs behind a pointer: `Read references/<topic>.md when [condition].`
|
|
319
|
+
|
|
320
|
+
Resource organization — **content lives inside the skill that uses it, by default**:
|
|
321
|
+
|
|
322
|
+
```
|
|
323
|
+
skill-name/
|
|
324
|
+
├── SKILL.md (required)
|
|
325
|
+
├── references/ — Detailed docs, loaded on demand
|
|
326
|
+
├── scripts/ — Executable helpers for deterministic / repetitive steps
|
|
327
|
+
└── assets/ — Files used in output (templates, fonts, icons)
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
Sync copies the whole directory, so a bundled helper travels with its skill into every tool. **Promote a helper out of the skill folder only when a second skill needs it** — then it lives beside the source groups (e.g. `<umbrella>/scripts/`) and every skill resolves it the same way. The dividing line is reuse, not repetition: a helper one skill runs a hundred times still belongs to that skill.
|
|
331
|
+
|
|
332
|
+
### Writing principles
|
|
333
|
+
|
|
334
|
+
Apply to skill bodies, rule bodies, and agent bodies — anywhere LLM-facing instructions are authored.
|
|
335
|
+
|
|
336
|
+
**Use imperative form.** "Read the config file" works better than "You should read the config file."
|
|
337
|
+
|
|
338
|
+
**Explain the WHY.** LLMs follow positive instructions better when reasoning is visible. "Use module boundaries — AI knows which imports are allowed without guessing" works better than "Use module boundaries (MUST)."
|
|
339
|
+
|
|
340
|
+
**Reserve absolute language for true invariants.** ALL-CAPS MUSTs and NEVERs fit security, safety, output format — places where the constraint is non-negotiable. For judgment calls, write **decision rules** in positive form: "When X, do Y" instead of "NEVER do Z." If you find yourself writing ALWAYS or NEVER in all caps for a judgment call, that's a yellow flag — reframe and explain the reasoning.
|
|
341
|
+
|
|
342
|
+
**Keep prompts lean.** Remove instructions that aren't pulling their weight. Padding wastes context and dilutes the instructions that matter.
|
|
343
|
+
|
|
344
|
+
**Lead with positive defaults.** Rule body order: REQUIRED → Invariants → Architecture → Build & Test → Examples → Patterns to recognize and replace. The LLM acts on the positive instruction it reads first; anti-patterns sit at the end as reference documentation, not as instructions.
|
|
345
|
+
|
|
346
|
+
**Bundle repeated patterns as scripts.** If the LLM reinvents the same helper on every invocation, encode it in `scripts/` and have the skill call it.
|
|
347
|
+
|
|
348
|
+
## Generated Output
|
|
349
|
+
|
|
350
|
+
| Target | Rules output | Skills location | Agents location | Git-ignored |
|
|
351
|
+
|--------|--------------|-----------------|-----------------|-------------|
|
|
352
|
+
| `agents` | inlined into `AGENTS.md` (always-on); listed (scoped) | n/a | listed in `AGENTS.md` | No (committed) |
|
|
353
|
+
| Claude Code | `.claude/rules/` (full) | `.claude/skills/` | `.claude/agents/` | Yes |
|
|
354
|
+
| Cursor | `.cursor/rules/*.mdc` (scoped only) | `.cursor/skills/` | `.cursor/agents/` | Yes |
|
|
355
|
+
| GitHub Copilot | `.github/instructions/*.instructions.md` (scoped only) | `.github/skills/` | `.github/agents/` | Partial |
|
|
356
|
+
| OpenAI Codex | none (reads `AGENTS.md`) | `.agents/skills/` | `.codex/agents/*.toml` | Yes |
|
|
357
|
+
| Pi | `.pi/intelligence-sync/rules/*.md` + `.pi/extensions/intelligence-sync-rules.ts` (scoped only; always-on via `AGENTS.md`) | `.agents/skills/` | `.pi/prompts/intelligence-agent-*.md` | Partial |
|
|
358
|
+
| opencode | none (always-on via `AGENTS.md`; users may opt in to scoped rules via `instructions:` globs in `opencode.json`) | `.agents/skills/` | `.opencode/agents/*.md` (mode: subagent) | Yes |
|
|
359
|
+
|
|
360
|
+
Skill locations all comply with the Agent Skills open standard. Cursor reads from `.cursor/skills/` and `.agents/skills/`; Copilot reads from `.github/skills/`, `.claude/skills/`, and `.agents/skills/`; Codex, Pi, and opencode all read from `.agents/skills/`; Claude Code reads from `.claude/skills/`.
|
|
361
|
+
|
|
362
|
+
**Rule routing rationale:** AGENTS.md is canonical for Cursor/Copilot/Codex/Pi/opencode (all read it natively), so always-on rule content is inlined there once and the per-IDE rule directories carry only path-scoped rules — no duplication. Claude Code does not read AGENTS.md, so its adapter receives the full rule set.
|
|
363
|
+
|
|
364
|
+
`AGENTS.md` is always enabled and regenerated on every sync. The static header (`targets.agents.header` in `config.yaml`) is the only hand-authored part; everything below it is rebuilt from frontmatter — agents/skills tables, the rules list, and the inlined content of every always-on rule (those without `paths:`). Path-scoped rules are listed by name only so AGENTS.md does not balloon in monorepos.
|
|
365
|
+
|
|
366
|
+
## Migration & Module Contract
|
|
367
|
+
|
|
368
|
+
Structural changes to the module layout are handled by **versioned migrations**, not ad-hoc scripts or manual instructions. The model is designed for an *unbounded, uncoordinated* upgrade window — a project may sit on an old version indefinitely and still migrate safely whenever it finally runs.
|
|
369
|
+
|
|
370
|
+
**Division of responsibility**
|
|
371
|
+
|
|
372
|
+
- **Bash = deterministic, fail-closed core.** It performs only mechanically safe, reversible-until-committed steps and **never guesses**. Any state it cannot resolve safely is reported, not forced.
|
|
373
|
+
- **`intelligence-update` skill = intelligent layer.** It detects project state, bootstraps the engine, runs bash, interprets the status, and resolves the cases bash refuses (asking the user when genuinely ambiguous).
|
|
374
|
+
|
|
375
|
+
**The schema-version contract key.** The applied schema version is a managed, top-level scalar `sync_version` in `config.yaml` — *not* a dotfile, *not* `scripts/VERSION`. `config.yaml` is what most future breaking changes reshape, so the schema version lives with what it versions. **Invariant: this key is permanent and format-stable** — no migration may ever rename, move, or change its shape, so any engine (however old/new) can always read "what schema is this?" before parsing the rest. The bootstrap/INIT flow emits it for fresh projects (= engine `scripts/VERSION`) and must preserve it on re-bootstrap. `scripts/VERSION` = what the engine *is*; the key = what has been *applied*; the gap = pending breaking changes.
|
|
376
|
+
|
|
377
|
+
**Every `migrate_to_<ver>` obeys this contract**
|
|
378
|
+
|
|
379
|
+
1. **Version-named & ordered.** Suffix is the target version (`migrate_to_0_3_1`); listed in `MIGRATIONS=()` ascending, append-only — never reorder or rewrite shipped migrations.
|
|
380
|
+
2. **Idempotent structural precondition is the correctness mechanism.** Each migration self-detects from the actual on-disk/config structure whether its change is already applied, and is a silent no-op if so. The dispatcher runs the whole chain in order; it does **not** gate on the version stamp — so a wrong/missing `sync_version` can never cause a needed migration to be skipped. Replaying any number of times never fails or duplicates.
|
|
381
|
+
3. **Transactional / fail-closed.** Stage → **verify postcondition (sentinel)** → commit → only then delete the old state. A crash or partial input leaves the prior state intact; nothing is destroyed before the replacement is verified.
|
|
382
|
+
4. **Version-compat guard.** A stale engine refuses to operate on a project whose `sync_version` is newer than it understands (`ahead-of-engine`). This is the *only* role of the stamp — a guard, never a gate.
|
|
383
|
+
5. **Status hand-off is first-class.** "Cannot safely automate" is a normal outcome, reported via the contract below — not an error to paper over.
|
|
384
|
+
|
|
385
|
+
**Breaking-change releases carry a `### Breaking` CHANGELOG subsection**, each item stating its post-condition. The `intelligence-update` skill reads the changelog across the version gap, surfaces these, and verifies each post-condition after applying. `sync.sh` is a pure synchronizer — it never migrates; it fails closed (`needs-update`) across an un-applied gap so a stale engine can't generate against a newer schema. `update.sh` (+ the skill) is the sole migrator.
|
|
386
|
+
|
|
387
|
+
**bash ↔ skill status contract** (codes are public; never renumber)
|
|
388
|
+
|
|
389
|
+
| `IS_STATUS` | exit | Meaning |
|
|
390
|
+
|---|---|---|
|
|
391
|
+
| `ok` | 0 | Up to date / nothing to do |
|
|
392
|
+
| `migrated` | 0 | Migration performed this run |
|
|
393
|
+
| `error` | 1 | Generic failure (detail in message) |
|
|
394
|
+
| `config-missing` | 2 | No `config.yaml` — project not bootstrapped |
|
|
395
|
+
| `ambiguous` | 3 | Conflicting state; skill/human-only (bash never emits it) |
|
|
396
|
+
| `ahead-of-engine` | 4 | Project schema newer than this engine |
|
|
397
|
+
| `aborted-incomplete` | 5 | Staged module incomplete; prior state left intact |
|
|
398
|
+
| `needs-update` | 6 | Pending breaking changes — run the update flow first |
|
|
399
|
+
|
|
400
|
+
Bash emits `IS_STATUS=<code> [IS_DETAIL=...]` on stdout and exits with the matching code; callers capture it with `cmd || rc=$?` (never `if ! cmd; then exit $?` — that loses the code). The skill branches on the code.
|
|
401
|
+
|
|
402
|
+
**Module model.** The engine self-locates by its own path; it does not assume a folder name (`sync/` by convention). Each `<umbrella>/<module>/` is self-contained: its own `scripts/`(+`VERSION`), `skills/`, `INIT.md`, `docs/`. Modules update independently and never touch sibling modules or project content (`rules/`, `agents/`, non-meta `skills/`) nor `config.yaml` beyond the idempotent additive `sources.skills` line and the `sync_version` key.
|
|
403
|
+
|
|
404
|
+
## .gitignore Pattern
|
|
405
|
+
|
|
406
|
+
```
|
|
407
|
+
# AI IDE tools (generated by intelligence-sync, local preferences)
|
|
408
|
+
CLAUDE.md
|
|
409
|
+
.cursorrules
|
|
410
|
+
.agents/
|
|
411
|
+
.codex/
|
|
412
|
+
.pi/intelligence-sync/
|
|
413
|
+
.pi/extensions/intelligence-sync-rules.ts
|
|
414
|
+
.pi/prompts/intelligence-agent-*.md
|
|
415
|
+
|
|
416
|
+
# opencode: the generated subagents and slash commands are owned by the adapter.
|
|
417
|
+
# .opencode/opencode.json (and any other hand-authored config) stays tracked.
|
|
418
|
+
.opencode/agents/
|
|
419
|
+
.opencode/commands/
|
|
420
|
+
|
|
421
|
+
# Claude Code: ignore everything except project-shared settings.
|
|
422
|
+
.claude/*
|
|
423
|
+
!.claude/settings.json
|
|
424
|
+
|
|
425
|
+
# Cursor: same pattern.
|
|
426
|
+
.cursor/*
|
|
427
|
+
!.cursor/settings.json
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
The inverse pattern (`.claude/*` + `!.claude/settings.json`) ignores every generated subdir (`rules/`, `skills/`, `agents/`) plus any per-machine state Claude writes (`settings.local.json`, `*.lock`, `scheduled_tasks.*`, `sessions/`, `cache/`, etc.) without having to enumerate filenames Claude may add later. Only `.claude/settings.json` (project-shared bash allowlist, tool permissions) is tracked. Same logic for `.cursor/`. Pi and opencode are narrower: only the generated adapter-owned paths are ignored (`.pi/intelligence-sync/`, `.pi/extensions/intelligence-sync-rules.ts`, `.pi/prompts/intelligence-agent-*.md`, `.opencode/agents/`, `.opencode/commands/`), so `.pi/settings.json`, `.opencode/opencode.json`, and any hand-authored Pi extensions/prompts remain available for tracking. The opencode adapter additionally protects hand-authored slash commands by an emit-marker (`<!-- Generated by intelligence-sync. Do not edit manually. -->`): re-sync only deletes marker-bearing files in `.opencode/commands/`, so a project may track a hand-authored command alongside the generated ones (typically by un-ignoring it). If a project needs to track another file under `.claude/` or `.cursor/` (e.g., a hand-authored `.claude/commands/<name>.md`), add another `!<path>` line.
|
|
431
|
+
|
|
432
|
+
## Project Entry Points
|
|
433
|
+
|
|
434
|
+
| File | Role | Git status |
|
|
435
|
+
|------|------|-----------|
|
|
436
|
+
| `AGENTS.md` | Auto-generated canonical project doc for LLMs (do not edit manually) | Tracked |
|
|
437
|
+
| `CLAUDE.md` | Local user preferences (gitignored) | Ignored |
|
|
438
|
+
| `<umbrella>/config.yaml` | Sync config + `sync_version` schema-version contract key (committed) | Tracked |
|
|
439
|
+
| `<umbrella>/{rules,agents,skills}/` | Project source of truth | Tracked |
|
|
440
|
+
| `<umbrella>/sync/` | intelligence-sync module (engine+`scripts/VERSION`, meta-skills, INIT, docs) — vendored upstream-owned | Tracked |
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: intelligence-authoring
|
|
3
|
+
description: "Authoring discipline for the intelligence layer - subtraction first, rule vs skill vs agent, scoping, size"
|
|
4
|
+
paths:
|
|
5
|
+
- "<umbrella>/**"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Authoring the intelligence layer
|
|
9
|
+
|
|
10
|
+
Applies when writing or changing anything under `<umbrella>/`. The mechanics — frontmatter fields, tier and access vocabulary, how each tool is fed — live in `<module>/docs/CONVENTIONS.md`. This rule is the judgement that sits on top of them.
|
|
11
|
+
|
|
12
|
+
## Subtraction is the job
|
|
13
|
+
|
|
14
|
+
**Every line here is loaded into someone's context, and that budget is shared and finite.** An always-on rule is loaded into *every* session, forever. A line you add is a line something else loses — and the loss is invisible, so nobody ever notices what it cost.
|
|
15
|
+
|
|
16
|
+
So the default answer to "should this be a rule?" is **no**. Delete before you add. Merge before you split. The registry that gets trusted is the small one: a crowded one gets skimmed, and a skimmed rule is worse than a missing one, because it looks like coverage.
|
|
17
|
+
|
|
18
|
+
Three ways to shorten, in order of what they are worth:
|
|
19
|
+
|
|
20
|
+
1. **Make the rule unnecessary.** The best rule is a gate the model cannot skip. A rule that lists which command to run for which change is a *menu*, and a menu gets ordered from; the same decision expressed once, in a script the work has to pass through, cannot be forgotten, mis-remembered or skimmed past. **Ask this first, every time.**
|
|
21
|
+
2. **Delete what the code already says.** A rule restating what a reader can see in the file is noise, and noise trains people to skim the lines that are not.
|
|
22
|
+
3. **Cut the words, keep the reason.** Prose can shrink; the *why* cannot — an instruction without its reason does not survive contact with a judgement call.
|
|
23
|
+
|
|
24
|
+
**Never solve a problem by adding an artifact when moving one, or removing one, would do.** A new rule is the most expensive answer available, and it is the one that feels cheapest to write.
|
|
25
|
+
|
|
26
|
+
## Source of truth
|
|
27
|
+
|
|
28
|
+
Edit the sources listed in `config.yaml` — the `rules/`, `agents/` and `skills/` directories it names — and `config.yaml` itself. Everything else is derived: `.claude/`, `.cursor/`, `.github/{instructions,agents,skills}/`, `.codex/`, `.agents/skills/`, `.pi/`, `.opencode/` and `AGENTS.md` are **generated output**, and a hand edit there survives exactly until the next sync.
|
|
29
|
+
|
|
30
|
+
`<module>/` is the vendored engine. It owns its own rules, agents and meta-skills; `update.sh` replaces them wholesale, so a local edit there is lost at the next update. Fix it upstream instead.
|
|
31
|
+
|
|
32
|
+
After any change: `<sync-cmd>`. A change that was not synced does not exist for any tool.
|
|
33
|
+
|
|
34
|
+
## Pick the right artifact
|
|
35
|
+
|
|
36
|
+
| Type | Intent | How it loads |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| **Rule** | The model **respects** a constraint while doing other work | Automatically — always-on, or path-scoped via `paths:` |
|
|
39
|
+
| **Skill** | The model **performs** a defined procedure | Explicitly — `/skill-name` |
|
|
40
|
+
| **Agent** | The model **adopts** a persona | Explicitly — via the agent picker |
|
|
41
|
+
|
|
42
|
+
The mistakes that actually happen, in order of frequency:
|
|
43
|
+
|
|
44
|
+
- A **checklist** written into an agent body → a checklist is a *procedure*; it belongs in a **skill**. This one keeps happening because a checklist *feels* like expertise. It is not: it changes with the task, a role does not. An agent is what it is for, what it optimises for, where it stops, and what it calls done.
|
|
45
|
+
- A **convention** written into an agent body → it belongs in a **rule**, so every agent gets it, not just the one you happened to be editing.
|
|
46
|
+
- A **workflow** written into a rule body → it belongs in a **skill**. A rule is loaded always; a procedure should be invoked.
|
|
47
|
+
- **Expertise** written into a skill body → it belongs in an **agent**; the persona is reusable across skills.
|
|
48
|
+
|
|
49
|
+
## Rules
|
|
50
|
+
|
|
51
|
+
**Scope with `paths:`.** A rule without `paths:` is loaded into *every* session and inlined into `AGENTS.md` — the most expensive context real estate there is. Earn it. A rule that only matters when someone touches the frontend belongs scoped to the frontend.
|
|
52
|
+
|
|
53
|
+
**Lead with the positive default, then the invariant.** The model acts on the first instruction it reads, and it follows whatever is named — negation ("never do X") draws attention to X. Reserve absolute language (NEVER, MUST) for true must-nots: safety, security, output format. A judgement call written as a NEVER only teaches the model that NEVERs are negotiable.
|
|
54
|
+
|
|
55
|
+
**Derive from the code, not from prose that already exists.** Every REQUIRED and every invariant must be backed by something observed in the repository. Documentation is a claim, not evidence — read the file.
|
|
56
|
+
|
|
57
|
+
**Describe the repository, not a machine.** The OS, the shell, the editor, a local dev stack, personal tooling — these are environment facts. They belong in a personal, gitignored `CLAUDE.md`. A rule is committed and read by everyone, so a shell-specific command or an absolute local path in it is simply wrong for whoever is on another platform.
|
|
58
|
+
|
|
59
|
+
**Explain the why — but only a why you can back.** A reason the reader can check is what makes an instruction survive a judgement call. An invented reason is worse than none: it sounds like evidence.
|
|
60
|
+
|
|
61
|
+
### Invariants
|
|
62
|
+
|
|
63
|
+
- **Never state behaviour of a tool or engine you have not verified in its documentation or source.** This invariant exists because the claim *"Claude Code does not auto-load `.claude/rules/`"* was once written into this layer as fact. It is false — rules without `paths:` load at launch, path-scoped ones activate on matching files, and custom subagents inherit both (Claude Code docs: *Memory → Organize rules with `.claude/rules/`*, and *Subagents → What loads at startup*). An unverified claim about tooling is worse than a gap: nothing in the repository contradicts it, so it silently reshapes every decision downstream.
|
|
64
|
+
- **Never write a current defect into a rule as if it were the design.** Known breakage belongs in one place that says so. Every other rule describes the project *as it is meant to work* — a workaround documented as procedure becomes permanent.
|
|
65
|
+
- **Never link from one always-on rule to another.** Always-on rules are inlined verbatim into `AGENTS.md`, and the path-scoped channels carry only scoped rules, so a relative link is dead in at least one output. Name the rule instead; it loads on its own.
|
|
66
|
+
|
|
67
|
+
## Agents
|
|
68
|
+
|
|
69
|
+
An agent is **thin**: who it is, where it stops, how it verifies. Nothing else.
|
|
70
|
+
|
|
71
|
+
- **Do not list rules for an agent to read.** They load on their own — Claude Code loads `.claude/rules/` into every custom subagent's startup context, and Cursor, Copilot, Codex, Pi and opencode receive always-on rules inlined in `AGENTS.md`. Naming a rule is fine; copying it is duplication that drifts.
|
|
72
|
+
- **Point at a rule, do not restate it.** Wanting to copy a rule into an agent means the rule is in the wrong place — move it.
|
|
73
|
+
- **Do carry** what is genuinely the agent's own: its boundaries ("if the app will not start, stop — do not hand-write the output"), its verification commands, its definition of done.
|
|
74
|
+
|
|
75
|
+
## Skills
|
|
76
|
+
|
|
77
|
+
A skill is a repeatable procedure someone invokes, and **it ends in a verification**. If there is nothing to verify at the end, or it will only ever run once, it is not a skill — it is a note, or just the work.
|
|
78
|
+
|
|
79
|
+
### Naming
|
|
80
|
+
|
|
81
|
+
`<domain>-<verb>-<noun>`. The domain prefix carries the weight: it clusters siblings and says which system the skill acts on. Take it from the set already in use; add a new domain deliberately, not by accident.
|
|
82
|
+
|
|
83
|
+
The verb just names the action — `add-`, `run-`, `review-`, `extract-`, `plan-`, `validate-` all read fine. Prefer a verb already in use over a new synonym for the same thing. A stage that turns one thing into another reads naturally as `<domain>-to-<target>`.
|
|
84
|
+
|
|
85
|
+
Two verbs are told apart by what already exists. **`add-` puts one new member into a set that is already there** — a field on an existing type, a record among records, a component in the inventory the project keeps — so the noun names the member, and the number of files it takes to land is not the point. **`create-` brings the container itself into existence**, where nothing hosted it before. Neither verb describes how a skill is factored inside, so splitting a skill's internals never renames it.
|
|
86
|
+
|
|
87
|
+
`intelligence-` is **reserved** for the engine's own artifacts. A project skill carrying that prefix is pruned by the updater — rename it.
|
|
88
|
+
|
|
89
|
+
### Shape
|
|
90
|
+
|
|
91
|
+
- **A skill is executed, so it must not hardcode what can move.** Its steps are followed literally: a path, a command or a project name baked into a procedure breaks the moment the layout moves. Resolve them from a rule or from `config.yaml` instead. This does **not** apply to rules and agents — a rule's job is to *describe* the repository, so naming a path in prose is exactly right. Naming a path is description; baking one into a procedure is a defect waiting to fire.
|
|
92
|
+
- **Keep everything the skill needs inside the skill's own folder.** The Agent Skills standard lets a skill ship `scripts/`, `references/` and `assets/` beside `SKILL.md`, and sync copies the whole directory, so a bundled helper travels with the skill to every tool. That is the default.
|
|
93
|
+
- **Promote a helper out of the skill folder only when a second skill needs it** — then it belongs beside the source groups, and every skill resolves it the same way. The dividing line is reuse, not repetition: one skill's helper stays with that skill however often it runs.
|
|
94
|
+
- **A helper is code.** It gets what code gets — a test, and a way to run it that does not assume one person's machine.
|
|
95
|
+
|
|
96
|
+
## Size — the backstop, not the goal
|
|
97
|
+
|
|
98
|
+
The goal is subtraction, above. These are only the line past which something is definitely wrong.
|
|
99
|
+
|
|
100
|
+
| Type | Hard cap |
|
|
101
|
+
|---|---|
|
|
102
|
+
| Rule | 500 lines |
|
|
103
|
+
| Agent | 200 lines |
|
|
104
|
+
| `SKILL.md` | 1000 lines |
|
|
105
|
+
|
|
106
|
+
**Ceilings, not quotas.** An artifact that says everything it needs to is finished, not underweight — nothing here is a reason to pad. Over the cap means the artifact is doing two jobs, or the detail belongs in `references/<topic>.md` with a pointer from the body.
|
|
107
|
+
|
|
108
|
+
`description` fields compete for one shared budget across the whole registry: a long one pushes another artifact out of reach. Four to eight words when the name is unambiguous; longer only when a sibling does something similar and needs distinguishing. (The tools reject a `description` over 1024 characters outright — but that is a wall to stay far away from, not a target.)
|
|
109
|
+
|
|
110
|
+
## Verifying a change to this layer
|
|
111
|
+
|
|
112
|
+
The per-artifact checks are a procedure, not a constraint to hold in mind while doing other work — so they live in the meta-skills, not here. Invoke the one that matches what you are doing: `intelligence-add-rule`, `intelligence-add-agent`, `intelligence-add-skill`, `intelligence-extract-skill`, `intelligence-review-skills`, `intelligence-learn-from-context`, `intelligence-sync`, `intelligence-update`, `intelligence-install-adapter`, `intelligence-uninstall-adapter`.
|
|
113
|
+
|
|
114
|
+
A change to this layer is done when `<sync-cmd>` reports `IS_STATUS=ok` and the skill you invoked reports clean.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.11.0
|