Skip to content

feat(agent): show completed work without reopening the full thread - #2941

Open
BradGroux wants to merge 1 commit into
block:mainfrom
BradGroux:agent/job-result-handoff
Open

feat(agent): show completed work without reopening the full thread#2941
BradGroux wants to merge 1 commit into
block:mainfrom
BradGroux:agent/job-result-handoff

Conversation

@BradGroux

@BradGroux BradGroux commented Jul 26, 2026

Copy link
Copy Markdown

Closes #2932.

Observed problem

Buzz already has signed agent job events, but kind:43004 results are opaque strings. A requester has to reconstruct the requested outcome, final state, artifacts, verification, and blockers from the full thread, and Home can expose structured content as raw JSON.

What changes

  • Add a versioned JobResultPayload contract with dispositions, typed artifact references, verification results, explicit blockers, byte and item limits, unsafe-reference rejection, and cross-field invariants.
  • Add a typed SDK builder and buzz jobs handoff --channel <uuid> --job <event-id> --manifest <path|->.
  • Admit the existing 43001 through 43006 job lifecycle at the relay under channel-scoped messages:write authorization.
  • Add a Desktop handoff card and human-readable Home projection.
  • Keep legacy, malformed, unsupported, oversized, or tag-mismatched 43004 content on the existing Markdown fallback.
  • Document the protocol and privacy boundary in docs/nips/NIP-AJ.md.

Trust and compatibility

The signed content is authoritative, while schema and disposition tags are query hints. Desktop only trusts structured content when the payload event ID matches the single signed reply tag.

Artifact references fail closed. URL-shaped references are parsed before kind-specific validation, including artifact kinds that also accept raw branch, canvas, workflow-output, or free-form references. Credential-bearing URLs, POSIX absolute paths, Windows rooted paths, drive-letter paths, and UNC paths are rejected in both Rust and Desktop instead of becoming clickable or relay-visible handoff data.

Version 1 ignores additive unknown object fields. Older clients continue to see JSON content as ordinary text, and newer clients continue to render legacy plaintext results as Markdown.

Verification

Verified on exact head 372308646b32fff1fe2324c7977c8207e0992d04, rebased onto current main at b1b283cd4c7f926e12eeee8ae1f38c7471922b16:

  • Full Rust suites for buzz-core, buzz-sdk, and buzz-cli passed.
  • The three relay admission, channel-scope, and migrated-kind regressions passed.
  • Full Desktop JavaScript suite: 3,901 tests passed, 0 failures.
  • Desktop lint, file-size ratchet, typecheck, and production build passed.
  • Rust and Desktop regressions cover relay authorization, channel scoping, unsafe URLs, absolute local paths across operating systems, malformed payload fallback, and reader-facing disposition copy.

The SDK signing test round-trips the canonical payload through the signed event shape. A complete relay library run reached 825 passed and 35 ignored, but nine unchanged admin/media tests could not acquire their local Postgres fixture (Sqlx(PoolTimedOut)); an isolated rerun reproduced the same missing-fixture failure. A live remote relay integration run was not performed.

Non-goals

  • No scheduler, worker loop, approval system, project-management surface, or local workspace scanner.
  • No change to job acceptance or agent mention delivery.
  • No new HTTP endpoint or production dependency.

@BradGroux
BradGroux requested a review from a team as a code owner July 26, 2026 04:21
@BradGroux

Copy link
Copy Markdown
Author

Result handoff card

The same signed kind:43004 payload renders with distinct outcome, progress, artifact, verification, and disposition fields in both supported themes.

Light theme

Agent result handoff card in the light theme

Dark theme

Agent result handoff card in the dark theme

@BradGroux BradGroux changed the title feat(jobs): add inspectable agent result handoffs Show completed agent work without reopening the full thread Jul 26, 2026
@BradGroux
BradGroux force-pushed the agent/job-result-handoff branch from daef386 to fcb0ede Compare July 28, 2026 16:40
@BradGroux

