Commit graph

92 commits

Author SHA1 Message Date
Kent Overstreet
cf1c64f936 Split context_state_summary: ContextBudget for compaction, UI-only for display
context_state_summary() was used for both compaction decisions (just
needs token counts) and debug screen display (needs full tree with
labels). Split into:

- Agent::context_budget() -> ContextBudget: cheap token counting by
  category, used by compact(), restore_from_log(), mind event loop
- ContextBudget::format(): replaces sections_budget_string() which
  fragily pattern-matched on section name strings
- context_state_summary(): now UI-only, formatting code stays here

Also extracted entry_sections() as shared helper with include_memories
param — false for context_state_summary (memories have own section),
true for conversation_sections_from() (subconscious screen shows all).

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 19:02:58 -04:00
Kent Overstreet
9737641c86 Fix build warnings across workspace
- Remove redundant token fields from StreamEvent::Finished (data
  already delivered via Usage event)
- Remove dead hotkey_adjust_sampling, MAX_HISTORY, now()
- Fix unused variable warnings (delta, log)
- Suppress deserialization-only field warnings (jsonrpc, role)
- Make start_stream/chat_completion_stream_temp pub(crate)
- Remove unnecessary pub(crate) re-export of internal types

Remaining warnings are TODO items: SkipIndex (scoring not wired),
notify (MCP notifications not wired).

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 13:55:30 -04:00
Kent Overstreet
c64295ddb2 Reduce pub visibility in agent::api and user modules
api/: parsing module private, SamplingParams/StreamEvent/StreamResult/
AbortOnDrop/build_response_message/collect_stream to pub(crate).
Internal types (ChatRequest, ChunkChoice, Delta, etc.) to pub(crate).
StreamResult fields to pub(crate). Parsing functions to pub(super).

user/: context, subconscious, unconscious, thalamus modules private
(only chat needs pub(crate) for mind/ access).

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 13:43:25 -04:00
Kent Overstreet
f33b1767da Restrict API types visibility — types module is now private
Only Message, Role, MessageContent, ContentPart, ToolCall,
FunctionCall, Usage, ImageUrl are pub-exported from agent::api.

Internal types (ChatRequest, ChatCompletionChunk, ChunkChoice,
Delta, ReasoningConfig, ToolCallDelta, FunctionCallDelta) are
pub(crate) — invisible outside the crate.

All callers updated to import from agent::api:: instead of
agent::api::types::.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 13:39:20 -04:00
Kent Overstreet
7de816022a kill off pub in src/usr/mod.rs
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-07 13:19:08 -04:00
Kent Overstreet
0df5ec11d1 Fix bounds check panic and batched lock in collect_results
- subconscious.rs: use .get(fork_point..) instead of direct slice
  to avoid panic when fork_point > entries.len()
- dmn.rs: batch all output injections (surface, reflection, thalamus)
  under a single agent lock acquisition instead of three separate ones
- dmn.rs: use Store::cached() instead of Store::load() when rendering
  surfaced memories
- Add scoring persistence analysis notes

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 03:49:49 -04:00
Kent Overstreet
39dcf27bd0 Memory scores on entries, not a separate Vec
ConversationEntry::Memory gains score: Option<f64>. The scorer
writes scores directly onto entries when results arrive. Removes
Agent.memory_scores Vec and the memory_scores parameter from
context_state_summary().

Scores are serialized to/from the conversation log as memory_score.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 03:14:24 -04:00
Kent Overstreet
93f5f8b0c7 Shared forked agent — UI reads subconscious entries live
The forked agent is now behind Arc<tokio::sync::Mutex<Agent>>,
stored on SubconsciousAgent and passed to the spawned task. The
subconscious detail screen locks it via try_lock() to read entries
from the fork point — live during runs, persisted after completion.

Removes last_run_entries snapshot. Backend::Forked now holds the
shared Arc, all push operations go through the lock.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 03:09:06 -04:00
Kent Overstreet
04e260c081 Kill publish_context_state() — screens lock the agent directly
F1 and F2 screens now call agent.context_state_summary() directly
via try_lock/lock instead of reading from a shared RwLock cache.
Removes SharedContextState, publish_context_state(), and
publish_context_state_with_scores().

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 03:03:24 -04:00
Kent Overstreet
6191f30aec Move Subconscious + SubconsciousAgent into dmn.rs
Subconscious owns agents and shared walked state. trigger() and
collect_results() take the conscious agent Arc as a parameter.
Mind holds Subconscious behind a tokio Mutex and calls into it
from the event loop.

