{"id":47580746,"url":"https://github.com/claw-army/claude-node","last_synced_at":"2026-04-01T17:01:14.689Z","repository":{"id":346110111,"uuid":"1188538173","full_name":"claw-army/claude-node","owner":"claw-army","description":"claude-node runs the installed Claude Code CLI as the runtime, giving Python code direct access to Claude Code’s native capabilities with high compatibility, explicit control, and minimal abstraction.","archived":false,"fork":false,"pushed_at":"2026-03-22T08:19:55.000Z","size":54,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-22T23:13:01.876Z","etag":null,"topics":["agent-routing","agentic-code","agentic-coding","ai","ai-workflow-optimization","anthropic","claude-code","coding-agents","llm","runtime-deploy","stream-json"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/claw-army.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-22T08:11:58.000Z","updated_at":"2026-03-22T15:59:04.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/claw-army/claude-node","commit_stats":null,"previous_names":["claw-army/claude-node"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/claw-army/claude-node","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/claw-army%2Fclaude-node","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/claw-army%2Fclaude-node/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/claw-army%2Fclaude-node/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/claw-army%2Fclaude-node/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/claw-army","download_url":"https://codeload.github.com/claw-army/claude-node/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/claw-army%2Fclaude-node/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31290538,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T13:12:26.723Z","status":"ssl_error","status_checked_at":"2026-04-01T13:12:25.102Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent-routing","agentic-code","agentic-coding","ai","ai-workflow-optimization","anthropic","claude-code","coding-agents","llm","runtime-deploy","stream-json"],"created_at":"2026-03-31T19:00:16.618Z","updated_at":"2026-04-01T17:01:14.678Z","avatar_url":"https://github.com/claw-army.png","language":"Python","funding_links":[],"categories":["Cloud Infrastructure","SDKs","Development Tools Mcp Servers","📂 Server Implementations","Official Resources","Plugins","Contributing","Development"],"sub_categories":["🖥️ Command Line","Python","All Plugins","Prebuilt releases (macOS / Linux / Windows)","LLM Ops"],"readme":"# claude-node\n\n**A thin subprocess-based Python bridge for persistent Claude Code sessions.**\n\n`claude-node` drives the local `claude` CLI as a long-lived subprocess and communicates with it over `stream-json`. Because it runs the installed CLI directly as its runtime, Python code gets access to Claude Code's native behavior through the CLI itself — achieving maximum compatibility with the CLI.\n\nThis is not a higher-level reimplementation or a message API wrapper. It is a direct bridge to the installed `claude` executable.\n\n---\n\n## The CLI bridge\n\n`claude-node` sits at the subprocess boundary:\n\n```\nYour Python code          claude-node           Your local claude CLI\n─────────────────        ────────────          ──────────────────────\nClaudeController  ───►   stdin/stdout   ───►   Claude Code runtime\n                    ◄──   JSON events  ◄───\n```\n\n- **Maximum compatibility**: because `claude-node` delegates entirely to the local `claude` CLI, any capability the CLI exposes is available — skills, slash commands, tools, agent modes, and session management.\n- **Process isolation**: the Claude runtime lives in its own OS process, independent of the Python interpreter.\n- **Protocol transparency**: raw `stream-json` behavior is visible and debuggable.\n- **Easy embedding**: drop it into any Python environment — workers, web backends, job runners, or supervisor processes.\n\n---\n\n## Positioning\n\n`claude-node` gives Python direct control over the real local Claude Code runtime. It preserves native CLI capabilities with `stream-json`, explicit session lifecycle, and process-level supervision — built for embedding and integration, not for hiding Claude behind another framework.\n\n**What this is not**\n\n* Not another high-level agent framework\n* Not a reimplementation of Claude\n* Not a wrapper that hides the CLI behind a new abstraction\n* Not a workflow or memory platform\n\n**What this is**\n\n* A thin Python runtime layer for controlling the real local Claude Code process\n* A subprocess-first integration surface with explicit session and process control\n* A practical foundation for embedding Claude Code into backends, workers, and internal tooling\n\n---\n\n## Runtime model\n\nThis project is a **pure Python package**, but it has an **external runtime dependency**:\n\n- The package itself is standard Python.\n- At runtime, it requires a local `claude` executable in `PATH`.\n\nIn other words:\n\n- `pip install claude-node` installs the Python package.\n- `claude-node` only works if `claude --version` works on that machine.\n\nThis split is intentional. The project does not attempt to ship or emulate Claude Code. It controls an existing local Claude Code runtime.\n\n---\n\n## Installation\n\n### Python package\n\n```bash\npip install claude-node\n```\n\n### Runtime requirement\n\nMake sure Claude Code / Claude CLI is installed and available:\n\n```bash\nclaude --version\n```\n\nIf that command fails, `claude-node` cannot start a session.\n\n---\n\n## Requirements\n\n- Python 3.11+\n- a local `claude` executable in `PATH`\n- a working Claude Code login / configuration on the host machine\n- macOS or Linux recommended\n\nWindows support has not been validated in this repository.\n\n---\n\n## Quick start\n\n### Single controller\n\n```python\nfrom claude_node import ClaudeController\n\nwith ClaudeController(skip_permissions=True) as ctrl:\n    result = ctrl.send(\"List the files in the current directory\")\n    if result:\n        print(result.result_text)\n        print(\"session:\", ctrl.session_id)\n```\n\n### Real-time callback\n\n```python\ndef on_message(msg):\n    if msg.is_assistant:\n        for text in msg.assistant_texts:\n            print(\"[assistant]\", text)\n    if msg.is_tool_result:\n        for block in msg.tool_results:\n            print(\"[tool_result]\", block.get(\"tool_use_id\"), block.get(\"is_error\"))\n\nctrl = ClaudeController(on_message=on_message, skip_permissions=True)\nctrl.start()\nresult = ctrl.send(\"Run the tests and summarize failures\", timeout=120)\nctrl.stop()\n```\n\n### Resume a session\n\n```python\nfrom claude_node import ClaudeController\n\nwith ClaudeController(skip_permissions=True) as ctrl:\n    result = ctrl.send(\"Remember that the project codename is ALPHA. Reply only OK.\")\n    saved_session_id = ctrl.session_id\n\nctrl = ClaudeController(resume=saved_session_id, skip_permissions=True)\nctrl.start()\nresult = ctrl.send(\"What is the project codename?\")\nprint(result.result_text if result else None)\nctrl.stop()\n```\n\n### Lightweight multi-session routing\n\n```python\nfrom claude_node import MultiAgentRouter, AgentNode\n\nwith MultiAgentRouter() as router:\n    router.add(AgentNode(\"PM\", system_prompt=\"You are a product manager.\"))\n    router.add(AgentNode(\"DEV\", system_prompt=\"You are a backend engineer.\"))\n    router.start_all()\n\n    pm_reply = router.send(\"PM\", \"Design a JWT login feature.\")\n    dev_reply = router.route(\n        pm_reply or \"\",\n        to=\"DEV\",\n        wrap=\"PM proposal:\\n{message}\\n\\nPlease review technical feasibility.\",\n    )\n\n    print(\"PM:\", pm_reply)\n    print(\"DEV:\", dev_reply)\n```\n\n---\n\n## Public API\n\nThe current public surface is intentionally small:\n\n```python\nfrom claude_node import (\n    ClaudeController,\n    ClaudeMessage,\n    MultiAgentRouter,\n    AgentNode,\n)\n```\n\n### `ClaudeController`\n\nControls one long-lived Claude CLI subprocess.\n\nCurrent responsibilities:\n\n- start / stop one `claude` process,\n- write `user` messages to stdin,\n- read JSON lines from stdout / stderr,\n- wait for `type=result` as the turn-completion signal,\n- track `session_id`,\n- provide parsed messages via `ClaudeMessage`,\n- expose simple callbacks through `on_message`.\n\n### `ClaudeMessage`\n\nRepresents one parsed JSON event from the CLI stream.\n\nUseful helpers include:\n\n- `is_init`\n- `is_result`\n- `is_result_ok`\n- `is_result_error`\n- `is_api_error`\n- `truly_succeeded`\n- `is_assistant`\n- `is_tool_result`\n- `assistant_texts`\n- `tool_calls`\n- `tool_results`\n- `result_text`\n- `session_id`\n- `cost_usd`\n- `num_turns`\n\n### `MultiAgentRouter`\n\nA minimal multi-session routing layer.\n\nIt currently provides:\n\n- named node registration,\n- bulk start / stop,\n- send to one named agent,\n- message wrapping and routing,\n- simple parallel fan-out,\n- access to an underlying controller via `get_ctrl()`.\n\nThis is a lightweight primitive layer, not a full orchestration framework.\n\n---\n\n## Current architecture\n\n```text\nclaude_node/\n├── __init__.py       # Public exports\n├── controller.py     # ClaudeController, ClaudeMessage\n├── router.py        # AgentNode, MultiAgentRouter\n├── runtime.py       # Binary discovery and version checking\n└── exceptions.py    # Typed exception hierarchy\n```\n\n### `controller.py`\n\nContains:\n\n- `ClaudeMessage`\n- `ClaudeController`\n- `_send_lock` for serializing concurrent send calls\n\n### `router.py`\n\nContains:\n\n- `AgentNode`\n- `MultiAgentRouter`\n\n### `runtime.py`\n\nBinary discovery and version introspection:\n\n- `find_claude_binary(cli_path)` — resolve CLI path via `shutil.which`\n- `get_claude_version(binary_path)` — read version from `--version`\n- `check_claude_available(cli_path)` — raises `ClaudeBinaryNotFound` if missing\n\n### `exceptions.py`\n\nTyped exception hierarchy (all inherit from `ClaudeError → RuntimeError`):\n\n- `ClaudeBinaryNotFound` — claude binary not in PATH\n- `ClaudeStartupError` — subprocess failed to start\n- `ClaudeTimeoutError` — operation exceeded timeout\n- `ClaudeSendConflictError` — concurrent send to same controller\n\nThe codebase is intentionally compact. The long-term direction is to keep the library **narrow and dependable**, not large and feature-heavy.\n\n---\n\n## The protocol this library is built on\n\n`claude-node` communicates with Claude Code through newline-delimited JSON over stdin/stdout.\n\nTypical launch shape:\n\n```bash\nclaude --input-format stream-json --output-format stream-json --verbose\n```\n\nTypical input shape:\n\n```json\n{\"type\":\"user\",\"message\":{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"your message\"}]}}\n```\n\nTypical output flow per turn:\n\n1. `system/init` — appears on initial startup and includes session metadata\n2. `assistant` — may include thinking, text, and `tool_use` blocks\n3. `user/tool_result` — emitted by the CLI after internal tool execution\n4. `result` — the turn is complete; this is the main synchronization point\n\nThe most important rule is simple:\n\n\u003e Wait for `type=result` before sending the next message.\n\nThat rule is the backbone of the current implementation.\n\n---\n\n## Session model\n\nThe repository currently supports:\n\n- new sessions,\n- explicit resume via `resume=\u003csession_id\u003e`,\n- implicit “continue most recent” via `continue_session=True`,\n- session forking via `controller.fork()` — creates a new controller resuming the current session.\n\n### Recommended practice\n\nIn multi-session or multi-node environments, prefer:\n\n- explicit `resume=\u003csession_id\u003e`\n\nand avoid depending on:\n\n- `--continue`\n\nbecause `--continue` resumes the most recent session in the working directory rather than the exact session you intend.\n\n### Important note\n\nThe README you are reading is intentionally honest about the **current code**:\n\n- `resume` exists now,\n- `continue_session` exists now,\n- `fork()` exists now — creates a new controller resuming the current session.\n\n---\n\n## Current status and known limitations\n\nThis repository is functional and in **alpha** state.\n\n### What works now\n\n- persistent Claude subprocess control,\n- multi-turn sessions,\n- result waiting,\n- assistant / tool result parsing,\n- basic session resume,\n- session forking via `controller.fork()`,\n- lightweight router patterns,\n- controller-level send serialization (`_send_lock`),\n- structured exception hierarchy (`ClaudeError`, `ClaudeBinaryNotFound`, etc.),\n- runtime discovery (`claude_node.runtime`),\n- transcript / JSONL export (`transcript_path` parameter).\n\n### Current limitations\n\n- `send()` timeout returns `None` rather than raising `ClaudeTimeoutError` (partial exception integration),\n- integration tests require a working local `claude` binary and are opt-in (see [CONTRIBUTING.md](CONTRIBUTING.md)).\n\nThis is why the project should currently be described as **alpha**.\n\nFor the full list of known limitations, see [docs/06-roadmap-and-limitations.md](docs/06-roadmap-and-limitations.md).\n\n---\n\n## Design principles\n\nThese principles define the project’s direction.\n\n### 1. Subprocess-first\nThe library controls a real Claude CLI process.\n\n### 2. Thin wrapper, not platform\nThe goal is a dependable bridge, not a giant framework.\n\n### 3. Explicit session control\nLifecycle, resume behavior, and routing should stay visible and controllable.\n\n### 4. Protocol transparency\nThe stream should remain understandable and debuggable.\n\n### 5. Lightweight routing only\nMulti-session patterns are welcome; orchestration sprawl is not.\n\n---\n\n## Documentation map\n\nAdditional docs live under `docs/`:\n\n- `docs/00-index.md` — documentation index\n- `docs/01-positioning.md` — project identity and scope\n- `docs/02-architecture.md` — architecture and internal boundaries\n- `docs/03-api-reference.md` — API reference based on the current code\n- `docs/04-protocol.md` — stream-json protocol notes\n- `docs/05-development.md` — repository workflow and testing reality\n- `docs/06-roadmap-and-limitations.md` — current gaps and next steps\n\n### Runnable examples\n\nAll examples are in `examples/`:\n\n- [`examples/demo_end_to_end.py`](examples/demo_end_to_end.py) — library usage reference (all core APIs)\n- [`examples/demo_cli_native_features.py`](examples/demo_cli_native_features.py) — CLI-native capabilities (skills, callbacks, transcript)\n- [`examples/demo_protocol_trace.py`](examples/demo_protocol_trace.py) — raw stream-json protocol reference\n\nSee [`examples/README.md`](examples/README.md) for the full demo map.\n\n---\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for contribution guidelines, testing instructions, and scope boundaries.\n\n---\n\n## License\n\nApache-2.0\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclaw-army%2Fclaude-node","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fclaw-army%2Fclaude-node","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclaw-army%2Fclaude-node/lists"}