CyberClaw: A LangGraph Agent That Forces Skills Through a help-then-run Gate
👾 下一代透明智能体架构 | Next-Gen Transparent Agent Architecture 🔍 全行为审计 | 🛡️ 两段式安全调用 | 🧠 双水位记忆 | ⏰ 心跳任务 📊 P0 级事故率降低 80% | 兼容 OpenClaw + Claude Code 技能生态
At a glance
- What is it?
- CyberClaw is a single-machine Python CLI agent built on LangGraph. Its distinguishing mechanism is a two-phase skill invocation where a one-time help_token must be obtained before a dynamic skill will execute, and the README is unusually candid about what that gate does not prove.
- Who is it for?
- Adopt CyberClaw if you want a readable, MIT-licensed LangGraph agent where dynamic skill execution is gated by a session-bound help_token and every tool call lands in a JSONL file you can tail. Do not adopt it if you need exactly-once tool side effects, OS-level sandboxing, background subagent jobs that survive a restart, or per-user memory isolation; the README says none of those exist yet.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 6 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The problem CyberClaw targets: agents that pick a tool before reading what it does
Most agent loops let the model emit a tool call as soon as it has a plausible name. If the tool is a loaded skill with its own arguments and conventions, the model is guessing. CyberClaw's answer is to split skill use into two calls. The model first invokes the skill in help mode, which returns the full instruction text plus a random help_token. Only then can it invoke run mode with a command and that token. The README states the intent plainly: the model gets the skill description before deciding to execute it or switch to a different skill.
The audience is narrow and specific. This is a single-machine CLI application, not a service. It suits engineers who already work in Python, want their agent's decision path to be inspectable in a terminal, and are willing to run a config wizard before the first prompt. It is also aimed at people who have looked at OpenClaw or Claude Code skills and want to reuse SKILL.md-style descriptions without adopting the Node.js runtime. The README is explicit that OpenClaw is a reference point for product ideas and the SKILL.md convention, and that this is not a module-by-module port with feature parity.
The state graph and where the two-phase gate actually sits
The workflow is a LangGraph state graph with three nodes: START goes to agent, agent goes to tools, tools goes back to agent, and the request ends when the model stops returning tool_calls. Session state lives in SQLite through AsyncSqliteSaver, keyed by thread_id, storing messages and summary. Context trimming happens by turn, not by token: the helper trim_context_messages defaults to 8/4, but agent_node passes 40/10, so once the main call reaches 40 turns it keeps the 10 most recent and asks the LLM to merge the older summary. The README notes these watermarks are only adjustable in code, with no CLI setting, and that trimming fires on reaching the threshold rather than every 40 new turns.
The gate itself is enforcement in the skill loader, not a prompt instruction. When run is called, the loader checks the thread_id from trusted runtime config, the skill identity, the description path, and a SHA-256 of the description content. The credential lives 300 seconds and is consumed atomically before the executor is reached; concurrent reuse of the same token is allowed at most once. Missing, cross-session, cross-skill, expired, replayed, or description-changed cases all refuse execution. A new help call replaces the old credential for that skill in that session, and clearing the cache or restarting the process revokes credentials too.
One detail deserves emphasis because it is easy to misread as a security boundary. The README states that the credential proves the session obtained that version of the description. It does not prove the model understood it, that execution is safe, or that the user authorized anything. The gate constrains the dynamic skill interface only. The built-in execute_office_shell is a separate tool with its own whitelist-based checks.
Getting a session running: commands, config keys, and the workspace path
The README gives a Linux or WSL2 sequence: git clone the repository, cd into it, create a venv with python3 -m venv .venv, activate it, run python -m pip install -e ., then cyberclaw config followed by cyberclaw run. On Windows PowerShell the activation line is .\.venv\Scripts\Activate.ps1. Python 3.10 or newer is required. The config wizard writes model settings and tests ordinary message connectivity.
If you prefer to write configuration by hand, copy .env.example to .env and set DEFAULT_PROVIDER, DEFAULT_MODEL, the matching API key, and the base URL. OpenAI-compatible endpoints use OPENAI_API_KEY with an optional OPENAI_API_BASE. The Anthropic branch needs langchain-anthropic installed separately, and the Ollama branch needs langchain-community plus a running local model server. The README states these optional branches were not validated against real APIs in the regression that produced the current documentation, so treat them as unproven paths.
Data lands in a workspace directory under the project by default. CYBERCLAW_WORKSPACE overrides that with a writable directory of your choosing, which you will want on any deployment where the checkout is not writable. A second terminal can run cyberclaw monitor to watch logs for the current CLI session. /exit ends the CLI, and the README notes heartbeat tasks stop with the main process. Skills go under workspace/office/skills/<skill-name>/ with a SKILL.md and optional scripts; the {baseDir} placeholder in a command expands to that skill directory relative to office.
Subagent delegation: in-process, budgeted, and not a job queue
The default CLI registers a delegate_task tool. Two preset roles ship with it: code_reviewer and document_analyst, both limited to listing directories and reading files. The main agent can also define an ad-hoc role at delegation time by supplying agent_name, instructions, and tool_names. The host validates the tool whitelist, rejects out-of-scope tools, and refuses attempts to override the presets. Ad-hoc roles exist for that delegation only; they are not registered permanently.
Each subtask gets a fresh message context and execution thread_id. It does not inherit the parent checkpoint or the global user profile, and a subagent cannot delegate further. The budgets are concrete: at most 2 concurrent subgraph calls per app with busy returned on excess, a 120-second wait budget, at most 16 graph steps, and a 6000-character cap on the returned result. The main agent is expected to inspect statuses such as completed, failed, and timeout. The README is honest that timeout is cooperative cancellation and cannot guarantee that an already-started synchronous tool, thread, or remote request stops immediately.
This is in-process delegation where the main task waits. Subgraphs are not persisted, so a restart cannot resume them, and the README states that tool registration isolation is not an OS sandbox. If you need durable background work with retries, CyberClaw's delegate_task is the wrong primitive. SDK callers can set allow_dynamic_subagents=False to keep only the presets, adjust dynamic_subagent_tools, or disable the feature with enable_subagents=False.
Audit logging: five event types, a bounded queue, and the losses that come with it
Instrumentation covers five event types: llm_input, tool_call, tool_result, ai_message, and system_action. The llm_input event records a message count, not the prompt text. tool_result records the first 200 characters of a result. help_token values appearing in audited arguments and result previews are masked. Events are written by a background thread to logs/<thread_id>.jsonl through a bounded queue of 4096 entries. When the queue fills, new events are dropped and a dropped_events counter increments; write failures increment write_errors. A normal shutdown stops accepting events and drains the queue, and a repeated shutdown does not wait on an already-exited thread.
The README draws its own limit here, and it is worth repeating rather than softening: this is local structured logging for observation and troubleshooting. Inputs are not stored as full prompts, results are truncated, and a crash or a full queue can lose events. The README explicitly says you cannot claim full traceability or complete replay from these files. The monitor command reads the fixed CLI session log by default; other thread_id files have to be opened separately. If your compliance story depends on reconstructing every prompt and full tool output, this log format does not support it.
Where the execution boundary stops: shell, files, and task scheduling
File tools validate parent-child relationships on canonical paths and reject absolute paths, drive-letter paths, same-prefix sibling directories, and pre-existing symlinks that escape the workspace. Shell execution uses a command whitelist and filters some expansion, redirection, and interpreter arguments, with a 60-second subprocess timeout. The README states that the timeout does not guarantee the whole child process tree is stopped and that there is no independent resource quota.
That is the honest core of the limitation. Shell commands run with the host user's privileges; office is only a working directory. Path checks and command filtering cannot constrain all I/O inside a script, and the README says outright that they are not a substitute for a container, a low-privilege account, or OS isolation. If you were hoping the help_token gate also sandboxes execution, it does not; it governs the skill invocation protocol.
Scheduled tasks are handled by an in-process heartbeat coroutine that checks tasks.json every 10 seconds, supporting one-shot and hourly, daily, weekly, or monthly rules. Task JSON is updated through a temp file with flush/fsync and an atomic same-directory replace; a failed write keeps the old file, and a failed heartbeat write-back does not continue delivery. The README still names a crash window between the JSON write-back and the in-memory queue enqueue, and notes there is no persistent claim, ACK, or idempotent task execution protocol. SQLite checkpoints save recoverable graph state; they do not give exactly-once execution of external tool side effects.
The 50 to 90 percent figure, and why the README stops citing it
The repository contains historical evaluation material covering 20 hand-constructed tool-selection scenarios. In that material, single-phase selection scored 10/20 (50 percent) and two-phase scored 18/20 (90 percent), with average decision time of 19.33 seconds versus 23.88 seconds. The README frames the change as a 40 percentage point improvement and then immediately qualifies it: the numbers were not re-measured after the current fixes, and they are not a general task accuracy figure. It also notes that older material described both of the two-phase failures as both an incident and a safety abort, which is why the README declines to keep citing a P0 incident reduction of 80 percent as a conclusion.
That self-correction is the most useful thing in the document. A project that publishes a headline number and then explains why the number should not be used as a headline is telling you how to read the rest of its claims. The practical takeaway is that the two-phase gate costs roughly four and a half seconds per decision in that historical sample and buys a large improvement on a narrow, hand-built task set. Whether it helps on your tasks is unmeasured. If you adopt CyberClaw for the gate, plan to build your own scenario set rather than inheriting this one.
Alternatives, and what the two-phase gate does not cover
The obvious comparison is OpenClaw, which the README names as the inspiration. OpenClaw is a Node.js project with its own runtime protocol, permission model, dependency installation, hooks, and skill conventions. CyberClaw reads OpenClaw and Claude Code style SKILL.md descriptions but the README states it does not automatically implement the full permission, dependency, hook, and runtime protocol of either ecosystem. Script dependencies and available commands are the deployer's responsibility. There is also no native MCP session client in the repository; the README suggests MCP could be reached through third-party skills instead. So the difference is not just language. Adopting CyberClaw means accepting a smaller compatibility surface in exchange for a Python codebase you can read end to end.
Within the same language, a plain LangGraph agent plus your own tool wrappers is the realistic alternative. You would get the state graph, checkpointing, and tool binding, and you would write your own gate. What you would not get is the specific combination here: SHA-256-bound description validation, a 300-second single-use credential consumed atomically before the executor, masking of tokens in audit output, and JSONL events with dropped-event counters. That combination is the actual product. If you do not need pre-execution validation of dynamic skills, the extra call and the roughly four-second historical overhead are cost without benefit.
A few boundaries are worth stating as boundaries. Long-term memory is a Markdown user profile, currently a single global file, not isolated per user. The metadata scan cache is 60 seconds; descriptions are read and validated on every help and run, capped at 64 KiB with an explicit rejection above that. Content cache defaults to 50 entries and the credential store to 1024. Duplicate skill names, or a skill whose name collides with a built-in tool, raise an error. After adding, deleting, or renaming skills, the README says to call reload_skills and update the model binding and ToolNode, or simply restart the CLI.
Editorial conclusion
Adopt CyberClaw if you want a readable, MIT-licensed LangGraph agent where dynamic skill execution is gated by a session-bound help_token and every tool call lands in a JSONL file you can tail. Do not adopt it if you need exactly-once tool side effects, OS-level sandboxing, background subagent jobs that survive a restart, or per-user memory isolation; the README says none of those exist yet. Before committing, verify three things yourself: that cyberclaw config completes against your provider (the README notes the Anthropic and Ollama branches were not validated with real API calls), that execute_office_shell's command whitelist covers the commands your skills actually need, and that CYBERCLAW_WORKSPACE points at a writable directory, since the default is a workspace folder inside the project.
Community notes