Releases: ForgeAILab/smith
Release list
v0.2.9
Smith v0.2.9
Smith 0.2.9 fixes task_output, which could never run, and stops the
capability budget from killing turns: reference skills now register as an
outline plus one entry per section, skills get a bounded share of the
budget, and the budget itself follows the model instead of being a fixed
count.
Fixed: task_output could never read a background task
Polling a background task failed every single time with prepared filesystem permission requires a filesystem resource. The tool claimed
fs.read over a resource named by task ID, and the executor pairs a
declared permission against the prepared resource before any host is
asked: a filesystem permission requires a filesystem resource, and a task
ID is not one. Nothing about the task or the host mattered — the call was
rejected before it ran.
A background task's spool is a captured stream, not a workspace file, so
it claims stdio.read over the background_task resource and declares
no filesystem effect. Smith's tool authority allows it unattended, bound
to that resource kind so stdio authority cannot be borrowed to read
anything else: polling a build you already started does not raise an
approval prompt, and a model that backgrounded a long build can watch it
again.
Fixed: activating one more capability could kill the turn
A turn died with capability budget exceeded: 12101 tokens of 12000
while its input budget still had 900k tokens free. Three things
compounded.
Mid-turn registry.search staged capabilities as though the session were
empty. The selector consumes its budget from zero — right for the first
selection of a turn, wrong for every later one — so it bound a schema
that fit on its own but not beside what was already active, and the
planner then rejected the whole turn instead of the model getting a
"nothing fit" answer it could act on. Staging now charges the active set
first.
Skills had no ceiling. A tool schema is a few hundred tokens; a skill
carries instruction prose and can be thousands, and activation is
monotonic, so one bound speculatively on the first turn still holds its
tokens on the last. Skills now get a bounded share of the capability
budget — a tenth, floored so one reference section always fits and capped
at half so they can never crowd the tool schemas out.
And the overflow was fatal. The capability budget is resolver
discipline, and by the time the planner sees the fragments the
capabilities are already bound, so refusing the plan sheds nothing — it
only destroys a turn that would have fit the model's window. An overflow
is now recorded on the plan and carried on context_planned as
capability_overflow. What does not fit the input budget is still
rejected exactly as before.
Changed: reference skills load a section, not a document
Each built-in reference embedded a whole shipped document, so activating
smith.security spent 4.3k tokens and smith.configuration about 10k —
and because activation is monotonic, a reference bound on an early turn
held those tokens for the rest of the session. Three of them together
took 10,289 tokens of a 12,000 budget and left almost nothing for tools.
A reference now registers as a cheap outline naming its sections, plus
one activatable skill per ## section. The agent binds the outline to
see what a reference covers, then binds only the section that answers the
question in front of it. The same three references cost 715 tokens
instead of 10,289. The split happens by heading at load time rather than
by splitting the files, so docs/*.md stay whole for human readers and
for the links they carry, and an activated section is still byte-identical
to the shipped document.
Changed: the capability budget follows the model
context.capability_budget was an absolute token count applied to every
model. The input budget it is carved from is derived per model, so the
same number was a comfortable allowance on a million-token window and an
immediate failure on a small one, with nothing in a run to say which you
had.
Left unset, it is now derived from the model's own input budget — 15%,
clamped to 8,192–65,536 — and narrowed to the input budget itself, so a
model too small for the floor is bounded by its own window. Setting the
key explicitly still overrides the derivation.
Upgrading
Existing configuration, sessions, and protected checkpoints remain
compatible. An explicit context.capability_budget keeps working and
still wins over the derived value; removing it lets Smith size the budget
from the model.
Built-in reference skills changed name and shape: smith.configuration,
smith.headless, smith.persistence, and smith.security are now
outlines, and each section is its own entry such as
smith.security.credentials-and-secret-handling. A user, workspace, or
session skill that shadows one of the four by name shadows the outline,
as before.
The pinned Agent Runtime revision moves to 5291844
(smith-baseline-v0.2.9).
Full Changelog: v0.2.8...v0.2.9
v0.2.8
Smith v0.2.8
Smith 0.2.8 makes /undo reach the edits Smith made itself, keeps wide
characters on the screen and in the clipboard, and turns cache-miss
notices on by default.
Added: the plugin can discover which profiles exist
The plugin documented --profile without ever saying what a profile is
or where to find one, so Claude had to read ~/.smith/config.toml to
answer "which profiles can I use" — a file that can carry plaintext
api_key values. scripts/smith-profiles answers it instead: one local
read, no API call, resolving extends chains, marking the default, and
printing provider, model, posture, reasoning effort, and description per
profile, with --json for machine use. It reads only [profiles.*] and
never emits a [providers.*] table. The /smith:profiles command
injects the table inline, and the smith-profiles skill teaches the rule
the approval policy cannot express: posture outranks --approval,
because a plan or review profile never registers edit or shell
at all.
Changed: /undo recovers Smith's own edits in a mixed turn
A turn that mixed an exact Smith edit with an ambiguous shell delta used
to block automatic undo entirely, even though the exact half carried both
images and could be reversed with a checked write. /undo now targets
any not-yet-undone turn with at least one exact mutation: it reverses
those images after their per-path post-image checks, names the
unattributable tools in the preview, and leaves every path it cannot
attribute untouched. Turns with nothing but ambiguous deltas still refuse
and point at /diff and /revert, and /redo covers exactly what such
an undo reversed. The timeline labels a mixed turn mixed, and /status
plus the turn-complete notice say how far the automatic undo reaches.
Fixed: wide characters wrap and copy faithfully
Ratatui's word wrapper measures a pending word before adding the
grapheme that overflows it, so an unbroken run — every Chinese, Japanese,
or Korean sentence — could produce a row one column wider than the area,
and the last glyph silently disappeared past the right edge. Smith wraps
its own lines now, with the same rules for prose plus glyph-boundary
breaks for a word wider than the area, and the cursor follows the text
onto the wrapped row. Copying and highlighting snap to whole glyphs, so a
drag that stops on the second cell of a double-width character still
takes the character, and a copied line of Chinese no longer carries a
space after every character. A setup preview longer than its byte budget
also used to cut inside a multi-byte character and crash the TUI; the cut
lands on a character boundary now.
Changed: cache-miss notices are on by default
A significant cache miss is money already spent, and only the local
surface can say so while the user can still act on it, so the built-in
default for cache.miss_notices flips to true. The setting stays
presentation-only — provider requests, cache state, machine events, and
usage accounting are identical either way — and disabling it in a file,
profile, or run works exactly as before:
[cache]
miss_notices = falseUpgrading
Existing configuration, sessions, and protected checkpoints remain
compatible. The pinned Agent Runtime revision is unchanged from 0.2.7.
The one visible default change is cache-miss notices, shown above how to
turn off; /undo in a mixed turn now asks the same explicit confirmation
but reverses only the edits Smith made itself and names the rest.
Full Changelog: v0.2.7...v0.2.8
v0.2.7
Smith v0.2.7
Smith 0.2.7 makes a session identifiable from outside its own window, and
fixes two places where the interface described state it did not have.
Added: the terminal window is named after the session
Nothing in Smith wrote a window title, so the shell's last title stood for the
life of the TUI and several concurrent sessions left several identical tabs.
The data that tells them apart was already on screen, in the status model the
header renders from.
The TUI now sets the window or tab title to smith · <project> · <model>,
appending a short activity label while a turn or a child wait is actually in
flight. The title is written only when the rendered text changes, so a busy
redraw loop is not a stream of escape sequences, and it is cleared once when
the session ends. Restoring the title the shell had before Smith started is
deliberately not attempted: reading a title back is not portable across
terminals, and the shell's own prompt hook reasserts its title on the next
prompt.
A project name comes from the filesystem and a model id from configuration, so
neither is Smith's own text. Both are sanitized before they enter the escape
sequence — control characters, Trojan-Source bidi and invisible formatting
codepoints, collapsed whitespace, and a bounded length — and the write is
guarded by a terminal check. Piped stdout and smith -p receive no title
bytes; the latter is not wired to the title at all.
Fixed: installed coding agents resolve to a usable model
The selection inventory knew only explicit, trusted, and catalog origins, and
installed coding agents declare none of those. A profile naming
cli/<kind>/<model> was therefore reported as failing to resolve to a usable
provider and model pair, contradicting the zero-declaration contract those
agents are built on. The inventory now falls back to the built-in CLI
bookkeeping limits under their own BuiltIn provenance, and an explicit
[models] table still wins over it.
Previews had a second problem: they carried the active profile's
request-output and reserve values across as hard constraints, which disabled
every candidate with a smaller ceiling even though those values would not
survive the switch. Profile-scoped budgets no longer apply when previewing
another candidate. Values from layers that do survive a switch — environment,
flags, session overrides — still apply, and still disable a conflicting
candidate with a stated reason.
Fixed: the cursor sits where wide characters actually end
The composer reported the cursor as a character count while the renderer
placed it as a display column. On any line holding double-width text the two
disagreed: four CJK characters occupy eight columns and reported four, so the
cursor drew mid-glyph and drifted further with every wide character typed.
Cursor position and the position-to-index mapping are both measured in display
columns now, and remain inverses of each other.
Upgrading
Existing configuration, sessions, and protected checkpoints remain compatible.
The pinned Agent Runtime revision is unchanged from 0.2.6. The window title
needs no configuration and has no opt-out key; a terminal that ignores OSC 0
is unaffected.
Full Changelog: v0.2.6...v0.2.7
v0.2.6
Smith v0.2.6
Smith 0.2.6 stops installing a semantic-summary coordinator on every
persistent session.
Changed: semantic summarization is opt-in
Enabling persistence also enabled semantic summarization, and there was no
configuration key to decline it. Persistence says where a session is stored. It
does not say that a second model route should summarize it, and the coupling
meant every ordinary session carried a summary provider, an idle
summarization budget, and a protected projection for a feature it was never
asked about.
That projection was doing close to nothing. Across a full local session
history, turn-boundary compaction had fired zero times and idle compaction
three times in eighty-eight snapshots.
Summarization is now requested per session, resume included, so a session does
not inherit a second model route from the fact that it once had one.
Not changed: structural compaction
StructuralCompactor is what keeps a long session inside its input budget. It
is installed independently and is unaffected. Sessions still compact; they no
longer pay a model to write prose about themselves first.
Upgrading
Existing configuration, sessions, and protected checkpoints remain compatible.
A resumed session that previously carried summary state keeps it on disk; it is
restored when summarization is requested for that session. The pinned Agent
Runtime revision is unchanged from 0.2.5.
Full Changelog: v0.2.5...v0.2.6
v0.2.5
Smith v0.2.5
Smith 0.2.5 shows the model, not just the operator, why a sub-agent failed.
Fixed: the agent tool reports a failed child's reason
v0.2.3 gave a failed child's cause to the parent, and the TUI and the session
journal have shown it since. The agent tool did not: it rendered the child's
status snapshot, which carried state: failed and nothing about why. That is
the one reader whose next action depends on the answer, and a failure with no
reason attached reads as one worth retrying.
The runtime now records the cause on the child's status, and the tool result
carries it:
{
"child_id": "child-1",
"state": "failed",
"error": "child turn failed: Gemini provider rejected the request: Input
blocked: the prompt contains sensitive words that violate
Google's Generative AI Prohibited Use policy.",
"tokens_used": 0
}
The field is absent rather than null when a child has not failed, and it is
cleared when a child starts a later task, so it always describes the state the
child is in.
Upgrading
Existing configuration, sessions, and protected checkpoints remain compatible.
The pinned Agent Runtime revision advances to 7c6ae53.
Full Changelog: v0.2.4...v0.2.5
v0.2.4
Smith v0.2.4
Smith 0.2.4 says why a provider rejected a request, instead of only that one
did.
Fixed: a rejected request carries the provider's reason
A non-success response was classified from its status and its body was dropped
unread, deliberately, because a provider error body commonly echoes the
offending request with the authorization header inside it. The cost was that
no reason survived anywhere: a content block, a malformed request, and an
unsupported model all arrived as the provider rejected the request, and the
Gemini adapter then rebuilt the error without even the status it had been
given.
Smith now reads a bounded prefix of an error body and keeps only the two
fields providers document for the purpose, error.status and error.message,
truncated and recorded as provider.detail. A body that does not parse, or
that carries neither field, still yields nothing; the echoed request lives in
neither field, so what motivated dropping these bodies never crosses the
boundary. The Gemini adapter carries that metadata through and names the
reason:
Gemini provider rejected the request: INVALID_ARGUMENT: Input blocked: the
prompt contains sensitive words that violate Google's Generative AI
Prohibited Use policy.
Paired with v0.2.3's child failure causes, a sub-agent that dies on a rejected
prompt now reports that sentence to the parent rather than child turn failed.
Upgrading
Existing configuration, sessions, and protected checkpoints remain compatible.
The pinned Agent Runtime revision advances to 5ed4b54.
Full Changelog: v0.2.3...v0.2.4
v0.2.3
Smith v0.2.3
Smith 0.2.3 makes a failed sub-agent say why it failed.
Fixed: a failed child reports its actual cause
A child turn that failed reached the parent as a fixed internal error,
child turn failed, with the real cause discarded. The runtime emits that
cause immediately before completing the turn, but delegation ignored it and
substituted a constant string. Nothing else recovered it: a child's events are
not mirrored onto the parent stream, and a child session keeps no journal or
log file of its own. A provider rejection, a preflight budget failure, and an
internal fault were indistinguishable from each other and from a child that
never started.
Delegation now names the cause the child reported, keeping its kind,
retryability, and metadata, so a sub-agent that dies on a rejected request
reads as
sub-agent child-1 failed: child turn failed: Gemini provider rejected the request
A failure that never named a cause keeps the previous wording, and a parent
that branches on retryability now sees the child's answer rather than
delegation's.
Upgrading
Existing configuration, sessions, and protected checkpoints remain compatible.
The pinned Agent Runtime revision advances to 18dc8ec for this fix; nothing
else in the runtime contract changes.
Full Changelog: v0.2.2...v0.2.3
v0.2.2
Smith v0.2.2
Smith 0.2.2 derives a safe per-request output budget for catalog-backed models
whose published output ceiling is too large to use directly as an ordinary
request default.
Fixed: automatic output budgets for catalog models
When a model has no explicit max_output_tokens setting, Smith now derives a
request budget from the frozen model limits and context policy. The automatic
value is bounded by the model's output ceiling, 32,768 tokens, one quarter of
the context window, and the space left after the reasoning reserve. The same
value is used by provider requests and the context planner, keeping retries,
tool continuations, and child runtimes coherent.
Model selection now distinguishes the advertised output ceiling from the
effective request budget and labels the latter as automatic or configured.
Explicit request and reserve settings retain precedence, and impossible
reserve combinations remain visible with a bounded diagnostic instead of being
silently clamped.
Upgrading
The macOS and Linux archives, the curl installer, and
@forgeailab/smith@0.2.2 all carry this version. Existing configuration,
sessions, and protected checkpoints remain compatible, and the pinned Agent
Runtime revision is unchanged from 0.2.1.
Full Changelog: v0.2.1...v0.2.2
v0.2.1
Smith v0.2.1
Smith 0.2.1 makes 0.2.0's installed coding agents work where they were
advertised: as delegated children, on a Gemini binding, and with what they did
visible in the transcript.
Fixed: a child runs on the agent its profile names
Spawning a child on a profile whose model id is cli/claude-code/sonnet failed
on its first turn, reporting that a provider had rejected the request — naming
a provider the profile only borrows a model identity from.
The child had been composed against exactly that provider. Only the root path
installed an external agent backend, so a child profile that named an installed
agent resolved its provider for identity and limits, as it should, and was then
asked to produce the turn with cli/… as the model id. What the user saw was
an HTTP provider refusing a model it had never heard of.
A preflighted child route now carries what executes its turns, and three things
follow:
- A child on an installed-agent profile runs its turns on that agent, and a
child that inherits its parent's profile runs wherever its parent's turns do. - The backend runs in the child's own workspace, not its parent's, and the
CLI's own tools are narrowed to the same decision the child's tool view
already makes. A read-only spawn does not get write-capable tools back
through the agent it happens to run on, and no caller can grant tools the
owner did not configure. - An agent whose program is not installed is named. The root refuses to start
with the program and the[harness.<kind>]key that would fix it; a child
route reports it at spawn, so one uninstallable child profile cannot stop a
session that may never spawn it.
Fixed: child results are delivered on Gemini
Every completed child on a Gemini binding failed to reach its parent, moments
after finishing, as Config: Gemini provider rejected the request — and the
result was lost with it.
Gemini's Interactions API refuses a request whose conversation ends with a
model turn, and that is the shape every attributed internal turn plans: the
turn adds no message of its own, because its instruction rides in the turn's
context, so the conversation still ends where the assistant last spoke.
Delivering a completed child is one such turn. Smith now closes that ending
with one explicit continuation turn on this adapter, and only on it.
Installed agents show their work
A harness turn's tool rows read Read(run by the agent) — the tool's name and
nothing else — while the CLI's own stream was carrying what it had actually
done all along.
Those rows are now projected the way Smith's own calls are: Read(src/lib.rs · agent), Bash(cargo test · agent), with the agent's reported outcome as the
row's bounded result preview. The vocabulary is the vendors' — Claude Code's
Read, Bash, Edit, Grep, Task; Codex's commands, file changes, and MCP
calls — but the rule is Smith's: every displayed field is named beside the tool
that gives it meaning, then normalized and bounded, and a shape this build has
no reviewed projection for keeps the value-free row rather than a generic
rendering of JSON. agent stays as the last qualifier, because Smith still did
not dispatch these calls and cannot vouch for them.
Codex reports a command when it starts as well as when it finishes. Smith
ignored the start, so a slow command appeared only once it was over; its row
now opens when the command does.
Fixed: SMITH_LOG no longer refuses to start Smith
SMITH_LOG is the tracing level Smith documents and reads, but setting it
aborted configuration resolution as an unknown SMITH_* setting — exactly when
someone reaches for it. Host-process variables are now skipped rather than
matched against the setting table; any other unknown SMITH_* name is still
refused.
Upgrading
The macOS and Linux archives, the curl installer, and
@forgeailab/smith@0.2.1 all carry this version. Existing
~/.smith/config.toml files, sessions, and protected checkpoints are read
unchanged, and the pinned Agent Runtime revision is unchanged from 0.2.0.
One deliberate exception: a child route's policy fingerprint now records what
executes its turns, so a durable child persisted by an earlier version is
restored reporting child reconstruction policy changed, and one interrupted
mid-task is not resumable across the upgrade. Its record and result are intact;
spawn the task again rather than resuming it.
Full Changelog: v0.2.0...v0.2.1
v0.2.0
Smith v0.2.0
Smith 0.2.0 can run a turn on a coding agent already installed on the machine.
Claude Code and Codex are drivable as agents rather than as models: each keeps
its own conversation, runs its own tools under its own policy, and streams its
own events, which Smith renders in the transcript beside everything else.
Installed coding agents as a harness
A profile may name a harness — claude-code or codex — and its turns run
on that CLI instead of a model provider. A harness profile works as the main
agent or as a delegated child.
An agent is also selectable by model id anywhere a model is, with no
declaration at all:
smith --model cli/claude-code/sonnet
smith --model cli/codex/gpt-6-astra
Per-machine settings live under [harness.<name>]: the executable path, the
model, extra arguments, the working directory, the environment, and whether
the CLI may run its own tools. Every value stays layered and
source-explainable like the rest of Smith's configuration.
The CLI's own tools are off by default, named explicitly rather than left
to each CLI's default — an empty --allowedTools for Claude Code,
--sandbox read-only for Codex. Enabling them means the CLI executes reads,
writes, and commands Smith never approved, never scoped to the workspace, and
cannot record as tool history. That is why it is an owner-only setting.
The CLI's own session continues across turns rather than being replayed. Smith
stores the identity the CLI reports and offers it back on the next turn; a CLI
that cannot resume reports a new one and the turn proceeds. The ambient
environment is inherited rather than cleared, because an installed CLI depends
on its own login, PATH, and home — clearing it is what made the earlier
model-shaped bridge report "not logged in".
Harness activity is visible, and never claimed as Smith's
A harness turn streams its session identity, its narration, its answer, and
the tools the CLI ran itself, as they happen. Tools the CLI ran are rendered
distinctly from Smith's own calls — Read(run by the agent) rather than a
projected invocation — because Smith did not dispatch them, did not approve
them, and cannot vouch for them. Rendering the two identically would imply a
guarantee Smith cannot make. Headless output carries them under their own
external_* event types for the same reason.
Upgrading
The macOS and Linux archives, the curl installer, and
@forgeailab/smith@0.2.0 all carry this version. The change is additive: a
profile with no harness behaves exactly as before, and no existing
configuration changes meaning. Existing ~/.smith/config.toml files,
sessions, and protected checkpoints are read unchanged.
The pinned Agent Runtime revision moves to cf446b8 on
fix/smith-command-provider-compat, which makes an externally executed turn
durable the way a direct one is: it accepts a turn checkpoint before invoking
the backend and advances it through completion and publication. Without it
every harness turn published its terminal and then failed with
Internal: turn has no accepted checkpoint, leaving nothing durable behind.
Full Changelog: v0.1.0...v0.2.0