Skip to content

Show the thread's Build Spec or Ticket in the header, with cards and live chat links #78

Closed
7 of 7 issues completed

Description

@pechhe

Outcome

A thread shows which HQ Build Spec or Ticket it is working on, and Build Specs and Tickets mentioned in chat are live links. Hovering either shows a card with the item's current state from Build, so the person can see what a thread is for and how its work stands without opening HQ.

Today the header shows only project, workflow chip and title, and a Build link in chat is plain text.

Design (agreed from the prototype, 16 Oct)

Header segment. The breadcrumb gains one segment between the workflow chip and the thread title: Project / [workflow] / ◇ <Spec title> ● / <thread title>. A Ticket shows ▢ instead of ◇. The segment shows the item's title, truncated, with a status dot:

  • ring: not started (inbox, shaping, ready);
  • filled amber: in progress;
  • filled green: landed;
  • green with a halo: accepted;
  • gray: dropped.

Two overlays sit beside the dot, separate from status:

  • ⏸ Held (orange): the item has an open hold.
  • ⛓ Blocked (red): Build reports an unresolved wait on it (hq_build_waits).

T3 never works out blocking from statuses itself: a Spec blocker clears only when it is accepted, and Build has its own rules for Tickets blocking a Spec.

Clicking the segment opens the item in HQ, and its menu offers Change (paste a Build URL or number) and Unlink. The segment is absent when no item is linked. Link Build item sits with the thread's other actions on web (the header's thread menu and the command palette) and in mobile's thread menu.

Spec card, shown on hover after the PR preview's delays:

  • Header: ◇ Spec · <spec kind> · <horizon> and status.
  • Title and the three-line Build summary.
  • A segmented progress bar of its Tickets by status, with counts.
  • Up to five Tickets with their status, then "+N more".
  • A banner for a hold (its kind and note) or for acceptance.
  • Rows for acceptance and governing Decisions.
  • Footer: the lead thread, with its activity (active, quiet, stalled, ended), as a T3 thread link, and when the item was last updated.

Ticket card:

  • Header: ▢ Ticket in ◇ <Spec> and status.
  • Title and summary.
  • A banner for a hold, or for a block: "⛓ Blocked by (). Starts when it <is landed | is accepted>." Which one comes from the wait's required.
  • Rows for Blocked by, delivery attempt and last failure.
  • Footer: the worker thread, or "No thread working on it".

Chat. A Build item mention in a message, either a link or #<number>, renders as a chip: the kind glyph, the item's live title and its status dot, falling back to the link text while loading. Hovering the chip shows the same card.

Mobile. The linked item appears as the header subtitle. Tapping it, or a chat chip, opens the card as a sheet.

