@ainova-systems/intelligence 0.24.0 → 0.25.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/cli/internal/check.sh +123 -0
- package/engine/ENGINE_SHA +1 -1
- package/engine/VERSION +1 -1
- package/engine/adapters/agents.sh +14 -3
- package/engine/adapters/codex.sh +12 -5
- package/engine/adapters/pi.sh +4 -3
- package/engine/lib/common.sh +164 -49
- package/package.json +1 -1
- package/packages/sync/references/adapters.md +3 -3
- package/packages/sync/references/conventions.md +21 -10
- package/packages/sync/rules/intelligence-authoring.md +10 -9
- package/packages/sync/skills/intelligence-learn-from-repository/SKILL.md +7 -4
- package/packages/sync/skills/intelligence-learn-from-session/SKILL.md +22 -9
- package/packages/sync/skills/intelligence-manage-adapters/SKILL.md +3 -3
- package/packages/sync/skills/intelligence-review-context/SKILL.md +23 -19
- package/packages/sync/skills/intelligence-review-context/references/audit-checks.md +26 -2
- package/packages/sync/skills/intelligence-review-context/references/compaction.md +6 -4
- package/packages/sync/skills/intelligence-sync/SKILL.md +10 -10
- package/packages/sync/skills/intelligence-update-context/SKILL.md +3 -1
- package/packages/sync/skills/intelligence-update-context/references/skills.md +5 -4
- package/packages/sync/skills/intelligence-upgrade/SKILL.md +0 -1
package/cli/internal/check.sh
CHANGED
|
@@ -8,6 +8,74 @@ warn() { echo " ✗ $*"; problems=$((problems + 1)); }
|
|
|
8
8
|
note() { echo " ! $*"; }
|
|
9
9
|
ok() { echo " ✓ $*"; }
|
|
10
10
|
|
|
11
|
+
# claude_md_excluded <path> <settings>... - whether an entry of
|
|
12
|
+
# claudeMdExcludes in one of the settings files matches <path>. Claude Code
|
|
13
|
+
# matches those globs against absolute paths; this reads `**`, `*` and `?` and
|
|
14
|
+
# takes every other character literally. A Windows path is tried in both the
|
|
15
|
+
# Git Bash spelling and the drive spelling (`/d/x`, `D:/x`).
|
|
16
|
+
claude_md_excluded() {
|
|
17
|
+
local f alt=""
|
|
18
|
+
if command -v cygpath >/dev/null 2>&1; then alt="$(cygpath -m "$1")"; fi
|
|
19
|
+
for f in "${@:2}"; do
|
|
20
|
+
[ -f "$f" ] || continue
|
|
21
|
+
CMX_PATH="$1" CMX_ALT="$alt" awk '
|
|
22
|
+
function glob_re(g, i, c, out) {
|
|
23
|
+
out = "^"
|
|
24
|
+
for (i = 1; i <= length(g); i++) {
|
|
25
|
+
c = substr(g, i, 1)
|
|
26
|
+
if (c == "*" && substr(g, i + 1, 1) == "*") {
|
|
27
|
+
i++
|
|
28
|
+
if (substr(g, i + 1, 1) == "/") { i++; out = out "(.*/)?" }
|
|
29
|
+
else out = out ".*"
|
|
30
|
+
}
|
|
31
|
+
else if (c == "*") out = out "[^/]*"
|
|
32
|
+
else if (c == "?") out = out "[^/]"
|
|
33
|
+
else if (index("\\^$.|+()[]{}", c)) out = out "\\" c
|
|
34
|
+
else out = out c
|
|
35
|
+
}
|
|
36
|
+
return out "$"
|
|
37
|
+
}
|
|
38
|
+
{ buf = buf $0 "\n" }
|
|
39
|
+
END {
|
|
40
|
+
p = index(buf, "\"claudeMdExcludes\"")
|
|
41
|
+
if (!p) exit 1
|
|
42
|
+
s = substr(buf, p + 18)
|
|
43
|
+
if (!sub(/^[ \t\r\n]*:[ \t\r\n]*\[/, "", s)) exit 1
|
|
44
|
+
while (1) {
|
|
45
|
+
sub(/^[ \t\r\n,]*/, "", s)
|
|
46
|
+
if (substr(s, 1, 1) != "\"") exit 1
|
|
47
|
+
v = ""
|
|
48
|
+
for (i = 2; i <= length(s); i++) {
|
|
49
|
+
c = substr(s, i, 1)
|
|
50
|
+
if (c == "\\") { i++; v = v substr(s, i, 1); continue }
|
|
51
|
+
if (c == "\"") break
|
|
52
|
+
v = v c
|
|
53
|
+
}
|
|
54
|
+
s = substr(s, i + 1)
|
|
55
|
+
re = glob_re(v)
|
|
56
|
+
if (ENVIRON["CMX_PATH"] ~ re) exit 0
|
|
57
|
+
if (ENVIRON["CMX_ALT"] != "" && ENVIRON["CMX_ALT"] ~ re) exit 0
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
' "$f" && return 0
|
|
61
|
+
done
|
|
62
|
+
return 1
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
# claude_md_above <dir> - whether <dir> or a directory above it holds a
|
|
66
|
+
# CLAUDE.md, .claude/CLAUDE.md or CLAUDE.local.md, any of which keeps Claude
|
|
67
|
+
# Code from reading AGENTS.md. The user's own ~/.claude/CLAUDE.md does not.
|
|
68
|
+
claude_md_above() {
|
|
69
|
+
local d="$1" up
|
|
70
|
+
while :; do
|
|
71
|
+
[ ! -e "$d/CLAUDE.md" ] && [ ! -e "$d/CLAUDE.local.md" ] || return 0
|
|
72
|
+
if [ -e "$d/.claude/CLAUDE.md" ] && ! [ "$d" -ef "${HOME:-}" ]; then return 0; fi
|
|
73
|
+
up="${d%/*}"
|
|
74
|
+
[ -n "$d" ] && [ "$up" != "$d" ] || return 1
|
|
75
|
+
d="$up"
|
|
76
|
+
done
|
|
77
|
+
}
|
|
78
|
+
|
|
11
79
|
echo "environment:"
|
|
12
80
|
command -v git >/dev/null 2>&1 && ok "git $(git --version | awk '{print $3}')" || warn "git not found"
|
|
13
81
|
command -v awk >/dev/null 2>&1 && ok "awk present" || warn "awk not found"
|
|
@@ -144,6 +212,7 @@ content_dir="$(manifest_intelligence_dir "$manifest")"
|
|
|
144
212
|
# Ownership across enabled adapters: two adapters claiming one owned path prune
|
|
145
213
|
# each other silently, and sync reports success for both.
|
|
146
214
|
adapter_claims_reset
|
|
215
|
+
claude_out="" agents_out="" disabled_owned=""
|
|
147
216
|
while IFS= read -r target; do
|
|
148
217
|
[ -n "$target" ] || continue
|
|
149
218
|
output="$(get_target_output "$manifest" "$target")"
|
|
@@ -161,6 +230,14 @@ while IFS= read -r target; do
|
|
|
161
230
|
if [ "$(is_target_enabled "$manifest" "$target")" = "1" ]; then
|
|
162
231
|
adapter_claims_add_records "$target" "$records" \
|
|
163
232
|
|| warn "$IS_ADAPTER_CLAIM_CONFLICT"
|
|
233
|
+
case "$target" in
|
|
234
|
+
claude) claude_out="$output" ;;
|
|
235
|
+
agents) agents_out="$output" ;;
|
|
236
|
+
esac
|
|
237
|
+
else
|
|
238
|
+
while IFS=$'\t' read -r kind value; do
|
|
239
|
+
[ "$kind" != owned ] || disabled_owned+="$target"$'\t'"$value"$'\n'
|
|
240
|
+
done <<< "$records"
|
|
164
241
|
fi
|
|
165
242
|
while IFS=$'\t' read -r kind value; do
|
|
166
243
|
if [ "$kind" = "requires" ] \
|
|
@@ -204,6 +281,52 @@ while IFS= read -r target; do
|
|
|
204
281
|
ok "adapter $target contract v1"
|
|
205
282
|
done < <(target_names "$manifest")
|
|
206
283
|
|
|
284
|
+
# Disabling an adapter keeps its output for a cleanup the owner approves. An
|
|
285
|
+
# owned path an enabled adapter also claims is that adapter's output now. The
|
|
286
|
+
# empty line the here-string ends with reports the last adapter.
|
|
287
|
+
left_target="" left_paths=""
|
|
288
|
+
while IFS=$'\t' read -r target value; do
|
|
289
|
+
if [ "$target" != "$left_target" ] && [ -n "$left_paths" ]; then
|
|
290
|
+
note "adapter '$left_target' is disabled, and its output is still here: ${left_paths#, }. The intelligence-manage-adapters skill reviews it and removes what you approve"
|
|
291
|
+
left_paths=""
|
|
292
|
+
fi
|
|
293
|
+
left_target="$target"
|
|
294
|
+
[ -n "$target" ] || continue
|
|
295
|
+
[ -e "$IP_ROOT/$value" ] || [ -L "$IP_ROOT/$value" ] || continue
|
|
296
|
+
adapter_contract_rel_path "$value"
|
|
297
|
+
claimed=0
|
|
298
|
+
while IFS=$'\t' read -r _ _ path; do
|
|
299
|
+
[ -n "$path" ] || continue
|
|
300
|
+
case "$IS_ADAPTER_REL_PATH/" in "$path"/*) claimed=1 ;; esac
|
|
301
|
+
case "$path/" in "$IS_ADAPTER_REL_PATH"/*) claimed=1 ;; esac
|
|
302
|
+
done <<< "$IS_ADAPTER_CLAIMS"
|
|
303
|
+
[ "$claimed" = 1 ] || left_paths="$left_paths, $IS_ADAPTER_REL_PATH"
|
|
304
|
+
done <<< "$disabled_owned"
|
|
305
|
+
|
|
306
|
+
# Claude Code 2.1.277 and later reads AGENTS.md as project instructions when no
|
|
307
|
+
# CLAUDE.md, .claude/CLAUDE.md or CLAUDE.local.md exists in the project or above
|
|
308
|
+
# it, and keeps loading .claude/rules/ beside it (code.claude.com/docs/en/memory).
|
|
309
|
+
# With both targets enabled every always-on rule then loads twice. The contract
|
|
310
|
+
# preserves settings.json, so the exclude is the owner's to add.
|
|
311
|
+
if [ -n "$claude_out" ] && [ -n "$agents_out" ]; then
|
|
312
|
+
agents_output_path_var "$agents_out"
|
|
313
|
+
adapter_contract_rel_path "$IS_AGENTS_OUTPUT_PATH"
|
|
314
|
+
agents_md="$IS_ADAPTER_REL_PATH"
|
|
315
|
+
adapter_contract_rel_path "$claude_out"
|
|
316
|
+
claude_out="$IS_ADAPTER_REL_PATH"
|
|
317
|
+
case "/$agents_md" in
|
|
318
|
+
*/.agents/*) ;;
|
|
319
|
+
*/AGENTS.md)
|
|
320
|
+
if ! claude_md_above "$IP_ROOT" && [ ! -e "$IP_ROOT/$claude_out/CLAUDE.md" ] \
|
|
321
|
+
&& ! claude_md_excluded "$IP_ROOT/$agents_md" \
|
|
322
|
+
"$IP_ROOT/$claude_out/settings.json" "$IP_ROOT/$claude_out/settings.local.json"; then
|
|
323
|
+
note "Claude Code 2.1.277 and later reads $agents_md when there is no CLAUDE.md, $claude_out/CLAUDE.md or CLAUDE.local.md, so the always-on rules load twice: from $claude_out/rules/ and from $agents_md. Sync never edits settings; put this key in $claude_out/settings.json:"
|
|
324
|
+
printf ' { "claudeMdExcludes": ["**/%s"] }\n' "$agents_md"
|
|
325
|
+
fi
|
|
326
|
+
;;
|
|
327
|
+
esac
|
|
328
|
+
fi
|
|
329
|
+
|
|
207
330
|
# A local rule, agent or skill is one these patterns name (decision 0021): the
|
|
208
331
|
# engine keeps it out of every committed output, and without the pattern Git
|
|
209
332
|
# would still offer to commit the file itself.
|
package/engine/ENGINE_SHA
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
6dcb00c874ff7a12df5b838d3391f2dd96b06df0
|
package/engine/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.25.1
|
|
@@ -34,6 +34,17 @@ agents_md_module_rel() {
|
|
|
34
34
|
printf '%s' "${IS_MODULE_REL:-.intelligence/packages/@ainova-systems/sync}"
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
# agents_md_link_var <repo_root> <path>: the link target AGENTS.md gives an
|
|
38
|
+
# artifact in IS_REPO_REL, "" for its bare name. The package store is ignored,
|
|
39
|
+
# so a link into .intelligence/ is dead in every clone before a sync and on the
|
|
40
|
+
# forge: store content is listed by name, like content outside the root.
|
|
41
|
+
agents_md_link_var() {
|
|
42
|
+
repo_rel_link_var "$1" "$2"
|
|
43
|
+
case "$IS_REPO_REL" in
|
|
44
|
+
.intelligence/*) IS_REPO_REL="" ;;
|
|
45
|
+
esac
|
|
46
|
+
}
|
|
47
|
+
|
|
37
48
|
# Append the static header block from config.yaml (or a fallback).
|
|
38
49
|
agents_md_append_header() {
|
|
39
50
|
local output="$1"
|
|
@@ -73,7 +84,7 @@ agents_md_append_agents_table() {
|
|
|
73
84
|
while IFS=$'\x1f' read -r path tier access desc; do
|
|
74
85
|
name="${names[i]}"
|
|
75
86
|
i=$((i + 1))
|
|
76
|
-
|
|
87
|
+
agents_md_link_var "$repo_root" "$path"
|
|
77
88
|
if [ -n "$IS_REPO_REL" ]; then
|
|
78
89
|
rows+="| [$name]($IS_REPO_REL) | ${tier:--} | ${access:--} | ${desc:--} |"$'\n'
|
|
79
90
|
else
|
|
@@ -118,7 +129,7 @@ agents_md_append_skills_table() {
|
|
|
118
129
|
while IFS=$'\x1f' read -r path desc; do
|
|
119
130
|
name="${names[i]}"
|
|
120
131
|
i=$((i + 1))
|
|
121
|
-
|
|
132
|
+
agents_md_link_var "$repo_root" "$path"
|
|
122
133
|
if [ -n "$IS_REPO_REL" ]; then
|
|
123
134
|
rows+="| [$name]($IS_REPO_REL) | ${desc:--} |"$'\n'
|
|
124
135
|
else
|
|
@@ -162,7 +173,7 @@ agents_md_append_rules_list() {
|
|
|
162
173
|
else
|
|
163
174
|
global_rule_files+=("$path")
|
|
164
175
|
fi
|
|
165
|
-
|
|
176
|
+
agents_md_link_var "$repo_root" "$path"
|
|
166
177
|
if [ -n "$IS_REPO_REL" ]; then
|
|
167
178
|
lines+="- [$name]($IS_REPO_REL) ($scope)"$'\n'
|
|
168
179
|
else
|
package/engine/adapters/codex.sh
CHANGED
|
@@ -88,12 +88,10 @@ sync_codex_override() {
|
|
|
88
88
|
i=$((i + 1))
|
|
89
89
|
done <<< "$rows"
|
|
90
90
|
fi
|
|
91
|
+
# Only the Codex section is finalized: AGENTS.md already is, and a second
|
|
92
|
+
# pass would expand the tokens its rules escaped.
|
|
93
|
+
local section=""
|
|
91
94
|
{
|
|
92
|
-
if [ -f "$agents_file" ]; then
|
|
93
|
-
cat "$agents_file"
|
|
94
|
-
else
|
|
95
|
-
printf '%s\n\n' "$CODEX_OVERRIDE_MARKER"
|
|
96
|
-
fi
|
|
97
95
|
echo "---"
|
|
98
96
|
echo ""
|
|
99
97
|
echo "## Codex Project Context"
|
|
@@ -108,6 +106,15 @@ sync_codex_override() {
|
|
|
108
106
|
[ "${#files[@]}" -eq 0 ] || emit_rule_bodies "${files[@]}"
|
|
109
107
|
} > "$override"
|
|
110
108
|
finalize_output_file "$override"
|
|
109
|
+
IFS= read -r -d '' section < "$override" || true
|
|
110
|
+
{
|
|
111
|
+
if [ -f "$agents_file" ]; then
|
|
112
|
+
cat "$agents_file"
|
|
113
|
+
else
|
|
114
|
+
printf '%s\n\n' "$CODEX_OVERRIDE_MARKER"
|
|
115
|
+
fi
|
|
116
|
+
printf '%s' "$section"
|
|
117
|
+
} > "$override"
|
|
111
118
|
for ((i = 0; i < ${#names[@]}; i++)); do
|
|
112
119
|
echo " rule: ${names[i]} (AGENTS.override.md)"
|
|
113
120
|
done
|
package/engine/adapters/pi.sh
CHANGED
|
@@ -39,8 +39,9 @@ adapter_contract_pi() {
|
|
|
39
39
|
|
|
40
40
|
# Fork-free TS string escape: sets IS_PI_TS_ESCAPED.
|
|
41
41
|
pi_ts_escape_var() {
|
|
42
|
-
local s
|
|
43
|
-
|
|
42
|
+
local s
|
|
43
|
+
token_keep_var "$1"
|
|
44
|
+
s="${IS_TOKEN_KEPT//\\/\\\\}"
|
|
44
45
|
s="${s//\"/\\\"}"
|
|
45
46
|
s="${s//$'\r'/}"
|
|
46
47
|
s="${s//$'\n'/ }"
|
|
@@ -109,7 +110,7 @@ pi_rule_body_rows() {
|
|
|
109
110
|
/^---$/ && !past_fm { in_fm = !in_fm; if (!in_fm) past_fm = 1; next }
|
|
110
111
|
!past_fm { next }
|
|
111
112
|
{
|
|
112
|
-
line = is_repl($0, "\\", "\\\\")
|
|
113
|
+
line = is_repl(fin_keep($0), "\\", "\\\\")
|
|
113
114
|
line = is_repl(line, "\"", "\\\"")
|
|
114
115
|
line = is_repl(line, "\t", "\\t")
|
|
115
116
|
B[++n] = line
|
package/engine/lib/common.sh
CHANGED
|
@@ -18,16 +18,34 @@ normalize_file_to_lf() {
|
|
|
18
18
|
#
|
|
19
19
|
# The content directory is named by the project (`intelligence/`,
|
|
20
20
|
# `Intelligence/`, a codename), so package-shipped artifacts cannot hardcode
|
|
21
|
-
# it. Layout-sensitive paths and commands use tokens expanded at output time
|
|
21
|
+
# it. Layout-sensitive paths and commands use tokens expanded at output time,
|
|
22
|
+
# in EVERY generated file, frontmatter and body alike, so a scoped rule reaches
|
|
23
|
+
# Claude's `paths:`, Cursor's `globs:` and Copilot's `applyTo:` already
|
|
24
|
+
# carrying the project's real folder name.
|
|
22
25
|
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
#
|
|
26
|
+
# IS_LAYOUT_TOKENS is the one declaration of them, a `<name> <variable>
|
|
27
|
+
# <default>` row per token: `<name>` renders as the value of <variable>, which
|
|
28
|
+
# the CLI derives from the detected layout (never hardcoded) and exports
|
|
29
|
+
# before any adapter runs, or as <default>, the rest of the row, while that
|
|
30
|
+
# variable is unset or empty. Expansion (fin_line), the backslash that keeps a
|
|
31
|
+
# token as written (fin_keep, token_keep_var) and the source lint that warns
|
|
32
|
+
# about a token reading as ordinary text (_IS_AWK_LINT) all derive from these
|
|
33
|
+
# rows, so a new token is one row here plus its entry in the reference tables
|
|
34
|
+
# (packages/sync/references/conventions.md and adapters.md). A name is
|
|
35
|
+
# lowercase letters, digits and `-`: it is spliced into awk text and a Bash
|
|
36
|
+
# pattern.
|
|
37
|
+
IS_LAYOUT_TOKENS=(
|
|
38
|
+
'content-dir IS_CONTENT_REL intelligence'
|
|
39
|
+
'module IS_MODULE_REL .intelligence/packages/@ainova-systems/sync'
|
|
40
|
+
'manifest IS_MANIFEST_NAME intelligence.yaml'
|
|
41
|
+
'sync-cmd IS_SYNC_CMD intelligence sync'
|
|
42
|
+
)
|
|
43
|
+
IS_LAYOUT_NAMES=()
|
|
44
|
+
_is_names=""
|
|
45
|
+
for _is_row in "${IS_LAYOUT_TOKENS[@]}"; do
|
|
46
|
+
IS_LAYOUT_NAMES+=("${_is_row%% *}")
|
|
47
|
+
_is_names="$_is_names${_is_names:+ }${_is_row%% *}"
|
|
48
|
+
done
|
|
31
49
|
|
|
32
50
|
# Process spawns dominate sync time on Git Bash for Windows: one fork costs
|
|
33
51
|
# tens of milliseconds against ~1ms on Linux, so a helper that runs awk per
|
|
@@ -39,8 +57,10 @@ normalize_file_to_lf() {
|
|
|
39
57
|
#
|
|
40
58
|
# fin_line() uses literal (index-based) substitution, not gsub: a regex
|
|
41
59
|
# replacement would give `&` in a path its special meaning, and POSIX awk has
|
|
42
|
-
# no way to pass a replacement string verbatim.
|
|
43
|
-
#
|
|
60
|
+
# no way to pass a replacement string verbatim. The token names are part of
|
|
61
|
+
# the program text, so fin_keep works in every program that includes this
|
|
62
|
+
# library; the values are read in BEGIN from the environment variables that
|
|
63
|
+
# is_fin_awk_vars fills and names in IS_FIN_V.
|
|
44
64
|
IS_AWK_LIB='
|
|
45
65
|
function is_repl(s, from, to, out, i) {
|
|
46
66
|
out = ""
|
|
@@ -50,11 +70,36 @@ IS_AWK_LIB='
|
|
|
50
70
|
}
|
|
51
71
|
return out s
|
|
52
72
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
73
|
+
# FIN_TOK[k] is the k-th token of IS_LAYOUT_TOKENS, FIN_VAL[k] its value,
|
|
74
|
+
# FIN_ESC[k] the token escaped and FIN_HOLD[k] what fin_keep turns that into.
|
|
75
|
+
BEGIN {
|
|
76
|
+
FIN_N = split("'"$_is_names"'", is_tn, " ")
|
|
77
|
+
for (is_tk = 1; is_tk <= FIN_N; is_tk++) {
|
|
78
|
+
FIN_TOK[is_tk] = "<" is_tn[is_tk] ">"
|
|
79
|
+
FIN_ESC[is_tk] = "\\" FIN_TOK[is_tk]
|
|
80
|
+
FIN_HOLD[is_tk] = "\034" is_tn[is_tk] ">"
|
|
81
|
+
if (FIN_ENV != "") FIN_VAL[is_tk] = ENVIRON[FIN_ENV is_tk]
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
# A backslash keeps a token as written: `\<module>` renders as `<module>`.
|
|
85
|
+
# The escaped token waits on a control character while the others expand.
|
|
86
|
+
# A writer that doubles backslashes for YAML or TOML calls fin_keep (or
|
|
87
|
+
# token_keep_var) first: once escaped, `\\<module>` no longer reads as one.
|
|
88
|
+
function fin_keep(s, k) {
|
|
89
|
+
if (!index(s, "\\<")) return s
|
|
90
|
+
for (k = 1; k <= FIN_N; k++) s = is_repl(s, FIN_ESC[k], FIN_HOLD[k])
|
|
91
|
+
return s
|
|
92
|
+
}
|
|
93
|
+
# Every line of every rendered file passes here, and most hold no `<`, so
|
|
94
|
+
# those skip the token loop. Tokens expand from the last declared to the
|
|
95
|
+
# first, the order the engine has always used: a value that itself holds a
|
|
96
|
+
# token renders as it always did.
|
|
97
|
+
function fin_line(s, k) {
|
|
98
|
+
if (index(s, "<")) {
|
|
99
|
+
s = fin_keep(s)
|
|
100
|
+
for (k = FIN_N; k > 0; k--) s = is_repl(s, FIN_TOK[k], FIN_VAL[k])
|
|
101
|
+
}
|
|
102
|
+
if (index(s, "\034")) s = is_repl(s, "\034", "<")
|
|
58
103
|
return s
|
|
59
104
|
}
|
|
60
105
|
function fm_value_strip(val, n, first, last) {
|
|
@@ -112,17 +157,28 @@ IS_AWK_LIB='
|
|
|
112
157
|
return 1
|
|
113
158
|
}
|
|
114
159
|
'
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
#
|
|
118
|
-
#
|
|
160
|
+
unset _is_row _is_names
|
|
161
|
+
|
|
162
|
+
# is_fin_awk_vars — export each token's value as IS_LAYOUT_VALUE_<k>, <k> its
|
|
163
|
+
# row in IS_LAYOUT_TOKENS, and set the global IS_FIN_V to the -v binding that
|
|
164
|
+
# points IS_AWK_LIB at those variables; a program run without IS_FIN_V
|
|
165
|
+
# expands every token to nothing, as it always did. The values travel through
|
|
166
|
+
# the environment, which awk reads verbatim: a -v value has its backslashes
|
|
167
|
+
# read as escapes, and BSD awk refuses one that holds a newline. One variable
|
|
168
|
+
# per token, so no byte a value holds can split it into two. Rebuilt on every
|
|
169
|
+
# call: the IS_* env contract is exported after this file is sourced, and a
|
|
170
|
+
# caller may set one variable for a single call.
|
|
119
171
|
is_fin_awk_vars() {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
172
|
+
local row rest var def k=0
|
|
173
|
+
for row in "${IS_LAYOUT_TOKENS[@]}"; do
|
|
174
|
+
rest="${row#* }"
|
|
175
|
+
var="${rest%% *}"
|
|
176
|
+
def=""
|
|
177
|
+
case "$rest" in *' '*) def="${rest#* }" ;; esac
|
|
178
|
+
k=$((k + 1))
|
|
179
|
+
export "IS_LAYOUT_VALUE_$k=${!var:-$def}"
|
|
180
|
+
done
|
|
181
|
+
IS_FIN_V=(-v FIN_ENV=IS_LAYOUT_VALUE_)
|
|
126
182
|
}
|
|
127
183
|
|
|
128
184
|
# finalize_output_files <file>...
|
|
@@ -288,12 +344,28 @@ frontmatter_index() {
|
|
|
288
344
|
' "$@"
|
|
289
345
|
}
|
|
290
346
|
|
|
347
|
+
# token_keep_var <s> — fin_keep for the shell escapers below, whose output
|
|
348
|
+
# fin_line finalizes later: an escaped layout token gives up its backslash
|
|
349
|
+
# before they double backslashes. Sets IS_TOKEN_KEPT.
|
|
350
|
+
token_keep_var() {
|
|
351
|
+
local s="$1" fs=$'\034' t
|
|
352
|
+
case "$s" in
|
|
353
|
+
*'\<'*)
|
|
354
|
+
for t in "${IS_LAYOUT_NAMES[@]}"; do
|
|
355
|
+
s="${s//\\<$t>/$fs$t>}"
|
|
356
|
+
done
|
|
357
|
+
;;
|
|
358
|
+
esac
|
|
359
|
+
IS_TOKEN_KEPT="$s"
|
|
360
|
+
}
|
|
361
|
+
|
|
291
362
|
# Escape a string for safe interpolation into a TOML basic string ("..").
|
|
292
363
|
# Backslash and double-quote are escaped; control chars stripped.
|
|
293
364
|
# Fork-free form: sets IS_TOML_ESCAPED; the printing form wraps it.
|
|
294
365
|
toml_escape_var() {
|
|
295
|
-
local s
|
|
296
|
-
|
|
366
|
+
local s
|
|
367
|
+
token_keep_var "$1"
|
|
368
|
+
s="${IS_TOKEN_KEPT//\\/\\\\}"
|
|
297
369
|
s="${s//\"/\\\"}"
|
|
298
370
|
# Strip any literal newline / carriage return — TOML basic strings
|
|
299
371
|
# do not allow them; multi-line content belongs in `"""..."""`.
|
|
@@ -310,8 +382,9 @@ toml_escape() {
|
|
|
310
382
|
# Escape a string for safe interpolation into a YAML double-quoted scalar.
|
|
311
383
|
# Fork-free form: sets IS_YAML_ESCAPED; the printing form wraps it.
|
|
312
384
|
yaml_dq_escape_var() {
|
|
313
|
-
local s
|
|
314
|
-
|
|
385
|
+
local s
|
|
386
|
+
token_keep_var "$1"
|
|
387
|
+
s="${IS_TOKEN_KEPT//\\/\\\\}"
|
|
315
388
|
s="${s//\"/\\\"}"
|
|
316
389
|
s="${s//$'\n'/ }"
|
|
317
390
|
s="${s//$'\r'/}"
|
|
@@ -469,7 +542,7 @@ emit_wrapped_bodies() {
|
|
|
469
542
|
else if (!past_fm) next
|
|
470
543
|
line = $0
|
|
471
544
|
if (ESC[cur] == "toml") {
|
|
472
|
-
line = is_repl(line, "\\", "\\\\")
|
|
545
|
+
line = is_repl(fin_keep(line), "\\", "\\\\")
|
|
473
546
|
line = is_repl(line, "\"\"\"", "\"\"\\\"")
|
|
474
547
|
}
|
|
475
548
|
body[++body_n] = line
|
|
@@ -514,13 +587,15 @@ emit_rule_bodies() {
|
|
|
514
587
|
# When wrapping an unquoted value, literal `\` and `"` inside it are escaped
|
|
515
588
|
# (`\\`, `\"`) so an inner quote — e.g. `Use as a quick "what do we have" view`
|
|
516
589
|
# — cannot prematurely terminate the generated double-quoted scalar. Values the
|
|
517
|
-
# author already wrapped (in `"` or `'`) pass through untouched.
|
|
590
|
+
# author already wrapped (in `"` or `'`) pass through untouched. An escaped
|
|
591
|
+
# layout token is resolved first (fin_keep), so <dst> still needs
|
|
592
|
+
# finalize_output_file, as every emitted file does.
|
|
518
593
|
#
|
|
519
594
|
# Usage: copy_md_with_quoted_frontmatter "src.md" "dst.md"
|
|
520
595
|
copy_md_with_quoted_frontmatter() {
|
|
521
596
|
local src="$1"
|
|
522
597
|
local dst="$2"
|
|
523
|
-
awk '
|
|
598
|
+
awk "$IS_AWK_LIB"'
|
|
524
599
|
function yamlq(s, out, i, c) {
|
|
525
600
|
out = ""
|
|
526
601
|
for (i = 1; i <= length(s); i++) {
|
|
@@ -550,7 +625,7 @@ copy_md_with_quoted_frontmatter() {
|
|
|
550
625
|
first = substr(val, 1, 1)
|
|
551
626
|
last = substr(val, length(val), 1)
|
|
552
627
|
if ((first == "\"" && last == "\"") || (first == "\047" && last == "\047")) { print; next }
|
|
553
|
-
print key ": \"" yamlq(val) "\""
|
|
628
|
+
print key ": \"" yamlq(fin_keep(val)) "\""
|
|
554
629
|
next
|
|
555
630
|
}
|
|
556
631
|
state == "after" { print }
|
|
@@ -832,7 +907,7 @@ _skill_bundles_flush() {
|
|
|
832
907
|
first = substr(val, 1, 1)
|
|
833
908
|
last = substr(val, length(val), 1)
|
|
834
909
|
if (!((first == "\"" && last == "\"") || (first == "\047" && last == "\047"))) {
|
|
835
|
-
$0 = key ": \"" yamlq(val) "\""
|
|
910
|
+
$0 = key ": \"" yamlq(fin_keep(val)) "\""
|
|
836
911
|
}
|
|
837
912
|
}
|
|
838
913
|
}
|
|
@@ -1072,6 +1147,9 @@ enforce_authored_invocation_policies() {
|
|
|
1072
1147
|
# warning names the source exactly once however many tools render it. Unlike
|
|
1073
1148
|
# the lint notes it is an unindented `WARNING:` line, because `sync --compact`
|
|
1074
1149
|
# (and so `init`) keeps only those (decision 0015).
|
|
1150
|
+
# This form takes no repository root, so its warnings name each file as the
|
|
1151
|
+
# caller passed it; the engine's pass, source_frontmatter_scan, names it
|
|
1152
|
+
# relative to the root.
|
|
1075
1153
|
# Usage: lint_frontmatter_files "a.md" "b.md" ...
|
|
1076
1154
|
lint_frontmatter_files() {
|
|
1077
1155
|
[ "$#" -gt 0 ] || return 0
|
|
@@ -1080,7 +1158,10 @@ lint_frontmatter_files() {
|
|
|
1080
1158
|
|
|
1081
1159
|
# The lint rules, shared with source_frontmatter_scan, which runs them in the
|
|
1082
1160
|
# same pass that reads routing fields. Every rule may end with `next`, so a
|
|
1083
|
-
# program that joins them puts its own rules first.
|
|
1161
|
+
# program that joins them puts its own rules first. Every warning names the
|
|
1162
|
+
# source as lint_src: relative to ENVIRON["IS_LINT_ROOT"] when the file lies
|
|
1163
|
+
# under it, so a warning reads the same from any checkout, from the private
|
|
1164
|
+
# copy `sync --check` renders in, and in the replay of an unchanged sync.
|
|
1084
1165
|
_IS_AWK_LINT='
|
|
1085
1166
|
BEGIN {
|
|
1086
1167
|
nl = split(levels, LV, " ")
|
|
@@ -1089,9 +1170,40 @@ _IS_AWK_LINT='
|
|
|
1089
1170
|
LEVEL[LV[li]] = 1
|
|
1090
1171
|
allowed = allowed (li > 1 ? ", " : "") LV[li]
|
|
1091
1172
|
}
|
|
1173
|
+
lint_root = ENVIRON["IS_LINT_ROOT"]
|
|
1174
|
+
}
|
|
1175
|
+
# A layout token that cannot mean what it renders as: joined to a word
|
|
1176
|
+
# or a path around it, or an XML element closed on the same line. A
|
|
1177
|
+
# module-name placeholder `<module>_update_N` rendered as the package
|
|
1178
|
+
# path. Packages use tokens by design, so only project sources (under
|
|
1179
|
+
# the root, outside its package store) are read, and an escaped token
|
|
1180
|
+
# (`\<module>`) is literal. The tokens are FIN_TOK from IS_AWK_LIB.
|
|
1181
|
+
function tok_check(l, k, t, n, at, p, b, a) {
|
|
1182
|
+
for (k = 1; k <= FIN_N; k++) {
|
|
1183
|
+
t = FIN_TOK[k]; n = length(t); at = 0
|
|
1184
|
+
while ((p = index(substr(l, at + 1), t)) > 0) {
|
|
1185
|
+
at += p
|
|
1186
|
+
b = (at > 1) ? substr(l, at - 1, 1) : ""
|
|
1187
|
+
a = substr(l, at + n, 2)
|
|
1188
|
+
at += n - 1
|
|
1189
|
+
if (b == "\\") continue
|
|
1190
|
+
if (b ~ /[[:alnum:]_]/ || b == "/" || a ~ /^([[:alnum:]_-]|[.][[:alnum:]_])/ \
|
|
1191
|
+
|| index(l, "</" substr(t, 2))) {
|
|
1192
|
+
printf "WARNING: %s:%d %s is part of the text around it, but sync renders this layout token as %s; write \\%s to keep it as written\n", \
|
|
1193
|
+
lint_src, FNR, t, FIN_VAL[k], t > "/dev/stderr"
|
|
1194
|
+
break
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
FNR == 1 {
|
|
1200
|
+
in_fm = 0; done = 0; effort_seen = 0
|
|
1201
|
+
lint_under = lint_root != "" && index(FILENAME, lint_root "/") == 1
|
|
1202
|
+
lint_src = lint_under ? substr(FILENAME, length(lint_root) + 2) : FILENAME
|
|
1203
|
+
tok_own = lint_under && index(FILENAME, lint_root "/.intelligence/") != 1
|
|
1092
1204
|
}
|
|
1093
|
-
FNR == 1 { in_fm = 0; done = 0; effort_seen = 0 }
|
|
1094
1205
|
{ sub(/\r$/, "") }
|
|
1206
|
+
tok_own && index($0, ">") { tok_check($0) }
|
|
1095
1207
|
done { next }
|
|
1096
1208
|
FNR == 1 && $0 != "---" { done = 1; next }
|
|
1097
1209
|
FNR == 1 { in_fm = 1; next }
|
|
@@ -1099,11 +1211,11 @@ _IS_AWK_LINT='
|
|
|
1099
1211
|
in_fm && substr($0, 1, 7) == "effort:" && !effort_seen++ {
|
|
1100
1212
|
effort = fm_value_strip(substr($0, 8))
|
|
1101
1213
|
if (effort != "" && !(effort in LEVEL)) {
|
|
1102
|
-
printf "WARNING: %s:%d effort \"%s\" is not one of %s — ignored, so no tool receives an effort from this file\n",
|
|
1214
|
+
printf "WARNING: %s:%d effort \"%s\" is not one of %s — ignored, so no tool receives an effort from this file\n", lint_src, FNR, effort, allowed > "/dev/stderr"
|
|
1103
1215
|
}
|
|
1104
1216
|
}
|
|
1105
1217
|
in_fm && /^\t/ {
|
|
1106
|
-
printf "WARNING: %s:%d leading tab in frontmatter (use spaces)\n",
|
|
1218
|
+
printf "WARNING: %s:%d leading tab in frontmatter (use spaces)\n", lint_src, FNR > "/dev/stderr"
|
|
1107
1219
|
}
|
|
1108
1220
|
in_fm && /^[a-zA-Z0-9_-]+:[[:space:]]+[^"\047|>[{]/ {
|
|
1109
1221
|
value_start = index($0, ":") + 1
|
|
@@ -1111,10 +1223,10 @@ _IS_AWK_LINT='
|
|
|
1111
1223
|
sub(/^[[:space:]]+/, "", value)
|
|
1112
1224
|
if (value ~ /:[[:space:]]/ || value ~ /:$/) {
|
|
1113
1225
|
col = index(value, ":") + value_start
|
|
1114
|
-
printf "WARNING: %s:%d unquoted colon in value at column %d — wrap value in quotes\n",
|
|
1226
|
+
printf "WARNING: %s:%d unquoted colon in value at column %d — wrap value in quotes\n", lint_src, FNR, col > "/dev/stderr"
|
|
1115
1227
|
}
|
|
1116
1228
|
if (value ~ /"/) {
|
|
1117
|
-
printf "WARNING: %s:%d literal double quote in unquoted value — wrap value in single quotes or escape as \\\" so strict-YAML targets accept it\n",
|
|
1229
|
+
printf "WARNING: %s:%d literal double quote in unquoted value — wrap value in single quotes or escape as \\\" so strict-YAML targets accept it\n", lint_src, FNR > "/dev/stderr"
|
|
1118
1230
|
}
|
|
1119
1231
|
}
|
|
1120
1232
|
# Field-length limits. Both Claude Code and the Agent Skills standard
|
|
@@ -1133,7 +1245,7 @@ _IS_AWK_LINT='
|
|
|
1133
1245
|
}
|
|
1134
1246
|
limit = (key == "name") ? 64 : 1024
|
|
1135
1247
|
if (length(val) > limit) {
|
|
1136
|
-
printf "WARNING: %s:%d %s is %d chars — over the %d-char limit; the skill/agent will be REJECTED at load time\n",
|
|
1248
|
+
printf "WARNING: %s:%d %s is %d chars — over the %d-char limit; the skill/agent will be REJECTED at load time\n", lint_src, FNR, key, length(val), limit > "/dev/stderr"
|
|
1137
1249
|
}
|
|
1138
1250
|
}
|
|
1139
1251
|
'
|
|
@@ -2442,7 +2554,7 @@ source_catalog_build() {
|
|
|
2442
2554
|
# One pass reads what routing needs from every source's frontmatter
|
|
2443
2555
|
# and, for the engine, lints it. Captured, not streamed: a short answer
|
|
2444
2556
|
# must stop the run, not route the files it lost as always-on.
|
|
2445
|
-
rows="$(source_frontmatter_scan "$lint" "${files[@]}")" || {
|
|
2557
|
+
rows="$(source_frontmatter_scan "${lint:+$repo_root}" "${files[@]}")" || {
|
|
2446
2558
|
echo "ERROR: cannot read the frontmatter of the sources — refusing to render a partial list." >&2
|
|
2447
2559
|
exit 1
|
|
2448
2560
|
}
|
|
@@ -2466,20 +2578,23 @@ source_catalog_build() {
|
|
|
2466
2578
|
[ "${IS_SOURCE_FILES_MEMO:-0}" != 1 ] || IS_CAT_KEY="$key"
|
|
2467
2579
|
}
|
|
2468
2580
|
|
|
2469
|
-
# source_frontmatter_scan <lint> <file>...
|
|
2581
|
+
# source_frontmatter_scan <lint-root> <file>... - one row per file in argument
|
|
2470
2582
|
# order, \x1f-separated: the path; its `paths:` line count, read with
|
|
2471
2583
|
# frontmatter_index's `paths#` semantics; then for `targets:` and for
|
|
2472
2584
|
# `exclude_targets:` whether it is set and its ids, space-separated. Both take
|
|
2473
2585
|
# the list syntax `paths:` takes — a block list or a flow list `[a, b]`, items
|
|
2474
2586
|
# optionally quoted — and a bare value is a one-item list. The first
|
|
2475
2587
|
# occurrence of a key wins, and a key with no value at all is not set
|
|
2476
|
-
# (`targets: []` is: it is the empty list). With <lint
|
|
2477
|
-
# runs lint_frontmatter_files over every file
|
|
2588
|
+
# (`targets: []` is: it is the empty list). With <lint-root>, the repository
|
|
2589
|
+
# root, the same pass runs lint_frontmatter_files over every file and the
|
|
2590
|
+
# layout-token check over the project's own; warnings go to stderr and name
|
|
2591
|
+
# each source relative to that root.
|
|
2478
2592
|
source_frontmatter_scan() {
|
|
2479
|
-
local do_lint=0
|
|
2480
|
-
[ "$
|
|
2593
|
+
local do_lint=0 root="$1"
|
|
2594
|
+
[ -z "$root" ] || do_lint=1
|
|
2481
2595
|
shift
|
|
2482
|
-
|
|
2596
|
+
is_fin_awk_vars
|
|
2597
|
+
IS_LINT_ROOT="$root" awk -v levels="$IS_EFFORT_LEVELS" -v do_lint="$do_lint" "${IS_FIN_V[@]}" "$IS_AWK_LIB"'
|
|
2483
2598
|
BEGIN { SX_US = sprintf("%c", 31) }
|
|
2484
2599
|
function sx_items(s, k, parts, m, j, v, q) {
|
|
2485
2600
|
m = split(s, parts, ",")
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ainova-systems/intelligence",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.1",
|
|
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"
|
|
@@ -42,7 +42,7 @@ To stop syncing a target:
|
|
|
42
42
|
intelligence adapter disable mytool
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
-
Disabling changes only target state. Generated output is deliberately kept so disabling is reversible; the adapter contract identifies its paths for review. 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.
|
|
45
|
+
Disabling changes only target state. Generated output is deliberately kept so disabling is reversible; the adapter contract identifies its paths for review, and `intelligence status --check` names the owned paths still on disk and the `intelligence-manage-adapters` skill that removes 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
46
|
|
|
47
47
|
## Required interface
|
|
48
48
|
|
|
@@ -218,7 +218,7 @@ Intelligence routes always-on rules once through `AGENTS.md` for tools that cons
|
|
|
218
218
|
|
|
219
219
|
| Built-in | Always-on rules | Always-on, not in `AGENTS.md` | Scoped rules |
|
|
220
220
|
|---|---|---|---|
|
|
221
|
-
| `agents` | Inline in `AGENTS.md` |
|
|
221
|
+
| `agents` | Inline in `AGENTS.md` | None | List with links; package and out-of-tree content by name |
|
|
222
222
|
| `antigravity` | Omit; reads `AGENTS.md` | `.agents/rules/*.md` with `trigger: always_on` | `.agents/rules/*.md` with `trigger: glob` and `globs:` |
|
|
223
223
|
| `claude` | Copy | Copy | Copy with `paths:` preserved |
|
|
224
224
|
| `cursor` | Omit; reads `AGENTS.md` | `.mdc` with `alwaysApply: true` | `.mdc` with `globs:` |
|
|
@@ -305,7 +305,7 @@ Content shipped in `@ainova-systems/sync` cannot assume the project's content-di
|
|
|
305
305
|
| `<manifest>` | `intelligence.yaml` |
|
|
306
306
|
| `<sync-cmd>` | `intelligence sync` |
|
|
307
307
|
|
|
308
|
-
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.
|
|
308
|
+
Call `finalize_output_file` on every text file after transformation. It expands the tokens literally, keeps a token escaped with a backslash as written ([Layout tokens](conventions.md#layout-tokens)), and converts CRLF to LF. A generated file containing an unexpanded token is an adapter bug.
|
|
309
309
|
|
|
310
310
|
`copy_skill_bundle` already finalizes Markdown within a skill; do not run a second custom token pass.
|
|
311
311
|
|
|
@@ -142,6 +142,8 @@ Expansion applies to frontmatter and bodies. Thus `paths: ["<content-dir>/**"]`
|
|
|
142
142
|
|
|
143
143
|
Project-authored artifacts normally use their known project paths directly. Tokens are useful only when the same artifact must work under different content-directory or package-store locations.
|
|
144
144
|
|
|
145
|
+
The four tokens are reserved in every source, so a placeholder that means something else, such as a module name, needs a backslash: `\<module>` renders as `<module>`. Sync prints a `WARNING:` line with the file and line when a project source holds a token joined to the text around it (`<module>_update_N`, `modules/<module>.md`) or used as an XML element closed on the same line (`<manifest></manifest>`).
|
|
146
|
+
|
|
145
147
|
## Naming
|
|
146
148
|
|
|
147
149
|
Rule filenames, agent names and skill names share a domain prefix such as `backend-`, `frontend-`, `devops-`, `core-`, `tests-`, a project codename or a monorepo component. Pick the domain from repository structure and reuse it.
|
|
@@ -251,7 +253,7 @@ Skills take the same field. `.claude/skills/` receives Claude's level, the share
|
|
|
251
253
|
|
|
252
254
|
### Access mappings
|
|
253
255
|
|
|
254
|
-
`access: full` inherits ordinary tool permissions. `access: readonly` is transformed into the target's native restriction
|
|
256
|
+
`access: full` inherits ordinary tool permissions. `access: readonly` is transformed into the target's native restriction, and the targets differ on commands. Claude keeps `Bash` beside its read and search tools, with `Write` and `Edit` disallowed. Cursor receives `readonly: true`, which its documentation says blocks edits and state-changing shell commands. Copilot, OpenCode and Antigravity receive read and search tools only, and Pi receives the restriction as an instruction. Codex receives `sandbox_mode = "read-only"`, which its [subagent documentation](https://learn.chatgpt.com/docs/agent-configuration/subagents) says a custom agent file cannot set, so a Codex agent runs in the parent session's sandbox.
|
|
255
257
|
|
|
256
258
|
Use only `full` or `readonly` in source agents. Tool-specific permission syntax belongs in adapters.
|
|
257
259
|
|
|
@@ -283,7 +285,7 @@ Rule content in Markdown.
|
|
|
283
285
|
| Always-on | copied | omitted | omitted | omitted | inlined once into `AGENTS.md` |
|
|
284
286
|
| Always-on, not in `AGENTS.md` | copied | `.mdc` with `alwaysApply: true` | `.md` with `trigger: always_on` | `.instructions.md` with `applyTo: "**"` | Codex: `AGENTS.override.md`; Pi: added to the system prompt by its extension; OpenCode: none |
|
|
285
287
|
|
|
286
|
-
Cursor, Copilot, Codex, Pi, OpenCode and Antigravity consume `AGENTS.md`, so always-on rules are not duplicated in their tool-specific channels. Claude
|
|
288
|
+
Cursor, Copilot, Codex, Pi, OpenCode and Antigravity consume `AGENTS.md`, so always-on rules are not duplicated in their tool-specific channels. Claude receives the full rule set in `.claude/rules/`. Claude Code 2.1.277 and later also reads `AGENTS.md` when no `CLAUDE.md`, `.claude/CLAUDE.md` or `CLAUDE.local.md` exists in the working directory or above it ([memory docs](https://code.claude.com/docs/en/memory#agents-md)), so the always-on rules load twice until `.claude/settings.json` carries `"claudeMdExcludes": ["**/AGENTS.md"]`. Sync never edits that file; `intelligence status --check` prints the entry when it is missing. Codex's override lists scoped patterns and source links with an instruction to read matching rules on demand; this depends on the model following the instruction, not native glob-triggered loading. OpenCode users may configure `instructions:` globs themselves. See [adapter routing](adapters.md#rules) for delivery details.
|
|
287
289
|
|
|
288
290
|
An always-on rule `AGENTS.md` does not carry — a local one, or one whose set leaves `agents` out (see [Selecting adapters](#selecting-adapters)) — reaches each tool in its set through that tool's own channel instead, the last row. Codex reads `AGENTS.override.md` instead of `AGENTS.md` in the same directory, so the file holds the whole `AGENTS.md` plus scoped routing and additional always-on rules; it is ignored, exists while either needs it, and one Intelligence did not generate is never touched. Antigravity's `trigger: always_on` belongs to the same undocumented key family as its `trigger: glob`. OpenCode reads instructions only from `AGENTS.md` or its committed `opencode.json`, so it can receive neither a local nor a tool-targeted always-on rule.
|
|
289
291
|
|
|
@@ -308,9 +310,15 @@ argument-hint: "<route-name>"
|
|
|
308
310
|
4. Report the changed route and verification.
|
|
309
311
|
```
|
|
310
312
|
|
|
311
|
-
Standard optional fields (`license`, `compatibility`, `metadata`, `allowed-tools`) and tool extensions pass through unchanged.
|
|
313
|
+
Standard optional fields (`license`, `compatibility`, `metadata`, `allowed-tools`) and tool extensions pass through unchanged. `effort:` is the exception: sync renders it per tool, as [Effort mappings](#effort-mappings) describes. `targets:` and `exclude_targets:` select the adapters that receive the skill and are removed from every copy ([Selecting adapters](#selecting-adapters)).
|
|
314
|
+
|
|
315
|
+
`disable-model-invocation: true` makes a skill one only a person starts, as a slash command. The flag hides the procedure, not the act: Claude Code keeps the skill's description out of the model's context, so a request in words such as "commit this" never reaches the skill and is carried out without its checks. Keep the flag for a skill that starts a named person's decision, such as approving a plan, moving versions or changing adapters; the person typing the command after seeing what it acts on is the yes, so the skill does not ask again. A skill with side effects stays model-invocable, and its description names the requests that should reach it.
|
|
316
|
+
|
|
317
|
+
Claude Code, Cursor, Copilot, OpenCode and Pi read the field itself; Codex does not, so sync writes `agents/openai.yaml` with `allow_implicit_invocation: false` beside the skill in `.agents/skills/`. Keep the source to the field. A skill that ships its own `agents/openai.yaml` keeps everything else in it: sync adds the policy when the file sets none, and refuses one that sets it otherwise or not as a plain `allow_implicit_invocation: false` directly under `policy:`.
|
|
312
318
|
|
|
313
|
-
`
|
|
319
|
+
`context: fork`, `agent`, `background` and `model` are Claude Code fields, and sync copies them unchanged. A forked skill runs as a subagent of the `agent` type that receives the skill as its prompt, sees none of the conversation and has no `AskUserQuestion` tool. In an interactive session it runs in the background by default, so the caller's turn goes on before the result arrives, and a skill whose result its caller needs in the same turn sets `background: false` ([skills](https://code.claude.com/docs/en/skills#run-skills-in-a-subagent), [subagents](https://code.claude.com/docs/en/sub-agents#available-tools)). Without `context: fork`, `agent` selects nothing, and `model` switches the session's model for the rest of the turn, which then re-reads the whole conversation without the prompt cache ([prompt caching](https://code.claude.com/docs/en/prompt-caching#switching-models)). Of the other targets, only Copilot in VS Code documents `context: fork`, as experimental, and none documents `agent`, `background` or `model` for a skill (checked 2026-11-07).
|
|
320
|
+
|
|
321
|
+
Fork a skill whose inputs are files and arguments, that asks nothing on the way, and whose work is heavy reading, auditing or judging: the caller's context stays small and the work gets an independent reader. Keep a skill inline, with no `agent`, when its input is the conversation or its job is a dialogue or an approval with the person. A forked skill never asks. When it reaches a decision that belongs to the person, it stops before the write and ends its result with the decision, the options and its recommendation, so the caller asks.
|
|
314
322
|
|
|
315
323
|
These limits reject a skill instead of degrading it:
|
|
316
324
|
|
|
@@ -351,14 +359,15 @@ The engine copies the complete skill directory. Promote a helper outside the ski
|
|
|
351
359
|
|
|
352
360
|
A symlink inside a skills source renders as the file or directory it points at when that stays inside the same source, so one source can alias a skill or share a resource between skills. A link that leaves its source, dangles or points at a directory enclosing it is left out with a `WARNING:` line; a skill whose directory or `SKILL.md` is such a link is left out entirely. Add a skill kept elsewhere as its own source or package instead of linking it in. Generated skill directories never contain symlinks.
|
|
353
361
|
|
|
354
|
-
Size limits are backstops, not quotas:
|
|
362
|
+
Size limits are backstops, not quotas. They count words, because a paragraph written as one long line passes any line cap:
|
|
355
363
|
|
|
356
|
-
| Artifact |
|
|
364
|
+
| Artifact | Budget | Response |
|
|
357
365
|
|---|---|---|
|
|
358
|
-
| `SKILL.md`
|
|
359
|
-
| Reference file |
|
|
360
|
-
| Rule |
|
|
361
|
-
| Agent |
|
|
366
|
+
| `SKILL.md` | 1,500 words | Move detail to `references/` |
|
|
367
|
+
| Reference file | 3,000 words | Add a contents list past 1,500; split if still oversized |
|
|
368
|
+
| Rule | 2,000 words | Split by scope or move examples behind a skill reference |
|
|
369
|
+
| Agent | 500 words | Move procedures and constraints into skills/rules |
|
|
370
|
+
| Paragraph, list item or table row | 150 words | Split it into the thoughts it holds |
|
|
362
371
|
|
|
363
372
|
## Writing discipline
|
|
364
373
|
|
|
@@ -448,6 +457,8 @@ targets:
|
|
|
448
457
|
|
|
449
458
|
`AGENTS.md` stays committed by default: it is the tool-neutral fallback every tool reads, and a fresh clone has it only when it is committed, before anyone has synced.
|
|
450
459
|
|
|
460
|
+
Claude Code loads project skills from the checkout a session starts in, and from 2.1.277 a Git worktree without its own `.claude/skills`, such as one not yet synced, gets the main checkout's ([skills docs](https://code.claude.com/docs/en/skills#load-skills-in-monorepos-and-subdirectories)), so a task in a worktree runs in a session started there after `intelligence sync` there.
|
|
461
|
+
|
|
451
462
|
Git tracking and release packaging are separate policies. When a project
|
|
452
463
|
already has `.vscodeignore`, `.npmignore`, or `.dockerignore`, the CLI appends a
|
|
453
464
|
small idempotent block excluding the package store, `intelligence.yaml`,
|
|
@@ -21,7 +21,7 @@ Three ways to shorten, in order of what they are worth:
|
|
|
21
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
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
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.
|
|
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. The same holds inside an artifact: a fix restates the outcome once, and a clause added for each edge case or review finding is itself the defect.
|
|
25
25
|
|
|
26
26
|
## Source of truth
|
|
27
27
|
|
|
@@ -60,7 +60,7 @@ The mistakes that actually happen, in order of frequency:
|
|
|
60
60
|
|
|
61
61
|
### Invariants
|
|
62
62
|
|
|
63
|
-
- **Never state behaviour of a tool or engine you have not verified in its documentation or source.** An unverified claim about tooling is worse than a gap: nothing in the repository contradicts it, so it silently reshapes every decision downstream. Verified means a page you can cite - for how rules load, the Claude Code docs
|
|
63
|
+
- **Never state behaviour of a tool or engine you have not verified in its documentation or source.** An unverified claim about tooling is worse than a gap: nothing in the repository contradicts it, so it silently reshapes every decision downstream. Verified means a page you can cite - for how rules load, the Claude Code [memory](https://code.claude.com/docs/en/memory#organize-rules-with-claude/rules/) and [subagent startup](https://code.claude.com/docs/en/sub-agents#what-loads-at-startup) docs.
|
|
64
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
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
66
|
|
|
@@ -68,7 +68,7 @@ The mistakes that actually happen, in order of frequency:
|
|
|
68
68
|
|
|
69
69
|
An agent is **thin**: who it is, where it stops, how it verifies. Nothing else.
|
|
70
70
|
|
|
71
|
-
- **Do not list rules for an agent to read.** They load on their own
|
|
71
|
+
- **Do not list rules for an agent to read.** They load on their own: a Claude Code subagent starts with the project's instruction files, `.claude/rules/` included, unless it is the built-in Explore or Plan agent or its definition sets `omitClaudeMd`, and Cursor, Copilot, Codex, Pi, OpenCode and Antigravity receive always-on rules inlined in `AGENTS.md`. A step handed to an agent that starts without them names the rules it depends on in the delegation message. Naming a rule is fine; copying it is duplication that drifts.
|
|
72
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
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
74
|
|
|
@@ -95,15 +95,16 @@ Two verbs are told apart by what already exists. **`add-` puts one new member in
|
|
|
95
95
|
|
|
96
96
|
## Size — the backstop, not the goal
|
|
97
97
|
|
|
98
|
-
The goal is subtraction, above. These are only the line past which something is definitely wrong.
|
|
98
|
+
The goal is subtraction, above. These are only the line past which something is definitely wrong. They count words, because a line cap never sees a paragraph written as one long line.
|
|
99
99
|
|
|
100
|
-
| Type |
|
|
100
|
+
| Type | Budget |
|
|
101
101
|
|---|---|
|
|
102
|
-
| Rule |
|
|
103
|
-
| Agent |
|
|
104
|
-
| `SKILL.md` |
|
|
102
|
+
| Rule | 2,000 words |
|
|
103
|
+
| Agent | 500 words |
|
|
104
|
+
| `SKILL.md` | 1,500 words |
|
|
105
|
+
| Paragraph, list item or table row | 150 words |
|
|
105
106
|
|
|
106
|
-
**Ceilings, not quotas.** An artifact that says everything it needs to is finished, not underweight
|
|
107
|
+
**Ceilings, not quotas.** An artifact that says everything it needs to is finished, not underweight; nothing here is a reason to pad. Over the budget means the artifact is doing two jobs, or the detail belongs in `references/<topic>.md` with a pointer from the body, and a paragraph over it holds several thoughts to split.
|
|
107
108
|
|
|
108
109
|
`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
|
|
|
@@ -104,10 +104,13 @@ explains itself well.
|
|
|
104
104
|
back. Completion requires
|
|
105
105
|
`IS_STATUS=ok`, a clean final check, and no `onboarding is pending` header
|
|
106
106
|
after accepted migration.
|
|
107
|
-
11. Report what was created, updated, removed, or deliberately kept.
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
107
|
+
11. Report what was created, updated, removed, or deliberately kept. A
|
|
108
|
+
`status --check` note that names a tool settings change is the owner's step:
|
|
109
|
+
show it with the exact JSON it prints and leave the settings file to the
|
|
110
|
+
owner. Remind the user to commit source, manifest, lock and `AGENTS.md`
|
|
111
|
+
changes, plus Copilot's `.github/` output only when
|
|
112
|
+
`targets.copilot.commit_output` is `true`. Keep or remove the initial backup
|
|
113
|
+
only by separate user approval.
|
|
111
114
|
|
|
112
115
|
## Later learning
|
|
113
116
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: intelligence-learn-from-session
|
|
3
3
|
description: "Capture session lessons and workflows in project context"
|
|
4
|
-
|
|
4
|
+
argument-hint: "[lesson, or a folder of lesson records]"
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Learn from a session
|
|
@@ -9,6 +9,8 @@ agent: intelligence-architect
|
|
|
9
9
|
Capture a durable preference, working pattern, recurring friction, or successful
|
|
10
10
|
workflow from a session in an established Intelligence project. This skill owns
|
|
11
11
|
identifying and generalizing the lesson; `intelligence-update-context` owns writing it.
|
|
12
|
+
A lesson is saved only through that skill, as a source every clone and tool reads,
|
|
13
|
+
never in a tool's own memory.
|
|
12
14
|
|
|
13
15
|
## Verify readiness
|
|
14
16
|
|
|
@@ -23,7 +25,10 @@ identifying and generalizing the lesson; `intelligence-update-context` owns writ
|
|
|
23
25
|
|
|
24
26
|
2. Identify the lesson from the conversation or explicit user input. For a
|
|
25
27
|
workflow, list the actual steps performed, user decisions, branches, failure
|
|
26
|
-
recovery, and verification. Retain the sequence that worked.
|
|
28
|
+
recovery, and verification. Retain the sequence that worked. Given a folder
|
|
29
|
+
of lesson records, read every record against the current sources: report a
|
|
30
|
+
record the sources already satisfy as applied and drop it, and carry the rest
|
|
31
|
+
forward as lessons.
|
|
27
32
|
3. Generalize the evidence by removing instance-specific filenames, dates, and
|
|
28
33
|
phrasing. Keep the reason needed to apply the lesson to the next task. Prefer
|
|
29
34
|
a positive instruction such as "Default to one recommendation" for "Stop
|
|
@@ -33,18 +38,26 @@ identifying and generalizing the lesson; `intelligence-update-context` owns writ
|
|
|
33
38
|
4. Inspect configured sources for an existing owner. A preference or constraint
|
|
34
39
|
belongs in a rule, path-specific context in a scoped rule, an observed
|
|
35
40
|
repeatable procedure in a skill, and a persona or expertise boundary in an
|
|
36
|
-
agent. Prefer extending an existing artifact over adding a sibling.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
agent. Prefer extending an existing artifact over adding a sibling. A lesson
|
|
42
|
+
about installed package content or the CLI itself is fixed upstream, never in
|
|
43
|
+
the installed copy: draft an issue for the package's source repository, which
|
|
44
|
+
`intelligence.lock` records, or for Intelligence. The draft holds only safe
|
|
45
|
+
facts: versions from `intelligence version`, what was done, the expected and
|
|
46
|
+
the actual behavior, and nothing confidential or specific to the project.
|
|
47
|
+
5. Present each proposal with its action (`CREATE`, `UPDATE`, `ARCHIVE`, or
|
|
48
|
+
`UPSTREAM` for an issue draft), source path or repository, concrete draft, and
|
|
49
|
+
one-line reason. This phase is read-only; only user-accepted lessons become
|
|
50
|
+
persistent instructions. Reuse approval already given for the exact proposal.
|
|
41
51
|
|
|
42
52
|
## Apply and verify
|
|
43
53
|
|
|
44
54
|
6. Pass accepted proposals and their session evidence to
|
|
45
55
|
`/intelligence-update-context`. It handles artifact-specific authoring,
|
|
46
|
-
references, a single batch sync, and the final status check.
|
|
56
|
+
references, a single batch sync, and the final status check. An accepted
|
|
57
|
+
`UPSTREAM` draft goes into the report; filing it is a separate request the
|
|
58
|
+
person makes.
|
|
47
59
|
7. Compare the resulting source changes with the accepted lesson. For a workflow,
|
|
48
60
|
verify that its decisions, working steps, recovery, and proof of completion
|
|
49
61
|
remain executable without this conversation. Report the saved lesson, its
|
|
50
|
-
owner, and verification
|
|
62
|
+
owner, and verification, the records dropped as applied, and each upstream
|
|
63
|
+
draft with its state; a session-specific transcript is not completion.
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
name: intelligence-manage-adapters
|
|
3
3
|
description: "Enable, disable, or remove adapters and assess generated-output cleanup"
|
|
4
4
|
argument-hint: "<enable|disable|remove> <adapter-name>"
|
|
5
|
-
agent: intelligence-operator
|
|
6
5
|
disable-model-invocation: true
|
|
7
6
|
---
|
|
8
7
|
|
|
@@ -42,5 +41,6 @@ scaffolding, and sync. Adapter implementation follows the public adapter guide.
|
|
|
42
41
|
5. Verify with `intelligence adapter list` and `intelligence status --check`:
|
|
43
42
|
requested target state is correct, retained files are intact, and only approved
|
|
44
43
|
adapter-owned output was deleted. Report state, output paths, and any remaining
|
|
45
|
-
implementation or cleanup work
|
|
46
|
-
|
|
44
|
+
implementation or cleanup work, with each settings change a check note names
|
|
45
|
+
as the owner's step and its exact JSON. Preserve CLI refusals instead of
|
|
46
|
+
recreating lifecycle mechanics manually.
|
|
@@ -3,33 +3,37 @@ name: intelligence-review-context
|
|
|
3
3
|
description: "Audit rules, agents, and skills and propose behavior-preserving reductions"
|
|
4
4
|
argument-hint: "[rules|agents|skills|all] [compact]"
|
|
5
5
|
agent: intelligence-architect
|
|
6
|
+
context: fork
|
|
7
|
+
background: false
|
|
6
8
|
---
|
|
7
9
|
|
|
8
10
|
# Review project context
|
|
9
11
|
|
|
10
|
-
Audit the intelligence layer and
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
Audit the intelligence layer and return proposals. Work from the arguments and
|
|
13
|
+
the files alone and ask nothing: in Claude Code this skill runs as a subagent that
|
|
14
|
+
sees none of the conversation. Review and compaction analysis are read-only, so
|
|
15
|
+
never sync or edit. Accepted changes go through `intelligence-update-context`;
|
|
16
|
+
this skill owns their review criteria.
|
|
13
17
|
|
|
14
18
|
## Audit
|
|
15
19
|
|
|
16
20
|
1. Read `<manifest>` and enumerate its configured rule, agent, and skill sources.
|
|
17
21
|
Read the `intelligence-authoring` rule and
|
|
18
22
|
`<module>/references/conventions.md`. Review project-owned sources; an installed
|
|
19
|
-
package finding
|
|
23
|
+
package finding, an entry naming a package's directory however spelled,
|
|
20
24
|
belongs upstream. In a package's own repository, review its
|
|
21
25
|
authoritative source tree. Do not audit generated output prose. Its byte count
|
|
22
26
|
is the metadata-only exception.
|
|
23
27
|
2. Record source line and byte counts, and git history when available: first
|
|
24
28
|
addition, last edit, and edit count. Find incoming references before proposing
|
|
25
29
|
an archive. Resolve the shared agents output from the manifest and measure its
|
|
26
|
-
bytes
|
|
27
|
-
|
|
30
|
+
bytes. Mark missing or stale measurements; do not regenerate output during
|
|
31
|
+
analysis.
|
|
28
32
|
3. Read and apply [references/audit-checks.md](references/audit-checks.md). Reuse
|
|
29
33
|
these generic checks in any project-specific audit. Check subtraction before
|
|
30
34
|
proposing a split or rewrite: remove an unnecessary artifact, merge overlapping
|
|
31
35
|
owners, or replace prose with an existing deterministic gate where possible.
|
|
32
|
-
4. When the
|
|
36
|
+
4. When the arguments ask to compact context, or the audit proposes a merge, move,
|
|
33
37
|
deletion, scoping change, or size reduction, read
|
|
34
38
|
[references/compaction.md](references/compaction.md) and its principles. Build
|
|
35
39
|
the behavior ledger and draft the structural reduction before wording changes.
|
|
@@ -39,17 +43,17 @@ go through `intelligence-update-context`; this skill owns their review criteria.
|
|
|
39
43
|
3: description or naming polish). Compaction items also show the authoritative
|
|
40
44
|
owner, behavior preserved, estimated byte savings, and any change to meaning,
|
|
41
45
|
scope, or loading. Surface unverified reasons without silently rewriting them.
|
|
46
|
+
A finding about what an artifact says is a wrong or missing outcome, a
|
|
47
|
+
contradiction, or a stale reference; an edge case its outcome already covers
|
|
48
|
+
is no finding.
|
|
42
49
|
|
|
43
|
-
##
|
|
50
|
+
## Hand the decision back
|
|
44
51
|
|
|
45
|
-
6.
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
the compaction reference. Report each artifact as pass, fixed (what), or
|
|
54
|
-
flagged (for whom), plus unresolved proposals. A read-only review ends with
|
|
55
|
-
the evidenced punch-list; an apply run ends only after its checks complete.
|
|
52
|
+
6. End the result with the decision that belongs to the person: which numbered
|
|
53
|
+
items to accept, one by one or as a named batch, with the items you recommend
|
|
54
|
+
and the reason for each. Accepted items go to `/intelligence-update-context`
|
|
55
|
+
with their drafts. For compaction items, include what that skill needs to
|
|
56
|
+
verify them: the behavior ledger, the baseline counts with any missing
|
|
57
|
+
rendered measurement marked, and the steps under *Verify the accepted result*
|
|
58
|
+
in the compaction reference, copied into the result. The review is complete
|
|
59
|
+
when this evidenced punch-list is returned.
|
|
@@ -6,7 +6,8 @@ Apply these checks to the source groups resolved by the review skill.
|
|
|
6
6
|
|---|---|---|
|
|
7
7
|
| **Duplicate content** | Two artifacts cover overlapping scope, or their descriptions share trigger phrases | `MERGE` — present both, propose one |
|
|
8
8
|
| **Misplaced content** | A checklist or procedure in an agent body; a convention in an agent; a workflow in a rule; expertise in a skill (the *Pick the right artifact* table in `intelligence-authoring`) | `MOVE` — a move, not a rewrite: both files change together |
|
|
9
|
-
| **Over the
|
|
9
|
+
| **Over the budget** | `SKILL.md` over 1,500 words, rule over 2,000, agent over 500, skill reference over 3,000, or a paragraph, list item or table row over 150 (`R7`) | `SPLIT` - two artifacts, detail into `references/<topic>.md`, or a long paragraph into the thoughts it holds |
|
|
10
|
+
| **Rule repeats a gate** | A rule sentence restating what a script, test or sync already checks or refuses | `DELETE` - the gate holds the decision; a second copy in prose drifts from it and costs context in every session |
|
|
10
11
|
| **Shared instruction budget** | The measured shared agents output, or `agents-md` in sync's `CONTEXT:` summary, is over 32 KiB (32,768 bytes) | `COMPACT` — this is Intelligence's recommended maximum, not an adapter rejection threshold; use the compaction procedure in `intelligence-review-context` to reduce the owning sources without teaching terse output |
|
|
11
12
|
| **Rule links to a rule** | A markdown link from one rule to another (`R1`) | `UNLINK` — name the rule instead: always-on rules are inlined into `AGENTS.md` and the scoped channels carry only scoped rules, so the link is dead in at least one output |
|
|
12
13
|
| **Machine facts in a rule** | OS, shell, editor or a local absolute path (`R2`) | `MOVE` — these belong in a local rule, `<content-dir>/rules/<name>.local.md`, which Git ignores and sync keeps out of committed output; a rule is committed and read by everyone, including whoever is on another platform |
|
|
@@ -14,7 +15,7 @@ Apply these checks to the source groups resolved by the review skill.
|
|
|
14
15
|
| **Skill with no verification** | Nothing at the end proves the procedure worked (`R4`) | `FLAG` — a procedure that proves nothing is a note, or just the work: give it a verification, or delete it |
|
|
15
16
|
| **Pressure marker** | A heading or section named CRITICAL / MANDATORY / HARD RULE / READ FIRST, or a density of `MUST` / `NEVER` / `ALWAYS` with no reason beside it (`R5`) | `REWRITE` - plain heading, one reason per constraint; when several instructions are each marked critical the marker stops carrying information, so keep emphasis for the one instruction demonstrably under-weighted without it |
|
|
16
17
|
| **History narrative** | A PR number, incident id, commit SHA, date or "this session" inside a rule body (`R6`) | `REWRITE` - keep the causal sentence, drop the archaeology; a rule's authority is the behaviour it prescribes, and git history keeps the date |
|
|
17
|
-
| **
|
|
18
|
+
| **Name collision** | A project artifact named `intelligence-*` or like an installed package artifact it does not mean to override, or a skill named like a built-in command or bundled skill of an enabled tool ([Claude Code commands](https://code.claude.com/docs/en/commands)) | `RENAME` - the project artifact renders in the package's place, and a Claude Code skill replaces the command of its name but not that command's aliases, so one request runs different procedures depending on the name typed |
|
|
18
19
|
| **Naming** | A skill that is not `<domain>-<verb>-<noun>`, or a domain invented rather than reused | `RENAME` — or introduce the new domain deliberately |
|
|
19
20
|
| **Stale** | No edits in 6+ months and nothing cross-references it | `ARCHIVE` — move to `<content-dir>/_archive/` |
|
|
20
21
|
| **Negative-framed judgement call** | "Never do X" where a positive default fits, outside safety / security / output-format | `REWRITE` — state the default; reserve NEVER for true must-nots |
|
|
@@ -23,6 +24,7 @@ Apply these checks to the source groups resolved by the review skill.
|
|
|
23
24
|
| **Weak / duplicate description** | Identical to a sibling, or too vague to choose between them | `DIFFERENTIATE` — add the distinguishing trigger |
|
|
24
25
|
| **Description over budget** | Over ~250 characters (the shared registry budget); over **1024** the tools reject the artifact outright | `TRIM` — keep the distinguishing trigger, drop the rest |
|
|
25
26
|
| **Missing frontmatter field** | `name` or `description` absent | `PATCH` — add it |
|
|
27
|
+
| **Dead skill field** | `agent:` in a `SKILL.md` without `context: fork` (`R8`) | `PATCH` - delete `agent:`, which selects nothing without the fork, or fork the skill when the authoring conventions say it should |
|
|
26
28
|
| **Orphan rule** | Nothing points at it and nothing loads it | `FLAG` — intentional, or dead? |
|
|
27
29
|
|
|
28
30
|
Detection commands, portable on purpose — no `\b` and no `-P`, so the same command works in Git Bash on Windows, on macOS (BSD grep) and on Linux. Run each over the source directories resolved in step 2, never over generated output:
|
|
@@ -51,6 +53,28 @@ grep -rcE '(MUST|NEVER|ALWAYS)' <rule-dirs> <agent-dirs> <skill-dirs> | grep -vE
|
|
|
51
53
|
# R6 - history narrative in a rule body: PR numbers, incident ids, dates, "this session", commit SHAs
|
|
52
54
|
grep -rniE -e '(#|PR )[0-9]{3,}' -e '[0-9]{4}-[0-9]{2}-[0-9]{2}' -e 'this session|origin session' \
|
|
53
55
|
-e '`[0-9a-f]{7,40}`' <rule-dirs>
|
|
56
|
+
|
|
57
|
+
# R7 - words per file, then the longest paragraph; a list item or table row is its own paragraph
|
|
58
|
+
find <rule-dirs> <agent-dirs> <skill-dirs> -name '*.md' | while IFS= read -r f; do
|
|
59
|
+
awk -v f="$f" 'BEGIN { fence = sprintf("%c%c%c", 96, 96, 96) }
|
|
60
|
+
NR == 1 && /^---[ \t\r]*$/ { fm = 1; next }
|
|
61
|
+
fm { if (/^---[ \t\r]*$/) fm = 0; next }
|
|
62
|
+
{ w += NF }
|
|
63
|
+
index($1, fence) == 1 { code = !code; p = 0; next }
|
|
64
|
+
code || NF == 0 { p = 0; next }
|
|
65
|
+
/^[ \t]*(#|[-*] |[0-9]+\. |\|)/ { p = 0 }
|
|
66
|
+
{ p += NF; if (p > max) max = p }
|
|
67
|
+
END { printf "%6d %4d %s\n", w, max, f }' "$f"
|
|
68
|
+
done | sort -rn
|
|
69
|
+
|
|
70
|
+
# R8 - a skill's agent: without context: fork, read from the frontmatter only
|
|
71
|
+
find <skill-dirs> -name SKILL.md | while IFS= read -r f; do
|
|
72
|
+
awk -v f="$f" 'NR == 1 && /^---[ \t\r]*$/ { fm = 1; next }
|
|
73
|
+
fm && /^---[ \t\r]*$/ { exit }
|
|
74
|
+
fm && /^agent:/ { a = 1 }
|
|
75
|
+
fm && /^context:[ \t]*"?fork/ { c = 1 }
|
|
76
|
+
END { if (a && !c) print f }' "$f"
|
|
77
|
+
done
|
|
54
78
|
```
|
|
55
79
|
|
|
56
80
|
`R4` is a coarse net, not a verdict: a skill that merely *mentions* a verification command anywhere passes it. Read the final step of every skill regardless — the question is whether something at the end **proves the work landed**, not whether the word appears. So are `R5` and `R6`: a `NEVER` that carries its reason and a date inside a frontmatter template are both legitimate hits, and the row's action applies only where the marker or the id is doing no work.
|
|
@@ -35,12 +35,14 @@ product requirement.
|
|
|
35
35
|
|
|
36
36
|
Proposals use `DELETE`, `MERGE`, `SCOPE`, `MOVE`, `REFERENCE`, or `REWRITE` and name
|
|
37
37
|
the owner, semantic contract, estimated savings, and any changed behavior or load
|
|
38
|
-
timing. Keep unapproved passages byte-for-byte;
|
|
39
|
-
|
|
38
|
+
timing. Keep unapproved passages byte-for-byte; only accepted proposals reach
|
|
39
|
+
the shared authoring procedure, which runs the steps below.
|
|
40
40
|
|
|
41
41
|
## Verify the accepted result
|
|
42
42
|
|
|
43
|
-
1.
|
|
43
|
+
1. Before editing, when the baseline marks a rendered measurement missing, record
|
|
44
|
+
`<sync-cmd> --compact` output and require `IS_STATUS=ok`. After editing,
|
|
45
|
+
compare the ledger with the diff. Each original behavior exists once in its
|
|
44
46
|
authoritative owner, was deliberately removed with approval, or is enforced by
|
|
45
47
|
the named deterministic mechanism. Check for dead links, unconditional reference
|
|
46
48
|
loads, conflicting instructions, and unintended scope expansion.
|
|
@@ -54,4 +56,4 @@ accepted proposals to the shared authoring procedure.
|
|
|
54
56
|
and an ordinary explanation that reveals clipped language. Report explicitly
|
|
55
57
|
when this evaluation is unavailable: fewer bytes prove size, not quality.
|
|
56
58
|
4. Report artifacts changed, behavior checks, measurements, and remaining owner
|
|
57
|
-
decisions
|
|
59
|
+
decisions in the authoring skill's final report.
|
|
@@ -3,6 +3,7 @@ name: intelligence-sync
|
|
|
3
3
|
description: "Sync intelligence to enabled adapters"
|
|
4
4
|
agent: intelligence-operator
|
|
5
5
|
context: fork
|
|
6
|
+
background: false
|
|
6
7
|
---
|
|
7
8
|
|
|
8
9
|
# Sync intelligence
|
|
@@ -19,13 +20,12 @@ context: fork
|
|
|
19
20
|
`IS_STATUS=needs-update` (exit 6) means the project needs a migration only
|
|
20
21
|
`intelligence update` applies; report that, and never edit the manifest or
|
|
21
22
|
lock by hand to get past it. A frozen restore refusal means the
|
|
22
|
-
manifest and lock disagree or the locked commit cannot be verified
|
|
23
|
-
hand-copying package content.
|
|
24
|
-
4. On a probable Intelligence defect,
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
never invent a profile path or infer the intended scope.
|
|
23
|
+
manifest and lock disagree or the locked commit cannot be verified or restored;
|
|
24
|
+
report it without hand-copying package content.
|
|
25
|
+
4. On a probable Intelligence defect, end the result with a block headed
|
|
26
|
+
`Probable Intelligence defect` that holds only safe facts: the CLI and engine
|
|
27
|
+
versions from `intelligence version`, the command, the expected and the actual
|
|
28
|
+
behavior, and error text with nothing confidential or specific to the project.
|
|
29
|
+
Follow it with an issue draft built from those facts alone. The result is the
|
|
30
|
+
only place they go: send and file nothing, and use no telemetry. Filing the
|
|
31
|
+
draft is a separate request the person makes.
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
name: intelligence-update-context
|
|
3
3
|
description: "Create, revise, or remove project rules, agents, and skills"
|
|
4
4
|
argument-hint: "[rule|agent|skill] [request or accepted proposals]"
|
|
5
|
-
agent: intelligence-architect
|
|
6
5
|
---
|
|
7
6
|
|
|
8
7
|
# Update project context
|
|
@@ -74,3 +73,6 @@ the same procedure. Updating the layer can create a new artifact.
|
|
|
74
73
|
9. Report the created, updated, removed, or archived artifacts and their checks.
|
|
75
74
|
Return control to the originating workflow for its additional semantic,
|
|
76
75
|
compaction, migration, or packaging verification; those checks remain required.
|
|
76
|
+
Review proposals carry their verification steps instead, because the review
|
|
77
|
+
has already returned: run each at the point it names, before or after editing,
|
|
78
|
+
and report the results here.
|
|
@@ -22,15 +22,16 @@
|
|
|
22
22
|
name: <domain>-<verb>-<noun>
|
|
23
23
|
description: "What the skill does and when to use it"
|
|
24
24
|
argument-hint: "Expected arguments"
|
|
25
|
-
agent: <existing-agent>
|
|
26
25
|
---
|
|
27
26
|
```
|
|
28
27
|
|
|
29
28
|
Omit optional fields that do not apply. Add `effort:` only when the procedure
|
|
30
29
|
needs a reasoning effort other than the session's, using the scale in the
|
|
31
|
-
authoring conventions' effort mappings. Add
|
|
30
|
+
authoring conventions' effort mappings. Add `context: fork` with `agent:` only
|
|
31
|
+
for a skill the authoring conventions say to fork, and `background: false` when
|
|
32
|
+
its caller needs the result in the same turn. Add the skill to its matching agent's
|
|
32
33
|
`skills:` list when that agent is project-owned; propose an upstream change for
|
|
33
34
|
a package-owned agent instead of editing the installed copy. Verify bindings,
|
|
34
35
|
relative resource links, executable steps, and final success criteria. Apply the
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
word budgets from the authoring conventions, then return to the shared sync and
|
|
37
|
+
verification steps.
|