6 Commits
Author SHA1 Message Date
zeekay eb49cac620 name the env after the product, and the key after the stack it opens
457 sites carried an upstream prefix into every surface a user reaches — shell
exports, docs, CI, the SDK. CODEX_ is not our name and it was never going to
stop arriving on its own: it is what upstream writes, and every sync brings more.

Two namespaces, because they answer different questions.

  DEV_*            the app's own configuration — DEV_HOME, DEV_PROFILE, the rest
  HANZO_API_KEY    a credential for the Hanzo stack, which is not app config

CODEX_API_KEY held the literal string "CODEX_API_KEY", so the rename moves the
value and not just the constant. It becomes HANZO_API_KEY, which is what
create_hanzo_provider already reads through HANZO_MACHINE_ENV_KEYS — one name
for one credential instead of two spellings of it.

vendor/ is untouched, which is the point of vendor/: upstream code keeps
upstream names, and the boundary is a path rather than a habit.
2026-08-08 09:14:56 -07:00
zeekay 23b29ae484 model: offer the models we actually serve, in the order we mean
/model listed seventeen OpenAI presets and no Hanzo one, so the model dev
runs by default was not selectable in the view whose job is selecting it.
Adds the Zen and enso lineup from the catalog — ids and context windows read
from /v1/models, not guessed.

Two things had to go first, both of which re-derived order from the slug:

model_selection_view parsed a version out of `gpt-N.M`; everything else fell
to a branch that sorted it below every OpenAI model, so declaring zen5-coder
first would still have placed it sixth. chatwidget hoisted a hardcoded
five-slug shortlist to the front regardless of catalog order.

Both deleted. Order is the catalog's job now, decided once, and a test holds
the picker to leading with our default. The OpenAI presets stay: they serve
the openai provider as its offline fallback and for effort clamping.
2026-08-07 21:50:59 -07:00
zeekay 418d57f390 feat(tui,cli): the product says Hanzo Dev, not Code
The complaint was that the CLI and TUI still look like codex. They did, but
almost none of it was the word "ChatGPT" — the shipping tree has 69 of those
and most must stay, because they name a real OpenAI account the user actually
holds and renaming them would lie about whose login it is. What made it look
wrong was our own chrome naming itself after someone else's product.

The startup splash was the biggest piece and the one a ChatGPT/Codex grep can
never find: the ASCII art spelled EVERY over CODE — just-every's brand, not
ours. It now spells HANZO over DEV in all four size variants. While rewriting
it, `shift_left(lines, 3)` turned out to strip the first three space characters
anywhere in a line rather than three leading columns; that was invisible while
every line began with three spaces, and HANZO's first row does not. Replaced
with art written at final column positions, and the three near-duplicate
per-size word blocks collapsed into one HANZO array plus a word_lines() helper.
Added two tests for invariants nothing enforced before: declared art height
matches the line count, and each variant fits its own minimum width.

Also deleted a branding band-aid. The /help renderer ran
`cmd.description().replace("Codex", "Code")`, post-processing help text at
display time, which meant any rename that only edited slash_command.rs would be
silently mangled and "Hanzo" could never appear. Removed it and fixed the
source strings instead.

Renamed, because they name us: terminal window title, the DEFAULT_TERMINAL_TITLE
const, the desktop notification title, the assistant's label in the undo preview
("Dev", to stay balanced against "You"), the welcome banner and onboarding copy,
five slash-command descriptions, the settings-overlay upgrade line, the model
migration prompts, the `dev --help` config-override text, and `dev mcp add`.

Kept, because they name a real service or a wire contract: every "Sign in with
ChatGPT" / "your ChatGPT account" string, OPENAI_API_KEY, chatgpt.com and
openai.com URLs, OpenAI model ids including gpt-5.1-codex-max, the ~/.code/ and
~/.codex/ config paths, all CODEX_*/CODE_* env vars, config keys, OAuth client
ids, and the internal Line::from("codex") sentinels that pair with the
is_title_line matcher and are never rendered.

One upstream announcement was reworded rather than renamed: "Codex just got an
upgrade: meet gpt-5.1-codex-max" now names the model instead of the product,
since the model is real and ours is not the product being upgraded.