Drops ~170 lines from mind/mod.rs.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 02:31:52 -04:00
Kent Overstreet
f3ba7e7097 Shared subconscious state — walked keys are Mind-level, not per-agent
SubconsciousSharedState holds walked keys shared between all
subconscious agents. Enables splitting surface-observe into separate
surface and observe agents that share the same walked state.

Walked is passed to run_forked() at run time instead of living on
AutoAgent. UI shows walked count in the subconscious screen header.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 02:13:06 -04:00
Kent Overstreet
ef868cb98f Subconscious screen: detail view with post-fork entries
Track fork point in run_forked(), capture entries added during the
run. Subconscious screen shows these in a detail view (Enter to
drill in, Esc to go back) — only the subconscious agent's own
conversation, not the inherited conscious context.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 02:08:48 -04:00
Kent Overstreet
85aafd206c Subconscious screen: show AutoAgent state
F3 screen now displays SubconsciousSnapshot from Mind's AutoAgents
instead of the old process-based AgentSnapshot. Shows running status
(phase + turn), last run time, and walked key count.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 01:59:09 -04:00
Kent Overstreet
da24e02159 fix: prevent assistant message duplication during tool calls
- Fix sync logic to only break at matching assistant messages
- When assistant message changes (streaming → final), properly pop and re-display
- Add debug logging for sync operations (can be removed later)

The bug: when tool calls split an assistant response into multiple entries,
the sync logic was breaking at the assistant even when it didn't match,
causing the old display to remain while new entries were added on top.

The fix: only break at assistant if matches=true, ensuring changed entries
are properly popped before re-adding.

Co-Authored-By: ProofOfConcept <poc@bcachefs.org>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-07 00:28:39 -04:00
Kent Overstreet
dcf9dadb1c restore markdown formatting 2026-04-06 22:47:23 -04:00
Kent Overstreet
8971e6841b Fix streaming entry duplication and context state freshness
Replace pop+push of streaming entries with finalize_streaming() which
finds the unstamped assistant entry and updates it in place. The
streaming entry IS the assistant message — just stamp it when done.

Also: set dirty flag on agent_changed/turn_watch so the TUI actually
redraws when the agent state changes. Publish context state on F2
switch so the debug screen shows current data.

Age out images during compact() so old screenshots don't bloat the
request payload on startup.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-06 22:43:55 -04:00
Kent Overstreet
d5e6f55da9 Fix context budgeting and compaction
- Budget now counts exact message tokens matching what assemble_api_messages
  sends, not raw string content. Eliminates undercounting from formatting
  overhead (journal headers, personality separators, working stack).

- Load journal before trimming so trim accounts for journal cost.

- Compact before every turn, not just after turn completion. Prevents
  agent_cycle surfaced memories from pushing context over budget.

- Move agent_cycle orchestration from Agent::turn to Mind::start_turn —
  surfaced memories and reflections now precede the user message.

- Move AgentCycleState from Agent to Mind — it's orchestration, not
  per-agent state. memory_scoring_in_flight and memory_scores stay on
  Agent where they belong.

- Tag DMN entries as ConversationEntry::Dmn — compaction evicts them
  first since they're ephemeral. Compaction also prefers evicting
  memories over conversation when memories exceed 50% of entry tokens.

- Kill /retry slash command.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-06 22:43:55 -04:00
Kent Overstreet
c22b8c3a6f Unify budget and context state — single source of truth
Kill ContextBudget and recompute_budget entirely. Budget percentages,
used token counts, and compaction threshold checks now all derive from
the ContextSection tree built by context_state_summary(). This
eliminates the stale-budget bug where the cached budget diverged from
actual context contents.

Also: remove MindCommand::Turn — user input flows through
shared_mind.input exclusively. Mind::start_turn() atomically moves
text from pending input into the agent's context and spawns the turn.
Kill /retry. Make Agent::turn() take no input parameter.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-06 22:43:55 -04:00
Kent Overstreet
f63c341f94 fix unused imports 2026-04-06 22:43:55 -04:00
Kent Overstreet
3cb53d7a5d simplify main ui event loop
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-06 22:43:55 -04:00
Kent Overstreet
0d20d66196 Unify screen dispatch — put InteractScreen in the screens array
active_screen is now the F-key number (1-based), dispatch is just
screens[active_screen - 1].tick() everywhere. Eliminates the
special-cased interact variable and duplicated if/else branching.

