Date: 2026-04-28
Use this manual for day-to-day Whale development. It turns the first Windows bring-up lessons into a repeatable inner loop.
The active Rust workspace is:
Set-Location D:\WhaleCode\third_party\codex-cli\codex-rsThe repository root is not an active Cargo workspace. Run Rust build, test, and
install commands from third_party/codex-cli/codex-rs.
Whale reuses the Codex CLI release-version flow instead of adding a parallel version source:
- Release semver lives in
third_party/codex-cli/codex-rs/Cargo.tomlunder[workspace.package].version. - Rust release tags must stay
rust-vX.Y.Z; the release workflow validates that the tag matches the Cargo workspace version. - npm staging uses the same release semver through
scripts/stage_npm_packages.py --release-version.
Whale adds one checked-in monotonic build number at
third_party/codex-cli/BUILD_NUMBER. Increment it when preparing a release
build or handing off a locally installed build for user verification. Keep it a
positive integer, and commit it with the version bump. The TUI embeds it at
compile time and renders startup/status headers as
vX.Y.Z build N. GitHub Release display names include the build number, while
artifact names, npm versions, and WinGet versions keep the semver-only Codex
flow.
Run this guard after changing version, build, release workflow, or packaging files:
Set-Location D:\WhaleCode
.\scripts\check-build-profile-policy.ps1Feature work that should be isolated from main can use a sibling Git
worktree. The first alpha feature branch was created as:
git worktree add -b whalecode-alpha D:\whalecode-alpha
Set-Location D:\whalecode-alpha
git commit --allow-empty -m "chore: initialize whalecode alpha worktree"
git push -u origin whalecode-alphaOn Windows sandboxed shells, writes for a sibling worktree may still touch the
main repository metadata under D:\WhaleCode\.git\worktrees\.... If a commit
fails while creating index.lock, rerun the Git command in an approved host
shell instead of deleting lock files by hand. Pushes can also fail with
SEC_E_NO_CREDENTIALS when the sandbox cannot access the normal Windows Git
credential context; rerun the same git push from the host shell.
On Windows, use MSVC Rust. If the shell is not already a Developer PowerShell, load Visual Studio tools before Cargo commands:
$VsDevCmd = "C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\Tools\VsDevCmd.bat"
cmd /d /s /c "call `"$VsDevCmd`" -arch=x64 -host_arch=x64 >nul && cd /d D:\WhaleCode\third_party\codex-cli\codex-rs && cargo check -p codex-cli --locked"Move build output out of the source tree:
$env:WHALE_CACHE_ROOT = "D:\BuildCache\whalecode"
New-Item -ItemType Directory -Force $env:WHALE_CACHE_ROOT | Out-Null
$env:CARGO_TARGET_DIR = Join-Path $env:WHALE_CACHE_ROOT "cargo-target"For normal local development, keep incremental compilation enabled:
$env:CARGO_INCREMENTAL = "1"Use CARGO_INCREMENTAL=0 only for clean reproduction, CI-like checks, or when
you are deliberately trading rebuild speed for less incremental state.
Some spawned automation shells may not inherit the user PATH immediately. If
cargo is not recognized but Rust is installed for the user, repair only the
current process before running tests:
$env:PATH = "$env:USERPROFILE\.cargo\bin;$env:PATH"The first measured Windows bottleneck was not a single slow command. It was dependency fan-out.
codex-models-manager is on the path into codex-core,
codex-app-server, codex-tui, codex-exec, and finally codex-cli.
Changing model catalog or default-model code can therefore invalidate much of
the CLI stack. With CARGO_INCREMENTAL=0, Cargo cannot reuse the usual local
incremental state, so even debug rebuilds can stay slow.
Release installs used to be slower again because the old release profile used
expensive final optimization and link settings. The old settings in
third_party/codex-cli/codex-rs/Cargo.toml are:
[profile.release]
lto = "fat"
codegen-units = 1
strip = "symbols"fat LTO plus codegen-units = 1 intentionally optimizes across the whole
program, but it also collapses the final codegen and link path into one or a few
long CPU-bound units. On Windows this can look like Cargo is stuck even while
rustc.exe is still consuming CPU. This is a build-profile bottleneck, not a
sign that the machine is too slow.
The 2026-04-28 release-build probe showed this shape clearly: helper binaries
finished quickly, .fingerprint timestamps advanced through
codex-windows-sandbox, codex-app-server, and codex-tui, but the final
release\whale.exe stayed stale while release rustc.exe work continued for
more than 20 minutes. The bottleneck is the whale release codegen/link path,
especially the codex-tui and final CLI dependency closure.
The corrected policy is:
release: local optimized smoke profile,opt-level = 1,lto = false,incremental = true,codegen-units = 256, and no symbol stripping.dist: explicit production distribution profile,opt-level = 3,lto = "fat",incremental = false,codegen-units = 1, and symbol stripping.
This follows Cargo's own profile model: --release is just
--profile release, custom profiles inherit from a named profile, and each
custom profile writes to its own target directory.
The corrected Windows measurements on 2026-04-28:
cold cargo build -p codex-cli --bin whale --release --locked: 13m 06s
warm cargo build -p codex-cli --bin whale --release --locked: 3.2s
cold-ish cargo build -p codex-cli --bin whale --locked after profile/helper churn: 2m 55s
warm cargo build -p codex-cli --bin whale --locked: 3.0s
cold-ish cargo build -p codex-cli --bin whale --release --locked after helper split: 14m 16s
warm cargo build -p codex-cli --bin whale --release --locked: 3.4s
steady warm cargo build --release --locked --bin whale plus all forwarded helpers: 2.5s
The next dependency split moved hidden and non-primary command ownership out of
the top-level CLI. whale now forwards these surfaces to sibling helpers:
whale app-server ...->whale-app-serverwhale mcp-server->whale-mcp-serverwhale cloud .../whale cloud-tasks ...->whale-cloud-taskswhale responses-api-proxy ...->whale-responses-api-proxywhale stdio-to-uds ...->whale-stdio-to-udswhale exec-server ...->whale-exec-serverwhale debug app-server send-message-v2 ...->whale-app-server-test-client
Helpers that need to re-enter the agent CLI receive the original whale
binary path via hidden runtime flags, so the split does not accidentally make a
helper spawn itself. Keep those runtime flags private implementation detail.
This removes app-server, MCP server, cloud task UI, exec-server, stdio bridge,
proxy, and app-server test-client implementation crates from the main CLI
dependency closure. The main binary still carries the core agent stack, TUI, and
non-interactive exec path. The remaining heavy transitive app-server cost now
enters through codex-app-server-client in codex-tui and codex-exec, not
through hidden slash or debug helper command ownership. Further cold-build cuts
must split that public TUI/exec app-server transport boundary; do not put helper
crates back into codex-cli.
The cloud-task mock backend is also now a dev-dependency, so normal local and release builds do not compile the test-only mock client.
Choose the smallest valid gate for the files you changed.
| Change area | First gate | Escalate when |
|---|---|---|
| Documentation only | git diff --check |
Links, commands, or paths changed and need live validation. |
| Model catalog/default selection | cargo test -p codex-models-manager --locked |
TUI or app-server model picker behavior is affected. |
| Core model defaults/config | cargo test -p codex-core --locked defaults_to_deepseek_pro_provider |
Provider routing, auth, or config schema changed. |
| App-server model list | cargo test -p codex-app-server --test all --locked model_list |
Web/API model selection behavior changed. |
| Provider/API transport | cargo test -p codex-api --locked chat_completions |
SSE, streaming, auth, or usage parsing changed. |
| TUI/CLI surface | cargo build -p codex-cli --bin whale --locked |
Manual TUI smoke or local install is needed. |
| App-server CLI/helper | cargo check -p codex-app-server --bin whale-app-server --locked |
VS Code/app-server protocol behavior changed. |
| Forwarded helper command | cargo check -p <helper-crate> --bin <helper-binary> --locked |
Local install or npm/release packaging changed. |
Prefer package-level tests before building the full CLI. A full CLI build is a smoke gate, not the first response to every small Rust edit.
For app-server integration tests in the Whale fork, isolate child processes with
WHALE_HOME, not only CODEX_HOME. CODEX_HOME is kept only as a Codex
compatibility boundary and Whale runtime config loads from WHALE_HOME.
If a config RPC test unexpectedly reports C:\Users\<user>\.whale\config.toml
as its user layer or writes a value like model = "gpt-new" into the real local
config, restore the user config and fix the test harness before trusting the
result.
After changing model catalog, default picker, provider visibility, or Whale branding, run:
cargo test -p codex-models-manager --locked
cargo test -p codex-core --locked defaults_to_deepseek_pro_provider
cargo test -p codex-app-server --test all --locked model_listBuild the CLI only after these pass:
cargo build -p codex-cli --bin whale --lockedInstall the debug binary for local TUI smoke:
Set-Location D:\WhaleCode
.\scripts\install-whale-local.ps1 -PersistUserPath -BackupLegacyCopies
whale --version
whale debug modelsThe isolated local install path is %USERPROFILE%\.whale\bin\whale.exe.
whale --version reports the semver only; the monotonic build number is
embedded in the TUI/status version display (vX.Y.Z build N). When bumping
BUILD_NUMBER, update and run the status snapshot gate so the installed build
number is covered by tests as well as manual smoke.
Do not copy Whale into %USERPROFILE%\.cargo\bin, %USERPROFILE%\.local\bin,
%APPDATA%\npm, or WindowsApps. Those are shared tool locations and can make
Whale appear coupled to official Codex or npm-installed CLIs.
Verify the resolved binary and CLI separation:
where.exe whale
where.exe codex
.\scripts\check-cli-isolation.ps1check-cli-isolation.ps1 intentionally runs both whale --version and
codex --version. Treat any stderr from either command as a failed smoke test
even if PowerShell reports script exit code 0. On Windows, a
thread 'main' has overflowed its stack message means the freshly built
whale.exe itself is unhealthy; verify both
D:\BuildCache\whalecode\cargo-target\debug\whale.exe --version and the
installed %USERPROFILE%\.whale\bin\whale.exe --version before accepting the
install.
Existing terminals and long-running agent processes may keep an old PATH until
they are restarted. check-cli-isolation.ps1 refreshes PATH from the user and
machine environment by default to validate what a new terminal will see. Use
-UseCurrentProcessPath only when you intentionally want to diagnose the
currently running shell.
If install fails or a new terminal still shows old behavior, check for a running TUI that is holding the old executable open:
Get-Process whale -ErrorAction SilentlyContinue |
Select-Object Id,Path,StartTimeWindows cannot overwrite an executable while that exact whale.exe is running.
When the active agent process locks %USERPROFILE%\.whale\bin\whale.exe, stop
that process and rerun the normal installer:
Stop-Process -Id <pid>
.\scripts\install-whale-local.ps1 -PersistUserPath
.\scripts\check-cli-isolation.ps1Do not create a second Whale bin directory for normal local installs. It makes PATH order and future verification harder to reason about.
Expected first picker entries:
deepseek-v4-pro
deepseek-v4-flash
No GPT, ChatGPT, OpenAI, or Codex-branded model should appear in the picker.
deepseek-v4-pro should be marked as the default/current model unless the user
has explicitly selected another model in config.
Use the default release profile for local optimized builds, package smoke, and performance checks:
cargo build -p codex-cli --bin whale --release --locked
Set-Location D:\WhaleCode
.\scripts\install-whale-local.ps1 -BinaryPath D:\BuildCache\whalecode\cargo-target\release\whale.exe -PersistUserPath -BackupLegacyCopiesBuild helper binaries only when you need to exercise the forwarded helper commands locally:
cargo build -p codex-app-server --bin whale-app-server --release --locked
cargo build -p codex-app-server-test-client --bin whale-app-server-test-client --release --locked
cargo build -p codex-cloud-tasks --bin whale-cloud-tasks --release --locked
cargo build -p codex-exec-server --bin whale-exec-server --release --locked
cargo build -p codex-mcp-server --bin whale-mcp-server --release --locked
cargo build -p codex-responses-api-proxy --bin whale-responses-api-proxy --release --locked
cargo build -p codex-stdio-to-uds --bin whale-stdio-to-uds --release --locked
Set-Location D:\WhaleCode
.\scripts\install-whale-local.ps1 -BinaryPath D:\BuildCache\whalecode\cargo-target\release\whale.exe -PersistUserPath -BackupLegacyCopiesThe installer copies all forwarded helper binaries when they exist next to the
selected whale.exe. If a forwarded command reports that a helper is missing,
build the specific helper binary above and rerun the installer.
Use the explicit dist profile only for final distribution when binary size is worth the extra compile time:
cargo build -p codex-cli --bin whale --profile dist --locked
Set-Location D:\WhaleCode
.\scripts\install-whale-local.ps1 -BinaryPath D:\BuildCache\whalecode\cargo-target\dist\whale.exe -PersistUserPath -BackupLegacyCopiesDo not use cargo install as the Whale local install path, because it writes
into shared Cargo bin directories instead of the isolated
%USERPROFILE%\.whale\bin directory.
If a build appears stuck, check the actual processes before assuming a hang:
Get-Process cargo,rustc,link -ErrorAction SilentlyContinue |
Select-Object Id,ProcessName,CPU,StartTime,Path
Get-CimInstance Win32_Process -Filter "name='rustc.exe'" |
Select-Object ProcessId,CommandLineRun the profile guard after changing Cargo profiles or this runbook:
.\scripts\check-build-profile-policy.ps1Cargo references:
- https://doc.rust-lang.org/cargo/reference/profiles.html
- https://doc.rust-lang.org/book/ch14-01-release-profiles.html
Use user or process environment variables for secrets. Do not commit secrets to the repository:
$env:DEEPSEEK_API_KEY = "replace-with-real-key"
$env:WHALE_HOME = "$env:USERPROFILE\.whale"For an installed local debug build:
whale --version
whale debug modelsUse a live model smoke only when network access and billing are expected:
whale exec "Reply with one short sentence."When validating DeepSeek thinking mode with tools, use a prompt that forces at least one read-only command:
$env:DEEPSEEK_API_KEY = [Environment]::GetEnvironmentVariable("DEEPSEEK_API_KEY", "User")
whale exec "Run a read-only directory listing of D:\WhaleCode, then reply with exactly: OK"This catches the DeepSeek protocol requirement that assistant messages with
tool calls must carry the matching reasoning_content back into subsequent
Chat Completions requests.
Every repeated operational lesson should land in documentation before it is forgotten. Update the closest runbook or migration log when you learn something about:
- build setup;
- login or API-key configuration;
- local install paths;
- slow build bottlenecks;
- test gates;
- packaging and upload commands;
- failure recovery.
Runtime feature changes should also add structured logs or session events where they help future diagnosis. Documentation is not a substitute for runtime observability.
Whale development must not mutate official Codex installation or runtime state. Keep these boundaries:
- Whale binary:
%USERPROFILE%\.whale\bin\whale.exe - Whale runtime state:
%USERPROFILE%\.whaleor process-scopedWHALE_HOME - official Codex npm package:
%APPDATA%\npm\node_modules\@openai\codex - official Codex app package:
%ProgramFiles%\WindowsApps\OpenAI.Codex_* - official Codex runtime state:
%USERPROFILE%\.codex
Do not install Whale into npm global directories, WindowsApps, .cargo\bin, or
.local\bin. Do not copy .codex into .whale, and do not point
CODEX_HOME at WHALE_HOME. Whale also rejects WHALE_HOME values that point
at an official .codex state directory or the same path as CODEX_HOME.
Run the isolation guard after changing install scripts, PATH setup, wrapper files, or local machine configuration:
.\scripts\check-cli-isolation.ps1
.\scripts\check-codex-collision-risk.ps1If official Codex reports a missing optional dependency, repair Codex itself without changing Whale:
npm install -g @openai/codex@latest --include=optional
codex --versionThe Whale npm package under third_party/codex-cli/codex-cli is named
@ceasarxuu/whalecode and exposes only the whale command. It must not publish
or install @openai/codex, codex.js, or a codex command. See
docs/runbooks/npm-publishing.md before any npm release.
Stay on the current branch unless the user explicitly approves a new branch. Commit and push small completed themes. Leave no uncommitted repository changes after a finished task.
Before commit:
git status --short --branch
git diff --checkAfter commit:
git status --short --branch
git push origin main