···33Ein is a Rust-based AI agent framework. A gRPC server drives an LLM agent loop and executes tools implemented as pluggable WASM modules. Multiple model backends are supported (OpenRouter, Anthropic, OpenAI, Ollama). A terminal UI client connects to the server and provides an interactive chat interface. Sessions are persisted to SQLite so conversations can be resumed across reconnects.
4455```
66-┌─────────────────────────┐ ┌──────────────────────────────┐
77-│ ein-tui │ gRPC │ ein-server │
88-│ │◄────────►│ │
99-│ Interactive chat UI │ │ LLM agent loop │
1010-│ Connection retry │ │ WASM tool executor │
1111-│ Slash command hints │ │ Pluggable model clients │
1212-│ Animated thinking UI │ │ Per-session sandboxing │
1313-│ │ │ SQLite session persistence │
1414-└─────────────────────────┘ └──────────────────────────────┘
66+┌─────────────────────────────┐ ┌──────────────────────────────┐
77+│ ein-tui │ gRPC │ ein-server │
88+│ │ (proto) │ │
99+│ Ratatui terminal UI │◄────────►│ Agent loop + tool executor │
1010+│ Session picker on startup │ │ WASM plugin host │
1111+│ Slash command autocomplete │ │ Pluggable model clients │
1212+│ Animated thinking spinner │ │ Per-session sandboxing │
1313+│ Syntax-highlighted diffs │ │ SQLite session persistence │
1414+└─────────────────────────────┘ └──────────────────────────────┘
1515```
16161717## Getting Started
···111111cargo run -p ein-tui
112112```
113113114114-On first launch a floating dialog asks whether to grant the agent access to your current working directory for that session. The TUI connects to `localhost:50051` by default. To connect to a different address:
114114+The TUI connects to `localhost:50051` by default. To connect to a different address:
115115116116```bash
117117cargo run -p ein-tui -- http://my-server:50051
118118```
119119120120+To enable debug logging to `~/.ein/tui.log`:
121121+122122+```bash
123123+cargo run -p ein-tui -- --debug
124124+```
125125+126126+On first connection a **session picker** modal appears. Use `↑`/`↓` to navigate, `Enter` to select:
127127+- **New Session** — starts a fresh conversation; a follow-up modal asks whether to grant the agent access to your current working directory for that session
128128+- **Existing session** — resumes a prior conversation from where it left off
129129+120130## Configuration
121131122132The TUI stores its configuration at `~/.ein/config.json`. The file is created with defaults on first run.
···145155| `allowed_paths` | Filesystem paths all WASM plugins may read/write (preopened for every session) |
146156| `allowed_hosts` | Hostnames all WASM plugins may connect to (empty = deny all; `"*"` = allow all) |
147157148148-In addition, at startup the TUI asks whether to add the current working directory to `allowed_paths` for that session only — this is never written back to `config.json`.
158158+When starting a new session, the TUI asks whether to add the current working directory to `allowed_paths` for that session only — this is never written back to `config.json`.
149159150160### Per-plugin configuration (`plugin_configs`)
151161···185195| Key | Action |
186196|-----|--------|
187197| `Enter` | Send message / run slash command |
188188-| `↑` / `↓` | Scroll conversation history |
198198+| `↑` / `↓` | Scroll conversation history (also navigate session picker) |
189199| `Ctrl-C` | Force quit |
190200| `/exit` + `Enter` | Exit the TUI |
201201+| `/config` + `Enter` | Open `~/.ein/config.json` in `$EDITOR` |
191202192192-While the agent is working, an animated indicator appears in the chat panel. Tool invocations are shown inline as the agent uses them:
203203+While the agent is working, an animated thinking spinner appears in the conversation pane. Tool invocations are shown inline as the agent uses them:
193204194205```
195206 ▸ Bash ls -la
···198209 ▸ Edit src/main.rs
199210```
200211201201-`Edit` calls display a syntax-highlighted diff showing the removed and added lines.
212212+`Edit` calls display a syntax-highlighted diff showing the removed and added lines (up to 5 each), with line numbers.
202213203203-The status bar at the bottom shows the active model and cumulative token usage for the session.
214214+The status bar at the bottom shows the active model and cumulative token usage on the left, and the current session UUID on the right.
204215205216### Connection behaviour
206217207207-The TUI starts immediately regardless of whether the server is running. While disconnected, a red `●` icon and animated spinner appear in the conversation pane. The TUI reconnects automatically every 3 seconds. If the server goes away mid-session, an error message is shown and the TUI resumes connecting in the background.
218218+The TUI connects in the background immediately on startup. While disconnected, a red `●` icon and animated spinner appear in the conversation pane. The TUI reconnects automatically every 3 seconds. If the server goes away mid-session, an error message is shown and the TUI resumes connecting in the background — the session picker reappears on the next successful reconnect.
208219209220## Tools
210221211211-Tools are WASM components loaded at startup. Three are included out of the box:
222222+Tools are WASM components loaded at startup. Four are included out of the box:
212223213224| Tool | Description |
214225|------|-------------|
215215-| `Bash` | Execute shell commands |
226226+| `Bash` | Execute shell commands (streams stdout in real time) |
216227| `Read` | Read a file from the filesystem |
217228| `Write` | Write content to a file |
218229| `Edit` | Replace a specific string in a file with new content |
···231242 ein-server/ gRPC server — agent loop, WASM plugin host, session persistence
232243 ein-tui/ Terminal UI client
233244packages/
234234- ein_plugin/ WASM plugin interface (ToolPlugin trait, ToolDef, syscalls)
245245+ ein_tool/ WASM tool plugin interface (ToolPlugin trait, ToolDef, syscalls)
235246 ein_bash/ Bash tool plugin
236247 ein_read/ Read tool plugin
237248 ein_write/ Write tool plugin
···244255 ein_ollama/ Ollama model client plugin
245256```
246257247247-The protocol (`crates/ein-proto/proto/ein.proto`) defines a bidirectional streaming RPC. Each session opens with a `SessionConfig` message (global sandbox constraints + per-plugin config map + optional `session_id` for resume), followed by `UserInput` prompt messages. The server streams back `AgentEvent` messages as the agent thinks, calls tools, and produces output — starting with a `SessionStarted` event carrying the session's UUID and whether it was resumed. A `config_update` message variant allows the TUI to push plugin config changes to a live session without reconnecting.
258258+### Protocol
259259+260260+The protocol (`crates/ein-proto/proto/ein.proto`) defines a bidirectional streaming RPC (`AgentSession`) and a unary `ListSessions` RPC. Each session opens with a `SessionConfig` message (global sandbox constraints + per-plugin config map + optional `session_id` for resume), followed by `UserInput` prompt messages. The server streams back `AgentEvent` messages as the agent thinks, calls tools, and produces output — starting with a `SessionStarted` event carrying the session's UUID, a `resumed` boolean, and the prior conversation history when resuming. A `config_update` message variant allows the TUI to push plugin config changes to a live session without reconnecting.
261261+262262+`ListSessions` returns a list of `SessionSummary` records (newest-first), each containing the session ID, creation timestamp, a preview of the first user message, and the stored `SessionConfig` JSON needed to reconstruct the session on resume.
263263+264264+### Session persistence
248265249249-Sessions are persisted to `~/.ein/sessions.db`. Supplying a previously assigned `session_id` in `SessionConfig` causes the server to restore the conversation history and resume as if the session never disconnected.
266266+Sessions are persisted to `~/.ein/sessions.db`. Supplying a previously assigned `session_id` in `SessionConfig` causes the server to restore the full conversation history and resume as if the session never disconnected.
267267+268268+### TUI modules (`crates/ein-tui/src/`)
269269+270270+| File | Role |
271271+|------|------|
272272+| `main.rs` | Entry point, CLI args, event loop, terminal lifecycle |
273273+| `app.rs` | `App` state struct, `DisplayMessage` variants, session picker / CWD modal state |
274274+| `config.rs` | `ClientConfig` — load, save, and migrate `~/.ein/config.json` |
275275+| `connection.rs` | `connection_manager` — background reconnect loop, `ListSessions` handshake, config file watcher |
276276+| `input.rs` | Slash command registry (`COMMANDS`), key event handler, server event handler |
277277+| `render.rs` | Full render pass — conversation pane, input area, autocomplete, session picker and CWD modals, status bar |
278278+279279+Uses **Ratatui** (v0.29) for rendering and **crossterm** for keyboard events. The conversation pane renders a corgi pixel-art header on startup. Edit diffs are syntax-highlighted using `syntect` with the `base16-ocean.dark` theme.
280280+281281+### Server modules (`crates/ein-server/src/`)
282282+283283+| File | Role |
284284+|------|------|
285285+| `main.rs` | CLI arg parsing, `EinConfig`, `HarnessState`, `ModelClientHarnessState` (HTTP host filtering), server startup |
286286+| `grpc.rs` | `AgentServer` — tonic `Agent` impl; `AgentSession` and `ListSessions` handlers; session persistence; `ConfigUpdate` mid-session |
287287+| `agent.rs` | `run_agent` — the LLM ↔ tool loop |
288288+| `model_client.rs` | `ModelClientSessionManager`, WASM model client compilation and instantiation |
289289+| `persistence.rs` | `SessionStore` — SQLite-backed session storage; create, save, and load message history |
290290+| `tools.rs` | `ToolRegistry` + `WasmTool` — loads and calls WASM plugins |
291291+| `syscalls.rs` | Host functions exposed to WASM tool plugins (spawn, log, …) |
250292251293## License
252294