Commit graph

805 commits

Author SHA1 Message Date
Kent Overstreet
df62b7ceaa Persist memory scores, use them for eviction in trim_entries
Scores are saved to memory-scores.json alongside the conversation log
after each scoring run, and loaded on startup — no more re-scoring
on restart.

trim_entries now evicts lowest-scored memories first (instead of
oldest-first) when memories exceed 50% of context. The 50% threshold
stays as a heuristic for memory-vs-conversation balance until we have
a scoring signal for conversation entries too. Unscored memories get
0.0, so they're evicted before scored ones.

save_memory_scores rebuilds from current entries, so evicted memories
are automatically expired from the scores file.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 19:39:08 -04:00
Kent Overstreet
bef1bfbb33 Fix deadlock: lock subconscious before store (store is bottom-most)
subconscious_snapshots() was acquiring store→subconscious while
collect_results() holds subconscious→store — classic ABBA deadlock.

Fix: always acquire subconscious first, store second. Store is the
bottom-most lock in the ordering.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 19:27:36 -04:00
Kent Overstreet
27ca3c058d Shared persistent state across all subconscious agents
Moved persistent_state from per-agent to a single shared BTreeMap on
Subconscious. All agents read/write the same state — surface's walked
keys are visible to observe and reflect, etc.

- Subconscious.state: shared BTreeMap<String, String>
- walked() derives from state["walked"] instead of separate Vec
- subconscious-state.json is now a flat key-value map
- All agent outputs merge into the shared state on completion
- Loaded on startup, saved after any agent completes

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 19:23:08 -04:00
Kent Overstreet
578be807e7 Add expand/collapse all, per-pane key legends
SectionTree:
- 'e': expand all nodes
- 'c': collapse all nodes
- Home/End already wired from previous commit

Key legend shown at bottom border of each focused pane:
- Tree panes: nav, expand/collapse, expand/collapse all, paging
- Agent list: select, tab
- History: scroll, paging

Legend only appears on the focused pane to avoid clutter.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 19:09:04 -04:00
Kent Overstreet
19bb6d02e3 Fix scroll: PgUp/PgDn move cursor in place, add Scrollbar widget
SectionTree.handle_nav() now takes viewport height:
- PgUp/PgDn move both cursor and viewport by one page, keeping the
  cursor at the same screen position
- Home/End jump to first/last item
- scroll_to_selected() uses actual viewport height instead of
  hardcoded 30

Added render_scrollable() in widgets.rs: renders a Paragraph with a
vertical Scrollbar when content exceeds the viewport. Used by the
conscious and subconscious screens.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 19:07:00 -04:00
Kent Overstreet
818cdcc4e5 Three-pane subconscious debug screen with shared widgets
New layout for F3 screen:
- Top-left: agent list using ratatui List widget with ListState
- Middle-left: expandable agent state (persistent across runs)
- Bottom-left: memory store activity by provenance, walked keys
- Right: context tree from fork point, reusing SectionTree

Tab/Shift-Tab cycles focus clockwise between panes; focused pane
gets white border. Each pane handles its own input when focused.

Extracted user/widgets.rs:
- SectionTree (moved from mod.rs): expand/collapse tree for ContextSection
- pane_block_focused(): standard bordered block with focus indicator
- format_age()/format_ts_age(): shared duration formatting

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 19:03:14 -04:00
Kent Overstreet
edfa1c37f5 Subconscious: persistent agent state, store activity queries
- Agent state (outputs) persists across runs in subconscious-state.json,
  loaded on startup, saved after each run completes
- Merge semantics: each run's outputs accumulate into persistent_state
  rather than replacing
- Walked keys restored from surface agent state on load
- Store::recent_by_provenance() queries nodes by agent provenance for
  the store activity view
- Switch outputs from HashMap to BTreeMap for stable display ordering

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 19:03:05 -04:00
Kent Overstreet
cf1c64f936 Split context_state_summary: ContextBudget for compaction, UI-only for display
context_state_summary() was used for both compaction decisions (just
needs token counts) and debug screen display (needs full tree with
labels). Split into:

