Skip to content

afx: status builders table should include PID + terminal session id (parity with the architects section) #1115

Description

@amrmelsayed

Problem

afx status renders the Architects section with rich runtime metadata per row (name (pid=<n> port=<n> terminal=<uuid>)) but the Builders section omits both pid and terminalId columns. The asymmetry isn't an oversight — it's a side-effect of Spec 1057's owner-aware builders table sourcing from state.db instead of Tower's live terminal list — but it costs the diagnostic workflow during builder recovery / debugging.

The gap is felt the moment something goes wrong with a builder: identifying which OS process to inspect, signal, or kill currently requires dropping to sqlite3 ~/.agent-farm/global.db (or ps -axo string-matching) to discover the PID by hand. Hit during the pir-832 recovery session this issue spun out of.

Source

packages/codev/src/agent-farm/commands/status.ts — the architect rendering reads from workspaceStatus.terminals (the Tower runtime view, which has term.pid / term.terminalId populated per Spec 786 Phase 5):

const pid = term.pid ? `pid=${term.pid}` : 'pid=?';
const port = term.port ? ` port=${term.port}` : '';
const termIdValue = term.terminalId ?? term.id;
const termId = ` terminal=${termIdValue}`;
logger.info(`  ${chalk.cyan(name)} (${pid}${port}${termId})`);

The builder rendering immediately below it calls renderBuilders(builders, ownerFilter) with builders sourced from state.db.builders (Spec 1057, for the spawnedByArchitect column needed for owner-aware grouping). state.db.builders doesn't carry pid / terminalId — those are runtime fields Tower populates on its in-memory terminal_sessions view.

Proposed fix

Enrich each builder row in renderBuilders with a join against Tower's terminal list, additively. For each row from state.db, look up the matching terminal_sessions entry by role_id == builder-<id> and workspace_path == <workspace>, and append pid + terminalId as new columns.

Pseudocode:

const builderTerminals = workspaceStatus.terminals.filter(t => t.type === 'builder');
const tIndex = new Map(builderTerminals.map(t => [t.role_id ?? t.label, t]));

for (const b of builders) {
  const t = tIndex.get(`builder-${b.id}`);
  const pid = t?.pid ? `pid=${t.pid}` : '';
  const termId = t?.terminalId ? `terminal=${t.terminalId}` : '';
  // ... append to existing row format
}

The existing owner-aware grouping (Spec 1057's design point) is unchanged — the join just adds columns, doesn't change the row source or grouping axis.

Acceptance criteria

  • The afx status Builders section renders pid=<n> and terminal=<uuid> columns per row (when available from Tower's terminal list).
  • Owner-aware grouping (spawnedByArchitect column) is preserved unchanged.
  • A builder row whose Tower terminal entry is missing (Tower not running, or terminal session row not yet replayed by reconcile) renders the row without pid / terminal columns rather than pid=? — the empty case should be visually quiet, not noisy.
  • The legacy Tower-not-running fallback path in status.ts (which already explicitly says "PID/port not available") is untouched.

Out of scope

  • Adding architect-style columns (port, name, etc.) for builders. Builders don't expose a port and their role_id is already in the existing ID column.
  • Changing the data-source ordering — state.db stays the primary, Tower's terminal list is the secondary enrichment.
  • Any change to architect rendering — already correct.

Protocol

AIR. Small mechanical wiring change with no architectural decision: one Map-build, one per-row lookup, additive column rendering. Test coverage: a unit test asserting that a builder row with a matching Tower terminal renders with pid=<n> and terminal=<uuid>, and a row without a matching terminal renders without those fields.

Related

  • Spec 1057 — established the owner-aware Builders table sourced from state.db (the design this issue extends additively).
  • Spec 786 Phase 5 — established the TowerWorkspaceStatus rich-metadata extension that architect rendering already consumes.

Metadata

Metadata

Assignees

Labels

area/towerArea: Tower server / agent farm CLI

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions