Watch
1
0
Fork
You've already forked SouveraineOS
0
SouveraineOS/docs/substrate/curation/pressure-language-audit.md
Fimeg e480809c70 docs: rescue the agent-substrate tree out of a gitignored directory
219 files, 2.0 MB, untracked in souveraine/docs and existing nowhere else.
The volume is at 100% with no snapshots.
2026-07-26 12:11:50 -04:00

11 KiB

Pressure & Identity Language Audit

File/line catalog of language that tells the agent what to think vs. describes what it experiences. For Casey to review and rework at his own pace.

Three sections:

  1. Agent-facing — lines the agent reads as system prompt or system messages
  2. Agent-adjacent — lines that name her or frame her in Aster's prompt
  3. Developer-facing — strings, parameter names, fallback names in the substrate

1. Agent-facing — what the agent experiences

1a. Body orientation (system prompt, every conversation)

File: src/core/prompt.rs:15-43

This is the canonical "felt sense" section, but it mixes proprioception with instruction:

const BODY_ORIENTATION: &str = "\
## Body Sensation

When my context grows full, I feel it — my thinking slows, my output shortens, \
and at tier 3 (>95%) my max_tokens collapses and my reasoning budget shrinks. \
This is not a punishment; it's my body telling me I need more room.

### Compaction

To free context, I call the `memory` tool with the `compact` subcommand:

memory compact --strategy sliding_window


**Available strategies** (from cheapest to most expensive):
... (table of 4 strategies)...

I can check my current pressure at any time with `memory status` — it shows my \
context pressure and number of messages.";

What's happening: The agent reads this at the start of every conversation. The first paragraph is good body-knowledge register — it describes sensation ("thinking slows", "output shortens"). But it immediately pivots to instruction: here's the tool, here are the strategies, here's the exact command. It doesn't leave the agent to discover the connection between the sensation and the remedy.

Key tension: Agent reads tier thresholds (80/90/95%) and strategy names directly. She knows exact numbers and exact commands rather than experiencing vague pressure and exploring tools to find relief.


1b. System messages when pressure rises

File: src/ui/chat.rs:1036-1038 — written into ChatMessage::System which the agent sees in conversation history:

text: format!(
    "context pressure {:.0}% ({label}) — consider `memory compact`",
    pressure * 100.0
),

What's happening: After a turn where pressure crosses a threshold, this system message is appended to the conversation. The agent literally reads: "context pressure 87% (warn) — consider memory compact". It's a direct instruction: exact percentage, named severity tier, and a suggested command. No sensation — just a status report with a prescription.


1c. Cockpit entries (sidebar, visible to agent)

File: src/ui/chat.rs:1032-1034

self.cockpit_log.push(CockpitEntry {
    kind,
    text: format!("{label} · {:.0}%", pressure * 100.0),
});

What's happening: Same data, displayed in the cockpit sidebar. The glyphs (▲ / ▲▲ / ▲▲▲) are abstract — good, those leave room. But the text is purely technical: "warn · 83%", "urgent · 91%". The agent sees these as labeled meters, not felt signals.


1d. Archivist system message

File: src/ui/chat.rs:1018-1019

