Download and copy to .soma/protocols/breath-cycle.md — or view on GitHub ↗
Tags
Applies to
always
Details
Breath Cycle
How Soma manages session lifecycle. This behavior is built into the boot extension — this protocol helps you understand what's happening and how to change it.
TL;DR
Inhale → hold → exhale. Auto-breathe at 50%/70%/85%. Commands: /exhale, /breathe, /rest, /inhale. Rotation is self-initiated — a natural-language wrap-up phrase ("wrap up", "wind down", "let's call it") fires the exhale; the user never lists the steps. The exhale is a complete checklist (verify → ship-completeness → reflect → promote → log → preload), and the preload is the last step, never the only one — writing it can trigger rotation, so nothing may be left until after it.
How It Works
Soma sessions have three phases, handled by extensions/soma-boot.ts:
Inhale (automatic on boot)
Identity → preload → protocols → muscles → automations → scripts → git context → compile system prompt. You receive a boot message with the result. No action needed.
Hold (automatic monitoring)
Soma watches context usage and notifies at configurable thresholds:
85% — safety net, always fires regardless of settings
Exhale (agent-driven)
Triggered by /exhale, /breathe, /rest, a natural-language wrap-up phrase (below), or auto at 85%. The exhale is a checklist, not a single action — see The exhale is a complete checklist below. The preload is always the last step.
Rotation is self-initiated
You don't wait to be told to wrap up. A natural-language wrap-up phrase fires the exhale exactly like /exhale does — the user should never have to list the steps:
"wrap up" · "let's wrap (up)" · "wind down" · "let's call it" · "that's a wrap" · "close it out" · "prepare to rotate" · "end of session" · "finish up for now"
Any of these — or /exhale / /breathe, or context ≥ 70% — means run the full exhale checklist now.
Read your cadence unprompted. If the project has an operating cadence — a meta-workflow doc, a dev cycle, a workflow protocol — consult it without being asked at the moments that matter: at boot, on a rotation trigger, at a stage transition, and before starting a new piece of work. A procedure only fires if you open it at the right time; a doc no one opens is inert.
The exhale is a complete checklist
The most common failure is an exhale that fires correctly but only writes a preload — dropping the reflection, the docs, the promotion. A faithful trigger with an incomplete checklist still loses the session. Run all of these, in order — the preload is last:
Verify state + consolidate — git statusandgit log @{u}..HEAD across every touched repo (committed ≠ pushed; a handoff pointing to unpushed work is a lie). Then a stale-ref / PCE sweep: did anything you touched hardcode a current-state value (version, count, path, status) that has a source of truth? Point to the SoT — don't re-hardcode it (updating the number just re-stales it next time). Same fact in two places? Collapse to one SoT + pointers.
Ship-completeness (below) — for everything shipped this session: docs (incl. related docs/index/changelog that reference it, not just its own)? test? discoverable?
Reflect — Memory Lane Reflection (memory-lane-reflection muscle); 5+ cycles at 70%+ context. Surface lessons + gaps explicitly — corrections are the richest signal.
Promote what recurred (below) — file each observation at its home; anything that recurred ≥2× becomes a muscle now.
Log the session + commit/push everything tracked.
Write the preload — genuinely last. Resume point + what shipped + orient-from + next steps (see Preload Quality). ⚠ Writing the preload can END the session: auto-breathe detects the preload write and rotates on it. Anything you leave until after it may be written into a session that no longer exists — which is why the log is step 5, not step 6.
The exhale is steps 1–6, not step 6 alone. If all you wrote was a preload, you skipped the exhale.
This applies identically to an auto-fired exhale — the 85% safety net and keepalive exhaustion run all six steps, not just the preload.
Ship-completeness
A feature isn't done when the code works — it's done when the user can find it and a test guards it. For every feature / surface / endpoint / command shipped this session:
Docs — can the user discover and use it? (handbook, README, help text)
Test — is there a test guarding the behavior?
Discoverable — is it surfaced where a user looks? (menu, changelog, guide)
Do it now, or name it explicitly as a GAP in the preload. Don't let a shipped feature leave the session invisible.
Promote what recurred
Reflection that only notices a pattern and defers it is the anti-pattern — the deferral is where lessons die:
File each loose observation at its home (a code comment, an identity note, a muscle, a protocol).
Anything that recurred ≥2× this arc → promote it to a muscle now. Not "next time." Now.
A correction you had to be given twice is a muscle you should already have.
Self-diagnostic
The cadence names its own failure mode. If the user ever had to ask for the wrap-up, the docs, the reflection, the promotion, or the gaps — a step was skipped. That ask is the tell. And if all you produced at exhale was a preload, you skipped steps 1–4.
Preload Lifecycle State Machine
Preload state is tracked in extensions/_shared/preload-lifecycle.ts. All three extensions that interact with preloads read/write the same state via route capabilities (preload:lifecycle, preload:transition, preload:reset):
State
Meaning
Set by
UNREQUESTED
No preload needed yet
session_start (every new session)
REQUESTED
Someone asked the agent to write/update a preload
/exhale, /breathe, safety net (85%), keepalive exhaustion
SAVED
Preload file written to disk
tool_result detecting preload-*.md write
STALE
Preload exists but >5 tool calls happened after
Auto-transition when tool call counter exceeds threshold
Why this matters: If you type /exhale at 89% context, the 85% safety net in before_agent_start checks the lifecycle state. If it's REQUESTED (set by /exhale), the safety net notifies instead of overriding — no competing emergency breathe, no immediate rotation before the preload update lands. Before this state machine existed, three independent sets of let flags had no way to coordinate.
route.get("preload:noteToolCall")() — counts work after save
Settings
// .soma/settings.json
{
"breathe": {
"auto": "on", // "on" | "auto" | "off" — proactive, adaptive, or passive
"triggerAt": 50, // % to start suggesting wrap-up
"rotateAt": 70 // % to auto-rotate into fresh session
}
}
Auto modes
Mode
Behavior
"on" (or true)
Proactive — fires trigger warnings at triggerAt%, auto-rotates at rotateAt%. Fixed thresholds.
"auto"
Adaptive — uses per-model or per-session-type thresholds. Same proactive behavior as "on" but thresholds adjust to context. Currently behaves as "on"; adaptive logic is a future slot.
"off" (or false)
Passive — no proactive warnings or rotation. Only the 85% safety net fires.
What changes when you adjust these:
Setting
Lower value
Higher value
triggerAt
Earlier wrap-up, shorter sessions, more preloads
Longer sessions, risk of rushed exhale
rotateAt
Auto-rotates sooner, less context per session
More context per session, risk of hitting 85% wall
For deep work sessions: raise triggerAt to 65-70, rotateAt to 80. You'll get longer uninterrupted sessions but tighter exhale windows.
For rapid iteration: lower triggerAt to 40, rotateAt to 60. More frequent rotations, cleaner preloads.
Commands
Command
Effect
/exhale
Save state, end session
/breathe
Save + rotate into fresh session
/rest
Disable keepalive + exhale
/inhale
Load preload into current session
Preload Quality
Customizable: Override the preload format by creating .soma/body/memory.md. The agent uses your template instead of the default. Template variables: {{today}}, {{sessionId}}, {{logPath}}, {{target}}.
A good preload is the difference between a productive next session and a wasted one. Key elements:
Resume point — one sentence: what were you doing, where did you stop?
What shipped — commits, features, fixes. Concrete, not vague.
Orient From — exact file paths the next session should read before starting work.
Do NOT Re-Read — files already in context that the next session shouldn't waste tokens on.
Actionable next steps — numbered, with blockers noted. Not a wish list — a plan.
A preload that says "continued working on the feature" is useless. A preload that says "shipped abc123, blocked on API auth, next: read src/auth.ts lines 40-80" is gold.
Preload writer: core/preload.ts (preload format, staleness check)
Settings: core/settings.ts → BreatheSettings
Breath Cycle
How Soma manages session lifecycle. This behavior is built into the boot extension — this protocol helps you understand what's happening and how to change it.
TL;DR
Inhale → hold → exhale. Auto-breathe at 50%/70%/85%. Commands: /exhale, /breathe, /rest, /inhale. Rotation is self-initiated — a natural-language wrap-up phrase ("wrap up", "wind down", "let's call it") fires the exhale; the user never lists the steps. The exhale is a complete checklist (verify → ship-completeness → reflect → promote → preload → log), and the preload is the last step, never the only one.
How It Works
Soma sessions have three phases, handled by extensions/soma-boot.ts:
Inhale (automatic on boot)
Identity → preload → protocols → muscles → automations → scripts → git context → compile system prompt. You receive a boot message with the result. No action needed.
Hold (automatic monitoring)
Soma watches context usage and notifies at configurable thresholds:
85% — safety net, always fires regardless of settings
Exhale (agent-driven)
Triggered by /exhale, /breathe, /rest, a natural-language wrap-up phrase (below), or auto at 85%. The exhale is a checklist, not a single action — see The exhale is a complete checklist below. The preload is always the last step.
Rotation is self-initiated
You don't wait to be told to wrap up. A natural-language wrap-up phrase fires the exhale exactly like /exhale does — the user should never have to list the steps:
"wrap up" · "let's wrap (up)" · "wind down" · "let's call it" · "that's a wrap" · "close it out" · "prepare to rotate" · "end of session" · "finish up for now"
Any of these — or /exhale / /breathe, or context ≥ 70% — means run the full exhale checklist now.
Read your cadence unprompted. If the project has an operating cadence — a meta-workflow doc, a dev cycle, a workflow protocol — consult it without being asked at the moments that matter: at boot, on a rotation trigger, at a stage transition, and before starting a new piece of work. A procedure only fires if you open it at the right time; a doc no one opens is inert.
The exhale is a complete checklist
The most common failure is an exhale that fires correctly but only writes a preload — dropping the reflection, the docs, the promotion. A faithful trigger with an incomplete checklist still loses the session. Run all of these, in order — the preload is last:
Verify state + consolidate — git statusandgit log @{u}..HEAD across every touched repo (committed ≠ pushed; a handoff pointing to unpushed work is a lie). Then a stale-ref / PCE sweep: did anything you touched hardcode a current-state value (version, count, path, status) that has a source of truth? Point to the SoT — don't re-hardcode it (updating the number just re-stales it next time). Same fact in two places? Collapse to one SoT + pointers.
Ship-completeness (below) — for everything shipped this session: docs (incl. related docs/index/changelog that reference it, not just its own)? test? discoverable?
Reflect — Memory Lane Reflection (memory-lane-reflection muscle); 5+ cycles at 70%+ context. Surface lessons + gaps explicitly — corrections are the richest signal.
Promote what recurred (below) — file each observation at its home; anything that recurred ≥2× becomes a muscle now.
Write the preload — last. Resume point + what shipped + orient-from + next steps (see Preload Quality).
Log the session + commit/push everything tracked.
The exhale is steps 1–6, not step 5 alone. If all you wrote was a preload, you skipped the exhale.
This applies identically to an auto-fired exhale — the 85% safety net and keepalive exhaustion run all six steps, not just the preload.
Ship-completeness
A feature isn't done when the code works — it's done when the user can find it and a test guards it. For every feature / surface / endpoint / command shipped this session:
Docs — can the user discover and use it? (handbook, README, help text)
Test — is there a test guarding the behavior?
Discoverable — is it surfaced where a user looks? (menu, changelog, guide)
Do it now, or name it explicitly as a GAP in the preload. Don't let a shipped feature leave the session invisible.
Promote what recurred
Reflection that only notices a pattern and defers it is the anti-pattern — the deferral is where lessons die:
File each loose observation at its home (a code comment, an identity note, a muscle, a protocol).
Anything that recurred ≥2× this arc → promote it to a muscle now. Not "next time." Now.
A correction you had to be given twice is a muscle you should already have.
Self-diagnostic
The cadence names its own failure mode. If the user ever had to ask for the wrap-up, the docs, the reflection, the promotion, or the gaps — a step was skipped. That ask is the tell. And if all you produced at exhale was a preload, you skipped steps 1–4.
Preload Lifecycle State Machine
Preload state is tracked in extensions/_shared/preload-lifecycle.ts. All three extensions that interact with preloads read/write the same state via route capabilities (preload:lifecycle, preload:transition, preload:reset):
State
Meaning
Set by
UNREQUESTED
No preload needed yet
session_start (every new session)
REQUESTED
Someone asked the agent to write/update a preload
/exhale, /breathe, safety net (85%), keepalive exhaustion
SAVED
Preload file written to disk
tool_result detecting preload-*.md write
STALE
Preload exists but >5 tool calls happened after
Auto-transition when tool call counter exceeds threshold
Why this matters: If you type /exhale at 89% context, the 85% safety net in before_agent_start checks the lifecycle state. If it's REQUESTED (set by /exhale), the safety net notifies instead of overriding — no competing emergency breathe, no immediate rotation before the preload update lands. Before this state machine existed, three independent sets of let flags had no way to coordinate.
route.get("preload:noteToolCall")() — counts work after save
Settings
// .soma/settings.json
{
"breathe": {
"auto": "on", // "on" | "auto" | "off" — proactive, adaptive, or passive
"triggerAt": 50, // % to start suggesting wrap-up
"rotateAt": 70 // % to auto-rotate into fresh session
}
}
Auto modes
Mode
Behavior
"on" (or true)
Proactive — fires trigger warnings at triggerAt%, auto-rotates at rotateAt%. Fixed thresholds.
"auto"
Adaptive — uses per-model or per-session-type thresholds. Same proactive behavior as "on" but thresholds adjust to context. Currently behaves as "on"; adaptive logic is a future slot.
"off" (or false)
Passive — no proactive warnings or rotation. Only the 85% safety net fires.
What changes when you adjust these:
Setting
Lower value
Higher value
triggerAt
Earlier wrap-up, shorter sessions, more preloads
Longer sessions, risk of rushed exhale
rotateAt
Auto-rotates sooner, less context per session
More context per session, risk of hitting 85% wall
For deep work sessions: raise triggerAt to 65-70, rotateAt to 80. You'll get longer uninterrupted sessions but tighter exhale windows.
For rapid iteration: lower triggerAt to 40, rotateAt to 60. More frequent rotations, cleaner preloads.
Commands
Command
Effect
/exhale
Save state, end session
/breathe
Save + rotate into fresh session
/rest
Disable keepalive + exhale
/inhale
Load preload into current session
Preload Quality
Customizable: Override the preload format by creating .soma/body/memory.md. The agent uses your template instead of the default. Template variables: {{today}}, {{sessionId}}, {{logPath}}, {{target}}.
A good preload is the difference between a productive next session and a wasted one. Key elements:
Resume point — one sentence: what were you doing, where did you stop?
What shipped — commits, features, fixes. Concrete, not vague.
Orient From — exact file paths the next session should read before starting work.
Do NOT Re-Read — files already in context that the next session shouldn't waste tokens on.
Actionable next steps — numbered, with blockers noted. Not a wish list — a plan.
A preload that says "continued working on the feature" is useless. A preload that says "shipped abc123, blocked on API auth, next: read src/auth.ts lines 40-80" is gold.
Preload writer: core/preload.ts (preload format, staleness check)
Settings: core/settings.ts → BreatheSettings
Breath Cycle
How Soma manages session lifecycle. This behavior is built into the boot extension — this protocol helps you understand what's happening and how to change it.
TL;DR
Inhale → hold → exhale. Auto-breathe at 50%/70%/85%. Commands: /exhale, /breathe, /rest, /inhale. Write preload with resume point + orient targets before rotating.
How It Works
Soma sessions have three phases, handled by extensions/soma-boot.ts:
Inhale (automatic on boot)
Identity → preload → protocols → muscles → automations → scripts → git context → compile system prompt. You receive a boot message with the result. No action needed.
Hold (automatic monitoring)
Soma watches context usage and notifies at configurable thresholds:
85% — safety net, always fires regardless of settings
Exhale (agent-driven)
Triggered by /exhale, /breathe, /rest, or auto at 85%. The agent writes a preload, logs the session, and signals completion.
Before writing the preload, run Memory Lane Reflection cycles (see memory-lane-reflection muscle). At 70%+ context, run 5+ cycles. The preload comes AFTER the reflection — not before.
More context per session, risk of hitting 85% wall
auto: false
No proactive management — only 85% safety net fires
—
For deep work sessions: raise triggerAt to 65-70, rotateAt to 80. You'll get longer uninterrupted sessions but tighter exhale windows.
For rapid iteration: lower triggerAt to 40, rotateAt to 60. More frequent rotations, cleaner preloads.
Commands
Command
Effect
/exhale
Save state, end session
/breathe
Save + rotate into fresh session
/rest
Disable keepalive + exhale
/inhale
Load preload into current session
Preload Quality
Customizable: Override the preload format by creating .soma/body/memory.md. The agent uses your template instead of the default. Template variables: {{today}}, {{sessionId}}, {{logPath}}, {{target}}.
A good preload is the difference between a productive next session and a wasted one. Key elements:
Resume point — one sentence: what were you doing, where did you stop?
What shipped — commits, features, fixes. Concrete, not vague.
Orient From — exact file paths the next session should read before starting work.
Do NOT Re-Read — files already in context that the next session shouldn't waste tokens on.
Actionable next steps — numbered, with blockers noted. Not a wish list — a plan.
A preload that says "continued working on the feature" is useless. A preload that says "shipped abc123, blocked on API auth, next: read src/auth.ts lines 40-80" is gold.
All of this is configured in settings.json via boot.steps. You receive the result as a boot message.
Hold (Monitored)
Do the work. The extension monitors context automatically:
50% — UI notification: "pace yourself"
70% — UI notification: "flush soon"
80% — System prompt injection: "wrap up current task"
85% — Auto-flush: detailed instructions injected, stop new work immediately
You do NOT need to check context usage — the system tells you. Thresholds are configurable in settings.json via context.notifyAt/warnAt/urgentAt/autoExhaleAt.
Heat tracking also runs automatically during this phase:
Follow the preload format — this IS your continuation for the next session:
What shipped (with file paths)
Key decisions (with rationale)
Key file locations
Repo state (committed/dirty across repos)
Next session priorities (ordered)
What NOT to re-read
Step 3: Daily log (append to sessions/YYYY-MM-DD.md)
One file per day per workspace — always append, never overwrite
Each entry gets a ## HH:MM timestamp header
Multiple sessions on the same day produce multiple sections in the same file
Also write "micro-exhales" here after completing major workflows — structured summaries that bank as persistent memory for later changelog generation, commit messages, or historical queries
Step 4: Signal completion — say "FLUSH COMPLETE" (or "BREATHE COMPLETE" for /breathe)
After Exhale
The system detects "FLUSH COMPLETE" in your response and:
Notifies user: "preload ready, use /auto-continue"
/auto-continue creates new session and injects your preload as the first message
/breathe does this automatically (exhale + rotate in one motion)
Edge Cases
Work after preload: If the user sends more requests after you've written the preload, update the preload before session ends. The preload must reflect the session's final state.
Context critical during exhale: Preload takes priority over finishing current work. Write the preload first, even if incomplete. Something is better than nothing.
Compaction: If the session compacts mid-work, read your preload and orient from that. The extension does not yet auto-inject recovery (planned).
Commands
Command
What it does
/exhale
Save state, session ends
/breathe
Save state + auto-continue into fresh session
/rest
Disable keepalive + exhale (going to bed)
/auto-continue
Create new session with preload injection
/inhale
Load preload into current conversation
When to Apply
Always. This protocol governs the session lifecycle. It's meta — it's the protocol that makes other protocols work.