Skip to content

Releases: nickthelegend/loom

Loom v1.0.1

Choose a tag to compare

@github-actions github-actions released this 20 Sep 23:55
2207b2f

Loom 1.0.1 — orchestra spawns its workers again

Three bugs found by opening 1.0 on a real project and watching it fail.

The plan was being thrown away before it ran

Every orchestra run planned tasks and started none. The Fleet showed every
agent idle, no task threads appeared, and the thread said:

Your reply had no ```loom actions block, so nothing ran.

…directly underneath a reply that plainly contained one.

The engine parses accumulated turn text rather than the logged message, and
that text was capped to its last 20,000 characters. A plan's block sits at
the end of a long reply, so the cap kept the closing fence and threw away the
opening one. The parser saw an unterminated block and correctly reported that
there was nothing to run.

Which means the better the orchestrator planned, the more certainly its plan
was binned
— a thorough orchestrator writes long task prompts, and long is
exactly what killed it.

Replaying one real run through the shipped parser, the logged reply against the
same reply after the cap:

id=176  len= 26551  logged=6 acts   capped=NULL
id=207  len= 28329  logged=5 acts   capped=NULL
id=213  len= 24296  logged=5 acts   capped=NULL
id=227  len= 28318  logged=5 acts   capped=NULL
id=234  len= 20297  logged=5 acts   capped=NULL
id=564  len= 51901  logged=8 acts   capped=NULL
id=570  len= 50836  logged=8 acts   capped=NULL

Seven consecutive plans — 6, 5, 5, 5, 5, 8 and 8 tasks — every one parseable
from the log, every one destroyed. All seven parse intact now.

The budget is far clear of any plausible reply, and when it is reached the
cut is made at the start of the actions block rather than at a blind character
offset. What protects memory can no longer decapitate the payload.

Answer an agent where it asked you

An agent stopping to ask something was one flat line with nothing to click:

⏸ claude-code asks: Want me to dig into the DBC integration specifically, or
get the working tree into a committable state?

To answer it you went to the composer — and in an orchestra thread the composer
aims at the orchestrator, so your answer went to the wrong agent entirely.
The one moment Loom exists to surface had the worst affordance in the app.

It is now a card you answer in place. The reply goes to the agent that asked,
read off the card rather than off whatever the composer is pointed at. A
question that plainly offers a choice becomes buttons:

dig into the DBC integration specifically · get the working tree into a committable state

Anything ambiguous falls back to the text box. A wrong guess would put words in
your mouth and send them to an agent, so it guesses at nothing: no question
mark, no clean or, no buttons.

A giant icon no longer eats the Board

Board → GitHub rendered a single enormous ⓘ filling the whole pane, with the
columns pushed out of view, whenever gh couldn't list pull requests — a
common state, so the footnote became the screen.

svg() emitted no width or height. Every icon depends on a CSS rule to
size it, and an icon in a container that forgot one has no intrinsic size, so
in a flex row it stretches to fill the line. .bnote was such a container.

Icons now carry a default size. CSS still wins, so every existing rule is
unchanged — what this buys is that the next icon dropped somewhere unstyled
looks slightly wrong instead of covering the screen.

Loom v1.0.0

Choose a tag to compare

@github-actions github-actions released this 20 Sep 21:19
82a2d54

Loom 1.0 — you can see what it did, and you can take it back

The 0.2 line got the fleet working: several agents, one baton, one brain, goals
split into parallel tasks. This one is about what that felt like to watch —
and what happened when you didn't like the result.

Five things, all of them found by using it rather than reading it.

Rewind

An agent turn can touch forty files. Until now the honest answer to undo that
was "read the diff and retype it".

So Loom writes down what the files were before every turn, and the turn's
Update(…) card offers Rewind. There is a Rewind… list under More for
the whole history, and loom rewind in the terminal.

It is a working tree, not a history. Rewinding restores what changed, removes
what was created, brings back what was deleted — and does not move HEAD, does
not touch your commits, does not edit the thread. What happened still happened;
the files just don't have to live with it.

Three things it will never touch. Checkpoints are captured with git add -A,
so .gitignore applies: your node_modules, your build output and your .env
are never read, never stored and never restored. .loom/ is ignored too, which
is why a rewind cannot eat the event log.

It is itself rewindable. A rewind saves what it is about to replace before
it replaces it, and hands that back — Undo the rewind in the thread, an id on
the command line. A one-way undo is a trap, and the one time that matters is the
time someone rewinds past work they meant to keep.

It refuses while an agent is mid-turn, naming who. Replacing the tree under
a running agent gives it a working directory that contradicts everything it has
read, and the damage lands in whatever it writes next.

Checkpoints live on hidden refs under refs/loom/checkpoints/, so no branch
listing, no stash and no git log ever shows them. The newest 60 are kept.

A transcript you can turn up

The thread showed one fixed level of detail and no way to change it. More now
has a transcript section:

Normal what it said and did
Thinking + reasoning
Verbose + raw payloads

Normal drops reasoning entirely rather than folding it away — the working out
is not the transcript. Verbose opens it and attaches the raw payload to tool
calls and to the orchestrator's brief, the two places a one-line summary is
standing in for something much bigger.

The level is remembered per project, so reading one run at Verbose doesn't turn
every other project's thread into a wall of JSON.

And output you can reach the end of. A long block used to sit in a scroll
box you could see the start of and never the end of — the orchestrator's
{"actions": […]} plan, most visibly. Code now wraps instead of scrolling out
of the bubble, and every block carries a copy button.

Orchestrating from Main stays in Main

Orchestrating from a thread abandoned that thread. The run opened one of its
own, titled after the goal, and the app walked you into it — so the goal you
typed and every word of its answer lived somewhere you hadn't asked for.

Now the orchestrator answers where you asked. Each task still gets its own
thread, and each task row in the transcript opens it —
t3 · Document data model → Antigravity · done is a link now, not a label. They
were findable only by hunting the sidebar for a title you half remembered.

A run records whether it borrowed its thread. Replying in a run's own thread
steers the run for good; a borrowed thread stops answering for the run when the
run ends, so Main goes back to being Main instead of forwarding every message
you ever send to a finished goal.

A thread says who is working in it, and whether it is still going

Two bugs that were the same bug: a thread couldn't answer questions the daemon
already knew the answer to.

  • The wrong logo. A task thread claimed to be whoever held the project
    baton, so during a run with four workers a Codex task and an Antigravity task
    both wore the Claude Code mark. The header now comes from the task.
  • No sign of life. A thread row showed nothing about whether its work was
    running, done or failed. It now carries a mark — pulsing while it runs, green
    when it lands — and nothing at all when the daemon can't say, rather than a
    guess.

Models in Orchestrate

Orchestrate could pick who ran a goal and never what they ran it on. Every
agent chip — the orchestrator and each worker — now carries its model beside its
permission chip, click to change.

And an API model can join the cast without leaving the composer: a dashed
+ model chip adds one and opens its picker straight away, because the state
it lands in with no model chosen is the one state it cannot run in. Until one is
picked the chip says so in warning colour, and Orchestrate refuses to start —
naming the agent and opening its list — rather than failing three tasks into the
run.

Two things the model list itself was getting wrong: a model agent's list is
asked of the providers, and that case had no branch in the footer, so it printed
"no model list for this agent" directly above 446 of them. And it offered a
model agent a Default, which for that kind does not exist.

Install

brew tap nickthelegend/loom https://github.com/nickthelegend/loom
brew install --cask loom-desktop

Still unsigned, and still says so: Homebrew quarantines cask downloads on
purpose and this cask deliberately doesn't strip that, because it is the
protection that exists because the build is unsigned. First launch asks once.

Loom v0.2.6

Choose a tag to compare

@github-actions github-actions released this 20 Sep 15:43
e42fc31

Loom 0.2.6 — right-click, and a Setup that tells the truth

A small release, made entirely of things found by opening the app and looking
at it rather than by reading the code.

Right-click works now

A project — open, new chat, settings, rename, copy path, and remove.
Those were scattered: settings behind a gear, rename nowhere at all, and
removing a project only in loom projects --forget.

It says Remove from Loom, not Delete, and the confirm says the folder,
the history and .loom/ stay on disk — the route only unregisters. A menu item
that says delete and doesn't is as bad as one that says delete and does.

A thread — open, rename, pin which agent answers in it, forget. The main
thread's menu offers only what applies to it, rather than offering everything
and refusing half of it when you click.

Escape and any click outside close the menu, the arrow keys walk it, and it
flips rather than hanging off the edge of the window.

A composer that fits

That row was holding the model picker, the agent, a permission chip, MCPs,
Skills, a mic, Prompts, Plan and send — and wrapped on a narrow window.
MCPs and Skills are occasional settings, so they moved into a More menu
that also reaches Prompts and Attach. The skills count badge stayed on the
outside, because two skills are on is the part you need without opening
anything.

Setup tells the truth about your machine

  • Claude Code said "not installed" on machines where it is. Anthropic's
    installer puts the binary in ~/.local/bin, and Loom trusted PATH alone —
    which an interactive shell has and a detached daemon may not. Codex, Grok and
    Antigravity already looked in their known locations; claude-code was the one
    still guessing. Telling someone to reinstall software they already have is
    the worst kind of wrong answer, because they'll do it.
  • The Model (API) row said "couldn't confirm it's signed in" and printed a
    blank command. There is nothing to sign in to: it names the providers that
    have a key, and offers loom providers:set … when none does.
  • A new project no longer gets a model agent it can't use. That kind
    probes as available whenever any provider has a key — a true fact about the
    machine, and the wrong basis for a roster entry, because which model is a
    choice nobody has made yet. It landed with no options and refused every turn.

The desktop app says Loom

The menu bar said Electron. macOS takes that title from the running
bundle's Info.plist, not from app.setName() — which is why naming the app
in code never fixed it. CFBundleDisplayName is the lever: the packaged app
sets it, and a dev run gets a prestart script that stamps the disposable
Electron.app with the same name.

The .app filename is deliberately unchanged, because the Homebrew cask names
it and renaming would break every install that already has one.

If Setup looks wrong, restart the daemon first

Half of the above was a daemon that had been running since before the fixes
landed, serving answers from an older build. loom up --restart.

Loom v0.2.5

Choose a tag to compare

@github-actions github-actions released this 20 Sep 11:59
6e4a8f2

Loom 0.2.5 — an agent doesn't have to be a CLI

Every agent Loom drove was a command: claude, codex, opencode, grok,
agy. That was the right call — a CLI brings its own tools, its own session,
its own auth — and it meant your roster could only hold what somebody had
installed, and every turn cost whatever that CLI's subscription costs, whether
it was a four-hour refactor or a one-line summary.

This release adds agents that are models: an HTTP endpoint, any
OpenAI-compatible provider, a model you pick off a list. Nothing to install,
and on a provider's free tier, nothing to pay.

A model agent

loom providers:set openrouter --key sk-…     # or $OPENROUTER_API_KEY
loom models --free                           # what costs nothing today
loom agents:add model --as cheap --role reviewer \
  --model "google/gemma-4-31b-it:free" --tools

It streams into the thread like any other agent, shows reasoning as reasoning,
reports its token counts, holds the baton, and takes route steps. Out of the
box it's a thinker rather than an editor — planning, reviewing, summarising,
answering, routing, which is most of what a fleet does between edits.

Keys are never project config. .loom/config.json is committed in most
projects, so it names a provider; the key lives in the environment or in
~/.loom/providers.json at mode 0600. No route, log or listing hands one
back — you get the last four characters, which tells two keys apart and uses
neither.

Refusals are read, not guessed at. Each of these means something different
and gets a different answer:

the provider says Loom says Loom does
401 unauthorized client it refused Loom as a client, not your key stops
401 / 403 it rejected the key stops
402 dry pool no quota left for this model right now next model in fallbacks
429 it's rate-limiting this key next model in fallbacks
503 / 404 no channel for that model — the name may be wrong stops

Falling back on a 503 would hide a typo rather than fix it, which is why it
doesn't.

loom models asks each configured provider what it has right now, cached for
ten minutes and refreshable, free ones marked. A model list typed out by hand
goes stale; one that's asked for doesn't.

It can read the project, and write it if you say so

--tools adds read_file, list_files and search: read-only, inside the
project, .git and .loom refused, every path resolved and proven contained
before anything opens it. A reviewer that can't open the file it's reviewing is
being asked to guess.

--write adds write_file; --run "npm test" adds run with that
allow-list. Every write and every command is a card you allow or deny
first:

write_file — write src/app.ts: 40 lines (replacing 12) — fix the port
  [Allow] [Deny]

It asks in auto as well as ask, which is stricter than the mapping for
CLIs and deliberately so: a CLI in your roster is one you installed and signed
into, and a model agent is a name you picked off a provider's list an hour ago.
bypass is the only mode that doesn't ask. With nobody to ask, the answer is
no
— a write that went through because the UI wasn't wired up would be the
worst failure available here.

The allow-list is a prefix match on whole commands and there is no shell, so
npm test permits npm test --watch and refuses npm testify,
npm test; rm -rf ~, backticks, pipes and redirection. A tool is only offered
to the model when it can actually be used: no allow-list, no run tool at all.

Threads that remember who answers in them

A chat used to be a label on events — whoever held the baton answered
everywhere, so two threads couldn't be talking to two agents. Pin an agent to a
thread and it answers there whatever the baton is doing elsewhere: one thread
planning on a free model, one editing with Claude Code, neither waiting for the
other.

It doesn't take the baton. The baton is the write lock for work on the
repository; a conversation doesn't need it, and taking it would stop whatever
is actually working. The main thread still follows the baton — that's what
makes it the main thread.

Asking several models at once

loom ask --free --limit 3 "is this migration reversible?"

One prompt, one thread per model, all at the same time, each thread named after
the model that answered in it. With free quota, asking five models costs what
asking one costs — and which of these is right is a judgement a person makes
in ten seconds and a model makes badly. The agents are transient, so five asks
don't leave five agents in your roster, and one model failing leaves its error
in its own thread while the others answer.

Retrieval that can follow a synonym

The brain had three lexical channels and couldn't match how does login work
to a note about Supabase JWKS. brain.semantic adds an all-MiniLM-L6-v2
channel. Measured on the recall set that ships with the tests, recall@5:

lexical with the model
literal 1.00 1.00
word forms, typos 0.80 1.00
synonyms 0.50 1.00

It isn't a dependency and won't become one: the model is 23MB, the ONNX runtime
that executes it is ~470MB, so Loom asks you to install that
(npm i -g @huggingface/transformers) and behaves exactly as before when it's
missing.

Install it with Homebrew

brew tap nickthelegend/loom https://github.com/nickthelegend/loom
brew install --cask loom-desktop
brew upgrade --cask loom-desktop

The cask carries both architectures and is regenerated from the published
checksums by the release job, so it can't go stale. Check for Updates…
recognises a Homebrew install and offers to run the upgrade in Loom's own
terminal
— the one in the dock — so you watch it happen rather than having it
happen invisibly inside the app.

It does not get you past Gatekeeper and doesn't pretend to: Homebrew
quarantines cask downloads on purpose, and the cask deliberately does not strip
that attribute, because it's the protection that exists because this build is
unsigned. First launch asks once, as it does for a dmg you downloaded yourself.

(There is no free Apple Developer ID for open-source projects — the fee waiver
is for nonprofits, schools and government entities, and a free Apple ID cannot
sign for distribution at all. So: buy one, be one of those, or ship unsigned
and say so. Loom says so.)

Also

  • macOS Check for Updates… finds the build for your architecture,
    downloads it, and verifies its SHA-256 against the release's published
    checksums — a file that doesn't match is deleted, not opened — then opens the
    disk image for the drag.
  • loom team webhook --repo <r> no longer warns that a shared repo isn't
    shared. An empty cached team view was allowed to answer for the hub.
  • The README was audited against the code. Eight things it claimed had quietly
    stopped being true as features landed underneath them.

Loom v0.2.4

Choose a tag to compare

@github-actions github-actions released this 20 Sep 09:01
3b2ec9d

Loom 0.2.4 — a queue that waits, goals that share, routes that decide

The queue learned to wait

A queued prompt no longer means "next". It can wait for a time, until a
goal actually lands (merged, not merely finished), until that goal's
checks go green, or until the project has been quiet for a while. The
row says what it's waiting for, and a click releases it.

loom queue at 03:00 "run the migration"
loom queue after landed:o1 "update the changelog"
loom queue after green:o1 "cut the release"

Every branch reads a fact the daemon already has, so none of them can be wrong
in an interesting way — and a condition about a goal that no longer exists
releases the prompt rather than stranding it forever. The clock ticks only
while something is waiting on it.

Recipes. loom queue save ship keeps what's queued; loom queue run ship
replays it on any project. Steps remember their target by role, because an
agent id from one machine means nothing on another; a role this project hasn't
got becomes an Auto prompt rather than a refusal.

Reordering. Drag in the web app, and up/down on the phone, which had no way
to reorder at all. The arrows stay on both — the accessible path.

Goals: a cap, and more than one at a time

loom orchestrate --max-usd 2 stops a goal at its cap the way the team budget
always did: running work finishes, nothing new starts, the goal waits for you.
A project default lives in budgets.perGoalUsd, and a word lands in the thread
at 80%, because the halt shouldn't be the first you hear of a budget.

maxConcurrentGoals lets goals run side by side when their paths can't
collide
. A goal's scope is the touches its plan declares; one that hasn't
said what it touches counts as touching everything and waits. Anything not
provably disjoint queues with the collision named — waiting for "rework
billing" — both touch src/billing/** and src/billing/tax.ts
. Still one at a
time unless you ask for more.

Coming back to a project

A digest of what happened while you were away — goals, landings, failures,
a dead server, and what's waiting on you, newest first, each line clicking
through to the moment it came from. Nothing is written without an event behind
it, and a quiet night says nothing at all. loom digest --since 8 in the
terminal.

Notifications carry the question, not "an agent needs you" — and on macOS
you can answer from the notification. Nothing fires while you're already
looking at the conversation it would be about.

A pull request you asked for

With branch-per-card on, a card in review shows what a PR would carry: the
branch, its commits, its files, and the exact command. It opens only when you
press the button. Asking pushes nothing — publishing has never been implicit
here, and still isn't.

Routes: steps that decide whether to run

A route step can carry a condition on the previous turn, and is skipped when it
doesn't hold:

loom route 'planner,executor,reviewer?lines>200' "tighten the tax rules"

changed>N, changed<N, lines>N, lines<N, touched:<glob>,
!touched:<glob> — all read off the turn's own diff. That bar is the design: a
condition must be something Loom measured, never a judgement about whether
the work was any good; judgement stays with the LLM router. Unreadable
conditions are refused when the route is defined rather than silently never
matching, the first step can't be conditional (there's no turn before it), and
a skipped step says so in the thread with the numbers that decided it. Skipping
isn't failing: the route completes.

The baton can carry the work

With worktreePerAgent, handing A → B left B's checkout holding the state from
before A started. git.mergeOnHandoff merges agent/A into B's tree — and
refuses far more often than it merges: A's uncommitted work isn't on A's branch
(merging would deliver a convincing half of it), B's tree has to be clean, and
a merge already in progress is never stacked on. Each refusal says what to do
about it.

A conflict is left in place rather than aborted — those files are the thing
to resolve — and it's named at the top of the incoming briefing, in the handoff
event, and it stops a route instead of prompting a step on a tree full of
conflict markers.

Dark mode in the preview

Widths landed in 0.2.3; this is the other half. No API lets one document set
another's prefers-color-scheme — but Loom isn't outside the page: the proxy
served it and its stylesheets. So the bridge re-points the page's own
@media (prefers-color-scheme: …) rules, sets the UA colour-scheme, and makes
matchMedia answer to match (firing change, so an app that themes itself in
JavaScript re-renders). Every rewritten rule remembers the media text it came
with, so Auto is the page exactly as it shipped.

A page Loom isn't proxying says so instead of offering a switch that does
nothing, and the screenshot — a real browser — honours the scheme either way.
Both the width and the scheme ride along with what you send: Screenshot taken
at 375×812, dark mode
.

The desktop app can update itself, where that's honest

Help → Check for Updates… on Windows and the Linux AppImage: it
asks before downloading, installs on quit, and restarts only when you press
Restart. On macOS it refuses and says why — that build is ad-hoc signed,
and macOS only replaces an app signed by a certificate it already trusts — and
opens the releases page instead. A .deb is left to the package manager that
owns it. The release publishes the update feed for those two platforms and
deliberately not for macOS: advertising an update the OS will refuse to install
is worse than advertising none.

Also

  • loom team webhook --repo <r> no longer warns that a shared repo isn't
    shared. An empty cached team view was allowed to answer for the hub, and a
    view fetched before the share landed lists nothing.
  • Retrieval has a number now: recall@5 of 1.00 literal, 0.80 across
    word forms and typos, 0.50 across synonyms. The first two are floors a
    regression trips over; the third is the gap a dense channel would have to
    close.

Loom v0.2.3

Choose a tag to compare

@github-actions github-actions released this 20 Sep 05:48
2ab7359

Loom 0.2.3 — an Update button, and a Browser tab that runs your app

Loom updates itself

There are releases now, so Loom checks for one — a quiet pill in the status
bar, never a banner — and Settings → Updates has the button.

It says what it will do before it does it, because that depends on how you
installed it: a git checkout pulls, installs and rebuilds; a global npm
install
reinstalls itself; anything else is pointed at the release rather
than having a command guessed at and run over it. A checkout with uncommitted
changes is refused — that tree is yours. The commands run with their output
streaming, and the daemon comes back on the new build with the page
reconnecting to it.

From the terminal: loom update --check to look, loom update to do it.

(The desktop app still sends you to the release page: updating itself needs a
signed app, which needs a certificate. That's its own issue.)

The Browser tab becomes a real browser pane

It used to be an address bar and an iframe: you typed a port and hoped. Now
Loom knows what it's showing.

  • Your dev servers, run by Loom. Declared under servers in
    .loom/config.json and suggested from package.json — a suggestion you
    accept, never something that starts itself. Start, stop and restart from the
    rail or with loom servers.
  • State that's a fact, not a guess: running means a port answered,
    starting means the process is up and nothing is listening yet, and
    crashed carries the exit code it died with.
  • Server output under the page it serves, live — usually where the reason
    for a blank frame is — and a server that dies while an agent works against it
    says so in the thread.
  • The page reports back. Loom previews a server through its own proxy,
    which forwards everything (including the socket hot reload rides on) and
    injects one small script. The Page pane shows what the page logged and
    what it fetched, and one click puts a line in the composer as the context
    an agent needs.
  • Pick the broken thing. Click an element in the preview and its selector,
    text, size and markup land in the composer.
  • A camera that captures the live page into the composer, at the width
    you're previewing, using the project's own Playwright.
  • Width presets (Fit / 375 / 768 / 1280, remembered per project) and
    auto-reload when an agent changes what a server serves.

Nothing about a previewed page is rewritten — the injected script only reports,
and stays silent if any part of it fails.

Also fixed

  • An overridden loom/review no longer leaves its own "reviewing…" status
    pending for ever on a commit the owner already decided about.
  • A bad retarget of a queued prompt is refused when you make it, not when the
    queue reaches it.
  • A dev server that accepts a connection and never answers gets a 504 that says
    so, instead of a preview that hangs.
  • Five smaller ones found while building the preview: a buffered page keeping
    two framings, the hot-reload socket's first message pushed the wrong way,
    innerText being undefined on SVG icons, upgraded sockets blocking shutdown,
    and a restored Browser pane whose rail spun for ever.

Downloads

  • macOS: Loom-Desktop-0.2.3-arm64.dmg (Apple Silicon) or -x64.dmg (Intel)
  • Windows: the .exe installer
  • Linux: .AppImage or .deb
  • Android: loompad-0.2.3-android.apk
  • CLI: npm install -g github:nickthelegend/loom

The Android apk is signed with the project's release key. The desktop
installers are not signed by a certificate authority: on macOS the app is
ad-hoc signed, so right-click → Open the first time; on Windows, "More info →
Run anyway". Checksums are in SHA256SUMS.txt.

Full list of changes: CHANGELOG.md.

Loom v0.2.1

Choose a tag to compare

@github-actions github-actions released this 20 Sep 04:01
5741b2a

Loom 0.2.1 — the prompt queue, and a real Android build

Line up the next ones

Type while an agent is mid-turn, or while a goal is still running, and the
prompt waits above the composer instead of being refused or quietly swallowed.

  • Queue as many as you like. They run strictly one at a time, in order.
  • Each prompt says who takes it: one agent by name, the orchestrator
    (a whole new goal, started when the running one finishes), or Auto to let
    the router pick. Change a waiting prompt's target and the baton goes with it.
  • Edit, reorder, drop. Click a queued prompt to rewrite it (⌘⏎ saves, Esc
    cancels), move it up or down, or remove it — all before it runs.
  • Pause and resume. Stop pauses too: stopping a turn never silently
    discards what you lined up behind it.
  • A question holds the queue. If the agent stops to ask you something, the
    next queued prompt would answer a question you never read — so the queue waits
    and says who asked. Your reply goes out at once and lifts the hold.
  • A prompt enters the conversation when it is sent, not when it is queued,
    so the thread stays an honest record of what each agent was asked.

It survives a daemon restart (reloaded paused, so an hour-old queue doesn't
start itself) and it is the same queue everywhere: the web app, the desktop app,
the phone, and loom queue in the terminal — add, edit, to, move, rm,
clear, pause, resume.

Fixed

  • The v0.2.0 apk had no JavaScript bundle and would only open against a
    running dev server. This one is a release build with the bundle in it, signed
    with the project's release key — check it with
    apksigner verify --print-certs.
  • The macOS app is now a valid signed bundle (ad-hoc). codesign --verify --deep --strict passes; v0.2.0 carried only the linker's signature.
  • An overridden loom/review stays overridden. A review that came back
    after the owner had overridden it used to write failure over their decision
    — and, once that was fixed, to leave its own "reviewing…" status pending for
    ever on a repo that requires the check. Both are gone.
  • Agent turns are no longer blamed for Loom's own .loom/ files in a
    project that doesn't gitignore them.
  • grok-code and agy are detected from their own auth files instead of being
    reported signed-out, and the status bar says live, not offline, before a
    project is open.
  • A reply that lands after its window closed no longer throws from a redraw.

Downloads

  • macOS: Loom-Desktop-0.2.1-arm64.dmg (Apple Silicon) or -x64.dmg (Intel)
  • Windows: the .exe installer
  • Linux: .AppImage or .deb
  • Android: loompad-0.2.1-android.apk
  • CLI: npm install -g github:nickthelegend/loom

The Android apk is signed with the project's release key. The desktop
installers are not signed by a certificate authority: on macOS the app is
ad-hoc signed, so right-click → Open the first time; on Windows, "More info →
Run anyway". Checksums are in SHA256SUMS.txt.

Full list of changes: CHANGELOG.md.

Loom v0.2.0

Choose a tag to compare

@github-actions github-actions released this 19 Sep 08:34
f21448d

Loom 0.2.0 — Loom Teams

Several people, each with their own agents, on one GitHub repo — without
stepping on each other. Built in five phases (78 design decisions, in
docs/teams-architecture.md):

  1. See each other. Teammates' live agents, goals and the files they touch;
    a team feed of goals, PRs and CI. End-to-end encrypted: the hub can't read
    your goals.
  2. Stop colliding. Tasks declare the files they touch; overlaps need a
    decision; hard zones take one goal at a time; merge conflicts are predicted
    before anyone opens a PR; loom.team.json is the team's policy.
  3. One brain. What one agent learns, every agent knows — labelled by how
    sure to be. Canon lives in AGENTS.md, reviewed like code.
  4. Land safely. Failing checks are rerun, then fixed on the same PR; an
    agent from another vendor reviews; one click lands through GitHub's rules;
    stacks, Adopt, budgets, a merge-queue doctor.
  5. Runners. Your own always-on Loom takes your goals while your laptop
    sleeps; move a running goal there and bring it back. Deploy status and
    release notes.

Get started: docs/teams.md.

Downloads

  • macOS: Loom-Desktop-0.2.0-arm64.dmg (Apple Silicon) or -x64.dmg (Intel)
  • Windows: the .exe installer
  • Linux: .AppImage or .deb
  • Android: loompad-0.2.0-android.apk
  • CLI: npm install -g github:nickthelegend/loom

The installers are unsigned. On macOS, right-click → Open the first time; on
Windows, "More info → Run anyway". Checksums are in SHA256SUMS.txt.

Full list of changes: CHANGELOG.md.

Loom v0.1.0 — Codex (GPT‑5.6) orchestration + LoomPad

Choose a tag to compare

@nickthelegend nickthelegend released this 15 Jul 14:53

Loom — the shared-memory layer for AI dev environments. One brain across Claude Code, Codex (GPT‑5.6), OpenCode and Grok — plus the physical LoomPad (ESP32‑S3, hold‑to‑talk voice).

Downloads

Loom Desktop — native app that starts the daemon and pairs itself:

  • macOS (Apple Silicon): Loom-Desktop-0.1.0-arm64.dmg — ad-hoc signed, right‑click → Open the first time
  • Linux x64: Loom-Desktop-0.1.0-linux-x86_64.AppImage (or -arm64 for ARM) — chmod +x and run
  • Windows x64: Loom-Desktop-0.1.0-win-x64-Setup.exe

LoomPad Android app: loompad.apk — install (allow unknown sources) → open Loom → Scan QR code from the desktop's Connect a phone.

Install

  • CLI + TUI: npm i -g @loompad/cli → loom
  • Desktop: download for your OS above, or cd desktop && npm install && npm start
  • Web: loom pair → open the link

Codex & GPT‑5.6

Codex is a first‑class orchestrated agent (adapter drives codex exec --json, resumes threads, reads/writes the shared brain); every Codex turn runs GPT‑5.6. See the README → Codex & GPT‑5.6.