Commit graph

59 commits

Author SHA1 Message Date
Kent Overstreet
79e384f005 split out src/mind 2026-04-04 02:46:32 -04:00
Kent Overstreet
9bebbcb635 Move API code from user/ to agent/
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-04 00:34:48 -04:00
ProofOfConcept
021eafe6da delete ProcessTracker — replaced by ActiveToolCall + KillOnDrop
All process management now goes through active_tools:
- TUI reads metadata (name, elapsed time)
- Ctrl+K aborts handles (KillOnDrop sends SIGTERM)
- Running count from active_tools.len()

No more separate PID tracking, register/unregister, or
ProcessInfo. One data structure for everything.

Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 23:58:38 -04:00
ProofOfConcept
17a018ff12 fixup: consolidate tool types, fix build after reorganization
Move FunctionCall, FunctionDef, FunctionCallDelta from user/types
to agent/tools. Re-export from user/types for backward compat.
Merge duplicate dispatch functions in tools/mod.rs into dispatch
(agent-specific) + dispatch_shared (with provenance). Fix orphaned
derive, missing imports, runner→agent module path.

Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 23:21:16 -04:00
ProofOfConcept
474b66c834 shared active tools: Agent writes, TUI reads directly
Move active tool tracking from TUI message-passing to shared
Arc<RwLock> state. Agent pushes on dispatch, removes on
apply_tool_result. TUI reads during render. Background tasks
show as active until drained at next turn start.

Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 22:57:46 -04:00
Kent Overstreet
2f0c7ce5c2 src/thought -> src/agent
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 22:24:56 -04:00
ProofOfConcept
61deb7d488 delete dead code: channel-test, mcp-schema, cmd_mcp_schema
channel-test was a debug tool, mcp-schema was superseded by
consciousness-mcp, cmd_mcp_schema in cli/misc.rs was the old
poc-memory subcommand.

Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 20:52:40 -04:00
ProofOfConcept
b24e8e87a2 subscribe to channel daemon notifications
consciousness binary subscribes to all channel daemons on startup.
Notifications forwarded via NotifyForwarder callback through mpsc.
Pending notifications stored for thalamus agent consumption.
Channel list refreshed automatically when notifications arrive.

Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 20:14:22 -04:00
ProofOfConcept
8e66f0a66c wire channel list RPC into consciousness F5 screen
fetch_all_channels() connects to each daemon socket and calls
list() via capnp RPC. Runs on a dedicated thread (capnp uses Rc).
Results sent back via mpsc channel, TUI reads cached state.

Fetched at startup and when switching to F5 thalamus screen.
Also calls ensure_running() to restart dead daemons.

Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:53:23 -04:00
ProofOfConcept
e7be2a3ba0 wire thalamus idle state into consciousness binary
The consciousness binary now has its own idle state machine,
fed directly by TUI events:
- Key press → user_activity()
- Turn complete → response_activity()
- Render tick → decay_ewma(), snapshot to TUI

F5 thalamus screen shows presence/activity from the in-process
state instead of shelling out to poc-daemon status. No tmux
pane scraping, no socket RPC — the binary IS the presence.

Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:30:26 -04:00
Kent Overstreet
dd7f1e3f86 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:26:24 -04:00
ProofOfConcept
36afa90cdb F5 thalamus: cached channel status, refresh on entry
Channel status is cached on App and refreshed when switching
to F5, not polled every render frame. Shows connected/disconnected
status and unread count per channel daemon.

Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 19:05:48 -04:00
ProofOfConcept
a7f19cdc7e tui: event-driven rendering with dirty bit
Only redraw when something actually changed. The 50ms render
interval still ticks (for process count updates) but no longer
triggers draws. Dirty is set by key events, mouse events,
resize, UI messages, turn completions, and DMN ticks.

Saves bandwidth over SSH and reduces CPU usage when idle.

Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 18:51:22 -04:00
ProofOfConcept
ad5f69abb8 channel architecture: wire protocol, daemons, supervisor
Design and implement the channel system for external communications:

- schema/channel.capnp: wire protocol for channel daemons
  (recv with all_new/min_count, send, subscribe, list)
- channels/irc/: standalone IRC daemon crate (consciousness-channel-irc)
- channels/telegram/: standalone Telegram daemon crate
  (consciousness-channel-telegram)
