Learn about fin itself — what it is, how it works, its architecture. Use when asked about fin.
fin
fin is a minimal, opinionated CLI agent harness written in Go by meain.
Source code: https://github.com/meain/fin
What it does
fin takes a prompt, runs an agent loop (stream LLM response → execute tool calls → repeat), and exits. It supports session persistence, multiple LLM providers, an extensible skill system, and multiple output modes.
Usage
fin "explain this code"# basic prompt
fin -c "follow up"# continue last session
fin -s <uuid> "follow up"# continue specific session (prefix match or 1-based index)
fin -n <name> "prompt"# named session (resumes if it exists, else creates)
fin -match "prompt"# search recent sessions, offer to resume a match
git diff | fin "review this"# piped input
fin -export json|html|message # export session
fin -export message | glow # pipe last response to glow
fin -ui debug "what is in go.mod"# default + turn timings + token usage
fin -ui quiet "summarize" > out.txt # just the response on stdout
fin -sessions
fin -all -sessions
fin -since 1h -sessions
fin -approve all|safe|none
fin -yolo
fin --max-turns 5
fin -model provider/model
fin -color auto|always|never
fin -config <path>
fin -f script.fin
fin -f script.fin
fin -tools ,shell
fin -temp
fin -c -temp
fin -sessions -temp
fin -tag work
fin -c -t work
fin -c -t -work
fin -sessions -t work
fin -sessions -t -work
fin -c -repo
fin -sessions -repo
fin -fork
fin -s <uuid> -fork
fin -doctor
fin -migrate
fin -no-project
fin -h
# list last 10 sessions (JSON if piped, ANSI table on TTY)
# list all sessions
# filter sessions by age (1h, 2d, 1w, 30m)
"prompt"
# tool approval mode
"prompt"
# alias for -approve all
"prompt"
# cap agent loop iterations
"prompt"
# override model for this run (alias names also work)
# color output (NO_COLOR honored)
# override config file location
# read prompt from file (strips shebang line)
"extra args"
# file prompt + positional args appended
read
"prompt"
# restrict tool set (also: all, none)
"quick question"
# mark session as temporary (skipped by -c, shown as [temp] in listings)
"follow up"
# continue the last temp session
# list only temp sessions
"prompt"
# tag session as "work" (shown as #work in listings)
"follow up"
# continue last session tagged "work"
"follow up"
# continue last session NOT tagged "work"
# list sessions tagged "work"
# list sessions NOT tagged "work"
"follow up"
# continue last session created in the current repo
# list sessions created in the current repo
"try different approach"
# fork the last session into a new one and continue from there
[model_aliases] — short names mapping to provider/model (e.g. sonnet = "anthropic/claude-sonnet-4-6"). Alias chains resolved up to 10 hops.
[providers.*] — base_url, api_key_env, headers
[tools.*] — approval (auto/confirm/deny), allow/deny glob patterns for shell
Features
Multi-provider LLM support
Anthropic Claude, OpenAI, and any OpenAI-compatible API (Groq, OpenRouter, Ollama, local models). All via raw HTTP — no provider SDKs. Configurable per-provider base URLs, API keys, and custom headers.
Built-in tools
read — files with line numbers, images (base64 for vision models), directory trees
write — creates files and parent directories
edit — exact string replacement (old_string must be unique in the file)
shell — executes via sh -c, returns stdout and stderr separately
use_skill — activates a skill, loading its full instructions on demand
subagent — spawns an isolated child agent for a task; child gets the same tools (minus subagent) and config, but a fresh conversation
compact — summarizes the conversation into a new session, dropping older context
Agent skills (agentskills.io spec)
Progressive disclosure: only skill names and descriptions are loaded at startup. Full instructions load on activation. Skills are discovered from .agents/skills/ in the project (walks up to root), ~/.agents/skills/ globally, and any extra directories listed in settings.skills_dirs in the config (each expected to directly hold <name>/SKILL.md subdirs). Follows symlinks. Builtin skills are embedded in the binary.
Session management
Sessions saved incrementally as JSONL in ~/.local/share/fin/sessions/. First line is a session header (id, title, model, cwd, started_at); each subsequent line is one message.
Writes are append-only after the first save. Header changes (e.g. LLM-generated title) and resume both trigger an atomic tmp + rename full rewrite.
mtime conflict detection: refuses to overwrite if another fin process modified the file since load, to avoid clobbering concurrent runs.
Reader tolerates a truncated trailing line (crash mid-append) so earlier messages stay readable.
UUID-based with prefix matching (fin -s abc12 works). Named sessions via -n. Match recent sessions to the current prompt with -match.
Tag sessions with -tag <name> or -t <name>. Use -t <name> with -c or -sessions to filter by tag; prefix with - (e.g. -t -work) to exclude sessions with that tag.
Each session automatically records the repo it was started in (basename of the git/jj repo root, or cwd if neither is detected). Use -repo with -c or -sessions to filter to sessions created in the current repo.
Fork sessions with -fork: copies all messages into a new session with previous_session pointing to the origin. Forks are shown grouped under their parent in fin -sessions (TTY) and as a flat array with parent_id in JSON. Exports walk the full ancestor chain root-first.
Export
JSON — full session with all messages and metadata
HTML — rendered markdown, foldable tool results, edit diffs with red/green, collapsible sections
message — just the last assistant response (pipeable to pbcopy, glow, etc.)
debug — like default plus turn timings, token usage, retry events, prompt size
quiet — only the response text on stdout, nothing on stderr (for scripting)
Piped input
git diff | fin "review this" — stdin pipe detected automatically, content prepended to prompt.
Tool approval system
Per-tool configurable: auto, confirm, or deny. Shell tool supports allow/deny glob patterns. -approve all|safe|none overrides at runtime; -yolo is shorthand for -approve all.
Tool selection
-tools filters the active tool set. all (default) enables everything; none disables every tool; a comma list (-tools read,shell) enables only the named tools. Filter applies to subagents too. Valid names: read, write, edit, shell, compact, use_skill, subagent.
Retry with backoff
Rate limits (429) and server errors (5xx) retried up to 3 times with exponential backoff + jitter.
Layered system prompt
Assembled from: embedded base prompt → runtime context (date, OS, cwd) → skill list → ~/.agents/AGENTS.md → project AGENTS.md (walks up to root) → Claude Code auto-memory. Base prompt sections are gated by -tools so a disabled tool's section never reaches the model. -no-project drops the project AGENTS.md layer and the project-level .agents/skills/ walk-up, keeping only global (~/.agents/) context.
Claude Code auto-memory pickup
If the current project has a Claude Code auto-memory directory (~/.claude/projects/<project>/memory/, keyed by git root with / replaced by -, falling back to cwd outside a repo), fin reads its MEMORY.md index — capped at 200 lines/25KB, the same limit Claude Code itself applies — and appends it to the system prompt, along with paths to any sibling topic files the model can read on demand. Read-only; fin never writes to that directory. Disable with disable_claude_memory = true under [settings]. Shown in fin -doctor.
Replaceable UI
The agent talks to the UI through agent.UIWriter. Payloads crossing the boundary are structured data (no ANSI escapes, no pre-formatted strings). The terminal ui package is the current implementation; a TUI, web, or audio frontend can drop in by implementing the same interface — no agent change needed.
Live progress
Shows streaming line count during tool call argument generation (e.g. write (47 lines) updates in real-time). Esc / Ctrl+C cancels a turn.
Type-ahead input
Raw-mode TTY multiplexer captures keystrokes during execution so the next prompt can be typed while a turn is still running.
Exploring the source
Clone into a temporary directory and read through the files:
Agent skills spec (agentskills.io) for extensibility
System prompt and builtin skills are embedded markdown files
Sessions stored as append-only JSONL so nothing is lost if killed mid-execution
All terminal output flows through a single UI layer; callers pass structured data, the UI decides how to render (so the layer can be swapped for web, audio, etc.)