Skip to content

Releases: scgopi/GraphCode

0.1.49-beta3 — the unlanded commit count is the real one

Choose a tag to compare

@scgopi scgopi released this 25 Aug 05:27

A correctness fix on top of 0.1.49-beta2, found by reading the sweeper's own output.

The commit count on an unmerged worktree was always 1

The reading that measures how much of a branch has landed takes the nearest answer across the default branch and its remote-tracking counterpart. Its accumulator was seeded with the value a failed read falls back to — 1 — so min clamped every real count down to it:

Branch Actually outstanding Row said Row says now
four commits 4 1 commit not in main 4 commits not in main
forty commits 40 1 commit not in main 40 commits not in main

The merged/not-merged verdict was never affected — a merged worktree still read as merged, and an unmerged one still stayed out of the safe tier. Only the number was wrong, and that number is the whole point of the line: it is what the row is telling you is at stake.

The fallback now belongs only to a read that actually failed.


Install: download the DMG, drag to Applications. Signed with a Developer ID and notarized by Apple.

0.1.49-beta2 — worktree hygiene believes your merged PRs

Choose a tag to compare

@scgopi scgopi released this 25 Aug 04:49

Worktree hygiene had two blind spots, and they compounded: it did not believe your merged PRs were merged, and when you removed a worktree anyway it could quietly fail to.

Merged PRs now read as merged

Whether a branch had landed came from git cherry against your local default branch. That answers wrongly three ways, all of them everyday:

Case What the sweeper said Why
GitHub "Squash and merge" of a multi-commit PR 3 commits not in main, forever the squash arrives as one combined patch that matches none of the three commits
PR merged on GitHub, nobody has fetched since N commits not in main the merge is in origin/main; your local main is behind
Merged PR whose branch GitHub deleted not pushed — never reclaimable @{upstream} reads "gone" ever after

All three are fixed. A squash merge is now detected by replaying the branch's whole diff as one commit on the merge base and asking git whether that patch is upstream; landing is measured against origin/<default> as well as the local branch; and being unpushed no longer holds a merged worktree back — once the work is in the default branch, an unpushed tip is nothing left to lose.

A landed branch also says so first now, whatever else is wrong with the directory. A merged PR whose folder has build residue used to read 1 file uncommitted and never mention the merge at all; it now reads merged into main · 1 file uncommitted.

A removal that fails says why

Every removal was wrapped in a swallowed error. Git's refusal went nowhere, the sheet closed on a click it had not carried out, and the row was back on reopen with nothing said.

The sheet now stays up until the removals answer, and names what it could not take:

  • git refused it — in git's own words
  • a loop claimed the worktree between selecting it and removing it
  • it grew uncommitted files since the list was built, so it is refused rather than half-forced: whether to force is decided on what git says now, but consent is still yours

Install: download the DMG, drag to Applications. Signed with a Developer ID and notarized by Apple.

0.1.49-beta1 — workspaces switch in the order you made them

Choose a tag to compare

@scgopi scgopi released this 25 Aug 01:27

Fixes #175.

Workspaces are listed in creation order

They were sorted alphabetically, so making a workspace whose name sorted early moved every ⌥⌘n behind it onto a different workspace. The numbers are muscle memory, and muscle memory cannot survive a list that reshuffles.

The list is now the order you made them in — Default first, then each one behind it — which only ever appends. Renaming one leaves it where it is, too.

