orchestra-agents 1.0.0 → 1.0.1
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 +49 -0
- package/orchestra-max.mjs +26 -4
- package/orchestra.mjs +3 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,11 +1,24 @@
|
|
|
1
1
|
# Orchestra
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/orchestra-agents)
|
|
4
|
+
[](./LICENSE)
|
|
5
|
+
[](https://nodejs.org)
|
|
6
|
+
|
|
3
7
|
A multi-agent system in one file. One conductor agent takes your goal, breaks it into independent tasks, fans out specialist sub-agents in parallel (scouts, analysts, writers), sends adversarial critics to attack their work, then synthesizes everything into one final deliverable.
|
|
4
8
|
|
|
9
|
+
**Runs on your Claude subscription. No API credits required.**
|
|
10
|
+
|
|
5
11
|
Built on the Claude API (`@anthropic-ai/sdk`). No framework. This is the "main agent talks to a bunch of sub-agents" pattern, owned end to end in plain JavaScript you can read in one sitting.
|
|
6
12
|
|
|
7
13
|
## Install
|
|
8
14
|
|
|
15
|
+
```
|
|
16
|
+
npm install -g orchestra-agents
|
|
17
|
+
orchestra "your goal here"
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Or clone it and read the source (it's three small files):
|
|
21
|
+
|
|
9
22
|
```
|
|
10
23
|
git clone https://github.com/vyn-store/orchestra-agents.git
|
|
11
24
|
cd orchestra-agents
|
|
@@ -31,6 +44,42 @@ node orchestra.mjs "quick test" --cheap # haiku everywhere, costs pennies
|
|
|
31
44
|
| `--worker M` | sub-agent model (default: same as --model) |
|
|
32
45
|
| `--no-critics` | skip the adversarial pass |
|
|
33
46
|
|
|
47
|
+
## What a run looks like
|
|
48
|
+
|
|
49
|
+
A real run, on a Claude subscription, costing nothing in API credits:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
$ orchestra-max "name 3 colours that work well together" --agents 2 --cheap
|
|
53
|
+
|
|
54
|
+
ORCHESTRA MAX subscription-powered · conductor=haiku workers=haiku max-agents=2
|
|
55
|
+
[goal] name 3 colours that work well together
|
|
56
|
+
[conductor] planning...
|
|
57
|
+
[conductor] strategy: Decompose into research, evaluation, and presentation tasks to
|
|
58
|
+
identify three visually distinct, complementary colors.
|
|
59
|
+
[conductor] casting 2 sub-agents
|
|
60
|
+
[agent 1] scout: Research popular, distinct colors
|
|
61
|
+
[agent 2] analyst: Evaluate color harmony and contrast
|
|
62
|
+
[agent 1] Research popular, distinct colors done
|
|
63
|
+
[agent 2] Evaluate color harmony and contrast done
|
|
64
|
+
[critic 1] score 8/10
|
|
65
|
+
[critic 2] score 7/10
|
|
66
|
+
[conductor] synthesizing final deliverable...
|
|
67
|
+
|
|
68
|
+
------------------------------------------------------------
|
|
69
|
+
### 1. Navy Blue + Warm Gold + Cream White
|
|
70
|
+
Why it works: complementary pair (navy and gold sit opposite on the colour wheel).
|
|
71
|
+
High contrast but sophisticated, the cream softens the intensity.
|
|
72
|
+
...
|
|
73
|
+
------------------------------------------------------------
|
|
74
|
+
|
|
75
|
+
DONE 6 agent calls · 283,593 in / 7,582 out tokens
|
|
76
|
+
$0.00 API credits (nominal value $0.27, covered by your subscription)
|
|
77
|
+
saved: runs/2026-07-13T14-16-35_name-3-colours-that-work-well-together.md
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Both agents ran at the same time, not one after the other. Swap the goal for something
|
|
81
|
+
real ("research what my competitors charge and write my pricing page") and cast more agents.
|
|
82
|
+
|
|
34
83
|
## How it works (the 4 phases)
|
|
35
84
|
|
|
36
85
|
1. **PLAN**: the conductor gets the goal and returns a structured JSON plan (enforced by the API's structured outputs, so it can never come back malformed): a strategy plus one self-contained prompt per sub-agent.
|
package/orchestra-max.mjs
CHANGED
|
@@ -20,14 +20,34 @@
|
|
|
20
20
|
// (an ANTHROPIC_API_KEY in the environment is deliberately stripped so runs
|
|
21
21
|
// can never silently bill your credit balance).
|
|
22
22
|
|
|
23
|
-
import {
|
|
23
|
+
import { spawn } from "node:child_process";
|
|
24
24
|
import fs from "node:fs";
|
|
25
25
|
import path from "node:path";
|
|
26
|
-
import { promisify } from "node:util";
|
|
27
26
|
import { fileURLToPath } from "node:url";
|
|
28
27
|
import { ROLES } from "./roles.mjs";
|
|
29
28
|
|
|
30
|
-
|
|
29
|
+
// Spawn with stdin closed. `claude -p` waits ~3s for piped stdin and warns if it
|
|
30
|
+
// never arrives, which stalls (and can fail) every agent when Orchestra runs
|
|
31
|
+
// without a TTY: cron, CI, or with its output piped anywhere.
|
|
32
|
+
function run(cmd, args, { cwd, env, maxBuffer = 32 * 1024 * 1024, timeout = 15 * 60 * 1000 } = {}) {
|
|
33
|
+
return new Promise((resolve, reject) => {
|
|
34
|
+
const child = spawn(cmd, args, { cwd, env, stdio: ["ignore", "pipe", "pipe"] });
|
|
35
|
+
let stdout = "", stderr = "", settled = false;
|
|
36
|
+
const finish = (fn, arg) => { if (!settled) { settled = true; clearTimeout(timer); fn(arg); } };
|
|
37
|
+
const timer = setTimeout(() => { child.kill("SIGKILL"); finish(reject, Object.assign(new Error(`timed out after ${timeout}ms`), { stdout, stderr })); }, timeout);
|
|
38
|
+
|
|
39
|
+
child.stdout.on("data", (d) => {
|
|
40
|
+
stdout += d;
|
|
41
|
+
if (stdout.length > maxBuffer) { child.kill("SIGKILL"); finish(reject, Object.assign(new Error("stdout exceeded maxBuffer"), { stdout, stderr })); }
|
|
42
|
+
});
|
|
43
|
+
child.stderr.on("data", (d) => { stderr += d; });
|
|
44
|
+
child.on("error", (e) => finish(reject, Object.assign(e, { stdout, stderr })));
|
|
45
|
+
child.on("close", (code) => {
|
|
46
|
+
if (code === 0) finish(resolve, { stdout, stderr });
|
|
47
|
+
else finish(reject, Object.assign(new Error(`${cmd} exited with code ${code}`), { stdout, stderr }));
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
}
|
|
31
51
|
const DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
32
52
|
const AGENT_HOME = path.join(DIR, "agent-home"); // empty cwd so agents don't inherit a project CLAUDE.md
|
|
33
53
|
fs.mkdirSync(AGENT_HOME, { recursive: true });
|
|
@@ -173,7 +193,9 @@ log("green", "conductor", `casting ${p.tasks.length} sub-agents`);
|
|
|
173
193
|
|
|
174
194
|
const slug = GOAL.toLowerCase().replace(/[^a-z0-9]+/g, "-").slice(0, 50).replace(/^-|-$/g, "");
|
|
175
195
|
const stamp = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
176
|
-
const
|
|
196
|
+
const RUNS_DIR = path.join(DIR, "runs");
|
|
197
|
+
fs.mkdirSync(RUNS_DIR, { recursive: true }); // not shipped in the package: a fresh install has no runs/
|
|
198
|
+
const runFile = path.join(RUNS_DIR, `${stamp}_${slug}.md`);
|
|
177
199
|
let ok = [];
|
|
178
200
|
let final = null;
|
|
179
201
|
let runError = null;
|
package/orchestra.mjs
CHANGED
|
@@ -228,7 +228,9 @@ log("green", "conductor", `casting ${p.tasks.length} sub-agents`);
|
|
|
228
228
|
// (rate limit, empty credit balance, network drop) never loses paid-for work.
|
|
229
229
|
const slug = GOAL.toLowerCase().replace(/[^a-z0-9]+/g, "-").slice(0, 50).replace(/^-|-$/g, "");
|
|
230
230
|
const stamp = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
231
|
-
const
|
|
231
|
+
const RUNS_DIR = path.join(DIR, "runs");
|
|
232
|
+
fs.mkdirSync(RUNS_DIR, { recursive: true }); // not shipped in the package: a fresh install has no runs/
|
|
233
|
+
const runFile = path.join(RUNS_DIR, `${stamp}_${slug}.md`);
|
|
232
234
|
let ok = [];
|
|
233
235
|
let final = null;
|
|
234
236
|
let runError = null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "orchestra-agents",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Multi-agent orchestrator on the Claude API: one conductor plans, sub-agents execute in parallel, adversarial critics attack, the conductor synthesizes one deliverable.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|