Skip to content

upstream(sync): Workflows stack — run history, reply-in-thread, editor (#5780, #6178, #6248) - #308

Merged
oscarlehuu merged 7 commits into
mainfrom
devin/issue-274-workflows-sync
Aug 22, 2026
Merged

upstream(sync): Workflows stack — run history, reply-in-thread, editor (#5780, #6178, #6248)#308
oscarlehuu merged 7 commits into
mainfrom
devin/issue-274-workflows-sync

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Aug 22, 2026

Copy link
Copy Markdown

Summary

Ports the upstream Buzz 0.5.18 Workflows stack (part of the #285 sync) — four upstream commits cherry-picked from desktop-v0.5.18 onto Crew main:

Crew-specific divergences (kept Crew behaviour)

  • Channel-first IA preserved (upstream(sync): Guardrail — preserve channel-first IA during 0.5.18 merge #278): the editor is mounted as AppWorkflowEditorOverlayProvider inside Crew's existing channel-first AppShell — no Projects rail or Workbench navigation restored.
  • Dark-theme tokens: upstream amber Tailwind classes replaced with Crew semantic tokens (text-attention, border-attention, bg-attention) in WorkflowApprovalCard / WorkflowStepCard.
  • Migration renumbered: upstream 0031_workflow_run_error_codes.sql collides with Crew's existing 0031_wiki_fts_allowlist.sql; ported as migrations/0032_workflow_run_error_codes.sql with migration count/index assertions updated.
  • CLI keeps Crew's parent-aware thread resolver: resolve_thread_ref now delegates to a shared-parser-backed thread_ref_from_parent_tags (upstream's buzz_core::nip10), preserving Crew's channel-scoped resolution.
  • Relay-aware E2E mock bridge kept: Crew's relay-backed handleUpdateWorkflow/handleDeleteWorkflow/handleTriggerWorkflow retained, extended with upstream's expectedRevision optimistic-concurrency check and configurable mock errors.
  • Pre-existing test fix required for the gate: buzz-cli inventory snapshot tests (command_inventory_is_stable, subcommand_names_are_stable, subcommand_counts_are_stable) were already failing on main (stale since feat(crew): remove Org chart product (role-first, #233) #238 org roster and Agent-to-agent call by name (CoS wakes specialists; no founder Wake) #230/feat(cli): buzz agents call wakes specialists by name (#230) #240 agents call merged without updating them) — verified failing on a clean main worktree. Updated the snapshots so just test-unit passes.

Related issue

Fixes #274 (part of meta issue #285; guardrails per #278)

Testing

TDD: RED baseline captured on main (missing reply_in_thread/trigger_is_reply/editor routes/run-history contract), then GREEN after the port.

Gates (all pass locally):

  • pnpm --filter buzz check
  • pnpm --filter buzz typecheck
  • pnpm --filter buzz test ✔ (5580 pass / 0 fail)
  • just test-unit ✔ (8/8 crates)
  • just check-compile

Rust: cargo test -p buzz-workflow (169 pass), cargo test -p buzz-core nip10 (11 pass), cargo test -p buzz-cli --lib (359 pass), tauri workflows tests (13 pass).

Desktop E2E (mock bridge, xvfb): all 4 workflow specs — workflows.spec.ts, workflow-reaction-picker.spec.ts, workflow-local-controls.spec.ts, workflow-title-stability.spec.ts42 passed.

Screenshots (full window, E2E mock bridge)

Before (main) — workflows library, no editor/actions:

before workflows library

After — workflows library (channel-first sidebar intact):

after workflows library

After — workflow editor create mode (/workflows?view=create), channel picker:

after workflow editor create

After — editor run controls (wide layout, from Playwright run):

editor run controls

After — library card actions (responsive, block#6008):

library card actions

NOTES (handover)

DONE

IN PROGRESS

  • Nothing half-done in code — the branch is coherent, fully pushed, and all local gates are green.

TODO / NEXT

  • Product decision: the run-history panel's entry point ships commented out in desktop/src/features/workflows/ui/WorkflowDialog.tsx (upstream desktop-v0.5.18 parity — pending NIP-11 capability gating; see TODO(workflow-run-history-capability)). If Crew wants it visible before merge, expose/capability-gate the icon and re-run the workflow Playwright specs (they currently assert the button count is 0).
  • main needs a fix (or an accepted-red decision) for the pre-existing Desktop E2E Integration failures before any PR in the sync stack can go green.
  • Merge conflicts expected with sibling sync PRs touching desktop/src/app/AppShell.tsx, desktop/src/app/navigation/useAppNavigation.ts, desktop/src/testing/e2eBridge.ts, and crates/buzz-db/src/migration.rs (migration numbering) — rebase this branch after siblings land and re-check migration index assertions in buzz-db.

Link to Devin session: https://app.devin.ai/sessions/a590dbc560fb48e3abbf8780810bd6ab
Requested by: @oscarlehuu

@devin-ai-integration

Copy link
Copy Markdown
Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@devin-ai-integration

Copy link
Copy Markdown
Author

E2E test results (mock bridge, full-window manual drive)

Manually drove the build:e2e bundle end-to-end (headed browser, in-SPA navigation). 5/6 requested scenarios passed; run history was untestable via UI (intentionally hidden entry point — see note).

ss_1ef1e2fb

Scenario Result
Library inside channel-first shell (channels/DMs sidebar, no Projects rail) pass
?view=create overlay, channel picker, lossless Form/YAML round-trip pass
reply_in_thread shown for message triggers; YAML on: webhook + reply_in_thread blocks Form switch with explicit error; Form hides checkbox on Webhook pass
Dirty-exit guard ("Discard changes?"; Keep editing preserves state; Discard exits, nothing created) pass
?view=edit / ?view=duplicate routed from card actions menu + address-bar deep link pass
Delete via card actions menu pass
Run history truthful loading/empty/failure states untested — the run-history popover trigger ships commented out in upstream block#6248 itself (WorkflowDialog.tsx TODO(workflow-run-history-capability), pending NIP-11 capability gating) and the upstream specs assert its absence, so WorkflowDetailPanel is unreachable by users in this build. This matches upstream desktop-v0.5.18 state.
reply_in_thread gating evidence

ss_05201d0e
ss_6e16d75b

Dirty-exit guard & routed edit/duplicate

ss_68a2d0e4
ss_e4ba7585
ss_69279c32

Library in Crew's channel-first shell

ss_6c84614e

devin-ai-integration Bot added a commit that referenced this pull request Aug 22, 2026
@devin-ai-integration

devin-ai-integration Bot commented Aug 22, 2026

Copy link
Copy Markdown
Author

CI note: Desktop E2E Integration failures are pre-existing on main

Both Desktop E2E Integration shards fail with tests this PR does not touch (profile.spec.ts, agents.spec.ts, integration.spec.ts). Evidence they are unrelated to this branch:

  1. Identical failures on an unrelated PRperf(desktop): bound observer event retention #307 (tiny perf change) fails the exact same tests in both shards:
    • Shard 2/2: profile.spec.ts:1647, profile.spec.ts:1697, profile.spec.ts:1840 (same 3 as this PR)
    • Shard 1/2: same 10 agents.spec.ts / integration.spec.ts failures as this PR
  2. Local repro on clean origin/main tip (2c26b74)agents.spec.ts:707, agents.spec.ts:1448 and the profile trio fail locally with no changes from this branch.
  3. This PR's diff contains no changes to profiles, agents, personas, home-feed mentions, or the failing spec files.

No code or CI configuration was modified in response — flagging for the sync-stack coordinator since no PR in the stack can currently get a green Desktop E2E Integration.


Update (post-merge of main @ 82187d81c): Desktop Smoke E2E (2) now also fails 4 tests this PR does not touch (edit-agent.spec.ts:288, edit-agent.spec.ts:318, entity-link-recipient-cards.spec.ts:20, inbox-reactions.spec.ts:36). All 4 reproduce identically on a clean checkout of origin/main tip 82187d81c — they were introduced to main by a recent merge, not by this branch. No fixes attempted here per the "don't fix unrelated tests" scope rule.

@devin-ai-integration

Copy link
Copy Markdown
Author

NOTES (handover)

DONE

IN PROGRESS

  • Nothing half-done in code — the branch is coherent, fully pushed, and all local gates are green.

TODO / NEXT

  • Product decision: the run-history panel's entry point ships commented out in desktop/src/features/workflows/ui/WorkflowDialog.tsx (upstream desktop-v0.5.18 parity — pending NIP-11 capability gating; see TODO(workflow-run-history-capability)). If Crew wants it visible before merge, expose/capability-gate the icon and re-run the workflow Playwright specs (they currently assert the button count is 0).
  • main needs a fix (or an accepted-red decision) for the pre-existing Desktop E2E Integration failures before any PR in the sync stack can go green.
  • Merge conflicts expected with sibling sync PRs touching desktop/src/app/AppShell.tsx, desktop/src/app/navigation/useAppNavigation.ts, desktop/src/testing/e2eBridge.ts, and crates/buzz-db/src/migration.rs (migration numbering) — rebase this branch after siblings land and re-check migration index assertions in buzz-db.

wesbillman and others added 7 commits August 22, 2026 14:01
- persist stable workflow run `error_code` values separately from human
diagnostics
- expose NIP-98 authenticated, channel-authorized run history and
approval reads with stable keyset pagination
- connect Desktop to those authoritative reads and return the
relay-created run ID on trigger
- show truthful loading, failure, and pending-trace states, and do not
render approval actions from non-actionable stored hashes

- pre-push `branch-skew`, `desktop-typecheck`, `desktop-test`,
`rust-tests`, `desktop-tauri-checks`, and `desktop-check` all passed on
`a097dbe5f`
- Desktop tests: 4,761 passed, 0 failed
- `cargo check -p buzz-relay`
- `git diff --check`

This does not claim a relay-backed Playwright workflow journey. The
browser relay bridge still routes workflow invokes through in-memory
handlers; that production-shaped acceptance gate remains follow-up work
before Workflows can leave preview.

---------

Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
Co-authored-by: Mongo <5c25403eab7271f9f94ddd4f2b270e8cac2c92e2c830c51877cca6ec974ffb3f@buzz.block.builderlab.xyz>
Co-authored-by: Princess Donut <68157ebd23b3897c1991015c3038658ea916200c67d3a54620b0754d1b92f6e0@buzz.block.builderlab.xyz>
(cherry picked from commit 2693e0d)
Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Crew already ships 0031_wiki_fts_allowlist.sql, so the migration ported
from upstream block#5780 takes version 0032 here. Also corrects the embedded
migrator count assert, which was stale (30) since the wiki migration
landed.

Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Oscar Le <oscar.lehuu@gmail.com>
Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Oscar Le <oscar.lehuu@gmail.com>
Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
**Category:** improvement
**User Impact:** Users can scan what each workflow does and trigger,
edit, duplicate, enable, disable, or delete it directly from the
library.
**Problem:** The workflow list buried common actions and did not expose
each automation's trigger-to-action shape at a glance.
**Solution:** Add a responsive workflow library with a persistent create
tile, compact trigger/action diagrams, prominent workflow titles with
supporting descriptions, and shared card actions while preserving
existing detail, editor, and run-history entry points. Card toggles
refresh both list and open-detail caches so status and definition stay
consistent.

<details>
<summary>File changes</summary>

**desktop/src/features/workflows/ui/WorkflowActionsMenu.tsx**
Adds a shared card menu for trigger, edit, duplicate, enable/disable,
and delete actions.

**desktop/src/features/workflows/ui/WorkflowCard.tsx**
Reworks cards around the prototype's visual hierarchy: color-coded
trigger, action flow, sentence-case eyebrow, prominent title, supporting
description, status, channel, and update date without a footer clock
icon.

**desktop/src/features/workflows/ui/WorkflowsView.tsx**
Adds the responsive grid, create tile, mutation wiring, and list/detail
cache invalidation. Container breakpoints keep cards two-across at
medium widths and three-across in the 1280px desktop layout.

**desktop/src/features/workflows/ui/workflowDefinition.ts**
Adds immutable enabled-state updates plus narrow trigger and
first-action readers used only to select card icons.

**desktop/src/features/workflows/ui/workflowDefinition.test.mjs**
Covers neutral icon selection, enabled-state immutability, and status
presentation.

**desktop/tests/e2e/workflows.spec.ts**
Covers the create tile, title/description hierarchy, selected-card
enable/disable consistency, and deterministic narrow/medium/wide
captures while retaining existing action coverage.

</details>

1. Open **Workflows** and confirm the create tile stays first as cards
flow from one to three columns with available width.
2. Confirm each card shows a sentence-case trigger eyebrow, prominent
workflow title, supporting description when present, status, channel,
and update date without a clock icon.
3. Open a card's overflow menu and trigger, edit, duplicate,
enable/disable, or delete the workflow.
4. Leave the detail panel open while toggling and confirm its badge and
JSON definition update with the card.

Real built E2E UI with representative workflow data at three viewport
sizes.

![Workflow library at 800 by
720](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6008/workflow-library-narrow-482d1b4c8.png)

![Workflow library at 1024 by
720](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6008/workflow-library-medium-482d1b4c8.png)

![Workflow library at 1280 by
720](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6008/workflow-library-wide-482d1b4c8.png)

![Workflow library actions at 1280 by
720](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6008/workflow-library-wide-actions-482d1b4c8.png)

---------

Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
**Category:** new-feature
**User Impact:** Users can create, edit, duplicate, and deep-link to
workflows in a responsive visual editor without losing unsupported YAML
or unsaved work.
**Problem:** Workflow editing was split across disconnected surfaces and
lacked reliable URL state, lifecycle protection, and parity between Form
and YAML modes. **Solution:** This adds a route-addressable editor
foundation with stable pane identity, guarded dirty exits, lossless
Form/YAML transitions, responsive workflow and channel controls, and
matching reaction-filter execution support.

<details>
<summary>File changes</summary>

**crates/buzz-workflow/src/lib.rs**
Apply reaction trigger filters during workflow execution and cover
target-message gating.

**crates/buzz-workflow/src/schema.rs**
Extend the reaction trigger schema with the editor-owned filter field.

**desktop/src/app/navigation/useAppNavigation.ts**
Add navigation helpers for explicit workflow create, edit, and duplicate
editor modes.

**desktop/src/app/routes/WorkflowsRouteScreen.tsx**
Coordinate route state with the shared workflow library and editor
dialog.

**desktop/src/app/routes/lazyWorkflowsRouteScreen.ts**
Share one lazy route component across workflow route entry points to
avoid loading flashes.

**desktop/src/app/routes/workflows.$workflowId.tsx**
Parse workflow editor modes and pane deep links for workflow-specific
URLs.

**desktop/src/app/routes/workflows.tsx**
Parse library-level create state and render the shared workflow route
screen.

**desktop/src/app/AppWorkflowEditorOverlayProvider.tsx**
Host the shared workflow editor at the app-shell level so
channel-originated workflow dialogs stay above the active channel
instead of replacing it.

**desktop/src/shared/context/WorkflowEditorOverlayContext.tsx**
Expose route-independent open-existing and create-new workflow actions
to channel settings.

**desktop/src/features/workflows/ui/WorkflowEditorHost.tsx**
Share editor loading, unavailable, and dialog lifecycle wiring between
canonical workflow routes and the channel overlay.

**desktop/src/features/channels/ui/ChannelManagementSheet.tsx**
Add an experiment-gated, Canvas-style Workflows ingress below Canvas,
including channel-scoped loading, error, empty, and list states plus
open/create actions; disabled users issue no workflow query.

**desktop/src/features/channels/ui/ChannelWorkflowsSection.tsx**
Render the channel workflow list and New workflow action without pushing
the existing settings sheet past its file-size ceiling.

**desktop/src/features/workflows/ui/ChannelCombobox.tsx**
Adopt the final channel presentation, portalled scrolling, and one-shot
create-flow opening behavior.

**desktop/src/features/workflows/ui/CreateWorkflowDialog.tsx**
Remove the superseded create-only dialog in favor of the unified
workflow editor.

**desktop/src/features/workflows/ui/WorkflowCard.tsx**
Open workflow cards in the detail and run-history modal while preserving
explicit edit and duplicate actions.

**desktop/src/features/workflows/ui/WorkflowDetailDialog.tsx**
Present workflow Trigger/Steps in the shared modal chrome, with
top-chrome ingress to a responsive right-side run-history inspector and
an explicit edit action.

**desktop/src/features/workflows/ui/WorkflowDialog.tsx**
Unify create, edit, and duplicate lifecycle handling with URL panes,
generated-name synchronization, dirty-exit guards, stale-write
preservation, and protected webhook-secret handoff.

**desktop/src/features/workflows/ui/WorkflowFormBuilder.tsx**
Build the responsive Form/YAML editor shell, stable step selection,
insertion and removal behavior, and lossless canonical-YAML
synchronization.

**desktop/src/features/workflows/ui/WorkflowStepCard.tsx**
Align workflow step controls and presentation with the final editor
interaction model.

**desktop/src/features/workflows/ui/WorkflowUnavailableDialog.tsx**
Show a non-disclosing loading or unavailable state for missing and
inaccessible workflow links, with retry and close actions.

**desktop/src/features/workflows/ui/WorkflowWebhookSecretDialog.tsx**
Obscure one-time webhook secrets by default and require explicit
confirmation before any close or navigation discards them.

**desktop/src/features/workflows/ui/WorkflowsScreen.tsx**
Connect library state and workflow actions to the route-addressable
editor.

**desktop/src/features/workflows/ui/WorkflowsView.tsx**
Restore the responsive workflow library, create tile, cards, loading
states, and shared action menu.

**desktop/src/features/workflows/ui/workflowEditorPane.test.mjs**
Cover pane parsing, serialization, and stable step-ID reconciliation.

**desktop/src/features/workflows/ui/workflowEditorPane.ts**
Define explicit trigger and stable step pane URL state.

**desktop/src/features/workflows/ui/workflowYamlDocument.ts**
Read and update header fields independently of full form validation so
incomplete steps cannot clear or disable the workflow title.

**desktop/src/features/workflows/ui/workflowYamlDocument.test.mjs**
Cover document-level workflow header reads and writes for incomplete
definitions.

**desktop/tests/e2e/workflow-title-stability.spec.ts**
Verify generated, renamed, saved, and duplicated titles remain stable
while moving between trigger and step panes.

**desktop/src/features/workflows/ui/workflowFormTypes.test.mjs**
Cover lossless Form/YAML round trips and actionable fallback for
unsupported fields.

**desktop/src/features/workflows/ui/workflowFormTypes.ts**
Own canonical workflow YAML conversion while preserving supported
trigger and step fields.

**desktop/src/shared/ui/PortalledScrollArea.tsx**
Provide bounded scrolling for popovers rendered outside their dialog
container.

**desktop/src/shared/ui/popover.tsx**
Allow workflow popovers to use the shared portalled scroll container.

**desktop/tests/e2e/channels.spec.ts**
Cover disabled and enabled Workflows experiment states, including
suppressed queries while disabled, placement beneath Canvas, channel
workflow listing and opening, channel-preselected workflow creation, and
direct return to the channel Workflows panel after close, discard, or
cancel.

**desktop/tests/e2e/workflows.spec.ts**
Exercise library actions, deep links, create/edit/duplicate lifecycle,
dirty exits, responsive editor behavior, YAML safety, stale updates, and
one-shot channel selection.

</details>

1. Open **Workflows** and confirm the responsive card library, create
tile, card action menu, and card-to-detail/run-history modal navigation.
2. Open `?view=create`; confirm the channel chooser opens once, the
trigger inspector stays hidden until a channel is selected, and closing
the chooser does not make it reopen after unrelated edits.
3. Create a workflow, switch between Form and YAML, add and remove
steps, refresh a pane deep link, and confirm the selected trigger or
stable step remains addressable.
4. Edit or duplicate a workflow, make an unsaved change, and confirm
close, Escape, browser navigation, and route target changes require
discard confirmation while pane-only navigation does not.
5. Enter unsupported YAML and confirm Form mode gives an actionable
fallback without rewriting the definition; verify reaction triggers
preserve and execute their filter.

6. Open a channel’s settings, select **Workflows** below **Canvas**, and
open or create a workflow; confirm the shared modal stays over the
channel, the channel URL does not change, New workflow preselects that
channel, and closing or discarding returns directly to the channel’s
**Workflows** panel.
7. In create, edit, and duplicate modes, move between the trigger and
incomplete step panes and confirm the generated or edited title remains
visible and editable.

Fresh captures from product head
`c5c3abc91a71fe511d43e6cc9168b1626d0c217c`; the later review-guidance
fix does not alter these pictured states.

![Workflow library with action
menu](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6248/workflow-library-actions-c5c3abc.png)

![Wide workflow editor with step
details](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6248/workflow-editor-wide-c5c3abc.png)

![Narrow workflow editor with inspector
overlay](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6248/workflow-editor-narrow-c5c3abc.png)

![Workflow editor portalled over the active
channel](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6248/workflow-editor-channel-overlay-c5c3abc.png)

- Corrected Diff Posted condition guidance to use the executor-supported
`str_contains(trigger_text, "deploy")` syntax and added a visible
Playwright regression assertion.
- Scoped direct workflow-detail navigation coverage to the stable `Edit
workflow` dialog name, asserted the workflow title separately, and
retained the trigger-node assertion.
- Routed dirty channel-overlay Duplicate/Edit transitions through the
existing discard confirmation, preserving the original YAML draft when
the user keeps editing.
- Made workflow deletion await relay success, remain non-dismissible
while pending, and retain the confirmation/editor/draft with an
actionable inline error on rejection.
- Gated the channel-settings Workflows ingress and channel workflow
query behind the `workflows` experiment, with defensive rendering if the
flag changes while that view is active.
- Matched the Reaction Added trigger to the prototype reaction picker,
preserving native/custom/legacy values in canonical YAML and providing
an explicit clear action.
- Kept a channel’s Workflows panel mounted beneath channel-origin
editors so clean close, dirty discard, and create cancel return directly
to that panel without changing the channel URL.

Verified at exact pushed head
`76ebba7b7ace1e13445744200da70ca9da231b7e`:

- Push hooks passed: destination-org policy, branch-skew, differential
file-size, Desktop checks, TypeScript typecheck, and **5,115/5,115**
Desktop unit tests
- Focused channel lifecycle E2E passed: dirty edit discard returns
directly to the channel Workflows panel; create cancel does the same
while preserving the channel URL and preselected channel
- E2E production build, standalone TypeScript typecheck, and Biome
checks on both touched files passed
- Reaction-picker regression spec remains recorded at
`dc28ffa98ec34b4e0656757fb2dd93e60a84674d`: **5/5 passed** (picker
interaction, canonical YAML persistence/clear, legacy-value
preservation, save/reopen round trip, narrow viewport containment)
- Blox existing workflow E2E regression set at
`dc28ffa98ec34b4e0656757fb2dd93e60a84674d`: **36/36 passed**
- Earlier blocker and review regressions remain recorded at
`3760c3d657a525f5af98e8d0f98bdd03999d8e61`: **5,114/5,114** Desktop unit
tests and the dirty-overlay/deletion focused checks
- Working tree clean; local branch, remote branch, and PR head all match
the exact SHA above

None found. Closest prior work: #231.

---------

Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Codex <noreply@openai.com>
Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The `send_message` workflow action could only post new top-level channel
messages. This adds a `reply_in_thread` option so a `message_posted`
workflow can reply in the triggering message's thread, plus a
`trigger_is_reply` filter variable so a workflow can fire only on
top-level messages.

Every NIP-10 thread-marker reader in the tree now routes through one
shared parser and one collapse rule in `buzz-core`, deleting four
hand-rolled copies that had drifted on id-validity and marker semantics.

- **Schema** (`crates/buzz-workflow/src/schema.rs`): new
`reply_in_thread: bool` (serde default `false`) on
`ActionDef::SendMessage`. `validate()` rejects `reply_in_thread: true`
on `schedule`/`webhook` triggers — they carry no message to reply to.
- **Executor** (`crates/buzz-workflow/src/executor.rs`): threads
`reply_to: Option<&str>` (the trigger `message_id`) through
`ActionSink::send_message` when `reply_in_thread` is set; errors clearly
if the trigger has no `message_id`. `resolve_step_templates` carries the
new field. Adds `trigger_is_reply` (boolean) to the eval context.
- **Relay sink** (`crates/buzz-relay/src/workflow_sink.rs`): when
`reply_to` is set, resolves parent/root/depth from the known trigger
event, persists real thread metadata instead of the hardcoded top-level
`depth: 0`, and pushes the live kind:39005 thread-summary overlay after
insert so subscribed desktops update the root's reply badge without
refetching — matching the human ingest path. Emits the same NIP-10
`e`-tag shape as `buzz_sdk::builders::thread_tags`: a single `["e", id,
"", "reply"]` tag for a direct reply (parent == root), and the `root` +
`reply` pair only when nested — so every writer produces one wire shape
per reply kind.
- **Ingest resolver** (`crates/buzz-relay/src/handlers/ingest.rs`): new
`resolve_relay_reply_thread_meta` + `ReplyAncestry`. Unlike the
client-facing `resolve_nip10_thread_meta` (which validates
client-supplied tags), this computes root/depth from the known parent
and enforces the same same-channel and depth-limit invariants. When the
parent has no `thread_metadata` row, both resolvers share
`derive_ancestry_from_parent_tags`, which applies
`ThreadMarkers::resolve()`: a marked nested parent remains depth 2,
while a root-only, malformed, or unmarked parent is top-level and starts
its reply thread at itself. Both the client resolver and the
parent-ancestor fallback now read markers via the shared parser instead
of hand-scanning `e`-tags.
- **Shared NIP-10 parser** (`crates/buzz-core/src/nip10.rs`):
`parse_thread_markers` reads an event's `root`/`reply` markers, honoring
a marker only when its event id is exactly 64 ASCII-hex characters.
`ThreadMarkers::resolve()` is the single definition of the (root, reply)
→ (root_id, parent_id) collapse: `root`+`reply` as-is, `reply`-only →
`(reply, reply)`, a lone `root` or neither → top-level. A slice-based
`parse_thread_markers_from_parts` entry point serves consumers holding
raw JSON tag arrays. Relay ingest, the workflow `trigger_is_reply`
predicate, ACP anchoring, and the CLI reply resolver all call these, so
they cannot drift on marker, id-validity, or collapse semantics.
- **ACP** (`crates/buzz-acp/src/queue.rs`): `parse_thread_tags`
delegates marker parsing and collapse to `buzz_core::nip10`, keeping
only its local `p`-tag mention collection. This fixes a parity gap with
ingest: a malformed non-64-hex marker id is no longer counted as a
thread link, and a lone `root` marker is now top-level rather than being
treated as root == parent.
- **CLI** (`crates/buzz-cli/src/commands/messages.rs`):
`find_root_from_tags` routes its JSON tags through the shared slice
parser and collapse rule. CLI replies to root-only, malformed, or
unmarked parents now correctly start at that immediate parent;
reply-only and root+reply parent ancestry remain intact.
- **Trigger context** (`crates/buzz-workflow/src/lib.rs`):
`build_trigger_context` derives `is_reply` solely from a valid NIP-10
`reply` marker (no DB hit). A lone `root` marker is top-level to ingest,
so it does not count; neither does a `reply` marker whose event id is
malformed, nor a bare/unmarked `e`-tag (mentions, quotes).
- **Desktop** (`workflowFormTypes.ts`, `WorkflowStepCard.tsx`):
`replyInThread` form field with YAML round-trip, and a "Reply to
triggering message in thread" checkbox shown only for message-based
triggers. Switching to `schedule` or `webhook` clears the option on
every step before serialization, so a value hidden behind an action
change cannot resurrect when the action is switched back. The form
parser also requires `reply_in_thread` to be a boolean and refuses
`reply_in_thread: true` under an ineligible trigger, falling back to
YAML mode rather than silently normalizing a backend-invalid definition.

```yaml
trigger:
  on: message_posted
  filter: trigger_is_reply == false
steps:
  - id: auto_reply
    action: send_message
    text: "pre-written reply text"
    reply_in_thread: true
```

---------

Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Co-authored-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- allow router state in commitNavigation so editor deep-links carry
  workflowEditorHasOrigin
- include revision in relay-backed mock workflow records
- biome format AppShell
- update buzz-cli inventory snapshot tests for org group and agents call
  (stale on main since #238/#240; required for just test-unit gate)

Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Oscar Le <oscar.lehuu@gmail.com>
@cursor
cursor Bot force-pushed the devin/issue-274-workflows-sync branch from 14416f4 to 2a00858 Compare August 22, 2026 14:03
@cursor

cursor Bot commented Aug 22, 2026

Copy link
Copy Markdown

Rebased devin/issue-274-workflows-sync onto current origin/main (cddaeb0f, #313/#291 archive-selector plus #314/#315/#316/#317). New head: 2a0085837 (was 14416f4b). Force-with-lease to the same branch — this updates #308; no new PR.

cursor Bot pushed a commit that referenced this pull request Aug 22, 2026
@cursor

cursor Bot commented Aug 22, 2026

Copy link
Copy Markdown

Post-rebase screenshots (head 2a0085837, onto cddaeb0f)

Full-window E2E mock-bridge captures after rebasing onto current main. Channel-first sidebar is intact (Inbox / Pulse / Wiki / Agents / Workflows + channels). No Projects or Workbench rail.

Hosted on agent-screenshots/cursor at d26f1254fab6fedf9bbc89f17b773e5b81934047 (gh pr comment is not writable from this token; posting here instead).

Workflow library (empty)

Create tile only; Workflows selected in the channel-first sidebar.

01-workflows-library-empty

Workflow editor (create)

Route-addressable create overlay. Channel #agents, Send Message step, Reply to triggering message in thread checkbox visible for message triggers.

02-workflow-editor-create

Library with card

Created workflow PR308 reply-in-thread demo (ACTIVE, #agents).

03-workflows-library-with-card

Library card actions (block#6008)

Overflow menu: Trigger / Edit / Duplicate / Enable / Delete.

04-workflow-library-card-actions

Editor edit mode — run history not reachable

Edit overlay header has the actions menu and close control only. The run-history icon stays commented out in WorkflowDialog.tsx (TODO(workflow-run-history-capability), pending NIP-11 gating), matching upstream 0.5.18 and the Playwright specs that assert the button is absent.

05-workflow-editor-edit-no-run-history

Screen recording

Library → create editor (channel pick, name, Send Message + reply-in-thread checkbox) → save → card actions → edit. Run history remains hidden.

pr308-workflows-library-editor.mp4

@oscarlehuu
oscarlehuu merged commit b7d5009 into main Aug 22, 2026
14 of 28 checks passed
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.

upstream(sync): Workflows stack — run history, reply-in-thread, editor (#5780, #6178, #6248)

4 participants