⌘` steps to the next workspace

New in File ▸ Workspace:

Shortcut Does
⌘` Next workspace, wrapping round at the end
⌘⇧` Previous workspace

Both walk the same list the ⌥⌘n numbers are drawn from. Taking these two from the system is safe here: a workspace is a separate instance with one window, so macOS's own window-cycling has nothing to cycle within any of them.

The shortcut docs, the README and the in-app tour all say so now.


Install: download the DMG, drag to Applications. Signed with a Developer ID and notarized by Apple.

0.1.48 — Main loops, and OpenCode as a fourth backend

Choose a tag to compare

@scgopi scgopi released this 24 Aug 12:04

The loop type you start from is now called Main, and OpenCode joins as a fourth backend.

Sketch is now Main

The loop you reach for when the work has no shape yet is called Main everywhere you see
it: the card and picker label, onboarding, the draft and promotion forms, the messages the
graph gives when it refuses something, and the CLI's help and --type token.

--type main works now; --type sketch still does too, so existing scripts keep running.

It also takes the brightest slot in the palette — near-white rather than mid grey — and a
house glyph in place of the scribble. It is the loop you start from, and it now looks like
the centre rather than a margin note.

Nothing changes on disk. The identifier and stored value are still sketch, the same
precedent as composite storing as proactive. Existing graphs decode unchanged, and an older
graphcoded or graphcode CLI in ~/.graphcode/bin still reads graphs the new app writes.

OpenCode as a fourth backend

Alongside Claude Code, Copilot and Codex, loops can now run on OpenCode. Pick it in
Settings, in the new-workspace starter, or with --backend openCode from the CLI.

Presence, activity, token usage and session resume all work, delivered through a plugin
handed to OpenCode via OPENCODE_CONFIG — the route that merges over your own OpenCode
config rather than replacing it. It writes the same session labels Claude Code's hooks do, so
every existing reader in GraphCode serves OpenCode without changes. Sub-agent sessions are
filtered out so they don't appear as loops of their own.

A new OpenCode Permissions setting sits under Settings → Permissions, defaulting to
auto.

Not yet: the summary rail (OpenCode keeps its transcript in SQLite), export and import, and
remote-host presence.

This backend is new and lightly exercised. It was built against OpenCode 1.18.21 with the
plugin driven under test, but the machine it was developed on had no working model provider,
so a full end-to-end run with real tool calls hasn't happened yet. The other three backends
are unaffected — if you don't select OpenCode, nothing here changes for you.

Install

brew install --cask scgopi/tap/graphcode

Already installed: brew upgrade --cask graphcode, or Check for Updates in the app.

0.1.48-beta1 — Sketch loops are now Main loops

Choose a tag to compare

@scgopi scgopi released this 24 Aug 11:53

Sketch loops are now Main loops — and OpenCode joins as a fourth backend.

Sketch is now Main

The loop type you start with when the work has no shape yet is called Main everywhere you
see it: the card and picker label, onboarding, the draft and promotion forms, the messages
the graph gives when it refuses something, and the CLI's help and --type token.

--type main works now; --type sketch still does too, so scripts don't break.

It also takes the brightest slot in the palette — near-white rather than mid grey — and a
house glyph in place of the scribble. It is the loop you start from, and it now looks like
the centre rather than a margin note.

Nothing changes on disk. The identifier and stored value are still sketch, the same
precedent as composite storing as proactive, so existing graphs decode unchanged and an
older graphcoded or graphcode CLI in ~/.graphcode/bin still reads graphs the new app
writes.

OpenCode as a fourth backend

Alongside Claude Code, Copilot and Codex, you can now run loops on OpenCode. Pick it in
Settings, in the new-workspace starter, or with --backend openCode from the CLI.

Presence, activity, token usage and session resume all work, delivered through a plugin
handed to OpenCode via OPENCODE_CONFIG — the route that merges over your own OpenCode
config rather than replacing it. It writes the same session labels Claude Code's hooks do, so
every existing reader in GraphCode serves OpenCode without changes. Sub-agent sessions are
filtered out so they don't show up as loops of their own.

There's a new OpenCode Permissions setting under Settings → Permissions, defaulting to
auto.

Not yet: the summary rail (OpenCode keeps its transcript in SQLite), export and import, and
remote-host presence.

Worth knowing this is new and lightly exercised. It was built against OpenCode 1.18.21
with the plugin driven under test, but the machine it was developed on had no working model
provider, so a full end-to-end run with real tool calls hasn't happened yet. If you use
OpenCode, this is the build to try it on — and to report what breaks.

Also

The Star buttons on graphcode.app open the repo in a new tab and show the live star count.
Site only.

Install

brew install --cask scgopi/tap/graphcode@beta

Already on the beta channel: brew upgrade --cask graphcode@beta, or Check for Updates in
the app.

0.1.47 — the starter means what it shows

Choose a tag to compare

@scgopi scgopi released this 24 Aug 01:30

A targeted fix on 0.1.46's Workspaces starter, not a feature release.

The new-workspace starter applies the agent it shows you

The starter asks which agent runs a new workspace's loops, and preselects the one the
workspace you created it from uses — a filled checkmark and a SAME AS badge on that row.

Only a tap wrote the choice. So if the preselected agent was already the one you wanted and
you simply pressed Start Working, nothing was written and the workspace ran on the
built-in default. Tapping two rows in a row worked, which is what made it look arbitrary.
The checkmark was showing you a selection the app wasn't going to honour.

Start Working, Skip and Escape now all apply whatever is selected on screen. Taps
still apply immediately, and a second dismissal can't write the choice twice. The one case
that keeps the old behaviour is a workspace whose starter never opened at all — no dialog, no
suggestion, nothing written.

If you created a workspace on 0.1.46 and accepted the suggested agent without tapping it,
that workspace is on the built-in default.
Check it in that workspace's Settings; new ones
are correct.

Everything else is 0.1.46 — see its notes
for Workspaces.

Install

brew install --cask scgopi/tap/graphcode

Already installed: brew upgrade --cask graphcode, or Check for Updates in the app.

0.1.47-beta1 — the starter means what it shows

Choose a tag to compare

@scgopi scgopi released this 24 Aug 01:08

The new-workspace starter now applies the agent it shows you.

The bug

The starter asks which agent runs a new workspace's loops, and preselects the one the
workspace you created it from uses — a filled checkmark and a SAME AS badge on that row.

Only a tap wrote the choice. So if the preselected agent was already the one you wanted and
you simply pressed Start Working, nothing was written and the workspace ran on the
built-in default. Tapping two rows in a row worked, which is what made it look arbitrary.

The checkmark was showing you a selection the app wasn't going to honour.

The fix

Start Working, Skip and Escape all apply whatever is selected on screen. Taps
still apply immediately, and a second dismissal can't write the choice twice.

The one case that keeps the old behaviour is a workspace whose starter never opened at all —
no dialog, no suggestion, nothing written.

If you created a workspace on 0.1.46 and accepted the suggested agent without tapping it,
that workspace is on the built-in default.
Check it in that workspace's Settings; new ones
are correct.

Install

brew install --cask scgopi/tap/graphcode@beta

Already on the beta channel: brew upgrade --cask graphcode@beta, or Check for Updates in
the app.

0.1.46 — Workspaces

Choose a tag to compare

@scgopi scgopi released this 24 Aug 00:24

A workspace is a whole second GraphCode: its own projects, its own loops, its own daemon, in
its own window.

File ▸ Workspace ▸ New Workspace… (⌥⌘N) makes one. It lives in its own directory
beside the default — ~/.graphcode-<name> — and shares nothing with the others, which is
the point: unrelated lines of work stop competing for one sidebar. It gets its own Dock tile
and can sit on a second screen.

Switching. ⌥⌘1 … ⌥⌘9, or the switcher at the foot of the sidebar, which shows each
workspace's loop count and whether a window already has it open — so switching is a decision
rather than a guess.

Managing. Rename and Delete live in Manage Workspaces, where each row shows what that
workspace holds and says why a row can't be acted on. Deleting takes the daemon out of
launchd, ends that workspace's terminal sessions, and moves the folder to the Trash
recoverable until you empty it. The Default workspace, the one you're in, and any a second
window has open are never offered.

A new workspace asks once which agent runs its loops, preselected to whatever the
workspace you created it from uses. settings.json lives inside each support directory, so
without the question a new workspace would quietly start on the built-in default rather than
the agent you actually work with.

Updates are the Default workspace's job. Every workspace is the same bundle in
/Applications, so the banner and Check for Updates appear there only — and installing
offers to close your other workspace windows first, waiting for them to actually go before
replacing the app underneath them.

Loops in different workspaces can still message each other straight into a running
session. Separate graphs, not a wall.

The first-run tour gains a page on workspaces, and anyone updating from before 0.1.46 gets a
one-time note explaining it. Its main point: nothing moved. Everything you already have
is in the workspace called Default.

There's a walkthrough with video at graphcode.app/#workspaces.

Also in this release

Starting a chain from a lane's entry dot, which now reveals the same connector handle a card
does and creates a top-level loop in that folder. The Graph view's loop menu grew to match
the sidebar's — New Child Loop, Pilot and Arm, Rename, Export and Import, Delete — working on
loops whose folder isn't the selected one.

The daemon now handles shutdown signals safely. It called exit from signal-handler context,
which is not async-signal-safe: an idle daemon always died cleanly, but a busy one could
deadlock until launchd escalated after about twenty seconds. Measured at 0.03s to exit now,
idle or under load.

One thing to expect on this update

The first update onto 0.1.46 pays one last slow daemon shutdown. The binary being
replaced predates the signal fix, so it's the old one shutting down. Every shutdown after
that is instant.

Install

brew install --cask scgopi/tap/graphcode

Already installed: brew upgrade --cask graphcode, or Check for Updates in the app.

0.1.46-beta9 — deleting a workspace works

Choose a tag to compare

@scgopi scgopi released this 23 Aug 22:45

Deleting a workspace works. Three defects in one dialog, all fixed.

It didn't delete

Clicking Delete Workspace in the confirmation silently deleted nothing. A
confirmationDialog clears its binding before running the button you tapped, so Delete
read state its own dismissal had already cleared and quietly did nothing at all.

It came back after being dismissed

The confirmation was a window-modal dialog raised while the Manage sheet was still
dismissing. AppKit deferred it and re-attempted it, so it reappeared seconds after being
sent away.

The workspace sheets are now one presentation, chosen from state — the window shows at most
one, ever. That also replaces the timing-based hand-off beta8 used to get Rename and Delete
out of Manage Workspaces, so those no longer depend on an animation finishing when it is
expected to.

It froze the app

Confirming ran the whole tear-down on the main thread. Booting the workspace's daemon out of
launchd waits for that process to actually exit — tens of seconds for a KeepAlive service
slow to die (29 seconds, measured). The window was frozen with the confirmation still on
screen the whole time, which is indistinguishable from a dialog that has stuck.

The tear-down runs in the background now and the sheet dismisses immediately.

One deliberate change

Return no longer confirms deletion. Escape still cancels. Deleting a workspace is not
something to arrive at by pressing the default key.

Still outstanding

graphcoded does not exit promptly on SIGTERM, which is why the boot-out takes around
29 seconds — the delete no longer blocks on it, but the daemon side is tracked separately as
issue #167 and is not fixed here.

Install

brew install --cask scgopi/tap/graphcode@beta

Already on the beta channel: brew upgrade --cask graphcode@beta, or Check for Updates in
the app.

0.1.46-beta8 — three workspace fixes

Pre-release

Choose a tag to compare

@scgopi scgopi released this 23 Aug 21:58

Three fixes for bugs reported against beta6 and beta7, all in the workspace surfaces.

The workspace name became unreadable once the sidebar filled

The name at the foot of the sidebar sat on a transparent strip. Space was reserved for it
but nothing was painted, so as soon as the project list grew past the fold, rows scrolled
underneath it and straight through it — the workspace name and its icon sitting on top of
moving text, both illegible.

It has an opaque bar material behind it now, the same glass the sidebar is made of.

A new workspace ignored the agent you picked for it

The starter asks which agent runs a new workspace's loops. The answer never reached disk, so
the workspace kept using Claude Code however you answered — in Settings, and for its first
loop.

The write went through the app's live settings singleton, and the starter is often the very
first thing in a freshly opened window to touch it, so the pick depended on that model
already existing. It now writes straight to that workspace's settings.json and syncs the
live model afterwards, so the answer lands whether or not anything has read a setting yet.

If you created a workspace in beta6 or beta7 and chose an agent other than Claude Code,
that workspace is still on Claude Code.
Change it in that workspace's Settings; new
workspaces get it right.

Rename and Delete in Manage Workspaces did nothing

A view presents one sheet at a time, and both bindings were being flipped in the same
update — so Manage stayed put and the sheet it was handing to never came up, leaving the
buttons looking inert.

Manage now closes first and the next sheet comes up after it has gone. New Workspace inside
Manage goes through the same hand-off.

Install

brew install --cask scgopi/tap/graphcode@beta

Already on the beta channel: brew upgrade --cask graphcode@beta, or Check for Updates in
the app.