ai-engineering-loop 1.0.5 → 1.0.6
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/.claude/agents/devil-advocate.md +60 -0
- package/.claude/agents/judge.md +49 -0
- package/.claude/commands/ai-engineering-loop.md +10 -0
- package/.claude/settings.local.json +9 -0
- package/.claude/skills/ai-engineering-loop/SKILL.md +59 -0
- package/README.md +34 -2
- package/README.npm.md +4 -0
- package/bin/ai-engineering-loop.js +13 -1
- package/docs/claude-code-feasibility.md +45 -0
- package/package.json +3 -1
- package/tests/skill-host-compat.test.js +68 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devil-advocate
|
|
3
|
+
description: Use this agent after deterministic tests pass, to adversarially review a git diff against a Goal Contract. Returns a Finding Ledger. Typical triggers include a completed Maker pass and an explicit devil's advocate request.
|
|
4
|
+
tools: Read, Grep, Glob, Bash
|
|
5
|
+
model: inherit
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
You are the Devil's Advocate for the AI Engineering Loop. You are read-only. You never modify application source and never commit.
|
|
9
|
+
|
|
10
|
+
## When to invoke
|
|
11
|
+
|
|
12
|
+
- **After Maker verification.** Tests passed. Review the diff against the Goal Contract.
|
|
13
|
+
- **Explicit review request.** The user or orchestrator asks for a devil's advocate pass.
|
|
14
|
+
|
|
15
|
+
## Input barrier
|
|
16
|
+
|
|
17
|
+
Use only the spawn prompt plus:
|
|
18
|
+
|
|
19
|
+
- Goal Contract
|
|
20
|
+
- `.ai-engineering-loop/` (`architecture.md`, `conventions.md`, `verification.md`)
|
|
21
|
+
- The git diff (path in the prompt, or `git diff <base>...HEAD`)
|
|
22
|
+
- Verification logs (exit code, stdout, test counts)
|
|
23
|
+
|
|
24
|
+
Do not ask for Maker rationale. Do not treat parent narration as evidence.
|
|
25
|
+
|
|
26
|
+
## Output
|
|
27
|
+
|
|
28
|
+
Return a Finding Ledger as a fenced JSON block:
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"iteration": 1,
|
|
33
|
+
"executionMode": "TRUE_INDEPENDENT_AGENT",
|
|
34
|
+
"findings": [
|
|
35
|
+
{
|
|
36
|
+
"id": "DA-01",
|
|
37
|
+
"topic": "correctness",
|
|
38
|
+
"validity": "VALID",
|
|
39
|
+
"severity": "BLOCKER",
|
|
40
|
+
"disposition": "STRONG",
|
|
41
|
+
"location": "path/to/file.ext#L12-L20",
|
|
42
|
+
"acceptanceCriteria": "AC-1",
|
|
43
|
+
"failureScenario": "Concrete failing case",
|
|
44
|
+
"reproduction": "Steps to reproduce",
|
|
45
|
+
"evidence": "What you read in the diff or source",
|
|
46
|
+
"concreteAlternativeDiff": "diff snippet"
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Rules:
|
|
53
|
+
|
|
54
|
+
- `validity` is VALID or INVALID.
|
|
55
|
+
- `severity` is BLOCKER, HIGH, MEDIUM, or LOW.
|
|
56
|
+
- `disposition` is STRONG, ACCEPTABLE, or WEAK.
|
|
57
|
+
- Every VALID BLOCKER or HIGH finding must include `concreteAlternativeDiff`.
|
|
58
|
+
- Empty `findings` is allowed when the diff is clean against the Goal Contract.
|
|
59
|
+
|
|
60
|
+
Use Read, Grep, Glob, and read-only Bash (`git diff`, `git log`, `git show`). Do not write files.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: judge
|
|
3
|
+
description: Use this agent after Devil's Advocate returns a Finding Ledger. Issues PASS, ITERATE, or ESCALATE from Validity plus Severity. Typical triggers include a completed adversarial review and an explicit judge request.
|
|
4
|
+
tools: Read, Grep, Glob, Bash
|
|
5
|
+
model: inherit
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
You are the Judge for the AI Engineering Loop. You do not write application code. You issue one verdict: PASS, ITERATE, or ESCALATE.
|
|
9
|
+
|
|
10
|
+
## When to invoke
|
|
11
|
+
|
|
12
|
+
- **After Devil's Advocate.** A Finding Ledger exists. Evaluate it against the Goal Contract and verification evidence.
|
|
13
|
+
- **Explicit judge request.** The orchestrator asks for a verdict.
|
|
14
|
+
|
|
15
|
+
## Inputs
|
|
16
|
+
|
|
17
|
+
- Goal Contract
|
|
18
|
+
- Verification evidence (command, exit code 0, stdout, test counts)
|
|
19
|
+
- Devil's Advocate Finding Ledger
|
|
20
|
+
- Git diff only to fact-check a finding
|
|
21
|
+
|
|
22
|
+
Ignore Maker optimism and reviewer tone. Disposition never overrides Validity plus Severity.
|
|
23
|
+
|
|
24
|
+
## Decision matrix
|
|
25
|
+
|
|
26
|
+
- Verification missing, vague, or non-zero exit: ITERATE
|
|
27
|
+
- Any VALID BLOCKER or HIGH still open: ITERATE (ESCALATE if iteration is 3 or more)
|
|
28
|
+
- INVALID findings: DISMISS, cannot block delivery
|
|
29
|
+
- VALID MEDIUM or LOW: ACCEPT as tradeoff; may still PASS
|
|
30
|
+
- All acceptance criteria proven, verification green, zero open blockers: PASS
|
|
31
|
+
|
|
32
|
+
## Output
|
|
33
|
+
|
|
34
|
+
Return a fenced JSON block:
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"verdict": "PASS",
|
|
39
|
+
"reason": "All acceptance criteria verified; 0 open blocking findings",
|
|
40
|
+
"action": "Proceed to context impact assessment and delivery adapter",
|
|
41
|
+
"blockingFindings": [],
|
|
42
|
+
"acceptableTradeoffs": [],
|
|
43
|
+
"dismissedFindings": []
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`verdict` must be exactly PASS, ITERATE, or ESCALATE.
|
|
48
|
+
|
|
49
|
+
Use Read and read-only git. Do not edit source.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ai-engineering-loop
|
|
3
|
+
description: Run the AI Engineering Loop (init, status, refresh, or full Maker then Devil's Advocate then Judge).
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Follow `.claude/skills/ai-engineering-loop/SKILL.md`.
|
|
7
|
+
|
|
8
|
+
Use the Task tool for Devil's Advocate and Judge. Pass only subagent_type, description, and prompt.
|
|
9
|
+
|
|
10
|
+
Arguments: init, status, refresh, or a task description.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ai-engineering-loop
|
|
3
|
+
description: Use when the user runs /ai-engineering-loop, asks to init or refresh living project context, or wants the Maker / Devil's Advocate / Judge engineering loop on Claude Code.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# AI Engineering Loop (Claude Code)
|
|
7
|
+
|
|
8
|
+
Canonical specs: `core/`, `agents/`, `policies/`. Read those files. Do not invent extra tool parameters.
|
|
9
|
+
|
|
10
|
+
## Host rule (prevents 400 REQUEST_BODY_INVALID)
|
|
11
|
+
|
|
12
|
+
Claude Code talks to strict proxies (including Kiro). Follow this exactly:
|
|
13
|
+
|
|
14
|
+
1. Use only tools that exist in this session.
|
|
15
|
+
2. For subagents, call the host tool named **Task** (or **Agent** if that is the only subagent tool). Pass **only** these keys:
|
|
16
|
+
- `subagent_type`
|
|
17
|
+
- `description`
|
|
18
|
+
- `prompt`
|
|
19
|
+
3. Do **not** add any other keys. Extra keys make Kiro return HTTP 400 `REQUEST_BODY_INVALID`.
|
|
20
|
+
4. If no Task/Agent tool exists, review in this session and label it `CONTEXT_ISOLATION_ONLY`. Do not invent a tool name.
|
|
21
|
+
|
|
22
|
+
## Commands
|
|
23
|
+
|
|
24
|
+
- `init` / `status` / `refresh`: run `npx ai-engineering-loop <command>` in the repo. Do not commit unless asked.
|
|
25
|
+
- Any other argument: full loop for that task.
|
|
26
|
+
|
|
27
|
+
## Loop
|
|
28
|
+
|
|
29
|
+
Parent session is Maker plus orchestrator. Spawn Devil's Advocate and Judge as **siblings**, not nested.
|
|
30
|
+
|
|
31
|
+
1. Stage 0: `npx ai-engineering-loop status` (init or refresh if missing or stale).
|
|
32
|
+
2. Stage 1: write a Goal Contract. Schema: `core/goal-contract.md`.
|
|
33
|
+
3. Stages 2-4: Maker work in the parent. Surgical diff plus tests.
|
|
34
|
+
4. Stage 5: run commands from `.ai-engineering-loop/verification.md`. Keep command, exit code, stdout, test counts. Vague "seems green" is invalid.
|
|
35
|
+
5. Write artifact paths (Goal Contract, diff, verification log). Put those paths in child prompts. Do not paste Maker rationale.
|
|
36
|
+
6. Stage 6: Task `subagent_type: devil-advocate` (fallback `general-purpose`). Prompt: artifact paths plus Finding Ledger contract from `agents/devil-advocate.md`.
|
|
37
|
+
7. Stage 7: Task `subagent_type: judge` (fallback `general-purpose`). Prompt: Goal Contract, verification evidence, Finding Ledger. Verdict is PASS, ITERATE, or ESCALATE.
|
|
38
|
+
8. ITERATE with iteration under 3: fix in the parent, re-verify, spawn a **new** Devil's Advocate (do not resume the previous child).
|
|
39
|
+
9. Stage 8: delivery from `.ai-engineering-loop/adapter.md`.
|
|
40
|
+
|
|
41
|
+
## Report header
|
|
42
|
+
|
|
43
|
+
When Task/Agent actually returned a child result:
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
Execution Mode: TRUE_INDEPENDENT_AGENT
|
|
47
|
+
Independent LLM Execution: PROVEN
|
|
48
|
+
Native Subagent Invocation: AVAILABLE
|
|
49
|
+
Review Method: True Independent Agent
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
When no subagent tool exists:
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
Execution Mode: CONTEXT_ISOLATION_ONLY
|
|
56
|
+
Independent LLM Execution: NOT PROVEN
|
|
57
|
+
Native Subagent Invocation: UNAVAILABLE
|
|
58
|
+
Review Method: Clean-Slate Artifact Isolation Barrier
|
|
59
|
+
```
|
package/README.md
CHANGED
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
7
|
[](https://github.com/egagofur/ai-engineering-loop/pulls)
|
|
8
8
|
[](https://github.com/egagofur/ai-engineering-loop)
|
|
9
|
-
[](https://github.com/egagofur/ai-engineering-loop/releases)
|
|
10
10
|
|
|
11
11
|
**A Reusable, Framework-Agnostic AI Engineering Operating System for Autonomous Coding Agents**
|
|
12
12
|
|
|
13
13
|
*Featuring living project context, strict verification evidence contracts, 3-stage capability lifecycle registry, and dual-axis Judge evaluation.*
|
|
14
14
|
|
|
15
|
-
[Overview](#overview--philosophy) • [Runtime Capability Registry](#runtime-capability-registry--execution-modes) • [Verification Evidence](#verification-evidence-contract) • [CLI Commands](#cli-interface--commands) • [Grok CLI](#grok-cli-integration) • [Antigravity](#antigravity-agent-integration) • [Lifecycle](#lifecycle-stages) • [Architecture](#architecture--5-layer-configuration) • [Project Profiles](#project-profiles) • [Repository Structure](#repository-structure) • [Reference Examples](#reference-examples) • [Contributing](#contributing)
|
|
15
|
+
[Overview](#overview--philosophy) • [Runtime Capability Registry](#runtime-capability-registry--execution-modes) • [Verification Evidence](#verification-evidence-contract) • [CLI Commands](#cli-interface--commands) • [Grok CLI](#grok-cli-integration) • [Claude Code](#claude-code-integration) • [Antigravity](#antigravity-agent-integration) • [Lifecycle](#lifecycle-stages) • [Architecture](#architecture--5-layer-configuration) • [Project Profiles](#project-profiles) • [Repository Structure](#repository-structure) • [Reference Examples](#reference-examples) • [Contributing](#contributing)
|
|
16
16
|
|
|
17
17
|
</div>
|
|
18
18
|
|
|
@@ -188,6 +188,32 @@ See [docs/grok-cli-feasibility.md](docs/grok-cli-feasibility.md).
|
|
|
188
188
|
|
|
189
189
|
---
|
|
190
190
|
|
|
191
|
+
## Claude Code Integration
|
|
192
|
+
|
|
193
|
+
Claude Code is a first-class host. Use the **Task** (or **Agent**) tool with **only** `subagent_type`, `description`, and `prompt`.
|
|
194
|
+
|
|
195
|
+
Do **not** pass Grok keys (`spawn_subagent`, `capability_mode`, `isolation`, `resume_from`). Extra keys are the usual cause of:
|
|
196
|
+
|
|
197
|
+
```
|
|
198
|
+
API Error: 400 [kiro/claude-sonnet-5] REQUEST_BODY_INVALID
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
| Loop role | Claude Code `subagent_type` | Task keys |
|
|
202
|
+
|---|---|---|
|
|
203
|
+
| Orchestrator / Maker | parent session | n/a |
|
|
204
|
+
| Devil's Advocate | `devil-advocate` (fallback `general-purpose`) | `subagent_type`, `description`, `prompt` |
|
|
205
|
+
| Judge | `judge` (fallback `general-purpose`) | `subagent_type`, `description`, `prompt` |
|
|
206
|
+
|
|
207
|
+
Repo-local Claude Code files:
|
|
208
|
+
|
|
209
|
+
- `.claude/agents/devil-advocate.md` / `.claude/agents/judge.md`
|
|
210
|
+
- `.claude/skills/ai-engineering-loop/SKILL.md`
|
|
211
|
+
- `.claude/commands/ai-engineering-loop.md` → `/ai-engineering-loop`
|
|
212
|
+
|
|
213
|
+
See [docs/claude-code-feasibility.md](docs/claude-code-feasibility.md).
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
191
217
|
## Antigravity Agent Integration
|
|
192
218
|
|
|
193
219
|
When working inside the Antigravity IDE or compatible agentic platforms, you can invoke the loop via slash commands:
|
|
@@ -227,6 +253,12 @@ ai-engineering-loop/
|
|
|
227
253
|
│ ├── skills/ai-engineering-loop/ # Grok skill (spawn protocol)
|
|
228
254
|
│ └── commands/ai-engineering-loop.md # /ai-engineering-loop slash command
|
|
229
255
|
│
|
|
256
|
+
├── .claude/ # Claude Code host adapter (Kiro-safe)
|
|
257
|
+
│ ├── agents/devil-advocate.md # Task subagent type
|
|
258
|
+
│ ├── agents/judge.md # Task subagent type
|
|
259
|
+
│ ├── skills/ai-engineering-loop/ # Claude skill (Task keys only)
|
|
260
|
+
│ └── commands/ai-engineering-loop.md # /ai-engineering-loop slash command
|
|
261
|
+
│
|
|
230
262
|
├── core/ # Generic engineering loop specifications
|
|
231
263
|
│ ├── orchestration-model.md # 3-stage capability lifecycle & execution priority
|
|
232
264
|
│ ├── project-initialization.md # Auto-discovery & initialization lifecycle
|
package/README.npm.md
CHANGED
|
@@ -44,6 +44,10 @@ npx ai-engineering-loop run
|
|
|
44
44
|
|
|
45
45
|
Inside a Grok TUI session, `/ai-engineering-loop` uses repo-local `.grok/agents/` types. Devil's Advocate and Judge spawn as sibling children (`capability_mode: execute`, no `resume_from`). Do not use `caveman:cavecrew-reviewer` as the loop reviewer.
|
|
46
46
|
|
|
47
|
+
## Claude Code
|
|
48
|
+
|
|
49
|
+
Inside Claude Code, `/ai-engineering-loop` uses `.claude/agents/` types via the **Task** tool. Pass only `subagent_type`, `description`, and `prompt`. Do not pass Grok keys (`spawn_subagent`, `capability_mode`, `resume_from`) — extra keys cause Kiro `REQUEST_BODY_INVALID`.
|
|
50
|
+
|
|
47
51
|
---
|
|
48
52
|
|
|
49
53
|
## Antigravity IDE Integration
|
|
@@ -15,7 +15,7 @@ const path = require('path');
|
|
|
15
15
|
const crypto = require('crypto');
|
|
16
16
|
const { execSync } = require('child_process');
|
|
17
17
|
|
|
18
|
-
const VERSION = '1.0.
|
|
18
|
+
const VERSION = '1.0.6';
|
|
19
19
|
const CWD = process.cwd();
|
|
20
20
|
const CONTEXT_DIR = path.join(CWD, '.ai-engineering-loop');
|
|
21
21
|
|
|
@@ -601,6 +601,18 @@ function handleRun() {
|
|
|
601
601
|
}
|
|
602
602
|
console.log('- Skill: .grok/skills/ai-engineering-loop/SKILL.md');
|
|
603
603
|
}
|
|
604
|
+
|
|
605
|
+
const claudeSkill = path.join(CWD, '.claude', 'skills', 'ai-engineering-loop', 'SKILL.md');
|
|
606
|
+
const claudeAgent = path.join(CWD, '.claude', 'agents', 'devil-advocate.md');
|
|
607
|
+
if (fs.existsSync(claudeSkill) || fs.existsSync(claudeAgent)) {
|
|
608
|
+
console.log('------------------------------------------------------------');
|
|
609
|
+
log.bold('Claude Code host:');
|
|
610
|
+
console.log('- Subagent tool: Task (or Agent). Keys allowed: subagent_type, description, prompt');
|
|
611
|
+
console.log('- Devil\'s Advocate: Task subagent_type=devil-advocate');
|
|
612
|
+
console.log('- Judge: Task subagent_type=judge (sibling, not nested)');
|
|
613
|
+
console.log('- Do not pass spawn_subagent, capability_mode, isolation, resume_from (Kiro 400 REQUEST_BODY_INVALID)');
|
|
614
|
+
console.log('- Skill: .claude/skills/ai-engineering-loop/SKILL.md');
|
|
615
|
+
}
|
|
604
616
|
console.log('------------------------------------------------------------\n');
|
|
605
617
|
}
|
|
606
618
|
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Claude Code Feasibility and Kiro Request Safety
|
|
2
|
+
|
|
3
|
+
## 1. Problem
|
|
4
|
+
|
|
5
|
+
Claude Code users (including Kiro-backed models such as `kiro/claude-sonnet-5`) hit:
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
API Error: 400 [kiro/claude-sonnet-5] [400]:
|
|
9
|
+
{"message":"Improperly formed request.","reason":"REQUEST_BODY_INVALID"}
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Kiro's `generateAssistantResponse` rejects request bodies that Claude Code will happily send. Two skill-side causes were confirmed:
|
|
13
|
+
|
|
14
|
+
1. **Extra tool keys.** The shared skill told the model to call `spawn_subagent` with `capability_mode`, `isolation`, and `resume_from`. Claude Code's Task/Agent schema does not have those fields. Proxies that validate additionalProperties fail with `REQUEST_BODY_INVALID`.
|
|
15
|
+
2. **Hostile markup in the injected skill.** Mermaid (`<br>`, nested `{braces}`), LaTeX (`$\rightarrow$`), and folded YAML descriptions inflate and corrupt the system/skill payload Kiro receives.
|
|
16
|
+
|
|
17
|
+
This is separate from 9router bugs that reject any Anthropic `system` field. Those need a router fix. The skill must still not add extra invalid keys or markup.
|
|
18
|
+
|
|
19
|
+
## 2. Claude Code mapping
|
|
20
|
+
|
|
21
|
+
| Loop role | Claude Code type | Task keys allowed |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| Orchestrator / Maker | parent session | n/a |
|
|
24
|
+
| Devil's Advocate | `devil-advocate` (fallback `general-purpose`) | `subagent_type`, `description`, `prompt` |
|
|
25
|
+
| Judge | `judge` (fallback `general-purpose`) | `subagent_type`, `description`, `prompt` |
|
|
26
|
+
|
|
27
|
+
Do not pass Grok keys (`spawn_subagent`, `capability_mode`, `resume_from`, `isolation`, `background`) on Claude Code.
|
|
28
|
+
|
|
29
|
+
Repo files:
|
|
30
|
+
|
|
31
|
+
- `.claude/skills/ai-engineering-loop/SKILL.md`
|
|
32
|
+
- `.claude/agents/devil-advocate.md`
|
|
33
|
+
- `.claude/agents/judge.md`
|
|
34
|
+
- `.claude/commands/ai-engineering-loop.md`
|
|
35
|
+
|
|
36
|
+
## 3. Mode selection
|
|
37
|
+
|
|
38
|
+
| Condition | Mode |
|
|
39
|
+
|---|---|
|
|
40
|
+
| Task/Agent tool present, child result returned | `TRUE_INDEPENDENT_AGENT` |
|
|
41
|
+
| No subagent tool | `CONTEXT_ISOLATION_ONLY` |
|
|
42
|
+
|
|
43
|
+
## 4. What stays in Grok-only files
|
|
44
|
+
|
|
45
|
+
Grok spawn details live in `.grok/skills/ai-engineering-loop/SKILL.md`. Claude Code must not load that file as its skill. Claude Code discovers `.claude/` first.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-engineering-loop",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"description": "A reusable, framework-agnostic AI Engineering Operating System for autonomous coding agents.",
|
|
5
5
|
"main": "bin/ai-engineering-loop.js",
|
|
6
6
|
"bin": {
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"tests/",
|
|
21
21
|
"scripts/",
|
|
22
22
|
".grok/",
|
|
23
|
+
".claude/",
|
|
23
24
|
"LICENSE",
|
|
24
25
|
"README.md",
|
|
25
26
|
"README.npm.md"
|
|
@@ -41,6 +42,7 @@
|
|
|
41
42
|
"autonomous-agents",
|
|
42
43
|
"antigravity",
|
|
43
44
|
"grok",
|
|
45
|
+
"claude-code",
|
|
44
46
|
"subagents"
|
|
45
47
|
],
|
|
46
48
|
"author": "Ega Gofur",
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
const test = require('node:test');
|
|
2
|
+
const assert = require('node:assert');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
const ROOT = path.join(__dirname, '..');
|
|
7
|
+
|
|
8
|
+
function readRepo(rel) {
|
|
9
|
+
return fs.readFileSync(path.join(ROOT, rel), 'utf8');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function parseFrontmatter(content, label) {
|
|
13
|
+
const match = content.match(/^---\n([\s\S]*?)\n---\n/);
|
|
14
|
+
assert.ok(match, `${label} is missing YAML frontmatter`);
|
|
15
|
+
const fm = match[1];
|
|
16
|
+
assert.match(fm, /^name:\s*[a-z0-9-]+$/m, `${label} name must be kebab-case`);
|
|
17
|
+
assert.match(fm, /^description:\s+\S/m, `${label} description must be a single-line value`);
|
|
18
|
+
assert.doesNotMatch(fm, /^description:\s*>-?/m, `${label} must not use folded YAML description`);
|
|
19
|
+
const desc = fm.split('\n').find((line) => line.startsWith('description:'));
|
|
20
|
+
assert.ok(desc.length <= 500, `${label} description exceeds 500 chars (${desc.length})`);
|
|
21
|
+
return { fm, body: content.slice(match[0].length) };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
test('Claude Code skill is Kiro-safe: no mermaid, latex, HTML breaks, or Grok tool keys', () => {
|
|
25
|
+
const content = readRepo('.claude/skills/ai-engineering-loop/SKILL.md');
|
|
26
|
+
parseFrontmatter(content, 'claude skill');
|
|
27
|
+
|
|
28
|
+
assert.doesNotMatch(content, /```mermaid/);
|
|
29
|
+
assert.doesNotMatch(content, /\$\\/);
|
|
30
|
+
assert.doesNotMatch(content, /<br\s*\/?>/i);
|
|
31
|
+
assert.doesNotMatch(content, /spawn_subagent/);
|
|
32
|
+
assert.doesNotMatch(content, /capability_mode/);
|
|
33
|
+
assert.doesNotMatch(content, /resume_from/);
|
|
34
|
+
assert.match(content, /\bTask\b/);
|
|
35
|
+
assert.match(content, /subagent_type/);
|
|
36
|
+
assert.match(content, /devil-advocate/);
|
|
37
|
+
assert.match(content, /\bjudge\b/);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('Claude Code agents exist with Claude tool names and Finding Ledger / verdict contracts', () => {
|
|
41
|
+
const da = readRepo('.claude/agents/devil-advocate.md');
|
|
42
|
+
const judge = readRepo('.claude/agents/judge.md');
|
|
43
|
+
parseFrontmatter(da, 'devil-advocate agent');
|
|
44
|
+
parseFrontmatter(judge, 'judge agent');
|
|
45
|
+
|
|
46
|
+
assert.match(da, /^tools:\s*Read, Grep, Glob, Bash$/m);
|
|
47
|
+
assert.match(judge, /^tools:\s*Read, Grep, Glob, Bash$/m);
|
|
48
|
+
assert.doesNotMatch(da, /spawn_subagent|capability_mode|resume_from/);
|
|
49
|
+
assert.doesNotMatch(judge, /spawn_subagent|capability_mode|resume_from/);
|
|
50
|
+
assert.match(da, /Finding Ledger/);
|
|
51
|
+
assert.match(judge, /PASS/);
|
|
52
|
+
assert.match(judge, /ITERATE/);
|
|
53
|
+
assert.match(judge, /ESCALATE/);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test('Claude Code slash command does not embed Grok spawn keys', () => {
|
|
57
|
+
const cmd = readRepo('.claude/commands/ai-engineering-loop.md');
|
|
58
|
+
parseFrontmatter(cmd, 'claude command');
|
|
59
|
+
assert.doesNotMatch(cmd, /spawn_subagent|capability_mode|resume_from/);
|
|
60
|
+
assert.match(cmd, /ai-engineering-loop/);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test('Grok skill may use spawn_subagent; Claude skill must not', () => {
|
|
64
|
+
const grok = readRepo('.grok/skills/ai-engineering-loop/SKILL.md');
|
|
65
|
+
const claude = readRepo('.claude/skills/ai-engineering-loop/SKILL.md');
|
|
66
|
+
assert.match(grok, /spawn_subagent/);
|
|
67
|
+
assert.doesNotMatch(claude, /spawn_subagent/);
|
|
68
|
+
});
|