Skip to content

feat(examples): add review-agent + linear-shipper (Relayfile-VFS clients)#93

Open
khaliqgant wants to merge 5 commits into
feat/integrations-vfsfrom
feat/integrations-vfs-examples
Open

feat(examples): add review-agent + linear-shipper (Relayfile-VFS clients)#93
khaliqgant wants to merge 5 commits into
feat/integrations-vfsfrom
feat/integrations-vfs-examples

Conversation

@khaliqgant
Copy link
Copy Markdown
Member

Summary

Two reference example agents demonstrating the Relayfile-VFS integration-client pattern landed in #92:

  • examples/review-agent/ — GitHub PR review + autofix. Reviews opened PRs (`pull_request.opened`), responds to `@mention` in issue/review comments, proposes fixes on failed CI checks, replies in Slack on `app_mention`. Uses `ctx.github.{getPr,postReview,comment}` + `ctx.slack.reply` + `ctx.harness.run`.
  • examples/linear-shipper/ — Paraglide-style headless agent. On `linear.issue.created`, clones the target repo into the sandbox, runs the harness on the issue body, opens a draft PR via `ctx.github`, comments back on the Linear issue.

Ported from the closed `codex/deploy-v1-pr` branch (#88) and adapted to the `WorkforceProviderEvent` shape — examples read the provider payload from `event.payload` rather than treating the event as the payload itself.

Stacked on #92 (Relayfile-VFS substrate). Will rebase to `main` once that lands.

Test plan

  • `pnpm -r run typecheck` — clean
  • `pnpm run typecheck:examples` — clean (verified locally)
  • Personas dry-run: `workforce deploy ./examples/review-agent/persona.json --dry-run` and `workforce deploy ./examples/linear-shipper/persona.json --dry-run` both pass

🤖 Generated with Claude Code

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 12, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d2950e77-c94b-4820-9fcf-316fd383c400

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/integrations-vfs-examples

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 4 additional findings in Devin Review.

Open in Devin Review

Comment thread examples/linear-shipper/agent.ts Outdated
if (!ctx.linear) throw new Error('linear-shipper requires the linear integration');
if (!ctx.github) throw new Error('linear-shipper requires the github integration');

const issueRef = (event as LinearIssueEvent).issue;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Linear issue data read from event envelope instead of event.payload

On line 29, (event as LinearIssueEvent).issue casts the WorkforceProviderEvent envelope itself to LinearIssueEvent and reads .issue from it. However, the WorkforceProviderEvent type (packages/runtime/src/types.ts:49-62) stores the raw provider payload in event.payload, not on the event envelope. Since WorkforceProviderEvent has no issue field, issueRef is always undefined, causing issueId to be undefined, and the handler always throws "Linear event is missing an issue id" on line 31. The review-agent correctly uses payloadOf(event.payload) (examples/review-agent/agent.ts:96) to extract the nested payload. The fix is to read from event.payload instead of event.

Suggested change
const issueRef = (event as LinearIssueEvent).issue;
const issueRef = (event.payload as LinearIssueEvent)?.issue;
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

khaliqgant and others added 2 commits May 12, 2026 20:17
…t style

Switches workforce's integration clients from direct REST calls to the
Relayfile-VFS writeback pattern used by sage + the cloud workflows.
Handler-side surface (ctx.github.upsertIssue, ctx.linear.comment, etc.)
stays identical; the wire underneath flips from "speak HTTP to GitHub"
to "write a JSON draft inside the Relayfile mount and let the writeback
worker do the actual API call." Aligns workforce with the rest of the
org's integration story and inherits writeback durability + retry for
free.

Substrate
  - packages/runtime/src/errors.ts (top-level): WorkforceIntegrationError
    moves here with the { provider, operation, cause, retryable } shape
    sage/cloud already use. Old clients/errors.ts is removed; the public
    surface re-exports it from the same package import path so existing
    consumers (mcp-workforce) keep compiling.
  - packages/runtime/src/clients/request.ts: shared VFS helpers
    (readJsonFile, readTextFile, listJsonFiles, listDirectoryEntries,
    writeJsonFile + atomic write-then-rename) with mount-root path
    validation and optional writeback-receipt polling.

Clients
  - github.ts is rewritten as a VFS client. Same GithubClient interface
    (comment, createIssue, upsertIssue, getPr, postReview); each method
    now reads/writes files at canonical paths under
    `/github/repos/<owner>/<repo>/...`.
  - linear, slack, notion, jira ship as new typed clients with the same
    pattern. IntegrationClients in types.ts now types all five concretely
    instead of leaving four as unknown.

Tests
  - github.test.ts is rewritten end-to-end against a tempdir mount.
  - linear/slack/notion/jira tests run against tempdir mounts too.
  - 29 runtime tests pass (up from 18), 386 across the repo.

Example
  - weekly-digest/agent.ts drops the WORKFORCE_INTEGRATION_GITHUB_TOKEN
    plumbing; the github client picks up RELAYFILE_MOUNT_ROOT instead.
  - weekly-digest/README.md documents the writeback model + Relayfile
    mount env requirement, and drops the GITHUB_TOKEN setup step.

Notes
  - mcp-workforce (PR #91) imports createGithubClient with a different
    construction shape today (`{ token }`); it'll need a follow-up
    commit to switch to IntegrationClientOptions once this lands. The
    MCP package depends on the new shape, not the old.
  - The direct-REST github implementation that shipped in #90 is
    replaced wholesale. No persona today depends on it; weekly-digest
    is updated in this commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Follow-on to the persona-tier flatten refactor — the openclaw-routing
example still read from selection.runtime.* and selection.tier, which no
longer exist after PersonaSelection lost its per-tier wrapper.
Required to keep the examples typecheck green on top of the flatten.
@khaliqgant khaliqgant force-pushed the feat/integrations-vfs branch from efb115b to 1f8dcdb Compare May 12, 2026 18:20
khaliqgant and others added 3 commits May 12, 2026 20:30
Ports the two example agents from the closed codex/deploy-v1-pr branch
to the Relayfile-VFS integration-client style introduced in #92.

review-agent
  - GitHub PR opened: pulls the diff via ctx.github.getPr, runs the
    persona's harness on the diff body, posts a review via
    ctx.github.postReview.
  - @mention in an issue/review comment: harness with the comment
    thread as context, posts the reply via ctx.github.comment.
  - check_run.completed (failure): harness with the failed CI logs as
    context, proposes a fix in a comment.
  - Slack app_mention: conversational reply via ctx.slack.

linear-shipper
  - Linear issue created: clones the target repo into the sandbox,
    runs ctx.harness.run on the issue body, opens a draft PR via
    ctx.github, comments back on the Linear issue with the PR link.
  - Headless (no traits in the persona); demonstrates the paraglide
    "Linear issue → ship" pattern.

Both examples adapt to the WorkforceProviderEvent shape — they read
the raw provider payload from event.payload rather than treating the
event as the payload itself.

Tests: typecheck clean across the workspace and against
examples/tsconfig.json (which path-maps @agentworkforce/runtime to
the workspace source).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Same shape mismatch I fixed in review-agent: the agent was reading
event.issue as if event were the raw Linear webhook body, but
WorkforceProviderEvent.payload is where the provider payload lives.
Without this fix, every linear.issue.created delivery to the
shipper failed at the "Linear event is missing an issue id" guard
because issueRef was always undefined.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
persona-kit's parser rejects unknown intents. "implementation" is in
PERSONA_TAGS, not PERSONA_INTENTS, so the persona failed at
parsePersonaSpec(...) with `persona[implementation].intent is invalid`
before deploy could do anything. Swap to `implement-frontend` — the
closest valid intent. Not a perfect domain match (the shipper isn't
frontend-specific) but accurate enough to demonstrate the pattern;
users will customize per their own routing taxonomy.

Verified end-to-end: `workforce deploy ./examples/linear-shipper/persona.json --dry-run`
now exits 0 with "persona linear-shipper: 2 integration(s)".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgant khaliqgant force-pushed the feat/integrations-vfs-examples branch from 6718791 to b84f738 Compare May 12, 2026 18:31
@khaliqgant khaliqgant force-pushed the feat/integrations-vfs branch 3 times, most recently from af8f4a2 to 2fa0ef9 Compare May 12, 2026 22:51
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