Locus 1.6.0
Locus is now a single self-contained download — no Python install required. The app embeds a relocatable CPython 3.14.6 (python-build-standalone) and the agent service with all its dependencies. This is also the first release from the combined repository: the app and the ollama-code agent now live together, with the agent in agent/.
Download Locus-macOS.zip, move Locus to Applications, and open it. The build is signed with a development certificate and is not notarized, so macOS blocks the first open of a downloaded copy: try to open Locus once, then go to System Settings ▸ Privacy & Security and click Open Anyway — or run xattr -dr com.apple.quarantine /Applications/Locus.app in Terminal. You still need Ollama for local models.
If you downloaded this asset before it was replaced on 2026-07-28 evening and macOS called the file damaged, that was a packaging defect (the bundle's code-signature seal was broken after signing) — delete that copy and download again.
Added
- Permission approval moved into the composer, the way Claude Code and
Codex ask. While a tool waits, the input is replaced by a prompt with the
tool, a preview of what will run, and a keyboard-first option list —
1 Yes, allow once · 2 Yes, and don't ask again for that tool this
session · 3 No, and tell Locus what to do differently.↑/↓move,
↵confirms,Escdenies, digits answer directly, and focus returns to
the editor after any decision. The transcript's tool card keeps the status
but no longer carries buttons. - Git quick actions in Changes: stage, unstage, and discard per file
(discard always confirms; untracked files move to the Trash instead of
git clean), plus a commit area with Draft with AI — the staged diff
goes to the local Ollama model, reasoning tags and fences are stripped,
and the subject is capped at 72 characters; with no local model it falls
back to a deterministic summary. Git runs directly in the workspace with
literal pathspecs and a watchdog timeout; stderr surfaces in the toast. - Find in conversation (
⌘F): a search bar over the transcript with a
liven of mcount,↵/⇧↵navigation with wrap-around,Escto close,
and scroll-to-match with the current match outlined. - A thinking view mode for the transcript —
/thinking hidden|collapsed|expanded, also in the workspace…menu. Hidden shows
answers only (with a minimal "Thinking…" line while a reply is still all
reasoning), Collapsed keeps the expandable cards, Expanded pins every card
open. Persisted with the other settings. - Show/Hide Sidebar (
⌘0), and the sidebar's state now persists across
launches like the inspector's. Defaults follow Claude's layout: the session
sidebar starts open, and the right-hand inspector starts collapsed — the
conversation gets the room, and⌘1–⌘5or⌘⌥Ibring the panel back. - Model recommendations now consider this Mac's memory. The Hugging Face
library used to pre-select Q4_K_M no matter what — which put a 22 GB model
on a 32 GB machine, where it starved the context window until tool calls
were cut off mid-generation. The pre-selected quantization is now the best
one that comfortably fits the machine's unified memory, every variant card
carries an honest badge (RECOMMENDED / TIGHT FIT / TOO LARGE), the header
states the Mac's memory, and the download panel warns — without blocking —
before a tight or oversized download. The post-install toast repeats the
warning, and Settings → Status now shows Ollama's own error text (a model
too large to load, a dead server), which was captured and displayed
nowhere. Theollama-codebackend gained the matching resilience: old
tool outputs are evicted in place when a single turn outgrows the window,
and a tool call cut off mid-generation is retried once after making room
instead of failing the turn.
Changed
-
The app is now fully self-contained — no Python install required. The
build embeds a relocatable CPython from python-build-standalone (3.14.6)
together with the agent's dependencies, replacing the old copy of the
build machine's Homebrew Python, which kept resolving its dylib and
standard library from/opt/homebrewand made the shipped app require
python@3.14. The first build downloads and checksum-verifies the
interpreter (~26 MB) into a reusable.agent-runtime/cache;
LOCUS_BUNDLE_MODE=venvrestores the old behavior,skipbundles
nothing. The bundled runtime is pruned (tests, tkinter, pip, headers) and
pre-compiled so first launch doesn't byte-compile from the read-only
bundle. -
App and agent now live in one repository. The
ollama-codeservice
moved from the separateollama-code-clicheckout intoagent/, the
bundling scripts default to it, and the default fallback backend folder is
now~/Documents/locus/agent. The product site is no longer nested in the
checkout. -
The context meter tells the truth. It measures against the same
context_limitthe agent budgets compaction with (falling back to the
model list), estimates growth while a reply streams instead of freezing
mid-turn, and no longer double-counts the context pack — included files
are already inside the session count after each send. With no known
window — remote endpoints do not advertise one — the chip shows the token
count plainly instead of a percentage of an invented 32k window; the
popover's pack row now reads "Context pack (next send)". -
Test Connection is side-effect free. It probes the endpoint directly
with the values as typed. It used to save the settings draft, write the
API key to the keychain, and switch the live agent's provider — all of
which survived Cancel and made the following Save skip its reconnect. -
The agent now budgets against the window Ollama actually serves
(fixed in theollama-codebackend): it reads the loaded window back
from/api/ps, an optionalcontext_windowsetting pinsnum_ctx
explicitly, and/api/modelsreports the window in use separately from
the trained maximum. The model picker's "ctx" figure now shows the
trained window — the number to compare models by — while the meter keeps
measuring against the window in use.
Fixed
/compactcrashed the app — it re-entered the slash-command matcher
and recursed until the stack overflowed. Forwarded commands now bypass
local matching.- A permission request without a request id locked the app — send,
Clear Chat, and New Session all disable while a request waits, and one
that cannot be answered kept them disabled forever. Such requests now
surface as errors instead of arming that state;turn_donesweeps any
card still waiting; requests attach to the newest matching card; the
in-place upgrade now triggers the auto-scroll that used to leave the
prompt off-screen; and clearing the chat re-checks for a request that
arrived while the confirmation alert was open. - The console could be bricked by a disconnect — only a backend event
cleared its running state, and after a drop none was coming. The command
field now recovers, and cancelling against a dead socket says so. - A transient git error emptied the Changes list and rendered "Nothing
changed" over edits that still existed. The last known list is kept, with
a stale-warning triangle in the header; a superseded refresh no longer
clears the newer request's spinner. - Diff requests broke on legal filenames —
&,+,=, or?in a
path truncated or corrupted the query. Requests now build through
URLComponents, and the two force-unwraps in the URL builder are gone. - Draining the queue destroyed the draft: a queued message that failed
to send was written into the composer over whatever had been typed since.
It returns to the head of the queue instead. - The slash popup could run a command you never saw — arrow keys walked
the selection past the eight rendered rows. The list is now capped where
the selection walks it. - Stop reported success even when the interrupt never left the app; it
now says the agent is unreachable and leaves cleanup to the reconnect
path. Orphan tool results synthesize a card instead of vanishing. - Quitting or changing the backend URL froze the app for up to four
seconds waiting for the old backend child to exit. The restart path
waits off the main thread; quitting waits half a second, then SIGKILLs. - One missing field in
session_infosilently disabled workspace tracking,
the file index, and permissions display at once — session, model, and
history decoding is now tolerant, so a single absent field can no longer
nil the whole struct (or fail an entire resume on one null tool message). - The home directory can no longer be recorded as a recent workspace by
typing before the agent connects. - The preview's WKWebView no longer uses the private
drawsBackgroundKVC
key, which would crash uncatchably if WebKit renamed it. - Dead code removed (
changeBlocks, the unused provider verifier); the
context-pack folder expansion reuses the shared file-type lists, fixing a
drifted skip list that missed.venv.
Product site
- A site for Locus, in
website/: one server-rendered page covering the
workspace, the three work modes, the principles behind the app, the
inspector, and model selection. Next 16 on vinext, served as a Cloudflare
Worker. Its test renders the compiled worker in-process and checks the
finished page — including that the starter template's placeholder copy is
gone — rather than trusting the build to have succeeded. - The site is a separate git repository nested inside this checkout, so none of
it ships with the app and the release build never sees it.
website/README.mdcovers running, testing, and deploying it; this
repository's README gained a section pointing at it, and at the copy there
that has to be re-checked against each release.