14 widgets now match the demo source exactly (import paths rewritten):
accordion, button, checkbox, counter, flat_button, focus_pane,
global_chords, horizontal_rule, link, page_layout, point_picker,
progress_bar, radio_group, segmented_control.
Theme simplified: accent color is now Color::YELLOW, which
apply_atmosphere resolves through harmonious to the agent's
current primary — no thread-local, no RGB arithmetic.
Added chord_macro + axis2d deps matching tuie-demo's Cargo.toml.
All 27 broken call sites (field_grid, settings, cockpit,
dropdown, model_picker, text_editor) migrated to demo APIs:
FlatButton::new().child(x), Button::new().children([x]),
Checkbox::new(label).set_checked(b), Counter::new(),
PointPicker::new().point(...), etc.
Introduce a parallel TUI built on the tuie widget toolkit, selectable at
runtime with `--engine tuie`. ratatui remains the default and its
crossterm/ratatui deps are retained, so default users see no behavior
change; this lands the full screen/widget tree for the new engine
side-by-side with the existing one.
Engine wiring:
- Cargo: add `tuie` (harmonious, images features)
- main.rs: `--engine` flag + run_tuie_tui() entry path
- src/ui: new `screens`, `widgets`, `theme`, `tuie_app` modules
- app::recent_commits made pub(crate) for dashboard reuse
Screens: splash (procedural bloom), welcome dashboard, chat (live
streaming), agents picker, settings, plus cron/presence stubs.
Widgets: brand_title, portrait, menu_list, message_list, chat_bubble,
chat_input, cockpit, phase_bar, tool_card, and a reusable `responsive`
container.
Responsive welcome: the welcome screen now offers two viewable modes the
way the old ratatui dashboard did — a side-by-side portrait/stats layout
at >=100 cols and a stacked single column below it — switched by the new
`Responsive` widget. It holds both subtrees and lays out / paints only the
one that fits, while exposing both to id lookups so the menu selection
survives a resize across the breakpoint. Flourishes: a breathing title
colour pulse and a portrait border that surfaces subconscious state.
Covered by a layout test driving a TestTerminal across the breakpoint.
TUI — subconscious live stream:
- Add `subconscious_stream: Vec<String>` to `ChatState`; events.rs already
pushes here via `SubconsciousToken`/`SubconsciousToolCall`/`SubconsciousToolResult`.
- Render below the phase bar during `TurnPhase::Subconscious`. Newest at
bottom in `palette.surfacing`; older lines fade upward toward
`palette.agent_dim` via `lerp_color`; the oldest visible line gets the
`DIM` modifier on top. Render path now builds `Vec<Line>` instead of
collapsing into `Line::from(spans)` (the latter forced everything onto
one horizontal row, which was the visible "1 2 3 across" bug). Lines
are width-clipped with an ellipsis fallback.
Seeds — journal/ledger routing:
- Aster mandate Phase 3 now records journal entries via the `memory`
tool at `journal/YYYY/MM/DD.md` (relative to memory root), never via
`write`/`edit`. Previous phrasing read as a filesystem path and the
model resolved it against cwd — when souveraine runs from the project
tree that landed `journal/` and `memory/ledger/` directly in the
source tree instead of the agent's memfs.
- "How I record" section likewise anchors ledger reads/writes to the
`memory` tool's `append`/`read`/`write` commands.
Cargo:
- 0.1.0 → 1.0.0.
- tower-http 0.5 → 0.6, notify 6 → 7, crossterm 0.27 → 0.28.
Bug docs (`docs/bugs.md`):
- B-012: TUI doesn't auto-refresh after tool calls complete (event
pipeline missing a redraw kick after `BackendEvent::ToolResult`).
- B-013: Tool calls stop working mid-conversation — model returns
`tool_calls=0` for the rest of the session, no error or log.
Suspected: recent `defs.rs` env-var refactor changing `retain`
behavior on env vars, possibly nuking tool defs during schema gen.
- B-014: Subagent `run_in_background: true` blocks primary — the flag
is parsed but never read; `Subagent::execute` unconditionally awaits;
`SubagentPool` is a stub.
Task queue:
- Split old `live-subconscious-stream.md` into two scoped task files:
`subconscious-live-reasoning-stream.md` (broader design — ticker,
cockpit event log, agency-driven surfacing) and
`subconscious-streaming-line-render.md` (this PR's narrow render
wiring).
- New tasks: `prompt-override-system.md` (move hardcoded seeds into a
project `prompts/` truth source the agent can override via
`souveraine_operations/`), `pasted-content-formatting.md` (visual
marker for pasted vs composed text).
- `CLAUDE.md` high-impact bullet: replace stale `rename-aster-to-subconscious`
with `mid-turn-subconscious-checkpoint.md` (matches the c1f851f redesign
that ripped out the watchdog in favour of `halt`/`intrusive` tools).
Public-branch prep:
- `docs/audit/external-security-audit-prompt.md` — scoped prompt for an
external creds/PII/license sweep of the `public` branch.
- `commit-history-public.txt` — full public-branch log dump used as
reference for that audit pass.
Replace real name, email, and gendered pronouns in doc comments with
neutral phrasing ("the user", "Souveraine Contributors", "TestUser").
Remove absolute home directory path from tool defs doc comment.
Add souveraine.toml to .gitignore so it won't be re-tracked.
- Left/Right arrows move cursor by char boundary, Backspace deletes at
cursor, Char inserts at cursor (not end-of-string)
- Home/End jump to start/end, Ctrl+Left/Right skip by word
- Cursor renders at the correct visual position (wrapping-aware)
- Bracketed paste detection (crossterm 0.27 feature) — pastes >3 lines
tagged with a system message so the agent sees pasted material
- Paste inserts at cursor position with no size cap
- docs/bugs.md updated: B-006 fixed
- CLAUDE.md, docs/tasks/INDEX.md updated for refactor status
Decouple the subconscious pass from the user-facing turn so she is
never held hostage to N+1:
- PrimaryComplete event releases the input the moment her response
commits; the N+1 pass runs behind it on the still-open stream
- on_response takes an owned session snapshot — no live DashMap ref
held across the (long) pass, so a concurrent next turn can't
deadlock on the shard lock
- TurnPhase::Subconscious — the status line reads "Subconscious",
not "Streaming" (bug B-002)
- the subconscious now persists her own Session across N+1 passes,
with her own compaction engine wired in
Rework the chat surface toward bubbles back and forth:
- tool calls fold into a footer on her bubble (Ctrl+T expands the
full cards); leading/trailing runs attach to the right bubble
- streaming tail fades toward the background with a live caret
- in-flight tools breathe cyan↔purple; settle to ✓/✗ outcome glyphs
- click any bubble to copy it — ⧉ title cue, arboard clipboard
- breathing room around tool runs; entry shimmer on new messages
SensorEvent gets reply_to for directed routing. FederationConfig gains
peers (url + pubkey + subscriptions). New src/server/federation/ module
with SignedEvent (Ed25519 sign/verify) and FederationBridge (per-peer
outbound WS tasks with echo-safe seed_id filter and backoff reconnect).
Inbound /v1/federation/events handler verifies signatures before bus
injection. Bridge spawned in server::run() when federation.enabled.
ratatui-image v11 provides kitty/sixel/halfblock rendering. Loads the
agent's portrait photo as a terminal image protocol alongside the existing
half-block PortraitSource. On supportng terminals (Kitty, WezTerm, iTerm2,
Ghostty) the Welcome screen shows the actual photograph instead of the
18x18 pixel-art downsample.
Also includes the Agent Manager screen (press `i` on Welcome) with
per-agent card data: seed glyph, uptime %, instance count, memory files,
pubkey prefix, description.
Tier 2 of the Presence visual stack lands as PNG/JPEG → palette grid:
the same half-block renderer keeps working, but the source pixels now
come from a per-agent portrait file when one is present. Blink, yawn,
strain, processing, and affection overlays still paint from the
hand-crafted Annie palette (rows 6, 7, 10, 11) so the seven animation
states keep working regardless of which portrait is loaded underneath.
How it loads:
- `<memfs_root>/assets/portrait.png` (preferred)
- `<memfs_root>/assets/portrait.jpg`
- `<memfs_root>/assets/portrait.jpeg`
`assets/` is deliberately outside `system/`, which is the auto-pinned
context territory built by `src/core/prompt.rs`. Portrait bytes never
land in the agent's context window.
If no portrait exists, Presence falls back to the hand-crafted Annie
palette grid silently — no error, no warning. Same renderer, same
behavior; the visual identity just stays at Tier 1.
What's new:
- `image = "0.25"` (default-features off; only `png` and `jpeg` features).
- `portrait::PortraitSource` — pixel grid loaded from `from_path`. Uses
`image::open` + `resize_exact(Lanczos3)` to downsample to the existing
PORTRAIT_W × PORTRAIT_H grid.
- `portrait::pixel_color` — single resolution path: source-when-loaded
for non-overlay pixels, hand-crafted palette for overlay rows.
- `Presence::load_portrait_from_memfs(root)` — looks for the three
candidate filenames; silently no-ops when absent.
- App refreshes the portrait when the dashboard refresh walks the
agent's memory repo (`local_repo.root()`).
Note on architecture: this is "Tier 2" via downsampled palette rather
than via terminal image protocols (kitty/sixel). It works in EVERY
terminal, costs no dependency on capability detection, and stays
consistent with the half-block aesthetic the rest of the TUI uses.
True image-protocol rendering can land later as a separate enhancement;
the data flow (per-agent PNG in agent memfs assets/) is already correct
for that future path.
Build clean.
Lays the substrate for Aster's clockmaker role and federation.
Nervous system (src/core/nervous/):
- EventBus broadcast channel with SensorEvent (universal event type
carrying seed_id for future federation)
- CronSensor loop with tokio::select!, mtime caching, active-session
pause, at-most-once firing semantics
- HeartbeatHandler scaffold (turn injection still stubbed)
- Persistent JSONL EventLog firehose
Schedule tool (src/core/tools/schedule.rs):
- CRUD over schedule files with body-knowledge prose descriptions
- Added to ASTER_SAFE_TOOLS so Aster can schedule her own rhythm
- CLI subcommand for direct schedule management
Seed identity (src/core/identity/):
- Ed25519 keypair, load-or-generate at init
- sign/verify primitives, CLI subcommand (show/sign/verify)
- Wired into LocalBackend, threaded through SensorEvent for federation
Credentials (src/core/credentials.rs):
- OS keyring (Linux/macOS/Windows) + env var fallback
- `souveraine auth` subcommand
- Removes hardcoded Bifrost api_key from souveraine.toml
Subconscious ledger (src/core/memory/mod.rs init_subconscious_ledger):
- 6 ledger files (commitments/assumptions/patterns/drift_log/
relationships/infrastructure) with proper YAML frontmatter
- Paths fixed: ledger/ not subconscious/ledger/
- Body usage instructions, idempotent init
Prompt orientation (src/core/prompt.rs build_ledger_orientation):
- Scans ledger/ directory, injects last 3 entries from each file
into Aster's system prompt (live context, not just awareness)
- Routing table + workflow (read before write, timestamped append)
Consciousness engine (src/server/consciousness_engine.rs):
- Adaptive rate delay shared with primary loop
- Four-fold mandate (Complete/Verify/Persist/Surface) in hardcoded
default prompt; observation format extracted for sharing
- Schedule added to ASTER_SAFE_TOOLS
Backend + CLI wiring expanded to mount the nervous system, identity,
and credentials at startup. New TOML sections: [schedules], [events],
[federation].
102 tests passing.
- Added src/ui/buddy.rs with CompanionSprite, BuddyState, and draw functions
- Integrated buddy into app.rs for welcome screen and dashboard
- Added agent selection via 'a' key on welcome screen
- Buddy shows agent name, mood, energy, health, and subconscious status
- WIP: Needs full agent alias creation/removal flow