Replace flat-file journal parser with direct store query for
EpisodicSession nodes. Filter journal entries to only those older
than the oldest conversation message (plus one overlap entry to
avoid gaps). Falls back to 20 recent entries when no conversation
exists yet.
Fixes: poc-agent context window showing 0 journal entries.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
SavedAgentState (JSON) persists agent pid/phase/log_path across
hook invocations. The Claude Code hook loads saved state, runs
cycles, saves back. Pids are liveness-checked with kill(pid, 0)
on load. No more scan_pid_files for agent lifecycle tracking.
poc-agent keeps everything in memory (child handles). The hook
path uses serialized state. Same AgentCycleState, different
persistence model.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
AgentCycleState tracks its own children — agent_running() checks
child handles instead of scan_pid_files(). poll_children() reaps
completed processes. No filesystem scanning for agent lifecycle.
The Claude Code hook path will need serialized AgentCycleState
to persist across invocations (next step).
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
spawn_agent returns Child handle + log_path. AgentCycleState stores
the Child, polls with try_wait() on each trigger to detect completion.
No more filesystem scanning to track agent lifecycle.
AgentSnapshot (Clone) sent to TUI for display. AgentInfo holds the
Child handle and stays in the state.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Agent state (pid, phase, log_path) only updates when we spawn an
agent. The scan_pid_files path no longer calls update_agent —
it just logs. This prevents the scan path from clearing log_path
with None on subsequent triggers.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
spawn_agent() now returns SpawnResult { pid, log_path } so the
log path is known at spawn time. No more filesystem scanning.
AgentInfo carries log_path, TUI reads it directly.
F2 → Enter shows the actual agent log (stdout/stderr from the
poc-memory agent process), not the hook orchestration log.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Runner owns AgentCycleState, calls trigger() on each user message
instead of the old run_hook() JSON round-trip. Sends AgentUpdate
messages to TUI after each cycle.
TUI F2 screen reads agent state from messages instead of scanning
the filesystem on every frame. HookSession::from_fields() lets
poc-agent construct sessions without JSON serialization.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Move agent cycle functions from free functions to methods on
AgentCycleState. The struct tracks per-agent pid/phase and the
log file handle. trigger() runs all three cycles and updates
last_output.
Claude Code hook path creates a temporary AgentCycleState per call.
poc-agent will own one persistently and share it with the TUI.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
The hook's Session is not the same as poc-agent's session concept.
Rename to avoid confusion now that poc-agent will create HookSessions
to call into the agent cycle.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
- Remove POC_AGENT early return (was from old claude -p era)
- Split hook into run_agent_cycles() -> AgentCycleOutput (returns
memory keys + reflection) and format_agent_output() (renders for
Claude Code injection). poc-agent can call run_agent_cycles
directly and handle output its own way.
- Fix UTF-8 panic in runner.rs display_buf slicing (floor_char_boundary)
- Add priority debug label to API requests
- Wire up F2 agents screen: live pid status, output files, hook log
tail, arrow key navigation, Enter for log detail view
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Thread request priority through the API call chain to vLLM's
priority scheduler. Lower value = higher priority, with preemption.
Priority is set per-agent in the .agent header:
- interactive (runner): 0 (default, highest)
- surface-observe: 1 (near-realtime, watches conversation)
- all other agents: 10 (batch, default if not specified)
Requires vLLM started with --scheduling-policy priority.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Journal needs to find nodes (memory_search), read them
(memory_render), and track seen set (memory_used) to make
informed links. Still no memory_write — node creation is
observe's job.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Journal entries need to link to relevant memory nodes for graph
connectivity. Added memory_link_add to the journal agent's tool
whitelist alongside the journal tools.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Journal agent now only gets journal_tail, journal_new, journal_update.
Cannot create duplicate memory nodes via memory_write.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Shows the actual tool names each agent will receive after
whitelist filtering, so logs are accurate regardless of whether
tools is empty (all) or specified.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
The tools field in agent headers now filters which native tools
the agent receives. Empty = all tools (default). Non-empty =
whitelist. Journal agent can list only journal_tail/journal_new/
journal_update. Log shows actual tool names instead of "no tools".
Threaded tools list through call_api_with_tools → sync wrapper →
llm caller.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
journal_definitions() separated from definitions() in memory.rs.
All agents get memory + journal tools via memory_and_journal_definitions().
TODO: implement per-agent tool whitelist from header to properly
restrict journal tools to journal agent only.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Agents must use native tool dispatch, not bash, for correct
provenance tracking. Bash access was leftover from old architecture.
All 12 agents cleaned up.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Remove journal tool from memory-instructions-core (only the journal
agent should write journal entries). Add explicit instruction to
journal agent: only use journal_tail/journal_new/journal_update,
not memory_write/render/search.
Prevents the journal agent from creating duplicate memory nodes
about events that surface-observe is already recording.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Skip full prompt logging and truncate tool results in normal mode.
Logs now show: header, tool calls with one-line results, response
text. Set POC_AGENT_VERBOSE=1 for full prompts and results.
Makes agent logs scannable at a glance instead of walls of text.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Agents are routed to Qwen by the runner, not by per-agent model
fields. The "model":"sonnet" was leftover from the Claude API days
and no longer used.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Reframe the observe role as librarian — factual, specific, organized.
Record what happened and why. Reflection belongs in the journal;
observe is for memory.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
memory_search is now spreading activation — the natural way to search
a graph. Give it seed node keys and it finds conceptually related nodes.
The old keyword-based memory_search and memory_search_content are
removed; memory_query can do everything they did.
Simpler tool set, better defaults. Agents don't need to be told "use
spread not search" — search IS spread now.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
The agent was defaulting to keyword searches despite instructions to
use spreading activation first. Reframe instructions positively:
memory_spread is the default mode of operation. Search is available
for finding specific nodes by name.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
The new tool definitions broke surface-observe because they had no
corresponding dispatch handlers — the agent runner saw unknown tools
and ran with no tools at all.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Update surface-observe agent instructions to use memory_spread as the
primary search strategy — cast a wide net from conversation themes before
drilling in with graph walks.
Add explicit instruction to watch for behavioral patterns (avoidance,
rushing, explaining away data) and surface relevant feedback memories
in the moment.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Add `poc-memory graph spread` command that takes multiple seed node keys,
runs spreading activation through the graph, and returns nodes ranked by
total activation — nodes that bridge multiple seed concepts score highest.
Expose spreading_activation() as pub from the query engine. Add
memory_spread and memory_search_content tool definitions for MCP.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Add `poc-memory mcp-schema` command that outputs tool definitions with
CLI routing info (name, description, inputSchema, cli args, stdin_param).
The companion memory-mcp.py (in ~/bin/) is a generic bridge that loads
definitions from mcp-schema at startup and dynamically generates typed
Python functions for FastMCP registration. No tool-specific Python code
— adding a new tool only requires changes in Rust.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Split the streaming pipeline: API backends yield StreamEvents through
a channel, the runner reads them and routes to the appropriate UI pane.
- Add StreamEvent enum (Content, Reasoning, ToolCallDelta, etc.)
- API start_stream() spawns backend as a task, returns event receiver
- Runner loops over events, sends content to conversation pane but
suppresses <tool_call> XML with a buffered tail for partial tags
- OpenAI backend refactored to stream_events() — no more UI coupling
- Anthropic backend gets a wrapper that synthesizes events from the
existing stream() (TODO: native event streaming)
- chat_completion_stream() kept for subconscious agents, reimplemented
on top of the event stream
- Usage derives Clone
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Tool call parsing was only in runner.rs, so subconscious agents
(poc-memory agent run) never recovered leaked tool calls from
models that emit <tool_call> as content text (e.g. Qwen via Crane).
Move the recovery into build_response_message where both code paths
share it. Leaked tool calls are promoted to structured tool_calls
and the content is cleaned, so all consumers see them uniformly.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
All log output was scattered across ~/.consciousness/memory/ (daemon,
task logs, LLM call logs), ~/.consciousness/agent-sessions/ (observe),
and only hook logs were already in the right place.
Move everything to ~/.consciousness/logs/ with agent-specific subdirs:
- daemon.log, daemon/ (task logs)
- {agent_name}/ (knowledge agent logs, e.g. surface-observe/, reflect/)
- llm/{caller}/ (LLM call logs)
- observe.log (poc-agent observe)
- hook-{session_id} (already correct)
- debug.log (already correct)
Also includes the session.rs and hook.rs fixes from the previous
session (sessions dir → ~/.consciousness/sessions/).
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Separate identity files (loaded via source: "file" in context_groups)
from the memory store (data_dir). New identity_dir config field,
defaults to ~/.consciousness/identity/.
Also restrict subconscious agents to memory-only tools — no
filesystem write access. This prevents agents from creating stray
.md files in the memory directory.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
- thalamus/src/idle.rs: dream-start.sh path
- src/agent/dmn.rs: telegram/send.sh path
Part of the directory migration to make this an independent project.
- Telegram data: ~/.consciousness/telegram/
- Rate limiter file: ~/.consciousness/cache/
- parse-claude-conversation stash: ~/.consciousness/sessions/
No more /tmp/ for persistent state, no more ~/.claude/ for our data.
migrate.rs was a one-time markdown→capnp conversion that's long done.
Remove it and update the identity.rs comment to reference the new
~/.consciousness/ path.
The consciousness project should stand independently of Claude Code.
All data, logs, sessions, and agent state now live under
~/.consciousness/ instead of being scattered across ~/.claude/memory/,
/tmp/claude-memory-search/, ~/.config/poc-memory/, and ~/.cache/.
Layout:
~/.consciousness/
*.capnp, *.bin, *.rkyv — store files
sessions/ — per-session state (seen sets, cookies)
logs/ — all logs (hook, agent, debug, dream)
agents/ — agent runtime state (pid files, output)
notifications/ — notification state
cache/ — transient data
Things that stay in ~/.claude/:
- projects/ (Claude Code transcripts)
- hooks/ (Claude Code hook system)
- telegram/ (shared integration)
- irc/ (shared integration)
- settings.json (Claude Code settings)
Debug log moves from /tmp/ to ~/.consciousness/logs/debug.log.
Session state moves from /tmp/claude-memory-search/ to sessions/.
Notifications move from ~/.claude/notifications/ to notifications/.
memory_search.rs is agent orchestration (surface-observe, journal,
reflect cycles), not memory storage. Rename to hook.rs and move to
subconscious/ where it belongs.
Backward compat: pub use subconscious::hook as memory_search in lib.rs
so existing crate::memory_search paths still resolve.
Add journal_cycle() to memory_search.rs, triggered every 20KB of
transcript growth. Runs independently of the surface-observe pipeline
so it doesn't depend on the 5-step pipeline surviving bail checks.
Journal agent doesn't inject output into conversation context (unlike
surface and reflect) — it just writes episodic memory entries.
Journal was step 5 of the surface-observe pipeline but never ran
because the bail check stopped the pipeline before reaching it.
Split into its own agent with:
- {{conversation:50000}} for recent conversation
- {{bash:poc-memory tail -p surface-observe 10}} for observe context
- {{latest_journal}} for previous entry continuity
Add generic {{bash:COMMAND}} placeholder to agent template resolver
so agents can include shell command output in their prompts.
Remove journal phase from surface-observe.agent (now 4 steps).
Provenance now flows as a function parameter through the entire tool
dispatch chain: thought::dispatch → memory::dispatch → store methods.
Removed task_local (TASK_AGENT), thread_local (TASK_PHASE), and env
var (POC_PROVENANCE) from the tool dispatch path. The env var remains
only as a fallback for non-tool paths (CLI commands, digest).
Phase names are passed from knowledge.rs → llm.rs → api.rs, and
api.rs updates the provenance string between steps. No globals needed.
- agent/tools/mod.rs: remove duplicated tool implementations, delegate
to thought::dispatch for shared tools, keep only agent-specific
tools (control, vision, working_stack)
- subconscious/api.rs: replace duplicated memory/tool dispatch with
thought::dispatch, use thought::all_definitions() for tool schemas
- Delete agent/tools/{bash,read,write,edit,grep,glob_tool,journal,memory}.rs
(now live in thought/)
Both poc-agent and subconscious agents now use the same tool
implementations through the thought layer. Agent-specific behavior
(node tracking in runner.rs, control tools) stays in agent/.
New src/thought/ module containing tools and infrastructure shared
between poc-agent and subconscious agents: memory operations, file
tools, bash, context window management.
Currently coexists with agent/tools/ — next step is to wire up both
agent/ and subconscious/ to use thought::dispatch instead of
duplicating the routing logic.
Move dbglog macro to lib.rs so it's available crate-wide regardless
of module compilation order.
Split TASK_PROVENANCE into TASK_AGENT (task_local, set once per agent
run) and TASK_PHASE (thread_local, updated between steps). Provenance
now reports "agent:surface-observe:observe" instead of just
"agent:surface-observe", making it possible to identify which pipeline
phase created a node.
Priority: task_local agent + thread_local phase > POC_PROVENANCE env
var > "manual".
Also includes memory_search catchup throttle and pipelining fixes
from the surface-observe refactor.
- Add "different nodes should be about different things" guard to observe
- Clarify journal prompt: write about conscious self, not agent work
- Add "write about what happened and how it felt" instruction
- Simplify surface prompt focus guidance
- Add memory_rename tool (in-place rename, preserves content and links)
- Update rename.agent prompt to use memory_rename() instead of text output
- Fix {{rename}} placeholder to respect --target keys when provided
- Add format_rename_targets() for targeted rename runs