- Agent::context_budget() -> ContextBudget: cheap token counting by
  category, used by compact(), restore_from_log(), mind event loop
- ContextBudget::format(): replaces sections_budget_string() which
  fragily pattern-matched on section name strings
- context_state_summary(): now UI-only, formatting code stays here

Also extracted entry_sections() as shared helper with include_memories
param — false for context_state_summary (memories have own section),
true for conversation_sections_from() (subconscious screen shows all).

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 19:02:58 -04:00
Kent Overstreet
9e49398689 Agent-aware provenance for memory tools
Add provenance field to Agent, set to "agent:{name}" for forked
subconscious agents. Memory tools (write, link_add, supersede,
journal_new, journal_update) now read provenance from the Agent
context when available, falling back to "manual" for interactive use.

AutoAgent passes the forked agent to dispatch_with_agent so tools
can access it.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 17:46:40 -04:00
Kent Overstreet
74f8952399 Fix: push all responses to forked agent entries
The final assistant response in run_with_backend wasn't being pushed
to the backend — only intermediate step responses were. This meant
the subconscious debug screen only showed the prompt, not the full
conversation.

Now push assistant response immediately after receiving it, before
checking for next steps. Remove the duplicate push in the multi-step
path.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 17:38:23 -04:00
Kent Overstreet
1f873140ae Reduce pub visibility: hippocampus, subconscious internals
hippocampus: cursor navigation, transcript parsing, similarity
functions to pub(crate). counters::open() made private.

subconscious: all format_* prompts helpers to pub(super),
load_defs and keys_to_replay_items made private,
consolidate_full_with_progress made private.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 17:29:12 -04:00
Kent Overstreet
9737641c86 Fix build warnings across workspace
- Remove redundant token fields from StreamEvent::Finished (data
  already delivered via Usage event)
- Remove dead hotkey_adjust_sampling, MAX_HISTORY, now()
- Fix unused variable warnings (delta, log)
- Suppress deserialization-only field warnings (jsonrpc, role)
- Make start_stream/chat_completion_stream_temp pub(crate)
- Remove unnecessary pub(crate) re-export of internal types

Remaining warnings are TODO items: SkipIndex (scoring not wired),
notify (MCP notifications not wired).

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 13:55:30 -04:00
Kent Overstreet
c64295ddb2 Reduce pub visibility in agent::api and user modules
api/: parsing module private, SamplingParams/StreamEvent/StreamResult/
AbortOnDrop/build_response_message/collect_stream to pub(crate).
Internal types (ChatRequest, ChunkChoice, Delta, etc.) to pub(crate).
StreamResult fields to pub(crate). Parsing functions to pub(super).

user/: context, subconscious, unconscious, thalamus modules private
(only chat needs pub(crate) for mind/ access).

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 13:43:25 -04:00
Kent Overstreet
f33b1767da Restrict API types visibility — types module is now private
Only Message, Role, MessageContent, ContentPart, ToolCall,
FunctionCall, Usage, ImageUrl are pub-exported from agent::api.

Internal types (ChatRequest, ChatCompletionChunk, ChunkChoice,
Delta, ReasoningConfig, ToolCallDelta, FunctionCallDelta) are
pub(crate) — invisible outside the crate.

All callers updated to import from agent::api:: instead of
agent::api::types::.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 13:39:20 -04:00
Kent Overstreet
25f4cfabbb Remove dead functions from spectral.rs and identity.rs
spectral.rs: remove print_summary, to_embedding, save_embedding,
nearest_neighbors, unlinked_neighbors, dominant_dimensions,
SpectralResult, shorten_key. Core functions (load_embedding,
nearest_to_seeds_weighted, analyze_positions, etc.) kept.

