agentcruise
v1.0.17
Published
Autopilot for AI coding agents — put Claude / Codex / Gemini on cruise control and loop tasks unattended.
Maintainers
Readme
AgentCruise
🚀 Autopilot for AI coding agents — put Claude Code / OpenAI Codex / Gemini CLI on "cruise control" and loop tasks unattended.
✨ Features
- 🤖 Multi-agent support — one tool drives
claude/codex/gemini, auto-detecting each and injecting its own no-confirmation flags - 🔄 Automatic loops — run the same command any number of times
- ⏱️ Inter-command delay — configurable wait time between commands
- 📊 Visual progress bar — live progress and estimated time remaining
- 🔔 Agent-reported round completion — the agent itself signals when a turn ends, instead of AgentCruise guessing from the screen: Claude Code gets a
Stophook injected via--settings, Codex gets anotifyprogram via-c notify=[...]. Both are single-launch injections that never touch your own config files, and wrapper launchers (cxh/cch) pass them through. Rounds advance the moment the agent reports done, instead of after the silence timeout. Disable with--no-hooks. - 🎯 Smart completion detection — the fallback whenever no signal arrives (unsupported agent, older version,
--no-hooks): soft/hard dual timeout: after silence exceeds the soft timeout, if the screen still shows a busy indicator (e.g. codex'sesc to interruptduring a reasoning stream) it keeps waiting (even beyond the configured hard timeout), so a "busy but quiet" sub-agent isn't mistaken for idle and sent the next command or restarted prematurely - 🏁 Sentinel-based round completion —
--until <sentinel>: when the agent prints the agreed sentinel on its own line, the round is marked done once the busy indicator disappears, then the next one starts — faster and more accurate than pure silence timeout - 🚪 Stand by when done — keep the agent available for manual input or remote commands after all rounds finish; press Ctrl+C to exit.
--exit-on-doneis retained for compatibility and has no effect. - 🛡️ Unattended — automatically handles permission prompts and interactive menus; restarts on disconnect/idle
- 🎛️ Runtime hotkey tuning — press
Ctrl+Owhile running to open a config panel and change loops / delay / timeout / command / launcher / clear / restart mid-run; a local launcher change is queued for the next process restart. Changing the launcher from the dashboard restarts it immediately. - 🕐 Scheduled windows — run only within a given time window (e.g. overnight)
- ✅ Conditional execution — run only when a condition is met (e.g. sufficient credits)
- 🌐 Proxy support — specify a proxy server
- 🌈 Colored logging — clear, color-coded status output
🤖 Supported Agents
| Command | Aliases | Auto-injected flags | Clear command |
|---------|---------|---------------------|---------------|
| claude | cld ccd ccr | --dangerously-skip-permissions | /clear |
| codex | cx | --dangerously-bypass-approvals-and-sandbox | /new |
| gemini | gm | --yolo | /clear |
📦 Installation
Global (npm)
npm install -g agentcruiseFrom source
npm install # local install
npm install -g . # global install from sourceAfter installing you can use agentcruise or the short alias cruise.
🚀 Usage
Basics
# Run once (defaults to claude)
agentcruise "ls -la"
# Use codex / gemini
agentcruise codex "ls -la"
agentcruise gemini "ls -la"
# Run multiple times
agentcruise "ls -la" --loops 5
# Set the delay between commands
cruise "ls -la" --loops 5 --delay 3Options
agentcruise [<agent-command>] <command-to-run> [options]
Positional arguments:
agent-command Command that launches the AI agent (default: claude; also codex / gemini)
command-to-run Command to execute inside the agent
Options:
--loops, -l <n> Number of runs (default: 1)
--delay, -d <sec> Delay between commands (default: 1s)
--timeout, -t <sec> Command execution timeout (default: 30s)
--proxy, -p <addr> Proxy server, e.g. 127.0.0.1:7897 (default: none)
--command, -c <cmd> Command to execute (option form)
--clear Clear before each command (claude: /clear, codex: /new)
--restart Fully stop and restart the agent process after each command
--time <window> Run only within a time window, e.g. 1:00-13:00 (24-hour)
--condition <type> Execution condition check, e.g. aiwithcode (credits > 4000)
--no-hooks Do not inject the completion-signal hooks (claude's --settings Stop
hook / codex's -c notify); fall back to screen detection entirely.
Injected by default (also: AGENTCRUISE_NO_HOOKS=1)
--until <sentinel> When the agent prints this string on its own line, mark the round
done and move on (a note is auto-appended each round telling the
agent to emit the sentinel)
--exit-on-done Compatibility flag; completion leaves the agent standing by (Ctrl+C to exit)Examples
# Basic
agentcruise "echo hello"
# Run codex 10 times, 2s apart
agentcruise codex "date" --loops 10 --delay 2
# Short flags
cruise "pwd" -l 3 -d 5
# Full option form
agentcruise --command "ls -la" --loops 5 --delay 3
# Clear conversation history before each command
agentcruise "echo test" --clear -l 10
# Restart the process after each command
agentcruise "echo test" --restart -l 10
# Only run between 1:00 and 13:00
agentcruise "echo hello" --time 1:00-13:00
# Only run when credits are sufficient
agentcruise "echo hello" --condition aiwithcode -l 10
# Use a proxy server
agentcruise "echo hello" --proxy 127.0.0.1:7897
# Combined: custom agent + proxy + multiple runs
agentcruise codex "ls -la" --proxy 127.0.0.1:7897 --loops 5 --delay 2📊 Progress Bar
When running multiple times (loops > 1), a progress bar is shown:
┌─────────────────────────────────────────────────────────────────────────────┐
│ Progress: [████████████░░░░░░░░] 60% (3/5) │ Since last activity: 15s │
│ Current command: ls -la │ Est. remaining: 2m30s │
└─────────────────────────────────────────────────────────────────────────────┘- 📈 Live progress — current progress and percentage
- ⏰ Activity monitor — time since the agent's last activity
- 🔮 Time estimate — smart estimate of remaining time from elapsed runs
- 🎨 Clean UI — Unicode box-drawing borders
🛠️ How It Works
- Identify the agent — detect claude / codex / gemini from the command and inject the matching no-confirmation flags
- Launch the process — start the AI agent inside a pseudo-terminal (pty)
- Handle permissions — automatically deal with permission prompts and interactive menu selections
- Send the command — use multiple methods to make sure the command is delivered
- Completion detection (rendered terminal state) — after no output for the soft timeout (
-t, default 30s), first check whether the bottom of the screen still shows a busy indicator (esc to interrupt): if still busy, keep waiting until the busy indicator disappears. This avoids mistaking an agent that is quietly waiting on a reasoning stream (e.g. codex) for idle - Self-healing loop — on idle/disconnect/context-overflow, automatically clear or restart, then run the next round after the configured delay
⏱️ About Timeouts
- Agent-reported completion (default on;
--no-hooksorAGENTCRUISE_NO_HOOKS=1to disable). Reading the screen is guesswork — the marker wording changes between agent versions, a narrow terminal truncates it, the agent's own prose can contain it, and a frozen completion frame keeps showing a stale one. So AgentCruise asks the agent to report instead:- Claude Code:
--settings <tmp>injectsStop/UserPromptSubmit/Notificationhooks.--settingsmerges with your own settings, so nothing of yours is overwritten. TheStoppayload also carriesbackground_tasks— a structured list of background shells still running — which replaces screen-scraping for--bg-waitentirely. - Codex:
-c notify=[...]registers a notify program that firesagent-turn-complete. Codex's own hooks are not used: they require a one-off interactive "Hooks need review" trust step that an unattended loop cannot pass, and they never fire undercodex exec.notifyhas no such gate. - Gemini: not wired up yet; it falls back to screen detection.
- Events reach AgentCruise over a private unix socket (not HTTP — a global
HTTP_PROXYcan swallow loopback HTTP hooks). If nothing ever arrives, the timeout path below runs exactly as before. - Troubleshooting:
AGENTCRUISE_HOOK_DEBUG=<path>makes the emitter (src/hook-emit.js) log every step it takes inside the agent process.
- Claude Code:
-t, --timeout <sec>: the soft timeout, the silence threshold for "possibly done" (default 30s). With agent-reported completion working, rounds normally advance well before this.- Hard timeout: defaults to
0(no hard cap). After the soft timeout, a screen that still looks busy keeps the round running. A positive value enables an overdue warning; it never declares a visibly busy agent complete or sends another task:AGENTCRUISE_HARD_TIMEOUT_SEC=300 agentcruise codex "..." -t 30 - Waiting on a background task (
--bg-wait <sec>, default 1800; envAGENTCRUISE_BG_WAIT_SEC, configbgWait): an agent can end its turn while a background shell it started is still running — Claude Code printsBaked for 1m 29s · done 1:43 pm · 1 shell still runningand keeps1 shell · ↓ to manageon its bottom bar, then resumes on its own once the shell exits. This is not "busy" (the prompt is usable andesc to interruptis gone), but injecting the next round there would interrupt the wait or burn a round. AgentCruise therefore keeps the round open while the screen shows a running background shell/terminal, and only declares the round complete once that wait exceeds--bg-wait. The cap is required: the bar keeps showing1 shellfor as long as the process exists (a dev server you left running would otherwise hang the loop forever).--bg-wait 0disables the wait. - Completion detection uses a terminal emulator (the rendered screen, not a tail of raw bytes) to preserve status lines across cursor moves and partial redraws. This matters for both agents: Codex leaves its
Workingfooter untouched for hours, and Claude Code keepsesc to interruptonly on its bottom key-hint bar while each spinner tick rewrites just the spinner line — a byte tail misses the marker while busy (the next command would be queued and injected mid-turn, e.g. right afterRead 1 file) and keeps the stale marker after completion (hangs "busy"). The progress bar counts finished rounds, andidletracks received output even after automatic rounds finish. - Debug event log: set
AGENTCRUISE_EVENT_LOG=<path>to write lifecycle events as JSON Lines —ready/command_sent/idle_complete/idle_but_busy/idle_but_background/bg_wait_expired/restart/all_done, sentinel-basedround_done, agent-reportedsignal_attached/signal_turn_start/signal_turn_done/signal_turn_background/signal_notification, and config-panelconfig_open/config_set/config_close— handy for troubleshooting and automated tests (seetest/). Around_donecarriesreason:signal(the agent reported it),until(sentinel), or it arrives asidle_complete(silence fallback).
🏁 Sentinel-based Round Completion (--until)
By default a round is considered done via silence timeout (plus the busy indicator) — you have to wait until the agent has been quiet long enough. --until is faster and more precise: the agent emits an agreed sentinel on its own line when each round's task is done, and the moment AgentCruise detects that line it marks the round complete and moves to the next one, without waiting for the silence timeout (the busy indicator must disappear first).
# Loop 20 rounds; each round advances once the agent prints <promise>DONE</promise>
agentcruise "continue implementing the next TODO item" -l 20 --until "<promise>DONE</promise>"- No need to write the sentinel instruction yourself: with
--untilenabled, AgentCruise auto-appends a note at the end of each round's command telling the agent to print the sentinel on its own line when done. (If your command already contains the sentinel string, it's assumed you provided the instruction and nothing extra is injected.) - Only counts a sentinel the agent actually emits on its own line: the sentinel inside the injected note is quoted and embedded mid-sentence, so it doesn't occupy a line by itself when the command is echoed — command echo is never mistaken for completion. Only the bare sentinel the agent prints on a fresh line counts.
- Detection waits for a complete terminal line, including Codex's cursor moves between rows. Split color escapes and partial output such as
DONEfollowed by_NOT_DONEdo not trigger completion. The scan buffer is cleared each round. - A match writes a
round_done{reason:"until"}event to the log for automation.
🎛️ Runtime Config Panel (Ctrl+O)
During long unattended runs you often want to tweak a parameter mid-run without interrupting the current turn. Press Ctrl+O anytime to open the config panel (rendered on the terminal's alternate screen; the agent keeps running in the background and its display is restored exactly on exit):
AgentCruise · Runtime parameters (Claude)
────────────────────────────────────
▶ loops 2 left / 20 total
delay 5 s
timeout(soft) 30 s
timeout(hard) 180 s
command "continue with the next todo"
clear ● on
restart ○ off
background 浅灰 light (1/6)
────────────────────────────────────
背景预览:
AgentCruise Claude ▕██████░░░░░░▏ 50% 1/2 示例消息 sample text 00:12:34 · idle 5s · ↑ ...
────────────────────────────────────
↑↓ select Enter edit/toggle q back Esc back↑↓(ork/j) to select a field,Enterto edit a numeric/text field or toggle a boolean,qto return.Esccancels an unsubmitted field edit, or closes the panel; it does not undo settings already submitted with Enter.loopsaccepts an absolute value (e.g.30) or a relative change (+5/-2); it can't be set below the number of runs already completed.backgroundcycles the bottom status-bar color theme (Enter to switch); a live preview of the bar is shown right below the fields. Six themes ship —light(default),paper,sky,mint,rose,dark— all light-background exceptdark.- Loop settings are read by subsequent rounds. A local launcher change takes effect at the next process restart; the panel displays the pending launcher.
- The panel is only available on an interactive TTY; in non-TTY runs (pipe/background) the hotkey is automatically disabled.
Set the default theme without opening the panel via env var:
AGENTCRUISE_BAR_THEME=paper agentcruise "..." -l 20🛰️ Central Control (optional)
An AgentCruise instance still runs fully standalone. Optionally, it can also report its status to a central hub and be controlled remotely — so one dashboard (or any script) can watch every instance's progress and history, and push commands/control to any of them.
The hub is a plain service; the web page is just an optional shell on top of it — any WebSocket client speaks the same protocol, and a REST snapshot is exposed at /api/agents.
Start the hub:
agentcruise serve # binds 127.0.0.1:8787 by default
agentcruise serve --port 9000 --no-web # custom port, disable the web shellPoint an instance at it (per-run flag, env var, or config file):
agentcruise codex "继续做任务" -l 50 --server ws://127.0.0.1:8787 --name box-A- The instance dials out to the hub over WebSocket, so it works behind NAT/inside a private network — the hub only needs one inbound port.
- The link is a pure side-channel: if the hub is down or the connection drops, the instance keeps looping and silently auto-reconnects. Standalone reliability always comes first.
- It reports: current loop
x/y, state, idle/uptime, current command, structured lifecycle events, and a rolling ANSI-stripped output tail. - It accepts, over the same link: command (
send= inject into the agent now) and control — every field of the Ctrl+O panel (loops / delay / soft & hard timeout / looped command / launcher / clear / restart / theme) is editable per instance right from the dashboard. Launcher changes restart that agent automatically; other changes apply live (next round). - The dashboard renders each instance's terminal with xterm.js (faithful ANSI/TUI, colors), and keeps a per-round history you can page through with a dropdown (实时 / 第 k 轮). View modes: grid / rows, plus a per-card maximize (⤢). Choices persist in
localStorage. - Login: the dashboard is password-protected. On first visit you set a password (
sha256stored in the config file); afterwards you log in. Pass--password <pw>to set it without persisting, or--no-authto disable (e.g. tests). Agent dial-in (/agent) is not gated; the dashboard and control/launch are. - Launch from the UI: the + 新建 button starts a new instance — pick a directory, launcher (
cxh/cch/codex/ …), task and loops; the hub spawnsagentcruisethere and it dials back in. (This is effectively remote execution, hence gated behind login.) - First release is localhost, in-memory (state resets when the hub restarts).
Endpoints: ws://host:port/agent (instances), ws://host:port/dashboard (dashboards), GET /api/agents (JSON snapshot), GET / (web shell).
⚙️ Config File
Long-lived settings live in ~/.agentcruise/config.json (e.g. hub URL, default theme, instance name):
{
"server": { "url": "ws://127.0.0.1:8787", "enabled": true },
"theme": "paper",
"name": "box-A"
}Resolution order (highest wins): CLI flag > environment variable > config file > built-in default.
📋 Requirements
- Node.js >= 18 (works on 18 / 20 / 22 / 24 — the native PTY ships prebuilt binaries, so no compiler or specific Node version is required)
- The corresponding AI agent CLI installed (Claude Code / Codex / Gemini)
- An environment that supports pseudo-terminals
🔧 Dependencies
@homebridge/node-pty-prebuilt-multiarch— pseudo-terminal support with prebuilt binaries across Node versions and platforms (no build toolchain needed)ws/playwright— helpers for condition checks and related features
📝 Development
# Clone
git clone https://github.com/fuzihaofzh/agentcruise.git
cd agentcruise
# Install dependencies
npm install
# Local test
./index.js "echo test" --loops 3🤝 Contributing
Issues and Pull Requests are welcome!
📄 License
MIT License
🤖 Generated with Claude Code
Development checks
npm test # CLI, hub, fake-agent loops, TTY controls, restart and resize regressions
npm run test:web # Headless Chromium: dashboard rendering and reconnect behaviorThe core suite uses a local fake agent and localhost sockets; it does not need AI API credentials.
Browser checks require Playwright's Chromium to be installed (npx playwright install chromium).
Loops and timeouts must be positive integers; delay accepts zero. Invalid options fail before launching an agent.
Use cruise codex -c "task" to select a launcher with an explicit task, or cruise -- "--help" for a task beginning with a dash.
Optional real-model checks using your installed free CXH launcher:
node test/cxh-smoke.js basic # Chinese + emoji, two rounds, completion marker
node test/cxh-smoke.js clear # /new before each round
node test/cxh-smoke.js restart # restart the agent between rounds
node test/cxh-smoke.js tool # real shell call with an 8-second waitThese checks use temporary working directories, record terminal output and lifecycle events there, and stop after completion or a four-minute deadline. They require CXH credentials/network access and are not part of npm test. Use the same Node installation/architecture as your installed PTY dependency.
