Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/ISSUE_TEMPLATE/bug.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ body:
id: version
attributes:
label: Version
description: Settings → About, or the GitHub Release tag (for example 0.20.0).
placeholder: 0.20.0
description: Settings → About, or the GitHub Release tag (for example 0.21.0).
placeholder: 0.21.0
validations:
required: true
- type: dropdown
Expand Down
16 changes: 15 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,24 @@ jobs:
run: npx playwright install --with-deps chromium
working-directory: apps/desktop
- run: npm run test:visual
- name: Upload visual diffs
if: ${{ failure() }}
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: visual-diffs
path: apps/desktop/test-results/
if-no-files-found: ignore
retention-days: 14
# Run the remaining checks even when an earlier step failed, so a
# screenshot or test failure cannot hide a lint/type/format/build break.
- run: npm run typecheck
if: ${{ !cancelled() }}
- run: npm run lint
if: ${{ !cancelled() }}
- run: npm run format:check
if: ${{ !cancelled() }}
- run: npm run build --workspace=@locus/desktop
if: ${{ !cancelled() }}

docker-image:
runs-on: ubuntu-latest
Expand All @@ -41,7 +55,7 @@ jobs:
run: |
mkdir -p images/agent/vendor
node scripts/prefetch-github-release-asset.mjs --owner coder --repo code-server --tag v4.96.4 --file code-server-4.96.4-linux-amd64.tar.gz --out images/agent/vendor/code-server.tar.gz
- run: docker build -t locus/agent:0.1 -t locus/agent:0.20.0 images/agent
- run: docker build -t locus/agent:0.1 -t locus/agent:0.21.0 images/agent

android:
runs-on: ubuntu-latest
Expand Down
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,28 @@

## Unreleased

## 0.21.0 — 2026-11-13

Decide from the Inbox, a turn summary card, tray and actionable notifications, encrypted backup and restore, background update checks with one-click install, a model benchmark, a smoother first hour with a public repo, and much faster workspaces on large repos. Settings → About is **0.21.0**.

**Inbox decisions.** The Inbox shows a decision card for each waiting item: what will run, where it runs, the agent's last words, and a risk hint. Approve, Deny, Always allow and Open chat sit on the card, with keyboard shortcuts (J/K, A, D, Enter) and **Approve all** when several chats wait on the same tool.

**Turn summary and first task.** When a turn changes files, runs tests or opens a PR, a card under the reply lists the files changed, whether tests passed, and next steps: Review changes, Open PR, Continue, or Undo this turn. The first-task card on New agent now suggests real work on your most recent repo or folder.

**Tray and notifications.** The desktop app has a tray icon and dock/taskbar badge with the needs-you count. Notifications say what the agent wants and open the chat when clicked; on macOS, approvals can be answered straight from the notification.

**Backup and restore.** Settings → Advanced → Back up and restore, or `locus backup` / `locus restore`, writes one passphrase-encrypted file with your sessions, settings, boards, projects, Jobs, Brain, workspaces and stored keys. Machine-bound keys are never copied; the vault is re-encrypted for the new machine, so a restore on a new laptop keeps every provider key. A wrong passphrase or tampered file is refused.

**Updates.** The desktop checks for new releases shortly after launch and every six hours, and **Install** downloads, verifies the checksum and installs (in place for Linux AppImage). Turn it off in Settings → About. CLI: `locus update`.

**Model benchmark.** Settings → Benchmark, or `locus eval run`, runs five small coding tasks against the models you pick and records pass rate, tokens, cost, tool calls and time per model.

**First hour with a public repo.** With Docker stopped, actions that need a container say so and offer to start on Host instead. A linked repo is preselected across New agent, Design, Jobs, Brain and IDE. No-token accounts show their rate limit and when it resets. Codebase gains an About card for the repo, and the setup wizard tests local servers such as Ollama with a real call.

**Performance on large repos.** Agent search after an edit no longer rebuilds the whole index (seconds down to milliseconds on very large repos), VM file listings, search without ripgrep, repo index rebuilds, the repo map and Quick Open are all much faster, and the desktop app now ships ripgrep.

**Fixes.** Undo on a git workspace reliably restores edited files. The desktop app uses Electron's async secure-storage API, so the deprecation warnings are gone and existing vault keys still unlock. The control plane and worker start without `ssh-keygen` (only VM agents need it).

## 0.20.0 — 2026-11-11

