Don't be evil.
  • Rust 68.3%
  • TypeScript 22.7%
  • CSS 6.4%
  • JavaScript 2.5%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
axoisaxo 90f507ec9f
Some checks are pending
Quality / quality (push) Waiting to run
Merge branch 'chore/release-v0.2.0'
2026-10-28 00:06:25 +01:00
.github/workflows Add agent quality runtime 2026-10-27 22:54:51 +01:00
docs Update quality report test counts 2026-10-27 22:59:05 +01:00
evals/tasks Add agent quality runtime 2026-10-27 22:54:51 +01:00
scripts Add signed in-app updates 2026-10-27 23:44:20 +01:00
src Add signed in-app updates 2026-10-27 23:44:20 +01:00
src-tauri Resolve sandbox workspace symlinks for macOS checks 2026-10-28 00:02:04 +01:00
tests Add signed in-app updates 2026-10-27 23:44:20 +01:00
updates Publish the 0.2.0 updater manifest 2026-10-28 00:06:13 +01:00
.gitignore Ignore CommandCode data 2026-10-27 23:48:19 +01:00
AGENTS.md Add signed in-app updates 2026-10-27 23:44:20 +01:00
package-lock.json Add terminal, files, and changes tabs to the right panel 2026-10-27 19:43:21 +01:00
package.json Add signed in-app updates 2026-10-27 23:44:20 +01:00
README.md Add signed in-app updates 2026-10-27 23:44:20 +01:00
tsconfig.json Migrate desktop runtime to Rust and Tauri and fix agent lifecycle 2026-10-26 21:30:10 +01:00
tsconfig.web.json Migrate desktop runtime to Rust and Tauri and fix agent lifecycle 2026-10-26 21:30:10 +01:00
vite.config.ts Migrate desktop runtime to Rust and Tauri and fix agent lifecycle 2026-10-26 21:30:10 +01:00

Kolora

A desktop coding agent with a Rust runtime and Tauri 2 shell, plus a React/TypeScript interface. Electron and the Node agent runtime have been removed. Node is used only for frontend development and build tooling.

The Rust backend owns provider streaming, the agent loop, approval gates, session storage, filesystem tools, shell processes, embedded WebKit browser automation, screen captures, and native desktop input.

Requirements

  • macOS or Linux; Windows desktop tools are not supported.
  • A stable Rust toolchain, Node.js 20.19+ (or 22.12+), and npm. Installing skills from the marketplace additionally needs Node.js 22.20+ and npx.
  • On macOS: Xcode command line tools. On Linux: Tauri's GTK/WebKit development libraries, PipeWire development headers (pipewire-devel / libpipewire-0.3-dev), Clang/libclang (clang-devel / libclang-dev, needed by xcap's bindgen step), GBM/EGL/Wayland development headers (mesa-libgbm-devel, mesa-libEGL-devel, wayland-devel / libgbm-dev, libegl-dev, libwayland-dev), and the Secret Service keyring backend. On Fedora: sudo dnf install pipewire-devel clang-devel mesa-libgbm-devel mesa-libEGL-devel wayland-devel. See the Tauri prerequisites.
  • The embedded browser uses WKWebView on macOS and WebKitGTK on Linux. No separate Firefox installation is required.
  • Either a Command Code account/API key, a local Codex installation signed in with ChatGPT, an Inception Labs key, or an API key and a model supporting tool calls through an OpenAI-compatible /chat/completions endpoint. Screenshots also require a vision model.
npm install
npm run dev

Command Code is the default provider. Open Einstellungen → Anbieter to connect a provider: that panel only stores the base URL and the API key. Command Code uses your existing Command Code CLI login (~/.commandcode/auth.json) when available, so it works out of the box; otherwise paste a Command Code API key from Studio.

The model and the reasoning effort are chosen in the composer, in the two pills under the input field. The model pill opens a searchable list of every connected provider's models and switches the provider when you pick a model from another one; the reasoning pill sets Default, Low, Medium, High, or Max for the active provider. Those pills are what the next request actually uses.

