src/
├── main.rs Entry point, terminal setup
├── tui.rs Terminal initialization/restore
├── event.rs Crossterm event loop → EventHandler
├── action.rs Action enum (73 variants)
├── connection.rs AgentConnection (TLS reader/writer)
├── credentials.rs Credential storage (keychain)
├── ssh.rs SSH helpers (sshpass, known_hosts)
├── connect.rs Agent connection flow (SSH + start agent)
├── install.rs Remote agent installation
├── shutdown.rs Remote agent shutdown
├── code.rs VS Code Remote-SSH integration
├── local_pty.rs Local PTY for editor/code processes
│
├── app/ Application state & dispatch
│ ├── mod.rs App struct, run(), draw(), handle_event()
│ ├── session.rs AgentSession, SubSession, SshCredentials
│ ├── cleanup.rs Connection/session cleanup
│ ├── discovery.rs mDNS agent discovery
│ └── dispatch/
│ ├── mod.rs dispatch_action() router
│ ├── connection.rs Connect/disconnect/reconnect
│ ├── shell.rs Shell open/input/resize
│ ├── editor.rs Editor sync lifecycle
│ ├── code.rs VS Code lifecycle
│ ├── file_browser.rs File browser actions
│ ├── operations.rs Install/SSH connect/shutdown
│ └── network.rs Network message handling
│
├── editor/ Mutagen editor sync
│ ├── mod.rs Re-exports
│ ├── workspace.rs Hash computation, paths
│ ├── ssh_config.rs SSH config injection/removal
│ ├── control_master.rs SSH ControlMaster management
│ └── sync.rs Mutagen sync lifecycle
│
└── components/ UI components
├── mod.rs Component trait
├── shell.rs VT100 terminal emulator
├── status_bar.rs Bottom status bar
├── command_palette.rs Command input modal
├── file_browser.rs File/directory browser
└── dashboard/
├── mod.rs DashboardView struct
├── types.rs SessionInfo, SystemInfoData
├── render_agents.rs Agent list rendering
├── render_panels.rs Operation panels (install/connect/etc.)
├── render_layout.rs Workspace, session, system info layout
├── key_handling.rs Keyboard event dispatch
└── action_handling.rs Action processing
The client has four views:
| View | Purpose |
|---|---|
Workspace |
Agent discovery, connection management |
Dashboard |
Active session info, system stats, sub-sessions |
Shell |
Full-screen terminal emulator |
FileBrowser |
Remote directory navigation |
EventHandlerApp::handle_event() → active component’s handle_key_event()Action variantdispatch_action() matches the action to a handler moduleApp state, may send network messagesApp::draw() calls Component::render() on the active viewSwitchView, SwitchSession, NextSession, SwitchSubSessionConnect, SessionConnected, Disconnect, ConnectionLost, ReconnectOpenShell, ShellInput, ResizeShellOpenEditor, EditorProgress, EditorReady, EditorFailedOpenCode, CodeProgress, CodeReady, CodeFailedOpenFileBrowser, FileBrowserNavigate, FileBrowserSelect, FileBrowserCreateDirInstallAgent, SshConnect, ShutdownAgentSessionNetworkMessageStartDiscovery, AgentDiscovered, AgentLostpub 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);
}
Components are passive renderers. They don’t own connections or spawn tasks — that’s the App’s responsibility via the dispatch system.
struct AgentSession {
connection: Arc<AgentConnection>, // Shared TLS connection
sub_sessions: Vec<SubSession>, // Shells, editors, code sessions
ssh_creds: Option<SshCredentials>, // For editor/code SSH operations
}
struct SubSession {
id: SessionId, // UUID
shell: ShellView, // VT100 terminal state
label: String, // Display name
sync_name: Option<String>, // Mutagen sync name (editors)
sync_hash: Option<String>, // SSH config hash (code)
local_pty: Option<LocalPty>, // Local PTY for editor/code processes
}