Remove AgentVisit, TranscriptSegment, and all related visit tracking code.
Provenance is what we've been using to track agent interaction with nodes.
Also removes dead fields from Node (state_tag, created).
-349 lines.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
- Remove CACHED_STORE, cached(), is_stale(), set_store() - redundant
- Convert all Store::cached() callers to use access_local()
- Single Store::load() call remains in access() fallback path
All store access now goes through hippocampus::access() / access_local(),
which handles socket connection or local fallback with caching.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Replace Result<_, String> with anyhow::Result throughout:
- hippocampus/store module (persist, ops, types, view, mod)
- CLI modules (admin, agent, graph, journal, node)
- Run trait in main.rs
Use .context() and .with_context() instead of .map_err(|e| format!(...))
patterns. Add bail!() for early error returns.
Add access_local() helper in hippocampus/mod.rs that returns
Result<Arc<Mutex<Store>>> for direct local store access.
Fix store access patterns to properly lock Arc<Mutex<Store>> before
accessing fields in mind/unconscious.rs, mind/mod.rs, subconscious/learn.rs,
and hippocampus/memory.rs.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
resolve_placeholders() and run_agent() no longer take &Store.
All placeholders now use async memory_render/memory_links/memory_query
directly. The "siblings" placeholder uses Vec<LinkInfo> for ranking
neighbors by link_strength * node_weight.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
- links() in memory.rs: use cached_store() instead of MemoryNode::load()
- identity.rs: use memory_rpc for Store context loading
- defs.rs: delete dead placeholders (topology, nodes/episodes, health, split)
- agents now use {{tool: graph_topology}} etc instead
- prompts.rs: delete unused format_split_plan_node()
Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
- Add memory_history MCP tool for version history
- Convert cmd_history to use memory_rpc
- Add raw parameter to memory_render for editing
- Remove unused: dump-json, list-edges, lookup-bump, lookups
- Fix render_node path in defs.rs/subconscious.rs
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
refresh_health() was doing Store::load() + compute_graph_health()
while holding the Unconscious lock, causing 12 second stalls.
Split into needs_health_refresh() (quick check) and set_health()
(quick store), with the slow I/O happening outside the lock.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Split trigger() into phases so the Unconscious mutex is only held briefly:
- reap_finished(): check handles, restore completed autos
- select_to_spawn(): pick agents, take their autos out
- prepare_spawn(): slow work (Store::load, query, Agent::new) - NO LOCK
- complete_spawn()/abort_spawn(): store results back
Previously held the lock for 28+ seconds during Store::load and query
execution. Now lock hold time should be milliseconds.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
TrackedMutex and TrackedRwLock wrappers that record hold durations
by source location using #[track_caller]. Stats written to
~/.consciousness/lock-stats.json every second, sorted by max hold time.
Re-exported as crate::Mutex so all locks are instrumented. To disable,
swap the re-export back to tokio::sync::Mutex.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Previously, spawning an agent used std::mem::replace with an empty-name
AutoAgent as placeholder. This caused ghost stats entries under "" when
those placeholders accidentally got their stats logged.
Now uses Option<AutoAgent> with .take() - the type honestly represents
that the agent is unavailable while running. Panic recovery in
subconscious now properly recreates the agent from its definition.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
- Read max_concurrent from config (llm_concurrency) instead of hardcoding 2
- Add not-visited: and visited: filters to query parser (were in engine
but missing from parser after unification)
The organize agent was stuck in a spawn/fail loop because its query used
not-visited: which the parser didn't recognize.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
- Remove TurnResult.text (was dead code - Agent::turn handles text internally)
- Simplify run_with_backend to just iterate over steps (Agent::turn loops
for tool calls and handles empty responses internally)
- Change run/run_shared/run_forked_shared to return Result<(), String>
- Remove AgentResult.output field (no callers used it)
- Stub out legacy text-parsing code (audit, compare) that needs redesign
- Update digest.rs to not depend on text return
- Add level parameter to journal_new/journal_update for digest support
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
The system prompt duplicated what's already in core-personality and
other memory nodes. Moving everything to memory means it's all
trainable data rather than hardcoded strings.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Unconscious agent definitions already include {{tool: memory_render
core-personality}} etc. Loading standard context via reload_for_model
duplicated those nodes. Now they get empty system_prompt and
personality — everything comes from the agent definition.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
The system prompt was advertising a fixed set of tools regardless of
what the agent actually has access to. Tools are already listed in
the separate tools section that's built from the agent's actual
tool list.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Stats now survive daemon restarts via ~/.consciousness/agent-stats.json,
loaded into a global Mutex<HashMap> on first access. Each tool type
tracks last count, EWMA (alpha=0.3), and total calls.
UI shows a grid view: tool | last | avg | total, sorted by total desc.
Failures row appears at bottom if any occurred.
Also fixes temperature/priority not being applied to spawned agents.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
- RunStats now includes tool_calls_by_type HashMap
- AutoAgent tracks runs, last_stats, and EWMA for tool calls/failures
- Removed duplicate stats fields from individual agent structs
- Fixed provenance to use bare agent name (no "agent:" prefix)
- Subconscious screen now displays both agent types consistently
- Added Stats pane showing tool call breakdown sorted by count
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
- Remove bogus "agent:" prefix from provenance - just use agent name
- Add history field to UnconsciousSnapshot
- Update snapshots() to fetch store activity via recent_by_provenance
- Fix TUI to display store activity for both agent types
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Both Mind-run agents (unconscious/subconscious) and CLI-run agents
(poc-memory agent run) now use the same logging path. AutoAgent::run()
calls save_agent_log automatically at the end.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Every unconscious agent gets memory_tools() as baseline. The tools
field in the agent def specifies additional tools on top of that —
digest agent now gets journal_tail, journal_new, journal_update.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
The system prompt was advertising all tools to every agent, but
the runtime only dispatched the agent's actual subset. This caused
unconscious agents to call tools that returned "Unknown tool."
Agent::new now takes the tool list explicitly. Each caller passes
its own tools — the prompt and runtime always match. MCP tool
definitions are still appended for agents that use them.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
The old code wrote a JSON object with named section keys, which
serde_json serialized in alphabetical order — putting conversation
before system, making logs misleading. Write a single flat array
in section order instead, matching what the model actually sees.
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>
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>
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>
- 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>
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>
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>
- 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>
- Scan agents directory for all .agent files instead of hardcoded list
- Persist enabled state to ~/.consciousness/agent-enabled.json
- Spacebar on F3 agent list toggles selected agent on/off
- Both subconscious and unconscious agents support toggle
- Disabled agents shown dimmed with "off" indicator
- New agents default to disabled (safe default)
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Graph health stats (alpha, gini, cc, episodic ratio, consolidation
plan) now computed directly by the unconscious module on startup and
every 10 minutes, instead of fetching from the poc-memory daemon.
F4 screen renamed to hippocampus, stripped down to just the health
gauges — daemon task list removed (agents now shown on F3).
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
- AutoAgent.enabled: universal toggle for any auto agent
- Subconscious: should_trigger checks auto.enabled
- Unconscious: simplified from consolidation-plan-driven budgets to
simple loop with cooldown. Static agent list, max 2 concurrent.
- TUI: unconscious agents shown in F3 subconscious screen under
separator, with enabled/running/runs display
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
The log records what goes into context, so it belongs under the context
lock. push() now auto-logs conversation entries, eliminating all the
manual lock-state-for-log, drop, lock-context-for-push dances.
- ContextState: new conversation_log field, Clone impl drops it
(forked contexts don't log)
- push(): auto-logs Section::Conversation entries
- push_node, apply_tool_results, collect_results: all simplified
- collect_results: batch nodes under single context lock
- Assistant response logged under context lock after parse completes
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
- push_node: notify before dropping state lock instead of relocking
- Mind::run: single lock for timeout + turn_active + has_input;
single lock for turn_handle + complete_turn
- Agent triggers (subconscious/unconscious) spawned as async tasks
so they don't block the select loop
- has_pending_input() peek for DMN sleep guard — don't sleep when
there's user input waiting
- unconscious: merge collect_results into trigger, single store load
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Unconscious agents (organize, linker, distill, etc.) run independently
of the conversation context. They create fresh Agent instances, select
target nodes via their .agent file queries, and are scheduled by the
consolidation plan which analyzes graph health metrics.
Key differences from subconscious agents:
- No fork — standalone agents with fresh context
- Self-selecting — queries in .agent files pick target nodes
- Budget-driven — consolidation plan allocates runs per type
- Max 2 concurrent, 60s min interval between same-type runs
Wired into Mind event loop alongside subconscious trigger/collect.
TUI display not yet implemented.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
The file contains both the DMN state machine and the subconscious agent
orchestration. Renaming to match the conceptual grouping — next step is
adding mind/unconscious.rs for the standalone graph maintenance agents
(organize, linker, etc.) that don't need conversation context.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Observe was creating byte-identical nodes under slightly different names
(e.g. april-8-evening-folded-presence, -presence-2, -folded-state)
because it had no visibility into its own prior writes across runs.
Query recent writes by provenance in trigger(), pass through
run_forked_shared/resolve_prompt as {{recently_written}}, and include
the list in the observe phase prompts so the agent knows what it
already recorded.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
collect_results now checks existing Memory nodes in the conversation
before surfacing. Prevents the same memory from being pushed every
time the surface agent runs.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
The output tool closure writes directly to Subconscious.state,
so auto.outputs is always empty. collect_results now reads surface,
reflection, and thalamus keys from self.state.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>