Repository navigation
aterm 0.102.0
aterm is the terminal for AI. New here? What each file is:
aterm-0.102.0.dmg— the signed, notarized app as a drag-install DMG. The ALab toolchain installs itself on first launch (or on demand viaaterm pkg install --default-set).aterm-0.102.0-mac.zip— the same app as a zip; this is the container the in-app updater and Homebrew stage from.aterm.dmg/aterm-mac.zip— permanentreleases/latest/download/names for the DMG and the zip above (byte-identical copies)..sha256files verify a download:shasum -a 256 -c <asset>.sha256.aterm-appcast.toml/aterm-machines.toml(and their.sig) are consumed by the in-app self-updater — not for humans.- Releases named
atpkg-index-Nare machine-readable package indexes, not app releases.
Added
- Code has one home,
~/Developer, and aterm measures that Spotlight skips it. Spotlight
indexes every text file in your home and, since macOS 27, attaches an embedding to each, so
source trees there costmds_storesreal CPU. Apple documents one way to keep a folder out
of the index: System Settings ▸ Spotlight ▸ Search Privacy. Add~/Developerthere once per
Mac.aterm doctorandaterm pkg doctorgain two rows:devroot:names the git checkouts
and worktrees under your home that are not in~/Developer, andspotlight:MEASURES
whether Spotlight skips~/Developer(a probe file and a later control, both removed), never
assuming it from the name (a~/Developerthat is a link is never opened, and is not
measured).aterm pkg devrootlists each checkout outside, where it would go and what
holds it;aterm pkg devroot move --all(or named checkouts) moves them, refusing the
whole run while any has uncommitted work, a process working in it or in another checkout
of its repository, or an agent session, and never splitting a repository that has
submodules (their links are relative). It moves one repository at a time and repairs what
names the old paths — worktree links (git worktree repair), the git config and
alternates of every git directory, submodules' included (a cut clone's
aterm-release.receiptsFrom), Claude Code's~/.claude/projects/<path-key>folders (not
the transcripts in them),aterm pkg linkdev links and the publication engine's registry
rows — then checks that every checkout still answersgit status. A ^C waits for it to
finish.aterm pkg devroot verifymeasures the root on demand. The window's six-hourly look
raises one entry in Messages ▸ To look at, only when it measures Spotlight indexing the
root, and its button opens Search Privacy. The move is a one-time migration: it goes once
every owner Mac on the release roster reports a cleandevroot:row; the survey, the rows
and the measurement stay. The window's disk cleanup looks for idle build output in the
checkouts in~/Developeras it does in your home's.
Changed
-
The supervisor's trust roots and the publication engine follow
~/Developer.
[harness] trust_rootsdefaults to~/Developer/aterm*,~/Developer/ay*,
~/Developer/trust*and/private/tmp/claude-*, so a checkout left in your home is
no longer answered for. The release tools and the export content scan read the engine
at$PUBLICATION_ENGINE, else~/Developer/publication. The agent primer (v14) says
where code lives. Runaterm pkg devroot move --allright after updating: until the
checkouts move, the merge gate'sexport contentstage is NOT RUN (its reason names
~/Developer/publicationand the move), and the supervisor answers for no session in
the old checkouts. -
A rerouted tool name warns in one line and runs, instead of stopping your command.
Inside an aterm session,clippy,rustfmt,rustdocandleanwith no Trust tool
installed now run the upstream copy after a line namingaterm pkg install <program>or
aterm pkg repair(they exited 127),z3runs upstream after a line namingay(it exited
2), and so does a stub that cannot reach aterm's package manager. Only a name with nothing
to run still exits 127;[reroute] announce = falsesilences the lines and[reroute] strict = truebrings back the refusals (aterm help reroute). One place refuses by design:
inside a Trust source checkout acargoorrustcthat is not Trust (next entry). -
A bare
cargoorrustcin a session now says what it is about to run — Trust or
stock, by name — and inside a Trust source checkout a stock one does not run. The line
used to say "running upstream 'rustc' (no proof claim)" whatever that name ran, so after
rustup default trustit said it over Trust itself. Now aterm asks the copy on PATH what
it is (throughrustup whichwhen it is rustup's proxy,+toolchainincluded, then that
file's-vV) and names it:-> Trust 7d5533b2, via rustup trust (the rustup default), or
-> STOCK rustc 1.97.1 (…), via rustup 1.97.1-… (pinned by ./rust-toolchain.toml); not Trust, plus one line naming the file. STOCK is said only when nothing in the answer marks
Trust: a build that prints a Trust mark but notrust:version (the cargo of the Trust
seal e9ca4908) is "not known to be Trust", and so is a copy that does not answer as a Rust
tool; neither is ever called Trust. Inside a Trust source checkout (anx.pybeside a
src/stage0sayingcompiler_dist_channel=trust) acargo/rustcthat is not Trust
exits 2 without running, naming the Trust spelling and how to run it anyway, a session
started withaterm --no-reroute: there a stock compiler would build part of Trust. A
cargo/rustca tool spawns there by name is judged the same — a cargo subcommand, an
xtask, a build script runningrustc +nightly, the compiles a stock cargo started by its
path spawns — including beneath a Trust cargo the reroute let run (its children are not
announced again, but no longer inherit the escape), with no package store resolving, and
with aterm's package manager unreachable (then a stub refuses there outright). A compiler
run by its own path, or handed to cargo asRUSTC, is looked up by no name and is not
judged.[reroute] announce = falsedoes not silence the refusal. The answer is cached in
the package prefix (reroute-identity.cache), but only for rustup's answers and a
toolchain's own compiledcargo/rustc; a wrapper or shim in front of them is asked on
every call, because it can run a different compiler in each directory.
Removed
- The Spotlight rename pass and
[machine] spotlight_noindex. aterm no longer walks your
home renaming cargotargetfolders totarget.noindexbehind a symlink: the name trick is
not an Apple mechanism, and the developer root above replaces it for your checkouts.
aterm pkg noindex scan|migrate|apply, the Spotlight half ofaterm pkg machine apply,
its row on Settings ▸ Security and thespotlight_noindexkey are gone (a file that still
sets the key gets the ordinary unknown-key note).aterm pkg noindex verify <dir>stays,
as the measurement. Folders an earlier pass renamed are left as they are, and still build.
The trees aterm's own gate and release tools make beside a checkout keep their.noindex
names for now (<checkout>-verify.noindex,-verify-cells.noindex,
<clone>-release.noindex,<checkout>-cut.noindex,dist/cut-<build>.noindex): on a
Mac whose code is not yet in~/Developerthey keep Spotlight off build output, and they
go once every owner Mac has moved.
Fixed
-
A pane kept open after its command ended has no clickable links in its scrollback after an
update. Since 0.101.0 a--holdpane's scrollback crosses an update along with its last
screen. The links on that screen were removed, because nothing runs behind the pane, but the
links in the scrollback above it could still be clicked. The scrollback now crosses with every
word and colour and no links, the same as the screen. -
Resizing the window no longer deletes spaces or misplaces the prompt. A space just before a wide
character (CJK, emoji) at the end of a wrapped line was deleted by a width change, words in history
could run together after a rewrap, and after a full-screen program exited following a resize the
prompt could land on top of earlier output. -
Neovim's cursor stays on the right character on lines with CJK or emoji. Neovim 0.11 and later
turn on a grapheme mode in which aterm moved the cursor by whole characters instead of by cells. -
Copy and find give back exactly what is on screen. Copying a wrapped line no longer drops the
space at the wrap point; with right-to-left text (Hebrew, Arabic) the selection now copies the words
it highlights; find and double-click measure wide ambiguous characters as drawn; find gives the same
results for a line on screen and in history; and dragging over double-width text selects what is
under the pointer. -
Wide ambiguous symbols are two cells in wide mode. With
ambiguous_width = "wide", symbols such
as ★ ♪ ☎ ❶ were drawn one cell wide. -
A terminal session no longer freezes when you paste into a program that is not reading. Running
atermas a session in another terminal, pasting or typing ahead more than about a kilobyte into a
program that prints but does not read its input (ping,tail -f, a build) stopped everything for
good: no output, no keystrokes, no resize. The program's output keeps flowing now, and what it has not
read yet waits until it does. -
A resize while
atermstarts reaches the program. A terminal resized in the moment a session
started (a window manager or split laying it out) left the program at its starting size until the next
resize. -
Zooming the font over a picture no longer uses gigabytes of memory. An inline image (
imgcat,
sixel, Kitty) was decoded at the size of its cells at the new font size, so zooming a window-wide
picture to the largest font asked for about 2 GB a step and could reach 13 GB. A picture now decodes
to at most a full-window raster, however far the font is zoomed. -
Screens full of pictures or large emoji repaint without starting over. Showing more images than
the image cache held at once (two window-wide photos, layered Kitty images, a sheet of thumbnails)
decoded every one again on every repaint, a tenth of a second to seconds each time; drawn without a
GPU, a screen of distinct emoji at a large font was rasterized again on every full repaint. What the
screen shows now stays decoded and rasterized between repaints. -
Caps Lock and non-US keyboard layouts type what the key shows. Caps Lock + A typed
a; on a
German, French, Russian or other non-US layout, Shift typed the US character for that key (German
Shift+2 gave@, French number-row digits could not be typed, Russian capitals came out lowercase),
and Ctrl with a Russian letter typed the letter instead of the control key (Ctrl+С now interrupts).
Typing now sends the character your layout produced, and Ctrl+letter on a non-Latin layout sends the
same control key as on a US keyboard. -
Option keeps working on Backspace, Enter, Tab and Escape when Option is not Meta. With
option_as_meta = false, these keys lost the Option modifier (Option+Backspace erased one character
instead of a word in shells that bind it). -
Ctrl+Alt+Backspace deletes a word and Ctrl+Alt+Space reaches the program. They were sent without
the Alt. Ctrl+~ now sends the control character other terminals send. -
The mouse over a split pane talks to that pane. Hovering, scrolling or right-clicking over a pane
that does not have focus went to the focused pane's program instead; a button released after switching
tabs or panes went to the wrong program; releasing one of two held buttons stopped drag reports; and a
program tracking the mouse got a report for every pixel moved inside a character cell. -
Output that scrolls a huge count no longer freezes the window.
CSI 65535 S(scroll up) archived one
history line per count, so a few kilobytes of it from any program, acatof a file or an ssh session,
held the terminal for seconds and froze the window's redraw. A scroll of a screenful or more now
archives exactly that screenful and leaves the screen blank, as xterm does. -
Links in scrollback can no longer use gigabytes of memory. The web addresses of links (OSC 8) that
had scrolled into the in-memory history were counted by no limit, so output full of long, distinct
links could hold about 4 GB in one tab, out of reach of the memory-pressure trim. They now count
toward the tab's history budget: past a quarter of it, the oldest rows' links are dropped (the text
stays), and the memory-pressure trim frees them. -
Copy mode's cursor stays on its text. With output streaming, the vi cursor on a fixed row below a
scrolling area (Codex's composer, apt's progress bar) was dragged up a row per line of output; it now
stays put while rows in the scrolling area and in history still carry it with their text. A resize,
clearor a lowered history limit no longer leaves it off the grid or on other text. -
A control client that stalls or stops reading no longer turns the other clients away.
Eight connections could tie up every control thread, and every other client (aterm ctl,
each supervised tab's harness) was then answeredERR control server busy; retryuntil
they let go. A connection did this by stopping part way through itsAUTHline (no token
needed), stopping part way through a request or afeed-bin/paste-binbody, or not
reading a long answer (aterm ctl help --fullinto a pager that pauses). A control thread
now takes a connection only once it holds a whole request, and it does not wait for the
client to read the answer; a pager that pauses still gets every byte. -
The control verbs
wait,readyandawaitrefuse a timeout that is not a whole
number of milliseconds.wait 2s,ready timeout=1.5andawait idle 500 timeout=5s
waited the 30 s default instead, andwait 2sanswered a command that had already
finished as if2swere fine. They now answer their usage line, asturn timeout=
already did. A number still waits that long, held at 600 s. -
The cursor pet no longer flashes an old cat you could not see after a screen or pane switch.
When the pet changed breed under a text selection, the cat it was replacing was hidden by the
selection, yet an alternate-screen enter or a split-pane switch brought it back at full
brightness for a moment (or let the new cat jump straight to full brightness beside it). A cat
now crosses those switches at the brightness it was last drawn at, and one that was hidden
does not come back. -
aterm --headlessno longer connects to the WindowServer (macOS). A headless
instance built the real AppKit event loop, and creating its application object opened
a WindowServer connection, so WindowServer ran a synchronous privacy check of the
binary on its own main thread for every headless launch: one per idle instance, 50 in
one run of the headless integration tests. From a build directory holding a very large
number of files that check has outlasted WindowServer's watchdog and taken every window
on the machine down with it. A headless launch now runs a display-free event loop with
no application object, so neither opens a WindowServer connection and LaunchServices
holds no record for the process. (A headless render on the GPU of a Mac with several
GPUs, none of them low-power, still asks Metal for the system default device, which
does connect.)aterm ctl chromeon a headless instance now answersmenu (none)(it
answered AppKit's default menu, which only existed because of that object), and a
headless instance paces its frames at the fixed 8 ms interval, as a display-free Linux
run always did. -
Vi mode moves by the text you see when the view is scrolled back. Scrolled back, a
motion on a line of the live screen (w,e,b,^,%,{,},f,t) read the
history line that many rows above it and landed mid-word;H,MandLjumped to the
live screen instead of the top, middle and bottom rows on view; and output that scrolled
the screen left the cursor on its row while its text moved up, so it sat on the wrong line.
Every motion now reads the line the cursor is drawn on, and the cursor moves with its text. -
aterm pkg verifyno longer calls an untouched install drifted. On a Mac's default
case-insensitive disk, an archive that laid two directories whose names differ only in case
or Unicode form (Dir/anddir/) merged them on disk while aterm recorded both, and a
home folder on an HFS+ disk stored an accented name under other bytes than the archive's, so
the install's recorded fingerprint described files that were not there. Such an archive is
now refused at install, with nothing left behind. -
A Containment shell can no longer change your preferences or register a login item.
Under--containment containment(aterm --sandbox), a contained program could write any
app's preferences (defaults write), which the macOS preferences daemon saves outside the
sandbox, and could ask the ServiceManagement daemon to register a login item or launch
daemon that runs outside the sandbox later. Both are refused now; shells, git, Python,
compilers andcodesignwork as before. -
A program's output can no longer change what Escape and Enter send. Output holding
the sequence a Windows console host uses to ask for key records (catof a file, an ssh
session) switched the tab's Escape, Ctrl+[, Alt+[, Alt+Backspace and Shift/Ctrl+Enter to
Windows key-record sequences for every program after it, until a reset: vim read them as
stray keys, and an agent's Escape did not stop it. Only a Windows console host turns that
mode on now; a web host in front of one turns it on withset_win32_input_enabled. -
Dropping a file into PowerShell or Git Bash can no longer run code from its name
(Windows). A dropped or pasted file whose name held$(…), a backtick or a curly double
quote (a download, a file from an archive) ran a command when you pressed Enter. Such a
name is now inserted in single quotes. -
Pasting text that holds a NUL character or half an emoji works (macOS). A clipboard
holding a NUL character pasted only the text before it, and one holding half of an emoji
(left by an app that cut text in the middle of one) pasted nothing. Copied text beginning
with an invisible byte-order mark (U+FEFF) lost it. Text now crosses the clipboard, input
methods, the tab-rename field and dropped file names exactly, and a lone half of an emoji
shows as �.