Open Einstellungen → ChatGPT / Codex to use your existing local Codex login and ChatGPT plan usage. If necessary, click Mit ChatGPT anmelden and complete the browser login. The account panel keeps the Codex model, reasoning effort, and speed, then Speichern. The account panel displays remaining percentages and reset times from Codex; unavailable usage data is shown explicitly. API-key authentication never counts as a ChatGPT-plan connection.

The integration runs the official codex app-server over private stdio. It finds codex on PATH, in standard Homebrew paths, or bundled inside the ChatGPT/Codex desktop app. Set KOLORA_CODEX if your executable is elsewhere. Credentials and token refresh remain in Codex's credential store; Kolora does not copy access tokens into settings or send them to its React interface. Login is shared with your local Codex clients.

Select Eigene API (OpenAI-kompatibel) in the provider dropdown to keep using the original provider mode, and configure the base URL and key. The model comes from the composer picker, which queries that provider's /models endpoint. API usage has separate provider billing. The launcher also finds standard rustup installations in ~/.cargo/bin when the launching application has an older PATH.

Build and test

npm run build:ui       # TypeScript check and production frontend bundle
npm run build          # production native executable
npm run dist:mac       # macOS DMG (build on macOS)
npm run dist:linux     # Linux AppImage (build on Linux)
npm test               # Node UI tests plus Rust unit and mock-provider tests
npm run test:browser   # native browser integration test; opens an isolated test window
npm run eval           # live evaluation when a key is set; eval:dry validates fixtures
npm run test:codex     # live Codex smoke test; uses one turn of ChatGPT quota
npm run check:rust     # Clippy, including test targets, with warnings treated as errors
npm run sign:mac       # sign src-tauri/target/release/Kolora.app with an Apple Development identity

Keychain approvals survive rebuilds when the app is signed with a stable Apple Development identity; macOS asks once, then remembers the decision.

The browser smoke test opens a local fixture, snapshots controls, types Unicode text and clicks through native WebKit input, verifies trusted click events, scrolling, tabs, history, reload, cancellation, browser screenshots and denial of application RPC from a remote page. It opens an isolated app window and temporary data store; it does not use your browser profile or model quota. The default suite tests file tools including exact-match edits, shell timeouts and cancellation, session persistence, plan-mode tool filtering and write blocking, streamed tool-call assembly, permission denial, remembered approvals within one run, cancelling/resuming a multi-tool conversation, Codex stdio message routing, account-mode detection, and Codex chat resumption. Tests use temporary data directories and a local mock provider; they do not send model API requests.

Updates

Installed release builds check the signed update manifest at updates/latest.json once at startup, within a ten-second timeout. The prompt shows the installed and available versions; Update installieren downloads the platform bundle, verifies its signature, replaces the installed app, and relaunches it. Users do not need Git, Node, or a compiler. Linux updates use the AppImage bundle and macOS updates use the app bundle. Debug builds and release binaries run from their source checkout skip the check.

The Tauri public key is pinned in src-tauri/tauri.conf.json. Keep the private signing key outside the repository, for example at $HOME/.config/kolora/updater-signing.key, and back it up: losing it means existing installs cannot receive future updates. The dismissed version is remembered so the same prompt does not repeat. Turn the check off with Einstellungen → Verhalten → Beim Start nach Updates suchen (checkUpdates in settings.json).

To publish an update:

  1. Bump the version in package.json, src-tauri/Cargo.toml, and src-tauri/tauri.conf.json; update the checked-in updates/latest.json after building.
  2. Build with TAURI_SIGNING_PRIVATE_KEY set to the private key path. Tauri emits the platform updater bundle and a matching .sig file.
  3. Upload the bundle and .sig to the matching v<version> release on the Git host.
  4. Generate the manifest with every released platform, for example:
npm run update-manifest -- --version 0.2.1 \
  --artifact linux-x86_64=src-tauri/target/release/bundle/appimage/Kolora_0.2.1_amd64.AppImage \
  --artifact darwin-aarch64=src-tauri/target/release/bundle/macos/Kolora.app.tar.gz

The script reads each artifact's .sig file, writes updates/latest.json, and defaults asset URLs to the matching release tag. Commit the manifest after the release assets are reachable.