identity.rs: remove context_file_info (zero callers).

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 13:33:45 -04:00
Kent Overstreet
f4def8d03b Fix: reap stale agent pid files in poc-hook
scan_pid_files was removed as dead code but it was actually needed
by the hook path — the bug was that it was never wired in. Add
reap_agent_pids() directly to poc-hook.rs and call it on every
UserPromptSubmit. Kills timed-out agents (10min) and cleans up
pid files for dead processes.

Also remove dead subconscious/subconscious.rs (420 lines) — was
forked to claude/agent_cycles.rs and never removed.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 13:27:59 -04:00
Kent Overstreet
39965556dd Remove dead code: scan_pid_files, backend_label, entries_mut, post_json
All confirmed unused anywhere in src/ or channels/.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 13:25:18 -04:00
Kent Overstreet
9598e8b86c Remove dead files: parse-claude-conversation.rs, test-conversation.rs
Orphaned binaries — not in Cargo.toml, not declared as modules.
~395 lines of dead code.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 13:22:35 -04:00
Kent Overstreet
7de816022a kill off pub in src/usr/mod.rs
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-07 13:19:08 -04:00
Kent Overstreet
d7c93ffdf1 Upgrade redb 2 → 4, slim down tui-markdown
redb: add ReadableDatabase trait import for begin_read().
tui-markdown: disable highlight-code (drops syntect), fix
test deps leaking into normal dependencies.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 13:06:02 -04:00
Kent Overstreet
61b0a43cf5 Use tui-markdown fork — tracing fully eliminated
Point to koverstreet/tui-markdown which replaces tracing with log.
tracing is now completely gone from the dependency tree.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 13:00:29 -04:00
Kent Overstreet
3625764ca5 organize cargo deps 2026-04-07 12:54:23 -04:00
Kent Overstreet
1cf4f504c0 Kill reqwest — minimal HTTP client on raw hyper + tokio-rustls
New src/agent/api/http.rs: ~240 lines, supports GET/POST, JSON/form
bodies, SSE streaming via chunk(), TLS via rustls. No tracing dep.

Removes reqwest from the main crate and telegram channel crate.
Cargo.lock drops ~900 lines of transitive dependencies.

tracing now only pulled in by tui-markdown.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 12:50:40 -04:00
Kent Overstreet
a421c3c9f3 Upgrade capnp 0.20 → 0.25, capnp-rpc 0.20 → 0.25
RPC trait methods changed from &mut self to self: Rc<Self> and
return types from Promise<(), Error> to impl Future<Output = Result<...>>.

Updated all Server impls across 6 files: DaemonImpl (rpc.rs),
NotifyForwarder (channels.rs), and ChannelServerImpl in all channel
crates (irc, telegram, tmux, socat). Local pry! macro replaces
capnp_rpc::pry to match the new impl Future return type.

Warning-clean workspace build.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 12:29:44 -04:00
Kent Overstreet
382ebc95aa Analysis notes: UI desync pop/push line count mismatch
Documents the root cause of the streaming display bug —
pop removes 1 line per entry but push produces N lines
(markdown, tool results). Includes concrete fix approach
using per-entry line count tracking.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 11:54:30 -04:00
Kent Overstreet
f387041aca Replace unreachable!() with proper error in retry loop
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 03:50:57 -04:00
Kent Overstreet
c2eb9c53cb Remove dead Backend::log() stub
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 03:50:19 -04:00
Kent Overstreet
0df5ec11d1 Fix bounds check panic and batched lock in collect_results
- subconscious.rs: use .get(fork_point..) instead of direct slice
  to avoid panic when fork_point > entries.len()
- dmn.rs: batch all output injections (surface, reflection, thalamus)
  under a single agent lock acquisition instead of three separate ones
- dmn.rs: use Store::cached() instead of Store::load() when rendering
  surfaced memories
