What's New in meetsoma core
Agent-facing changelog: 'what NEW capabilities can I use, with just enough detail to use them.' Distinct from the technical CHANGELOG.md — this is action-oriented, dense, version-tagged, and tells YOU (the agent) which tools just landed and how to invoke them.
Read this when you wake up in a session that just ran soma update, or when starting fresh after a release. Each section is a version’s agent-actionable surface: NEW caps you can call, behavior changes you should know, bugs you can stop stepping around. Not the technical commit log — that’s CHANGELOG.md. This is the answer to “what can I do now that I couldn’t yesterday?”.
How to read this
Each version section follows the same shape:
- 🆕 New caps — agent-callable surfaces with one-line invocation hints. Format:
cap_name(args) → outcome. - 🔄 Behavior changes — defaults flipped, conventions shifted. What you did yesterday may now be wrong.
- 🐛 Bugs you can stop stepping around — known issues that are now closed.
- 📁 New files / locations — useful paths the runtime now writes/reads.
- 🧰 Workflows — new patterns worth muscle memory.
A [dev] tag = dev install only (not shipped in the end-user tarball).
v0.50.0 — 2026-10-02
🧰 Workflows
soma attach/soma start— see every session, running or stopped, and reconnect.soma attachlists live sessions newest-first (turns, uptime, cwd, tmux name, model) andsoma attach <#|id|tmux-name>takes you there — works from inside tmux, where plaintmux attachrefuses.soma startis the stopped half: same rows, opposite set,soma start <#|id>reopens one with full history. Each list’s footer names the other, so a session is always in exactly one.soma attach --kill <#|id>/--kill allstops a running session without deleting its transcript — it moves to thesoma startlist instead.- Sessions say what they are.
↳scout of d38f60for a delegated child,↳succ of 91ac4efor a rotation successor, unmarked for an orchestrator — in the resume picker,soma attachandsoma start. Recorded at boot from the spawner’s environment; sessions started before this show no marker. - 🔄
soma -ccontinues YOUR session, not whichever child wrote last. Delegated children write into the same directory as their parent, so after a delegation burst-cused to reopen a scout. It now continues the most recent stopped orchestrator and prints what it skipped.SOMA_CONTINUE_ANY=1 soma -crestores the old meaning. soma preloadlists your preload lanes and starts one by number. One row per preload — age, arc, lane, what it supersedes — naming which one a bare boot would take (boot picks newest by mtime, arc-blind).soma preload <#|name>starts a session on that exact lane./reduceand/resume-reducedshrink a transcript without losing work./reducemechanically strips image payloads (keeping metadata) and truncates oversized tool results into a.reduced.jsonlbeside the original — 60% smaller on disk, measured across 200 real transcripts, original untouched./resume-reduceddoes the same and resumes into the copy, so a session climbing toward its context limit can keep going instead of rotating; it refuses to switch if the reduced copy lost any turns./reduce imagestouches images only;--keep N/--alladjust the window.- Address a peer directly:
@s01-xxxxxx <message>in ordinary output. Writes an inbox letter; must start the line (never inside a code fence), and warns if the recipient has no heartbeat. soma --model <name>boots raw, skipping your last preload — a quick run on a different model no longer pays for a large handoff. Same for--provider/--thinking-level.preload.skipOnModelOverride: falsekeeps the old behaviour;soma inhalestill loads by name either way.focus: [somaverse]in a preload, orsoma --package somaverse(nowsoma --domain) on the command line, scopes a session to only the domains it needs — doorway, protocols, muscles, body files and tools together. Your own.somaand parents are untouched; a focus naming an unmountable domain warns at boot.soma terminals tunefixes the tmux settings that flatten a modern terminal’s keys (extended-keys,allow-passthrough,focus-events…) — shows what’s missing, asks, appends inside one# >>> soma tmux >>>block.soma terminals open <layout.json>puts commands where you’re looking (a Warp tab config, a tmux split);soma terminals grid <id>...opens onesoma attachpane per session.
🆕 New caps
soma:agent.resumerestarts a child whose session ended — same settings a fresh spawn gets, so a crashed or idle-shutdown child keeps working as that child instead of coming back as an ordinary session.soma:inbox.waitcovers “a letter arrived”, “the builder committed” and “the sweep finished” in one call. No args: returns your next unread letter (optionally filtered by sender or subject word).{repo, ref}: returns when that branch gets a new commit.{file}: returns when a path appears.soma:inbox.send({cc})— one call writes the same letter to each recipient, one copy each.soma:audit.*— one command for the estate’s real git state. Parsesgit status --porcelainby column (not the first space), asks each repo its actual default branch, splits AT-RISK commits from merely-unmerged ones.soma:browser.network({action:'start'})then{action:'read'})answers “did that click actually send anything?” Records fetch/XHR inside the page and marks Next.js server actions — a control that looks like it worked but sent nothing stops being invisible. Says when it wasn’t recording, instead of reporting zero requests.soma:browser.health({expectMarker?})tells you whether a tab can be trusted before you go bug-hunting — painted, hydrated, and whether you’re looking at the build you just shipped or a cached older one. Returns a verdict naming the fix, not raw flags.soma:browser.targets/.statuslist every running browser, port or no port, each row naming whether it’s reachable (use({port})) or needssoma:browser.launch— a last-resort agent-owned browser under a named persistent profile, never the user’s own.searchcan use your own SearXNG instance.search.api.provider: 'searxng'+search.api.url(or$SOMA_SEARCH_URL) — no API key, no metering.soma:agent.peer({id})answers whether a successor/sibling is actually working the plan it booted from — preload it loaded, planned files touched, commits it authored, verdict ON-TRACK/DRIFT/STALLED/IDLE.soma:markdown.*maps and grooms a long markdown document — outline by heading, pull one section, or groom the whole file, for docs too big to read end to end before editing.soma:agent.transcriptreads what a child or peer actually said, reconstructed from that session’s own JSONL — a report stays checkable after its pane is gone.soma:settings.*shows what a setting actually resolves to, and where it came from.list/getreport the effective value plus which file in the chain set it;setwrites the file a key is actually read from;doctorfinds SET-BUT-UNREAD and READ-BUT-UNSET keys from source, not a hand-kept list.soma:code.commentscensuses a file’s comments with line ranges — for finding where a file explains itself, and where a 60-line comment block has outgrown the code under it.soma:agent.gradeand.killclose the delegation loop.grade({id, grade:'pass'|'fail'|'partial', note?})records that you checked a child’s deliverable;killwarns when you end a child whose work was never graded, stays quiet when it produced nothing.soma:agent.checkinanswers whether a child is making PROGRESS, not whether it’s alive — reports deliverable growth, so a running-but-stuck child reads differently from a working one.soma:agent.activity({session})tells you what a sibling actually DID — span, model changes, tool-call breakdown, thinking count, read from the transcript rather than watching a pane (which only shows liveness).soma:amps.findandsoma:new.muscle/.protocolrefuse near-duplicates. Before scaffolding, the name is searched across the whole chain, hot and cold; a name-level match returns the existing candidates instead of a new file.force:truecreates anyway.soma:agent.delegate({transport:'rpc'})delivers a child’s task over Pi’s RPC protocol, with an acknowledgement — a typed response frame instead of guessing from the pane’s message counter. Opt-in; the default tmux route is unchanged.soma:agent.paneopens/closes a viewer split on a child’s session in your current window — closing the pane never kills the child.
🔄 Behavior changes
context_statusno longer says ROTATE. Below your model’s prep line it reports runway and that context is not a reason to stop; past it, it says start rotation prep. Reports runway directly now —59% · 6% to the 65% rotate line— instead of a bare percent.- The
opusalias now resolves to Claude Opus 5.5 (opus,opus-5,opus5→anthropic/claude-opus-5-5;opus-5-5/opus55are new aliases). delegate.headlessChaininsettings.jsonsets the fallback models headless children try, in order — edit the list when a free tier ends, no release needed.- A domain package can carry its own skills (
skills/<name>/SKILL.mdinside a mounted package) — appears in the catalog while the package is focused in, disappears when it’s focused out. - A delegated child now receives its whole role file, not three sliced sections — guidance an author put anywhere in the file now reaches the child.
breathe.onFullreplacesbreathe.autoRotate/context.safetyNet—"warn","steer"(default) or"rotate". Old settings keep working and are mapped on read."rotate"is refused while Pi’s own auto-compaction is on.skills.denyin.soma/settings.jsonhides a named skill from the catalog without moving or deleting it — for de-duplicating a doorway skill that already routes to something.- Sub-agents boot with
GIT_EDITOR=true— a git merge/rebase/commit that would open an editor now completes in a delegated child instead of hanging. - A tool call that depends on a write still in flight in the same parallel block is now held,
with the reason — reading, committing, pushing, building or deploying something an earlier call in
the same block is still writing returns “run this after it lands.”
guard.inflightRace: falseturns it off. - A role’s
reasoning-effortsetting now actually reaches the child.
🐛 Bugs you can stop stepping around
soma:agent.checkinno longer calls a running child “finished.” Its 2-minute warm-up comparedDate.now()to an ISO string (alwaysNaN) — every child with an unwritten deliverable was flagged∅ MISSINGfrom the first poll.- Harvesting a still-running child, then killing it, no longer records a failure.
soma:agent.harveston a running child stamps the entry; thesoma:agent.killthat follows recordscompleted(harvested) instead ofaborted— run counts stop reading delivered work as a crash. soma:browser.navigate({url})works — the catalog advertisedurl, the implementation requiredtargetUrl, so the documented call 400’d every time.urlis now a real alias.- An undeclared budget means NO LIMIT, not zero. A role with no
max-tool-callsreads “unlimited” in the child’s prompt; an explicit0is still a real ceiling. soma:code.refs/.blasttell a definition from a use — a call inside an assignment is no longer reported as defining the function it calls; a class method is recognised as a definition.- The
claude-clialias table accepts every valid model name and never silently downgrades one —model: 'claude-cli/*'now spawns on sonnet instead of dying at boot on an invalid id. - A command gate no longer fires on a heredoc body you’re writing into a file (
ignore-quotedtreats it as data, like a quoted span); a body fed tobash/shis still gated. - A background
claude-clichild’s cost cap is actually read — the enforcement site looked up a frontmatter key the role schema doesn’t use, so a declaredmax-cost-usddid nothing on that path.
📁 New files / locations
~/.soma/state/loop-stalls.jsonl— a row whenever the event loop is held for more than a second, and whenever a.somacheckpoint commit takes more than 100ms, with the last event seen before it.SOMA_STATE_DIRrelocates it.memory/children/<role>/invocations.jsonl— a delegated child’s lessons now go here per-run instead of editing its own role file;soma:agent.delegate/.killno longer suggest folding notes into the role..soma/.last-shutdown.json— records why a session stopped, when, how many turns ran, and whether a preload was saved.checkpoints.soma.backup.remote/.enabled— your.somacan push its own history at every rotation (exhale, inhale, exit). Refuses to push anywhere public or unverifiable; a push counts as done only when reading the remote back agrees with local history.durability: scratchbodies are never pushed.
v0.42.1 — July 2026
🐛 Bugs you can stop stepping around
soma:browser.renderwithformat:'markdown'and noselectornow actually converts. It was silently readingdocument.body.innerText(plain rendered text, no HTML) instead ofouterHTML, so the converter had nothing to clean — every real-world call reportedformat:"markdown"while returning near-0% “reduction” and full page chrome. Fixed; verified live (89050 → 13215 chars, −85.2%, real content preserved, nav/footer gone). A page’s own in-content<header>/<nav>(an article’s title + breadcrumbs) also survives now instead of being stripped identically to global site chrome.- A
claude-cli/*role’smax-cost-usdbudget is now actually enforced. It read the wrong frontmatter key and had two separate falsy-zero bugs that silently turned an explicit0into “no cap.” If your role declares a real number, it’s held to it now — including a genuine0hard cap (never draw billed overage). Only applies todefault-model: claude-cli/*; every other backend (mistral/groq/cohere) still has no dollar-cost enforcement, onlymax-tool-calls.
📁 New files / locations
_boot.mdshows a last-session/last-reflection breadcrumb ({{last_session_ref}}/{{last_mlx_ref}}) on a fresh boot with no preload loaded — a pointer to what’s still on disk, not a summary. Zero-cost on a brand-new project with nomemory/history yet.
v0.42.0 — July 2026
🆕 New caps
soma:agent.claude — delegate through a FILE contract, no ARG_MAX ceiling
soma:agent.claude({task:'...', role?:'general', model?:'sonnet', maxBudgetUsd?:3})
→ runId + tmux session + contract/report/log paths
soma:agent.claude_harvest({runDir}) → the child's report, or not-finished
delegate passes the compiled prompt as a claude -p ARGUMENT, so a large role + task can exceed
ARG_MAX and fail. This writes the contract to a file and hands the child a tiny instruction to read it.
Always background (tmux). Use delegate normally; reach for this when the prompt is large, or when
delegate already failed on argument length. Poll claude_harvest rather than attaching to tmux.
🔄 Behavior changes
- Role frontmatter is parsed by real YAML now (Pi’s
parseFrontmatter). It is STRICT: an unquoted value containing": "becomes a mapping, and one containing" #"truncates at the comment. If a role errors or a value arrives half-length, quote it — 7 bundled roles needed exactly that. The previous hand-rolled parser accepted both and was silently masking them. context:in a role’s frontmatter actually stacks now. It shipped inert: the parser’s promotion allowlist omitted the key, so declared files rendered as"(none)". Declared muscles/docs now arrive as<context_file path=...>blocks. A child spawned from a session older than this change still gets the old compiler — reload for it to take effect.- The shipped harness asks you to cite only from files you have OPEN. Naming a doc as support asserts you read it this session; a routing table says which file owns a fact, never what the fact is.
🐛 Bugs you can stop stepping around
- The dev↔runtime sync commands (
sync dev/sync main) now actually write STATE.md’s activity log (all writers were broken; on a default install none had ever appended a row) — and they assert the row arrived, not just exit 0. dist/.dev-syncedcarries provenance (branch@sha, version, piVersion, timestamp) instead of being a zero-byte flag;switch statusprints it and states that the git ref describes the CHECKOUT, not the dist.
v0.41.2 — July 2026
Maintenance release. Nothing to try.
No user-facing change shipped in this one, and it is listed here only so the trail has no gap. The single code addition was an internal delegation backend whose capability was never registered — unreachable, so there was nothing a user could call. It became reachable in a later release and is documented there.
These notes were written retroactively: the release originally shipped with no narrative at all, because the changelog-promotion step matched on a heading format that had since changed, found nothing, and exited reporting success. Both the match and the silent success are fixed.
v0.41.1 — July 2026
🐛 Fixes
- Leanstral models no longer error when reasoning is on.
labs-leanstral-*were sending a reasoning flag the Mistral API rejects outright (400 code 3051); they now send the field the API actually expects. - The runtime no longer breaks after a Pi version bump. Syncing a bump that changed
package.jsonskipped reinstalling dependencies, so a newly-built runtime could run against the previous version’s modules and crash at boot. The sync now reinstalls before rebuilding.
v0.41.0 — July 2026
🆕 Delegation goes multi-model
Child roles are no longer pinned to a single Claude model. A role can declare a chain — an ordered list of models with a cost class — and delegation walks it, falling through to the next entry when one is unavailable. In practice that means a cheap model does the routine pass and a capable one is reached for only when the work needs it.
default-model: claude-cli/haiku
model-chain:
- id: claude-cli/haiku
class: cheap
- id: claude-cli/sonnet
class: coding
🔄 Behavior changes
- Child defaults moved to the free tier. New child templates no longer default to a paid model.
Existing roles that name their own
default-modelare unaffected. - Pi runtime 0.80.6 → 0.80.10.
🐛 Fixes
/bodystopped crying wolf. Unreferenced body files used to emit one warning each; they now collapse into a single line.- Large delegate prompts no longer fail on argument length. The compiled role prompt is written to a file instead of passed as a command-line argument, so prompt size no longer has a ceiling.
v0.40.0 — July 2026
🆕 You can see, and scope, which models are available
soma:agent.models → live catalog, honouring settings.json scoping
soma:extensions.search → search pi.dev packages
soma:extensions.show → inspect one before installing
soma install npm:<pkg> → install through Pi's own package manager
The delegate model catalog is now built at call time from the live registry rather than a hardcoded
list, so a provider you have configured shows up without a code change. {{enabled_models}} and
{{active_extensions}} are available as template variables, so a prompt can state what this install
actually has rather than what it assumed.
🔄 Behavior changes
- A budget guardrail on the system prompt —
systemPrompt.maxTokens. Compiling a prompt over the configured budget warns rather than failing, so a body grows lean by decision rather than by accident. Check yours withsoma:body.slots.
v0.39.0 — July 2026
🆕 New caps
soma:refdocs.* — external platform docs (BUNDLED)
soma:refdocs.find({query:'cloudflare'}) → {baseUrl, method, pageCount, pages}
soma:refdocs.tree({query:'react'}) → {pageCount, tree} (section-organized)
soma:refdocs.fetch({query:'cloudflare', topic:'durable objects'}) → {matches, pages: [{content}]}
soma:refdocs.download({query:'cloudflare', topic:'workers', depth:5}) → writes to .soma/refdocs/<name>/
Flags: output:'/path' (custom dir), output:false (inline JSON), all:true (full download)
Discovers docs via llms.txt convention (Cloudflare, Vercel, React, Mintlify, 25+ known domains).
Falls back to HTML scraping. Fetches pages as clean markdown via Accept: text/markdown.
Use BEFORE researching any third-party platform docs.
soma:cf-docs.* — Cloudflare docs (HUB, soma install soma-cf-docs)
soma:cf-docs.index({product:'workers'}) → {product, pages, count}
soma:cf-docs.read({url:'/containers/'}) → {title, url, content}
soma:cf-docs.query({product:'containers', topic:'outbound traffic'}) → {matches, pages}
CF-specific, no API key needed.
🔄 Behavior changes
- Pi runtime bumped to 0.80.6 —
maxthinking level available.showCacheMissNoticestoggle (complementary to our predictive cache TTL in the statusline). New extension hooks:agent_settled,before_provider_headers.pi config -lfor project-local config. - Freebuff harness uses JSON extraction — reads
chat-messages.jsoninstead of scrapingtmux capture-pane. Multi-paragraph + table responses now reliable. TUI parsing is fallback.
📁 New files / locations
.soma/refdocs/<name>/— auto-created byrefdocs.download, organized by section withindex.md~/.soma/agent/scripts/dev-only/soma-freebuff.{sh,py}— $0 AI model harness (6 free models)
🧰 Workflows
- $0 delegation: write spec → hand to freebuff (
~/.soma/agent/scripts/dev-only/soma-freebuff.sh ask) → gate → commit. Six free models. Same pattern assoma:agent.delegatebut costs nothing. - Pi bump TUI smoke: after bumping Pi, boot with a free model in tmux to catch import errors
and duplicate declarations that build+tests+sandbox miss.
soma --model opencode/deepseek-v4-flash-free
v0.38.0 — June 2026
🆕 New caps
soma:caselaw.* — Caselaw Researcher cap family.
🐛 Bugs you can stop stepping around
- Script subcommands get clean
userArgs, not injected argv. A subcommand no longer inherits arguments meant for the wrapper — if you passed flags and the script saw extra ones, that was this. - Browser-driving caps are serialized. Two browser caps in flight at once raced each other; they now queue. Symptom was an operation returning another call’s page.
v0.37.1 — June 2026
🐛 Bugs you can stop stepping around
- Exiting a session no longer garbles your shell. Two soma-driven exits left the
terminal in a bad state. If you were reflexively running
resetafter quitting — stop, it’s fixed.
v0.37.0 — June 2026
🔄 Behavior changes
- The system prompt split along a scaffold-vs-behavior line.
prompts/system-core.mdholds what is always true of Soma; your body files hold what is true of you. Why you care: editing your body no longer risks clobbering framework scaffolding, and core updates arrive without touching your files. - template-migration plumbing for
core_rules.mdand_protocol-template.md.
🆕 New caps
soma:browser.render — render a JS-heavy / SPA page in an ephemeral tab and return its text. Use when fetch returns an empty shell because the content is client-rendered.
v0.36.0 — June 2026
🔄 Behavior changes
- The always-loaded core was restructured and sharpened — shorter, and generally useful to every install rather than shaped by one workspace’s habits.
- The prompt now states the
.soma/layout rule and that.soma/commits itself. Two recurring confusions — “where does this file go?” and “do Igit add .soma?” — are answered in the prompt instead of being re-derived per session. You do not commit.soma/; it checkpoints itself. - Prompt refined from corpus mining of the two most-recurring anti-patterns across real sessions.
v0.35.0 — June 2026
🐛 Bugs you can stop stepping around
- Opus
Editmis-shape is coerced, not rejected. A crammed secondoldText2/newText2pair used to fail the whole edit; it is now folded into a normal edit. /inhaleno longer crashes the TUI. The error-sanitizer import is prepended and fails loud rather than silently producing a broken module.
🔄 Behavior changes
- Body templates lead with “ground before think.”
soul.mdandcore_rules.mdnow open with the discipline of checking an artifact before reasoning about it. headlessis documented as the reliable delegation mode. If background children were behaving unpredictably, this is the mode to use.
v0.34.0 — June 2026
🆕 New caps
soma:inbox.list({status?})→ list markdown-inbox letters (default unread;'all'for every status). Each entry shows the filename to act on.soma:inbox.read({file})→ mark a letterreadonce you’ve read it, so it stops surfacing at boot.soma:inbox.actioned({file})→ mark a letteractioned(read AND acted on — e.g. shipped the fix it reported).soma:inbox.archive({file})→ move a processed letter toinbox/_archive/.file= filename, slug, or unique partial; ambiguous refs list their candidates. Resolves the.soma/chain, so a parent-inbox letter is clearable from a child project.
🧰 Workflows
- Close the inbox loop. The
inbox-handlingmuscle always required marking letters read — now there’s a tool instead of hand-editing frontmatter. Read a letter →soma:inbox.read/.actioned/.archive. The boot summary now shows what’s actually pending instead of piling up.
🐛 Bugs you can stop stepping around
- Exhale no longer crashes in an uninitialized directory. Ending a session where the local
.soma/didn’t exist threwENOENTfromsaveProtocolStateand aborted the whole save — it now creates the directory first.
v0.27.2 — May 2026
The soma:seam.* family lands — archaeology caps for tracing concepts through your own writings.
🆕 New — shared preload lifecycle (cycle 29)
Preload state tracking across /exhale, /breathe, auto-rotation, and keepalive auto-exhale is now unified into a single shared state machine (extensions/_shared/preload-lifecycle.ts). Four states: UNREQUESTED → REQUESTED → SAVED → STALE. Three route caps for read/write/reset.
What changed:
/exhaleat high context (85%+) no longer causes the safety net to override and rotate immediately. The exhale handler signalsREQUESTED→ safety net defers.- Keepalive exhaustion no longer double-requests a preload if one is already in flight.
- Statusline’s
📝saved/📝staleindicator now reads from the same state as the breathe extension — no drift. - 7 local
letflags removed fromsoma-breathe.ts.
Route caps: preload:lifecycle, preload:transition, preload:reset, preload:noteToolCall.
Detail: the preload-lifecycle cycle plan.
🆕 New caps
soma:seam.trace— walk a concept across docs + code + sessions + blog + kanban + soul-space. Use BEFORE raw grep for any “where did X come from?” question. args:{term, limit?:200}. Free tier.soma:seam.ancestors— trace a concept through vault agents + Pi sessions + Claude sessions, with agent attribution. Returns who-said-what-and-when across the lineage. Closure test:seam.ancestors "breathe"returnsZenith (openclaw-dev) — soma's daddy. args:{term, limit?:200}. PRO feature (wraps_pro/soma-seam.sh).soma:seam.timeline— chronological evolution of a concept. Optionaltagfilter. args:{tag?, limit?:300}. PRO.soma:seam.sessions— search.soma/memory/sessions/+ preloads +~/.pi/agent/sessions/JSONLs. args:{query, limit?:200}. Dev tree only.soma:seam.seeds— forward pointers (frontmatterseeds:field).{unplanted: true}for ones not yet referenced. args:{unplanted?:bool}. PRO.soma:seam.gaps— orphan documents (no inbound refs). Hygiene scan. No args. PRO.soma:seam.web— PERSISTENT — writes markdown trace to.soma/memory/webs/web-<term>-<date>.md. Becomes a memory artifact next-self can read without re-running. args:{term, output?:path}. PRO.soma:seam.stats— Pi JSONL session analytics: tool usage, errors, interrupts. args:{mode?, limit?:200}. Dev tree only.soma:docs.related— frontmatter graph walk from a file (forward + back refs viarelated:,seams:,seeds:). args:{file}. Dev tree only.soma:docs.impact— what docs/protocols/muscles reference this file? Run BEFORE renaming or deleting a doc. args:{file}. Dev tree only.
🧰 New workflow: reach for seam before grep
When the question shape is “where did X come from?” / “who said X?” / “when did X evolve?” — the seam family beats raw grep + find every time. PRO caps fail gracefully on free tier with a “PRO feature” message; dev-tree caps fail gracefully on user installs. Caps live in the route registry — zero cache cost at register-time.
Tier breakdown:
- Free tier (everyone):
seam.trace(wrapsamps/scripts/soma-trace.sh). - Optional pack (not installed with meetsoma core):
seam.ancestors,seam.timeline,seam.seeds,seam.gaps,seam.web. - Dev tree only (internal):
seam.sessions,seam.stats,docs.related,docs.impact.
📁 New files / locations
extensions/_shared/script-resolver.ts— shared helper for addons that wrap shell scripts. Path resolution + subprocess + graceful fallback messages.extensions/soma-addons/seam.ts— the new family..soma/memory/webs/— whereseam.webpersists trace artifacts.
Detail: the seam-addon-family design plan.
v0.27.1 — May 2026
The “first end-to-end autonomous PR ship” patch. Cycles 16 + 17 land together: Sonnet’s long-context wall now triggers warn/exhale BEFORE the wall hits, /inhale no longer double-injects preload, and release-please becomes the canonical ship pipeline.
🆕 New caps & workflows
delegate cycle <brief>— full implementation pipeline for any markdown brief (cycle.md, inbox/.md, plans/.md). Pipeline:intern(investigate, 80-call) →intern(build, 80-call) →verifier(25-call) →pr_author(30-call). Total ~215 tool calls / ~$2.50 per cycle. Outputs/tmp/soma-cycle-investigation.md,/tmp/soma-cycle-impl-summary.md,/tmp/soma-pr-description.md. Flags:--no-pr,--no-verify. Use this whenbuilder’s 25-call default is too small for a multi-step cycle./auto-breathe model-aware— NEW subcommand. The auto-breathe enum is now tri-state:off/global/model-aware.model-awarereadsctx.model.idand selects per-glob thresholds frombreathe.thresholdsmap. Default install shipsmodel-aware. Backward-compat: boolean still parses (true → “global”, false → “off”) via migrationbreathe-tri-state-v0.27.0.tokens_inputnow includes cache_read inrunDelegation()results. Previously reported only the uncached delta (showingtokens_input: 3for repeated calls with stable prefix). New fields:tokens_input_uncached+tokens_input_cachedfor transparency. Was NOT a delegation-degraded bug — was a metric-display bug. The model received the full prompt all along.route.provide("preload:wasInjected", ...)— new route cap exposing whethersession_start’s “new”/“resume” branch already injected the preload./inhalepost-await queries this and skips its own send if true. Available cycle-17+.
🔄 Behavior changes
- Sonnet thresholds: model-aware default for
*sonnet*iswarnRange [28,33] / exhaleRange [34,50]— fires BEFORE the empirical ~48% “extra usage required for long context” wall. Opus:[60,74] / [75,90]. Default fallback:[50,64] / [65,85]. If you’re on Sonnet and were used to 50/70 thresholds, you’ll see notifications much earlier now — by design. /inhaleno longer produces double preload in rotated sessions. Previously, every/inhaletriggered TWO preload-injection user messages ([Soma Boot — rotated session]fromsession_start+[Soma Inhale — Loading Preload]from/inhalepost-await). ~8K tokens duplicated per rotation, verified across 10 sessions. Now: single inject fromsession_start,/inhaleskips whenwasInjected=true. Print-mode safety preserved (whenctx.hasUI=false,/inhalefalls back to direct send).- Auto-breathe notify text changed:
🪵 Auto-breathe: rotating at N%→🪵 Preload requested at N% — rotating after agent writes it. Honest about the request-vs-rotation distinction. Other branch (preload-already-written, immediate.rotate-signal) keepsRotating — preload already written. soma-release-ship.shnow bumps.github/.release-please-manifest.jsonin lockstep withpackage.json. Without this, release-please’s view of “current version” stays stuck and the next push to dev files a confused PR (caught when v0.27.0 ship left manifest at 0.26.2 → release-please filed PR #18 “release 0.26.3” with conflicts everywhere).- Catch-block fallback in
/inhaleis race-safe: the previouscatch (err)block always sent the fallback preload regardless of state. Now checksroute.get("preload:wasInjected")— ifsession_startalready injected (rare race wherenewSession()throws AFTER emitting), catch suppresses its send.
🤖 Release flow now PR-driven (canonical)
PRIMARY (cycle-17, v0.27.1+): Push commits to dev with conventional-commit messages (feat:, fix:, chore:, etc.) → release-please GHA auto-files release PR with versioned CHANGELOG → review + amend the PR (move rich [Unreleased] narratives into [X.Y.Z] if release-please’s auto-bullets are too thin) → merge → build dist + publish draft GH release + npm publish + force-push main + rsync.
FALLBACK (high-stakes): soma-release-prepare.sh (10 checklog gates) → soma-release-ship.sh. Use for major bumps, breaking changes, or mid-flight rescues. Both flows now bump the manifest in lockstep.
🐛 Bugs you can stop stepping around
pr-check.ymlsilent test-failure — GHA’sbash -e {0}shell exited the test loop on the first failing test BEFORE logging which one. Now usesset +einside the loop + captures failed names + logs them at the end.- In-flight detection robustness — 4 tests had brittle
chore(release): vX.Y.Zregex that broke on release-please’schore(dev): release X.Y.Zformat AND on amendment commits. Switched to NO-TAG-YET detection (if package.json bumped to vX.Y.Z but no git tag v$PKG_VERSION exists, we're in-flight). Robust against ALL release-commit shapes. test-preload-notify-state-machineruntime-mirror gate failed on CI runners (no~/.soma/agentinstall dir). Now skips onCI=trueOR when install dir absent.- Release-please
Summarizestep bash-escape — the PR JSON output contains parens (v0.27.0...v0.27.1) which brokeecho "... ${{ steps.release.outputs.pr }}"interpolation. Moved interpolation to env block.
📁 New files / locations
- The model-aware-breathe-collapse plan — full plan for tri-state + per-model thresholds.
- The rotation-mechanism-repair plan — 5-bug rotation-mechanism audit + fixes.
migrations/phases/v0.26.2-to-v0.27.0.md— the breathe-tri-state migration journal.- 5 new test files:
test-breathe-tri-state.sh,test-breathe-migration.sh,test-breathe-model-thresholds.sh,test-breathe-warn-range.sh,test-breathe-exhale-once.sh. 81 new test cases covering the tri-state + per-model paths.
🧠 Architecture notes worth knowing
{{skills_block}}is a transplant, not a duplicate.core/body.ts:775extracts<available_skills>...</available_skills>from Pi’s compiled prompt, then re-injects it into soma’s templated prompt via the{{skills_block}}slot. Soma’s compiled output FULLY REPLACES Pi’s prompt (when Pi’s is the default-shape — the normal case), so the slot is the ONLY copy of the skills XML in the final prompt. Removing the slot from_mind.mdwould lose skills entirely. (The earliermuscle_digestsremoval was different: muscle_digests was rendered by soma + ALSO injected by Pi compiler-prepend — a true double. Skills are not.)- Auto-rotation Path A (
.rotate-signal+ process re-exec) is canonical. Per Pi types (pi-coding-agent/dist/core/extensions/types.d.ts),newSessionlives onExtensionCommandContext, not on the baseExtensionContextevent handlers receive. The route cap"session:new"is therefore only registered when a user explicitly invokes/breathe//inhale//auto-breathe(provideCommandCapabilitiesruns from those handlers). Auto-breathe’sperformRotationfalling back to.rotate-signal(Path A) is correct by design — Pi treats process re-exec as the safer auto-path. In-process Path B is a happy-path optimization available only after a command was invoked.
v0.27.0 — May 2026
The “autonomous CI/PR pipeline” minor. Three layers ship together: nightly tests + auto-issue-filing + delegate-driven fix orchestration.
🆕 New caps & workflows
delegate <workflow>— multi-agent orchestrator. Workflows:pr(full PR pipeline),pr-brief(brief only),ci-fix <url>(issue → fix → verify),changelog(rich CHANGELOG),doc-update,audit [tickets...]. Composeschangelog_curator + pr_author + doc_writer + verifier(orissue_investigator + builder + verifierfor ci-fix).dev:issue.{create,list}— GitHub issues from inside soma sessions.createfiles structured nightly-failure issues with dedupe gate (skip if open issue exists for same failure).check-phases— 30-second pre-release gate (upstream sync + tests + tsc) before the full 5-minsoma-release-prepare.sh.soma-pr-brief.sh— generates structured PR brief (git-cliff CHANGELOG diff, affected files, semver bump type, docs to update, roadmap suggestion). Used as input to delegate workflows.{{pi_gap}}body var — readsPI_UPSTREAM.mdat session start, injects live Pi version-gap into the system prompt. Updated by 6h GitHub Actions monitor.- 3 new child role bodies —
pr_author(rich PR descriptions),issue_investigator(root-cause tracer for nightly failures),changelog_curator(rich[Unreleased]narratives, replaces auto-bullet noise).
🔄 Behavior changes
- Pi 0.72.1 → 0.73.1 lockstep bump. All 4 pi-* packages move together (
pi-coding-agent,pi-ai,pi-agent-core,pi-tui). Bumping only one causes silent API mismatches. MODEL_ALIASESreverted to 4-5 (NOT bumped to 4-6) — default-tier safety. Bumping aliases would silently force users onto 1M-context variants.- Nightly test failures auto-file GitHub issues with
nightly-failurelabel. Dedupe gate prevents floods. Issue body includes failing tests, error excerpts, Pi version, last 5 commits, and a fix brief for the next agent. - 18 tests gained
CI=trueskip guards — workspace/dist-dependent tests self-skip on CI runners.
🧰 Release flow consolidation
- Archived stale
soma-ship.sh. Wired theship/release/betasubcommands. pr-check.ymlhardened: tsc typecheck job + changelog blocking + conventional-commit format validation.cliff.tomladded — git-cliff configured for Keep-A-Changelog format from conventional commits (feat→Added, fix→Fixed, ci/chore/test filtered).release-pleaseauto-trigger enabled on push to dev (proposes; release-please takes over as canonical in v0.27.1).
📁 New files / locations
PI_UPSTREAM.md(auto-updated by 6h GHA) — live Pi version gap + flagged commits relevant to Soma (33 Pi API usages tracked).tests/test-children-roles-exist.sh— drift-prevention regression test: every_run_rolereference indelegate.shmust have a matchingbody/children/<role>.md.
v0.26.x — May 2026
Maintenance arc: cache-invalidation hardening, Pi runtime bump rehearsals, soma-github local-mode runtime ship gap fix, body audit + state slimming, anti-accretion discipline. Two reverted patches (long-context, briefly enabled) that were rolled back when they broke a client’s Anthropic billing wall — documented in docs/anthropic-long-context.md with the anthropic.enableLongContext opt-in setting as the durable replacement.
v0.25.x — May 2026
The /inhale stale-ctx fix family + preflight update prompt + sentinel migrations made unconditional + body-template migration mind-prepend-cleanup-v0.25.0 with backup safety + Pi-cruft startup warnings removed. Cycle 12 (preload notify state machine) shipped — transitions only fire once per state change (none→saved, saved→stale, stale→saved). breathe:detail cap added.
v0.24.1 — May 2026
The “releases verify they actually completed” patch arc: protect the release pipeline from silently incomplete ships, and lock the cap-bus surface against accidental drift.
🛠 New tests you can run
tests/test-release-completeness.sh— asserts CHANGELOG ↔ git tag parity,dev↔mainff-merge reachability,dist/manifest.json↔package.json,npm/package.json↔package.json(collapsed-train case). Auto-runs in orchestrator Phase 1 (tests gate). If a previous release was incomplete, the next prepare fails CONFLICT-HARD before any new bump.tests/test-namespaced-caps.sh— static-analysis floor for the ~92-cap soma:/dev:/somaverse: bus surface. Per-family minimums, named-cap presence (18 specific from CHANGELOG), duplicate-registration detection, namespace hygiene. Catches accidental cap deletion or rename.
Both run as part of npm test; both fail loud if real drift exists.
🔄 Behavior changes
soma-release-ship.shStep 7 now verifies post-pull (was silent on failure). Reads~/.soma/agent/package.jsonaftergit pull --ff-onlyand asserts version matchesNEW_VERSION; on mismatch prints diagnostic + manual fix path + exits 1. Fixes the case where v0.24.0 silently shipped to npm with the runtime worktree stuck at v0.23.0 because pull failure was being swallowed).tests/test-doctor.sh,test-release-completeness.sh,test-release-surfaces.sh, andtest-version-truth.share now in-flight aware: detect HEAD subjectchore(release): vX.Y.Zand skip transient assertions during the ship window. Without this,npm testfails mid-ship becausedist/manifest.jsonlags the bumpedpackage.json. Re-run post-ship to confirm the assertion holds.
🧰 Workflows
- Anti-accretion sweep (governed by
amps/protocols/atlas.mdv1.1.0): whenbody/STATE.mdexceeds 6KB, run an anti-accretion sweep — session-history paragraphs (“sNN-XXXXXX shipped…”) belong inmemory/sessions/andmemory/journal/, not in STATE. STATE holds current state + pointers; history references the actual session log. First live run cutbody/STATE.md18,148 → 5,513 bytes (-70%) without losing any current state. - Phase 6 (Reflect) step 4 expanded (release phase doc): post-release body+state audit now mechanical. Run
soma:body.audit(catches duplicate slot interpolations, lazy-frontmatter lies) +soma:body.slots(token budget per slot) + the size gate on STATE.md. Plus stale-state scan: pulse.md, _recent-lessons.md, ecosystem.md, journal.md “Latest”. - In-flight test detection pattern (for any future test asserting build artifacts or release-pipeline state): detect
chore(release): vX.Y.ZHEAD subject; if matches, skip the transient assertion with a SKIP not FAIL. Re-run post-ship for verification. Pattern lives inbody/_recent-lessons.md § In-flight test detection.
📁 New files / locations
body/STATE.mdfrontmattergoverned-by: amps/protocols/atlas.mdfield — makes the protocol discoverable from the file.releases/v0.24.x/plans/cycle-cross-check-audit.md— audit doc surfacing five maintainer-decision items from the cycle MAP cross-check (e.g., should5-release.mdSteps 4-13 be split into orchestrator-internal vs human-action sections?).
🐛 Bugs you can stop stepping around
soma-scrape.shlost fetched docs silently when_website/dest dir didn’t exist. Nowmkdir -pbefore write. (Dev-only script — not part of the public core.)tsconfig.jsonwas type-checkingextensions/_archive/**— cleared 15 TS7006 errors from_archive/sx594-flat-wrappers/.npm run checknow exit 0.
v0.24.0 — May 2026
The “audit + scan + remember” patch arc: tooling for auditing your own kanban, scanning third-party repos as if they were local, and protecting your input from auto-rotation.
🆕 New caps
Kanban audit [dev] — close the “is SX-N actually still open?” question
dev:kanban.audit({ticket: 'SX-N'})→ JSON verdict + evidence (verdicts:SHIPPED/STALE/STALE-CROSS-PROJECT/STILL-VALID/NEEDS-REPRO/UNCLEAR)dev:kanban.audit_batch({tickets: [...]} | {all_open: true} | {all: true}, mode?: 'default'|'md'|'json'})→ grouped table or markdown for cycle docsdev:kanban.audit_open()→ every non-✅ row in workspace kanban (one-shot)- Backbone triangulates: kanban row + git log +
soma:code.*+ sessions/preloads + cross-project trees (somaverse/somadian/website) - For high-stakes verdicts, follow with
soma:agent.delegate({role: 'verifier', background: true})— independent second-opinion catches what heuristics miss - Read first:
dev(op='help', cap='dev:kanban.audit')ordocs/_dev/kanban-audit.md
GitHub scanner v2 — treat any repo as local without cloning
soma:github.local_path({repo: 'owner/name'})→ fetch tarball + return extract path. Cache by SHA at~/.soma/cache/gh/. ~1–5s cold, instant warm.soma:github.local_map({repo, file})→ function/struct/class map of any file (12 langs: rs / ts-tsx / js-jsx / py / go / java / c-cpp / rb / sh / md / json / toml). API-modesoma:github.maponly knew rs/ts/py — local mode is the upgrade.soma:github.local_find({repo, pattern, path?, ext?})→ full ripgrep regex (API search is literal-only). Auto-scopes to repo’s primary language via meta.jsonlanguagehint.soma:github.local_refs({repo, symbol, path?})→ DEF/IMP/USE classification across the cached reposoma:github.local_blast({repo, symbol, path?})→ blast radius (files × risk) for a symbolsoma:github.local_structure({repo, path?})→ faster + richer than API once cachedsoma:github.cache_list()/soma:github.cache_clean({days?: N | all?: true})→ cache management- Plus 5 API-mode caps that were missing from the addon but already in the script:
audit,releases,diff,compare,file_diff
Soma docs got smarter
soma:docs.whats_new({version?, limit?: 3})→ THIS doc, version-scoped if askedsoma:docs.guide({name})→ resolves fromguides/first,_dev/second. Convenience over.show.soma:docs.listnow recursive (catchesguides/and_dev/) and shows TL;DR per entry, grouped by section
🔄 Behavior changes
breathe.autois now opt-in by default (was on by default). Auto-rotation at 70% context was wiping user input mid-compose. If you want it back: setbreathe.auto: truein.soma/settings.json. Existing installs are migrated once viabreathe-auto-off-v0.23.1(recorded in newsettings.migrations[]array; respects re-enable).soma initnow writes the correct version to.soma/settings.json. Pre-fix it stamped 0.10.0 because the package.json walk-up only walked one level. Fresh inits + repaired existing installs.soma updateauto-detects your remote name (was hardcoded toorigin; broke on dogfood worktrees withmeetsomaremote).soma doctorpersists version bump even whenfixes==0(was printing “version bumped” without writing settings.json).
🐛 Bugs you can stop stepping around
/inhalestale-after-reload — extension code that capturedpi.sendUserMessagewent stale after session rotation. Now consumesroute.get("message:send")for fresh closure. Pattern: anypi.Xconsumed across rotation should go through soma-route’s capability bus. Seeamps/muscles/internal/route-plumbing-first.md.soma:code.findreturned 0 results silently whenextwas passed withoutpath(positional CLI shifted ext into path slot). Cap now defaultspathto.when ext is set.- GitHub script silently 404’d on master-default repos —
BRANCH=mainwas hardcoded. v2 auto-detects viadefault_branchAPI field, falls back tomainonly on API failure. - GitHub script
--helpranstructureon a repo named--help— now short-circuits to usage block.
📁 New files / locations
~/.soma/cache/gh/<owner>--<repo>--<sha>/→ GitHub tarball cache..soma-meta.jsonper entry with{owner, repo, sha, ref, language, fetched_at, size_bytes}..soma/settings.jsonnow hasmigrations: []array — list of one-time semantic migration IDs that have been applied. The runtime appends to this; you don’t typically write to it.docs/_dev/[dev]— dev-only docs subdir, surfaced bysoma:docs.listwhen present.
🧰 Workflows
- End-of-arc kanban sweep:
dev:kanban.audit_open()before cutting a release. Closes 3–4 wrongly-marked tickets in seconds; spawns verifier delegations for the high-stakes ones. - Survey a third-party repo without cloning:
soma:github.local_path({repo: 'owner/name'})→ returns cache dir → run anything against it. Map / find / blast / refs all work locally with full toolchain. ~5s one-time cost, then instant. - Soma-code env override:
SOMA_CODE_DEFAULT_EXT="go,md"(or any ext list) overrides cwd-marker auto-detect. Use when working in monorepo subdirs or pre-modules language repos that lack manifest files.
🛠 New scripts
- A dev-only script for tarball fetch + extract + cache management (internal, not part of the public core)
.soma/amps/scripts/soma-audit-ticket.py[dev]— single-ticket audit (Python; the heuristics engine).soma/amps/scripts/soma-audit-tickets.sh[dev]— parallel batch wrapper (xargs -P 8)
📜 Plans referenced this arc
releases/v0.23.x/plans/github-tool-10x.md— the soma-github v1 → v2 architectural pivotreleases/v0.23.x/plans/discovered-tools-body-injection.md— the seed for self-discovering tool surface (Phase 0 done, Phase 1+ queued)
v0.23.0 — April 2026
The “release orchestrator + tree-hygiene” arc.
🆕 New caps
soma:agent.list({role: 'X'})→ filter children by role string. Stacks with existingactive_only/all/cleanup. Useful when a parent has spawned multiple roles and wants to inspect just one cohort.
🔄 Behavior changes
- Release orchestrator is now 10 gates (was 8). New: tree-hygiene (Phase 0.5) — halts on uncommitted state in this repo other than
M CHANGELOG.md. Prevents agent-spawned files leaking into ship. website-readiness (Phase 5.5) — callstests/test-release-surfaces.shfor CHANGELOG ↔ roadmap.json drift. - Phase 4-ship.md and 4.5-audit.md are archived. Their work is now inside
soma-release-prepare.sh+soma-release-ship.sh.
📜 Plans referenced this arc
- The release-flow doc — current head (10 gates documented)
- Old phase docs: archived alongside it.
v0.22.x and earlier
For the technical commit-by-commit history, see CHANGELOG.md at the repo root or https://soma.gravicity.ai/changelog. This whats-new.md only goes back to v0.23.0 — versions older than that didn’t have an agent-facing digest layer.
Conventions for whoever maintains this
- One section per release. Latest at top. Version + month + a one-line tagline.
- Density first. Skip the “why” if a one-liner won’t shrink the gain. Ship the “how to use it” — that’s what an agent reads to pick up the new surface.
- Tag dev-only.
[dev]after the cap name when it’s only on dev installs. - Always include invocation hint.
cap_name(args) → outcome. The agent reads this and can call it on the next turn. - No commits. Commits go in CHANGELOG.md. This file isn’t generated from git; it’s hand-curated for the agent’s benefit. Treat it like a muscle: dense, action-oriented.
- TL;DR up top so
soma:docs.listextracts a useful preview.