Structure

src-tauri/src/main.rs       desktop entry point (thin); Tauri lifecycle
src-tauri/src/desktop.rs    Tauri builder, RPC dispatch, legacy-data migration
src-tauri/src/lib.rs        the core library shared by both binaries
src-tauri/src/bin/kolora-exec.rs  headless runner (one task, no desktop)
src-tauri/src/browser_host.rs     BrowserHost trait, headless host, spawner
src-tauri/src/agent.rs      Engine, approvals, cancellation, tool dispatch
src-tauri/src/runtime/      Goal/contract, ledger, verification, policy, checkpoints, critics, context, report
src-tauri/src/provider.rs   HTTP provider and SSE parsing
src-tauri/src/codex.rs      private Codex app-server process, auth, models, usage
src-tauri/src/codex_run.rs  Codex turns, resumption, dynamic tools, interruption
src-tauri/src/store.rs      atomic JSON persistence and OS keyring
src-tauri/src/browser.rs    embedded WebKit tabs shared by user and agent
src-tauri/src/tools.rs      tool schemas, filesystem, shell, screenshots, desktop input
src-tauri/src/agents_doc.rs workspace AGENTS.md discovery and prompt section
src-tauri/src/skills.rs    skills.sh catalogue search, installs, and leaderboard proxy
src-tauri/src/skill_runtime.rs  installed Agent Skills discovery and prompt section
src/renderer               React interface
src/renderer/src/lib/native.ts  typed Tauri bridge exposing window.rc
src/shared                 frontend message and API types