Also adds diff_mind_state() for dirty-flag tracking and gates the
bottom-of-loop render on dirty, avoiding redundant redraws.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-06 22:43:55 -04:00
Kent Overstreet
6e9ad04bfc Render only visible lines in conversation and tools panes
ratatui's Paragraph with Wrap does full unicode grapheme segmentation
on render — including for scrolled-off content. Cache per-line wrapped
heights on PaneState (recomputed only on width change or new lines),
then slice to only the visible lines before handing to ratatui.

Eliminates O(total_lines) grapheme work per frame, replacing it with
O(viewport_height) — ~30 lines instead of potentially thousands.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-06 22:43:55 -04:00
Kent Overstreet
f4664ca06f Cache context budget instead of recomputing every frame
budget() called tiktoken on every UI tick, which was the main CPU hog
during rapid key input. Move the cached ContextBudget onto ContextState
and recompute only when entries actually change (push_entry, compact,
restore_from_log).

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-06 22:43:55 -04:00
Kent Overstreet
49cd6d6ab6 rendering 2026-04-06 22:43:55 -04:00
ProofOfConcept
36d698a3e1 Remove dead code: append_text, needs_assistant_marker, target param
append_text was the TextDelta streaming handler — replaced by
append_streaming on Agent entries. needs_assistant_marker tracked
turn boundaries for the old message path. target removed from
Agent::turn — routing now determined by entry content.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-05 22:40:38 -04:00
ProofOfConcept
f390fa1617 Delete ui_channel.rs — relocate types, remove all UiMessage/UiSender plumbing
Types relocated:
- StreamTarget → mind/mod.rs (Mind decides Conversation vs Autonomous)
- SharedActiveTools + shared_active_tools() → agent/tools/mod.rs
- ContextSection + SharedContextState → agent/context.rs (already there)
- StatusInfo + ContextInfo → user/mod.rs (UI display state)

Removed UiSender from: Agent::turn, Mind, learn.rs, all function signatures.
The entire message-passing layer is gone. All state flows through
Agent fields (activities, entries, streaming) read by the UI via try_lock.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-05 22:34:48 -04:00
ProofOfConcept
cfddb55ed9 Kill TextDelta, Info — UiMessage is dead. RAII ActivityGuards replace all status feedback
Streaming text now goes directly to agent entries via append_streaming().
sync_from_agent diffs the growing entry each tick. The streaming entry
is popped when the response completes; build_response_message pushes
the final version.

All status feedback uses RAII ActivityGuards:
- push_activity() for long-running work (thinking, streaming, scoring)
- notify() for instant feedback (compacted, DMN state changes, commands)
- Guards auto-remove on Drop, appending "(complete)" and lingering 5s
- expire_activities() cleans up timed-out notifications on render tick

UiMessage enum reduced to a single Info variant with zero sends.
The channel infrastructure remains for now (Mind/Agent still take
UiSender in signatures) — mechanical cleanup for a follow-up.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-05 22:18:07 -04:00
ProofOfConcept
e7914e3d58 Kill Reasoning, Debug, Activity variants — read status from Agent directly
Reasoning tokens: dropped for now, will land in context entries later.
Debug sends: converted to dbglog! macro (writes to debug.log).
Activity: now a field on Agent, set directly, read by UI via try_lock.
score_memories_incremental takes agent Arc for activity writes.

UiMessage down to 2 variants: TextDelta, Info.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-05 21:45:55 -04:00
ProofOfConcept
eafc2887a3 Kill StatusUpdate, Activity, DmnAnnotation, ContextInfoUpdate, AgentUpdate
Status bar reads directly from Agent and MindState on each render tick.
Activity is now a field on Agent — set by agent code directly, read by
UI via try_lock. DmnAnnotation, ContextInfoUpdate, AgentUpdate were
already dead (no senders).

UiMessage down to 4 variants: TextDelta, Reasoning, Debug, Info.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-05 21:34:27 -04:00
ProofOfConcept
1745e03550 Kill UiMessage variants replaced by state-driven rendering
sync_from_agent reads directly from agent entries, so remove:
- UserInput (pending input shown from MindState.input)
- ToolCall, ToolResult (shown from entries on completion)
- ToolStarted, ToolFinished (replaced by shared active_tools)
- replay_session_to_ui (sync_from_agent handles replay)

