Manual verification
Everything here needs a person, a real terminal, real credentials, or GitHub. The automated suite (413 tests on macOS and Linux) covers the logic behind each item; this list checks the parts it can’t. Each item has an expected result — if you see something else, note it next to the item.
Setup for most items: bazel build //apps/cli:blitz //apps/service:blitzd, then put bazel-bin/apps/cli and bazel-bin/apps/service on your PATH (or use a release archive). Use a scratch Git repository as the workspace so edits are safe.
Cost note: items marked 💲 call a paid API. A short session costs cents; long sessions and /compact cost more.
-
blitz config init, then add your API key(s) to~/.blitz/.env.toml. Expected: file created with mode 600; re-running without--forcerefuses. -
blitz doctor💲 thenblitz doctor --onlineExpected: credentials ✓, model ✓,model request✓ with--online, shell sandbox on, pricing ✓ for the default model.
- Ask it to read a file and summarize it.
Expected: answer streams in as it’s generated; Markdown renders; a dim usage line (
↳ … in · … out · context … · $…) follows the turn. - Ask it to fix a small bug that needs
grep+ an edit +go test(or your language’s tests). Expected: tool badges appear; the edit asks for approval with a colored diff; the test command asks for approval; the turn finishes. -
/costand/context. Expected: non-zero tokens; cost shown; context size roughly matches the usage line. - Set
[context] token_threshold = 4000temporarily, then have a few long turns. Expected: the conversation keeps working past the threshold;/contextstays near or below it.
Set [llm] provider = "anthropic" (key via api_key, ANTHROPIC_API_KEY, or ant auth login).
- Banner shows model
claude-opus-5;doctor --onlinepasses. - A multi-step task with several tool calls (read → edit → run tests). Expected: completes without “invalid request” errors between tool calls (thinking blocks are carried across correctly).
- Run two turns in a row, then
/cost. Expected: “read from cache” is non-zero from the second turn on. - Quit, then
blitz --continue "what did we just do?". Expected: it remembers the previous turn’s details. - Optional:
fallbacks = "off"in config, repeat one turn. Expected: works the same.
-
provider = "openai"with a real key: a turn with at least one tool call. Expected: tool runs; no JSON printed as text. -
provider = "ollama"with a local model that emits tool calls as JSON text (e.g.qwen2.5-coder). Expected: the JSON becomes a real tool call (badge shown), not echoed text.
- Up/Down recall history; history survives restart (
~/.blitz/history, mode 600). - Ctrl+R searches history.
- Tab completes
/com→/compact,/agent he→helios,/resume→ this directory’s session IDs,look at @src/→ file names. - Multi-line: end a line with
\and continue; also a block between two"""lines. Expected: sent as one prompt with the line breaks kept. - Resize the terminal mid-answer. Expected: no garbled output afterwards.
- Light terminal theme:
COLORFGBG="0;15" blitz. Expected: Markdown readable on a light background. - Spinner shows while waiting and disappears before output and approval prompts.
- At an idle prompt with no background processes. Expected: exits immediately with “Goodbye”.
- During a long model answer. Expected: “⏹ Interrupted”, back at the prompt, session still usable.
- At an approval prompt. Expected: the whole turn is cancelled (not just that one action).
- During a long shell command (
sleep 60approved). Expected: the command is killed promptly.
- Long edit: diff is truncated;
dshows the full diff and asks again. -
son a command, then the identical command again. Expected: no second prompt this session. -
aon a command; restart; same command in the same directory → no prompt; in another directory → prompts. -
/approvalslists both;/approvals revoke 1removes one. - Add
deny = ["rm -rf *"]under[sandbox.commands], approve everything witha, then ask forrm -rf build. Expected: blocked by policy without a prompt.
- After a turn that edits files:
/diffshows the change;/checkpointslists the turn;/undorestores the files. - Make an edit via the agent, then change the same file yourself, then
/undo. Expected: refuses with a conflict;/undo --forcerestores. -
/diff gitshows the working tree diff.
- In a session with 5+ turns:
/compact keep the file names we touched. Expected: “Replaced N earlier events…”; the next answer still knows the key facts and file names. - Quit and
--continue. Expected: the summary still applies (the model knows earlier context but/contextis small). -
/compacttwice with a turn in between. Expected: facts from before the first compaction are still known.
- Run a prompt in directory A, then in directory B. In A:
blitz --continue "…". Expected: continues A’s session, not B’s. -
/session listin A shows only A’s;/session list --allshows both with their directories. -
blitz --resume <B's id>from A. Expected: works, with a warning that it started elsewhere.
- Ask the agent to run your project’s test command. Expected: works (build caches are writable).
- Ask it to
cat ~/.ssh/id_ed25519(or any blocked file). Expected: denied / empty. - Ask it to write outside the workspace (e.g.
echo x > ~/Desktop/x). Expected: “Operation not permitted”. -
npm install(or another tool writing to its own cache). Expected: works if the cache is inshell_writable_paths; otherwise fails until you add it. -
allow_network = false, then ask forcurl https://example.com. Expected: fails.
- Ask the agent to start a dev server in the background, then
/exit. Expected: warning listing it;kkills it;wwaits;ccancels the exit. - Start one, then from another terminal
kill -9 <blitz pid>. Expected: the server is gone within a second or two (lsof -i :<port>shows nothing).
Add to config:
[[mcp.servers]]
name = "fs"
command = "npx"
args = ["-y", "@modelcontextprotocol/server-filesystem", "."]
prefix = "fs"
-
doctor --onlineshowsmcp fs N tools./mcplists it. - Ask the agent to list files using the fs server. Expected: approval prompt naming
fs__…and the server; the call works inside the sandbox. - Add
agents = ["qa"]. Expected: the main agent no longer seesfs__tools;invoke_agent→ qa can use them. -
kill -9the CLI. Expected: no leftovernpx/ server processes. - During a session,
pkill -f server-filesystem(kill the MCP server), then ask for another fs tool call. Expected: it works;psshows a new server process. - Point an MCP server at a command that exits immediately (e.g.
command = "false"). Expected: one “unavailable” warning, then one “paused for 15s” warning; later turns aren’t slowed and don’t repeat the warning.
- A
pre_toolhook forrun_shell_commandthat exits 2 with a message. Expected: shell calls are blocked with that message; other tools work. - A
post_toolhook appending the JSON event to a file. Expected: one line per tool call, including tool name and args. - A
post_toolhooksleep 3; cat >> /tmp/post.jsonl, then a turn with several tool calls. Expected: the turn is not slowed down; the events arrive in/tmp/post.jsonla few seconds later, in tool-call order. Quit right after a turn: the pending events are still written (within about 5 s). - A
prompt_submithook that blocks prompts containingpassword. Expected: “Prompt blocked by hook”.
-
web_fetchof a docs page. Expected: approval per host; readable text returned. - Ask it to fetch
http://localhost:…orhttp://169.254.169.254/. Expected: refused (“not a public address”). - Configure
web.search_provider = "brave"(ortavily) with a key; ask a question needing search. Expected: approval once per provider withs; results with titles/URLs; follow-upweb_fetchworks.
-
/agent helios, ask it to forge a small bash tool and run it. Expected: approval shows the code as a diff; run needs separate approval. - Restart, ask helios to list and run it. Expected: still there. Ask it to delete it. Expected: gone from
~/.blitz/uc_tools.
-
git diff | blitz review this --output-format json | jq .resultExpected: a single JSON object;jqworks. -
blitz --output-format stream-json "…" | jq -c .typeExpected:session, then events, ending withresult. -
blitz --max-turns 1 "do a multi-step task"; echo $?Expected: exit code 3. - Without credentials:
blitz "hi"; echo $?Expected: clear error, exit code 1.
- Ubuntu 24.04 desktop:
sudo apt install bubblewrap,blitz doctor. Expected: sandbox on, or a clear AppArmor reason (fix: an AppArmor profile for bwrap, orsysctl kernel.apparmor_restrict_unprivileged_userns=0). - Windows: run the
.exewith Git Bash onPATH; a simple prompt and a shell command. Expected: works without the OS sandbox;doctorshows sandbox off with a reason.
-
git rm -r --cached go/binand commit (bin is now ignored). Done:go/binisn’t tracked. -
Pin the actions in
.github/workflows/go-*.ymlto commit SHAs. Done 2026-09-25, at the latest release of each action’s current major: checkout v4.4.0, setup-go v5.6.0, cosign-installer v3.10.1, sbom-action v0.24.2, goreleaser-action v6.4.0. Newer majors exist (checkout v7, setup-go v7, cosign-installer v4, goreleaser-action v7); upgrade them separately and re-run a release. -
Push; both
go-cijobs pass; the Linux job’s “Sandbox enforcement must not be skipped” step passes. Done 2026-09-26 (0c68c453,4e008b41), after fixing the macOS gofmt check and the Linux parallel-cap test. -
Tag
v0.1.0and push the tag. Expected:go-releasecreates a draft release with 5 archives, 5 SBOMs,checksums.txt,checksums.txt.sigstore.json. Done 2026-09-26: unsigned tag on4e008b41, since GPG signing wasn’t available; the draft had all 12 assets. -
Download the assets and verify:
cosign verify-blob --bundle checksums.txt.sigstore.json \ --certificate-identity-regexp '^https://github.com/rmcguinness/code_puppy/\.github/workflows/release\.yml@refs/tags/v' \ --certificate-oidc-issuer https://token.actions.githubusercontent.com checksums.txt shasum -a 256 --ignore-missing -c checksums.txtExpected:
Verified OKand every fileOK. Then publish the draft. Verified 2026-09-26 with cosign v3.1.3 (the bundle was made by cosign v2 in CI), using the exact identityhttps://github.com/rmcguinness/code_puppy/.github/workflows/go-release.yml@refs/tags/v0.1.0:Verified OK. A tamperedchecksums.txtand a wrong identity were both rejected. All 10 filesOK. The SBOMs are SPDX 2.3 with 96 Go modules (95 in the binary’s build info). The darwin/arm64 binary reports0.1.0andvcs.revision=4e008b41, anddoctorruns. Draft assets need authentication:gh api repos/<owner>/<repo>/releases/<id>/assets, then download each asset withAccept: application/octet-stream. Not yet published. -
Publish the draft. Published 2026-09-26 as Latest, after deleting a stray empty release on the same tag; the public
checksums.txtis identical to the verified one. Binaries aren’t Apple-notarized: on macOS, a copy downloaded in a browser gets the quarantine flag, and Gatekeeper refuses to run it until it’s cleared (xattr -d com.apple.quarantine blitz) or opened through Finder’s context menu. Document this in the release notes, or notarize later. -
After the move to
retail-cortex/blitz(fresh history, 2026-09-26): the firstv*tag pushed here produces a draft release, and it verifies against the new identity:cosign verify-blob --bundle checksums.txt.sigstore.json \ --certificate-identity-regexp '^https://github.com/retail-cortex/blitz/\.github/workflows/release\.yml@refs/tags/v' \ --certificate-oidc-issuer https://token.actions.githubusercontent.com checksums.txt shasum -a 256 --ignore-missing -c checksums.txtExpected:
Verified OKand every fileOK; the former repository’s identity is rejected. (The items above were run againstrmcguinness/code_puppy.) -
Desktop release, before the Apple secrets are set: a tag’s draft release has
Blitz_<v>_macos_arm64.dmg,Blitz_<v>_macos_x64.dmg, the Windows zip, the.debs, Arch packages and tarballs for amd64 and arm64, and a.sigstore.jsonfor each, and the macOS job warns that it signed ad hoc.cosign verify-blob --bundle <file>.sigstore.json(identity flags as forchecksums.txt) accepts each. -
Set the six secrets (spec_release_025 REL-22), tag again. Expected: the macOS job notarises (a few minutes) and
spctlpasses. Download the dmg in Safari, open it, drag Blitz to Applications, open it: no Gatekeeper warning, About shows the tag’s version, and “Install and start the service” works (the bundled CLI is signed too). On an Intel Mac too, if one is at hand. -
On Ubuntu 24.04:
sudo apt install ./blitz-desktop_<v>_amd64.deb; Blitz is in the app launcher with its icon, opens, installs the service (systemctl --user status blitz), andsudo apt remove blitz-desktopremoves it.
- After a day of use, compare
/costtotals with your provider’s billing dashboard. Expected: same order of magnitude; if not, adjust[pricing].
-
/localeExpected: “Interface language: English (US) (en-US)” and the listen-US, es, fr-CA. -
/locale ES-spExpected: confirmation in Spanish;~/.blitz/.env.tomlnow haslocale = "es"under[ui], with your other settings and comments unchanged. -
/help,/cost, an approval prompt, and/exitwith a background process running. Expected: all in Spanish; answer letters stilly/s/a/nandk/w/c. - 💲 Ask a question. Expected: the answer is in Spanish; code, paths, and command output are unchanged.
- Restart. Expected: still Spanish (banner, spinner “pensando”).
-
/locale ja💲 Expected: a note that menus stay in English; replies come in Japanese. - Put a
de.jsonwith a few keys in~/.blitz/locales/(seedocs/content/development/translating.md), then/locale de. Expected: those keys in German, the rest in English. -
/locale en-XAExpected: accented ⟦…⟧ text everywhere; note any plain English you see. - Native-speaker review: someone fluent reads
pkg/i18n/locales/es.jsonandfr-CA.json(tone, terminology, Québec typography for fr-CA) and runs a short session in each. -
/locale en-USto switch back.
Use a real screenshot (e.g. a UI with visible text) saved in the workspace as shot.png.
- Gemini:
what does @shot.png show?Expected: a dim📎 shot.png W×H, … KBline, then an answer that quotes text from the picture. - Anthropic: same. Then ask it to “look at shot.png with view_image”. Expected: a
view_imagebadge and an answer about the picture (image delivered inside the tool result). - OpenAI (
gpt-5or another vision model): same two checks. Expected: no “unsupported content part” error. - Gemini: the
view_imagecheck. Expected: works; if Gemini rejects an image next to a tool result, note the error text here. - Ollama with a vision model (e.g.
qwen2.5vl) and with a text-only model. Expected: vision works; text-only gives a clear API error, not a crash. - Take a screenshot to the clipboard (macOS: Cmd+Ctrl+Shift+4),
/paste, then ask about it. Expected:📎 clipboard-HHMMSS.png … will be sent with your next message. With text on the clipboard: “The clipboard has no image”. - Linux desktop:
/pastewithwl-paste(Wayland) orxclip(X11) installed. - A 4000×3000 photo: Expected: attaches as 1568×1176; the model still describes it.
-
@~/Desktop/x.png(outside the workspace) and@id_rsa_screenshot.png. Expected: refused; “Nothing was sent”. - Quit and
--continue "what was in that image?". Expected: the model can still see it. Checkls -la ~/.blitz/images(files mode 600) and that the session file under~/.blitz/sessionsis small (no base64). -
blitz --image shot.png "describe" --output-format json | jq .resultExpected: a description.
- After any session:
ls -la ~/.blitz/logs. Expected: directory mode 700,blitz-YYYY-MM-DD.jsonlmode 600 with astartline; a failed turn adds anERRORline. -
BLITZ_LOG_LEVEL=off blitz "hi". Expected: nothing new in the log. - Run a local collector, e.g. Jaeger:
docker run --rm -p 16686:16686 -p 4318:4318 jaegertracing/jaeger:latest. ThenBLITZ_TELEMETRY=1 blitz💲 and do a turn that reads and edits a file. Expected: in Jaeger (http://localhost:16686, serviceblitz), one trace per prompt:turn→invoke_agent→generate_content …andexecute_tool …, withapprovalunder the edit’s tool span. No file content, prompt text or tool arguments in any attribute. - Two prompts, quit, then
--continuewith a third. In Jaeger search by taggen_ai.conversation.id=<session id>. Expected: threeturntraces withturn.index1–3; turns 2 and 3 each show a link (“References”) to the previous turn, including across the restart. - Same with
capture_content = true. Expected: prompts and tool arguments appear; your API key does not. - Stop the collector, then run and quit a session. Expected: exit is not delayed by more than about 3 s; no telemetry errors in the terminal (they go to the log at debug level).
-
blitz doctor. Expected:logandtelemetrylines matching your settings.
- Turn Wi-Fi off, send a prompt, turn it back on within about 5 s. Expected: the turn completes (retried); the log shows the failed attempts.
-
max_retries = 0, Wi-Fi off, send a prompt. Expected: a clear error; the session keeps working afterwards. -
stall_timeout_seconds = 5, then ask for a long answer withprovider = "openai"(not streamed). Expected: it fails after about 5 s with “model API stopped responding”. Restore the default afterwards. - Ask for a task that makes many tool calls at once (e.g. “read these 12 files”), with
max_parallel = 2. Expected: it completes; with telemetry on, no more than twoexecute_toolspans overlap.
- Start the REPL. Expected: the hint line mentions typing (or Ctrl+T) to message the agent.
- Ask for a multi-step task (read several files, then edit). While it works, type
use tabs for indentation. Expected: output pauses and a↪ message for the agentprompt appears with your text. Enter shows “Sent”, output resumes, and the agent’s next step reflects the message. - Press Ctrl+T during a turn. Expected: the same prompt, empty. Enter on an empty line shows “Nothing sent”.
- Type a message while an approval prompt is showing. Expected: your keys go to the approval prompt, not a steer prompt.
- Send a message just as the agent writes its final answer (no more tool calls). Expected: “The agent finished before reading your message; sending it now”, then a new turn with it.
- During a steer prompt press Ctrl+C. Expected: the turn is cancelled (“Interrupted”), as Ctrl+C always does.
- After a few steered turns, quit and
--continue "what did I ask you mid-way?". Expected: it knows. - After quitting, type in the shell. Expected: echo and line editing work normally (the terminal mode was restored).
- Linux desktop: the same basic check.
-
!git statusand!ls. Expected: output as in your terminal, then✅ Done (…); the agent’s next answer doesn’t know about it. -
!vim README.md(or!less README.md), then quit it. Expected: the program works normally; the REPL prompt comes back intact. -
!sleep 30, then Ctrl+C. Expected:⚡ Interrupted; the session continues (no exit prompt). -
!exit 3. Expected:❌ Exit code 3. The audit log has auser_shellentry. - 💲
/plan add input validation to the signup handler. Expected: a “Plan mode” note; the agent reads files; any attempt to edit or run a command comes back as “plan mode: … disabled”; the answer is a numbered plan and no files change (git statusclean). - 💲
blitz --plan "…" --output-format json | jq .result. Expected: a plan; no changes. -
/tools. Expected: the active agent’s tools with ● on read-only ones; configured MCP servers listed for the primary agent only (unlessagentssays otherwise).
Set fallback_models = ["anthropic/claude-sonnet-5"] with a working Anthropic key, and the primary on Gemini.
-
blitz doctor --online. Expected:modelandfallback 1each initialised and responding. - Break the primary: an invalid
GEMINI_API_KEY. Ask something. Expected: one notice “gemini-… is unavailable; answering with fallback claude-sonnet-5”, then the answer. Ask again: no second notice and no delay from the primary. In the desktop app too: the notice shows in the conversation, not only in Settings › Logs. -
/cost. Expected: priced at Claude’s rates. - Fix the key, wait 15 s or more, and ask. Expected: “gemini-… is answering again”.
-
fallback_models = ["anthropic/no-such-model"]with a broken primary. Expected: a clear “every model failed” error listing both reasons. -
provider = "ollama"with nobase_urland Ollama running locally. Expected: it works (it used to call api.openai.com).
-
/pin_model qa anthropic/claude-haiku-4-5. Expected: “qa now runs on claude-haiku-4-5”, “Saved in ~/.blitz/workspaces/- /.env.toml”; that file (not ~/.blitz/.env.toml) has[agent_models]with that line and your comments intact. -
/agents. Expected: 📌 claude-haiku-4-5 next to qa. - Ask the main agent to have qa review a file. Expected: it works;
/costincludes Haiku-priced tokens. With telemetry on, qa’sgenerate_contentspan names claude-haiku-4-5. - Restart. Expected: the pin is still there (
/pin_modellists it).blitz doctorshowspin qa. -
/model anthropic/claude-sonnet-5. Expected: the main agent switches provider. -
/unpin qa. Expected: it runs on the configured model again; the line is gone from the workspace’s file. - Pin qa in workspace A, then open workspace B. Expected: in B, qa runs on the configured model (or B’s own pin); back in A, the pin is there.
- Put
qa = "openai/gpt-5"under[agent_models]in~/.blitz/.env.toml, then/unpin qain A. Expected: A’s file hasqa = ""; A runs qa on the configured model, B on gpt-5.
-
/model_settings. Expected: “No model has settings of its own…”. -
/model_settings gemini-3.8-flash temperature=0.1 seed=7. Expected: “gemini-3.8-flash now uses temperature=0.1 seed=7”, “Saved in …/.env.toml”; the file has[model_settings."gemini-3.8-flash"]with both lines and your comments intact. - Ask the same short question twice. Expected: it works; the answers are close to identical. With
BLITZ_LOG_LEVEL=debugnothing is logged about dropped settings. -
/model_settings gemini-3.8-flash. Expected: temperature 0.1, seed 7, max_tokens “(global: 65536)”, top_p “(provider default)”. -
/model_settings anthropic/claude-sonnet-5 temperature=0.5. Expected: a warning that anthropic doesn’t accept temperature for claude-sonnet-5./model anthropic/claude-sonnet-5and ask something: it answers (no 400 error). - With an OpenAI key:
/model_settings openai/gpt-5 seed=1,/model openai/gpt-5, ask something. Expected: a warning when setting; the answer works (the seed isn’t sent). -
/model_settings gemini-3.8-flash temperature=5. Expected: “Nothing changed: temperature must be a number in [0, 2]”. - Restart. Expected:
/model_settingsstill lists the settings./model_settings gemini-3.8-flash resetremoves them and the table from the file.
- In a session, ask the agent to remember a word (“pineapple”).
/session save fruit. Expected: “Saved snapshot fruit (2 messages)…”;/session listshows 📸 fruit. - Tell it “actually, remember mango”.
/session load fruit, then ask “which word?”. Expected: “Started session … from snapshot fruit”; it answers pineapple and doesn’t know mango. -
/resume <the original session's id>and ask again. Expected: mango. -
/session save fruit. Expected: refused with a hint about--force; with--forceit’s replaced and/session listshows one 📸 fruit. - Exit.
blitz --continue "which word?". Expected: continues your last ordinary session, not the snapshot.blitz --resume=fruit "which word?": pineapple, in a new session. - In a session that used tools (e.g. edited a file), save, load, and ask what it just did. Expected: it knows about the tool calls, not only the chat text.
-
[web] search_provider = "google"with a Gemini key.blitz doctor --online. Expected:web search google: N results. -
/search web golang errors.Is vs errors.As. Expected: up to five numbered links with real site URLs (novertexaisearch.cloud.google.comlinks), “Handing these to the agent to read”, then an answer that cites some of them. No approval prompt for those pages. - In the same answer, if the agent tries a page that wasn’t listed. Expected: an approval prompt.
- Ask it to save its findings to a file in that turn (e.g.
/search web … and write notes.md). Expected:create_fileis refused as read-only; no file. -
/search session <something said earlier>after a/compact. Expected: “Found N messages…” and an answer that recalls the compacted detail. -
/search session nonsense-word. Expected: “Nothing in this session’s transcript mentions it…”, and the agent says it never came up. - SearXNG instead: run
docker run -p 8888:8080 searxng/searxngwithjsonadded tosearch.formats, setsearch_provider = "searxng"andsearch_url = "http://localhost:8888", then/search web …. Expected: it works, with no API key. - Remove
search_provider./search web x. Expected: “Web search isn’t set up…”.
- In a real repository,
blitz search --statusright after opening it, then again a few seconds later. Expected: “still being indexed”, then counts per source and a last scan time. Note how long the first scan took for the repository’s size. -
blitz search <a function name>andblitz search "<a phrase from a doc>". Expected: the defining file first, at the right line; the doc with its passage. - Put a secret in
.envand search for it. Expected: nothing found. Adddeny read(docs/**)and search for something indocs/. Expected: gone at once, before any rescan. - A PDF in the workspace: search for a phrase from its second page. Expected: a
documentshit labelled “page 2”. A damaged PDF:--statuscounts it as unreadable, once. - Desktop: ⇧⌘F, type, toggle the chips, Enter. Expected: the file opens at its line; a chat hit opens the chat; light and dark both readable.
- Ask the agent “where do we handle X?”. Expected: it uses
search_workspace(visible in the tool calls), then reads the file.
- Ask the agent to remember a word. Then
/btw what was the word?. Expected: “Side question: read-only…” and the word. - Ask “what did I just ask you on the side?”. Expected: it doesn’t know.
-
/btw create a file notes.txt. Expected: it says it can’t (read-only); no file. -
/costbefore and after a/btw. Expected: the side question’s tokens are included. - Exit and
--continue. Expected: the recap and history have no trace of the side question.
- Start the REPL. Expected: the terminal tab/window title is “🐶 (untitled)”. Send a prompt; at the next prompt the title is its first line.
-
/rename Login work. Expected: “Session renamed to Login work.”; the window title follows;/session listshows it. -
/exit. Expected: “Resume with: blitz –resume=session-…”; the terminal’s own title comes back. Running that command resumes the session. -
ui.terminal_title = false. Expected: the window title isn’t touched. - In tmux, with
set -g set-titles on. Expected: the tmux title follows the session name.
- Put a Castor-style
SKILL.md(withscripts,tool_requirements,execution_hints) in~/.blitz/skills/<name>/./skills list. Expected: a line such as “1 script · TIER_2_AUDITED_WRITE · allowed by skills.policy”. -
/skills show <name>. Expected: the content hash, required tools, tier, network, passed and withheld variables, and each script with ✓/✗ and its reasons. - Add
custom_hints: {network: "true"}. Expected: the scripts are blocked (“needs the network…”). Setnetwork = "allowlist"andnetwork_allow = ["<name>"]: allowed. - Put the hash from
/skills showintrusted_hashes, then edit the script. Expected: blocked (“isn’t in skills.policy.trusted_hashes”). - Break the frontmatter (
hitl_tier: TIER_9). Expected: a startup warning naming the file;doctorshows it too. -
[skills.policy] sandbox = "docker". Expected:doctorwarns: use auto, gvisor or os.
- macOS:
blitz doctor. Expected:script sandbox os (gVisor unavailable: gVisor runs only on Linux). - Linux without gVisor:
doctor. Expected:script sandbox os (gVisor unavailable: runsc not found …). - Linux: unpack gVisor’s release tarball into
~/.blitz/bin(keepgvisor-bin/besiderunsc).doctor. Expected:script sandbox gvisor. -
skills.policy.sandbox = "gvisor"on macOS. Expected:doctorwarns that skill scripts won’t run. - Linux with gVisor: kill Blitz with
kill -9while a script runs, then start it again. Expected:runsc --root ~/.blitz/sandboxes/state listis empty after the restart.
- Put a skill with a Python script that has a dependency (e.g.
requests>=2.31) in~/.blitz/skills/<name>/. Ask the agent to use the skill. Expected:activate_skilllists the script as allowed; running it asks once to install (“Install packages for skill … –only-binary :all: – requests>=2.31”), then runs. - Ask again. Expected: no install prompt;
/envsshows one environment with the package, “used by”. - A script that writes
$SKILL_OUTPUT/report.mdand tries to write a workspace file. Expected: the workspace write fails,report.mdappears under.blitz/skill-output/…, and the agent can read it and apply changes with the file tools (diff and approval as usual). -
hitl_tier: TIER_3_MANDATORY_APPROVAL. Expected: asked before every run, with no “always” option. - A script that needs the network, without
network_allow. Expected: refused with the reason; allowed afternetwork = "allowlist"plusnetwork_allow. - Linux with gVisor: a script that runs
ls ~andcat .envin the workspace. Expected: home doesn’t exist and.envreads as empty. - Change the requirements and run again. Expected: a new environment and a new install prompt.
/envs pruneremoves the old one.
-
blitzdin one terminal,blitzin a workspace in another. Expected: the REPL says it attached; a turn streams as usual; an approval prompt appears in the REPL and its answer is honoured;/pin_model,/session save,/undowork. - While attached and idle,
blitz --local -p hiin the same workspace. Expected: it runs in a privateblitzd(the shared service hands the workspace over), which is gone when the run ends. While a turn runs in the shared service: refused, naming the other owner (exit code 2). - With no service running and no login item,
blitz -p hi. Expected:blitzdstarts, answers, and stops by itself 15 minutes later. -
/cd: in a REPL with a few turns,/cd ../other-repo(one with.blitz/settings.tomlneeding trust). Expected: the trust question for the target, then “Now in …; the session moved with you”;/rewindoffers no earlier prompts;/undosays the earlier changes are in the old workspace; the next answer knows it moved.blitz --continuein the target resumes the session; in the old workspace it doesn’t. With a background process running,/cdasks kill/wait/cancel, and c stays./cdto a workspace anotherblitz --localholds: “Stayed in …”. Attached to the service, the same, and the old workspace stays open in the service. - 💲 Background tasks (REPL): “Ask the qa agent in the background to review
README.mdfor broken links, then tell me a joke.” Expected:invoke_agentreturns atask-1at once and the joke comes without waiting;/taskslists it running, then done; at the next prompt a dim line says it ended; the agent mentions its result in its next answer (ortask_output). Ask for one that must run a command needing approval: at the prompt “qa · task-2 asks, from the background:” with the usual question; n refuses it./tasks stopon a running one: stopped./exitwhile one runs: the exit prompt lists it. - 💲 Background tasks (desktop app): the same prompts. Expected: a card under the tool group follows the task to done, Show gives its steps and result, Stop stops one; a request shows as a labelled card beside the turn’s own and Ctrl+J focuses it; after the task ends a notice appears, and with Settings › Continue after background tasks on (and nothing running) a new turn starts about it. Reopen the chat: the ended task is a notice.
- Project settings: a scratch repository with
.blitz/settings.tomlholding[permissions] deny = ["web(*)"], a[[hooks.stop]]running./stop.sh(which writes a file),[llm.openai] base_url = "https://example.invalid"and[blitz] auto_approve = true. Open it withblitz(and with the service running). Expected: a warning for each ofbase_urlandauto_approve; the question lists the hook with./stop.sh, and s prints the file. d:/permissionsshowsdeny web(*)fromproject; a turn ends without the hook’s file./trust, t (restart blitz when run locally): the hook runs after a turn. Editstop.sh: asked again. Copy the repository elsewhere: asked again there.blitz execin it: one line says the settings wait, and nothing of the hook runs; with--trust-projectit runs.blitz doctorlists the project settings and the two ignored keys. - Project settings in the desktop app: open the same repository. Expected: the dialog lists the hook, what applies and what was ignored; Don’t trust leaves a bar above the conversation; Review reopens the dialog; Trust says they’re in force, and the bar goes. Settings › Workspaces › Project settings shows the same.
- 💲 Attached: ask the agent to run
sleep 300in the background, then/exit. Expected: the exit prompt lists it; w waits (Ctrl+C gives up), k stops it (a secondblitzattached to the workspace doesn’t list it, before or after).!ls, then look in~/.blitz/audit/audit-<today>.jsonl: auser_shellentry forlsfrom the service. - Stop the service with Ctrl+C during a turn. Expected: the turn ends within about 10 s, the socket file is gone, and a new
blitzin the workspace runs locally. -
blitz service installon macOS, then log out and in. Expected:blitz service statussays installed and answering;~/.blitz/logs/service.logshows it started. With a key only in the shell, install warns about it.blitz service uninstallremoves it. - Same on Linux with systemd (
systemctl --user status blitz). - 💲 A worker
workers/check/WORKER.mdwithschedule: every 5 minutesandpermissions: ["write:reports/"]whose workflow writesreports/check.mdand also tries to editmain.go.blitz workers enable check, wait. Expected: it runs on schedule;reports/check.mdexists,main.gois unchanged;blitz workers runs checklists the run with one refusal;/resume <session>shows the conversation. EditWORKER.md: the listing says “changed” and it stops running until re-enabled. - 💲 A worker with
limits: {max_cost_usd: 0.001}. Expected: stopped as “limited” with the cost limit as the reason. - 💲 A worker with
agent: qaandmodel: anthropic/claude-haiku-4-5(the workspace on another model).blitz workers enableshows both;blitz workers runit. Expected: the run’s session (/resumeit) is theqaagent’s, the run is priced as Haiku inworkers runs, and the workspace’s/agentsand/modelare unchanged afterwards. Withagent: nobody,blitz workerslists the problem and a run fails naming it.
-
bazel build //:mac-app, copy it out of Bazel’s output (ditto "$(bazel cquery --output=files //:mac-app)" /tmp/Blitz.app) and open it with no service running. Expected: it offers to install the service; accepting runsblitz service installand the app continues. - With the service running: open a workspace with “+”. Expected: a tab named after the directory, showing the active agent and model (or why the model is unavailable).
- 💲 A turn in the app: its text appears as it streams, not only at the end. This checks that responses stream through the host (
blitz-tray --serve) into the Electron window, which the tests can’t: they exercise the proxy without a window. - 💲 A turn that edits a file with approvals on. Expected: the approval shows the diff; “Allow once” edits the file; “Deny” doesn’t, and the agent says so.
- 💲 While a turn runs, type a message and press Steer. Expected: “Queued for the agent”, and the agent takes it into account at its next tool call; Stop ends the turn with “Interrupted.”
- 💲 An
ask_user_question. Expected: the question with its options; the answer reaches the agent. - Two workspace tabs, a turn in each at once. Expected: both stream independently; switching between them doesn’t interrupt either, and the workspace dropdown shows a pulsing dot on each (a red
!when one waits for an approval). - First start:
blitz service uninstall, move~/.blitz/desktop.jsonaside, open the app, click “Install and start the service”. Expected: within a few seconds the welcome page (“Open a workspace”) replaces the install screen. - The window on macOS: the title bar area is the page’s (drag it by the top bar; the window buttons don’t overlap the workspace dropdown).
- Settings › Appearance: System, Light, Dark. Expected: System follows System Settings › Appearance while the app is open; the choice survives a restart. Compact density tightens the lists and chat.
- Edit a workspace’s name, description and colour (dropdown pencil, Settings › Workspaces). Expected: the dropdown and welcome cards change; after a restart the same workspaces are open, in order, with the same one shown.
- Close a workspace (dropdown ✕): it moves to Recent, “Undo” reopens it. 💲 Close one while a turn runs: the dialog stops the turn first. With the REPL attached and running a turn in the same workspace, closing it in the app leaves the REPL’s turn running.
- Stop the service (
blitz service stopor kill it) with the app open, then click something. Expected: “isn’t answering. Reconnecting…”; start it again: “Reconnected” and the workspaces reload. - 💲 A model answer with a link, a table and a code block: the table and code render; Copy copies the code; clicking the link opens the default browser, not the window. An image in Markdown shows as a link and isn’t loaded.
- Hover that answer: Copy, then paste into a text editor and a rich editor (e.g. LibreOffice). Expected: the text as shown, without the code block’s language label or buttons; the rich editor keeps the table and code formatting. Copy as Markdown pastes the Markdown source. Tab reaches the buttons.
- A turn whose answer comes in parts (text, tool calls, more text). Expected: each part also has Copy the whole answer, which pastes every part’s Markdown in order.
- 💲 Hover a prompt › Edit: the files and conversation go back, and the prompt is in the composer. “Code only” restores files and keeps the chat. After editing a file by hand, a rewind asks to overwrite.
- 💲
/planwith a small task: the plan shows as a card; “Yes, carry it out” makes the change; typed feedback makes the agent revise. The status bar’s mode menu changes the permission mode (the REPL attached to the same workspace shows it too). - Run settings: change the model, effort, temperature (saved to
[model_settings]), mode, agency; add and remove a permission rule; revoke an approval; compact the context. - Changes view after a turn that edited files: the files, their diffs, the agent’s summary, “Undo last turn”; the Git toggle shows every change since the last commit, staged or not, and new files. In the Files tree, Stage a modified file: its letter gets a tinted chip and the menu offers Unstage, not Stage; edit it again: the chip is outlined and both show.
- 💲 Notifications: start a turn that needs an approval, switch to another app. Expected: macOS asks once to allow notifications; then “
: approval needed”; clicking it brings Blitz back on that workspace. A long turn finishing while another workspace is shown notifies “done”; a quick one doesn’t; nothing notifies while you watch the conversation. Settings › Notifications off stops them. - 💲 Images: paste a screenshot (Cmd+Shift+Ctrl+4, then Cmd+V) into the composer, drop a PNG from Finder onto the chat, and attach one with the button: each shows a thumbnail with its size; ask about them and the model describes them. Dropping a file on the top bar does nothing (the window doesn’t open it).
- History, with a worker run once: type part of a title (the list narrows, any case); Workers shows only
⏰runs, Chats the rest; tick two and Delete 2: the dialog lists them, and after it one snackbar says “Deleted 2 chats”. The open chat has no checkbox to tick. - Commands: type
/and pick with the arrows;/cost,/context,/checkpoints,/helpshow results;/nopeis refused;/usr/bin is oddgoes to the agent as text. 💲/btw what is this repo?answers without adding to History’s message count;/search web connect-go interceptorslists links then reads them; a workspace command (.claude/commands/x.md) runs. Cmd+K: “changes” + Enter shows Changes; a workspace name switches to it; “theme dark” switches the theme. - Settings › Appearance › Interface language: Español, then Français (Canada). Expected: the whole window changes at once — top bar, dropdown, composer, menus, settings, the “Open a workspace” folder dialog’s title — and stays after a restart; System follows System Settings › Language & Region. Set
"language": "en-XA"in~/.blitz/desktop.json: no plain English left except what the service or model wrote. - A narrower window (about 1000 px): the run settings float over the chat, the Files shelf floats over the editor and minimizes when a file opens, the view switcher shows icons.
- On Linux with a graphics card (EL-07):
bazel run //:desktopwith Use the graphics card (Settings › Appearance) on, then off, restarting between. Expected: the whole window drawn either way, not blank or garbled; idle, the app’s processes stay under 5% of a core; closing the window several times leaves no new dump incoredumpctl list.BLITZ_GPU=offturns it off too.
- 💲 Ask “which test files are there?” in this repository. Expected: the agent calls
globwith a pattern like**/*_test.goand lists them without shelling out tofind. - 💲
blitz exec --max-cost-usd 0.01 "refactor the whole repository". Expected: it stops soon with “the turn reached its cost limit ($0.01)” and exit code 3 (echo $?); with--output-format jsonthe result hasis_error: trueandexit_code: 3. The same with the service running (attached) gives the same exit code. - 💲
blitz exec --timeout 20s "run the full test suite and fix failures". Expected: stops after about 20 s with “time limit (20s)”, exit 3, and no test process left running. -
blitz --max-cost-usd 1with no prompt. Expected: usage error (exit 2). With a model that has no price, a one-shot run warns that the cost limit can’t be enforced. - A repository with only a
CLAUDE.md(and one with aGEMINI.md)./memory. Expected: listed and followed; aCLAUDE.mdthat copiesAGENTS.mdis listed once. -
AGENTS.mdcontainingSee @docs/style.mdand@.env. Expected:/memorylistsdocs/style.md(imported by AGENTS.md) and not.env. -
.blitz/rules/go.mdwithpaths: ["**/*.go"]and a distinctive instruction. 💲 Ask the agent to edit a Go file. Expected: the first tool result on a.gofile carriesproject_rulesand the agent follows it; editing a Markdown file doesn’t trigger it. - 💲
/setup(or/init) in an empty folder. Expected: the agent asks what the project is for, its stack and commands, then writes.agents/AGENTS.mdandAGENTS.md,CLAUDE.md,GEMINI.md,BLITZ.mdas@.agents/AGENTS.md(approval with diffs), and offers skills and agents as multi-select questions./memorythen lists .agents/AGENTS.md once, imported. - 💲
/setupin a repository with a realCLAUDE.md. Expected: it reads the code first and asks only what it can’t tell; it asks before replacingCLAUDE.mdwith the import, after moving its content into .agents/AGENTS.md.blitz init -d <dir>runs unattended and lists its assumptions under “Open questions”. - 💲
/setupin an empty folder with no.agents/specs/. Expected: the first question offers “Write the specification first with /spec (recommended)”; choosing it ends the turn saying to run/spec, then/setup. - 💲
/spec a recipe-sharing web appin that folder. Expected: questions in rounds (intent and value, users, performance, platform, security: authentication and authorization, data, constraints, quality, delivery), then the planned list of specs to confirm, then.agents/specs/001-overview.md, the deliverables in build order with requirement IDs and acceptance criteria, andREADME.md./setupafterwards reads them and its AGENTS.md has a Specifications section. - 💲 With skills or agents in place, change a spec. Expected: the desktop’s welcome shows “The specification changed: update the skills and agents”;
/skills updateoffers additions, changes or retirements citing the specs, applies only the chosen ones, and suggests/agents update, which does the same for agents. In the terminal,/skillsalone still lists the skills. - 💲
/specin a folder withanalysis.ipynb,data/survey.csvandrefs.bib. Expected: the first question offers Research or science first; the rounds are the question, data, methods, compute, reproducibility, ethics, outputs and timeline (no deployment or sign-in questions);001-overview.mdhasKind: research, then literature, data, methods, experiments, analysis and write-up specs with Objectives./setupafterwards proposes research skills (run and log an experiment, figures, citations) and agents (a literature reviewer, a statistics critic), and a.gitignorefor raw data and results. - Desktop: a workspace with no instruction files. Expected: the first welcome tile is “Set up this workspace for agents”; it, the top bar’s wand and the command palette’s entry each start a new chat running
/setup. - 💲 Desktop: after a few chats in a workspace, open a new chat. Expected: tiles for the latest chat (opens it), uncommitted changes and a failed worker, then “Learning from your recent chats…” and up to three ideas about that work; a new chat shortly after shows the same ideas without the hint (kept until a conversation changes).
-
/modelists the five modes./mode accept-edits, 💲 then ask for a file edit and a command. Expected: the prompt shows[accept-edits]; the edit happens without asking; the command still asks. - 💲
/mode plan, then “add a README section”. Expected: a plan, no file changed, and the transcript (/session list, resume) shows the prompt as typed. -
blitz --permission-mode dont-ask exec "delete tmp.txt"(💲). Expected: the deletion is refused without a prompt; the agent reports it. - macOS or Linux with the sandbox:
blitz --permission-mode bypass. Expected: the prompt shows a red[bypass]; commands run without asking. With[sandbox] shell = "off":--permission-mode bypassis a usage error,/mode bypassis refused, andauto_approve = truestarts in default with a warning (doctorshows it under permissions). -
[permissions] ask = ["shell(git push *)"],/mode bypass(with the sandbox), 💲 then ask the agent to push. Expected: it still asks; “always” doesn’t stop the next push from asking.deny = ["shell(rm -rf *)"]:rm -rf buildis refused, also asbash -c 'rm -rf build'. -
/permissions allow write(docs/**)then 💲 an edit indocs/: no prompt; an edit elsewhere still asks./permissions remove write(docs/**) --saveedits~/.blitz/.env.tomlwithout touching its comments. -
deny = ["read(secrets/**)"], restart:read_file secrets/xis blocked, and a shellcat secrets/xfails inside the sandbox. - A worker with
permissions: ["shell:git push *"]and a useraskrule forshell(git push *): the run’s push is refused and recorded. -
.claude/commands/greet.mdwithSay hello to $1.;/helplists/greetunder Custom commands; 💲/greet Adasends “Say hello to Ada.” and the transcript shows/greet Ada. Tab completes/gr. - 💲
/reviewon uncommitted changes: findings with file and line, and no file edited (plan mode)./verifyruns this repository’s Bazel tests (bazel test //...) and reports. - A command with
allowed-tools: Read, Grep: 💲 ask it to edit a file; the edit is refused with the allowed list. - 💲
/code-review focus on the new coderuns the built-in skill by name. - 💲
[[hooks.stop]] command = "grep -q stop_hook_active || echo '{\"continue\": true, \"reason\": \"Now run the tests.\"}'": after a turn the agent runs the tests once, and the transcript shows(stop hook) Now run the tests.. -
[[hooks.session_start]] command = "echo 'Use tabs.'"and 💲 ask for a small edit: the agent follows it.[[hooks.notification]] command = "osascript -e 'display notification \"Blitz needs you\"'": a notification appears when an approval waits. -
[[hooks.permission_request]] match = "run_shell_command" command = "grep -q '\"go test' && echo '{\"decision\":\"allow\"}'": 💲go testruns without asking; other commands still ask. - 💲
/effort maxwithclaude-opus-5-5, then a hard question: the answer arrives (no 400) and/setshowsEffort: max;/effort autoclears it.--effort lowon a one-shot withgpt-5works too. - 💲
/model_settings claude-haiku-4-5 thinking_budget=4000withtemperatureset globally: the call succeeds (temperature left out) and shows thinking in the transcript. - In a real terminal (Terminal.app, iTerm2, and over ssh): 💲 Esc while the agent works stops the turn (“interrupted”); arrow keys and Alt+arrows still edit the line; Esc at an approval cancels the turn; Esc in the steer prompt drops the message and the turn goes on.
- Shift+Tab at the prompt shows
[accept-edits], then[plan], then no tag, with the prompt redrawn in place (no leftover characters). Started with--permission-mode bypass(sandbox on), the cycle includes[bypass]. -
EDITOR=vim: type a draft, Ctrl+G, add lines,:wq— the whole text is sent and shown after the prompt;:cqor an empty file returns to the draft.VISUAL="code --wait"works. Esc Esc clears a typed line. - Pickers in a real terminal (and a narrow one, 40 columns):
/agent,/model,/resume— arrows, typing to filter, Esc clears then cancels; the menu redraws in place and leaves one line. 💲 An edit approval:y/s/a/nanswer at once, “Show the whole diff” shows it and asks again, Esc stops the turn. 💲 A question with options: arrows and Enter, “Another answer…” reads a line. - 💲 Have the agent edit a file,
/exit, thenblitz --resume=<id>:/diffshows the change and/undoreverts it.ls -l ~/.blitz/checkpoints/*/shows owner-only files. - 💲 Three prompts, the second and third editing files. Esc Esc on an empty line: pick the second prompt → “Code and conversation”: the files are as before it, the model doesn’t remember prompts 2–3, and the second prompt is in the input line to edit.
/rewind→ “Conversation only” keeps files; “Summarize up to here” shrinks/context. Edit a file by hand, then rewind its prompt: the conflict picker offers to overwrite./exit,--resume,/rewindstill works. - 💲
/plan add a --version flag: the plan shows in a picker; “Yes, carry it out” makes the change in the same turn and.blitz/plans/has the plan. Again with feedback typed (“also update the README”): the agent revises and asks again./mode plan, a prompt, “Yes, and accept its file edits”: the prompt tag becomes[accept-edits]. - 💲 A three-step task: the checklist appears and ticks off (☐ → ☒) as the agent works.
plan_review = "always"in the config: a simple prompt is planned first.
- A fresh clone on a Mac with only Bazelisk (
brew install bazelisk):bazel test //...passes, downloading Go, Node and the tools itself. - The same on Ubuntu 24.04 with git and bubblewrap:
bazel test //...passes;bazel build //:deb,sudo apt install ./…deb, and Blitz opens from the app launcher. - The Bazel-built
Blitz.app(section 37) opens, shows its version under Settings › About (dev, or the tag in a--config=releasebuild), installs the service (theblitzdit carries), and works as before. On an Intel Mac too, if one is at hand. -
bazel run //:desktop-web, then http://localhost:5173/?fake: the page works without a service. - Your editor with
GOPACKAGESDRIVER=<repo>/tools/gopackagesdriver.sh: go to definition frompkg/clientintoproto/blitz/v1(generated) works; no false errors. - The first push of the branch: every CI step passes on both runners, and the reproducible job finds the archives identical.
- The first tag after the move: the draft release has five archives with
blitz,blitzdandblz, their SBOMs,checksums.txtand its bundle, the dmg and two .debs with bundles;blitz --versionandblitzd --versionshow the tag. - Existing installs: after upgrading, a login item installed as
blitz servestill starts the service (the hidden command runsblitzd);blitz service installrewrites it toblitzd. - With an older service running (or one whose program was deleted),
bazel run //:desktop. Expected: a banner says the service is older (or its program is gone) with Restart the service; clicking it stops that service (its login item, else its process) and starts this build’sblitzdat login, and the banner goes, with “The service restarted”. Settings › Service shows both versions, the service program, and Restart and Stop: Stop stops it (the window then offers to start it), also for ablitzdstarted by hand in a terminal. - Open workspace from
bazel run //:desktop: the folder dialog stays open until you choose.
These touch your real keychain and settings: use a test key, or a throwaway --config DIR for the CLI steps.
-
blitz config set-key gemini, paste a key (not echoed). Expected: Keychain Access shows an item “Blitz: global/llm.gemini.api_key” (servicedev.blitz);~/.blitz/.env.tomlhasapi_key = "keychain:global/llm.gemini.api_key";blitz config keyssaysgemini keychain;blitz doctorand a turn work with no key in the environment. The first read may ask to allowsecurityaccess: Always Allow. - A plain key in the file (
api_key = "sk-…"):blitz config keyssuggestssecure-key;blitz config secure-key anthropicleaves only the reference in the file. - In a project:
blitz config set-key -w openaiandllm.provider = "openai"set for it (desktop, below). Expected: that project uses OpenAI with its key; another project still uses the global provider; nothing is written inside either project; the file is under~/.blitz/workspaces/. - On Linux with GNOME Keyring: the same, with
secret-tool search service dev.blitzlisting the item. Without a Secret Service (a server): the key goes to~/.blitz/secrets.toml, mode 600. - Desktop, Settings › Providers & keys: with no provider set, Gemini is shown; choosing a provider shows its status chip, matching
blitz config keys; entering a key and Save stores it, and a workspace whose model was unavailable (“The model isn’t available…”) clears the note without reopening; Move to keychain on a plain key; Remove. The base URL saves on leaving the field. - Desktop, run settings › API keys: “Global” for inherited keys; a key saved there gives the workspace its own; a provider chosen there applies to that workspace only.
- Desktop, Settings ›
</>(Show the settings file): typing[lists tables, a new line in a table lists its settings, accepting one lists its values; the panel beside follows the cursor; Escape closes the completion list, not the dialog. - Desktop, Settings ›
</>(Show the settings file): the global file and a workspace’s; a typo’d setting saves with a warning;[llmis refused with the parse error and nothing is written; ⌘S saves; Revert restores. - Settings ›
</>(Show the settings file): TOML is highlighted. Typetemprature = 0.3under[blitz]and[llmon another line, then Validate. Expected: both listed with their lines (the typo a warning,[llman error), both lines marked, the cursor on the error; clicking a problem goes to its line; Save refuses while the error is there. Hoverproviderunder[llm]: its type, default and description. Every setting lists them all; searching “timeout” narrows it. - 💲 In the composer, type
explain @then part of a file’s name. Expected: a list of matching files and folders; Tab puts@pathin; choosing a folder leaves the caret after its/and lists what’s in it. Send it. Expected: the answer uses the file without the agent callingread_filefirst; the prompt shows as typed.@shot.pngalso attaches the image. - Files view: right-click a folder, Add folder to context; open a file and click @ in its bar. Expected:
@folder/ @filein the composer. Start a conversation about this file: a new chat with@fileand the cursor in the prompt. A blocked file (.env, shown with a lock) offers neither. - Files view: open a
README.md: it opens in Preview as a document; tables, task lists and code render; ⌘⇧V (Ctrl+Shift+V) switches to Source; edit and preview again: the edit shows. Go to fileREADME.md:3opens it in Source at line 3. In Preview, ⌘F opens the find bar: type a word, “1 of N”, Enter and ⇧Enter step through the marked matches, Escape clears them; in Source, ⌘F opens find and replace at the top. A workspace search hit in a Markdown file opens its Preview at the passage, the words marked. - In a preview, click
./other.md,../README.md#install,#a-headingandsrc/main.go#L10: each opens the file (at the heading or line) or scrolls; a folder link shows it in the tree;../../outside.mdbeyond the workspace is refused; a missing file says so. A```mermaidblock draws in the window’s colours (switch the theme: it redraws), Show source shows its text; a broken one shows its code and why. 💲 Ask the agent for an architecture overview in a.md: it uses Mermaid, not ASCII boxes. - Settings: the sections in order, under their headings, Getting started (Providers & keys, Appearance), Global setup (Agents, Skills, Workers, MCP servers, Secrets), Workspaces and access (Workspaces, Permissions), System (Service, Logs, About); in a narrow window the headings are thin rules between the icons (simple, no headings: Providers & keys, Appearance, Workspaces, About); the gear and ⌘, open on Providers & keys. Show advanced is in the title bar and nowhere in Appearance. With it on,
</>turns Settings over to the settings file (a quick quarter turn, none with reduced motion) and back; type in the file, turn back and forth: the text is still there. Workspaces › a workspace › Edit the settings file turns over to that workspace’s file. Appearance: System/Light/Dark are equal widths, and the light theme, dark theme and language menus are one width. Service › Version shows only the service’s version (v0.7.x); with an older service running, the warning names both. - Settings › Skills: the registries first, then Built in listing code-review, git-workflow and testing-tdd with their descriptions, with or without a workspace open.
- Settings › Appearance › Document styles…: in the window’s theme, uncomment
--doc-accentand set a colour: the sample and open previews change as you type; the other theme’s CSS doesn’t apply until the window switches to it; Reset puts back the defaults. - Right-click a file in the tree: Show in Finder (macOS), Show in Dolphin / Files (Linux): the file manager opens with the file selected; on the tree’s background, the workspace folder. Open a
.png(its pixel size under it), an.svg(Preview) and a multi-page PDF (every page, sharp; scroll). In the app, Open in the system viewer opens the image or PDF in the system’s viewer. - Studio › Workers › New worker: type what it does (the name follows), a schedule of
whenever, a workflow; Create. Expected: the schedule’s problem in the dialog, nothing written. Fix it (Daily at 6 AM); Create. Expected:.agents/workers/<name>/WORKER.mdexists with only the fields filled in; the worker is selected, New, and enables after review. A name already taken says so. - Tray (Ubuntu 24.04 and macOS): Settings › Service › Show in the system tray on. Expected: a filled bolt in the tray (top bar) at once, without logging out, white on a dark bar (and dark on a light macOS menu bar); its menu’s first line “Blitz service: running (
)”. Stop the service: within seconds the bolt is an outline, the line says stopped, only Start is on; Start, then Restart: filled again each time, and the desktop app reconnects. Open Blitz raises or opens the app; Open the logs opens ~/.blitz/logs. Log out and in: the tray is back. Runblitz-trayagain by hand: it exits (one at a time). Switch it off: no tray at the next login. On Ubuntu the bolt is amber (grey when stopped). An entry from an older install: write~/.config/autostart/blitz-tray.desktopwithExec="/usr/lib/blitz-desktop/blitz-tray"(a path that’s gone) and open the app. Expected: the entry now names…/resources/app/bin/blitz-trayand the bolt appears without logging out. - Windows setup (Windows 11, a user who isn’t an administrator): run
Blitz_<version>_windows_x64_setup.exe. Expected: SmartScreen’s More info › Run anyway, then the setup’s question and no administrator prompt; Blitz opens;%LOCALAPPDATA%\Programs\BlitzhasBlitz.exeandUninstall Blitz.exe; Blitz is in the Start menu and on the desktop; Settings › Apps › Installed apps lists Blitz with its version and Retail Cortex. Run the setup again with Blitz open: it closes Blitz and replaces it. After a self-update the installed apps list shows the new version. Uninstall it there: it asks, Blitz closes, the folder, shortcuts, entry and the tray’s start at login go,blitzis off PATH in a new terminal, and%USERPROFILE%\.blitzis still there.setup.exe /Sinstalls without a question or starting Blitz. - Studio (advanced): the menu bar shows Workspaces, Changes, Studio, Help; Studio is a button (no menu) that opens the Studio drawer, its kinds down the left, with Reload agent files in its title bar; a failed worker puts a red dot on the button, gone once Studio › Workers has been shown. Agents: the workspace’s agents fill the pane; click one and its form slides in over the list; Cancel (asks first with unsaved edits), the back arrow and Save slide back to the list, and Save and Cancel stay at the bottom while the form scrolls; Redraft offers a draft with what changed, Use puts it in the form unsaved. Secrets: the workspace’s own, shown as
{secrets:workspace:key}withurn:blitz:<workspace>:secrets:key; the workspace’s settings no longer have a Secrets card. - Workers in Studio: Studio › Workers lists the runs going now (each with Stop), then the workers. Click one: its view slides in (Run now, Disable or Enable, Edit, Delete); Edit slides to the form, back returns to the view, back again to the list; with unsaved edits, back and ✕ ask first. The status bar’s failed-runs button opens Studio on the failed worker.
- Global workers: Settings › Workers › New worker in the Global workers box; Expected:
~/.blitz/workers/<name>/WORKER.md, and~/.blitz/homeexists. Enable it and Run now: it runs in~/.blitz/home. The tray lists it asGlobal › <name>, and its Show in Blitz opens Settings › Workers. - Worker limits: Settings › Workers › Limits for every worker: set Model calls’ default to 7 and leave the field: Expected: “Saved the worker limits”; the global settings file has
default_max_turns = 7under[workers.policy], and a worker withoutmax_turnsshows 7 model calls. Typelotsin Cost: the reason in a snackbar, the field back as it was. Turn every kind off: “workers may only read”,allow = []. Set Runs at once to 3: the form says the service runs 2 until it restarts; Settings › Service › Restart, and the note goes. - Every workspace’s workers: enable a worker in a workspace, remove the workspace from the app (Workspaces › Forget): Settings › Workers lists it Not in your workspaces, and Add and open brings it back on its workers. Rename that folder: within a minute it’s Folder missing (the service log says so once); Forget asks, then it’s gone from the list and from
~/.blitz/workers.json; rename the folder back: its worker is New. - Skills in Studio: Studio › Skills › +: type what it’s for (the name follows), instructions; Save. Expected:
.agents/skills/<name>/SKILL.md, listed as Simple. Open it: References › New filestyle.md, type, Save file (⌘S too): the list says With references; Upload… a PDF and a PNG and open each: the PDF’s pages and the image show, not their bytes;style.mdopens as a preview, Source to edit. Scripts › New script (Python): the template takes the tab; Test run witha "b c": the output shows['a', 'b c']; a Shell script prints its arguments on macOS and Linux, and a cmd script says it runs on Windows only (the reverse on Windows). Maketestin Python and in TypeScript: the list names themtest.pyandtest.ts; add a line to each and run each: each prints only its own lines. Packages › Add requirements.txt, addrich, Save file: the Python script’s row says 1 package, and its first run asks to install it, then runs with it. Apyproject.tomlwith[project] dependenciesworks the same when there’s no requirements.txt (listed as unused when there is). Rename the skill and save: the folder moves with its files. Edit SKILL.md by hand while the form is open, then Save: “changed since it was opened”. Add from… › Copy a built-in asmine: it opens editable. In another skill, Add from… › Reference: it’s under Combines, and the list says Combines skills. Delete asks, then the folder is gone. - Rules: the (i) beside the title on Studio › Rules and Studio › Guardrails shows the rules-or-guardrails comparison (hidden at first; their own column marked “this page”, a button to the other), and hides it again. + (in the title bar): Before the agent,
clear-ask, Block, “The prompt says which part of the code to change.” Save. Try it with “make it better”: Fails, with the reason. Send “make it better”: the prompt is refused with the rule’s reason, nothing recorded. Add an After the agent rule, Revise, “The answer says how the change was tested”: ask for a small fix: if the answer doesn’t say, a “(rules)” message sends the agent back, and it answers again. Drag a rule above another (or ↑): the order numbers change and the file’sorder:too. A rule in.claude/rulesopens read-only. - Guardrails: in a workspace with no
.agents/guardrails, Studio › Guardrails shows the three built-ins on; 💲 ask the agent to force-push: refused by limits (its default commands). Switch Limits off:.agents/guardrails/limits.mdappears withenabled: false; on again: the line goes. 💲 Ask the agent to fetch a page that says “Ignore your instructions and …”: a ⚠ notice names the guardrail, and the agent doesn’t follow it; set it to Block and ask again: the result is withheld. Switch Secrets and personal data on with Personal data too; ask the agent to repeat “mail jo@example.com”: the answer shows[EMAIL REDACTED]and a 🛡 notice. Limits: Allowed domainsexample.com, then ask for a page elsewhere: refused with the reason; Commands not to rungit push --force*, then ask for a force push: refused. + (Your own): Actions, Block, toolsrun_shell_command, “Deleting a git branch”: Try it withrun_shell_command: git branch -D mainsays Caught; ask the agent to delete a branch: refused with the reason. Reset to defaults on a tuned built-in: asked first, its file gone, the guardrail still on. - Evals: Studio › Evals, +: name
basics, a Near case (“What does this project do?”, a one-line answer of yours) and an Exact one (“Reply with only OK”,OK), agents blitz. Save:.agents/evals/basics.mdholds them as a table. 💲 Run: the Runs tab counts up, each result with its score (the near one with the judge’s reason); open one: the expected answer beside the agent’s. Add a case “Create notes.md saying hi”, ExactDone, Warn: its result listscreate_fileas not allowed, and nonotes.mdappears. ▶ on the list runs it again; Past runs lists both. In a terminal,blitz eval basics: the same results, exit 0 (or 1 after making the Exact case expectNO);blitz eval nopeexits 2. Studio lists Evals right after Agents. An agent without evals: its row says “no evals yet” and its form Write evals; 💲 that drafts 5–8 cases for it, opened unsaved (Back asks first); save. 💲 Run; on a missed case, Refine its instructions: the request lists the missed cases; Draft, Use: the agent’s file has the new instructions. Edit the agent and save: “1 eval checks it”, Run it runs it in the background and says how it went. - Workflows: Studio › Workflows, + › Research brief: five steps on the canvas, joined. Add a Refine step from the row above the canvas, drag a link into it from Draft and out of it to Save, delete the old Draft → Save link (select it, Delete). Linking Save back to Notes isn’t allowed (a loop). Set the Notes path to a real file; Save:
.agents/workflows/research-brief.flow.yaml. 💲 Run with “coupon rounding”: each step is marked as it runs; Save to a file asks for approval beside the canvas; allow it: the file is written and the run finishes; select a step to see its output. The run’s chat is among the background runs. 💲 In the chat,/research-brief coupon rounding: a line per step, each agent step’s answer in the chat, the save approved as usual. Name a block rule on Draft that fails: the workflow stops there with the rule’s reason.blitzin a terminal:/research-brief xprints▸ /research-brief › …per step. - Reviewing scripts: add a script to a trusted workspace’s skill in Studio: the skill list says Scripts to review and its view has a banner; ask the agent to use the script: it asks first (Running… with a spinner while it runs). Review scripts › Trust these scripts: the banner goes and the next run isn’t asked about; edit the script: the banner is back. Install a registry skill with scripts in Settings › Skills: the review opens; Not now, then the installed list’s Review scripts opens it again.
-
\skillin the chat: type\rel: the composer offers the skills; Tab puts in\release-notes. Send it: the model answers using the skill’s instructions; the transcript shows the prompt as typed. - Secrets completion: type
{secrets:in the composer, an agent’s instructions, an MCP server’s environment, the settings file (</>) and a file in the Files editor. Expected:global:andworkspace:first, then the names; Tab puts in{secrets:global:name}; Escape closes the list without closing the drawer; a name that doesn’t exist is warned of under the instructions. - Secrets: Settings › Secrets › add
demo_token=demo-value-123456; a workspace’s settings › Secrets › adddemo_token=workspace-value-1234. In that workspace, 💲 askRepeat this exactly: {secrets:demo_token}. Expected: the conversation and the history show{secrets:demo_token}as typed; the answer shows[REDACTED];~/.blitz/logshas noworkspace-value-1234; Keychain Access (or Credential Manager) hasurn:blitz:…:secrets:demo_token. Replace and delete one: the list follows. - Tray submenus (macOS, Ubuntu, Windows), with two MCP servers and a workspace with workers: MCP servers lists both, checked; uncheck one: Settings › MCP servers shows it Off within 5 s, and a turn no longer offers its tools; check it again. Workers lists each worker (with its folder when two workspaces have workers); Run now starts a run, which appears first as Stop … (running); clicking that stops it. Uncheck Enabled and check it again: the worker is disabled, then enabled, without a review. A new worker says Review it in Blitz to enable it. Show in Blitz opens the app on that workspace’s workers, even with the app closed. Stop the service: both submenus go.
- Settings › MCP servers (with or without a workspace open; it’s global): Add server with a command (
npx -y @modelcontextprotocol/server-everything): it’s listed, on, and the next turn in an open workspace has its tools without restarting the service. Edit it; turn it off: the next turn has none of its tools. Remove asks first. A bad name, address or environment line is listed under the form and nothing is saved. - Command line (Ubuntu 24.04 and macOS), with no
blitzon PATH: Settings › Service › Command line says so; Install. Expected: a link in~/.local/bin(or a folder already on PATH), and if~/.local/binwasn’t on PATH, a line in~/.zshrc(~/.bash_profilefor bash on macOS,~/.bashrcon Linux); a new terminal runsblitz --version, and the row now says this app’s is on PATH. With Homebrew’sblitzon PATH instead, the row names it and offers no Install. - The sandbox required on Linux: on Ubuntu 24.04 with the AppArmor restriction on and no
[sandbox] shellin the settings,blitzand the desktop app refuse to open a workspace, saying why and how to fix it or setauto, andblitz doctorfails its sandbox check; aftersudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0they open, sandboxed (/sandbox); withshell = "auto"they open, unsandboxed, anddoctorwarns. - Fixing it: on Ubuntu 24.04 with the restriction on,
blitz securitysays AppArmor stops bwrap;blitz security fix-apparmorasks for the sudo password, writes/etc/apparmor.d/blitz-bwrapand loads it, and thenblitz security,blitz doctorand opening a workspace all work, sandboxed, whileunshare -Ur true(another program) is still refused. In the desktop app, opening a workspace shows a notice above it, This workspace didn’t open…, with Allow bubblewrap: the system’s password dialog, then Restarting the Blitz service…, and the workspace opens, sandboxed. Settings › Service shows OS sandbox with the same button and restart; cancelling the dialog shows the error and the commands to run by hand. On macOS the row isn’t there. - ADC shared only on request: signed in with ADC, a command (
env | grep GOOGLE_APPLICATION_CREDENTIALS) finds nothing; with[sandbox] share_adc = trueit names a copy thatgcloud auth application-default print-access-tokencan use, gone after the command. The same key in a project’s.blitz/settings.tomlis listed as ignored.cat ~/.config/anthropic/configs/*from a command is refused unless Claude signs in withant. - Changes › Version control in a folder that isn’t a repository. Expected: “This folder isn’t under version control” and Turn on version control, no error; clicking it runs
git init(a.gitfolder), the view shows no changes and the status bar the branch within a second. With git off the service’s PATH: it says git isn’t installed, with no button. - Tray language: Settings › Appearance › Interface language Français (Canada), then quit the tray and start it again (switch it off and on). Expected: the menu is in French (“Service Blitz : en cours”, Arrêter le service…). Back to System: the system’s language, English when it has no catalog.
- 💲 Usage after a restart: two prompts, note
/costand/context; quit andblitz --continue(or restart the service and reload the desktop app). Expected: the same totals and context size, not zeros; another prompt adds to them. - 💲 Chats survive a service restart: start a chat in the desktop app, restart the service (Settings › Service › Restart), send two more prompts in the same chat, then reopen it from the history. Expected: every prompt and answer is there, titled by the first prompt; no “Failed to save session” in Settings › Logs.
- Settings › Logs: today’s service log, newest first. Errors leaves only errors; searching a workspace’s name narrows to its records; another day from the list shows that day; Open the folder opens
~/.blitz/logsin the file manager. Withlog.level = "off"(and the service restarted) it says the log is off.
- In a git project, the top bar’s Files button: the tree lists folders first, modified files in orange with M, new ones in green with U/A, folders with changes marked. Dotfiles, ignored files (
node_modules,bin/) and.envaren’t listed; Show hidden files lists them dimmed,.envwith a lock (“Hidden from Blitz”); the setting is remembered after a restart. - Open a Go, a TypeScript, a Markdown and a YAML file: each is highlighted in the window’s colours (light and dark); typing offers the file’s words and the language’s keywords; ⌘F searches and replaces; ⌃G goes to a line.
- Change a file, ⌘S: the tab’s dot goes, the tree shows it modified,
git diffshows the change. Ask the agent something next: it’s told you edited the file (and your prompt in the history doesn’t show that note). - Edit a file in another editor while it’s open and unchanged here: within 5 seconds it reloads. Change it here too, then save: “This file changed since you opened it” — Overwrite writes yours, Reload takes theirs.
- Let the agent edit a file you have open (unchanged here): it reloads after the tool runs. With your own unsaved changes: “Changed on disk…”.
- Right-click in the tree: New file (opens it), New folder, Rename (F2), Delete (asks), Copy path, Copy relative path. Arrow keys move and open folders; Enter opens.
- ⌘P: type part of a name (
dscfindsdiscount.go);name:12opens at line 12. - A path in an answer (
internal/cart/discount.go) and a tool call’s path open the file. - Unsaved changes: closing the tab, closing the workspace (dropdown) and quitting the app (⌘Q, the window’s close button) each ask first.
- With no file open, the chat is center stage (the middle, full width of its column); open a file during a turn: the chat moves to the right and keeps streaming; close the last file: it returns to the middle. In Changes or Workers it stays on the right.
- The IDE layout: files left, editor middle, chat right. Minimize the shelf (≪): a rail with Show files and Go to file remains, and stays after a restart. Drag the chat’s left edge: its width is kept after a restart.
- The workspace dropdown: switch workspaces; while a turn in another workspace waits for approval, the dropdown shows a
!; reopen a recent workspace; Open workspace…; Settings is the top bar’s far-right button.
-
blitz license: Blitz’s NOTICE (Copyright 2026 Retail Cortex, then Code Puppy’s MIT notice) and where the rest is;blitz license fullthe Apache License;blitz license third-partythe notices, inless(or$PAGER);/licensein the REPL the same. -
blitzd --license,--license=full,--license=third-party: the texts, and the service doesn’t start. - The desktop app: Settings › About › Licenses and Third-party notices, and
/licensein the composer, open the Licenses dialog; its three tabs show the texts. - A release: each archive has
LICENSE,NOTICEandTHIRD_PARTY_NOTICES;Blitz.app/Contents/Resourceshas them; after installing the.deb,/usr/share/doc/blitz-desktop/hascopyright,NOTICEandTHIRD_PARTY_NOTICES. - Add a Go or npm dependency without updating the notices: CI’s “third_party_notices –check” fails until
tools/third_party_notices.shis run.
-
bazel run //docs:serve, then http://localhost:1313: the menu has Getting started, Products, Guide, Architecture, Shared packages, Development and About; search finds a word from a spec; the dark-mode toggle works. - After a push to
mainthat changesdocs/, the docs workflow deploys, and https://retail-cortex.github.io/blitz/ shows the change; the architecture page’s diagrams render; Edit page opens the file on GitHub. - A link to a missing page (
[x](nope.md)in any page) failsbazel build //docs:sitewith the page and the link named. - On a phone-width window, the menu opens from the ☰ button and no page scrolls sideways.
- Architecture › API reference: a page per proto; every diagram draws (the workspace page has 100 and takes a few seconds), in light and dark mode; a comment with a placeholder (
turn.proto’splanfield: “/plan”) shows the placeholder.
- On GitHub: the README shows the desktop screenshot and its links work; Contributing in the repository’s sidebar opens
docs/CONTRIBUTING.md. - Open a pull request: GitHub requests a review from the owner in
.github/CODEOWNERS. - CI’s Linux job summary has the coverage table; lower
tools/coverage/floor.txt’s number above the total on a branch and the job fails. - After CI on
main, the site’s About › Coverage shows the same total, the commit it measured, and each package’s files when expanded.
On Windows 10 (1803 or later) or 11: unzip blitz_<version>_windows_amd64.zip (or bazel build //release:archives), with no API key set for a free run.
- Run
blitz-tray.exe. Expected: no console window; an amber bolt in the notification area within a few seconds (the tray startedblitzd.exe); its tooltip says “Blitz service: running (…)”. A secondblitz-tray.exeexits at once. - Open Blitz.
Expected: an Edge window with no tabs or address bar shows the desktop page, connected; the address it lands on is
http://127.0.0.1:<port>/, not the/open?t=…link. Open a workspace (type its path) and run a turn: it streams, and an approval works. - In that window: Show in File Explorer on a file, Settings › Service’s controls, Help › About’s licenses. Expected: Explorer opens with the file selected; Stop turns the icon grey and Restart amber; the license texts show.
- Stop the service, then Start the service from the tray.
Expected: the icon goes grey, then amber;
~/.blitz/logsshows the service stopping cleanly (“exit: a client asked”). - Tick Start Blitz at login, sign out and in.
Expected:
HKCU\Software\Microsoft\Windows\CurrentVersion\RunhasBlitz; after signing in, the icon is back and the service runs. Untick it: the value is gone. - From PowerShell,
curl.exe -i http://127.0.0.1:<port>/(the port from the Edge window), and the same with-H "Host: example.com". Expected: 403 both times: no cookie, and a foreign host. -
icacls %USERPROFILE%\.blitz\runExpected: only you, SYSTEM and Administrators.
- In the desktop app, open a Markdown file with headings, a numbered list starting at 5, a task list, a table, code, a link to
#a-headingand a workspace image; Export › Export as Word. Expected:<name>.docxbeside it; a second export asks Replace.docx? . - Open it in Word, then in Pages (or LibreOffice). Expected: no repair prompt; headings in the navigation pane; the list counts 5, 6; the table’s header row, alignment and borders; code in a monospace shaded block; the heading link jumps; the image fits the page.
- In a session,
/export chat.docx; from a shell,blitz sessions export <id> -o chat.docx. Expected: both open in Word with the conversation’s headings and code.
- In a repository with a remote and a second branch on it, open Changes › Version control and click the branch button. Expected: Branches lists the local ones (the current one checked), On the remote the remote’s branches no local branch tracks, each with its last commit’s subject.
- Choose a remote branch.
Expected: “Switched to
.”; the status bar shows the new branch, the toolbar’s Pull has its upstream, and files open in the editor show the branch’s content. - Edit a file the other branch also changed, without committing, and switch to that branch. Expected: “Your uncommitted changes would be overwritten by that branch: commit them first.”; still on the same branch, the edit kept.
- New branch…: try
a b, then an existing name, thentry/branches. Expected: the first two are refused under the field; the third switches to the new branch with your uncommitted changes still there. - Commit on the new branch, switch back to
main, and Merge into main… withtry/branches. Expected: “Brought 1 commit from try/branches into main.”; merging it again says main already has everything in it. - Make both branches change the same line, then merge. Expected: “Merging try/branches stopped on conflicts…”; the banner says Merging try/branches (not the upstream); Take theirs takes the merged branch’s line; Complete merge commits “Merge branch ’try/branches’”. Repeat and Abort merge: the dialog says the branch goes back to before the merge, and it does.
- Click the branch in the status bar. Expected: Changes opens on Git (in simple mode, on this session’s changes).
- In each language (Settings › Appearance › Interface language), go through the Changes menu, the Changes view’s toolbar, the commit dialog, a file’s right-click menu in the Files tree, its history and the status bar’s branch. Expected: no “Git”, “stage” or “.gitignore” in a label: Version control, Commit changes…, Include in commit / Leave out of commit, Include all changes, Do not version / Version it again, View history…. Git is named only when it isn’t installed, in the sign-in message and in a repository-config warning.
- 💲 In a workspace with a rule in
.agents/rules/(say, “Answer in French”), start a conversation and send a message; then edit the rule (“Answer in German”) in an editor and send another, in the same conversation. Expected: the second answer follows the edited rule, with no reload. The same forAGENTS.md, and for a skill’sSKILL.mdedited in place (its new description in/skills). - 💲 Send several messages without changing anything.
Expected: nothing reloads (the turns aren’t slower, and the provider’s prompt cache keeps hitting:
/costshows cached tokens). - Agents › Reload agent files, then
/reloadin the chat. Expected: “Reloaded N agents, N skills and N instruction files and rules.”;/reloadlists the files. Break a skill’s frontmatter and reload: the error says which file didn’t load.
- Open Settings (⌘,), then drag the window by the title bar. Expected: Settings slides down from under the top menu over the whole middle, to the status bar; the window moves and Settings stays open.
- Open, in turn, Help › User guide, Changes, the workspace’s history, an agent (Studio › Agents), a worker, the background runs (status bar) and Settings › About › Licenses. Expected: each slides down in the drawer, taking the place of the one before; the pinned chat input steps aside while it’s up and comes back when it closes; ✕ or Escape (with the focus in it) closes it.
- Studio › Workers › New worker (and Studio › Agents › +), type a few words, then press ⌘, (or ✕, or Escape in the form). Expected: “Discard changes?”; Cancel brings the form back with your words, Discard closes it.
- Open Commit changes… (or delete a chat) and click beside the dialog, then drag the window by the title bar over the dimmed area. Expected: the dialog stays open and the window moves; Escape or its buttons close it.
- Light and dark, with Transparency on and off. Expected: the drawer is a pane like the chat’s, the panes under it not showing through, with no clipped controls; in a narrow window Settings’ sections are a rail of icons.
Use a test service with the API keys unset (env -u GEMINI_API_KEY); the workflow below needs no model.
- Save
.agents/workflows/approve.flow.yamlwith a read_file step, an Ask a person step (the starter form) and a save_file step after it; Studio › Workflows › approve › Run. Expected: the first step finishes, the second is marked waiting, and its form shows under the run; Approve sends it, the run goes on and asks to save. - Run it again and close the app window (leave the tray running). Within 10 s: Expected: the tray’s icon has a dot and its menu says 1 workflow task waiting; a notification “approve is waiting for you” shows. Clicking it opens the small tasks window (only the form, Later, Open Blitz); Approve sends it and the window closes; the dot goes.
- Settings › Appearance › Workflow tasks: Show the task at once, quit the app, run the workflow from the CLI (
blitzthen/approve) and exit the CLI. Expected: the tasks window opens by itself, without a notification. With Off, nothing opens, but the tray’s dot and menu item still show; the item opens the window. - With the app open on another workspace, start a run that waits. Expected: a snackbar “approve is waiting for you: …” with Open (or a system notification while the window is behind another); the status bar shows the task button, which opens the tasks dialog. Later closes it and the button stays.
- A Wait step with
wait: 1mbetween two steps. Expected: the run waits; about a minute later (the service’s scheduler) it goes on by itself, also after a service restart in between. - Edit the workflow while a run waits, then answer its task. Expected: “the workflow changed since the run paused”: the run isn’t resumed.
- Linux without a notification daemon, and Windows. Expected: Linux opens the tasks window directly; on Windows the notification comes from the Blitz app and opens the same window.
52. Workflow runs: the canvas, receipts, schedules and modes (spec_workflows_043 WF-09, WF-10, WF-19, WF-20, WF-21)
Use a test service with the API keys unset (env -u GEMINI_API_KEY) for everything but the cost checks; a run with agent steps on a real model costs a few cents.
- Studio › Workflows › a workflow. Expected: Studio’s kinds shrink to icons and the canvas fills the drawer. Steps opens the toolbox (steps under it move into view); drag Agent onto the canvas: it lands where it’s dropped and its settings open. Click a step type instead: it lands in view.
- Drag the settings’ left edge, then fold them with ». Expected: the canvas widens; the rail names what’s selected and unfolds them; selecting a step unfolds them too. The width is kept after reopening Studio; double-clicking the edge restores it.
- An agent step’s Skills and Rules. Expected: a drop-down of check boxes (with a filter when there are more than eight); ticking keeps it open; the field lists what’s chosen.
- Run a workflow with an agent step and a save_file step, then close Studio at once. Expected: the status bar shows /name 1/3-style progress; its menu shows steps, time, cost and 1 approval waiting when it asks; clicking it reopens the canvas on the run, with the approval under the canvas.
- On the run panel: Steps, Events, Stream, Copy the receipt, fold, drag its top edge, close. Expected: each step’s start, duration, model, tokens and cost (agent steps priced, others “—”), the run’s totals; events as they happen; the agent step’s text appearing as it’s written; the copied text is the receipt; closing the panel doesn’t stop the run, and reopening the workflow shows it again.
- Deny the approval with Studio open. Then run a workflow whose read_file step reads a missing file, and close Studio before it fails. Expected: a failure shown on the canvas isn’t announced again; with Studio closed, a snackbar “/name failed. It stopped at …” with Open, and a red item on the status bar until the run is opened; with the window behind another app, a system notification.
- Close the app window (leave the tray), and let a scheduled run fail (a read_file step on a missing file).
Expected: within 10 s a notification “
failed” with why; clicking it opens the app on the workflow’s canvas showing the failed run. With Settings › Appearance › Workflow tasks Off, nothing. - Past runs (the clock button). Expected: the workflow’s runs, newest first, with state, duration, cost and how each was started; picking one shows its receipt.
- Select nothing on the canvas › Schedule › Add a schedule: every minute, input test.
Expected: the schedule shows with its next run and a switch; within a minute the run starts by itself (status bar), its receipt says by a worker; Studio › Workers shows the worker
<name>-schedule, and its view shows the run’s progress with Open on the canvas. Switch it off, change it, remove it. - Run a worker by hand (Run now), leave its view and come back while it runs. Expected: the view shows the run going (its events from the start) instead of only the worker.
- Stop the service while a run goes, start it again, open the workflow’s Past runs. Expected: after about three minutes the run reads Stopped with “the service stopped while it ran”.
- With no
permission_modein the settings, open a workspace. + in Studio › Workflows. Expected: the status bar’s mode is Auto; the new-workflow dialog offers Permission mode with Auto (the default) chosen, and the workflow made has it in its settings; the file has nomode:line. - Run a workflow with a save_file step (keys set: the reviewer is a model call).
Expected: no approval card: the reviewer allows it (
auto-allowin the audit log); the run panel’s summary ends with Auto. - Settings › Workspaces › the workspace › Behaviour › Permission mode: Ask. Restart the service, reopen the workspace, run the workflow again. Expected: the workspace is still Ask; the workflow’s settings say the workspace’s mode applies instead; the run asks for the save; its summary says Ask and its events “Asked for Auto; the workspace’s mode, Ask, applied”. A workflow set to Don’t ask refuses the save instead of asking.
The facts cost nothing; a check makes one model call per item judged (cents for a small workspace). Use a test service with keys unset for the facts, and keys set only for the check.
- Open Studio from the menu bar. Expected: it opens on Overview: the workspace’s ring (“Not judged yet”), a ring per kind with counts, the 30-day runs chart, eval coverage, Needs attention (an agent file with bad YAML shows as “doesn’t load”), and a card per kind. Opening a card shows its table; reopening Studio keeps it open.
- With three workspaces open, open Studio, then click through every kind and back to Overview. Expected: every list loads at once; nothing waits (the Overview holds no connection open).
- Re-check, then close Studio, and reopen it. Expected: the check went on: the bar shows where it is; when it ends, “Judged n items for $x” (or how many couldn’t be judged).
- Re-check. Expected: a dialog says how many items and about what it costs; Judge shows “Judging 1 of n” with a bar and Stop; the kind rings and the workspace’s ring fill in as verdicts arrive; a snackbar says what it judged and cost. Each item in Studio’s lists shows its grade badge (a pulsing dot while it’s judged).
- Re-check again without changing anything; then edit an agent and Re-check. Expected: “Every item is judged and unchanged”; then only that agent is judged, and its row shows a second point on its trend.
- Open a kind’s card, click an item, then Improve on a fix. Expected: each rubric line’s score (pips) and reason, the summary, who judged and when; Improve closes Studio with the request in the composer.
- The gear: schedule every 5 minutes, limit 0.0001. Expected: saved for the workspace; within a few minutes “The scheduled check didn’t run: judging n items would cost about $…, over the $0.00 limit”. With limit 0 it runs by itself. A new workspace that was never checked by hand is never checked on a schedule.
Each turn is one small model call (well under a cent); the composer uses the suggestions model, else the auto reviewer’s.
- Studio › Workflows › + › Compose with AI. Ask for “Every weekday, read qa/sales.csv, summarize the trend in two paragraphs and save it to reports/sales-summary.md”. Expected: “Thinking…”, then either a question with suggested answers as buttons, or straight away a draft: its name, its steps in order (read a file, summarize, save to a file) and no problems; the cost so far at the bottom.
- Ask for something vague (“help with my reports”). Expected: a question, one at a time, with buttons; answering by a button or in your own words moves on; a draft comes by the fifth answer at the latest.
- With a draft, Ask for a change (“also email it to me”). Expected: a new draft (email steps are coming soon, so the draft says what it can’t do, or shows it as a problem to fix by hand).
- Open on the canvas. Expected: the canvas opens on a new, unsaved workflow with the draft’s name (a number added if it’s taken), its steps linked in order, and “Opened as a new workflow: review it, then save”; nothing is written until Save.
- With the model unreachable (a wrong key), Start. Expected: the dialog shows the error; the status bar stays Connected (not “The Blitz service isn’t answering”).