Runtime behavior

  • Addon Marketplace → Skills browses and searches the public skills.sh catalogue from the Rust backend, so the desktop webview does not need cross-origin access. It shows the site's current leaderboard, offers topic shortcuts, links each skill to its skills.sh page, and installs skills directly through the official npx skills add CLI. Installations go either into the selected project's .agents/skills directory or globally when Global is selected; the panel also lists what is currently installed. The install button requires Node.js 22.20 or newer with npx available.

  • Installed Agent Skills are discovered from user-level ~/.claude/skills, ~/.commandcode/skills, ~/.agents/skills, ~/.config/agents/skills, and ~/.config/kolora/skills, plus every .claude/skills, .commandcode/skills, and .agents/skills directory from the repository root down to the working directory. A project skill wins over a user skill with the same name. The agent can install skills itself with the skill_search and skill_install tools, which use the same project or global universal directories and respect the exec permission. The marketplace and / menu refresh after installs and after each agent run. Every installed skill also appears as /<skill-slug> in the composer's / menu; invoking it injects the full SKILL.md body for that turn, expands $ARGUMENTS and skill/project path placeholders, and keeps the original slash command in the transcript instead of showing the hidden prompt. The system prompt contains each skill's name, description, and SKILL.md path; the agent reads the file with its normal read tool only when the task matches. Settings → Verhalten can turn skills off (loadSkills).

  • Type /planmodus (or / and pick the command) to switch a chat to plan mode: the agent only receives read-only tools, and a hard block rejects writes, commands and desktop input even if permissions allow them. /buildmodus switches back; Plan ausführen applies the plan in build mode.

  • /status shows the remaining quota for the active provider (Codex 5-hour and weekly windows when the plan exposes them) and token usage otherwise.

  • File tools cover edit_file (exact-match replacement with a diff), delete_file and move_file alongside read_file and write_file.

  • In Codex mode, chats persist their Codex thread IDs and resume them on the next turn. Changing accounts or switching between API and Codex imports the visible conversation into a fresh Codex thread as needed. Authentication errors never trigger an automatic switch to API billing.

  • Workspace instructions come from the user-level <platform config dir>/kolora/AGENTS.md (for example ~/.config/kolora/AGENTS.md on Linux; override the directory with KOLORA_HOME) and every AGENTS.md from the repository root down to the working directory, with the nearest file taking precedence. Settings → Verhalten can disable loading them and lists the files detected for the default working directory.

  • Codex receives namespaced Kolora dynamic tools, so filesystem, shell, browser, and desktop calls go through the same live permission checks and approval cards as API mode. The Codex execution environment is read-only, native shell access is disabled, and unsupported native privilege requests are refused. Dynamic tools require a compatible recent app-server version; the CLI schema is experimental.

  • The browser panel splits the workspace 50/50 and embeds real WebKit tabs. You can click, type, select text, scroll and play media directly. The agent reads and controls those same tabs using the existing browser tools; browser_tabs opens, switches and closes them.

  • Desktop pages that keep a wider minimum layout than the panel (Google Search, for example) are scaled down slightly to fit instead of forcing horizontal paging. The adjustment is applied at load and on resize only when the content overflows by 2–60 %, so ordinary pages are untouched.

  • Browser pages render directly in native child webviews; there is no screenshot polling or remote-debugging port. Agent snapshots read the active page through host-side JavaScript evaluation, input targets the native browser surface, and screenshots are captured on demand through WebKit. Browser actions keep the existing live permission and plan-mode checks. The panel opens when the agent uses browser tools; native input requires a visible app and browser panel, and is refused while the page is hidden by a dialog. Remote pages receive no application capabilities, cannot invoke application RPC, and do not receive agent/session events. Only HTTP(S) and the empty about:blank page are allowed. Browser data belongs to the app’s WebKit store, independently of Safari, Chrome or Firefox profiles.

  • Chats can be reordered inside their project by pressing anywhere on a chat row and dragging it; the cursor turns into a grab hand while dragging and an accent line shows the insertion point. The order is kept in the renderer's local storage (kolora:chat-order) and survives restarts; chats that were added later follow after the ordered ones.

  • Öffnen in sits at the left of every chat header: it opens the project folder in the detected file manager (Finder on macOS, xdg-open on Linux) or in an installed editor. Editors are detected from /Applications, /System/Applications and ~/Applications on macOS (VS Code, Cursor, Zed, Sublime Text, Xcode, JetBrains IDEs, TextEdit, …) and from PATH on Linux; only installed apps are listed. The same menu offers Pfad kopieren for the project path, and the project right-click menu has Im Finder zeigen / Im Explorer zeigen plus pinning and a new chat.

  • Projects, chats and models can be pinned. Right-click a project to pin it and it jumps to the top of the sidebar; right-click a chat for rename/delete; hover a model row in the composer picker and click its star to move it into the Favoriten section. All menus are single-column popups that close when you click anywhere beside them. Pins live in the renderer's local storage (kolora:starred-projects, kolora:starred-models).

  • The right panel mixes browser tabs with tool tabs: Dateien (expandable file tree with git status and preview), Änderungen (structured diff), Terminal (real zsh/bash session) and Kontext (session, provider, model, context limit, token usage, cost, timestamps, and raw message IDs). Its start page lists Browser, Dateien, Änderungen, Terminal and Kontext, and the + button always sits directly to the right of the open tabs. Sitzung exportieren in the context tab writes the session as pretty-printed JSON to ~/Downloads and shows the resulting path.

  • On macOS, closing the main window cancels the current run and hides the window. Reopening from the Dock shows the same window and runtime, preserving valid browser references. Quit exits the application.

  • write_file, run_command, and computer have ask, auto, or deny permission modes. Remembering an approval updates settings before releasing the waiting call. Every subsequent call reads the current permission mode.

  • Cancellation aborts HTTP requests and kills shell process groups. Every unanswered tool call receives an interruption result before the session is saved, so the conversation can be resumed. Old interrupted transcripts are repaired on their next run too.

  • Tool results are written before screenshot attachment messages, including for multiple calls in one assistant turn.

  • Session changes are blocked while a run is active. Events carry a session ID, so late events cannot append messages to a different open session.

  • Screenshots for the agent use Rust's xcap; macOS requires Screen Recording permission, and a failing capture is reported in the tool result. Native input requires Accessibility permission. Input actions are advertised according to the detected backend.

Platform Input backend Actions
macOS osascript, optionally cliclick typing and keys; pointer actions with cliclick
Linux X11 xdotool pointer, typing, keys, scroll
Linux Wayland wtype typing and keys

