+74
-74
Diff
round #6
+8
-8
CLAUDE.md
+8
-8
CLAUDE.md
···
4
4
5
5
## What is Ein
6
6
7
-
Ein is a Rust-based AI agent framework with a client-server architecture. A gRPC server drives an LLM agent loop and executes tools implemented as pluggable WASM modules. Multiple model client plugins are supported (OpenRouter, Anthropic, OpenAI, Ollama). A terminal UI client (`ein-tui`) connects to the server and provides an interactive chat interface. Sessions are persisted to SQLite so conversations can be resumed across reconnects.
7
+
Ein is a Rust-based AI agent framework with a client-server architecture. A gRPC server drives an LLM agent loop and executes tools implemented as pluggable WASM modules. Multiple model client plugins are supported (OpenRouter, Anthropic, OpenAI, Ollama). A terminal UI client (`ein`) connects to the server and provides an interactive chat interface. Sessions are persisted to SQLite so conversations can be resumed across reconnects.
8
8
9
9
## Setup
10
10
11
11
```bash
12
12
rustup target add wasm32-wasip2
13
13
cargo build # Build all crates
14
-
cargo build -p ein-tui # Build just the TUI client
14
+
cargo build -p ein # Build just the TUI client
15
15
cargo build -p eind # Build just the server
16
16
```
17
17
···
45
45
cargo run --bin eind
46
46
47
47
# Terminal 2 โ start the TUI (connects to localhost:50051 by default)
48
-
cargo run --bin ein-tui
48
+
cargo run --bin ein
49
49
50
50
# Optional: connect to a non-default server address
51
-
cargo run -p ein-tui -- http://my-server:50051
51
+
cargo run -p ein -- http://my-server:50051
52
52
```
53
53
54
54
The server creates `~/.ein/sessions.db` on first run to persist session history.
···
59
59
60
60
```
61
61
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
62
-
โ ein-tui โ gRPC โ eind โ
62
+
โ ein โ gRPC โ eind โ
63
63
โ โ (proto) โ โ
64
64
โ Ratatui terminal UI โโโโโโโโโโโบโ Agent loop + tool executor โ
65
65
โ Keyboard / render loop โ โ WASM plugin host โ
···
105
105
106
106
Database migrations live in `eind/migrations/`.
107
107
108
-
### Client config (`crates/ein-tui/src/config.rs`)
108
+
### Client config (`ein/src/config.rs`)
109
109
110
110
`ClientConfig` is loaded from (or created at) `~/.ein/config.json` on TUI startup. Structure mirrors `SessionConfig`. At startup the TUI shows a floating modal asking whether to add the current working directory to `allowed_paths` for that session; this is never persisted to `config.json`.
111
111
···
129
129
130
130
**Plugin loading** (`src/tools.rs`): scans the plugin directory for `.wasm` files and instantiates each as a Wasmtime component. The filename stem (e.g. `ein_bash`) is used as the plugin's config identity to look up its entry in `plugin_configs`; global `allowed_paths`/`allowed_hosts` are merged with any plugin-specific overrides before the WASI context is built. After instantiation, `name()`/`schema()` are called to get the display name (e.g. `"Bash"`) and tool schema exposed to the model. In debug mode both tool and model client plugins are loaded from `./target/wasm32-wasip2/debug/`; in release mode tool plugins come from `~/.ein/plugins/tools/` and model client plugins from `~/.ein/plugins/model_clients/`.
131
131
132
-
### TUI (`crates/ein-tui/`)
132
+
### TUI (`ein/`)
133
133
134
-
Six source files under `crates/ein-tui/src/`:
134
+
Six source files under `ein/src/`:
135
135
136
136
| File | Role |
137
137
|------|------|
+26
-26
Cargo.lock
+26
-26
Cargo.lock
···
970
970
source = "registry+https://github.com/rust-lang/crates.io-index"
971
971
checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
972
972
973
+
[[package]]
974
+
name = "ein"
975
+
version = "0.1.8"
976
+
dependencies = [
977
+
"anyhow",
978
+
"chrono",
979
+
"clap",
980
+
"crossterm",
981
+
"dirs",
982
+
"ein-proto",
983
+
"notify",
984
+
"ratatui",
985
+
"reqwest",
986
+
"serde",
987
+
"serde_json",
988
+
"syntect",
989
+
"tar",
990
+
"tokio",
991
+
"tokio-stream",
992
+
"tonic",
993
+
"tracing",
994
+
"tracing-appender",
995
+
"tracing-subscriber",
996
+
"xz2",
997
+
]
998
+
973
999
[[package]]
974
1000
name = "ein-agent"
975
1001
version = "0.1.8"
···
1002
1028
"tonic-build",
1003
1029
]
1004
1030
1005
-
[[package]]
1006
-
name = "ein-tui"
1007
-
version = "0.1.8"
1008
-
dependencies = [
1009
-
"anyhow",
1010
-
"chrono",
1011
-
"clap",
1012
-
"crossterm",
1013
-
"dirs",
1014
-
"ein-proto",
1015
-
"notify",
1016
-
"ratatui",
1017
-
"reqwest",
1018
-
"serde",
1019
-
"serde_json",
1020
-
"syntect",
1021
-
"tar",
1022
-
"tokio",
1023
-
"tokio-stream",
1024
-
"tonic",
1025
-
"tracing",
1026
-
"tracing-appender",
1027
-
"tracing-subscriber",
1028
-
"xz2",
1029
-
]
1030
-
1031
1031
[[package]]
1032
1032
name = "ein_anthropic"
1033
1033
version = "0.1.8"
+3
-3
Cargo.toml
+3
-3
Cargo.toml
···
1
1
[workspace]
2
2
members = [
3
3
"eind",
4
-
"crates/ein-tui",
4
+
"ein",
5
5
"crates/ein-proto",
6
6
"crates/ein-agent",
7
7
"crates/ein-core",
···
9
9
]
10
10
default-members = [
11
11
"eind",
12
-
"crates/ein-tui",
12
+
"ein",
13
13
"crates/ein-proto",
14
14
"crates/ein-agent",
15
15
"crates/ein-core",
···
35
35
"x86_64-unknown-linux-gnu",
36
36
]
37
37
pr-run-mode = "plan"
38
-
members = ["crates/ein-tui"]
38
+
members = ["ein"]
39
39
# Allow manual edits to the generated workflow (we add a protoc install step).
40
40
allow-dirty = ["ci"]
41
41
+10
-10
README.md
+10
-10
README.md
···
4
4
5
5
```
6
6
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
7
-
โ ein-tui โ gRPC โ eind โ
7
+
โ ein โ gRPC โ eind โ
8
8
โ โ (proto) โ โ
9
9
โ Ratatui terminal UI โโโโโโโโโโโบโ Agent loop + tool executor โ
10
10
โ Session picker on startup โ โ WASM plugin host โ
···
23
23
cargo binstall --git https://github.com/mstallmo/ein ein
24
24
```
25
25
26
-
This installs both `ein-tui` (terminal UI) and `eind` (gRPC agent server). You can also install them individually:
26
+
This installs both `ein` (terminal UI) and `eind` (gRPC agent server). You can also install them individually:
27
27
28
28
```bash
29
-
cargo binstall --git https://github.com/mstallmo/ein ein-tui
29
+
cargo binstall --git https://github.com/mstallmo/ein ein
30
30
cargo binstall --git https://github.com/mstallmo/ein eind
31
31
```
32
32
···
134
134
Start the TUI client in another:
135
135
136
136
```bash
137
-
cargo run --bin ein-tui
137
+
cargo run --bin ein
138
138
```
139
139
140
140
The TUI connects to `localhost:50051` by default. To connect to a different address:
141
141
142
142
```bash
143
-
cargo run --bin ein-tui -- http://my-server:50051
143
+
cargo run --bin ein -- http://my-server:50051
144
144
```
145
145
146
146
To enable debug logging to `~/.ein/tui.log`:
147
147
148
148
```bash
149
-
cargo run --bin ein-tui -- --debug
149
+
cargo run --bin ein -- --debug
150
150
```
151
151
152
152
On first connection a **session picker** modal appears. Use `โ`/`โ` to navigate, `Enter` to select:
···
270
270
```
271
271
crates/
272
272
ein-proto/ Protocol Buffer definitions (gRPC service + message types)
273
-
eind/ gRPC server โ agent loop, WASM plugin host, session persistence
274
-
ein-tui/ Terminal UI client
273
+
ein/ Terminal UI client
274
+
eind/ gRPC server โ agent loop, WASM plugin host, session persistence
275
275
packages/
276
276
ein_tool/ WASM tool plugin interface (ToolPlugin trait, ToolDef, syscalls)
277
277
ein_bash/ Bash tool plugin
···
302
302
303
303
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.
304
304
305
-
### TUI modules (`crates/ein-tui/src/`)
305
+
### TUI modules (`ein/src/`)
306
306
307
307
| File | Role |
308
308
|------|------|
···
329
329
330
330
## Releasing
331
331
332
-
Releases are fully automated via CI using [cargo-dist](https://axodotdev.github.io/cargo-dist/). Only the `crates/ein` meta-package is distributed โ it includes both the `ein-tui` and `eind` binaries.
332
+
Releases are fully automated via CI using [cargo-dist](https://axodotdev.github.io/cargo-dist/).
333
333
334
334
**1. Bump the version**
335
335
+3
-3
crates/ein-tui/Cargo.toml
ein/Cargo.toml
+3
-3
crates/ein-tui/Cargo.toml
ein/Cargo.toml
···
1
1
[package]
2
-
name = "ein-tui"
2
+
name = "ein"
3
3
version.workspace = true
4
4
edition.workspace = true
5
5
authors.workspace = true
···
8
8
homepage.workspace = true
9
9
10
10
[lib]
11
-
name = "ein_tui"
11
+
name = "ein"
12
12
path = "src/lib.rs"
13
13
14
14
[[bin]]
···
23
23
crossterm = { version = "0.28", features = ["event-stream"] }
24
24
notify = "6"
25
25
dirs = "6.0.0"
26
-
ein-proto = { path = "../ein-proto" }
26
+
ein-proto = { path = "../crates/ein-proto" }
27
27
ratatui = { version = "0.29", features = ["unstable-rendered-line-info"] }
28
28
serde = { workspace = true }
29
29
serde_json = { workspace = true }
crates/ein-tui/src/app.rs
ein/src/app.rs
crates/ein-tui/src/app.rs
ein/src/app.rs
+20
-20
crates/ein-tui/src/bootstrap.rs
ein/src/bootstrap.rs
+20
-20
crates/ein-tui/src/bootstrap.rs
ein/src/bootstrap.rs
···
249
249
250
250
let plist = format!(
251
251
r#"<?xml version="1.0" encoding="UTF-8"?>
252
-
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
253
-
<plist version="1.0">
254
-
<dict>
255
-
<key>Label</key>
256
-
<string>{LAUNCH_AGENT_LABEL}</string>
257
-
<key>ProgramArguments</key>
258
-
<array>
259
-
<string>{bin}</string>
260
-
</array>
261
-
<key>RunAtLoad</key>
262
-
<true/>
263
-
<key>KeepAlive</key>
264
-
<true/>
265
-
<key>StandardOutPath</key>
266
-
<string>{log}</string>
267
-
<key>StandardErrorPath</key>
268
-
<string>{log}</string>
269
-
</dict>
270
-
</plist>
271
-
"#,
252
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
253
+
<plist version="1.0">
254
+
<dict>
255
+
<key>Label</key>
256
+
<string>{LAUNCH_AGENT_LABEL}</string>
257
+
<key>ProgramArguments</key>
258
+
<array>
259
+
<string>{bin}</string>
260
+
</array>
261
+
<key>RunAtLoad</key>
262
+
<true/>
263
+
<key>KeepAlive</key>
264
+
<true/>
265
+
<key>StandardOutPath</key>
266
+
<string>{log}</string>
267
+
<key>StandardErrorPath</key>
268
+
<string>{log}</string>
269
+
</dict>
270
+
</plist>
271
+
"#,
272
272
LAUNCH_AGENT_LABEL = LAUNCH_AGENT_LABEL,
273
273
bin = bin.display(),
274
274
log = log.display(),
crates/ein-tui/src/config.rs
ein/src/config.rs
crates/ein-tui/src/config.rs
ein/src/config.rs
crates/ein-tui/src/connection.rs
ein/src/connection.rs
crates/ein-tui/src/connection.rs
ein/src/connection.rs
crates/ein-tui/src/input.rs
ein/src/input.rs
crates/ein-tui/src/input.rs
ein/src/input.rs
+2
-2
crates/ein-tui/src/lib.rs
ein/src/lib.rs
+2
-2
crates/ein-tui/src/lib.rs
ein/src/lib.rs
···
3
3
4
4
//! Ein TUI library.
5
5
//!
6
-
//! Exposes [`run`] so both the standalone `ein-tui` binary and the `ein`
6
+
//! Exposes [`run`] so both the standalone `ein` binary and the `ein`
7
7
//! meta-package binary can share the same entry-point without duplicating code.
8
8
9
9
mod app;
···
96
96
None
97
97
};
98
98
99
-
info!(server_addr = %args.server_addr, "ein-tui starting");
99
+
info!(server_addr = %args.server_addr, "ein starting");
100
100
101
101
// In release builds: download eind if absent, then register it as a
102
102
// system service. Runs before raw mode so stdout is visible for progress.
+2
-2
crates/ein-tui/src/main.rs
ein/src/main.rs
+2
-2
crates/ein-tui/src/main.rs
ein/src/main.rs
crates/ein-tui/src/render.rs
ein/src/render.rs
crates/ein-tui/src/render.rs
ein/src/render.rs
History
7 rounds
0 comments
mstallmo.com
submitted
#6
1 commit
expand
collapse
Rename
ein-tui to ein. Move from crates/ directory to top level project directory.
merge conflicts detected
expand
collapse
expand
collapse
- CLAUDE.md:4
- Cargo.lock:970
- Cargo.toml:1
- README.md:4
expand 0 comments
mstallmo.com
submitted
#5
1 commit
expand
collapse
Rename
ein-tui to ein. Move from crates/ directory to top level project directory.
expand 0 comments
mstallmo.com
submitted
#4
1 commit
expand
collapse
Rename
ein-tui to ein. Move from crates/ directory to top level project directory.
expand 0 comments
mstallmo.com
submitted
#3
1 commit
expand
collapse
Rename
ein-tui to ein. Move from crates/ directory to top level project directory.
expand 0 comments
mstallmo.com
submitted
#2
1 commit
expand
collapse
Rename
ein-tui to ein. Move from crates/ directory to top level project directory.
expand 0 comments
mstallmo.com
submitted
#1
1 commit
expand
collapse
Rename
ein-tui to ein. Move from crates/ directory to top level project directory.
expand 0 comments
mstallmo.com
submitted
#0
1 commit
expand
collapse
Rename
ein-tui to ein. Move from crates/ directory to top level project directory.