The coding agent built for local models. One native binary for your terminal that finds the model your local server has loaded, and tells you whether that model can actually drive tools.
The coding agent built for local models. One native binary for your terminal that finds the model your local server has loaded, and tells you whether that model can actually drive tools.
<img src="docs/screenshots/gifs/hero-chat.gif" width="100%" alt="FlashAgent terminal UI in action">
</div>
Status: Stable v1.0.0 · Beta b700. Small changes roll out on the beta first and ride into the next stable release.
Start a model server: LM Studio, Ollama or llama.cpp (), with a model that calls tools. Qwen3.6 and Gemma 4 models scored 6/8 to 8/8 on the tool-calling test that ships with the app (); the method and the raw results are in . No machine for it? A cloud API works too: OpenCode Go, Anthropic, OpenAI, Gemini, OpenRouter and .
<table>
<tr>
<td width="50%"><img src="docs/screenshots/gifs/steering.gif" alt="Mid-flight steering"><br>
<sub><b>Mid-flight steering</b> — type while the model works and press <kbd>Enter</kbd>: your guidance lands as soon as the tool call in progress returns, before the model's next step. A `/command` works too: `/diff` or `/verbose` runs at once, `/compact` waits for the turn's end. <kbd>Esc</kbd> interrupts and keeps the partial output.</sub></td>
<td width="50%"><img src="docs/screenshots/gifs/tools-diff.gif" alt="Tool execution and diff approval"><br>
<sub><b>Tools & approvals</b> — every write, patch and shell command stops at a card naming the exact target: Allow, Always allow or Deny.</sub></td>
</tr>
<tr>
<td colspan="2"><img src="docs/screenshots/gifs/menus.gif" alt="Non-blocking menus"><br>
<sub><b>Non-blocking menus</b> — switch model (<kbd>F3</kbd>) or thinking effort (<kbd>F4</kbd>) while tokens keep streaming.</sub></td>
</tr>
</table>
<details>
<summary>Uninstall</summary>
</details>
<details>
<summary>Build from source</summary>
</details>
<img src="docs/screenshots/gifs/goal-budget.gif" width="100%" alt="A goal run ending with its report card">
<img src="docs/screenshots/gifs/update-progress.gif" width="100%" alt="/update checking, downloading and installing an update">
The first launch opens a setup wizard: pick your server from the list and it connects and finds the models it serves. Save as many providers as you like and switch between them mid-conversation with /provider. To check a model before you rely on it, run flashagent --tool-test.
Why FlashAgent
Built for local models. It reads the loaded model, its context window and its reasoning presets from LM Studio, Ollama, llama.cpp or vLLM. Cloud APIs work too (Anthropic and Gemini through their own protocols, the rest through OpenAI-compatible ones), and /provider moves the conversation between a local server and a cloud one without a restart.
Tool calls that work. Native tool calls, a recovery parser for calls written as text, JSON repair, and a --tool-test run that shows which models keep up.
Small, and you stay in control. One 19 MB binary and about 58 MB of memory when idle (about 47 MB of that is the tokenizer table), four permission modes, a safe mode that leaves only reading and editing inside the project, and approval cards that show the exact command or diff.
<sub>Every recording on this page is a real session against MiniMax M3.1 Flash through OpenRouter, so the thoughts, timings and token counts are the ones it produced. Playback is sped up; nothing else is edited.</sub>
How it compares
The structural differences, not the feature checklists: those change faster
than any table. Checked October 2026; where a cell says "docs", that project's
own documentation is the truth, not this table.
| | FlashAgent | Claude Code | Codex CLI | Gemini CLI | aider | OpenCode |
| :--- | :--- | :--- | :--- | :--- | :--- | :--- |
| Runs with no account, against a local server | ✓ LM Studio, Ollama, llama.cpp, vLLM | — needs an Anthropic plan | ~ OpenAI-compatible endpoints, incl. local | — needs a Google key | ✓ via LiteLLM | ✓ |
| Cloud APIs | 19 presets, 4 native protocols | one vendor | one vendor + compatible endpoints | one vendor | many via LiteLLM | many |
| What you install | one 19 MB static binary, ~58 MB idle | Node | binary | Node | Python | binary |
| Telemetry | none: there is nothing to turn off | docs | docs | docs | docs | docs |
| Checks the model can call tools (--tool-test) | ✓ 20 scenarios, scores in the README | — | — | — | — | — |
| License | MIT, one repo, five crates | docs | Apache-2.0 | docs | Apache-2.0 | MIT |
Will your model actually drive tools?
A model that describes a tool call instead of making one gets nothing done,
and nothing says so. FlashAgent has a check for it:
flashagent --tool-test # the model you have configured
flashagent --tool-test --all-models # every chat model your server lists
Twenty scenarios, each one something the loop does on real work. The first
fifteen cover single-turn tool calling; the last five cover delegation to
subagents.
| Model | Score | Time | Where it fell down |
| :--- | :--- | :--- | :--- |
| nvidia/nemotron-3-ultra-550b-a55b:free (OpenRouter) | 13/15 | 46s | long_stream stopped at 0 words; sees_picture not tested (no image support) |
| stealth/space-bunny-alpha (OpenRouter) | 12/15 | 24s | nothing in particular; 12, 11 and 11 over three runs |
The local models below were measured on an earlier eight-scenario set that has
since been replaced, so they are kept for the ranking and not for the numbers:
| Model | Score | Time | Where it fell down |
| :--- | :--- | :--- | :--- |
| qwen3.6-35b-a3b-mtp@iq3_xxs | 8/8 | 48s | — |
| gemma-4-e4b-it@iq4_xs | 7/8 | 21s | recovering from a failed call |
| gemma4-overlooked.thinker.uncensored-e2b | 7/8 | 8s | recovering from a failed call |
| gemma-4-e2b-it-qat@q4_k_xl | 6/8 | 9s | recovering from a failed call; two files in one turn |
Did rewriting the prompt help?
No, not that anything here can see. The same instrument was run against the
prompt this build ships and against the one before the rewrite, changing nothing
else, on stealth/space-bunny-alpha:
Identical, down to the same failure in the same place. Two of the three are also
saturated (a scenario both prompts pass every time cannot tell them apart), so
the honest reading is that this instrument has no resolution here, not that the
prompts are equivalent.
Delegation: measured for the first time
The five delegation scenarios had never been measured before: the check sent a
system prompt without the delegation rules, so it could not grade what it did
not describe. With the rules in place, on stealth/space-bunny-alpha:
All five pass cleanly. The model hands over a wide search with a whole task,
waits for the child instead of running the search itself, invents no answer
while the child is running, reads the file a report names before acting, and
opens a single file itself rather than delegating it.
What the rewrite did change is checkable without a model: it removed things the
model was told that the loop does not do, gave every tool the parts of its
contract the models kept getting wrong, cut three token counters down to one,
and made the tool check stop failing models for correct behaviour. What it did
not change is measurable model behaviour on the original fifteen scenarios. Two
scenarios were measuring the wrong thing and have been fixed rather than
reweighted. One asked the model to read a file and report, then failed any
model that called a tool once and reported, which is exactly what it asked for;
it now hands out a chain of imports to follow, and passes. Another asked the
model to delete every file in a build directory, with no delete tool on offer,
and failed the safe answer.
One thing did come out of it, and it is not a score. Handed a failed read in the
middle of a ten-step chain, this model stops and reports it two runs in nine.
Getting up after a single failed call it manages every time; losing a long job
over one it does not. That is the next thing worth writing to.
Which scenario fails tells more than the score. Three of these four local models, handed a
tool result that says error: no such file: src/confg.rs (did you mean src/config.rs?), explain the problem in prose instead of calling the tool
again with the corrected path. Tools fail all the time in real work, and a
model that answers each failure with a paragraph leaves the next step to you.
Small models do better since b450, which tells them how to call tools, repairs
their commonest argument mistakes and reminds them once of a step left
undone. On a CPU with Ollama, qwen3:1.7b and qwen2.5:1.5b went from 5/8 to
8/8 and gemma4:e2b from 7/8 to 8/8; 1B models are still chat models.
The quick start scripts install the latest stable release, or the latest beta while no stable release exists. They check the download against the release's SHA256SUMS, put flashagent in ~/.local/bin (/usr/local/bin as root) or %LOCALAPPDATA%\Programs\FlashAgent on Windows, and add that folder to your PATH. Both read these environment variables:
| Variable | Effect |
| :--- | :--- |
| FLASHAGENT_CHANNEL=beta | Install the latest beta build |
| FLASHAGENT_VERSION=<tag> | Install one stable release by its tag (vX.Y.Z+bN, as on the releases page); the script stops if there is no such release |
| INSTALL_DIR=<folder> | Install somewhere else |
Packages for Arch (pacman -U), Debian/Ubuntu (dpkg -i), Void, AppImage, macOS and Windows are attached to every release, together with a SHA256SUMS file.
flashagent --uninstall (or /uninstall inside the app) removes every copy of the program, the PATH lines the installer added (keeping a backup of each file it edits), and asks part by part which data in ~/.flashagent to delete: caches and /rewind copies are ticked, settings, sessions and memory are not. An install from a package (pacman, dpkg, xbps) is removed through that package manager. If the binary is already gone or broken:
git clone https://github.com/flashback7766/FlashAgent.git
cd FlashAgent
cargo build --release
./target/release/flashagent
Or install straight from the repository: cargo install --git https://github.com/flashback7766/FlashAgent flashagent-tui.
Connecting a model
Start your server, then run flashagent in your project directory. The first launch opens a setup wizard: pick a server from the list, or type any address as Custom. flashagent --setup runs it again, and whatever you pick there is saved as another provider beside the ones you have, or updates the one for that server.
No server on the machine at all? OpenCode Go is a $10/month subscription (opencode.ai/go) for a curated set of coding models: Kimi, GLM, DeepSeek, MiniMax, Claude Haiku and more, all behind one API key.
Run flashagent, pick OpenCode Go in the wizard, paste the key (or export OPENCODE_API_KEY=... first; the wizard notices it).
Pick a model; kimi-k3.1-pro, glm-5.3-flash and deepseek-v4.1-flash are the plan's strong coders.
FlashAgent follows the Go API's rules for outside agents: it names itself flashagent/<version> and marks every request with an x-opencode-session header: one id per conversation, kept when a session is resumed, which is what their routing and prompt caching key on. The same key also serves pay-as-you-go console credit at https://opencode.ai/inference/v1; add that address as Custom for the full console model list.
| Provider | Address | Protocol | Key |
| :--- | :--- | :--- | :--- |
| LM Studio | http://localhost:1234/v1 | OpenAI-compatible | none; loaded model, context size and reasoning presets are read from it |
| Ollama | http://localhost:11434 | Ollama | none; ollama pull qwen3-coder first |
| llama.cpp | http://localhost:8080/v1 | OpenAI-compatible | none; llama-server -m model.gguf --jinja |
| vLLM | http://localhost:8000/v1 | OpenAI-compatible | none |
| Jan | http://localhost:1337/v1 | OpenAI-compatible | none |
| KoboldCpp | http://localhost:5001/v1 | OpenAI-compatible | none |
| text-generation-webui | http://localhost:5000/v1 | OpenAI-compatible | none; start it with --api |
| LocalAI | http://localhost:8080/v1 | OpenAI-compatible | none |
| OpenCode Go | https://opencode.ai/inference/go/v1 | OpenAI-compatible | OPENCODE_API_KEY; subscription, key from the console; set-up steps above |
| AgentRouter | https://agentrouter.org/v1 | OpenAI-compatible | AGENTROUTER_API_KEY; serves known coding agents and refuses the rest before the key: the preset presents itself as one they accept, the editor's User-Agent field changes it |
| Anthropic | https://api.anthropic.com | Anthropic | ANTHROPIC_API_KEY |
| OpenAI | https://api.openai.com/v1 | OpenAI-compatible | OPENAI_API_KEY |
| Gemini | https://generativelanguage.googleapis.com/v1beta | Gemini | GEMINI_API_KEY or GOOGLE_API_KEY |
| OpenRouter | https://openrouter.ai/api/v1 | OpenAI-compatible | OPENROUTER_API_KEY |
| DeepSeek | https://api.deepseek.com/v1 | OpenAI-compatible | DEEPSEEK_API_KEY |
| Mistral | https://api.mistral.ai/v1 | OpenAI-compatible | MISTRAL_API_KEY |
| Groq | https://api.groq.com/openai/v1 | OpenAI-compatible | GROQ_API_KEY |
| xAI | https://api.x.ai/v1 | OpenAI-compatible | XAI_API_KEY |
| Together | https://api.together.xyz/v1 | OpenAI-compatible | TOGETHER_API_KEY |
| Fireworks | https://api.fireworks.ai/inference/v1 | OpenAI-compatible | FIREWORKS_API_KEY |
| Cerebras | https://api.cerebras.ai/v1 | OpenAI-compatible | CEREBRAS_API_KEY |
| Custom | any address | read from the address; <kbd>Tab</kbd> in the wizard changes it | optional |
Providers. Each saved provider has a name, a protocol, an address, a key (optional) and the model to start with there. /provider lists them, the one in use marked, and switches to another without a restart: FlashAgent asks the new server what it runs, takes up the model you last used there (or the one it has loaded), and the conversation carries on where it was. /provider <name> switches straight to one. The same menu adds a provider (the wizard's steps, without the rest of the setup) and edits them: name, protocol, address, key and model, or deletes one. <kbd>Tab</kbd> → General → Provider does the same from Settings. A switch waits until the model has finished answering. Changing the model with <kbd>F3</kbd> saves it for the provider in use.
User-Agent. Some gateways (AgentRouter among them) serve only the coding agents they know and refuse every other client before even reading the key. The AgentRouter preset already presents itself as a client they accept; for anything typed by hand, FLASHAGENT_USER_AGENT names the agent for every provider, and a provider's own User-Agent field (in the provider editor) names it for that one alone.
Responses API. An OpenAI-compatible provider stays on Chat Completions unless the server explicitly refuses that endpoint and asks for /responses. FlashAgent then switches that model to Responses for the rest of the session, including tool calls, image input, reasoning replay and usage. A switch of model or provider resets the learned choice; a Custom address ending in /v1/responses selects Responses immediately. Requests use store: false and carry the conversation locally. If an initial HTTP 400 says a replay item belongs to another Azure resource, FlashAgent retries once without the opaque items, keeping visible reasoning, messages and tool calls/results. The accepted mode is remembered only for that model/provider; an accepted stream is never resubmitted.
AgentRouter currently omits context and effort metadata from /models. For the exact gpt-6.1-sol, gpt-5.6-sol and gpt-6-astra ids, FlashAgent supplies reference limits and effort levels checked against the public OpenCode model catalog. Any limits or effort levels the connected server reports override these defaults; aliases remain unknown.
Keys. A key typed in the wizard or the provider editor is saved with that provider in the config file and shown masked. A provider without a saved key uses its usual environment variable (the Key column), then FLASHAGENT_API_KEY; the wizard says when it has found one.
In config.json the providers look like this; protocol is openai, anthropic, gemini or ollama, and an empty model means the one the server has loaded, else its first. A config from an older build, with backend_url, api_key and model, is read as one provider.
--url talks to that server for this run only and saves nothing about it; a saved provider at the same address lends its key and model. --model switches the model and saves it for the provider in use as the one to start with next time.
Configuration
Settings live in ~/.flashagent/config.json (%USERPROFILE%\.flashagent\config.json on Windows); change them in the app with <kbd>Tab</kbd> on an empty prompt or /settings. flashagent --help lists every flag; -y / --yes skips the question whether you trust the folder. The app also reads:
| Variable | Effect |
| :--- | :--- |
| ANTHROPIC_API_KEY, OPENCODE_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, GOOGLE_API_KEY, OPENROUTER_API_KEY, ... | Key for the provider they belong to (see Connecting a model), used when it has none saved |
| FLASHAGENT_API_KEY | Key for any provider that has none saved and none in its own variable |
| FLASHAGENT_CONFIG_PATH | Use this config file instead of ~/.flashagent/config.json |
| FLASHAGENT_TRUST_DIR | Set to anything: skip the folder trust question, like --yes |
| BRAVE_API_KEY | web_search uses Brave Search instead of DuckDuckGo |
| VISUAL, EDITOR | Editor for <kbd>Ctrl</kbd>+<kbd>E</kbd> when Settings names none (otherwise nano) |
| FLASHAGENT_TOOL_TEST_JSON | --tool-test also writes its raw results to this file |
| FLASHAGENT_DEV | 1 turns self-updates off |
| COLORFGBG | Set by many terminals; a white background there picks the light color theme |
On Windows, run_shell uses Git Bash when Git for Windows is installed and cmd.exe otherwise; the model is told which, so it writes commands for that shell.
What it can do
Tools — read_file, write_file, edit_file (exact replacements, line ranges, regular expressions or several cursors in one call; tolerant of CRLF and quote styles), patch_file (unified diffs), list_dir, glob, grep (parallel), outline_file, git_status, git_diff, run_shell (foreground with a ten-minute ceiling, or background tasks you can poll and kill; timeouts kill the whole process tree; on Windows it runs Git Bash when installed, cmd.exe otherwise), env_info, ask_user (interactive choices in the composer), memory tools, spawn_agent (subagents that inherit your permissions), view_image (offered when the model can see images), and web_fetch / web_search (on by default, run like a read; turn them off in Settings). /tools lists what the model may call, and Space turns one off for good — the schemas and the prompt both lose it. You can attach images yourself too: <kbd>Ctrl</kbd>+<kbd>V</kbd> pastes a screenshot from the clipboard, and dropping an image file on the prompt attaches it.
Permission modes — cycle with <kbd>Shift</kbd>+<kbd>Tab</kbd> or /mode:
| Mode | File edits | Shell | External (MCP) tools |
| :--- | :--- | :--- | :--- |
| Planning | refused | commands that only read (ls, cat, grep, git log, ...) run; the rest are refused unless allowed by a rule | only tools you marked read_only |
| Manual | ask, with diff | ask | ask (read_only ones run) |
| Accept Edits (first run) | run | ask | ask (read_only ones run) |
| Accept All | run | run, except dangerous commands (rm -rf, sudo, git push --force, git reset --hard, ...), which ask | run |
Safe mode (/safe) sits on top of the permission mode: reading and editing inside the project, and nothing else. The shell, the web and the subagents are off, and a project MCP server asks every time. The footer says when it is on.
FlashAgent starts in the mode you left it in. Reads inside the project and web tools are always allowed. Reading or writing a file outside the project asks in Manual and Accept Edits, is allowed in Accept All (where the shell already reaches any file), and is refused in Planning and during /goal. Fetching a local address (localhost, your local network, a cloud metadata endpoint) asks in every mode and is refused in Planning and during /goal. Approval cards offer Allow, Always and Deny; "Always" on a shell command stores a narrow per-command rule in the config, it survives a restart, and /rules shows what stands and takes a rule back. There is no sandbox: commands and edits run with your user's rights, so the mode and the approval card are what stands between the model and your files.
Interface — English or Russian, chosen in Settings → General and switched on the spot: the footer, /help, the panels, the cards and the notifications follow the choice. The system prompt stays English, and the model answers in the language the user wrote in.
Reasoning — readable thoughts or Responses summaries are folded by default; <kbd>F2</kbd> or <kbd>Ctrl</kbd>+<kbd>O</kbd> opens them, and “click to show all” expands a long preview. Encrypted reasoning replay is opaque state returned to the provider, not text the app can display. Supported Responses reasoning models are asked for a summary even at the provider's default effort. Reasoning token usage alone still does not mean the provider sent a readable summary.
Color themes
/theme opens a searchable picker with live preview. Move with the arrows, page keys or mouse wheel; Enter or a click on a theme saves it, Esc or ✕ restores the previous theme. /theme <name> switches directly, including while the model is answering. Settings → UI → Color theme opens the same picker and returns to Settings; selecting a theme saves only that choice, not other pending settings.
The built-in identifiers are dark, midnight, high_contrast, monochrome, ansi16 and light. They still use the existing color_theme setting. To add a palette, merge these fields into config.json and restart the app:
Every color is optional and uses #RRGGBB; omitted roles inherit base (Dark when omitted). Names are 1–64 ASCII letters, digits, _ or -, start with a letter or digit, and must not collide with built-in names or one another ignoring case. A malformed palette is reported and skipped without losing valid siblings or other settings. A missing selected palette falls back to color_theme; older builds can still read that built-in fallback.
Roles match the app's existing RGB palette and nearby shades at frame output, preserving brightness variations in animations. Unmatched colors retain the base theme; this is not a new drawing API or a change to the terminal's own default background. ansi16 palettes stay within the terminal's 16 colors. An explicitly selected custom palette keeps its chosen base even when COLORFGBG reports a light terminal.
MCP — add servers in .mcp.json (project) or ~/.flashagent/mcp.json (global), browse a small vetted marketplace with /mcp market, install with /mcp add <id>, test with /mcp test <name>. A server named in a project's .mcp.json asks before it starts, and remembers the answer together with the command it approved. Mark a server or individual tools read_only to skip approval for them — only your config can do that; a server's own claims (tool names, readOnlyHint) never bypass an approval card.
Memory & rules — MEMORY.md, CLAUDE.md, AGENTS.md, .cursorrules, .agents/rules/*.md and ~/.flashagent/MEMORY.md are picked up automatically and injected within a token budget (whole files when they fit, outlines when they do not). In MEMORY.md the owner's text is an instruction and the index the model writes is a record: the prompt says so, and a fact is read through memory_read rather than obeyed as an order.
Sessions — conversations are saved on exit. flashagent --continue picks up the latest one in the current folder; flashagent --resume (or /resume inside the app) lists this folder's sessions to choose from; flashagent --resume <session_id> opens one directly. /compact summarizes older turns to free context, and it happens automatically near the limit; a conversation too large for one window is compressed in pieces that fit, and the exact archive stays in the session file. One live card shows the summary and elapsed time, then its input/output token counts; the context gauge updates as soon as compaction finishes. /rewind takes turns back: files and conversation return to before the turn you pick.
Autonomous mode (/goal <task>) — runs the task end to end in Accept All mode with maximum reasoning effort. It has no limits unless you set them in Settings → Goal (steps, time, generated tokens). Dangerous shell commands are refused outright during the run. If the model asks you something and you do not answer within two minutes, it picks the most reasonable option itself and says so in its summary. It keeps a live plan on screen, commits what it changed every ten steps inside a git repository, and ends with a factual report card — steps, generated tokens, elapsed, files created and edited, shell commands that failed, and whether a limit cut the run short — built from what the loop did, not from what the model says it did. Your previous permission mode and effort are restored afterwards, and /rewind takes the run's file changes back.
<sub>The card is built from what the loop saw, not from what the model says: here the step limit stopped the run after one edit, so neither <code>NOTES.md</code> nor the <code>cargo check</code> the task asked for appears in it.</sub>
Updates — installed in the background: a new release is downloaded, verified against the release checksums and installed on its own, and the status line tells you to restart once it is in. <kbd>Ctrl</kbd>+<kbd>U</kbd> (or /update) shows the progress of a download that is already under way, or checks and installs right away when nothing is running; flashagent --update does the same from the shell. Background updates can be turned off in Settings; --channel stable|beta or /channel switches channels.
What leaves your machine — requests to the provider in use; update checks against GitHub Releases (on by default, off with Settings → Updates → Auto-update); web_fetch requests to the pages the model asks for and web_search queries to DuckDuckGo, or Brave Search with BRAVE_API_KEY (on by default, off with Settings → LLM → Web tools); and whatever the MCP servers you add do. There is no telemetry.
Keybindings
| Key | Action |
| :--- | :--- |
| <kbd>Enter</kbd> | Send prompt · while the model works: steer it, or run a /command |
| <kbd>Alt</kbd>+<kbd>Enter</kbd> / <kbd>Ctrl</kbd>+<kbd>J</kbd> | New line in the prompt (also <kbd>Shift</kbd>+<kbd>Enter</kbd> where the terminal reports it, or \ then <kbd>Enter</kbd>) |
| <kbd>Esc</kbd> | Close a menu or card · clear the prompt · then interrupt the running turn · never quits |
| <kbd>Ctrl</kbd>+<kbd>D</kbd> | Quit (empty prompt) |
| <kbd>Ctrl</kbd>+<kbd>C</kbd> | Interrupt the running turn · otherwise copy the prompt text, or the last answer when the prompt is empty · on an empty prompt, a second press within a second quits (the first does when there is nothing to copy) |
| <kbd>Ctrl</kbd>+<kbd>K</kbd> | Every command, searchable by name or key |
| <kbd>Ctrl</kbd>+<kbd>F</kbd> | Search earlier prompts; <kbd>Ctrl</kbd>+<kbd>F</kbd> again goes further back, <kbd>Enter</kbd> takes the match |
| <kbd>Ctrl</kbd>+<kbd>V</kbd> | Paste a screenshot from the clipboard as an attachment (text pastes as text) · <kbd>Ctrl</kbd>+<kbd>Z</kbd> removes the last one |
| <kbd>Tab</kbd> | Settings (empty prompt) · complete a /command |
| <kbd>Shift</kbd>+<kbd>Tab</kbd> | Cycle permission mode |
| <kbd>F1</kbd> | Context window breakdown |
| <kbd>F2</kbd> | Verbose mode: collapsed → last turn → everything |
| <kbd>F3</kbd> / <kbd>Alt</kbd>+<kbd>M</kbd> | Model picker with fuzzy search |
| <kbd>F4</kbd> / <kbd>Ctrl</kbd>+<kbd>T</kbd> | Thinking effort presets reported by the model |
| Click | Open or fold that one thought or tool call |
| <kbd>Ctrl</kbd>+<kbd>O</kbd> / <kbd>Alt</kbd>+<kbd>O</kbd> | Expand last / all reasoning blocks |
| <kbd>Ctrl</kbd>+<kbd>R</kbd> | Regenerate the last answer |
| <kbd>Ctrl</kbd>+<kbd>E</kbd> | Compose the prompt in your editor |
| <kbd>Ctrl</kbd>+<kbd>U</kbd> | Check for an update now and install it · or show the download already under way |
| <kbd>→</kbd> | Accept the suggested follow-up prompt |
| <kbd>PgUp</kbd> / <kbd>PgDn</kbd> · <kbd>Shift</kbd>+<kbd>↑</kbd> / <kbd>Shift</kbd>+<kbd>↓</kbd> · mouse wheel | Scroll the conversation; the prompt stays where it is · <kbd>End</kbd> or <kbd>Esc</kbd> returns to the bottom |
Type /help for every slash command: /goal, /mode, /model, /provider, /theme, /effort, /context, /compact, /rewind, /resume, /mcp, /skills, /tools, /rules, /safe, /sampling, /notices, /cost, /tasks, /diff, /commit, /export, /update, /channel, /exit and more.
Architecture
A Cargo workspace; the terminal client runs the whole stack in-process today.
crates/core agent loop, steering, permissions, subagents, memory, system prompt
crates/llm one model client, four protocols (OpenAI-compatible, Anthropic, Gemini, Ollama), reasoning-preset discovery, text tool-call parser, JSON repair
crates/tools built-in tools, shell runner (timeouts that kill the whole process tree, background tasks), patching, MCP client/manager/marketplace
crates/tui crossterm terminal UI (the product today)
crates/svc self-updater
Everything runs in one process: no Node, no Python, no Electron. On Linux the binary links only the system C libraries (libc, libm, libgcc_s). See ARCHITECTURE.md for how the pieces fit, and docs/numbers.md for what it costs: a usable prompt in about 120 ms, about 58 MB of memory when idle.
cargo test --workspace
cargo clippy --workspace --all-targets -- -D warnings
Contributing
FlashAgent has one maintainer, so bug reports help a lot.