gaslamp 2.2.2 → 3.0.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/bin/gaslamp.mjs CHANGED
@@ -1,12 +1,10 @@
1
1
  #!/usr/bin/env node
2
- // gaslamp: let Claude Code and Codex consult each other — and Gemini and Grok —
3
- // from the shell.
2
+ // gaslamp: let coding agents consult each other from the shell — Claude,
3
+ // Codex, Gemini and Grok.
4
4
  //
5
- // gaslamp claude … / codex … one blocking consult (the heart of it)
6
- // gaslamp gemini … / grok … the same, against Antigravity CLI / Grok Build
7
- // gaslamp fleet <backend> … fan out a bounded fleet of consults
8
- // gaslamp jobs / poll read the durable consult records
9
- // gaslamp setup [--local] allowlist the command for Claude Code
5
+ // gaslamp claude|codex|gemini|grok … one blocking consult (the heart of it)
6
+ // gaslamp jobs / poll / threads read the durable records
7
+ // gaslamp setup link the skill, allowlist the command
10
8
  //
11
9
  // Each agent backgrounds the call with its own facility, so consults run in
12
10
  // parallel and replies trickle in as they finish. No MCP servers, no daemon:
@@ -19,114 +17,54 @@ import { fileURLToPath } from "node:url";
19
17
  const HERE = dirname(fileURLToPath(import.meta.url));
20
18
  const pkg = JSON.parse(readFileSync(join(HERE, "..", "package.json"), "utf8"));
21
19
 
22
- const HELP = `gaslamp ${pkg.version}: let Claude Code and Codex consult each other from the shell
23
- (and consult Gemini and Grok).
20
+ const HELP = `gaslamp ${pkg.version}: let coding agents consult each other from the shell.
24
21
 
25
22
  Usage:
