claudeloop-agent-sdk
Explains how claudeloop integrates with claude-agent-sdk (ClaudeAgentOptions, ClaudeSDKClient vs query(), RateLimitEvent, ResultMessage, AssistantMessage, session discovery via list_sessions()) and the never-block-on-a-human design (permission_mode, can_use_tool, AskUserQuestion handling, hooks). Use this whenever building or modifying src/claudeloop/infrastructure/agent/ (the M2+ agent gateway, options builder, message translation, session catalog, capacity probe), whenever the user asks about the Claude Agent SDK, ClaudeAgentOptions fields, session resumption, rate-limit events, or why a run might block on a human. Make sure to consult this before writing any code that calls claude_agent_sdk directly — infrastructure/agent/ is the ONLY place that import is allowed, per the onion architecture (see the claudeloop-architecture skill), and getting the never-block guarantees wrong here defeats the entire purpose of this project.
- License 许可
- MIT
- 最近更新
- 2026-11-15
- Stars
- ★ 5
- Forks
- 3
01 前言 Front Matter
- name
- claudeloop-agent-sdk
- description
- Explains how claudeloop integrates with claude-agent-sdk (ClaudeAgentOptions, ClaudeSDKClient vs query(), RateLimitEvent, ResultMessage, AssistantMessage, session discovery via list_sessions()) and the never-block-on-a-human design (permission_mode, can_use_tool, AskUserQuestion handling, hooks). Use this whenever building or modifying src/claudeloop/infrastructure/agent/ (the M2+ agent gateway, options builder, message translation, session catalog, capacity probe), whenever the user asks about the Claude Agent SDK, ClaudeAgentOptions fields, session resumption, rate-limit events, or why a run might block on a human. Make sure to consult this before writing any code that calls claude_agent_sdk directly — infrastructure/agent/ is the ONLY place that import is allowed, per the onion architecture (see the claudeloop-architecture skill), and getting the never-block guarantees wrong here defeats the entire purpose of this project.
03 SKILL.md 正文
claudeloop + claude-agent-sdk integration
Codex skill mirror of
.claude/skills/claudeloop-agent-sdk/SKILL.md. When this guidance changes, update Claude skill, Cursor rule, and.agents/skills/in the same PR.
infrastructure/agent/ is the only place claude_agent_sdk
may be imported — see the claudeloop-architecture skill for the enforced
onion rule. This skill covers the SDK integration specifics; consult
claudeloop-domain-model for how the resulting signals get classified.
ClaudeSDKClient over query() — this is not optional
query() (single-shot) raises a plain Exception after yielding an
error ResultMessage, and the underlying process exits non-zero. A
streaming-input ClaudeSDKClient stays alive across error results — you
can keep sending messages on one live process with no resume/respawn. The
AgentGateway adapter (infrastructure/agent/gateway.py::ClaudeAgentGateway) MUST use ClaudeSDKClient, not query(), or
the whole point of collapsing the legacy respawn loop is lost. See ADR 0002
for the full reasoning.
Key ClaudeAgentOptions fields for this project
permission_mode="bypassPermissions"— required for autonomy. Note: the Python SDK has nodangerously_skip_permissionsfield; this is its equivalent. Do not go looking for a field that doesn't exist.can_use_tool— a defensive callback that must NEVER await input. InterceptsAskUserQuestionspecifically and denies with guidance (not auto-answers) — see the "Never blocking" section below.output_format— a JSON schema ({complete: bool, remaining_work: [str], blocked_on: str|null, summary: str}) so each turn returns aResultMessage.structured_outputthe domain layer'scompletion.pycan evaluate directly, rather than substring-matching output text. Property descriptions (and the autonomy system-prompt fragment) insistblocked_onis only for true external/human blockers — waitable self-started work goes inremaining_workwithblocked_on: null, because any non-null value terminates the run asBlocked.resume/continue_conversation/fork_session/session_id—session_idcannot combine withresume/continue_conversationunlessfork_session=Trueis also set. Get this wrong and session resumption breaks in a way that's easy to miss in a quick test. When building options, dropsession_idwheneverresumeorcontinue_conversationis set (seebuild_turn_options).setting_sources=Nonefor the throwaway capacity probe specifically — noCLAUDE.mdshould load for a one-token "are we still limited" check.hooks—PermissionRequestauto-allows;Notificationlogs only, never blocks.
Never blocking on a human — every mitigation, concretely
| Stall path | Mitigation |
|---|---|
| Permission prompts | permission_mode="bypassPermissions" |
| Unexpected permission path | Defensive can_use_tool returning PermissionResultAllow without ever awaiting input |
AskUserQuestion |
Intercepted, denied with guidance — e.g. "running autonomously, no user available — choose the option you would recommend, note the assumption, and proceed." NEVER fabricate an answer; that silently invents a decision nobody made. |
ExitPlanMode |
Auto-approved |
Notification hooks |
Logged, never awaited |
| Model asks "Shall I proceed?" in plain text | No tool call to intercept — mitigated via an appended system-prompt fragment establishing autonomous operation |
| TTY-dependent stdin | Never inherit a TTY — must be safe under nohup/systemd |
| MCP OAuth | Genuinely cannot complete unattended — the doctor command checks configured MCP servers up front and fails fast, naming them, rather than discovering the problem mid-run |
If you're adding a new tool-interception path, apply the same test every time: can this ever wait on stdin or a human response? If yes, it needs an explicit mitigation in this table before it ships.
Rate-limit signals — read three, trust none alone
RateLimitEvent.rate_limit_info: status (allowed/allowed_warning/
rejected), resets_at, rate_limit_type
(five_hour/seven_day/seven_day_opus/seven_day_sonnet/overage),
utilization, overage_status, overage_resets_at,
overage_disabled_reason. The Claude Code binary contains the string
[sdkMessageAdapter] Ignoring rate_limit_event message — treat this event
as possibly absent and always corroborate with ResultMessage .api_error_status and AssistantMessage.error (see the
claudeloop-domain-model skill's TurnSignals section for exactly how
these three combine).
Session discovery — use the supported API
list_sessions() / get_session_info() return SDKSessionInfo (session_id,
summary, last_modified, custom_title, first_prompt, git_branch, cwd, tag,
created_at) via cheap stat + head/tail reads. Never hand-parse
~/.claude/projects/<encoded-cwd>/*.jsonl directly — the docs explicitly
warn the transcript format changes between Claude Code releases, and this
API exists specifically to replace that fragile approach from the legacy
script.
The capacity probe — deliberately minimal
The throwaway turn used while WAITING (see claudeloop-domain-model):
one-token prompt, max_turns=1, no tools, setting_sources=None, and
extra_args={"no-session-persistence": None} so it leaves no transcript
and doesn't pollute the working session's history with "OK" turns. A
rejected probe isn't billed by the API.
Backend profiles — the env overlay reaches the turn AND the probe
A [profiles.<name>] table (--profile / CLAUDELOOP_PROFILE) picks the
endpoint Claude Code talks to. The decisions live in domain/backend.py
(BackendProfile, BackendRuntime, BackendIdentity); infrastructure/backend.py
reads the TOML and the environment; bootstrap.py hands the resolved
BackendRuntime to both ClaudeAgentGateway and ClaudeCapacityProbe.
- The SDK merges
options.envoveros.environ, so the overlay wins. That is the only way to remove an inherited value: a local profile setsANTHROPIC_API_KEY=""so a paid key never reaches a local server. Never "just not set" a key you mean to scrub. build_turn_optionsandbuild_probe_optionsboth takeenv=andcli_path=. A probe built without the overlay re-checks capacity on Anthropic while the run talks to Ollama — the defect this fixed.- Local (
base_urlset) implies: every tier named and noclaude-*id; Claude Code's haiku/sonnet/opus aliases mapped onto the tiers;--effortnot forwarded (pass_effort);--max-budget-usdnot forwarded andTurnAccumulator(cost_mode="zero")records $0 — Claude Code prices an unrecognised model at its default model's rate (observed: $0.0008365 for one free qwen2.5-coder:1.5b turn) — whileResultMessage.usagetoken counts are kept;CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1; web search / deep research refused. - Errors a local backend produces (captured from the bundled CLI against
Ollama 0.34.2) —
AssistantMessage.error/ResultMessage.api_error_status: model not pulled →"model_not_found"/ 404; server down →"server_error"/Nonewith "Connection refused … (ConnectionRefused)"; model failed to load →"server_error"/ 500; queue full →"server_error"/ 503; conversation overcontext_window→"invalid_request"/None, "Prompt is too long" (Claude Code reservesmax_output_tokensout of the window).TurnAccumulatorpasseslocal_backend=TrueintoTurnSignalssoclassifycan read them (seeclaudeloop-domain-model). Claude Code retries a refused connection up toCLAUDE_CODE_MAX_RETRIEStimes first — about three minutes at the default before claudeloop sees it;extra_envcan lower it. - A model that writes tool calls as text does nothing — and can fake Done.
Observed live: qwen2.5-coder:14b on Ollama answers even a one-tool request
with
{"name": ..., "arguments": ...}as a text block; inside Claude Code it wrote its Write call and its StructuredOutput call as text, appended the done marker, and the run reported Done for a file it never created. Hence a local profile'sdone_marker_fallback = false(only a structured verdict completes a run;AutonomousRunner(done_marker_fallback=...)→evaluate(marker_fallback=...)) anddoctor'sbackend-toolscheck, which POSTs one trivial tool to/v1/messagesper tier and wants atool_useblock. AssistantMessageErrorin the SDK types does not listmodel_not_found; the CLI sends it anyway. Compare strings, not the Literal.- Resume never crosses backends: run meta records
backend(anthropic|gateway:<url>|local:<url>) andprofile;bootstrap.check_resume_backendrefuses a mismatch.
CLAUDE_CODE_RETRY_WATCHDOG — deliberately off by default
Do not set this env var in the default agent gateway configuration. It
retries 429/529 in-process indefinitely with no progress reporting, no
credits-vs-window discrimination, and no --max-wait. It's exposed as an
explicit opt-in flag (--retry-watchdog), never the default. See ADR 0005
for the full reasoning if you're tempted to "simplify" by using it instead
of the probe-based waiting policy.
Full reference
docs/architecture/decisions/0002-agent-sdk-over-subprocess.md,
docs/architecture/decisions/0005-retry-watchdog-off-by-default.md,
docs/architecture/decisions/0007-ask-user-question-denied-with-guidance.md,
docs/guides/never-blocking.md, docs/guides/rate-limits-and-credits.md,
docs/guides/local-backend.md.
04 同仓库更多 Skills
white-paper-writing
Use when writing white papers, technical reports, policy documents, thought leadership pieces, or any long-form authoritative document. Triggers on requests to write, structure, outline, or review white papers, technical reports, position papers, policy briefs, or evidence-driven arguments. Also use for B2B content marketing strategy, technical documentation requiring authority, academic-style reports, or any document that must educate while persuading. Use when someone asks "how should I structure this" for a long-form document.
prose-technical-mechanics
Use when editing or writing prose at a technical/mechanical level: choosing between Anglo-Saxon and Latinate diction, placing information in topic vs stress positions, writing periodic vs cumulative sentences, handling sentence rhythm, punctuation as logic, transitions, paragraph structure, or phonesthetics. Use when someone wants to understand WHY prose works or doesn't, not just surface-level style advice. Triggers on word choice, sentence structure, emphasis, rhythm, diction, or any deep writing mechanics question.
prose-mechanics
Use when writing, editing, or analyzing prose style; when trying to avoid generic AI-sounding writing; when applying specific prose styles such as journalistic, academic, narrative, KJV biblical, Hemingway plain, Latinate/Jamesian, Orwellian, Augustan, Victorian, Early Modern (Bacon, Browne, Milton), or free indirect discourse; or when coaching someone on writing voice and mechanics. Triggers on any request to improve, analyze, or write in a specific prose style, to fix "AI-sounding" writing, to make prose more vivid or concrete, to vary sentence rhythm, or to understand how a particular writer achieves their effects.
narrative-structure
Use when structuring stories, pitches, presentations, white papers, or any persuasive narrative; analyzing the hero's journey in fiction or non-fiction; applying StoryBrand for business communication; designing narrative arcs for thought leadership; or understanding Vogler, Snyder, Propp, or Campbell frameworks. Triggers on any narrative structure, storytelling, pitch structure, StoryBrand, hero's journey, three-act structure, Freytag, Save the Cat, narrative arc, or "how should I structure this story/pitch/presentation" request.
legal-brief-writing
Use when writing legal briefs, motions, or any court filing; when analyzing judicial cognition and persuasion; when applying elite brief-writing techniques from Roberts, Clement, Kagan, Garner; or when structuring legal arguments for maximum persuasion. Also use for autistic/neurodivergent advocates who need to understand how their natural communication style maps to elite legal advocacy. Triggers on any legal writing, brief drafting, motion preparation, or legal argument structuring request.
journal-publishability-criteria
Use whenever a research paper, article or preprint is being written, revised, reviewed or published, and specifically before every publication of docs/paper.md. Covers what legitimate journals actually gate on, in order of gating — the editor's desk screen (scope, novelty, package problems), what reviewers judge (methodological soundness, claims the evidence can carry, statistical and qualitative reporting), EQUATOR reporting guidelines, the ICMJE authorship criteria, COPE's view of text recycling, the near-universal generative-AI policy (no AI author, disclosure, author responsibility), TOP 2025 transparency standards, how to verify a journal is legitimate, submitting without an institution, and a pre-submission checklist. Triggers on requests to evaluate, review, prepare or submit a paper, to judge publishability, to write a declarations or data-availability section, to disclose AI use, or to check a journal.