Skip to content

feat: Create Bead UI with AI enrichment and mayor notification#2776

Open
jrf0110 wants to merge 8 commits intogastown-stagingfrom
convoy/feat-create-bead-ui-with-ai-enrichment-a/2390e466/head
Open

feat: Create Bead UI with AI enrichment and mayor notification#2776
jrf0110 wants to merge 8 commits intogastown-stagingfrom
convoy/feat-create-bead-ui-with-ai-enrichment-a/2390e466/head

Conversation

@jrf0110
Copy link
Copy Markdown
Contributor

@jrf0110 jrf0110 commented Apr 23, 2026

Summary

  • Adds Bead UI with AI enrichment capabilities and mayor notification flow
  • Fixes: moves planning file from repo root to .plans/ per AGENTS.md convention
  • Fixes: replaces unsafe as cast in services/gastown/src/trpc/router.ts with flow-sensitive typing

Verification

  • Manually verified the planning file is now at .plans/create-bead-ui-convoy.md
  • Verified the responseText extraction uses a safe two-step pattern with a typeof runtime check

Visual Changes

N/A

Reviewer Notes

N/A

jrf0110 and others added 4 commits April 23, 2026 21:14
…d gt:held reconciler exclusion (#2772)

* feat(gastown): add createBead/startBead/enrichBead tRPC procedures and gt:held reconciler exclusion

- Add HELD_LABEL and HELD_LABEL_LIKE constants to patrol.ts
- Exclude gt:held beads from reconciler Rule 1 dispatch
- Add createHeldBead(), notifyMayorOfNewBead(), startHeldBead() to TownDO
- Add createBead, startBead, enrichBead tRPC procedures to router
- Update sling procedure to accept optional labels
- Add create-bead-ui-convoy.md shared context for convoy polecats

* fix(gastown): verify bead rig ownership in startHeldBead and use waitUntil for mayor notification

- CRITICAL: startHeldBead now accepts a rigId and throws if the bead does not belong to that rig, preventing cross-rig gt:held label removal within the same town
- WARNING: mayor notification in createBead uses ctx.executionCtx.waitUntil() so the Worker stays alive until the RPC completes; add executionCtx to TRPCContext and pass it from the Hono createContext callback

---------

Co-authored-by: John Fawcett <john@kilcoode.ai>
…2773)

* feat(gastown): add CreateBeadDrawer with MDXEditor and AI enrichment

- Install @mdxeditor/editor for rich markdown editing
- Add MarkdownEditor.tsx wrapper with dark theme CSS overrides
- Add CreateBeadDrawer.tsx: right-side vaul drawer (620px) with:
  - Title input (AI-populated, respects user edits via userEditedTitle flag)
  - Label chips with AI-suggested sparkle labels and manual add
  - MDXEditor body (dynamic import, min-height 300px)
  - Start immediately checkbox (default: held for mayor planning)
  - 1500ms debounced enrichBead mutation on body > 20 chars
  - Toast on success: 'Work dispatched' vs 'Bead created — notifying mayor'
- Replace SlingDialog with CreateBeadDrawer in RigDetailPageClient
- Add createBead, startBead, enrichBead to router.d.ts type declarations

* fix: discard stale AI enrichment responses using sequence counter

Track enrichment request sequence numbers so that older in-flight
responses cannot overwrite newer suggestions or repopulate a closed
drawer with stale title/labels. The sequence is advanced on each
new request and also when the drawer closes, causing any pending
callbacks to bail out early on completion.

---------

Co-authored-by: John Fawcett <john@kilcoode.ai>
…ations (#2774)

* feat(gastown): update mayor system prompt to handle held bead notifications

- Update notifyMayorOfNewBead() message to match spec exactly, including
  explicit instruction to create a message bead with parent_bead_id so
  the response surfaces in the bead drawer
- Add '## User-Created Beads' section to mayor system prompt with guidance
  on acknowledging beads, offering planning options, and using gt_sling /
  gt_bead_update to respond and start work
- Update create-bead-ui-convoy.md with Bead 3 notes for future implementors

gt_bead_update in mayor-tools.ts already exposes both labels and body — no
changes needed there.

* fix(gastown): correct user-created bead reply instructions in mayor prompt

- Remove unsupported gt_sling({ type: 'message', parent_bead_id }) call;
  gt_sling only creates issue-type beads and does not accept type or
  parent_bead_id fields — this would fail validation at runtime.
- Fix gt_bead_update label removal: labels: [] replaces the full label
  set. Instruct the mayor to filter out only gt:held from current labels
  to avoid dropping other labels like gt:pr-fixup etc.

* fix: align notifyMayorOfNewBead message with system prompt - remove contradictory gt_sling message bead instruction

---------

Co-authored-by: John Fawcett <john@kilcoode.ai>
Comment thread apps/web/src/components/gastown/CreateBeadDrawer.tsx Outdated
Comment thread services/gastown/src/trpc/router.ts Outdated
@kilo-code-bot
Copy link
Copy Markdown
Contributor

kilo-code-bot Bot commented Apr 23, 2026

Code Review Summary

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0

Fix these issues in Kilo Cloud

Issue Details (click to expand)

WARNING

File Line Issue
apps/web/src/components/gastown/CreateBeadDrawer.tsx 48 userEditedTitleRef is only synced in an effect, so the title-overwrite race can still happen before that effect runs
Other Observations (not in diff)

No new issues in the incremental diff. The active warning above is carried forward from unchanged code.

Files Reviewed (3 files)
  • .plans/create-bead-ui-convoy.md
  • apps/web/src/components/gastown/BeadBoard.tsx
  • apps/web/src/components/gastown/MarkdownEditor.tsx

Reviewed by gpt-5.4-2026-03-05 · 1,038,502 tokens

jrf0110 and others added 4 commits April 24, 2026 09:30
* feat(gastown): surface held beads and mayor responses in rig UI

- BeadBoard: show Clock icon and amber 'Held' badge for gt:held beads,
  hide the gt:held label from the label chips, add hover 'Start now'
  quick-action button wired to onStartBead prop
- RigDetailPageClient: wire startBead mutation and pass onStartBead to BeadBoard
- BeadPanel: detect gt:held label, render amber 'Held' status badge and
  'Start now' button that calls startBead tRPC mutation; render mayor
  responses (type='message' child beads) as a conversation thread above
  the event timeline

* chore: delete create-bead-ui-convoy.md (final convoy bead)

---------

Co-authored-by: John Fawcett <john@kilcoode.ai>
…diately return

- CreateBeadDrawer: read userEditedTitle via a ref in the enrichment
  response callback so edits made after the request starts win over the
  AI-suggested title.
- createBead tRPC: when startImmediately is set, return the post-start
  bead from startHeldBead() so the gt:held label removal and status
  changes are reflected in the mutation result.
The markdown editor toolbar icons were rendering as dark-gray-on-gray
because MDXEditor's default light theme drives SVG color via
--baseTextContrast (near-black), which clashed with our dark drawer
background. Switch to the library's built-in dark-theme class to swap
the full Radix color palette in one shot, and drop the brittle
hashed-class-fragment overrides that tried to re-derive it.
lucide-react icons don't accept a `title` prop (SVGAttributes). Wrap
the held-bead Clock icon in a span carrying the tooltip, and keep an
aria-label on the icon itself for screen readers.
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