{"_id":"@buzzie-ai/claude-inject","_rev":"3-dd4b850c629d2cfe8c1a43551b265b1a","name":"@buzzie-ai/claude-inject","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.0":{"name":"@buzzie-ai/claude-inject","version":"0.1.0","keywords":["claude","claude-code","anthropic","sdk","agent","automation","channel","mcp"],"author":{"url":"https://github.com/Buzzie-AI","name":"Buzzie AI"},"license":"MIT","_id":"@buzzie-ai/claude-inject@0.1.0","maintainers":[{"name":"buzzie","email":"arvind.raj.naidu@gmail.com"}],"homepage":"https://github.com/Buzzie-AI/claude-inject#readme","bugs":{"url":"https://github.com/Buzzie-AI/claude-inject/issues"},"dist":{"shasum":"8a993322cddc819d7c3e39f3b0dc3b148776adc1","tarball":"https://registry.npmjs.org/@buzzie-ai/claude-inject/-/claude-inject-0.1.0.tgz","fileCount":15,"integrity":"sha512-YHXJbFuqNalmJCcT60PReLHAP4OeuMS0c4LxayWcT75r/kqf1RZ9JV1czy3+NmLr04hxC5OAt2wDxpRFbwQavw==","signatures":[{"sig":"MEUCIA2MbUxs5rPFXmURg1zjKFCy15cPfInY0TV6pscx1jmWAiEAuN5KDxE7UFWK8RBp0f76dRAVcAvCr3g2W+BA2pHkVAk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":32454},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=20"},"gitHead":"b331c61d621873060da310c3671d46f842e90e4f","scripts":{"test":"npm run test:session && npm run test:role-check","build":"tsc","demo:simple":"tsx examples/simple/index.ts","test:session":"npx tsx test/session.test.ts","prepublishOnly":"npm run build","test:role-check":"npx tsx test/role-check.ts","demo:two-claudes":"tsx examples/two-claudes/index.ts"},"_npmUser":{"name":"buzzie","email":"arvind.raj.naidu@gmail.com"},"repository":{"url":"git+https://github.com/Buzzie-AI/claude-inject.git","type":"git"},"_npmVersion":"10.9.4","description":"SDK to launch a Claude Code session in a child process and inject prompts into it programmatically. A 'good enough' replacement for the experimental channel mechanism in environments where channels are disabled.","directories":{},"_nodeVersion":"22.22.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.0.0","blessed":"^0.1.81","commander":"^12.0.0","typescript":"^5.0.0","@types/node":"^20.0.0","@types/blessed":"^0.1.25"},"_npmOperationalInternal":{"tmp":"tmp/claude-inject_0.1.0_1778187108898_0.004511082894326446","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Pre-rewrite docs and stale description. Please upgrade to 0.1.1+ (no API changes)."},"0.1.1":{"name":"@buzzie-ai/claude-inject","version":"0.1.1","keywords":["claude","claude-code","anthropic","sdk","agent","automation","channel","mcp"],"author":{"url":"https://github.com/Buzzie-AI","name":"Buzzie AI"},"license":"MIT","_id":"@buzzie-ai/claude-inject@0.1.1","maintainers":[{"name":"buzzie","email":"arvind.raj.naidu@gmail.com"}],"homepage":"https://github.com/Buzzie-AI/claude-inject#readme","bugs":{"url":"https://github.com/Buzzie-AI/claude-inject/issues"},"dist":{"shasum":"de4dd9a9595df54767bbb03fbb276f1bdb02cf6d","tarball":"https://registry.npmjs.org/@buzzie-ai/claude-inject/-/claude-inject-0.1.1.tgz","fileCount":15,"integrity":"sha512-hxZJmAPTAjFu3d6F6vUbo644SWsl/gdgF8/90Q1Ez08V7nZdW8AE/bUGCQtKrq+Dzl6lQvjw07RhyEdMqwL6vw==","signatures":[{"sig":"MEQCIE5c90m/qLHllFHWmq/mwqgl+zCDhPGL9SzQ9msO4N4TAiBtKDs2IWrThJxpeeTp05hhL/PrnlxcdwP+xKZjI0ox/w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":34674},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=20"},"gitHead":"e5d479ceac0a652e534b1630c896bba920d4be48","scripts":{"test":"npm run test:session && npm run test:role-check","build":"tsc","demo:simple":"tsx examples/simple/index.ts","test:session":"npx tsx test/session.test.ts","prepublishOnly":"npm run build","test:role-check":"npx tsx test/role-check.ts","demo:two-claudes":"tsx examples/two-claudes/index.ts"},"_npmUser":{"name":"buzzie","email":"arvind.raj.naidu@gmail.com"},"repository":{"url":"git+https://github.com/Buzzie-AI/claude-inject.git","type":"git"},"_npmVersion":"10.9.4","description":"Drive a long-lived Claude Code session from Node, with structured event streams instead of PTY scraping. Wraps the local claude CLI via stream-json, inheriting the user's existing auth and MCP/plugin config.","directories":{},"_nodeVersion":"22.22.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.0.0","blessed":"^0.1.81","commander":"^12.0.0","typescript":"^5.0.0","@types/node":"^20.0.0","@types/blessed":"^0.1.25"},"_npmOperationalInternal":{"tmp":"tmp/claude-inject_0.1.1_1778438972673_0.6742609452131643","host":"s3://npm-registry-packages-npm-production"}}},"time":{"created":"2026-05-07T20:51:48.833Z","modified":"2026-05-10T18:50:42.349Z","0.1.0":"2026-05-07T20:51:49.027Z","0.1.1":"2026-05-10T18:49:32.832Z"},"bugs":{"url":"https://github.com/Buzzie-AI/claude-inject/issues"},"author":{"url":"https://github.com/Buzzie-AI","name":"Buzzie AI"},"license":"MIT","homepage":"https://github.com/Buzzie-AI/claude-inject#readme","keywords":["claude","claude-code","anthropic","sdk","agent","automation","channel","mcp"],"repository":{"url":"git+https://github.com/Buzzie-AI/claude-inject.git","type":"git"},"description":"Drive a long-lived Claude Code session from Node, with structured event streams instead of PTY scraping. Wraps the local claude CLI via stream-json, inheriting the user's existing auth and MCP/plugin config.","maintainers":[{"name":"buzzie","email":"arvind.raj.naidu@gmail.com"}],"readme":"# claude-inject\n\nAn SDK that launches a Claude Code session in a child process and lets you inject prompts into it programmatically — getting structured event streams and full text replies back.\n\n## Why\n\nDrive a long-lived Claude Code session from Node, with structured event streams instead of PTY scraping.\n\nThe Claude Code CLI already supports streaming JSON I/O (`--input-format stream-json --output-format stream-json`), but using it correctly across many turns — keeping one subprocess alive, framing prompts as NDJSON, parsing partial-message events, tracking the session UUID for resume — is enough fiddly plumbing that most people give up and shell out to `claude -p` one-shot per turn.\n\n`claude-inject` is that plumbing as a small SDK: your code *owns* a persistent `claude` process and feeds it prompts. You get tool-call events, streaming text chunks, and full replies back as typed events. Same authentication, same MCP/plugin config, and same tool permissions as the user's interactive Claude Code — no API key required.\n\n## How it works\n\nUnder the hood, the SDK spawns:\n\n```\nclaude -p --input-format stream-json --output-format stream-json \\\n          --include-partial-messages --verbose\n```\n\nThat keeps `claude` alive across many user messages: each `session.send(...)` writes a single line of NDJSON to stdin, and the SDK parses the streamed events back out of stdout. There's no PTY scraping and no terminal escape-code parsing — everything is structured.\n\n## How this differs from the Claude Agent SDK\n\nAnthropic ships an official [Claude Agent SDK](https://docs.anthropic.com/en/api/agent-sdk) that talks to the Anthropic API directly. If you're building a standalone agent from scratch with your own MCP/tool wiring and you have an API key, that's the right tool.\n\n`claude-inject` is for the case where you want to drive **Claude Code itself** — the user's already-installed, already-authenticated CLI — from code:\n\n|  | Claude Agent SDK | `claude-inject` |\n|---|---|---|\n| Talks to | Anthropic API | Local `claude` CLI binary |\n| Auth | API key | Inherits user's existing Claude Code auth |\n| MCP / plugins / tool permissions | You configure | Inherits user's existing config |\n| Updates | SDK version bumps | Free — comes with `claude` CLI updates |\n| Dependency | `@anthropic-ai/sdk` | `claude` on PATH + its stream-json protocol |\n| Best for | Building a new agent end-to-end | Scripting / extending an existing Claude Code setup |\n\nThe tradeoff is that `claude-inject` is coupled to the CLI binary and its stream-json protocol. Pin the `claude` CLI version in CI if reproducibility matters.\n\n## Limitations\n\nWorth knowing before you adopt this:\n\n- **No human in the loop.** Permission prompts don't surface to a UI — the spawned `claude` runs headless under whatever `permissionMode` / `tools` config you pass. If you need per-tool-call approval, build that yourself.\n- **One `send()` in flight at a time per session.** Subsequent calls queue FIFO. Spawn multiple `ClaudeSession`s for parallelism.\n- **`dangerouslySkipPermissions` is a foot-gun.** Same caveat as the underlying CLI flag — only use it in trusted, sandboxed contexts.\n- **Behavior depends on the installed `claude` CLI version.** The stream-json event shapes can shift between CLI releases. Pin the version in CI.\n- **Session resume requires a previous session UUID.** `sessionId` is populated during the first `send()` (not `start()`), because stream-json mode doesn't emit `system/init` until the first message arrives.\n\n## Install\n\n```bash\nnpm install @buzzie-ai/claude-inject\n```\n\nRequires Node ≥ 20 and the `claude` CLI (Claude Code) on your PATH (or pass `claudePath` explicitly).\n\n### Local development\n\n```bash\ngit clone https://github.com/Buzzie-AI/claude-inject\ncd claude-inject\nnpm install\nnpm run build\n```\n\n## Quick start\n\n```ts\nimport { ClaudeSession } from '@buzzie-ai/claude-inject';\n\nconst session = new ClaudeSession({\n  cwd: process.cwd(),\n  systemPrompt: 'You are a helpful assistant. Be concise.',\n});\n\nsession.on('chunk', (text) => process.stdout.write(text));\nsession.on('tool_use', ({ name }) => console.log(`[${name}]`));\n\nawait session.start();\nconst reply = await session.send('Hello, what is 2 + 2?');\nconsole.log('\\nReply:', reply);\n\nconst reply2 = await session.send('And times 3?');\nconsole.log('\\nReply2:', reply2);  // same session — claude remembers turn 1\n\nawait session.close();\n```\n\n## API\n\n### `new ClaudeSession(options)`\n\n| Option | Type | Notes |\n|---|---|---|\n| `cwd` | `string` | Working dir. Defaults to `process.cwd()`. |\n| `systemPrompt` | `string` | Sent on first start; ignored on resume. |\n| `claudePath` | `string` | Path to `claude`. Defaults to PATH lookup. |\n| `tools` | `string` | `\"\"` disables all, `\"default\"` enables all, or `\"Bash,Edit,Read\"`. |\n| `allowedTools` | `string[]` | Allowlist alternative to `tools`. |\n| `disallowedTools` | `string[]` | Denylist. |\n| `permissionMode` | `'acceptEdits' \\| 'auto' \\| 'bypassPermissions' \\| 'default' \\| 'dontAsk' \\| 'plan'` | |\n| `dangerouslySkipPermissions` | `boolean` | Equivalent to `--dangerously-skip-permissions`. |\n| `model` | `string` | Alias (`opus`, `sonnet`, `haiku`) or full ID. |\n| `sessionId` | `string` | Pin the session UUID. |\n| `resumeSessionId` | `string` | Resume an existing session by UUID. |\n| `persistSession` | `boolean` | Defaults to `true` (matches the CLI). |\n| `env` | `NodeJS.ProcessEnv` | Extra env vars. |\n\n### Methods\n\n- **`start(): Promise<void>`** — spawn `claude` and resolve as soon as the subprocess is running. (In stream-json input mode, claude doesn't emit anything until you send the first message, so `sessionId` is populated during the first `send()`, not during `start()`.)\n- **`send(prompt: string): Promise<string>`** — inject a prompt, resolve with the full text reply. Multiple concurrent calls queue (FIFO).\n- **`close(): Promise<void>`** — close stdin and wait for the subprocess to exit.\n\n### Getters\n\n- **`busy: boolean`** — true while a `send()` is in flight or queued.\n- **`sessionId: string | null`** — captured from the `system/init` event.\n\n### Events\n\n| Event | Payload | When |\n|---|---|---|\n| `chunk` | `string` | Text deltas as they stream |\n| `tool_use` | `{ id, name, input }` | A tool call starts |\n| `tool_result` | `{ toolUseId, content, isError }` | A tool call's result is folded back in |\n| `assistant_message` | `{ text }` | Full assistant turn (concatenation of all text blocks) |\n| `result` | `{ text, isError, sessionId }` | A turn finishes |\n| `error` | `Error` | Subprocess error |\n| `exit` | `{ code, stderr }` | Subprocess exited |\n\n### Concurrency\n\nOne `send()` is in flight at a time. Subsequent calls queue and resolve in order. Inspect with `session.busy`.\n\n## Examples\n\n- [`examples/simple/`](examples/simple/) — 25-line \"start → send twice → close\"\n  ```bash\n  npm run demo:simple\n  ```\n- [`examples/two-claudes/`](examples/two-claudes/) — the original Director / Builder / Worker TUI demo, refactored to drive two `ClaudeSession`s\n  ```bash\n  npm run demo:two-claudes -- --builder --turns 6 --seed 'I want a program that prints hello world.'\n  ```\n\n## Tests\n\n```bash\nnpm run test:session     # SDK end-to-end (spawn, send twice, assert)\nnpm run test:role-check  # Builder-mode role check via examples/two-claudes\nnpm test                 # both\n```\n\n## History\n\nThis started as a **Director pattern** experiment: two `claude -p` subprocesses conversing with each other, rendered side-by-side in a `blessed` TUI. The original code spawned a one-shot subprocess per turn and chained them by hand.\n\nThe SDK pivot replaces the one-shot pattern with a persistent `claude -p --input-format stream-json` subprocess that stays alive across many user messages — closer to what an interactive session feels like, but driven by code instead of a human keyboard. The original two-Claude TUI lives on as `examples/two-claudes/`.\n","readmeFilename":"README.md"}