Skip to content

ACE TUI User Guide

Overview

ACE (Agentic ChangeSpec Explorer) is the primary TUI for the SASE toolkit. It provides an interactive interface for navigating, managing, and operating on ChangeSpecs, agents, and the Axe daemon.

Launching

sase ace [QUERY] [options]

If no query is provided, the last used query is loaded (falling back to !!! for error suffixes).

CLI Options

Option Description
QUERY (positional) Query string for filtering ChangeSpecs
-m, --model-tier Override model tier for all LLM providers (large or small)
-M, --model-size Deprecated alias for --model-tier (big or little)
-p, --profile [PATH] Profile the TUI session with pyinstrument (writes text output to PATH or $SASE_TMPDIR/ace_profile_<ts>.txt)
-r, --refresh-interval Auto-refresh interval in seconds (default: 10, 0 to disable)
-x, --no-axe Disable auto-starting the axe daemon on startup
-v, --vcs-provider Override VCS provider (git, hg, or auto)
-R, --restart-axe Restart the axe daemon on startup (shows RESTARTING indicator)

Examples

sase ace                              # Last query or "!!!"
sase ace '"feature" AND "Drafted"'    # Filter by name and status
sase ace '+myproject'                 # Filter by project
sase ace -m small -r 30 '!!! OR @@@' # Small model, 30s refresh

Tab System

ACE has three tabs, cycled with Tab and Shift+Tab:

Tab Description
CLs (ChangeSpecs) Browse and act on ChangeSpecs matching the current query
Agents View running and completed agents, their files and prompts
Axe Monitor the Axe daemon and background commands

Keybindings: CLs Tab

Key Action
j / k Move to next / previous visible row (banner at fold < L2, CL at the leaf level)
< / > / ~ Navigate to ancestor / child / sibling CL
' Jump to entry by hint character (current tab); hints land on collapsed banners too
` Jump to entry across all tabs (see Jump All Modal)
Ctrl+O / Ctrl+K Jump back / forward in CL history
o / O Cycle CL grouping mode forward / reverse (BY_PROJECTBY_DATEBY_STATUS)
g / G Scroll detail panel to top / bottom
Ctrl+D / Ctrl+U Scroll detail panel down / up (half page)

Note: o/O ("organize") cycles the L0 grouping bucket forward / reverse on the Agents and CLs tabs (each tab keeps its own in-session mode). On the AXE tab it is a silent no-op. See CL Grouping and Folding and the Agents-tab Grouping Modes below.

CL Actions

Key Action
a Accept proposal (! = spec only, @ = mark ready to mail)
b Rebase CL onto parent
C / c1-c9 Checkout CL (primary / workspace 1-9)
d Show diff
e Edit spec file
f Edit hooks (re-run / delete via hint input)
M Mail CL
m Mark / unmark current CL (auto-advances to next)
n Rename CL (non-Sub/Rev CLs only)
R Rewind to previous commit (! suffix skips VCS operations)
s Change status (opens status modal)
S Bulk status change for all marked CLs
T Checkout + tmux (opens workspace input modal for number)
u Clear all marks
v View files (hint mode)
w Reword CL description
W Add tag to CL description
Y Sync workspace

CL Grouping and Folding

The CLs tab is always grouped — the renderer walks one of BY_PROJECT, BY_DATE, or BY_STATUS and emits a banner row above each bucket. BY_PROJECT is the startup default; o cycles BY_PROJECT → BY_DATE → BY_STATUS for the current session.

Mode L0 buckets Notes
BY_PROJECT Project name Adds an L1 sibling-root sub-banner shared by foobar_1 / foobar_2 style suffixed siblings. Singletons suppress their L1 banner.
BY_DATE Today / Yesterday / This Week / Earlier Bucket from the latest TIMESTAMPS entry. Today/Yesterday add 4-hour L1 windows; hourly L2 headings appear only inside 4-hour windows with 2+ CLs. This Week adds day headings; Earlier adds week headings plus (no timestamp).
BY_STATUS Mailed / Ready / WIP / Draft / Submitted / Reverted / Archived Bucket from the literal status field; actionable buckets first (Mailed = awaiting response, Ready = next to mail), terminal states last. Adds an L1 sibling-root sub-banner shared by foobar_1 / foobar_2 style suffixed siblings inside each status bucket. Singletons suppress their L1 banner.

In BY_DATE mode, CLs sort newest-first within each date bucket. Today and Yesterday are grouped first by compact 4-hour windows (8AM-12PM); one-hour headings (09:00) appear only when that 4-hour window contains at least two CLs. This Week uses calendar-day subgroups; Earlier uses Monday-start week ranges. CLs without a parseable TIMESTAMPS entry fall into (no timestamp) under Earlier.

The active grouping mode is shown in the CLs-tab info-panel header as a [group: <label>] badge.

Key Action
l Expand the focused banner one level (or peel one layer of the visible tree)
h Collapse the focused banner; on a collapsed L1 banner, escalate to its parent. With agent focus, collapse the deepest enclosing group.
L Snap to fully expanded — all banners and CL rows visible
H Snap to fully collapsed — collapse every visible banner

Collapsed banner rows are first-class navigation stops: j/k step through them just like CL rows, and ' jump-hints land on them too. After a fold change that hides the focused CL, focus snaps to the deepest collapsed ancestor banner so the cursor always sits on a row the user can see.

Fold Mode (z prefix)

Key Action
z c Cycle commits section (expand → collapse)
z d Cycle deltas section (folded ↔ unfolded)
z h Cycle hooks section (expand → collapse)
z m Cycle mentors section (expand → collapse)
z t Cycle timestamps section (expand → collapse)
z C Toggle commits section (collapsed ↔ fully expanded)
z D Toggle deltas section (folded ↔ unfolded)
z H Toggle hooks section (collapsed ↔ fully expanded)
z M Toggle mentors section (collapsed ↔ fully expanded)
z T Toggle timestamps section (collapsed ↔ fully expanded)
z z Cycle all sections
z Z Toggle all sections (expand ↔ collapse)

COMMITS, HOOKS, MENTORS, and TIMESTAMPS sections each cycle through three fold levels:

Level Behavior
Collapsed Notes truncated to fit; multi-line body shown as [+N lines]; only latest drawers
Expanded Full notes; body shown in dimmed text; all CHAT/DIFF/PLAN drawers visible
Fully Expanded Everything visible including rejected proposals

The lowercase cycle keys (z c, z h, z m, z t) step through all three levels in order. The uppercase toggle keys (z C, z H, z M, z T) skip the intermediate Expanded state, jumping directly between Collapsed and Fully Expanded.

When collapsed, a [folded: CHAT + DIFF + PLAN + N proposals] indicator appears on COMMITS entries with hidden content. The indicator width is pre-calculated so that note truncation accounts for it. TIMESTAMPS shows a [folded: N] indicator inline with the header and displays the most recent timestamp entry when collapsed, giving a quick view of the last lifecycle event.

The DELTAS section uses two semantic states. When folded, the section renders a one-line file and line-count summary such as DELTAS: +3 (+428) ~6 (+91 ~37 -14) -1 (-22) (10 files). When unfolded, the alphabetical entry list is shown with colored glyphs (green +, gold ~, red -) and inline line-count tokens. Binary files display binary; zero-count entries display 0 lines. The section is omitted entirely when the ChangeSpec has no deltas.

Workflows and Agents

Key Action
r Run workflow on current CL
@ Run a custom agent (opens project/CL selection)
Space Run agent from current CL

If ACE cannot detect a workspace provider for the selected ChangeSpec or agent, the quick-launch actions show an error toast instead of opening a prompt with a broken VCS prefix.

Bang Mode (! prefix)

Key Action
!! Run background command (opens hook history modal)
!x Start / stop axe (or select process)

Hook History Modal

Pressing !! opens the hook history modal showing previously run background commands:

Key Action
j / k Navigate through hook history
Enter Select and execute highlighted hook
Ctrl+D Delete highlighted hook from history
Ctrl+G Edit first — select hook and open in input
Esc / q Cancel and close modal

The modal supports live filtering as you type in the search box and displays last-used timestamps for each hook.

Leader Mode (, prefix)

Key Action
,! Run command using current CL context
,c Clear COMMENTS field (kills CRS agents, deletes CRS proposals)
,h Run agent with the default #cd:~ directory context
,m Review mentors (opens Mentor Review modal)
,M Kill running mentors
,P Set/clear temporary default model (see Temporary Model Override)
,r Show runners info
,t Open task queue modal (see Task Queue Modal)
,<space> Run agent from current CL (skips project selection)
,. Open prompt history modal for the last CL
,> Open prompt history modal with cancelled prompts visible

Note: ,x (kill & edit) is only available on the Agents tab — see Agents Tab Leader Mode.

Mentor Review Modal

Press ,m to open the Mentor Review modal, which lets you navigate mentor comments, accept or reject suggestions, and apply accepted changes. See docs/mentors.md for the full mentor system reference.

Key Action
j / k Navigate between mentors
n / p Navigate between comments within a mentor
N / P Navigate between accepted comments only
Ctrl+D / Ctrl+U Scroll comment details down / up
Space Toggle acceptance of the current comment
Enter Apply all accepted comments (launches agent)
a Apply accepted comments and propose (amend with propose)
A Apply accepted comments and commit
r Run a mentor profile (opens profile picker)
y Copy the current comment to the clipboard
Shift+K Kill a running mentor
Esc / q Close modal

Copy Mode (% prefix)

Key Action
%% Copy ChangeSpec
%! Copy ChangeSpec + snapshot
%b Copy bug number
%c Copy CL number
%n Copy CL name
%p Copy project spec file
%s Copy sase ace snapshot

Keybindings: Agents Tab

Key Action
j / k Move to next / previous visible row (banner at fold < L3, agent at L3)
J / K Cycle focus across tag side panels (forward / reverse)
' Jump to entry by hint character (current tab); on the Agents tab, hints land on collapsed banners too
` Jump to entry across all tabs (see Jump All Modal)
o / O Cycle grouping mode forward / reverse (STANDARDBY_DATEBY_STATUS)
g Scroll to top (file, thinking, or metadata panel)
G Scroll to bottom (file, thinking, or metadata panel)
Ctrl+D / Ctrl+U Scroll file panel down / up
Ctrl+F / Ctrl+B Scroll prompt panel down / up

