onde-ed – Agent Instructions
What this repo is
onde-ed is a Rust Cargo workspace providing the embeddable agentic core
used across Onde products (macOS, iOS, Tauri, CLI). The workspace is organised
into focused crates; do not merge them.
Crate map
| Crate | Purpose |
|---|---|
ed-agent |
Core library: Ed struct, lifecycle, send/stream/run, tool approval, EventSink, SessionStore seams |
ed-acp |
ACP v1 server: Profile trait, serve/serve_stdio, sessions, LLM streaming, tool routing, MCP |
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 |
ed-mcp |
MCP integration over rmcp: tool namespacing (mcp__<server>__<tool>, max 64 bytes), SharedServer, McpExecutor, timeouts, cancellation |
ed-acp-tui |
ratatui TUI frontend for ACP agents over stdio |
ed-acp-testkit |
Mock Onde Cloud endpoint + conformance test suite |
ed-agent-ffi |
UniFFI bridge → Apple XCFramework (FfiEd, FfiToolExecutor, FfiApprovalHandler, FfiEventListener) |
ed-agent-tauri |
Tauri command bindings that emit events to the webview |
Non-negotiable architecture rules
One
Edinstance, one engine, one model.EdisSend + Sync, notClone. Never try to clone or share it across threads withoutArc.Profileis the product seam. A product crate (or binary) implementsProfile(info,system_prompt,toolsets,builtin_mcp_servers).ed-acphandles the ACP server, session management, and LLM glue. Do not put product-specific logic insideed-acp.Tool risk gates approval.
ToolRisk::ReadOnlyvsToolRisk::Mutatingdetermines whether the approval handler is invoked. Per-session grants are tracked viaApprovalDecision::AllowForSession. Do not bypass this gate.MCP tool names ≤ 64 bytes. Names are sanitised to
mcp__<server>__<tool>. Anything longer is truncated. Do not assume the original tool name survived intact.FFI types are wrappers, not source of truth.
FfiEddelegates toEd;FfiToolExecutorbridges a foreign callback into theToolExecutortrait. Keep FFI types thin.Tauri and FFI are separate bindings.
ed-agent-taurianded-agent-ffiboth wraped-agentbut must not depend on each other.ed-acp-tauriis the Tauri host fored-acpagents; it does not depend oned-agent-tauri.A product's own sign-in goes through
Profile::auth.ed-acpknows terminal auth and the<PREFIX>_*env file. A product with a browser or session sign-in supplies anAuthProvider; do not put its flow ined-acp.
LLM providers
Configured via ed-acp/src/llm.rs. Three variants: Onde, OpenAi, Local.
| Env var | Effect |
|---|---|
<PREFIX>_PROVIDER |
onde / openai / local |
ONDE_API_KEY |
Cloud key for Onde provider |
OPENAI_API_KEY |
Key for OpenAi provider |
Default cloud model: onde-kkk.
Default local model: Qwen3-4B (desktop) / Qwen3-1.7B (mobile).
LlmEnv drives config-dir, env-file loading, and variable namespacing per
product. Do not hard-code env vars; always go through LlmEnv.
Working in this repo
Before changing anything
- Read the relevant
lib.rsand the trait/struct you are modifying first. - Check whether a public API is re-exported from
ed-agent'slib.rsbefore adding a new one; keep the public surface minimal. - If touching
ed-agent-ffi, remember it must compile for Apple targets (macOS + iOS); avoid anything that does not cross the FFI boundary cleanly.
Making changes
- Keep crate boundaries: adding a dependency from a lower-level crate
(
ed-agent) on a higher-level one (ed-acp) is forbidden. - New tool definitions belong in the crate that owns the domain, exposed via
ToolExecutoror MCP server, not inlined intoEd. - Prefer
async_trait+Arc<dyn Trait>for seams; avoid generics onEditself. - When adding an FFI type, add the matching
From<Ffi*>/From<*>impls immediately so both sides stay in sync.
After changes
- Run
cargo check --workspaceto catch compile errors across all crates. - Run
cargo test --workspacebefore committing. - For FFI changes, note that a full XCFramework build requires the Apple SDK
toolchain; CI handles that — local
cargo checkis sufficient to validate Rust correctness.
Branches
- Base branch is
development. Open all PRs againstdevelopment, notmain. - Feature branches:
feature/<short-description>. - Stacked PRs are fine; always target the parent feature branch, not
development, when stacking.
Commit messages
- Scope to the affected crate(s):
ed-agent: …,ed-acp: …,ed-mcp: …. - Keep the subject line under 72 chars.
- Always end the commit with:
Co-Authored-By: siGit Code v1.6.6-acp <noreply@sigit.si>
Things to avoid
- Do not add
#[allow(unused)]blanket suppressions — fix the unused item. - Do not store
tokio::runtime::Runtimeinside an FFI object; useblock_ononly at the outermost FFI boundary. - Do not panic inside async tasks — convert errors to
AgentErrorand surface them through the event sink or return type. - Do not hard-code model names anywhere outside
ed-acp/src/llm.rs. - Do not bypass
ToolRiskapproval for any mutating tool, even in tests — use anAllowAlltest double instead.