Verified: cargo nextest run --no-fail-fast --locked -> 1673/1674 pass. The one
failure, code-core git_info::test_collect_git_info_with_remote, is this machine's
`[email protected]:.insteadof https://github.com/` rewriting the test's URL; it
passed on CI run 31143152415.
2026-08-06 20:58:49 -07:00
zeekayandHanzo Dev 23a7fe1109 feat: the product says its own name, and can be driven from outside
Branding. The reported "OpenAI Codex" was not a banner — the TUI banner has
said "Welcome to Code" all along. It was the model describing itself. Every
request carries BASE_INSTRUCTIONS, and `zen5-coder` matches none of the
OpenAI slug prefixes in find_family_for_model, so it lands on
derive_default_model_family -> core/prompt.md, whose first line read "You are
a coding agent running in the Codex CLI ... led by OpenAI". The agent was
told who it was, and it answered honestly.

Fixed the harness identity in all eight prompts (keeping each model's own
identity: "based on GPT-5" stays, the harness around it becomes Hanzo Dev),
the per-turn header, approval and model pickers, the login success page, MCP
tool titles and approval prompts on both client and server sides, seatbelt
policy header, cloud copy, two stale User-Agents, and the CLI hints that
named the wrong binary. Golden JSON fixtures moved with the code they assert.

Deliberately NOT changed, because they are wire and not text: `OPENAI_*` and
`CODEX_*` env vars, the `codex`/`codex-reply` MCP tool names and the
`code-mcp-server` server name (hosts key allowlists off them), `codex.*` OTEL
event names, the `openai` provider id, model slugs, `~/.code` on disk, and
the `https://api.openai.com/auth` JWT claim namespace.

Control. `cli/src/proto.rs` was a complete bidirectional control plane —
Submission JSON lines in, Event JSON lines out, the whole `Op` set including
QueueUserInput — exported from lib.rs with no subcommand to reach it. Wired
it up as `dev proto`. That is the difference between interrupting a turn and
steering one: `app-server`'s sendUserMessage hardcodes Op::UserInput, which
calls sess.abort() and restarts the turn.

  $ printf '%s\n' '{"id":"s1","op":{"type":"interrupt"}}' \
                  '{"id":"s2","op":{"type":"shutdown"}}' | dev proto
  {"id":"","event_seq":0,"msg":{"type":"session_configured",
   "session_id":"4d82071e-...","model":"zen5-coder",...}}
  {"id":"s2","event_seq":1,"msg":{"type":"shutdown_complete"}}

Also: upstream-merge.yml polled openai/codex every 30 minutes. That is the
wrong upstream (codex-rs reaches us through just-every) and a cron cannot
work against a disjoint history anyway — it needs a hand-supplied merge base.
Retargeted to just-every/code and made it manual, pointing at the procedure
in LLM.md. Purged @just-every/code from the release and recovery pipelines,
which would otherwise have published our binaries under their scope.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-05 23:28:50 -07:00
zeekayandHanzo Dev 6cbbea2d03 merge: just-every/code v0.6.169 (e4fe007150) — keep Hanzo identity
Our history is just-every's with author emails rewritten, so the graphs are
disjoint and git finds no merge base. Supplied one by hand: d1f1f51a41, the
just-every commit matching our Oct-2025 fork point (22 files apart). 9618
upstream commits, 7004 files, +1.81M/-159k, 37 conflicts.

Resolution:
- Upstream code where our side was the Oct-2025 prototype of a feature they
  have since reimplemented 3-5x larger (agent_runs, browser_sessions,
  history_cell/{agent,browser}, the vt100 harness and its snapshots).
- Upstream's config.rs module split (builder/defaults/sources/validation)
  kept; zen5-coder and the provider-follows-model rule re-applied on top.
- Ours where the file IS the identity: README, package.json, postinstall,
  release notes pipeline, integration-zed.
- Hybrid where upstream improved a file we had branded: updates.rs (their
  release-repo migration, our hanzoai/dev), release.yml (their fail-fast npm
  auth check, our package name), chatwidget.rs (their turn handling, our
  HANZO_USER_KEY hint), exec human output (their 237 lines, our banner).

Superseded and dropped deliberately: our resume_command_name() coder-alias
hack — upstream's derive_resume_command_name() reads the invocation basename
generically, which yields "dev" for us.

LLM.md now records the real topology and the sync point; AGENTS.md and
CLAUDE.md are symlinks to it again. Single parent on purpose: adopting
jecode/main as a second parent would re-import 13,742 commits carrying the
upstream author emails a prior rewrite deliberately removed.

Version 0.2.188 -> 0.2.189.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-05 23:09:12 -07:00
James Peter 220a6b3b9c feat(code-rs): add forked workspace and dual build support 2025-10-05 04:27:49 +10:00