Something went wrong. Try again.
small gleam coding and persistent agent daemon with a detachable cli and a canvas ui forked from okami.mom/albedo
Something went wrong. Try again.
README.md
UI review kit #
A private daemon with seeded chats, albedo web on it and a Chrome page, driven
from an albedo python kernel, for looking at the web client by hand or for a
fan-out of reviewer agents. Opt-in; nothing here runs in the gate.
seed.pybuilds/tmp/albedo-review(or--base, or$ALBEDO_UX): a daemon snapshot, a web build indist/, two git workspaces inws/, andseed/, a home with ten named chats whose replies cover markdown, code, tables, thinking, tool cells, a file edit and a failed turn.replies.pyis the fake model's script (test/e2e/fake_provider.py): a message with slow, hang, fail, tool, start jobs (three background jobs), start agents (three child agents), edit, think, code, table or long gets that kind of reply; anything else a short markdown one.kit.pystarts a run on a copy of the seed home and drives the page.kit.scenarios()lists the boardsload()builds through the UI.
running a review #
nix develop -c python3 test/manual/ux/seed.py # again after daemon or web changes
import sys; sys.path.insert(0, "test/manual/ux"); import kit
ui = await kit.start("dock") # runs/dock/{home,shots}; width=, height=, dark=, reduced_motion=, dist=
await ui.load("sections") # first load builds the board, later ones restore it
await ui.windows(); await ui.layout() # w0, w1, ... and the tree, section names quoted
show_image(await ui.shot("sections"))
await ui.drag(a, b) # returns the dock hint and preview seen before letting go
await ui.hold(a); await ui.probe(x, y); await ui.release(x, y)
await ui.palette("layout: canvas"); await ui.key("ArrowRight", kit.ALT | kit.SHIFT)
await ui.say("w2", "slow please"); await ui.errors()
await ui.mark(); ...; await ui.remounted() # windows made again since mark(), [] after a move
print(await ui.stop()) # [] when nothing is left running
To check a change, await kit.build(path) and kit.start(..., dist=path).
To check the tethers, import tethers_check; await tethers_check.check(ui) runs
the flows that move a line's target and raises on any stale tether:.
reviewer brief #
Give each reviewer one area, the scenarios to start from, and what to try
there. They look and report; they do not edit the checkout. Each one starts its
own run, reproduces a finding twice before reporting it, and ends with
await ui.stop(). The report, in a file and in the mail body:
- one line: what was covered and for how long.
- findings, most important first: title · broken / confusing / sloppy / nit · scenario and exact steps · what happens vs what was expected · screenshot paths · confidence sure / likely / taste.
- what works well, briefly.
- outside my area.
- kit or setup notes: what got in the way.
gotchas #
load()swaps the boards only. Messages sent and notes made stay in the daemon;kit.start()again for a clean home.- A theme picked in settings or with
palette("theme: …")is saved and beatsmedia(dark=…)untilpalette("theme: system"). key()sends what a US keyboard does:key("!")orkey("1", kit.SHIFT)is ⇧1, letters type themselves, Enter clicks a focused button.page.pressrefuses" "and"["; usekey().- Text fields:
ui.type(text)inserts;key("Backspace")andkey("a", kit.META)edit. The composer is a contenteditable.editor;say()drives it. click()hovers first and leaves 80 ms between press and release; some controls ignore a bare CDP click.- A tile under 160 px refuses every drop ("no room"). Scenarios check that their tiles stay at 160 px or more at 1440×900; keep new ones that way.
- A floating note dropped over another float lands on that float, not the canvas under it.
errors()collects page errors from every load; no listener to re-add. It also holdsstale tether: …records:start()setswindow.__albedoAudit, so every 500 ms at rest the tethers compare what they draw with what a fresh frame would, and a difference means something moved a line without waking it.tethers_check.pydrives the flows that could.shot()saves and returns a path without showing it;show_image(path)orshot(label, show=True)when you want to look.- Kernels outlive their daemon on purpose;
stop()reaps what runs under the run's home and returns anything still alive. - Workspaces in
ws/are shared by every run, so file edits pile up there until the next seed.