Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

The Interactive Session

heph with no subcommand opens the interactive session on the project in the current directory (-C DIR for another). It takes the terminal over until you leave by pressing Ctrl-D twice.

Conversations

Plain heph creates a fresh conversation every time, initially displayed as <unnamed>. Opening it or typing a draft starts no turn and calls no model. The UUID is its identity; empty conversations and drafts survive exit and crash. You can also start with heph 'fix the tests' or heph fix the tests. The initial prompt follows the ordinary submission and base-branch choice flow. Until submission succeeds it is kept as a draft.

The first submission saves a prompt-derived name immediately, before provider setup or turn creation. It uses up to three non-filler ASCII words, capped at 24 characters each, or a short prompt hash if none remain. Once the prompt is stored, the title role may improve that name asynchronously. Input, the main request, and review do not wait for it. Failure or cancellation keeps the local name; unusable output does not become session-N. /rename NAME takes precedence over a delayed title, even when choosing the local name. Reopening retries a pending title once; legacy unnamed conversations with stored input get a local name first.

heph --continue reopens the most recently active branch conversation. heph --continue NAME or heph --continue FULL-UUID opens exactly that existing conversation, with its history, draft, routing, and pending review. Missing or locked targets error, never create replacements. A startup prompt cannot accompany --continue; restored drafts are not automatically submitted. Fresh startup uses configured routing plus flags, not the previous ref's routing.

heph --continue-branch BRANCH resumes by an exact current or recorded publication branch in this checkout. One match opens directly; several prompt with session metadata and cached /summary content so you can choose. Enter or q cancels. It excludes startup prompts and other startup selectors. See Resuming by publication branch.

Inside a session, /stats shows the active conversation's full UUID as Session ID: at the top, even while accounting loads or fails. Use that ID with heph --continue FULL-UUID or /switch FULL-UUID to reopen it.

/refs lists labels, full UUIDs, activity, tips, and branches; /switch NAME or /switch FULL-UUID opens one while idle. Names are exact and case-insensitive; UUID prefixes and <unnamed> are not selectors. /new <prompt> starts another root with the same immediate, nonblocking naming flow, inheriting the active routing and base. /fork <prompt> keeps its naming-before-creation flow (Forking and Switching Conversations).

A long history is rendered one screenful at a time. A resize or sidebar toggle keeps the source position of a scrolled view; it does not rewrap the entire conversation. Live appends keep compatible displayed prefixes while replacement layout runs, and running-tool clocks do not replace the conversation with a loading pane. A genuinely cold layout may briefly say rendering history while the input and sidebar remain responsive; unavailable regions keep their neighbors. more below indicates that newer content follows the view, without measuring all preceding rows.

Draft durability

Every edit requests an asynchronous save. The input border shows draft pending, draft saved, or draft save failed; only saved input has been acknowledged as committed. Unsent intermediate versions coalesce. A crash can lose unacknowledged edits, with no fixed time bound while SQLite is busy.

Submission waits for the original prompt's save before starting its runner. Ref changes drain old-ref saves before releasing its lease. You can keep typing while these operations wait; Enter keeps your input, and Esc cancels the action. Normal quit freezes input and flushes for up to ten seconds. On save failure, R retries and Esc cancels. Failed quit also offers X to explicitly leave without saving pending changes. Reopening restores the last committed draft, never automatically submits it.

Tool-result cost diagnostics

/stats shows estimated generating-request shares and a separate tool-result lifetime section. It reports recorded result appearances, replay input, following output, and their retrospective lifetime estimate. Full results and later one-line stubs are captured as distinct prepared-request forms.

These are not extra charges or causal measurements. Costs are allocated by result bytes relative to the request's local input estimate, with cache pricing averaged within that request. Images are particularly approximate. Generating and following-output shares overlap; never add them to the provider total. Older requests have no snapshots, and estimated requests may not have reached the provider. There is no forecast of future replay rounds.

Work summaries

/summary reads a cached memory jogger: generation asks for 3-5 short Markdown bullets, at most 100 words, covering the current goal, key progress or decision, and the next step or blocker rather than an exhaustive recap. The UI renders Markdown, including in older cached summaries. Use /summary --refresh to replace an older, longer summary with the terse format.

It shows the covered turn and age, and warns if the ref has moved since generation. The cache survives reopening and renaming; a new or forked ref gets its own summary. An empty cache says how to request one.

Automatic generation runs after the first completed turn, then after five new turns or fifteen minutes since the last summary, whichever comes first. These checks happen only when a turn ends, not while idle. Pending reviews wait. /summary --refresh regenerates from the stored transcript while idle. Only one generation runs at a time, and interactive generation never blocks input. Leaving or switching away cancels it. heph exec also checks the policy and finishes a due generation before exiting.

Summaries use the summarize model role and record usage on the covered turn. They do not rewrite history, consume a conversation turn, or change what the agent remembers. /clear does not erase them. Failed refreshes keep the old cache; a delayed result is not installed if the ref has moved. Automatic refresh failures are logged at debug level; requested failures are displayed.

Input is bounded to 80,000 transcript characters, favoring recent turns, with per-block limits of 12,000 text characters or 1,500 tool characters. Omitted content is marked. Automatic updates also carry the previous summary when it belongs to the current chain. Output uses [context] summary_max_tokens, capped by the selected tier's token limit. This is a model-generated overview, not a replacement for reviewing the actual changes or test results.

The turn, on screen

