┌──────────────────────────────────────────────────────────────┐
│ parasite-client │
│ TUI (ratatui) │ Components │ Dispatch │ SSH/Editor/Code │
├──────────────────────────────────────────────────────────────┤
│ parasite-core │
│ Protocol │ Config │ Scripts │ Crypto │ Auth │ Discovery │
├──────────────────────────────────────────────────────────────┤
│ parasite-agent │
│ Server │ Session │ PTY │ File Operations │
└──────────────────────────────────────────────────────────────┘
Both client and agent depend on parasite-core. The client and agent never depend on each other directly — they communicate over TLS using the shared protocol.
Client Agent
│ │
├── TCP connect ───────────────>│
├── TLS handshake ─────────────>│
├── HandshakeRequest { token } ─>│
│<── HandshakeResponse { ok } ──┤
│ │
│ ┌── Message loop ──────────┐ │
│ │ ShellOpen/Data/Resize │ │
│ │ DirList/Create/Delete │ │
│ │ SystemInfoRequest │ │
│ │ Ping/Pong │ │
│ └─────────────────────────┘ │
Terminal Events ──> EventHandler ──> App::handle_event()
│
Action dispatched
│
dispatch_action()
┌────┴─────────────┐
│ connection.rs │
│ shell.rs │
│ editor.rs │
│ code.rs │
│ file_browser.rs │
│ operations.rs │
│ network.rs │
└──────────────────┘
│
Component::render()
│
Terminal Output
All state changes flow through the Action enum. Terminal events, network messages, and timer callbacks all produce Action values that are sent through an MPSC channel and processed by the main dispatch loop.
// Terminal key press → Action
fn handle_key_event(&mut self, key: KeyEvent) -> Option<Action>;
// Network message → Action
Action::SessionNetworkMessage { session_id, msg }
// Timer/background task → Action
Action::EditorReady { sub_id, local_path, sync_name }
UI components implement a shared trait for consistent lifecycle:
pub trait Component {
fn handle_key_event(&mut self, key: KeyEvent) -> Option<Action>;
fn handle_action(&mut self, action: &Action);
fn render(&mut self, frame: &mut Frame, area: Rect);
}
Implementations: DashboardView, FileBrowserView, ShellView, StatusBar, CommandPalette.
App
├── AgentSession (connection to remote-1)
│ ├── SubSession: Shell #1
│ ├── SubSession: Editor (mutagen sync)
│ └── SubSession: VS Code
├── AgentSession (connection to remote-2)
│ └── SubSession: Shell #1
└── (more sessions...)
Each AgentSession holds an Arc<AgentConnection> for sending messages. Sub-sessions share the connection but have independent PTY/shell state.
Messages are serialized with bincode and framed with a 4-byte length prefix:
┌──────────┬────────────────────┐
│ len: u32 │ bincode payload │
└──────────┴────────────────────┘
Maximum message size: 16 MB (MAX_MESSAGE_SIZE).