An agentic coding runtime in Go β multi-provider, MCP-native, plugin-extensible.
β οΈ Experimental. The code compiles and passesgo vet, but most ported features have not been manually validated. Use at your own risk. Contributions and testing are very welcome.
claw-code-go is a Go-native runtime for Claude Codeβstyle agentic coding sessions: a streaming model loop, a permissions engine, a tool registry, MCP integration, plugins, sandboxing, and persistence β all callable from Go and runnable as a single CLI binary.
It is a fork of daolmedo/claw-code-go (the original Go port) augmented with features ingested from ultraworkers/claw-code (a Rust port that emerged after the source leak): hooks, plugins, MCP lifecycle + OAuth, sandbox, classifier-driven permissions, multi-provider routing, prompt caching, OTLP telemetry, and more.
The Rust β Go porting was driven end-to-end by Iterion, a workflow engine for multi-agent LLM pipelines. See How this was built below for the run stats.
Five providers are wired through a unified <provider>/<model-id> addressing scheme (e.g. openai/gpt-5.4-mini, anthropic/claude-sonnet-4-6, bedrock/anthropic.claude-sonnet-4-6):
- Anthropic & OpenAI β validated end-to-end (OpenAI routes through both
/v1/chat/completionsand/v1/responsesfor reasoning + tools). - Codex ChatGPT login β
--codex-authuses the local Codex sign-in for the current session. It reads$CODEX_HOME/auth.json(or~/.codex/auth.json) without changing it; API-key and other-provider selection remain unchanged unless this flag is set. - AWS Bedrock, Google Vertex AI, Azure AI Foundry β real implementations on top of the official SDKs, with live smoke tests under build tag
live. - Capability-aware routing, fallback chains, and per-provider
reasoning_efforttranslation ininternal/apikit. - Typed
api.APIError(StatusCode,Retryable) so callers drive retry classification viaerrors.As.
A rich tool surface re-exported from pkg/api/tools β pair of XxxTool() api.Tool (schema) + ExecuteXxx(ctx, input) (runtime):
- π File I/O β
ReadFile,WriteFile,FileEdit,Glob,Grep,ReadImage,NotebookEdit, PDF extraction. - πΌοΈ Image generation β OpenAI API and Codex sessions can call
image_gento create a PNG withgpt-image-2; the verified file is saved under~/.claw-code/generated_images/(override with--image-dir) and its path is returned in the conversation. Custom OpenAI-compatible endpoints are not assumed to support images. - π» Execution β
Bash(with workspace validation),WebFetch(size cap, header filtering). - π±οΈ Computer use β full Anthropic action surface (
screenshot,*_click,type,key,mouse_move,cursor_position,left_click_drag) backed byxdotool+ ImageMagick on Linux/X11. Returns typedErrComputerUseUnavailablewhen display/binaries are missing. - π£οΈ Interaction β
AskUserwith pluggableAskerinterface (StdinAsker,ProgrammaticAsker,TUIAsker) and structured options;RemoteTriggerHTTP wrapper with timeout, body cap, header allow/deny lists, CRLF guard. - π€ Multi-agent β
Worker*,Team*,Task*,Cron*tools (create / get / list / update / stop) for spawning isolated agents, scheduling, and parallel orchestration. - π MCP & LSP β
ListMcpResources,ReadMcpResource,McpAuth, plus first-class LSP queries. - π§ Workflow β
TodoWrite,Sleep,StructuredOutput,REPL,Skill(slash command dispatch),ToolSearch(discover tools by description), plan-mode toggles.
| Mode | Behavior |
|---|---|
ModeAllow |
Permits all operations without prompting. |
ModePrompt |
Consults the ruleset; asks the prompter when no rule matches. |
ModeReadOnly |
Allows read-only operations only; denies writes/exec. |
ModeWorkspaceWrite |
Allows writes within the workspace directory; denies outside. |
ModeDangerFullAccess |
Allows arbitrary command execution and system access. |
ModeDontAsk |
Strict allow-list β never prompts; denies anything not explicitly listed. |
ModeAuto |
Delegates to a Classifier (default safe-list permits read-only ops, prompts on writes). |
Pluggable classifiers in internal/permissions/:
RuleClassifierβ rule-based safe-list.LLMClassifierβ small-model (Haiku-backed) classifier with TTL+FIFO decision cache (1024 entries, 1h TTL by default) and fail-safe-to-Ask invariant on transport errors. Untrusted args are wrapped in<tool_invocation>tags so payloads cannot hijack the decision.
Programmatic Runner with sequential dispatch and "first non-Continue wins" semantics:
| Tool events | Session events | Plugin events |
|---|---|---|
PreToolUse |
UserPromptSubmit |
PrePluginInstall |
PostToolUse |
PreCompact |
PostPluginInstall |
PostToolUseFailure |
PostCompact |
PrePluginUninstall |
Stop |
PostPluginUninstall |
Subprocess shell-script hooks (hooks/runner.go) cover the same lifecycle for ops who prefer scripts β Unix and Windows exec adapters, exec.CommandContext so cancelling the conversation kills any in-flight hook script.
Full Model Context Protocol support in internal/mcp/:
- π‘ Transports β stdio, SSE, WebSocket. RPC protocol layer is shared.
- π OAuth Authorization Code + PKCE broker with atomic disk-backed token storage. RFC 6749 / 7636 compliant: loopback callback for browser flows, automatic refresh near expiry, typed
ErrReauthRequiredfor headless contexts (where opening a browser is impossible). Bearer header injection viaTransportConfig.AuthFunc. - Public faΓ§ade:
pkg/api/mcp/oauthre-exportsBroker,NewBroker,Token,Storage,ErrReauthRequired.
Local plugin manager in plugin/ with install / uninstall / list / dispatch, plus a remote marketplace with end-to-end verification:
- πΊοΈ Two-tier layout β
<base>/index.jsonadvertises plugins;<base>/<name>/manifest.jsondescribes each. - π SHA-256 + cosign signature verification, delegated to a single path so the slash command and the public API agree.
- π‘οΈ HTTPS-only by default, opt-in
--insecure-marketplaceescape, 1 MiB metadata size cap. - πͺ Lifecycle hooks fire around every install/uninstall (
Pre*can block,Post*always fires with error info on failure). - π§° CLI:
claw-code-go plugin install --marketplace <url> [--require-signed] <name>. Env vars:CLAW_MARKETPLACE_URL,CLAW_PLUGIN_PUBLIC_KEY,CLAW_REQUIRE_SIGNED.
internal/runtime/sandbox/ provides per-session isolation with graceful fallback on non-Linux hosts or inside containers:
- Filesystem modes β
Off,WorkspaceOnly,AllowList. - Namespaces β PID, UTS, IPC, network restrictions on Linux.
- Auto-detection β recognizes
/.dockerenv,/run/.containerenv, and cgroup state to skip nesting. - Status reporting via the runtime so callers can observe whether isolation is active.
internal/runtime/ persists every turn as JSONL events (legacy single-JSON sessions auto-loaded via LoadSessionAuto):
- π Fork / inherit sessions to preserve KV cache across related phases (this is what made the Iterion port converge fast).
- β―οΈ Resume any session by ID,
latest, or path. - π Timeline subcommand renders chronological event view (
pretty|json|md). - π§Ή Compaction with
Pre/PostCompacthooks, summary compression, and recent-N-turns preservation.
Claude Code-parity memory (internal/context/) with every automatic system-prompt section individually toggleable β heavy prompt engineering hurts small models, so everything is opt-out:
- π CLAUDE.md discovery β
~/.claude/CLAUDE.md, ancestor directories (recursive walk-up),<cwd>/CLAUDE.md,<cwd>/.claude/CLAUDE.md;@pathimports expand recursively (5 hops, cycle-safe, code fences skipped); 48KB combined cap. - ποΈ Scoped memory for embedding hosts β
pkg/runtime.PromptConfigdecides which origins feed the CLAUDE.md section:MemorySkipUser(leave~/.claude/CLAUDE.mdout),MemoryRoot(the workspace boundary: ancestors up to and including it are the workspace's, those strictly above are outer),MemorySkipWorkspace,MemorySkipOuter, andMemoryClaudeCodeLayout(also each directory's.claude/CLAUDE.mdand.claude/rules/**/*.md, plus~/.claude/ruleswith the user scope; a rule scoped by a frontmatterpathskey is conditional in Claude Code and is skipped). WithMemoryRootset, the workspace's@importsmust resolve inside it (transitively) and a workspace file symlinked out of it is skipped; the user scope and the outer ancestors are not confined. Every zero value keeps the unscoped behaviour. They are values, not sections, so the CLI toggles do not know them. (internal/context/memory.go) - πΎ Auto memory β per-workspace persistent
MEMORY.mdunder~/.claw-code/memory/<fingerprint>/(override:CLAW_MEMORY_DIR), injected at session start with maintenance instructions; the model updates it with the standard file tools. - π§ Operating posture + behavioral sections β authored sections covering the qualities Claude Code teaches natively: the posture core (read-before-edit, git safety, concision, verification honesty) plus
communication(final-message discipline,file:linerefs, the<system-reminder>contract),task-management(todo hygiene incl. post-compaction reseed),doing-tasks(anti-over-engineering, objectivity, no time estimates),tool-policy(parallel calls, dedicated tools over shell, tool_search before "unavailable"),git-safety(the full git protocol) andcontext-management(don't wrap up early + end-of-turn self-check). Original text, not a Claude Code copy; embedding hosts compose viapkg/runtime.OperatingPosture()/BuildSystemContext(). - ποΈ Toggles everywhere β tri-state
"prompt"block insettings.json({"prompt": {"minimal": true, "projectInstructions": true}}= CLAUDE.md only), CLI--minimal-prompt/--prompt-sections/--disable-prompt-sections, CLAUDE.md frontmatterminimalPrompt/promptSections/disablePromptSections. Sections:environment,git-status,project-instructions,mcp-tools,compaction-summary,memory-walk-up,memory-imports,auto-memory,posture,communication,task-management,doing-tasks,tool-policy,git-safety,context-management. Defaults all-on;--system-promptreplaces the authored base,--append-system-promptsuffixes the assembled prompt; inspect withclaw-code-go print-system-prompt --minimal-prompt.
- π€ Real background sub-agents β the
agenttool spawns a child conversation loop (typed:explore/plan/verification/general-purpose), streams its transcript into the task registry, and announces completion via a<system-reminder>at the next turn boundary;define_subagentregisters session-scoped custom types (persona + tool allow-list + model). (internal/runtime/subagent.go) - πΈοΈ Task graph β registry tasks carry
blocks/blocked_bydependency edges (maintained reciprocally),subject/active_form/owner, and derivedblocked/work_status;todo_writestays the flat session checklist. (internal/runtime/task/) - π§ Oracle β one read-only, tool-less consultation of a stronger model (
oracleModelsetting /CLAW_ORACLE_MODEL) with files inlined, for architecture decisions and gnarly debugging. (internal/tools/oracle.go) - π§© Workflow DSL β a goja event loop runs plain-JS orchestration scripts: promise-returning
agent(),parallel()/pipeline()(no inter-stage barrier; thrown stages drop items to null),phase()/log(), hard caps on agents/concurrency/time. (internal/runtime/workflow.go) - π semantic_search β local relevance-ranked code search (BM25 + identifier-split tokens): "where is X handled?" without exact strings, no network, no credentials. (
internal/tools/semantic_search.go)
Anthropic-native cache_control breakpoint manager with session-scoped fingerprints, cache-break detection (unexpected drops in cache_read_input_tokens), and persistent stats (hits / misses / writes / unexpected breaks). Cache-aware retry logic in internal/apikit/retry.go.
Two exporters built on the official OpenTelemetry SDKs:
- π¨
internal/apikit/telemetry/otlpβ OTLP/HTTP-JSON (CLAWD_OTLP_HTTP_ENDPOINT). - π¨
internal/apikit/telemetry/otlpgrpcβ OTLP/gRPC viaotlploggrpc(CLAWD_OTLP_GRPC_ENDPOINT,CLAWD_OTLP_GRPC_INSECURE,CLAWD_OTLP_GRPC_HEADERS). - π·οΈ Standard resource attributes:
service.name=claw-code-go(override withCLAWD_SERVICE_NAME),service.versionviaCLAWD_SERVICE_VERSION. β οΈ The legacyITERION_*env vars are deprecated β useCLAWD_*.
internal/tui/ ships a Bubble Tea-backed interface: markdown rendering, syntax-highlighted code blocks, themes, REPL history, logo. The same renderer powers the timeline subcommand.
A first-class LSP tool (internal/lsp/ + pkg/api/lsp) lets the model query language servers for diagnostics, hover, and definitions during a coding session.
Beyond single-agent loops, runtime primitives in internal/runtime/ support multi-agent fleets:
- π· Workers β observable state machine (
SpawningβTrustRequiredβReadyForPromptβRunningβFinished/Failed) with failure classification (TrustGate, PromptDelivery, Protocol, Provider). - π₯ Teams β sub-agent registry and coordination primitives.
- ποΈ Tasks β background task lifecycle (
create/get/list/update/output/stop). - β° Cron β scheduled recurring tasks.
- π¦ Lanes / Policies / Recovery β declarative rule engine for branch-locked workflows, freshness analysis, and 7 named failure-recovery scenarios.
claw-code-go [--prompt | --repl | --session ID] ...
claw-code-go timeline --session <id> [--format pretty|json|md] [--limit n]
claw-code-go plugin install --marketplace <url> [--require-signed] <name>
claw-code-go dump-manifests [--json]
claw-code-go bootstrap-plan
claw-code-go print-system-prompt [--cwd ...] [--date ...] [--minimal-prompt] [--prompt-sections ...]
claw-code-go resume-session <file> [commands...]
Main-mode flags include --model, --permission-mode, --allowed-tools, --reasoning-effort, --output-format, --session-dir, --work-dir, --dangerously-skip-permissions, the prompt-section toggles --minimal-prompt / --prompt-sections / --disable-prompt-sections, and --system-prompt / --append-system-prompt.
import (
"context"
"github.com/SocialGouv/claw-code-go/pkg/api"
"github.com/SocialGouv/claw-code-go/pkg/api/tools"
)
defs := []api.Tool{
tools.ReadFileTool(),
tools.WriteFileTool(),
tools.GlobTool(),
tools.GrepTool(),
tools.FileEditTool(),
tools.WebFetchTool(),
tools.BashTool(),
tools.ReadImageTool(),
tools.ComputerUseTool(),
}
// Dispatch a tool call from the model:
out, err := tools.ExecuteReadFile(ctx, map[string]any{"path": "README.md"})ExecuteBash additionally takes a workspace string for command validation (pass "" to skip). The wrapper pins permissions to ModeAllow; gate invocations upstream (e.g. via an Iterion workflow's allowed_tools list).
Bash accepts optional timeout_seconds, a whole number from 1 to 600. Omit it
to keep the 30-second default; request a longer bound explicitly for builds or
tests, for example {"command":"go test ./...","timeout_seconds":120}.
Invalid values fail before starting a process. The caller's cancellation or
earlier deadline always wins, and cancellation errors wrap the corresponding
Go context error. On Unix, cancellation kills the process group, including
descendants. Combined output retains only its first 10,000 bytes plus a
truncation marker while draining the rest; extending the deadline does not
extend the retained output or permissions.
To generate an image with your Codex ChatGPT login, sign in with codex login first, then run:
claw-code-go --codex-auth --model gpt-5.5 --prompt 'Generate a drawing of a red square with image_gen.'The generated PNG is private to your user account and remains on disk after the session. If Codex's access token has expired, open Codex to renew the login and retry. --codex-auth is opt-in; an OpenAI API key continues to work through the usual API path.
| Provider | Status | Path |
|---|---|---|
| Anthropic | π’ validated end-to-end | pkg/api/providers/anthropic |
| OpenAI | π’ validated end-to-end (/v1/chat/completions + /v1/responses) |
pkg/api/providers/openai |
| Bedrock | π‘ available, untested in production (built on aws-sdk-go-v2) |
pkg/api/providers/bedrock |
| Vertex AI | π‘ available, untested in production (Google ADC + canonical MapModelID) |
pkg/api/providers/vertex |
| Azure Foundry | π‘ available, untested in production (OpenAI-wire compatible) | pkg/api/providers/foundry |
Each cloud provider ships a smoke test gated by the live Go build tag. The tests skip cleanly when the relevant credentials are not set, so the default go test ./... is unaffected.
# AWS Bedrock β uses the standard AWS SDK credentials chain.
AWS_REGION=us-east-1 \
AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=... \
BEDROCK_MODEL=anthropic.claude-3-5-sonnet-20241022-v2:0 \
go test -tags live -run TestLiveStreamSmokeBedrock -v ./internal/api/providers/bedrock/...
# Google Vertex AI β uses Application Default Credentials.
GOOGLE_CLOUD_PROJECT=my-project \
GOOGLE_CLOUD_REGION=us-east5 \
GOOGLE_APPLICATION_CREDENTIALS=/path/to/sa.json \
VERTEX_MODEL=claude-sonnet-4-20250514 \
go test -tags live -run TestLiveStreamSmokeVertex -v ./internal/api/providers/vertex/...
# Azure AI Foundry β api-key auth, or DefaultAzureCredential when key is unset.
AZURE_OPENAI_ENDPOINT=https://my-resource.openai.azure.com \
AZURE_OPENAI_API_KEY=... \
FOUNDRY_MODEL=my-deployment \
go test -tags live -run TestLiveStreamSmokeFoundry -v ./internal/api/providers/foundry/...Each test asserts only that the stream produced at least one text delta and a message_stop event β enough to confirm authentication, request shape, and SSE decoding work end-to-end.
runner := hooks.NewRunner()
runner.Register(hooks.PreToolUse, func(ctx context.Context, hctx hooks.Context) (hooks.Decision, error) {
if hctx.ToolName == "bash" {
return hooks.Decision{Action: hooks.ActionBlock, Reason: "no shell"}, nil
}
return hooks.Decision{Action: hooks.ActionContinue}, nil
})
decision, _ := runner.Fire(ctx, hooks.Context{Event: hooks.PreToolUse, ToolName: "bash"})The runner is wired into internal/runtime/conversation.go; nil runners are a documented no-op.
The Rust-to-Go feature porting was orchestrated by Iterion β a workflow engine for complex multi-agent LLM pipelines, using Claude Code, Codex, and other backends. This repo is the real-world example that drove Iterion's development:
- π rust_to_go_port.iter β the Iterion workflow definition (DSL).
- π rust_to_go_port.md β design decisions, lessons learned, empirical data.
| Metric | Value |
|---|---|
| Refinement runs | 4 (workflow iterated alongside the engine) |
| Outer loop iterations | 25+ batches across all runs |
| Commits added | 48 (47 by Iterion, 1 by Claude Code) |
| Go code generated | 37,995 lines across 173 files + 96 test files |
| New Go packages | 30+ (hooks, plugin, apikit, worker, lane, policy, recovery, sandbox, lsp, task, team, β¦) |
| Feature parity | 100% (37/37 features) |
| Final run | 100% parity in 41 min, single batch, zero fix loops, zero interventions |
| Longest autonomous stretch | 2h25m without human intervention |
| Dual-judge verdicts | 30+ across all runs (Claude + Codex) |
The workflow breaks the porting into dependency-ordered batches. Each batch goes through: plan β implement β simplify β commit β test β parity scan β dual-judge review β fix loop. Session continuity (fork/inherit) preserves KV cache across related phases. A human gate pauses for high-risk batches and auto-approves routine ones. See the full writeup for details on convergence strategies, stagnation detection, and model allocation.
Experimental. The code compiles and passes go vet, but most of it has not been manually tested. The latest commit (Anthropic prompt caching with cache_control breakpoints) was done directly with Claude Code outside the Iterion workflow.
Contributions, testing, and feedback are welcome.
For the running list of changes, see CHANGELOG.md. For the parity matrix versus upstream Claude Code, see docs/parity.md.
- daolmedo/claw-code-go β the original Go port of Claude Code (upstream).
- ultraworkers/claw-code β the Rust port of Claude Code (feature source).
- Iterion β the workflow orchestration engine that performed the porting.
MIT