Quality runtime

See docs/harness/quality-report.md for the measured offline suite, fixtures, and known limits.

Every assisted or unattended native-loop run creates a Goal before changing anything; manual mode keeps the previous single loop with approvals. The Goal is persisted with the session, versioned on refinement, and turned into a typed contract: criteria, scope, research sources, assumptions, risk, and task class. Until the contract is accepted the model only receives read-only tools. The run then plans, records a baseline, implements, verifies, critiques, and asks the harness whether the Goal is met. The model's "done" is a proposal, not the decision.

  • Evidence is binding. Every tool result becomes a ledger record (ev_0001) with a SHA-256 digest. finish must cite evidence; unsourced numbers, private URLs, secrets, home paths, stale evidence, out-of-scope changes, and hidden unmet criteria are rejected before the report reaches you. Reports are rendered from the structured record, not from model prose.

  • Verification is scheduled. The project profile pins checks from package.json, Cargo.toml, and the check scripts. A rewritten script, a removed or ignored test, or a zero-test exit is rejected as evidence. A red baseline is recorded and reported, not blamed on the run. run_check runs an argv-pinned check inside the OS sandbox (bwrap on Linux, sandbox-exec on macOS); free-form run_command requires the same sandbox. Without a working sandbox, repository execution is unavailable: checks are marked unavailable, the report is partial, and the Goal cannot claim verified completion.

  • Risky work is reversible. Before delete, move, restore, and completion-adjacent mutations the runner writes a git checkpoint ref (refs/kolora/checkpoints/...) through a temporary index, leaving your branch, index, and history untouched. Without git it uses a content-addressed scope snapshot. Deleted and overwritten files go to the app-data trash; retention is 7 days or 20 runs, whichever is longer.

  • Completion is a gate. Deterministic criteria run first, then the critic panel, then the Goal review. The default review re-evaluates every criterion and consumes the requirements critic. Set Einstellungen → Agent → Entscheidungsmodell (for example jev) to use a fresh-context Goal Judge instead; it must cite evidence, cannot waive a hard gate, and falls back to harness+critic on error (decision: fallback).

  • Desktop tasks are declared. computer and screenshot_desktop require a contract research source with kind: "desktop" and a non-empty target window description; the statement alone is not permission.

  • Autonomy is a policy, not a prompt. unattended allows reads and in-scope writes; desktop input, untrusted browser_eval, network installs, and unsandboxed shell are denied with a reason and the model adapts. auto resolves to unattended only when the workspace is checkpointable and, for tasks that execute repository code, a sandbox exists. manual keeps the previous approval flow.

  • Merging stays manual. autoMerge is reserved and off; merging to main remains an explicit policy boundary (AGENTS.md requires approval).

  • Subagents are capped at depth 1 and concurrency 4. Explore/verifier/critic/visual children run with a fresh read-only context and per-role allowlists. Implementer children run in an isolated git worktree under a write lease, are cancelled with the parent, and return a patch that the parent applies only after a scope and conflict check. Provider-owned Codex turns get a post-turn baseline/check audit, but their Goal contract remains advisory because Codex owns the turn.

  • Headless execution. kolora-exec links the same library with the desktop feature off:

    cargo build --manifest-path src-tauri/Cargo.toml --no-default-features --bin kolora-exec
    KOLORA_API_KEY=… ./src-tauri/target/debug/kolora-exec \
      --task task.md --cwd ./project --out ./run --json --autonomy unattended
    

    Exit codes: 0 Goal met, 1 not met, 2 runtime/configuration error, 3 blocked by policy or a missing capability. It never opens the desktop app and reports browser_unavailable; a browser or visual task cannot be claimed in a headless run. --decision-model and --decision-provider select the Goal Judge.

  • Evaluation. evals/tasks/<id>/ contains task.md, optional setup.sh, checks.json, and an optional reference.patch that is never shown to the agent. npm run eval validates the fixtures offline; live runs use KOLORA_API_KEY and write metrics to --out. The runner never puts the reference patch in the agent's context.

Data and migration

