Skip to content

zgx: Activity sidebar, with Waiting and Sleep in the engine - #1262

Merged
wingleeio merged 16 commits into
zeron/zgxfrom
zgx/activity-sidebar
Nov 7, 2026
Merged

wingleeio merged 16 commits into
zeron/zgxfrom
zgx/activity-sidebar

Conversation

@wingleeio

@wingleeio wingleeio commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

This is a beta update that ships together with the stable engine release. It adds a sidebar view called Activity, plus three engine features it depends on: Waiting, synced Sleep, and Woke.

Activity (zgx)

  • Turning it on: the sidebar's … menu, or Settings → Activity.
  • The list: one list of every chat, newest return at the top, with Pinned above it.
  • Shelves at the bottom of the sidebar, folded until opened:
    • Working: running, or waiting on background work that will wake the agent.
    • Asleep: the chat's corner counts down until it wakes.
    • Archived.
  • Options set aside while it's on: Organize, Sort, Active when collapsed, Empty projects, Show archived (always on here), and Create section are disabled. "Move to" leaves the chat menu.
  • Sleep (right-click a chat):
    • Preset times: in 1 hour, in 3 hours, this evening, tomorrow, next week. Each shows when it wakes, in local wall-clock time.
    • Custom… opens a new ds.DatePicker in a dialog.
    • Wake wakes it.
  • Woke: a woken chat shows a new alarm-clock glyph (status-woke, yellow) until it's opened.
  • Stop waiting appears on a chat that is waiting on work its agent marked. Use it when a dev server was marked by mistake.
  • Settings → Activity: the view itself, the Working shelf, how Sleep works, and Archive idle chats (Never by default, or 1/3/7/14/30 days).
    • Auto-archive skips pinned, open, asleep, woken, under-way and waiting-on-you chats.
    • A chat you unarchive isn't archived again for being old.
  • New ds.DatePicker: a month grid plus a 15-minute time select, keyboard support, days before min disabled, cells changed in place. It has a gallery page and 10 tests.

Waiting (engine)

