English · Deutsch · Español · Français · 日本語 · 한국어 · Português (Brasil) · 简体中文
The AI workspace that builds things you keep, with your keys, on your machine.
Conduit is an open-source desktop app for working with large language models. Bring your own key for any of seventeen providers, or run a local model with Ollama or LM Studio, and ask for things you can keep: a personal app that pulls live data, a slide deck you edit by asking, an answer cited from your own documents, a research report whose every finding is checked against the page it came from, a workflow that runs on a schedule or when something new arrives, and stops to ask. Connect your tools over MCP: tools that change things, and every site a page wants to reach, ask you first.
Everything lives on your disk: chats, documents, apps and decks, in a local SQLite database with optional encryption at rest. There is no Conduit account, no backend and no telemetry. Built on Tauri 2 with a Rust core and a React interface.
The screenshots follow one example: the team behind Ferry, a made-up open-source sync app built with Rust and Tauri.
Ask for a tool and you get a working page: a dashboard, a converter, a tracker, a game. Save as app (in the page's ⋯ menu) keeps it as a personal app you open from Apps on the rail, and it keeps working after you delete the chat. The dashboard above is one: it calls the GitHub API live, after asking once for that site.
Personal apps can do three things a plain page in a sandbox can't, each declared by the page and checked by Conduit:
- Keep data between launches: a small store per app (up to 5 MB), kept with the rest of your data and encrypted when encryption at rest is on.
- Take settings: a page declares a few inputs, like a repo or a city, and Conduit draws the form. Changing them updates the running app.
- Ask your AI model, after you allow it for that page. The prompt names the provider and says plainly when text would leave your device; the page gets text back and nothing else: no tools, chat history, memory or documents.
Every personal app has its own Settings page: which model answers it, tokens per day with a daily limit for cloud models (100,000 by default; models on your computer are never limited), its saved data key by key with Export and Clear, the sites and providers it may use, and a week of one-line activity records, never prompts, replies or saved values. Eight starter apps come built in, from a Pomodoro timer to a live weather dashboard.
Describe the story, or ask for a deck in any chat. The assistant drafts a storyline for you to approve, then builds one live deck: every change edits that deck instead of producing yet another copy of the file. The deck opens in a studio with the slide large in the middle and the chat beside it.
- Targeted changes. Ask for a change and the assistant edits one slide, or swaps a word across the deck. History keeps a version for every change, labelled by your request.
- Built to fit. The assistant fills in each layout's parts and the app lays them out, drawing charts from the numbers, so text fits the slide and axes and labels are right. After each change it checks the slides it touched and fixes what doesn't fit.
- Script shows every word of the deck as one document. Type there, or double-click text on a slide; text you write is kept when the assistant rewrites a slide, unless you ask it to change that text.
- Themes: two built in, plus any theme the assistant designs for you.
- Present full screen, with a separate presenter window (current and next slide, speaker notes, a timer) to keep private while you share the slides.
- Export as a single HTML file that presents itself in any browser, or as a PDF (Windows).
| Script: every word of the deck as one document | The presenter window: next slide, notes, timer |
|---|---|
Documents holds collections of your files (plain text, Markdown, CSV, Word and PDF), or drop files on the window outside a chat. Attach a collection to a chat and the assistant searches it while it answers; the documents it drew on are named with the reply, and clicking one shows the exact passage. Retrieval is hybrid: semantic search for passages that mean the same thing, keyword search for exact terms like error codes and names.
For one file, attach it to the message instead: drop a PDF, Word, text or CSV file on the chat, or pick it with +. Every model reads its text; models that read PDFs themselves (Claude, OpenAI, Gemini) get the PDF, charts and scans included. The document's text, or the PDF, goes to the chat's provider with the message.
A collection's PDFs are read on your machine. Indexing sends a document's text to the provider that embeds the collection, so you are asked before the first document goes to each provider, and you can withdraw that consent at any time. With local-only mode on, a collection needs a local provider such as Ollama.
For a question that needs more than a quick search, turn on Research in the composer's + menu (or pick it on Home). It first proposes a brief: the sub-questions it will answer, a scope and a depth (Quick, Standard or Deep, each with its search, page and time limits), which you edit and approve. Then it searches, reads the pages in full, web pages and PDFs alike, and pulls out facts, each with the exact words that support it. A fact counts only if those words are really on the page; the app checks that, not the model. It searches again for what is still unanswered, then writes a report into the chat's documents: a summary, findings per sub-question, open questions, and numbered sources, with every finding cited. Each source is rated for credibility, and a weak one is flagged rather than presented as established fact. Page text only ever reaches a model call that has no tools, so a page that tries to give instructions can't make it search, fetch or save anything.
Writing is for long pieces: blog posts, technical docs, reports and newsletters. Describe what you're writing and the assistant proposes an outline (the sections, what each must say, a target length) that you edit and approve. Then it writes the draft section by section into a Markdown editor beside the chat. It can draw on the web, your document collections or a finished Research report, linking each fact to its source and marking anything it can't source as a TODO instead of making it up. Ask for a change and only that part is rewritten, or select text for Rewrite, Shorter, Clearer and more. Text you write yourself stays word for word, History keeps every version, and a draft exports as Markdown or HTML.
Workflows run routines for you. A step can fetch pages, search the web, run Research, search your Documents, read files from the workflow's own folder and turn CSV or JSON into tables, or call a read-only tool from a connector. Others summarise with a model chosen per workflow or per step, continue only if something changed, update a saved deck or draft, export a file, notify you, save a document, or suggest a memory.
Start from a ready-made workflow, describe what you want in your own words and let the model draft it, or save a chat as a workflow. Run it now, on a schedule, or when a new post appears in a feed or a new file lands in its folder. Turning automatic runs on first lists everything the workflow will be allowed to do on its own, for you to approve, and a run that needs more pauses and asks.
Add a connector by searching the official MCP registry, pasting a remote server's URL, or running a local command. Local stdio and remote streamable-HTTP servers run under a supervisor with restart backoff, a concurrency cap and per-call timeouts. Tool calls show inline, results are redacted and size-capped, and a tool asks before it runs unless its server marks it read-only; you can remember an approval for one chat or always, and review those approvals on the Connectors page.
A server's prompts and resources are reachable from the composer too, not only its tools: the prompt picker fills in a prompt's arguments, and the resource picker attaches a document to the next message.
The app opens on Home. One box starts anything: ask for a deck and Slides
opens with a storyline; anything else starts a chat. Below it, Needs you
lists workflow approvals, workflow questions and memory suggestions waiting on
you, Pick up where
you left off shows your latest chats, decks and apps, and every area of the
app sits in a tile with a live count, or an example to try while it is empty.
Ctrl+1 to Ctrl+9 (⌘ on macOS) jump to each area, and the command palette
(Ctrl+K) has a "Go to" entry for each.
Pick any model you have set up from the composer: Anthropic, OpenAI, Gemini, OpenRouter, OpenCode Zen, Groq, DeepSeek, Mistral, xAI, Z.ai, Moonshot AI, Qwen, Together AI, Fireworks AI, LM Studio, Ollama, or any OpenAI-compatible endpoint. When a chat nears the model's context window, older turns are summarised automatically so it keeps going.
Web search works on any model with no setup. OpenAI, Gemini, Anthropic and OpenRouter use their own built-in search; every other model searches through Exa, which needs no key, or a service you choose (Tavily, Brave or your own SearXNG), with a link in Settings to get a key. Allowed and blocked domain lists narrow it, and sources show with the answer and in the inspector.
The + in the composer attaches files (images and documents) and adds web search, a workspace folder the assistant can read and edit, document collections, skills and connector prompts. While a turn runs you can queue a follow-up or interrupt and steer it. Tool calls, searches and sites appear in the inspector's Activity tab with timings, and what an answer drew on in Sources.
Library keeps the prompts you reuse, in folders and with tags. A prompt can
have {{variables}} you fill in when you insert it into the composer. Its
Skills tab holds SKILL.md skill packages: instructions and files the
assistant loads for a chat when you add the skill.
Memory holds facts the assistant keeps in mind across every chat. It can propose something to remember during a chat, but a proposal waits for you and is never used until you save it. The list is yours to read, edit, pin as core or delete, and one switch stops saved memory being added to chats at once. Memory is encrypted on disk.
On OpenAI, Gemini and OpenRouter, ask for a picture and you get one, saved with the chat and shown in the side panel. Images are stored locally, not linked from the provider, so they don't vanish when a remote URL expires. Each image is billed, so Conduit asks once before the first one.
Model-generated code, HTML, JSON and Markdown open in a side panel with preview
and source views. HTML renders in a null-origin sandboxed iframe with
connect-src 'none'; it cannot reach the network or the app on its own. A page
that calls fetch() shows a banner naming the site, and you allow it this once,
always for that page, or not at all. The globe in the panel header lists every
site and request. Long documents are built section by section, a turn that runs
out of time offers Continue building, and revisions change only the part
that differs.
One design in two modes (dark, light, or following your system), with a main colour you can pick per mode. The interface is available in English, German, Spanish, French, Japanese, Korean, Brazilian Portuguese and Simplified Chinese; dates, numbers and file sizes follow the language you pick.
- A base URL for each provider where it makes sense (xAI, Z.ai, Moonshot AI, Qwen, Together AI, Fireworks AI, Anthropic and OpenAI) for regional or self-hosted endpoints, a compatible API or a LiteLLM proxy.
- First-run setup covers language, theme, text size, local-only mode, key storage, update checks and diagnostics.
- Ideas: a page of things to try, each starting a chat with the prompt filled in, chosen on your device from what you've tried.
- Conversations can be pinned, archived, filed in folders and exported; the chat list shows which chat is running or needs you.
- Vision attachments, Mermaid diagrams and KaTeX maths in replies.
- Usage & Cost counts every model call, priced from a bundled catalog, OpenRouter's listed prices and your own overrides, with an optional daily spend alert. A per-chat reasoning effort setting, and a model menu you can search.
- Settings search and a keyboard shortcuts sheet (
Ctrl+/,⌘/on macOS). - White-label branding: a name, mark and colours from a
brand.md.
See CHANGELOG.md for everything in each release.
- The interface never sees your API key. Keys live in the OS keychain;
settings hold only a
keychain://conduit/<provider>reference, and every network call happens in Rust. This is enforced by the architecture; seedocs/architecture/foundation-contracts.md. - Everything asks first. Each site a page wants to reach, each side-effecting tool call, each scheduled workflow's permissions, each provider that indexes your documents and the first billed image.
- Optional encryption at rest. AES-256-GCM over attachment and artifact
blobs and several database columns, with a master key wrapped in the OS
keychain. It is off by default (
AppSettings.encryption_at_rest) and does not cover message content yet. It never silently downgrades: if the key is unavailable and encrypted data exists, the app refuses to start rather than fall back to plaintext. - Local-only mode refuses cloud providers entirely, so only a local model such as Ollama or LM Studio can answer.
- No telemetry. Update checks are opt-in and send only
Conduit-Updater/<version>. Checking is manual by default; background checking and install-on-quit are opt-in, and Conduit never restarts itself.
v1.0.0-rc.10 — release candidate. Installers for Windows, macOS (Apple silicon and Intel) and Linux are on the releases page. They are not OS-code-signed, so the first launch shows a Gatekeeper or SmartScreen warning. Building from source works too.
This is a release candidate for 1.0: everything below works, and what's left is checking it on real installs before calling it final.
| Area | State |
|---|---|
| Provider streaming (17 providers, cancellation, normalization) | Working |
| Local SQLite persistence, migrations, encryption at rest | Working |
| MCP connector runtime (stdio and streamable HTTP, consent, supervision) | Working |
| Artifacts — create, render, edit, export | Working |
| Multi-round agent loop with tool results | Working |
| Agent run-control — follow-up queue, interrupt/steer, per-tool approval memory | Working |
| Context gauge with automatic compaction | Working |
Skills (SKILL.md) and user-approved encrypted memory |
Working |
| Conversation pin, archive and folders | Working |
| Image and document attachments (PDF, Word, text, Markdown, CSV), Mermaid/KaTeX, conversation export | Working |
| Usage & Cost — every model call, catalog and listed prices with overrides, daily spend alert | Working |
| Web search (hosted OpenAI/Gemini/Anthropic/OpenRouter + Exa, Tavily, Brave, SearXNG) | Working |
| Knowledge base — document collections with hybrid retrieval and citations | Working |
| Research — approved brief, reads web pages and PDFs, quote-checked claims, rated sources, reviewed and cited report | Working |
| Writing — approved outline, section-by-section drafts, sourced facts, your text kept, history, Markdown/HTML export | Working |
| Image generation (OpenAI, Gemini, OpenRouter) | Working |
| MCP prompts and resources in the composer | Working |
| One design in dark and light, with a main-colour setting | Working |
| Workflows — ready-made, custom or drafted from a description; run now, on a schedule, or on a new feed post or file; a model per step; Research, Documents and read-only connector steps; with approval | Working |
| Personal apps — save a page, eight starter apps, per-app storage, settings, model access and usage limits | Working |
| Slides — storyline, one live deck built from layout parts, charts drawn from data, a layout check after each change, Script, history, themes, presenter window | Working |
| Slides export — HTML on every platform, PDF on Windows | Working |
Home — ask box, needs-you, pick up, area tiles, Ctrl+1…9 navigation |
Working |
| Interface in eight languages | Working |
| Update/packaging pipeline, with opt-in automatic updates | Working — 1.0.0-rc.10 built, signed and published on all four targets; the updater itself is not yet verified by a real install |
| OS code-signing | Not done — bundles are unsigned |
| Cloud sync / accounts | Not planned in this repository |
- macOS: a page can open a WebRTC connection. A page's content security policy doesn't cover WebRTC, so on macOS a page's script could reach a host through STUN/TURN even when it has no network permission. Windows and Linux block it in the webview itself; macOS has no webview setting for it, so there only the page's own script removes it, which isn't a boundary. Open HTML pages and apps you got from someone else with care on macOS.
- Going back to rc.2 or earlier starts with an empty database. rc.3 added to the local database for Slides; an older version can't read it and starts fresh (the old file is kept as a backup).
- Node 22+ and pnpm 10.34.4 (
corepack enable && corepack prepare pnpm@10.34.4 --activate) - Rust stable (rustup) —
rust-toolchain.tomlpins the channel - Platform toolchain:
- Windows — Visual Studio 2022 Build Tools with the C++ workload. Run
./check-setup.ps1to verify. - macOS — Xcode Command Line Tools (
xcode-select --install), macOS 11+. - Linux —
sudo apt-get install -y libwebkit2gtk-4.1-dev libgtk-3-dev \ libayatana-appindicator3-dev librsvg2-dev patchelf build-essential libssl-dev
- Windows — Visual Studio 2022 Build Tools with the C++ workload. Run
git clone https://github.com/runningpixels/conduit
cd conduit
pnpm install
pnpm dev # Vite on :5173, then the Tauri shellpnpm build produces a release bundle. On first launch, onboarding asks for a
provider key (or point it at a local Ollama instance, which needs no key).
cargo fmt --all --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace # Rust unit + integration tests
pnpm -C packages/config-schema check # schema-drift gate
pnpm -C apps/desktop check # tsc -b
pnpm -C apps/desktop test # renderer testsEverything is under one per-user directory resolved by directories::ProjectDirs:
| Platform | Path |
|---|---|
| Windows | %LOCALAPPDATA%\Conduit\Conduit\data |
| macOS | ~/Library/Application Support/com.Conduit.Conduit |
| Linux | ~/.local/share/conduit |
It contains settings.json, conduit.sqlite, and the attachments/,
artifacts/, exports/, logs/, diagnostics/, updates/ and streams/
folders. API keys are not there — they are in the OS keychain. Deleting that
directory resets the app completely.
A polyglot monorepo: a Cargo workspace and a pnpm workspace sharing one root.
apps/desktop/ Tauri app — src/ (React renderer) + src-tauri/ (Rust backend)
crates/provider-core/ Provider-agnostic LLM abstraction, adapters, the trust boundary
crates/mcp-runtime/ MCP transport + protocol core (stdio and streamable HTTP)
packages/config-schema/ Generated TS mirror of the Rust schema (@conduit/config-schema)
packages/ui/ Design tokens, primitives, bundled fonts (@conduit/ui)
The invariant everything else follows: the renderer presents state and intent only; Rust owns secrets, persistence, and privileged operations. A chat turn:
React ChatView
└─ ipc/client.startChatStream(ProviderRequest, onEvent)
└─ Tauri invoke('start_chat_stream', { request, channel }) ← per-request Channel
└─ StreamManager
├─ provider_core::get_adapter(active_provider)
├─ build_adapter_context (key from keychain, base URL from settings)
├─ adapter.stream_chat(request, ctx, CancellationToken)
└─ per ProviderEvent: append to the event log (one txn) → channel.send
Renderer: streamState.ts folds ProviderEvents into AssistantStreamState and renders it
Persistence is an append-only event log plus a materialized message view, with
view == fold(events) as a checked invariant — the view is rebuilt from the log
on drift or crash recovery.
crates/provider-core/src/schema.rs is the single source of truth for on-wire
types; packages/config-schema/src/generated/ is generated from it by ts-rs and
CI fails if the two drift. Never hand-edit the generated bindings.
docs/project-overview.md— how the pieces fit togetherdocs/architecture/foundation-contracts.md— the trust boundarydocs/adr/— nine architecture decision recordsdocs/schemas/internal-models.md— canonical data shapesdocs/postmortems/— incident write-upsdocs/release/,docs/support/runbook.md— operations
Contributions are welcome — see CONTRIBUTING.md.
Note: Conduit requires contributors to sign a Contributor License Agreement so the project can continue to be offered under both the AGPL and a commercial license. The CLA bot will prompt you on your first pull request.
Please do not open public issues for vulnerabilities. See
SECURITY.md for private disclosure.
Copyright (C) 2026 Emilio Olivares. Licensed under the GNU AGPL v3.0 only.
If you run a modified version as a network service, AGPL section 13 requires you
to offer its source to users. Conduit is a local desktop app, so this does not
apply to normal use. See LICENSING.md for scope, the section
7 OpenSSL permission, and commercial-licensing terms;
NOTICE for third-party attributions.
Built with Tauri, React, sqlx and rustls. Typeset in Schibsted Grotesk and JetBrains Mono, both OFL-1.1. Syntax highlighting by Prism.