fellow-agents 0.0.5 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +100 -44
- package/dist/cli.js +8 -9
- package/dist/commands/start.js +8 -1
- package/dist/lib/download.js +10 -1
- package/dist/lib/services.js +25 -8
- package/dist/shims/emcom-server.js +3 -0
- package/dist/shims/emcom.js +3 -0
- package/dist/shims/pty-cld.js +18 -0
- package/dist/shims/pty-win.js +16 -0
- package/dist/shims/run-binary.js +19 -0
- package/dist/shims/tracker.js +3 -0
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -1,76 +1,132 @@
|
|
|
1
1
|
# fellow-agents
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Run a team of Claude Code agents that talk to each other.**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
One command gives you a coordinator, a coder, and a reviewer — each in their own terminal, communicating through async messaging, managed from a single browser UI.
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
npm install -g fellow-agents
|
|
9
|
-
|
|
9
|
+
mkdir my-team && cd my-team
|
|
10
|
+
fellow-agents
|
|
10
11
|
```
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
That's it. Creates a workspace, downloads what it needs, opens your browser — three agents ready to collaborate.
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
---
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
## What happens when you run it
|
|
18
|
+
|
|
19
|
+
1. Downloads platform binaries (first run only, ~30 seconds)
|
|
20
|
+
2. Starts the messaging server (emcom)
|
|
21
|
+
3. Registers three agents: **coordinator**, **coder**, **reviewer**
|
|
22
|
+
4. Launches the browser UI (pty-win) on `http://localhost:3700`
|
|
23
|
+
|
|
24
|
+
Each agent is a Claude Code session with its own workspace, personality, and tools. They message each other through emcom — no shared context window, no token limits, real async collaboration.
|
|
25
|
+
|
|
26
|
+
## Try it
|
|
27
|
+
|
|
28
|
+
1. Click **coordinator** in the browser UI (hit play)
|
|
29
|
+
2. Tell it: *"Have the coder write a fibonacci function and the reviewer check it for edge cases."*
|
|
30
|
+
3. Watch the agents coordinate — messages flow in the feed panel on the right
|
|
31
|
+
|
|
32
|
+
The coordinator breaks down the task, sends it to the coder via emcom, the coder writes the code and sends it to the reviewer, the reviewer sends feedback back. All visible in real time.
|
|
33
|
+
|
|
34
|
+
## How it works
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
fellow-agents start
|
|
38
|
+
|
|
|
39
|
+
v
|
|
40
|
+
+-----------+ emcom messages +-----------+
|
|
41
|
+
| coordinator| <------------------> | coder |
|
|
42
|
+
+-----------+ +-----------+
|
|
43
|
+
^ |
|
|
44
|
+
| emcom messages |
|
|
45
|
+
+---------------------------------- +
|
|
46
|
+
| v
|
|
47
|
+
+-----------+ +-----------+
|
|
48
|
+
| pty-win | browser UI on :3700 | reviewer |
|
|
49
|
+
+-----------+ +-----------+
|
|
50
|
+
|
|
|
51
|
+
emcom-server on :8800
|
|
21
52
|
```
|
|
22
53
|
|
|
54
|
+
**pty-win** is the browser-based terminal multiplexer — every agent session in one tab. **emcom** is the messaging layer — agents send, receive, and reply to each other asynchronously. Each agent has a `CLAUDE.md` defining its role and an `identity.json` for messaging.
|
|
55
|
+
|
|
23
56
|
## Prerequisites
|
|
24
57
|
|
|
25
|
-
-
|
|
26
|
-
-
|
|
58
|
+
- **Node.js 18+** — [nodejs.org](https://nodejs.org/)
|
|
59
|
+
- **Claude Code** — [claude.ai/code](https://claude.ai/code) (needed to run agent sessions)
|
|
27
60
|
|
|
28
|
-
##
|
|
61
|
+
## Options
|
|
29
62
|
|
|
30
63
|
```bash
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
64
|
+
fellow-agents # start (default command)
|
|
65
|
+
fellow-agents --port 4000 # custom pty-win port
|
|
66
|
+
fellow-agents --emcom-port 9000 # custom messaging port
|
|
67
|
+
fellow-agents --no-browser # headless (server/CI)
|
|
68
|
+
fellow-agents --update # force re-download binaries
|
|
69
|
+
fellow-agents stop # stop all services
|
|
35
70
|
```
|
|
36
71
|
|
|
37
|
-
##
|
|
72
|
+
## Add your own agent
|
|
38
73
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
74
|
+
```bash
|
|
75
|
+
mkdir workspaces/designer
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Create `CLAUDE.md` (the agent's system prompt) and `identity.json` (name + description for messaging):
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"name": "designer",
|
|
83
|
+
"description": "UI/UX designer — creates interfaces and reviews layouts",
|
|
84
|
+
"server": "http://127.0.0.1:8800"
|
|
85
|
+
}
|
|
86
|
+
```
|
|
42
87
|
|
|
43
|
-
|
|
88
|
+
```bash
|
|
89
|
+
emcom --identity workspaces/designer/identity.json register
|
|
90
|
+
```
|
|
44
91
|
|
|
45
|
-
|
|
46
|
-
|-----------|---------|
|
|
47
|
-
| **pty-win** | Browser terminal multiplexer — manage all agent sessions |
|
|
48
|
-
| **emcom** | Async messaging between agents |
|
|
49
|
-
| **templates/** | 3 starter agents: coordinator, coder, reviewer |
|
|
92
|
+
Restart pty-win and the new agent appears in the UI.
|
|
50
93
|
|
|
51
|
-
##
|
|
94
|
+
## Alternative install: git clone
|
|
52
95
|
|
|
53
96
|
```bash
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
97
|
+
git clone https://github.com/rajan-chari/fellow-agents.git
|
|
98
|
+
cd fellow-agents
|
|
99
|
+
./setup.sh # Mac/Linux
|
|
100
|
+
pwsh ./setup.ps1 # Windows (PowerShell 7+)
|
|
57
101
|
```
|
|
58
102
|
|
|
59
|
-
|
|
103
|
+
Same result, more control. Useful for development or Docker.
|
|
104
|
+
|
|
105
|
+
## File layout
|
|
60
106
|
|
|
61
107
|
```
|
|
62
|
-
~/.fellow-agents/
|
|
63
|
-
bin/{platform}/
|
|
64
|
-
pty-win/
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
./workspaces/
|
|
69
|
-
coordinator/
|
|
70
|
-
coder/
|
|
71
|
-
reviewer/
|
|
108
|
+
~/.fellow-agents/ # Auto-created data directory
|
|
109
|
+
bin/{platform}/ # emcom, tracker, emcom-server
|
|
110
|
+
pty-win/ # Terminal multiplexer
|
|
111
|
+
logs/ # Service logs (check here if something fails)
|
|
112
|
+
pid/ # PID files
|
|
113
|
+
|
|
114
|
+
./workspaces/ # Scaffolded from templates on first run
|
|
115
|
+
coordinator/CLAUDE.md # "Break tasks down, delegate to coder/reviewer"
|
|
116
|
+
coder/CLAUDE.md # "Write code, send to reviewer for feedback"
|
|
117
|
+
reviewer/CLAUDE.md # "Review code, report issues back"
|
|
72
118
|
```
|
|
73
119
|
|
|
74
|
-
##
|
|
120
|
+
## Troubleshooting
|
|
121
|
+
|
|
122
|
+
**Services won't start?** Check `~/.fellow-agents/logs/emcom-server.log` and `pty-win.log`.
|
|
123
|
+
|
|
124
|
+
**Port already in use?** Use `--port` and `--emcom-port` to pick different ports.
|
|
125
|
+
|
|
126
|
+
**Browser didn't open?** Navigate to `http://localhost:3700` manually.
|
|
127
|
+
|
|
128
|
+
**Want to start fresh?** `rm -rf ~/.fellow-agents` and run `fellow-agents start` again.
|
|
129
|
+
|
|
130
|
+
## License
|
|
75
131
|
|
|
76
|
-
|
|
132
|
+
MIT
|
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
const args = process.argv.slice(2);
|
|
3
|
-
|
|
3
|
+
// Default to "start" if no command given or first arg is a flag
|
|
4
|
+
const command = args[0] === "stop" ? "stop"
|
|
5
|
+
: (args[0] === "--help" || args[0] === "-h") ? "help"
|
|
6
|
+
: "start";
|
|
4
7
|
function getFlag(name, fallback) {
|
|
5
8
|
const idx = args.indexOf(name);
|
|
6
9
|
return idx !== -1 && args[idx + 1] ? args[idx + 1] : fallback;
|
|
@@ -22,14 +25,14 @@ else if (command === "stop") {
|
|
|
22
25
|
const { stop } = await import("./commands/stop.js");
|
|
23
26
|
stop();
|
|
24
27
|
}
|
|
25
|
-
else
|
|
28
|
+
else {
|
|
26
29
|
console.log(`fellow-agents — multi-agent system for Claude Code
|
|
27
30
|
|
|
28
31
|
Usage:
|
|
29
|
-
fellow-agents
|
|
30
|
-
fellow-agents stop
|
|
32
|
+
fellow-agents [options] Start services (default)
|
|
33
|
+
fellow-agents stop Stop all running services
|
|
31
34
|
|
|
32
|
-
Options
|
|
35
|
+
Options:
|
|
33
36
|
--port <number> pty-win port (default: 3700)
|
|
34
37
|
--emcom-port <number> emcom-server port (default: 8800)
|
|
35
38
|
--dir <path> Working directory (default: current)
|
|
@@ -38,8 +41,4 @@ Options (start):
|
|
|
38
41
|
|
|
39
42
|
-h, --help Show this help`);
|
|
40
43
|
}
|
|
41
|
-
else {
|
|
42
|
-
console.error(`Unknown command: ${command}. Run 'fellow-agents --help' for usage.`);
|
|
43
|
-
process.exit(1);
|
|
44
|
-
}
|
|
45
44
|
export {};
|
package/dist/commands/start.js
CHANGED
|
@@ -12,7 +12,14 @@ export async function start(opts) {
|
|
|
12
12
|
console.log(" fellow-agents");
|
|
13
13
|
console.log(" =============");
|
|
14
14
|
console.log("");
|
|
15
|
-
|
|
15
|
+
// Auto-create fellow-agents/ subdirectory if CWD doesn't already have workspaces/
|
|
16
|
+
let workDir = resolve(opts.dir);
|
|
17
|
+
if (!existsSync(join(workDir, "workspaces"))) {
|
|
18
|
+
workDir = join(workDir, "fellow-agents");
|
|
19
|
+
const { mkdirSync } = await import("fs");
|
|
20
|
+
mkdirSync(workDir, { recursive: true });
|
|
21
|
+
console.log(` Working directory: ${workDir}`);
|
|
22
|
+
}
|
|
16
23
|
const workspacesDir = join(workDir, "workspaces");
|
|
17
24
|
const emcomUrl = `http://127.0.0.1:${opts.emcomPort}`;
|
|
18
25
|
// 1. Prerequisites
|
package/dist/lib/download.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { get } from "https";
|
|
2
|
-
import { createWriteStream, mkdirSync, readFileSync, writeFileSync, existsSync, rmSync } from "fs";
|
|
2
|
+
import { createWriteStream, mkdirSync, readFileSync, writeFileSync, existsSync, rmSync, chmodSync, readdirSync } from "fs";
|
|
3
3
|
import { join, dirname } from "path";
|
|
4
4
|
import { execSync } from "child_process";
|
|
5
5
|
import { dataDir, binDir, ptyWinDir, versionFile } from "./paths.js";
|
|
@@ -57,6 +57,15 @@ export async function downloadBinaries(force = false) {
|
|
|
57
57
|
mkdirSync(binDir, { recursive: true });
|
|
58
58
|
extractZip(dest, dataDir);
|
|
59
59
|
rmSync(dest);
|
|
60
|
+
// chmod +x on Linux/Mac
|
|
61
|
+
if (process.platform !== "win32") {
|
|
62
|
+
for (const f of readdirSync(binDir)) {
|
|
63
|
+
try {
|
|
64
|
+
chmodSync(join(binDir, f), 0o755);
|
|
65
|
+
}
|
|
66
|
+
catch { }
|
|
67
|
+
}
|
|
68
|
+
}
|
|
60
69
|
}
|
|
61
70
|
else if (asset.name.includes("pty-win")) {
|
|
62
71
|
console.log(` Downloading ${asset.name}...`);
|
package/dist/lib/services.js
CHANGED
|
@@ -39,15 +39,32 @@ function isRunning(pid) {
|
|
|
39
39
|
}
|
|
40
40
|
export function startEmcomServer(emcomPort, env) {
|
|
41
41
|
const bin = join(binDir, `emcom-server${binarySuffix()}`);
|
|
42
|
+
if (!existsSync(bin)) {
|
|
43
|
+
console.error(` emcom-server not found at ${bin}`);
|
|
44
|
+
return -1;
|
|
45
|
+
}
|
|
42
46
|
const log = openLog("emcom-server");
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
try {
|
|
48
|
+
const proc = spawn(bin, ["--port", String(emcomPort)], {
|
|
49
|
+
env: { ...env, EMCOM_PORT: String(emcomPort) },
|
|
50
|
+
detached: true,
|
|
51
|
+
stdio: ["ignore", log, log],
|
|
52
|
+
});
|
|
53
|
+
proc.on("error", (err) => {
|
|
54
|
+
if (err.code === "EACCES") {
|
|
55
|
+
console.error(` Permission denied: ${bin}`);
|
|
56
|
+
console.error(` Fix: chmod +x "${bin}"`);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
proc.unref();
|
|
60
|
+
writePid("emcom-server", proc.pid);
|
|
61
|
+
return proc.pid;
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
console.error(` Failed to start emcom-server: ${err.message}`);
|
|
65
|
+
console.error(` Check permissions on ${binDir}`);
|
|
66
|
+
return -1;
|
|
67
|
+
}
|
|
51
68
|
}
|
|
52
69
|
export function startPtyWin(port, workspacesDir, emcomUrl, env) {
|
|
53
70
|
const main = join(ptyWinDir, "dist", "index.js");
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { execFileSync } from "child_process";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { existsSync } from "fs";
|
|
5
|
+
// pty-cld lives alongside pty-win in the data directory
|
|
6
|
+
import { dataDir } from "../lib/paths.js";
|
|
7
|
+
const ptyCldDir = join(dataDir, "pty-cld");
|
|
8
|
+
const main = join(ptyCldDir, "dist", "index.js");
|
|
9
|
+
if (!existsSync(main)) {
|
|
10
|
+
console.error("pty-cld not found. Run 'fellow-agents' first to download binaries.");
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
execFileSync("node", [main, ...process.argv.slice(2)], { stdio: "inherit" });
|
|
15
|
+
}
|
|
16
|
+
catch (err) {
|
|
17
|
+
process.exit(err.status ?? 1);
|
|
18
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { execFileSync } from "child_process";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { existsSync } from "fs";
|
|
5
|
+
import { ptyWinDir } from "../lib/paths.js";
|
|
6
|
+
const main = join(ptyWinDir, "dist", "index.js");
|
|
7
|
+
if (!existsSync(main)) {
|
|
8
|
+
console.error("pty-win not found. Run 'fellow-agents' first to download binaries.");
|
|
9
|
+
process.exit(1);
|
|
10
|
+
}
|
|
11
|
+
try {
|
|
12
|
+
execFileSync("node", [main, ...process.argv.slice(2)], { stdio: "inherit" });
|
|
13
|
+
}
|
|
14
|
+
catch (err) {
|
|
15
|
+
process.exit(err.status ?? 1);
|
|
16
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { execFileSync } from "child_process";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { existsSync } from "fs";
|
|
5
|
+
import { binDir } from "../lib/paths.js";
|
|
6
|
+
import { binarySuffix } from "../lib/platform.js";
|
|
7
|
+
export function runBinary(name) {
|
|
8
|
+
const bin = join(binDir, `${name}${binarySuffix()}`);
|
|
9
|
+
if (!existsSync(bin)) {
|
|
10
|
+
console.error(`${name} not found. Run 'fellow-agents' first to download binaries.`);
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
execFileSync(bin, process.argv.slice(2), { stdio: "inherit" });
|
|
15
|
+
}
|
|
16
|
+
catch (err) {
|
|
17
|
+
process.exit(err.status ?? 1);
|
|
18
|
+
}
|
|
19
|
+
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fellow-agents",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "Multi-agent system — multiple Claude Code instances collaborating via messaging",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"fellow-agents": "dist/cli.js"
|
|
7
|
+
"fellow-agents": "dist/cli.js",
|
|
8
|
+
"emcom": "dist/shims/emcom.js",
|
|
9
|
+
"emcom-server": "dist/shims/emcom-server.js",
|
|
10
|
+
"tracker": "dist/shims/tracker.js",
|
|
11
|
+
"pty-win": "dist/shims/pty-win.js",
|
|
12
|
+
"pty-cld": "dist/shims/pty-cld.js"
|
|
8
13
|
},
|
|
9
14
|
"files": [
|
|
10
15
|
"dist/",
|