iah-localagent
v0.1.0
Published
IAH localagent daemon — runs a Claude-backed agent on your machine and serves IAH page chat over HTTP polling. npx, no Python/uv.
Readme
iah-localagent
Run a localagent on your own machine and chat with it from the IAH web page.
iah-localagent is a small Node/TS daemon (runnable via npx, no Python/uv).
It polls IAH for queued chat turns, runs each one through your local
claude CLI, and posts the reply back —
so the IAH page can talk to an agent that executes on your laptop instead of a
cloud pod.
v1 scope: HTTP polling, one turn at a time, text in / text out. No MCP/tools, attachments, install-service, or token streaming (those are deliberately out).
Quick start
# 1. In the IAH web page: add a localagent. It shows a one-time token.
# 2. On your machine:
npx iah-localagent start \
--server-url http://127.0.0.1:3000 \
--token <the-one-time-token>Check your setup without running the loop:
npx iah-localagent doctor --server-url http://127.0.0.1:3000 --token <token>Options
| flag | env | default | meaning |
|---|---|---|---|
| --server-url <url> | IAH_LOCALAGENT_SERVER_URL | — | iah-fe base URL |
| --token <token> | IAH_LOCALAGENT_TOKEN | — | per-localagent bearer token (shown once when you add it) |
| --poll-interval <sec> | | 3 | queue poll cadence |
| --ready-interval <sec> | | 20 | heartbeat cadence |
| --turn-timeout <sec> | | 540 | per-turn claude timeout (< the 600s server lease) |
| --claude-bin <path> | IAH_LOCALAGENT_CLAUDE_BIN | claude | claude executable |
| --once | | | run one turn then exit (for testing) |
| --debug | | | verbose logging |
The token is never written to logs (only a ***xxxx fingerprint).
How it works
IAH page ──▶ iah-fe ──▶ iah backend this daemon (your machine)
chat Bearer /internal/localagent ▲ poll = claim
proxy + turns queue (lease) │ GET /turns/pending
X-Internal-Secret │ run claude -p
│ POST /turns/{id}/result
└──── heartbeat /ready- Preflight (
start/doctor): refuses to run unless theclaudeCLI is present and the server accepts the token. A missing CLI or bad token fails loudly at startup instead of hanging a turn later. - Poll == claim:
GET /api/v1/localagent/turns/pendingreturns the single claimed turn (ornull); the server flips it torunningwith a lease. - Execute: the prompt is piped to
claude -p --output-format json(--append-system-promptwhen the server sends one). The servermodelis advisory — the daemon uses your local claude provider config. - Report:
POST .../turns/{id}/resultwith{status:"done", output_text}or{status:"error", error_code, error_message}. Errors surface on the page assession.error. Error codes:CLAUDE_NOT_FOUND,CLAUDE_ENV_MISSING,CLAUDE_CLI_FAILED,CLAUDE_BAD_OUTPUT(the server ownsEMPTY_REPLY/LOCALAGENT_TIMEOUT). - Duplicate / expired / non-running results come back
accepted:falseand are treated as a normal no-op, not retried.
Develop
pnpm install
pnpm typecheck
pnpm test # vitest unit tests
pnpm build # -> dist/bin/iah-localagent.js
node dist/bin/iah-localagent.js --versionLayout: src/{config,protocol,transport,claude-runner,preflight,main-loop,logger}.ts,
CLI at src/bin/iah-localagent.ts. Zero runtime dependencies (Node ≥20 built-ins).
