@softspark/ai-toolkit 4.23.1 → 4.24.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 +26 -0
- package/README.md +12 -12
- package/app/.claude-plugin/plugin.json +1 -1
- package/app/skills/documentation-standards/SKILL.md +14 -4
- package/app/surface.json +2 -0
- package/kb/reference/plugin-pack-conventions.md +42 -3
- package/llms-full.txt +43 -4
- package/manifest.json +1 -1
- package/package.json +1 -1
- package/scripts/plugin.py +35 -11
- package/scripts/validate.py +14 -3
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,32 @@ Versioning follows [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## v4.24.0 — external packs stop dying on upgrade (2026-08-18)
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **`~/.softspark/ai-toolkit/plugins/` is a second pack root.** Until now
|
|
15
|
+
`plugin.py` scanned exactly one directory — `app/plugins/`, inside the npm
|
|
16
|
+
package — so the only way to add a pack from its own repository was to drop it
|
|
17
|
+
in there, where the next `npm install -g @softspark/ai-toolkit` deleted it along
|
|
18
|
+
with the rest of `app/`. External packs now live in the user-owned data dir and
|
|
19
|
+
survive every upgrade. `plugin list`, `install`, `update`, `remove` and `status`
|
|
20
|
+
all see both roots; `AI_TOOLKIT_HOME` moves the user root with the data dir.
|
|
21
|
+
|
|
22
|
+
A **core pack wins a name collision**, so an external directory cannot shadow
|
|
23
|
+
shipped behaviour. Each pack dict carries `_root` (`core` or `user`) — `_source`
|
|
24
|
+
was already taken as the hook-ownership marker.
|
|
25
|
+
|
|
26
|
+
The entry may be a directory or a **symlink**, which is what gives an external
|
|
27
|
+
pack a versioned update path: point it at an npm-installed package and
|
|
28
|
+
`npm install -g <pack>@latest` rewrites the target in place, with nothing to
|
|
29
|
+
re-link. Documented in `kb/reference/plugin-pack-conventions.md`
|
|
30
|
+
(*Where Packs Live*), including the per-scope registry caveat when one package
|
|
31
|
+
in a scope is public and another private.
|
|
32
|
+
|
|
33
|
+
- **Three tests.** A pack in the user root is listed, installs with both its agent
|
|
34
|
+
and skill linked back into that root, and loses a name collision to a core pack.
|
|
35
|
+
|
|
10
36
|
## v4.23.1 — a pack could ship an agent nobody installed (2026-08-18)
|
|
11
37
|
|
|
12
38
|
### Fixed
|
package/README.md
CHANGED
|
@@ -6,18 +6,18 @@
|
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
[](app/skills/)
|
|
8
8
|
[](app/agents/)
|
|
9
|
-
[](tests/)
|
|
10
|
+
|
|
11
|
+
## What's New in v4.24.0
|
|
12
|
+
|
|
13
|
+
**v4.24.0** — a plugin pack maintained in its own repository had nowhere safe to
|
|
14
|
+
live: the only directory the toolkit scanned was `app/plugins/`, inside the npm
|
|
15
|
+
package, so every `npm install -g` upgrade deleted it. Packs now also load from
|
|
16
|
+
`~/.softspark/ai-toolkit/plugins/`, which the user owns and upgrades never touch.
|
|
17
|
+
The entry can be a symlink to an npm-installed package, so updating an external
|
|
18
|
+
pack is one `npm install -g` with nothing to re-link. Core packs still win a name
|
|
19
|
+
collision. Ships with v4.23.1's fix for pack-shipped agents, which the same
|
|
20
|
+
external-pack workflow depends on.
|
|
21
21
|
|
|
22
22
|
See [CHANGELOG.md](CHANGELOG.md) for full history.
|
|
23
23
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "ai-toolkit",
|
|
4
4
|
"displayName": "AI Toolkit",
|
|
5
5
|
"description": "Professional-grade engineering skills, agents, rules, and lifecycle guardrails for Claude Code, Claude Chat, and Cowork.",
|
|
6
|
-
"version": "4.
|
|
6
|
+
"version": "4.24.0",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "SoftSpark",
|
|
9
9
|
"url": "https://github.com/softspark"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: documentation-standards
|
|
3
|
-
description: "KB conventions: YAML frontmatter,
|
|
3
|
+
description: "KB conventions: YAML frontmatter, 10-category taxonomy (reference/howto/procedures/troubleshooting/best-practices/decisions/runbooks/planning/business/templates). Triggers: kb/, SOP, runbook, howto, frontmatter, knowledge base."
|
|
4
4
|
effort: medium
|
|
5
5
|
user-invocable: false
|
|
6
6
|
allowed-tools: Read
|
|
@@ -17,7 +17,7 @@ Every document in `kb/` MUST start with YAML frontmatter:
|
|
|
17
17
|
```yaml
|
|
18
18
|
---
|
|
19
19
|
title: "Document Title" # REQUIRED — English, descriptive
|
|
20
|
-
category: reference # REQUIRED — one of
|
|
20
|
+
category: reference # REQUIRED — one of the 10 valid categories
|
|
21
21
|
service: ai-toolkit # REQUIRED — service identifier
|
|
22
22
|
tags: [tag1, tag2, tag3] # REQUIRED — minimum 1, recommended 3+
|
|
23
23
|
last_updated: "YYYY-MM-DD" # REQUIRED — ISO format
|
|
@@ -53,11 +53,21 @@ and never authoritative on its own.
|
|
|
53
53
|
| `decisions` | `kb/decisions/` | Architecture decision records and design rationale | `adr-004-kb-migration.md` |
|
|
54
54
|
| `runbooks` | `kb/runbooks/` | Procedures run against a live system, usually under pressure | `deployment.md`, `incident-response.md` |
|
|
55
55
|
| `planning` | `kb/planning/` | Roadmaps, PRDs, work not yet done | `q3-roadmap.md` |
|
|
56
|
+
| `business` | `kb/business/` | Domain model, requirements, use cases, user stories | `domain-model.md`, `user-stories.md` |
|
|
57
|
+
| `templates` | `kb/templates/` | Reusable document templates | `adr-template.md`, `sop-template.md` |
|
|
56
58
|
|
|
57
59
|
**Rule:** A document filed under one of the directories above MUST declare that
|
|
58
60
|
category. The rule is scoped to those directories deliberately: `kb/history/`
|
|
59
|
-
and
|
|
60
|
-
under `history/completed/` is still a `planning` document.
|
|
61
|
+
and `kb/summaries/` are lifecycle and runtime locations rather than types, and a
|
|
62
|
+
finished plan filed under `history/completed/` is still a `planning` document.
|
|
63
|
+
|
|
64
|
+
**Templates carry placeholders on purpose.** A file under `templates/` exists to
|
|
65
|
+
be copied, so a literal `YYYY-MM-DD` date and `[placeholder]` body text are
|
|
66
|
+
correct there rather than defects. Every other convention still applies.
|
|
67
|
+
|
|
68
|
+
This taxonomy lives in three places: ai-toolkit's `scripts/validate.py`,
|
|
69
|
+
rag-mcp's `scripts/validate_kb_frontmatter.py`, and this document. They are one
|
|
70
|
+
list, and a change belongs in all three.
|
|
61
71
|
|
|
62
72
|
## Naming Conventions
|
|
63
73
|
|
package/app/surface.json
CHANGED
|
@@ -230,12 +230,14 @@
|
|
|
230
230
|
],
|
|
231
231
|
"kb_categories": [
|
|
232
232
|
"best-practices",
|
|
233
|
+
"business",
|
|
233
234
|
"decisions",
|
|
234
235
|
"howto",
|
|
235
236
|
"planning",
|
|
236
237
|
"procedures",
|
|
237
238
|
"reference",
|
|
238
239
|
"runbooks",
|
|
240
|
+
"templates",
|
|
239
241
|
"troubleshooting"
|
|
240
242
|
],
|
|
241
243
|
"cli_commands": [
|
|
@@ -3,9 +3,9 @@ title: "Plugin Pack Conventions"
|
|
|
3
3
|
category: reference
|
|
4
4
|
service: ai-toolkit
|
|
5
5
|
tags: [plugins, plugin-packs, conventions, manifests, hooks, policy-packs]
|
|
6
|
-
version: "1.
|
|
6
|
+
version: "1.2.0"
|
|
7
7
|
created: "2026-03-28"
|
|
8
|
-
last_updated: "2026-
|
|
8
|
+
last_updated: "2026-08-18"
|
|
9
9
|
description: "Conventions for experimental ai-toolkit plugin packs, policy packs, hook packs, and plugin-creator scaffolding across Claude Code and Codex runtimes."
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -13,7 +13,46 @@ description: "Conventions for experimental ai-toolkit plugin packs, policy packs
|
|
|
13
13
|
|
|
14
14
|
## Purpose
|
|
15
15
|
|
|
16
|
-
`ai-toolkit` includes experimental plugin packs under `app/plugins/` for Claude Code and optional global Codex layering. These internal pack manifests are distinct from the official uploadable Claude app plugin built by `ai-toolkit claude-app export`.
|
|
16
|
+
`ai-toolkit` includes experimental plugin packs under `app/plugins/` for Claude Code and optional global Codex layering, and discovers external packs under `~/.softspark/ai-toolkit/plugins/` (see *Where Packs Live*). These internal pack manifests are distinct from the official uploadable Claude app plugin built by `ai-toolkit claude-app export`.
|
|
17
|
+
|
|
18
|
+
## Where Packs Live
|
|
19
|
+
|
|
20
|
+
| Root | Owner | Survives `npm install -g @softspark/ai-toolkit` | Use for |
|
|
21
|
+
|------|-------|------------------------------------------------|---------|
|
|
22
|
+
| `app/plugins/<pack>/` | this repository | no — the upgrade replaces `app/` wholesale | packs shipped with the toolkit (`memory-pack`, `enterprise-pack`) |
|
|
23
|
+
| `~/.softspark/ai-toolkit/plugins/<pack>/` | the user | **yes** | external / private packs maintained in their own repository |
|
|
24
|
+
|
|
25
|
+
Both roots are scanned by `plugin list`, `install`, `update`, `remove` and
|
|
26
|
+
`status`. A **core pack wins a name collision**, so an external directory cannot
|
|
27
|
+
shadow shipped behaviour. `AI_TOOLKIT_HOME` moves the user root along with the
|
|
28
|
+
rest of the toolkit data dir, which is what the test suite uses.
|
|
29
|
+
|
|
30
|
+
Before v4.24.0 there was only the first root, so the only way to add an external
|
|
31
|
+
pack was to drop it inside the npm package — where the next toolkit upgrade
|
|
32
|
+
deleted it. That is what the user root exists to end.
|
|
33
|
+
|
|
34
|
+
### Installing an external pack
|
|
35
|
+
|
|
36
|
+
The entry may be a directory **or a symlink**, which is what gives an external
|
|
37
|
+
pack a versioned update path:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# Distributed as a package (private registry example)
|
|
41
|
+
npm install -g @softspark/<pack> --registry=https://npm.pkg.github.com
|
|
42
|
+
mkdir -p ~/.softspark/ai-toolkit/plugins
|
|
43
|
+
ln -s "$(npm root -g)/@softspark/<pack>" ~/.softspark/ai-toolkit/plugins/<pack>
|
|
44
|
+
ai-toolkit plugin install --editor claude <pack>
|
|
45
|
+
|
|
46
|
+
# Update later: the symlink target is rewritten in place, nothing to re-link
|
|
47
|
+
npm install -g @softspark/<pack>@latest --registry=https://npm.pkg.github.com
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
A plain `git clone` into the same directory works too; update it with `git pull`.
|
|
51
|
+
|
|
52
|
+
> **Scope note:** `npm` resolves a registry per **scope**, not per package. If one
|
|
53
|
+
> package in a scope lives on public npm and another on a private registry, the
|
|
54
|
+
> private one needs `--registry=` on every command — a scope-wide
|
|
55
|
+
> `npm config set @scope:registry` would misroute the public one.
|
|
17
56
|
|
|
18
57
|
## Pack Types
|
|
19
58
|
|
package/llms-full.txt
CHANGED
|
@@ -109,7 +109,7 @@
|
|
|
109
109
|
- **design-engineering**: UI craftsmanship: animation rules, easing, micro-interactions, state polish. Triggers: animation, transition, ease-out, motion, micro-interaction, hover, loading state, UI polish.
|
|
110
110
|
- **docker-devops**: Docker/K8s: Dockerfile, multi-stage, compose, manifests, Helm. Triggers: Docker, Dockerfile, container, Kubernetes, k8s, compose, Helm, pod.
|
|
111
111
|
- **docs**: Generates/updates README, API docs, architecture notes. Triggers: docs, README, API docs, architecture note, documentation.
|
|
112
|
-
- **documentation-standards**: KB conventions: YAML frontmatter,
|
|
112
|
+
- **documentation-standards**: KB conventions: YAML frontmatter, 10-category taxonomy (reference/howto/procedures/troubleshooting/best-practices/decisions/runbooks/planning/business/templates). Triggers: kb/, SOP, runbook, howto, frontmatter, knowledge base.
|
|
113
113
|
- **ecommerce-patterns**: E-commerce: cart, checkout, payments (Stripe/Adyen), order state, inventory, promos, tax. Triggers: cart, checkout, SKU, payment, Stripe, Shopify, Medusa, Magento, coupon, refund.
|
|
114
114
|
- **evaluate**: Evaluates RAG retrieval and LLM-as-judge metrics (faithfulness, relevancy, context precision). Triggers: measure RAG quality, knowledge gap, RAG eval, golden dataset.
|
|
115
115
|
- **evolve**: Analyzes agent/skill failures, drafts prompt/permission fixes. Triggers: improve agent, refine skill, system prompt, optimize agent.
|
|
@@ -14349,9 +14349,9 @@ title: "Plugin Pack Conventions"
|
|
|
14349
14349
|
category: reference
|
|
14350
14350
|
service: ai-toolkit
|
|
14351
14351
|
tags: [plugins, plugin-packs, conventions, manifests, hooks, policy-packs]
|
|
14352
|
-
version: "1.
|
|
14352
|
+
version: "1.2.0"
|
|
14353
14353
|
created: "2026-03-28"
|
|
14354
|
-
last_updated: "2026-
|
|
14354
|
+
last_updated: "2026-08-18"
|
|
14355
14355
|
description: "Conventions for experimental ai-toolkit plugin packs, policy packs, hook packs, and plugin-creator scaffolding across Claude Code and Codex runtimes."
|
|
14356
14356
|
---
|
|
14357
14357
|
|
|
@@ -14359,7 +14359,46 @@ description: "Conventions for experimental ai-toolkit plugin packs, policy packs
|
|
|
14359
14359
|
|
|
14360
14360
|
## Purpose
|
|
14361
14361
|
|
|
14362
|
-
`ai-toolkit` includes experimental plugin packs under `app/plugins/` for Claude Code and optional global Codex layering. These internal pack manifests are distinct from the official uploadable Claude app plugin built by `ai-toolkit claude-app export`.
|
|
14362
|
+
`ai-toolkit` includes experimental plugin packs under `app/plugins/` for Claude Code and optional global Codex layering, and discovers external packs under `~/.softspark/ai-toolkit/plugins/` (see *Where Packs Live*). These internal pack manifests are distinct from the official uploadable Claude app plugin built by `ai-toolkit claude-app export`.
|
|
14363
|
+
|
|
14364
|
+
## Where Packs Live
|
|
14365
|
+
|
|
14366
|
+
| Root | Owner | Survives `npm install -g @softspark/ai-toolkit` | Use for |
|
|
14367
|
+
|------|-------|------------------------------------------------|---------|
|
|
14368
|
+
| `app/plugins/<pack>/` | this repository | no — the upgrade replaces `app/` wholesale | packs shipped with the toolkit (`memory-pack`, `enterprise-pack`) |
|
|
14369
|
+
| `~/.softspark/ai-toolkit/plugins/<pack>/` | the user | **yes** | external / private packs maintained in their own repository |
|
|
14370
|
+
|
|
14371
|
+
Both roots are scanned by `plugin list`, `install`, `update`, `remove` and
|
|
14372
|
+
`status`. A **core pack wins a name collision**, so an external directory cannot
|
|
14373
|
+
shadow shipped behaviour. `AI_TOOLKIT_HOME` moves the user root along with the
|
|
14374
|
+
rest of the toolkit data dir, which is what the test suite uses.
|
|
14375
|
+
|
|
14376
|
+
Before v4.24.0 there was only the first root, so the only way to add an external
|
|
14377
|
+
pack was to drop it inside the npm package — where the next toolkit upgrade
|
|
14378
|
+
deleted it. That is what the user root exists to end.
|
|
14379
|
+
|
|
14380
|
+
### Installing an external pack
|
|
14381
|
+
|
|
14382
|
+
The entry may be a directory **or a symlink**, which is what gives an external
|
|
14383
|
+
pack a versioned update path:
|
|
14384
|
+
|
|
14385
|
+
```bash
|
|
14386
|
+
# Distributed as a package (private registry example)
|
|
14387
|
+
npm install -g @softspark/<pack> --registry=https://npm.pkg.github.com
|
|
14388
|
+
mkdir -p ~/.softspark/ai-toolkit/plugins
|
|
14389
|
+
ln -s "$(npm root -g)/@softspark/<pack>" ~/.softspark/ai-toolkit/plugins/<pack>
|
|
14390
|
+
ai-toolkit plugin install --editor claude <pack>
|
|
14391
|
+
|
|
14392
|
+
# Update later: the symlink target is rewritten in place, nothing to re-link
|
|
14393
|
+
npm install -g @softspark/<pack>@latest --registry=https://npm.pkg.github.com
|
|
14394
|
+
```
|
|
14395
|
+
|
|
14396
|
+
A plain `git clone` into the same directory works too; update it with `git pull`.
|
|
14397
|
+
|
|
14398
|
+
> **Scope note:** `npm` resolves a registry per **scope**, not per package. If one
|
|
14399
|
+
> package in a scope lives on public npm and another on a private registry, the
|
|
14400
|
+
> private one needs `--registry=` on every command — a scope-wide
|
|
14401
|
+
> `npm config set @scope:registry` would misroute the public one.
|
|
14363
14402
|
|
|
14364
14403
|
## Pack Types
|
|
14365
14404
|
|
package/manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@softspark/ai-toolkit",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.24.0",
|
|
4
4
|
"description": "AI coding toolkit: 109 skills, 44 agents, 12 developer-tool integrations, recoverable native tool-output filtering, Claude Chat/Cowork export, safety constitution, SARIF audit, and signed npm provenance.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude",
|
package/scripts/plugin.py
CHANGED
|
@@ -60,6 +60,12 @@ from plugin_schema import resolve_hook_event
|
|
|
60
60
|
|
|
61
61
|
|
|
62
62
|
PLUGINS_DIR = app_dir / "plugins"
|
|
63
|
+
# External packs live outside the npm package so a toolkit upgrade cannot delete
|
|
64
|
+
# them: `npm install -g @softspark/ai-toolkit` replaces app/ wholesale, taking any
|
|
65
|
+
# third-party pack dropped in there with it. TOOLKIT_DATA_DIR is user-owned and
|
|
66
|
+
# survives. The entry may be a directory or a symlink (e.g. to an npm-installed
|
|
67
|
+
# pack), which is how an external pack gets a versioned update path.
|
|
68
|
+
USER_PLUGINS_DIR = TOOLKIT_DATA_DIR / "plugins"
|
|
63
69
|
CLAUDE_DIR = Path.home() / ".claude"
|
|
64
70
|
CODEX_ROOT = Path.home()
|
|
65
71
|
CODEX_HOME = Path(os.environ.get("CODEX_HOME", CODEX_ROOT / ".codex")).expanduser()
|
|
@@ -178,22 +184,40 @@ def _set_installed(state: dict, editor: str, names: list[str]) -> None:
|
|
|
178
184
|
# Plugin discovery
|
|
179
185
|
# ---------------------------------------------------------------------------
|
|
180
186
|
|
|
187
|
+
def plugin_roots() -> list[Path]:
|
|
188
|
+
"""Directories scanned for packs, in precedence order.
|
|
189
|
+
|
|
190
|
+
Core packs ship inside the npm package; user packs live under
|
|
191
|
+
TOOLKIT_DATA_DIR and outlive every toolkit upgrade. A core pack wins a name
|
|
192
|
+
collision so a stray external directory cannot shadow shipped behaviour.
|
|
193
|
+
"""
|
|
194
|
+
return [PLUGINS_DIR, USER_PLUGINS_DIR]
|
|
195
|
+
|
|
196
|
+
|
|
181
197
|
def list_available() -> list[dict]:
|
|
182
|
-
"""List all available plugin packs."""
|
|
198
|
+
"""List all available plugin packs, core first, then user-installed."""
|
|
183
199
|
packs: list[dict] = []
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
manifest = d / "plugin.json"
|
|
188
|
-
if not manifest.is_file():
|
|
200
|
+
seen: set[str] = set()
|
|
201
|
+
for root in plugin_roots():
|
|
202
|
+
if not root.is_dir():
|
|
189
203
|
continue
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
204
|
+
for d in sorted(root.iterdir()):
|
|
205
|
+
manifest = d / "plugin.json"
|
|
206
|
+
if not manifest.is_file():
|
|
207
|
+
continue
|
|
208
|
+
try:
|
|
209
|
+
with open(manifest, encoding="utf-8") as f:
|
|
210
|
+
data = json.load(f)
|
|
211
|
+
except (json.JSONDecodeError, OSError):
|
|
212
|
+
continue
|
|
213
|
+
name = data.get("name")
|
|
214
|
+
if not name or name in seen:
|
|
215
|
+
continue
|
|
216
|
+
seen.add(name)
|
|
193
217
|
data["_dir"] = str(d)
|
|
218
|
+
# "_source" is taken: hook entries use it as an ownership marker.
|
|
219
|
+
data["_root"] = "core" if root == PLUGINS_DIR else "user"
|
|
194
220
|
packs.append(data)
|
|
195
|
-
except (json.JSONDecodeError, OSError):
|
|
196
|
-
continue
|
|
197
221
|
return packs
|
|
198
222
|
|
|
199
223
|
|
package/scripts/validate.py
CHANGED
|
@@ -97,15 +97,26 @@ HOOK_REQUIRED_FIELDS = {
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
# The taxonomy. `app/skills/documentation-standards/SKILL.md` documents the same
|
|
100
|
-
#
|
|
101
|
-
#
|
|
100
|
+
# list and is what authors read; this set is what rejects a typo. rag-mcp holds
|
|
101
|
+
# a third copy in `scripts/validate_kb_frontmatter.py`, which runs against
|
|
102
|
+
# knowledge bases this validator never sees. They are one list in three places,
|
|
103
|
+
# so a change belongs in all of them.
|
|
102
104
|
#
|
|
103
105
|
# `decisions` and `runbooks` were missing until v4.21.0 while the kb-migration
|
|
104
106
|
# SOP had been telling people to create those directories for months, so a
|
|
105
107
|
# correctly-filed ADR failed validation.
|
|
108
|
+
#
|
|
109
|
+
# `business` and `templates` were missing for the same reason: rag-mcp's
|
|
110
|
+
# `add-new-repository-to-rag-mcp.md` mandates `kb/business/` and
|
|
111
|
+
# `kb/templates/`. A directory an SOP mandates must be a category the validator
|
|
112
|
+
# accepts, or the two documents contradict each other.
|
|
113
|
+
#
|
|
114
|
+
# `history/` and `summaries/` are deliberately absent. They are lifecycle and
|
|
115
|
+
# runtime locations, not types: a finished plan under `history/completed/` is
|
|
116
|
+
# still a `planning` document and declares that.
|
|
106
117
|
VALID_KB_CATEGORIES = frozenset({
|
|
107
118
|
"reference", "howto", "procedures", "troubleshooting", "best-practices",
|
|
108
|
-
"decisions", "runbooks", "planning",
|
|
119
|
+
"decisions", "runbooks", "planning", "business", "templates",
|
|
109
120
|
})
|
|
110
121
|
|
|
111
122
|
# Skill body budget, in bytes after the frontmatter block.
|