A turn that ends while its agent waits on background work that will wake it now reads Waiting, not finished. "Finished" is announced once, when the agent is actually done.

  • What counts as waiting:

    • A runtime that brings its agent back on its own declares it.
      • Claude Code: verified live on 2.1.319. The CLI started a new turn 0.1 s after a background shell ended.
      • Muse: starts its own wake turns.
      • Codex: verified live on 0.167. It doesn't wake its agent for a finished background terminal, so it doesn't declare it.
    • On such a runtime, background agents always count.
    • A background process counts once the agent says so with the Zeron MCP tool wait_on_background. That call is pinned to the agent's own chat by the agent gate.
    • The tool is offered only on runtimes that wake their agent (Harness::wakes_on_background: Claude Code and Muse). On Codex, Pi or a registry agent, a turn that ends means the agent is done, so the tool isn't listed and can't be called.
    • A dev server left running never counts.
  • Holding the completion back: the engine withholds the completion marker while the chat waits. That one change fixes the desktop banner, the chimes, the phone push (the edge already keys off the marker) and MCP wait_for_turn (which also now waits through a wait).

  • Every way a wait ends:

    Event Result
    The wake turn starts Working from that moment. Claude's start message is now passed on to the engine instead of being dropped.
    The work ends and no wake turn starts within 15 s The held completion is recorded.
    The person writes The new turn takes over.
    The person presses Stop waiting (StopWaiting, forwarded to the chat's host) The marks are released.
    The run ends: stopped, crashed, reaped or replaced The held completion is still recorded, unless the person stopped the run.
    The engine dies Its row goes stale, and every client reads the turn as finished and unseen.
  • Instructions: wherever the tool is offered, the rule for when to use it is in the tool's own description and the Zeron MCP server's initialize instructions. A Claude Code chat run also gets it in its system prompt, as a short --append-system-prompt note. Live probes on 2.1.319 showed that matters: with the MCP text alone, Sonnet never called the tool, and with the note, Sonnet and Opus both did. Muse tracks its background agents itself, so it needs no note.

  • Look: in zgx, Waiting is drawn exactly as Working: the same ring, in the same hue. The row title is strong, the chat counts toward a tab's corner, and a folded place keeps it showing. Its tooltip still reads "Waiting".

Sleep (engine, synced)

  • Chat.sleep {until, at, wokeAt} is stored field by field on the chat row, so it syncs to every device. It's set by Mutate setChatSleep, which agents can't call.
  • The chat's host wakes it early the moment it starts asking for the person or fails. A question that was already open when it was put to sleep doesn't wake it.
  • Woke shows until the chat is seen after it woke.

One status rule

  • The zgx host's own copy of the status rule is replaced by proto's (display_status_from, which takes a chat's seen marks so raw rows aren't cloned).
  • The old desktop app has no Waiting of its own: it reads Waiting as Working, so it draws nothing new.
  • Mobile shows Waiting as Working until the apps draw it themselves.

What behaves differently

  • With Activity off, in the zgx app:
    • A run that went quiet while working reads idle rather than done, as on every other client.
    • A terminal's own activity now counts toward status.
    • Archive and the updater's "running chats" count also cover Waiting.
  • Everywhere:
    • A turn that ends into a wait no longer pings "finished" until the agent is done.
    • wait_for_turn returns at that point too.

Tests

  • proto 117, including stale waits reading finished and sleep states.
  • doc 169, including sleep set, wake and clear, cross-device last-write-wins, and a lenient waiting.
  • harness: background 14, a Claude fake-CLI scenario replaying the live 2.1.319 frame order, and a test that only a chat's run gets the note.
  • engine: 7 wait-lifecycle tests on a scripted runtime, plus an agent-gate test.
  • mcp: includes tests that the tool and its instructions appear only on a runtime that wakes its agent.
  • zgx host: session tests.
  • zgx UI: Activity (11) and DatePicker (10). The sidebar set has the same 5 failures as the untouched base.
  • lint: zgx lint ui reports 0 errors.
  • Unrelated failures: 2 Claude skills harness tests fail identically on the base.

🤖 Generated with Claude Code

wingleeio and others added 10 commits November 6, 2026 14:07
The sidebar's "…" gains Activity: one list of every chat, the one that
came back last at the top, with pinned above it and three shelves at its
foot, folded until opened: Working (a chat while its agent runs, back at
the top a moment after it stops), Asleep (chats put to sleep from their
menu until a time, woken early by a new question, an approval or a
failure) and Archived. Grouping, sorting, sections and the folds that
only groups have are out of reach while it's on. Settings → Activity
holds the view, the Working shelf, what Sleep does, and archiving chats
idle for a number of days (never by default; never pinned, working,
asleep or waiting on you).

Off, the sidebar is as it was. Sleep and the settings are this device's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: zeronsh[bot] <346184242+zeronsh[bot]@users.noreply.github.com>
…ynced rows

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…wake its agent

A runtime that wakes its agent when background work ends (Claude Code,
live-verified 2.1.319; Muse) says so. Its background agents are waited
on, and a background process once the agent says it waits on it
(AwaitBackground, scoped to the caller's own chat). A finished turn with
such work parks into a wait: the session reads Waiting and the
completion is held back until the wake turn ends it, or the work ends
with no wake (15 s grace), or the run goes. The person's StopWaiting
releases it. The wake turn is Working from its start, not its first
words.

A chat's sleep is synced on its row (setChatSleep), and its host wakes
it the moment it starts asking or fails.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…l; mobile shows it as working until it draws its own

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…leep through it

The zgx host's own copy of the status rule gives way to proto's
(display_status_from, taking a chat's seen marks so raw rows needn't be
cloned into Chats). What behaves differently: a run that went quiet
while working reads idle, not done, as on every other viewport; a
terminal's own activity counts. Each chat's row carries what its agent
waits on and its sleep, and the host looks again as a sleeper's time
comes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…host

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… Stop waiting

Sleep is the engine's now (synced, woken early by the chat's host); a
chat waiting on background work that will wake it is under way, in
Working. Woke wears an alarm until looked at. Sleep's menu gains
Custom… (a new ds.DatePicker), and a chat waiting on work its agent
marked gains Stop waiting. Sleep times are local wall-clock times
(Luau's os.time reads a table as UTC). Activity's one timer ticks a
minute and works only while a chat sleeps or auto-archive is on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ver sleeps one

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@wingleeio wingleeio changed the title zgx: Activity sidebar zgx: Activity sidebar, with Waiting and Sleep in the engine Nov 6, 2026
wingleeio and others added 6 commits November 6, 2026 15:59
As wide as its dialog, seven even columns; the chosen day the segmented
control's selected wash, today a dot of the accent, past days the only
dim ones and other months' days left blank (a sixth row only for a month
that needs it); the month's arrows on the grid's edge; the time of day on
its own row under a hairline. Sleep → Custom… opens on tomorrow at 9 and
says when the chat wakes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…when it couldn't

Every part starts on the dialog's left edge and ends on its right (the
days are boxes spread edge to edge), its parts one gap apart, rows a
compact 32. The moment chosen is the dialog's subtitle. A sleep or wake
the chat's host refuses says so; an engine from before Sleep (it doesn't
know the request) says Zeron there needs an update.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hey wait

- Waiting draws exactly as Working in zgx: the same ring and hue, a strong
  title, counted in a tab's corner and kept showing in a folded place.
- A Claude Code chat run gets a short --append-system-prompt note on when
  to call wait_on_background (live probes: Sonnet ignored the MCP text
  alone; Sonnet and Opus both called it with the note).
- The old desktop app draws nothing new: it reads Waiting as Working.
- Zeron v2's base record re-blessed (it named a stray .orig file).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: zeronsh[bot] <346184242+zeronsh[bot]@users.noreply.github.com>
On Codex (and Pi, registry agents) a turn that ends is the agent done, so
the tool and its instructions aren't offered there at all: the engine marks
Zeron's server with ZERON_WAITS_ON_BACKGROUND=1 only when the harness says
it brings its agent back as background work ends (Claude Code, Muse), and
Claude's system-prompt note follows the same flag.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: zeronsh[bot] <346184242+zeronsh[bot]@users.noreply.github.com>
zeron/zgx's idle fix publishes a chat's live state only when it changed;
it now judges that from the sessions as this branch reads them (the shown
indicator, waits, subagents, the outcome), so a change in what a chat
waits on is shown. Its heartbeat test's rows carry a deviceId, as the
engine's do, since a row without one is no session.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: zeronsh[bot] <346184242+zeronsh[bot]@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: zeronsh[bot] <346184242+zeronsh[bot]@users.noreply.github.com>
@wingleeio
wingleeio merged commit 9685e54 into zeron/zgx Nov 7, 2026
17 checks passed
@wingleeio wingleeio mentioned this pull request Nov 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant