Reference for tinycode after you have a binary and a working model. Install from install.md. The first session is quickstart.md. This guide covers the interface, commands, agents, sessions, configuration, and tinycode run.
Table of Contents
- Getting Started
- The Interface
- Slash Commands
- Keyboard Shortcuts
- File References
- Agents
- Subagents and Swarm Mode
- Providers and Models
- Sessions
- Configuration
- MCP Integration
- LSP Integration
- Plugins
- Web UI
- Run Mode
- CLI Reference
- Troubleshooting
Install from install.md. The first session is quickstart.md.
On startup, tinycode checks configuration, the embedded server, providers, agents, plugins, sessions, and MCP. A failed check is a red X. tinycode still launches. /connect picks a provider when none was discovered. After boot, the footer lists / commands, @ files, Tab for agents, and Ctrl+P for the palette.
The main area shows the conversation: your prompts, the model's responses, tool calls, and their output. Responses stream in real-time with markdown rendering. Scroll with PgUp/PgDn or mouse wheel.
At the bottom of the screen. Supports:
- Enter to submit
- Shift+Enter or Alt+Enter to insert a newline (for multi-line prompts)
- / to trigger slash command autocomplete
- @ to trigger file path autocomplete
- Tab/Shift+Tab to cycle through agents
- Up/Down arrow in autocomplete to navigate suggestions
- Ctrl+C to clear input (or quit if already empty)
The prompt line shows the current agent name and model on the right side.
Below the prompt. Shows:
- Current working directory
- Active model and provider
- Agent name (color-coded per agent)
- An animated braille-wave spinner while the model is working
- "ctrl+x ..." hint when the leader key is pending
- SAFE MODE indicator (orange, bold) when
--safe-modeis active
Toggle with Ctrl+X b. The sidebar shows:
- Context -- token usage (input/output), percentage of context window used, cost spent, and provider balance remaining (if applicable)
- MCP -- connected MCP servers with status indicators (green dot = connected, red = error, gray = disconnected) and tool counts
- Sessions -- the 5 most recent titled sessions; click to switch
- LSP -- diagnostics count from the language server (errors/warnings/clean/disabled)
- Metadata -- current agent and model
- Footer -- working directory and tinycode version
Type / in the prompt to see the autocomplete list. Commands are handled either client-side (instant) or server-side (sent to the model as instructions).
These execute immediately without sending anything to the model.
| Command | Description |
|---|---|
/connect |
Open the provider/model selector |
/theme |
Open the theme picker (with live preview) |
/compact |
Compact the current session context (summarize older messages to free tokens) |
/export |
Export the current session as a Markdown file in the working directory |
/export html |
Export the current session as an HTML file with syntax highlighting (alias: /export-html) |
/archive |
Soft-delete the current session (removes from session list, recoverable) |
/copy |
Copy the last assistant response to the clipboard |
/rename <title> |
Rename the current session |
/editor |
Open $EDITOR to compose a long prompt; contents are submitted on save+quit |
/editor @file.md |
Open a file in $EDITOR for direct editing |
/shell |
Drop into an interactive shell session; return to tinycode on exit |
/diagnostics |
Open a diagnostics dialog showing config, paths, providers, and system info |
/debug |
Ask the debugger agent to find one root cause. This is not the diagnostics dialog |
/thinking <level> |
Set the reasoning level: off, low (1k tokens), medium (4k), high (16k), max (128k) |
/thinking |
Show the current reasoning level |
/scoped-models |
Toggle model scoping -- mark favorite models so the model list only shows those |
/auto-approve |
Toggle auto-approve for the current session (skips tool permission prompts) |
/rewind |
Open a picker of conversation turns and roll back to a selected point; press f to fork instead of rewind |
/undo |
Revert the last AI file changes (snapshot-based) |
/redo |
Restore previously reverted changes |
/diff |
Show uncommitted git changes in the working directory |
/paste-image |
Paste an image from the clipboard for multimodal input (alias: /image) |
/mcp |
Open the MCP server management dialog (reconnect, view status) |
/help |
Open the command palette showing all keybindings and commands |
/exit |
Quit tinycode |
These are processed by the model. They show up in autocomplete alongside client commands.
| Command | Description |
|---|---|
/ask <agent> <message> |
Route a prompt to a specific agent (e.g., /ask architect design the auth flow) |
/swarm <task> |
Split a task into subtasks and dispatch parallel subagents (see Swarm Mode) |
/work-loop <task> |
Iterate on a task autonomously until complete or blocked |
/review [target] |
Ask code-reviewer to review a change |
/init |
Generate root AGENTS.md from repo signals (ecosystem detection) and guided project setup |
If you have skill files in ~/.config/tinycode/skills/ or .tinycode/skills/, they appear as additional slash commands. Skills are markdown files with a SKILL.md in a named directory that inject specialized instructions into the prompt.
tinycode bundles seven skills. User and project skills override them by name. /debug, /trace, /plan, /verify, /test, and /review delegate to agents instead of expanding a skill. See authoring.md to add either one.
| Skill | Description |
|---|---|
remember |
Triage session findings across memory surfaces |
deepinit |
Per-directory AGENTS.md files |
doctor |
Diagnose the tinycode environment |
mcp-setup |
Guided MCP server configuration |
incident |
Triage a live system failure: impact, evidence, one next command |
change |
Plan one cluster or host change: the command, the check, and the undo |
host |
Inspect a machine, local or over ssh: health, misconfiguration, and exposure |
Use /paste-image (or /image) to paste an image from the system clipboard into the conversation. The image is encoded and sent as a multimodal content block alongside your next prompt, enabling the model to see screenshots, diagrams, or error output.
Requirements: the model must support vision/multimodal input, and the clipboard must contain image data (not a file path).
Prefix a command with ! to run it locally and feed the output to the model:
!git log --oneline -10
The shell command runs in the working directory and its output is included as context for the model's next response. A command that names a .env file, a credentials file, a .key file, or a .pem file asks for approval before it runs. Shell commands, plugins, and MCP servers do not receive credential environment variables such as OPENROUTER_API_KEY or GITHUB_TOKEN. PATH, HOME, and SSH_AUTH_SOCK are still passed through. A token a single MCP server or formatter needs belongs in that entry's env or environment map.
| Key | Action |
|---|---|
| Ctrl+P | Open command palette |
| Ctrl+F | Open in-transcript search |
| Ctrl+C | Clear prompt input, or quit if empty |
| Ctrl+D | Quit |
| Escape | Interrupt the current model operation. On a permission prompt, reject the request |
| Key | Action |
|---|---|
| Enter | Submit prompt |
| Shift+Enter | Insert newline |
| Alt+Enter | Insert newline (alternative) |
| Tab | Cycle to next agent |
| Shift+Tab | Cycle to previous agent |
| F2 | Cycle to next recent model |
| Shift+F2 | Cycle to previous recent model |
| Ctrl+S | Stash current draft / restore stash (when empty) |
| Ctrl+R | Open prompt history browser |
| Key | Action |
|---|---|
| PgUp | Scroll conversation up |
| PgDn | Scroll conversation down |
| Mouse wheel | Scroll conversation |
The leader key is Ctrl+X. Press it, then press a follow-up key within 500ms.
| Sequence | Action |
|---|---|
| Ctrl+X b | Toggle sidebar |
| Ctrl+X n | New session |
| Ctrl+X o | Open session list |
| Ctrl+X m | Open model selector |
| Ctrl+X a | Open agent list |
| Ctrl+X x | Export session as Markdown |
| Ctrl+X e | Open $EDITOR to compose a prompt |
| Ctrl+X d | Open diff viewer (uncommitted changes) |
| Ctrl+X t | Open theme picker |
| Ctrl+X i | Open MCP server management dialog |
| Ctrl+X y | Copy last response to clipboard |
| Ctrl+X u | Undo last AI file changes |
| Ctrl+X r | Redo reverted changes |
Press Ctrl+F to open the search bar at the top of the chat viewport. Search is case-insensitive and scans all message text and reasoning blocks.
| Key | Action |
|---|---|
| Ctrl+F | Open search (or close if already open) |
| Ctrl+N / Enter | Jump to next match |
| Ctrl+P | Jump to previous match |
| Escape / Ctrl+C | Close search |
The search bar shows the current match position (e.g., "3/12") and auto-scrolls the viewport to the message containing the match.
When you press Ctrl+X (the leader key), a floating panel appears in the bottom-right corner showing all available follow-up keys grouped by category:
- Navigation --
b(sidebar),o(session list),n(new session) - Edit --
e($EDITOR),d(diff viewer),u(undo),r(redo) - Tools --
a(agent list),m(model list),t(theme picker),i(MCP servers) - Actions --
y(copy last response),x(export session)
The panel is non-modal -- any keypress hides it and the key is forwarded normally.
tinycode rings the terminal bell (audible or visual, depending on your terminal settings) in two situations:
- When a task completes (the model finishes working)
- When a permission prompt appears (a tool needs approval)
This is useful when you switch to another window while the model is working -- you hear the bell when it needs attention.
When a dialog is open (agents, models, sessions, themes):
| Key | Action |
|---|---|
| Up / k | Move selection up |
| Down / j | Move selection down |
| Enter | Confirm selection |
| Esc / q | Close dialog |
| d | Toggle enable/disable (agent dialog only, non-native agents) |
On a permission prompt, Left/Right or h/l move between Allow once, Allow always, and Reject. Enter confirms the highlighted choice. Esc rejects the request.
Type @ followed by a path to reference files in your prompt. An autocomplete dropdown shows files in the working directory.
@src/main.go explain the startup sequence
@internal/config/ what config options are available?
fix the bug in @pkg/plugin/protocol.go
How it works:
- Autocomplete triggers when you type
@at the start of the input or after a space - Directories appear with a trailing
/and are shown first, highlighted in blue -- select one to drill down into its contents - Hidden files (dotfiles) are excluded from the listing
- Up to 20 items are shown at once
- Select with Up/Down arrows, confirm with Tab or Enter
- The file's contents are read and included as context when you submit the prompt
You can reference multiple files in one prompt:
compare @go.mod with @go.sum and check for inconsistencies
Agents are specialized personas that share the same tools but have different system prompts and permission sets. The default agent is build, which handles general coding tasks and knows when to delegate.
| Agent | Mode | Description |
|---|---|---|
| build | primary | Default agent. Handles simple work inline and delegates the rest. |
| plan | primary | Planning mode. Interviews the user, researches the codebase, and writes work plans; edits restricted to plans/* and drafts/*. Use plan_enter/plan_exit to switch. |
| analyst | subagent | Turns decided scope into acceptance criteria and catches gaps before planning. |
| architect | subagent | Design decisions, API design, system-level trade-offs. Read-only. |
| code-reviewer | subagent | Severity-rated code review with SOLID checks, logic defect detection, performance analysis. |
| critic | subagent | Plan and gap review with a pre-mortem. Code defects go to code-reviewer. |
| debugger | subagent | Root-cause analysis. One hypothesis at a time, minimal diff fixes. |
| designer | subagent | UI implementation. Detects the framework and keeps the visual design intentional. |
| document-specialist | subagent | External SDK docs, API references, changelogs, and integration guides. |
| executor | primary | Focused task implementation. Smallest viable diff, no scope creep. |
| explore | subagent | Fast codebase search. Read-only: grep, glob, read, bash only. |
| general | subagent | Plain assistant. Answers directly and uses a tool only when the question needs one. |
| git-master | subagent | Git history management, rebasing, atomic commits. |
| ops | primary | Cluster and host administration. Read-only first. Asks before a command that changes the system. |
| scout | subagent | Upstream dependency source. Official docs go to document-specialist. |
| security-reviewer | subagent | OWASP Top 10, secrets detection, unsafe patterns, dependency CVEs. |
| test-engineer | subagent | Test strategy, coverage authoring, TDD workflows. |
| tracer | subagent | Causal tracing with competing hypotheses, evidence for and against, and a next probe. |
| verifier | subagent | Evidence-based completion checks. No approval without fresh evidence. |
| writer | subagent | Technical documentation with verified examples. |
Hidden utility agents (compaction, title, summary) handle internal tasks and are not selectable.
Some agents (code-simplifier, qa-tester, scientist) are disabled by default but can be enabled in config.
How to add an agent or a skill is in authoring.md.
- primary -- Can be set as your active agent to handle the conversation directly
- all -- Can be used as either a primary agent or spawned as a subagent
- subagent -- Designed to be spawned by the build agent (or invoked via
/ask) for specific tasks; cannot be set as the default agent
Each agent has a .compact variant that is automatically used when the model has 8B parameters or fewer. Compact prompts are shorter and simpler, tuned for smaller models.
Tab/Shift+Tab -- Cycle through agents in the prompt (default: build, general, ops, plan, architect, code-reviewer). The agent name and its color update in the status bar. Configure the cycle list with cycle_agents in config.
ops is the agent for a live cluster or machine. It reads first, names the blast radius, and makes one change. /incident triages a failure. /change plans one update. /host inspects the machine tinycode is running on, or another host over ssh. A failed ssh stops there.
Read-only oc and kubectl commands (get, describe, logs) run. apply, delete, scale, patch, drain, cordon, rollout, and exec ask. On a host, systemctl status runs. systemctl restart, firewall edits, account changes, and address or route changes ask, including when the command is sent over ssh.
ops uses the plugin that owns the product. An ambiguous cause goes to tracer. Product docs go to document-specialist. Config in this repo goes to explore. Exposure in source goes to security-reviewer. File edits go to executor. Application bugs go to debugger.
Ctrl+X a -- Open the agent dialog showing all agents (including disabled ones). Navigate with j/k or arrows, press Enter to select.
/ask -- Route a single message to a specific agent without switching:
/ask architect should we use a message queue here?
/ask debugger why is TestAuth failing?
The /ask command has its own autocomplete -- after typing /ask , it shows agent names filtered by what you type.
In the agent dialog (Ctrl+X a), press d on any non-native agent to toggle it on/off. Disabled agents show [off] and are not included in Tab cycling or autocomplete. Native agents (build, plan, general, explore, scout) cannot be disabled.
You can also disable agents in config:
{
"agents": {
"scientist": { "disable": true },
"my-custom-agent": {
"prompt": "You are a documentation specialist.",
"description": "Custom docs agent",
"mode": "subagent"
}
}
}The build agent (default) can spawn subagents for complex tasks. When you ask for something that involves multiple files or systems, build may delegate to executor, architect, or other agents internally using a task tool.
You can also explicitly request delegation:
/ask executor implement the login form across all 5 files
Subagent output appears in the conversation as nested messages showing which agent handled what.
Swarm mode splits a task into independent subtasks and runs them in parallel via multiple subagents.
/swarm run tests on internal/config, internal/provider, and internal/agent packages
What happens:
- The build agent receives your task with swarm instructions prepended
- It analyzes the task and creates 2-4 independent subtasks
- Each subtask is dispatched to a subagent (executor or explore) via the
tasktool - Subagents run in parallel, each with its own tool access
- After all subagents complete, the build agent synthesizes a report
Swarm mode automatically enables auto-approve for tool permissions (the subagents need to run without waiting for approval).
Constraints:
- Subagents get one round of work -- they do not retry on failure
- The coordinator does not use tools directly -- it only dispatches via the task tool
- If a subagent times out or errors, the coordinator reports what failed and synthesizes partial results
Work-loop mode iterates autonomously on a task until it is complete or blocked:
/work-loop fix all lint errors in this project
The agent cycles through: understand, plan, act, verify, assess. It continues without asking for confirmation until the task is done or the same action fails 3 times.
| Provider | Type | Discovery |
|---|---|---|
| Ollama | Local | Auto-discovered at localhost:11434 (prefer TINYCODE_OLLAMA_HOST, then OLLAMA_HOST) |
| vLLM | Local | Set TINYCODE_VLLM_HOST to enable (e.g., http://localhost:8000) |
| LM Studio | Local | Auto-discovered at localhost:1234 (override with TINYCODE_LMSTUDIO_HOST) |
| OpenRouter | Cloud | Set OPENROUTER_API_KEY to enable |
Any OpenAI-compatible API endpoint (Anthropic, OpenAI, Azure, etc.) can also be configured as a custom provider via the provider config block -- see Configuration.
On startup, tinycode probes local providers synchronously so models are available immediately. It then polls every 30 seconds in the background. If a provider fails 3 consecutive health checks, it is removed and polling stops. Restarting tinycode re-enables discovery.
For Ollama models, tinycode sends a warmup probe to pre-load the model into GPU memory and verify tool-call support. Models that do not support tool calling are flagged and work in text-only mode.
Ctrl+X m or /connect -- Opens the model selector. This is a two-step dialog:
- Select provider -- shows all discovered providers with model counts
- Select model -- scrollable list of models for the chosen provider
In the model list, type to search (e.g., "qwen" to filter). Backspace clears the filter. Esc goes back to the provider list.
F2 / Shift+F2 -- Cycle through recently used models without opening a dialog.
Tab in the model list -- moves between available models.
Use /scoped-models to mark specific models as favorites. When scoping is active, the model selector only shows your favorites instead of the full list from every provider.
Configure in config:
{
"scopedModels": [
"ollama/qwen3:8b",
"ollama/qwen3.5:9b",
"openrouter/anthropic/claude-sonnet-4-20250514"
]
}Control how much the model "thinks" before responding:
/thinking off # No reasoning (default)
/thinking low # 1k token budget
/thinking medium # 4k token budget
/thinking high # 16k token budget
/thinking max # 128k token budget
Higher thinking levels give better results on complex tasks but use more tokens and take longer. The current level is shown in the prompt and persists for the session.
Small models (9B–14B) sometimes enter reasoning loops — repeating "but wait" or restating the same sentence. tinycode detects this and stops the stream automatically. The default completion cap is 8192 tokens with an 8-minute wall clock. If a loop is detected earlier, the stream stops immediately and the model's partial answer is returned.
Sessions are conversations. Each session maintains its own message history, agent selection, and model choice.
When you send the first prompt in a new session, tinycode automatically generates a title based on the content. The title appears in the sidebar and session list.
- Ctrl+X n -- Create a new session
- Starting tinycode always begins with a clean session
- Ctrl+X o -- Open the session list dialog. Navigate with arrows, press Enter to switch.
- Sidebar -- Click a session title in the sidebar to switch to it.
/rename my feature branch work
/archive -- Soft-deletes the current session. The session is removed from the session list and sidebar but can be recovered. After archiving, a new session is created automatically.
Ctrl+X x or /export -- Writes the current session transcript as a Markdown file (session-<title>.md) in the working directory. Includes all messages, tool calls, and their output.
/export html -- Exports the session as an HTML file with syntax highlighting. The HTML export is self-contained and can be shared or viewed in any browser.
tinycode session list # List sessions for the current project
tinycode session delete <id> # Delete a session by IDtinycode uses a two-stage approach to keep conversations within the model's context window:
Stage 1 — Elision (~80% of context). When input tokens reach approximately 80% of the available context window, tinycode automatically replaces old tool results with compact stubs ([output masked]), preserving the 5 most recent tool outputs. This is lightweight — no LLM call, no information loss from conversation text, just tool output trimming. Elision defers the more expensive summarization step and is especially valuable on local models with smaller context windows (32k-64k).
Stage 2 — Summarization (~100% of context). When input tokens approach the full context limit, tinycode triggers a full LLM-powered summarization of older messages. This replaces the conversation history with a structured summary while preserving recent context. You can also trigger this manually with /compact.
Both stages run automatically. Elision fires first and may be sufficient for shorter sessions — many conversations never need the full summarization step.
Bounded tool previews. Tool outputs over 50 lines are automatically formatted as head+tail previews (first 30 + last 20 lines) with a structured header showing total size. This reduces context consumption at the source.
Configure compaction behavior in config:
{
"compaction": {
"mask_observations": true,
"preserve_recent_tokens": 8000,
"max_messages": 80
}
}mask_observations defaults to true and replaces old tool results with stubs. preserve_recent_tokens is how many recent tokens stay unsummarized; values outside 2000–15000 are clamped. max_messages defaults to 80 and triggers summarization once the session reaches that many messages. auto, prune, tail_turns, and reserved are accepted in the file and not applied.
tinycode reads config from multiple locations, merging them in order (later files override earlier ones):
- Global config:
~/.config/tinycode/tinycode.jsonc(also checkstinycode.jsonandconfig.json) - Project config:
tinycode.jsoncortinycode.jsonfiles walking up from the working directory (innermost wins) - Project dot-directory:
.tinycode/directory in the project
Override the config directory with TINYCODE_CONFIG_DIR or XDG_CONFIG_HOME.
Config files support JSONC (JSON with comments) and environment variable substitution.
| Option | Default | Description |
|---|---|---|
model |
(auto) | Default model in provider/model format |
small_model |
(none) | Smaller model for lightweight tasks (titles, summaries) |
default_agent |
build |
Agent loaded on startup |
cycle_agents |
build, general, ops, plan, architect, code-reviewer |
Ordered Tab/Shift-Tab persona list |
shell |
(system) | Shell for tool execution |
logLevel |
(none) | Log verbosity (wired into the logger) |
theme |
(default) | Color theme name |
temperature |
(none) | Default LLM temperature (applied when prompting/creating sessions) |
top_p |
(none) | Default nucleus sampling (applied when prompting/creating sessions) |
max_tokens |
(none) | Default max output tokens |
tool_output |
(defaults) | Tool output truncation limits |
share |
"disabled" |
Session share/publish (manual/auto/disabled); Go web UI has no working share feature |
subagent_depth |
(none) | Maximum nesting depth for subagents |
autoApprove |
false |
Auto-approve all tool permissions globally |
scopedModels |
[] |
List of model favorites |
instructions |
[] |
Custom instructions prepended to system prompt |
disabled_providers |
[] |
Providers to hide |
enabled_providers |
[] |
Providers to show (if set, only these appear) |
formatter |
off | Run a formatter after write, edit, and apply_patch. true enables built-in gofmt |
tool_output.max_lines |
2000 |
Lines kept from a tool result before truncation |
tool_output.max_bytes |
51200 |
Bytes kept from a tool result before truncation |
skills.paths |
(none) | Extra directories scanned for */SKILL.md |
hooks |
(none) | Shell commands on session and tool events. See below |
Shell commands, ! commands, monitors, diagnostics, goal checks, plugins, MCP stdio servers, language servers, and custom formatters do not inherit credential environment variables from the tinycode process. A command such as env cannot read OPENROUTER_API_KEY and put it in the transcript.
A name is removed when it matches any of these, ignoring case:
- It ends with
_API_KEY,_APIKEY,_SECRET,_TOKEN,_PASSWORD,_PASSWD,_CREDENTIAL,_CREDENTIALS,_PRIVATE_KEY, or_ACCESS_KEY - It contains
API_KEY,SECRET_KEY,ACCESS_KEY,SESSION_TOKEN, orAUTH_TOKEN - It is exactly
AUTHORIZATION,AUTH_HEADER,SECRET,TOKEN, orPASSWORD
Everything else is passed through, including PATH, HOME, USER, LANG, KUBECONFIG, SSH_AUTH_SOCK, GOPROXY, and TERM. git and gh still work when their credentials live in the system keychain. The interactive /shell session is your own shell and still receives the full environment.
A token that one child needs belongs in that child's config map. Those values are applied after the filter:
{
"mcp": {
"github": {
"command": "github-mcp",
"env": { "GITHUB_TOKEN": "{env:GITHUB_TOKEN}" }
}
},
"lsp": {
"servers": {
"typescript": { "env": { "NPM_TOKEN": "{env:NPM_TOKEN}" } }
}
},
"formatter": {
"prettier": {
"command": ["prettier", "--write"],
"extensions": [".ts", ".tsx"],
"environment": { "PRETTIER_TOKEN": "{env:PRETTIER_TOKEN}" }
}
}
}{env:VAR} is replaced when the config file is loaded. The parent process still has the variable. Only the child named in that map receives the copy.
Each permission.allow or permission.deny entry is a permission name, or a name and a pattern separated by the first space. A name alone means pattern *. ~ and $HOME at the start of a pattern expand to your home directory.
{
"permission": {
"allow": ["read", "bash *"],
"deny": ["edit /etc/*", "shell rm *"]
}
}Deny entries are applied after allow entries, so a deny wins over an allow for the same match inside this list. The last matching rule wins overall, including later rules from the agent. bash and shell are the same permission. read .env* , webfetch *, paths outside the project, destructive shell commands, and shell commands that name a secret file ask even when a broad allow exists, unless a later rule allows them. Destructive shell includes recursive rm, force-push, cluster mutations (oc delete, kubectl apply, helm upgrade), and host mutations (systemctl restart, firewall edits, account changes, route changes), including the same command over ssh. oc get and systemctl status do not ask.
hooks runs a shell command when a session or tool event fires. The command receives the filtered environment from the section above. $SESSION_ID, $TOOL, and $ARGS are replaced and single-quoted.
| Event | When it runs | Failure |
|---|---|---|
session.start |
Session begins | Logged; stdout JSON can add context |
session.end |
Session ends | Logged |
tool.execute.before |
Before a tool runs | Non-zero exit aborts the tool |
tool.execute.after |
After a tool finishes | Logged; stdout JSON can add context |
timeout is seconds. The default is 10. match runs the hook only when every listed variable equals that value. Match keys are looked up in uppercase (tool matches TOOL). The value must match exactly.
{
"hooks": {
"tool.execute.before": [
{
"command": "echo '{\"hookSpecificOutput\":{\"additionalContext\":[\"run tests after edits\"]}}'",
"match": { "TOOL": "edit" },
"timeout": 5
}
]
}
}Plain text on stdout is ignored. A JSON object with hookSpecificOutput.additionalContext is added to the model context. Each string is capped at 10,000 characters.
experimental.auto_continue applies to tinycode run only. 0 leaves the agent stopped after a turn. A positive number lets tinycode run continue that many times without another prompt. The TUI does not read this field.
experimental.doom_loop_threshold is the number of identical tool calls in a row that stop the session. Unset or 0 stops after 3. The value applies to tinycode run, the TUI, and subagents.
skills.urls is stored and not fetched. Only skills.paths is scanned.
These keys are accepted and currently have no effect: attachment, watcher, reference, command, effort, snapshot, and username. The TUI effort level is a session control, not the effort config field.
Binding tinycode serve or tinycode web to a non-localhost address with auth disabled is refused unless you set TINYCODE_FORCE_NO_AUTH=1.
# Local providers
TINYCODE_OLLAMA_HOST=http://localhost:11434 # preferred Ollama URL override
OLLAMA_HOST=http://localhost:11434 # fallback if TINYCODE_OLLAMA_HOST unset
TINYCODE_VLLM_HOST=http://localhost:8000 # vLLM URL
TINYCODE_LMSTUDIO_HOST=http://localhost:1234 # LM Studio URL (default)
# Cloud providers
OPENROUTER_API_KEY=your-key
# Server settings
TINYCODE_PORT=4096 # API server port
TINYCODE_HOST=127.0.0.1 # Bind address
TINYCODE_DB=/path/to/db # Database path override
TINYCODE_LOG_LEVEL=debug # Log level
TINYCODE_WEB_DIR=./packages/app/dist # Web UI directory (dev mode)
TINYCODE_AUTH_TOKEN=my-token # Auth token for serve/web mode
TINYCODE_NO_AUTH=1 # Disable auth entirely| What | Path |
|---|---|
| Config | ~/.config/tinycode/tinycode.jsonc |
| Database | ~/.local/share/tinycode/tinycode.db |
| Log file | ~/.local/share/tinycode/tinycode.log |
| Plugins | ~/.config/tinycode/plugins/ |
| Skills | ~/.config/tinycode/skills/ |
Override data directory with TINYCODE_DATA_DIR or XDG_DATA_HOME.
Model Context Protocol (MCP) servers provide additional tools to the model. For example, an MCP server could provide database queries, API access, or custom integrations.
Manage MCP servers without hand-editing JSON:
| Command | Purpose |
|---|---|
tinycode mcp list |
List configured servers and best-effort connection status |
tinycode mcp add NAME -- CMD [args...] |
Add a stdio server to user config |
tinycode mcp add --transport sse|http NAME URL |
Add a remote SSE or streamable-http server |
tinycode mcp auth NAME --token TOKEN |
Set Authorization: Bearer <token> |
tinycode mcp auth NAME --env VAR |
Set Authorization: Bearer {env:VAR} |
tinycode mcp logout NAME |
Clear the Authorization header |
tinycode mcp debug NAME |
Connect once and print handshake / tools diagnostics |
Flags: --project writes to the innermost project config (creates .tinycode/tinycode.json if needed). Without --project, writes go to the user config under ConfigDir (creates tinycode.json when none exists). -e KEY=VALUE sets stdio env; --header "Key: Value" sets remote headers. http is an alias for streamable-http.
mcp list and mcp debug start a short-lived MCP client in-process (they do not require tinycode serve). Interactive browser OAuth is not supported — use Bearer tokens or {env:VAR} refs (see below).
Examples:
tinycode mcp add context7 -- npx -y @upstash/context7-mcp
tinycode mcp add -e EXA_API_KEY exa -- npx -y exa-mcp-server
tinycode mcp add --transport http github https://api.githubcopilot.com/mcp/
tinycode mcp auth github --env GITHUB_PERSONAL_ACCESS_TOKEN
tinycode mcp list
tinycode mcp debug context7You can also add MCP servers directly in your config file:
{
"mcp": {
"my-server": {
"command": "npx",
"args": ["-y", "@my/mcp-server"],
"env": {
"API_KEY": "{env:MCP_API_KEY}"
}
}
}
}The command field accepts either a string or an array (["npx", "-y", "@my/mcp-server"]). You can also use "command": "npx" with a separate "args" array. Config env substitution uses {env:VAR} only (not $VAR / ${VAR}).
Stdio (default) -- tinycode spawns the MCP server as a child process and communicates over stdin/stdout:
{
"mcp": {
"local-server": {
"command": "my-mcp-server",
"args": ["--port", "0"]
}
}
}SSE -- connect to a remote MCP server over HTTP Server-Sent Events:
{
"mcp": {
"remote-server": {
"url": "https://mcp.example.com/sse",
"transport": "sse"
}
}
}Streamable HTTP -- the newer MCP transport:
{
"mcp": {
"streamable-server": {
"url": "https://mcp.example.com/mcp",
"transport": "streamable-http"
}
}
}Interactive MCP OAuth (browser login) is parked / unsupported. Prefer:
tinycode mcp auth NAME --token …or--env VAR(writes anAuthorizationheader)- Static headers in config, e.g.
"Authorization": "Bearer {env:TOKEN}" - Optional
oauth.access_tokenin config (library helpers only; no product OAuth flow)
Use tinycode mcp list / debug from the CLI, or /mcp / Ctrl+X i in the TUI. The dialog shows connection status and tool counts. From the dialog you can:
- View each server's status (connected, error, disconnected)
- Trigger a reconnect for failed or disconnected servers
- See the number of tools each server provides
When running tinycode serve / tinycode web:
| Method | Path | Response |
|---|---|---|
GET |
/mcp or /mcp/status |
Map of server name → {name, status, error?, toolCount} |
POST |
/mcp/{name}/reconnect |
{"status":"reconnecting"} |
Status values: disconnected, connecting, connected, reconnecting, error.
MCP server status also appears in the sidebar (Ctrl+X b):
- Green dot -- connected, with tool count
- Red dot -- error (hover for details)
- Gray dot -- disconnected or connecting
Tinycode automatically reconnects MCP servers that disconnect.
Language Server Protocol (LSP) integration provides code intelligence to the model -- go-to-definition, diagnostics, hover info.
LSP is enabled by default. Set "lsp": false to disable it entirely:
{
"lsp": false
}Or configure per-server overrides (timeout is in seconds):
{
"lsp": {
"enabled": true,
"timeout": 30,
"servers": {
"go": {
"command": "gopls",
"args": ["serve"],
"env": {}
},
"typescript": {
"disabled": true
}
}
}
}Server keys are language names (go, typescript, python, rust, …), not binary names.
When enabled, tinycode detects available language servers on your PATH (gopls for Go, typescript-language-server for TypeScript, etc.) and starts them lazily when a relevant file is opened.
A formatter rewrites a file after the agent writes or edits it. Formatting is off until you turn it on. The web status popover lists the result of GET /formatter on the LSP tab.
"formatter": true enables the built-in gofmt formatter for .go files. It uses Go's go/format package, so the gofmt binary does not need to be on PATH.
{
"formatter": true
}An object enables the built-ins and then applies per-name overrides. A custom formatter's command is an argument list. Tinycode appends the file path as the last argument and runs the command in the file's directory, with a 30 second timeout. When more than one enabled formatter lists the same extension, the one whose name comes first alphabetically runs.
{
"formatter": {
"gofmt": { "disabled": true },
"prettier": {
"command": ["prettier", "--write"],
"extensions": [".ts", ".tsx", ".js", ".jsx"]
}
}
}write, edit, and apply_patch (creates and updates) run the formatter after the file is saved. Deletes are left alone. The tool output says Formatted with <name> when the bytes change. If the formatter fails, the written file stays as the agent saved it and the tool output says Formatter failed:.
Plugins are standalone Go binaries that extend tinycode with custom tools and lifecycle hooks. They communicate over JSON-RPC via stdin/stdout. On load, each plugin tool is registered as plugin__{pluginName}__{toolName}.
These run in-process and are always available — do not add them to "plugins" or run plugin install:
| Builtin | Description |
|---|---|
| notify | Desktop notifications for session events |
| code-review | Git diff formatted as a markdown review block |
| handoff | Cross-session context save/load |
| context-pruning | Deduplicates repeated tool outputs to save context |
# List curated registry plugins (INSTALLED + IN_CONFIG columns)
tinycode plugin list
# List by category (sre, security, ai-ml, platform, developer, essential)
tinycode plugin list --category sre
# Install from source (if cmd/plugin-<name> exists in the repo)
tinycode plugin install safety-net
# Install from a pre-built binary
tinycode plugin install safety-net --from dist/plugins/plugin-safety-netBinary resolution order when a plugin is loaded:
~/.config/tinycode/plugins/<name>tinycode-plugin-<name>on your PATH- Registry install hint if the name is curated but no binary was found
From a tinycode checkout, make build-plugins writes binaries to dist/plugins/plugin-* (e.g. dist/plugins/plugin-safety-net). Copy or install with --from as above.
Add external plugin names to your config:
{
"plugins": [
"safety-net",
"telemetry"
]
}Plugins are organized by category (sre, security, ai-ml, platform, developer, essential). Run tinycode plugin list for the full list. Highlights:
| Plugin | Category | Description |
|---|---|---|
| safety-net | security | Pre-execution safety checks for destructive commands |
| pilot | essential | Autonomous agent pilot mode |
| telemetry | essential | Usage telemetry and analytics |
| ocp-context-injection | sre | OpenShift cluster context injection |
| container-linter | security | Containerfile linting and bootc support |
See plugin-catalog.md for the complete catalog.
tinycode initOptional Red Hat plugin/role setup (not required for first run). Walks you through username and role-based plugin selection (OpenShift SRE, Security, AI/ML, Platform, Developer), and can set a default model if providers are already available. For model setup on first run, use /connect in the TUI, set OPENROUTER_API_KEY, or run Ollama.
tinycode plugin uninstall safety-nettinycode webThis starts the API server and opens the embedded web interface in your browser (with an auth URL that sets a session cookie). The web UI is a SolidJS SPA (embedded via go:embed) that communicates with the same backend as the TUI. The in-browser terminal (PTY) is not available in the Go product (PTY_SUPPORTED=false); session share/publish is disabled by default (config.share defaults to "disabled").
tinycode serve exposes the JSON API plus a thin ops console (status, doctor, models, providers, agents, sessions, plugins) — not the full chat SPA. Use tinycode web for the Solid chat UI. If you open the serve URL without auth, you get a short HTML recovery page. The one-shot ?auth_token=… URL is printed to the terminal when tinycode serve starts.
By default, tinycode serve / tinycode web generates an auth token. The log records Bearer usage, the server URL, and the first 8 characters of the token. tinycode web opens a URL with ?auth_token=… that sets a cookie (SameSite=Lax), then redirects to a clean path. tinycode serve prints that URL to the terminal (it does not open a browser, and it does not write the URL to the log). Set a custom token:
TINYCODE_AUTH_TOKEN=my-secret tinycode webOr disable auth entirely (for local-only use):
TINYCODE_NO_AUTH=1 tinycode serveThe web UI has its own set of keyboard shortcuts:
| Key | Action |
|---|---|
| Mod+Shift+P | Open command palette |
| Mod+N | New session |
| Mod+Shift+A | Archive session |
| Mod+. | Open settings |
| Mod+/ | Toggle sidebar |
| Mod+Shift+1 | Focus file tree |
| Mod+Shift+M | Select model |
| Mod+Shift+E | Select agent |
| Enter | Send message |
| Shift+Enter | Newline in prompt |
| Escape | Cancel / close dialog |
("Mod" is Cmd on macOS, Ctrl on Linux/Windows.)
The web UI provides:
- File tree -- browse and navigate project files in the sidebar; click to reference in prompt
- Session management -- create, archive, fork, and switch sessions
- Agent system -- same agent selection as the TUI
- VCS integration -- view git status and diffs
- Settings -- configure model, theme, and preferences visually
Not available in the Go web UI: in-browser terminal/PTY, and session share/publish (config.share defaults to "disabled").
GET /help returns a JSON response with keybindings, commands, and features:
curl http://localhost:4096/helpResponse structure:
{
"keybindings": [{"key": "mod+shift+p", "description": "Open command palette", "category": "General"}],
"commands": [{"name": "review", "description": "Review changes", "source": "builtin"}],
"features": [{"name": "@ File References", "description": "Type @ to reference files..."}]
}The run subcommand runs tinycode non-interactively -- process a prompt and exit. Same agents, tools, and permissions as the TUI.
# Prompt from arguments
tinycode run -m ollama/qwen3:8b "explain the main function"
# Pipe from stdin
echo "explain this codebase" | tinycode run -m ollama/qwen3:8b
# Specific directory
tinycode run ~/projects/myapp -m ollama/qwen3:8b "add validation"
# Use a specific agent
tinycode run --agent debugger -m ollama/qwen3:8b "why is TestFoo failing?"
# Continue an existing session
tinycode run -c -m ollama/qwen3:8b "now add tests for that"| Flag | Description |
|---|---|
-m, --model |
Model to use (provider/model) |
--agent |
Agent to use (default: build) |
--format |
Output format: default (text) or json (NDJSON events) |
-c, --continue |
Continue the most recently updated session |
-s, --session |
Session ID to continue (exact ID) |
-r, --resume |
Resume by session ID or title/slug |
--title |
Session title; with -c, updates the continued session title |
--dangerously-skip-permissions |
Auto-approve all tool permissions |
-i, --interactive |
Show permission prompts on stderr |
--permissions |
Permission handling: default or json |
--max-iterations |
Max processor iterations (default: 200) |
--multi-turn |
Loop on stdin after initial prompt |
--fail-fast |
Multi-turn: exit on first turn error |
--append-system-prompt |
Append text to the system prompt |
--append-system-prompt-file |
Append file contents to the system prompt |
--max-tokens |
Cumulative token budget (input+output) |
--safe-mode |
Skip plugins, MCP, and user agents |
Default rules allow read *. Asks (shell/edit/etc.) are auto-rejected in headless mode unless you opt in:
| Mode | Flag | Behavior |
|---|---|---|
| Auto-reject asks | (default) | Allowed rules (e.g. read *) pass; Ask requests are rejected |
| Auto-approve | --dangerously-skip-permissions |
All permissions approved |
| Interactive | -i |
Prompts on stderr, reads yes/no from stdin |
| JSON | --permissions json |
NDJSON permission protocol via stdin/stdout |
| Config | permission.allow / deny |
Pre-approve or deny patterns |
All output is emitted as newline-delimited JSON events:
| Event type | Description |
|---|---|
session |
Session resolved (sessionID) |
text |
Text delta from the model |
tool_begin |
Tool call started |
tool_call_end |
LLM finished tool-call args |
tool_end |
Tool execution completed (output, isError) |
reasoning |
Model thinking/reasoning block |
step_start |
Processor iteration started |
step_finish |
Processor iteration completed |
warning |
Non-fatal warning |
compacted |
Context compaction occurred |
permission |
Ask request (--permissions json) |
ready |
Multi-turn ready for next prompt |
done |
Run finished (ok: true) |
error |
Run/turn failed (message) |
In text format, tool progress goes to stderr (tool <name> begin / tool <name> end (...)).
With --multi-turn, tinycode loops on stdin after the initial prompt. Any turn error causes a non-zero exit at the end (or immediately with --fail-fast). Type exit/quit or Ctrl+D to stop.
tinycode run --multi-turn -m ollama/qwen3:8b "explain main.go"
# After response, type next prompt:
# > now add error handling
# > exitIn JSON mode, use structured messages:
← stdout: {"type":"session","sessionID":"ses_..."}
→ stdin: {"type":"prompt","text":"explain main.go"}
← stdout: {"type":"ready"}
→ stdin: {"type":"prompt","text":"now add tests"}
← stdout: {"type":"ready"}
→ stdin: {"type":"exit"}
← stdout: {"type":"done","sessionID":"ses_...","ok":true}
tinycode [command|directory] [flags]
Running with no command starts the TUI.
| Command | Description |
|---|---|
tui |
Start terminal UI (default) |
run |
Run a prompt non-interactively and exit |
serve |
Start headless API server (port 4096) |
web |
Start server and open web interface |
acp |
Agent Client Protocol mode (stdio, for IDE integration) |
models |
List available models |
providers |
List discovered providers |
session |
Manage sessions (list, delete) |
export |
Export session messages as JSON |
agent |
List available agents |
plugin |
Manage plugins (list, install, uninstall) |
init |
Red Hat plugin/role setup (optional; not first-run) |
doctor |
Run diagnostics and check system health (providers, config, database, agents) |
debug |
Debug info (config, paths) |
status |
Show server health and version info |
version |
Print version |
help |
Show usage |
These flags apply to the TUI (default mode) and run mode:
| Flag | Description |
|---|---|
-m, --model |
Model to use (provider/model) |
--title |
Set the session title |
-c, --continue |
Continue the most recent session |
-r, --resume <id> |
Resume a session by ID or title substring |
--append-system-prompt <text> |
Append text to the system prompt |
--append-system-prompt-file <path> |
Append file contents to the system prompt |
--max-tokens <n> |
Cumulative token budget (input+output); session aborts when exceeded |
--safe-mode |
Skip plugins, MCP servers, and user-defined agents |
The --max-tokens flag sets a cumulative token ceiling for a session. The processor tracks total input and output tokens across all iterations; when the sum exceeds the budget, the session stops with a "token budget exceeded" error. This is useful for unattended runs (tinycode run) where you want to cap cost.
# Abort after 50k total tokens
tinycode run --max-tokens 50000 -m ollama/qwen3:8b "refactor main.go"
# Also works in TUI mode
tinycode --max-tokens 100000--safe-mode starts tinycode without loading plugins, MCP servers, or user-defined agents. Only built-in agents and tools are available. The status bar shows a bold orange SAFE MODE indicator when active.
tinycode --safe-modeResume a previous session from the command line:
# Continue the most recent session
tinycode -c
# Resume a specific session by ID or title substring
tinycode -r "auth refactor"
tinycode -r ses_01HQXY...In run mode, the same flags work:
tinycode run -c -m ollama/qwen3:8b "now add tests for that"
tinycode run -r "auth refactor" -m ollama/qwen3:8b "continue"
tinycode run -c --title "renamed" -m ollama/qwen3:8b "next step"# TUI
tinycode # Current directory
tinycode ~/projects/myapp # Specific directory
tinycode -m ollama/qwen3:8b # With specific model
# Non-interactive
tinycode run -m ollama/qwen3:8b "fix the bug"
echo "explain main.go" | tinycode run -m ollama/qwen3:8b
# Server
tinycode serve -m ollama/qwen3:8b # Headless API
tinycode web # Web UI
# Inspection
tinycode models # List models
tinycode providers # List providers
tinycode agent # List agents
tinycode status # Health check
tinycode doctor # Full diagnostics check
tinycode debug config # Dump merged config as JSON
tinycode debug paths # Show all config/data pathstinycode is designed so your data stays on your machine by default.
What is stored locally:
| Data | Location |
|---|---|
| Sessions, messages, conversation history | ~/.local/share/tinycode/tinycode.db (SQLite) |
| Config, agents, skills, themes | ~/.config/tinycode/ |
| Logs | ~/.local/share/tinycode/log/ |
What leaves your machine:
Nothing --- unless you configure a cloud provider. When you send a prompt to a cloud provider (OpenRouter, Anthropic, OpenAI, etc.), the current prompt and conversation context are sent to that provider's API endpoint. Local providers (Ollama, LM Studio, vLLM) keep everything on your network.
What is not collected:
No telemetry, no analytics, no crash reports, no usage tracking. No sign-up or account required. The binary makes zero network calls unless you explicitly configure a provider.
Type /privacy in the TUI to see this information with your configured providers listed.
Logs are written to ~/.local/share/tinycode/tinycode.log. The file rotates at 5 MiB and keeps three older copies (tinycode.log.1 through tinycode.log.3). For verbose output:
TINYCODE_LOG_LEVEL=debug tinycodeRun tinycode doctor for a headless health check that verifies every subsystem without starting the TUI:
tinycode doctorIt checks: version, Go runtime, config validity, data directory writability, database access, agent loading, provider connectivity, MCP servers, plugins, skills, and log file writability. Each check shows a green check, red X, or yellow warning. Non-zero exit code if any critical check fails.
Type /diagnostics in the TUI to open a diagnostics dialog showing:
- Merged config
- Provider status
- Active agents and plugins
- MCP server connections
- System info (Go version, OS, architecture)
/debug asks the debugger agent to investigate a failure. It does not open this dialog, and it is not tinycode debug.
From the CLI:
tinycode debug config # Print merged config as JSON
tinycode debug paths # Show all file paths| Problem | Solution |
|---|---|
| "No models discovered" | Make sure Ollama (or your provider) is running. Check with ollama list or curl http://localhost:11434/api/tags. |
| Model not found | ollama pull <model> to download it first. |
| Tool calling not working | The model may not support function calling. Try a larger model (8B+). Tinycode probes for this on startup and disables the capability if unsupported. |
| Provider disappeared | After 3 consecutive failures, providers are removed. Restart tinycode to re-discover. |
| Spinner frozen | Make sure to propagate the tea.Cmd returned by SetWorking(true). If you are developing tinycode, this is a known pitfall. |
| MCP server not connecting | Check the command path and args in your config. Run the MCP server manually to verify it starts. Status is shown in the sidebar. |
| Config not loading | Config files are checked as tinycode.jsonc, tinycode.json, then config.json in each directory. Run tinycode debug paths to see which files are found. |
| Wrong config applied | Project config files walk up the directory tree, with innermost overriding outermost. Use tinycode debug config to see the merged result. |
/helpin the TUI shows the command palette with all keybindings and commandstinycode helpshows CLI usage- Architecture docs for how tinycode works internally
- Plugin Development for building custom plugins
- Troubleshooting guide for more detailed solutions
{ // Default model (provider/model format) "model": "ollama/qwen3:8b", // Default agent on startup "default_agent": "build", // Tab/Shift-Tab persona cycle (agent picker still lists all) "cycle_agents": ["build", "general", "ops", "plan", "architect", "code-reviewer"], // Shell for tool execution "shell": "/bin/zsh", // Log level: debug, info, warn, error "logLevel": "info", // Model favorites for /scoped-models "scopedModels": [ "ollama/qwen3:8b", "ollama/qwen3.5:9b" ], // Color theme "theme": "dracula", // Permission rules "permission": { "allow": ["read", "grep", "glob"], "deny": ["shell rm *"] }, // Custom instructions included in every prompt "instructions": [ "Always use Go standard library where possible" ], // Agent overrides "agents": { "scientist": { "disable": true }, "my-agent": { "prompt": "You are a Go expert.", "description": "Custom Go agent", "mode": "primary" } } }