Lines 1-31javascript
1// Agent harnesses installed on this machine, and how to invoke them headlessly.
3// PHEWSH is not a harness — it's the layer that uses the ones you already
4// have. Each of these carries its OWN auth (Claude Code uses your Claude
5// subscription, Codex your ChatGPT plan, Gemini your Google login), so going
6// through them needs no API key in phewsh at all.
9// phewsh serve — web-dispatched jobs execute through these
10// phewsh ai — harnesses double as no-key providers
12const { execSync, spawn } = require('child_process');
13
HighChild Process
Package source references child process execution.
lib/harnesses.jsView on unpkg · L11 14// args: how to run a one-shot prompt headlessly. args: null = we only know
15// how to launch it interactively (detection + /work still fully supported —
16// never guess flags; a wrong invocation looks like phewsh being broken).
18// args takes (prompt, model). model is passed straight through to the
19// harness's own flag and validated BY the harness — phewsh keeps no model
20// list of its own, so it can never go stale. Harnesses without a known
21// model flag ignore the preference and use their own config.
23 'claude-code': { bin: 'claude', label: 'Claude Code', role: 'writes code', bestFor: 'repo edits, tests, native coding loops', auth: 'Claude subscription / Console', models: true, modelHints: ['sonnet', 'opus', 'haiku'], streamFormat: 'claude-json', args: (p, m) => ['-p', p, '--output-format', 'stream-json', '--include-partial-messages', '--verbose', ...(m ? ['--model', m]
24 'codex': { bin: 'codex', label: 'Codex CLI', role: 'reasons & reviews', bestFor: 'reviews, reasoning, second opinions', auth: 'ChatGPT plan', models: true, args: (p, m) => ['exec', '--skip-git-repo-check', ...(m ? ['-m', m] : []), p], interactiveArgs: (brief, m) => [...(m ? ['-m'
25 'gemini': { bin: 'gemini', label: 'Gemini CLI', role: "another model's take", bestFor: 'broad scans, alternate framing', auth: 'Google login', models: true, args: (p, m) => ['-p', p, ...(m ? ['-m', m] : [])], interactiveArgs: (brief, m) => ['--prompt-interactive', brief, ...(m ? ['--model'
26 'cursor': { bin: 'cursor-agent', label: 'Cursor Agent', role: 'edits files', bestFor: 'editor-side file edits', auth: 'Cursor account', models: true, args: (p, m) => ['-p', p, '--output-format', 'text', ...(m ? ['--model', m] : [])] },
27 'opencode': { bin: 'opencode', label: 'OpenCode', role: 'general agent', bestFor: 'open-source agent work', auth: 'OpenCode Zen / configured', args: (p) => ['run', p], interactiveArgs: (brief) => ['--prompt', brief] },
28 'grok': { bin: 'grok', label: 'Grok Build', role: "xAI's take", bestFor: 'outside take from xAI', auth: 'SuperGrok / X Premium+', args: (p) => ['-p', p] },
29 'kiro': { bin: 'kiro-cli', label: 'Kiro CLI', role: 'spec-driven dev', bestFor: 'spec-driven development', auth: 'Kiro / AWS account', args: (p) => ['chat', '--no-interactive', p] },
30 'copilot': { bin: 'copilot', label: 'Copilot CLI', role: 'github-native', bestFor: 'GitHub-native tasks', auth: 'GitHub Copilot plan', args: (p) => ['-p', p] },
31 'hermes': { bin: 'hermes', label: 'Hermes', role: 'runs loops', bestFor: 'orchestration and continuity', auth: 'Nous account', args: null },