You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Change the harness leader prefix from Ctrl+Shift+Space to Ctrl+I (Control on
both platforms — never Cmd+I), tmux/zellij-style. The leader is still a prefix, not a
held chord: press Ctrl+I, let go, then ? / Escape / t (the existing thinking
default-collapse chord, #742) / any future leader command within LEADER_WINDOW_MS
(800). Ctrl+Shift+Space stops arming; Cmd+I and Ctrl+Shift+I (Inspect) are left
to the browser, never handled. Pure Wasm change — no bridge export, no protocol bump, no
new caps.
Goals
#
Goal
Success signal
1
Leader prefix is Ctrl+I (Control, both platforms — not Cmd+I)
match(.i, .down, .{ .control = true }, …) → Action.leader. In-canvas help + docs say Ctrl+I
2
Ctrl+Shift+Space no longer arms
space + ctrl_shift → .none in the normal (non-leader) context
3
Cmd+I does not arm (Mac italic / Get Info / not our prefix)
command + i → not Action.leader; not marked handled (.none)
4
Ctrl+Shift+I stays with the browser (Inspect)
reserved deny-list entry .i+.ctrl_shift → Outcome.browser; never marked handled, even while a leader is pending
5
IME / Spotlight still safe
Ctrl+Space / Cmd+Space still do not arm (existing test unchanged)
6
Leader commands unchanged
?, Escape, t, re-arm on the new prefix all behave identically
Non-goals / out of scope
Do not change LEADER_WINDOW_MS (800) or KEYMAP_MAX (64)
Do not add a DOM window keydown / host keyboard UI
Do not steal Ctrl+Shift+I (devtools) or Ctrl+B (leave to tmux)
Do not make Cmd+I the Mac leader — Control on both platforms, same as today's leader
Do not add or remove a leader command — the existing thinking-toggle t chord
(row thinking_default_toggle, keymap.zig line 294, plan plan: thinking default-collapsed toggle via keyboard shortcut #742 — .key=.t, when_true.leader_pending, wired to the toggleThinkingDefault seam) is kept
and only its on-screen chord string re-worded to the new prefix; no new leader
command ships
No new caps, no bridge protocol change, no build.zigexport_symlink_names change (no new exports)
Forbidden wiring: dual DOM chat · secrets in Wasm · laptop-only Production ops
Architectural decisions
Decision
Options considered
Choice
Why
Modifier prereq for the leader
reuse ctrl_or_cmd / reuse ctrl_shift / new ModPrereq.control
new ModPrereq.control (control AND NOT command/shift/alt)
ctrl_or_cmd would arm on Cmd+I (violates goal 3); ctrl_shift requires Shift (wrong). A control-only prereq is the only option that makes Cmd+I, Ctrl+Shift+I, and Cmd+Space all non-arming
.i in RESERVED
keep .i+.ctrl_or_cmd / remove it
remove .i+.ctrl_or_cmd
The reserved deny-list runs before table match, so keeping it would make Ctrl+I Outcome.browser and the leader could never fire. Removal is required for the prefix to work
Explicit Inspect deny
leave Ctrl+Shift+I to fall-through .none / add .i+.ctrl_shift
add .i+.ctrl_shift to RESERVED
While a leader is pending, a fall-through Ctrl+Shift+I would otherwise be .swallow_leader (marked handled + disarms). Reserving it keeps Outcome.browser (never handled) with no behavior difference outside the window — matches goal 4 exactly
Leader row + re-arm
keep space+ctrl_shift / i+.control
.key = .i, .prereq = .control in the leader row and the match leader_pending re-arm branch
Table and re-arm must move together so the prefix and its re-arm stay coherent
Protocol / bridge
bump / none
no change
Keymap is a pure Wasm concern; no new inv_* export, no host change. No build.zigexport_symlink_names update needed
Layer placement
Concern
Layer
Path(s)
Rationale
Modifier prereq + leader row + reserve list + re-arm
harness (Wasm)
native/harness/src/keymap.zig
Pure, host-unit-tested; ownership per module header (#741)
Chord glyph + help copy
harness (Wasm)
native/harness/src/ui/help_overlay.zig
Overlay IS the table; chord strings live here
Dispatcher comment
harness (Wasm)
native/harness/src/ui/keymap_dispatch.zig
Doc comment only (arming copy); one per-frame walk unchanged
Keyboard & focus row
docs
docs/harness-limits.md
Durable operator behavior table
DOM shell
—
none
No host key handling, no window keydown (per AGENTS/feature-divide contract)
Current baseline (live code)
Claim
Path / symbol
Notes
Leader chord
native/harness/src/keymap.zigKEY_TABLE id leader, lines 266–274
docs/harness-limits.md line 63: **Ctrl+I** row — "Arm the leader
prefix (800 ms). Within the window press ? to toggle help; t
toggles thinking default-collapsed; Escape cancels; an unmatched key
swallows (never lands in the prompt); a reserved browser chord still yields
to the browser."
Update the existing "leader arms on Ctrl+Shift+Space" test to Ctrl+I; keep
the IME/Spotlight (Ctrl+Space / Cmd+Space) test; add/adjust the cases below.
Edge cases & invariants
Cmd+I (no ctrl): no row matches .control (fails !mods.command), no
longer reserved → Outcome.none, never handled → browser/app keeps Mac italic.
Ctrl+Shift+I: reserved .browser; outside the window it passes through
(same as today); inside a leader window it is .browser (not .swallow_leader),
so Inspect is never swallowed — matches goal 4.
Ctrl+Shift+Space (goal 2): removed from both the leader row and the re-arm
branch; no row matches → Outcome.none in the normal context.
Leader + Ctrl+I re-arms (identical to today's Space+ctrl_shift re-arm).
Bare i (no modifier) still types the letter in the composer — .control
is strict, .none outside the window.
No cap, budget, or frame-loop change: one extra ModPrereq switch arm and
a same-shaped re-arm branch; LEADER_WINDOW_MS/KEYMAP_MAX untouched.
No Wasm artifact ABI change: no new inv_* export, so build.zig export_symlink_names and the protocol row are untouched.
Cloud ops path
N/A — no Production mutate. Wasm keymap only; no environment, data, GHA, or
deploy cutover. The rebuild of public/harness/harness.wasm is the normal
harness artifact path (build-harness GHA is the release-wasm gate; the agent
rebuilds locally for the debug/wasm gates).
Living docs plan
Surface
Change
Notes
docs/harness-limits.md
Keyboard & focus table — replace the Ctrl+Shift+Space row with Ctrl+I and the matching leader-window copy (incl. keeping the t thinking row)
timeless; no phase/issue artifacts
AGENTS.md
N/A — line 299 references the keymap table/leader generically, no chord string
verified
docs/feature-divide.md
N/A — line 49 references the keymap/leader generically, no chord string
verified
README.md
N/A — no keyboard docs
SECURITY.md
N/A — no secrets/trust-boundary change
.env.example
N/A — no env change
Implementation order
native/harness/src/keymap.zig — add ModPrereq.control + modsMatch arm
Same file — leader row → .i+.control, help string, re-arm branch, and the RESERVED.i swap (remove ctrl_or_cmd, add ctrl_shift); update comments
help overlay paints Ctrl+I / Leader I, then ? / Leader I, then t chords
harness
operator smoke
canvas help (Ctrl/Cmd+/ then leader)
Minimum locked (DoD): cases 1–11 in keymap.zig pass; zig fmt --check clean
on touched files; zig build test-rich and zig build test-rich-invariants pass; zig build harness -Doptimize=Debug (full Wasm compile) succeeds; artifact native/harness/zig-out/bin/harness.wasm rebuilt so it can be copied to public/harness/ for the wasm-int suite if bridge signatures changed (they do
not here). CI build-harness remains the release-wasm gate.
ui/help_overlay.zig chords read Ctrl+I / Leader I, then ? / Leader I, then t (no Space/Ctrl+Shift+Space string remains in the overlay)
ui/keymap_dispatch.zig + keymap inline comments no longer reference Ctrl+Shift+Space (incl. the RESERVED doc comment, line 308, and the leader-row doc lines 106/366)
docs/harness-limits.md Keyboard & focus row reads Ctrl+I (and keeps the t thinking chord)
zig fmt --check clean on touched .zig files
zig build test-rich + zig build test-rich-invariants green
zig build harness -Doptimize=Debug (full Wasm compile) green
Cloud ops: N/A (no Production mutate) — explicitly
Living docs: docs/harness-limits.md updated; AGENTS/feature-divide/README/SECURITY/.env.example N/A justified
No bridge/protocol/build.zig export_symlink_names change (additive-not-needed verified)
Caps table
Cap / ceiling
Value
Rationale
Code location
Verdict
LEADER_WINDOW_MS
800 (unchanged)
leader window; plan explicitly non-goal
keymap.zig line 18
no change
KEYMAP_MAX
64 (unchanged)
static table cap; plan explicitly non-goal
keymap.zig line 15
no change
No new or changed cap — no human-gate decision required. (The ModPrereq enum
addition is a code artifact, not a cap.)
Risks & mitigations
Risk
Mitigation
Ctrl+I collides with a browser/OS shortcut on some platform and never reaches the canvas
Deliberate product decision (the source issue's premise). Emits Action.leader when the canvas receives the chord; Cmd+I / Ctrl+Shift+I explicitly left to the browser so no Inspect/italic regression
Forgetting the re-arm branch while changing the table row leaves the leader stuck
Re-arm must change with the row (decision #4); covered by test 6
Regressing the reserved deny-list and re-marking Ctrl+I .browser
.i removed from RESERVED; covered by test 8
Reserved Inspect chord swallowed during a pending leader
.i+.ctrl_shift added to RESERVED (runs before leader handling); covered by test 3
Missing the thinking-toggle chord string (keeps "Leader Space, then t" on-screen)
Design step 6 re-words .thinking_default_toggle too; covered by test 11 (behavior) + test 12 (overlay string); DoD asserts no Space/Ctrl+Shift+Space string remains in the overlay
Docs/AGENTS/feature-divide drift to old chord
Only docs/harness-limits.md carries the chord string (verified); the other surfaces reference "leader" generically
Open questions
None — all in-scope engineering choices are locked above (no human decisions
remain; no existing cap is changed).
Plan header
docs/harness-limits.md(Keyboard & focus row); AGENTS / feature-divide N/A (they reference "leader" generically, no chord string)Summary
Change the harness leader prefix from Ctrl+Shift+Space to Ctrl+I (Control on
both platforms — never Cmd+I), tmux/zellij-style. The leader is still a prefix, not a
held chord: press Ctrl+I, let go, then
?/ Escape /t(the existing thinkingdefault-collapse chord, #742) / any future leader command within
LEADER_WINDOW_MS(800).
Ctrl+Shift+Spacestops arming; Cmd+I and Ctrl+Shift+I (Inspect) are leftto the browser, never handled. Pure Wasm change — no bridge export, no protocol bump, no
new caps.
Goals
match(.i, .down, .{ .control = true }, …)→Action.leader. In-canvas help + docs sayCtrl+Ispace+ ctrl_shift →.nonein the normal (non-leader) contextcommand+i→ notAction.leader; not marked handled (.none).i+.ctrl_shift→Outcome.browser; never marked handled, even while a leader is pending?, Escape,t, re-arm on the new prefix all behave identicallyNon-goals / out of scope
LEADER_WINDOW_MS(800) orKEYMAP_MAX(64)windowkeydown / host keyboard UItchord(row
thinking_default_toggle,keymap.zigline 294, plan plan: thinking default-collapsed toggle via keyboard shortcut #742 —.key=.t,when_true.leader_pending, wired to thetoggleThinkingDefaultseam) is keptand only its on-screen chord string re-worded to the new prefix; no new leader
command ships
build.zigexport_symlink_nameschange (no new exports)Architectural decisions
ctrl_or_cmd/ reusectrl_shift/ newModPrereq.controlModPrereq.control(control AND NOT command/shift/alt)ctrl_or_cmdwould arm on Cmd+I (violates goal 3);ctrl_shiftrequires Shift (wrong). A control-only prereq is the only option that makes Cmd+I, Ctrl+Shift+I, and Cmd+Space all non-arming.iinRESERVED.i+.ctrl_or_cmd/ remove it.i+.ctrl_or_cmdOutcome.browserand the leader could never fire. Removal is required for the prefix to work.none/ add.i+.ctrl_shift.i+.ctrl_shifttoRESERVED.swallow_leader(marked handled + disarms). Reserving it keepsOutcome.browser(never handled) with no behavior difference outside the window — matches goal 4 exactlyspace+ctrl_shift/i+.control.key = .i,.prereq = .controlin theleaderrow and thematchleader_pending re-arm branchinv_*export, no host change. Nobuild.zigexport_symlink_namesupdate neededLayer placement
native/harness/src/keymap.zig#741)native/harness/src/ui/help_overlay.zignative/harness/src/ui/keymap_dispatch.zigdocs/harness-limits.mdwindowkeydown (per AGENTS/feature-divide contract)Current baseline (live code)
native/harness/src/keymap.zigKEY_TABLEidleader, lines 266–274.key = .space,.prereq = .ctrl_shift,.help = "Leader: Ctrl+Shift+Space"ModPrereqhas no control-onlykeymap.zigModPrereq, lines 71–82none,ctrl_or_cmd,ctrl_shift,shift,alt;ctrl_or_cmdrequires!mods.shift(so Ctrl+Shift+I already passes through today).ireservedkeymap.zigRESERVED, line 323{ .key = .i, .prereq = .ctrl_or_cmd }— must be removed for Ctrl+I to armkeymap.zigmatch, lines 374–419space+ctrl_shiftre-arms (lines 400–402)keymap.zigKEY_TABLEidthinking_default_toggle, lines 293–301.key = .t,.prereq = .none,when_true.leader_pending— ships in the live table (#742); kept, string onlykeymap.zigKey.i(line 48) +ui/keymap_dispatch.zigfromDvui(line 79).i => .ialready mapped;Modsalready hascontrolui/help_overlay.zigrowChord(lines 20–35).leader => "Ctrl+Shift+Space",.help_toggle_leader => "Leader Space, then ?",.thinking_default_toggle => "Leader Space, then t"docs/harness-limits.mdline 63AGENTS.mdline 299,docs/feature-divide.mdline 49Design
keymap.zig— addModPrereq.control; extendmodsMatchwith.control => mods.control and !mods.command and !mods.shift and !mods.alt..key = .i,.prereq = .control,.help = "Leader: Ctrl+I".if (key == .i and modsMatch(mods, .control))→
Action.leader(re-arm), replacingspace+ctrl_shift.RESERVED(line 323): remove{ .key = .i, .prereq = .ctrl_or_cmd };add
{ .key = .i, .prereq = .ctrl_shift }so Ctrl+Shift+I (Inspect) is anexplicit
Outcome.browser— never handled, including during the leader window.keymap.zig(lines 17, 106, 308, 366) andui/keymap_dispatch.zig(line 46): point at Ctrl+I, not Ctrl+Shift+Space.help_overlay.zigrowChord:.leader => "Ctrl+I",.help_toggle_leader => "Leader I, then ?",.thinking_default_toggle => "Leader I, then t"(keeps the plan: thinking default-collapsed toggle via keyboard shortcut #742 chord,re-worded) (and
leader_cancelstays).docs/harness-limits.mdline 63:**Ctrl+I**row — "Arm the leaderprefix (800 ms). Within the window press
?to toggle help;ttoggles thinking default-collapsed; Escape cancels; an unmatched key
swallows (never lands in the prompt); a reserved browser chord still yields
to the browser."
the IME/Spotlight (Ctrl+Space / Cmd+Space) test; add/adjust the cases below.
Edge cases & invariants
.control(fails!mods.command), nolonger reserved →
Outcome.none, never handled → browser/app keeps Mac italic..browser; outside the window it passes through(same as today); inside a leader window it is
.browser(not.swallow_leader),so Inspect is never swallowed — matches goal 4.
branch; no row matches →
Outcome.nonein the normal context.Space+ctrl_shift re-arm).t(thinking-toggle, plan: thinking default-collapsed toggle via keyboard shortcut #742) behavior unchanged — only the on-screenchord string changes to
Leader I, then t.i(no modifier) still types the letter in the composer —.controlis strict,
.noneoutside the window.ModPrereqswitch arm anda same-shaped re-arm branch;
LEADER_WINDOW_MS/KEYMAP_MAXuntouched.inv_*export, sobuild.zigexport_symlink_namesand the protocol row are untouched.Cloud ops path
N/A — no Production mutate. Wasm keymap only; no environment, data, GHA, or
deploy cutover. The rebuild of
public/harness/harness.wasmis the normalharness artifact path (
build-harnessGHA is the release-wasm gate; the agentrebuilds locally for the debug/wasm gates).
Living docs plan
docs/harness-limits.mdtthinking row)AGENTS.mddocs/feature-divide.mdREADME.mdSECURITY.md.env.exampleImplementation order
native/harness/src/keymap.zig— addModPrereq.control+modsMatcharm.i+.control, help string, re-arm branch, and theRESERVED.iswap (removectrl_or_cmd, addctrl_shift); update commentsnative/harness/src/ui/help_overlay.zig—rowChordstrings (all three:.leader,.help_toggle_leader,.thinking_default_toggle)native/harness/src/ui/keymap_dispatch.zig— doc comment copy onlydocs/harness-limits.md— Keyboard & focus rowkeymap.zigTesting
Action.leaderzig build test-rich.nonezig build test-richOutcome.browser(never handled), incl. while leader pendingzig build test-rich.none(no longer arms)zig build test-rich.none(IME / Spotlight — existing test unchanged)zig build test-richAction.leader(re-arm)zig build test-rich?→help_toggle_leader; leader + Escape →leader_cancel(with help open →help_close); leader + unmatched →swallow_leader(unchanged)zig build test-richOutcome.browser(regression onRESERVED.iremoval)zig build test-richi(no modifier) →.none(letter still types)zig build test-richModPrereq.controlstrictness: control only, Cmd/Alt/Shift each excludedzig build test-richt→thinking_default_togglebehavior unchanged (existing #742 tests stay green)zig build test-richCtrl+I/Leader I, then ?/Leader I, then tchordsCtrl/Cmd+/then leader)Minimum locked (DoD): cases 1–11 in
keymap.zigpass;zig fmt --checkcleanon touched files;
zig build test-richandzig build test-rich-invariantspass;zig build harness -Doptimize=Debug(full Wasm compile) succeeds; artifactnative/harness/zig-out/bin/harness.wasmrebuilt so it can be copied topublic/harness/for the wasm-int suite if bridge signatures changed (they donot here). CI
build-harnessremains the release-wasm gate.Definition of done
native/harness/src/keymap.zig—ModPrereq.control+.i/.controlleader (row + re-arm) +.ireserve swap; tests updated/added (cases 1–11)ui/help_overlay.zigchords readCtrl+I/Leader I, then ?/Leader I, then t(noSpace/Ctrl+Shift+Spacestring remains in the overlay)ui/keymap_dispatch.zig+ keymap inline comments no longer referenceCtrl+Shift+Space(incl. theRESERVEDdoc comment, line 308, and the leader-row doc lines 106/366)docs/harness-limits.mdKeyboard & focus row readsCtrl+I(and keeps thetthinking chord)zig fmt --checkclean on touched.zigfileszig build test-rich+zig build test-rich-invariantsgreenzig build harness -Doptimize=Debug(full Wasm compile) greendocs/harness-limits.mdupdated; AGENTS/feature-divide/README/SECURITY/.env.exampleN/A justifiedbuild.zig export_symlink_nameschange (additive-not-needed verified)Caps table
LEADER_WINDOW_MSkeymap.zigline 18KEYMAP_MAXkeymap.zigline 15No new or changed cap — no human-gate decision required. (The
ModPrereqenumaddition is a code artifact, not a cap.)
Risks & mitigations
Action.leaderwhen the canvas receives the chord; Cmd+I / Ctrl+Shift+I explicitly left to the browser so no Inspect/italic regression.browser.iremoved fromRESERVED; covered by test 8.i+.ctrl_shiftadded toRESERVED(runs before leader handling); covered by test 3.thinking_default_toggletoo; covered by test 11 (behavior) + test 12 (overlay string); DoD asserts noSpace/Ctrl+Shift+Spacestring remains in the overlaydocs/harness-limits.mdcarries the chord string (verified); the other surfaces reference "leader" genericallyOpen questions
None — all in-scope engineering choices are locked above (no human decisions
remain; no existing cap is changed).
References
its
tleader chord ships in the live table and is kept here, string re-wordedonly), feat(harness): single keymap + leader + help overlay for shortcuts (plan #741) #746
Implemented as PR #773 (
plan/leader-ctrl-i, commit1c4a965). Statusflipped HANDOFF-READY → IMPLEMENTED.