@skill-map/spec 0.2.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +321 -2
- package/README.md +68 -39
- package/architecture.md +45 -4
- package/cli-contract.md +69 -10
- package/conformance/coverage.md +66 -0
- package/db-schema.md +47 -11
- package/index.json +23 -13
- package/job-events.md +124 -4
- package/job-lifecycle.md +48 -14
- package/package.json +1 -1
- package/plugin-kv-api.md +8 -6
- package/schemas/extensions/action.schema.json +81 -0
- package/schemas/extensions/adapter.schema.json +40 -0
- package/schemas/extensions/audit.schema.json +47 -0
- package/schemas/extensions/base.schema.json +44 -0
- package/schemas/extensions/detector.schema.json +35 -0
- package/schemas/extensions/renderer.schema.json +29 -0
- package/schemas/extensions/rule.schema.json +37 -0
- package/schemas/frontmatter/agent.schema.json +1 -6
- package/schemas/frontmatter/base.schema.json +10 -0
- package/schemas/history-stats.schema.json +172 -0
- package/schemas/plugins-registry.schema.json +1 -1
- package/schemas/project-config.schema.json +42 -7
- package/versioning.md +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,318 @@
|
|
|
1
1
|
# Spec changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 334c51a: Document `--all` as targeted fan-out, not a global flag, in `spec/cli-contract.md`.
|
|
8
|
+
|
|
9
|
+
`--all` is valid only on verbs whose contract explicitly lists it:
|
|
10
|
+
|
|
11
|
+
- `sm plugins enable <id> | --all` and `sm plugins disable <id> | --all`.
|
|
12
|
+
- `sm job cancel <job.id> | --all` (cancels every `queued` and `running` job).
|
|
13
|
+
- `sm job submit <action> --all` and `sm job run --all`.
|
|
14
|
+
|
|
15
|
+
Unsupported `--all` usage is an operational error (exit `2`), the same as any other unknown or invalid flag.
|
|
16
|
+
|
|
17
|
+
Classification: minor — targeted fan-out semantics are additive for the listed verbs, while avoiding a global flag contract.
|
|
18
|
+
|
|
19
|
+
- 3e89d8f: Audit-driven alignment pass. Multiple normative additions and a casing cleanup:
|
|
20
|
+
|
|
21
|
+
- **Extension schemas**: add `spec/schemas/extensions/{base,adapter,detector,rule,action,audit,renderer}.schema.json` (7 new files). `architecture.md` §Extension kinds now points to them and mandates manifest validation at load time. Unblocks the "contract tests for the 6 kinds" invariant.
|
|
22
|
+
- **Adapter `defaultRefreshAction`**: normatively required on every `Adapter` extension. Maps node `kind` → `actionId` and drives the UI's `🧠 prob` button. Previously mentioned only in ROADMAP (Decision #45); now part of the schema.
|
|
23
|
+
- **Triple protection for mode B**: `db-schema.md` now specifies the exact order — parse → DDL validation → prefix injection → scoped connection. Validation runs **before** the rewrite so kernel-table references are caught under their authored names.
|
|
24
|
+
- **Automatic rename heuristic**: new `db-schema.md` §Rename detection. On scan, `body_hash` match → high-confidence auto-rename with `state_*` FK migration; `frontmatter_hash` match → medium-confidence, same migration + `auto-rename-medium` issue; no match → orphan with issue. Replaces the prior "scan emits orphans, user runs `sm orphans reconcile` manually" flow.
|
|
25
|
+
- **Skill agent envelope**: `job-events.md` now mandates a synthetic `r-ext-<ts>-<hex>` run envelope (`run.started mode=external` → `job.claimed` → `job.callback.received` → `job.completed|failed` → `run.summary`) around jobs claimed by a Skill agent without entering `sm job run`. Keeps the WebSocket broadcaster contract ("every job event inside a run envelope") intact across both runner paths.
|
|
26
|
+
- **"Skill runner" → "Skill agent"**: `architecture.md` and `job-lifecycle.md` clarify that the Skill path is a peer driving adapter (alongside CLI and Server), NOT a `RunnerPort` implementation. Only `ClaudeCliRunner` and its test fake implement the port. Name was misleading; structure unchanged.
|
|
27
|
+
- **Casing**: `db-schema.md` `auto_migrate` → `autoMigrate`; `README.md` prose mention `spec-compat` → `specCompat`. Brings prose into sync with the camelCase rule already enforced by the schemas.
|
|
28
|
+
- **Coverage matrix**: new `spec/conformance/coverage.md` tracks each schema (and each non-schema normative artifact) against its conformance case. 28 schemas + 11 artifact invariants catalogued; 19 schemas and 10 artifacts flagged as missing, each with a step-blocker note. Release gate: v1.0.0 requires every row 🟢 or explicitly deferred.
|
|
29
|
+
|
|
30
|
+
Classification: minor per §Pre-1.0 (`0.Y.Z`). The new required field `defaultRefreshAction` on the Adapter kind is technically breaking — no conforming Adapter ships in the reference impl yet, so the impact is zero. Post-1.0 the same change would be major.
|
|
31
|
+
|
|
32
|
+
### Patch Changes
|
|
33
|
+
|
|
34
|
+
- 93ffe34: Editorial pass: remove "MVP" terminology from four prose documents.
|
|
35
|
+
|
|
36
|
+
The project shipped two competing readings of "MVP" — sometimes "`v0.5.0`", sometimes "the whole product through `v1.0`". That drift produced contradictions in companion docs (e.g. the summarizer pattern: was `v0.8.0` or `v0.5.0` supposed to ship them?). To close the ambiguity once, `ROADMAP.md` and `AGENTS.md` standardised on explicit versioned releases and `post-v1.0` in the same audit window. This change brings the four spec prose touches that still said "MVP" into the same vocabulary.
|
|
37
|
+
|
|
38
|
+
- **`cli-contract.md` §Jobs**: `sm job run --all` description `(MVP: sequential)` → `(sequential through v1.0; in-runner parallelism deferred)`.
|
|
39
|
+
- **`job-events.md` §Event catalog**: `(post-MVP)` parallel-run note → `(deferred to post-v1.0)`.
|
|
40
|
+
- **`job-lifecycle.md` §Concurrency**: `MVP (v0.x): one job at a time.` → `Through v1.0 (spec v0.x): one job at a time.`
|
|
41
|
+
- **`plugin-kv-api.md` §Backup and retention**: `sm plugins forget <id> (post-MVP)` → `sm plugins forget <id> (deferred to post-v1.0)`.
|
|
42
|
+
|
|
43
|
+
Classification: patch. Editorial only — no schema, exit code, verb signature, or MUST/SHOULD statement changes meaning. All four replacements preserve the technical content; only the label changes from project-scoped ("MVP") to version-scoped (`v1.0`), which is the convention the rest of the spec already uses. Integrity block regenerated.
|
|
44
|
+
|
|
45
|
+
## 0.3.0
|
|
46
|
+
|
|
47
|
+
### Minor Changes
|
|
48
|
+
|
|
49
|
+
- 334c51a: Promote `--all` to a normative universal flag in `spec/cli-contract.md §Global flags`.
|
|
50
|
+
|
|
51
|
+
Any verb that accepts a target identifier (`-n <node.path>`, `<job.id>`, `<plugin.id>`) MUST accept `--all` as "apply to every eligible target matching the verb's preconditions". Mutually exclusive with a positional target or `-n <path>` on the same invocation. Verbs that inherently target everything (`sm scan` without `-n`, `sm list`, `sm check`, `sm doctor`) accept the flag as a no-op for script-composition uniformity. Verbs where fan-out is nonsensical (`sm record`, `sm init`, `sm version`, `sm help`, `sm config get/set/reset/show`, `sm db *`, `sm serve`) MUST reject `--all` with exit `2`.
|
|
52
|
+
|
|
53
|
+
Concretely extended in this pass:
|
|
54
|
+
|
|
55
|
+
- `sm plugins enable <id> | --all` and `sm plugins disable <id> | --all`.
|
|
56
|
+
- `sm job cancel <job.id> | --all` (cancels every `queued` and `running` job).
|
|
57
|
+
|
|
58
|
+
Already normative before this change: `sm job submit <action> --all` and `sm job run --all`.
|
|
59
|
+
|
|
60
|
+
Classification: minor — new global flag semantics, backward compatible (existing invocations without `--all` behave identically). ROADMAP Decision #60 stays as the canonical narrative; this changeset brings the spec into line with it.
|
|
61
|
+
|
|
62
|
+
- 3e89d8f: Audit-driven alignment pass. Multiple normative additions and a casing cleanup:
|
|
63
|
+
|
|
64
|
+
- **Extension schemas**: add `spec/schemas/extensions/{base,adapter,detector,rule,action,audit,renderer}.schema.json` (7 new files). `architecture.md` §Extension kinds now points to them and mandates manifest validation at load time. Unblocks the "contract tests for the 6 kinds" invariant.
|
|
65
|
+
- **Adapter `defaultRefreshAction`**: normatively required on every `Adapter` extension. Maps node `kind` → `actionId` and drives the UI's `🧠 prob` button. Previously mentioned only in ROADMAP (Decision #45); now part of the schema.
|
|
66
|
+
- **Triple protection for mode B**: `db-schema.md` now specifies the exact order — parse → DDL validation → prefix injection → scoped connection. Validation runs **before** the rewrite so kernel-table references are caught under their authored names.
|
|
67
|
+
- **Automatic rename heuristic**: new `db-schema.md` §Rename detection. On scan, `body_hash` match → high-confidence auto-rename with `state_*` FK migration; `frontmatter_hash` match → medium-confidence, same migration + `auto-rename-medium` issue; no match → orphan with issue. Replaces the prior "scan emits orphans, user runs `sm orphans reconcile` manually" flow.
|
|
68
|
+
- **Skill agent envelope**: `job-events.md` now mandates a synthetic `r-ext-<ts>-<hex>` run envelope (`run.started mode=external` → `job.claimed` → `job.callback.received` → `job.completed|failed` → `run.summary`) around jobs claimed by a Skill agent without entering `sm job run`. Keeps the WebSocket broadcaster contract ("every job event inside a run envelope") intact across both runner paths.
|
|
69
|
+
- **"Skill runner" → "Skill agent"**: `architecture.md` and `job-lifecycle.md` clarify that the Skill path is a peer driving adapter (alongside CLI and Server), NOT a `RunnerPort` implementation. Only `ClaudeCliRunner` and its test fake implement the port. Name was misleading; structure unchanged.
|
|
70
|
+
- **Casing**: `db-schema.md` `auto_migrate` → `autoMigrate`; `README.md` prose mention `spec-compat` → `specCompat`. Brings prose into sync with the camelCase rule already enforced by the schemas.
|
|
71
|
+
- **Coverage matrix**: new `spec/conformance/coverage.md` tracks each schema (and each non-schema normative artifact) against its conformance case. 28 schemas + 11 artifact invariants catalogued; 19 schemas and 10 artifacts flagged as missing, each with a step-blocker note. Release gate: v1.0.0 cut requires every row 🟢 or explicitly deferred.
|
|
72
|
+
|
|
73
|
+
Classification: minor per §Pre-1.0 (`0.Y.Z`). The new required field `defaultRefreshAction` on the Adapter kind is technically breaking — no conforming Adapter ships in the reference impl yet, so the impact is zero. Post-1.0 the same change would be major.
|
|
74
|
+
|
|
75
|
+
- d41b9ae: Close two gaps surfaced in the audit pass: config keys that `ROADMAP.md` promised but `project-config.schema.json` did not declare, and WebSocket event families that `ROADMAP.md §UI` mentioned ("scan updates + issue changes") but `job-events.md` did not cover.
|
|
76
|
+
|
|
77
|
+
**`project-config.schema.json` — new optional fields, all non-breaking:**
|
|
78
|
+
|
|
79
|
+
- `autoMigrate: boolean` (default `true`) — auto-apply pending kernel + plugin migrations at startup after auto-backup. `false` → startup fails fast if migrations are pending.
|
|
80
|
+
- `tokenizer: string` (default `cl100k_base`) — name of the offline tokenizer; stored alongside counts so consumers know which encoder produced them.
|
|
81
|
+
- `scan.maxFileSizeBytes: integer` (default `1048576`) — files larger are skipped with an `info` log.
|
|
82
|
+
- `jobs.ttlSeconds: integer` (default `3600`) — global fallback TTL when an action manifest omits `expectedDurationSeconds` (typically `mode: local` actions where the field is advisory).
|
|
83
|
+
- `jobs.perActionPriority: { <actionId>: integer }` — per-action priority overrides. Frozen on `state_jobs.priority` at submit time; overrides action manifest `defaultPriority`; overridden by CLI `--priority`. Ratifies decision #40a in the schema.
|
|
84
|
+
- `jobs.retention: { completed, failed }` — GC policy for `state_jobs` rows. Defaults: `completed = 2592000` (30 days), `failed = null` (never auto-prune; keep for post-mortem). `sm job prune` reads these; no implicit pruning during normal verbs.
|
|
85
|
+
|
|
86
|
+
**`job-events.md` — new `Non-job events` section, Stability: experimental across v0.x:**
|
|
87
|
+
|
|
88
|
+
- `scan.*`: `scan.started`, `scan.progress` (throttled ≥250 ms), `scan.completed`.
|
|
89
|
+
- `issue.*`: `issue.added`, `issue.resolved` — emitted after `scan.completed` when the new scan's issue set differs from the previous one. Diff key: `(ruleId, nodeIds sorted, message)`.
|
|
90
|
+
- Synthetic run ids follow the existing `r-<mode>-YYYYMMDD-HHMMSS-XXXX` pattern (`r-scan-...`, `r-check-...`) alongside `r-ext-...` for external Skill claims.
|
|
91
|
+
|
|
92
|
+
These families ship at Step 12 of the reference impl alongside the WebSocket broadcaster. Marking them experimental keeps the shape mutable until real UI consumers exercise the stream; promotion to `stable` is a later minor bump.
|
|
93
|
+
|
|
94
|
+
Classification: minor per §Pre-1.0. All additions are optional fields in a permissive config schema and new event types outside the stable job family — zero impact on existing implementations. Matching `ROADMAP.md` §Notable config keys and §Progress events updates land in the same change.
|
|
95
|
+
|
|
96
|
+
- d41b9ae: Align the frontmatter tools story with Claude Code's own conventions (the audit pass surfaced that the spec had `tools` on agent only and no equivalent for skills, while `ROADMAP.md` decision #55 referenced a non-existent `expected-tools` field).
|
|
97
|
+
|
|
98
|
+
**`spec/schemas/frontmatter/base.schema.json` — two new top-level optional fields:**
|
|
99
|
+
|
|
100
|
+
- `tools: string[]` — **allowlist**. When present, the host MUST restrict the node to exactly these tools. Matches Claude Code's subagent `tools` frontmatter. Kind-specific interpretation: an `agent` uses it to lock the spawned subagent; a `skill` uses it as a declarative hint (skills typically inherit their parent's tools, but the field is carried for parity and discovery); other kinds use it as information only.
|
|
101
|
+
- `allowedTools: string[]` — **pre-approval**. Tools the host MAY use without per-use permission prompts while the node is active. Distinct from `tools`: every other tool remains callable, governed by the host's normal permission settings. Matches Claude Code's skill `allowed-tools` frontmatter. Accepts argument-scoped patterns where the host supports them (e.g. `Bash(git add *)`).
|
|
102
|
+
|
|
103
|
+
**`spec/schemas/frontmatter/agent.schema.json`:** `tools` removed from the kind-specific body because it now lives on `base` and is inherited via `allOf`. The agent schema's title/description updated to reflect that only `model` remains kind-specific. Consumers reading `tools` from an agent frontmatter see no behavioural change — the field is still there, just sourced from `base`.
|
|
104
|
+
|
|
105
|
+
`expectedTools` on `extensions/action.schema.json` is unchanged. That field is a hint from an action template to the runner (which tools the rendered prompt expects access to) — a distinct semantics from the node-level `tools` / `allowedTools` pair, and the name difference preserves the distinction.
|
|
106
|
+
|
|
107
|
+
Classification: minor per §Pre-1.0. Additions to `base` are optional fields in a permissive schema (no break for existing frontmatter). Removing `tools` from the agent schema's own properties is compatible because `allOf: [base]` continues to supply it — any document that validated before still validates, any document that used `additionalProperties: true` is unaffected. Matching `ROADMAP.md` updates (§Frontmatter standard, decision #55) land in the same change.
|
|
108
|
+
|
|
109
|
+
- 5935948: Add `sm history stats` schema and normative elapsed-time reporting.
|
|
110
|
+
|
|
111
|
+
- **New schema** `spec/schemas/history-stats.schema.json`. Shape for `sm history stats --json`: `range` (configurable via `--since` / `--until`), `totals`, `tokensPerAction[]`, `executionsPerPeriod[]` (granularity via `--period day|week|month`, default `month`), `topNodes[]` (length via `--top N`, default 10), `errorRates` (global + per-action + per failure reason — all failure-reason enum values always present with `0` when unseen for predictable dashboards), and top-level `elapsedMs`. Duration stats in `tokensPerAction[]`: `durationMsMean` + `durationMsMedian` for MVP; percentiles deferred to a later minor bump.
|
|
112
|
+
- **cli-contract.md §Elapsed time** (new normative section). Every verb that does non-trivial work MUST report its own wall-clock:
|
|
113
|
+
- **Pretty (stderr)**: last line `done in <formatted>` where `<formatted>` ∈ `{ <N>ms | <N.N>s | <M>m <S>s }`. Suppressed by `--quiet`.
|
|
114
|
+
- **JSON stdout**: top-level `elapsedMs` when the shape is an object; schemas whose shape is an array or ndjson don't carry it (stderr is the sole carrier).
|
|
115
|
+
- **Exempt** verbs (sub-millisecond, informational): `sm --version`, `sm --help`, `sm version`, `sm help`, `sm config get`, `sm config list`, `sm config show`.
|
|
116
|
+
- Measurement spans from after arg-parsing to before terminal write.
|
|
117
|
+
- **cli-contract.md** `sm history stats` entry: flags enumerated (`--since`, `--until`, `--period`, `--top`) and schema referenced.
|
|
118
|
+
- **Coverage matrix**: row `29` for `history-stats.schema.json` (blocked by Step 4); artifact row `L` for the elapsed-time reporting invariant (blocked by Step 3).
|
|
119
|
+
|
|
120
|
+
Classification: minor per §Pre-1.0. The elapsed-time contract introduces a SHOULD-emit line that didn't exist before — no existing consumer breaks, and the line goes to stderr where it doesn't clash with stdout JSON.
|
|
121
|
+
|
|
122
|
+
- 1455cb1: Normative `priority` for jobs.
|
|
123
|
+
|
|
124
|
+
The `state_jobs.priority` column (INTEGER, default `0`) existed in the schema and was used by the atomic-claim SQL (`ORDER BY priority DESC, createdAt ASC`), but no surface let the user set it. This release closes the gap:
|
|
125
|
+
|
|
126
|
+
- **`cli-contract.md` §Jobs**: new flag `sm job submit ... --priority <n>`. Integer; higher runs first; default `0`; negatives permitted (deprioritize).
|
|
127
|
+
- **`job-lifecycle.md` §Submit**: new step 6 resolving priority with precedence `action manifest defaultPriority → user config jobs.perActionPriority.<actionId> → flag`. The resolved value is frozen on submit and immutable for the life of the job. Ties in the claim order break by `createdAt ASC`.
|
|
128
|
+
- Configuration key `jobs.perActionPriority.<actionId>`: optional per-action integer override.
|
|
129
|
+
- Action manifest `defaultPriority`: optional integer; defaults to `0` when omitted.
|
|
130
|
+
|
|
131
|
+
Classification: minor per `cli-contract.md` §Stability ("adding a flag is a minor bump"). No existing consumer breaks: jobs submitted before this release default to `0`, which is the identity element of the ordering. The claim SQL already read `priority`, so the wire protocol is unchanged.
|
|
132
|
+
|
|
133
|
+
- 1455cb1: Manifest alignment pass on `spec/index.json`: expose already-normative schemas, rename the payload-shape field, and add a stable version field consumers can rely on.
|
|
134
|
+
|
|
135
|
+
- **Rename `specVersion` → `indexPayloadVersion`** (breaking). The old name collided semantically with every other use of `specVersion` (compat logic in `versioning.md`, `scan-result.specVersion`, `sm help --format json`). The field describes the shape of `index.json` itself, not the spec a caller implements.
|
|
136
|
+
- **New `specPackageVersion`** top-level field, auto-populated by `scripts/build-spec-index.mjs` from `spec/package.json.version`. This is the source of truth for "which `@skill-map/spec` release is this", previously missing from the manifest — consumers had to read `package.json` separately, and `sm version` was incorrectly reporting the payload-shape version as the spec version.
|
|
137
|
+
- **`schemas.topLevel`** gains `history-stats` (shape for `sm history stats --json`, already referenced in `cli-contract.md` §History).
|
|
138
|
+
- **New `schemas.extensions` subsection** lists the 7 kind-manifest schemas (`base`, `adapter`, `detector`, `rule`, `action`, `audit`, `renderer`) already required by `architecture.md` §Extension kinds for load-time manifest validation.
|
|
139
|
+
- **CHANGELOG fix** on the `[Unreleased]` v0.1.0 line: "10 event types" → "11 canonical event types plus one synthetic `emitter.error`". Text-only correction on a shipped release.
|
|
140
|
+
- **README example** updated to show both fields side-by-side so the distinction is obvious to first-time consumers.
|
|
141
|
+
- **Integrity block** regenerated.
|
|
142
|
+
|
|
143
|
+
No schema contents change. The schema files and their normative status are unchanged since 0.1.0; the index now enumerates them all and uses unambiguous field names.
|
|
144
|
+
|
|
145
|
+
**Migration for consumers**: any caller that reads `specIndex.specVersion` MUST switch to `specIndex.specPackageVersion` (for the release) or `specIndex.indexPayloadVersion` (for the manifest shape). The rename is the source of the `minor` bump rather than `patch` — pre-1.0 minors MAY contain breaking changes per `versioning.md` §Pre-1.0.
|
|
146
|
+
|
|
147
|
+
Classification: minor per §Pre-1.0. One breaking rename + two additive fields + two additive schema subsections. The reference impl's `sm version` is updated in the same release to read `specPackageVersion`, so `sm version` now reports the actual npm package version (was the payload-shape version, a latent bug).
|
|
148
|
+
|
|
149
|
+
- 1455cb1: New CLI verb `sm orphans undo-rename <new.path> [--force]` to reverse a medium-confidence auto-rename.
|
|
150
|
+
|
|
151
|
+
The scan's rename heuristic (added in the previous spec release) migrates `state_*` FKs automatically when a deleted path and a newly-seen path share the same `frontmatter_hash` ("medium" confidence, body differs) and emits an `auto-rename-medium` issue for the user to verify. Until now the spec said "revert via `sm orphans reconcile --to <old.path>`", but `sm orphans reconcile` is defined for the forward direction (orphan path → live node) and awkward for the reverse case where both paths exist.
|
|
152
|
+
|
|
153
|
+
This release closes the gap with a dedicated reverse verb:
|
|
154
|
+
|
|
155
|
+
- **`cli-contract.md` §Browse**: new row `sm orphans undo-rename <new.path> [--force]`. Requires an active `auto-rename-medium` or `auto-rename-ambiguous` issue targeting `<new.path>`. Reads the prior path from `issue.data_json.from`, migrates `state_*` FKs back, resolves the issue. Exit `5` if no matching active issue.
|
|
156
|
+
- **`db-schema.md` §Rename detection**: issue payload now normative.
|
|
157
|
+
- `auto-rename-medium.data_json` MUST include `{ from, to, confidence: "medium" }`.
|
|
158
|
+
- `auto-rename-ambiguous.data_json` MUST include `{ to, candidates: [from_a, from_b, ...] }`. `sm orphans undo-rename` requires `--from <old.path>` to pick one.
|
|
159
|
+
- **Destructive verb**: prompts for confirmation unless `--force`. After undo, the prior path becomes an `orphan` (file no longer exists), emitting the normal `orphan` issue on next scan.
|
|
160
|
+
|
|
161
|
+
Rationale: dedicated name makes intent clear (forward = reconcile, reverse = undo-rename), failure is early (no active issue → immediate exit 5 with a helpful message), and the user does not re-type paths the kernel already knows.
|
|
162
|
+
|
|
163
|
+
Classification: minor per `cli-contract.md` §Stability ("adding a verb is a minor bump"). No existing behavior changes; `sm orphans reconcile` semantics are unaffected.
|
|
164
|
+
|
|
165
|
+
- 334c51a: **Breaking**: rename two state-zone tables to comply with the normative plural rule in `db-schema.md §Naming conventions`.
|
|
166
|
+
|
|
167
|
+
- `state_enrichment` → `state_enrichments`
|
|
168
|
+
- `state_plugin_kv` → `state_plugin_kvs`
|
|
169
|
+
|
|
170
|
+
Index names renamed in lockstep:
|
|
171
|
+
|
|
172
|
+
- `ix_state_enrichment_stale_after` → `ix_state_enrichments_stale_after`
|
|
173
|
+
- `ix_state_plugin_kv_plugin_id` → `ix_state_plugin_kvs_plugin_id`
|
|
174
|
+
|
|
175
|
+
The two tables were the only kernel-owned state-zone tables violating the rule "Tables: `snake_case`, plural" — every other catalog entry (`state_jobs`, `state_executions`, `state_summaries`, `config_plugins`, `config_preferences`, `config_schema_versions`, `scan_nodes`, `scan_links`, `scan_issues`) was already plural. The exceptions were historical drift, not intentional.
|
|
176
|
+
|
|
177
|
+
Updated spec artefacts:
|
|
178
|
+
|
|
179
|
+
- `spec/db-schema.md` — table section headings, column comments, primary-key footers, index names, and the cross-reference list in §Rename heuristic.
|
|
180
|
+
- `spec/cli-contract.md` — `sm db reset --state` row in §Database.
|
|
181
|
+
- `spec/plugin-kv-api.md` — §Overview opener and every downstream reference.
|
|
182
|
+
- `spec/schemas/plugins-registry.schema.json` — description of the `kv` mode `const`.
|
|
183
|
+
|
|
184
|
+
**Migration for implementations**: no reference implementation has shipped the SQLite adapter yet (Step 1a lands it), so this is a rename-on-paper change. Any future kernel migration that creates these tables MUST use the plural names. Any third-party implementation already experimenting with the spec against the old names MUST rename before targeting `@skill-map/spec ≥ 0.3.0`.
|
|
185
|
+
|
|
186
|
+
Classification: **minor with breaking change**, per `spec/versioning.md §Pre-1.0` which allows breaking changes on minor bumps while the spec is `0.y.z`. Reference-impl touch: `src/kernel/ports/plugin-loader.ts` comment updated; no code paths read these names at runtime yet.
|
|
187
|
+
|
|
188
|
+
Companion prose updates in `ROADMAP.md` (§Persistence, §Plugin system, §Enrichment, §Summarizer pattern, Decision #61) and `AGENTS.md` (§Persistence).
|
|
189
|
+
|
|
190
|
+
- 93ffe34: Clean up `history.*` in `spec/schemas/project-config.schema.json`.
|
|
191
|
+
|
|
192
|
+
**Breaking (pre-1.0 minor per `versioning.md` §Pre-1.0):**
|
|
193
|
+
|
|
194
|
+
- **Remove** `history.retentionDays`. The field promised execution-record GC, but `ROADMAP.md` §Step 6 and the job-retention section make it explicit that `state_executions` is append-only in `v0.1` and that the kernel does not use this key. Declaring a config key whose behaviour is "silently ignored" is worse than not declaring it — consumers would wire it in and never see an effect. The field will be re-introduced in a later minor bump when the GC path actually lands, with a concrete default and enforcement semantics.
|
|
195
|
+
|
|
196
|
+
**Editorial:**
|
|
197
|
+
|
|
198
|
+
- `history.share.description` mentioned `./.skill-map/history.json` — an artefact of the pre-SQLite architecture. The actual DB is `./.skill-map/skill-map.db` (see `db-schema.md` §Scope and location). Description corrected; field itself unchanged.
|
|
199
|
+
|
|
200
|
+
Classification: minor per §Pre-1.0 (`0.Y.Z` may contain breaking changes in a minor bump). Integrity block regenerated via `npm run spec:index`. Companion prose in `ROADMAP.md §Notable config keys` updated in the same change.
|
|
201
|
+
|
|
202
|
+
**Migration for consumers**: any `.skill-map.json` that set `history.retentionDays` will now fail schema validation (`additionalProperties: false` on `history`). Remove the key; no kernel behaviour changes because nothing was consuming it.
|
|
203
|
+
|
|
204
|
+
- 93ffe34: Promote the trigger-normalization pipeline (Decision #21) from implicit to normative in `spec/architecture.md`.
|
|
205
|
+
|
|
206
|
+
Before this change, `link.trigger` carried `originalTrigger` and `normalizedTrigger` fields (defined in `schemas/link.schema.json`), and the `trigger-collision` rule keyed on the normalized value — but no spec prose documented **how** to normalize. The pipeline lived only in `AGENTS.md §Decisions already locked` and in `ROADMAP.md` as a one-line Step 6 bullet. That left implementations free to diverge, which silently breaks the `trigger-collision` rule across implementations (two conforming CLIs could disagree on whether `hacer-review` and `Hacer Review` collide).
|
|
207
|
+
|
|
208
|
+
Added under `architecture.md §Extension kinds`, paralleling the existing `Adapter · defaultRefreshAction` subsection:
|
|
209
|
+
|
|
210
|
+
- **Detector · trigger normalization** — field contract, normative 6-step pipeline, and 8 worked examples.
|
|
211
|
+
|
|
212
|
+
Pipeline (applied in exactly this order):
|
|
213
|
+
|
|
214
|
+
1. Unicode NFD.
|
|
215
|
+
2. Strip Unicode `Mn` (diacritics).
|
|
216
|
+
3. Lowercase (locale-independent).
|
|
217
|
+
4. Separator unification: hyphen / underscore / any whitespace run → single ASCII space.
|
|
218
|
+
5. Collapse whitespace (run of ≥2 spaces → 1 space).
|
|
219
|
+
6. Trim leading/trailing whitespace.
|
|
220
|
+
|
|
221
|
+
Non-letter / non-digit characters outside the separator set (`/`, `@`, `:`, `.`, etc.) are **preserved** — stripping them is the detector's concern, not the normalizer's. This keeps namespaced invocations (`/skill-map:explore`, `@my-plugin/foo`) comparable in their intended form.
|
|
222
|
+
|
|
223
|
+
§Stability in `architecture.md` updated: adding a new step at the end is a minor bump; reordering, removing, or changing any existing step (including the character classes in step 4) is a major bump. Implementations that produce different `normalizedTrigger` output for equivalent input are non-conforming.
|
|
224
|
+
|
|
225
|
+
Classification: minor. The pipeline was always the intent (Decision #21 existed since the 2026-04-19 session) and `schemas/link.schema.json` already carried the fields, but this is the first time the spec prose binds implementations to a specific algorithm. A strict v0 implementation that did not normalize (or normalized differently) would begin failing conformance at the next spec release; worth a minor bump so plugin authors and alternative impls see it in the changelog.
|
|
226
|
+
|
|
227
|
+
Companion prose in `ROADMAP.md §Trigger normalization` (Decision #21 now points here for full rationale + examples).
|
|
228
|
+
|
|
229
|
+
### Patch Changes
|
|
230
|
+
|
|
231
|
+
- 334c51a: Clarify `sm orphans undo-rename` signature in `spec/cli-contract.md §Browse` by surfacing the `[--from <old.path>]` flag in the command cell itself.
|
|
232
|
+
|
|
233
|
+
The flag was already documented prose-only in `spec/db-schema.md §Rename heuristic` ("`auto-rename-ambiguous` issues ... `sm orphans undo-rename` requires the user to pass `--from <old.path>` to disambiguate") but was absent from the signature in the `cli-contract.md` table. A reader consulting only the CLI contract would miss the flag and assume the command took `<new.path>` alone.
|
|
234
|
+
|
|
235
|
+
The row now:
|
|
236
|
+
|
|
237
|
+
- Shows `[--from <old.path>] [--force]` in the signature.
|
|
238
|
+
- Explicitly distinguishes the `auto-rename-medium` case (omit `--from`, previous path read from `issue.data_json`) from `auto-rename-ambiguous` (REQUIRES `--from` to pick from `data_json.candidates`).
|
|
239
|
+
- Adds an exit-`5` condition for `--from` referencing a path not in `candidates`.
|
|
240
|
+
|
|
241
|
+
No behavioural change — the flag was already normative and implementations were already expected to support it. Classification: patch (clarifying drift between two spec prose docs, not a new capability).
|
|
242
|
+
|
|
243
|
+
- 93ffe34: Split `sm db reset` into three explicit levels of destruction, each with distinct semantics.
|
|
244
|
+
|
|
245
|
+
Before: `sm db reset` dropped BOTH `scan_*` and `state_*` in one command — so a user who wanted "please rescan from scratch" would wipe their job history, summaries, enrichment, and plugin KV data. The "reset" name suggested a soft operation; the behavior was aggressive.
|
|
246
|
+
|
|
247
|
+
After:
|
|
248
|
+
|
|
249
|
+
- `sm db reset` — drops `scan_*` only. Keeps `state_*` and `config_*`. Non-destructive, no prompt. Equivalent to asking for a fresh scan.
|
|
250
|
+
- `sm db reset --state` — also drops `state_*` and every `plugin_<normalized_id>_*` table (mode B) plus `state_plugin_kvs` (mode A). Keeps `config_*`. Destructive; requires confirmation unless `--yes` (or `--force`, kept as an alias).
|
|
251
|
+
- `sm db reset --hard` — deletes the DB file entirely. Keeps the plugins folder on disk. Destructive; requires confirmation unless `--yes`.
|
|
252
|
+
|
|
253
|
+
Updated files:
|
|
254
|
+
|
|
255
|
+
- `spec/cli-contract.md` §Database — new table rows and a rewritten confirmation paragraph.
|
|
256
|
+
- `spec/db-schema.md` §Zones — one-liner rewritten to list all three levels.
|
|
257
|
+
- `spec/plugin-kv-api.md` §Scope and lifecycle — three bullets replacing the single prior bullet, explicit about which reset level touches plugin storage.
|
|
258
|
+
|
|
259
|
+
Classification: patch in intent but **behavior-changing for `sm db reset` without modifier**. Implementations of `v0.x` that currently drop `state_*` on `sm db reset` MUST narrow the behavior; users relying on the old "reset = wipe everything below config" workflow must switch to `sm db reset --state`. Classified as patch because the spec is pre-1.0 and no implementation has shipped the CLI yet (Step 1a lands storage + the `sm db *` verbs together — this is the first time the boundary is normative in code).
|
|
260
|
+
|
|
261
|
+
Companion prose updates in `ROADMAP.md` §DB management commands and §Step 1a acceptance list.
|
|
262
|
+
|
|
263
|
+
- 93ffe34: Editorial pass: remove "MVP" terminology from four prose documents.
|
|
264
|
+
|
|
265
|
+
The project shipped two competing readings of "MVP" — sometimes "CUT 1 / `v0.5.0`", sometimes "the whole product through `v1.0`". That drift produced contradictions in companion docs (e.g. the summarizer pattern: was `v0.8.0` or `v0.5.0` supposed to ship them?). To close the ambiguity once, `ROADMAP.md` and `AGENTS.md` standardised on `CUT 1` / `CUT 2` / `CUT 3` and `post-v1.0` in the same audit window. This change brings the four spec prose touches that still said "MVP" into the same vocabulary.
|
|
266
|
+
|
|
267
|
+
- **`cli-contract.md` §Jobs**: `sm job run --all` description `(MVP: sequential)` → `(sequential through v1.0; in-runner parallelism deferred)`.
|
|
268
|
+
- **`job-events.md` §Event catalog**: `(post-MVP)` parallel-run note → `(deferred to post-v1.0)`.
|
|
269
|
+
- **`job-lifecycle.md` §Concurrency**: `MVP (v0.x): one job at a time.` → `Through v1.0 (spec v0.x): one job at a time.`
|
|
270
|
+
- **`plugin-kv-api.md` §Backup and retention**: `sm plugins forget <id> (post-MVP)` → `sm plugins forget <id> (deferred to post-v1.0)`.
|
|
271
|
+
|
|
272
|
+
Classification: patch. Editorial only — no schema, exit code, verb signature, or MUST/SHOULD statement changes meaning. All four replacements preserve the technical content; only the label changes from project-scoped ("MVP") to version-scoped (`v1.0`), which is the convention the rest of the spec already uses. Integrity block regenerated.
|
|
273
|
+
|
|
274
|
+
- 93ffe34: Refresh the `spec/README.md` §Repo layout tree so it matches reality.
|
|
275
|
+
|
|
276
|
+
The previous tree was frozen at the Step 0a snapshot and listed only 20 schemas (9 top-level + 6 frontmatter + 5 summaries) plus outdated `(Step 0a phase N)` annotations. The actual spec ships 29 schemas (11 top-level + 7 extension + 6 frontmatter + 5 summaries) and the package adds `index.json` and `package.json`.
|
|
277
|
+
|
|
278
|
+
Changes:
|
|
279
|
+
|
|
280
|
+
- Show the full set of 29 JSON Schemas with a brace grouping per bucket, making the counts and the `allOf` inheritance (frontmatter kinds → base; summaries → report-base) legible at a glance.
|
|
281
|
+
- Add the missing top-level schemas `conformance-case.schema.json` and `history-stats.schema.json`.
|
|
282
|
+
- Add the whole `schemas/extensions/` folder (base + one per extension kind) — validated at plugin load.
|
|
283
|
+
- List `package.json` and `index.json` explicitly so external readers know they are published assets.
|
|
284
|
+
- Drop `(Step 0a phase N)` annotations — Step 0a is complete, the marker is noise.
|
|
285
|
+
- Under `conformance/cases/`, note `basic-scan` and `kernel-empty-boot` as the two shipped cases and point at `../ROADMAP.md` for the deferred `preamble-bitwise-match` case.
|
|
286
|
+
- Under `interfaces/`, clarify that `security-scanner.md` is a convention over the Action kind, NOT a 7th extension kind — the six kinds remain locked.
|
|
287
|
+
|
|
288
|
+
Classification: patch. Editorial prose only — no normative schema, rule, or contract changes. Companion updates to `ROADMAP.md` (repo layout + package layout) ship alongside; they are outside the spec package and do not need a changeset.
|
|
289
|
+
|
|
290
|
+
- d41b9ae: Promote the casing rule from implicit (stated only in `CHANGELOG.md` §Conventions locked and in individual schema descriptions) to explicit, with a new **Naming conventions** section in `spec/README.md`. Two rules, both normative:
|
|
291
|
+
|
|
292
|
+
- **Filesystem artefacts in kebab-case**: every file, directory, enum value, and `issue.ruleId` value. Values stay URL/filename/log-key safe without escaping.
|
|
293
|
+
- **JSON content in camelCase**: every key in schemas, frontmatter, configs, manifests, job records, reports, event payloads, API responses. The SQL layer (`snake_case`) is the sole exception, bridged by the storage adapter.
|
|
294
|
+
|
|
295
|
+
Companion alignment in `spec/db-schema.md` §Rename detection: the prose mixed column names (`body_hash`, `frontmatter_hash`, `rule_id`, `data_json`) with domain-object references. The heuristic is specified against the domain types (`bodyHash`, `frontmatterHash`, `ruleId`, `data`) as defined in `node.schema.json` / `issue.schema.json`; the SQLite columns are the storage shape, not the contract. Added a one-line casing note that points back to §Naming conventions so the bridge is explicit.
|
|
296
|
+
|
|
297
|
+
Classification: patch. The rule itself is unchanged — it was already enforced by every shipped schema and repeated in `CHANGELOG.md`. The additions are purely documentary so new implementers find the rule without digging through the changelog, and so the rename-detection prose stops looking like it references SQLite-specific identifiers when it means domain-object fields.
|
|
298
|
+
|
|
299
|
+
- 93ffe34: Clarify the TTL resolution procedure in `spec/job-lifecycle.md`.
|
|
300
|
+
|
|
301
|
+
The previous text defined the formula as `ttlSeconds = max(expectedDurationSeconds × graceMultiplier, minimumTtlSeconds)` and said the precedence chain was `global default → manifest → user config → flag`. Two problems:
|
|
302
|
+
|
|
303
|
+
- When `expectedDurationSeconds` is absent from the manifest (typical for `mode: local` actions), the formula is undefined. The existing config key `jobs.ttlSeconds` was documented elsewhere as a "global fallback" but never tied into the formula.
|
|
304
|
+
- The word "precedence" collapsed three distinct mechanisms — base value selection, formula application, and full override — into one list, so `minimumTtlSeconds` (a floor, never a default) appeared as the first entry of a "later wins" chain.
|
|
305
|
+
|
|
306
|
+
This patch rewrites the §TTL precedence section as §TTL resolution, split into three explicit steps:
|
|
307
|
+
|
|
308
|
+
1. **Base duration**: manifest `expectedDurationSeconds` OR config `jobs.ttlSeconds` (default `3600`).
|
|
309
|
+
2. **Computed TTL**: `max(base × graceMultiplier, minimumTtlSeconds)`.
|
|
310
|
+
3. **Overrides** (later wins, skips formula): `jobs.perActionTtl.<actionId>`, then `--ttl` flag.
|
|
311
|
+
|
|
312
|
+
Five worked examples added. Negative / zero overrides are rejected at submit time (exit 2). A Stability note states the procedure is locked going forward — new override sources are minor, formula-shape changes are major. The §Submit checklist step 5 now references the new §TTL resolution section instead of inlining a broken one-liner.
|
|
313
|
+
|
|
314
|
+
Classification: patch. No field or schema changed. Every existing manifest and config combination resolves to the same TTL except for the previously-undefined case (manifest without `expectedDurationSeconds`), which was silently implementation-defined; the new text makes the `jobs.ttlSeconds` fallback normative. Companion prose updates land in `ROADMAP.md §TTL per action` and §Notable config keys.
|
|
315
|
+
|
|
3
316
|
## 0.2.1
|
|
4
317
|
|
|
5
318
|
### Patch Changes
|
|
@@ -74,6 +387,12 @@ Tag convention: `spec-vX.Y.Z` (distinct from CLI tags `cli-vX.Y.Z`).
|
|
|
74
387
|
|
|
75
388
|
Initial public spec bootstrap (Step 0a phases 1–3).
|
|
76
389
|
|
|
390
|
+
### Changed
|
|
391
|
+
|
|
392
|
+
- `cli-contract.md`: `--all` is no longer a global flag. It is valid only on verbs that explicitly document fan-out semantics: `sm job submit`, `sm job run`, `sm job cancel`, and `sm plugins enable/disable`.
|
|
393
|
+
- `job-events.md`: the common `runId` envelope now explicitly documents the optional mode segment (`r-<mode>-YYYYMMDD-HHMMSS-XXXX`) used by external Skill claims, scan runs, and standalone issue recomputations.
|
|
394
|
+
- `versioning.md` and related prose: replace ambiguous milestone terminology with explicit versioned release language.
|
|
395
|
+
|
|
77
396
|
### Added
|
|
78
397
|
|
|
79
398
|
- Foundation:
|
|
@@ -88,7 +407,7 @@ Initial public spec bootstrap (Step 0a phases 1–3).
|
|
|
88
407
|
- `architecture.md` — hexagonal ports & adapters; 5 ports (`StoragePort`, `FilesystemPort`, `PluginLoaderPort`, `RunnerPort`, `ProgressEmitterPort`); 6 extension kinds (Adapter, Detector, Rule, Action, Audit, Renderer); kernel boundary + forbidden/permitted imports.
|
|
89
408
|
- `cli-contract.md` — CLI surface: global flags, env vars, 30+ verbs (`sm init`, `sm scan`, `sm list`, `sm show`, `sm check`, `sm findings`, `sm graph`, `sm export`, `sm job *`, `sm record`, `sm history`, `sm plugins *`, `sm audit *`, `sm db *`, `sm serve`, `sm help`), exit codes (0–5 defined, 6–15 reserved), `--json` output rules, `--format json|md|human` introspection.
|
|
90
409
|
- `dispatch-lifecycle.md` — job state machine (queued → running → completed | failed), atomic claim (`UPDATE ... RETURNING id`), duplicate prevention via `contentHash`, TTL with auto-reap, nonce authentication for `sm record`, sequential concurrency for MVP, retention and GC.
|
|
91
|
-
- `job-events.md` — canonical event stream: envelope (`type`, `timestamp`, `runId`, `jobId`, `data`),
|
|
410
|
+
- `job-events.md` — canonical event stream: envelope (`type`, `timestamp`, `runId`, `jobId`, `data`), 11 canonical event types (`run.started`, `run.reap.started`, `run.reap.completed`, `job.claimed`, `job.skipped`, `job.spawning`, `model.delta`, `job.callback.received`, `job.completed`, `job.failed`, `run.summary`) plus one synthetic error event (`emitter.error`, emitted only on serialization failure), three output adapters (`pretty`, `stream-output`, `json`), ordering rules.
|
|
92
411
|
- `prompt-preamble.md` — verbatim normative preamble text that the kernel prepends to every rendered job file; `<user-content id="...">` delimiter contract with zero-width-space escaping; `safety` + `confidence` contract on model output; conformance fixture at `conformance/fixtures/preamble-v1.txt`.
|
|
93
412
|
- `db-schema.md` — engine-agnostic table catalog: three zones (`scan_*`, `state_*`, `config_*`), naming conventions (snake*case, zone prefix, `_at` / `_ms` / `_hash` / `_json` / `_count` suffixes, `is*`/`has\_` prefixes), kernel table list per zone, migration rules (`.sql`files,`NNN_snake_case.sql`, up-only, auto-backup), plugin storage modes.
|
|
94
413
|
- `plugin-kv-api.md` — `ctx.store` contract for mode A (`KvStore.get/set/delete/list`, plugin-scoped, optional node-scoped), mode B dedicated-tables rules (prefix injection, DDL validation, scoped Database wrapper), typed errors (`KvKeyInvalidError`, `KvValueNotSerializableError`, `KvValueTooLargeError`, `KvOperationFailedError`, `ScopedDbViolationError`). Mixing modes in a plugin is forbidden.
|
|
@@ -99,7 +418,7 @@ Initial public spec bootstrap (Step 0a phases 1–3).
|
|
|
99
418
|
|
|
100
419
|
- JSON Schema dialect: draft 2020-12.
|
|
101
420
|
- Casing: camelCase for all JSON keys (domain, configs, manifests, reports); kebab-case for filenames.
|
|
102
|
-
- `$id` scheme: `https://skill-map.dev/spec/v<major>/<path>.schema.json`. `v0` throughout pre-1.0; bumps to `v1` at the first stable
|
|
421
|
+
- `$id` scheme: `https://skill-map.dev/spec/v<major>/<path>.schema.json`. `v0` throughout pre-1.0; bumps to `v1` at the first stable release.
|
|
103
422
|
- Identity: `node.path` (relative to scope root) is the canonical node identifier in v0. Future UUID-based `node.id` lands with write-back.
|
|
104
423
|
- Required frontmatter: `name`, `description`, `metadata`, `metadata.version`.
|
|
105
424
|
- Frontmatter: `additionalProperties: true` (rules handle unknown fields). Summaries: `additionalProperties: false` (strict).
|
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ This document is the **source of truth**. The reference implementation under `..
|
|
|
13
13
|
- The **job contract**: lifecycle states, event stream, prompt preamble, submit/claim/record semantics.
|
|
14
14
|
- The **frontmatter standard**: base fields and per-kind extensions.
|
|
15
15
|
- The **summary standard**: shape of action-produced summaries per kind.
|
|
16
|
-
- The **plugin manifest**: metadata,
|
|
16
|
+
- The **plugin manifest**: metadata, `specCompat` range, storage mode, security declarations.
|
|
17
17
|
|
|
18
18
|
## What this spec does not define
|
|
19
19
|
|
|
@@ -34,48 +34,76 @@ These are implementation decisions. The reference impl picks them (see `../CLAUD
|
|
|
34
34
|
- **Platform-neutral**: no platform (Claude Code, Obsidian, …) is privileged. Each is expressed as an adapter extension.
|
|
35
35
|
- **Conformance-tested**: every conforming implementation passes the suite under `conformance/`. Pass/fail is binary.
|
|
36
36
|
|
|
37
|
+
## Naming conventions
|
|
38
|
+
|
|
39
|
+
Two rules govern every identifier in the spec. They are **normative**.
|
|
40
|
+
|
|
41
|
+
- **Filesystem artefacts use kebab-case.** Every file and directory in `spec/` (and in any conforming implementation) — `scan-result.schema.json`, `job-lifecycle.md`, `report-base.schema.json`, `auto-rename-medium` (as an `issue.ruleId` value), `direct-override` (as a `safety.injectionType` enum value), and so on — is kebab-case lowercase. Enum values and issue rule ids follow the same convention so they can be echoed back into URLs, filenames, and log keys without escaping.
|
|
42
|
+
- **JSON content uses camelCase.** Every key inside a JSON Schema, frontmatter block, config file, plugin manifest, action manifest, job record, report, event payload, or API response is camelCase: `whatItDoes`, `injectionDetected`, `expectedTools`, `conflictsWith`, `docsUrl`, `examplesUrl`, `ttlSeconds`, `runId`, `jobId`. This matches the JS/TS ecosystem the reference impl ships in and the Kysely `CamelCasePlugin` that bridges to the `snake_case` SQL layer — but the rule is spec-level, not implementation-level: an alternative implementation in any language still exposes camelCase JSON keys.
|
|
43
|
+
|
|
44
|
+
The SQL persistence layer is the sole exception: tables, columns, and migration filenames use `snake_case` (see `db-schema.md`). That boundary is crossed only inside a storage adapter; nothing that leaves the kernel should ever be `snake_case`.
|
|
45
|
+
|
|
37
46
|
## Repo layout
|
|
38
47
|
|
|
39
48
|
```
|
|
40
|
-
spec/
|
|
41
|
-
├── README.md
|
|
42
|
-
├── CHANGELOG.md
|
|
43
|
-
├── versioning.md
|
|
44
|
-
├──
|
|
45
|
-
├──
|
|
46
|
-
|
|
47
|
-
├──
|
|
48
|
-
├──
|
|
49
|
-
├──
|
|
50
|
-
├──
|
|
51
|
-
├──
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
│
|
|
55
|
-
|
|
56
|
-
│ ├──
|
|
57
|
-
│ ├──
|
|
58
|
-
│ ├──
|
|
59
|
-
│ ├──
|
|
60
|
-
│ ├──
|
|
61
|
-
│ ├──
|
|
62
|
-
│
|
|
63
|
-
│
|
|
64
|
-
│
|
|
65
|
-
│
|
|
66
|
-
│
|
|
67
|
-
│ │
|
|
68
|
-
│
|
|
69
|
-
│
|
|
70
|
-
│
|
|
71
|
-
│
|
|
72
|
-
│
|
|
73
|
-
│
|
|
49
|
+
spec/ ← published as @skill-map/spec
|
|
50
|
+
├── README.md ← this file
|
|
51
|
+
├── CHANGELOG.md ← spec history (independent from CLI)
|
|
52
|
+
├── versioning.md ← evolution policy
|
|
53
|
+
├── package.json ← npm manifest for @skill-map/spec
|
|
54
|
+
├── index.json ← machine-readable manifest + per-file sha256 (generated)
|
|
55
|
+
│
|
|
56
|
+
├── architecture.md ← hexagonal ports & adapters
|
|
57
|
+
├── cli-contract.md ← verbs, flags, exit codes, JSON introspection
|
|
58
|
+
├── job-events.md ← canonical event stream schema
|
|
59
|
+
├── prompt-preamble.md ← canonical injection-mitigation preamble (verbatim normative)
|
|
60
|
+
├── db-schema.md ← table catalog (kernel-owned)
|
|
61
|
+
├── plugin-kv-api.md ← ctx.store contract for storage mode A
|
|
62
|
+
├── job-lifecycle.md ← queued → running → completed | failed
|
|
63
|
+
│
|
|
64
|
+
├── schemas/ ← 29 JSON Schemas, draft 2020-12, camelCase keys
|
|
65
|
+
│ ├── node.schema.json ┐
|
|
66
|
+
│ ├── link.schema.json │
|
|
67
|
+
│ ├── issue.schema.json │
|
|
68
|
+
│ ├── scan-result.schema.json │
|
|
69
|
+
│ ├── execution-record.schema.json │ 11 top-level
|
|
70
|
+
│ ├── project-config.schema.json │
|
|
71
|
+
│ ├── plugins-registry.schema.json │
|
|
72
|
+
│ ├── job.schema.json │
|
|
73
|
+
│ ├── report-base.schema.json │
|
|
74
|
+
│ ├── conformance-case.schema.json │
|
|
75
|
+
│ ├── history-stats.schema.json ┘
|
|
76
|
+
│ │
|
|
77
|
+
│ ├── extensions/ ← one per extension kind; validated at plugin load
|
|
78
|
+
│ │ ├── base.schema.json ┐
|
|
79
|
+
│ │ ├── adapter.schema.json │
|
|
80
|
+
│ │ ├── detector.schema.json │ 7 extension schemas
|
|
81
|
+
│ │ ├── rule.schema.json │ (base + 6 kinds)
|
|
82
|
+
│ │ ├── action.schema.json │
|
|
83
|
+
│ │ ├── audit.schema.json │
|
|
84
|
+
│ │ └── renderer.schema.json ┘
|
|
85
|
+
│ │
|
|
86
|
+
│ ├── frontmatter/ ← user-authored; additionalProperties: true
|
|
87
|
+
│ │ ├── base.schema.json ┐
|
|
88
|
+
│ │ ├── skill.schema.json │
|
|
89
|
+
│ │ ├── agent.schema.json │ 6 frontmatter schemas
|
|
90
|
+
│ │ ├── command.schema.json │ (base + 5 kinds; each kind
|
|
91
|
+
│ │ ├── hook.schema.json │ extends base via allOf)
|
|
92
|
+
│ │ └── note.schema.json ┘
|
|
93
|
+
│ │
|
|
94
|
+
│ └── summaries/ ← kernel-controlled; additionalProperties: false
|
|
95
|
+
│ ├── skill.schema.json ┐
|
|
96
|
+
│ ├── agent.schema.json │ 5 summaries (each extends
|
|
97
|
+
│ ├── command.schema.json │ report-base via allOf)
|
|
98
|
+
│ ├── hook.schema.json │
|
|
99
|
+
│ └── note.schema.json ┘
|
|
100
|
+
│
|
|
74
101
|
├── interfaces/
|
|
75
|
-
│ └── security-scanner.md
|
|
102
|
+
│ └── security-scanner.md ← convention over the Action kind (NOT a 7th extension kind)
|
|
76
103
|
└── conformance/
|
|
77
|
-
├── fixtures/
|
|
78
|
-
└── cases/
|
|
104
|
+
├── fixtures/ ← controlled MD corpora + preamble-v1.txt
|
|
105
|
+
└── cases/ ← declarative test cases: basic-scan, kernel-empty-boot
|
|
106
|
+
(preamble-bitwise-match deferred to ../ROADMAP.md Step 9)
|
|
79
107
|
```
|
|
80
108
|
|
|
81
109
|
## How to read this spec
|
|
@@ -110,7 +138,8 @@ npm i @skill-map/spec
|
|
|
110
138
|
import specIndex from '@skill-map/spec';
|
|
111
139
|
import nodeSchema from '@skill-map/spec/schemas/node.schema.json' with { type: 'json' };
|
|
112
140
|
|
|
113
|
-
console.log(specIndex.
|
|
141
|
+
console.log(specIndex.specPackageVersion); // → "0.2.0" (npm package version; source of truth for `spec` in `sm version`)
|
|
142
|
+
console.log(specIndex.indexPayloadVersion); // → "0.0.1" (payload shape of `index.json` itself; bumps only when this manifest's structure changes)
|
|
114
143
|
console.log(specIndex.integrity.algorithm); // → "sha256"
|
|
115
144
|
console.log(nodeSchema.$id); // → "https://skill-map.dev/spec/v0/node.schema.json"
|
|
116
145
|
```
|
package/architecture.md
CHANGED
|
@@ -77,7 +77,7 @@ Two reference implementations:
|
|
|
77
77
|
- `ClaudeCliRunner` — subprocess `claude -p < jobfile`.
|
|
78
78
|
- `MockRunner` — deterministic fake for tests.
|
|
79
79
|
|
|
80
|
-
The Skill
|
|
80
|
+
The **Skill agent** does NOT implement this port: it is a peer driving adapter (alongside CLI and Server) that runs inside an LLM session and consumes `sm job claim` + `sm record` as a kernel client. The name "Skill runner" is descriptive, not structural — only the `ClaudeCliRunner` (and its test fake) implement `RunnerPort`. See `job-lifecycle.md`.
|
|
81
81
|
|
|
82
82
|
### `ProgressEmitterPort`
|
|
83
83
|
|
|
@@ -117,17 +117,56 @@ No extension is privileged. The Claude adapter ships bundled with the reference
|
|
|
117
117
|
|
|
118
118
|
## Extension kinds
|
|
119
119
|
|
|
120
|
-
Six kinds, all first-class, all loaded through the same registry. Each kind has a JSON Schema describing its manifest shape
|
|
120
|
+
Six kinds, all first-class, all loaded through the same registry. Each kind has a JSON Schema describing its manifest shape under `spec/schemas/extensions/<kind>.schema.json`. Implementations MUST validate every extension manifest against the schema for its declared kind at load time; validation failure → the extension is skipped with status `invalid-manifest`.
|
|
121
121
|
|
|
122
122
|
| Kind | Role | Input | Output |
|
|
123
123
|
|---|---|---|---|
|
|
124
|
-
| **Adapter** | Recognizes a platform. Decides which files are nodes and what kind they are. | Filesystem walk results, candidate path. | `{ kind, adapter } \| null`. |
|
|
124
|
+
| **Adapter** | Recognizes a platform. Decides which files are nodes and what kind they are. Declares per-kind `defaultRefreshAction` (an action id that drives the probabilistic-refresh surface). | Filesystem walk results, candidate path. | `{ kind, adapter } \| null`. |
|
|
125
125
|
| **Detector** | Extracts signals from a node body. | Parsed node (frontmatter + body). | `Link[]`. |
|
|
126
126
|
| **Rule** | Evaluates the graph. | Full graph (nodes + links). | `Issue[]`. |
|
|
127
127
|
| **Action** | Operates on one or more nodes. Two modes: `local` (code) or `invocation-template` (LLM prompt). | Node(s), optional args. | Local: report JSON. Template: rendered prompt that a runner executes. |
|
|
128
128
|
| **Audit** | Deterministic workflow that composes rules and actions. Produces a structured report. | Graph + optional scope filter. | Audit report (hardcoded shape, kind-specific). |
|
|
129
129
|
| **Renderer** | Serializes the graph. | Graph + optional filter. | String (ASCII / Mermaid / DOT / JSON / user-defined). |
|
|
130
130
|
|
|
131
|
+
### Adapter · `defaultRefreshAction`
|
|
132
|
+
|
|
133
|
+
Every `Adapter` extension MUST declare a map `defaultRefreshAction: { <kind>: <actionId> }` covering every `kind` it emits. The referenced action MUST exist in the registry by the time the graph is queried; a dangling reference is a load-time error for the adapter. Consumers (CLI `🧠 prob` buttons in `sm show`, Web UI inspector) dispatch `sm job submit <defaultRefreshAction[kind]> -n <nodePath>` when the user asks for a probabilistic refresh on a node. Implementations MAY allow plugins to override the default per-node via `metadata.refreshAction`, but the adapter default is normative.
|
|
134
|
+
|
|
135
|
+
### Detector · trigger normalization
|
|
136
|
+
|
|
137
|
+
Detectors that emit invocation-style links (slashes, at-directives, command names) populate the `link.trigger` block defined in `schemas/link.schema.json`:
|
|
138
|
+
|
|
139
|
+
- `originalTrigger` — the exact source text the detector saw, byte-for-byte. Used only for display.
|
|
140
|
+
- `normalizedTrigger` — the output of the pipeline below. Used for equality and collision detection — the built-in `trigger-collision` rule keys on this field.
|
|
141
|
+
|
|
142
|
+
Both fields MUST be present whenever `link.trigger` is non-null. Implementations MUST produce byte-identical `normalizedTrigger` output for byte-identical input across platforms and locales.
|
|
143
|
+
|
|
144
|
+
#### Normalization pipeline (normative)
|
|
145
|
+
|
|
146
|
+
Applied in exactly this order:
|
|
147
|
+
|
|
148
|
+
1. **Unicode NFD** — canonical decomposition (`String.prototype.normalize('NFD')` in JS).
|
|
149
|
+
2. **Strip diacritics** — remove every code point in Unicode category `Mn` (Nonspacing_Mark).
|
|
150
|
+
3. **Lowercase** — locale-independent Unicode lowercase.
|
|
151
|
+
4. **Separator unification** — replace every hyphen (`-`), underscore (`_`), and run of whitespace (space, tab, newline, NBSP, …) with a single ASCII space.
|
|
152
|
+
5. **Collapse whitespace** — runs of two or more spaces become one.
|
|
153
|
+
6. **Trim** — strip leading and trailing whitespace.
|
|
154
|
+
|
|
155
|
+
Characters outside the separator set that are not letters or digits (e.g. `/`, `@`, `:`, `.`) are **preserved**. Stripping them is the detector's concern, not the normalizer's — the normalizer operates on whatever the detector classifies as "the trigger text". This keeps namespaced invocations like `/skill-map:explore` or `@my-plugin/foo` comparable in their intended form.
|
|
156
|
+
|
|
157
|
+
#### Examples
|
|
158
|
+
|
|
159
|
+
| `originalTrigger` | `normalizedTrigger` |
|
|
160
|
+
|---|---|
|
|
161
|
+
| `Hacer Review` | `hacer review` |
|
|
162
|
+
| `hacer-review` | `hacer review` |
|
|
163
|
+
| `hacer_review` | `hacer review` |
|
|
164
|
+
| ` hacer review ` | `hacer review` |
|
|
165
|
+
| `Clúster` | `cluster` |
|
|
166
|
+
| `/MyCommand` | `/mycommand` |
|
|
167
|
+
| `@FooDetector` | `@foodetector` |
|
|
168
|
+
| `skill-map:explore` | `skill map:explore` |
|
|
169
|
+
|
|
131
170
|
### Contract rules
|
|
132
171
|
|
|
133
172
|
1. An extension declares its kind in its module export and its manifest. Kind mismatch → load-error.
|
|
@@ -200,7 +239,7 @@ Alternative implementations MAY use workspaces, separate packages, or a compiled
|
|
|
200
239
|
The CLI, Server, and Skill driving adapters are **peers**. None depends on another.
|
|
201
240
|
|
|
202
241
|
- The Server MUST NOT call the CLI (no `child_process.spawn('sm', ...)`).
|
|
203
|
-
- The Skill
|
|
242
|
+
- The Skill agent MUST NOT depend on the Server (it can be used offline).
|
|
204
243
|
- The CLI MUST NOT embed HTTP logic.
|
|
205
244
|
|
|
206
245
|
All three consume the same kernel API. Any use case a driving adapter needs MUST be available as a kernel function — if it isn't, the gap is a kernel bug, not a driving-adapter workaround.
|
|
@@ -216,3 +255,5 @@ The **port list** is stable as of spec v1.0.0. Adding a sixth port is a major bu
|
|
|
216
255
|
The **extension kind list** (6 kinds) is stable as of spec v1.0.0. Adding a seventh kind is a major bump.
|
|
217
256
|
|
|
218
257
|
The **dependency rules** above are stable as of spec v1.0.0. Relaxing any is a major bump; tightening (forbidding an allowed import) is a minor bump.
|
|
258
|
+
|
|
259
|
+
The **Detector · trigger normalization** pipeline (six steps, in order) is stable from the next spec release. Adding a new step at the end is a minor bump; reordering, removing, or changing any existing step (including the character classes in step 4) is a major bump. Implementations that produce different `normalizedTrigger` output for equivalent input are non-conforming.
|