Anvil TUI: eight layouts (v2.2.17)

Four architectural directions × with-and-without-tabs = 8 variants. Classic is the pre-v2.2.16 monolithic renderer and the new default. Vertical Split brings a persistent left rail + swappable deck. Three-Pane is always-on input (no vim modal). Journal is single-column with a Ctrl-K palette.

without tabs
Layout A0 · classic
anvil — classic ~/projects/anvil-dev
[1: main][2: aegis-fix][3: deploy-prep]Ctrl+T new Ctrl+W close
sonnet-4.6│ in:42 out:17 │ git:main +12,-5
>wire the new dispatch path through commands/dispatch.rs
ARouting through the canonical dispatcher now. Spec entry added, drift test green.
>go
AHandler wired. All tests pass.
────────────────────────────────────────────────────────────
>next prompt…
branch:main +12,-5 │ in:42 out:17 │ sonnet-4.6

The pre-v2.2.16 monolithic renderer, now a first-class layout. Tab bar + model bar across the top, conversation in the middle, separator + input + status line at the bottom. Single-deck, no rail. The fastest, least chrome, and the new default for fresh installs.

Layout A · vertical split
anvil — vertical split ~/projects/anvil-dev
wire the new dispatch path through commands/dispatch.rs
Routing through the canonical dispatcher now. I'll add the spec entry first so the drift test passes, then wire the handler.
go
Added slash_command_specs::TuiPreview and an arm in dispatch_slash_command. Drift test green. Want me to also wire the completion?
yes, and run the slash drift test
every_slash_command_variant_has_a_spec passed. completion wired.

what should we tackle next…

g switch deck·d tools·s sessions·a agents·? help

Persistent context, swappable focus. Right for long sessions where you bounce between conversation and tool output frequently. The left rail makes session/agent switching one keystroke without breaking the conversation flow.

Layout B · three-pane
anvil — three-pane horizontal crates/runtime/src/turn.rs
Focus— anvil is editing crates/runtime/src/turn.rs
142 let mut ctx = TurnContext::new();
143 ctx.attach_memory(layer);
+ ctx.set_routine_archive(&archive);
+ ctx.emit_otel("turn.start", &meta);
+ if let Some(packet) = packet { ctx.absorb(packet); }
144 let result = ctx.run().await?;
145 Ok(result)
Log
14:02:08read · crates/runtime/src/turn.rs
14:02:09grep · routine_archive
14:02:11edit · turn.rs (+3 lines)
14:02:12cargo check ← we are here
·cargo test (queued)
model sonnet-4.6tok 38,412cost $0.81
memoryL1L2L3L7 HIT
scopeturn.rs·routines/mod.rs·dispatch.rs
PageUp/PageDown scroll·Ctrl+Tab tabs·Ctrl+R deck·/quit exit

Always-on input, file-editor-shaped. No vim modal — just start typing. The fixed three-pane structure (Focus / Log / Context) means the assistant's current action is always visible at the top, not scrolled past. Right for engineers who want dense information density without modal gates.

Layout C · journal
anvil — journal ~/projects/anvil-dev
anvil-dev · v2.2.17 · sonnet-4.6
14:02:11 you
can you look at auth.rs and see if the session check is doing the right thing for refresh tokens?
14:02:13 anvil · thinking…
readauth.rs4.2 KB
readsession.rs2.8 KB
greprefresh_token in crates/auth/6 hits
14:02:18 anvil
The refresh path skips the expiry check on line 88. I'll fix it so refreshes go through the same TTL guard as initial sessions.
editauth.rs+37 −0 ✓
ctrl-k for command palette·↑ history·enter to send

Calm, paper-like, low chrome. Right for prose work, exploration, learning. Looks like a terminal journal more than an IDE. Commands live in a Ctrl-K palette like Linear/Slack/VS Code — discoverable, not memorized.

