@cleocode/skills 2026.4.14 → 2026.4.16
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/package.json +1 -1
- package/skills/ct-grade/SKILL.md +16 -2
- package/skills/ct-grade-v2-1/MIGRATION.md +28 -0
- package/skills/ct-master-tac/SKILL.md +116 -0
- package/skills/ct-master-tac/__tests__/install.test.ts +283 -0
- package/skills/ct-master-tac/bundled/README.md +40 -0
- package/skills/ct-master-tac/bundled/protocols/architecture-decision.cant +90 -0
- package/skills/ct-master-tac/bundled/protocols/artifact-publish.cant +105 -0
- package/skills/ct-master-tac/bundled/protocols/consensus.cant +85 -0
- package/skills/ct-master-tac/bundled/protocols/contribution.cant +92 -0
- package/skills/ct-master-tac/bundled/protocols/decomposition.cant +102 -0
- package/skills/ct-master-tac/bundled/protocols/implementation.cant +77 -0
- package/skills/ct-master-tac/bundled/protocols/provenance.cant +100 -0
- package/skills/ct-master-tac/bundled/protocols/release.cant +107 -0
- package/skills/ct-master-tac/bundled/protocols/research.cant +77 -0
- package/skills/ct-master-tac/bundled/protocols/specification.cant +77 -0
- package/skills/ct-master-tac/bundled/protocols/testing.cant +99 -0
- package/skills/ct-master-tac/bundled/protocols/validation.cant +75 -0
- package/skills/ct-master-tac/bundled/teams/platform.cant +115 -0
- package/skills/ct-master-tac/manifest.json +55 -0
package/package.json
CHANGED
package/skills/ct-grade/SKILL.md
CHANGED
|
@@ -1,7 +1,21 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: ct-grade
|
|
3
|
-
description:
|
|
4
|
-
|
|
3
|
+
description: >-
|
|
4
|
+
CLEO session grading and A/B behavioral analysis with token tracking. Evaluates agent
|
|
5
|
+
session quality via a 5-dimension rubric (S1 session discipline, S2 discovery efficiency,
|
|
6
|
+
S3 task hygiene, S4 error protocol, S5 progressive disclosure). Supports three modes:
|
|
7
|
+
(1) scenario — run playbook scenarios S1-S5 via CLI; (2) ab — blind A/B
|
|
8
|
+
comparison of different CLI configurations for same domain operations with token cost
|
|
9
|
+
measurement; (3) blind — spawn two agents with different configurations, blind-comparator
|
|
10
|
+
picks winner, analyzer produces recommendation. Use when grading agent sessions, running
|
|
11
|
+
grade playbook scenarios, comparing behavioral differences, measuring token
|
|
12
|
+
usage across configurations, or performing multi-run blind A/B evaluation with statistical
|
|
13
|
+
analysis and comparative report. Triggers on: grade session, evaluate agent behavior,
|
|
14
|
+
A/B test CLEO configurations, run grade scenario, token usage analysis, behavioral rubric,
|
|
15
|
+
protocol compliance scoring.
|
|
16
|
+
version: 2.1.0
|
|
17
|
+
argument-hint: "[mode=scenario|ab|blind] [scenario=s1-s5|all] [runs=N] [session-id=<id>]"
|
|
18
|
+
allowed-tools: ["Bash(python *)", "Bash(cleo-dev *)", "Bash(cleo *)", "Bash(kill *)", "Bash(lsof *)", "Agent", "Read", "Write", "Glob"]
|
|
5
19
|
tier: 2
|
|
6
20
|
core: false
|
|
7
21
|
category: quality
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
# MIGRATION NOTICE — ct-grade-v2-1
|
|
3
|
+
|
|
4
|
+
This directory is a **decommissioned staging copy** of `ct-grade` v2.1.
|
|
5
|
+
|
|
6
|
+
## Status
|
|
7
|
+
|
|
8
|
+
**Superseded.** All content has been merged into `packages/skills/skills/ct-grade/`.
|
|
9
|
+
|
|
10
|
+
## What Changed (T429 skill dedupe)
|
|
11
|
+
|
|
12
|
+
- `ct-grade-v2-1/SKILL.md` description, `argument-hint`, `allowed-tools`, and version
|
|
13
|
+
(2.1.0) were promoted into `ct-grade/SKILL.md`.
|
|
14
|
+
- `ct-grade-v2-1/manifest-entry.json` remains here as an archived snapshot; the
|
|
15
|
+
canonical manifest entry lives in `packages/skills/skills/manifest.json` under name
|
|
16
|
+
`ct-grade`.
|
|
17
|
+
- The `grade-viewer/` tooling in this directory was already reachable from `ct-grade/`
|
|
18
|
+
via its `agents/` and `evals/` directories. No content was lost.
|
|
19
|
+
|
|
20
|
+
## Migration Date
|
|
21
|
+
|
|
22
|
+
2026-04-08 — T429 hygiene wave, epic T382.
|
|
23
|
+
|
|
24
|
+
## Action Required
|
|
25
|
+
|
|
26
|
+
None. Do NOT load this skill. Use `ct-grade` instead.
|
|
27
|
+
If you need the A/B or blind-compare modes documented here, they are now part of
|
|
28
|
+
`ct-grade`'s SKILL.md description and invocation modes.
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ct-master-tac
|
|
3
|
+
description: >-
|
|
4
|
+
Master Tactical Bundle for CleoOS autonomous execution. Installs the complete
|
|
5
|
+
primitive library needed to run the full agentic execution layer on a fresh CleoOS
|
|
6
|
+
install: 12 CANT protocol files (research, consensus, architecture-decision,
|
|
7
|
+
specification, decomposition, implementation, validation, testing, contribution,
|
|
8
|
+
release, artifact-publish, provenance), the canonical platform team definition, and
|
|
9
|
+
the skills manifest entry. Use when bootstrapping a new CleoOS project, verifying that
|
|
10
|
+
all protocol primitives are present, or recovering a broken protocol tree. Triggers on:
|
|
11
|
+
"install master tac", "bootstrap protocols", "tools.skill.install ct-master-tac",
|
|
12
|
+
"verify protocol bundle", "repair protocol files", "fresh CleoOS install".
|
|
13
|
+
version: 1.0.0
|
|
14
|
+
tier: 1
|
|
15
|
+
core: false
|
|
16
|
+
category: meta
|
|
17
|
+
protocol: null
|
|
18
|
+
argument-hint: "[--verify] [--force]"
|
|
19
|
+
allowed-tools: ["Read", "Write", "Bash(cp *)", "Bash(ls *)", "Bash(mkdir *)", "Bash(test *)"]
|
|
20
|
+
dependencies:
|
|
21
|
+
- ct-cleo
|
|
22
|
+
sharedResources:
|
|
23
|
+
- subagent-protocol-base
|
|
24
|
+
compatibility:
|
|
25
|
+
- claude-code
|
|
26
|
+
- cursor
|
|
27
|
+
- windsurf
|
|
28
|
+
- gemini-cli
|
|
29
|
+
license: MIT
|
|
30
|
+
install-hook: "tools.skill.install ct-master-tac"
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
# ct-master-tac — Master Tactical Bundle
|
|
34
|
+
|
|
35
|
+
> **Provenance**: @task T430, @epic T382, @umbrella T377
|
|
36
|
+
> **Bundle version**: 1.0.0 — ships with CleoOS v2026.4.x
|
|
37
|
+
|
|
38
|
+
The Master TAC (Tactical Asset Cache) plugin bundles every protocol primitive the
|
|
39
|
+
autonomous execution layer requires. After `tools.skill.install ct-master-tac`, a
|
|
40
|
+
fresh CleoOS install has batteries-included support for the full RCASD-IVTR+C
|
|
41
|
+
lifecycle.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## What's Inside
|
|
46
|
+
|
|
47
|
+
### 12 CANT Protocol Files (`bundled/protocols/`)
|
|
48
|
+
|
|
49
|
+
| File | ID | Stage | Skill |
|
|
50
|
+
|------|----|-------|-------|
|
|
51
|
+
| `research.cant` | RSCH | research | ct-research-agent |
|
|
52
|
+
| `consensus.cant` | CONS | consensus | ct-consensus-voter |
|
|
53
|
+
| `architecture-decision.cant` | ADR | architecture-decision | ct-adr-recorder |
|
|
54
|
+
| `specification.cant` | SPEC | specification | ct-spec-writer |
|
|
55
|
+
| `decomposition.cant` | DCMP | decomposition | ct-epic-architect |
|
|
56
|
+
| `implementation.cant` | IMPL | implementation | ct-task-executor |
|
|
57
|
+
| `validation.cant` | VALID | validation | ct-validator |
|
|
58
|
+
| `testing.cant` | TEST | testing | ct-ivt-looper |
|
|
59
|
+
| `contribution.cant` | CONT | cross-cutting | ct-contribution |
|
|
60
|
+
| `release.cant` | REL | release | ct-release-orchestrator |
|
|
61
|
+
| `artifact-publish.cant` | ART | release | ct-artifact-publisher |
|
|
62
|
+
| `provenance.cant` | PROV | release | ct-provenance-keeper |
|
|
63
|
+
|
|
64
|
+
### Platform Team (`bundled/teams/platform.cant`)
|
|
65
|
+
|
|
66
|
+
Canonical 3-tier team definition with planning-lead, engineering-lead, and
|
|
67
|
+
validation-lead. Mirrors the `.cleo/teams.cant` seed from a standard CleoOS init.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Install Behaviour
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
tools.skill.install ct-master-tac
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The install hook:
|
|
78
|
+
|
|
79
|
+
1. Copies `bundled/protocols/*.cant` to
|
|
80
|
+
`packages/core/src/validation/protocols/cant/` (skips files that already exist
|
|
81
|
+
unless `--force` is provided).
|
|
82
|
+
2. Copies `bundled/teams/platform.cant` to `.cleo/teams.cant` (skips if exists).
|
|
83
|
+
3. Verifies that all 12 protocol files are present and parseable.
|
|
84
|
+
4. Emits an install summary to stdout.
|
|
85
|
+
|
|
86
|
+
Running install a second time is a no-op (idempotent).
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Verify Mode
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
tools.skill.install ct-master-tac --verify
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Read-only. Checks that all bundled files are present at their target locations and
|
|
97
|
+
reports any missing or mismatched files without writing anything.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Plugin Boundary (§11 criteria)
|
|
102
|
+
|
|
103
|
+
This plugin meets all three §11 criteria from `docs/specs/CLEO-OPERATION-CONSTITUTION.md`:
|
|
104
|
+
|
|
105
|
+
- **(a)** Requires reading protocol CANT files managed outside the core CLI binary.
|
|
106
|
+
- **(b)** Reads `bundled/` assets not managed by the CLEO core package.
|
|
107
|
+
- **(c)** Removing it from core does not break any mandatory agent workflow — it is
|
|
108
|
+
a bootstrap/recovery utility only.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Upgrade Path
|
|
113
|
+
|
|
114
|
+
When new protocol files are added, bump `version` in this SKILL.md and
|
|
115
|
+
`manifest.json`, add the new `.cant` file to `bundled/protocols/`, and update the
|
|
116
|
+
`manifest.json` `files` array. The install hook will copy the new file on next run.
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Install verification tests for the ct-master-tac plugin (T431).
|
|
3
|
+
*
|
|
4
|
+
* Asserts:
|
|
5
|
+
* - SKILL.md has valid YAML frontmatter
|
|
6
|
+
* - manifest.json parses correctly and references the correct files
|
|
7
|
+
* - All files referenced in manifest.json `files` array exist under bundled/
|
|
8
|
+
* - Install is idempotent (second run produces no additional writes)
|
|
9
|
+
* - Bundle contains exactly 12 protocol files + 1 platform team file
|
|
10
|
+
*
|
|
11
|
+
* @task T431
|
|
12
|
+
* @epic T382
|
|
13
|
+
* @umbrella T377
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
17
|
+
import { dirname, join, resolve } from 'node:path';
|
|
18
|
+
import { fileURLToPath } from 'node:url';
|
|
19
|
+
import { describe, expect, it } from 'vitest';
|
|
20
|
+
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// Helpers
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
const thisFile = fileURLToPath(import.meta.url);
|
|
26
|
+
/** Absolute path to the ct-master-tac root directory */
|
|
27
|
+
const skillRoot = resolve(dirname(thisFile), '..');
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Parse YAML frontmatter from a Markdown file.
|
|
31
|
+
* Returns the raw frontmatter string between the opening and closing `---`.
|
|
32
|
+
*/
|
|
33
|
+
function extractFrontmatter(content: string): string | null {
|
|
34
|
+
const match = /^---\r?\n([\s\S]*?)\r?\n---/m.exec(content);
|
|
35
|
+
return match ? match[1] : null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Minimal frontmatter key extractor — no external deps, just key: value lines.
|
|
40
|
+
*/
|
|
41
|
+
function parseFrontmatterKeys(fm: string): Record<string, string> {
|
|
42
|
+
const result: Record<string, string> = {};
|
|
43
|
+
for (const line of fm.split('\n')) {
|
|
44
|
+
const m = /^(\w[\w-]*):\s*(.*)$/.exec(line.trimEnd());
|
|
45
|
+
if (m) {
|
|
46
|
+
result[m[1]] = m[2].replace(/^["']|["']$/g, '');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Mock install helper for idempotency test
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
|
|
56
|
+
interface InstallResult {
|
|
57
|
+
copiedFiles: string[];
|
|
58
|
+
skippedFiles: string[];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Simulated install helper — copies bundled/ files to target paths.
|
|
63
|
+
* Returns lists of copied and skipped files so idempotency can be verified.
|
|
64
|
+
*/
|
|
65
|
+
function mockInstall(
|
|
66
|
+
manifestFiles: string[],
|
|
67
|
+
alreadyInstalled: Set<string>,
|
|
68
|
+
): InstallResult {
|
|
69
|
+
const copiedFiles: string[] = [];
|
|
70
|
+
const skippedFiles: string[] = [];
|
|
71
|
+
|
|
72
|
+
for (const f of manifestFiles) {
|
|
73
|
+
if (alreadyInstalled.has(f)) {
|
|
74
|
+
skippedFiles.push(f);
|
|
75
|
+
} else {
|
|
76
|
+
copiedFiles.push(f);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return { copiedFiles, skippedFiles };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// ---------------------------------------------------------------------------
|
|
84
|
+
// Tests
|
|
85
|
+
// ---------------------------------------------------------------------------
|
|
86
|
+
|
|
87
|
+
describe('ct-master-tac plugin (T431)', () => {
|
|
88
|
+
describe('SKILL.md frontmatter', () => {
|
|
89
|
+
const skillMdPath = join(skillRoot, 'SKILL.md');
|
|
90
|
+
|
|
91
|
+
it('SKILL.md exists', () => {
|
|
92
|
+
expect(existsSync(skillMdPath)).toBe(true);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('SKILL.md contains valid frontmatter delimiters', () => {
|
|
96
|
+
const content = readFileSync(skillMdPath, 'utf-8');
|
|
97
|
+
const fm = extractFrontmatter(content);
|
|
98
|
+
expect(fm).not.toBeNull();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('frontmatter has required fields: name, description, version, tier', () => {
|
|
102
|
+
const content = readFileSync(skillMdPath, 'utf-8');
|
|
103
|
+
const fm = extractFrontmatter(content);
|
|
104
|
+
expect(fm).not.toBeNull();
|
|
105
|
+
const keys = parseFrontmatterKeys(fm!);
|
|
106
|
+
expect(keys['name']).toBe('ct-master-tac');
|
|
107
|
+
expect(keys['description'] ?? keys['description']).toBeTruthy();
|
|
108
|
+
expect(keys['version']).toBeTruthy();
|
|
109
|
+
expect(keys['tier']).toBeTruthy();
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
describe('manifest.json', () => {
|
|
114
|
+
const manifestPath = join(skillRoot, 'manifest.json');
|
|
115
|
+
let manifest: Record<string, unknown>;
|
|
116
|
+
|
|
117
|
+
it('manifest.json exists', () => {
|
|
118
|
+
expect(existsSync(manifestPath)).toBe(true);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('manifest.json parses as valid JSON', () => {
|
|
122
|
+
const raw = readFileSync(manifestPath, 'utf-8');
|
|
123
|
+
expect(() => {
|
|
124
|
+
manifest = JSON.parse(raw) as Record<string, unknown>;
|
|
125
|
+
}).not.toThrow();
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('manifest has required top-level keys', () => {
|
|
129
|
+
const raw = readFileSync(manifestPath, 'utf-8');
|
|
130
|
+
manifest = JSON.parse(raw) as Record<string, unknown>;
|
|
131
|
+
expect(manifest['name']).toBe('ct-master-tac');
|
|
132
|
+
expect(manifest['version']).toBeTruthy();
|
|
133
|
+
expect(Array.isArray(manifest['files'])).toBe(true);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('files array contains exactly 13 entries (12 protocols + 1 team)', () => {
|
|
137
|
+
const raw = readFileSync(manifestPath, 'utf-8');
|
|
138
|
+
manifest = JSON.parse(raw) as Record<string, unknown>;
|
|
139
|
+
const files = manifest['files'] as string[];
|
|
140
|
+
expect(files).toHaveLength(13);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('files array contains at least 12 protocol entries', () => {
|
|
144
|
+
const raw = readFileSync(manifestPath, 'utf-8');
|
|
145
|
+
manifest = JSON.parse(raw) as Record<string, unknown>;
|
|
146
|
+
const files = manifest['files'] as string[];
|
|
147
|
+
const protocolFiles = files.filter((f) => f.startsWith('bundled/protocols/'));
|
|
148
|
+
expect(protocolFiles.length).toBeGreaterThanOrEqual(12);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('files array contains platform team entry', () => {
|
|
152
|
+
const raw = readFileSync(manifestPath, 'utf-8');
|
|
153
|
+
manifest = JSON.parse(raw) as Record<string, unknown>;
|
|
154
|
+
const files = manifest['files'] as string[];
|
|
155
|
+
expect(files).toContain('bundled/teams/platform.cant');
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
describe('bundled files exist', () => {
|
|
160
|
+
it('all files referenced in manifest.json exist under bundled/', () => {
|
|
161
|
+
const raw = readFileSync(join(skillRoot, 'manifest.json'), 'utf-8');
|
|
162
|
+
const manifest = JSON.parse(raw) as { files: string[] };
|
|
163
|
+
const missingFiles: string[] = [];
|
|
164
|
+
|
|
165
|
+
for (const f of manifest.files) {
|
|
166
|
+
const abs = join(skillRoot, f);
|
|
167
|
+
if (!existsSync(abs)) {
|
|
168
|
+
missingFiles.push(f);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
expect(missingFiles).toEqual([]);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('each bundled protocol file is non-empty', () => {
|
|
176
|
+
const raw = readFileSync(join(skillRoot, 'manifest.json'), 'utf-8');
|
|
177
|
+
const manifest = JSON.parse(raw) as { files: string[] };
|
|
178
|
+
const emptyFiles: string[] = [];
|
|
179
|
+
|
|
180
|
+
for (const f of manifest.files.filter((f) =>
|
|
181
|
+
f.startsWith('bundled/protocols/'),
|
|
182
|
+
)) {
|
|
183
|
+
const abs = join(skillRoot, f);
|
|
184
|
+
const content = readFileSync(abs, 'utf-8');
|
|
185
|
+
if (content.trim().length === 0) {
|
|
186
|
+
emptyFiles.push(f);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
expect(emptyFiles).toEqual([]);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('each bundled protocol file has CANT frontmatter (kind: protocol)', () => {
|
|
194
|
+
const raw = readFileSync(join(skillRoot, 'manifest.json'), 'utf-8');
|
|
195
|
+
const manifest = JSON.parse(raw) as { files: string[] };
|
|
196
|
+
const badFiles: string[] = [];
|
|
197
|
+
|
|
198
|
+
for (const f of manifest.files.filter((f) =>
|
|
199
|
+
f.startsWith('bundled/protocols/'),
|
|
200
|
+
)) {
|
|
201
|
+
const abs = join(skillRoot, f);
|
|
202
|
+
const content = readFileSync(abs, 'utf-8');
|
|
203
|
+
if (!content.includes('kind: protocol')) {
|
|
204
|
+
badFiles.push(f);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
expect(badFiles).toEqual([]);
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
describe('idempotent install (mock)', () => {
|
|
213
|
+
it('first install copies all 13 files', () => {
|
|
214
|
+
const raw = readFileSync(join(skillRoot, 'manifest.json'), 'utf-8');
|
|
215
|
+
const manifest = JSON.parse(raw) as { files: string[] };
|
|
216
|
+
const already = new Set<string>();
|
|
217
|
+
|
|
218
|
+
const result = mockInstall(manifest.files, already);
|
|
219
|
+
expect(result.copiedFiles).toHaveLength(13);
|
|
220
|
+
expect(result.skippedFiles).toHaveLength(0);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it('second install (files already present) skips all 13 files', () => {
|
|
224
|
+
const raw = readFileSync(join(skillRoot, 'manifest.json'), 'utf-8');
|
|
225
|
+
const manifest = JSON.parse(raw) as { files: string[] };
|
|
226
|
+
// Simulate first install — all files now "present"
|
|
227
|
+
const already = new Set<string>(manifest.files);
|
|
228
|
+
|
|
229
|
+
const result = mockInstall(manifest.files, already);
|
|
230
|
+
expect(result.copiedFiles).toHaveLength(0);
|
|
231
|
+
expect(result.skippedFiles).toHaveLength(13);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it('partial install (3 missing) copies only missing files', () => {
|
|
235
|
+
const raw = readFileSync(join(skillRoot, 'manifest.json'), 'utf-8');
|
|
236
|
+
const manifest = JSON.parse(raw) as { files: string[] };
|
|
237
|
+
// 10 of 13 already installed
|
|
238
|
+
const already = new Set<string>(manifest.files.slice(0, 10));
|
|
239
|
+
|
|
240
|
+
const result = mockInstall(manifest.files, already);
|
|
241
|
+
expect(result.copiedFiles).toHaveLength(3);
|
|
242
|
+
expect(result.skippedFiles).toHaveLength(10);
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
describe('bundle completeness', () => {
|
|
247
|
+
const EXPECTED_PROTOCOLS = [
|
|
248
|
+
'research.cant',
|
|
249
|
+
'consensus.cant',
|
|
250
|
+
'architecture-decision.cant',
|
|
251
|
+
'specification.cant',
|
|
252
|
+
'decomposition.cant',
|
|
253
|
+
'implementation.cant',
|
|
254
|
+
'validation.cant',
|
|
255
|
+
'testing.cant',
|
|
256
|
+
'contribution.cant',
|
|
257
|
+
'release.cant',
|
|
258
|
+
'artifact-publish.cant',
|
|
259
|
+
'provenance.cant',
|
|
260
|
+
] as const;
|
|
261
|
+
|
|
262
|
+
for (const protocol of EXPECTED_PROTOCOLS) {
|
|
263
|
+
it(`bundled/protocols/${protocol} exists`, () => {
|
|
264
|
+
expect(
|
|
265
|
+
existsSync(join(skillRoot, 'bundled', 'protocols', protocol)),
|
|
266
|
+
).toBe(true);
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
it('bundled/teams/platform.cant exists', () => {
|
|
271
|
+
expect(existsSync(join(skillRoot, 'bundled', 'teams', 'platform.cant'))).toBe(
|
|
272
|
+
true,
|
|
273
|
+
);
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
it('bundle contains exactly 12 CANT protocol files', () => {
|
|
277
|
+
const protocolFiles = EXPECTED_PROTOCOLS.filter((f) =>
|
|
278
|
+
existsSync(join(skillRoot, 'bundled', 'protocols', f)),
|
|
279
|
+
);
|
|
280
|
+
expect(protocolFiles).toHaveLength(12);
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# ct-master-tac Bundle Contents
|
|
2
|
+
|
|
3
|
+
> @task T430 @epic T382 @umbrella T377
|
|
4
|
+
> Source: `packages/skills/skills/ct-master-tac/bundled/`
|
|
5
|
+
|
|
6
|
+
This directory holds the canonical bundle assets shipped with the `ct-master-tac` plugin.
|
|
7
|
+
|
|
8
|
+
## protocols/
|
|
9
|
+
|
|
10
|
+
Copies of the 12 CANT protocol files from
|
|
11
|
+
`packages/core/src/validation/protocols/cant/`.
|
|
12
|
+
|
|
13
|
+
Each file defines a protocol primitive in the RCASD-IVTR+C lifecycle:
|
|
14
|
+
|
|
15
|
+
| File | ID | RCASD Stage |
|
|
16
|
+
|------|----|-------------|
|
|
17
|
+
| `research.cant` | RSCH | R — Research |
|
|
18
|
+
| `consensus.cant` | CONS | C — Consensus |
|
|
19
|
+
| `architecture-decision.cant` | ADR | A — Architecture Decision |
|
|
20
|
+
| `specification.cant` | SPEC | S — Specification |
|
|
21
|
+
| `decomposition.cant` | DCMP | D — Decomposition |
|
|
22
|
+
| `implementation.cant` | IMPL | I — Implementation |
|
|
23
|
+
| `validation.cant` | VALID | V — Validation |
|
|
24
|
+
| `testing.cant` | TEST | T — Testing |
|
|
25
|
+
| `contribution.cant` | CONT | cross-cutting |
|
|
26
|
+
| `release.cant` | REL | R — Release |
|
|
27
|
+
| `artifact-publish.cant` | ART | release sub-protocol |
|
|
28
|
+
| `provenance.cant` | PROV | release sub-protocol |
|
|
29
|
+
|
|
30
|
+
## teams/
|
|
31
|
+
|
|
32
|
+
| File | Description |
|
|
33
|
+
|------|-------------|
|
|
34
|
+
| `platform.cant` | Canonical 3-tier CleoOS platform team seed |
|
|
35
|
+
|
|
36
|
+
## Maintenance
|
|
37
|
+
|
|
38
|
+
When protocol files change in `packages/core/src/validation/protocols/cant/`,
|
|
39
|
+
re-copy them here and bump the version in `ct-master-tac/manifest.json` and
|
|
40
|
+
`ct-master-tac/SKILL.md`.
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
---
|
|
2
|
+
kind: protocol
|
|
3
|
+
version: 1.0.0
|
|
4
|
+
id: ADR
|
|
5
|
+
title: "Architecture Decision Record Protocol"
|
|
6
|
+
status: active
|
|
7
|
+
type: conditional
|
|
8
|
+
audience: "llm-agent, orchestrator"
|
|
9
|
+
tags: "adr, architecture, decisions"
|
|
10
|
+
skillRef: ct-adr-recorder
|
|
11
|
+
lastUpdated: 2026-04-08
|
|
12
|
+
enforcement: advisory
|
|
13
|
+
stage: "architecture-decision"
|
|
14
|
+
consult-when: "Recording a formal architecture decision after consensus reaches PROVEN verdict; superseding an existing ADR; any task carrying --protocol adr flag"
|
|
15
|
+
input:
|
|
16
|
+
consensus_manifest_id: "string — ID of the originating consensus manifest (required)"
|
|
17
|
+
decision_title: "string — short title for the ADR"
|
|
18
|
+
options_evaluated: "string[] — options that were considered"
|
|
19
|
+
output:
|
|
20
|
+
adr_id: "string — canonical ADR identifier (ADR-NNN)"
|
|
21
|
+
status: "proposed | accepted | superseded"
|
|
22
|
+
stored_at: "string — path to .cleo/adrs/<id>.md and decisions table row"
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
# Architecture Decision Record (ADR) Protocol
|
|
26
|
+
#
|
|
27
|
+
# Provenance: @task T4798 (ADR-006 Implementation), @task T428 (gap patch)
|
|
28
|
+
# Type: Conditional Protocol
|
|
29
|
+
# Stage: RCADSD - A (ADR)
|
|
30
|
+
# Max Active: 3 protocols (including base)
|
|
31
|
+
#
|
|
32
|
+
# Trigger Conditions
|
|
33
|
+
#
|
|
34
|
+
# This protocol activates when the task involves:
|
|
35
|
+
# Decision Recording: "decision", "adr", "architecture decision"
|
|
36
|
+
# Stage Transition: "after consensus", "begin adr"
|
|
37
|
+
# Formalization: "lock in decision", "formalize choice", "decide"
|
|
38
|
+
# Architectural Shift: "pivot", "new architecture", "supersede"
|
|
39
|
+
# Record Creation: "create adr", "write adr", "record decision"
|
|
40
|
+
#
|
|
41
|
+
# Explicit Override: --protocol adr flag on task creation.
|
|
42
|
+
#
|
|
43
|
+
# Requirements (RFC 2119)
|
|
44
|
+
#
|
|
45
|
+
# MUST:
|
|
46
|
+
# ADR-001: MUST be generated from an accepted Consensus report verdict
|
|
47
|
+
# ADR-002: MUST include a consensus_manifest_id linking to its originating consensus
|
|
48
|
+
# ADR-003: MUST require explicit HITL approval to transition from proposed to accepted
|
|
49
|
+
# ADR-004: MUST include Context, Options Evaluated, Decision, Rationale, and Consequences sections
|
|
50
|
+
# ADR-005: MUST trigger downstream invalidation if superseded
|
|
51
|
+
# ADR-006: MUST be stored in the canonical decisions SQLite table via Drizzle ORM
|
|
52
|
+
# ADR-007: MUST set agent_type: "decision" in manifest entry
|
|
53
|
+
# ADR-008: MUST block the Specification stage until the ADR status is accepted
|
|
54
|
+
#
|
|
55
|
+
# SHOULD:
|
|
56
|
+
# ADR-010: SHOULD document the exact data structures or schema changes required
|
|
57
|
+
# ADR-011: SHOULD explicitly list which existing ADRs are superseded, with rationale
|
|
58
|
+
# ADR-012: SHOULD flag known technical debt introduced by the decision
|
|
59
|
+
# ADR-013: SHOULD document rejected alternatives with rationale for rejection
|
|
60
|
+
#
|
|
61
|
+
# MAY:
|
|
62
|
+
# ADR-020: MAY include diagrams (Mermaid) illustrating the architectural shift
|
|
63
|
+
# ADR-021: MAY link to external prior art or research documents
|
|
64
|
+
# ADR-022: MAY reference related ADRs that are not superseded but contextually relevant
|
|
65
|
+
#
|
|
66
|
+
# Decision Status Lifecycle:
|
|
67
|
+
# proposed -> accepted -> superseded
|
|
68
|
+
# \-> deprecated
|
|
69
|
+
#
|
|
70
|
+
# HITL Gate:
|
|
71
|
+
# 1. Agent drafts the ADR based on consensus verdict
|
|
72
|
+
# 2. Status is set to proposed
|
|
73
|
+
# 3. Pipeline pauses (HANDOFF_REQUIRED - exit code 65)
|
|
74
|
+
# 4. Human reviews the proposed ADR
|
|
75
|
+
# 5. If approved, status transitions to accepted
|
|
76
|
+
# 6. Only an accepted ADR unlocks the Specification stage
|
|
77
|
+
#
|
|
78
|
+
# Exit Codes:
|
|
79
|
+
# 65: HANDOFF_REQUIRED - ADR drafted as proposed, awaiting HITL acceptance
|
|
80
|
+
# 84: PROVENANCE_REQUIRED - Attempted to create ADR without linked Consensus report
|
|
81
|
+
# 18: CASCADE_FAILED - Downstream work blocked because governing ADR was superseded
|
|
82
|
+
#
|
|
83
|
+
# Anti-Patterns:
|
|
84
|
+
# - Creating ADR without consensus (decisions lack evidence foundation)
|
|
85
|
+
# - Auto-accepting without HITL review (bypasses human oversight gate)
|
|
86
|
+
# - Omitting downstream impact section (future implementers unaware of cascade)
|
|
87
|
+
# - Superseding without updating specs (creates orphaned specifications)
|
|
88
|
+
# - Using ADR to define implementation requirements (that is Specification's role)
|
|
89
|
+
# - Storing ADR only as markdown without SQLite record (loses relational queries)
|
|
90
|
+
# - Skipping rejected alternatives (loses institutional knowledge)
|