main
md 125 lines 5.48 KB
Rendered Raw
1 # onde-ed – Agent Instructions
2
3 ## What this repo is
4 `onde-ed` is a **Rust Cargo workspace** providing the embeddable agentic core
5 used across Onde products (macOS, iOS, Tauri, CLI). The workspace is organised
6 into focused crates; do not merge them.
7
8 ---
9
10 ## Crate map
11
12 | Crate | Purpose |
13 |---|---|
14 | `ed-agent` | Core library: `Ed` struct, lifecycle, `send`/`stream`/`run`, tool approval, `EventSink`, `SessionStore` seams |
15 | `ed-acp` | ACP v1 server: `Profile` trait, `serve`/`serve_stdio`, sessions, LLM streaming, tool routing, MCP |
16 | `ed-acp-tauri` | Hosts an `ed-acp` agent in a Tauri app: in-process `serve` over `Channel::duplex`, permission prompts, `fs/*` inside per-session roots, URL-elicitation sign-in via the system browser, session and config-option commands |
17 | `ed-mcp` | MCP integration over `rmcp`: tool namespacing (`mcp__<server>__<tool>`, max 64 bytes), `SharedServer`, `McpExecutor`, timeouts, cancellation |
18 | `ed-acp-tui` | ratatui TUI frontend for ACP agents over stdio |
19 | `ed-acp-testkit` | Mock Onde Cloud endpoint + conformance test suite |
20 | `ed-agent-ffi` | UniFFI bridge → Apple XCFramework (`FfiEd`, `FfiToolExecutor`, `FfiApprovalHandler`, `FfiEventListener`) |
21 | `ed-agent-tauri` | Tauri command bindings that emit events to the webview |
22
23 ---
24
25 ## Non-negotiable architecture rules
26
27 1. **One `Ed` instance, one engine, one model.** `Ed` is `Send + Sync`, not
28 `Clone`. Never try to clone or share it across threads without `Arc`.
29
30 2. **`Profile` is the product seam.** A product crate (or binary) implements
31 `Profile` (`info`, `system_prompt`, `toolsets`, `builtin_mcp_servers`).
32 `ed-acp` handles the ACP server, session management, and LLM glue. Do not
33 put product-specific logic inside `ed-acp`.
34
35 3. **Tool risk gates approval.** `ToolRisk::ReadOnly` vs `ToolRisk::Mutating`
36 determines whether the approval handler is invoked. Per-session grants are
37 tracked via `ApprovalDecision::AllowForSession`. Do not bypass this gate.
38
39 4. **MCP tool names ≤ 64 bytes.** Names are sanitised to
40 `mcp__<server>__<tool>`. Anything longer is truncated. Do not assume the
41 original tool name survived intact.
42
43 5. **FFI types are wrappers, not source of truth.** `FfiEd` delegates to
44 `Ed`; `FfiToolExecutor` bridges a foreign callback into the
45 `ToolExecutor` trait. Keep FFI types thin.
46
47 6. **Tauri and FFI are separate bindings.** `ed-agent-tauri` and
48 `ed-agent-ffi` both wrap `ed-agent` but must not depend on each other.
49 `ed-acp-tauri` is the Tauri host for `ed-acp` agents; it does not depend on
50 `ed-agent-tauri`.
51
52 7. **A product's own sign-in goes through `Profile::auth`.** `ed-acp` knows
53 terminal auth and the `<PREFIX>_*` env file. A product with a browser or
54 session sign-in supplies an `AuthProvider`; do not put its flow in `ed-acp`.
55
56 ---
57
58 ## LLM providers
59
60 Configured via `ed-acp/src/llm.rs`. Three variants: `Onde`, `OpenAi`, `Local`.
61
62 | Env var | Effect |
63 |---|---|
64 | `<PREFIX>_PROVIDER` | `onde` / `openai` / `local` |
65 | `ONDE_API_KEY` | Cloud key for `Onde` provider |
66 | `OPENAI_API_KEY` | Key for `OpenAi` provider |
67
68 Default cloud model: `onde-kkk`.
69 Default local model: `Qwen3-4B` (desktop) / `Qwen3-1.7B` (mobile).
70
71 `LlmEnv` drives config-dir, env-file loading, and variable namespacing per
72 product. Do not hard-code env vars; always go through `LlmEnv`.
73
74 ---
75
76 ## Working in this repo
77
78 ### Before changing anything
79 - Read the relevant `lib.rs` and the trait/struct you are modifying first.
80 - Check whether a public API is re-exported from `ed-agent`'s `lib.rs` before
81 adding a new one; keep the public surface minimal.
82 - If touching `ed-agent-ffi`, remember it must compile for Apple targets
83 (macOS + iOS); avoid anything that does not cross the FFI boundary cleanly.
84
85 ### Making changes
86 - Keep crate boundaries: adding a dependency from a lower-level crate
87 (`ed-agent`) on a higher-level one (`ed-acp`) is forbidden.
88 - New tool definitions belong in the crate that owns the domain, exposed via
89 `ToolExecutor` or MCP server, not inlined into `Ed`.
90 - Prefer `async_trait` + `Arc<dyn Trait>` for seams; avoid generics on `Ed`
91 itself.
92 - When adding an FFI type, add the matching `From<Ffi*>` / `From<*>` impls
93 immediately so both sides stay in sync.
94
95 ### After changes
96 - Run `cargo check --workspace` to catch compile errors across all crates.
97 - Run `cargo test --workspace` before committing.
98 - For FFI changes, note that a full XCFramework build requires the Apple SDK
99 toolchain; CI handles that — local `cargo check` is sufficient to validate
100 Rust correctness.
101
102 ### Branches
103 - Base branch is **`development`**. Open all PRs against `development`, not `main`.
104 - Feature branches: `feature/<short-description>`.
105 - Stacked PRs are fine; always target the parent feature branch, not `development`, when stacking.
106
107 ### Commit messages
108 - Scope to the affected crate(s): `ed-agent: …`, `ed-acp: …`, `ed-mcp: …`.
109 - Keep the subject line under 72 chars.
110 - Always end the commit with:
111 ```
112 Co-Authored-By: siGit Code v1.6.6-acp <noreply@sigit.si>
113 ```
114
115 ---
116
117 ## Things to avoid
118 - Do not add `#[allow(unused)]` blanket suppressions — fix the unused item.
119 - Do not store `tokio::runtime::Runtime` inside an FFI object; use `block_on`
120 only at the outermost FFI boundary.
121 - Do not panic inside async tasks — convert errors to `AgentError` and surface
122 them through the event sink or return type.
123 - Do not hard-code model names anywhere outside `ed-acp/src/llm.rs`.
124 - Do not bypass `ToolRisk` approval for any mutating tool, even in tests — use
125 an `AllowAll` test double instead.