with tabs (core feature)
Layout D0 · classic + tabs
anvil — classic ~/projects/anvil-dev
[1: main][2: aegis-fix][3: deploy-prep]Ctrl+T new Ctrl+W close
sonnet-4.6│ in:42 out:17 │ git:main +12,-5
>wire the new dispatch path through commands/dispatch.rs
ARouting through the canonical dispatcher now. Spec entry added, drift test green.
>go
AHandler wired. All tests pass.
────────────────────────────────────────────────────────────
>next prompt…
branch:main +12,-5 │ in:42 out:17 │ sonnet-4.6

Classic renderer with the tab bar enabled. Identical to A0 but the tab strip appears at row 0. This is the out-of-box default for all new Anvil installs (v2.2.16+). Tabs switch instantly, layout otherwise unchanged from the monolithic renderer users already know.

Layout D · vertical split + workspace tabs
anvil — vertical split + workspace tabs ~/projects/anvil-dev
main
aegis-fix2
deploy-prep
+
Ctrl+1-9 · Ctrl+T new
wire the new dispatch path through commands/dispatch.rs
Routing through the canonical dispatcher now. Spec entry added, drift test green.
good. while you do that, the aegis-fix tab needs a perm (badge on tab ⚠)
Switching to tab 2 won't lose this thread — the rail keeps both sessions live. Ctrl+2 to swap.

ask main, or Ctrl+2 to go to aegis-fix…

Ctrl+1-9 tab·Ctrl+T new tab·Ctrl+W close·s sessions·? help

Tabs live inside the deck pane. Parallel sessions share the same rail. Switch tabs to swap conversation context, but session list / agents / status stay anchored. Right when each tab is a separate workspace branch (debugging session A, deploying B) but you want one global view of what's running across all of them.

Layout E · three-pane + tabs
anvil — three-pane + tabs crates/runtime/src/turn.rs
[1] anvil-dev*·[2] aegis-fix·[3] deploy~·[+]3 buffers · :ls
Focus— buf 1 · anvil is editing crates/runtime/src/turn.rs
142 let mut ctx = TurnContext::new();
143 ctx.attach_memory(layer);
+ ctx.set_routine_archive(&archive);
+ ctx.emit_otel("turn.start", &meta);
144 let result = ctx.run().await?;
Log— buf 1
14:02:08read · crates/runtime/src/turn.rs
14:02:11edit · turn.rs (+3 lines)
14:02:12cargo check ← we are here
·buf 2 (aegis-fix) waiting on perm ⚠
buf 1 anvil-devmodel sonnet-4.6tok 38,412
scopeturn.rs·routines/mod.rs
Ctrl+Tab switch tab·Ctrl+1-9 jump tab·PageUp/Down scroll·Ctrl+R deck·/quit exit

Three-pane always-on input with tab strip. Tabs switch with Ctrl+Tab or Ctrl+1-9. Each tab has its own Focus/Log/Context panes and conversation. Input is always active — just start typing. Right for engineers who want maximum visible structure with parallel sessions.

Layout F · journal with named threads
anvil — journal + threads ~/projects/anvil-dev
anvil-dev·aegis-fix2·deploy-prep·+Ctrl+1-9 · /thread <name>
anvil-dev · v2.2.17 · sonnet-4.6
14:02:11 you
can you look at auth.rs and see if the session check is doing the right thing for refresh tokens?
14:02:13 anvil · thinking…
readauth.rs4.2 KB
greprefresh_token in crates/auth/6 hits
14:02:18 anvil
The refresh path skips the expiry check on line 88. I'll fix it so refreshes go through the same TTL guard as initial sessions.
editauth.rs+37 −0 ✓
ctrl-k palette·Ctrl+1-9 thread·/thread new·enter to send

Threads instead of tabs. Each thread is a named conversation with its own model and journal. Switch threads with Ctrl+1-9 or /thread <name>. The journal layout never gains chrome — the thread switcher is one extra line at the top, then it's back to pure single-column flow. Right for users who want the calm of layout C but need to keep multiple parallel projects open.