Skip to content

feat(sheets): an agent column can run a base agent, and arrives already pointing at one - #22

Merged
richard-epsilla merged 4 commits into
mainfrom
feat/agent-columns-pick-a-base
Aug 29, 2026
Merged

feat(sheets): an agent column can run a base agent, and arrives already pointing at one#22
richard-epsilla merged 4 commits into
mainfrom
feat/agent-columns-pick-a-base

Conversation

@richard-epsilla

Copy link
Copy Markdown
Contributor

The problem

A new sheet was never runnable. The builder agent cannot see the person's own agents, so it wrote harness_id: "" and told them to pick one in the column menu. The shipped templates ship blank for the same reason. So every route to a sheet ended at a Run button that refused on every column until you opened each menu in turn.

The missing piece

A base is a perfectly good answer, and the server already supports it: a base's id is its base name (codex, opencode, …), and _backend_of_builtin accepts it as a harness id directly. So a column can run one without anybody having configured anything first.

And unlike a chrn_ id, a base id is stable. That is what makes it safe for the builder to write one: it is not inventing an id it cannot see.

What changed

  • The picker lists base agents beside your own, under a heading for each. Bases come from /v1/bases and are filtered on what this deployment reports ready with an available model, never a list written down in the kit. Offering an uninstalled base would produce a sheet that looks configured and fails on the first row.
  • The builder names a base suited to the work. The skill documents the ids, and its validator accepts them (and now warns on a blank instead of requiring one).
  • The app fills any blank agent column with a base it has just confirmed this deployment can run. That covers the templates and every sheet written before this. Blanks only: a column pointing at an agent that no longer exists keeps refusing, because quietly re-pointing it would run something other than what the sheet says it runs.

The kit's own Harness stays excluded, since a sheet whose column runs the sheet's own agent is recursion with a file-write race in it. The base it happens to sit on is not excluded: different agent, own session, no interest in sheet.json.

Verified on the public VM

  • Asked for a sheet in one sentence. It came back with its agent column bound to codex, chosen by the builder itself (confirmed in the agent's own end-of-turn capture), and Run enabled without touching a menu.
  • An existing sheet with 5 unbound agent columns picked up the default on open, persisted it, and went from refusing to runnable.
  • The picker shows both groups: 32 configured agents under "Your agents", all 7 bases under "Base agents".

🤖 Generated with Claude Code

https://claude.ai/code/session_01X7VoW2QzfDkxEoudktbjVY

richard-epsilla and others added 4 commits August 28, 2026 23:41
…dy pointing at one

A new sheet was never runnable. The builder cannot see the person's own agents,
so it wrote harness_id "" and said to pick one; the shipped templates ship
blank for the same reason. Every route to a sheet therefore ended at a Run
button that refused on every column until you opened each menu in turn.

The missing piece was that a BASE is a perfectly good answer. Its id IS its
base name, which the server already accepts as a harness id, so a column can
run one without anybody having configured anything. And unlike a chrn_ id, a
base id is stable, so the builder can write one without inventing anything.

- The column picker lists base agents beside the person's own, under a heading
  for each. Bases come from /v1/bases and are filtered on what this deployment
  reports ready with an available model, never a list written down here:
  offering one that is not installed would produce a sheet that looks
  configured and fails on the first row.
- The builder now names a base suited to the work. The skill documents the ids
  and its validator accepts them, so a sheet arrives runnable.
- The app fills any blank agent column with a base it has just confirmed this
  deployment can run, which covers the templates and every sheet written before
  this. Blanks only: a column pointing at an agent that no longer exists keeps
  refusing, because quietly re-pointing it would run something other than what
  the sheet says it runs.

The kit's own Harness stays excluded from the list, since a sheet whose column
runs the sheet's own agent is recursion with a file-write race in it. The base
it happens to sit on is not excluded: that is a different agent, with its own
session and no interest in sheet.json.

Verified on the public VM: a sheet asked for in one sentence came back with its
agent column bound to codex, chosen by the builder itself, and Run enabled
without touching a menu.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X7VoW2QzfDkxEoudktbjVY
…nswer was thrown away

Two things the base-agent change walked into, both visible on the first run of
a sheet built the new way.

The banner. The app carries its own copy of the sheet rules in model.js, and
only the skill's Python copy learned about base ids — so a sheet the builder
had just written correctly was reported broken by the app that asked for it:
'harness_id: is "codex". Leave it "" unless you were given a real agent id.'

The empty cells. A cell was filled only when the terminal status read exactly
"completed". A turn read a moment before its label catches up comes back
terminal with its answer already in the record, and the cell threw that answer
away and wrote "the turn ended without an answer" over it. An answer is an
answer whatever the turn was labelled, so the content decides now and the
status only chooses the wording when there is nothing to show. A Stop stays a
Stop: partial output under a green tick would read as a success nobody got.

Verified on the public VM: the same three rows that failed came back done, with
real sentences, and no banner.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X7VoW2QzfDkxEoudktbjVY
An agent cell keeps its files under its answer, which makes the row tall. Every
other cell in that row was showing one ellipsised line above a block of empty
row, because the line count was one number shared by the whole row.

The measuring now happens per cell, in SheetGrid (reifyui 0.11.2). This side is
the half the kit owns: the answer text marks itself with data-shg-clamp-text so
the grid can tell it apart from the file cards beside it and work out how much
room each actually has.

NOTE: needs reifyui 0.11.2 on npm. The fix is in that package; this bump is
what picks it up.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X7VoW2QzfDkxEoudktbjVY
… we ship with

The previous commit asked for reifyui ^0.11.2, which is where the fix belongs but
is not on the registry — so `npm ci` failed with ETARGET and the sheets build
went red. Doing it here instead makes the fix work against the version already
published, and CI green without waiting on a release.

--shg-clamp is set per <td>. A custom property resolves from the nearest
ancestor, so this wins over the row-level value SheetGrid sets, and it reaches
both this kit's answer text and the grid's own value cell.

Three things have to be true at once, and each is a trap on its own:

- The basis cannot be the RENDERED height. More lines makes the row taller,
  which allows more lines: measured live the rows climb 92 → 137 → 182 and never
  settle. Every clamp goes back to one line before measuring, so the basis is
  the height the row's OTHER content needs — which the clamp cannot influence.
- The basis cannot be the <td>. A table cell is stretched to its row and reports
  the row height for every column, so they all look equally full. Measured on
  the text's own box, which sizes to its content.
- The count cannot be shared by the row. A cell carrying files under its text
  has far less room than one carrying nothing; one number for both is the bug
  restated.

Verified on the public VM against reifyui 0.8.1: a 137px row gives its
file-card column 4 lines plus the card and every other column 7, a 272px row
gives 13 and 16, and a second pass computes the same answer rather than
ratcheting the rows upward.

The same fix is on ReifyUI main for 0.11.2. When that is published this copy
should go, so the measuring lives in the grid that owns the markup.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X7VoW2QzfDkxEoudktbjVY
@richard-epsilla
richard-epsilla merged commit 255df29 into main Aug 29, 2026
6 checks passed
@richard-epsilla
richard-epsilla deleted the feat/agent-columns-pick-a-base branch August 29, 2026 08:16
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