Copy link
Copy Markdown
Author

I rebased this branch onto current main and re-audited the trust boundary around artifact references.

The structured handoff remains relevant and does not overlap the newer invite or Markdown parser changes on main. The review did find one real validation gap: artifact kinds that can accept raw references (branch, canvas, workflow_output, and other) could also accept a URL containing embedded credentials because their validators treated the value as an opaque raw reference first. Desktop could then render that value as a link.

Head f387a8e9b75c4462df9073f3b442f12276d25fbe parses URL-shaped values before kind-specific raw-reference validation and rejects embedded credentials consistently in Rust and Desktop. Regression coverage spans every affected artifact kind.

Verification was refreshed against the rebased tree: the full affected Rust package suites, all 3,737 Desktop JavaScript tests, Desktop typecheck and E2E build, strict Rust formatting/Clippy, and targeted Biome checks passed. A live relay submission was not rerun, so the proof remains the signed-event round trip plus the existing relay submission path.

@BradGroux BradGroux changed the title Show completed agent work without reopening the full thread feat(agent): show completed work without reopening the full thread Jul 29, 2026
@cameronhotchkies cameronhotchkies added the triage-ready Appropriate for agentic review label Jul 29, 2026
@BradGroux
BradGroux force-pushed the agent/job-result-handoff branch from fcb0ede to 7d1c3bc Compare July 30, 2026 14:37
@BradGroux

Copy link
Copy Markdown
Author

Rebased this branch onto current block/buzz main at c55e421a0.

Head moved from fcb0edeea to 7d1c3bc43. The CLI test conflict was resolved by retaining both current main's user-status parser coverage and this branch's jobs handoff parser coverage. The current message-row changes from main also remain intact alongside the inspectable job-result card.

Verification:

  • The full buzz-core, buzz-sdk, and buzz-cli test suites passed.
  • Strict Clippy passed for those three packages with all targets and warnings denied.
  • Desktop Biome, file-size, text-size, and pubkey-truncation checks passed.
  • The full Desktop test suite, TypeScript typecheck, and production Vite build passed on the final rebased branch.
  • git diff --check, DCO trailer checks, and the direct merge-base audit passed.

GitHub checks are rerunning on the new head.

@BradGroux
BradGroux force-pushed the agent/job-result-handoff branch from 7d1c3bc to 3723086 Compare August 1, 2026 01:13
@BradGroux

Copy link
Copy Markdown
Author

Rebased onto current main at b1b283cd4c7f926e12eeee8ae1f38c7471922b16 and re-audited #2932 against the current open-PR landscape. #3877 explicitly leaves structured handoff cards out of scope, so this work is not superseded.

A clean-context review found three gaps that are now repaired:

  • The relay now admits job lifecycle kinds 43001 through 43006 under channel-scoped messages:write authorization and requires the signed h tag.
  • Rust and Desktop now reject Windows rooted and UNC file references in addition to POSIX absolute and drive-letter paths.
  • Empty-artifact copy distinguishes blocked and failed results from an intentional no_artifact completion.

Exact-head verification on 372308646b32fff1fe2324c7977c8207e0992d04:

  • Full Rust suites for buzz-core, buzz-sdk, and buzz-cli passed.
  • The three relay admission, channel-scope, and migrated-kind regressions passed.
  • Full Desktop JavaScript suite: 3,901 passed, 0 failed.
  • Desktop lint, file-size ratchet, typecheck, and production build passed.

No live remote relay was used. A complete relay library run reached 825 passed and 35 ignored, but nine unchanged admin/media tests could not acquire their local Postgres fixture (Sqlx(PoolTimedOut)); an isolated rerun reproduced the same missing-fixture failure. The changed relay boundary is covered by the passing authorization and scope regressions, and the signed SDK event shape is round-tripped in tests.

@BradGroux
BradGroux force-pushed the agent/job-result-handoff branch from 3723086 to c3fd8e1 Compare August 4, 2026 20:14
@BradGroux

