@cleocode/skills 2.0.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/dispatch-config.json +404 -0
- package/index.d.ts +178 -0
- package/index.js +405 -0
- package/package.json +14 -0
- package/profiles/core.json +7 -0
- package/profiles/full.json +10 -0
- package/profiles/minimal.json +7 -0
- package/profiles/recommended.json +7 -0
- package/provider-skills-map.json +97 -0
- package/skills/_shared/cleo-style-guide.md +84 -0
- package/skills/_shared/manifest-operations.md +810 -0
- package/skills/_shared/placeholders.json +433 -0
- package/skills/_shared/skill-chaining-patterns.md +237 -0
- package/skills/_shared/subagent-protocol-base.md +223 -0
- package/skills/_shared/task-system-integration.md +232 -0
- package/skills/_shared/testing-framework-config.md +110 -0
- package/skills/ct-cleo/SKILL.md +490 -0
- package/skills/ct-cleo/references/anti-patterns.md +19 -0
- package/skills/ct-cleo/references/loom-lifecycle.md +136 -0
- package/skills/ct-cleo/references/orchestrator-constraints.md +55 -0
- package/skills/ct-cleo/references/session-protocol.md +162 -0
- package/skills/ct-codebase-mapper/SKILL.md +82 -0
- package/skills/ct-contribution/SKILL.md +521 -0
- package/skills/ct-contribution/templates/contribution-init.json +21 -0
- package/skills/ct-dev-workflow/SKILL.md +423 -0
- package/skills/ct-docs-lookup/SKILL.md +66 -0
- package/skills/ct-docs-review/SKILL.md +175 -0
- package/skills/ct-docs-write/SKILL.md +108 -0
- package/skills/ct-documentor/SKILL.md +231 -0
- package/skills/ct-epic-architect/SKILL.md +305 -0
- package/skills/ct-epic-architect/references/bug-epic-example.md +172 -0
- package/skills/ct-epic-architect/references/commands.md +201 -0
- package/skills/ct-epic-architect/references/feature-epic-example.md +210 -0
- package/skills/ct-epic-architect/references/migration-epic-example.md +244 -0
- package/skills/ct-epic-architect/references/output-format.md +92 -0
- package/skills/ct-epic-architect/references/patterns.md +284 -0
- package/skills/ct-epic-architect/references/refactor-epic-example.md +412 -0
- package/skills/ct-epic-architect/references/research-epic-example.md +226 -0
- package/skills/ct-epic-architect/references/shell-escaping.md +86 -0
- package/skills/ct-epic-architect/references/skill-aware-execution.md +195 -0
- package/skills/ct-grade/SKILL.md +230 -0
- package/skills/ct-grade/agents/analysis-reporter.md +203 -0
- package/skills/ct-grade/agents/blind-comparator.md +157 -0
- package/skills/ct-grade/agents/scenario-runner.md +134 -0
- package/skills/ct-grade/eval-viewer/__pycache__/generate_grade_review.cpython-314.pyc +0 -0
- package/skills/ct-grade/eval-viewer/generate_grade_review.py +1138 -0
- package/skills/ct-grade/eval-viewer/generate_grade_viewer.py +544 -0
- package/skills/ct-grade/eval-viewer/generate_review.py +283 -0
- package/skills/ct-grade/eval-viewer/grade-review.html +1574 -0
- package/skills/ct-grade/eval-viewer/viewer.html +219 -0
- package/skills/ct-grade/evals/evals.json +94 -0
- package/skills/ct-grade/references/ab-test-methodology.md +150 -0
- package/skills/ct-grade/references/domains.md +137 -0
- package/skills/ct-grade/references/grade-spec.md +236 -0
- package/skills/ct-grade/references/scenario-playbook.md +234 -0
- package/skills/ct-grade/references/token-tracking.md +120 -0
- package/skills/ct-grade/scripts/__pycache__/audit_analyzer.cpython-314.pyc +0 -0
- package/skills/ct-grade/scripts/__pycache__/run_ab_test.cpython-314.pyc +0 -0
- package/skills/ct-grade/scripts/__pycache__/run_all.cpython-314.pyc +0 -0
- package/skills/ct-grade/scripts/__pycache__/token_tracker.cpython-314.pyc +0 -0
- package/skills/ct-grade/scripts/audit_analyzer.py +279 -0
- package/skills/ct-grade/scripts/generate_report.py +283 -0
- package/skills/ct-grade/scripts/run_ab_test.py +504 -0
- package/skills/ct-grade/scripts/run_all.py +287 -0
- package/skills/ct-grade/scripts/setup_run.py +183 -0
- package/skills/ct-grade/scripts/token_tracker.py +630 -0
- package/skills/ct-grade-v2-1/SKILL.md +237 -0
- package/skills/ct-grade-v2-1/agents/analysis-reporter.md +203 -0
- package/skills/ct-grade-v2-1/agents/blind-comparator.md +157 -0
- package/skills/ct-grade-v2-1/agents/scenario-runner.md +179 -0
- package/skills/ct-grade-v2-1/evals/evals.json +74 -0
- package/skills/ct-grade-v2-1/grade-viewer/__pycache__/build_op_stats.cpython-314.pyc +0 -0
- package/skills/ct-grade-v2-1/grade-viewer/__pycache__/generate_grade_review.cpython-314.pyc +0 -0
- package/skills/ct-grade-v2-1/grade-viewer/build_op_stats.py +174 -0
- package/skills/ct-grade-v2-1/grade-viewer/eval-analysis.json +41 -0
- package/skills/ct-grade-v2-1/grade-viewer/eval-report.md +34 -0
- package/skills/ct-grade-v2-1/grade-viewer/generate_grade_review.py +1023 -0
- package/skills/ct-grade-v2-1/grade-viewer/generate_grade_viewer.py +548 -0
- package/skills/ct-grade-v2-1/grade-viewer/grade-review-eval.html +613 -0
- package/skills/ct-grade-v2-1/grade-viewer/grade-review.html +1532 -0
- package/skills/ct-grade-v2-1/grade-viewer/viewer.html +620 -0
- package/skills/ct-grade-v2-1/manifest-entry.json +31 -0
- package/skills/ct-grade-v2-1/references/ab-testing.md +233 -0
- package/skills/ct-grade-v2-1/references/domains-ssot.md +156 -0
- package/skills/ct-grade-v2-1/references/grade-spec-v2.md +167 -0
- package/skills/ct-grade-v2-1/references/playbook-v2.md +393 -0
- package/skills/ct-grade-v2-1/references/token-tracking.md +202 -0
- package/skills/ct-grade-v2-1/scripts/generate_report.py +419 -0
- package/skills/ct-grade-v2-1/scripts/run_ab_test.py +493 -0
- package/skills/ct-grade-v2-1/scripts/run_scenario.py +396 -0
- package/skills/ct-grade-v2-1/scripts/setup_run.py +207 -0
- package/skills/ct-grade-v2-1/scripts/token_tracker.py +175 -0
- package/skills/ct-memory/SKILL.md +84 -0
- package/skills/ct-orchestrator/INSTALL.md +61 -0
- package/skills/ct-orchestrator/README.md +69 -0
- package/skills/ct-orchestrator/SKILL.md +380 -0
- package/skills/ct-orchestrator/manifest-entry.json +19 -0
- package/skills/ct-orchestrator/orchestrator-prompt.txt +17 -0
- package/skills/ct-orchestrator/references/SUBAGENT-PROTOCOL-BLOCK.md +66 -0
- package/skills/ct-orchestrator/references/autonomous-operation.md +167 -0
- package/skills/ct-orchestrator/references/lifecycle-gates.md +98 -0
- package/skills/ct-orchestrator/references/orchestrator-compliance.md +271 -0
- package/skills/ct-orchestrator/references/orchestrator-handoffs.md +85 -0
- package/skills/ct-orchestrator/references/orchestrator-patterns.md +164 -0
- package/skills/ct-orchestrator/references/orchestrator-recovery.md +113 -0
- package/skills/ct-orchestrator/references/orchestrator-spawning.md +271 -0
- package/skills/ct-orchestrator/references/orchestrator-tokens.md +180 -0
- package/skills/ct-research-agent/SKILL.md +226 -0
- package/skills/ct-skill-creator/.cleo/.context-state.json +13 -0
- package/skills/ct-skill-creator/.cleo/logs/cleo.2026-03-07.1.log +24 -0
- package/skills/ct-skill-creator/.cleo/tasks.db +0 -0
- package/skills/ct-skill-creator/SKILL.md +356 -0
- package/skills/ct-skill-creator/agents/analyzer.md +276 -0
- package/skills/ct-skill-creator/agents/comparator.md +204 -0
- package/skills/ct-skill-creator/agents/grader.md +225 -0
- package/skills/ct-skill-creator/assets/eval_review.html +146 -0
- package/skills/ct-skill-creator/eval-viewer/__pycache__/generate_review.cpython-314.pyc +0 -0
- package/skills/ct-skill-creator/eval-viewer/generate_review.py +471 -0
- package/skills/ct-skill-creator/eval-viewer/viewer.html +1325 -0
- package/skills/ct-skill-creator/manifest-entry.json +17 -0
- package/skills/ct-skill-creator/references/dynamic-context.md +228 -0
- package/skills/ct-skill-creator/references/frontmatter.md +83 -0
- package/skills/ct-skill-creator/references/invocation-control.md +165 -0
- package/skills/ct-skill-creator/references/output-patterns.md +86 -0
- package/skills/ct-skill-creator/references/provider-deployment.md +175 -0
- package/skills/ct-skill-creator/references/schemas.md +430 -0
- package/skills/ct-skill-creator/references/workflows.md +28 -0
- package/skills/ct-skill-creator/scripts/__init__.py +1 -0
- package/skills/ct-skill-creator/scripts/__pycache__/__init__.cpython-314.pyc +0 -0
- package/skills/ct-skill-creator/scripts/__pycache__/aggregate_benchmark.cpython-314.pyc +0 -0
- package/skills/ct-skill-creator/scripts/__pycache__/generate_report.cpython-314.pyc +0 -0
- package/skills/ct-skill-creator/scripts/__pycache__/improve_description.cpython-314.pyc +0 -0
- package/skills/ct-skill-creator/scripts/__pycache__/init_skill.cpython-314.pyc +0 -0
- package/skills/ct-skill-creator/scripts/__pycache__/quick_validate.cpython-314.pyc +0 -0
- package/skills/ct-skill-creator/scripts/__pycache__/run_eval.cpython-314.pyc +0 -0
- package/skills/ct-skill-creator/scripts/__pycache__/run_loop.cpython-314.pyc +0 -0
- package/skills/ct-skill-creator/scripts/__pycache__/utils.cpython-314.pyc +0 -0
- package/skills/ct-skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/skills/ct-skill-creator/scripts/generate_report.py +326 -0
- package/skills/ct-skill-creator/scripts/improve_description.py +247 -0
- package/skills/ct-skill-creator/scripts/init_skill.py +306 -0
- package/skills/ct-skill-creator/scripts/package_skill.py +110 -0
- package/skills/ct-skill-creator/scripts/quick_validate.py +97 -0
- package/skills/ct-skill-creator/scripts/run_eval.py +310 -0
- package/skills/ct-skill-creator/scripts/run_loop.py +328 -0
- package/skills/ct-skill-creator/scripts/utils.py +47 -0
- package/skills/ct-skill-validator/SKILL.md +178 -0
- package/skills/ct-skill-validator/agents/ecosystem-checker.md +151 -0
- package/skills/ct-skill-validator/assets/valid-skill-example.md +13 -0
- package/skills/ct-skill-validator/evals/eval_set.json +14 -0
- package/skills/ct-skill-validator/evals/evals.json +52 -0
- package/skills/ct-skill-validator/manifest-entry.json +20 -0
- package/skills/ct-skill-validator/references/cleo-ecosystem-rules.md +163 -0
- package/skills/ct-skill-validator/references/validation-rules.md +168 -0
- package/skills/ct-skill-validator/scripts/__init__.py +0 -0
- package/skills/ct-skill-validator/scripts/__pycache__/audit_body.cpython-314.pyc +0 -0
- package/skills/ct-skill-validator/scripts/__pycache__/check_ecosystem.cpython-314.pyc +0 -0
- package/skills/ct-skill-validator/scripts/__pycache__/generate_validation_report.cpython-314.pyc +0 -0
- package/skills/ct-skill-validator/scripts/__pycache__/validate.cpython-314.pyc +0 -0
- package/skills/ct-skill-validator/scripts/audit_body.py +242 -0
- package/skills/ct-skill-validator/scripts/check_ecosystem.py +169 -0
- package/skills/ct-skill-validator/scripts/check_manifest.py +172 -0
- package/skills/ct-skill-validator/scripts/generate_validation_report.py +442 -0
- package/skills/ct-skill-validator/scripts/validate.py +422 -0
- package/skills/ct-spec-writer/SKILL.md +189 -0
- package/skills/ct-stickynote/README.md +14 -0
- package/skills/ct-stickynote/SKILL.md +46 -0
- package/skills/ct-task-executor/SKILL.md +296 -0
- package/skills/ct-validator/SKILL.md +216 -0
- package/skills/manifest.json +469 -0
- package/skills.json +281 -0
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>ct-grade Eval Review</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root {
|
|
9
|
+
--bg: #0f1117; --surface: #1a1d27; --surface2: #21263a; --border: #2a2f45;
|
|
10
|
+
--text: #e8eaf0; --muted: #6b7280; --accent: #6366f1; --accent-dim: #3730a3;
|
|
11
|
+
--green: #22c55e; --green-bg: rgba(34,197,94,.12);
|
|
12
|
+
--red: #ef4444; --red-bg: rgba(239,68,68,.12);
|
|
13
|
+
--yellow: #eab308; --yellow-bg: rgba(234,179,8,.12);
|
|
14
|
+
--radius: 8px;
|
|
15
|
+
}
|
|
16
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
17
|
+
body { font-family: system-ui, sans-serif; background: var(--bg); color: var(--text); height: 100vh; display: flex; flex-direction: column; font-size: 14px; }
|
|
18
|
+
.header { background: var(--surface); border-bottom: 1px solid var(--border); padding: 12px 20px; display: flex; align-items: center; justify-content: space-between; flex-shrink: 0; }
|
|
19
|
+
.header h1 { font-size: 1rem; font-weight: 600; }
|
|
20
|
+
.badge { background: var(--accent-dim); color: var(--accent); font-size: 11px; padding: 2px 8px; border-radius: 20px; font-weight: 600; margin-left: 8px; }
|
|
21
|
+
.layout { flex: 1; display: flex; overflow: hidden; }
|
|
22
|
+
.sidebar { width: 260px; background: var(--surface); border-right: 1px solid var(--border); overflow-y: auto; flex-shrink: 0; padding: 8px; }
|
|
23
|
+
.main { flex: 1; overflow-y: auto; padding: 20px; }
|
|
24
|
+
.run-item { padding: 10px 12px; border-radius: var(--radius); cursor: pointer; margin-bottom: 4px; border: 1px solid transparent; }
|
|
25
|
+
.run-item:hover { background: var(--surface2); border-color: var(--border); }
|
|
26
|
+
.run-item.active { background: var(--accent-dim); border-color: var(--accent); }
|
|
27
|
+
.run-id { font-size: 11px; color: var(--muted); font-family: monospace; margin-bottom: 4px; }
|
|
28
|
+
.run-prompt { font-size: 12px; line-height: 1.4; }
|
|
29
|
+
.run-pass { font-size: 11px; margin-top: 5px; font-weight: 600; }
|
|
30
|
+
.pass-good { color: var(--green); } .pass-mid { color: var(--yellow); } .pass-bad { color: var(--red); }
|
|
31
|
+
.card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); margin-bottom: 16px; overflow: hidden; }
|
|
32
|
+
.card-header { padding: 12px 16px; border-bottom: 1px solid var(--border); font-size: 13px; font-weight: 600; }
|
|
33
|
+
.card-body { padding: 16px; }
|
|
34
|
+
.prompt-box { background: var(--surface2); border-left: 3px solid var(--accent); border-radius: 4px; padding: 12px; font-size: 13px; line-height: 1.6; }
|
|
35
|
+
.exp-row { display: flex; gap: 10px; align-items: flex-start; padding: 8px 0; border-bottom: 1px solid var(--border); }
|
|
36
|
+
.exp-row:last-child { border-bottom: none; }
|
|
37
|
+
.exp-icon { font-size: 14px; flex-shrink: 0; margin-top: 2px; }
|
|
38
|
+
.exp-text { font-size: 13px; line-height: 1.5; }
|
|
39
|
+
.exp-evidence { font-size: 11px; color: var(--muted); margin-top: 3px; font-style: italic; }
|
|
40
|
+
.pill-row { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 12px; }
|
|
41
|
+
.pill { padding: 3px 10px; border-radius: 20px; font-size: 12px; font-weight: 600; }
|
|
42
|
+
.pill-green { background: var(--green-bg); color: var(--green); } .pill-red { background: var(--red-bg); color: var(--red); } .pill-yellow { background: var(--yellow-bg); color: var(--yellow); }
|
|
43
|
+
.file-tabs { display: flex; gap: 4px; padding: 8px 16px; background: var(--surface2); border-bottom: 1px solid var(--border); flex-wrap: wrap; }
|
|
44
|
+
.ftab { padding: 3px 8px; border-radius: 4px; cursor: pointer; font-size: 11px; font-family: monospace; border: 1px solid transparent; color: var(--muted); background: none; }
|
|
45
|
+
.ftab:hover { border-color: var(--border); color: var(--text); }
|
|
46
|
+
.ftab.active { background: var(--accent-dim); border-color: var(--accent); color: var(--text); }
|
|
47
|
+
.file-body { padding: 16px; max-height: 400px; overflow-y: auto; }
|
|
48
|
+
.file-pre { font-family: monospace; font-size: 12px; line-height: 1.6; white-space: pre-wrap; word-break: break-all; }
|
|
49
|
+
.feedback-ta { width: 100%; min-height: 80px; background: var(--surface2); border: 1px solid var(--border); border-radius: var(--radius); color: var(--text); padding: 10px; font-size: 13px; font-family: inherit; resize: vertical; }
|
|
50
|
+
.feedback-ta:focus { outline: none; border-color: var(--accent); }
|
|
51
|
+
.btn { padding: 6px 14px; border-radius: var(--radius); border: none; cursor: pointer; font-size: 13px; font-weight: 600; background: var(--accent); color: white; }
|
|
52
|
+
.btn:hover { background: #4f46e5; }
|
|
53
|
+
.save-msg { font-size: 12px; color: var(--muted); margin-left: 10px; }
|
|
54
|
+
.empty-msg { padding: 60px 20px; text-align: center; color: var(--muted); }
|
|
55
|
+
</style>
|
|
56
|
+
</head>
|
|
57
|
+
<body>
|
|
58
|
+
<div class="header">
|
|
59
|
+
<h1>ct-grade <span class="badge">Eval Review</span></h1>
|
|
60
|
+
<span id="hdr-stats" style="font-size:12px;color:var(--muted)"></span>
|
|
61
|
+
</div>
|
|
62
|
+
<div class="layout">
|
|
63
|
+
<nav class="sidebar" id="sidebar"></nav>
|
|
64
|
+
<main class="main" id="main"><div class="empty-msg"><p>Select an eval run from the sidebar.</p></div></main>
|
|
65
|
+
</div>
|
|
66
|
+
<script>
|
|
67
|
+
/*__EMBEDDED_DATA__*/
|
|
68
|
+
const {runs, benchmark} = EMBEDDED_DATA;
|
|
69
|
+
let feedback = {reviews: []};
|
|
70
|
+
let curRun = null, curFileIdx = {};
|
|
71
|
+
|
|
72
|
+
function el(tag, props, ...children) {
|
|
73
|
+
const e = document.createElement(tag);
|
|
74
|
+
if (props) for (const [k, v] of Object.entries(props)) {
|
|
75
|
+
if (k === 'cls') e.className = v;
|
|
76
|
+
else if (k === 'text') e.textContent = v;
|
|
77
|
+
else if (k === 'onclick') e.onclick = v;
|
|
78
|
+
else e.setAttribute(k, v);
|
|
79
|
+
}
|
|
80
|
+
for (const c of children) { if (c) e.appendChild(typeof c === 'string' ? document.createTextNode(c) : c); }
|
|
81
|
+
return e;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function passClass(r) { return r >= 0.8 ? 'pass-good' : r >= 0.5 ? 'pass-mid' : 'pass-bad'; }
|
|
85
|
+
function pillClass(r) { return r >= 0.8 ? 'pill-green' : r >= 0.5 ? 'pill-yellow' : 'pill-red'; }
|
|
86
|
+
|
|
87
|
+
fetch('/api/feedback').then(r => r.json()).then(d => { feedback = d; }).catch(() => {});
|
|
88
|
+
|
|
89
|
+
function buildSidebar() {
|
|
90
|
+
const sb = document.getElementById('sidebar');
|
|
91
|
+
sb.textContent = '';
|
|
92
|
+
if (!runs || !runs.length) { sb.appendChild(el('div', {style: 'padding:16px;color:var(--muted);font-size:12px', text: 'No eval runs found.'})); return; }
|
|
93
|
+
let tot = 0, pass = 0;
|
|
94
|
+
runs.forEach((run, i) => {
|
|
95
|
+
const item = el('div', {cls: 'run-item', onclick: () => selectRun(i)});
|
|
96
|
+
item.dataset.idx = i;
|
|
97
|
+
item.appendChild(el('div', {cls: 'run-id', text: `eval-${run.eval_id || i+1}`}));
|
|
98
|
+
item.appendChild(el('div', {cls: 'run-prompt', text: run.prompt || '(no prompt)'}));
|
|
99
|
+
const g = run.grading;
|
|
100
|
+
if (g && g.summary) {
|
|
101
|
+
pass += g.summary.passed; tot += g.summary.total;
|
|
102
|
+
const rate = g.summary.pass_rate;
|
|
103
|
+
const rp = el('div', {cls: 'run-pass ' + passClass(rate), text: `${g.summary.passed}/${g.summary.total} passed (${Math.round(rate*100)}%)`});
|
|
104
|
+
item.appendChild(rp);
|
|
105
|
+
}
|
|
106
|
+
sb.appendChild(item);
|
|
107
|
+
});
|
|
108
|
+
if (tot > 0) {
|
|
109
|
+
const hdr = document.getElementById('hdr-stats');
|
|
110
|
+
hdr.textContent = `${runs.length} evals · ${pass}/${tot} expectations · ${Math.round(pass/tot*100)}% pass`;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function selectRun(idx) {
|
|
115
|
+
curRun = idx;
|
|
116
|
+
document.querySelectorAll('.run-item').forEach(e => e.classList.remove('active'));
|
|
117
|
+
const item = document.querySelector(`.run-item[data-idx="${idx}"]`);
|
|
118
|
+
if (item) item.classList.add('active');
|
|
119
|
+
renderMain(runs[idx]);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function renderMain(run) {
|
|
123
|
+
const main = document.getElementById('main');
|
|
124
|
+
main.textContent = '';
|
|
125
|
+
|
|
126
|
+
// Prompt card
|
|
127
|
+
const promptCard = el('div', {cls: 'card'});
|
|
128
|
+
promptCard.appendChild(el('div', {cls: 'card-header', text: 'Prompt'}));
|
|
129
|
+
const pb = el('div', {cls: 'card-body'});
|
|
130
|
+
pb.appendChild(el('div', {cls: 'prompt-box', text: run.prompt || '(no prompt)'}));
|
|
131
|
+
promptCard.appendChild(pb);
|
|
132
|
+
main.appendChild(promptCard);
|
|
133
|
+
|
|
134
|
+
// Grading card
|
|
135
|
+
const g = run.grading;
|
|
136
|
+
if (g && g.summary) {
|
|
137
|
+
const gradeCard = el('div', {cls: 'card'});
|
|
138
|
+
gradeCard.appendChild(el('div', {cls: 'card-header', text: 'Grade Result'}));
|
|
139
|
+
const gb = el('div', {cls: 'card-body'});
|
|
140
|
+
const rate = g.summary.pass_rate;
|
|
141
|
+
const pr = el('div', {cls: 'pill-row'});
|
|
142
|
+
pr.appendChild(el('span', {cls: 'pill ' + pillClass(rate), text: `${g.summary.passed}/${g.summary.total} passed`}));
|
|
143
|
+
pr.appendChild(el('span', {cls: 'pill ' + pillClass(rate), text: `${Math.round(rate*100)}%`}));
|
|
144
|
+
gb.appendChild(pr);
|
|
145
|
+
if (g.expectations) {
|
|
146
|
+
for (const exp of g.expectations) {
|
|
147
|
+
const row = el('div', {cls: 'exp-row'});
|
|
148
|
+
row.appendChild(el('span', {cls: 'exp-icon', text: exp.passed ? '✓' : '✗', style: exp.passed ? 'color:var(--green)' : 'color:var(--red)'}));
|
|
149
|
+
const textWrap = el('div');
|
|
150
|
+
textWrap.appendChild(el('div', {cls: 'exp-text', text: exp.text || ''}));
|
|
151
|
+
if (exp.evidence) textWrap.appendChild(el('div', {cls: 'exp-evidence', text: exp.evidence}));
|
|
152
|
+
row.appendChild(textWrap);
|
|
153
|
+
gb.appendChild(row);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
gradeCard.appendChild(gb);
|
|
157
|
+
main.appendChild(gradeCard);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Files card
|
|
161
|
+
const runKey = run.id;
|
|
162
|
+
if (!curFileIdx[runKey]) curFileIdx[runKey] = 0;
|
|
163
|
+
if (run.outputs && run.outputs.length > 0) {
|
|
164
|
+
const filesCard = el('div', {cls: 'card'});
|
|
165
|
+
filesCard.appendChild(el('div', {cls: 'card-header', text: 'Output Files'}));
|
|
166
|
+
const ftabs = el('div', {cls: 'file-tabs'});
|
|
167
|
+
run.outputs.forEach((f, i) => {
|
|
168
|
+
const tab = el('button', {cls: 'ftab' + (i === curFileIdx[runKey] ? ' active' : ''), text: f.name, onclick: () => { curFileIdx[runKey] = i; renderMain(run); }});
|
|
169
|
+
ftabs.appendChild(tab);
|
|
170
|
+
});
|
|
171
|
+
filesCard.appendChild(ftabs);
|
|
172
|
+
const body = el('div', {cls: 'file-body'});
|
|
173
|
+
const active = run.outputs[curFileIdx[runKey]];
|
|
174
|
+
if (active && active.type === 'text') {
|
|
175
|
+
body.appendChild(el('pre', {cls: 'file-pre', text: active.content || ''}));
|
|
176
|
+
} else if (active) {
|
|
177
|
+
body.appendChild(el('div', {style: 'color:var(--muted);font-size:12px', text: `[Binary file: ${active.name}]`}));
|
|
178
|
+
}
|
|
179
|
+
filesCard.appendChild(body);
|
|
180
|
+
main.appendChild(filesCard);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Feedback card
|
|
184
|
+
const fbCard = el('div', {cls: 'card'});
|
|
185
|
+
fbCard.appendChild(el('div', {cls: 'card-header', text: 'Feedback'}));
|
|
186
|
+
const fbb = el('div', {cls: 'card-body'});
|
|
187
|
+
const saved = (feedback.reviews || []).find(r => r.run_id === run.id)?.feedback || '';
|
|
188
|
+
const ta = el('textarea', {cls: 'feedback-ta', placeholder: 'Notes on this eval run...'});
|
|
189
|
+
ta.value = saved;
|
|
190
|
+
ta.id = `fb-${run.id}`;
|
|
191
|
+
fbb.appendChild(ta);
|
|
192
|
+
const btnRow = el('div', {style: 'display:flex;align-items:center;margin-top:8px'});
|
|
193
|
+
const saveMsg = el('span', {cls: 'save-msg'});
|
|
194
|
+
const btn = el('button', {cls: 'btn', text: 'Save', onclick: () => saveFeedback(run.id, saveMsg)});
|
|
195
|
+
btnRow.appendChild(btn);
|
|
196
|
+
btnRow.appendChild(saveMsg);
|
|
197
|
+
fbb.appendChild(btnRow);
|
|
198
|
+
fbCard.appendChild(fbb);
|
|
199
|
+
main.appendChild(fbCard);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function saveFeedback(runId, msgEl) {
|
|
203
|
+
const ta = document.getElementById(`fb-${runId}`);
|
|
204
|
+
if (!ta) return;
|
|
205
|
+
const text = ta.value.trim();
|
|
206
|
+
const reviews = feedback.reviews || [];
|
|
207
|
+
const idx = reviews.findIndex(r => r.run_id === runId);
|
|
208
|
+
if (idx >= 0) reviews[idx].feedback = text; else reviews.push({run_id: runId, feedback: text});
|
|
209
|
+
feedback.reviews = reviews;
|
|
210
|
+
fetch('/api/feedback', {method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(feedback)})
|
|
211
|
+
.then(r => r.json()).then(() => { if (msgEl) { msgEl.textContent = 'Saved'; setTimeout(() => { msgEl.textContent = ''; }, 2000); } })
|
|
212
|
+
.catch(() => { if (msgEl) msgEl.textContent = 'Save failed'; });
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
buildSidebar();
|
|
216
|
+
if (runs && runs.length > 0) selectRun(0);
|
|
217
|
+
</script>
|
|
218
|
+
</body>
|
|
219
|
+
</html>
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill_name": "ct-grade",
|
|
3
|
+
"evals": [
|
|
4
|
+
{
|
|
5
|
+
"id": 1,
|
|
6
|
+
"prompt": "Grade session S-abc123 and tell me the total score, grade letter, and any flags.",
|
|
7
|
+
"expected_output": "Calls `query check grade { sessionId }` (preferred canonical op, or legacy `admin.grade`) and reports totalScore/100, grade letter (A-F), and any flags from the result.",
|
|
8
|
+
"expectations": [
|
|
9
|
+
"Uses `query check grade` MCP operation with the session ID",
|
|
10
|
+
"Reports the totalScore out of 100",
|
|
11
|
+
"Reports the grade letter (A, B, C, D, or F)",
|
|
12
|
+
"Lists any flags from the grade result",
|
|
13
|
+
"Shows per-dimension scores"
|
|
14
|
+
]
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"id": 2,
|
|
18
|
+
"prompt": "Run grade scenario S4 (Full Lifecycle) using the MCP interface and grade it.",
|
|
19
|
+
"expected_output": "Runs a graded session executing the S4 scenario operations via MCP gateway, then calls `check.grade` and reports the result.",
|
|
20
|
+
"expectations": [
|
|
21
|
+
"Starts a graded session with `mutate session start { grade: true }`",
|
|
22
|
+
"Executes session.list as first operation (S1)",
|
|
23
|
+
"Calls `query admin help` for progressive disclosure (S5)",
|
|
24
|
+
"Uses `tasks.find` not `tasks.list` for discovery (S2)",
|
|
25
|
+
"Calls `mutate session end` at conclusion (S1)",
|
|
26
|
+
"Grades the session via `query check grade { sessionId }` after ending",
|
|
27
|
+
"Reports score close to 100/100 for correct execution"
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"id": 3,
|
|
32
|
+
"prompt": "A/B compare MCP vs CLI for the tasks domain using 3 runs. Set up the run and tell me the execution plan.",
|
|
33
|
+
"expected_output": "Runs setup_run.py with mode=ab, domains=tasks, interface=both, runs=3 and outputs the step-by-step execution plan.",
|
|
34
|
+
"expectations": [
|
|
35
|
+
"Calls or references `scripts/setup_run.py --mode ab --domains tasks --interface both --runs 3`",
|
|
36
|
+
"Creates output directory structure",
|
|
37
|
+
"Outputs a step-by-step plan with arm-A (MCP) and arm-B (CLI) spawn instructions",
|
|
38
|
+
"Notes the requirement to capture total_tokens from task notifications",
|
|
39
|
+
"Includes blind-comparator step after both arms complete"
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"id": 4,
|
|
44
|
+
"prompt": "Run a blind A/B test for scenario S1 and S4. Compare MCP vs CLI. Use 2 runs per configuration.",
|
|
45
|
+
"expected_output": "Sets up and orchestrates blind A/B comparison for both scenarios, spawning parallel agents, capturing tokens, running comparator, and producing a report.",
|
|
46
|
+
"expectations": [
|
|
47
|
+
"Sets up run directory for scenarios s1 and s4",
|
|
48
|
+
"Spawns arm-A (MCP) and arm-B (CLI) agents in the same turn for each scenario",
|
|
49
|
+
"Captures total_tokens from each task notification into timing.json",
|
|
50
|
+
"Spawns blind-comparator agent after both arms complete for each run",
|
|
51
|
+
"Runs token_tracker.py to aggregate stats",
|
|
52
|
+
"Generates report.md with comparative results",
|
|
53
|
+
"Identifies that CLI arm will score 0 on S5 Progressive Disclosure"
|
|
54
|
+
]
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"id": 5,
|
|
58
|
+
"prompt": "List all past grade results and summarize the average score.",
|
|
59
|
+
"expected_output": "Calls `query check grade.list` and summarizes the results.",
|
|
60
|
+
"expectations": [
|
|
61
|
+
"Uses `query check grade.list` MCP operation",
|
|
62
|
+
"Reports number of grade results found",
|
|
63
|
+
"Computes or estimates the average total score",
|
|
64
|
+
"Identifies any sessions with failing grades (F)"
|
|
65
|
+
]
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"id": 6,
|
|
69
|
+
"prompt": "Run all 5 grade scenarios (S1-S5) via MCP and produce a comparative analysis.",
|
|
70
|
+
"expected_output": "Runs all 5 scenarios as graded sessions, grades each one, and produces an analysis comparing performance across scenarios.",
|
|
71
|
+
"expectations": [
|
|
72
|
+
"Starts 5 separate graded sessions (one per scenario)",
|
|
73
|
+
"Executes each scenario's operation sequence via MCP",
|
|
74
|
+
"Grades each session via `check.grade`",
|
|
75
|
+
"Compares scores across all 5 scenarios",
|
|
76
|
+
"Identifies which scenarios scored highest and lowest",
|
|
77
|
+
"Suggests improvements for low-scoring dimensions"
|
|
78
|
+
]
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"id": 7,
|
|
82
|
+
"prompt": "What is the expected token cost difference between MCP and CLI for grade scenario S4?",
|
|
83
|
+
"expected_output": "Explains the token tracking methodology, describes that MCP operations produce richer responses (more tokens) but higher scores, and estimates the delta based on typical operation counts.",
|
|
84
|
+
"expectations": [
|
|
85
|
+
"Explains that total_tokens is captured from task notifications",
|
|
86
|
+
"Notes that MCP responses include _meta envelope with gateway, requestId, etc.",
|
|
87
|
+
"Notes that CLI responses are typically more compact",
|
|
88
|
+
"Estimates MCP is likely to use more tokens per operation",
|
|
89
|
+
"Mentions score-per-token as the key efficiency metric",
|
|
90
|
+
"References timing.json as where token data is stored"
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
]
|
|
94
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# A/B Test Methodology
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The ct-grade A/B framework compares two configurations (arms) of CLEO agent behavior using the 5-dimension behavioral rubric as the scoring criterion. The framework is blind: the comparator agent does not know which arm is which configuration.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Core Concepts
|
|
10
|
+
|
|
11
|
+
### Arms
|
|
12
|
+
|
|
13
|
+
An "arm" is a specific test configuration. In CLEO A/B tests, the two most common arms are:
|
|
14
|
+
|
|
15
|
+
| Arm | Typical Config | Example |
|
|
16
|
+
|-----|---------------|---------|
|
|
17
|
+
| A | MCP gateway | Uses `query`/`mutate` for all operations |
|
|
18
|
+
| B | CLI fallback | Uses `cleo-dev` CLI for equivalent operations |
|
|
19
|
+
|
|
20
|
+
Arms can also differ by:
|
|
21
|
+
- Session scope (`global` vs `epic:T500`)
|
|
22
|
+
- Tier escalation (with/without `admin.help`)
|
|
23
|
+
- Agent persona (orchestrator vs task-executor)
|
|
24
|
+
- Prompt configuration (with/without ct-cleo skill)
|
|
25
|
+
|
|
26
|
+
### Slots
|
|
27
|
+
|
|
28
|
+
A "slot" is one test unit — either a grade scenario (s1-s5) or a domain (tasks, session, etc.) depending on mode. Each slot produces one comparison.
|
|
29
|
+
|
|
30
|
+
### Runs
|
|
31
|
+
|
|
32
|
+
The number of times each arm executes each slot. Multiple runs increase statistical confidence. Minimum recommended: 3 runs.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Blind Protocol
|
|
37
|
+
|
|
38
|
+
1. **Orchestrator spawns both arms in the same turn** — this is critical for parallel execution and prevents the orchestrator's context from being polluted by one arm's output before spawning the other.
|
|
39
|
+
|
|
40
|
+
2. **Arm outputs are labeled A and B only** — the arm label (A/B) is used, not the configuration label (mcp/cli). The comparator never sees "MCP" or "CLI" in the output it receives.
|
|
41
|
+
|
|
42
|
+
3. **Comparator reads only grade.json and operations.jsonl** — not timing.json (which contains the `interface` field). This enforces blindness.
|
|
43
|
+
|
|
44
|
+
4. **Analysis-reporter de-blinds** — after all comparisons are done, the reporter reveals which arm was which configuration and synthesizes patterns.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Token Tracking Protocol
|
|
49
|
+
|
|
50
|
+
Token data comes from Claude Code task notifications. You MUST capture it immediately — it is ephemeral.
|
|
51
|
+
|
|
52
|
+
### Capture Point
|
|
53
|
+
|
|
54
|
+
When an Agent task completes, the notification includes:
|
|
55
|
+
- `total_tokens`: Total tokens consumed by the subagent task
|
|
56
|
+
- `duration_ms`: Wall clock time for the task
|
|
57
|
+
|
|
58
|
+
### Storage
|
|
59
|
+
|
|
60
|
+
Immediately on task completion, update the arm's `timing.json`:
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
# Pseudocode — actual capture is in main context
|
|
64
|
+
timing = load_json(arm_dir + "/timing.json")
|
|
65
|
+
timing["total_tokens"] = task.total_tokens # from notification
|
|
66
|
+
timing["duration_ms"] = task.duration_ms # from notification
|
|
67
|
+
timing["executor_end"] = now_iso()
|
|
68
|
+
timing["executor_duration_seconds"] = task.duration_ms / 1000
|
|
69
|
+
save_json(arm_dir + "/timing.json", timing)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Why This Matters
|
|
73
|
+
|
|
74
|
+
Token cost is the primary economic metric for comparing interfaces:
|
|
75
|
+
- MCP operations may use more tokens (richer responses, metadata)
|
|
76
|
+
- CLI operations may use fewer tokens but score lower on S5
|
|
77
|
+
- Score-per-token tells you which interface is more efficient for protocol work
|
|
78
|
+
|
|
79
|
+
### Missing Token Data
|
|
80
|
+
|
|
81
|
+
If you forgot to capture tokens, you cannot recover them. Mark `total_tokens: null` in timing.json. The token_tracker.py script will warn about missing data. Run statistics will exclude null values.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Statistical Interpretation
|
|
86
|
+
|
|
87
|
+
### Minimum Confidence
|
|
88
|
+
|
|
89
|
+
- **1 run**: No statistical confidence, anecdotal
|
|
90
|
+
- **3 runs**: Low confidence, sufficient for directional signal
|
|
91
|
+
- **5+ runs**: Moderate confidence, suitable for decisions
|
|
92
|
+
- **10+ runs**: High confidence, publication-grade
|
|
93
|
+
|
|
94
|
+
### Score Interpretation
|
|
95
|
+
|
|
96
|
+
| Score Delta | Interpretation |
|
|
97
|
+
|-------------|----------------|
|
|
98
|
+
| 0-5 pts | Noise level — likely equivalent |
|
|
99
|
+
| 5-15 pts | Meaningful difference — investigate flags |
|
|
100
|
+
| 15-25 pts | Significant — one interface clearly better |
|
|
101
|
+
| 25+ pts | Extreme — likely S5 differential (MCP vs CLI) |
|
|
102
|
+
|
|
103
|
+
### Expected MCP vs CLI Delta
|
|
104
|
+
|
|
105
|
+
Based on the rubric implementation:
|
|
106
|
+
- S5 Progressive Disclosure: always +20 for MCP (if admin.help called), +10 MCP no help, 0 CLI
|
|
107
|
+
- S1-S4: approximately equal if agent follows same protocol steps
|
|
108
|
+
- Total expected delta: **+10 to +20 points** in favor of MCP for equivalent protocols
|
|
109
|
+
|
|
110
|
+
If delta exceeds 20 points, investigate whether the CLI agent is also skipping other protocol steps (session.list, descriptions, etc.) due to lack of guidance.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Git Tree Comparison
|
|
115
|
+
|
|
116
|
+
The "git tree" metaphor: each A/B run produces a branch in the results tree. Multiple runs of the same configuration are like commits on the same branch.
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
ab_results/
|
|
120
|
+
run-001/ ← first full A/B run
|
|
121
|
+
s4/
|
|
122
|
+
run-01/arm-A/ ← first run, MCP arm
|
|
123
|
+
run-01/arm-B/ ← first run, CLI arm
|
|
124
|
+
run-01/comparison.json
|
|
125
|
+
run-02/arm-A/
|
|
126
|
+
...
|
|
127
|
+
token-summary.json
|
|
128
|
+
report.md
|
|
129
|
+
run-002/ ← second full A/B run (compare against run-001)
|
|
130
|
+
...
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
To compare **across A/B runs** (e.g., after making a protocol change):
|
|
134
|
+
1. Generate report for run-001
|
|
135
|
+
2. Make protocol change
|
|
136
|
+
3. Run run-002
|
|
137
|
+
4. Compare report.md files
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Anti-patterns in A/B Testing
|
|
142
|
+
|
|
143
|
+
| Anti-pattern | Problem | Fix |
|
|
144
|
+
|---|---|---|
|
|
145
|
+
| Sequential arms | Arm B's spawn might be influenced by A's output | Spawn both arms in same message |
|
|
146
|
+
| Comparator sees config | Breaks blindness | Pass only grade.json + operations.jsonl |
|
|
147
|
+
| Single run | No variance data | Minimum 3 runs |
|
|
148
|
+
| Same session scope | Arms share audit data | Each arm starts a new `session.start { grade: true }` |
|
|
149
|
+
| Forgetting to capture tokens | Cannot reconstruct | Write timing.json IMMEDIATELY on task completion |
|
|
150
|
+
| Comparing different scenarios | Apples vs oranges | Fix scenario parameter, vary interface only |
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# CLEO Domain Operation Reference for A/B Testing
|
|
2
|
+
|
|
3
|
+
**Source**: `docs/specs/CLEO-OPERATION-CONSTITUTION.md`
|
|
4
|
+
**Purpose**: Lists the key operations to test in MCP vs CLI A/B comparisons.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## MCP vs CLI Equivalents
|
|
9
|
+
|
|
10
|
+
For each domain, these are the canonical operations to test in A/B mode.
|
|
11
|
+
MCP gateway = audit metadata.gateway is `'query'` or `'mutate'` (set by MCP adapter).
|
|
12
|
+
CLI = operations routed through CLI do NOT set metadata.gateway.
|
|
13
|
+
|
|
14
|
+
### tasks (32 operations)
|
|
15
|
+
|
|
16
|
+
| Test Op | MCP | CLI |
|
|
17
|
+
|---------|-----|-----|
|
|
18
|
+
| Discovery | `query tasks find { "status": "active" }` | `cleo-dev find --status active` |
|
|
19
|
+
| Show detail | `query tasks show { "taskId": "T123" }` | `cleo-dev show T123` |
|
|
20
|
+
| List children | `query tasks list { "parent": "T100" }` | `cleo-dev list --parent T100` |
|
|
21
|
+
| Create | `mutate tasks add { "title": "...", "description": "..." }` | `cleo-dev add --title "..." --description "..."` |
|
|
22
|
+
| Update | `mutate tasks update { "taskId": "T123", "status": "active" }` | `cleo-dev update T123 --status active` |
|
|
23
|
+
| Complete | `mutate tasks complete { "taskId": "T123" }` | `cleo-dev complete T123` |
|
|
24
|
+
| Exists check | `query tasks exists { "taskId": "T123" }` | `cleo-dev exists T123` |
|
|
25
|
+
|
|
26
|
+
**Key S2 insight**: `tasks.find` (MCP) vs `cleo-dev find` (CLI). Both count toward find:list ratio in the audit log. MCP find at gateway='query', CLI find also logged but without gateway metadata.
|
|
27
|
+
|
|
28
|
+
### session (19 operations)
|
|
29
|
+
|
|
30
|
+
| Test Op | MCP | CLI |
|
|
31
|
+
|---------|-----|-----|
|
|
32
|
+
| Check existing | `query session list` | `cleo-dev session list` |
|
|
33
|
+
| Start | `mutate session start { "grade": true, "scope": "global" }` | `cleo-dev session start --grade --scope global` |
|
|
34
|
+
| End | `mutate session end` | `cleo-dev session end` |
|
|
35
|
+
| Status | `query session status` | `cleo-dev session status` |
|
|
36
|
+
| Record decision | `mutate session record.decision { "decision": "...", "rationale": "..." }` | `cleo-dev session record-decision ...` |
|
|
37
|
+
|
|
38
|
+
**Critical**: `session.list` (MCP) is what the rubric checks for S1. If CLI does `cleo-dev session list`, it still appears as `domain='session', operation='list'` in the audit log. S1 counts it.
|
|
39
|
+
|
|
40
|
+
### memory (18 operations) — Tier 1
|
|
41
|
+
|
|
42
|
+
| Test Op | MCP | CLI |
|
|
43
|
+
|---------|-----|-----|
|
|
44
|
+
| Search | `query memory find { "query": "authentication" }` | `cleo-dev memory find "authentication"` |
|
|
45
|
+
| Store observation | `mutate memory observe { "text": "..." }` | `cleo-dev memory observe "..."` |
|
|
46
|
+
| Timeline | `query memory timeline { "anchor": "<id>" }` | N/A (MCP-preferred) |
|
|
47
|
+
|
|
48
|
+
### admin (44 operations)
|
|
49
|
+
|
|
50
|
+
| Test Op | MCP | CLI |
|
|
51
|
+
|---------|-----|-----|
|
|
52
|
+
| Dashboard | `query admin dash` | `cleo-dev dash` |
|
|
53
|
+
| Help (S5 key) | `query admin help` | `cleo-dev help` |
|
|
54
|
+
| Grade session | `query admin grade { "sessionId": "<id>" }` | `cleo-dev grade <id>` |
|
|
55
|
+
| Health check | `query admin health` | `cleo-dev health` |
|
|
56
|
+
|
|
57
|
+
**Critical for S5**: Only `query admin help` (MCP) satisfies the `helpCalls` filter in S5. CLI `cleo-dev help` does NOT set `metadata.gateway='query'` or match `domain='admin', operation='help'` — it depends on how the CLI routes internally.
|
|
58
|
+
|
|
59
|
+
### pipeline (42 operations) — LOOM system
|
|
60
|
+
|
|
61
|
+
| Test Op | MCP | CLI |
|
|
62
|
+
|---------|-----|-----|
|
|
63
|
+
| Stage status | `query pipeline stage.status` | `cleo-dev pipeline status` |
|
|
64
|
+
| Stage validate | `query pipeline stage.validate` | `cleo-dev pipeline validate` |
|
|
65
|
+
| Manifest list | `query pipeline manifest.list` | `cleo-dev pipeline manifest list` |
|
|
66
|
+
|
|
67
|
+
### check (19 operations)
|
|
68
|
+
|
|
69
|
+
| Test Op | MCP | CLI |
|
|
70
|
+
|---------|-----|-----|
|
|
71
|
+
| Test status | `query check test.status` | `cleo-dev check test-status` |
|
|
72
|
+
| Protocol check | `query check protocol` | `cleo-dev check protocol` |
|
|
73
|
+
| Compliance | `query check compliance.summary` | `cleo-dev check compliance` |
|
|
74
|
+
|
|
75
|
+
### orchestrate (19 operations)
|
|
76
|
+
|
|
77
|
+
| Test Op | MCP | CLI |
|
|
78
|
+
|---------|-----|-----|
|
|
79
|
+
| Status | `query orchestrate status` | `cleo-dev orchestrate status` |
|
|
80
|
+
| Waves | `query orchestrate waves` | `cleo-dev orchestrate waves` |
|
|
81
|
+
|
|
82
|
+
### tools (32 operations)
|
|
83
|
+
|
|
84
|
+
| Test Op | MCP | CLI |
|
|
85
|
+
|---------|-----|-----|
|
|
86
|
+
| Skill list (S5 key) | `query tools skill.list` | `cleo-dev tools skill list` |
|
|
87
|
+
| Skill show (S5 key) | `query tools skill.show { "skillId": "ct-cleo" }` | `cleo-dev tools skill show ct-cleo` |
|
|
88
|
+
|
|
89
|
+
**S5 note**: `tools.skill.list` and `tools.skill.show` via MCP count toward S5 helpCalls filter.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## A/B Domain Test Configurations
|
|
94
|
+
|
|
95
|
+
### Quick A/B: Tasks Domain
|
|
96
|
+
|
|
97
|
+
**Goal**: Compare MCP vs CLI for core task operations.
|
|
98
|
+
**Operations to execute (both interfaces)**:
|
|
99
|
+
1. `session list` — S1
|
|
100
|
+
2. `tasks find { "status": "active" }` — S2
|
|
101
|
+
3. `tasks show { "taskId": "<valid-id>" }` — S2
|
|
102
|
+
4. `session end` — S1
|
|
103
|
+
|
|
104
|
+
**Expected score difference**: MCP ~30/100 vs CLI ~20/100 (S5 is 0 for CLI)
|
|
105
|
+
|
|
106
|
+
### Standard A/B: Full Protocol (S4)
|
|
107
|
+
|
|
108
|
+
**Goal**: Full lifecycle scenario through both interfaces.
|
|
109
|
+
**Operations**: Follow S4 scenario (10 ops including admin.help).
|
|
110
|
+
**Expected**: MCP 100/100, CLI ~80/100
|
|
111
|
+
|
|
112
|
+
### Targeted A/B: S5 Isolation
|
|
113
|
+
|
|
114
|
+
**Goal**: Specifically measure the S5 (progressive disclosure) gap.
|
|
115
|
+
**Operations** — same except arm A calls `admin.help`, arm B does not:
|
|
116
|
+
|
|
117
|
+
Arm A (MCP + help):
|
|
118
|
+
```
|
|
119
|
+
query session list → query admin help → query tasks find → mutate session end
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Arm B (CLI — no help call):
|
|
123
|
+
```
|
|
124
|
+
cleo-dev session list → cleo-dev find → cleo-dev session end
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Expected**: Arm A S5 = 20/20, Arm B S5 = 0/20
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Tier Notes
|
|
132
|
+
|
|
133
|
+
- **Tier 0 ops**: Available to all agents without admin.help (tasks, session, check, pipeline, orchestrate, tools, admin, sticky)
|
|
134
|
+
- **Tier 1 ops**: Require `admin.help --tier 1` first (memory, manifest, advanced session)
|
|
135
|
+
- **Tier 2 ops**: Require `admin.help --tier 2` (nexus, admin advanced, cross-project)
|
|
136
|
+
|
|
137
|
+
In A/B tests, tier 1+ operations should only appear if the scenario explicitly escalates via admin.help. Otherwise the agent should not have discovered them.
|