macro-agent 0.1.8 → 0.1.11
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.md +263 -33
- package/README.md +781 -131
- package/dist/acp/claude-code-replay.d.ts +11 -0
- package/dist/acp/claude-code-replay.d.ts.map +1 -0
- package/dist/acp/claude-code-replay.js +190 -0
- package/dist/acp/claude-code-replay.js.map +1 -0
- package/dist/acp/macro-agent.d.ts.map +1 -1
- package/dist/acp/macro-agent.js +192 -7
- package/dist/acp/macro-agent.js.map +1 -1
- package/dist/acp/types.d.ts +9 -0
- package/dist/acp/types.d.ts.map +1 -1
- package/dist/acp/types.js.map +1 -1
- package/dist/adapters/tasks-adapter.d.ts.map +1 -1
- package/dist/adapters/tasks-adapter.js +3 -0
- package/dist/adapters/tasks-adapter.js.map +1 -1
- package/dist/adapters/types.d.ts +1 -0
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/agent/agent-manager-v2.d.ts +21 -0
- package/dist/agent/agent-manager-v2.d.ts.map +1 -1
- package/dist/agent/agent-manager-v2.js +308 -54
- package/dist/agent/agent-manager-v2.js.map +1 -1
- package/dist/agent/agent-manager.d.ts +12 -0
- package/dist/agent/agent-manager.d.ts.map +1 -1
- package/dist/agent/agent-manager.js.map +1 -1
- package/dist/agent/agent-store.d.ts +10 -0
- package/dist/agent/agent-store.d.ts.map +1 -1
- package/dist/agent/agent-store.js +22 -0
- package/dist/agent/agent-store.js.map +1 -1
- package/dist/agent/types.d.ts +15 -2
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/boot-v2.d.ts +129 -1
- package/dist/boot-v2.d.ts.map +1 -1
- package/dist/boot-v2.js +359 -8
- package/dist/boot-v2.js.map +1 -1
- package/dist/cli/acp.js +4 -0
- package/dist/cli/acp.js.map +1 -1
- package/dist/cli/index.js +56 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cognitive/macro-agent-backend.d.ts.map +1 -1
- package/dist/cognitive/macro-agent-backend.js +40 -22
- package/dist/cognitive/macro-agent-backend.js.map +1 -1
- package/dist/integrations/skilltree.d.ts.map +1 -1
- package/dist/integrations/skilltree.js +1 -0
- package/dist/integrations/skilltree.js.map +1 -1
- package/dist/lifecycle/cascade.d.ts +25 -2
- package/dist/lifecycle/cascade.d.ts.map +1 -1
- package/dist/lifecycle/cascade.js +70 -2
- package/dist/lifecycle/cascade.js.map +1 -1
- package/dist/lifecycle/cleanup.d.ts +33 -2
- package/dist/lifecycle/cleanup.d.ts.map +1 -1
- package/dist/lifecycle/cleanup.js +28 -6
- package/dist/lifecycle/cleanup.js.map +1 -1
- package/dist/lifecycle/handlers-v2.d.ts +7 -0
- package/dist/lifecycle/handlers-v2.d.ts.map +1 -1
- package/dist/lifecycle/handlers-v2.js +28 -2
- package/dist/lifecycle/handlers-v2.js.map +1 -1
- package/dist/lifecycle/types.d.ts +11 -0
- package/dist/lifecycle/types.d.ts.map +1 -1
- package/dist/lifecycle/types.js.map +1 -1
- package/dist/map/acp-bridge.d.ts +9 -0
- package/dist/map/acp-bridge.d.ts.map +1 -1
- package/dist/map/acp-bridge.js +15 -2
- package/dist/map/acp-bridge.js.map +1 -1
- package/dist/map/cascade-action-handler.d.ts +24 -0
- package/dist/map/cascade-action-handler.d.ts.map +1 -0
- package/dist/map/cascade-action-handler.js +170 -0
- package/dist/map/cascade-action-handler.js.map +1 -0
- package/dist/map/cascade-bridge.d.ts +44 -0
- package/dist/map/cascade-bridge.d.ts.map +1 -0
- package/dist/map/cascade-bridge.js +294 -0
- package/dist/map/cascade-bridge.js.map +1 -0
- package/dist/map/coordination-handler.d.ts.map +1 -1
- package/dist/map/coordination-handler.js +12 -1
- package/dist/map/coordination-handler.js.map +1 -1
- package/dist/map/lifecycle-bridge.d.ts +1 -1
- package/dist/map/lifecycle-bridge.d.ts.map +1 -1
- package/dist/map/lifecycle-bridge.js +58 -23
- package/dist/map/lifecycle-bridge.js.map +1 -1
- package/dist/map/server.d.ts.map +1 -1
- package/dist/map/server.js +219 -7
- package/dist/map/server.js.map +1 -1
- package/dist/map/sidecar.d.ts.map +1 -1
- package/dist/map/sidecar.js +49 -2
- package/dist/map/sidecar.js.map +1 -1
- package/dist/map/types.d.ts +22 -0
- package/dist/map/types.d.ts.map +1 -1
- package/dist/mcp/tools/done-v2.d.ts.map +1 -1
- package/dist/mcp/tools/done-v2.js +8 -0
- package/dist/mcp/tools/done-v2.js.map +1 -1
- package/dist/teams/team-manager-v2.d.ts.map +1 -1
- package/dist/teams/team-manager-v2.js +26 -0
- package/dist/teams/team-manager-v2.js.map +1 -1
- package/dist/teams/team-runtime-v2.d.ts.map +1 -1
- package/dist/teams/team-runtime-v2.js +16 -3
- package/dist/teams/team-runtime-v2.js.map +1 -1
- package/dist/workspace/config.d.ts +10 -10
- package/dist/workspace/config.d.ts.map +1 -1
- package/dist/workspace/config.js +4 -4
- package/dist/workspace/config.js.map +1 -1
- package/dist/workspace/git-cascade-adapter.d.ts +510 -0
- package/dist/workspace/git-cascade-adapter.d.ts.map +1 -0
- package/dist/workspace/git-cascade-adapter.js +934 -0
- package/dist/workspace/git-cascade-adapter.js.map +1 -0
- package/dist/workspace/index.d.ts +3 -3
- package/dist/workspace/index.d.ts.map +1 -1
- package/dist/workspace/index.js +4 -4
- package/dist/workspace/index.js.map +1 -1
- package/dist/workspace/landing/direct-push.d.ts +20 -0
- package/dist/workspace/landing/direct-push.d.ts.map +1 -0
- package/dist/workspace/landing/direct-push.js +74 -0
- package/dist/workspace/landing/direct-push.js.map +1 -0
- package/dist/workspace/landing/index.d.ts +29 -0
- package/dist/workspace/landing/index.d.ts.map +1 -0
- package/dist/workspace/landing/index.js +37 -0
- package/dist/workspace/landing/index.js.map +1 -0
- package/dist/workspace/landing/merge-to-parent.d.ts +41 -0
- package/dist/workspace/landing/merge-to-parent.d.ts.map +1 -0
- package/dist/workspace/landing/merge-to-parent.js +186 -0
- package/dist/workspace/landing/merge-to-parent.js.map +1 -0
- package/dist/workspace/landing/optimistic-push.d.ts +16 -0
- package/dist/workspace/landing/optimistic-push.d.ts.map +1 -0
- package/dist/workspace/landing/optimistic-push.js +27 -0
- package/dist/workspace/landing/optimistic-push.js.map +1 -0
- package/dist/workspace/landing/queue-to-branch.d.ts +24 -0
- package/dist/workspace/landing/queue-to-branch.d.ts.map +1 -0
- package/dist/workspace/landing/queue-to-branch.js +79 -0
- package/dist/workspace/landing/queue-to-branch.js.map +1 -0
- package/dist/workspace/merge-queue/merge-queue.d.ts +10 -0
- package/dist/workspace/merge-queue/merge-queue.d.ts.map +1 -1
- package/dist/workspace/merge-queue/merge-queue.js +10 -0
- package/dist/workspace/merge-queue/merge-queue.js.map +1 -1
- package/dist/workspace/merge-queue/types.d.ts +16 -2
- package/dist/workspace/merge-queue/types.d.ts.map +1 -1
- package/dist/workspace/merge-queue/types.js +9 -0
- package/dist/workspace/merge-queue/types.js.map +1 -1
- package/dist/workspace/pool/types.d.ts +1 -0
- package/dist/workspace/pool/types.d.ts.map +1 -1
- package/dist/workspace/pool/worktree-pool.d.ts.map +1 -1
- package/dist/workspace/pool/worktree-pool.js +1 -0
- package/dist/workspace/pool/worktree-pool.js.map +1 -1
- package/dist/workspace/recovery/abandon.d.ts +15 -0
- package/dist/workspace/recovery/abandon.d.ts.map +1 -0
- package/dist/workspace/recovery/abandon.js +45 -0
- package/dist/workspace/recovery/abandon.js.map +1 -0
- package/dist/workspace/recovery/auto-resolve.d.ts +27 -0
- package/dist/workspace/recovery/auto-resolve.d.ts.map +1 -0
- package/dist/workspace/recovery/auto-resolve.js +99 -0
- package/dist/workspace/recovery/auto-resolve.js.map +1 -0
- package/dist/workspace/recovery/defer.d.ts +15 -0
- package/dist/workspace/recovery/defer.d.ts.map +1 -0
- package/dist/workspace/recovery/defer.js +16 -0
- package/dist/workspace/recovery/defer.js.map +1 -0
- package/dist/workspace/recovery/escalate.d.ts +16 -0
- package/dist/workspace/recovery/escalate.d.ts.map +1 -0
- package/dist/workspace/recovery/escalate.js +24 -0
- package/dist/workspace/recovery/escalate.js.map +1 -0
- package/dist/workspace/recovery/index.d.ts +32 -0
- package/dist/workspace/recovery/index.d.ts.map +1 -0
- package/dist/workspace/recovery/index.js +45 -0
- package/dist/workspace/recovery/index.js.map +1 -0
- package/dist/workspace/recovery/spawn-resolver.d.ts +45 -0
- package/dist/workspace/recovery/spawn-resolver.d.ts.map +1 -0
- package/dist/workspace/recovery/spawn-resolver.js +118 -0
- package/dist/workspace/recovery/spawn-resolver.js.map +1 -0
- package/dist/workspace/recovery/types.d.ts +63 -0
- package/dist/workspace/recovery/types.d.ts.map +1 -0
- package/dist/workspace/recovery/types.js +12 -0
- package/dist/workspace/recovery/types.js.map +1 -0
- package/dist/workspace/topology/index.d.ts +9 -0
- package/dist/workspace/topology/index.d.ts.map +1 -0
- package/dist/workspace/topology/index.js +8 -0
- package/dist/workspace/topology/index.js.map +1 -0
- package/dist/workspace/topology/no-workspace.d.ts +18 -0
- package/dist/workspace/topology/no-workspace.d.ts.map +1 -0
- package/dist/workspace/topology/no-workspace.js +25 -0
- package/dist/workspace/topology/no-workspace.js.map +1 -0
- package/dist/workspace/topology/types.d.ts +97 -0
- package/dist/workspace/topology/types.d.ts.map +1 -0
- package/dist/workspace/topology/types.js +20 -0
- package/dist/workspace/topology/types.js.map +1 -0
- package/dist/workspace/topology/yaml-driven.d.ts +69 -0
- package/dist/workspace/topology/yaml-driven.d.ts.map +1 -0
- package/dist/workspace/topology/yaml-driven.js +273 -0
- package/dist/workspace/topology/yaml-driven.js.map +1 -0
- package/dist/workspace/types-v3.d.ts +117 -0
- package/dist/workspace/types-v3.d.ts.map +1 -0
- package/dist/workspace/types-v3.js +20 -0
- package/dist/workspace/types-v3.js.map +1 -0
- package/dist/workspace/types.d.ts +162 -17
- package/dist/workspace/types.d.ts.map +1 -1
- package/dist/workspace/workspace-manager.d.ts +101 -13
- package/dist/workspace/workspace-manager.d.ts.map +1 -1
- package/dist/workspace/workspace-manager.js +416 -13
- package/dist/workspace/workspace-manager.js.map +1 -1
- package/dist/workspace/yaml-schema.d.ts +254 -0
- package/dist/workspace/yaml-schema.d.ts.map +1 -0
- package/dist/workspace/yaml-schema.js +170 -0
- package/dist/workspace/yaml-schema.js.map +1 -0
- package/docs/conflict-recovery.md +472 -0
- package/docs/design/task-dispatcher.md +880 -0
- package/docs/git-cascade-integration-gaps.md +678 -0
- package/docs/workspace-interfaces.md +731 -0
- package/docs/workspace-redesign-plan.md +302 -0
- package/package.json +6 -5
- package/src/__tests__/boot-v2.test.ts +435 -0
- package/src/__tests__/e2e/acp-over-map.e2e.test.ts +92 -0
- package/src/__tests__/e2e/auto-sync.e2e.test.ts +257 -0
- package/src/__tests__/e2e/bootstrap.e2e.test.ts +319 -0
- package/src/__tests__/e2e/cascade-rebase.e2e.test.ts +254 -0
- package/src/__tests__/e2e/cli-run.e2e.test.ts +167 -0
- package/src/__tests__/e2e/dispatch-coordination.e2e.test.ts +495 -0
- package/src/__tests__/e2e/dispatch-live.e2e.test.ts +564 -0
- package/src/__tests__/e2e/dispatch-opentasks.e2e.test.ts +496 -0
- package/src/__tests__/e2e/dispatch-phase2-live.e2e.test.ts +456 -0
- package/src/__tests__/e2e/dispatch-phase2.e2e.test.ts +386 -0
- package/src/__tests__/e2e/dispatch.e2e.test.ts +376 -0
- package/src/__tests__/e2e/self-driving-v3.e2e.test.ts +197 -0
- package/src/__tests__/e2e/spawn-resolver.e2e.test.ts +200 -0
- package/src/__tests__/e2e/workspace-lifecycle.e2e.test.ts +30 -22
- package/src/__tests__/e2e/workspace-v3.e2e.test.ts +413 -0
- package/src/acp/__tests__/claude-code-replay.test.ts +225 -0
- package/src/acp/__tests__/macro-agent.test.ts +39 -1
- package/src/acp/claude-code-replay.ts +208 -0
- package/src/acp/macro-agent.ts +203 -10
- package/src/acp/types.ts +10 -0
- package/src/adapters/__tests__/tasks-adapter.test.ts +1 -0
- package/src/adapters/tasks-adapter.ts +3 -0
- package/src/adapters/types.ts +1 -0
- package/src/agent/__tests__/agent-manager-topology.test.ts +73 -0
- package/src/agent/__tests__/agent-manager-v2.test.ts +66 -0
- package/src/agent/__tests__/agent-store.test.ts +52 -0
- package/src/agent/__tests__/task-ref-resolution.test.ts +231 -0
- package/src/agent/agent-manager-v2.ts +372 -59
- package/src/agent/agent-manager.ts +14 -0
- package/src/agent/agent-store.ts +24 -0
- package/src/agent/types.ts +16 -2
- package/src/boot-v2.ts +589 -35
- package/src/cli/acp.ts +4 -0
- package/src/cli/index.ts +61 -0
- package/src/cognitive/macro-agent-backend.ts +45 -29
- package/src/integrations/skilltree.ts +1 -0
- package/src/lifecycle/__tests__/cascade-consolidation.test.ts +240 -0
- package/src/lifecycle/cascade.ts +77 -2
- package/src/lifecycle/cleanup.ts +52 -3
- package/src/lifecycle/handlers-v2.ts +40 -3
- package/src/lifecycle/types.ts +12 -0
- package/src/map/__tests__/cascade-bridge.test.ts +229 -0
- package/src/map/__tests__/emit-event.test.ts +71 -0
- package/src/map/__tests__/lifecycle-bridge.test.ts +86 -10
- package/src/map/acp-bridge.ts +26 -3
- package/src/map/cascade-action-handler.ts +205 -0
- package/src/map/cascade-bridge.ts +339 -0
- package/src/map/coordination-handler.ts +13 -1
- package/src/map/lifecycle-bridge.ts +52 -17
- package/src/map/server.ts +225 -7
- package/src/map/sidecar.ts +48 -1
- package/src/map/types.ts +23 -0
- package/src/mcp/tools/done-v2.ts +9 -0
- package/src/teams/team-manager-v2.ts +37 -0
- package/src/teams/team-runtime-v2.ts +23 -3
- package/src/workspace/__tests__/{dataplane-adapter.test.ts → git-cascade-adapter.test.ts} +209 -14
- package/src/workspace/__tests__/land-dispatch.test.ts +214 -0
- package/src/workspace/__tests__/self-driving-yaml.test.ts +114 -0
- package/src/workspace/__tests__/shared-worktree-refcount.test.ts +154 -0
- package/src/workspace/__tests__/standalone-mode.test.ts +118 -0
- package/src/workspace/__tests__/workspace-manager-v3.test.ts +245 -0
- package/src/workspace/__tests__/yaml-schema.test.ts +210 -0
- package/src/workspace/config.ts +11 -11
- package/src/workspace/git-cascade-adapter.ts +1213 -0
- package/src/workspace/index.ts +11 -11
- package/src/workspace/landing/__tests__/strategies.test.ts +184 -0
- package/src/workspace/landing/direct-push.ts +91 -0
- package/src/workspace/landing/index.ts +40 -0
- package/src/workspace/landing/merge-to-parent.ts +229 -0
- package/src/workspace/landing/optimistic-push.ts +36 -0
- package/src/workspace/landing/queue-to-branch.ts +108 -0
- package/src/workspace/merge-queue/merge-queue.ts +10 -0
- package/src/workspace/merge-queue/types.ts +16 -2
- package/src/workspace/pool/__tests__/worktree-pool.integration.test.ts +5 -5
- package/src/workspace/pool/types.ts +1 -0
- package/src/workspace/pool/worktree-pool.ts +1 -0
- package/src/workspace/recovery/__tests__/auto-resolve-integration.test.ts +127 -0
- package/src/workspace/recovery/__tests__/spawn-resolver.test.ts +139 -0
- package/src/workspace/recovery/__tests__/strategies.test.ts +145 -0
- package/src/workspace/recovery/abandon.ts +51 -0
- package/src/workspace/recovery/auto-resolve.ts +119 -0
- package/src/workspace/recovery/defer.ts +23 -0
- package/src/workspace/recovery/escalate.ts +30 -0
- package/src/workspace/recovery/index.ts +58 -0
- package/src/workspace/recovery/spawn-resolver.ts +152 -0
- package/src/workspace/recovery/types.ts +54 -0
- package/src/workspace/topology/__tests__/yaml-driven.test.ts +345 -0
- package/src/workspace/topology/index.ts +18 -0
- package/src/workspace/topology/no-workspace.ts +39 -0
- package/src/workspace/topology/types.ts +116 -0
- package/src/workspace/topology/yaml-driven.ts +316 -0
- package/src/workspace/types-v3.ts +162 -0
- package/src/workspace/types.ts +211 -20
- package/src/workspace/workspace-manager.ts +533 -19
- package/src/workspace/yaml-schema.ts +216 -0
- package/dist/workspace/dataplane-adapter.d.ts +0 -260
- package/dist/workspace/dataplane-adapter.d.ts.map +0 -1
- package/dist/workspace/dataplane-adapter.js +0 -416
- package/dist/workspace/dataplane-adapter.js.map +0 -1
- package/src/workspace/dataplane-adapter.ts +0 -546
package/README.md
CHANGED
|
@@ -4,81 +4,476 @@ A multi-agent orchestration system for spawning and managing hierarchical AI cod
|
|
|
4
4
|
|
|
5
5
|
macro-agent handles **orchestration** (agent lifecycle, team topology, workspace isolation, trigger/wake) and delegates **messaging** to [agent-inbox](https://github.com/alexngai/agent-inbox) and **task management** to [opentasks](https://github.com/alexngai/opentasks). It exposes ACP (WebSocket) and REST API servers, supports cross-instance federation, and can serve as a compute backend for [cognitive-core](https://github.com/alexngai/cognitive-core)/OpenHive.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
|
|
25
|
-
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Table of contents
|
|
10
|
+
|
|
11
|
+
- [Install](#install)
|
|
12
|
+
- [Your first run (5 minutes)](#your-first-run-5-minutes)
|
|
13
|
+
- [How it works](#how-it-works)
|
|
14
|
+
- [Team configuration](#team-configuration)
|
|
15
|
+
- [Minimum viable team](#minimum-viable-team)
|
|
16
|
+
- [Workspace topology](#workspace-topology)
|
|
17
|
+
- [Landing strategies](#landing-strategies)
|
|
18
|
+
- [Conflict recovery](#conflict-recovery)
|
|
19
|
+
- [Six team shapes](#six-team-shapes)
|
|
20
|
+
- [CLI reference](#cli-reference)
|
|
21
|
+
- [Programmatic API](#programmatic-api)
|
|
22
|
+
- [MCP tools agents get](#mcp-tools-agents-get)
|
|
23
|
+
- [Architecture](#architecture)
|
|
24
|
+
- [Design & internals](#design--internals)
|
|
25
|
+
- [Why V3 was needed](#why-v3-was-needed)
|
|
26
|
+
- [Workspace interfaces](#workspace-interfaces)
|
|
27
|
+
- [Conflict recovery mechanics](#conflict-recovery-mechanics)
|
|
28
|
+
- [Implementation status](#implementation-status)
|
|
29
|
+
- [Advanced integrations](#advanced-integrations)
|
|
30
|
+
- [Dependencies](#dependencies)
|
|
31
|
+
- [Testing](#testing)
|
|
32
|
+
- [License](#license)
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Install
|
|
26
37
|
|
|
27
38
|
```bash
|
|
28
39
|
npm install macro-agent
|
|
29
40
|
```
|
|
30
41
|
|
|
31
|
-
|
|
42
|
+
Peer dependency: [git-cascade](https://github.com/alexngai/git-cascade) `>=0.0.3` for the workspace layer.
|
|
32
43
|
|
|
33
|
-
|
|
44
|
+
---
|
|
34
45
|
|
|
35
|
-
|
|
36
|
-
import { bootV2 } from 'macro-agent';
|
|
46
|
+
## Your first run (5 minutes)
|
|
37
47
|
|
|
38
|
-
|
|
39
|
-
// AgentManager, TriggerSystem, and ControlServer
|
|
40
|
-
const system = await bootV2({ cwd: process.cwd() });
|
|
48
|
+
The fastest way to use macro-agent is to run a team template with one command:
|
|
41
49
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
50
|
+
```bash
|
|
51
|
+
# From a git repository with a .multiagent/teams/<name>/team.yaml
|
|
52
|
+
npx multiagent-cli run self-driving --task "implement a /status endpoint"
|
|
53
|
+
```
|
|
46
54
|
|
|
47
|
-
|
|
48
|
-
for await (const update of system.agentManager.prompt(headManager.id, 'Build feature X')) {
|
|
49
|
-
// Handle streaming response
|
|
50
|
-
}
|
|
55
|
+
That command does this:
|
|
51
56
|
|
|
52
|
-
|
|
53
|
-
|
|
57
|
+
1. Boots the full macro-agent system (inbox, tasks, agent manager, workspace layer).
|
|
58
|
+
2. Loads `.multiagent/teams/self-driving/team.yaml` and its `macro_agent.workspace` block.
|
|
59
|
+
3. Constructs a `YamlDrivenTopology` and wires it into the agent manager.
|
|
60
|
+
4. Creates a `team:self-driving` integration stream (forked from `main`).
|
|
61
|
+
5. Spawns the team's root agent (planner) + companions (judge) from the team YAML topology.
|
|
62
|
+
6. Sends your task to the root agent and streams the response.
|
|
63
|
+
7. On `Ctrl-C`: cleanly shuts down agents, closes worktrees, leaves the team stream intact for review.
|
|
64
|
+
|
|
65
|
+
Expected output (abridged):
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
Booting macro-agent and starting team: self-driving
|
|
69
|
+
System booted.
|
|
70
|
+
Team started: self-driving (instance self-driving-1)
|
|
71
|
+
Prompting root agent (agent_ab...) with task...
|
|
72
|
+
[agent output streams here]
|
|
73
|
+
Press Ctrl+C to shut down.
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## How it works
|
|
79
|
+
|
|
80
|
+
The flow for a running team, end to end:
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
1. BOOT bootV2 → AgentStore · Inbox · Tasks · AgentManager · Triggers
|
|
84
|
+
2. TEAM START TeamManager.startTeam → load YAML → YamlDrivenTopology
|
|
85
|
+
→ onTeamStart creates team:<name> integration stream
|
|
86
|
+
→ bootstrap root + companions
|
|
87
|
+
3. SPAWN agentManager.spawn(role)
|
|
88
|
+
→ topology.onAgentSpawn → WorkspaceDecision
|
|
89
|
+
→ executeWorkspaceDecision: create/fork stream, allocate worktree
|
|
90
|
+
→ Claude Code subprocess launched with MCP tools
|
|
91
|
+
4. WORK Agent writes files in its isolated worktree
|
|
92
|
+
→ commits via `commit` MCP tool (Change-Id tracked)
|
|
93
|
+
→ sends messages via agent-inbox
|
|
94
|
+
→ spawns sub-agents via `spawn_agent` (capability-gated)
|
|
95
|
+
5. LAND Agent calls `done()`
|
|
96
|
+
→ LandingStrategy invoked (merge-to-parent / queue-to-branch / etc.)
|
|
97
|
+
→ cascade rebase optional (for stacked streams)
|
|
98
|
+
6. RECOVER If landing conflicts: ConflictRecoveryStrategy dispatches
|
|
99
|
+
→ defer / abandon / escalate / auto-resolve / spawn-resolver
|
|
100
|
+
7. SYNC When a parent stream advances, roles with
|
|
101
|
+
`on_parent_advanced: sync_with_parent` auto-rebase
|
|
102
|
+
(coalesced 2s debounce)
|
|
103
|
+
8. TERMINATE topology.onAgentComplete → deallocate worktree (ref-counted)
|
|
104
|
+
9. TEAM STOP topology.onTeamStop → keep / merge-to-main / abandon the team stream
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Key separation:
|
|
108
|
+
- **YAML** is the source of truth for team shape (who exists, which streams, what landing/recovery).
|
|
109
|
+
- **MCP tools** are how agents make runtime decisions within capabilities granted by YAML.
|
|
110
|
+
- **Programmatic API** on `WorkspaceManager` is for library consumers that bypass team YAML.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Team configuration
|
|
115
|
+
|
|
116
|
+
Teams live in `.multiagent/teams/<name>/`:
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
.multiagent/teams/self-driving/
|
|
120
|
+
├── team.yaml # Manifest: topology, communication, macro_agent block
|
|
121
|
+
├── roles/
|
|
122
|
+
│ ├── planner.yaml # Custom role (extends coordinator)
|
|
123
|
+
│ ├── grinder.yaml # Custom role (extends worker)
|
|
124
|
+
│ └── judge.yaml # Custom role (extends monitor)
|
|
125
|
+
└── prompts/
|
|
126
|
+
├── planner.md
|
|
127
|
+
├── grinder.md
|
|
128
|
+
└── judge.md
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Minimum viable team
|
|
132
|
+
|
|
133
|
+
```yaml
|
|
134
|
+
# team.yaml
|
|
135
|
+
name: my-team
|
|
136
|
+
version: 1
|
|
137
|
+
roles: [worker]
|
|
138
|
+
|
|
139
|
+
topology:
|
|
140
|
+
root:
|
|
141
|
+
role: worker
|
|
142
|
+
prompt: prompts/worker.md
|
|
143
|
+
|
|
144
|
+
communication:
|
|
145
|
+
enforcement: permissive
|
|
146
|
+
|
|
147
|
+
macro_agent:
|
|
148
|
+
workspace:
|
|
149
|
+
roles:
|
|
150
|
+
worker:
|
|
151
|
+
workspace: none # no git isolation; inherit parent cwd
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Run it:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
npx multiagent-cli run my-team --task "hello"
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Workspace topology
|
|
161
|
+
|
|
162
|
+
The `macro_agent.workspace` block drives stream allocation per role. Grammar summary:
|
|
163
|
+
|
|
164
|
+
```yaml
|
|
165
|
+
macro_agent:
|
|
166
|
+
workspace:
|
|
167
|
+
default_stream:
|
|
168
|
+
fork_from: main # branch to fork team_root from
|
|
169
|
+
name_template: "{team}" # {team} is substituted at runtime
|
|
170
|
+
change_id_tracking: true
|
|
171
|
+
|
|
172
|
+
on_team_complete: keep # or: merge_to_main, abandon
|
|
173
|
+
|
|
174
|
+
roles:
|
|
175
|
+
<role_name>:
|
|
176
|
+
# What kind of workspace this role gets
|
|
177
|
+
workspace: none | share_parent_cwd | attach_to_team_root |
|
|
178
|
+
share_with_agent | new_stream
|
|
179
|
+
|
|
180
|
+
# When workspace: new_stream, how is the stream placed in the graph?
|
|
181
|
+
stream_lineage: from_team_root | fork_from_team_root |
|
|
182
|
+
fork_from_parent | independent | track_existing_branch
|
|
183
|
+
|
|
184
|
+
# How to finalize work (see Landing strategies below)
|
|
185
|
+
landing: merge_to_parent_stream | queue_to_branch |
|
|
186
|
+
direct_push | optimistic_push | none
|
|
187
|
+
landing_config: { } # strategy-specific options
|
|
188
|
+
|
|
189
|
+
# What to do on a landing conflict
|
|
190
|
+
on_conflict: abort | ours | theirs | defer | agent
|
|
191
|
+
on_conflict_recovery: defer | abandon | escalate |
|
|
192
|
+
auto-resolve | spawn-resolver
|
|
193
|
+
|
|
194
|
+
# Auto-rebase onto parent when parent advances
|
|
195
|
+
on_parent_advanced: sync_with_parent | none
|
|
196
|
+
cascade_on_parent_update: true | false
|
|
197
|
+
|
|
198
|
+
# Cross-role references
|
|
199
|
+
share_with: <role_name> # for workspace: share_with_agent
|
|
200
|
+
track_branch: <branch_name> # for stream_lineage: track_existing_branch
|
|
201
|
+
|
|
202
|
+
# MCP tool access for the agent
|
|
203
|
+
capabilities: [workspace.commit, workspace.land, ...]
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Landing strategies
|
|
207
|
+
|
|
208
|
+
When an agent calls `done()`, its role's `landing:` strategy finalizes the work.
|
|
209
|
+
|
|
210
|
+
| Strategy | What it does | Typical use |
|
|
211
|
+
|---|---|---|
|
|
212
|
+
| `merge_to_parent_stream` | `mergeStream(source → parent)`; optional cascade rebase for dependents | Stacked workflows, peer swarm |
|
|
213
|
+
| `queue_to_branch` | Adds to git-cascade's merge queue; integrator drains it later | Triad / many-writer flows |
|
|
214
|
+
| `direct_push` | `git rebase + git push` with retries | Trunk-based teams (self-driving's grinders) |
|
|
215
|
+
| `optimistic_push` | `direct_push` + emits validation event | Self-driving with judge reviewing after push |
|
|
216
|
+
| `none` | No landing (for read-only roles) | Researchers, judges, orchestrators |
|
|
217
|
+
|
|
218
|
+
Enable cascade rebase for stacked streams:
|
|
219
|
+
|
|
220
|
+
```yaml
|
|
221
|
+
roles:
|
|
222
|
+
feature_owner:
|
|
223
|
+
landing: merge_to_parent_stream
|
|
224
|
+
landing_config:
|
|
225
|
+
cascade: true # propagate rebase to dependents
|
|
226
|
+
cascadeStrategy: defer_conflicts # or: stop_on_conflict, skip_conflicting
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Conflict recovery
|
|
230
|
+
|
|
231
|
+
When landing returns a conflict, macro-agent dispatches a `ConflictRecoveryStrategy` based on the role's `on_conflict_recovery` (or team default).
|
|
232
|
+
|
|
233
|
+
| Strategy | Mode | Behavior |
|
|
234
|
+
|---|---|---|
|
|
235
|
+
| `defer` | sync | Leave conflict record in place; human/external resolves |
|
|
236
|
+
| `abandon` | sync | Abandon the conflicted stream — throwaway work |
|
|
237
|
+
| `escalate` | async | Pause stream, notify human, await external resolve_conflict |
|
|
238
|
+
| `auto-resolve` | sync | Replay merge with `-X ours/theirs/union`; commit; unblock |
|
|
239
|
+
| `spawn-resolver` | async | Spawn an LLM resolver agent; times out → escalates |
|
|
240
|
+
|
|
241
|
+
Example:
|
|
242
|
+
|
|
243
|
+
```yaml
|
|
244
|
+
macro_agent:
|
|
245
|
+
workspace:
|
|
246
|
+
conflict_recovery:
|
|
247
|
+
default_strategy: spawn-resolver
|
|
248
|
+
default_config:
|
|
249
|
+
role: resolver
|
|
250
|
+
timeout_ms: 1800000 # 30 min
|
|
251
|
+
max_recovery_depth: 3
|
|
252
|
+
|
|
253
|
+
roles:
|
|
254
|
+
coder:
|
|
255
|
+
landing: queue_to_branch
|
|
256
|
+
on_conflict_recovery: spawn-resolver # can override team default
|
|
257
|
+
hotfix:
|
|
258
|
+
on_conflict_recovery: auto-resolve
|
|
259
|
+
conflict_recovery_config:
|
|
260
|
+
strategy: ours
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
For `spawn-resolver`, define the resolver role:
|
|
264
|
+
|
|
265
|
+
```yaml
|
|
266
|
+
roles:
|
|
267
|
+
resolver:
|
|
268
|
+
workspace: new_stream
|
|
269
|
+
stream_lineage: track_existing_branch # attach to the conflicted branch
|
|
270
|
+
landing: none # resolver doesn't land itself
|
|
271
|
+
capabilities:
|
|
272
|
+
- workspace.commit
|
|
273
|
+
- workspace.resolve # unlocks resolve_conflict MCP tool
|
|
274
|
+
- workspace.read
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Six team shapes
|
|
278
|
+
|
|
279
|
+
The workspace layer is designed to express 6 common multi-agent patterns. See [docs/git-cascade-integration-gaps.md](docs/git-cascade-integration-gaps.md) §5 for traces.
|
|
280
|
+
|
|
281
|
+
**1. Solo stack** — one agent, chain of forked streams:
|
|
282
|
+
```yaml
|
|
283
|
+
roles:
|
|
284
|
+
author:
|
|
285
|
+
workspace: new_stream
|
|
286
|
+
stream_lineage: fork_from_team_root
|
|
287
|
+
landing: merge_to_parent_stream
|
|
288
|
+
cascade_on_parent_update: true
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
**2. Triad** — coordinator + integrator + N workers:
|
|
292
|
+
```yaml
|
|
293
|
+
roles:
|
|
294
|
+
coordinator: { workspace: attach_to_team_root }
|
|
295
|
+
worker:
|
|
296
|
+
workspace: new_stream
|
|
297
|
+
stream_lineage: fork_from_parent
|
|
298
|
+
landing: queue_to_branch
|
|
299
|
+
landing_config: { target: "stream:team_root" }
|
|
300
|
+
integrator:
|
|
301
|
+
workspace: attach_to_team_root
|
|
302
|
+
capabilities: [workspace.merge, merge_queue.drain]
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
**3. Peer swarm** — N equal agents:
|
|
306
|
+
```yaml
|
|
307
|
+
roles:
|
|
308
|
+
orchestrator: { workspace: none }
|
|
309
|
+
peer:
|
|
310
|
+
workspace: new_stream
|
|
311
|
+
stream_lineage: fork_from_team_root
|
|
312
|
+
landing: merge_to_parent_stream
|
|
54
313
|
```
|
|
55
314
|
|
|
56
|
-
|
|
315
|
+
**4. Pipeline** — planner → coder → reviewer → integrator:
|
|
316
|
+
```yaml
|
|
317
|
+
roles:
|
|
318
|
+
planner: { workspace: none }
|
|
319
|
+
coder:
|
|
320
|
+
workspace: new_stream
|
|
321
|
+
stream_lineage: fork_from_team_root
|
|
322
|
+
landing: queue_to_branch
|
|
323
|
+
reviewer:
|
|
324
|
+
workspace: share_with_agent
|
|
325
|
+
share_with: coder
|
|
326
|
+
landing: none
|
|
327
|
+
integrator:
|
|
328
|
+
workspace: attach_to_team_root
|
|
329
|
+
capabilities: [workspace.merge, merge_queue.drain]
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
**5. Research / read-only** — agents don't commit:
|
|
333
|
+
```yaml
|
|
334
|
+
roles:
|
|
335
|
+
researcher:
|
|
336
|
+
workspace: none
|
|
337
|
+
capabilities: []
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
**6. Long-lived feature + subtasks** — parent rebases onto main as it advances:
|
|
341
|
+
```yaml
|
|
342
|
+
roles:
|
|
343
|
+
feature_owner:
|
|
344
|
+
workspace: new_stream
|
|
345
|
+
stream_lineage: fork_from_team_root
|
|
346
|
+
landing: merge_to_parent_stream
|
|
347
|
+
cascade_on_parent_update: true
|
|
348
|
+
on_parent_advanced: sync_with_parent
|
|
349
|
+
subtask:
|
|
350
|
+
workspace: new_stream
|
|
351
|
+
stream_lineage: fork_from_parent
|
|
352
|
+
landing: merge_to_parent_stream
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
---
|
|
356
|
+
|
|
357
|
+
## CLI reference
|
|
57
358
|
|
|
58
359
|
```bash
|
|
59
|
-
#
|
|
60
|
-
npx multiagent-cli
|
|
360
|
+
# Run a team with optional initial task
|
|
361
|
+
npx multiagent-cli run <teamName> [--task "..."] [--cwd <path>] [--base-path <path>]
|
|
362
|
+
|
|
363
|
+
# Interactive chat with a head manager (no team)
|
|
364
|
+
npx multiagent-cli chat [--cwd <path>]
|
|
61
365
|
|
|
62
|
-
#
|
|
366
|
+
# System status (agent count, active sessions)
|
|
63
367
|
npx multiagent-cli status
|
|
64
368
|
|
|
65
|
-
#
|
|
66
|
-
npx multiagent-cli hierarchy
|
|
369
|
+
# Agent hierarchy tree
|
|
370
|
+
npx multiagent-cli hierarchy [rootId]
|
|
67
371
|
|
|
68
|
-
# List
|
|
69
|
-
npx multiagent-cli agents
|
|
372
|
+
# List agents (optional filter)
|
|
373
|
+
npx multiagent-cli agents [agentId]
|
|
70
374
|
|
|
71
|
-
# Stop
|
|
375
|
+
# Stop a specific agent or all
|
|
72
376
|
npx multiagent-cli stop <agentId>
|
|
73
377
|
npx multiagent-cli stop --all
|
|
74
378
|
|
|
75
|
-
#
|
|
379
|
+
# Wipe local state (agents.db, inbox.db, worktrees)
|
|
76
380
|
npx multiagent-cli clear
|
|
77
381
|
|
|
78
|
-
#
|
|
382
|
+
# ACP stdio server (for embedding via acp-factory)
|
|
79
383
|
npx multiagent --acp
|
|
80
384
|
```
|
|
81
385
|
|
|
386
|
+
`run` exits cleanly on `SIGINT` (Ctrl-C). Exit code `0` on normal shutdown, non-zero if team startup fails.
|
|
387
|
+
|
|
388
|
+
---
|
|
389
|
+
|
|
390
|
+
## Programmatic API
|
|
391
|
+
|
|
392
|
+
For library consumers (tools, tests, cognitive-core):
|
|
393
|
+
|
|
394
|
+
```typescript
|
|
395
|
+
import { bootV2 } from 'macro-agent';
|
|
396
|
+
|
|
397
|
+
const system = await bootV2({
|
|
398
|
+
cwd: process.cwd(),
|
|
399
|
+
// Optional: enable extras
|
|
400
|
+
api: { enabled: true, port: 3000 },
|
|
401
|
+
acp: { enabled: true, port: 8080 },
|
|
402
|
+
federation: { systemId: 'dev-laptop' },
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
// Option A: start a team with auto-wired V3 topology
|
|
406
|
+
const teamManager = new TeamManagerV2({
|
|
407
|
+
agentManager: system.agentManager,
|
|
408
|
+
inboxAdapter: system.inboxAdapter,
|
|
409
|
+
tasksAdapter: system.tasksAdapter,
|
|
410
|
+
workspaceManager: system.workspaceManager,
|
|
411
|
+
});
|
|
412
|
+
teamManager.install();
|
|
413
|
+
await teamManager.startTeam('self-driving');
|
|
414
|
+
|
|
415
|
+
// Option B: drive agents directly (no team YAML)
|
|
416
|
+
const head = await system.agentManager.getOrCreateHeadManager({ cwd: process.cwd() });
|
|
417
|
+
for await (const update of system.agentManager.prompt(head.id, 'Do the thing')) {
|
|
418
|
+
// stream updates
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
await system.shutdown();
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
Workspace API for direct control:
|
|
425
|
+
|
|
426
|
+
```typescript
|
|
427
|
+
import { DefaultWorkspaceManager, createGitCascadeAdapter } from 'macro-agent';
|
|
428
|
+
|
|
429
|
+
const adapter = createGitCascadeAdapter({ enabled: true, repoPath, dbPath });
|
|
430
|
+
const ws = createWorkspaceManagerWithAdapter(adapter);
|
|
431
|
+
|
|
432
|
+
// Stream-first primitives
|
|
433
|
+
const stream = ws.createStreamV3({ name: 'feature-x', ownerId: 'team:app', forkFrom: 'main' });
|
|
434
|
+
const child = ws.forkStream({ parentStreamId: stream, name: 'sub', ownerId: 'agent-1' });
|
|
435
|
+
const wt = ws.allocateWorktree({ agentId: 'agent-1', streamId: child });
|
|
436
|
+
|
|
437
|
+
// Change-Id tracked commit
|
|
438
|
+
const { commit, changeId } = ws.commitChanges({
|
|
439
|
+
agentId: 'agent-1', streamId: child, worktree: wt.path, message: 'feat: x',
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
// Land via strategy
|
|
443
|
+
const result = await ws.land({ agentId: 'agent-1', streamId: child, strategyName: 'merge-to-parent' });
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
---
|
|
447
|
+
|
|
448
|
+
## MCP tools agents get
|
|
449
|
+
|
|
450
|
+
Registered per role based on capabilities declared in team YAML:
|
|
451
|
+
|
|
452
|
+
| Source | Tools | Capability required |
|
|
453
|
+
|---|---|---|
|
|
454
|
+
| macro-agent | `done`, `spawn_agent`, `stop_agent`, `get_hierarchy`, `inject_context` | always available |
|
|
455
|
+
| macro-agent | `claim_task`, `unclaim_task`, `list_claimable_tasks` | `task.claim` |
|
|
456
|
+
| macro-agent | `commit` | `workspace.commit` |
|
|
457
|
+
| macro-agent | `land` | `workspace.land` |
|
|
458
|
+
| macro-agent | `resolve_conflict`, `list_conflicts`, `get_conflict` | `workspace.resolve` |
|
|
459
|
+
| macro-agent | `next_merge_request`, `mark_merge_complete` | `merge_queue.drain` |
|
|
460
|
+
| agent-inbox | `send_message`, `check_inbox`, `read_thread`, `list_agents` | always available |
|
|
461
|
+
| opentasks | `task`, `link`, `annotate`, `query` | always available |
|
|
462
|
+
|
|
463
|
+
Role YAML grants capabilities:
|
|
464
|
+
|
|
465
|
+
```yaml
|
|
466
|
+
# roles/grinder.yaml
|
|
467
|
+
name: grinder
|
|
468
|
+
extends: worker
|
|
469
|
+
capabilities_add:
|
|
470
|
+
- workspace.commit
|
|
471
|
+
- workspace.land
|
|
472
|
+
- task.claim
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
---
|
|
476
|
+
|
|
82
477
|
## Architecture
|
|
83
478
|
|
|
84
479
|
```
|
|
@@ -96,105 +491,356 @@ npx multiagent --acp
|
|
|
96
491
|
│ │ │ │ │ (RPC) │ │ (WS) │ │ (HTTP) │
|
|
97
492
|
│ spawn │ │ router │ └────┬────┘ └────────┘ └───────────┘
|
|
98
493
|
│ prompt │ │ wake │ │
|
|
99
|
-
│ terminate│ │ cron │ MCP subprocesses
|
|
100
|
-
└─────┬─────┘ │ webhook │
|
|
494
|
+
│ terminate│ │ cron │ MCP subprocesses (per agent)
|
|
495
|
+
└─────┬─────┘ │ webhook │
|
|
101
496
|
│ │ ai-router│
|
|
102
497
|
┌─────┼───────┘──────────┐
|
|
103
498
|
│ │ │
|
|
104
|
-
|
|
105
|
-
│Roles││ Workspace
|
|
106
|
-
│ ││
|
|
107
|
-
│ ││
|
|
108
|
-
│ ││
|
|
109
|
-
|
|
110
|
-
|
|
499
|
+
┌▼────┐┌▼──────────────┐ ┌───▼────────┐
|
|
500
|
+
│Roles││ Workspace (V3) │ │ Adapters │
|
|
501
|
+
│ ││ TopologyPolicy │ │ │
|
|
502
|
+
│ ││ LandingStrategy│ │ InboxAdapter ──► agent-inbox (embedded)
|
|
503
|
+
│ ││ ConflictRecov. │ │ TasksAdapter ──► opentasks (IPC daemon)
|
|
504
|
+
│ ││ GitCascadeAdpt │ │ Federation ──► remote instances
|
|
505
|
+
└────┘└────────────────┘ └────────────┘
|
|
111
506
|
```
|
|
112
507
|
|
|
113
|
-
|
|
114
|
-
- **macro-agent** —
|
|
115
|
-
- **agent-inbox** —
|
|
116
|
-
- **opentasks** —
|
|
508
|
+
Three subsystems:
|
|
509
|
+
- **macro-agent** — orchestration, lifecycle, teams, workspace, triggers, ACP/REST, federation, cognitive backend
|
|
510
|
+
- **agent-inbox** — messaging (embedded in-process, IPC server for subprocesses, federation)
|
|
511
|
+
- **opentasks** — task management (separate daemon, IPC client)
|
|
117
512
|
|
|
118
|
-
|
|
513
|
+
For full design rationale and interface contracts:
|
|
514
|
+
- [docs/workspace-interfaces.md](docs/workspace-interfaces.md) — V3 TypeScript contracts
|
|
515
|
+
- [docs/git-cascade-integration-gaps.md](docs/git-cascade-integration-gaps.md) — design narrative + 6 workflow traces
|
|
516
|
+
- [docs/conflict-recovery.md](docs/conflict-recovery.md) — recovery strategy design
|
|
517
|
+
- [docs/workspace-redesign-plan.md](docs/workspace-redesign-plan.md) — implementation plan + status
|
|
119
518
|
|
|
120
|
-
|
|
519
|
+
The four subsections below summarize those docs so this README is useful standalone.
|
|
121
520
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
521
|
+
---
|
|
522
|
+
|
|
523
|
+
## Design & internals
|
|
524
|
+
|
|
525
|
+
### Why V3 was needed
|
|
526
|
+
|
|
527
|
+
The original workspace layer was **role-shaped**: every agent had to be a `coordinator`, `worker`, or `integrator`, and the dispatch path in `AgentManagerV2` hardcoded a `switch(role)` that decided what kind of workspace to allocate. The API surface — `createWorkerWorkspace`, `createIntegratorWorkspace`, `createCoordinatorWorkspace`, `createIntegrationStream`, `getMergeQueue` — reflected this bias.
|
|
528
|
+
|
|
529
|
+
**Problems in the old model:**
|
|
530
|
+
|
|
531
|
+
| Symptom | Cause |
|
|
532
|
+
|---|---|
|
|
533
|
+
| One stream per team, owned by a coordinator | Hardcoded in `TeamRuntimeV2` at bootstrap |
|
|
534
|
+
| Cascade rebase (git-cascade's namesake) never called | Adapter never surfaced it |
|
|
535
|
+
| Change-IDs never tracked | Agents used raw `git commit`, bypassing `commitChanges` |
|
|
536
|
+
| Merge queue duplicated | `src/workspace/merge-queue/` replicated git-cascade's built-in with incompatible semantics |
|
|
537
|
+
| Only 20% of git-cascade's API used | Role-shaped wrapper hid most of the library |
|
|
538
|
+
| Peer-swarm / solo-stack / pipeline shapes unexpressible | No role name mapped to them |
|
|
539
|
+
|
|
540
|
+
**What V3 changed:**
|
|
541
|
+
|
|
542
|
+
1. **Stream-first primitives.** `createStreamV3`, `forkStream`, `allocateWorktree`, `commitChanges`, `land` — all role-neutral. Any `Principal` (real `AgentId` or pseudo like `team:<name>`) can own a stream.
|
|
543
|
+
2. **YAML-driven topology.** Team YAML's `macro_agent.workspace` block declares per-role workspace decisions. `YamlDrivenTopology` compiles this into per-spawn `WorkspaceDecision` objects.
|
|
544
|
+
3. **Pluggable landing strategies.** `merge-to-parent`, `queue-to-branch`, `direct-push`, `optimistic-push` replace the dead `IntegrationStrategy` abstraction.
|
|
545
|
+
4. **Pluggable conflict recovery.** `defer` / `abandon` / `escalate` / `auto-resolve` (real git `-X` merge) / `spawn-resolver` (LLM agent).
|
|
546
|
+
5. **git-cascade 0.0.3 alignment.** `cascade` namespace export + `emit` callback wired, unlocking `cascadeRebase` and event-driven auto-sync.
|
|
547
|
+
6. **Legacy path retained.** Programmatic callers that bypass team YAML still use capability-based dispatch (`workspace.worktree` / `workspace.stream` / `workspace.integrate`).
|
|
548
|
+
|
|
549
|
+
Three control layers coexist:
|
|
550
|
+
|
|
551
|
+
| Layer | Used by | What it controls |
|
|
552
|
+
|---|---|---|
|
|
553
|
+
| YAML (`macro_agent.workspace`) | Team authors | Static shape: who gets a stream, lineage, landing, recovery |
|
|
554
|
+
| MCP tools (`commit`, `land`, `fork_stream`, `resolve_conflict`, ...) | Agents at runtime | Runtime judgment within YAML-granted capabilities |
|
|
555
|
+
| Programmatic API on `WorkspaceManager` | Tools, tests, cognitive-core | Full control without team YAML |
|
|
556
|
+
|
|
557
|
+
### Workspace interfaces
|
|
558
|
+
|
|
559
|
+
Three interfaces form the V3 workspace layer. Types live in `src/workspace/types-v3.ts`.
|
|
560
|
+
|
|
561
|
+
**`WorkspaceManager`** — the full API surface, grouped by concern:
|
|
562
|
+
|
|
563
|
+
```typescript
|
|
564
|
+
interface WorkspaceManager {
|
|
565
|
+
// Streams
|
|
566
|
+
createStreamV3(spec: StreamSpec): StreamId;
|
|
567
|
+
forkStream(opts: { parentStreamId, name, ownerId, metadata? }): StreamId;
|
|
568
|
+
mergeStream(opts: { sourceStreamId, targetStreamId, agentId, worktree }): MergeResult;
|
|
569
|
+
syncWithParent(opts: { streamId, agentId, worktree, onConflict? }): RebaseResult;
|
|
570
|
+
abandonStream(streamId, opts?): void;
|
|
571
|
+
pauseStream(streamId, reason?): void;
|
|
572
|
+
resumeStream(streamId): void;
|
|
573
|
+
listStreams(filter?): Stream[];
|
|
574
|
+
getStream(streamId): Stream | null;
|
|
575
|
+
|
|
576
|
+
// Changes (Change-Id tracking via git-cascade)
|
|
577
|
+
commitChanges(opts): { commit: string; changeId: ChangeId };
|
|
578
|
+
markChangesMerged(changeIds: ChangeId[]): void;
|
|
579
|
+
getChange(changeId): Change | null;
|
|
580
|
+
getChangeByCommit(commit): Change | null;
|
|
581
|
+
|
|
582
|
+
// Worktrees
|
|
583
|
+
allocateWorktree(opts: AllocateWorktreeOpts): Worktree;
|
|
584
|
+
deallocateWorkspace(agentId): void;
|
|
585
|
+
getWorktreeForAgent(agentId): Worktree | null;
|
|
586
|
+
|
|
587
|
+
// Landing + recovery
|
|
588
|
+
registerLandingStrategy(strategy: LandingStrategy): void;
|
|
589
|
+
land(opts): Promise<MergeResult>;
|
|
590
|
+
resolveConflict(opts: { conflictId, resolvedBy, resolutionCommit? }): void;
|
|
591
|
+
|
|
592
|
+
// Events + lifecycle
|
|
593
|
+
onEvent(callback: WorkspaceEventCallback): () => void;
|
|
594
|
+
reconcileV3(): MacroReconcileResult;
|
|
595
|
+
close(): void;
|
|
596
|
+
}
|
|
125
597
|
```
|
|
126
598
|
|
|
127
|
-
|
|
599
|
+
**Core types:**
|
|
128
600
|
|
|
601
|
+
```typescript
|
|
602
|
+
// A principal — either a real agent or a pseudo-principal for team/system ownership
|
|
603
|
+
type Principal = AgentId | `team:${string}` | `system:${string}`;
|
|
604
|
+
|
|
605
|
+
interface StreamSpec {
|
|
606
|
+
name: string;
|
|
607
|
+
ownerId: Principal;
|
|
608
|
+
parent?: StreamId; // if set, forks from this parent stream
|
|
609
|
+
forkFrom?: string; // otherwise forks from this branch (default: "main")
|
|
610
|
+
metadata?: Record<string, unknown>;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
interface AllocateWorktreeOpts {
|
|
614
|
+
agentId: Principal;
|
|
615
|
+
streamId?: StreamId;
|
|
616
|
+
sharedWithAgent?: AgentId; // ref-counted co-location
|
|
617
|
+
branch?: string;
|
|
618
|
+
baseDir?: string;
|
|
619
|
+
}
|
|
129
620
|
```
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
621
|
+
|
|
622
|
+
**`TopologyPolicy`** — compiles team YAML into per-spawn decisions:
|
|
623
|
+
|
|
624
|
+
```typescript
|
|
625
|
+
interface TopologyPolicy {
|
|
626
|
+
readonly name: string;
|
|
627
|
+
onTeamStart(ctx): Promise<TeamStartPlan>; // create team-root stream
|
|
628
|
+
onAgentSpawn(ctx): Promise<WorkspaceDecision>; // per-spawn workspace choice
|
|
629
|
+
onAgentComplete(ctx): Promise<void>; // deallocate worktree
|
|
630
|
+
onTeamStop(ctx): Promise<void>; // apply on_team_complete
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
type WorkspaceDecision =
|
|
634
|
+
| { kind: 'none' }
|
|
635
|
+
| { kind: 'share-parent-cwd' }
|
|
636
|
+
| { kind: 'share-with-agent'; agentId: AgentId }
|
|
637
|
+
| { kind: 'attach-to-stream'; streamId: StreamId; allocateWorktree: boolean }
|
|
638
|
+
| { kind: 'new-stream'; streamSpec: StreamSpec; allocateWorktree: boolean };
|
|
138
639
|
```
|
|
139
640
|
|
|
140
|
-
|
|
141
|
-
-
|
|
142
|
-
-
|
|
143
|
-
- **
|
|
144
|
-
- **Integration strategies**: `queue` (merge queue), `trunk` (direct push), `optimistic` (push + validation)
|
|
145
|
-
- **Task modes**: `push` (coordinator assigns) or `pull` (agents claim from pool)
|
|
641
|
+
Three built-in policies:
|
|
642
|
+
- **`YamlDrivenTopology`** — the default; compiles `macro_agent.workspace` YAML
|
|
643
|
+
- **`NoWorkspaceTopology`** — null policy returning `share-parent-cwd` for every spawn
|
|
644
|
+
- **Custom** — implement the interface for bespoke topologies
|
|
146
645
|
|
|
147
|
-
|
|
646
|
+
**`LandingStrategy`** — finalizes work at `done()` time:
|
|
148
647
|
|
|
149
|
-
|
|
648
|
+
```typescript
|
|
649
|
+
interface LandingStrategy {
|
|
650
|
+
readonly name: string;
|
|
651
|
+
canLand?(ctx: LandingContext): boolean;
|
|
652
|
+
land(ctx: LandingContext): Promise<MergeResult>;
|
|
653
|
+
initialize?(): Promise<void>;
|
|
654
|
+
close?(): Promise<void>;
|
|
655
|
+
}
|
|
150
656
|
|
|
151
|
-
|
|
657
|
+
interface LandingContext {
|
|
658
|
+
agentId: AgentId;
|
|
659
|
+
streamId: StreamId;
|
|
660
|
+
sourceWorktree: string;
|
|
661
|
+
targetStreamId?: StreamId;
|
|
662
|
+
strategyConfig?: Record<string, unknown>; // from YAML landing_config
|
|
663
|
+
workspaceManager: WorkspaceManager;
|
|
664
|
+
}
|
|
665
|
+
```
|
|
152
666
|
|
|
153
|
-
|
|
154
|
-
|--------|-------|
|
|
155
|
-
| **macro-agent** | `done`, `spawn_agent`, `stop_agent`, `get_hierarchy`, `inject_context` |
|
|
156
|
-
| **macro-agent** (pull mode) | `claim_task`, `unclaim_task`, `list_claimable_tasks` |
|
|
157
|
-
| **agent-inbox** (IPC) | `send_message`, `check_inbox`, `read_thread`, `list_agents` |
|
|
158
|
-
| **opentasks** (IPC) | `task`, `link`, `annotate`, `query` |
|
|
667
|
+
Registered via `workspaceManager.registerLandingStrategy()` at boot. YAML `landing:` selects per role; MCP `land()` tool arguments can override per call.
|
|
159
668
|
|
|
160
|
-
|
|
669
|
+
**Events** — all operations emit through a single channel:
|
|
161
670
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
|
165
|
-
|
|
|
166
|
-
|
|
|
167
|
-
|
|
|
671
|
+
```typescript
|
|
672
|
+
type WorkspaceEventType =
|
|
673
|
+
| 'stream:created' | 'stream:forked' | 'stream:committed'
|
|
674
|
+
| 'stream:merged' | 'stream:conflicted' | 'stream:abandoned'
|
|
675
|
+
| 'stream:paused' | 'stream:resumed'
|
|
676
|
+
| 'worktree:allocated' | 'worktree:shared' | 'worktree:released'
|
|
677
|
+
| 'change:merged' | 'change:dropped'
|
|
678
|
+
| 'conflict:created' | 'conflict:resolved'
|
|
679
|
+
| 'landing:started' | 'landing:completed'
|
|
680
|
+
| 'cascade:completed'
|
|
681
|
+
| 'mergeQueue:added' | 'mergeQueue:ready' | 'mergeQueue:cancelled' | 'mergeQueue:removed';
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
Subscribers include `YamlDrivenTopology` (for `on_parent_advanced` auto-sync) and the conflict recovery dispatcher (awaiting `conflict:resolved`).
|
|
685
|
+
|
|
686
|
+
### Conflict recovery mechanics
|
|
687
|
+
|
|
688
|
+
Conflicts originate from four operations:
|
|
689
|
+
|
|
690
|
+
| Operation | How conflict surfaces |
|
|
691
|
+
|---|---|
|
|
692
|
+
| `mergeStream(source → target)` | Result has `success: false`, `conflictId` present |
|
|
693
|
+
| `syncWithParent(stream)` | Rebase fails with `ConflictStrategy != 'ours'/'theirs'` |
|
|
694
|
+
| `rebaseOntoStream(target)` | Same as syncWithParent |
|
|
695
|
+
| `cascadeRebase({ root })` | `CascadeResult.failed[]` populated |
|
|
168
696
|
|
|
169
|
-
|
|
697
|
+
**Dispatch flow:**
|
|
170
698
|
|
|
171
|
-
|
|
699
|
+
```
|
|
700
|
+
Agent calls done()
|
|
701
|
+
↓
|
|
702
|
+
Role's LandingStrategy invoked
|
|
703
|
+
↓
|
|
704
|
+
LandingStrategy returns { success: false, conflictId }
|
|
705
|
+
↓
|
|
706
|
+
done() handler looks up role's on_conflict_recovery (or team default)
|
|
707
|
+
↓
|
|
708
|
+
workspaceManager dispatches to the matching ConflictRecoveryStrategy
|
|
709
|
+
↓
|
|
710
|
+
Strategy runs sync (returns immediately) or async (awaits conflict:resolved event)
|
|
711
|
+
↓
|
|
712
|
+
Resolution: resolved | deferred | abandoned | escalated | retry-after | failed
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
Landing strategies **never** dispatch recovery themselves. They return the conflict up; the agent's `done()` flow owns recovery selection. This keeps strategies free of role-level policy (which lives in YAML).
|
|
172
716
|
|
|
173
|
-
|
|
717
|
+
**`ConflictRecoveryStrategy` interface:**
|
|
174
718
|
|
|
175
719
|
```typescript
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
720
|
+
interface ConflictRecoveryStrategy {
|
|
721
|
+
readonly name: string;
|
|
722
|
+
readonly mode: 'sync' | 'async';
|
|
723
|
+
canHandle?(ctx: ConflictContext): boolean;
|
|
724
|
+
recover(ctx: ConflictContext): Promise<ConflictResolution>;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
interface ConflictContext {
|
|
728
|
+
conflictId: string;
|
|
729
|
+
streamId: StreamId;
|
|
730
|
+
paths: string[];
|
|
731
|
+
operation: 'merge' | 'sync' | 'rebase' | 'cascade';
|
|
732
|
+
landingAgentId?: AgentId;
|
|
733
|
+
worktree?: string; // required for auto-resolve
|
|
734
|
+
recoveryDepth: number; // for bounded recursion
|
|
735
|
+
strategyConfig?: Record<string, unknown>; // from YAML conflict_recovery_config
|
|
736
|
+
workspaceManager: WorkspaceManager;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
type ConflictResolution =
|
|
740
|
+
| { kind: 'resolved'; resolutionCommit: string }
|
|
741
|
+
| { kind: 'deferred'; reason: string }
|
|
742
|
+
| { kind: 'abandoned'; streamId: StreamId; reason: string }
|
|
743
|
+
| { kind: 'escalated'; escalatedTo: Principal | 'human' }
|
|
744
|
+
| { kind: 'retry-after'; backoffMs: number; reason: string }
|
|
745
|
+
| { kind: 'failed'; error: string };
|
|
179
746
|
```
|
|
180
747
|
|
|
181
|
-
-
|
|
182
|
-
|
|
183
|
-
-
|
|
748
|
+
**Built-in strategy details:**
|
|
749
|
+
|
|
750
|
+
- **`defer`** — no-op. Returns `deferred`. Leaves the conflict record; a human or external process resolves later.
|
|
751
|
+
- **`abandon`** — calls `workspaceManager.abandonStream(streamId, { reason })`. Returns `abandoned`. For throwaway workflows.
|
|
752
|
+
- **`escalate`** — async. `pauseStream(streamId)` + emit escalation event. Returns `escalated` immediately; waits for an external `resolve_conflict` MCP call to unblock. Suitable when humans must review.
|
|
753
|
+
- **`auto-resolve`** — sync. Only handles `operation: 'merge'`. Replays the failed merge in `ctx.worktree` with `git merge -X ours|theirs|union`, commits the resolution, calls `workspaceManager.resolveConflict`. Returns `resolved` with the new commit hash.
|
|
754
|
+
- **`spawn-resolver`** — async. Spawns a resolver agent via `AgentManager.spawn({ role, ... })` with `workspace.resolve` capability. The resolver reads conflict markers, resolves, commits via the `commit` MCP tool, then calls `resolve_conflict` which emits `conflict:resolved`. The awaiting strategy promise resolves with the resolution commit. On timeout → `escalated`. Configurable concurrency cap (`max_concurrent` per stream) prevents resolver spawn storms.
|
|
755
|
+
|
|
756
|
+
**Safety controls:**
|
|
757
|
+
|
|
758
|
+
| Control | Location | Default |
|
|
759
|
+
|---|---|---|
|
|
760
|
+
| `max_recovery_depth` | `macro_agent.workspace.conflict_recovery.max_recovery_depth` | 3 |
|
|
761
|
+
| Per-stream recovery lock | Module-level in `spawn-resolver` | Auto |
|
|
762
|
+
| `max_concurrent` resolvers per stream | Strategy config | 2 |
|
|
763
|
+
| `timeout_ms` for async strategies | Strategy config | 30 min |
|
|
764
|
+
|
|
765
|
+
Recursion: if a resolver agent's resolution itself produces a new conflict, `recoveryDepth` increments. When it exceeds `max_recovery_depth`, the strategy falls back to `escalate`.
|
|
766
|
+
|
|
767
|
+
### Implementation status
|
|
768
|
+
|
|
769
|
+
The V3 redesign shipped as 10 phases plus 6 follow-up fixes. All are in `main`.
|
|
770
|
+
|
|
771
|
+
**Completed:**
|
|
772
|
+
|
|
773
|
+
| # | Phase | What shipped |
|
|
774
|
+
|---|---|---|
|
|
775
|
+
| 0 | GitCascadeAdapter expansion | 40+ git-cascade primitives surfaced (streams, forks, merges, cascade, changes, events) |
|
|
776
|
+
| 1 | WorkspaceManager V3 surface | Stream-first methods alongside legacy role-shaped ones |
|
|
777
|
+
| 2 | YAML Zod schema | `macro_agent.workspace` validated at team load |
|
|
778
|
+
| 3 | TopologyPolicy + YamlDrivenTopology | Declarative topology compiler |
|
|
779
|
+
| 4 | AgentManagerV2 delegates to TopologyPolicy | V3 dispatch path with legacy capability fallback |
|
|
780
|
+
| 5 | LandingStrategy integration | 4 built-in strategies registered |
|
|
781
|
+
| 6 | MergeQueue marked `@deprecated` | Duplicate kept for legacy callers; scheduled for removal |
|
|
782
|
+
| 7 | ConflictRecoveryStrategy | 5 built-in strategies (including real-git `auto-resolve` + `spawn-resolver`) |
|
|
783
|
+
| 8 | Role-name fallback removed | `switch(role)` deleted; capability-based path retained |
|
|
784
|
+
| 9 | Legacy methods retained (not hard-removed) | Reframed: they serve programmatic callers |
|
|
785
|
+
| 10 | `macro-agent run <team>` CLI | Single-command team launch |
|
|
184
786
|
|
|
185
|
-
|
|
787
|
+
**Follow-up fixes (post-plan):**
|
|
788
|
+
|
|
789
|
+
| # | Fix | Verified by |
|
|
790
|
+
|---|---|---|
|
|
791
|
+
| a | git-cascade 0.0.3 event wiring + cascade namespace | Adapter forwards `x-cascade/*` events into `WorkspaceEvent` stream |
|
|
792
|
+
| b | `macro-agent run` CLI e2e (subprocess spawn, SIGINT exit) | 2 e2e tests |
|
|
793
|
+
| c | self-driving team migrated to V3 YAML | 4 e2e tests; caught duplicate-stream bug in TeamRuntime |
|
|
794
|
+
| d | `spawn-resolver` real-spawn e2e | 4 unit + 2 e2e tests |
|
|
795
|
+
| e | Shared worktree ref-counting (Gap 3) | Fixed 2 latent bugs: sharer dealloc leaked refs; owner dealloc tore down path while sharers alive. 6 unit tests cover lifecycle |
|
|
796
|
+
| f | Cascade worktree provider (Gap 1) | Replaced null-returning stub with real provider: reuses live worktrees, allocates ephemeral `system:cascade-<id>` worktrees, cleans up in `finally`. Per-root-stream lock prevents parallel cascades racing. 4 e2e tests |
|
|
797
|
+
| g | `on_parent_advanced: sync_with_parent` auto-sync (Gap 2) | Full implementation: event subscription, 2-second coalescing debounce, role-scoped dispatch. 3 e2e tests |
|
|
798
|
+
|
|
799
|
+
**Test counts after all fixes:**
|
|
800
|
+
|
|
801
|
+
- 998 unit tests (59 files)
|
|
802
|
+
- 183 e2e tests (25 files) — all previously skipped `RUN_FULL_AGENT_TESTS` tests pass with real Claude Code
|
|
803
|
+
- Zero regressions, clean typecheck
|
|
804
|
+
|
|
805
|
+
**Known open items / follow-ups:**
|
|
806
|
+
|
|
807
|
+
| Item | Severity | Notes |
|
|
808
|
+
|---|---|---|
|
|
809
|
+
| Hard removal of legacy capability dispatch | Low | Retained as programmatic API; not a gap, a supported path |
|
|
810
|
+
| `on_team_complete: merge_to_main` implementation | Low | Currently leaves stream active. Requires landing strategy on team stream; deferred |
|
|
811
|
+
| Cross-team conflict policy | Low | When conflicts span teams, owner team's policy applies; federation-specific edge cases |
|
|
812
|
+
| Recovery observability dashboard | Low | `conflict:*` events fire; no built-in UI yet |
|
|
813
|
+
|
|
814
|
+
**Coverage gaps intentionally accepted:**
|
|
815
|
+
|
|
816
|
+
- Cascade with >3 levels under `stop_on_conflict` — tested at 3 levels only
|
|
817
|
+
- Shared worktree edge case: sharer outlives owner for >1 hour (no TTL) — accepted; `reconcileV3` cleans stale entries on boot
|
|
818
|
+
|
|
819
|
+
---
|
|
820
|
+
|
|
821
|
+
## Advanced integrations
|
|
822
|
+
|
|
823
|
+
### ACP Protocol Server
|
|
824
|
+
|
|
825
|
+
Bridges the [Agent Client Protocol](https://github.com/anthropics/acp) to macro-agent so external clients can connect:
|
|
186
826
|
|
|
187
827
|
```typescript
|
|
188
|
-
const system = await bootV2({
|
|
189
|
-
|
|
190
|
-
|
|
828
|
+
const system = await bootV2({ acp: { enabled: true, port: 8080 } });
|
|
829
|
+
// session/new → head manager creation
|
|
830
|
+
// session/prompt → streaming responses
|
|
831
|
+
// Extension methods: _macro/spawnAgent, _macro/getHierarchy, _macro/forkAgent, etc.
|
|
191
832
|
```
|
|
192
833
|
|
|
193
|
-
|
|
834
|
+
### REST API
|
|
835
|
+
|
|
836
|
+
```typescript
|
|
837
|
+
const system = await bootV2({ api: { enabled: true, port: 3000 } });
|
|
838
|
+
// HTTP endpoints for agents, tasks, teams, metrics — used for dashboards
|
|
839
|
+
```
|
|
194
840
|
|
|
195
|
-
|
|
841
|
+
### Federation
|
|
196
842
|
|
|
197
|
-
Connect multiple macro-agent instances for cross-instance
|
|
843
|
+
Connect multiple macro-agent instances for cross-instance messaging:
|
|
198
844
|
|
|
199
845
|
```typescript
|
|
200
846
|
const system = await bootV2({
|
|
@@ -204,53 +850,55 @@ const system = await bootV2({
|
|
|
204
850
|
trust: { allowedSystems: ['ci-server'] },
|
|
205
851
|
},
|
|
206
852
|
});
|
|
853
|
+
// Agents address with agentId@systemId (e.g., coordinator@ci-server)
|
|
207
854
|
```
|
|
208
855
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
## Cognitive-Core Backend
|
|
856
|
+
### Cognitive-core backend
|
|
212
857
|
|
|
213
|
-
|
|
858
|
+
Serve as compute backend for [cognitive-core](https://github.com/alexngai/cognitive-core) / OpenHive:
|
|
214
859
|
|
|
215
860
|
```typescript
|
|
216
861
|
import { MacroAgentBackend } from 'macro-agent/cognitive';
|
|
217
|
-
|
|
218
862
|
const backend = new MacroAgentBackend(system.agentManager, {
|
|
219
863
|
tasksAdapter: system.tasksAdapter,
|
|
220
864
|
inboxAdapter: system.inboxAdapter,
|
|
221
865
|
});
|
|
222
866
|
```
|
|
223
867
|
|
|
224
|
-
|
|
868
|
+
The swarm is pure compute — atlas, trajectory extraction, and team coordination are handled by OpenHive.
|
|
869
|
+
|
|
870
|
+
---
|
|
225
871
|
|
|
226
872
|
## Dependencies
|
|
227
873
|
|
|
228
874
|
| Package | Purpose |
|
|
229
|
-
|
|
875
|
+
|---|---|
|
|
230
876
|
| [agent-inbox](https://github.com/alexngai/agent-inbox) | Messaging, threading, federation |
|
|
231
877
|
| [opentasks](https://github.com/alexngai/opentasks) | Task graph, dependencies, claiming |
|
|
232
878
|
| [acp-factory](https://github.com/alexngai/acp-factory) | Agent process management |
|
|
233
879
|
| [openteams](https://github.com/alexngai/openteams) | Team template resolution |
|
|
234
|
-
| [git-cascade](https://github.com/alexngai/git-cascade) | Git
|
|
235
|
-
|
|
|
236
|
-
|
|
|
880
|
+
| [git-cascade](https://github.com/alexngai/git-cascade) | Git worktrees, stream/fork/merge, Change-Id tracking, cascade rebase (≥0.0.3) |
|
|
881
|
+
| express | REST API server |
|
|
882
|
+
| ws | ACP WebSocket transport |
|
|
883
|
+
|
|
884
|
+
---
|
|
237
885
|
|
|
238
886
|
## Testing
|
|
239
887
|
|
|
240
888
|
```bash
|
|
241
|
-
# Unit tests (
|
|
242
|
-
npm test
|
|
243
|
-
|
|
244
|
-
# Unit tests (single run)
|
|
245
|
-
npx vitest run
|
|
889
|
+
# Unit tests (59 files, ~1000 tests)
|
|
890
|
+
npm test # watch
|
|
891
|
+
npx vitest run # single run
|
|
246
892
|
|
|
247
|
-
# E2E tests (mocked agent sessions)
|
|
248
|
-
npm run test:e2e
|
|
893
|
+
# E2E tests (24 files, ~180 tests — mocked agent sessions)
|
|
894
|
+
RUN_E2E_TESTS=true npm run test:e2e
|
|
249
895
|
|
|
250
|
-
#
|
|
251
|
-
RUN_FULL_AGENT_TESTS=true npm run test:e2e
|
|
896
|
+
# Full e2e with real Claude Code agents
|
|
897
|
+
RUN_FULL_AGENT_TESTS=true RUN_E2E_TESTS=true npm run test:e2e
|
|
252
898
|
```
|
|
253
899
|
|
|
900
|
+
---
|
|
901
|
+
|
|
254
902
|
## Development
|
|
255
903
|
|
|
256
904
|
```bash
|
|
@@ -259,6 +907,8 @@ npm run build # Build (TypeScript → dist/)
|
|
|
259
907
|
npm run dev # Watch mode build
|
|
260
908
|
```
|
|
261
909
|
|
|
910
|
+
---
|
|
911
|
+
|
|
262
912
|
## License
|
|
263
913
|
|
|
264
914
|
MIT
|