-139 lines. Remaining variants are streaming (TextDelta, Reasoning),
status bar state, or ephemeral UI messages (Info, Debug).

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-05 21:21:08 -04:00
Kent Overstreet
306788e0f1 kill event_loop.rs 2026-04-05 21:16:49 -04:00
ProofOfConcept
48beb8b663 Revert to tokio::sync::Mutex, fix lock-across-await bugs, move input ownership to InteractScreen
The std::sync::Mutex detour caught every place a MutexGuard lived
across an await point in Agent::turn — the compiler enforced Send
safety that tokio::sync::Mutex silently allows. With those fixed,
switch back to tokio::sync::Mutex (std::sync blocks tokio worker
threads and panics inside the runtime).

Input and command dispatch now live in InteractScreen (chat.rs):
- Enter pushes directly to SharedMindState.input (no app.submitted hop)
- sync_from_agent displays pending input with dimmed color
- Slash command table moved from event_loop.rs to chat.rs
- cmd_switch_model kept as pub fn for tool-initiated switches

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-05 21:13:48 -04:00
Kent Overstreet
3e1be4d353 agent: switch from tokio::sync::Mutex to std::sync::Mutex
The agent lock is never held across await points — turns lock briefly,
do work, drop, then do async API calls. std::sync::Mutex works and
can be locked from sync contexts (screen tick inside terminal.draw).

Fixes: blocking_lock() panic when called inside tokio runtime.

Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-05 20:08:25 -04:00
Kent Overstreet
f29b4be09c Move chat code to chat.rs 2026-04-05 20:08:18 -04:00
Kent Overstreet
65d23692fb chat: route_entry returns Vec for multi-tool-call entries
An assistant entry can have text + multiple tool calls. route_entry
now returns Vec<(PaneTarget, String, Marker)> — tool calls go to
tools pane, text goes to conversation, all from the same entry.

Pop phase iterates the vec in reverse to pop correct number of
pane items per entry.

Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-05 19:43:48 -04:00
Kent Overstreet
222b2cbeb2 chat: PartialEq on ConversationEntry for proper diff
Add PartialEq to Message, FunctionCall, ToolCall, ContentPart,
ImageUrl, MessageContent, ConversationEntry. Sync now compares
entries directly instead of content lengths.

Phase 1 pops mismatched tail entries using PartialEq comparison.
Phase 2 pushes new entries with clone into last_entries buffer.

TODO: route_entry needs to handle multiple tool calls per entry.

Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-05 19:41:16 -04:00
Kent Overstreet
ca9f2b2b9a chat: double-buffered sync with content-length diffing
Store content lengths of rendered entries. On each tick:
- Generation changed → full pane reset
- Entries removed → pop from tail
- Last entry content length changed → pop and re-render (streaming)
- New entries → route and push

PaneState gains pop_line() for removing the last rendered entry.
This handles streaming (last entry growing), compaction (generation
bump), and normal appends.

Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-05 19:35:19 -04:00
Kent Overstreet
563771e979 chat: route_entry helper separates routing from sync
PaneTarget enum + route_entry() function: given a ConversationEntry,
returns which pane it belongs to (or None to skip). The sync loop
becomes: detect desync → pop, then route new entries.

Routing: User→Conversation, Assistant→ConversationAssistant,
tool_calls→Tools, Tool results→ToolResult, Memory/System→None.

Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-05 19:27:14 -04:00
Kent Overstreet
b89bafdf6b chat: full entry type routing in sync_from_agent
Route agent entries to correct panes:
- User messages → conversation (cyan, User marker)
- Assistant text → conversation (Assistant marker)
- Assistant tool_calls → tools pane (yellow)
- Tool results → tools pane (truncated at 20 lines)
- Memory/system-reminder entries → skipped
- System role → skipped

Two phases: detect generation change (reset panes if needed),
then route new entries. PaneState is the rendered view of agent
entries, updated incrementally.

Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-05 19:22:31 -04:00
Kent Overstreet
350c447ebc chat: state-driven sync from agent entries
InteractScreen holds agent ref, syncs conversation display from
agent.entries() on each tick via blocking_lock(). Tracks generation
counter and entry count to detect compactions and new entries.

Agent gets a generation counter, incremented on compaction and
non-last-entry mutations (age_out_images).