Eight new Terminal themes, a UI/UX polish pass on Swarm, the composer, and empty states, and launchers that check Docker is actually running before they start. Settings → About is **0.20.0**.
Expand Down
5 changes: 3 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Thanks for trying Locus. This tree is a Node workspaces monorepo (`apps/*`, `pac

- Node.js 22.22+ (Brain FTS5 needs `node:sqlite`; GitHub Actions uses 22.22)
- npm 10+ (comes with Node)
- `ssh-keygen` (`openssh-client` on Debian/Ubuntu) for VM agents. Without it the control plane still starts and logs a warning; Host and Docker agents work
- Optional: QEMU + `qemu-img` for real VMs; Docker CLI for real containers. Without them the mocks still run the UI

```bash
Expand Down Expand Up @@ -48,8 +49,8 @@ First agent without Docker: Settings → Providers (Ollama needs no key) then Ne
After merge to `main`:

```bash
git tag v0.20.0
git push origin v0.20.0
git tag v0.21.0
git push origin v0.21.0
```

GitHub Releases are the distribution channel (`v*` tags). Pushing a `v*` tag publishes Linux, macOS, and Windows installers, then **Prune GitHub Releases** deletes older published releases so only the last three remain (git tags are kept). See [docs/public-release.md](docs/public-release.md) for listing settings this tree cannot change (visibility, vulnerability reporting, unsigned macOS/Windows). Keep the repository description as the README tagline and topics `ai-agents`, `qemu`, `docker`, `computer-use`, `electron`, `local-first`.
Expand Down
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

Locus is a desktop control plane for AI coding agents that run on hardware you own — a Docker container, a QEMU virtual machine, or a folder on disk. Chat on one side, the live guest on the other. Code, keys, sessions, and disks stay under `~/.locus`.

This is **v0.20.0** (MIT). The API binds to loopback. Linux, macOS, and Windows. Bring any LLM provider you have a key for.
This is **v0.21.0** (MIT). The API binds to loopback. Linux, macOS, and Windows. Bring any LLM provider you have a key for.

## Install

Expand Down Expand Up @@ -206,13 +206,15 @@ The **Services** tab on that rail lists Swarm nodes and services when this engin

### Settings

Grouped as **Models** (Providers, MCP, Skills), **Workspace** (Machines, Workers, Environments, Git, Integrations), and **System** (Appearance, Notifications, Phone, Chrome, Advanced, About). The page can find a provider, MCP server, skill, worker, environment, Git account, or integration by name.
Grouped as **Models** (Providers, MCP, Skills, Benchmark), **Workspace** (Machines, Workers, Environments, Git, Integrations), and **System** (Appearance, Notifications, Phone, Chrome, Advanced, About). The page can find a provider, MCP server, skill, worker, environment, Git account, or integration by name.

Git includes **Sign in with GitHub** / **Sign in with GitLab** / **Sign in with Bitbucket**. MCP defaults to deferred tool schemas (**Preload tool schemas** per server). HTTP MCP to an AWS API Gateway signs SigV4 when AWS keys are in that server's env. Traces live on the agent or design ⋯ menu → **View trace**.

Settings → About checks GitHub Releases at launch and every six hours. **Install** verifies the download against `SHA256SUMS`, then swaps a Linux AppImage in place and relaunches, runs the Windows installer, or opens the dmg / deb / rpm. Settings → Advanced → **Back up and restore** writes one passphrase-encrypted `.locusbak` with sessions, settings, stored keys, boards, projects, Jobs and Brain, and restores it on another machine at the next start (`locus backup` / `locus restore`). Settings → **Benchmark** runs five small coding tasks as real Host turns against the models you pick and compares pass rate, cost and time (`locus eval run`).

Settings → Phone mints a LAN pairing token (QR on that tab). Settings → Workers lists LAN / Cloud VM / Fargate hosts. Settings → Environments lists named boxes saved from New agent or Automations. Settings → Notifications toggles desktop alerts and quiet hours. Settings → Appearance filters themes and sets editor font size, format on save, and the minimap. Settings → Advanced **Tailscale Funnel** exposes **only** `/api/hooks` (never the whole control plane) so GitHub can reach forge webhooks; `locus config funnel enable|disable`.

Integrations: Slack, Grafana, Jira, Confluence, Linear, Miro, Figma, incident.io, AWS IAM, Portainer, Kubernetes, Sentry, Gmail, Google Calendar, Google Drive, and agent-authored HTTP plugins. Settings → About is **0.20.0**.
Integrations: Slack, Grafana, Jira, Confluence, Linear, Miro, Figma, incident.io, AWS IAM, Portainer, Kubernetes, Sentry, Gmail, Google Calendar, Google Drive, and agent-authored HTTP plugins. Settings → About is **0.21.0**.

<table>
<tr>
Expand Down Expand Up @@ -306,7 +308,7 @@ Developer / Swarm in the sidebar switches the product shell. Developer keeps the

**CLI.** `npx locus` / `npm run locus --` is a loopback client for the same control plane: agents, design, games, assets, IDE, projects, Codebase, Brain, Slack, Grafana, Docker, automations, workflows, Settings, phone remote, and Funnel. `locus serve` starts the server when the app is not running. `locus project keep` leaves that control plane up after the desktop quits. `locus workflow` imports and runs Agent Loop Builder graphs. `locus brain setup` writes personal editor hooks that send a redacted transcript tail to the local brain. Live VNC and canvas clicking stay in the desktop. Guide: [docs/cli.md](docs/cli.md).

**App.** 106 themes (Ember default). Settings → About is **0.20.0**. Electron packages (Linux AppImage, macOS dmg, Windows NSIS), or `npm run dev` in the browser. **Ctrl/Cmd+K** command palette. **Ctrl/Cmd+N** new agent, new automation, or (on Design, Games, Assets) the empty composer. **Ctrl/Cmd+F** find in chat. **Ctrl/Cmd+,** settings.
**App.** 106 themes (Ember default). Settings → About is **0.21.0**. Electron packages (Linux AppImage, macOS dmg, Windows NSIS), or `npm run dev` in the browser. **Ctrl/Cmd+K** command palette. **Ctrl/Cmd+N** new agent, new automation, or (on Design, Games, Assets) the empty composer. **Ctrl/Cmd+F** find in chat. **Ctrl/Cmd+,** settings.

## Security model

Expand Down
1 change: 1 addition & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ Please use [GitHub private vulnerability reporting](https://docs.github.com/en/c
- **What goes to providers.** Chat messages, tool results (after secret redaction), and screenshots when Vision is on are sent to the provider you enabled. Locus does not send traces, vault files, or `master.key`.
- **Training.** Locus does not train models. Whether a provider trains on API traffic is that provider's policy; use your provider's zero-retention / API-data controls when you need them.
- **Retention.** Session JSON, traces, screenshots, recordings, and disks stay under `~/.locus` on this machine until you delete the session or Reset all data. Automations that open a new chat per run keep the newest 60 chats for that job (pinned and in-flight chats stay) and delete the rest from this machine. There is no cloud copy of the control plane.
- **Backups.** A `.locusbak` from Settings → Advanced or `locus backup` contains every stored key and token, decrypted inside an AES-256-GCM archive keyed by your passphrase (scrypt). Treat the file and passphrase like the keys themselves. `master.key`, `master.key.safe` and `secrets.enc` are never copied; restore re-encrypts the vault with the target machine's key. Backup and restore routes refuse anyone but the local operator (not a paired phone). A wrong passphrase or tampered archive fails the GCM check and nothing is staged.
- **Isolation.** This is a single-operator local app. Each agent has its own guest (Docker workspace or VM disk). That is workspace isolation, not multi-tenant SaaS tenancy. Do not run untrusted operators against one `~/.locus`.

## Reliability
Expand Down
4 changes: 2 additions & 2 deletions apps/android/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ android {
applicationId = "app.locus.android"
minSdk = 26
targetSdk = 35
versionCode = 34
versionName = "0.20.0"
versionCode = 35
versionName = "0.21.0"
}
buildTypes {
release {
Expand Down
2 changes: 1 addition & 1 deletion apps/chrome-extension/manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "Locus",
"version": "0.20.0",
"version": "0.21.0",
"description": "Let Locus host agents use your Chrome tabs — navigate, click, type, and screenshot the pages you already have open.",
"action": {
"default_title": "Locus",
Expand Down
4 changes: 2 additions & 2 deletions apps/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@locus/cli",
"version": "0.20.0",
"version": "0.21.0",
"private": true,
"description": "Locus CLI — control plane client for agents, Slack, Codebase, Docker, and automations",
"type": "module",
Expand All @@ -22,6 +22,6 @@
"@types/node": "^26.6.5",
"@types/ws": "^8.18.2",
"typescript": "^7.0.2",
"vitest": "^5.0.5"
"vitest": "^5.1.0"
}
}
10 changes: 9 additions & 1 deletion apps/cli/src/args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ const BOOLEAN_FLAGS = new Set([
"printable",
"no-texture",
"no-enhance",
"include-disks",
"inspect",
]);

const VALUE_FLAGS = new Set([
Expand Down Expand Up @@ -137,9 +139,15 @@ const VALUE_FLAGS = new Set([
"notify",
"node",
"memory",
"case",
"repeat",
"out",
"current",
"passphrase-env",
"poll-ms",
]);

const MULTI_VALUE_FLAGS = new Set(["arg", "repo"]);
const MULTI_VALUE_FLAGS = new Set(["arg", "repo", "model", "case"]);

function appendFlag(prev: FlagValue | undefined, name: string, next: string): string {
if (MULTI_VALUE_FLAGS.has(name) && typeof prev === "string" && prev.length) {
Expand Down
21 changes: 21 additions & 0 deletions apps/cli/src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,16 @@ import { helpFor } from "./help.js";
import { isCompletionShell, renderCompletion } from "./completion.js";
import { startServer } from "./serve.js";
import { CLI_VERSION } from "./version.js";
import {
cmdBackup,
cmdEvalCancel,
cmdEvalCases,
cmdEvalList,
cmdEvalRun,
cmdEvalShow,
cmdRestore,
cmdUpdate,
} from "./maintenance.js";

export interface Ctx {
client: LocusClient;
Expand Down Expand Up @@ -388,6 +398,17 @@ const ROUTES: Array<{ path: string[]; run: Handler }> = [
{ path: ["image", "fetch-virtio"], run: cmdImageFetchVirtio },
{ path: ["image"], run: cmdImageList },

{ path: ["backup"], run: (ctx) => cmdBackup(ctx) },
{ path: ["restore"], run: (ctx) => cmdRestore(ctx) },
{ path: ["update"], run: cmdUpdate },

{ path: ["eval", "cases"], run: cmdEvalCases },
{ path: ["eval", "run"], run: cmdEvalRun },
{ path: ["eval", "list"], run: cmdEvalList },
{ path: ["eval", "show"], run: cmdEvalShow },
{ path: ["eval", "cancel"], run: cmdEvalCancel },
{ path: ["eval"], run: cmdEvalList },

{ path: ["debug", "logs"], run: cmdDebugLogs },
{ path: ["debug", "log"], run: cmdDebugLog },
{ path: ["debug", "eval"], run: cmdDebugEval },
Expand Down
45 changes: 45 additions & 0 deletions apps/cli/src/help.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,16 @@ Config / Settings:
locus config revoke-all --confirm REVOKE
locus config reset --confirm RESET

Backup / updates:
locus backup [file.locusbak] [--include-disks] Encrypted copy of ~/.locus
locus restore <file.locusbak> --yes [--inspect] Applies at the next start
locus restore status|cancel
locus update [download] Check GitHub releases

Model benchmark:
locus eval run --model provider/model[,…] [--case id,…] [--repeat N] [--wait]
locus eval cases|list|show <run>|cancel <run>

Images / debug:
locus image list|capture|delete|fetch|fetch-virtio
locus debug logs|log|eval|egress|approvals
Expand Down Expand Up @@ -311,6 +321,41 @@ Agents flag bad claims with correct_graph; inbox Accept/Dismiss is the human gat
locus config theme ember
locus config workers add 'locus-worker:add?url=…'
locus config reset --confirm RESET`,
backup: `Write an encrypted backup of ~/.locus (sessions, settings, vault, boards, projects, Brain).

locus backup [file.locusbak] [--include-disks]

The passphrase comes from LOCUS_BACKUP_PASSPHRASE (or --passphrase-env NAME), or a hidden
prompt. Stored secrets travel inside the encrypted file and are re-encrypted with the target
machine's key on restore. VM disks and images are left out unless --include-disks.`,
restore: `Restore a backup made by \`locus backup\` or Settings → Advanced.

locus restore <file.locusbak> --inspect Check the passphrase and show what is inside
locus restore <file.locusbak> --yes Stage it; quit and reopen Locus to apply
locus restore status
locus restore cancel

The swap happens at the next start, before anything loads. Current files move to
~/.locus/.before-restore-<time>/. This machine's master key stays in place.`,
update: `Check GitHub Releases for a newer Locus.

locus update Show the latest release for this platform
locus update download Download the installer and verify it against SHA256SUMS

The desktop app checks at launch and every six hours unless Settings → About →
Check automatically is off. On a Linux AppImage, Install swaps the file and relaunches.`,
eval: `Benchmark models on small coding tasks as real Host agent turns.

locus eval cases
locus eval run --model openai/gpt-5 --model anthropic/claude-sonnet [--case fix-add,off-by-one]
[--repeat 3] [--timeout 10] [--wait]
locus eval list
locus eval show <run>
locus eval cancel <run>

Each case starts with failing tests. A case passes when \`npm test\` passes afterwards and the
tests were not edited. Runs record tokens, estimated cost and time. Benchmark sessions are
archived so you can open a failure. Results: ~/.locus/benchmarks/.`,
debug: `JSONL traces under ~/.locus/traces, plus audit exports.

locus debug logs
Expand Down
Loading
Loading