New data lives in Tauri's application data directory for com.kolora.harness (on macOS, ~/Library/Application Support/com.kolora.harness). It contains settings.json, sessions/*.json, captures/*.png, runs/<session>/<run>/ sidecars (goal, contract, plan, append-only ledger, checks, compactions, checkpoints, report, artifacts), and trash/. Settings and sessions are atomically replaced; session IDs are validated before constructing disk paths. Captures are served to the interface through Tauri's scoped asset protocol.

On first launch, the app copies sessions, captures, and settings from the previous ColorCode data directory (com.redcode.harness) and the original Electron redcode directory when present. It also copies the user-level AGENTS.md from the previous config directory and moves API keys from the previous keyring service. The migration only fills files that are still missing, so existing Kolora data always wins; the original files remain intact.

Re-enter your API key after migrating from Electron. Electron safeStorage ciphertext is not compatible with the Rust keyring API. New keys are stored in the OS keyring; a keyring write failure is reported and does not silently fall back to plaintext. Legacy plaintext keys can still be read until replaced.

Limits

  • Unattended runs compact automatically at 80% of the context window (configurable 50–95%), with a 95% hard stop. The transcript stays canonical in the session; the wire context is derived. There is no per-turn step limit; token, wall-time, tool-call, and compaction budgets bound the loop.
  • Manual mode keeps the previous single-loop behavior, including approvals. Unattended mode never prompts: safe actions run, risky actions are denied with a reason, and every mutation is checkpointed.
  • Shell output retained for the model and UI is capped. Persistent servers should be explicitly backgrounded with output redirected to a file.
  • Browser calls have bounded protocol/wait timeouts. Cancellation waits for an in-flight native browser/input/capture operation to return; it prevents subsequent calls.
  • Screen capture support depends on OS permissions and the compositor/portal backend. Desktop input remains limited to the detected platform backend.
  • On Linux, npm run dev needs a free inotify instance for Tauri's file watcher. If startup prints Too many open files or the inotify limit is exhausted, raise it with sudo sysctl fs.inotify.max_user_instances=1024 (persistent: /etc/sysctl.d/99-kolora.conf). scripts/native.mjs detects this case and prints the same hint instead of core-dumping.
  • On Linux, Kolora sets WEBKIT_DMABUF_RENDERER_FORCE_SHM=1 to avoid the WebKitGTK Gdk-Message: Error 71 startup crash while keeping the accelerated compositor and transparent windows. Do not set WEBKIT_DISABLE_DMABUF_RENDERER; on WebKitGTK 2.54 it disables window transparency and makes the rounded outer corners square. Any user-set WebKit renderer variable takes precedence.
  • Linux uses a frameless window with a custom title bar, resize handles, and rounded outer corners. The rounded corners rely on the transparent window surface above. The inner workspace panels are rounded independently.
  • Deleting captures makes those historical image attachments unavailable; the provider receives an explicit missing-image message.
  • macOS builds are unsigned unless you configure signing and notarization.

The local Codex integration follows the official Codex app-server protocol. The separate live Codex test consumes plan usage and is excluded from npm test.

Command Code

Settings → Anbieter → Command Code is the default connection. It talks to the OpenAI-compatible endpoint at https://api.commandcode.ai/provider/v1 and lists models from /models. Kolora reuses the key from an existing Command Code CLI login when one is available; a key saved in the app is stored separately in the OS keyring. Usage is billed to the Command Code account. Switching providers keeps every provider's model and key, so you can move between Command Code, ChatGPT/Codex, Inception, and a custom API without losing settings; the composer picker selects which stored model is active.

Inception Labs

Settings → Inception connects directly to https://api.inceptionlabs.ai/v1 using a separate Inception API key stored in the OS keyring. The default chat model is mercury-3; you can pick another model from the live chat-model catalog in the composer after saving your key. Generic API settings and the ChatGPT/Codex login remain available when switching providers. Inception usage is billed to the Inception account, independently of Codex plan usage.

Mercury chat models support text, streaming, and tool calling. Kolora does not send image attachments in Inception mode; existing screenshot messages become explanatory text. See the official Inception documentation.