sync_from_agent() is the single path for pane updates. UiMessage
handle_ui_message still exists but will be removed once sync
handles all entry types (streaming, tool calls, DMN).

Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-05 19:17:13 -04:00
Kent Overstreet
6f000bd0f6 user: hook up screen_legend from ScreenView::label()
Build legend string from actual screen labels instead of hardcoded
constant. Computed once at startup via OnceLock, accessible from
all screen draw methods.

Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-05 19:03:06 -04:00
Kent Overstreet
68f115b880 user: InteractScreen extracted, all screens use ScreenView trait
InteractScreen in chat.rs owns conversation/autonomous/tools panes,
textarea, input history, scroll state. App is now just shared state
(status, sampling params, agent_state, channel_status, idle_info).

Event loop holds InteractScreen separately for UiMessage routing.
Overlay screens (F2-F5) in screens vec. F-key switching preserves
state across screen changes.

handle_ui_message moved from App to InteractScreen.
handle_key split: global keys on App, screen keys in tick().
draw dispatch eliminated — each screen draws itself.

Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-05 18:57:54 -04:00
Kent Overstreet
8418bc9bc9 event_loop: wire F-key screen switching with ScreenView
Create overlay screens vec (ConsciousScreen, SubconsciousScreen,
UnconsciousScreen, ThalamusScreen). F-keys switch active_screen.
Screen tick() called during render phase with pending key event.
Screen actions (Switch, Hotkey) applied after draw.

Interact (F1) still draws via App::draw_main(). Overlay screens
draw via ScreenView::tick(). State persists across switches.

Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-05 17:59:33 -04:00
Kent Overstreet
927cddd864 user: ScreenView trait, overlay screens extracted from App
Convert F2-F5 screens to ScreenView trait with tick() method.
Each screen owns its view state (scroll, selection, expanded).
State persists across screen switches.

- ThalamusScreen: owns sampling_selected, scroll
- ConsciousScreen: owns scroll, selected, expanded
- SubconsciousScreen: owns selected, log_view, scroll
- UnconsciousScreen: owns scroll

Removed from App: Screen enum, debug_scroll, debug_selected,
debug_expanded, agent_selected, agent_log_view, sampling_selected,
set_screen(), per-screen key handling, draw dispatch.

App now only draws the interact (F1) screen. Overlay screens are
drawn by the event loop via ScreenView::tick. F-key routing and
screen instantiation to be wired in event_loop next.

InteractScreen (state-driven, reading from agent entries) is the
next step — will eliminate the input display race condition.

Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-05 17:54:40 -04:00
Kent Overstreet
7458fe655f event_loop: command table with inline closures
SlashCommand registry with name, help, and handler as inline
closures in commands(). Single source of truth — send_help reads
it, dispatch_command looks up by name. No separate named functions.

run() takes &Mind instead of individual handles. Dispatch reduced
to: quit check, command lookup, or submit as input.

Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-05 17:05:34 -04:00
Kent Overstreet
3c4220c079 event_loop: run() takes &Mind instead of individual handles
Simplifies the interface — run() receives one reference to Mind
and extracts agent, shared, turn_watch locally. Reduces parameter
count from 7 to 5.

Also: command table data structure (SlashCommand) and commands()
function for single source of truth. send_help uses it. Dispatch
refactor to follow.

Also: fix input submission — diff before push, clone after push,
so prev_mind captures the input for consumption detection.

Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-05 16:53:05 -04:00
Kent Overstreet
2b9aba0e5d fix shutdown hang and slow startup
Mind::run() breaks when input_rx channel closes (UI shut down).
Previously the DMN timer kept the loop alive forever.

UI renders immediately without blocking on agent lock. Conversation
replay happens lazily on the render tick via try_lock — the UI
shows "consciousness v0.3" instantly, fills in model info and
conversation history once Mind init completes.

Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-05 16:18:10 -04:00
Kent Overstreet
71351574be event_loop: display user input when Mind consumes it
Show user text in the conversation window when the MindState diff
detects input was consumed (prev.input non-empty, cur.input empty).
Input stays editable in the text area until Mind takes it.

Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-05 16:13:04 -04:00
Kent Overstreet
8d045a3e6b use ratatui::crossterm re-exports, add event-stream feature
All crossterm imports go through ratatui::crossterm. Direct crossterm
dep kept only for the event-stream feature flag (EventStream for
async terminal input).

Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-05 06:22:31 -04:00
Kent Overstreet
120ffabfaa Kill socket, read/write subcommands
Redundant with channels

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-05 05:58:51 -04:00