From b6a8a72fa88cab03db37d1e65a07dfefefd8330b Mon Sep 17 00:00:00 2001 From: Seto Elkahfi <1797197+setoelkahfi@users.noreply.github.com> Date: Mon, 2 Nov 2026 11:47:57 +0100 Subject: [PATCH 1/2] Release 1.4.0: bump the workspace Minor release: ed-acp-tauri gains the external stdio agent and the ed-claude crate is new. The release skill now lists both crates in the pin list and explains how to publish a new crate's first version. Co-Authored-By: Claude Sonnet 5.5 --- .agents/skills/release/SKILL.md | 21 +++++++++++++++++++++ Cargo.lock | 20 ++++++++++---------- Cargo.toml | 18 +++++++++--------- 3 files changed, 40 insertions(+), 19 deletions(-) diff --git a/.agents/skills/release/SKILL.md b/.agents/skills/release/SKILL.md index d68e736..a482e5c 100644 --- a/.agents/skills/release/SKILL.md +++ b/.agents/skills/release/SKILL.md @@ -31,9 +31,11 @@ explicitly: ed-agent = { version = "X.Y.Z", path = "crates/ed-agent" } ed-mcp = { version = "X.Y.Z", path = "crates/ed-mcp" } ed-acp = { version = "X.Y.Z", path = "crates/ed-acp" } +ed-acp-tauri = { version = "X.Y.Z", path = "crates/ed-acp-tauri" } ed-acp-tui = { version = "X.Y.Z", path = "crates/ed-acp-tui" } ed-acp-testkit = { version = "X.Y.Z", path = "crates/ed-acp-testkit" } ed-onde-account = { version = "X.Y.Z", path = "crates/ed-onde-account" } +ed-claude = { version = "X.Y.Z", path = "crates/ed-claude" } ``` Bump all of these together. The crate manifests under `crates/*/Cargo.toml` @@ -146,6 +148,25 @@ here — this is the safety net for step 6. release URL + checksum, copies the generated `ed_agent_ffi.swift`, commits, pushes to `ed-swift` `main`, and tags it `vX.Y.Z`. +## Adding a new crate + +crates.io only allows a trusted publisher on a crate that already exists +(RFC 3691), so a new crate's first version goes up by hand, before the tag that +would publish it: + +1. Create a token with scope `publish-new` only, crate pattern set to the new + crate, expiry 1 day. Keep it in `CARGO_REGISTRY_TOKEN` for one command; never + write it to `~/.cargo/credentials.toml`. +2. Publish the first version. If the crate needs an API that the last published + `ed-acp` lacks, it won't compile against the registry, so publish a + placeholder `0.0.1` (empty `lib.rs`, same license and metadata) from a + scratch directory. A caret requirement such as `"1.4"` never selects it. +3. Revoke the token. +4. On the crate's Settings → Trusted Publishing, add a GitHub publisher: owner + `ondeinference`, repository `ed`, workflow `release-sdk-rust.yml`, and the + same environment as `ed-acp`. Check the owners match `ed-acp`'s. +5. Tag as usual. The real crate then publishes through OIDC. + ## Manual / recovery runs Both workflows have a `workflow_dispatch` with a `publish` boolean and a diff --git a/Cargo.lock b/Cargo.lock index 7a4298f..8f1a211 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1995,7 +1995,7 @@ checksum = "e1d926b4d407d372f141f93bb444696142c29d32962ccbd3531117cf3aa0bfa9" [[package]] name = "ed-acp" -version = "1.3.5" +version = "1.4.0" dependencies = [ "agent-client-protocol", "anyhow", @@ -2018,7 +2018,7 @@ dependencies = [ [[package]] name = "ed-acp-tauri" -version = "1.3.5" +version = "1.4.0" dependencies = [ "agent-client-protocol", "ed-acp", @@ -2034,7 +2034,7 @@ dependencies = [ [[package]] name = "ed-acp-testkit" -version = "1.3.5" +version = "1.4.0" dependencies = [ "serde_json", "tokio", @@ -2043,7 +2043,7 @@ dependencies = [ [[package]] name = "ed-acp-tui" -version = "1.3.5" +version = "1.4.0" dependencies = [ "agent-client-protocol", "anyhow", @@ -2055,7 +2055,7 @@ dependencies = [ [[package]] name = "ed-agent" -version = "1.3.5" +version = "1.4.0" dependencies = [ "async-trait", "futures-core", @@ -2069,7 +2069,7 @@ dependencies = [ [[package]] name = "ed-agent-ffi" -version = "1.3.5" +version = "1.4.0" dependencies = [ "async-trait", "cc", @@ -2084,7 +2084,7 @@ dependencies = [ [[package]] name = "ed-agent-tauri" -version = "1.3.5" +version = "1.4.0" dependencies = [ "async-trait", "ed-agent", @@ -2098,7 +2098,7 @@ dependencies = [ [[package]] name = "ed-claude" -version = "1.3.5" +version = "1.4.0" dependencies = [ "agent-client-protocol", "anyhow", @@ -2113,7 +2113,7 @@ dependencies = [ [[package]] name = "ed-mcp" -version = "1.3.5" +version = "1.4.0" dependencies = [ "agent-client-protocol", "anyhow", @@ -2132,7 +2132,7 @@ dependencies = [ [[package]] name = "ed-onde-account" -version = "1.3.5" +version = "1.4.0" dependencies = [ "axum", "reqwest 0.13.5", diff --git a/Cargo.toml b/Cargo.toml index 9d3fae9..5787b6b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ members = [ # Shared across every crate in the workspace so a release moves one number. # `sync-version` tooling (see the Makefile) reads these. [workspace.package] -version = "1.3.5" +version = "1.4.0" edition = "2021" rust-version = "1.94" license = "MIT OR Apache-2.0" @@ -60,14 +60,14 @@ directories = "6" base64 = "0.23" # Internal -ed-agent = { version = "1.3.5", path = "crates/ed-agent" } -ed-mcp = { version = "1.3.5", path = "crates/ed-mcp" } -ed-acp = { version = "1.3.5", path = "crates/ed-acp" } -ed-acp-tauri = { version = "1.3.5", path = "crates/ed-acp-tauri" } -ed-acp-tui = { version = "1.3.5", path = "crates/ed-acp-tui" } -ed-acp-testkit = { version = "1.3.5", path = "crates/ed-acp-testkit" } -ed-onde-account = { version = "1.3.5", path = "crates/ed-onde-account" } -ed-claude = { version = "1.3.5", path = "crates/ed-claude" } +ed-agent = { version = "1.4.0", path = "crates/ed-agent" } +ed-mcp = { version = "1.4.0", path = "crates/ed-mcp" } +ed-acp = { version = "1.4.0", path = "crates/ed-acp" } +ed-acp-tauri = { version = "1.4.0", path = "crates/ed-acp-tauri" } +ed-acp-tui = { version = "1.4.0", path = "crates/ed-acp-tui" } +ed-acp-testkit = { version = "1.4.0", path = "crates/ed-acp-testkit" } +ed-onde-account = { version = "1.4.0", path = "crates/ed-onde-account" } +ed-claude = { version = "1.4.0", path = "crates/ed-claude" } # gemm-common (via candle, via onde) depends on sysctl for every # `target_vendor = "apple"`, but sysctl 0.6.0 only has a `sys` module behind From 42751e60f777c814dfeaacd28a2fd337fe204d3c Mon Sep 17 00:00:00 2001 From: Seto Elkahfi <1797197+setoelkahfi@users.noreply.github.com> Date: Mon, 2 Nov 2026 12:05:32 +0100 Subject: [PATCH 2/2] Slim the README to match our other repos Cut the pitch essay, showcase list, API walkthrough and crate tables. Add badges, an install section and a "Use it your way" list that now covers ed-acp-tauri and ed-claude. The quick start no longer pins a version. The API detail lives in crates/ed-agent/README.md. Co-Authored-By: Claude Sonnet 5.5 --- README.md | 142 +++++++++++++++++++++++++++--------------------------- 1 file changed, 71 insertions(+), 71 deletions(-) diff --git a/README.md b/README.md index fba4de1..cd36d1f 100644 --- a/README.md +++ b/README.md @@ -1,52 +1,41 @@ -# Ed - -**Embed Ed.** Your app gets a brain. Your users keep their data. - -Ed is an agent you drop into an application. It loads an open-weights model, -keeps the conversation, calls only the host tools you register, and hands back -replies. The model runs on the user's device — there is no metered inference -API and private context does not need to leave the device. - -## Why it exists - -Seven applications needed the same thing: load a model, know whether it's ready, -keep a conversation, hand back a reply. Seven times somebody wrote it again. Two -of them ended up byte-identical in three files. - -None of that code was interesting. It was the wiring between an inference engine -that reports status by polling and a user interface that needs to be told — -plus the flattening of `Result` into one payload a view can -render either way. Ed is that layer, written once. - -It deliberately doesn't own sessions, persistence, model catalogues, or -downloads. Those differ per application and stay yours. - -## Onde runs the model. Ed makes it a feature. - -[Onde](https://ondeinference.com) is the inference engine: weights, quantisation, -Metal and CPU backends, tokens out. Ed is the part above it your users touch. - -## See it live +

