15 KiB
Helder Functional Design
This document describes how Helder behaves: every panel, interaction, and state, at the functional and UX level. It does not cover technical architecture. It is written to match the agreed user interface exactly.
Helder is a dark, AI-first desktop code editor for reviewing and navigating code written by an AI agent. It opens one project per window and has no light mode and no theme toggle.
1. Window layout
The window has three horizontal regions stacked top to bottom:
- A top bar.
- The main body, split into four resizable columns.
- A bottom status bar.
The four columns of the body, left to right, are:
- Source Control
- Explorer (file tree)
- Editor (tabs and code)
- Agent and Terminal, a single column split into two stacked panes: the Claude agent pane on top and a shell terminal below it.
Every boundary between panes is a draggable splitter. The vertical splitters between the four columns adjust their widths. The horizontal splitter between the agent pane and the terminal pane adjusts their heights. Splitter positions persist across launches. Panes have sensible minimum widths and heights so they cannot be collapsed to nothing by dragging.
The interface is dark only. Code is always syntax highlighted, in every panel and every view.
2. Top bar
The top bar contains, left to right:
- The Helder mark and name.
- A breadcrumb showing the path to the active file, for example
console / src / Http / Controller / UserController.php. The breadcrumb is display only for now. It is not clickable and does not navigate. - On the right, two controls: Go to File (
Cmd/Ctrl+P) and Search (Cmd/Ctrl+F). Both open overlays described in section 9.
3. Source Control panel
The leftmost column. It shows the working state of the project's git repository and is where staging and committing happen.
Header
A SOURCE CONTROL header with a count badge showing the total number of changed files (staged plus unstaged).
Commit area
Directly under the header:
- A single-line commit message input.
- A Commit button whose label includes the staged count, for example
Commit 2. - The Commit button is enabled only when there is at least one staged change and the message field is not empty. Clicking it commits the staged changes with the typed message, clears the message field, and moves the committed files out of the staged section. The working tree updates accordingly.
Sections
Two stacked sections, each with its own header and count:
- STAGED CHANGES (n) on top, listing files that are staged.
- CHANGES (n) below, listing unstaged working-tree changes (added, modified, deleted).
Row anatomy
Each row, identical in both sections:
- A status letter on the far left:
Aadded,Mmodified,Ddeleted, each in its own color (added teal, modified amber, deleted amber-deep). - A file-type icon, then the file name.
- The dimmed relative path, aligned to the right of the name.
- Change counts at the far right: additions in teal (
+N) and deletions in amber-deep (-N). - Deleted files are shown with the file name struck through and dimmed.
- Rows have default, hover, and selected states. The selected row is the file currently open in the editor.
Interactions
- Left-click a row opens that file in the editor, in Actual. It does not open the full-screen Diff.
- Right-click a row opens a context menu, designed to grow over time:
- In CHANGES (unstaged): Open diff, Stage file, and Discard changes.
- In STAGED: Open diff, and Unstage file.
- Open diff is the explicit way into the full-screen Diff (section 5).
- Hover quick action: on hover, an unstaged row shows a
+to stage it in one click, and a staged row shows a-to unstage it. - Optional section actions: Stage all on the CHANGES header and Unstage all on the STAGED header.
- Discard is a destructive action. It asks for confirmation first (controlled by
git.confirmDiscard, default on). Discarding reverts a modified file to its committed state and restores a deleted file. - Staging and unstaging do not ask for confirmation by default (
git.confirmStageandgit.confirmUnstage, default off).
Branch summary bar
At the very bottom of this column, a bar shows the current branch name and the total line changes across the working tree, for example feat/payments-balance +50 -38. This bar is display only. It does not switch branches.
Empty states
- When nothing is staged, the STAGED section shows a dimmed line:
No staged changes. - When the working tree is clean, the CHANGES section shows a dimmed line:
Working tree clean.
Scope note: git in this version covers staging, unstaging, committing, and discarding. Push, pull, fetch, and branch switching are not part of this version.
4. Explorer panel
The second column. A standard project file tree.
- An
EXPLORERheader. - Folders expand and collapse. Files and folders use type icons.
- Files that have changes show the same status letter as the Source Control panel (
A,M,D) on the right of their row. - Left-click a file opens it in the editor. The selected file is highlighted.
- The tree hides paths matched by
files.excludeand, whenfiles.followGitignoreis on, paths ignored by git. - Right-click a file offers Copy reference, which copies the file's project-relative path to the clipboard (the file-level form of the editor's Copy reference).
5. Editor
The third and widest column. Tabs on top, a view toolbar under them, and the code below.
Tabs
- Each open file is a tab showing its type icon and name.
- A tab opened on a changed file shows a small DIFF badge.
- A tab shows an unsaved indicator (a dot in place of the close control) when the file has unsaved edits. This matters because auto-save is off by default (
editor.autoSave). - Each tab has a close control (
x). Clicking a tab switches to it. Closing a tab with unsaved edits prompts to save or discard.
View toolbar
A row under the tabs:
- On the left, a status summary for the active file, for example
Modified +6 -2. - On the right, a segmented control: Actual | Original | Diff, with a fourth segment, Preview, on markdown files only. The active segment is highlighted. This control appears only for files that have changes relative to their committed state. Its starting mode follows
git.defaultDiffMode(defaultActual).
View modes
All are presentations of the same change set for the file:
- Actual: the current, editable version of the file. It marks the changed lines in place, with a teal tint, a 2px teal left rule, and a teal line number. There is no sign column, no
+or-pair, and no removed line inline. A pure deletion has no current line to mark, so the neighbouring current line carries a 2px amber-deep rule on its top edge, or on its bottom edge at the end of the file. - Original: the file as it was before the change, read-only. Changed and removed lines get an amber-deep bar in the left gutter. No inline plus or minus markers.
- Diff: the editor expands to full screen, covering the other columns. The original file is on the left and the updated file is on the right, lines aligned.
Esc, or a collapse control in the corner, returns to the normal layout and the previously active mode. - Preview: markdown files only. It shows the rendered document instead of the source.
In Actual, the removed lines appear on a click. The user clicks a marked line, and a panel opens over the agent and terminal column: 496px wide, with a 2px amber-deep left border. The panel holds the whole original file, and it scrolls so that the previous version of the picked line sits level with the picked line. A second click on the same line closes the panel, and so does a click anywhere off the code. Hover does nothing, and there is no animation.
Shared rules: teal is what the file holds now, amber-deep is what it held before. There is no green and no red anywhere. Syntax highlighting stays on in all modes. Line numbers follow editor.lineNumbers (default absolute).
Editing behavior
- A file with no changes opens directly in a normal editable view with no view-mode control, since there is nothing to diff.
- Editing follows the editor settings: indentation, indent width, trim trailing whitespace, insert final newline, word wrap, indent guides, whitespace rendering, and active-line highlight, all read from configuration (section 10).
- Word wrap follows
editor.wordWrap:markdown(default),on, oroff. When it is on, a line too wide for the pane folds onto the next row instead of scrolling sideways. Only the first row of a folded line carries a line number; the rows below it stay blank. The original panel folds at the same points as the editor, so each old line stays level with its current line. Diff never wraps, because its two panes align row by row.
Right-click in code
Right-clicking inside the code area, with or without a selection, shows a context menu with exactly two items:
- Copy reference: copies a reference to the clicked location to the clipboard. With no selection it is path plus single line, for example
src/Http/Controller/UserController.php:42. With a selection it is path plus start and end line, for examplesrc/Http/Controller/UserController.php:42-58. The path is project-relative. - Pass on to Agent: opens a small inline input popup anchored near the click or selection, with a single optional text field. On confirm (
Enter), it composes one line, the typed text followed by the same reference, and inserts it into the agent pane's input. The insert does not submit. It lands as a new, unsubmitted line and the cursor sits on a fresh line, so the action can be repeated to stack several references before the user sends.Esccancels with no insert. An empty field passes the bare reference.
File-state behavior in the view modes
- Added file: only the Actual content exists. Actual marks every line as added, Original is empty, and Diff shows an empty left pane with the file on the right.
- Deleted file: only the Original content exists. Actual is empty and has no line to mark, and Diff shows the file on the left with an empty right pane.
- Binary or unsupported file: cannot be shown as editable text. The editor shows a short placeholder stating the file cannot be displayed, and the view-mode control is not shown.
6. Agent pane
The top pane of the fourth column.
- A
claudeheader with anagent sessionlabel. - It is a single terminal running the configured agent command. On launch it auto-runs that command when
ai.autoLaunchis on (default), usingai.command(defaultclaude). - The pane shows the live agent session and has an input line at the bottom.
- It receives the Pass on to Agent inserts from the editor: text arrives in the input as content, never as a submitted command, so the user can stack several and send when ready.
- It is one terminal only. There are no additional agent tabs or sessions in this version.
7. Terminal pane
The bottom pane of the fourth column.
- A header showing the shell and working directory, for example
zshand the project path. - It is a single shell terminal. It uses the operating system default shell, or the override in
terminal.shellwhen set. - It behaves as a normal terminal for that shell.
- It is one terminal only. There are no additional terminal tabs in this version.
8. Status bar
A bar across the bottom of the window. All items are display only for now; none are clickable.
- On the left: the current branch and the working-tree line totals, for example
feat/payments-balance +50 -38. - On the right: cursor position (
Ln, Col), indentation (Spaces: 4), encoding (UTF-8), language (PHP), and the active view mode (Actual).
9. Global interactions
Go to File (Cmd/Ctrl+P)
Opens a fuzzy file-open overlay. The user types part of a file name or path, the list narrows as they type, and selecting a result opens that file in the editor. Esc closes the overlay.
Search (Cmd/Ctrl+F)
Opens a modal search overlay that searches both file contents and file names at once. The overlay covers 90 percent of the application width and is centered over a dimmed background.
Inside the overlay:
- A query field at the top.
- Two result columns below:
- Left column, 70 percent width: matches found inside files (content search), grouped by file, each match shown as the matching line with the query highlighted in context.
- Right column, 30 percent width: files whose name or path matches the query.
- Selecting a content result opens the file and jumps to that line. Selecting a file-name result opens that file.
- When nothing matches, each column shows a brief no-results message.
Esccloses the overlay. The respected excludes are the same as the Explorer (files.excludeand, when on, gitignore).
Pane resizing
Dragging any splitter resizes the adjacent panes. Positions persist across launches.
Session restore
When session.restoreOnLaunch is on (default), reopening a project restores the previously open tabs, the active tab, and the pane and splitter layout.
10. Configuration and theming
Settings and theming are project-scoped and live in a .helder folder in the project root.
.helder/config.json: the user's settings. It is sparse and holds only the values the user has overridden..helder/config.default.json: the full set of defaults, with a default for every value. Helder regenerates this file on launch from its built-in defaults, so it always matches the installed version and serves as live documentation of every available setting. The app never reads user edits from this file.- Effective value of any setting: the value from
config.jsonif present, otherwise the value fromconfig.default.json, merged key by key. .helder/theme.css: a custom theme expressed as CSS, applied on top of the built-in dark theme. The code font and font size live here, not in the config files.
Settings that affect behavior described above include indentation and editor display, file and search excludes, the default diff mode, git confirmation prompts, the terminal shell override, the agent auto-launch and command, and session restore.
11. States and edge cases summary
- No project open: the window shows an empty state inviting the user to open a project folder.
- Clean working tree: Source Control shows its empty-section messages; the Explorer still shows the full tree.
- Unchanged file open: normal editable view, no view-mode control.
- Added or deleted file: view modes behave as described in section 5.
- Binary or unsupported file: placeholder, no view-mode control.
- Search with no matches: per-column no-results messages.
- Agent command not available: the agent pane is a terminal, so a missing or failing command surfaces as ordinary terminal output in that pane.
Open assumptions to confirm
- In the Search overlay, content matches are on the left (70 percent) and file-name matches on the right (30 percent). Confirm this assignment, or swap the two sides.
- Tabs show an unsaved indicator because auto-save defaults to off. Confirm that behavior is wanted.
- The Explorer right-click offers a file-level Copy reference (path only), consistent with the editor's Copy reference. Confirm this is in scope.