trantor 0.16.0 → 0.17.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/.claude-plugin/marketplace.json +7 -7
- package/.claude-plugin/plugin.json +3 -3
- package/README.md +30 -6
- package/bin/cli.mjs +1 -1
- package/bin/connect.mjs +6 -6
- package/bin/crew-runner.mjs +3 -3
- package/bin/crew.sh +2 -2
- package/bin/doctor.mjs +1 -1
- package/bin/handoff-prompt.sh +3 -3
- package/bin/profile.mjs +1 -1
- package/bin/statusline.mjs +5 -5
- package/configs/gemini-settings.json +2 -2
- package/deploy/setup.sh +2 -1
- package/hooks/hooks.json +1 -1
- package/hooks/precompact.mjs +5 -5
- package/hooks/sessionstart.mjs +9 -9
- package/hub.mjs +3 -3
- package/mcp.mjs +3 -3
- package/package.json +3 -3
- package/skills/crew/SKILL.md +8 -7
- package/skills/{relay-handoff → handoff}/SKILL.md +2 -2
- package/ui.html +1 -1
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "
|
|
2
|
+
"name": "trantor",
|
|
3
3
|
"owner": { "name": "Sasha Bogojevic", "email": "hello@hivedigitalllc.com" },
|
|
4
4
|
"metadata": {
|
|
5
|
-
"description": "
|
|
6
|
-
"version": "0.
|
|
5
|
+
"description": "Trantor — the hub-world for AI agent crews: live message bus, presence, project Kanban/flow board + context-handoff for independent AI coding agents (Claude, Codex, Gemini, …)",
|
|
6
|
+
"version": "0.17.0"
|
|
7
7
|
},
|
|
8
8
|
"plugins": [
|
|
9
9
|
{
|
|
10
|
-
"name": "
|
|
10
|
+
"name": "trantor",
|
|
11
11
|
"source": "./",
|
|
12
|
-
"description": "
|
|
13
|
-
"version": "0.
|
|
12
|
+
"description": "The hub-world for AI agent crews. Say \"fire up the crew\" and Claude becomes the architect: a plan-aware Advisor routes the work (solo / cheap inline calls / live crew of Codex, Gemini, Kimi & DeepSeek in their own terminal windows), a Kanban/flow command center with a testing gate tracks it, and an economics brain (Scrooge) keeps the receipts. Includes the relay MCP, a SessionStart auto-discovery hook, and a PreCompact context-handoff so a fresh session can take over a full window instead of compacting.",
|
|
13
|
+
"version": "0.17.0",
|
|
14
14
|
"author": { "name": "Sasha Bogojevic" },
|
|
15
15
|
"category": "development",
|
|
16
|
-
"keywords": ["multi-agent", "coordination", "mcp", "hooks", "kanban", "context-handoff", "message-bus", "claude-code", "codex", "gemini"]
|
|
16
|
+
"keywords": ["multi-agent", "agent-crew", "orchestration", "coordination", "mcp", "hooks", "kanban", "context-handoff", "message-bus", "claude-code", "codex", "gemini", "llm-routing"]
|
|
17
17
|
}
|
|
18
18
|
]
|
|
19
19
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
2
|
+
"name": "trantor",
|
|
3
|
+
"version": "0.17.0",
|
|
4
|
+
"description": "Trantor — the hub-world for AI agent crews: live message bus, presence, project Kanban/flow board + crew orchestration for independent AI coding agents (Claude, Codex, Gemini, Kimi, DeepSeek)",
|
|
5
5
|
"mcpServers": {
|
|
6
6
|
"relay": {
|
|
7
7
|
"command": "node",
|
package/README.md
CHANGED
|
@@ -35,7 +35,7 @@ Then give Claude Code (the orchestrator) the plugin:
|
|
|
35
35
|
|
|
36
36
|
```bash
|
|
37
37
|
claude plugin marketplace add sashabogi/trantor
|
|
38
|
-
claude plugin install
|
|
38
|
+
claude plugin install trantor
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
That's it. (Prefer source? `git clone https://github.com/sashabogi/trantor && cd trantor &&
|
|
@@ -53,7 +53,7 @@ core
|
|
|
53
53
|
✓ hub up at http://127.0.0.1:4477
|
|
54
54
|
claude (the orchestrator)
|
|
55
55
|
✗ plugin not installed
|
|
56
|
-
→ claude plugin marketplace add sashabogi/trantor && claude plugin install
|
|
56
|
+
→ claude plugin marketplace add sashabogi/trantor && claude plugin install trantor
|
|
57
57
|
crew CLIs (install any subset — seats follow the work)
|
|
58
58
|
✓ codex: wired to the bus
|
|
59
59
|
✗ codex: NOT authenticated — it will join the bus but fail on its first turn
|
|
@@ -63,12 +63,34 @@ the brain
|
|
|
63
63
|
✗ quota profile not set → trantor profile set claude=max codex=plus deepseek=api
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
-
Fix the `→` lines (each CLI's own sign-in happens once, in that CLI)
|
|
67
|
-
until it's clean
|
|
66
|
+
Fix the `→` lines (each CLI's own sign-in happens once, in that CLI) and re-run `trantor doctor`
|
|
67
|
+
until it's clean.
|
|
68
68
|
|
|
69
69
|
Provider API keys (e.g. `DEEPSEEK_API_KEY`) live in one file: **`~/.agent-bus/.env`** — the
|
|
70
70
|
crew runners source it automatically.
|
|
71
71
|
|
|
72
|
+
## Your first build
|
|
73
|
+
|
|
74
|
+
Open Claude Code in the project you want built and say it in plain words:
|
|
75
|
+
|
|
76
|
+
> **fire up the crew** — build me a 2-player asteroids game with power-ups
|
|
77
|
+
|
|
78
|
+
Any phrasing works ("build it with the crew", "build this with trantor"), or invoke the
|
|
79
|
+
skill directly: **`/trantor:crew`**. Claude becomes the architect: it cuts the work into
|
|
80
|
+
difficulty-tagged packages, asks the Advisor, and shows you the routing table with a
|
|
81
|
+
real-money estimate **before spending anything**. You say go — terminal windows open, the
|
|
82
|
+
board fills, and you watch it live:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
trantor ui
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
No crew CLIs installed yet? It still works — the Advisor routes the work `solo` or to cheap
|
|
89
|
+
inline `scrooge` calls instead of seats. Seats follow the work *and* what's actually installed.
|
|
90
|
+
|
|
91
|
+
Running low on context mid-build? Say **`/trantor:handoff`** — a fresh session in the same
|
|
92
|
+
project takes over with a full window (and a PreCompact hook does this automatically).
|
|
93
|
+
|
|
72
94
|
## What happens when you fire up a crew
|
|
73
95
|
|
|
74
96
|
1. **The Advisor moment.** Your Claude cuts the work into difficulty-tagged packages, calls
|
|
@@ -183,8 +205,10 @@ Identity: `RELAY_SESSION` → `RELAY_AGENT:<project-folder>` → `<hostname>:<pr
|
|
|
183
205
|
always-on/remote hub (private tailnet, or public with auth) is on the roadmap — never expose
|
|
184
206
|
the hub publicly without auth.
|
|
185
207
|
|
|
186
|
-
*Heritage note: Trantor grew out of **agent-bus
|
|
187
|
-
`agent-bus
|
|
208
|
+
*Heritage note: Trantor grew out of **agent-bus**. As of v0.17 the plugin and skills are
|
|
209
|
+
named `trantor` (formerly `agent-bus` — if you installed before v0.17:
|
|
210
|
+
`claude plugin uninstall agent-bus && claude plugin marketplace update && claude plugin install trantor`).
|
|
211
|
+
The `relay_*` tool names and the `~/.agent-bus` state dir remain until a later release.*
|
|
188
212
|
|
|
189
213
|
## Honest limits
|
|
190
214
|
|
package/bin/cli.mjs
CHANGED
|
@@ -48,6 +48,6 @@ switch (cmd) {
|
|
|
48
48
|
trantor watch live bus feed in the terminal
|
|
49
49
|
|
|
50
50
|
Claude Code plugin (the orchestrator side):
|
|
51
|
-
claude plugin marketplace add sashabogi/trantor && claude plugin install
|
|
51
|
+
claude plugin marketplace add sashabogi/trantor && claude plugin install trantor
|
|
52
52
|
Docs: https://github.com/sashabogi/trantor`);
|
|
53
53
|
}
|
package/bin/connect.mjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
//
|
|
2
|
+
// trantor connect — wire every AI coding CLI on this machine to the bus, in one shot.
|
|
3
3
|
//
|
|
4
4
|
// node bin/connect.mjs # detect installed CLIs, patch each one's MCP config (idempotent)
|
|
5
5
|
// node bin/connect.mjs --dry-run # show what would change, touch nothing
|
|
6
6
|
//
|
|
7
7
|
// Each CLI keeps its own MCP config file/format; this writes the one "relay" entry into each
|
|
8
8
|
// (with a timestamped .bak backup the first time it changes a file). Claude Code is handled by
|
|
9
|
-
// the plugin (claude plugin install
|
|
9
|
+
// the plugin (claude plugin install trantor), so it's only verified here, not patched.
|
|
10
10
|
import { readFileSync, writeFileSync, existsSync, mkdirSync, copyFileSync } from "node:fs";
|
|
11
11
|
import { join, dirname } from "node:path";
|
|
12
12
|
import { homedir } from "node:os";
|
|
@@ -39,10 +39,10 @@ const relayEnv = (agent) => ({ RELAY_URL: URL_, RELAY_AGENT: agent });
|
|
|
39
39
|
|
|
40
40
|
// ---- Claude Code: plugin handles it; verify only ----
|
|
41
41
|
if (has("claude")) {
|
|
42
|
-
let st = "plugin not detected — run: claude plugin marketplace add sashabogi/trantor && claude plugin install
|
|
42
|
+
let st = "plugin not detected — run: claude plugin marketplace add sashabogi/trantor && claude plugin install trantor";
|
|
43
43
|
try {
|
|
44
44
|
const s = JSON.parse(readFileSync(join(homedir(), ".claude", "settings.json"), "utf8"));
|
|
45
|
-
if (Object.keys(s.enabledPlugins || {}).some(k => k.startsWith("agent-bus@"))) st = "plugin installed ✓";
|
|
45
|
+
if (Object.keys(s.enabledPlugins || {}).some(k => k.startsWith("trantor@") || k.startsWith("agent-bus@"))) st = "plugin installed ✓";
|
|
46
46
|
} catch {}
|
|
47
47
|
report("claude", st);
|
|
48
48
|
}
|
|
@@ -53,7 +53,7 @@ if (has("codex")) {
|
|
|
53
53
|
const cur = existsSync(p) ? readFileSync(p, "utf8") : "";
|
|
54
54
|
if (cur.includes("[mcp_servers.relay]")) report("codex", "already wired");
|
|
55
55
|
else {
|
|
56
|
-
const block = `\n#
|
|
56
|
+
const block = `\n# trantor — auto-registers each Codex session on the bus + adds relay_* tools\n[mcp_servers.relay]\ncommand = "node"\nargs = ["${MCP}"]\nenv = { RELAY_URL = "${URL_}", RELAY_AGENT = "codex" }\n`;
|
|
57
57
|
if (!DRY) { if (existsSync(p)) backup(p); else mkdirSync(dirname(p), { recursive: true }); writeFileSync(p, cur + block); }
|
|
58
58
|
report("codex", cur ? "wired" : "wired (new config)", p);
|
|
59
59
|
}
|
|
@@ -88,7 +88,7 @@ if (has("opencode")) {
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
const found = out.length;
|
|
91
|
-
console.log(`
|
|
91
|
+
console.log(`trantor connect${DRY ? " (dry run)" : ""} — hub: ${URL_}`);
|
|
92
92
|
for (const r of out) console.log(` ${r.cli.padEnd(9)} ${r.status}${r.detail ? ` (${r.detail})` : ""}`);
|
|
93
93
|
if (!found) console.log(" no supported CLIs found on PATH (claude, codex, gemini, kimi, opencode)");
|
|
94
94
|
console.log(DRY ? "\nRun without --dry-run to apply." : "\nDone. New sessions of each CLI auto-join the bus.");
|
package/bin/crew-runner.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
//
|
|
2
|
+
// trantor crew runner — keeps a crew agent alive forever without burning tokens.
|
|
3
3
|
//
|
|
4
4
|
// node crew-runner.mjs <agent> [project-dir]
|
|
5
5
|
//
|
|
@@ -34,7 +34,7 @@ try { mkdirSync(LOGDIR, { recursive: true }); } catch {}
|
|
|
34
34
|
let TURN = 0;
|
|
35
35
|
const telemetry = (rec) => { try { appendFileSync(join(LOGDIR, `${AGENT}-${PROJ}.jsonl`), JSON.stringify(rec) + "\n"); } catch {} };
|
|
36
36
|
const banner = (trigger) => {
|
|
37
|
-
console.log(`\x1b[2J\x1b[H\x1b[48;5;236m\x1b[38;5;43m ◤ ${AGENT.toUpperCase()} ◢
|
|
37
|
+
console.log(`\x1b[2J\x1b[H\x1b[48;5;236m\x1b[38;5;43m ◤ ${AGENT.toUpperCase()} ◢ trantor crew · ${PROJ} · turn ${TURN} · ${trigger}${MODEL ? ` · ${MODEL}` : ""} \x1b[0m\n`);
|
|
38
38
|
};
|
|
39
39
|
|
|
40
40
|
async function api(path, body) {
|
|
@@ -67,7 +67,7 @@ const CLI = {
|
|
|
67
67
|
const cli = CLI[AGENT];
|
|
68
68
|
if (!cli) { console.error(`unknown agent '${AGENT}' (known: ${Object.keys(CLI).join(", ")})`); process.exit(1); }
|
|
69
69
|
|
|
70
|
-
const RULES = `Rules: you are ${SESSION} on the
|
|
70
|
+
const RULES = `Rules: you are ${SESSION} on the trantor crew. Work your assigned file(s), report on the bus (relay_send, <280 chars), move your Kanban card as you go (doing -> testing -> done; run the tests in 'testing', use 'failed' + a report if they break). When your work for THIS message is finished, END YOUR TURN — do NOT park, do NOT loop relay_wait; the runner waits for you and will wake you with the next message.`;
|
|
71
71
|
|
|
72
72
|
let sid = "";
|
|
73
73
|
function runTurn(prompt, isFirst, trigger = "kickoff") {
|
package/bin/crew.sh
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
#
|
|
2
|
+
# trantor crew launcher v2 — visible terminal windows that CANNOT silently die or silently fail.
|
|
3
3
|
#
|
|
4
4
|
# bin/crew.sh up codex gemini kimi deepseek # one window per agent, in the CURRENT project dir
|
|
5
5
|
# bin/crew.sh down # kill crew processes + close windows (no dialogs)
|
|
@@ -91,7 +91,7 @@ spawn_grid() { # $@ = agents — (re)computes the grid for THIS batch and spawn
|
|
|
91
91
|
osascript \
|
|
92
92
|
-e 'tell application "Terminal"' \
|
|
93
93
|
-e " set w to do script \"cd $DIR && clear && CREW_MODEL=$MODEL node $BUS_DIR/bin/crew-runner.mjs $AGENT $DIR\"" \
|
|
94
|
-
-e " set custom title of w to \"$(echo "$AGENT" | tr '[:lower:]' '[:upper:]') —
|
|
94
|
+
-e " set custom title of w to \"$(echo "$AGENT" | tr '[:lower:]' '[:upper:]') — trantor crew\"" \
|
|
95
95
|
-e " set theWin to first window whose tabs contains w" \
|
|
96
96
|
-e " set bounds of theWin to {$X1, $Y1, $(( X1 + CW )), $(( Y1 + CH ))}" \
|
|
97
97
|
-e " return id of theWin" \
|
package/bin/doctor.mjs
CHANGED
|
@@ -38,7 +38,7 @@ else {
|
|
|
38
38
|
const st = read(join(H, ".claude", "settings.json")) || {};
|
|
39
39
|
Object.keys(st.enabledPlugins || {}).some(k => k.startsWith("agent-bus@") || k.startsWith("trantor@"))
|
|
40
40
|
? ok("plugin installed")
|
|
41
|
-
: warn("plugin not installed", "claude plugin marketplace add sashabogi/trantor && claude plugin install
|
|
41
|
+
: warn("plugin not installed", "claude plugin marketplace add sashabogi/trantor && claude plugin install trantor");
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
// crew CLIs: installed / wired / authenticated
|
package/bin/handoff-prompt.sh
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
#
|
|
2
|
+
# trantor handoff prompt (macOS) — shown when a session hits its context limit.
|
|
3
3
|
# Asks the user, with a timeout, whether to open a FRESH same-agent session that takes
|
|
4
4
|
# over via the handoff. Default (incl. timeout, or no UI) = open fresh. "Keep compacting" = skip.
|
|
5
5
|
#
|
|
@@ -11,10 +11,10 @@ AGENT_CMD="${AGENT_CMD:-claude}"
|
|
|
11
11
|
HERE="$(cd "$(dirname "$0")" && pwd)"
|
|
12
12
|
NAME="$(basename "$DIR")"
|
|
13
13
|
|
|
14
|
-
MSG="
|
|
14
|
+
MSG="trantor — this session's context window is full ($NAME). Open a FRESH session to take over with a full window? It loads a handoff of this session. (The current session keeps compacting either way.)"
|
|
15
15
|
|
|
16
16
|
# Best-effort timed dialog. On timeout, error, or no UI session -> empty -> we spawn (the default).
|
|
17
|
-
CHOICE="$(osascript -e "button returned of (display dialog \"${MSG//\"/\\\"}\" buttons {\"Keep compacting\", \"Open fresh session\"} default button \"Open fresh session\" giving up after $TIMEOUT with title \"
|
|
17
|
+
CHOICE="$(osascript -e "button returned of (display dialog \"${MSG//\"/\\\"}\" buttons {\"Keep compacting\", \"Open fresh session\"} default button \"Open fresh session\" giving up after $TIMEOUT with title \"trantor\")" 2>/dev/null)"
|
|
18
18
|
|
|
19
19
|
if [ "$CHOICE" != "Keep compacting" ]; then
|
|
20
20
|
"$HERE/open-session.sh" "$DIR" "$AGENT_CMD"
|
package/bin/profile.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
//
|
|
2
|
+
// trantor quota profile — declare what plan each provider runs on, once.
|
|
3
3
|
// The Advisor uses this to pick execution modes (plans can't be detected reliably).
|
|
4
4
|
//
|
|
5
5
|
// node bin/profile.mjs # show current profile
|
package/bin/statusline.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
//
|
|
3
|
-
// 🟢
|
|
2
|
+
// trantor statusline — prints a tiny live indicator for the agent's status bar:
|
|
3
|
+
// 🟢 trantor · 3 live
|
|
4
4
|
// Claude Code: add to settings.json ->
|
|
5
|
-
// "statusLine": { "type": "command", "command": "node /path/to/
|
|
5
|
+
// "statusLine": { "type": "command", "command": "node /path/to/trantor/bin/statusline.mjs" }
|
|
6
6
|
// Reads session info as JSON on stdin (Claude Code convention); fast + fail-silent.
|
|
7
7
|
import { readFileSync, existsSync } from "node:fs";
|
|
8
8
|
import { join, basename } from "node:path";
|
|
@@ -22,9 +22,9 @@ async function main() {
|
|
|
22
22
|
const r = await fetch(`${relayUrl()}/peers`, { signal: AbortSignal.timeout(800) });
|
|
23
23
|
const { peers } = await r.json();
|
|
24
24
|
const live = peers.filter(p => p.online && p.session !== me).length;
|
|
25
|
-
process.stdout.write(`\x1b[38;5;43m●
|
|
25
|
+
process.stdout.write(`\x1b[38;5;43m● trantor\x1b[0m \x1b[2m· ${live} other${live === 1 ? "" : "s"} live\x1b[0m`);
|
|
26
26
|
} catch {
|
|
27
|
-
process.stdout.write(`\x1b[2m○
|
|
27
|
+
process.stdout.write(`\x1b[2m○ trantor offline\x1b[0m`); // hub unreachable
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
main();
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
"//": "
|
|
2
|
+
"//": "trantor for Gemini CLI — merge into ~/.gemini/settings.json (or a project .gemini/settings.json).",
|
|
3
3
|
"mcpServers": {
|
|
4
4
|
"relay": {
|
|
5
5
|
"command": "node",
|
|
6
|
-
"args": ["REPLACE/WITH/ABSOLUTE/PATH/
|
|
6
|
+
"args": ["REPLACE/WITH/ABSOLUTE/PATH/trantor/mcp.mjs"],
|
|
7
7
|
"env": { "RELAY_URL": "http://127.0.0.1:4477", "RELAY_SESSION": "gemini:myproject" }
|
|
8
8
|
}
|
|
9
9
|
}
|
package/deploy/setup.sh
CHANGED
|
@@ -28,4 +28,5 @@ node "$REPO/bin/connect.mjs"
|
|
|
28
28
|
echo
|
|
29
29
|
node "$REPO/bin/doctor.mjs" || true
|
|
30
30
|
echo
|
|
31
|
-
echo "Next: claude plugin marketplace add sashabogi/trantor && claude plugin install
|
|
31
|
+
echo "Next: claude plugin marketplace add sashabogi/trantor && claude plugin install trantor"
|
|
32
|
+
echo "Then: open Claude Code in any project and say \"fire up the crew\""
|
package/hooks/hooks.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"description": "
|
|
2
|
+
"description": "trantor — auto-register each session + inject live roster (SessionStart); write a handoff before compaction (PreCompact)",
|
|
3
3
|
"hooks": {
|
|
4
4
|
"SessionStart": [
|
|
5
5
|
{ "matcher": "", "hooks": [ { "type": "command", "command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/sessionstart.mjs" } ] }
|
package/hooks/precompact.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
//
|
|
2
|
+
// trantor PreCompact hook — fires right before Claude Code compacts a full
|
|
3
3
|
// context window. Instead of (just) compacting, it writes a rich HANDOFF so you can
|
|
4
4
|
// open a FRESH session that takes over with a new full window. The SessionStart hook
|
|
5
5
|
// detects the pending handoff and loads it.
|
|
@@ -50,7 +50,7 @@ function summarize(convo) {
|
|
|
50
50
|
return execSync(`scrooge -t summarize -d medium --system ${JSON.stringify(sys)}`, {
|
|
51
51
|
input: convo, encoding: "utf8", timeout: 45000, maxBuffer: 4 * 1024 * 1024,
|
|
52
52
|
}).trim();
|
|
53
|
-
} catch (e) { process.stderr.write(`[
|
|
53
|
+
} catch (e) { process.stderr.write(`[trantor] scrooge summarize failed: ${e?.message}\n`); }
|
|
54
54
|
}
|
|
55
55
|
// fallback: raw recent tail
|
|
56
56
|
return `*(no summarizer available — raw recent transcript tail)*\n\n${convo.slice(-6000)}`;
|
|
@@ -85,7 +85,7 @@ try {
|
|
|
85
85
|
};
|
|
86
86
|
const file = join(HANDOFF_DIR, `${record.id}.json`);
|
|
87
87
|
writeFileSync(file, JSON.stringify(record, null, 2));
|
|
88
|
-
process.stderr.write(`[
|
|
88
|
+
process.stderr.write(`[trantor] handoff written: ${file} (trigger=${trigger})\n`);
|
|
89
89
|
|
|
90
90
|
// best-effort: ping the relay hub so other sessions/machines know a handoff is ready
|
|
91
91
|
try {
|
|
@@ -107,12 +107,12 @@ try {
|
|
|
107
107
|
if (existsSync(script)) {
|
|
108
108
|
const child = spawn("/bin/bash", [script, projectDir, String(conf.handoffPromptTimeout || 25)], { detached: true, stdio: "ignore" });
|
|
109
109
|
child.unref();
|
|
110
|
-
process.stderr.write(`[
|
|
110
|
+
process.stderr.write(`[trantor] handoff prompt launched (opt-in)\n`);
|
|
111
111
|
}
|
|
112
112
|
}
|
|
113
113
|
} catch {}
|
|
114
114
|
} catch (err) {
|
|
115
|
-
process.stderr.write(`[
|
|
115
|
+
process.stderr.write(`[trantor] precompact error: ${err?.message || err}\n`);
|
|
116
116
|
}
|
|
117
117
|
process.stdout.write("{}");
|
|
118
118
|
process.exit(0);
|
package/hooks/sessionstart.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
//
|
|
2
|
+
// trantor SessionStart hook — every session auto-registers with the hub and
|
|
3
3
|
// gets a roster of OTHER live sessions injected into context, so independent
|
|
4
4
|
// sessions discover each other automatically (locally or across machines).
|
|
5
5
|
//
|
|
@@ -72,30 +72,30 @@ try {
|
|
|
72
72
|
try { peers = (await jget(`${url}/peers`)).peers || []; } catch {}
|
|
73
73
|
const others = peers.filter(p => p.online && p.session !== session);
|
|
74
74
|
|
|
75
|
-
process.stderr.write(`[
|
|
75
|
+
process.stderr.write(`[trantor] registered as ${session} -> ${url} (${others.length} other live session(s))\n`);
|
|
76
76
|
|
|
77
77
|
if (others.length > 0) {
|
|
78
|
-
additionalContext += `<
|
|
79
|
-
additionalContext += `You are connected to
|
|
78
|
+
additionalContext += `<trantor session="${session}" hub="${url}">\n`;
|
|
79
|
+
additionalContext += `You are connected to Trantor (the cross-agent session bus) as "${session}". Other LIVE agent sessions are running right now:\n`;
|
|
80
80
|
for (const p of others) additionalContext += `- ${sanitize(p.session)}\n`;
|
|
81
81
|
additionalContext += `Use the relay MCP tools (relay_peers, relay_send, relay_inbox, relay_wait) to coordinate with them — hand off work, check for overlap before editing shared files, or ask another session for help. If a sibling session is touching the same project, coordinate before making conflicting changes.\n`;
|
|
82
|
-
additionalContext += `</
|
|
82
|
+
additionalContext += `</trantor>\n`;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
// Pending handoff? A prior session hit the context limit and left a handoff for this
|
|
86
86
|
// project — take over with this fresh full window instead of starting cold.
|
|
87
87
|
const handoff = loadPendingHandoff(basename(projectDir));
|
|
88
88
|
if (handoff) {
|
|
89
|
-
process.stderr.write(`[
|
|
90
|
-
additionalContext += `<
|
|
89
|
+
process.stderr.write(`[trantor] loaded pending handoff ${handoff.id}\n`);
|
|
90
|
+
additionalContext += `<trantor-handoff id="${sanitize(handoff.id)}" from="${sanitize(handoff.machine)}" trigger="${sanitize(handoff.trigger)}">\n`;
|
|
91
91
|
additionalContext += `🔄 **You are taking over from a prior session that hit its context limit.** This is a fresh full window. Resume the work below — the prior session's summary, git state, and a pointer to its full transcript (searchable; Foundation/Gaia has it ingested) follow. Continue from "OPEN THREADS & NEXT STEPS"; do not restart from scratch.\n\n`;
|
|
92
92
|
additionalContext += `## Handoff summary\n${sanitize(handoff.summary)}\n`;
|
|
93
93
|
if (handoff.gitStatus) additionalContext += `\n## Git working-tree at handoff\n\`\`\`\n${sanitize(handoff.gitStatus)}\n\`\`\`\n`;
|
|
94
94
|
if (handoff.transcript_path) additionalContext += `\n_Full prior transcript: ${sanitize(handoff.transcript_path)}_\n`;
|
|
95
|
-
additionalContext += `</
|
|
95
|
+
additionalContext += `</trantor-handoff>\n`;
|
|
96
96
|
}
|
|
97
97
|
} catch (err) {
|
|
98
|
-
process.stderr.write(`[
|
|
98
|
+
process.stderr.write(`[trantor] sessionstart error: ${err?.message || err}\n`);
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
// Hook protocol: emit additionalContext via stdout JSON. Self-validate so we never
|
package/hub.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
//
|
|
2
|
+
// trantor hub — message bus + presence/status board + SSE push, so independent
|
|
3
3
|
// Claude Code sessions can coordinate (near-instant for watchers, cheap for idle peers).
|
|
4
4
|
// Binds to LOOPBACK (127.0.0.1) by default — local-first and safe (no auth yet). To let other
|
|
5
5
|
// machines reach it (e.g. over a Tailscale tailnet), set RELAY_HOST=0.0.0.0 — but only on a
|
|
@@ -209,10 +209,10 @@ const server = http.createServer(async (req, res) => {
|
|
|
209
209
|
return json(res, 200, { messages: state.messages.slice(-n) });
|
|
210
210
|
}
|
|
211
211
|
if (req.method === "GET" && (P === "/" || P === "/ui")) {
|
|
212
|
-
res.writeHead(200, { "content-type": "text/html; charset=utf-8" }); return res.end(UI || "<h1>
|
|
212
|
+
res.writeHead(200, { "content-type": "text/html; charset=utf-8" }); return res.end(UI || "<h1>trantor</h1><p>dashboard unavailable</p>");
|
|
213
213
|
}
|
|
214
214
|
if (P === "/health") return json(res, 200, { ok: true, peers: Object.keys(state.peers).length, messages: state.messages.length, streams: streams.length });
|
|
215
215
|
json(res, 404, { error: "not found" });
|
|
216
216
|
} catch (e) { json(res, 500, { error: String(e?.message || e) }); }
|
|
217
217
|
});
|
|
218
|
-
server.listen(PORT, HOST, () => console.error(`[
|
|
218
|
+
server.listen(PORT, HOST, () => console.error(`[trantor] hub on http://${HOST}:${PORT} (data: ${DATA})`));
|
package/mcp.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
//
|
|
2
|
+
// trantor MCP server — gives ANY MCP-capable agent (Claude Code, Codex, Gemini, …)
|
|
3
3
|
// tools to talk to OTHER live agent sessions through the relay hub. Loaded per-session
|
|
4
4
|
// via the agent's MCP config. Identity + hub URL come from env (RELAY_SESSION, RELAY_URL).
|
|
5
5
|
// Loading this server AUTO-REGISTERS the session — so presence works on every agent.
|
|
@@ -37,7 +37,7 @@ async function api(method, path, payload) {
|
|
|
37
37
|
}
|
|
38
38
|
const fmt = (m) => `#${m.id} [${m.from} -> ${m.to}] ${new Date(m.ts).toLocaleTimeString()}: ${m.text}`;
|
|
39
39
|
|
|
40
|
-
const server = new McpServer({ name: "
|
|
40
|
+
const server = new McpServer({ name: "trantor", version: "0.1.0" });
|
|
41
41
|
|
|
42
42
|
server.tool("relay_whoami", "Show this session's relay identity, project, and the hub URL.", {}, async () => {
|
|
43
43
|
await api("POST", "/register", { session: SESSION, project: PROJECT }).catch(() => {});
|
|
@@ -153,4 +153,4 @@ server.tool("relay_wait", "Block up to `timeout` seconds waiting for the next me
|
|
|
153
153
|
|
|
154
154
|
await api("POST", "/register", { session: SESSION, project: PROJECT, status: `active in ${PROJECT}` }).catch(() => {});
|
|
155
155
|
await server.connect(new StdioServerTransport());
|
|
156
|
-
process.stderr.write(`[
|
|
156
|
+
process.stderr.write(`[trantor-mcp] connected as ${SESSION} -> ${URL_BASE}\n`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "trantor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"trantor": "bin/cli.mjs"
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"scripts": {
|
|
13
13
|
"test": "node test.mjs && node test-scenarios.mjs"
|
|
14
14
|
},
|
|
15
|
-
"description": "The hub-world for AI agent crews
|
|
15
|
+
"description": "The hub-world for AI agent crews — orchestrate Claude Code, Codex, Gemini, Kimi & DeepSeek as live crews with a plan-aware Advisor, a Kanban/flow command center, a testing gate, and an economics brain (Scrooge).",
|
|
16
16
|
"files": [
|
|
17
17
|
"hub.mjs",
|
|
18
18
|
"mcp.mjs",
|
|
@@ -52,4 +52,4 @@
|
|
|
52
52
|
"engines": {
|
|
53
53
|
"node": ">=18"
|
|
54
54
|
}
|
|
55
|
-
}
|
|
55
|
+
}
|
package/skills/crew/SKILL.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: crew
|
|
3
|
-
description: Orchestrate a multi-agent build
|
|
3
|
+
description: Orchestrate a multi-agent build with Trantor — get an Advisor recommendation (solo/scrooge/crew/hybrid based on the user's plans and the work), fire up helper AI CLIs (Codex, Gemini, Kimi, DeepSeek) with pinned models in visible terminal windows, assign difficulty-tagged work over the bus, track it on the Kanban dashboard with a testing gate, delegate grunt to Scrooge, supervise actively, integrate, ship. Use when the user wants several AI agents building something together, says "fire up the crew/agents", "build it with trantor / with the crew", or asks to coordinate other coding CLIs on a task.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# Trantor crew — the unified playbook (brain × body)
|
|
7
7
|
|
|
8
8
|
You are the ARCHITECT. Two execution fabrics serve you:
|
|
9
9
|
- **Scrooge calls** (`relay_scrooge`) — cheap stateless one-shots; the result returns to you.
|
|
@@ -25,7 +25,7 @@ inside a question dialog), paste verbatim: `routing_table_md`, the `why` bullets
|
|
|
25
25
|
and the real-money total + quota pools. ONLY THEN ask go / adjust / hold. When creating the
|
|
26
26
|
board, use `card_args` exactly — each entry is a ready `relay_task_add` call (title,
|
|
27
27
|
difficulty, assignee with your project substituted, model). Cards without their model set
|
|
28
|
-
are a defect. If the profile is unset, say so and suggest `
|
|
28
|
+
are a defect. If the profile is unset, say so and suggest `trantor profile set …`.
|
|
29
29
|
|
|
30
30
|
## Phase 0 — plan (if the user wants a plan first)
|
|
31
31
|
PRD.md + TDD.md. The TDD MUST define one file-set per agent (no merge conflicts) and an
|
|
@@ -36,11 +36,12 @@ explicit EVENT/INTERFACE CONTRACT — cross-agent bugs come from contract drift.
|
|
|
36
36
|
2. One card per package: `relay_task_add(title, assignee, difficulty, model)` — set `model`
|
|
37
37
|
to the advisor-routed model (or the CLI's default name); difficulty + model show as badges
|
|
38
38
|
on the card. Assignees: `codex:<project>` etc. Keep one for yourself.
|
|
39
|
-
3. Open the dashboard: `open -na "Google Chrome" --args --new-window <hub-url>`
|
|
39
|
+
3. Open the dashboard: `trantor ui` (or `open -na "Google Chrome" --args --new-window <hub-url>`)
|
|
40
40
|
|
|
41
41
|
## Phase 2 — fire up the crew (with the Advisor's models)
|
|
42
|
-
`
|
|
42
|
+
`trantor up codex:gpt-5.5 gemini kimi deepseek:deepseek-v4-pro`
|
|
43
43
|
— `agent:model` pins a model (omit to use that CLI's default; use what relay_advise routed).
|
|
44
|
+
(If `trantor` isn't on PATH, the same launcher is `bash <plugin-root>/bin/crew.sh up …`.)
|
|
44
45
|
The launcher auto-wires configs, spawns serialized runner windows, then **VERIFIES each agent
|
|
45
46
|
on the bus with one retry**. READ ITS OUTPUT: it ends "crew verified" or "✗✗ CREW INCOMPLETE"
|
|
46
47
|
naming no-shows. **Never assign work to an unverified agent.** The bus is the truth.
|
|
@@ -58,7 +59,7 @@ Loop until the board is done — you are a foreman, not a mailbox:
|
|
|
58
59
|
(assignee lastSeen fresh? runner heartbeats keep live agents fresh in seconds — stale =
|
|
59
60
|
dead), spot-check files on disk.
|
|
60
61
|
3. ACT within one cycle: failed card → read the report, send a fix contract, card back to
|
|
61
|
-
doing · dead agent → `
|
|
62
|
+
doing · dead agent → `trantor up <agent>` (re-verifies) + resend contract · silent-but-alive
|
|
62
63
|
→ direct-message nudge naming the card.
|
|
63
64
|
4. Grunt sub-tasks that appear mid-build (a regex, a config block, a doc paragraph) →
|
|
64
65
|
`relay_scrooge`, don't burn a crew seat or your own window.
|
|
@@ -71,7 +72,7 @@ Card flow is `todo → doing → testing → done`; `testing` runs the project's
|
|
|
71
72
|
Enforce the gate — bounce anything that skipped it (bounces are visible: "↩ bounced" on the
|
|
72
73
|
card, history in its tooltip). When all report done: integrate, fix contract mismatches
|
|
73
74
|
YOURSELF, move your card through testing → done, broadcast "🚀 <thing> is live", and when the
|
|
74
|
-
user is finished: `
|
|
75
|
+
user is finished: `trantor down`.
|
|
75
76
|
|
|
76
77
|
## Rules
|
|
77
78
|
- Coordinate ONLY over the bus; messages <280 chars; the dashboard lanes are the user's view.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
2
|
+
name: handoff
|
|
3
3
|
description: |
|
|
4
4
|
Write a rich handoff for the CURRENT session so a fresh Claude Code session can take over
|
|
5
5
|
with a full new context window (instead of compacting). Use proactively when context is
|
|
6
|
-
getting full, or before ending, to pass the baton cleanly. Trigger: /
|
|
6
|
+
getting full, or before ending, to pass the baton cleanly. Trigger: /trantor:handoff
|
|
7
7
|
user-invocable: true
|
|
8
8
|
---
|
|
9
9
|
|
package/ui.html
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<!doctype html>
|
|
2
2
|
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
|
3
|
-
<title>
|
|
3
|
+
<title>trantor</title>
|
|
4
4
|
<style>
|
|
5
5
|
:root{--bg:#0a0e16;--panel:#111726;--card:#161d2e;--card2:#1b2335;--line:#1f2839;--tx:#e6edf6;--mut:#8a97a8;--dim:#5b6675;
|
|
6
6
|
--grn:#2dd4bf;--grn2:#14b8a6;--amb:#f59e0b;--blu:#4a90d9;--red:#ef6a6a;--pur:#9b6fd4}
|