agentopology 0.2.4 → 0.3.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/README.md +92 -10
- package/dist/bindings/__tests__/bindings.test.js +2 -2
- package/dist/bindings/__tests__/claude-code-hybrid.test.d.ts +2 -0
- package/dist/bindings/__tests__/claude-code-hybrid.test.d.ts.map +1 -0
- package/dist/bindings/__tests__/claude-code-hybrid.test.js +152 -0
- package/dist/bindings/__tests__/claude-code-hybrid.test.js.map +1 -0
- package/dist/bindings/__tests__/claude-workflow.test.d.ts +2 -0
- package/dist/bindings/__tests__/claude-workflow.test.d.ts.map +1 -0
- package/dist/bindings/__tests__/claude-workflow.test.js +204 -0
- package/dist/bindings/__tests__/claude-workflow.test.js.map +1 -0
- package/dist/bindings/__tests__/hybrid-e2e.test.d.ts +15 -0
- package/dist/bindings/__tests__/hybrid-e2e.test.d.ts.map +1 -0
- package/dist/bindings/__tests__/hybrid-e2e.test.js +94 -0
- package/dist/bindings/__tests__/hybrid-e2e.test.js.map +1 -0
- package/dist/bindings/claude-code.d.ts.map +1 -1
- package/dist/bindings/claude-code.js +407 -3
- package/dist/bindings/claude-code.js.map +1 -1
- package/dist/bindings/claude-workflow.d.ts +28 -0
- package/dist/bindings/claude-workflow.d.ts.map +1 -0
- package/dist/bindings/claude-workflow.js +684 -0
- package/dist/bindings/claude-workflow.js.map +1 -0
- package/dist/bindings/index.d.ts +1 -0
- package/dist/bindings/index.d.ts.map +1 -1
- package/dist/bindings/index.js +3 -0
- package/dist/bindings/index.js.map +1 -1
- package/dist/bindings/lib/seam.d.ts +35 -0
- package/dist/bindings/lib/seam.d.ts.map +1 -0
- package/dist/bindings/lib/seam.js +42 -0
- package/dist/bindings/lib/seam.js.map +1 -0
- package/dist/cli/index.js +195 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/parser/__tests__/parser.test.js +170 -0
- package/dist/parser/__tests__/parser.test.js.map +1 -1
- package/dist/parser/ast.d.ts +39 -0
- package/dist/parser/ast.d.ts.map +1 -1
- package/dist/parser/index.d.ts.map +1 -1
- package/dist/parser/index.js +58 -2
- package/dist/parser/index.js.map +1 -1
- package/dist/parser/validator.d.ts.map +1 -1
- package/dist/parser/validator.js +66 -3
- package/dist/parser/validator.js.map +1 -1
- package/dist/visualizer/__tests__/brain.test.d.ts +2 -0
- package/dist/visualizer/__tests__/brain.test.d.ts.map +1 -0
- package/dist/visualizer/__tests__/brain.test.js +138 -0
- package/dist/visualizer/__tests__/brain.test.js.map +1 -0
- package/dist/visualizer/__tests__/topology-brain-link.test.d.ts +2 -0
- package/dist/visualizer/__tests__/topology-brain-link.test.d.ts.map +1 -0
- package/dist/visualizer/__tests__/topology-brain-link.test.js +41 -0
- package/dist/visualizer/__tests__/topology-brain-link.test.js.map +1 -0
- package/dist/visualizer/brain.d.ts +97 -0
- package/dist/visualizer/brain.d.ts.map +1 -0
- package/dist/visualizer/brain.js +473 -0
- package/dist/visualizer/brain.js.map +1 -0
- package/dist/visualizer/index.d.ts +19 -1
- package/dist/visualizer/index.d.ts.map +1 -1
- package/dist/visualizer/index.js +26 -11
- package/dist/visualizer/index.js.map +1 -1
- package/examples/company-brain-team.at +241 -0
- package/examples/company-brain.at +104 -0
- package/examples/logos/gmail.svg +1 -0
- package/examples/logos/slack.svg +1 -0
- package/examples/matchmat-ship.at +249 -0
- package/package.json +1 -1
- package/spec/grammar.md +42 -3
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<h1 align="center">AgenTopology</h1>
|
|
2
2
|
|
|
3
3
|
<p align="center">
|
|
4
|
-
<strong>The Terraform for AI agents
|
|
5
|
-
Define your agent team once. Deploy to any platform.
|
|
4
|
+
<strong>Harness as code.</strong> The Terraform for AI agents.<br/>
|
|
5
|
+
Define your agent team — and its memory — once. Deploy to any platform.
|
|
6
6
|
</p>
|
|
7
7
|
|
|
8
8
|
<p align="center">
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
</p>
|
|
13
13
|
|
|
14
14
|
<p align="center">
|
|
15
|
-
<strong>Claude Code</strong> · <strong>OpenClaw</strong> · <strong>Codex</strong> · <strong>Cursor</strong> · <strong>Gemini CLI</strong> · <strong>Copilot</strong> · <strong>Kiro</strong>
|
|
15
|
+
<strong>Claude Code</strong> · <strong>Claude Workflow</strong> · <strong>OpenClaw</strong> · <strong>Codex</strong> · <strong>Cursor</strong> · <strong>Gemini CLI</strong> · <strong>Copilot</strong> · <strong>Kiro</strong>
|
|
16
16
|
</p>
|
|
17
17
|
|
|
18
18
|
<p align="center">
|
|
@@ -54,18 +54,32 @@ topology code-review : [pipeline] {
|
|
|
54
54
|
```
|
|
55
55
|
|
|
56
56
|
```bash
|
|
57
|
-
agentopology scaffold my-team.at --target claude-code
|
|
58
|
-
agentopology scaffold my-team.at --target
|
|
59
|
-
agentopology scaffold my-team.at --target
|
|
60
|
-
agentopology scaffold my-team.at --target
|
|
57
|
+
agentopology scaffold my-team.at --target claude-code # → .claude/agents/
|
|
58
|
+
agentopology scaffold my-team.at --target claude-workflow # → my-team.workflow.js (+ SEAM/README/LOSSY-REPORT)
|
|
59
|
+
agentopology scaffold my-team.at --target openclaw # → .openclaw/soul.md
|
|
60
|
+
agentopology scaffold my-team.at --target codex # → .codex/
|
|
61
|
+
agentopology scaffold my-team.at --target cursor # → .cursor/rules/
|
|
61
62
|
```
|
|
62
63
|
|
|
63
|
-
One file.
|
|
64
|
+
One file. Every platform. The topology IS the documentation.
|
|
64
65
|
|
|
65
66
|
<p align="center">
|
|
66
67
|
<img src="docs/visualizer-preview.png" alt="AgenTopology Visualizer" width="900" />
|
|
67
68
|
</p>
|
|
68
69
|
|
|
70
|
+
### Hybrid: host + embedded workflow
|
|
71
|
+
|
|
72
|
+
One `.at` topology can compile to **two coupled targets at once**. `claude-code` is the **host** — the event-driven layer that owns agents, hooks, the Blackboard, concurrent observability, and the human/gate/branching nodes. `claude-workflow` is the embedded **deterministic rung** — the parallel fan-out phases, compiled into a Claude Workflow tool script. The host launches the rung and observes its Blackboard writes live (via a `PostToolUse` hook), so you get concurrent observability the Workflow runtime can't do on its own.
|
|
73
|
+
|
|
74
|
+
Mark a phase for the rung with `extensions { claude-workflow { execution: workflow } }`, then scaffold both:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
agentopology scaffold my-team.at --target claude-code # the host
|
|
78
|
+
agentopology scaffold my-team.at --target claude-workflow # the embedded rung
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The hybrid is opt-in — a topology with no `execution: workflow` marker compiles to pure `claude-code`, unchanged. See [docs/AT_VS_WORKFLOW_STRATEGY.md](docs/AT_VS_WORKFLOW_STRATEGY.md) for why.
|
|
82
|
+
|
|
69
83
|
---
|
|
70
84
|
|
|
71
85
|
## What It Does
|
|
@@ -78,6 +92,7 @@ AgenTopology is a **declarative language** (`.at` files) and a **CLI compiler**
|
|
|
78
92
|
│ (you write) │ │ Validator │ │ (auto-generated) │
|
|
79
93
|
└──────────────┘ └────────────┘ └─────────────────────┘
|
|
80
94
|
├── .claude/agents/
|
|
95
|
+
├── <topology>.workflow.js
|
|
81
96
|
├── .openclaw/
|
|
82
97
|
├── .codex/
|
|
83
98
|
├── .cursor/rules/
|
|
@@ -244,7 +259,8 @@ This defines three agents, their tools and memory, a quality gate, and a flow wi
|
|
|
244
259
|
|
|
245
260
|
| Target | Command | What It Generates |
|
|
246
261
|
|--------|---------|-------------------|
|
|
247
|
-
| **Claude Code** | `--target claude-code` | `.claude/agents/`, `.claude/skills/`, `.mcp.json`, `.claude/settings.json` |
|
|
262
|
+
| **Claude Code** | `--target claude-code` | `.claude/agents/`, `.claude/skills/`, `.mcp.json`, `.claude/settings.json` (the event-driven host) |
|
|
263
|
+
| **Claude Workflow** | `--target claude-workflow` | `<topology>.workflow.js` (deterministic fan-out rung) + `-SEAM.md`, `-README.md`, `-LOSSY-REPORT.md` |
|
|
248
264
|
| **OpenClaw** | `--target openclaw` | `.openclaw/soul.md`, `.openclaw/skills/`, `.openclaw/config.json` |
|
|
249
265
|
| **Codex** | `--target codex` | `.codex/config.toml`, `AGENTS.md` |
|
|
250
266
|
| **Cursor** | `--target cursor` | `.cursor/rules/*.mdc`, `.cursor/mcp.json`, `.cursor/hooks.json` |
|
|
@@ -348,6 +364,36 @@ mcp-servers {
|
|
|
348
364
|
}
|
|
349
365
|
```
|
|
350
366
|
|
|
367
|
+
</td>
|
|
368
|
+
</tr>
|
|
369
|
+
<tr>
|
|
370
|
+
<td>
|
|
371
|
+
|
|
372
|
+
**Company Brain** — agent-maintained, Obsidian-portable
|
|
373
|
+
```
|
|
374
|
+
store brain {
|
|
375
|
+
type: brain # markdown, no DB
|
|
376
|
+
path: "brain/"
|
|
377
|
+
format: obsidian # ports both ways
|
|
378
|
+
}
|
|
379
|
+
agent librarian {
|
|
380
|
+
custodian-of: [brain] # owns its upkeep
|
|
381
|
+
}
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
</td>
|
|
385
|
+
<td>
|
|
386
|
+
|
|
387
|
+
**Provenance styling** — color the graph by source
|
|
388
|
+
```
|
|
389
|
+
store brain {
|
|
390
|
+
sources {
|
|
391
|
+
gmail { color: "#EA4335" icon: "./gmail.svg" }
|
|
392
|
+
slack { color: "#4A154B" }
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
```
|
|
396
|
+
|
|
351
397
|
</td>
|
|
352
398
|
</tr>
|
|
353
399
|
</table>
|
|
@@ -373,6 +419,39 @@ In Claude Code, this compiles to a **file-based protocol** — a shared transcri
|
|
|
373
419
|
|
|
374
420
|
---
|
|
375
421
|
|
|
422
|
+
## Company Brain — Knowledge That Builds Itself
|
|
423
|
+
|
|
424
|
+
A **brain** is a folder of linked markdown that agents maintain, not you. It's the [Obsidian](https://obsidian.md) graph model — notes connected by `[[wikilinks]]` and `#tags` — but **agent-maintained instead of hand-curated**.
|
|
425
|
+
|
|
426
|
+
```
|
|
427
|
+
store brain {
|
|
428
|
+
type: brain # file-native: markdown, no database, no embeddings
|
|
429
|
+
path: "brain/"
|
|
430
|
+
format: obsidian # ports both ways — open it in Obsidian, the graph just works
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
agent librarian {
|
|
434
|
+
custodian-of: [brain] { # OWNS the brain's upkeep, not just read access
|
|
435
|
+
does: [link, tag, index, dedupe]
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
- **Custodian agents** own a memory layer. Drop a note in, the librarian wires it into the graph — resolving `[[links]]`, assigning `#tags`, updating hub notes. Humans drop; agents wire.
|
|
441
|
+
- **Ingester agents** feed it from anywhere. One agent per source (Gmail, Slack, calendar) writes raw notes; the librarian links them. See [`examples/company-brain-team.at`](examples/company-brain-team.at).
|
|
442
|
+
- **Pure markdown, zero infrastructure.** No vector DB, no MCP server. Coding agents retrieve with `grep`. The whole brain is a folder you can `git clone`.
|
|
443
|
+
- **100% Obsidian-compatible.** The vault *is* an Obsidian vault — agents build it, you open it in Obsidian for the graph view. Or use our built-in graph viewer (below) and skip Obsidian entirely.
|
|
444
|
+
|
|
445
|
+
**See it without Obsidian** — render any brain vault as an interactive graph in a single self-contained HTML file:
|
|
446
|
+
|
|
447
|
+
```bash
|
|
448
|
+
agentopology visualize-brain brain/
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
Nodes are colored by what they *are* (person / org / topic) and by where they *came from* (declare `sources { gmail { color, icon } }` and notes from Gmail render in Gmail red with the logo). When you `visualize` a topology that owns brains, the two graphs **cross-link** — jump from the team diagram to its brain and back.
|
|
452
|
+
|
|
453
|
+
This is **brain as code**: you declare the brain's architecture — its layers, its custodians, its sources — the same way you declare the agent team. See [`docs/company-brain.md`](docs/company-brain.md) for the full walkthrough.
|
|
454
|
+
|
|
376
455
|
---
|
|
377
456
|
|
|
378
457
|
## Programmatic API
|
|
@@ -446,6 +525,8 @@ You can `agentopology visualize` it into an interactive graph. You can hand it t
|
|
|
446
525
|
- [`data-processing.at`](examples/data-processing.at) — ETL pipeline with batch processing and metering
|
|
447
526
|
- [`scheduled-monitor.at`](examples/scheduled-monitor.at) — Monitoring system with scheduled health checks
|
|
448
527
|
- [`openclaw-assistant.at`](examples/openclaw-assistant.at) — Customer support with routing and scheduling
|
|
528
|
+
- [`company-brain.at`](examples/company-brain.at) — A plug-and-play company brain (librarian + researcher)
|
|
529
|
+
- [`company-brain-team.at`](examples/company-brain-team.at) — A team that ingests (Gmail/Slack/calendar), wires, and audits a brain
|
|
449
530
|
|
|
450
531
|
---
|
|
451
532
|
|
|
@@ -456,7 +537,8 @@ agentopology validate <file> Validate an .at file (82 rules)
|
|
|
456
537
|
agentopology scaffold <file> --target <t> Generate platform configs
|
|
457
538
|
agentopology sync <file> --target <t> --dir <d> Sync platform files back to .at
|
|
458
539
|
agentopology import --target <t> --dir <d> Reverse-engineer platform files to .at
|
|
459
|
-
agentopology visualize <file> Interactive topology graph
|
|
540
|
+
agentopology visualize <file> Interactive topology graph (+ cross-links any brains)
|
|
541
|
+
agentopology visualize-brain <folder> Render a brain vault as an Obsidian-style graph (no Obsidian)
|
|
460
542
|
agentopology export <file> --format <fmt> Export as markdown, mermaid, or json
|
|
461
543
|
agentopology info <file> Topology analysis and suggestions
|
|
462
544
|
agentopology targets List supported platforms
|
|
@@ -156,8 +156,8 @@ function assertStructuralInvariants(files) {
|
|
|
156
156
|
// Registry tests
|
|
157
157
|
// ---------------------------------------------------------------------------
|
|
158
158
|
describe("Binding registry", () => {
|
|
159
|
-
it("contains all
|
|
160
|
-
expect(Object.keys(bindings)).toHaveLength(
|
|
159
|
+
it("contains all 8 bindings", () => {
|
|
160
|
+
expect(Object.keys(bindings)).toHaveLength(8);
|
|
161
161
|
});
|
|
162
162
|
it("all bindings have a name and description", () => {
|
|
163
163
|
for (const [key, binding] of Object.entries(bindings)) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-code-hybrid.test.d.ts","sourceRoot":"","sources":["../../../src/bindings/__tests__/claude-code-hybrid.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { parse } from "../../parser/index.js";
|
|
6
|
+
import { claudeCodeBinding, claudeWorkflowBinding } from "../index.js";
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
// Hybrid-awareness of the claude-code binding (host half of the host+workflow
|
|
9
|
+
// model). Fixture: examples/matchmat-ship.at — builder (phase 2) is
|
|
10
|
+
// execution:workflow; phases 1 & 3 + the human node are host-side.
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
const fixturePath = path.resolve(here, "../../../examples/matchmat-ship.at");
|
|
14
|
+
const source = readFileSync(fixturePath, "utf-8");
|
|
15
|
+
const ast = parse(source);
|
|
16
|
+
const files = claudeCodeBinding.scaffold(ast);
|
|
17
|
+
function find(suffix) {
|
|
18
|
+
return files.find((f) => f.path.endsWith(suffix));
|
|
19
|
+
}
|
|
20
|
+
describe("claude-code binding — HYBRID awareness (matchmat-ship)", () => {
|
|
21
|
+
// (a) workflow-marked agent (builder) is NOT emitted as a host subagent.
|
|
22
|
+
it("does NOT emit .claude/agents/builder/AGENT.md (builder is execution:workflow)", () => {
|
|
23
|
+
const builderAgent = files.find((f) => f.path === ".claude/agents/builder/AGENT.md");
|
|
24
|
+
expect(builderAgent).toBeUndefined();
|
|
25
|
+
});
|
|
26
|
+
// (b) host phase-1 + phase-3 agents ARE still emitted as subagents.
|
|
27
|
+
it("still emits AGENT.md for host phase-1 and phase-3 agents", () => {
|
|
28
|
+
const expected = [
|
|
29
|
+
".claude/agents/contract-scout/AGENT.md",
|
|
30
|
+
".claude/agents/blast-radius-mapper/AGENT.md",
|
|
31
|
+
".claude/agents/boundary-drafter/AGENT.md",
|
|
32
|
+
".claude/agents/security-verifier/AGENT.md",
|
|
33
|
+
".claude/agents/contract-verifier/AGENT.md",
|
|
34
|
+
".claude/agents/closed-loop-verifier/AGENT.md",
|
|
35
|
+
];
|
|
36
|
+
for (const p of expected) {
|
|
37
|
+
expect(files.find((f) => f.path === p), `expected ${p} to be emitted`).toBeDefined();
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
// (c) a launch-workflow stub/skill artifact for the build phase IS emitted.
|
|
41
|
+
it("emits a launch-<phase>-workflow.sh stub for the workflow phase", () => {
|
|
42
|
+
const launch = find("launch-builder-workflow.sh");
|
|
43
|
+
expect(launch).toBeDefined();
|
|
44
|
+
expect(launch.path).toBe(".claude/skills/matchmat-ship/scripts/launch-builder-workflow.sh");
|
|
45
|
+
expect(launch.executable).toBe(true);
|
|
46
|
+
// It's a detectable scaffold stub.
|
|
47
|
+
expect(launch.content).toContain("# AGENTOPOLOGY_STUB");
|
|
48
|
+
// It documents launching the SAME workflow.js filename the sibling binding emits.
|
|
49
|
+
expect(launch.content).toContain("matchmat-ship.workflow.js");
|
|
50
|
+
expect(launch.content).toContain("/workflow matchmat-ship.workflow.js");
|
|
51
|
+
// It points at the shared Blackboard root + the seam doc.
|
|
52
|
+
expect(launch.content).toContain("workspace/");
|
|
53
|
+
expect(launch.content).toContain("matchmat-ship-SEAM.md");
|
|
54
|
+
});
|
|
55
|
+
// (d) CLAUDE.md carries the hybrid run-order block referencing the workflow.js.
|
|
56
|
+
it("emits a Hybrid run order block in CLAUDE.md referencing the workflow.js", () => {
|
|
57
|
+
const ctx = files.find((f) => f.path === ".claude/CLAUDE.md");
|
|
58
|
+
expect(ctx).toBeDefined();
|
|
59
|
+
expect(ctx.content).toContain("## Hybrid run order");
|
|
60
|
+
expect(ctx.content).toContain("matchmat-ship.workflow.js");
|
|
61
|
+
expect(ctx.content).toContain("Host launches");
|
|
62
|
+
// host phases described as in-session; workflow phase described as launched.
|
|
63
|
+
expect(ctx.content).toContain("phase 1 (contract-scout, blast-radius-mapper, boundary-drafter)");
|
|
64
|
+
expect(ctx.content).toContain("phase 2 (builder)");
|
|
65
|
+
expect(ctx.content).toContain("phase 3 (security-verifier, contract-verifier, closed-loop-verifier)");
|
|
66
|
+
// points at the seam doc both bindings honor.
|
|
67
|
+
expect(ctx.content).toContain("matchmat-ship-SEAM.md");
|
|
68
|
+
});
|
|
69
|
+
it("also mirrors the Hybrid run order block into the topology SKILL.md", () => {
|
|
70
|
+
const skill = files.find((f) => f.path === ".claude/skills/matchmat-ship/SKILL.md");
|
|
71
|
+
expect(skill).toBeDefined();
|
|
72
|
+
expect(skill.content).toContain("## Hybrid run order");
|
|
73
|
+
expect(skill.content).toContain("matchmat-ship.workflow.js");
|
|
74
|
+
});
|
|
75
|
+
// (e) the observe-hook is in settings.json (host-layer concurrent observer).
|
|
76
|
+
it("emits a PostToolUse(Write) observe-blackboard hook in settings.json", () => {
|
|
77
|
+
const settings = files.find((f) => f.path === ".claude/settings.json");
|
|
78
|
+
expect(settings).toBeDefined();
|
|
79
|
+
const parsed = JSON.parse(settings.content);
|
|
80
|
+
const postToolUse = parsed.hooks?.PostToolUse;
|
|
81
|
+
expect(postToolUse, "PostToolUse hooks present").toBeDefined();
|
|
82
|
+
const observe = postToolUse.find((h) => h.matcher === "Write" && h.hooks.some((x) => x.command.includes("observe-blackboard.sh")));
|
|
83
|
+
expect(observe, "observe-blackboard PostToolUse(Write) hook present").toBeDefined();
|
|
84
|
+
});
|
|
85
|
+
it("emits the observe-blackboard.sh script the hook points at", () => {
|
|
86
|
+
const observe = find("observe-blackboard.sh");
|
|
87
|
+
expect(observe).toBeDefined();
|
|
88
|
+
expect(observe.path).toBe(".claude/skills/matchmat-ship/scripts/observe-blackboard.sh");
|
|
89
|
+
expect(observe.executable).toBe(true);
|
|
90
|
+
expect(observe.content).toContain("# AGENTOPOLOGY_STUB");
|
|
91
|
+
// documents the Blackboard root it watches.
|
|
92
|
+
expect(observe.content).toContain("workspace/");
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
describe("claude-code binding — non-hybrid topologies are unaffected", () => {
|
|
96
|
+
// A topology with no execution:workflow agent must not get any hybrid artifacts.
|
|
97
|
+
const plain = parse(`topology plain-pipe : [pipeline] {
|
|
98
|
+
roles { worker: "do the work" }
|
|
99
|
+
agent worker { role: worker phase: 1 prompt { Do the thing. } }
|
|
100
|
+
flow { worker -> worker }
|
|
101
|
+
}`);
|
|
102
|
+
const plainFiles = claudeCodeBinding.scaffold(plain);
|
|
103
|
+
it("still emits the agent AGENT.md (no workflow seam)", () => {
|
|
104
|
+
expect(plainFiles.find((f) => f.path === ".claude/agents/worker/AGENT.md")).toBeDefined();
|
|
105
|
+
});
|
|
106
|
+
it("emits no launch-*-workflow.sh stub", () => {
|
|
107
|
+
expect(plainFiles.find((f) => f.path.includes("launch-") && f.path.endsWith("-workflow.sh"))).toBeUndefined();
|
|
108
|
+
});
|
|
109
|
+
it("emits no Hybrid run order block", () => {
|
|
110
|
+
const ctx = plainFiles.find((f) => f.path === ".claude/CLAUDE.md");
|
|
111
|
+
if (ctx)
|
|
112
|
+
expect(ctx.content).not.toContain("## Hybrid run order");
|
|
113
|
+
});
|
|
114
|
+
it("emits no synthesized observe-blackboard hook (no Blackboard)", () => {
|
|
115
|
+
expect(plainFiles.find((f) => f.path.endsWith("observe-blackboard.sh"))).toBeUndefined();
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
describe("claude-code + claude-workflow — the two bindings AGREE on the seam", () => {
|
|
119
|
+
const hostFiles = claudeCodeBinding.scaffold(ast);
|
|
120
|
+
const wfFiles = claudeWorkflowBinding.scaffold(ast);
|
|
121
|
+
it("host omits builder/AGENT.md while the workflow.js OWNS builder", () => {
|
|
122
|
+
expect(hostFiles.find((f) => f.path === ".claude/agents/builder/AGENT.md")).toBeUndefined();
|
|
123
|
+
const wf = wfFiles.find((f) => f.path.endsWith(".workflow.js"));
|
|
124
|
+
expect(wf).toBeDefined();
|
|
125
|
+
expect(wf.content).toContain("{ phase: 2, agents: ['builder'] }");
|
|
126
|
+
});
|
|
127
|
+
it("both reference the same workflow.js filename", () => {
|
|
128
|
+
const wf = wfFiles.find((f) => f.path.endsWith(".workflow.js"));
|
|
129
|
+
expect(wf.path).toBe("matchmat-ship.workflow.js");
|
|
130
|
+
const ctx = hostFiles.find((f) => f.path === ".claude/CLAUDE.md");
|
|
131
|
+
expect(ctx.content).toContain("matchmat-ship.workflow.js");
|
|
132
|
+
});
|
|
133
|
+
it("both reference the same Blackboard workspace root and SEAM doc", () => {
|
|
134
|
+
const seam = wfFiles.find((f) => f.path.endsWith("-SEAM.md"));
|
|
135
|
+
const ctx = hostFiles.find((f) => f.path === ".claude/CLAUDE.md");
|
|
136
|
+
// workspace root
|
|
137
|
+
expect(seam.content).toContain("`workspace/`");
|
|
138
|
+
expect(ctx.content).toContain("`workspace/`");
|
|
139
|
+
// seam doc filename
|
|
140
|
+
expect(seam.path).toBe("matchmat-ship-SEAM.md");
|
|
141
|
+
expect(ctx.content).toContain("matchmat-ship-SEAM.md");
|
|
142
|
+
});
|
|
143
|
+
it("both use the same 'Host launches ... LIVE' run-order phrasing", () => {
|
|
144
|
+
const seam = wfFiles.find((f) => f.path.endsWith("-SEAM.md"));
|
|
145
|
+
const ctx = hostFiles.find((f) => f.path === ".claude/CLAUDE.md");
|
|
146
|
+
expect(seam.content).toContain("Host launches");
|
|
147
|
+
expect(ctx.content).toContain("Host launches");
|
|
148
|
+
expect(seam.content).toContain("observe those writes LIVE");
|
|
149
|
+
expect(ctx.content).toContain("observe those writes LIVE");
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
//# sourceMappingURL=claude-code-hybrid.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-code-hybrid.test.js","sourceRoot":"","sources":["../../../src/bindings/__tests__/claude-code-hybrid.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-workflow.test.d.ts","sourceRoot":"","sources":["../../../src/bindings/__tests__/claude-workflow.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { parse } from "../../parser/index.js";
|
|
6
|
+
import { bindings, claudeWorkflowBinding } from "../index.js";
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
// Fixture: the dogfood topology (examples/matchmat-ship.at)
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const fixturePath = path.resolve(here, "../../../examples/matchmat-ship.at");
|
|
12
|
+
const source = readFileSync(fixturePath, "utf-8");
|
|
13
|
+
const ast = parse(source);
|
|
14
|
+
const files = claudeWorkflowBinding.scaffold(ast);
|
|
15
|
+
function find(suffix) {
|
|
16
|
+
return files.find((f) => f.path.endsWith(suffix));
|
|
17
|
+
}
|
|
18
|
+
describe("claude-workflow binding — registry", () => {
|
|
19
|
+
it("is registered under the 'claude-workflow' key with a matching name", () => {
|
|
20
|
+
expect(bindings["claude-workflow"]).toBeDefined();
|
|
21
|
+
expect(bindings["claude-workflow"].name).toBe("claude-workflow");
|
|
22
|
+
});
|
|
23
|
+
it("scaffold returns a non-empty array of GeneratedFile", () => {
|
|
24
|
+
expect(files.length).toBeGreaterThan(0);
|
|
25
|
+
for (const f of files) {
|
|
26
|
+
expect(f.path).toBeTruthy();
|
|
27
|
+
expect(typeof f.content).toBe("string");
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
describe("claude-workflow binding — workflow.js emission (matchmat-ship)", () => {
|
|
32
|
+
// (a) a *.workflow.js file is emitted
|
|
33
|
+
it("emits a <topology>.workflow.js file", () => {
|
|
34
|
+
const wf = find(".workflow.js");
|
|
35
|
+
expect(wf).toBeDefined();
|
|
36
|
+
expect(wf.path).toBe("matchmat-ship.workflow.js");
|
|
37
|
+
});
|
|
38
|
+
const wf = find(".workflow.js");
|
|
39
|
+
// (b) STRICT SEAM: meta.phases contains ONLY the workflow-marked phase (2 / builder).
|
|
40
|
+
it("contains `export const meta` as a pure literal with ONLY the workflow-marked phase", () => {
|
|
41
|
+
expect(wf.content).toContain("export const meta");
|
|
42
|
+
expect(wf.content).toContain("phases:");
|
|
43
|
+
// The meta literal must not contain computed/nondeterministic values
|
|
44
|
+
expect(wf.content).not.toContain("Date.now");
|
|
45
|
+
expect(wf.content).not.toContain("Math.random");
|
|
46
|
+
// Only phase 2 (builder) — not phase 1 or 3.
|
|
47
|
+
expect(wf.content).toContain("{ phase: 2, agents: ['builder'] }");
|
|
48
|
+
expect(wf.content).not.toContain("phase: 1");
|
|
49
|
+
expect(wf.content).not.toContain("phase: 3");
|
|
50
|
+
});
|
|
51
|
+
it("uses parallel(...) for the builder fan-out", () => {
|
|
52
|
+
expect(wf.content).toContain("parallel(");
|
|
53
|
+
});
|
|
54
|
+
it("uses phase() to title the workflow phase", () => {
|
|
55
|
+
expect(wf.content).toContain("phase('Phase 2')");
|
|
56
|
+
});
|
|
57
|
+
it("compiles ONLY the builder (scaled) phase with isolation:'worktree'", () => {
|
|
58
|
+
expect(wf.content).toContain("isolation: 'worktree'");
|
|
59
|
+
// builder has scale {max: 6} → deterministic Array.from fan-out, no random
|
|
60
|
+
expect(wf.content).toContain("Array.from({ length: 6 }");
|
|
61
|
+
expect(wf.content).toMatch(/label: `builder-\$\{i\}`/);
|
|
62
|
+
});
|
|
63
|
+
// STRICT SEAM: the host-side verifier phase (3) must NOT be in the workflow.js.
|
|
64
|
+
it("does NOT contain the host phase-1 agents (contract-scout, blast-radius-mapper, boundary-drafter)", () => {
|
|
65
|
+
expect(wf.content).not.toContain("contract-scout");
|
|
66
|
+
expect(wf.content).not.toContain("blast-radius-mapper");
|
|
67
|
+
expect(wf.content).not.toContain("'boundary-drafter'");
|
|
68
|
+
});
|
|
69
|
+
it("does NOT contain the host phase-3 verifier agents (security-verifier, etc.)", () => {
|
|
70
|
+
expect(wf.content).not.toContain("security-verifier");
|
|
71
|
+
expect(wf.content).not.toContain("contract-verifier");
|
|
72
|
+
expect(wf.content).not.toContain("closed-loop-verifier");
|
|
73
|
+
});
|
|
74
|
+
it("does NOT contain a verifier verdict schema (phase 3 is HOST-side)", () => {
|
|
75
|
+
// The verdict enum belongs to the phase-3 verifiers, which are host-side now.
|
|
76
|
+
expect(wf.content).not.toContain("verdict:");
|
|
77
|
+
});
|
|
78
|
+
it("embeds the builder's Blackboard read/write paths in its prompt (no filesystem)", () => {
|
|
79
|
+
// builder reads contract-delta/blast-radius/contracts-touched, writes build-report.
|
|
80
|
+
expect(wf.content).toContain("workspace/contract-delta.md");
|
|
81
|
+
expect(wf.content).toContain("workspace/build-report.md");
|
|
82
|
+
});
|
|
83
|
+
// STRICT SEAM: verify-gate is between phase 3 and ship-report (host) → NOT in the workflow.
|
|
84
|
+
it("does NOT contain the host-side verify-gate (it sits outside the workflow span)", () => {
|
|
85
|
+
expect(wf.content).not.toContain("bounce-back");
|
|
86
|
+
expect(wf.content).not.toContain("verify-gate");
|
|
87
|
+
expect(wf.content).not.toContain("for (let attempt");
|
|
88
|
+
});
|
|
89
|
+
// (d) the workflow.js does NOT contain the human node — neither as an agent nor a boundary block.
|
|
90
|
+
it("does NOT contain the human 'promote' node as an agent() call", () => {
|
|
91
|
+
expect(wf.content).not.toMatch(/agent\([^)]*label: 'promote'/);
|
|
92
|
+
// Strict seam: the human is host-side downstream — no in-script HUMAN BOUNDARY block.
|
|
93
|
+
expect(wf.content).not.toContain("HUMAN BOUNDARY");
|
|
94
|
+
// It is still surfaced loud as an UNREPRESENTABLE comment, though.
|
|
95
|
+
expect(wf.content).toContain("UNREPRESENTABLE: human 'promote'");
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
describe("claude-workflow binding — human split (matchmat-ship)", () => {
|
|
99
|
+
// (c) a human-split README is emitted (topology has a `human promote` node)
|
|
100
|
+
it("emits a <topology>-README.md documenting the human handoff", () => {
|
|
101
|
+
const readme = find("-README.md");
|
|
102
|
+
expect(readme).toBeDefined();
|
|
103
|
+
expect(readme.path).toBe("matchmat-ship-README.md");
|
|
104
|
+
expect(readme.content).toContain("promote");
|
|
105
|
+
expect(readme.content.toLowerCase()).toContain("human");
|
|
106
|
+
expect(readme.content.toLowerCase()).toContain("downstream");
|
|
107
|
+
});
|
|
108
|
+
it("notes regression is a separate downstream workflow", () => {
|
|
109
|
+
const readme = find("-README.md");
|
|
110
|
+
expect(readme.content.toLowerCase()).toContain("separate");
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
describe("claude-workflow binding — LOSSY report (matchmat-ship)", () => {
|
|
114
|
+
it("emits a <topology>-LOSSY-REPORT.md", () => {
|
|
115
|
+
const report = find("-LOSSY-REPORT.md");
|
|
116
|
+
expect(report).toBeDefined();
|
|
117
|
+
expect(report.path).toBe("matchmat-ship-LOSSY-REPORT.md");
|
|
118
|
+
});
|
|
119
|
+
it("classifies the human node as UNREPRESENTABLE", () => {
|
|
120
|
+
const report = find("-LOSSY-REPORT.md");
|
|
121
|
+
expect(report.content).toContain("UNREPRESENTABLE");
|
|
122
|
+
expect(report.content).toContain("human");
|
|
123
|
+
});
|
|
124
|
+
it("classifies the host-side verify-gate as LOSSY (not in the workflow.js)", () => {
|
|
125
|
+
const report = find("-LOSSY-REPORT.md");
|
|
126
|
+
expect(report.content).toContain("verify-gate");
|
|
127
|
+
expect(report.content).toContain("HOST-side");
|
|
128
|
+
});
|
|
129
|
+
it("classifies agent.scale as LOSSY", () => {
|
|
130
|
+
const report = find("-LOSSY-REPORT.md");
|
|
131
|
+
expect(report.content).toContain("LOSSY");
|
|
132
|
+
expect(report.content).toContain("agent.scale");
|
|
133
|
+
});
|
|
134
|
+
// STRICT SEAM: phases 1 & 3 are correct HOST phases, NOT 'folded-in lossy' entries.
|
|
135
|
+
it("does NOT contain 'execution:host' folded-in LOSSY entries (strict seam)", () => {
|
|
136
|
+
const report = find("-LOSSY-REPORT.md");
|
|
137
|
+
expect(report.content).not.toContain("execution:host");
|
|
138
|
+
expect(report.content).not.toContain("folded");
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
describe("claude-workflow binding — Blackboard seam contract (matchmat-ship)", () => {
|
|
142
|
+
it("emits a <topology>-SEAM.md describing the file-based hand-off", () => {
|
|
143
|
+
const seam = find("-SEAM.md");
|
|
144
|
+
expect(seam).toBeDefined();
|
|
145
|
+
expect(seam.path).toBe("matchmat-ship-SEAM.md");
|
|
146
|
+
});
|
|
147
|
+
it("documents the workspace root and per-agent reads/writes", () => {
|
|
148
|
+
const seam = find("-SEAM.md");
|
|
149
|
+
expect(seam.content).toContain("workspace/");
|
|
150
|
+
expect(seam.content).toContain("builder");
|
|
151
|
+
expect(seam.content).toContain("contract-delta.md");
|
|
152
|
+
});
|
|
153
|
+
it("states the host .claude/ files are emitted by the claude-code binding, not this one", () => {
|
|
154
|
+
const seam = find("-SEAM.md");
|
|
155
|
+
expect(seam.content).toContain("claude-code");
|
|
156
|
+
});
|
|
157
|
+
it("documents the strict run order: host phase 1 → launch workflow build → host phase 3/gate → human promote", () => {
|
|
158
|
+
const seam = find("-SEAM.md");
|
|
159
|
+
expect(seam.content).toContain("STRICT SEAM");
|
|
160
|
+
// The workflow rung is the build; host runs the surrounding phases.
|
|
161
|
+
expect(seam.content).toContain("Host launches `matchmat-ship.workflow.js`");
|
|
162
|
+
expect(seam.content).toContain("build rung");
|
|
163
|
+
expect(seam.content).toContain("phase 1 (contract-scout");
|
|
164
|
+
expect(seam.content).toContain("phase 3 (security-verifier");
|
|
165
|
+
expect(seam.content).toContain("human `promote`");
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
describe("claude-workflow binding — UNREPRESENTABLE never dropped silently", () => {
|
|
169
|
+
const wf = find(".workflow.js");
|
|
170
|
+
it("surfaces UNREPRESENTABLE primitives as in-script comments", () => {
|
|
171
|
+
expect(wf.content).toContain("// UNREPRESENTABLE:");
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
// ---------------------------------------------------------------------------
|
|
175
|
+
// Edge case: a topology with NO seam marker → no workflow.js, loud note
|
|
176
|
+
// ---------------------------------------------------------------------------
|
|
177
|
+
describe("claude-workflow binding — no execution:workflow marker", () => {
|
|
178
|
+
const NO_SEAM = `
|
|
179
|
+
topology no-seam : [pipeline] {
|
|
180
|
+
meta { version: "1.0.0" description: "no workflow phase" }
|
|
181
|
+
orchestrator { model: opus handles: [intake] }
|
|
182
|
+
action intake { kind: external source: "user" }
|
|
183
|
+
agent solo {
|
|
184
|
+
model: sonnet
|
|
185
|
+
phase: 1
|
|
186
|
+
tools: [Read, Write]
|
|
187
|
+
reads: ["workspace/in.md"]
|
|
188
|
+
writes: ["workspace/out.md"]
|
|
189
|
+
permissions: autonomous
|
|
190
|
+
}
|
|
191
|
+
flow { intake -> solo }
|
|
192
|
+
}
|
|
193
|
+
`;
|
|
194
|
+
const noSeamAst = parse(NO_SEAM);
|
|
195
|
+
const noSeamFiles = claudeWorkflowBinding.scaffold(noSeamAst);
|
|
196
|
+
it("emits no workflow.js but still emits a LOSSY report explaining why", () => {
|
|
197
|
+
const wf = noSeamFiles.find((f) => f.path.endsWith(".workflow.js"));
|
|
198
|
+
expect(wf).toBeUndefined();
|
|
199
|
+
const report = noSeamFiles.find((f) => f.path.endsWith("-LOSSY-REPORT.md"));
|
|
200
|
+
expect(report).toBeDefined();
|
|
201
|
+
expect(report.content).toContain("execution");
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
//# sourceMappingURL=claude-workflow.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-workflow.test.js","sourceRoot":"","sources":["../../../src/bindings/__tests__/claude-workflow.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hybrid end-to-end test.
|
|
3
|
+
*
|
|
4
|
+
* Unit tests check each binding in isolation. THIS test compiles BOTH bindings
|
|
5
|
+
* from the SAME .at file and proves they COMPOSE into one coherent hybrid:
|
|
6
|
+
* - the host (claude-code) and the rung (claude-workflow) partition the agents
|
|
7
|
+
* with no overlap and no gap,
|
|
8
|
+
* - they agree on the seam (workflow filename, Blackboard root, SEAM doc),
|
|
9
|
+
* - the generated workflow.js is syntactically valid JavaScript,
|
|
10
|
+
* - nothing is silently dropped (the LOSSY report exists).
|
|
11
|
+
*
|
|
12
|
+
* This is the real "does the hybrid work end to end" gate.
|
|
13
|
+
*/
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=hybrid-e2e.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hybrid-e2e.test.d.ts","sourceRoot":"","sources":["../../../src/bindings/__tests__/hybrid-e2e.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG"}
|