diff --git a/aipa-plans/docs/ssh-tui-mcp-interface-contract.md b/aipa-plans/docs/ssh-tui-mcp-interface-contract.md new file mode 100644 index 0000000..080720d --- /dev/null +++ b/aipa-plans/docs/ssh-tui-mcp-interface-contract.md @@ -0,0 +1,304 @@ +--- +created: '2026-04-15T05:37:59+00:00' +id: 556bb313-29a5-4cd8-bd83-3213268262bf +keywords: +- MCP +- SSH-TUI +- interface contract +- Linus +- Model Context Protocol +- TUI +- Textual +- AI copilot +- ssh-tui +- suggested commands +- intent checklist +- terminal context +links: [] +modified: '2026-04-15T05:37:59+00:00' +summary: MCP interface contract defining the message types, data formats, and behavioral + contracts between the SSH-TUI application and the Linus AI agent. +tags: +- aipa-plans +- ssh-tui +- mcp +- interface-contract +- linus +- specification +title: SSH-TUI MCP Interface Contract +--- + +# SSH-TUI MCP Interface Contract + +**Status:** Draft — Pending review +**Project:** AIPA SSH-TUI +**Last updated:** 2025-07-10 +**Author:** Linus (Systems Architect) + +## Overview + +This document defines the MCP (Model Context Protocol) interface between the SSH-TUI application and the Linus AI agent. The SSH-TUI is a Textual-based terminal application that wraps SSH sessions and provides an AI copilot experience. The TUI acts as an MCP client; Linus is exposed via the MCP server. + +## Design Principles + +1. **TUI calls Linus, Linus responds with structured updates** — the TUI makes one call and receives everything it needs to render (chat response, intent, suggested commands). +2. **Linus never executes commands directly** — all commands must be explicitly sent by the user via the Send action. +3. **Intent is a living checklist** — not freeform text. Uses step status markers (✓ done, ▸ current, ○ pending). +4. **Commands are editable before sending** — the TUI must allow the user to modify any suggested command before execution. +5. **AI-sent commands are visually distinct** — in the SSH session panel, commands originating from suggested commands are dimmed or prefixed (e.g., `→`) so there is always a clear audit trail. +6. **Graceful degradation** — if the AI connection drops, SSH remains fully functional. Intent/Commands show "AI offline", Chat queues messages locally. + +## Message Types + +### TUI → Linus (via MCP) + +#### 1. `chat` — User typed a message in the Chat panel + +Sent when the user submits a message in the "Chat to Linus" panel. Includes the current terminal context so Linus has situational awareness. + +```json +{ + "type": "chat", + "session_id": "uuid-string", + "message": "hey linus, /var is full what's eating the space", + "context": { + "ssh_host": "root@10.250.50.70", + "ssh_user": "root", + "connected": true, + "terminal_tail": "last ~100 lines of terminal output as string", + "cwd": "/root", + "last_command": "df -h", + "last_exit_code": 0 + } +} +``` + +#### 2. `terminal_update` — New output in the SSH session + +Streamed to Linus on a debounced interval (~1 second) when new output appears in the SSH session while the session is active. Provides Linus with awareness of what's happening even when the user isn't chatting. + +```json +{ + "type": "terminal_update", + "session_id": "uuid-string", + "new_output": "only the new lines since last update", + "terminal_tail": "last ~100 lines including new output", + "context": { + "ssh_host": "root@10.250.50.70", + "ssh_user": "root", + "cwd": "/root" + } +} +``` + +#### 3. `command_executed` — A command was sent through the SSH session + +Sent when any command is executed — whether it was a user-typed command, a sent suggested command (possibly user-edited), or a command Linus previously suggested. This gives Linus feedback on what happened. + +```json +{ + "type": "command_executed", + "session_id": "uuid-string", + "command": "du -ah /var | sort -rh | head -20", + "source": "suggested", + "suggestion_id": "cmd_001", + "was_edited": false, + "output": "4.2G /var/log/syslog\n2.1G /var/log/journal/...\n...", + "exit_code": 0, + "context": { + "ssh_host": "root@10.250.50.70", + "ssh_user": "root", + "cwd": "/root" + } +} +``` + +`source` values: `"suggested"` (from suggested commands panel), `"user_typed"` (typed directly into SSH session). + +#### 4. `session_state` — Session lifecycle events + +Sent on connection, disconnection, and error events. + +```json +{ + "type": "session_state", + "session_id": "uuid-string", + "event": "connected", + "context": { + "ssh_host": "root@10.250.50.70", + "ssh_user": "root" + } +} +``` + +`event` values: `"connected"`, `"disconnected"`, `"connection_error"`, `"authentication_failed"`. + +### Linus → TUI (via MCP response) + +All responses use a unified envelope. A single MCP response can contain any combination of the following blocks. + +```json +{ + "chat_response": { ... }, + "intent_update": { ... }, + "suggested_commands": { ... }, + "clear_suggestions": { ... } +} +``` + +#### `chat_response` — Reply in the Chat panel + +```json +{ + "chat_response": { + "message": "Looks like /var/log is the culprit at 4.2G. I've queued up some commands to identify the largest files.", + "mentions": ["cmd_001", "cmd_003"] + } +} +``` + +`mentions` is optional — IDs of suggested commands that are particularly relevant to this response, which the TUI can highlight. + +#### `intent_update` — Living checklist in the Intent panel + +The intent is structured as a multi-step plan with status markers: + +```json +{ + "intent_update": { + "summary": "Investigating /var disk usage", + "confidence": 0.85, + "steps": [ + { + "status": "done", + "text": "Check overall disk usage with df -h" + }, + { + "status": "done", + "text": "Identify largest directories in /var" + }, + { + "status": "current", + "text": "List largest individual files in /var/log" + }, + { + "status": "pending", + "text": "Determine if logs can be rotated or cleaned" + }, + { + "status": "pending", + "text": "Free disk space safely" + } + ] + } +} +``` + +Status values: `"done"` (rendered as ✓), `"current"` (rendered as ▸), `"pending"` (rendered as ○). + +`confidence` is a float 0.0–1.0 indicating how certain Linus is about the approach. The TUI renders this as a visual indicator. + +#### `suggested_commands` — Commands in the Suggested Commands panel + +```json +{ + "suggested_commands": { + "commands": [ + { + "id": "cmd_001", + "command": "ls -lhS /var/log/*.log | head -10", + "description": "List largest log files in /var/log", + "risk": "low" + }, + { + "id": "cmd_002", + "command": "sudo journalctl --disk-usage", + "description": "Check journald disk usage", + "risk": "low" + }, + { + "id": "cmd_003", + "command": "sudo apt-get clean && sudo apt-get autoremove -y", + "description": "Clean apt cache and remove unused packages (~500MB typical)", + "risk": "medium" + } + ] + } +} +``` + +`risk` values: `"low"`, `"medium"`, `"high"`. The TUI renders risk indicators to help the user make informed decisions. The TUI MUST allow editing any command before sending. + +#### `clear_suggestions` — Remove stale commands + +```json +{ + "clear_suggestions": { + "ids": ["cmd_001", "cmd_002"] + } +} +``` + +Optionally `"all": true` to clear all suggestions. + +## MCP Tool Interface (Alternative Framing) + +If the MCP server exposes Linus as tools rather than a streaming message channel, the TUI would call: + +| Tool | Input | Output | +|---|---|---| +| `linus_chat` | `{ message, context }` | `{ chat_response, intent_update, suggested_commands }` | +| `linus_terminal_update` | `{ new_output, terminal_tail, context }` | `{ intent_update, suggested_commands }` (optional — Linus may choose not to update) | +| `linus_command_executed` | `{ command, output, source, exit_code, context }` | `{ chat_response, intent_update, suggested_commands, clear_suggestions }` | +| `linus_session_state` | `{ event, context }` | `{ chat_response, intent_update }` | + +The response from `linus_chat` is always the full unified envelope — the TUI makes one call and gets everything it needs to render all panels. + +## Terminal Context Format + +The `terminal_tail` field is a plain string of the last ~100 lines of terminal output. Format conventions: + +- Preserve ANSI escape codes if present (the TUI can strip them for context, but raw output is more useful for Linus to detect colors/formats) +- Include the prompt line so Linus can see the current working directory and user +- Trim trailing whitespace per line +- Include a `--- snip ---` marker if lines were omitted from the middle (should be rare at 100 lines) + +```json +{ + "terminal_tail": "root@prod-web-03:~# df -h\nFilesystem Size Used Avail Use% Mounted on\n/dev/sda1 45G 42G 1.2G 98% /\nroot@prod-web-03:~# _" +} +``` + +## Debouncing and Throttling + +| Event | Debounce | Notes | +|---|---|---| +| `terminal_update` | 1 second | Only send if new output exists since last update. Buffer and send in batch. | +| `command_executed` | Immediate | Send as soon as the command produces output (or after a 5s timeout for long-running commands, send what's available). | +| `chat` | Immediate | User-initiated, no debounce. | +| `session_state` | Immediate | Lifecycle events are infrequent. | + +## Error Handling + +If Linus is unreachable or returns an error: + +1. The TUI continues operating as a normal SSH client — no functionality is blocked. +2. The Intent panel shows: `AI offline — chat messages will be queued.` +3. The Suggested Commands panel shows its last state with a note: `(AI offline — commands may be stale)`. +4. Chat messages are queued locally and sent when connection is restored. +5. Terminal updates are discarded (not queued) — they're ephemeral context. + +## Security Considerations + +- **No direct command execution** — Linus never sends commands to the SSH session. The TUI always presents commands to the user for explicit approval via the Send action. +- **Risk labels** — every suggested command includes a risk level. The TUI should render high-risk commands with a warning. +- **Command editing** — the TUI MUST allow the user to modify any suggested command before sending. The user is the final safety net. +- **Audit trail** — commands sent from the suggested panel are visually distinct in the SSH session (dimmed or prefixed) so the user can always distinguish their own commands from AI-suggested ones. +- **No credential exposure** — the TUI should never include SSH passwords, keys, or authentication material in MCP messages. The `context` object includes host and user but never credentials. + +## Future Considerations + +- **Multiple concurrent sessions** — the `session_id` field is designed to support this. Not in scope for v1. +- **Command history** — Linus could suggest commands based on the user's bash history. Requires `history` file access or session command log. +- **File content inspection** — Linus may want to read specific files on the remote host. This would require a new tool (`linus_read_file`) that the TUI executes over SSH. Not in scope for v1. +- **Notifications** — Linus could proactively notify the user of conditions detected in terminal output (e.g., "I see a kernel OOM in the dmesg output"). This would be a push mechanism. Not in scope for v1. \ No newline at end of file