Note: o/O ("organize") cycles the grouping mode forward / reverse on the Agents and CLs tabs (each tab keeps its own in-session selection independently); on the AXE tab it is a silent no-op. g/G keep their conventional vim-style scroll-to-top/bottom meaning on every tab. See Grouping Modes below.

Agent Actions

Key Action
R Revive a previously dismissed agent
A Open completion artifacts for the focused agent; in tmux, press again to close the viewer pane
@ Run custom agent
a Cycle auto-approve state / answer HITL
n Name agent
r Resume agent (by name if running, by chat file if completed)
v View files (hint mode)
D Toggle prior-attempt view (only shown when the agent has retried)
V Open the Agent Run Log modal for the focused agent
w Wait/unwait agent (opens WaitModal — see below)
W Wait for agent (populate prompt with %w); with marks, fans out to %w:a,b,c
m Mark / unmark current agent (auto-advances to next)
U Toggle the focused agent's unread marker
u Clear all agent marks
x Kill / dismiss agent, every marked agent, or every agent in the focused group
X Open the cleanup panel for panel, global, tag, marked, group, or custom cleanup
Enter / L Jump to CL (for agents with meta_new_cl/meta_new_pr)
e Edit chat in editor
E Edit panel content in editor
t Open tmux window in the focused agent's claimed workspace
T Open tmux window in the agent's primary (workspace 1) directory
N Open the agent tag/untag modal (input is pre-seeded with pinned for untagged agents; submit empty to clear)
] / [ Cycle panels: file → thinking → metadata (forward / reverse)
p Toggle file / prompt layout
Ctrl+N / Ctrl+P Next / previous file in panel
- Reset file trim to default
= Show all file lines

Wait Modal

Press w on the Agents tab to open the WaitModal. Behavior depends on the agent's status:

  • WAITING agent: Enter another agent's name to wait for, or leave empty and press Enter to run immediately (unwait).
  • RUNNING agent: Enter an agent name to kill the current agent and restart it with a %w (wait) directive. This is useful for redirecting an agent to wait on a different dependency.

The modal supports readline-style keybindings (Ctrl+F/Ctrl+B/Ctrl+A/Ctrl+E) for cursor movement.

VCS Tag Resolution in Resume/Wait

When resuming or waiting on an agent, VCS tags in the prompt (e.g., #git(ref), #gh:ref) are automatically updated to point to the correct branch. For non-project agents, the ref is replaced with the agent's CL name (branch). For project agents using #pr, the ref is replaced with @<name> which resolves to the agent's branch. HITL suffixes (!!, ??) are stripped during replacement since resume scenarios should not carry over HITL overrides.

Workflow Visibility

Workflows launched via sase run are visible in the Agents tab alongside ACE-launched workflows. The TUI scans artifacts/run/* directories in addition to workflow-* and ace-run directories, and writes an initial workflow_state.json before execution so that step data appears immediately rather than showing a bare RUNNING entry. Specialized review runners launched by axe (mentor, CRS, fix-hook, and summarize-hook review agents) are also visible and are automatically grouped under the @review tag, matching the behavior of a %tag:review prompt launch.

Agent Artifacts

Press A on a focused agent to open the artifact panel whenever artifacts are associated with that agent. The list can include chat transcripts, plan files, generated Markdown PDFs, generated images, and explicit files saved with sase artifact create -p <path> [-n <label>] [-k <kind>]. ACE always opens the panel, even for a single artifact, so the label, kind, and path are visible before launching the terminal viewer.

Artifact panel controls:

Key Action
selector Open the artifact with that one-key selector (1-0, then letters)
j / k Move through artifact rows
m Mark / unmark the highlighted artifact and advance to the next row
Enter Open marked artifacts in list order, or the highlighted row if unmarked
A Open all artifacts in list order, ignoring marks
q / Esc Close the panel

When ACE is running inside tmux, artifact viewing opens in a right-side tmux pane so the TUI remains visible. Press A again while that ACE-opened viewer pane is still present to close it; if the pane was already closed, A opens the artifact panel normally. Outside tmux, ACE suspends while the terminal viewer runs in the current pane. The viewer supports image, Markdown, and PDF artifacts: images are displayed directly with kitten icat; Markdown is first rendered to PDF; PDFs are converted to PNG pages for paging. The viewer needs kitten for display, pdftoppm for PDF/Markdown paging, and pandoc plus a supported PDF engine for Markdown rendering. Missing tools produce a warning instead of failing the TUI.

Viewer controls:

Key Action
j Next page; wraps from the last page to the first
k Previous page; wraps from the first page to last
n Next artifact when viewing an artifact sequence
p Previous artifact when viewing an artifact sequence
r Refresh the current page
q Close the viewer

Only one plan artifact is shown for an agent. When both an archived plan and an SDD tale path are present, ACE prefers the committed SDD plan; otherwise it keeps the path that best matches the run metadata.

Tag Side Panels

The Agents tab is laid out as a series of vertically-stacked side panels, one per agent tag. Untagged agents live in their own (untagged) panel; each tagged group renders as @<tag> with an agent count in the panel title. Panel heights are sized to their content and separated by a one-row gap. When the panels fit, the first panel grows to absorb leftover vertical space while later panels stay pinned to their natural height; when the panels overflow, space is weighted by each panel's rendered row count.

Use J / K to move focus across panels (forward / reverse). J lands on the first selectable row in the new panel; K lands on the last selectable row, including collapsed group banners when those are visible. Per-panel actions (kill, dismiss, expand, etc.) operate on whichever panel currently holds focus. Press X to open the cleanup panel: d dismisses completed agents in the focused panel, D dismisses completed agents across loaded panels, k cleans the focused panel, K cleans all loaded panels, m cleans marked agents, g cleans the focused group, t chooses a tag, and c opens the custom selector.

Tags are set or cleared with N (see Agent Actions). When opening the modal on an untagged agent the input is pre-seeded with pinned so a single Enter promotes the agent into the standard "pinned" panel; that default makes tag removal discoverable too — opening the modal on a tagged agent and submitting an empty string clears the tag. The %tag <name> directive in a prompt assigns the tag at launch.

Group Banners and Folding

Within each tag side panel, agents are grouped into either a 2-level or 3-level banner hierarchy depending on whether any agent in the panel targets a ChangeSpec:

  • 3-level layout (panel contains at least one ChangeSpec-scoped agent): project → ChangeSpec → name-root. Project-scoped agents and agents with no cl_name fall into a synthetic (no ChangeSpec) bucket that sorts last.
  • 2-level layout (no ChangeSpec anywhere in the panel): project → name-root.

Banners are rendered between agent rows and carry a summary chip (N agents · K running · M failed). Workflow children inherit grouping identity from their parent agent so banners never appear between a parent and its workflow steps.

A single global fold level controls how much of the hierarchy is visible:

Level What's visible (3-level layout) What's visible (2-level layout)
L0 Project banners only Project banners only
L1 Project + ChangeSpec banners Project + name-root banners
L2 Project + ChangeSpec + name-root banners All banners and agent rows
L3 All banners and agent rows (and per-workflow folds apply) (same as L2)
Key Action
l Step the focused group's fold one level up (L0L1L2L3); at L3, expand the focused workflow
h Collapse the focused workflow; once it's collapsed (or no workflow is focused), step the group fold one level down
L Snap to fully expanded — every banner, every agent row, every workflow step visible
H Snap to fully collapsed — every per-workflow fold collapsed, then group fold to L0 (only top-level banners)

Banners at fold levels < 3 are selectable rows. When a banner is focused, x performs a bulk kill/dismiss on every top-level agent in that group (single confirmation modal). Marks take priority over the group, so a non-empty mark set always drives the bulk action regardless of banner focus. When a fold change hides the previously focused agent, focus snaps to the nearest visible ancestor banner so navigation context is never lost.

Visual treatment: every row carries a fixed-width tier-guide gutter built from one segment per ancestor L0/L1 banner (in the parent tier's dim accent — project blue or ChangeSpec cooler accent), so nesting reads as a tree at a glance. L0 project / bucket banners use a sky-blue left bar and a heavy rule; level-2 visual headings (ChangeSpec banners and BY_DATE 4-hour windows) get a cooler accent with a bar and a lighter rule. Level-3 visual headings (name-root banners and conditional BY_DATE hourly windows) use a branch glyph with a teal label. Singleton name-root groups suppress their banner entirely to reduce visual noise.

After a kill or dismiss, focus re-anchors on the visually-next row (rather than the next row in input order) so the selection always lands somewhere meaningful in the rendered tree.

Grouping Modes

Press o on the Agents tab to cycle the L0 grouping bucket through three modes. The Agents tab shows a brief toast (Grouping: by project / by date / by status) on each cycle:

Mode L0 buckets Notes
STANDARD Project (with optional ChangeSpec sub-level) The "by project" default. Uses the 2-/3-level layout described above.
BY_DATE Today / Yesterday / This Week / Earlier Date bucket at L0 and 4-hour window at L1; hour-of-day (HH:00) L2 appears only inside 4-hour windows with 2+ agents. Sorted newest-first.
BY_STATUS Needs Attention / Failed / Running / Waiting / Done Bucketed by shared status semantics; name-root sub-level inside each bucket.

In BY_DATE mode the L0 date bucket is sub-grouped by compact 4-hour windows (8AM-12PM), then by hour-of-day (09:00) only when the 4-hour window contains at least two agents, so long Today/Yesterday lists are easier to scan without adding extra headings for singleton windows. The time anchor is stop_time for terminal agents and start_time otherwise; both time levels sort newest-first within their date bucket. Workflow children inherit the parent's anchor so they stay adjacent regardless of their own start time, and agents with no usable timestamp fall into a (no time) bucket that sorts last. In BY_STATUS mode the L0 banner is the status bucket and L1 is the name-root, with the same singleton-suppression rule as STANDARD. The bucket order is fixed: Needs Attention, Failed, Running, Waiting, Done. Each mode keeps its own per-group fold registry, so collapsing buckets in BY_STATUS doesn't affect the project layout you had in STANDARD. BY_STATUS banners are prefixed with semantic glyphs (, , , , ) so the bucket title still leads visually.

The active grouping strategy is also surfaced in the Agents tab header via a [group: <label> (o)] badge so the current session mode is always visible after the cycle toast fades. Each TUI launch starts in by-project grouping; cycling only changes the current session. Waiting holds agents that are blocked but progressing on their own — WAITING with a wait_until timer (%wait:5m, %wait:1430) or a non-empty waiting_for dependency. Needs Attention keeps the strict "you need to act" semantics: a WAITING agent with neither a timer nor a dependency stays there because it's parked waiting on the user.

Agent Row Glyphs

To keep rows compact, agent statuses and types are rendered as one- or two-character badges instead of verbose text:

Glyph Meaning
RUNNING
DONE
✓P PLAN DONE
▶P PLAN APPROVED
★E EPIC CREATED
PLANNING
FAILED
WAITING
? QUESTION
RETRYING (followed by attempt count, e.g. ↻2)
Workflow row (top-level)
ChangeSpec / CL row (top-level)
Autonomous (%approve) agent
Hidden agent (visible only when . toggles them in)

Agents launched by sase bead work also show a gold ◆ <bead_id> badge between the status glyph and the tag/name. A phase agent named <epic_id>.<N> displays that phase bead ID; the final <epic_id> land agent displays the parent epic bead ID. Legacy <epic_id>.land land agents keep the same badge. Dismissed agents keep the badge by stripping only the date-prefix used for dismissal.

The right-hand edge of each row carries a runtime suffix (<start-timestamp> · <elapsed>) right-aligned within the panel. Active rows that have actually started include a 🏃‍♂️ marker before the ticking elapsed duration; unread completed rows use a 🎉 marker in the same suffix slot; and user-paused rows (PLANNING, QUESTION, WAITING INPUT) use a 🙋 marker while waiting for a human response. Pre-run WAITING rows with no BEGIN time hide the suffix so queued waits do not look like live runtime. For finished agents, the start-timestamp half is rendered as a humanized (date_prefix, time) pair sized to fit the existing 15-cell slot:

  • Same day: HH:MM:SS
  • Prior day, same year: Mon DD HH:MM (drops seconds — they're noise once a row finished hours ago)
  • Different year: Mon DD 'YY (date only)

The elapsed duration starts at BEGIN when a row recorded wait-before-run metadata, otherwise at the row start time. Completed DONE / PLAN DONE workflow rows use the terminal agent stop time when one exists; plan-step rows that finish without a subprocess stop time anchor to the latest recorded plan submission time so completed planning rows do not keep ticking. PLAN APPROVED rows with a running follow-up show active elapsed time for the planner segment plus the coder segment, excluding the idle approval gap between plan submission and code launch. The date prefix uses a softer dim #8787AF while the time half keeps the standard #8787AF, giving the column internal hierarchy without inflating the palette. Statuses not in the table fall back to (STATUS) text for forwards compatibility.

Press / on the Agents tab to open the query editor. The query language is a structured Boolean expression — parallel to the ChangeSpec query language but with a property-key allowlist tailored to agents. Bare words are substring-matched against an agent's cl_name, display_name, agent_name, and status, plus its xprompt, live reply/response, chat transcript, and prior attempt replies.

Property keys (closed allowlist):

Key Form Notes
status, cl, project, name, model, provider, tag, text, type, source key:value (substring match) source is axe (workflow / step) or manual.
pinned, hidden, attention, needs key:true / key:false Boolean keys.
age age<5m, age>=2h, age:1d, etc. : is sugar for >=. Suffixes: s/m/h/d.

Boolean operators: juxtaposition is implicit AND; explicit AND, OR, and NOT (with parentheses) are honored. Precedence is NOT > AND > OR. The help modal carries an Agent Query Syntax section listing the same grammar.

Parse failures are non-fatal: the loader falls back to "no filter" for that render and surfaces a transient toast; the query-edit modal re-validates on Apply, keeping itself open and rendering the error inline (in red) on failure.

Transcript files are read lazily (only while a query is active) and cached by (path, mtime_ns) so auto-refresh stays cheap. Per-file reads are capped at 512 KB; missing or unreadable files are skipped silently. Parsed ASTs are also cached by raw query string so re-renders skip the parse.

Leader Mode (, prefix)

Key Action
,h Run agent with the default #cd:~ directory context
,I Toggle manual idle (shows IDLE indicator; any keypress re-activates)
,j Jump to the newest unread completed agent; repeats move through older unread completions
,n Jump to agent notification (plan or question; auto-unhides if needed)
,P Set/clear temporary default model (see Temporary Model Override)
,r Edit prompt and relaunch agent (retry without killing)
,x Kill agent & edit prompt
,<space> Run agent from current agent's CL (skips selection)
,. Open prompt history modal for the last CL
,> Open prompt history modal with cancelled prompts visible

Bang Mode (! prefix)

Key Action
!! Run background command
!x Start / stop axe (or select process)

Copy Mode (% prefix)

Key Action
%c Copy chat file path
%E Copy file path
%n Copy the focused agent's agent_name (falls back to display_name; toast indicates which)
%p Copy agent prompt
%s Copy sase ace snapshot

Keybindings: Axe Tab

Key Action
j / k Move to next / previous command
Ctrl+N / Ctrl+P Next / previous lumberjack output
g Scroll to top
G Scroll to bottom (pins auto-scroll)

Commands

Key Action
@ Run agent
r Re-run the selected bgcmd (only when a completed bgcmd row is focused)
x Start / stop axe (or kill bgcmd)
X Clear output

Leader Mode (, prefix)

Key Action
,h Run agent with the default #cd:~ directory context
,P Set/clear temporary default model (see Temporary Model Override)
,r Show runners info

Bang Mode (! prefix)

Key Action
!! Run background command
!x Start / stop axe (or select process)

Copy Mode (% prefix)

Key Action
%o Copy visible output
%O Copy full output
%s Copy sase ace snapshot

Axe Control

Key Action
Q Stop axe and quit

Query System

Editing Queries

Press / to open the query editor. The current canonical query is pre-filled.

To save a query, prefix with #:

  • #3 "myproject" -- save to slot 3
  • # "myproject" -- save to next available slot
  • #3 (no query) -- delete slot 3

Saved Queries

Press 1-9 or 0 to instantly load a saved query. These also work from within the help modal (?).

Query History

Key Action
^ Navigate to previous query in history
_ Navigate to next query in history

Query history is available on the CLs tab and tracks queries as you switch between them.

See docs/query_language.md for the full query syntax reference, including boolean expressions, status shorthands, property filters, and searchable fields.

Global Keybindings

These work on all tabs:

Key Action
Tab / Shift+Tab Switch between CLs, Agents, and Axe tabs
# Open XPrompt Browser (see XPrompt Browser below)
. Toggle visibility of hidden items (reverted CLs, non-run agents, or axe commands)
: Open the context-aware Command Palette
,i Open Activity Dashboard modal
i Show notifications inbox
I Pin idle mode (IDLE stays until I is pressed again; keypresses don't clear it)
Q Stop axe daemon and quit
y Refresh current tab
q Quit
? Show help modal

Quit Confirmation

When quitting (q or Q) while background tasks are still running (task queue workers or background command slots), a confirmation dialog appears showing the count of active tasks and asking whether to kill them and quit. Declining the dialog cancels the quit and returns to the TUI.

Command Palette

Press : from any tab to open the Command Palette — a context-aware modal listing every keymapped action that is currently runnable. The palette is the discovery surface for the TUI: rather than memorizing every chord, you can search by command label, key sequence (e.g. %n, ,t, zc), category, or alias.

Behavior:

  • Only commands applicable to the current tab and selected entry are shown by default. For example, CL diff appears only when a CL is selected; AXE start/stop appears only on the AXE tab; agent-specific actions appear only when an agent row (not a group banner) is focused.
  • Each row shows the keybinding, the command label, and a category badge such as Navigation, CL Actions, Agent Actions, Copy, or Leader.
  • A title-bar badge (CLs, Agents, or AXE) reflects the current tab.

Keybindings inside the palette:

Key Action
Type Filter commands (case-insensitive substring)
/ Move highlight
Ctrl+P / Ctrl+N Move highlight
Enter Run the highlighted command
Esc Close without running anything

The palette delegates execution to the same handlers that the keybindings use, so behavior matches pressing the chord directly. Selecting a built-in mode subcommand (e.g. %n to copy an agent name) runs the action without forcing you through the transient prefix mode. Custom modes defined in sase.yml are also represented per-command.

The : binding follows your configured keymap. To rebind it, set ace.keymaps.app.open_command_palette in ~/.config/sase/sase.yml.

Temporary Model Override

Press ,P from any tab to open the Temporary Model Override modal. It sets a session-level default provider/model for new agent launches without editing ~/.config/sase/sase.yml.

When no override is active, the modal shows the current resolved default (e.g. Default: CLAUDE(opus)) and offers a Set override action. Pick a known model from the provider-grouped picker, or use Custom... to enter a freeform provider/model (e.g. codex/o3 or opencode/anthropic/claude-sonnet-4-5). Then choose a duration — quick options are 15m, 30m, 1h, 2h, 4h, or Until cleared — or type a custom duration like 45m, 1h30m, 90m. Confirming writes the override and shows a toast like Temporary LLM override: CODEX(o3) for 1h.

When an override is active, the modal shows an active badge (Active: CODEX(o3) expires in 47m) and offers Change override and Clear override. Clearing removes the active state immediately, even if the override was created by a different ACE instance, an earlier session, or another sase process.

Behavior

  • The override applies only to the default provider/model. Explicit prompt directives (%model:codex/o3, %model:opencode/anthropic/claude-sonnet-4-5) and an explicit provider_name argument always win.
  • Already-running agents keep their current provider/model. Only new launches use the override.
  • The override is persisted to ~/.sase/llm_override.json so all sase processes on the same machine see it. Reads are best-effort self-cleaning: expired or malformed state files are deleted on next access.
  • Until cleared is a no-expiry mode — convenient, but still a temporary state, not a permanent config edit.
  • The temporary override is independent of SASE_MODEL_TIER_OVERRIDE. A concrete temporary model override takes the full provider/model path; the tier override only applies when no concrete override is active.

Examples

  • codex/o3 for 1h — switch to Codex o3 for the next hour, then revert to the configured default.
  • opencode/anthropic/claude-sonnet-4-5 for 1h — switch to an OpenCode provider/model pair.
  • sonnet for 30m — known bare model name; the provider is inferred from plugin metadata.
  • Until cleared — leave the override active across sessions; clear it later from the same ,P modal.

See docs/llms.md for the resolution order and state-file format.

Notifications Modal

Press i (or the ,n leader chord to jump straight to an agent's notification) to open the notifications modal. See docs/notifications.md for the full keybinding reference, the priority/inbox/muted section taxonomy, and the per-notification snooze and mute affordances.

The top-bar notification indicator color reflects the highest-priority unread bucket: orange for PRIORITY notifications (plan approvals, user questions, mentor reviews, axe errors, CRS results, agent error reports), gold for regular INBOX notifications, and cyan when only MUTED notifications remain.

Notification Actions

Some notifications carry an action field that triggers a handler when the notification is selected. The following notification action types are supported:

Action Source Behavior
ViewErrorReport Axe daemon Opens the error digest file in $EDITOR for review
plan Agent Jumps to the agent's plan notification in the Agents tab
question Agent Jumps to the agent's question notification in the Agents tab

The ViewErrorReport action is created by the axe error_digest chop when errors accumulate. The digest file summarizing recent errors is stored at ~/.sase/axe/error_digests/digest_<timestamp>.txt.

Toast Notifications

Each newly-arrived notification produces a short toast in the TUI. The toast text is derived per-action type (plan, question, HITL, axe error, ChangeSpec sync, agent update) so the message previews the actual event rather than a generic "N new notification(s)" line. Severity is also picked per type: plans, questions, and HITL render as warnings; axe errors (and sync failures) render as errors; everything else renders as information.

When more than 3 notifications arrive in the same poll tick, per-notification toasts are consolidated into one grouped toast per severity bucket (e.g., 2 warnings: 1 plan, 1 question). Ordering is urgency-first: errors, then warnings, then information. Silent notifications are excluded from this pipeline entirely.

Agent completion and failure toasts include the %name-set agent name with an @ prefix when present (e.g., CLAUDE(opus) @sase-q.land completed: ace(run)-...); anonymous agents (no agent_name) keep the prior format.

XPrompt Browser

Press # on any tab to open the XPrompt Browser modal. It displays all discovered xprompts in a two-panel layout: a filterable list on the left and a syntax-highlighted preview on the right.

Xprompts are grouped by source (CWD .xprompts/, CWD xprompts/, Home ~/.xprompts/, Home ~/xprompts/, project-specific, config sase.yml, plugins, built-in). Workflow xprompts (multi-step YAML) are marked with a gear icon; standalone workflows are displayed with the #!name insertion syntax. Project-local xprompts defined in each project's sase.yml file are also included, even though the TUI's normal config loading does not read project-local config files.

The list rows and preview metadata show the same insertion form and visible input metadata used by Ctrl+T completion. Step-only inputs are hidden from this user-facing surface because they are supplied by workflow execution rather than typed by the user.

Keybindings

Key Action
Ctrl+N Navigate to next xprompt
Ctrl+P Navigate to previous xprompt
Ctrl+D Scroll preview panel down
Ctrl+U Scroll preview panel up / clear input
Enter Edit highlighted xprompt in $EDITOR
Ctrl+O Add a new xprompt
Esc Close browser

Type in the filter input to narrow the list in real time.

Editing XPrompts

Press Enter on any xprompt to edit it in $EDITOR. All xprompts are editable, including plugin and built-in sources — these are copied to the highest-priority user directory (~/.xprompts/) before opening, so edits create an override rather than modifying the original. After saving, the browser offers to commit and push changes to git if applicable.

Creating XPrompts

Press Ctrl+O to start the guided creation flow:

  1. Location modal — Choose where to save the new xprompt (CWD .xprompts/, CWD xprompts/, Home ~/.xprompts/, Home ~/xprompts/, or a config file). Press Ctrl+G to open the selected config file in $EDITOR instead of proceeding with creation.
  2. Filename modal — Enter a filename (.md for prompt parts, .yml for workflows). Workflow files are pre-filled with a YAML template containing the workflow scaffold.
  3. Editor — The file opens in $EDITOR for editing.
  4. Git commit — After saving, the browser offers to commit and push changes.

Idle Detection

ACE tracks user activity and displays an orange IDLE badge in the top bar when the user has been inactive for longer than the configured threshold (ace.inactive_seconds, default: 600 seconds). The badge is also shown when the user presses ,I (leader chord) to manually mark themselves as inactive. Any keypress re-activates the user and hides the badge.

Pressing I (capital) activates pinned idle mode, shown as a red ■ IDLE badge. Pinned idle stays active regardless of keypresses — only pressing I again clears it. This is useful when you want to remain marked as idle while still interacting with the TUI. Pinned idle state is persisted to ~/.sase/tui_pinned_idle and automatically restored when the TUI restarts, so the user remains marked as idle across sessions.

External tools (e.g., chop scripts) can call is_idle() from sase.ace.tui_activity to check idle status programmatically.

Jump All Modal

Press ` (backtick) on any tab to open the Jump All Modal. It displays all entries across CLs, Agents, and Axe tabs with single-keypress hint characters for instant navigation. Selecting an entry switches to the appropriate tab and focuses it.

Hint characters are drawn from an extended alphabet — lowercase az first, then uppercase AZ — so modals with many entries can still fit a unique single-keypress hint per row without resorting to multi-character hints.

Key Action
Hint char Jump to the corresponding entry
Esc / q Close modal

The modal groups entries by tab (CLs, Agents, Axe) and shows contextual information for each: CL names and statuses, agent names with running indicators, and Axe lumberjack/command labels.

Jump Back

Both jump modals support a jump-back feature for toggling between two entries:

  • Backtick jump-back: Pressing ` inside the Jump All Modal returns to the previous position, enabling quick toggling between two entries across tabs.
  • Apostrophe jump-back: Pressing ' twice ('') in the single-tab entry jump mode jumps back to the previously jumped-from entry. The footer shows a "JUMP" mode indicator with ' back when a target exists.

The single-tab variant (' apostrophe) shows entries only from the current tab with the same hint-character navigation.

Mentor Comment Stats in CL List

When a ChangeSpec has completed mentor reviews with comments, the CLs tab list entry shows inline stats:

  • checkmark + count (e.g., ✓3) — number of accepted comments
  • dot + count (e.g., ●2) — number of unread comments

These stats are computed from the latest commit entry's finished mentors. They update as you accept or read comments in the Mentor Review modal.

Tab Bar Display

The tab bar shows contextual counts alongside each tab label using the format (MxD.H):

  • M — main count (CLs, running agents, or running lumberjacks)
  • xD — done/completed count (separated by x)
  • .H — hidden count, shown when hidden items are visible (separated by .)

Examples:

  • CLs tab: CLs (5) for 5 CLs, or CLs (5.2) when 2 hidden (reverted) CLs are visible
  • Agents tab: Agents (2) for 2 running agents, Agents (2x1) for 2 running + 1 done, Agents (2x1.3) with 3 hidden also visible
  • AXE tab: AXE (3) for 3 running lumberjacks, AXE (3x2.1) for 3 lumberjacks + 2 done bgcmds + 1 hidden command visible

Background Task Indicator

A gear icon (⚙) with a count appears in the top bar when background tasks are running (e.g., sync, mail, accept operations). The indicator automatically hides when all background tasks complete.

Runners Modal

Press ,r (leader + r) to open the runners modal. It shows concurrency information including hook runners, agent runners, and a Background Tasks section listing active and recently completed background tasks (sync, rebase, accept, mail, add-tag). Each task entry shows its type, CL name, status, and timestamps.

File Panel Trimming

When viewing agent files on the Agents tab, large files are automatically trimmed to fit the visible viewport. A blue indicator shows "N more lines below" when content is trimmed. Trim controls (-, =) are listed in the Agent Actions keybindings above. Trim state is preserved when switching between agents or refreshing data.

Pressing G on a trimmed file auto-expands it first, then scrolls to the bottom — so jumping to the end of a large file never leaves you staring at a trimmed page.

Image Preview Foundation

ACE renders PNG, JPEG, WebP, and GIF attachments with a Pillow-backed Rich cell preview. The renderer decodes the first image frame, preserves aspect ratio within the visible panel bounds, composites transparency, and paints colored half-block cells using truecolor when the terminal advertises it and 256-color approximations otherwise.

Generated images are already attached to successful agent completion notifications and recorded in done.json as image_paths. The Agents tab file panel and notification modal route supported raster image attachments through this preview layer before attempting text decoding. See agent_images.md for supported image extensions, guardrails, and current preview behavior.

Agent Auto-Naming

All agents are automatically assigned a short name (a, b, ..., z, aa, ..., az, a0, ...) when launched without an explicit %name directive. Names are permanent IDs: a name used by any existing agent state remains reserved until that agent is explicitly wiped or deleted. This enables the resume-by-name workflow: press r on a running named agent to queue a follow-up that waits for it to finish and then loads its conversation history.

Provider/Model Suffixes

When the same base name is shared by multiple co-launched agents (e.g. multi-model fan-out via the %model: directive), the rendered display name carries a short .<provider> or .<provider>(<model>) suffix so each row is distinguishable. Provider suffixes are supplied by the LLM provider plugins via the llm_provider_short_name hook (built-in defaults: cld for Claude, cdx for Codex, gem for Gemini; jet ships in the sase-google plugin). Model-name shorthands come from the llm_model_short_aliases hook (e.g. opus, sonnet, haiku) and are resolved against the configured model so the suffix stays compact regardless of how the model was spelled in the prompt or config. Single-runtime spawns omit the suffix.

An explicit %name:<name> launch fails before spawning if <name> is already reserved. The prompt is saved as a cancelled history entry and the error suggests the lowest free numeric suffix, such as <name>1. To deliberately reuse a reserved name from the TUI, launch with %name:!<name>; after confirmation, SASE wipes the previous owner and then claims the name for the new agent. Reviving and dismissing agents preserve their stored names.

The durable registry lives at ~/.sase/agent_name_registry.json and is rebuilt from visible artifacts plus dismissed bundles when missing or stale. Use sase agents names migrate-auto to run the historical auto-name migration that moves older generated names into the permanent namespace; pass --force to rerun after the migration marker is present or --json for machine-readable output.

Per-Step Naming for Multi-Agent Workflows

When a workflow spawns follow-up agents (e.g., plan approval followed by a coder step), the agents receive dotted names derived from the base name. For example, if the initial agent is named a:

  1. The root agent keeps a
  2. The first follow-up agent becomes a.2
  3. Subsequent follow-ups become a.3, a.4, etc.

The base name (a) is reserved for the workflow as a whole, so %wait:a or @a references resolve correctly. Single- agent workflows (no follow-ups) keep their original name unchanged.

Agent Statuses

Each agent in the Agents tab displays a status label indicating its current state. Statuses fall into two categories: active (the agent is still running or awaiting input) and completed (the agent has finished).

Active Statuses

Status Color Description
RUNNING Gold Agent subprocess is executing
WAITING Light blue Agent is queued, waiting for another agent to succeed (%wait)
WAITING INPUT Amber/orange Workflow is paused at a human-in-the-loop (HITL) step
PLANNING Pink/magenta Agent has produced a plan and is waiting for user approval
PLAN APPROVED Cyan Plan was approved; follow-up agent has been spawned
EPIC APPROVED Cyan Plan was approved as an epic; .epic follow-up is running
PLAN COMMITTED Cyan Plan was approved with auto-commit; .commit follow-up is running
QUESTION Amber Agent is asking the user a question (via /sase_questions)
RETRYING Orange Agent hit a retryable error and is in a countdown before retrying

The footer also shows axe daemon status indicators:

Status Color Description
RUNNING Green Axe daemon is running normally
STOPPED Red Axe daemon is not running
STARTING Yellow Axe daemon is starting up
STOPPING Yellow Axe daemon is shutting down
RESTARTING Deep sky blue Axe daemon is restarting (triggered by --restart-axe flag)

During TUI startup the footer slot shows a live starting stopwatch with a rotating glyph in place of the daemon status, ticking at ~10 Hz until the TUI finishes mounting and the real axe status resolves. The background color turns from its normal tone to a slow-startup tone once the elapsed time crosses the slow threshold, giving immediate visual feedback on cold-start latency. A safety timeout forcibly retires the stopwatch if the mount signal never fires.

Completed Statuses

Status Color Description
DONE Green Agent completed successfully
PLAN DONE Green Plan workflow fully completed (all steps)
EPIC CREATED Green Plan workflow completed and its latest .epic follow-up finished successfully
FAILED Red Agent exited with an error

Completed agents can be dismissed with x on a single row, or through the X cleanup panel for focused-panel, global, tag, marked, group, and custom selections.

When a terminal agent becomes unread, ACE marks it with the completed-agent indicator and includes it in the Agents header unread count. Selecting that row, jumping to it with ,j, or toggling it back to read with U acknowledges the row and dismisses the matching user-agent completion notification. Manually marking a row unread with U arms it for normal acknowledgement after you move away and return, so the marker can be used as a short-lived reminder without leaving stale inbox entries.

Agent Revival

Press R on the Agents tab to revive a previously dismissed agent. All dismissed agent chats are saved as individual files under ~/.sase/dismissed_bundles/ and can be restored at any time. There is no limit on the number of dismissed agents that can be stored.

Dismiss operations are O(1) per agent — each agent is saved to its own file rather than a monolithic store. ACE keeps a SQLite summary index in that directory so revival and run-log lookups can load dismissed agents lazily. Use sase agents archive verify to check the index, or sase agents archive rebuild-index to rebuild it from bundle files.

Legacy Dismissed-Name Prefix

Current dismiss and revive operations preserve stored agent names. Older dismissed bundles may still contain YYmmdd.<base> names from the previous dismissal model, and ACE keeps compatibility helpers for reading those bundles. Bare %wait (no target) intentionally skips legacy dismissal-prefixed candidates so it anchors on a live, visible agent.

Agents Tab Metadata Panel

The Agents tab metadata panel (cycled to via ]/[) shows structured information about the selected agent:

  • Agent details: Name, status, model, provider, CL association, and chronologically sorted timestamps:
  • Bead — shown for agents launched by sase bead work, inferred from phase, exact epic, or legacy .land names
  • WAIT — when the agent was spawned (waiting for a slot)
  • BEGIN — when execution started
  • PLAN — each plan proposal round (multiple entries when re-planning occurs)
  • FBACK — each time the agent requested feedback from the user
  • QUEST — each time the agent asked the user a question
  • RETRY — each time the agent entered retry state (retryable error)
  • CODE — when the agent began writing code
  • EPIC — when an epic follow-up agent was launched after plan approval
  • END — when execution completed
  • AGENT REPLY: The agent's live or completed reply content, streamed from live_reply.md during execution and read from the artifacts directory after completion. When per-turn reply timestamps are available (recorded in live_reply_timestamps.jsonl), the reply is displayed with timestamp dividers between each agent turn. For agents with follow-up phases (planner, feedback rounds, coder), the AGENT REPLY section consolidates replies from all phases into a single view with purple phase dividers showing each phase's label and start time

When the file or thinking panel is empty, the g/G keys automatically fall back to scrolling the metadata panel.

Plan Workflows

When a workflow uses the %plan directive, the agent enters a planning phase before executing:

  • PLANNING — The agent has produced a plan and is waiting for user approval. Shown in pink/magenta in the prompt panel.
  • PLAN APPROVED — The plan has been approved and the follow-up agent has been spawned. Shown in cyan/turquoise.
  • PLAN REJECTED — The user rejected the plan via the r keybinding. Treated as a terminal decision (not a failed agent run): the rejected agent appears in the Done tab with this status, and the redundant completion notification is suppressed.

Plan files generated by the agent are displayed in the file panel alongside other agent artifacts. Plan approval notifications include the LLM provider and model name, so users can see which model proposed the plan (visible in both the TUI notification modal and Telegram delivery).

When sase plan writes the plan, it also touches ~/.sase/.ace_refresh_pulse to wake any running TUI immediately — PLANNING status appears without waiting for the next auto-refresh tick. The pulse file is consumed by the inotify artifact watcher (see Auto-Refresh) and is harmless if no TUI is open.

The Plan Review modal title shows a provider-themed PROVIDER(model) badge between the "Plan Review" label and the plan filename — orange for Claude, lime for Codex, Google blue for Gemini, neutral muted for other providers. The badge is omitted when provider/model metadata is absent, leaving the legacy title shape unchanged.

For active Agents-tab rows, a cycles through normal auto-approve, epic auto-approve, and disabled. Epic auto-approve is the same plan-specific path as the %epic directive: the next submitted plan is accepted as an epic, SDD epic artifacts are written, beads are initialized, and the epic follow-up agent is launched. It does not answer unrelated HITL prompts.

Plan Approval Keybindings

Key Action
a Save as tale and continue
A Tale with options (opens Tale Options)
r Reject the plan
f Request feedback (send follow-up questions to the agent)
e Edit the plan file in $EDITOR
E Mark the plan as an epic (creates bead)
L Mark the plan as a legend (creates legend-tier bead)
y Copy plan content to clipboard
Y Copy plan file path to clipboard
Ctrl+D/U Scroll plan content down / up
g / G Scroll to top / bottom
q / Esc Cancel

The question modal also supports y to copy questions and selected answers.

Tale Options

Pressing A in the plan approval modal opens an options dialog with fine-grained control over what happens after approval:

Key Action
Enter Tale with selections
Space Toggle focused switch
Ctrl+N Next field
Ctrl+P Previous field
q / Esc Cancel

The dialog presents toggle switches, an optional text input, and a model picker:

  • Commit plan (default: ON) — Whether to commit the plan file
  • Run coder agent (default: ON) — Whether to launch a coder agent after approval
  • Additional prompt — Optional extra instructions for the coder agent (only editable when coder is ON)
  • Coder model — Select an LLM model for the coder agent instead of inheriting the planner's model. Shows all registered models grouped by provider (Claude, Codex, Gemini, Qwen, OpenCode) with a "Custom..." option for freeform input.

At least one of commit/coder must be enabled — disabling one locks the other ON.

Linked Chats in Multi-Step Workflows

When a workflow spawns multiple agents (e.g., a planner step followed by a coder step), the chat history files for each step are cross-linked via a ## Linked Chats markdown section. This section is inserted near the top of each chat file and lists all related agents with their roles and file paths, making it easy to trace the full workflow from any individual agent's chat history.

For example, a plan-then-code workflow produces chat files with:

## Linked Chats

- **1. planner**`/path/to/planner_chat.md`
- 2. coder — `/path/to/coder_chat.md`

The current agent's entry is bolded for quick identification.

Retry/Fallback Display

When an agent encounters a retryable error (configured via llm_provider.retry), the Agents tab shows retry state:

  • RETRYING — Shown in bold orange when waiting before the next retry attempt. Includes a countdown timer: RETRYING (45s).
  • ↻N — Shown after the status for running agents that have retried. The number indicates how many retries have occurred (e.g., ↻2 means two retries so far).
  • ▸Model — Appended to the retry annotation when the agent has fallen back to an alternate model (e.g., ↻3▸flash).

Prior Agent Attempts

Every time the axe retry loop retries an agent — context-overflow restart, user-configured retry, or fallback-model switch — the failed attempt's partial reply, error text, timestamps, and model are snapshotted under <artifacts_dir>/attempts/<N>/. The AGENT REPLY area in the Agents tab renders these prior attempts inline with styled dividers before the current/final attempt, so the full arc of the agent's work stays visible in one scroll.

Press V to collapse the view to the current attempt only; press V again to re-expand. The binding only appears in the keybinding footer when the selected agent has one or more prior attempts.

Custom Keymaps

All TUI keybindings are configurable via the ace.keymaps section in sase.yml. You can remap any built-in key and define entirely new prefix-key modes.

Remapping Built-in Keys

Override any app-level keybinding under ace.keymaps.app:

ace:
  keymaps:
    app:
      next_changespec: "n" # Remap j → n
      prev_changespec: "p" # Remap k → p
      show_notifications: "N" # Remap i → N

Custom Modes

Define user-defined prefix-key modes under ace.keymaps.modes. Each custom mode has a prefix key and a keys dict where each sub-key specifies either a shell command or a built-in action:

ace:
  keymaps:
    modes:
      my_mode:
        prefix: ";"
        keys:
          run_tests:
            key: "t"
            shell: "just test"
          show_log:
            key: "l"
            shell: "git log --oneline -20"
          refresh:
            key: "r"
            action: "refresh"

Pressing ; activates the mode, then pressing t runs just test, l shows the git log, etc.

Validation

The keymap loader validates all configuration:

  • Invalid keys are reverted to their defaults with a warning
  • Duplicate keys (two actions bound to the same key) are detected and the conflicting override is reverted
  • Prefix conflicts between custom mode prefixes and existing app bindings are warned

See docs/configuration.md for the full ace.keymaps configuration reference.

Prompt Input Widget

The prompt input is a multiline TextArea widget that supports two editing modes: INSERT and NORMAL. The widget provides markdown syntax highlighting for prompt content (headings, bold, italic, code blocks, lists, etc.).

INSERT Mode (Default)

Key Action
Enter Submit the prompt
Ctrl+J Insert a newline
Ctrl+A Move to start of line (jumps to previous line start if already at col 0)
Ctrl+E Move to end of line (jumps to next line end if already at end)
Ctrl+G Open full prompt in $EDITOR
Ctrl+I Load a prompt from history
Ctrl+T Completion (directives, xprompts, slash skills, or file paths; see Completion)
Tab Snippet expansion (see below)
#@ Open XPrompt snippet picker (type # then @)
Escape Switch to vim NORMAL mode

Text automatically wraps at the terminal width, breaking at spaces (never mid-word). Line numbers appear in cyan when the text exceeds one line.

Completion

Press Ctrl+T to activate completion. The completion kind is determined by the token under the cursor:

  • XPrompt completion: When the cursor is on a #-prefixed token (e.g., #my_pro), completion shows matching xprompt names from all discovery sources. Built-in workspace references such as #cd are included; use #cd:<path> to run from a specific directory without VCS workspace management. Completion rows include the xprompt kind and visible typed inputs, with required arguments shown as name: type and optional arguments shown as name?: type plus a default when the default is a simple scalar. Standalone references use the #!name insertion form; typing #! filters completion to entries whose canonical insertion starts with #!.
  • Slash-skill completion: When the cursor is on a slash-skill token such as / or /sase_, completion filters the same catalog to xprompts marked as skill: true and inserts /skill_name. Packaged built-in skills are included, so /sase_plan, /sase_questions, and other bundled SASE skills are available without a project-local xprompt file.
  • XPrompt argument completion: When the cursor is inside a known xprompt argument position, Ctrl+T completes the active argument instead of the xprompt name. For path inputs it delegates to file path completion, for bool inputs it offers true and false, and inside parenthesized syntax it completes missing name= arguments without repeating names already present in the argument list. Numeric inputs keep the type hint visible but do not invent values.
  • Directive completion: When the cursor is on a %-prefixed directive token (e.g., %m), completion lists user-facing prompt directives and accepts aliases into their canonical forms. For example, %m completes to %model and %w completes to %wait. The panel shows each directive's aliases and whether it takes an argument or is a flag.
  • File path completion: When the cursor is on a path-like token (starting with /, ./, ../, ~/, or containing /), completion shows matching filesystem entries. Tokens starting with @ are also recognized — the @ prefix is preserved in the completed path (useful for file-reference arguments).
  • File-history completion: When the cursor is in whitespace (or at an empty prompt prefix), Ctrl+T opens a list of recently referenced files drawn from prompt history, ranked by recency. Project-local .sase/ paths are filtered out so internal bead/plan artifacts don't pollute the suggestions. Press Ctrl+D in the completion panel to delete the highlighted entry from the on-disk history.
Key Action
Ctrl+T Start completion or insert shared prefix
Ctrl+N / Down Next candidate
Ctrl+P / Up Previous candidate
Enter / Ctrl+L Accept highlighted candidate
Escape Cancel completion

For file completion, directories appear before files in the candidate list. Dotfiles are hidden unless the partial prefix starts with .. Accepting a directory automatically re-opens completion for the next level (drill-down). The completion panel shows up to 10 candidates at a time and scrolls to keep the highlight visible. When exactly one xprompt or file candidate matches, accepting completion inserts the canonical reference immediately.

Accepting an xprompt completion, or selecting an xprompt from the #@ picker, opens an xprompt args hint panel when the xprompt has required user-facing inputs. The panel shows the supported arguments and highlights the active one. Press : while the accepted reference is still current to switch to colon syntax, or press ( to insert a required-argument named snippet and use Tab to advance through the snippet fields.

The same smart insertion rules apply to #@ selections and Ctrl+T completions. A selected xprompt with no required inputs inserts a trailing space, a single required non-text input inserts colon syntax, a single required text input inserts double-colon shorthand, and multiple required inputs insert a parenthesized named-argument snippet.

The same hint panel appears while typing narrow, known argument forms such as #name:, #!name:, #ns/name:, #ns__name:, #name!!:, #name??:, #name(, and #name(arg=. The hint is advisory; the backend xprompt parser still owns expansion semantics when the prompt is submitted. Detection intentionally stays conservative, so prose shorthand, URLs, unknown xprompt names, #name+, and completed colon text such as #name: value do not keep the prompt-bar hint open.

Special Prompt Shortcuts

Input Action
. Open prompt history modal for the current CL
.x Open prompt history modal with cancelled prompts shown by default

NORMAL Mode

Press Escape in INSERT mode to enter vim-style NORMAL mode. The border title shows [NORMAL] and line numbers switch to relative numbering (current line shows absolute, others show offset).

Motions

Key Action
h / l Move left / right
j / k Move down / up (actual lines)
w / W Next word / WORD start
e / E Next word / WORD end
b / B Previous word / WORD start
f{c} / F{c} Find char forward / backward
t{c} / T{c} Till char forward / backward
; / , Repeat / reverse last f/F/t/T
0 / $ Line start / end
^ First non-blank character
gg / G Top / bottom of document
Ctrl+D/Ctrl+U Half-page down / up

All motions accept a numeric count prefix (e.g., 3j moves down 3 lines).

Operators

Key Action
d Delete (takes a motion, e.g. dw); copies to clipboard
c Change (takes a motion, e.g. cw); copies to clipboard
D Delete to end of line
C Change to end of line
dd Delete entire line
cc Change entire line
dae Delete entire buffer (copies to clipboard)
cae Change entire buffer (copies to clipboard)

Other Commands

Key Action
i Enter INSERT mode
a Append after cursor
A Append at end of line
I Insert at line start
o Open line below
O Open line above
u Undo
x Delete character
p Paste
~ Toggle case of character(s) at cursor (supports count: 5~)
. Repeat last mutation (supports count: 3.)
J Join current line with next (supports count: 5J)

The border subtitle shows pending operators and counts (e.g., 2d when a delete with count 2 is pending).

Prompt History Modal

Press ,. (leader + .) on the CLs or Agents tab to open the prompt history modal. It displays prompts previously run in ACE, sorted by relevance to the current CL/agent context. Prompts shorter than two words are skipped when writing to history, so trivial one-word inputs (e.g. y, ok) don't clutter the list.

Bare prompts are stored after launch normalization, so a prompt without an explicit workspace reference appears with the default #cd:~ prefix. Explicit workspace prefixes, including #cd:<path>, also feed the Ctrl+N / Ctrl+P MRU cycle when the prompt input is empty or contains only a workspace prefix.

Keybindings

Key Action
Enter Submit the highlighted prompt directly
Ctrl+G Edit first — load prompt into editor
Ctrl+I Load prompt into the input widget for editing
Ctrl+X Toggle visibility of cancelled prompts
Ctrl+Y Copy prompt to clipboard
Esc Close modal

Filtering

Type in the search box to filter prompts by text or branch/workspace name. Press Ctrl+X to toggle cancelled prompts on or off — when enabled, cancelled prompts appear in the results with a marker.

Prompt-history rows are compact single-line entries: marker, last-used timestamp (MM-DD HH:MM when parseable), compact branch/workspace context, and a first-line prompt preview. The preview panel still shows the full prompt and metadata. History writes use a sidecar lock plus atomic tempfile replacement so concurrent agent launches do not truncate the shared ~/.sase/prompt_history.json file.

Visual Markers

Marker Color Meaning
* Green Prompt matches current branch
~ Yellow Prompt matches current workspace
Magenta Prompt was cancelled

Task Queue Modal

Press ,t (leader + t) to open the task queue modal. It shows background tasks (hook runs, mentor executions, etc.) with live output for running tasks and completed output for finished ones.

Layout

The modal uses a two-panel layout: a task list on the left and an output pane on the right. Running tasks refresh their output every second.

Task Status Icons

Icon Color Meaning
Green Running
Cyan Success
Red Error
? Dim Unknown

Keybindings

Key Action
j / k Navigate task list
K Kill selected running task
d Dismiss selected completed task
D Dismiss all completed tasks
e Open task output in $EDITOR
y Copy task output to clipboard
Ctrl+D / U Scroll output pane down / up
q / Esc Close modal

Snippets

The prompt input supports expandable text snippets triggered by pressing Tab. Snippets are configured in the ace.snippets section of sase.yml as a mapping of trigger words to template strings:

ace:
  snippets:
    fix: "Please fix the following issue:\n$0"
    review: "Review this code for correctness, performance, and style."
    bug: "Bug in $1:\n\nExpected: $2\nActual: $3\n\nPlease fix.$0"

Usage

  1. Type a trigger word (e.g., fix) in the prompt input.
  2. Press Tab. If the word before the cursor matches a snippet, it is replaced with the template text.
  3. If the template contains tabstop markers ($1, $2, ...), the cursor jumps to $1 first. Press Tab again to advance to $2, then $3, and so on. $0 marks the final cursor position after all tabstops are visited. If there are no tabstop markers, the cursor moves to the end of the expanded text.

Tab priority: Snippet expansion always takes priority over tabstop advancement. If you type a trigger word at an active tabstop and press Tab, the snippet expands rather than jumping to the next tabstop.

Multi-line indentation: When a multi-line snippet is expanded on an indented line, continuation lines automatically inherit the leading whitespace of the trigger line. Tabstop positions are adjusted accordingly.

Trigger words are matched against the alphanumeric/underscore word immediately before the cursor. If no snippet matches, Tab advances to the next tabstop (if any are remaining from a previous expansion), or behaves normally.

XPrompt-derived snippets compose normal xprompt references before they enter the snippet registry. Entries configured directly in ace.snippets remain literal snippet templates.

Editors using sase lsp can receive the same registry as LSP snippet completions after bare trigger words when the client advertises completionItem.snippetSupport. The server uses the editor helper operation sase editor helper-bridge snippet-catalog as the authoritative source and falls back to native Rust loading only for simple snippets if the helper is unavailable. Clients without snippet support do not receive these entries, because raw $1 / $0 markers would not behave like ACE tabstops.

XPrompt Picker (#@)

Typing #@ (the # character followed by @) opens the XPrompt snippet picker modal. This lists all available xprompts (including project-local xprompts from sase.yml files) and inserts the selected reference at the cursor position. Inline-capable xprompts and workflows insert as #name; standalone workflows insert as #!name. The picker uses the same argument-aware skeletons as xprompt completion, so typed inputs can be filled immediately after selection. This is separate from the ace.snippets mechanism — it provides quick access to xprompt references rather than expanding static templates.

Auto-Refresh

ACE auto-refreshes data at a configurable interval (default: 10 seconds). The remaining time until the next refresh is shown in the info panel. Set --refresh-interval 0 to disable.

Tab switches are instant: cached data is shown immediately while a background refresh runs asynchronously, so moving between tabs never blocks on disk I/O.

When the inotify-based artifact watcher is active, the periodic tick is event-driven: it consults per-surface dirty flags (_dirty_changespecs, _dirty_agents, _dirty_axe) and short-circuits the whole tick when nothing has changed. A 60-second FULL_SANITY_REFRESH_SECONDS floor still triggers a full reconcile to recover from missed inotify events, so a quiet TUI does ~zero work between real changes without going stale.

Performance Tracing

For diagnosing TUI latency, set SASE_TUI_TRACE=1 before launching sase ace. Tracing is near-zero-cost when the env var is unset; with it enabled, each instrumented hot path emits one JSONL line per span to ~/.sase/perf/tui_trace.jsonl (override via SASE_TUI_TRACE_PATH=…). See docs/perf_runbook.md for the full span catalog, benchmark harness, and per-phase performance targets.