- src/thalamus/channels.rs: client connecting to daemon sockets
- src/thalamus/supervisor.rs: daemon lifecycle with file locking
  for multi-instance safety

Channel daemons listen on ~/.consciousness/channels/*.sock,
configs in *.json5, supervisor discovers and starts them.
IRC/Telegram modules removed from thalamus core — they're
now independent daemons that survive consciousness restarts.

Also: delete standalone tui.rs (moved to consciousness F4/F5),
fix build warnings, add F5 thalamus screen with channel status.

Co-Developed-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-03 18:46:41 -04:00
Kent Overstreet
604f442215 Move thalamus subcrate into main crate
Move thalamus/ (poc-daemon) source files into src/thalamus/ as a
module of the main crate. The daemon entry point becomes a library
function thalamus::run() with a thin poc-daemon binary for backward
compatibility.

- Copy thalamus source into src/thalamus/, fix crate:: -> super::
- Copy daemon.capnp into schema/, add to build.rs
- Re-export daemon_capnp at crate root (capnp codegen requires it)
- Add thalamus dependencies (capnp-rpc, tokio-util, toml, rustls, etc.)
- Keep thalamus/ subcrate for comparison

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-03 17:31:17 -04:00
Kent Overstreet
14dd8d22af Rename agent/ to user/ and poc-agent binary to consciousness
Mechanical rename: src/agent/ -> src/user/, all crate::agent:: ->
crate::user:: references updated. Binary poc-agent renamed to
consciousness with CLI name and user-facing strings updated.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-03 17:25:59 -04:00
Kent Overstreet
beb49ec477 scoring: add timeouts, progress feedback, error resilience
- 120s timeout on individual /v1/score HTTP calls
- Activity bar shows "scoring 3/24: memory-key..."
- Info messages at start and completion
- Per-memory timing and importance in debug pane
- Failed individual memories log error but don't abort (zero row)
- Removed duplicate completion message (info from score_memories)

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-03 01:23:21 -04:00
Kent Overstreet
78abf90461 fix scoring: HTTP error checking, context refresh, chunk logging
Check HTTP status from logprobs API (was silently ignoring 500s).
Call publish_context_state() after storing scores so F10 screen
updates. Add chunk size logging for OOM debugging.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-02 22:47:44 -04:00
Kent Overstreet
c01d4a5b08 wire up /score command and debug screen for memory importance
/score snapshots the context and client, releases the agent lock,
runs scoring in background. Only one score task at a time
(scoring_in_flight flag). Results stored on Agent and shown on
the F10 context debug screen with importance scores per memory.

ApiClient derives Clone. ContextState derives Clone.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-02 22:21:31 -04:00
Kent Overstreet
0148dbaa06 add tokio-console for async task debugging
console-subscriber on unix socket at
~/.consciousness/agent-sessions/console.sock.
Connect with: tokio-console ~/.consciousness/agent-sessions/console.sock

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-02 18:21:01 -04:00
Kent Overstreet
a360607fad fix stale process count after interrupt
Don't abort the tokio task when killing processes — let SIGTERM'd
processes exit normally so run_bash sees the exit and unregisters
them from the tracker. Only abort the turn when no processes are
running (e.g. interrupting a streaming response).

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-02 17:35:17 -04:00
Kent Overstreet
ef7dd59b7e skip Memory entries in conversation replay on restore
Memory entries (surfaced nodes, memory_render results) are part of
the context window but not the conversation display. Skip them
during replay_session_to_ui to avoid showing system-reminder
content as user messages.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-02 16:28:57 -04:00
Kent Overstreet
af3929cc65 simplify compaction: Agent owns config, compact() reloads everything
Agent stores AppConfig and prompt_file, so compact() reloads
identity internally — callers no longer pass system_prompt and
personality. restore_from_log() loads entries and calls compact().

Remove soft compaction threshold and pre-compaction nudge (journal
agent handles this). Remove /compact and /context commands (F10
debug screen replaces both). Inline do_compact, emergency_compact,
trim_and_reload into compact(). Rename model_context_window to
context_window, drop unused model parameter.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-02 16:08:41 -04:00
Kent Overstreet
d419587c1b WIP: trim_entries dedup, context_window rename, compact simplification
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-02 15:58:03 -04:00
Kent Overstreet
214806cb90 move context functions from agent/context.rs to thought/context.rs
trim_conversation moved to thought/context.rs where model_context_window,
msg_token_count, is_context_overflow, is_stream_error already lived.
Delete the duplicate agent/context.rs (94 lines).

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-02 15:28:00 -04:00
Kent Overstreet
a21cf31ad2 unify conversation persistence to append-only jsonl
Log ConversationEntry (with Memory/Message typing) instead of
raw Message. restore_from_log reads typed entries directly,
preserving Memory vs Message distinction across restarts.

Remove current.json snapshot and save_session — the append-only
log is the single source of truth. Remove dead read_all and
message_count methods. Add push_entry for logging typed entries.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-02 14:31:19 -04:00
Kent Overstreet
b9e3568385 ConversationEntry enum: typed memory vs conversation messages
Replace untyped message list with ConversationEntry enum:
- Message(Message) — regular conversation turn
- Memory { key, message } — memory content with preserved message
  for KV cache round-tripping

Budget counts memory vs conversation by matching on enum variant.
Debug screen labels memory entries with [memory: key]. No heuristic
tool-name scanning.

Custom serde: Memory serializes with a memory_key field alongside
the message fields, deserializes by checking for the field.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-02 03:26:00 -04:00
Kent Overstreet
eb4dae04cb Compute ContextBudget on demand from typed sources
Remove cached context_budget field and measure_budget(). Budget
is computed on demand via budget() which calls
ContextState::budget(). Each bucket counted from its typed source.
Memory split from conversation by identifying memory tool calls.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-02 03:07:45 -04:00
Kent Overstreet
55a037f4c7 Rename Session -> HookSession
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>
2026-04-02 00:42:25 -04:00
ProofOfConcept
f0af319e0d move telegram and remaining tmp paths to ~/.consciousness/
- 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.
2026-03-27 21:26:28 -04:00
ProofOfConcept
bf5b495632 move daemon, IRC, and remaining state to ~/.consciousness/
- Daemon socket/pid/log: ~/.consciousness/daemon.{sock,pid}, logs/daemon.log
- Daemon config: ~/.consciousness/daemon.toml
- Daemon state: ~/.consciousness/daemon-state.json
- IRC logs: ~/.consciousness/irc/logs/
- No more .claude/ references except Claude Code integration points
  (projects, settings, hooks, telegram, CLAUDE.md)
2026-03-27 21:11:02 -04:00
ProofOfConcept
6a1660cc9d move data home from ~/.claude/memory to ~/.consciousness
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/.
2026-03-27 21:07:17 -04:00
ProofOfConcept
84c78f7ae1 session: --session flag, journal agent cycle, conversation bytes config
- memory-search: add --session flag for multi-session support
- config: add surface_conversation_bytes option
- journal_agent_cycle: trigger journal agent every 10KB of conversation
- Session::from_id() constructor

Co-Authored-By: ProofOfConcept <poc@bcachefs.org>
2026-03-26 14:22:29 -04:00
ProofOfConcept
baf208281d tui: overlay screens via F-keys (F1=context, F2=agents)
Replaced debug_visible bool with an Overlay enum. F1 shows the
context/debug screen (Ctrl+D still works as alias), F2 shows the
agents screen (placeholder for now — will show surface, observe,
reflect, journal status). Esc closes any overlay.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-03-25 03:12:28 -04:00
ProofOfConcept
228815d807 config: unify memory and agent config into single module
Both hippocampus/config.rs and agent/config.rs read from the same
config file (~/.config/poc-agent/config.json5). Having two separate
implementations was a footgun — load_context_groups() was duplicated
three times across the codebase.

Merged into src/config.rs:
- Config (memory settings, global get()/reload())
- AppConfig (agent backend/model settings, figment-based loading)
- SessionConfig (resolved agent session, renamed from agent's Config)
- Single ContextGroup/ContextSource definition used everywhere

Eliminated: duplicate load_context_groups(), duplicate ContextGroup
definition in identity.rs, duplicate config file path constants.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-03-25 01:23:12 -04:00
ProofOfConcept
998b71e52c flatten: move poc-memory contents to workspace root
No more subcrate nesting — src/, agents/, schema/, defaults/, build.rs
all live at the workspace root. poc-daemon remains as the only workspace
member. Crate name (poc-memory) and all imports unchanged.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-03-25 00:54:12 -04:00
Kent Overstreet
fc48ac7c7f split into workspace: poc-memory and poc-daemon subcrates
poc-daemon (notification routing, idle timer, IRC, Telegram) was already
fully self-contained with no imports from the poc-memory library. Now it's
a proper separate crate with its own Cargo.toml and capnp schema.

poc-memory retains the store, graph, search, neuro, knowledge, and the
jobkit-based memory maintenance daemon (daemon.rs).

Co-Authored-By: ProofOfConcept <poc@bcachefs.org>
2026-03-08 20:43:59 -04:00
Kent Overstreet
e2f3a5a364 daemon: add test-send subcommand, flatten newlines in send_prompt
test-send calls send_prompt() directly for debugging tmux delivery.
Flatten newlines to spaces in literal mode to prevent premature
input submission.

Co-Authored-By: ProofOfConcept <poc@bcachefs.org>
2026-03-08 19:41:32 -04:00
ProofOfConcept
77fc533631 tmux: remove Escape/C-c/C-u clear sequence from send_prompt
The clear sequence (Escape q C-c C-u) was disrupting Claude Code's
input state, causing nudge messages to arrive as blank prompts.
Simplified to just literal text + Enter.
2026-03-08 18:49:30 -04:00
ProofOfConcept
95baba54c0 tmux: use send-keys -l for literal text input
Without -l, tmux send-keys treats spaces as key-name separators,
so multi-word messages like "This is your time" get split into
individual unrecognized key names instead of being typed as text.
This caused idle nudges to arrive as blank messages.
2026-03-08 18:39:47 -04:00
ProofOfConcept
55fdc3dad7 idle: afk command, configurable session timeout, fix block_reason
Add `poc-daemon afk` to immediately mark Kent as away, allowing the
idle timer to fire without waiting for the session active timeout.

Add `poc-daemon session-timeout <secs>` to configure how long after
the last message Kent counts as "present" (default 15min, persisted).

Fix block_reason() to report "kent present" and "in turn" states
that were checked in the tick but not in the diagnostic output.
2026-03-08 18:31:51 -04:00
ProofOfConcept
22a9fdabdb idle: EWMA activity tracking
Track activity level as an EWMA (exponentially weighted moving average)
driven by turn duration. Long turns (engaged work) produce large boosts;
short turns (bored responses) barely register.

Asymmetric time constants: 60s boost half-life for fast wake-up, 5-minute
decay half-life for gradual wind-down. Self-limiting boost formula
converges toward 0.75 target — can't overshoot.

- Add activity_ewma, turn_start, last_nudge to persisted state
- Boost on handle_response proportional to turn duration
- Decay on every tick and state transition
- Fix kent_present: self-nudge responses (fired=true) don't update
  last_user_msg, so kent_present stays false during autonomous mode
- Nudge only when Kent is away, minimum 15s between nudges
- CLI: `poc-daemon ewma [VALUE]` to query or set
- Status output shows activity percentage
2026-03-07 02:05:27 -05:00
ProofOfConcept
7ed6d8622c irc: client-side ping timeout and connection reliability
- Send PING after 120s of silence, disconnect after 30s with no PONG
- Reset backoff to base when a working connection drops (was registered)
- Validate channel membership before sending to channels

The ping timeout catches silent disconnects where the TCP connection
stays open but OFTC has dropped us. Previously we'd sit "connected"
indefinitely receiving nothing.
2026-03-06 15:21:39 -05:00
ProofOfConcept
9e52fd5b95 fix idle timer: daemon agent calls were resetting user activity
The daemon's claude -p subprocesses inherit hooks config, so every
agent LLM call triggered UserPromptSubmit → signal_user(), making the
idle timer think Kent was always active. The daemon was petting its
own tail.

Fix: set POC_AGENT=1 env var on all daemon claude subprocesses, and
return early from poc-hook when it's set.
2026-03-06 00:16:03 -05:00
Kent Overstreet
aa24c40a1c Extract lib.rs, inline search in memory-search hook
Create lib.rs so all binaries can share library code directly instead
of shelling out to poc-memory. memory-search now calls search::search()
and store::Store::load() in-process instead of Command::new("poc-memory").

The load-context call still shells out (needs get_group_content moved
from main.rs to a library module).

Also: add search::format_results(), deduplicate extract_query_terms.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 22:23:03 -05:00
ProofOfConcept
81d3ce93fe fix idle timer restart and hook event detection
Two fixes:

1. Reset activity timestamps to now() on daemon restart instead of
   loading stale values and suppressing with fired=true. Timers
   count cleanly from restart.

2. Fix poc-hook to read hook_event_name (not type) from Claude Code's
   JSON input. The hook was being called but never matched any event.
   Also switch daemon_cmd from spawn() to status() since the command
   takes 2ms — no reason to fire-and-forget.

Co-Authored-By: ProofOfConcept <poc@bcachefs.org>
2026-03-05 21:43:04 -05:00
ProofOfConcept
d0080698f3 cli: switch to clap, add notify-timeout, improve status display
Replace manual arg parsing with clap derive for the full command set.
Single source of truth for command names, args, and help text.

Add notify_timeout (default 2min) — controls how long after last
response before notifications inject via tmux instead of waiting
for the hook. Separate from idle_timeout (5min) which controls
autonomous prompts.

Improve `poc-daemon status` to show both timers with elapsed/configured
and block reason, replacing the terse one-liner.

Add new Status fields over capnp: idleTimeout, notifyTimeout,
sinceActivity, sinceUser, blockReason.

ExecStart in poc-daemon.service now uses `daemon` subcommand.

Co-Authored-By: ProofOfConcept <poc@bcachefs.org>
2026-03-05 21:32:27 -05:00
ProofOfConcept
eab656aa64 idle: persist timeout, suppress restart fire, add debug/save/idle-timeout commands
Several idle timer fixes and new inspection capabilities:

- Persist idle_timeout across daemon restarts (was reverting to 5min default)
- Set fired=true on load to suppress immediate fire from stale timestamps
- Add human-readable ISO timestamps to daemon-state.json for debugging
- Use to_string_pretty for readable state file
- Make save() public for RPC access
- Remove kb_idle_minutes() — go purely off message timestamps
- Add maybe_prompt_notification() with idle gate so notifications only
  inject via tmux when truly idle, not during active sessions
- Add debug_json() for full state inspection with computed values
  (would_fire, block_reason, all timers)

New RPC commands (schema @16-18):
  poc-daemon idle-timeout <secs>  — set idle timeout
  poc-daemon save                 — force state persistence
  poc-daemon debug                — dump full internal state as JSON

Also: save state on clean shutdown, route module notifications through
maybe_prompt_notification before submitting to queue.

Co-Authored-By: ProofOfConcept <poc@bcachefs.org>
2026-03-05 21:17:43 -05:00
ProofOfConcept
5eb8a4eb6a irc: handle non-UTF-8 input, CTCP VERSION, log outgoing messages
Three fixes:

1. Use read_until + from_utf8_lossy instead of AsyncBufRead::lines(),
   which returns Err on invalid UTF-8. IRC isn't guaranteed UTF-8 —
   Latin-1, Yiddish, etc. would crash the reader loop.

2. Handle CTCP requests (messages wrapped in \x01). Reply to VERSION
   queries so the server stops retrying, and skip CTCP for notification
   generation.

3. Log outgoing messages from the "send" command with append_log() so
   they appear in IRC logs alongside incoming traffic.

Co-Authored-By: ProofOfConcept <poc@bcachefs.org>
2026-03-05 21:15:49 -05:00
ProofOfConcept
bea1bd5680 daemon: fix UTF-8 panics on multi-byte character truncation
&str[..n] panics when n falls inside a multi-byte UTF-8 sequence.
This crashed the daemon when processing IRC messages containing
Hebrew/Yiddish characters (ehashman's messages hit byte 79-81).

Replace all byte-index truncation with chars().take(n).collect()
in tmux send_prompt preview, notification logging, and git context
truncation.

Co-Authored-By: ProofOfConcept <poc@bcachefs.org>
2026-03-05 21:15:40 -05:00