26
- gaslamp claude [opts] <prompt|-> Consult Claude (blocks until the reply).
27
- gaslamp codex [opts] <prompt|-> Consult Codex (blocks until the reply).
28
- gaslamp gemini [opts] <prompt|-> Consult Gemini via Antigravity CLI (agy).
29
- gaslamp grok [opts] <prompt|-> Consult Grok via Grok Build.
30
- gaslamp fleet <backend> [opts] Fan out a fleet of consults (one command).
31
- -n N <prompt> Replicate one prompt across N fresh sessions.
32
- - < tasks.jsonl Or one task per line on stdin (see below).
33
- gaslamp fleet --resume <fleet-id> Finish an interrupted fleet: done children
34
- replay their recorded replies, killed ones
35
- are nudged to conclude via their sessions,
36
- the rest rerun from the stored manifest.
37
- gaslamp jobs [-n N] [--json] List consult records, newest first.
38
- gaslamp threads List named threads, latest activity first.
39
- gaslamp poll <job|fleet|--last> [--json]
40
- Print one record's reply/status.
41
- gaslamp tail <job|--last> Follow one consult's events as one-liners
42
- (both backends' schemas, uniformly).
43
- gaslamp setup [--local] [--skill] Allowlist the command in Claude Code so
44
- consults don't stall on a permission prompt.
45
- --local pins this checkout's bin path.
46
- --skill also installs the gaslamp skill
47
- for BOTH agents (~/.claude/skills/,
48
- $CODEX_HOME/skills/).
23
+ gaslamp <claude|codex|gemini|grok> [opts] <prompt|->
24
+ Consult one; blocks until the reply. Run it in the
25
+ background and keep working.
26
+ gaslamp jobs [-n N] [--json] Recent consults, newest first.
27
+ gaslamp poll <job|--last> [--json] One consult's reply (exit 10 = running).
28
+ gaslamp threads Named conversations, latest first.
29
+ gaslamp setup Link the skill into Claude Code and Codex,
30
+ and allowlist the command for Claude Code.
49
31
 
50
32
  Consult options:
51
- --resume <session|job> Continue a session (a prior job id works too).
52
- --thread <name> Named session: continue it if the name is bound,
53
- else start fresh and bind it. The pointer chases
54
- claude's forked session ids so the name stays hot.
55
- --model <m> Backend model: an exact id, or a tier word —
56
- claude aliases (fable, opus, sonnet, haiku); codex
57
- (astra, sol, luna) and gemini (argon, flash) tiers
58
- resolve to the newest id in the harness's own
59
- catalog. gemini defaults to argon (Antigravity also
60
- serves non-Gemini models under the same account).
61
- --effort <level> Reasoning effort (claude --effort / codex
62
- model_reasoning_effort / agy --effort /
63
- grok --effort).
64
- --label <s> Tag the job record (shows in gaslamp jobs).
65
- --sandbox <mode> claude: read-only | danger-full-access
66
- codex: read-only | workspace-write | danger-full-access
67
- gemini: read-only | danger-full-access
68
- grok: read-only | workspace-write | danger-full-access
69
- Omitted: claude and codex defer to the consulted
70
- agent's own config; gemini and grok run read-only.
71
- --cwd <dir> Working directory for the consult (default: here).
72
- --schema <file|json> JSON Schema for the reply (native on both backends:
73
- claude --json-schema / codex --output-schema). The
74
- --json envelope gains data (the parsed object); a
75
- reply that doesn't parse marks the consult failed.
76
- --raw Skip the consult preamble (the few fixed lines that
77
- tell the consultee its reply returns verbatim).
78
- --json Machine envelope on stdout:
79
- {backend, jobId, sessionId, status, exitCode,
80
- content, data?}
81
- - Read the prompt from stdin (default when piped).
82
- With a prompt argument, piped stdin is instead
83
- appended as a <stdin> evidence block:
84
- git diff | gaslamp codex "review for races:"
33
+ --thread <name> Name the conversation: the first consult with a
34
+ name starts it, later ones continue it (from the
35
+ directory it started in).
36
+ --resume <job-id> Continue an unnamed consult's conversation.
37
+ --model <m> An exact id, or a tier: claude fable|opus|sonnet|
38
+ haiku; codex astra|sol|luna; gemini argon|flash
39
+ (default argon).
40
+ --effort <level> low|medium|high|xhigh|max (codex astra/sol: ultra).
41
+ --sandbox <mode> read-only | workspace-write | danger-full-access.
42
+ Omitted: claude and codex use their own config;
43
+ gemini and grok run read-only. The fenced modes
44
+ are OS-enforced; gemini's needs macOS.
45
+ --cwd <dir> Run the consult there (default: here).
46
+ --schema <file|json> JSON Schema for the reply; with --json the parsed
47
+ reply is in data, and one that doesn't parse fails.
48
+ --json {backend, jobId, status, thread, content, error?, data?}
49
+ - Read the prompt from stdin (the default when piped).
50
+ With a prompt argument, piped stdin is appended as
51
+ a <stdin> evidence block:
52
+ git diff | gaslamp codex "review for races:"
85
53
 
86
- Fleet options (in addition to --model / --sandbox / --cwd / --json, applied to
87
- every consult unless a per-task field on a stdin manifest overrides it):
88
- -n, --count N Replicate the prompt across N fresh sessions.
89
- -j, --concurrency N Max consults in flight (default 4 — quota-shaped).
90
- --stream Print each reply the moment it completes instead of
91
- collecting to the end (with --json: JSONL — one
92
- result line per reply, then a fleet.done line).
93
- - < tasks.jsonl One task per line: a {"prompt",…} JSON object (also
94
- model/sandbox/effort/cwd/resume/thread/label/schema/
95
- raw — schema may be an inline JSON object), or a
96
- bare prompt.
97
- A prompt argument + piped stdin shares one <stdin>
98
- evidence block across every replica.
99
- A fleet defaults its consults to --sandbox read-only (N writers in one cwd
100
- race); pass --sandbox to opt into writes. It blocks until every consult is in,
101
- then prints them all (--json: a results array, manifest order). A killed fleet
102
- leaves each child resumable; gaslamp poll <fleet-id> regroups them later.
103
-
104
- Run a consult (or a fleet) as a background shell task and keep working — several
105
- can run in parallel, replies land as the tasks finish. Every consult writes through to
106
- ~/.gaslamp/jobs/<id>/ (prompt, raw events, reply, stderr), and the session id
107
- is recorded the moment the backend reports it: a killed consult costs the
108
- in-flight turn, not the session. Recovery is --resume, not orphans.
54
+ Every consult writes through to ~/.gaslamp/jobs/<id>/ (prompt, raw events,
55
+ stderr, reply), and its session is recorded the moment the backend reports it:
56
+ a killed consult loses the turn in flight, not the conversation.
109
57
 
110
58
  Exit codes:
111
- 0 ok · 1 consult failed/killed · 2 usage · 3 nested (one-hop) refusal ·
112
- 4 network-disabled sandbox · 5 session busy · poll: 10 still running
59
+ 0 ok · 1 failed or killed · 2 usage · 3 nested (one-hop) refusal ·
60
+ 4 can't run here (no network, or no OS sandbox for the mode) ·
61
+ 5 conversation busy · poll: 10 still running
113
62
 
114
- Env knobs:
63
+ Env:
115
64
  GASLAMP_HOME state dir (default ~/.gaslamp)
116
- GASLAMP_ALLOWED_TOOLS tools the claude read-only override permits,
117
- comma-separated (default: Read,Grep,Glob,WebFetch,
118
- WebSearch + read-only git via Bash(git diff:*) etc)
119
65
  GASLAMP_ALLOW_RECURSION let consulted agents consult back (off = one hop)
120
- GASLAMP_DEBUG verbose stderr (spawn argv)
121
- CLAUDE_BIN / CODEX_BIN / AGY_BIN / GROK_BIN
122
- backend binaries (autodetected otherwise)
123
- GASLAMP_GEMINI_SEATBELT 0 = read-only gemini consults rely on Antigravity's
124
- preset check instead of Seatbelt (macOS default)
125
-
126
- Every job record (meta.json) carries provenance: provider, harness version,
127
- the model the backend reported (or unknown), the vendor system prompt's hash
128
- where the harness exposes it (grok) or known:false, the retrieval tools the
129
- consultee had and used, and the gaslamp version and git revision.
66
+ GASLAMP_DEBUG print the spawn argv
67
+ CLAUDE_BIN / CODEX_BIN / AGY_BIN / GROK_BIN backend binaries
130
68
  `;
131
69
 
132
70
  const [cmd, ...rest] = process.argv.slice(2);
@@ -140,34 +78,24 @@ switch (cmd) {
140
78
  runConsult(cmd, rest);
141
79
  break;
142
80
  }
143
- case "fleet": {
144
- const { runFleet } = await import(new URL("../src/fleet.mjs", import.meta.url));
145
- runFleet(rest[0], rest.slice(1));
146
- break;
147
- }
148
81
  case "jobs": {
149
82
  const { runJobs } = await import(new URL("../src/jobs.mjs", import.meta.url));
150
83
  runJobs(rest);
151
84
  break;
152
85
  }
153
- case "threads": {
154
- const { runThreads } = await import(new URL("../src/threads.mjs", import.meta.url));
155
- runThreads();
156
- break;
157
- }
158
- case "tail": {
159
- const { runTail } = await import(new URL("../src/tail.mjs", import.meta.url));
160
- runTail(rest);
161
- break;
162
- }
163
86
  case "poll": {
164
87
  const { runPoll } = await import(new URL("../src/jobs.mjs", import.meta.url));
165
88
  runPoll(rest);
166
89
  break;
167
90
  }
91
+ case "threads": {
92
+ const { runThreads } = await import(new URL("../src/threads.mjs", import.meta.url));
93
+ runThreads();
94
+ break;
95
+ }
168
96
  case "setup": {
169
97
  const { runSetup } = await import(new URL("../src/setup.mjs", import.meta.url));
170
- runSetup(rest);
98
+ runSetup();
171
99
  break;
172
100
  }
173
101
  case "-v":
@@ -179,6 +107,11 @@ switch (cmd) {
179
107
  case "--help":
180
108
  process.stdout.write(HELP);
181
109
  break;
110
+ case "fleet":
111
+ case "tail":
112
+ process.stderr.write(`gaslamp: ${cmd} is gone in gaslamp 3 — run several consults in the background instead (see gaslamp --help)\n`);
113
+ process.exitCode = 2;
114
+ break;
182
115
  default:
183
116
  process.stderr.write(`gaslamp: unknown command "${cmd}"\n\n` + HELP);
184
117
  process.exitCode = 2;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "gaslamp",
3
- "version": "2.2.2",
4
- "description": "Let Claude Code and Codex consult each other from the shell, and consult Gemini and Grok.",
3
+ "version": "3.0.0",
4
+ "description": "Let coding agents consult each other from the shell: Claude, Codex, Gemini and Grok.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "gaslamp": "bin/gaslamp.mjs"
@@ -9,6 +9,7 @@
9
9
  "files": [
10
10
  "bin/",
11
11
  "src/",
12
+ "skill/",
12
13
  "README.md",
13
14
  "LICENSE"
14
15
  ],
package/skill/SKILL.md ADDED
@@ -0,0 +1,60 @@
1
+ ---
2
+ name: gaslamp
3
+ description: Consult another coding agent (Claude, Codex, Gemini or Grok) from the shell for an independent read or a handoff. Use it to verify a fix or proof, spar on a design, review a diff, search, diagnose with fresh context, or hand off a piece of work. Use it when a claim deserves checking before you rely on it, or when asked to consult Claude / Codex / Gemini / Grok, get a second opinion, or hand work off.
4
+ ---
5
+
6
+ # gaslamp
7
+
8
+ gaslamp <claude|codex|gemini|grok> [options] "<prompt>"
9
+ git diff | gaslamp codex "review this for races:" # piped stdin rides along as <stdin> evidence
10
+ gaslamp claude - < notes.md # the whole prompt from a file
11
+
12
+ A consult blocks until the reply arrives, so run it in the background (`run_in_background` in Claude Code, a background terminal in Codex) and keep working. Several can run at once. You get the consultee's final message verbatim, then one `[gaslamp]` line with the job id and the command that continues the conversation. A consult is one hop: the consultee can't consult back, so the synthesis is yours.
13
+
14
+ Send raw evidence, such as errors, diffs and failing output, not just your reading of it.
15
+
16
+ ## Choosing a consultee
17
+
18
+ | target | `--model` | omitted `--model` | omitted `--sandbox` |
19
+ |--------|-----------|-------------------|---------------------|
20
+ | claude | fable, opus, sonnet, haiku | its own default | its own config |
21
+ | codex | astra, sol, luna | its own default | its own config |
22
+ | gemini | argon, flash | argon | read-only |
23
+ | grok | an id from `grok models` | the account default | read-only |
24
+
25
+ Roughly, strongest first: fable\* > opus ≈ astra > sonnet ≈ argon ≈ sol > haiku ≈ flash ≈ grok ≈ luna. Match the tier to the stakes, as you would when picking a subagent's model.
26
+
27
+ \* The public fable is a generation behind the others (5.1, against 5.5 for opus, sonnet and haiku), so for now it sits between opus and sonnet.
28
+
29
+ `--effort low|medium|high|xhigh|max` sets reasoning effort. astra and sol also take `ultra`. sol defaults to `low`, so set it when the consult matters.
30
+
31
+ ## Conversations
32
+
33
+ `--thread <name>` names a conversation. The first consult with a name starts it, and every later one continues it.
34
+
35
+ - Name it for its subject (`auth-race-review`, not `review`).
36
+ - For an independent second opinion, use a new name, because a reused name carries the earlier context along.
37
+ - A thread lives in the directory it started in. To continue it from anywhere else, pass `--cwd`.
38
+
39
+ Without `--thread` a consult is a one-off, though `--resume <job-id>` can still continue it.
40
+
41
+ ## Sandbox
42
+
43
+ `--sandbox read-only | workspace-write | danger-full-access`
44
+
45
+ - **read-only:** the consultee writes nothing outside its harness's own state and temp dirs.
46
+ - **workspace-write:** it writes only in the cwd.
47
+
48
+ The OS sandbox enforces both, and if the sandbox can't start, gaslamp refuses the consult instead of running it unfenced. Gemini's sandbox is macOS-only, so elsewhere only `danger-full-access` runs it.
49
+
50
+ The sandbox fences the filesystem, not search. A read-only consultee can still look things up: Google for Gemini, web and X for Grok. For a search consult, send the question and ask for source URLs, since a summary of search results isn't verification. For a review, pipe in the material.
51
+
52
+ ## The rest
53
+
54
+ - `--cwd <dir>` runs the consult in another directory.
55
+ - `--json` prints `{backend, jobId, status, thread, content, error?, data?}`.
56
+ - `--schema <file|json>` with `--json` puts the parsed reply in `.data`. A reply that doesn't parse fails the consult.
57
+ - `gaslamp jobs` lists recent consults, `gaslamp poll <job|--last>` prints one (exit 10 means it's still running), and `gaslamp threads` lists conversations.
58
+ - Each job lives in `~/.gaslamp/jobs/<id>/`, raw events included. A killed consult loses its current turn but keeps its conversation.
59
+
60
+ Exit codes: 0 ok · 1 failed or killed · 2 usage · 3 nested · 4 can't run here (no network, or no sandbox for the mode) · 5 conversation busy.
package/src/backends.mjs CHANGED
@@ -1,39 +1,19 @@
1
- // backends.mjs — the four consult targets and the facts every module needs
2
- // about them: job-id prefix, who serves the model, which harness binary, which
3
- // --sandbox values are honest, and what an omitted --sandbox means.
1
+ // backends.mjs — the four consult targets, and the two facts every module
2
+ // needs about them: the job-id prefix, and what an omitted --sandbox means.
4
3
  //
5
- // claude and codex are the original pair, and an omitted --sandbox defers to
6
- // the consulted agent's own config. gemini (Google's Antigravity CLI, `agy`)
7
- // and grok (xAI's Grok Build) joined in 2.2 as consult targets with narrow
8
- // operational trust: an omitted --sandbox means read-only, enforced by the
9
- // harness (see consult.mjs), and every job records provenance — the vendor's
10
- // model or system prompt can change under a stable product name.
4
+ // claude and codex defer to the consulted agent's own config, the way a
5
+ // harness's own subagents inherit theirs. gemini (Google's Antigravity CLI,
6
+ // `agy`) and grok (xAI's Grok Build) start read-only: the narrower trust
7
+ // they joined with.
11
8
 
12
9
  export const BACKENDS = {
13
- claude: {
14
- prefix: "cl", provider: "anthropic", harness: "claude",
15
- sandboxes: ["read-only", "danger-full-access"], defaultSandbox: null,
16
- },
17
- codex: {
18
- prefix: "cx", provider: "openai", harness: "codex",
19
- sandboxes: ["read-only", "workspace-write", "danger-full-access"], defaultSandbox: null,
20
- },
21
- gemini: {
22
- // Antigravity has no headless workspace-write: file writes and shell
23
- // commands are soft-denied under its default request-review preset, and
24
- // --mode accept-edits did not change that in a print-mode run (probed on
25
- // 1.4.3). The only escalation is --dangerously-skip-permissions.
26
- prefix: "gm", provider: "google", harness: "agy",
27
- sandboxes: ["read-only", "danger-full-access"], defaultSandbox: "read-only",
28
- },
29
- grok: {
30
- prefix: "gk", provider: "xai", harness: "grok",
31
- sandboxes: ["read-only", "workspace-write", "danger-full-access"], defaultSandbox: "read-only",
32
- },
10
+ claude: { prefix: "cl", defaultSandbox: null },
11
+ codex: { prefix: "cx", defaultSandbox: null },
12
+ gemini: { prefix: "gm", defaultSandbox: "read-only" },
13
+ grok: { prefix: "gk", defaultSandbox: "read-only" },
33
14
  };
34
15
 
35
- export const BACKEND_NAMES = Object.keys(BACKENDS);
36
- export const isBackend = (s) => Object.hasOwn(BACKENDS, s);
16
+ export const SANDBOXES = ["read-only", "workspace-write", "danger-full-access"];
37
17
 
38
- const PREFIXES = BACKEND_NAMES.map((b) => BACKENDS[b].prefix).join("|");
18
+ const PREFIXES = Object.values(BACKENDS).map((b) => b.prefix).join("|");
39
19
  export const JOB_ID_RE = new RegExp(`^(${PREFIXES})-\\d{8}-\\d{6}-[0-9a-f]{4}$`);