- Add scoring persistence analysis notes

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 03:49:49 -04:00
Kent Overstreet
03d2d070f9 Remove old subconscious-surface-observe.agent
Replaced by separate subconscious-surface.agent and
subconscious-observe.agent.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 03:45:13 -04:00
Kent Overstreet
25a3f4114c Resolve {assistant_name} in subconscious agent prompts
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 03:38:01 -04:00
Kent Overstreet
a8c239f3de Cache Store in process — stop reloading on every tool call
Store::cached() returns a process-global Arc<tokio::sync::Mutex<Store>>
that loads once and reloads only when log files change (is_stale()
checks file sizes). All memory and journal tools use cached_store()
instead of Store::load() per invocation.

Fixes CPU saturation from HashMap hashing when multiple subconscious
agents make concurrent tool calls.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 03:35:08 -04:00
Kent Overstreet
39dcf27bd0 Memory scores on entries, not a separate Vec
ConversationEntry::Memory gains score: Option<f64>. The scorer
writes scores directly onto entries when results arrive. Removes
Agent.memory_scores Vec and the memory_scores parameter from
context_state_summary().

Scores are serialized to/from the conversation log as memory_score.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 03:14:24 -04:00
Kent Overstreet
93f5f8b0c7 Shared forked agent — UI reads subconscious entries live
The forked agent is now behind Arc<tokio::sync::Mutex<Agent>>,
stored on SubconsciousAgent and passed to the spawned task. The
subconscious detail screen locks it via try_lock() to read entries
from the fork point — live during runs, persisted after completion.

Removes last_run_entries snapshot. Backend::Forked now holds the
shared Arc, all push operations go through the lock.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 03:09:06 -04:00
Kent Overstreet
77b68ecc50 Remove dead SharedContextState type and imports
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 03:05:21 -04:00
Kent Overstreet
04e260c081 Kill publish_context_state() — screens lock the agent directly
F1 and F2 screens now call agent.context_state_summary() directly
via try_lock/lock instead of reading from a shared RwLock cache.
Removes SharedContextState, publish_context_state(), and
publish_context_state_with_scores().

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 03:03:24 -04:00
Kent Overstreet
48c843234d Fix subconscious screen showing empty names during runs
Keep name and last_run_entries on SubconsciousAgent directly,
not just on the AutoAgent (which gets replaced with a placeholder
during spawned runs). Snapshot reads stable fields.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 02:39:16 -04:00
Kent Overstreet
3788695634 Run subconscious collect/trigger on every event loop iteration
Previously only fired after conscious turn completion. Now runs on
every wake — DMN timer, user input, background events. Subconscious
agents get checked regardless of what woke the loop.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 02:37:11 -04:00
Kent Overstreet
6191f30aec Move Subconscious + SubconsciousAgent into dmn.rs
Subconscious owns agents and shared walked state. trigger() and
collect_results() take the conscious agent Arc as a parameter.
Mind holds Subconscious behind a tokio Mutex and calls into it
from the event loop.

Drops ~170 lines from mind/mod.rs.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 02:31:52 -04:00
Kent Overstreet
b7ff205841 Split surface-observe into separate agents, add thalamus
- subconscious-surface: memory search + surfacing (single step)
- subconscious-observe: graph maintenance + recording (3 steps)
- subconscious-thalamus: watches conversation, nudges when stuck

Thalamus output routed as system-reminder into conscious context.
"ok" responses (nothing to say) are silently dropped.

TODO: thalamus needs inactivity timer + notification triggers,
not just post-turn firing.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 02:25:11 -04:00
Kent Overstreet
f3ba7e7097 Shared subconscious state — walked keys are Mind-level, not per-agent
SubconsciousSharedState holds walked keys shared between all
subconscious agents. Enables splitting surface-observe into separate
surface and observe agents that share the same walked state.