Settled constraints

  • Build is the only source. T3 stores which item a thread is linked to and nothing about the item itself.

  • The link is thread metadata. It is set with the existing thread.metadata.update command, like the workflow and linked PR. Its value is the Build item's id and number and the HQ origin it was resolved against. Older events must stay readable, and the link must survive restart and replay. If the project's HQ origin changes, the link shows as unavailable; it is never resolved by number against another HQ. Agents set and clear it through t3_thread_update, and a lead can set it on its delegated threads. People set and clear it from the segment menu. Both are one service method, and agents, scheduled tasks and the UI all reach it. Setting replaces any earlier link and clearing removes it. T3 never infers or overwrites a link on its own, including from Build sessions.

  • The server reads Build; clients never touch HQ. The T3 server reads through the HQ MCP with its own observer token (ci: use blob:none to reduce checkout data pingdotgg/t3code#2485), which it exchanges from the delegation Inject a per-agent YardSmith HQ MCP connection for each T3 thread #74 stores. This works whether or not any provider is running. It uses the HQ origin and delegation of the thread's project, as configured for Inject a per-agent YardSmith HQ MCP connection for each T3 thread #74. The cache is keyed by HQ connection and item, never by number alone. The observer is ended, not revoked, when no project uses that connection. Card data reaches clients over the existing WebSocket, so local, remote, tunnel and mobile clients all work. A project without HQ configured shows no segment, and its Build links render as ordinary links.

  • Freshness by polling, only while visible. Build has no change feed. While some client shows a segment or chip, the server re-reads its item and its waits once a minute, since a blocker's change does not move the item's own revision. While a card is open, its detail is re-read on the same cadence. A first read, or opening a card, reads at once, and only the periodic re-reads are rate-limited. A closed card or a segment no one is viewing costs nothing. This works independently of thread settlement: an idle thread's segment stays fresh while it is on screen. The header needs only title, number, kind, status, holds and waits, and that compact read is all that refreshes for a segment or chip. The card's detail (Tickets, attempts, acceptance, Decisions, sessions) is read when a card opens. Neither read uses hq_build_context, which returns full bodies. The server sends a client only the card fields, never item bodies.

  • Thread links come from Build. The lead and worker threads on the cards come from Build's sessions, not T3 metadata:

    • The lead is the coordinator session (parentSessionId null) of the Spec's current bind generation. When none is open, it is the most recently ended one, shown as ended.
    • A Ticket's worker is its open helper session in that generation whose ticketIds include it, with the latest lastActivityAt winning. When none is open, it is the most recently ended one, shown as ended. With no session at all, the card says "No thread working on it".
    • A session with harness t3 and sessionRef <environmentId>/<threadId> becomes a T3 thread link, rendered like a t3-thread:// chip, including its handling of an environment this client is not connected to.
    • Any other harness or reference shows as plain text with its activity.
    • An ended session shows as ended.

    Recording that sessionRef is the producer's job: the lead's bind or start_session and its delegate_session calls.

  • Recognised mentions, in projects with HQ configured, using that project's HQ origin:

    • https://<HQ origin>/build/<number> and https://<HQ origin>/build/specs/<number> links;
    • #<number>, HQ's own way of writing a Build item, for numbers of seven or more digits. Build numbers start at 1,000,000, so GitHub references such as #78 never match.

    Mentions inside code spans and code blocks stay as written. A #<number> that Build doesn't know stays plain text. Numbers without #, and slugs, are not recognised.

  • Unavailable HQ. If HQ is unreachable or the token is revoked, the segment keeps the last known title, and the card says Build couldn't be reached and when it was last updated. With nothing known yet (after a restart, say), the segment shows Build <number> with a gray dot. It never shows a spinner indefinitely.

  • No continuously running animation. The PR preview's hover card (apps/web/src/components/pullRequest/PullRequestLinkPreview.tsx) and the thread link chip (apps/web/src/components/chat/MarkdownThreadLink.tsx) are the patterns to follow.

Acceptance

  1. An agent links its thread to a Spec with t3_thread_update, and the web and mobile headers show its title and status. A person links an unlinked thread from Link Build item, and changes or unlinks it from the segment menu. Linking again replaces the link. The link survives a server restart.
  2. Against Development HQ data from seed:hq:
    • The Spec card shows the summary, Ticket counts by status and up to five Tickets.
    • A held item shows ⏸ Held and its hold note.
    • A Ticket blocked by an unfinished item shows ⛓ Blocked and names the blocker.
    • A Ticket blocked by a Ticket clears ⛓ Blocked once the blocker lands. A Ticket blocked by a Spec stays blocked when that Spec lands, and clears once it is accepted. Both are tested against Build's waits.
  3. Given sessions recorded with harness t3 and a <environmentId>/<threadId> sessionRef, the footer links to the lead or worker thread and opens it. A non-T3 reference, or an environment this client doesn't know, shows as plain text. An ended session shows as ended.
  4. A Build link or #<number> in an assistant or user message renders as a live chip with the same card. #78, a mention in code, and an unknown number stay as written, and in a project without HQ links stay plain links.
  5. With a controlled clock, tests show the server re-reads an item and its waits only while a client shows it, once per minute, and the card detail only while a card is open. First reads happen at once, and clients receive card fields but never bodies.
  6. With HQ unreachable or the observer token revoked, the segment and card show the last known state and say Build couldn't be reached.
  7. On mobile the item shows as the header subtitle, and tapping it or a chat chip opens the card sheet.
  8. The user guide gains a short section on linking a thread to Build work.

Non-goals

  • Editing Build from T3 beyond linking and unlinking: no status changes or holds.
  • Searching or browsing Build inside T3. Change takes a URL or number.
  • Recognising numbers without #, or slugs, in chat.
  • Linking a thread to more than one item.
  • Upstream (pingdotgg/t3code) support. This is fork-only, behind the project's HQ configuration.
  • Agent guidance to link threads, record T3 sessionRefs and refer to Build items as #<number>. That is pechhe/agent-config#7.

Relations

Blocked by pechhe/yardsmith#2485 (Build summaries, item URLs and the observer role) and by #74, which stores the delegation and exchanges tokens.

Activity

  1. added
    specA delivery or discovery outcome
    on Oct 16, 2026
  2. pechhe commented on Oct 16, 2026

    @pechhe
    OwnerAuthor

    Shaped 16 Oct. Decided by the owner: Build is the only source of item data; the item appears as a breadcrumb segment; Held and Blocked are separate overlays, not statuses. A standalone HTML prototype of the segment and both cards was agreed and is now recorded in the Design section. The prototype itself was disposable and has been deleted. A read-only advisor challenged two drafts. Its findings are settled in the body: the observer token, compact vs detail reads, waits as the source of Blocked, session selection, a first-link entry point, and cold and unavailable states. Tickets: #79 → #80 → #81 and #82. Blocked by pechhe/yardsmith#2485 and #74.

  3. pechhe commented on Oct 17, 2026

    @pechhe
    OwnerAuthor

    Spec review (spec-reviewer, Opus, fresh context)

    Finding Severity Disposition
    Acceptance 8: no user guide section blocking Fixed in #109, c3b9af6 (docs/user/build-items.md)
    Web and mobile recognise mentions differently; web chips #n inside raw HTML <code> should-fix Fixed in #110, 1844247: web recognises after raw HTML with the shared rehypeBuildMentions. Escaped \#n stays out of scope.
    Mobile says "no item" when Build is unreachable should-fix Fixed in #111, 82d2677: mentions reports unavailable
    A link from a previous HQ still reads its card on the current HQ should-fix Fixed in #111, 82d2677: such a card is unavailable and reads nothing
    Spec card has no acceptance row should-fix Rejected: Build's acceptance read carries only acceptedAt, which the card shows as a banner, and the status already shows when a Spec isn't yet accepted

    #110 and #111 each passed a ticket review. #109 is docs only.

    Evidence gaps, not blocking: the chat chip's hover card and the #82 footer thread links were not seen rendered against an HQ with Build data. The chip uses the same card component as the header segment, which was checked against Development HQ in #80. Mobile has not been checked on a device.

  4. pechhe commented on Oct 17, 2026

    @pechhe
    OwnerAuthor

    All Tickets (#79–#82, #109–#111) have landed and the Spec review's findings are answered. See the review comment above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    specA delivery or discovery outcome

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions