smith is the built-in agent that ships with construct. It talks to OpenAI,
Anthropic, Google Gemini, Meta Model API, xAI Grok, DeepSeek, OpenRouter, or a
local Ollama directly, and can also draw on your Codex, Claude Code, Grok, or
Kimi Code subscription. Smith runs its own agent loop with shell + patch editing
- browser automation + construct-control tools. Many PRs for the construct repository have already been made from smith sessions running inside construct.
# Pick a provider — only one of these needs to be set:
export ANTHROPIC_API_KEY=sk-ant-...
# or export OPENAI_API_KEY=sk-...
# or export GEMINI_API_KEY=... # (or GOOGLE_API_KEY)
# or export META_API_KEY=... # (or MODEL_API_KEY)
# or export GROK_API_KEY=... # (or XAI_API_KEY)
# or export DEEPSEEK_API_KEY=...
# or export OPENROUTER_API_KEY=sk-or-...
# or codex login, then use --model codex-oauth:gpt-5.4-mini
# or claude login, then use --model claude-oauth:sonnet
# or grok login, then use --model grok-oauth:grok-4.6
# or kimi login, then use --model kimi-oauth:k3
# or run a local ollama (default http://localhost:11434)
construct new --prompt "list the rust files in this repo and summarize what each crate does" smithPass --model <spec> on construct new (or set CONSTRUCT_SMITH_MODEL).
The spec is one of:
openai:<name>— e.g.openai:gpt-5-minianthropic:<name>— e.g.anthropic:claude-haiku-4-5claude-oauth:<name>— e.g.claude-oauth:sonnet(alias:claude-code-oauth:)gemini:<name>— e.g.gemini:gemini-2.5-prometa:<name>— e.g.meta:muse-spark-1.1usingMETA_API_KEYorMODEL_API_KEYgrok:<name>— e.g.grok:grok-4.6usingGROK_API_KEYorXAI_API_KEYdeepseek:<name>— e.g.deepseek:deepseek-v4-prousingDEEPSEEK_API_KEYopenrouter:<name>— e.g.openrouter:openrouter/autousingOPENROUTER_API_KEYgrok-oauth:<name>— e.g.grok-oauth:grok-4.6using the Grok CLI auth filekimi-oauth:<name>— e.g.kimi-oauth:k3using the Kimi Code CLI loginollama:<name>— e.g.ollama:llama3.1codex-oauth:<name>— e.g.codex-oauth:gpt-5.4-mini@<name>— a named endpoint profile (see Model profiles), e.g.@work-gatewayor@work-gateway:deepseek-v4-flashto override its model
Bare names auto-detect: gpt-* / o[1-5]* → OpenAI, claude-* →
Anthropic, gemini-* → Gemini, grok* → Grok, deepseek* → DeepSeek,
anything else → Ollama.
Use the explicit meta: prefix for Muse Spark; a bare muse-spark-1.1
continues to mean an Ollama model. When in doubt, use the explicit prefix.
openrouter: calls the OpenRouter aggregator (openrouter.ai/api/v1) using
OPENROUTER_API_KEY. Model IDs follow OpenRouter's vendor/model format (e.g.
openrouter:openrouter/auto or openrouter:stealth/ox-alpha). Because slash
IDs overlap with Ollama paths and routing through an aggregator is an explicit
billing choice (spec 0028), bare names never route to OpenRouter.
meta: calls Meta's Responses API directly. Smith streams assistant text,
supports parallel function calls and tool-result replay, and sends
store: false because construct persists and replays the conversation locally.
codex-oauth: uses your Codex CLI subscription login: run codex login
once so the credentials are stored, and smith reads them from
$CODEX_HOME/auth.json (falling back to ~/.codex/auth.json) and calls
the OpenAI-compatible API directly with the subscription OAuth token. The
codex CLI does not need to stay on PATH at runtime. Smith passes its own
tools natively, so construct's normal tool approvals and transcript persistence
apply. This path uses your subscription, not OPENAI_API_KEY (that's the
separate openai: path).
claude-oauth: (or claude-code-oauth:) uses your Claude Code subscription login:
run claude login once, and smith reads credentials from the macOS Keychain
(Claude Code-credentials) or ~/.claude/.credentials.json (overridable via
CONSTRUCT_CLAUDE_OAUTH_CREDENTIALS), calling Anthropic's Messages API directly
with OAuth bearer tokens and native tools.
grok-oauth: uses the same OpenAI-compatible xAI API endpoint as grok:, but
loads a bearer token from the Grok CLI auth file instead of GROK_API_KEY /
XAI_API_KEY. Run grok login first. Smith reads
$GROK_HOME/.grok/auth.json when GROK_HOME is set, otherwise
~/.grok/auth.json, and chooses the newest unexpired key entry.
kimi-oauth: uses your Kimi Code subscription login: run kimi login once,
and smith reads $KIMI_CODE_HOME/credentials/kimi-code.json (default
~/.kimi-code/credentials/kimi-code.json) and calls Moonshot's
Anthropic-compatible coding backend directly with the OAuth bearer token.
Kimi access tokens are short-lived, so smith refreshes them through Kimi's
own token endpoint and writes the rotated tokens back to the same file the
CLI uses. Models: k3, k3-256k, kimi-for-coding,
kimi-for-coding-highspeed.
If you don't pass a model and CONSTRUCT_SMITH_MODEL isn't set, smith
picks: ANTHROPIC_API_KEY → claude-opus-4-8, else OPENAI_API_KEY
→ gpt-5, else GEMINI_API_KEY (or GOOGLE_API_KEY) →
gemini-2.5-pro, else META_API_KEY (or MODEL_API_KEY) →
muse-spark-1.1, else DEEPSEEK_API_KEY → deepseek-v4-pro,
else OPENROUTER_API_KEY → openrouter/auto,
else smith fails to start with an error explaining
what's missing. The initial Status event records the chosen provider:model
so you can verify.
Earlier versions fell through to ollama:llama3.1 here unconditionally, so a
machine with no Ollama server running got a session that looked healthy and
then died mid-turn with a raw transport error instead of failing loudly at
start. OAuth subscriptions (claude-oauth:, codex-oauth:, grok-oauth:,
kimi-oauth:) and Ollama are still fully supported — pass one of the explicit prefixes
above (or CONSTRUCT_SMITH_MODEL) rather than relying on auto-detect to
guess them. In the construct TUI, run /configure (or M-x configure) to
see every auth method smith supports, its live-detected status, and — when
you pick one — persist it as smith's default via CONSTRUCT_SMITH_MODEL.
The base-URL env vars below bind one endpoint per wire protocol. To use
several endpoints of the same protocol in one session — e.g. first-party
OpenAI plus two OpenAI-compatible vendors — declare named profiles in
config.toml and switch between them at runtime with /model @<name>.
Each [smith.models.<name>] entry sets:
provider— wire protocol to speak:openai,anthropic,gemini,meta,grok,deepseek,openrouter, orollama. (OAuth providers can't be profiled — use their prefixes directly.)base_url— endpoint URL (defaults to the protocol's public endpoint).api_key_env— name of the env var holding the key (preferred). Orapi_key = "..."inline (discouraged). If neither is set, the protocol's standard key env var is used (OPENAI_API_KEY, etc.).model— default model name; override per call with@<name>:<model>.- Anthropic profiles may also set
anthropic_cache_control = true|false,anthropic_betas = ["..."], andanthropic_context_window_tokens = 1000000. Cache control defaults on only for the public Anthropic endpoint; compatible gateways must opt in.
None of the direct-API-key providers needs a profile — the key plus the
<provider>: prefix already reaches its public endpoint, and the same key
makes it a route target for other harnesses (spec 0179). Declare one only
for an endpoint Construct can't know: a private gateway, a reseller, a
second account.
[smith.models.work-gateway]
provider = "deepseek"
base_url = "https://deepseek.internal/v1"
api_key_env = "WORK_DEEPSEEK_KEY"
model = "deepseek-v4-pro"
[smith.models.groq-llama]
provider = "openai"
base_url = "https://api.groq.com/openai/v1"
api_key_env = "GROQ_API_KEY"
model = "llama-3.3-70b-versatile"
[smith.models.xai]
provider = "grok"
api_key_env = "XAI_API_KEY"
model = "grok-4.6"
[smith.models.meta]
provider = "meta"
api_key_env = "META_API_KEY"
model = "muse-spark-1.1"
[smith.models.claude-long]
provider = "anthropic"
api_key_env = "ANTHROPIC_API_KEY"
model = "claude-sonnet-4-6"
anthropic_cache_control = true
anthropic_betas = ["context-1m-2025-08-07"]
anthropic_context_window_tokens = 1000000construct new --model @work-gateway --prompt "..." smith # start on a profile
/model openai:gpt-5 # first-party OpenAI
/model deepseek:deepseek-v4-pro # DeepSeek's public endpoint
/model @work-gateway # DeepSeek via a private gateway
/model @groq-llama:llama-3.1-8b-instant # Groq, one-off model override
/model # shows current + lists @profiles
Profiles are always referenced with the explicit @ prefix; bare names never
resolve to a profile. The status line shows @<name>:<model> so you can tell
which endpoint is active.
Smith accepts PNG, JPEG, GIF, and WebP images as native multimodal user input.
In the TUI, use C-x v (or /paste) to paste a clipboard image, drop an image
file into the terminal, or include an explicit local path in the prompt:
Describe ./screenshots/error.png
Compare [#file:/path/to/session/attachments/before.png] with ./after.jpg
Construct stores pasted/uploaded bytes in the session first; Smith snapshots the image into its persisted conversation when the prompt is submitted. The same image therefore survives daemon restart and provider retry even if the source file later changes. Limits are 5 MiB per image and 20 images per turn.
OpenAI, Anthropic (including Claude/Kimi OAuth), Gemini, Meta, Codex OAuth, OpenRouter/Grok, and Ollama wires receive provider-native image content. The selected model must itself support vision. DeepSeek's current chat endpoint is text-only, so Smith rejects image turns locally and asks you to switch providers; it does not silently send a path as plain text.
Smith registers three tool sets: local development tools, Chrome DevTools browser automation, and daemon/fleet control tools (including subagents).
Smith provides a minimal, Codex-style tool surface rather than separate read/list/find primitives:
shell: run commands in a shell (command, optionaltimeout_secs,interactive,read_only). File reads, search, listing, and repo inspection go through standard tools (cat,rg,ls,git,sed -n) instead of dedicated file-reading tools.write_stdin: write text lines or send EOF to the standard input of an interactive process spawned byshell(addressed bypid).edit_file: atomic find-and-replace editor. Supports single edit (path,find,replacewith unique match required) or multi-hunk / multi-file batch edits (edits: [{path?, find, replace}]). Creating a new file uses an emptyfindand non-existentpathwith contents inreplace. All hunks are validated first and applied atomically; if any match fails or matches more than once, nothing is written.
Native tools drive Chrome through DevTools remote debugging and emit the browser preview thumbnail that the TUI renders above the session:
browser_open: open a URL in Chrome (starts Chrome with remote debugging on port 9222 if needed) and emit a preview overlay.browser_inspect: list open tabs (with no args) or inspect tab content (title, URL, visible body text, links) selected bytab_idorurl_contains.browser_screenshot: capture a screenshot (viewport orfull_page) of a Chrome tab and emit preview overlay.browser_eval: evaluate JavaScript / async expressions in a Chrome tab for browser automation and DOM extraction.
These tools are native to smith and are also exposed through construct's MCP server for other harnesses.
Unless withheld via CONSTRUCT_SMITH_FLEET_TOOLS=off, smith sessions have full read and write access to other sessions on the daemon and can orchestrate child subagents (specs 0089, 0171):
- Session inspection (Safe):
agentd_context(structured memory, widgets, environment, playbook, system reference),agentd_whoami(returns the calling session ID),agentd_list_sessions(lists every session with state, cwd, harness, approval mode, and activity timestamps),agentd_get_session(full summary and structured transcript),agentd_get_transcript(event log slice byfromsequence andlimit),agentd_get_output(recent PTY scrollback text),agentd_get_diff(git diff HEADfor a session's worktree),agentd_list_harnesses(lists available harnesses). - Session control (Risky):
agentd_create_session(spawn a session on any harness),agentd_send_input(send input line),agentd_send_keys(send raw base64 bytes for control/arrow keys),agentd_interrupt_session(sendC-c),agentd_stop_session(graceful stop),agentd_kill_session(SIGKILL adapter),agentd_delete_session(drop transcript and worktree),agentd_pin_session(toggle pin strip status),agentd_rename_session(set/clear session title),agentd_set_session_group(group assignment and position),agentd_move_session(reorder session up/down). - Recurring loops (scheduler):
agentd_loop_create(Risky; recurring prompt injected at interval),agentd_loop_list(Safe; list loops and next fire times),agentd_loop_update(Risky; change interval, prompt, or expiry),agentd_loop_remove(Risky; stop recurring loop). - Playbook:
agentd_playbook_get(Safe; read playbook markdown, version, and shimmer state),agentd_playbook_edit(Risky; apply anchored find/replace edits). - Subagents: Smith-owned child backing sessions nested under the parent session:
agentd_subagent_create(Risky; spawn subagent),agentd_subagent_list(Safe; list owned subagents and summaries),agentd_subagent_peek(Safe; inspect scrollback or structured event tail),agentd_subagent_enqueue(Risky; send follow-up prompt),agentd_subagent_cancel(Risky; interrupt subagent),agentd_subagent_delete(Risky; remove subagent).
Tool calls run with your permissions. Smith classifies each tool call by risk:
- Safe (runs immediately without prompting, fans out concurrently in the agent loop):
- Browser inspection:
browser_inspect,browser_screenshot. - Fleet and daemon reads:
agentd_context,agentd_whoami,agentd_list_sessions,agentd_get_session,agentd_get_transcript,agentd_get_output,agentd_get_diff,agentd_list_harnesses,agentd_loop_list,agentd_playbook_get,agentd_subagent_list,agentd_subagent_peek. - Dynamic downgrades:
- A
shellcall explicitly markedread_only: true(andinteractive: false/omitted) is downgraded to Safe, allowing read commands (e.g. search, inspection) to run concurrently without a gate. - An
edit_filecall whose targets all fall inside paths allowed by the auto-approval policy (such as session widget directories configured viaCONSTRUCT_AUTO_APPROVE_PATHS) is downgraded to Safe.
- A
- Browser inspection:
- Risky (governed by the session's approval mode):
- Local/browser mutations:
shell(mutating/default),write_stdin,edit_file(outside auto-approved paths),browser_open,browser_eval. - Fleet mutations: all session-modifying
agentd_*tools, loop creation/updates/removal, playbook edits, and subagent creation/lifecycle tools.
- Local/browser mutations:
Smith implements three explicit per-session approval modes (spec 0015):
manual(default): Safe tools run immediately. Risky tools pause and display an inline approval prompt in the session. The modeline badge displays[manual].auto_review: Safe tools run immediately. Risky tools are first evaluated by an automated reviewer prompt (or fast-path approved if recognized as a routine development shell command).- If the reviewer approves the action as routine, bounded, and task-relevant development work inside the git worktree, the tool runs automatically.
- If the action is ambiguous, broad, touches secrets, mutates outside the worktree, or the reviewer is uncertain, it defers to the user (
ask_user). - The reviewer never denies on its own — only a human makes the final rejection.
- The modeline badge displays
[auto-review].
always-approve(unsafe_autoon wire): Both Safe and Risky tools run automatically without asking the user. The modeline badge displays[always-approve].
When a Risky tool requires human decision in manual mode (or when auto_review defers):
y/ Enter: Approve the current call.n/ Esc /C-g/C-c: Deny the current call. Returns a synthetic "user denied" error to the model so it can adapt its approach.a/A: Switch the session toauto_reviewmode and vet this pending call immediately. If the reviewer approves, execution continues; if uncertain, it prompts again.f/F: Switch the session toalways-approve(unsafe_auto), approving the current call and running all future calls without prompts.
When an approval prompt changes the approval mode, Smith emits an ApprovalModeChanged event so the daemon and all connected clients update immediately.
- Cycle modes anytime: Press
C-x A(Emacs) orA(Vim normal mode), or click the[manual]/[auto-review]/[always-approve]badge on the TUI modeline. Cycling follows the order:manual→auto-review(auto_review) →always-approve(unsafe_auto) →manual. - Initial automode override: Set
CONSTRUCT_SMITH_AUTOMODE=1in the environment to start the session directly inalways-approve(unsafe_auto) mode rather thanmanual(ideal for non-interactive or batch runs).
The full tool output goes to the transcript (you see everything). The
agent's context only gets a truncated head + [… N bytes elided …] + tail
(8 KiB budget per call), so large command outputs don't overwhelm the context
window.
Smith automatically manages context budget through two layers:
- Auto-compaction: When the provider-anchored preflight count reaches 65%
of the model's effective context window (
AUTO_COMPACT_RATIO = 0.65), Smith requests a structured summary of older history and prepends a[Compacted earlier context]turn, preserving recent turn pairs verbatim (DEFAULT_KEEP_PAIRS = 4). You can also trigger manual compaction anytime with/compact [N]. Auto-compaction is enabled by default; disable withCONSTRUCT_SMITH_AUTO_COMPACT=off(or0/false). - Rolling prune: If context exceeds 70% utilization (
UTILIZATION = 0.70), the oldest turn pairs are pruned, always keeping at least the two most-recent turn pairs. Smith learns and persists runtime limits when providers report overflow errors (spec 0070).
After each response, the provider's input-token count is authoritative. Before the next request, Smith adds only a character-estimated delta for content added or removed since that report. Before the first report (including after resume), or when a provider omits usage, the whole request uses the character estimate as a preflight fallback. Smith starts Muse Spark 1.1 with its advertised one-million-token input window and retains the normal runtime limit-learning fallback.
First-party Anthropic API-key and Claude OAuth requests add prompt-cache breakpoints to the stable system/tool prefix and recent user boundaries. Known Claude Sonnet 4 models on the public API also enable Anthropic's one-million- token context beta automatically; set the Anthropic capability options on a named profile for a new model or compatible endpoint.
Beyond running its own sessions, smith powers several daemon-level conveniences. If none of the credentials above exist, these degrade — and the daemon tells you how (spec 0151):
- Session auto-naming — every new session's title is generated from its first prompt via a cheap smith one-shot. Without a smith credential, sessions on model harnesses (claude, codex, …) fall back to a hidden one-shot on their own harness; smith and shell sessions keep their default hash names.
- Next-prompt suggestions — smith and shell sessions generate suggestions via smith; other harnesses always use their own model.
- The minibuffer session — the bottom input strip is a smith session by default. Without a credential it still handles slash commands but cannot act as an agent (spec 0071).
Inspect the live status with construct harnesses (the ambient features:
block) or the /configure dialog's Features tab, which maps each
feature to its cause and fix. The first time a feature actually skips work
for lack of a credential, the TUI shows a clickable smith: no credential
notice in the status bar that opens /configure.
CONSTRUCT_SMITH_AUTOMODE=1— start the session inalways-approve(unsafe_auto) mode instead ofmanual.CONSTRUCT_SMITH_MODEL=<spec>— default model when--modelis omitted.CONSTRUCT_SMITH_FLEET_TOOLS=off— withhold tools that reach outside the session (daemon-control and subagents), exposing only local coding and browser tools.CONSTRUCT_SMITH_AUTO_COMPACT=off— disable auto-compaction before rolling prune.CONSTRUCT_SMITH_ANTHROPIC_CACHE_CONTROL=on|off— override prompt-cache breakpoints for the built-in Anthropic API-key provider.CONSTRUCT_SMITH_ANTHROPIC_BETAS=<beta,...>— add comma-separatedanthropic-betacapabilities to the built-in Anthropic provider.CONSTRUCT_SMITH_ANTHROPIC_CONTEXT_WINDOW_TOKENS=<count>— declare its effective input window (for example1000000).ANTHROPIC_API_KEY,OPENAI_API_KEY,GEMINI_API_KEY(orGOOGLE_API_KEY),META_API_KEY(orMODEL_API_KEY),GROK_API_KEY(orXAI_API_KEY),DEEPSEEK_API_KEY,OPENROUTER_API_KEY— API keys for each supported direct provider. Each key set in the daemon's environment also makes its provider a route target for other harnesses with no further config (spec 0179) — see Model routing.CODEX_HOME— override the base directory used forcodex-oauth:auth lookup (reads$CODEX_HOME/auth.jsoninstead of~/.codex/auth.json).CONSTRUCT_CLAUDE_OAUTH_CREDENTIALS— override the credentials file path used byclaude-oauth:(default reads macOS Keychain itemClaude Code-credentialsor~/.claude/.credentials.json). Note thatCONSTRUCT_CLAUDE_BIN/CONSTRUCT_CLAUDE_CMDconfigure the standaloneclaudeCLI adapter harness, not Smith's directclaude-oauth:provider.GROK_HOME— override the base directory used bygrok-oauth:token lookup; Smith reads$GROK_HOME/.grok/auth.jsoninstead of~/.grok/auth.json.KIMI_CODE_HOME— override the base directory used bykimi-oauth:credential lookup (default~/.kimi-code);CONSTRUCT_KIMI_OAUTH_CREDENTIALSpoints at an exact credentials file.OPENAI_BASE_URL/ANTHROPIC_BASE_URL/GEMINI_BASE_URL/META_BASE_URL/OLLAMA_HOST— point at alternate endpoints. PointingOPENAI_BASE_URLat an OpenAI-compatible vendor (OpenRouter, DeepSeek, Groq, xAI, Mistral, …) reuses theopenai:path with no extra config. These bind one endpoint per protocol; to switch between several at runtime, use Model profiles instead.