You type a prompt and press Enter. From then until the turn ends, the conversation fills in as things happen:

  • While the model is being waited on, a dim * ... with moving dots stands where its reply will go: right after Enter, and again after each tool call while the next round is on its way.

  • The model's text streams in as it is written.

  • When the model thinks before answering, the thinking is folded to one line: * thinking: <its first line> (Right to open). Right or Left with the input empty unfolds and folds the nearest thing that can be: the last tool call, or the last reply that has thinking. Thinking is the model's scratch work; heph never treats it as the model's stated reason for a change.

  • Each tool call is one line: a mark, the tool, and what it is acting on. .. means the model is still sending the call; >> means it is running, with a clock beside it; ok means it finished; !! means it failed. A finished call's ok is magenta when you approved it and green when it ran on its own.

  • A running command streams its last few lines of output under its line. When it finishes they fold away; unfolding the call shows all of its output and its full result, colored as a diff when it is one.

  • For work with several steps the model keeps a task list with the todos tool. Its line names the step in progress and the count done, and the list shows beneath it, [x] done, [>] in progress, [ ] to come, without unfolding; Left folds it. Each call replaces the list, so the newest is the one to read.

  • Lines beginning -- are heph speaking: running acceptance gates, a gate that failed, a denied call, and the last line of every turn: turn done, turn interrupted, or why it ended, with the turn's cost.

Messages stand apart with a blank line above and below. Tool calls that follow one another, and -- lines that follow one another, run together as a list.

The status bar uses one row when everything fits. Otherwise it separates session information (conversation and branch, mode, held locks, activity, edits, and queued messages) from usage information (live tokens, cost, cache-hit share, context window usage, and model). Narrower terminals add rows between complete fields, not in the middle of a label. Oversized names and lock lists end in ... rather than pushing other fields out of view.

Muted totals like $8.00 / $1.00 / $4.00 show today's global local-date spend, this active process, and this ref's persisted history. Refresh messages stay in /stats and the sidebar; missing totals show -. Activity is working 0:41, running shell 0:12, approve?, asking, review, or done. 1 queued means a message is waiting for the next turn. /stats shows the full accounting breakdown at any width. locks: ... lists the worktree lease, publication ownership when held, and execution resources, including background jobs. Long lock lists end in ...; full acquisition and release names remain in scrollback.

context N% is muted gray like cache N%. It shows the current request's size as a percentage of the running model's context window, rounded to a whole percent, not the session's cumulative tokens. While waiting for a reply, it is an estimate; after the reply, it counts the provider's input tokens (including cached tokens) plus output tokens. It is hidden if the window is unknown or no request has run since opening, switching, or clearing the conversation. If an Ollama response omits usage counts, the percentage keeps the pre-request estimate; token and cost totals are labeled incomplete instead of actual zero.

done means a turn finished and you have not touched the pane since. Your next keypress or scroll clears it. The same test decides whether a notification is sent, so "done" on the bar and a notification elsewhere never both happen.

Dialogs

Dialogs default to 120 content columns, plus four columns for borders and spacing. They are centered with at least two columns of outer margin on each side, shrinking to fit narrower terminals.

Every dialog shows the current conversation name centered in its top border, with the dialog name on the left and metadata on the right. This includes permission prompts, confirmations, questions, review, tiers, stats, and help. Permission levels stay muted gray; review's stage and help's closing hint sit on the right. Long conversation names are shortened with ... to avoid colliding with either side. On a very narrow dialog the centered name is hidden if there is no room; side labels are shortened when necessary too.

Scrolling

New output keeps the conversation scrolled to the bottom. PgUp and PgDn scroll by ten lines, Shift+Up and Shift+Down by one, the mouse wheel by three, Home and End (with the input empty) jump to the top and bottom. While you are scrolled up, a yellow marker in the corner counts the lines below you; any new output arrives without moving your view, and End brings you back.

The wheel works because heph takes the mouse, which is also why dragging does not select text as it does at the shell: hold Shift while you drag, and the terminal selects as usual. When a permission prompt, a question, or a review is up, the wheel scrolls that instead of the conversation behind it.

Leaving

Ctrl-D opens an exit confirmation. Press Ctrl-D again to leave; any other key cancels, leaving your input untouched. A half-typed prompt is saved and comes back next time. If a turn is running, the confirmation warns you; leaving anyway cancels it, and the next start closes it as interrupted with its work kept for review.

/quit and /exit leave immediately, without the confirmation. After shutdown, heph restores your terminal and prints the active session's latest saved metadata to stderr:

Session ended
  ID: 0195e123-4567-7abc-8123-456789abcdef
  Name: fix-parser
  Base: main
  Branch: heph/fix-parser

The ID is the full UUID you can pass to heph --continue. An unnamed session shows <unnamed>; a base or publication branch not yet chosen shows <unset>. This summary also appears after leaving with two presses of Ctrl-D, but not on startup failure or unexpected event-loop termination.

/clear starts the model fresh on the same conversation: when the work so far is done and the next thing is a new thread, the next turn is sent nothing of the earlier ones, which makes every round of it cheaper. Live token/cache counters restart, but daily, active-session, and historical spend do not. The worktree, uncommitted work, and the history are kept; the screen empties, and the next heph shows the earlier turns again above a line marking the clear. Use /clear <prompt> to clear and immediately send the prompt; a refused clear sends nothing. A running turn or pending review must finish first. /help and ? on an empty input show the key bindings. /commit commits what the last turns applied (Committing). /plan, /design, and /code switch plan and design mode on and off (Plan Turns, Design Turns). Those are the slash commands so far; anything else answers not a command yet.