Workflows & Agents
View .md

Coding Agents & Hooks

Transparently offload heavy test, typecheck, and lint runs from Claude Code and Codex worktrees using hooks, load thresholds, and NDJSON events.

Claude Code PreToolUse Hook Filter
Heavy verification commands route to remote slots while local navigation and dev servers stay instant
Agent Bash Call

Claude Code worktree containing .spotexec.toml

spotexec hook
  • 1. Parse shell AST
  • 2. Match tool rules
  • 3. Check when_load_above
Kept Local (0ms overhead)

git, rg, ls, vite dev, --watch, pipes, redirects, SPOTEXEC_LOCAL=1, or idle laptop

Rewritten → spotexec run -- '<cmd>'

vitest, jest, playwright, pytest, tsc, eslint, prettier, cargo/go test, mvn/gradle verify

Running multiple coding agents (Claude Code, Codex, or custom harnesses) across parallel Git worktrees is where laptops hit a wall: the agents themselves are lightweight HTTP loops, while the verification tools they spawn (vitest, playwright, tsc --noEmit, eslint, cargo test, go test) consume gigabytes of RAM per worktree.

spotexec integrates directly with coding agents through two mechanisms:

  1. Transparent command hooks that rewrite heavy verification commands to spotexec run -- '<cmd>' automatically while leaving fast local commands untouched.
  2. Structured NDJSON telemetry on non-TTY stderr, keeping the command's stdout and stderr clean for agent parsing.

Installing the Claude Code Hook#

sh
# Install into .claude/settings.local.json (per-worktree / gitignored)
spotexec hook install --claude

# Or commit into .claude/settings.json (--shared) or install globally in ~/.claude (--global)
spotexec hook install --claude --shared
spotexec hook install --claude --global

# Dry-run any command string to verify whether the hook offloads or keeps it local
spotexec hook check 'pnpm vitest run'
spotexec hook check 'git status'

What Gets Offloaded vs. Kept Local#

The PreToolUse Bash hook inspects the command AST before execution:

diagram
Agent invokes Bash("<command>")
  │
  ├─ Project has .spotexec.toml? ── No ──▶ Run locally (no-op)
  │
  ├─ Prefixed with SPOTEXEC_LOCAL=1, or uses pipes / redirects / background `&` / `cd ..`?
  │   └─ Yes ──▶ Run locally
  │
  ├─ Matches local-only tools (git, rg, ls, dev servers, --watch)?
  │   └─ Yes ──▶ Run locally
  │
  ├─ Matches heavy verification (test suites, tsc, linters, formatters, builds, gradle/mvn verify)
  │  AND laptop normalized load >= when_load_above?
  │   └─ Yes ──▶ Rewrite to: spotexec run -- '<command>'
  │
  └─ Otherwise ──▶ Run locally
  • Offloaded to remote runners: Unit & E2E test suites (vitest, jest, playwright, pytest, go test, cargo test), typecheckers (tsc), linters & formatters (eslint, prettier, biome, ruff, clippy), compilers/bundlers, and Maven/Gradle verify goals.
  • Kept local automatically: git, ls, rg, fd, interactive dev servers (next dev, vite dev), watch modes (--watch), shell pipelines, file redirects, background jobs, commands that cd outside the repository, and any command prefixed with SPOTEXEC_LOCAL=1.

Permission Rules in Claude Code#

The hook never auto-approves commands—it only rewrites the command string before Claude Code evaluates permissions. If you pre-approve test commands in Claude Code, add Bash(spotexec run:*) to your allowed tool list so rewritten commands run without manual prompts.

Load-Based Offloading & [hook] Tuning#

Configure [hook] in .spotexec.toml to offload commands only when your laptop is actually under load:

toml
[hook]
when_load_above = 0.6          # offload only when normalized CPU load exceeds 60%
patterns = ["^pnpm build:"]    # additional regexes to offload
exclude = ["test:unit:fast"]   # regexes to always keep local
# mode = "block"               # deny direct execution with instructions instead of rewriting
# disabled = false             # disable the hook in this repository

Codex and Other Agent Harnesses#

For harnesses without a PreToolUse command-rewriting hook (such as Codex CLI), spotexec generates a concise, machine-targeted section in AGENTS.md instructing the agent when to prefix commands with sx and how to interpret exit code 125 vs test failures:

sh
spotexec hook install --codex      # appends spotexec instructions to AGENTS.md
spotexec hook install --uninstall  # cleanly removes Claude or Codex hook configuration

Machine-Readable NDJSON Telemetry#

Whenever stderr is not a TTY—or when --json or SPOTEXEC_AGENT=1 is set—spotexec replaces the interactive terminal spinner with compact, deterministic NDJSON lifecycle events on stderr. The remote command's own output streams untouched:

json
{"event":"slot_acquired","connect_ms":13,"runner":"aws","slot":3,"waited_ms":0}
{"event":"sync_in","bytes":0,"duration_ms":0,"files":0,"mode":"fingerprint_hit"}
{"event":"sync_out","conflicts":[],"duration_ms":31,"mutated_files":["src/index.ts"]}
{"event":"result","duration_ms":4120,"exit_code":0,"timed_out":false}

Full lifecycle event types emitted for agents and log pipelines (--events-file):

  • Queueing & placement: queued, queue_position, placed, slot_acquired
  • Elastic scaling: scale_out, provision, instance_running, instance_ready
  • Execution pipeline: manifest, sync_in, deps, image, exec, sync_out, pull, cancel, result
  • Spot resilience: spot_interruption, spot_rebalance, retry
  • Diagnostics: warning (with stable codes: SYNC_CONFLICT, RUNNER_LOST, SPOT_INTERRUPTION, TIMEOUT, LOCAL_FALLBACK) and error (SPOTEXEC_ERROR, paired with exit code 125).