History
Blitz began as a Go port of the Python Code Puppy, under that name. Both implementations lived in one repository (python/ and go/, at github.com/rmcguinness/code_puppy) until the Go version reached feature parity; on 2026-09-26 the Python implementation was removed, the Go code moved to the repository root, and the product was renamed Blitz. The last commit with both is tagged python-final in that former repository. This repository (github.com/retail-cortex/blitz) starts from a fresh history.
What follows is the comparison as it stood when the Python code was retired, kept as a record. Paths such as python/ and go/ refer to that layout, and features added afterwards aren’t in it.
Go measurements were taken on 2026-09-24 on Apple Silicon (arm64), macOS, warm cache. Python startup and memory figures come from the earlier benchmark and were not re-run. Source counts were measured today for both.
| Metric | Python | Go | Notes |
|---|---|---|---|
Warm --version |
0.960 s | 0.020 s | ~48× faster |
| Interactive start → exit (config, sandbox probe, engine) | — | 0.030 s | |
| First run of a new binary | 25.3 s (env init) | 0.76 s | Go’s first run is macOS scanning the new binary |
Peak memory (RSS), --version |
136.3 MB | 37 MB | Go was 16.5 MB before MCP, Anthropic, Markdown and line-editor dependencies |
| Distribution | Python 3.11+ venv / pipx + wheels | Single static binary (CGO_ENABLED=0) |
No runtime dependencies |
| Binary size | n/a | 56–61 MB per platform | Grew from ~18 MB; see §4 |
Python (python/code_puppy) |
Go (go/cmd, go/pkg) |
|
|---|---|---|
| Source files (non-test) | 271 | 91 |
| Non-blank source lines | 71,962 | 16,443 |
| Test files | 380 | 64 |
| Non-blank test lines | — | 10,696 |
| Direct dependencies | 150+ (uv.lock) |
27 (go.mod; OpenTelemetry added 8) |
✅ supported · ➖ partial · ❌ not found
| Area | Python | Go | Go notes |
|---|---|---|---|
| Providers | ✅ many (Gemini, OpenAI/Codex, Anthropic, Z.ai, Gemini Code Assist, round-robin, model catalogue) | ➖ Gemini, Anthropic, OpenAI-compatible, Ollama | No model picker/catalogue; fallback chain instead of round-robin |
| Agents | ✅ Python classes + JSON | ✅ Markdown + YAML frontmatter, embedded | ./agents only with --trust-workspace; built-ins can’t be overridden |
| Sub-agent delegation | ✅ | ✅ | Depth-limited invoke_agent |
| Skills | ✅ | ✅ Agent Skills plus Castor definitions; sandboxed Python scripts with per-requirements environments | Scripts run in gVisor (Linux) or Seatbelt/bubblewrap, capped by [skills.policy]; they write only to an output directory |
| MCP servers | ✅ | ✅ stdio + HTTP | Per-server approval, prefixes, per-agent scoping; stdio servers sandboxed |
| Hooks | ✅ hook engine | ✅ pre/post tool, prompt submit | Exit-2 / JSON block protocol |
| Plugins | ✅ plugin system | ❌ | MCP and hooks cover some of the same ground |
| Approvals | ✅ confirmations | ✅ diff preview; once / session / always | Saved rules scoped per workspace; never override deny rules |
| Undo | ✅ undo manager | ✅ per-turn checkpoints, /undo, /diff |
Refuses to clobber later edits unless forced |
| Sessions | ✅ autosave, browser, /dump_context / /load_context |
✅ persistent, --resume / --continue, named snapshots (/session save, /session load <name>) |
Scoped per workspace; loading a snapshot starts a new session from it, as Python’s /load_context does |
| Compaction | ✅ | ✅ automatic + /compact [focus] |
|
| Token / cost tracking | ✅ | ✅ per turn and session | Cache reads/writes priced; doctor flags unpriced models |
| Project instructions | ✅ | ✅ AGENTS.md / PUPPY.md |
|
| Web | ➖ browser tooling | ✅ web_fetch, web_search (Google via Gemini grounding, Brave, Tavily, SearXNG), /search web |
SSRF protection on every hop; no browser automation |
| Session names | ✅ autosave names | ✅ named after the first prompt, /rename, terminal title, resume command printed on exit |
From Antigravity’s /rename, /title and exit hint |
| Side questions | ❌ | ✅ /btw <question> |
Answered in a throwaway copy of the session; read-only; nothing kept (idea from Google’s Antigravity CLI) |
/search |
❌ | ✅ /search web <terms> (top five links read by the agent), /search session <terms> (the transcript, including compacted turns) |
Search turns are read-only. Session search is literal and doesn’t cover tool output; Google search costs aren’t in /cost (see README, Search) |
| Images / attachments | ✅ | ✅ @image mentions, /attach, /paste, --image, view_image tool |
Gemini, Anthropic, OpenAI-compatible; images kept out of session files |
| i18n | ✅ | ✅ English, Spanish, Canadian French | /locale; external JSON catalogs; model replies in the chosen language |
| Shell passthrough | ✅ !cmd |
✅ !cmd |
Runs as the user in the workspace; audited |
| Plan mode | ➖ /plan (instructions only) |
✅ /plan, --plan |
Enforced: only read-only tools run, including in sub-agents |
| Slash commands | ✅ many | ➖ | No /cd (the workspace is the sandbox root; use -d), /truncate (use /compact), /tutorial |
| Per-model settings | ✅ /model_settings: sampling, reasoning/thinking, retry strategy |
➖ /model_settings, [model_settings."<model>"]: temperature, max_tokens, top_p, seed |
Reasoning/thinking settings not ported. Each fallback uses its own settings; settings a provider rejects are left out |
| Per-agent models | ✅ /pin_model, /unpin |
✅ /pin_model, /unpin, [agent_models], agent default_model |
Cross-provider; pinned sub-agents priced by their own model |
| Steering mid-turn | ✅ Ctrl+T, injected before the next model call | ✅ type or Ctrl+T; delivered with the next tool result | macOS and Linux; late messages become the next prompt |
| Onboarding / menus | ✅ wizard, interactive menus | ➖ config init, doctor, line editor with completion |
|
| Scripting | ➖ | ✅ json / stream-json, --max-turns, exit codes |
|
| File sandbox | ➖ access checks (fs_access.py) |
✅ os.Root roots, read-only roots, blocked globs incl. symlinks |
|
| OS sandbox for shell | ❌ not found in source | ✅ Seatbelt (macOS), bubblewrap (Linux) | Writes confined, secrets unreadable, network optional |
| Command policy | ➖ | ✅ parsed allow / deny / auto-approve | Checks every sub-command, including wrappers and bash -c |
| Process lifetime | ➖ backgrounding | ✅ nothing outlives the CLI | Guarded even against SIGKILL |
| Secret handling | ✅ secret store backends | ✅ env scrubbing, redacted audit log, owner-only files | |
| Audit log | ➖ | ✅ JSONL of prompts, tools, approvals, hooks, undo | |
| Diagnostic log | ✅ error log (error_logging.py) |
✅ slog JSONL, async writer, secrets masked |
Trace IDs on each line when telemetry is on |
| Resilience | ✅ HTTP retry, MCP circuit breaker / health monitor / retry manager | ✅ retries with backoff for every provider, stall timeouts, MCP restart + circuit breaker + timeouts, parallel tool cap | No MCP health dashboard |
| Model fallback | ✅ round-robin model | ✅ ordered llm.fallback_models, across providers |
Failover (not load balancing): per-model circuit breaker, notices, priced by the answering model |
| Telemetry | ✅ opt-in Logfire | ✅ opt-in OpenTelemetry (OTLP/HTTP traces + logs) | Turn → agent → model/tool spans; content stripped unless capture_content |
| Release | PyPI | ✅ GoReleaser: SBOMs, keyless cosign signatures, reproducible builds |
- Binary size: the MCP SDK, Anthropic SDK, Markdown renderer (glamour) and line editor took the binary from ~18 MB to ~58 MB. Startup is unaffected. If size matters, the Markdown renderer is the easiest to make optional with a build tag.
- Breadth: Python still leads on providers, plugins and interactive menus. Go leads on sandboxing, auditability, scripting and distribution.
- OS sandbox coverage: macOS and Linux only. Windows builds run without it and without the process guard.
graph LR
subgraph Go["Go (Google ADK)"]
CLI["Cobra CLI + line editor"] --> Cfg["Trusted config (modenv)"]
Cfg --> Engine["runtime.Engine"]
Engine --> Runner["ADK runner + persistent sessions + compaction"]
Runner --> Agents["llmagent tree (embedded Markdown personas)"]
Agents --> Tools["tools.Registry"]
Tools --> WS["Workspace sandbox (os.Root)"]
Tools --> Exec["ExecEnv: OS sandbox, process guard, env scrub"]
Tools --> MCP["MCP manager"]
Engine --> Hooks["Approvals, hooks, audit"]
end
1. Agent definitions
- Python: Agent definitions were hardcoded Python classes (
BaseAgentsubclasses) mixed with string templates and dynamic class imports. Adding or customizing an agent required editing Python source files or dealing with loose JSON schemas. - Go: Personas are standardized as Markdown files with YAML frontmatter (
internal/agents/builtin/*.md). They are baked directly into the binary at compile time via Go’s//go:embed, yet can also be dynamically dropped into./agents/*.mdor~/.code_puppy/agents/*.mdwithout recompilation.
2. Configuration and secrets
- Python: Configuration relied on raw
os.environreads, extensive monkey patching, and complex credential stores (secret_store.py). - Go: Driven by
retail-cortex/modenv(internal/config/config.go), enabling hierarchical environment cascading (.env.toml->.env.<runtime>.toml->.env.local.toml) and native decryption ofcloud://,pks://, andsimple://secret URIs.
3. Tool execution and schemas
- Python: Used
pydantic-aiwith heavy runtime introspection and multiple monkey patches (pydantic_patches.pywas 26 KB). - Go: Uses Google ADK
functiontool.New(), which automatically and safely infers compliant JSON Schemas from strongly-typed Go structs at initialization viagithub.com/google/jsonschema-go.
4. Concurrency and streaming
- Python: Constrained by the Global Interpreter Lock (GIL) and asyncio thread dispatching. Long shell commands or background subprocesses required intricate coordination to avoid blocking the event loop.
- Go: Leverages native goroutines, channel synchronization, and Go 1.23+
iter.Seq2[*session.Event, error]streaming, giving fluid TUI rendering with near-zero overhead.
Packaging and portability
- Python:
- Requires a pre-installed Python 3.11+ interpreter.
- Relies on platform-specific C/Rust extensions (
cryptography,pydantic-core,pillow), which frequently fail to compile on minimal containers, Termux/Android, or hardened CI runners. - Installation involves downloading hundreds of megabytes of wheel archives.
- Go:
- Compiles to a single static binary (
CGO_ENABLED=0). - Zero dependencies: runs out of the box in
scratchDocker containers, Alpine Linux, or bare metal.
- Compiles to a single static binary (