Walked is passed to run_forked() at run time instead of living on
AutoAgent. UI shows walked count in the subconscious screen header.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 02:13:06 -04:00
Kent Overstreet
ef868cb98f Subconscious screen: detail view with post-fork entries
Track fork point in run_forked(), capture entries added during the
run. Subconscious screen shows these in a detail view (Enter to
drill in, Esc to go back) — only the subconscious agent's own
conversation, not the inherited conscious context.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 02:08:48 -04:00
Kent Overstreet
c2a3844d69 In-memory output() tool — no more POC_AGENT_OUTPUT_DIR
AutoAgent intercepts output() tool calls and stores results in an
in-memory HashMap instead of writing to the filesystem. Mind reads
auto.outputs after task completion. Eliminates the env-var-based
output dir which couldn't work with concurrent agents in one process.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 02:04:29 -04:00
Kent Overstreet
85aafd206c Subconscious screen: show AutoAgent state
F3 screen now displays SubconsciousSnapshot from Mind's AutoAgents
instead of the old process-based AgentSnapshot. Shows running status
(phase + turn), last run time, and walked key count.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 01:59:09 -04:00
Kent Overstreet
94ddf7b189 AutoAgent: persistent across runs, run() vs run_forked()
AutoAgent holds config + walked state. Backend is ephemeral per run:
- run(): standalone, global API client (oneshot CLI)
- run_forked(): forks conscious agent, resolves prompt templates
  with current memory_keys and walked state

Mind creates AutoAgents once at startup, takes them out for spawned
tasks, puts them back on completion (preserving walked state).

Removes {{seen_previous}}, {{input:walked}}, {{memory_ratio}} from
subconscious agent prompts. Walked keys are now a Vec on AutoAgent,
resolved via {{walked}} from in-memory state.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 01:57:01 -04:00
Kent Overstreet
ba62e0a767 Resolve seen lists from ContextState, not filesystem
{{seen_current}} and {{seen_previous}} now read Memory entry keys
directly from the conscious agent's ContextState — the single source
of truth for what's been surfaced. No more reading session files
written by the old process-spawning path.

{{input:walked}} still reads from the output dir (inter-run state
written by the surface agent's output() tool).

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 01:43:00 -04:00
Kent Overstreet
e2e0371726 Resolve subconscious prompt placeholders in Mind
Lightweight resolver handles {{seen_current}}, {{seen_previous}}, and
{{input:KEY}} using the session_id and output_dir directly instead of
env vars. Runs in trigger_subconscious before creating AutoAgent.

Removes {{memory_ratio}} from surface-observe prompt — redundant with
existing budget mechanisms.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 01:41:11 -04:00
Kent Overstreet
2678d64b77 Rename forked agent files to subconscious-* prefix
subconscious-surface-observe, subconscious-journal, subconscious-reflect
are Mind's forked agents. The original surface-observe, journal, reflect
remain for the standalone CLI/hook path.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 01:36:28 -04:00
Kent Overstreet
58ff9a4d50 Wire subconscious agents through Mind via AutoAgent
Mind now holds SubconsciousAgent state (surface-observe, journal,
reflect) and triggers them after conscious turns complete. Each
agent forks from the conscious agent's context via AutoAgent,
runs as an async task, and routes output (surfaced memories,
reflections) back into the conscious agent.

Replaces the synchronous AgentCycleState that spawned child
processes and blocked start_turn.

Also adds .agent2 files — simplified prompts for the forked model
that strip {{conversation}} and {{agent-context}} (already in the
forked context).

TODO: resolve remaining placeholders (seen_current, input:walked,
memory_ratio) in the .agent2 prompts.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 01:33:07 -04:00
Kent Overstreet
b37b6d7495 Kill log callback — use ConversationEntry::Log for debug traces
Add Log variant to ConversationEntry that serializes to the
conversation log but is filtered out on read-back and API calls.
AutoAgent writes debug/status info (turns, tokens, tool calls)
through the conversation log instead of a callback parameter.

Removes the log callback from run_one_agent, call_api_with_tools,
and all callers.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 01:23:22 -04:00
Kent Overstreet
7c0d8b79d9 AutoAgent: forked backend operates on Agent's ContextState directly
Instead of snapshotting assemble_api_messages() at construction, the
forked backend pushes step prompts and tool results into the agent's
context.entries and reassembles messages each turn. Standalone backend
(oneshot CLI) keeps the bare message list.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 01:12:54 -04:00