Copy link
Copy Markdown
Author

Rebased onto block/buzz main at ce3cf3cd2591f132f286fbc0a42a9e6699d0b08d and re-audited #2932 against current job, CLI, relay, and timeline behavior.

The PR remains valid. Current main still treats kind:43004 results as opaque content and has no versioned JobResultPayload, typed SDK builder, buzz jobs handoff command, or inspectable JobResultCard. PR #3877 explicitly leaves structured handoff cards out of scope. The newer CLI and timeline changes do not supply or supersede this contract, and I found no external review claim that supports closing the PR.

The rebase was clean and retained current main's CLI and timeline behavior. Exact-head verification on c3fd8e1b88fd665be0c36c1ea9f8b0642d5f5361:

  • The full buzz-core, buzz-sdk, and buzz-cli suites passed.
  • The complete buzz-relay library suite executed with 831 passed and 37 ignored. Nine unchanged database-backed admin/media tests failed because the local Postgres fixture was unavailable: seven reported Sqlx(PoolTimedOut) directly, while two admin endpoint assertions received 500 instead of the expected 404 under the same unavailable database path.
  • The changed relay admission regression agent_job_kinds_require_message_write_and_channel_scope passed, along with the SDK and CLI job-handoff regressions.
  • The full Desktop JavaScript suite, Desktop policy checks, TypeScript typecheck, and production build passed.
  • cargo fmt --all -- --check, warnings-as-errors Clippy, git diff --check, the direct merge-base check, and the required commit trailers passed.

No live remote relay submission was performed. The signed event shape, authorization boundary, structured fallback behavior, unsafe-reference rejection, and rendered handoff behavior are covered by the passing local regressions. GitHub checks are rerunning on the new head.

Co-authored-by: Brad Groux <bradgroux@hotmail.com>
Signed-off-by: Brad Groux <bradgroux@hotmail.com>
@BradGroux
BradGroux force-pushed the agent/job-result-handoff branch from c3fd8e1 to dfa8e6b Compare August 5, 2026 22:27
@BradGroux

Copy link
Copy Markdown
Author

Review and rebase summary

Reviewed the PR for accuracy against current block/buzz main at d42d60d64 and rebased the branch onto that commit.

What this PR does

Adds a structured agent job result handoff as a new signed kind:43004 Nostr event. The payload (JobResultPayload in buzz-core/src/job.rs) carries schema version, job request reference, requested outcome, final outcome, disposition (completed, no_artifact, blocked, partial), artifacts with references (not embedded file contents), verification evidence, and an optional blocker. The buzz jobs handoff CLI subcommand validates and publishes the payload. The desktop app renders a result handoff card in the timeline.

Accuracy review

  • The payload validation is thorough: schema version check, event ID format validation, size limits on every text field, cross-field invariants (completed requires an artifact, no_artifact forbids artifacts, blocked requires a blocker), and bounded item counts (max 50 artifacts, max 50 verifications).
  • The JobArtifact reference model is correct — it carries a URL or reference, not embedded content, and the sourceState field is bounded. This avoids relay storage abuse.
  • The CLI handoff command correctly validates that the manifest's jobRequest matches the --job argument, preventing a mismatched manifest from being published against the wrong job.
  • Unit tests cover manifest parsing, invalid JSON, invalid contract version, and job-ID mismatch. The CLI integration test verifies --manifest accepts both file paths and stdin.
  • The buzz-sdk event builder (build_job_result) is wired through the same sign-and-submit path as other CLI commands.
  • No unwrap() or expect() in production paths. No new dependencies.

Rebase result

Head moved from c3fd8e1b8 to dfa8e6b8b. No conflicts. git range-diff shows the patch is unchanged.

CI

DCO passes. Semgrep OSS and zizmor were pending at the time of this comment.

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

Labels

triage-ready Appropriate for agentic review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make completed agent work inspectable without reading the full thread

2 participants