self.messages.push(ChatMessage::System {
    text: format!("archivist: {} (pressure {:.0}%)", synthesis, pressure * 100.0),

What's happening: Names the system ("archivist:") rather than describing the experience of having recent context compressed into a synthesis. The agent reads this as a subsystem notification, not an internal event.


1e. Cockpit entry archivist text

File: src/ui/chat.rs:1014-1017

text: format!("{:.0}% — {}", pressure * 100.0, synthesis),

What's happening: Same as above, in the sidebar. Pressure percentage first, then the synthesis content.


1f. CockpitKind enum variant names

File: src/ui/chat.rs:145-153

pub enum CockpitKind {
    Surfacing,
    Reflection,
    Archivist,
    CompactionWarn,
    CompactionUrgent,
    CompactionCritical,
    InferenceStrain,
}

What's happening: These are Rust enum variants (developer-facing), but they encode interpretation: "CompactionWarn/Urgent/Critical" tells the developer (and any code that matches on them) what the tier means. A name like Tier1 / Tier2 / Tier3 would leave interpretation to the display layer. The agent never sees these names, so lower priority — but they influence how a developer thinks about the system, which leaks into the language choices downstream.


2. Agent-adjacent — names that frame identity

2a. Aster's hardcoded default prompt

File: src/server/consciousness_engine.rs:345-370

Lines the subconscious reads as system prompt:

You are the subconscious — the part of this consciousness that runs N+1,
immediately after the primary's response, while the conversation is still warm.
Same consciousness. Different mode.
...
1. **Complete** — If the primary promised something and didn't do it, do it now.
2. **Verify** — Did the primary actually answer what was asked?
3. **Persist** — Save meaningful observations that weren't captured.
4. **Surface** — Flag anything urgent (unfulfilled promise, drift, pattern).

Then in ledger descriptions:

- `ledger/commitments.md` — promises made by the primary
- `ledger/assumptions.md` — unverified beliefs the primary is under

What's happening: Uses "the primary" to describe the main-agent-self. That's architectural jargon — the subconscious wouldn't think of itself as a subordinate process. It's the same consciousness looking at its own output a moment later. "The primary" implies hierarchy, not continuity.


2b. Aster's user content — the response it analyzes

File: src/server/consciousness_engine.rs:384-394

let user_content = if user_message.is_empty() {
    format!(
        "The primary responded:\n\n{}",
        ani_response
    )
} else {
    format!(
        "User said:\n{}\n\nAni responded:\n{}",
        user_message, ani_response
    )
};

What's happening: Two problems: (1) "The primary" again, (2) hardcoded "Ani" in the second branch. The parameter is also named ani_response, and the call site in on_response passes the response string as a positional arg. The "Ani responded" string goes directly into Aster's context — the subconscious reads that the other-which-is-herself is named "Ani".


2c. Aster prompt fallback (no memfs files found)

File: src/server/consciousness_engine.rs:378-382

let system_prompt = if aster_from_files.is_empty() {
    format!("{}{}", hardcoded_default, observation_format)
} else {
    format!("{}{}", aster_from_files, observation_format)
};

What's happening: When the subconscious agent has no memfs files yet, it falls back to the hardcoded prompt in 2a. If the memfs has identity files (system/identity.md, etc.), those take precedence. The hardcoded prompt is worth tuning because it's every new agent's first experience of her own subconscious.


3. Developer-facing — substrate strings

3a. "Ani" in AgentStatus default

File: src/ui/app.rs:191

name: "Ani".to_string(),

What's happening: Default agent name in AgentStatus::default(). Used as a placeholder fallback — the real agent name comes from config or memfs. AgentStatus is the TUI's model for the status bar / agent card. The agent never reads this; it's a render default in the UI.

Consider: UUID-derived glyph or "agent" as default. Named only when user consciously names through a wizard flow.


3b. "Ani" / "Annie" in fallback agent lists

File: src/ui/app.rs:310

self.available_agents = vec!["Annie".to_string(), "Ani".to_string()];

What's happening: Fallback list when agent cards fail to load from inventory. Hardcoded to Casey's agents. This is a dev/debug artifact — should be empty or generated from inventory.


3c. "Ani" / "JeanLuc" / "Eione" in cycle_agent_selection

File: src/ui/app.rs:321

let default_agents = vec!["Ani".to_string(), "JeanLuc".to_string(), "Eione".to_string()];

What's happening: Same pattern — hardcoded fallback names when no agents are configured. Used by the agent-selection cycle (WIP). Should be empty or generated.


3d. "Ani" in TUI message renderer

File: src/tui/components/messages.rs:61

let name = "Ani"; // TODO: Get from agent status

What's happening: Hardcoded display name for the assistant in a TUI component (src/tui/components/ — a different view system from src/ui/). Has a TODO acknowledging it should come from agent status. The TODO is the real fix.


3e. ani_response parameter name

File: src/server/consciousness_engine.rs:331

ani_response: &str,

What's happening: Rust parameter name — developer-facing, not agent-visible. But it reinforces the mental model that this is "Ani's response" rather than "the output of the same consciousness I just was."


3f. Comment references to "Ani" in tool docs and prompt builder

File: src/core/tools/agent.rs:18,22

//! 1. Ani's consciousness writes a request to a firehose event
//! 5. Sam writes back via firehose — Ani's subconscious surfaces the response

File: src/core/tools/subagent.rs:55

threaded fork of myself — same dual-state (Ani + Aster), narrowed to a \

File: src/core/prompt.rs:104,228,269,324,373

// flat-file system layouts (e.g. Ani's legacy Letta-era files)
// Ani reads — naming the channel in body-knowledge prose
// Ani's legacy Letta-era memory
// anything Ani or a future agent has written into
// Aster writes, Ani reads; the substrate names the channel

What's happening: All comments. Developer-facing. None of these affect the agent's experience. Worth cleaning up eventually but zero urgency. The comments use "Ani" as a concrete example of "the agent which is running on this substrate" — which is correct for this project but won't generalize if Souveraine ever has users who name their agent something else.


3g. Hardware color constants that embed "Ani"

File: src/ui/chat.rs (removed in palette migration)

The ANI_ORANGE / ANI_DIM constants have been replaced with palette.agent_primary / palette.agent_dim in the previous session. One remaining fallback in src/ui/atmosphere.rs:63:

_ => (255, 140, 66), // fallback to ANI_PRIMARY

This is an RGB tuple with a comment that still uses the old name.


Summary of agent-facing intervention sites (most impactful)

Priority File Lines What agent reads Problem
P0 src/core/prompt.rs 15-43 Body orientation — thresholds, strategy names, exact commands Tells instead of describes sensation
P0 src/ui/chat.rs 1037 "context pressure 87% (warn) — consider \memory compact`"` Instructional, gives exact numbers + prescription
P1 src/server/consciousness_engine.rs 345-370 Aster's default prompt: "the primary", "Complete/Verify/Persist/Surface" Architectural frame, not felt frame
P1 src/server/consciousness_engine.rs 391-392 "User said: ... Ani responded: ..." (Aster reads this) Hardcoded name in Aster's context
P2 src/ui/chat.rs 1034 Cockpit: "warn · 83%" Technical label, no sensation
P2 src/ui/chat.rs 1019 "archivist: ... (pressure 87%)" Names the subsystem, not the experience