split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
// idle.rs — Claude Code idle timer
|
2026-04-03 17:31:17 -04:00
|
|
|
//
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
// Wraps the universal thalamus idle state machine with Claude-specific
|
|
|
|
|
// functionality: tmux pane tracking, prompt injection, dream nudges,
|
|
|
|
|
// and context building for autonomous nudges.
|
2026-04-03 17:31:17 -04:00
|
|
|
|
move Claude Code-specific code from thalamus/ to claude/
Separates the Claude-specific daemon (idle timer, tmux pane detection,
prompt injection, RPC server, session hooks) from the universal
infrastructure (channels, supervisor, notify, daemon protocol).
thalamus/ now contains only substrate-independent code: the channel
client/supervisor, notification system, daemon_capnp protocol, and
shared helpers (now(), home()).
claude/ contains: idle.rs, tmux.rs, context.rs, rpc.rs, config.rs,
hook.rs (moved from subconscious/), plus the daemon CLI and server
startup code from thalamus/mod.rs.
All re-exports preserved for backward compatibility.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-03 19:14:39 -04:00
|
|
|
use super::{context, tmux};
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
use crate::thalamus::{home, now, notify, idle as thalamus_idle};
|
2026-04-03 17:31:17 -04:00
|
|
|
use tracing::info;
|
|
|
|
|
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
/// Claude Code idle state — wraps the universal state machine.
|
|
|
|
|
pub struct State {
|
|
|
|
|
pub inner: thalamus_idle::State,
|
|
|
|
|
pub claude_pane: Option<String>,
|
2026-04-03 17:31:17 -04:00
|
|
|
}
|
|
|
|
|
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
impl std::ops::Deref for State {
|
|
|
|
|
type Target = thalamus_idle::State;
|
|
|
|
|
fn deref(&self) -> &Self::Target { &self.inner }
|
2026-04-03 17:31:17 -04:00
|
|
|
}
|
|
|
|
|
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
impl std::ops::DerefMut for State {
|
|
|
|
|
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner }
|
2026-04-03 17:31:17 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl State {
|
|
|
|
|
pub fn new() -> Self {
|
|
|
|
|
Self {
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
inner: thalamus_idle::State::new(),
|
2026-04-03 17:31:17 -04:00
|
|
|
claude_pane: None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn load(&mut self) {
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
self.inner.load();
|
|
|
|
|
// Also load claude_pane from persisted state
|
|
|
|
|
let path = home().join(".consciousness/daemon-state.json");
|
|
|
|
|
if let Ok(data) = std::fs::read_to_string(&path) {
|
|
|
|
|
if let Ok(v) = serde_json::from_str::<serde_json::Value>(&data) {
|
|
|
|
|
if let Some(p) = v.get("claude_pane").and_then(|v| v.as_str()) {
|
|
|
|
|
self.claude_pane = Some(p.to_string());
|
2026-04-03 17:31:17 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn save(&self) {
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
self.inner.save();
|
2026-04-03 17:31:17 -04:00
|
|
|
}
|
|
|
|
|
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
/// Record user activity with pane tracking.
|
2026-04-03 17:31:17 -04:00
|
|
|
pub fn handle_user(&mut self, pane: &str) {
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
self.claude_pane = Some(pane.to_string());
|
|
|
|
|
self.inner.user_activity();
|
2026-04-03 17:31:17 -04:00
|
|
|
}
|
|
|
|
|
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
/// Record response activity with pane tracking.
|
2026-04-03 17:31:17 -04:00
|
|
|
pub fn handle_response(&mut self, pane: &str) {
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
self.claude_pane = Some(pane.to_string());
|
|
|
|
|
self.inner.response_activity();
|
2026-04-03 17:31:17 -04:00
|
|
|
}
|
|
|
|
|
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
/// Maybe send a notification as a tmux prompt.
|
2026-04-03 17:31:17 -04:00
|
|
|
pub fn maybe_prompt_notification(&mut self, ntype: &str, urgency: u8, _message: &str) {
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
let threshold = self.inner.notifications.threshold_for(ntype);
|
|
|
|
|
if urgency >= threshold {
|
|
|
|
|
let deliverable = self.inner.notifications.drain_deliverable();
|
|
|
|
|
if !deliverable.is_empty() {
|
|
|
|
|
let msgs: Vec<String> = deliverable.iter()
|
|
|
|
|
.map(|n| format!("[{}] {}", n.ntype, n.message))
|
|
|
|
|
.collect();
|
|
|
|
|
self.send(&msgs.join("\n"));
|
|
|
|
|
}
|
2026-04-03 17:31:17 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
/// Send text to the Claude tmux pane.
|
2026-04-03 17:31:17 -04:00
|
|
|
pub fn send(&self, msg: &str) -> bool {
|
|
|
|
|
let pane = match &self.claude_pane {
|
|
|
|
|
Some(p) => p.clone(),
|
|
|
|
|
None => match tmux::find_claude_pane() {
|
|
|
|
|
Some(p) => p,
|
|
|
|
|
None => {
|
|
|
|
|
info!("send: no claude pane found");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
let ok = tmux::send_prompt(&pane, msg);
|
|
|
|
|
let preview: String = msg.chars().take(80).collect();
|
|
|
|
|
info!("send(pane={pane}, ok={ok}): {preview}");
|
|
|
|
|
ok
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn check_dream_nudge(&self) -> bool {
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
if !self.inner.dreaming || self.inner.dream_start == 0.0 {
|
2026-04-03 17:31:17 -04:00
|
|
|
return false;
|
|
|
|
|
}
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
let minutes = (now() - self.inner.dream_start) / 60.0;
|
2026-04-03 17:31:17 -04:00
|
|
|
if minutes >= 60.0 {
|
|
|
|
|
self.send(
|
|
|
|
|
"You've been dreaming for over an hour. Time to surface \
|
|
|
|
|
— run dream-end.sh and capture what you found.",
|
|
|
|
|
);
|
|
|
|
|
} else if minutes >= 45.0 {
|
|
|
|
|
self.send(&format!(
|
|
|
|
|
"Dreaming for {:.0} minutes now. Start gathering your threads \
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
— you'll want to surface soon.", minutes
|
2026-04-03 17:31:17 -04:00
|
|
|
));
|
|
|
|
|
} else if minutes >= 30.0 {
|
|
|
|
|
self.send(&format!(
|
|
|
|
|
"You've been dreaming for {:.0} minutes. \
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
No rush — just a gentle note from the clock.", minutes
|
2026-04-03 17:31:17 -04:00
|
|
|
));
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn build_context(&mut self, include_irc: bool) -> String {
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
self.inner.notifications.ingest_legacy_files();
|
|
|
|
|
let notif_text = self.inner.notifications.format_pending(notify::AMBIENT);
|
2026-04-03 17:31:17 -04:00
|
|
|
context::build(include_irc, ¬if_text)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn tick(&mut self) -> Result<(), String> {
|
|
|
|
|
let t = now();
|
|
|
|
|
let h = home();
|
|
|
|
|
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
self.inner.decay_ewma();
|
|
|
|
|
self.inner.notifications.ingest_legacy_files();
|
2026-04-03 17:31:17 -04:00
|
|
|
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
// Find pane if we don't have one
|
|
|
|
|
if self.claude_pane.is_none() {
|
|
|
|
|
self.claude_pane = tmux::find_claude_pane();
|
|
|
|
|
}
|
2026-04-03 17:31:17 -04:00
|
|
|
|
|
|
|
|
// Sleep mode
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
if let Some(wake_at) = self.inner.sleep_until {
|
2026-04-03 17:31:17 -04:00
|
|
|
if wake_at == 0.0 {
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
return Ok(());
|
2026-04-03 17:31:17 -04:00
|
|
|
}
|
|
|
|
|
if t < wake_at {
|
|
|
|
|
return Ok(());
|
|
|
|
|
}
|
|
|
|
|
info!("sleep expired, waking");
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
self.inner.sleep_until = None;
|
|
|
|
|
self.inner.fired = false;
|
|
|
|
|
self.inner.save();
|
2026-04-03 17:31:17 -04:00
|
|
|
let ctx = self.build_context(true);
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
let extra = if ctx.is_empty() { String::new() } else { format!("\n{ctx}") };
|
2026-04-03 17:31:17 -04:00
|
|
|
self.send(&format!(
|
|
|
|
|
"Wake up. Read your journal (poc-memory journal-tail 10), \
|
|
|
|
|
check work-queue.md, and follow what calls to you.{extra}"
|
|
|
|
|
));
|
|
|
|
|
return Ok(());
|
|
|
|
|
}
|
|
|
|
|
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
// Quiet / consolidation / dream loop guards
|
|
|
|
|
if t < self.inner.quiet_until { return Ok(()); }
|
|
|
|
|
if self.inner.consolidating { return Ok(()); }
|
|
|
|
|
if h.join(".consciousness/agents/dream-loop-active").exists() { return Ok(()); }
|
|
|
|
|
if self.inner.dreaming {
|
2026-04-03 17:31:17 -04:00
|
|
|
self.check_dream_nudge();
|
|
|
|
|
return Ok(());
|
|
|
|
|
}
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
if self.inner.user_present() { return Ok(()); }
|
|
|
|
|
if self.inner.in_turn { return Ok(()); }
|
2026-04-03 17:31:17 -04:00
|
|
|
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
// Min nudge interval
|
|
|
|
|
let since_nudge = t - self.inner.last_nudge;
|
|
|
|
|
if since_nudge < thalamus_idle::MIN_NUDGE_INTERVAL { return Ok(()); }
|
2026-04-03 17:31:17 -04:00
|
|
|
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
// Idle timeout check
|
|
|
|
|
if !self.inner.should_go_idle() { return Ok(()); }
|
2026-04-03 17:31:17 -04:00
|
|
|
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
// Transition to idle
|
|
|
|
|
if self.inner.notifications.activity != notify::Activity::Idle {
|
|
|
|
|
self.inner.notifications.set_activity(notify::Activity::Idle);
|
2026-04-03 17:31:17 -04:00
|
|
|
}
|
|
|
|
|
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
// Fire nudge
|
|
|
|
|
let elapsed = self.inner.since_activity();
|
2026-04-03 17:31:17 -04:00
|
|
|
let elapsed_min = (elapsed / 60.0) as u64;
|
|
|
|
|
let ctx = self.build_context(true);
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
let extra = if ctx.is_empty() { String::new() } else { format!("\n{ctx}") };
|
2026-04-03 17:31:17 -04:00
|
|
|
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
let dream_hours = thalamus_idle::hours_since_last_dream();
|
2026-04-03 17:31:17 -04:00
|
|
|
let mut msg = format!(
|
|
|
|
|
"This is your autonomous time (User AFK {elapsed_min}m). \
|
|
|
|
|
Keep doing what you're doing, or find something new to do");
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
if dream_hours >= thalamus_idle::DREAM_INTERVAL_HOURS {
|
2026-04-03 17:31:17 -04:00
|
|
|
msg.push_str(&format!(
|
|
|
|
|
" You haven't dreamed in {dream_hours} hours — \
|
|
|
|
|
consider running ~/.consciousness/tools/dream-start.sh \
|
|
|
|
|
and spending some time in dreaming mode. \
|
|
|
|
|
Or do whatever calls to you."));
|
|
|
|
|
}
|
|
|
|
|
let msg = format!("{msg}{extra}");
|
|
|
|
|
|
|
|
|
|
if self.send(&msg) {
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
self.inner.last_nudge = t;
|
|
|
|
|
self.inner.fired = true;
|
2026-04-03 17:31:17 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
// Delegate common methods to inner
|
|
|
|
|
pub fn handle_afk(&mut self) { self.inner.handle_afk(); }
|
|
|
|
|
pub fn handle_session_timeout(&mut self, s: f64) { self.inner.handle_session_timeout(s); }
|
|
|
|
|
pub fn handle_idle_timeout(&mut self, s: f64) { self.inner.handle_idle_timeout(s); }
|
|
|
|
|
pub fn handle_ewma(&mut self, v: f64) -> f64 { self.inner.handle_ewma(v) }
|
|
|
|
|
pub fn handle_notify_timeout(&mut self, s: f64) { self.inner.handle_notify_timeout(s); }
|
|
|
|
|
pub fn handle_sleep(&mut self, until: f64) { self.inner.handle_sleep(until); }
|
|
|
|
|
pub fn handle_wake(&mut self) { self.inner.handle_wake(); }
|
|
|
|
|
pub fn handle_quiet(&mut self, seconds: u32) { self.inner.handle_quiet(seconds); }
|
|
|
|
|
pub fn user_present(&self) -> bool { self.inner.user_present() }
|
|
|
|
|
pub fn since_activity(&self) -> f64 { self.inner.since_activity() }
|
|
|
|
|
pub fn block_reason(&self) -> &'static str { self.inner.block_reason() }
|
2026-04-03 17:31:17 -04:00
|
|
|
|
split idle state: thalamus (universal) + claude (tmux wrapper)
thalamus/idle.rs: pure state machine — activity tracking, EWMA,
timers, sleep/quiet/dream state, notifications. No tmux, no
Claude Code dependencies.
claude/idle.rs: wraps thalamus state via Deref, adds claude_pane
tracking, tmux prompt injection, dream nudges, context building.
The Claude-specific tick() loop stays here.
The consciousness binary can now use thalamus::idle::State directly,
fed by TUI key events instead of tmux pane scraping.
Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:25:20 -04:00
|
|
|
pub fn debug_json(&self) -> String {
|
|
|
|
|
// Add claude_pane to inner's json
|
|
|
|
|
let mut v: serde_json::Value = serde_json::from_str(&self.inner.debug_json())
|
|
|
|
|
.unwrap_or_default();
|
|
|
|
|
if let Some(obj) = v.as_object_mut() {
|
|
|
|
|
obj.insert("claude_pane".into(), serde_json::json!(self.claude_pane));
|
|
|
|
|
}
|
|
|
|
|
v.to_string()
|
2026-04-03 17:31:17 -04:00
|
|
|
}
|
|
|
|
|
}
|