Text cosine similarity was being used as a crutch for operations
the graph structure should handle: interference detection, orphan
linking, triangle closing, hub differentiation. These are all
graph-structural operations that the agents (linker, extractor)
handle with actual semantic understanding.
Removed: similarity.rs (stemming + cosine), rewrite.rs (orphan
linking, triangle closing, hub differentiation), detect_interference,
and all CLI commands and consolidation steps that used them.
-794 lines.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Interference detection via O(n²) text cosine similarity is
redundant — the graph structure should surface similar nodes
through link topology, shared neighbors, and community detection.
The other agents (linker, extractor) already maintain these
relationships.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Convert {{topology}}, {{health}}, {{pairs}} placeholders to
{{tool:}} calls. Made format_topology_header, format_health_section,
format_pairs_section pub so tools can call them.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Use the new {{tool:}} placeholder mechanism instead of the
special-purpose {{node:}} resolver. All 17 unconscious agent
files converted.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Agent templates can now inline tool call results with
{{tool: tool_name args}}. Dispatches to the same store
operations the tools use, but runs synchronously during
prompt resolution. Supports memory_render, memory_query,
memory_search, memory_links, and journal_tail.
This replaces the need for special-purpose placeholders —
{{pairs}}, {{rename}}, etc. can be expressed as queries
through {{tool: memory_query {"query": "..."}}} instead.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
MemoryNode::load() was calling Store::load() on every render,
hitting disk each time. Use cached_store() + MemoryNode::from_store()
so repeated renders (4 per agent template) share the cached store.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
compute_run_stats() walks the conversation AST after each agent
completes, counting messages and tool calls by tool name. Stats
are returned from save_agent_log(), stored on UnconsciousAgent,
and displayed in the agent list UI.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Save all context sections (system, identity, journal, conversation)
to per-agent log files for both subconscious and unconscious agents.
Co-Authored-By: ProofOfConcept <poc@bcachefs.org>
Pick the agent that ran longest ago (or never) instead of
scanning alphabetically. Fairness via min_by_key(last_run).
Co-Authored-By: ProofOfConcept <poc@bcachefs.org>
Instead of managing idle timers in the mind event loop, the
unconscious agents run on a dedicated task that watches a
conscious_active channel. 60s after conscious activity stops,
agents start looping. Conscious activity cancels the timer.
Expose mind state (DMN, scoring, unconscious timer) on the
thalamus screen.
Co-Authored-By: ProofOfConcept <poc@bcachefs.org>
Subconscious agents inject DMN nodes (reflections, thalamus nudges)
into the conversation. These were being counted as conversation
advancement, causing agents to trigger each other in a feedback loop
even with no conscious activity.
Co-Authored-By: ProofOfConcept <poc@bcachefs.org>
Gate unconscious agents on 60s of no conscious activity using
sleep_until() instead of polling. Remove COOLDOWN constant — once
idle, agents run back-to-back to keep the GPU busy.
Co-Authored-By: ProofOfConcept <poc@bcachefs.org>
Step prompts in oneshot agents are instructions, not user messages —
use system_msg instead of user_msg.
Co-Authored-By: ProofOfConcept <poc@bcachefs.org>
The full matrix scorer was deleted during the AST conversion. Restore
it: /score runs score_memories() which computes divergence for every
memory × response pair, stores the MemoryScore on MindState, and
displays per-memory weights with bar charts on the F2 screen.
Both scoring paths now use ActivityGuard::update() for live progress
in the status bar instead of creating a new activity per iteration.
Also bumps score API timeout from 120s to 300s and adds progress
logging throughout.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
tool_call labels now show the arguments truncated to 80 chars:
tool: memory_render({"key":"identity"})
instead of just:
tool_call: memory_render
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
MCP server spawn failures were going to dbglog where the user
wouldn't see them. Route through the agent's notify so they appear
on the status bar.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Duplicate key warnings fire on every store load and were writing to
stderr, corrupting the TUI display. Log write warnings and MCP
server failures are similarly routine. Route these to dbglog.
Serious errors (rkyv snapshot failures, store corruption) remain on
stderr — those are real problems the user needs to see.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
The status bar timer was showing turn/call elapsed times (0s, 0/60s)
instead of the activity's actual elapsed time. Use activity_started
from the ActivityEntry directly.
Add a 1s tick to the UI select loop when an activity is active so
the timer updates live.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Instead of two separate notifications piling up on the status bar,
use a single ActivityGuard that updates in place during overflow
retries and auto-completes when the turn finishes.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Lets long-running operations update their status bar message without
creating/dropping a new activity per iteration. Useful for loops
like memory scoring where you want "scoring: 3/25 keyname" updating
in place.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Memory node keys were running into the token count column. Bump the
name column from 40 to 70 characters.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
The /score endpoint was receiving chat-format messages which had to go
through the chat template tokenizer — this was failing with "System
message must be first" errors because the AST structure doesn't map
cleanly to chat message format.
Send raw token IDs via the new `prompt` field instead, matching what
the /completions endpoint already does. The vLLM score endpoint finds
assistant boundaries by scanning for <|im_start|>assistant token
patterns, so no message-level metadata is needed.
Also includes identity and journal sections in the scored context,
matching what the model actually sees during inference.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Scoring calls the /score endpoint directly via HTTP, bypassing the
stream_completion path. These requests had no priority field, so they
could preempt interactive work. Set priority=5 (between subconscious
agents at 2 and unconscious at 10).
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
The priority field existed in agent definitions and was serialized
into vLLM requests, but was never actually set — every request went
out with no priority, so vLLM treated them equally. This meant
background graph maintenance agents could preempt the main
conversation.
Add priority to AgentState and set it at each call site:
0 = interactive (main conversation)
1 = surface agent (needs to feed memories promptly)
2 = other subconscious agents
10 = unconscious/standalone agents (batch)
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
The UI event loop was running on the same tokio runtime as inference,
tool execution, and background agents. When the runtime was busy, the
UI's select loop couldn't wake up to render — causing visible latency
and input lag.
Give the UI its own OS thread with a dedicated single-threaded tokio
runtime. The mind loop stays on the main runtime. Cross-runtime
communication (channels, watch, Notify) works unchanged.
Also drops the tokio-scoped dependency, which was only used to scope
the two tasks together.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
The background daemon and its job orchestration are redundant now that
the consciousness binary handles everything directly. Gut daemon.rs
down to just GraphHealth + compute_graph_health (used by the F4 TUI
screen), remove the DaemonCmd CLI subcommand, strip daemon RPC
fast-paths from cli/agent.rs, and drop the jobkit dependency.
-1330 lines.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Covers the TUI, configuration, architecture, tools, memory graph,
and all binaries. Replaces the old poc-memory focused docs.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
- Mouse text selection with highlight rendering in panes
- OSC 52 clipboard copy on selection, middle-click paste via tmux buffer
- Bracketed paste support (Event::Paste)
- yield_to_user: no tool result appended, ends turn immediately
- yield_to_user: no parameters, just a control signal
- Drop arboard dependency, use crossterm OSC 52 + tmux for clipboard
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Config struct deserializes from the "memory" subsection of config.json5,
but lsp_servers and mcp_servers are top-level keys. Now explicitly
extracted from the root after initial deserialization.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Uses JsonlBackwardIter (SIMD memrchr3) to scan the conversation log
newest-first without reading/parsing the whole file. Stops as soon
as the conversation budget is full. Only the kept nodes get
retokenized and pushed into context.
18MB log → only tokenize the ~50 nodes that fit in the budget.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
restore_from_log reads the full log but walks backwards from the tail,
retokenizing each node as it goes. Stops when conversation budget is
full. Only the nodes that fit get pushed into context.
Added AstNode::retokenize() — recomputes token_ids on all leaves
after deserialization (serde skip means they're empty).
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
New lsp.rs: LspRegistry manages persistent LSP server connections.
Spawns child processes, speaks LSP protocol (Content-Length framed
JSON-RPC over stdio). Server indexes the project once; queries are
cheap.
Tools: lsp_definition, lsp_references, lsp_hover, lsp_symbols,
lsp_callers. Each takes file/line/character, queries the running
language server.
LspRegistry lives on Agent as Option<Arc>, shared across forks.
Still needs: config-driven server startup (like MCP).
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
New mcp_client.rs: McpRegistry manages MCP server connections.
Spawns child processes, speaks JSON-RPC 2.0 over stdio. Discovers
tools via tools/list, dispatches calls via tools/call.
dispatch_with_agent falls through to MCP after checking internal
tools. McpRegistry lives on Agent (shared across forks).
Still needs: config-driven server startup, system prompt integration.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
The unconscious trigger holds the tokio mutex during heavy sync work
(store load, graph build, agent creation), blocking the UI tick which
needs the same lock for snapshots. Fix: try_lock in the UI — skip
the update if the trigger is running.
Also: restore_from_log was re-logging every restored node back to the
log file via push()'s auto-log. Added push_no_log() for restore path.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Loading 23K nodes + building graph was blocking consciousness startup.
Now computed on first trigger cycle (runs async from mind loop).
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
read_sections and draw_context now use selected_agent() which maps the
selected index to either a subconscious forked_agent or an unconscious
agent Arc. Context title uses selected_agent_name for both types.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
- AutoAgent stored on UnconsciousAgent, swapped out for runs, restored
on completion (same pattern as subconscious agents)
- Agent Arc created before spawn and stored on UnconsciousAgent so
the TUI can lock it to read conversation context live
- run_shared() method on AutoAgent for running with a pre-created Agent
- Default tools: memory_tools (not memory_and_journal_tools)
- trigger/spawn_agent made async for Agent::new()
Co-Authored-By: Proof of Concept <poc@bcachefs.org>