@guyghost/swarm-dao-tmux-adapter 0.2.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 ADDED
@@ -0,0 +1,81 @@
1
+ # Swarm DAO tmux Adapter
2
+
3
+ The swarm-forge execution model for Swarm DAO deliberation: **each agent runs
4
+ as its own detached tmux pane** — watchable live by the operator (`tmux
5
+ attach`), isolated from every other agent, with completion observable through
6
+ filesystem markers.
7
+
8
+ ```
9
+ .swarm-dao-p1-strategist ← pane running the strategist's agent CLI
10
+ .swarm-dao-p1-critic ← pane running the critic's agent CLI
11
+ ...
12
+ ```
13
+
14
+ ## How it works
15
+
16
+ For every agent the adapter:
17
+
18
+ 1. Writes the deliberation prompt to `.dao/tmux/<proposalId>/<agentId>/prompt.md`
19
+ (stale completion markers from previous runs are purged first).
20
+ 2. Starts a detached tmux session whose **program** is
21
+ `sh -c 'PROMPT="$(cat prompt.md)"; <command> > output.md 2> stderr.log; printf "%s" "$?" > done'`
22
+ — the command runs as the session program, so there is no typing race with
23
+ the pane shell.
24
+ 3. Polls for the `done` marker up to `timeoutMs`.
25
+ 4. Harvests `output.md` as the agent's output (exit code and `stderr.log`
26
+ surface as an error output), and kills the session unless `keepSessions`
27
+ is set (which leaves the pane's scrollback alive for inspection).
28
+
29
+ The outputs feed the **same deterministic tally** as every other host — no AI
30
+ authority, no proposal-state mutation.
31
+
32
+ ## Configuration
33
+
34
+ `.dao/config.json`:
35
+
36
+ ```json
37
+ {
38
+ "tmux": {
39
+ "command": "claude -p \"$PROMPT\"",
40
+ "timeoutMs": 300000,
41
+ "sessionPrefix": "swarm-dao",
42
+ "keepSessions": false
43
+ }
44
+ }
45
+ ```
46
+
47
+ - `command` (**required** for deliberation): the agent CLI. `$PROMPT` carries
48
+ the deliberation prompt; stdout is captured as the agent's output.
49
+ - `timeoutMs`: per-agent timeout (default 5 min). A timeout kills the session
50
+ and records a deterministic error output.
51
+ - `sessionPrefix`, `keepSessions`: session naming and pane retention.
52
+
53
+ ## Usage
54
+
55
+ ```typescript
56
+ import { createTmuxHostAdapter } from "@guyghost/swarm-dao-tmux-adapter";
57
+ import { loadConfig, handleDaoDeliberate } from "@guyghost/swarm-dao-core";
58
+
59
+ const config = await loadConfig(".dao");
60
+ const adapter = createTmuxHostAdapter({
61
+ workDir: process.cwd(),
62
+ command: config.tmux?.command,
63
+ });
64
+
65
+ const result = await handleDaoDeliberate(
66
+ { adapter, workDir: process.cwd(), deliberationMode: "auto", controlToolName: "dao_check" },
67
+ 1,
68
+ );
69
+ ```
70
+
71
+ ## Boundary
72
+
73
+ Deliberation is read-only analysis: agents share the repository checkout for
74
+ context and never need per-agent worktrees. Execution-side isolation stays
75
+ with the delivery layer's `GitWorkspace` (`execution.isolation`).
76
+
77
+ ## Testing
78
+
79
+ ```bash
80
+ bun test packages/tmux-adapter # unit (fake tmux) + real tmux (skipped if absent)
81
+ ```
@@ -0,0 +1,34 @@
1
+ import type { HostAdapter } from "@guyghost/swarm-dao-core";
2
+ /** Minimal command surface the adapter needs (node:child_process-backed by default). */
3
+ export interface TmuxRunner {
4
+ exec(command: string, options?: {
5
+ cwd?: string;
6
+ timeout?: number;
7
+ }): Promise<{
8
+ stdout: string;
9
+ stderr: string;
10
+ exitCode: number;
11
+ }>;
12
+ }
13
+ /** tmux session names and run-directory segments accept [a-zA-Z0-9_-] only. */
14
+ export declare function sanitizeSessionName(raw: string): string;
15
+ export interface TmuxAdapterOptions {
16
+ /** Repository root the sessions run in. */
17
+ workDir: string;
18
+ /** Agent command, e.g. 'claude -p "$PROMPT"'. $PROMPT carries the
19
+ * deliberation prompt; stdout streams into the pane and is harvested via
20
+ * capture-pane. Operator-only configuration (see security notes). */
21
+ command?: string;
22
+ /** Per-agent timeout in ms (default 5 min). */
23
+ timeoutMs?: number;
24
+ /** Session name prefix (default "swarm-dao"). */
25
+ sessionPrefix?: string;
26
+ /** Keep panes alive after harvest for operator inspection (default false). */
27
+ keepSessions?: boolean;
28
+ /** Injectable command runner (tests). */
29
+ runner?: TmuxRunner;
30
+ /** Polling interval for completion markers (default 250ms). */
31
+ pollIntervalMs?: number;
32
+ }
33
+ export declare function createTmuxHostAdapter(options: TmuxAdapterOptions): HostAdapter;
34
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAyB,WAAW,EAAY,MAAM,0BAA0B,CAAC;AAE7F,wFAAwF;AACxF,MAAM,WAAW,UAAU;IACzB,IAAI,CACF,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAC3C,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAClE;AAuBD,+EAA+E;AAC/E,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAGvD;AAED,MAAM,WAAW,kBAAkB;IACjC,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB;;yEAEqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iDAAiD;IACjD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,8EAA8E;IAC9E,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,yCAAyC;IACzC,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,+DAA+D;IAC/D,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAYD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,kBAAkB,GAAG,WAAW,CAoJ9E"}
@@ -0,0 +1,185 @@
1
+ // ============================================================
2
+ // Swarm DAO — tmux Host Adapter
3
+ // ============================================================
4
+ // The swarm-forge execution model for DAO deliberation: each agent runs as
5
+ // its own detached tmux session. Output streams LIVE into the pane (the
6
+ // operator can `tmux attach` and watch an agent think), and is harvested at
7
+ // completion via `tmux capture-pane` — no silent file-only redirection.
8
+ //
9
+ // Security notes:
10
+ // - agent ids are sanitized before touching the filesystem (a hostile id
11
+ // cannot traverse out of .dao/tmux/<proposalId>/) and before naming a
12
+ // session;
13
+ // - `tmux.command` is operator configuration and runs as-is inside the pane
14
+ // shell — the same trust level as package.json scripts. Never point it at
15
+ // untrusted input; the deliberation prompt travels via file ($PROMPT),
16
+ // never through the command line.
17
+ //
18
+ // Boundary: deliberation is read-only analysis. Agents share the repository
19
+ // checkout for context; execution-side isolation stays with the delivery
20
+ // layer's GitWorkspace.
21
+ import { exec as execCallback } from "node:child_process";
22
+ import { promises as fs } from "node:fs";
23
+ import path from "node:path";
24
+ import { promisify } from "node:util";
25
+ const execAsync = promisify(execCallback);
26
+ const defaultRunner = () => ({
27
+ exec: async (command, options) => {
28
+ try {
29
+ const { stdout, stderr } = await execAsync(command, {
30
+ cwd: options?.cwd,
31
+ timeout: options?.timeout,
32
+ });
33
+ return { stdout, stderr, exitCode: 0 };
34
+ }
35
+ catch (error) {
36
+ const failure = error;
37
+ return {
38
+ stdout: failure.stdout ?? "",
39
+ stderr: failure.stderr ?? failure.message ?? "command failed",
40
+ exitCode: Number.isInteger(failure.code) ? failure.code : 1,
41
+ };
42
+ }
43
+ },
44
+ });
45
+ /** tmux session names and run-directory segments accept [a-zA-Z0-9_-] only. */
46
+ export function sanitizeSessionName(raw) {
47
+ const cleaned = raw.replace(/[^a-zA-Z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
48
+ return cleaned.length > 0 ? cleaned : "agent";
49
+ }
50
+ const DEFAULT_TIMEOUT_MS = 5 * 60_000;
51
+ const DEFAULT_POLL_MS = 250;
52
+ /** Cap on capture-pane scrollback (-S is exclusive of the first lines). */
53
+ const CAPTURE_LINES = 100_000;
54
+ export function createTmuxHostAdapter(options) {
55
+ const runner = options.runner ?? defaultRunner();
56
+ const defaultTimeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
57
+ const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_MS;
58
+ const prefix = sanitizeSessionName(options.sessionPrefix ?? "swarm-dao");
59
+ const keepSessions = options.keepSessions === true;
60
+ /** Resolve adapter file access against workDir, contained (like other hosts). */
61
+ const containedPath = (file) => {
62
+ const resolved = path.resolve(options.workDir, file);
63
+ const root = path.resolve(options.workDir);
64
+ if (resolved !== root && !resolved.startsWith(`${root}${path.sep}`)) {
65
+ throw new Error(`path escapes the working directory: ${file}`);
66
+ }
67
+ return resolved;
68
+ };
69
+ const prepare = async (proposal, agent, prompt) => {
70
+ // Sanitize BOTH the session name and the run-directory segment: a
71
+ // hostile agent id ("../../x") can neither name a foreign session nor
72
+ // traverse out of the run directory.
73
+ const safeAgentId = sanitizeSessionName(agent.id);
74
+ const session = `${prefix}-p${proposal.id}-${safeAgentId}`;
75
+ const runDir = path.join(options.workDir, ".dao", "tmux", String(proposal.id), safeAgentId);
76
+ await fs.mkdir(runDir, { recursive: true });
77
+ // Clear stale completion markers so a rerun (e.g. after a crash) cannot
78
+ // harvest the previous attempt's output as this one's.
79
+ await Promise.allSettled(["done"].map((name) => fs.rm(path.join(runDir, name), { force: true })));
80
+ await fs.writeFile(path.join(runDir, "prompt.md"), prompt, "utf8");
81
+ return { session, runDir };
82
+ };
83
+ const startSession = async (run, command) => {
84
+ // Output streams into the pane (live, watchable); the done marker carries
85
+ // the exit code and makes completion observable from the outside. The
86
+ // trailing idle loop keeps the pane (and its scrollback) alive after the
87
+ // program exits — without it the pane dies before the harvest can
88
+ // capture-pane it. keepSessions simply skips the final kill.
89
+ const inner = `PROMPT="$(cat ${quote(path.join(run.runDir, "prompt.md"))})"; ${command}; printf '%s' "$?" > ${quote(path.join(run.runDir, "done"))}; while :; do sleep 3600; done`;
90
+ const sessionProgram = `sh -c ${quote(inner)}`;
91
+ // Clear any stale session with the same name (e.g. a keepSessions
92
+ // leftover) so reruns are deterministic.
93
+ await runner.exec(`tmux kill-session -t ${run.session}`);
94
+ const created = await runner.exec(`tmux new-session -d -s ${run.session} -c ${quote(options.workDir)} ${quote(sessionProgram)}`);
95
+ if (created.exitCode !== 0) {
96
+ throw new Error(`tmux new-session failed: ${created.stderr.trim().slice(0, 300)}`);
97
+ }
98
+ };
99
+ const waitForDone = async (run, timeoutMs) => {
100
+ const deadline = Date.now() + timeoutMs;
101
+ for (;;) {
102
+ try {
103
+ const raw = (await fs.readFile(path.join(run.runDir, "done"), "utf8")).trim();
104
+ const exitCode = Number(raw);
105
+ if (Number.isInteger(exitCode))
106
+ return { exitCode, timedOut: false };
107
+ }
108
+ catch {
109
+ // Not done yet.
110
+ }
111
+ if (Date.now() >= deadline)
112
+ return { exitCode: null, timedOut: true };
113
+ await sleep(pollIntervalMs);
114
+ }
115
+ };
116
+ const harvestPane = async (session) => {
117
+ const captured = await runner.exec(`tmux capture-pane -p -S -${CAPTURE_LINES} -t ${session}`);
118
+ // The last line can be the idle marker loop's shell prompt — trim
119
+ // trailing blank noise but keep the agent's own output verbatim.
120
+ return captured.stdout.replace(/\n+$/, "\n");
121
+ };
122
+ const harvest = async (proposal, agent, prompt, timeoutMs, startedAt) => {
123
+ const base = {
124
+ agentId: agent.id,
125
+ agentName: agent.name,
126
+ role: agent.role,
127
+ content: "",
128
+ durationMs: Date.now() - startedAt,
129
+ };
130
+ if (!options.command || options.command.trim().length === 0) {
131
+ return {
132
+ ...base,
133
+ error: 'tmux.command is not configured: set { "tmux": { "command": "your-agent-cli "$PROMPT"" } } in .dao/config.json ($PROMPT carries the deliberation prompt).',
134
+ };
135
+ }
136
+ const run = await prepare(proposal, agent, prompt);
137
+ try {
138
+ await startSession(run, options.command);
139
+ const { exitCode, timedOut } = await waitForDone(run, timeoutMs);
140
+ if (timedOut) {
141
+ return { ...base, error: `tmux agent ${agent.id} timed out after ${timeoutMs}ms (session ${run.session})` };
142
+ }
143
+ // Capture the pane BEFORE any cleanup kills it.
144
+ const content = await harvestPane(run.session);
145
+ if (exitCode !== 0) {
146
+ return { ...base, content, error: `tmux agent ${agent.id} exited with ${exitCode}` };
147
+ }
148
+ return { ...base, content };
149
+ }
150
+ catch (error) {
151
+ return { ...base, error: error instanceof Error ? error.message : String(error) };
152
+ }
153
+ finally {
154
+ if (!keepSessions) {
155
+ await runner.exec(`tmux kill-session -t ${run.session}`).catch(() => undefined);
156
+ }
157
+ }
158
+ };
159
+ return {
160
+ hostId: "tmux",
161
+ spawnAgent: async ({ agent, proposal, systemPrompt, timeoutMs }) => harvest(proposal, agent, systemPrompt, timeoutMs ?? defaultTimeoutMs, Date.now()),
162
+ spawnAgents: async ({ agents, proposal, maxConcurrent }) => {
163
+ const outputs = [];
164
+ for (let i = 0; i < agents.length; i += Math.max(1, maxConcurrent)) {
165
+ const batch = agents.slice(i, i + Math.max(1, maxConcurrent));
166
+ const startedAt = Date.now();
167
+ const results = await Promise.all(batch.map((agent) => harvest(proposal, agent, agent.systemPrompt, defaultTimeoutMs, startedAt)));
168
+ outputs.push(...results);
169
+ }
170
+ return outputs;
171
+ },
172
+ log: async ({ level, message }) => {
173
+ const line = `[tmux:${level}] ${message}`;
174
+ await fs.appendFile(path.join(options.workDir, ".dao", "tmux.log"), `${line}\n`, "utf8").catch(() => undefined);
175
+ },
176
+ getWorkingDirectory: () => options.workDir,
177
+ readFile: async (file) => fs.readFile(containedPath(file), "utf8"),
178
+ writeFile: async (file, content) => fs.writeFile(containedPath(file), content, "utf8"),
179
+ exec: (command, execOptions) => runner.exec(command, execOptions),
180
+ hasCapability: (capability) => capability === "parallel-spawn",
181
+ };
182
+ }
183
+ const quote = (value) => `'${value.replace(/'/g, `'\\''`)}'`;
184
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
185
+ //# sourceMappingURL=adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export type { TmuxAdapterOptions, TmuxRunner } from "./adapter.js";
2
+ export { createTmuxHostAdapter, sanitizeSessionName } from "./adapter.js";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AACnE,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { createTmuxHostAdapter, sanitizeSessionName } from "./adapter.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC"}
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@guyghost/swarm-dao-tmux-adapter",
3
+ "version": "0.2.0",
4
+ "description": "Swarm DAO tmux host — each deliberation agent runs as its own watchable tmux pane",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "sideEffects": false,
9
+ "files": [
10
+ "dist",
11
+ "README.md"
12
+ ],
13
+ "exports": {
14
+ ".": {
15
+ "types": "./dist/index.d.ts",
16
+ "import": "./dist/index.js"
17
+ }
18
+ },
19
+ "scripts": {
20
+ "build": "tsc",
21
+ "test": "bun test",
22
+ "lint": "biome check .",
23
+ "typecheck": "tsc --noEmit",
24
+ "prepublishOnly": "bun run build"
25
+ },
26
+ "dependencies": {
27
+ "@guyghost/swarm-dao-core": "^0.6.0"
28
+ },
29
+ "devDependencies": {
30
+ "@types/bun": "1.3.14",
31
+ "@types/node": "^26.0.1"
32
+ },
33
+ "keywords": [
34
+ "swarm-dao",
35
+ "tmux",
36
+ "dao",
37
+ "governance",
38
+ "multi-agent",
39
+ "deliberation",
40
+ "ai-agents",
41
+ "swarm-forge"
42
+ ],
43
+ "author": "guyghost",
44
+ "license": "MIT",
45
+ "repository": {
46
+ "type": "git",
47
+ "url": "git+https://github.com/guyghost/swarm-dao.git",
48
+ "directory": "packages/tmux-adapter"
49
+ },
50
+ "bugs": {
51
+ "url": "https://github.com/guyghost/swarm-dao/issues"
52
+ },
53
+ "homepage": "https://github.com/guyghost/swarm-dao#readme",
54
+ "publishConfig": {
55
+ "access": "public"
56
+ }
57
+ }