Skip to main content
Blitz
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage
Edit page

Development

Blitz is an AI coding agent in Go, built on the Google Agent Development Kit (google.golang.org/adk/v2). This section is for people and agents changing the code (contributing is the short version); the architecture and shared packages explain how the pieces fit. Start with Where to pick up (where work stands and what’s next); the roadmap explains what was built and why, and Manual verification holds the checks that need a person.

Layout

A monorepo of independent apps over shared packages, one Go module. The rule: apps depend on pkg/, never on each other (tests may run the service through apps/service/servicetest); front ends (the CLI’s REPL, the desktop app) depend on the contract (pkg/api) and the client (pkg/client), never on the engine; only the service and the CLI’s --local mode link pkg/engine. Code private to one app lives under apps/<app>/internal/.

Path What
apps/cli blitz, the CLI: flags, --dir, output modes, one-shot runs, doctor, config, workers, service install. Links no engine: attaches to the service (starting it when it isn’t running), or to a private blitzd for a run of its own (--local); doctor runs in blitzd
apps/cli/internal/tui The REPL: commands, rendering, input, steering keys. Drives an api.Backend
apps/service blitzd, the per-user service: internal/daemon runs it, internal/server has the Connect handlers over engine.Workspace (translation only) and the approval/question broker. servicetest runs it inside other packages’ tests
apps/vscode The VS Code extension (TypeScript): the desktop app’s page in a view, a local proxy to the service, packed by tools/vsix
apps/desktop/web The desktop page (React + TypeScript, pnpm, the generated Connect client in src/gen), shown by the Electron app, the tray’s page on Windows and the VS Code extension
apps/electron The desktop app (spec_electron_038): its main process and preload (TypeScript), with the page and blitz-tray --serve as its host (pkg/pagehost); the Electron runtime comes from MODULE.bazel; appicon.png its icon; winexe (Go, run at build time) gives the Windows program that icon and its details; packaging/ its macOS app, Windows zip and Linux packages (the Arch one made by tools/pacman) and the macOS signing script
apps/tray blitz-tray, the service in the system tray (fyne.io/systray: D-Bus StatusNotifierItem on Linux, Cocoa on macOS, Win32 on Windows): internal/tray has its behaviour (the menu for a status, the actions, the page’s /host/ calls), main.go draws it; shipped beside the app in the .deb and Blitz.app, and in the Windows zip, where it serves the desktop page (bazel run //apps/tray:blitz-tray_page tries that here)
pkg/api The contract between front ends and the engine: Backend, and the values, events and errors that cross it. Depends only on config and images
pkg/client Backend over the service’s API
pkg/loginitem Starting the service at login and controlling it (launchd, systemd), and the tray (also the registry’s Run key on Windows), for the CLI, the desktop app and the tray
pkg/pagehost The page’s calls to the program serving it (blitz-tray --serve for the Electron app, the tray’s page on Windows): the window’s preferences (~/.blitz/desktop.json), the service, installing the blitz command, the OS sandbox, updates
pkg/pageserver The desktop page in front of the service: the proxy to its socket (the tray uses it, for the Electron app and on Windows), and the loopback server, behind a one-time link and a cookie, that serves the page to a browser on Windows
pkg/fileview Showing files and folders in the system’s programs (file manager, viewer), never running one: for the desktop app and the tray
pkg/socket Where the service listens (the per-user Unix socket), and how to reach it
pkg/engine The program without a UI: engine.Open builds a Workspace (registries, tools, sessions, model, engine) implementing api.Backend with typed operations that return data and never print
pkg/engine/runtime The engine over the ADK runner: models and providers, fallback, per-model settings, compaction, steering, side questions, usage and cost
pkg/engine/tools Tools and their guardrails: workspace roots, approvals, command policy, OS sandbox, script sandbox (gVisor), skill scripts and their environments, web, MCP, hooks, checkpoints
pkg/engine/session Saved sessions, snapshots, the ADK event store, transcript search
pkg/engine/{skills,agents,commands,memory,workers,audit,breaker} Skill, agent and command definitions (built-ins embedded), memory files, workers, the audit log, the circuit breaker
pkg/{config,i18n,images,legal,observability,redact,secrets,textutil} Shared by every app: configuration (.env.toml through modenv) and its editing, message catalogs (en-US, es, fr-CA, also read by the desktop page), images, the license texts every program shows, the diagnostic log and OpenTelemetry, secret redaction, API keys in the OS keychain, text helpers
proto/blitz/v1 The service API as protos (buf.yaml, buf.gen.yaml at the root): SessionService (sessions, turns, steering, approvals), WorkspaceService (everything else api.Backend does), WorkerService; their Go code (messages and Connect, one package) is generated by Bazel, never committed
build How things are built: code generators (Connect, protoc-gen-es), nogo and its analyzers (doccomment), macOS signing, version stamping
tools Runnable checks and upkeep: check_deps, check_format.sh, license_headers, third_party_notices.sh (and its generator, notices), specs, tidy, buf, the gopls driver
third_party Patches to dependencies
docs This site: Hugo with the Geekdoc theme, built by Bazel (//docs:site) and published to GitHub Pages from main
release The CLI release archives, every platform (spec_monorepo_028 MR-22)
.github/workflows ci.yml (Bazel: every test with the race detector, sandbox and gVisor checks, the dependency rules, formatting, govulncheck, protos, on macOS and Linux; release archives must be identical on both), release.yml (Bazel-built archives, SBOMs, cosign, the desktop packages)

Commands

The short names (//:blitz, //:desktop, //:build-all, …) are aliases in the root BUILD.bazel, which lists them all.

bazel build //...               # everything; binaries in bazel-bin/apps/{cli,service,tray}
bazel build //:build-all        # this machine's programs and desktop package (//:build-all-linux, //:build-all-mac)
bazel test //...                # every test (cached: only what changed runs again)
bazel run //:blitz -- doctor --online   # the CLI; //:blitzd the service
bazel run //tools:check_deps    # apps depend on pkg/ only; front ends never on the engine
bazel run //:gazelle            # after adding a Go package or an import: update the BUILD files
bazel test --config=race //...  # the Go tests with the race detector, as CI runs them
bazel run //tools:tidy          # go mod tidy, bazel mod tidy, Gazelle (after changing dependencies)
tools/check_format.sh           # gofmt, BUILD files as Gazelle writes them, license headers
bazel run //tools:license_headers   # add the Apache header to new files
tools/third_party_notices.sh    # regenerate THIRD_PARTY_NOTICES after changing dependencies
bazel run //tools/specs         # the specs' index and the paths they name
bazel run //:docs               # this site at http://localhost:1313
tools/coverage.sh               # test coverage of apps/ and pkg/; fails below tools/coverage/floor.txt
bazel test //apps/desktop/web:coverage   # the desktop page's line and branch coverage; fails below vite.config.ts's thresholds
bazel run //tools/codeowners    # .github/CODEOWNERS from OWNERS.txt
bazel run //:desktop            # the desktop app (Electron, spec_electron_038) on this machine's service
bazel run //:desktop-web        # the desktop page in a browser (?fake: no service needed)
bazel build //:mac-app          # the desktop app for this Mac; //:deb, //:pacman, //:desktop-tar on Linux; //:windows-zip anywhere
bazel build //:archives         # the CLI release archives, every platform
BLITZ_TELEMETRY=1 BLITZ_LOG_LEVEL=debug bazel run //apps/cli:blitz   # traces to http://localhost:4318; logs in ~/.blitz/logs
bazel test //pkg/engine/tools:tools_test --test_env=BLITZ_PYENV_TESTS=1 --test_filter='PyEnv|InstallsPackages'   # real Python environments (network)

Everything goes through Bazel; host go, pnpm or buf commands are a last resort (bazel run @rules_go//go -- … is the go command). Plain go build and go test don’t work anyway: proto/blitz/v1 exists only in the build. Editors: point gopls at Bazel with GOPACKAGESDRIVER=$PWD/tools/gopackagesdriver.sh; for the page’s generated code, bazel build //apps/desktop/web:api_ts once. Static analysis (vet, staticcheck) runs in every compile; silence one finding with //nolint:<check>.

The docs

This site is in docs/: Markdown pages in docs/content/, built by Hugo with the Geekdoc theme through Bazel (bazel build //docs:site, which //... leaves out; bazel run //:docs previews it). Link pages by their files (../guide/safety.md); a link to a missing page fails the build.

  • Diagrams are Mermaid: a fenced code block with the language mermaid (flowcharts, sequence, class and state diagrams, …) renders as a diagram, in both themes. Geekdoc’s code-block render hook loads Mermaid only on pages that use it.
  • The API reference (architecture/api/) is generated, never written: //docs:api runs proto-gen-md-diagrams (a go.mod tool, built by Bazel) over proto/blitz/v1, and docs/api_pages.sh makes its Markdown into pages. A new proto file needs adding to the list in docs/BUILD.bazel; better comments in the protos make better pages.
  • Versions. The guide describes Blitz as it is, not how it changed. It names a Blitz version only as “since vN.N.N” (what an older release lacks) or “deprecated since vN.N.N”; what changed in a release goes on its page in releases/. A snippet that installs or uses a release names it with {{< release >}}, which the site fills with the latest published release (docs/layouts/shortcodes/release.html) and the app’s copy with its own version, so nothing needs bumping at a release. Other projects’ versions (a dependency, an example plugin.toml) are written as they are.

Conventions

  • One commit per feature, with a message explaining why.
  • New user-facing strings go into all three catalogs in pkg/i18n/locales/ (en-US, es, fr-CA); i18n_lint_test.go enforces this.
  • A bug fix comes with a test that was confirmed to fail without the fix (temporarily revert, run, restore).
  • Go tests use Testify: require for what the rest of the test depends on (setup, a value it goes on to use), assert for the checks; one assertion per fact, not a || b; the specific assertion (ErrorIs, Contains, Len, FileExists), not True(x == y); messages add what the values don’t say (which case, what it means) and never restate got and want. Table-driven loops run each case as a subtest, t.Run(name, …). t.Fatal and t.Error stay for control flow: a select’s timeout, an unexpected event, a helper that found nothing.
  • Each feature updates this site’s pages for it (the product and guide pages, its spec), a roadmap item, and a manual verification section.
  • Real-terminal behavior was checked with script against a local fake provider. Answer the line editor’s cursor-position query (ESC[6n) with ESC[1;1R in the scripted input, or it waits forever.
  • gVisor code only builds on Linux (//go:build linux, stub elsewhere); check it from macOS with bazel build --platforms=@rules_go//go/toolchain:linux_arm64 //pkg/engine/tools. Its tests need runsc (RUNSC_PATH); CI fails if they’re skipped.
  • License: Apache 2.0. Every source file starts with the Apache header (bazel run //tools:license_headers adds it; CI checks it). NOTICE credits Code Puppy, the Python project Blitz was ported from (MIT).
  • Every package and exported name has a doc comment; the doccomment analyzer (Go), doc.lint.test.ts (the page) and buf’s comment rules (protos) enforce it.