Unified Input
One input bar for every agent: the @ / and $ triggers, file reference chips, drag and drop, multi-line editing, voice, history and drafts.
Overview
Every agent terminal in Daintree uses the same input bar. It is one rich-text editor with file references, command discovery, chips, voice, multi-line editing, history and per-terminal drafts. You type the same way regardless of which agent you are talking to; Daintree resolves the per-agent differences on the way to the process.
The bar sits under the terminal, not in place of it. Everything you send still goes through the agent's own CLI, so the agent's TUI, its own key handling and its own slash commands all keep working.
Three triggers
Typing a trigger character opens a completion menu. Which triggers are live depends on the agent in the pane, because completion discovery is declared per agent rather than hard-coded.
| Trigger | Surfaces | Available on |
|---|---|---|
@ | Files in the worktree, plus Daintree's own reference tokens | Every agent |
/ | The agent's slash commands, its custom commands, and its skills | Every agent (the list is empty for agents that declare no sources) |
$ | Codex Skills and Plugins | Codex only: it is the one agent that declares a $ source |
Ranking is trigger-neutral: a leading /, $ or @ is stripped before matching, so typing $plug and plug rank the same candidates the same way.
@ file references
Type @ followed by part of a filename to search the worktree. The search covers files git tracks and files it does not yet (the backend asks git for cached and untracked entries with standard excludes applied), so a file you created a minute ago and have not staged is completable, while anything .gitignored stays out. In a plain folder that is not a git repository, the same search falls back to a filesystem walk with its own skip list.
Supported syntax
@src/index.ts: reference a file by path@"path with spaces/file.ts": quote paths containing spaces@'single-quoted.ts': single quotes work too
The @ trigger also owns four reserved tokens that are not file paths at all. They are expanded at send time, so what the agent receives is the content, not the token:
| Token | Expands to |
|---|---|
@terminal | The terminal's output |
@selection | Whatever is selected in the terminal |
@diff | The worktree's unstaged changes |
@diff:staged / @diff:head | Staged changes, or changes against HEAD |
@terminal and @selection need four characters typed before they claim the query, so @te still searches for files. The menu title changes to say which provider has claimed it: Files, Diffs, Terminal output, Terminal selection, Commands, or Capabilities.
How a reference reaches the agent
An @file token is not passed through verbatim. Daintree relativizes the path against the terminal's live working directory, read at the moment you send, so a cd since the panel opened is accounted for. A relative path costs no tokens on a prefix the agent already knows, survives the prompt being replayed in another worktree, and is what a fleet broadcast needs so each pane means its own copy of the file.
Three adjustments keep that safe: a file outside the working directory stays absolute, because relative would not resolve for it; a path that would collide with a reserved token gets a ./ prefix, so a file literally named terminal is not read as "paste the terminal buffer"; and a path containing quotes, whitespace or trailing punctuation is wrapped in @"…".
Chips
Anything atomic in the draft renders as a chip: file references, dropped and pasted files, images, slash commands, and the diff, terminal and selection tokens. Every chip has a hover tooltip and an inline × to remove it.
A typed or completed @path chip shows the whole path and wraps rather than truncating. Truncation hid the tail, which meant two files in different directories with the same name (or two long paths differing only at the end) rendered identically, and you could not tell which one you had attached. In a narrow pane the chip shrinks and wraps instead of blowing the pane out.
A drop or paste pill is different: it shows the file's basename with a file icon, and carries the absolute path in its tooltip and accessible name.
Backspace against a chip takes two presses. The first selects and stages it with a pending-delete style; the second removes it. Removal resolves by document position rather than by path, so if you have two chips for the same file, the one you targeted is the one that goes.
A slash-command chip is only atomic once the command is recognized. A token that is still being typed, or mistyped, stays plain editable text with a "no match" hint, so a finger slip is fixable with one Backspace instead of nuking the whole token.
Dragging and pasting files
Copy files in Finder or Explorer and paste with Command-V Control-V Control-V , or drag them straight onto the input bar. Each file becomes its own chip, inserted consecutively at the cursor. Images are handled separately and get an image chip with a thumbnail. Dragging a file out of Daintree's own File Browser works the same way.
Two behaviors worth naming because they used to surprise people:
- A drop inserts the reference and nothing else. The editor used to also read the dropped file and dispatch its text alongside the chip, so dropping a large file pasted the whole thing into your prompt. The drop handler now claims file drags outright, and the chip path is the only producer. Non-file drags are untouched: dropping text still inserts text, and moving a selection within the input still moves it.
- Drop and paste emit the same cwd-relative
@fileform that autocomplete produces. Three routes to the same reference can no longer disagree about what it looks like.
Dropping onto the terminal body (rather than the input bar) is agent-aware. Daintree reads what is actually running in the pane, not what the panel was launched as: an agent gets the same cwd-relative @path token every other route produces, while a plain shell gets an absolute, shell-escaped path, because that is what a shell can act on and a relative path only resolves if the shell's own directory still matches.
Right-clicking a selection in the composer that resolves to a path offers View file and Open folder. A selection that is not a path suppresses the menu entirely rather than showing an empty one.
/ commands
Type / at the start of the input to see what the focused agent offers. Enter on a / item runs it rather than inserting it; Tab completes without executing.
Built-in commands
Each agent CLI has its own set (/help, /clear, /compact, /model, /diff and so on) and the menu shows what applies to the agent in the pane.
One command is Daintree's own and is shared across both Claude Code and Codex: /goal. On Claude it sets a goal that must be met before the agent stops; on Codex it manages the session goal: edit, pause, resume, clear.
Custom commands and skills
Only three agents declare completion sources: Claude (on /), Gemini (on /), and Codex (on both / and $). Every other agent still gets Daintree's own @ providers and a / menu, but that menu is seeded from the built-in catalog only. This is data-driven off each agent's declared sources rather than an allowlist of agent ids, so an agent that grows a command directory gets discovery without a code change here.
| Agent | Source | Where it looks |
|---|---|---|
| Claude Code | Commands | .claude/commands/*.md, with the description read from YAML frontmatter |
| Claude Code | Skills | .claude/skills/*/SKILL.md, badged Skill |
| Gemini CLI | Commands | .gemini/commands/*.toml |
| Codex | Skills ($) | Codex's system and user skill directories, plus .agents/skills in the project, badged Skill |
| Codex | Plugins ($) | Codex's own plugin registry, badged Plugin |
Each directory source is searched across an eight-location ladder, not just two: the project, then the user's native config directory (honoring the agent's config-directory environment variable), then the XDG location, then the platform-wide locations. Precedence runs built-in, then global, then user, then project, later winning, so a project command overrides a user one of the same name, which overrides a global one.
Codex has no custom slash-command directory. Both .codex/commands and ~/.codex/prompts were retired upstream and neither exists in current Codex. Its custom surface is the $ trigger. If you have an older Daintree page or blog post bookmarked that says otherwise, that is the change.
Codex's $ menu surfaces Skills and Plugins with a category badge on each row. It does not surface Codex Apps: those are resolved server-side with no local manifest for Daintree to discover, so nothing populates that category today.
The daintreehq/commands repo holds a curated set you can clone into your global commands directory; they appear alongside your own. Claude Code only at the moment.
Multi-line and the expanded editor
Enter submits. Shift+Enter and Option-Enter Alt-Enter Alt-Enter insert a newline.
The bar grows as you type up to a fixed 160px height (roughly eight lines at the default font size) and scrolls after that. It is a pixel cap rather than a line count, so it holds fewer or more lines as you change the terminal font size.
Growing the input does not knock the terminal above it out of follow-bottom. A terminal pinned to the bottom stays pinned as the bar expands, rather than jumping into scrollback mid-sentence.
There is an expanded editor: a full-height modal titled "Expanded Editor" that reparents the same editor instance, so undo history and everything in the draft survives the move in both directions. Its binding, Shift-Command-E Control-Shift-E Control-Shift-E , is currently claimed by the global Send selection to another terminal action, which resolves first. To reach the expanded editor, rebind one of the two in Settings > Keyboard Shortcuts.
Fleet broadcast tinting
When the focused pane is armed and two or more panes are in the fleet, the input shell borders and rings amber, matching the fleet drafting pill. The shell itself says "Enter broadcasts" at the point where you are typing, rather than leaving that fact somewhere else on screen. Follower panes are mirrored keystroke by keystroke but are not tinted: only the pane you are typing in claims the warning. See Fleet Broadcasting.
Voice input
With voice configured, a microphone button appears in the input bar. Click it to start, or press Shift-Command-V Control-Shift-V Control-Shift-V , which toggles dictation into whichever panel input has focus. Transcribed text is inserted straight into the bar.
While recording, an animated orbit ring plays around the microphone and the input border turns accent-tinted. Live interim text appears at reduced opacity and solidifies once confirmed. Text under AI correction shows a dotted underline while it is being processed: the correction pass is still there even though the model dropdown that used to sit beside it is gone, because both model axes are now single-valued.
Corrections you make by hand to dictated text feed a dictionary at send time, so a name Daintree keeps mishearing gets learned.
Prompt history
There are two history stores, and they behave differently on purpose.
| Arrow recall | Command-R Control-R Control-R palette | |
|---|---|---|
| Scope | Per terminal, within a project | Per project |
| Size | 100 entries | 100 entries |
| Deduplication | Full, most-recent wins | On exact text, newest first |
| Persistence | In memory only | Persisted across restarts |
The Command-R Control-R Control-R palette merges its writes three-way against a baseline, so two windows open on one project do not clobber each other's history.
ArrowUp behaves differently on an agent pane. With an empty draft, and when you are not already mid-recall, ArrowUp is forwarded to the agent's own TUI instead of recalling host history. Codex's /model picker was the case that forced this. Once you are mid-recall, the arrows navigate host history as usual, and Command-R Control-R Control-R is always the way in. ArrowDown is unchanged.
A few other keys reach the process directly from an empty draft: ArrowLeft and ArrowRight, and Ctrl+C when nothing is selected, so copy still works when something is.
Drafts and the stash
Start typing in one terminal, switch to another, and your draft is kept exactly as you left it. Drafts are scoped by both project and terminal, so switching projects and coming back restores what you were writing. A typed but unsent draft also survives closing the window.
The stash is for deliberately setting something aside. Shift-Command-S Control-Shift-S Control-Shift-S stashes the current input and an archive icon appears in the bar; Shift-Command-X Control-Shift-X Control-Shift-X restores it. Use it to park a half-written prompt, send something else, then pick the first one back up. Stashes are scoped per project.
Input adaptation
Daintree adapts how your text reaches each CLI. None of this needs your attention (type and press Enter), but it is worth knowing it happens.
- Bracketed paste is used for agents that support it, triggered by any newline in the text or by a payload over roughly 200 characters. Agents that do not support it get a soft-newline sequence instead, plus a wait for output to settle before the Enter.
- Resolution is against the live detected agent, not the launch agent. A terminal launched as an agent whose process has since dropped back to a shell gets plain shell behavior, because that is what is actually running.
- Line endings are normalized per agent, and submission timing is tuned per agent.
Which agents support what is agent capability data and lives on Agents.
Autocomplete behavior
The file search is debounced, which means results can lag your typing by a few keystrokes. To stop a fast Enter or Tab accepting a match that belonged to an older query, stale rows are marked and cannot be accepted. Press Enter against a stale top match and it falls through to the normal send path, so your literal text wins rather than an outdated completion. Only the async file search can go stale: a static @diff list or a Codex $ list is never dimmed.
Escape cascades rather than doing one thing: it cancels a pending voice submit, then closes the autocomplete, then collapses the expanded editor, and only then forwards to the process.
The command picker
The ❯ button at the left of the input bar opens Daintree's own command picker, which is distinct from the agent's slash commands. A command whose result carries a prompt is sent straight through to the agent rather than being inserted for you to confirm.
Keyboard shortcuts
These act on the input bar while a panel has focus.
| Shortcut | Action |
|---|---|
| Enter | Submit, or run the selected / command |
| Shift+Enter / Alt+Enter | Insert a newline |
| Tab | Complete the selected item without running it |
| Command-V Control-V Control-V | Paste; files and images become chips |
| ArrowUp / ArrowDown | Move through the autocomplete, or recall history from an empty draft (see the note above for agent panes) |
| Command-R Control-R Control-R | Open the prompt history palette |
| Shift-Command-S Control-Shift-S Control-Shift-S | Stash the current input |
| Shift-Command-X Control-Shift-X Control-Shift-X | Restore the stashed input |
| Shift-Command-V Control-Shift-V Control-Shift-V | Toggle voice dictation into the focused panel input |
| Shift-Command-E Control-Shift-E Control-Shift-E | Send the terminal selection to another terminal |
| Control-Tab Control-Tab Control-Tab / Control-Shift-Tab Control-Shift-Tab Control-Shift-Tab | Focus the next or previous panel |
| Escape | Cancel voice, close the autocomplete, collapse the expanded editor, or forward to the process, in that order |
On Windows and Linux, Ctrl+Shift+V is reserved for the terminal's own paste while a terminal viewport has focus, following the usual terminal convention. It does not toggle dictation there. See Keyboard Shortcuts for the full reference.
For app-wide shortcuts covering panel navigation, worktrees and window management, see Keyboard Shortcuts.