+ Onde Inference +

+ +

Ed

+ +

+ Embed Ed. Your app gets a brain. Your users keep their data. +

+ +

+ ed-agent on crates.io + ed-acp on crates.io + Swift + CI + License +

+ +Ed is the agent layer above [Onde](https://ondeinference.com). It loads an +open-weights model, keeps the conversation, calls only the host tools you +register and hands back replies. The model runs on the user's device, so there +is no metered inference API and private context stays put. The `ed-acp` crates +build ACP agents (Onde Code, SplitFire Agent, siGit) on the same base. + +Ed doesn't own sessions, persistence, model catalogues or downloads. Those +differ per application and stay yours. + +## Install + +```sh +cargo add ed-agent # embedded chat +cargo add ed-acp # ACP agent +``` -- **[smbCloud MailX](https://smbcloudmail.com/en-us)** — siMail drafts replies, - summarises long threads, and helps triage the inbox. The mail never leaves the - machine to get read. -- **[Siti AI](https://github.com/getsigit/siti)** — a private assistant for - macOS, iOS, and Android, and the open reference app: its source is public, so - it's the codebase to read for a full integration. -- **[Pepak Basa Jawa Komplit](https://apps.apple.com/se/app/pepak-basa-jawa-komplit/id6752241812)** - — Joko, a Javanese tutor who answers offline, which matters where the app is - used. -- **[Rumi Learn Persian](https://apps.apple.com/se/app/rumi-l%C3%A4r-dig-persiska/id6753832408)** - — Rumi, a Persian tutor, same model, same device. +For Swift, add the package from [`ondeinference/ed-swift`](https://github.com/ondeinference/ed-swift). ## Quick start -```toml -[dependencies] -ed-agent = "1.2" -``` - ```rust use ed_agent::{Ed, GgufModelConfig}; @@ -57,39 +46,50 @@ let reply = ed.send("Summarise this thread.").await; println!("{}", reply.reply.unwrap_or_default()); ``` -Stream a reply with `Ed::stream` (plain chat) or let `Ed::run` forward deltas to -`EventSink::text_delta`. `Ed::restore_history` loads a saved conversation, -`Ed::generate` is a one-shot call that leaves the history alone, and -`Ed::set_system_prompt` / `set_sampling` change the model's settings. These -three need a loaded model. Persistence stays yours; implement `SessionStore` -over whatever you already have. +Streaming, history, tools and approvals are covered in [`crates/ed-agent`](crates/ed-agent). -Construct with `Ed::with_agent` to provide the executor for registered tools -and the approval handler for mutating tools. Read-only tools run directly; -mutating tools must receive `AllowOnce` or `AllowForSession` first. +## Use it your way -## Crates +- **In your app:** [`ed-agent`](crates/ed-agent), plus [`ed-agent-tauri`](crates/ed-agent-tauri) for Tauri and [`ed-agent-ffi`](crates/ed-agent-ffi) for Swift. +- **As an ACP agent:** [`ed-acp`](crates/ed-acp) with a `Profile`, and [`ed-acp-tui`](crates/ed-acp-tui) for a terminal UI. +- **Inside a Tauri app:** [`ed-acp-tauri`](crates/ed-acp-tauri) runs an ACP agent in process or an external stdio agent. +- **With Claude:** [`ed-claude`](crates/ed-claude), a profile on the Anthropic API with the user's key. +- **With MCP servers:** [`ed-mcp`](crates/ed-mcp). Onde accounts: [`ed-onde-account`](crates/ed-onde-account). Tests: [`ed-acp-testkit`](crates/ed-acp-testkit). -| Crate | What it's for | -| --- | --- | -| [`ed-agent`](crates/ed-agent) | The agent. No framework dependency. | -| [`ed-agent-ffi`](crates/ed-agent-ffi) | UniFFI bridge used by the Swift XCFramework. | -| [`ed-agent-tauri`](crates/ed-agent-tauri) | Tauri bindings: a sink that emits to the webview, the commands it invokes, and `EdSessions` for apps with a chat history and webview-answered approvals. | +## In production -The Onde Agent Platform crates, for agents that editors drive over the Agent Client Protocol -(ACP). SplitFire Agent is built on them. +[smbCloud MailX](https://smbcloudmail.com/en-us), [Siti AI](https://github.com/getsigit/siti) (the open reference app), +[Pepak Basa Jawa Komplit](https://apps.apple.com/se/app/pepak-basa-jawa-komplit/id6752241812) and +[Rumi](https://apps.apple.com/se/app/rumi-l%C3%A4r-dig-persiska/id6753832408). -| Crate | What it's for | -| --- | --- | -| [`ed-acp`](crates/ed-acp) | An ACP v1 server: sessions, auth, the turn loop on Onde Cloud, tool approval, workspace tools and MCP. A product supplies a `Profile`. | -| [`ed-acp-tui`](crates/ed-acp-tui) | A terminal UI for any ACP agent. | -| [`ed-mcp`](crates/ed-mcp) | MCP client glue over `rmcp`, the official Rust SDK: stdio and streamable HTTP servers, bearer tokens, tool namespacing, timeouts, progress and cancellation. With the `agent` feature, `McpExecutor` serves a toolset to Ed as tools. | -| [`ed-onde-account`](crates/ed-onde-account) | Onde Inference account client: sign in, activate an app and get its Onde Cloud API key through ondeinference.com, with no Onde secrets in the host app. | -| [`ed-acp-testkit`](crates/ed-acp-testkit) | Mock Onde Cloud endpoint, raw ACP client, the ACP registry probe and the ACP v1 conformance suite. | +## Docs -Free the intelligence. +Each crate has its own README: +[`ed-agent`](crates/ed-agent/README.md), +[`ed-agent-tauri`](crates/ed-agent-tauri/README.md), +[`ed-agent-ffi`](crates/ed-agent-ffi), +[`ed-acp`](crates/ed-acp/README.md), +[`ed-acp-tui`](crates/ed-acp-tui/README.md), +[`ed-acp-tauri`](crates/ed-acp-tauri), +[`ed-claude`](crates/ed-claude), +[`ed-mcp`](crates/ed-mcp/README.md), +[`ed-onde-account`](crates/ed-onde-account/README.md), +[`ed-acp-testkit`](crates/ed-acp-testkit/README.md). + +## Contributing + +Open pull requests against `development`. Before you push: + +```sh +cargo fmt --all -- --check && cargo clippy --locked --workspace --all-targets -- -D warnings && cargo test --locked --workspace +``` + +## License + +MIT or Apache-2.0, at your option. See [LICENSE-MIT](LICENSE-MIT) and [LICENSE-APACHE](LICENSE-APACHE). ## Copyright +Free the intelligence. + © 2026 [Onde Inference](https://ondeinference.com). -Licensed under MIT or Apache-2.0.