feat(examples): add review-agent + linear-shipper (Relayfile-VFS clients)#93
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
efb115b to
1f8dcdb
Compare
6718791 to
b84f738
Compare
2fa0ef9 to
8b2ebe1
Compare
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) <[email protected]>
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) <[email protected]>
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) <[email protected]>
b84f738 to
c123f2a
Compare
Track E2: Track E2 — rebase #93 (feat/integrations-vfs-examples) See workforce/docs/plans/deploy-v1-schema-cascade-spec.md
| function inputDefault(ctx: Parameters<Parameters<typeof handler>[0]>[0], name: string): string { | ||
| const value = ctx.persona.inputs?.[name]?.default; | ||
| if (!value) throw new Error(`${name} input is required`); | ||
| return value; | ||
| } |
There was a problem hiding this comment.
🔴 inputDefault reads static persona spec defaults, ignoring env-var overrides
The inputDefault helper at examples/linear-shipper/agent.ts:8 reads ctx.persona.inputs?.[name]?.default, which returns the literal default string from the persona JSON definition. This completely bypasses the persona-kit input resolution chain (resolvePersonaInputs at packages/persona-kit/src/inputs.ts:28-54) that checks explicit values → environment variables → defaults. When a user sets REPO_URL, GITHUB_OWNER, or GITHUB_REPO via environment variables (as the README at examples/linear-shipper/README.md:12 instructs), those overrides are silently ignored and the handler always uses the hardcoded JSON defaults (AgentWorkforce, workforce, etc.).
How the input resolution chain is supposed to work
The PersonaInputSpec type declares an env field that names the env var to read. When env is unset, the key name itself is the env var (e.g. REPO_URL maps to process.env.REPO_URL). resolvePersonaInputs implements this precedence. But inputDefault skips all of that and goes straight to .default.
Prompt for agents
The inputDefault function in examples/linear-shipper/agent.ts reads ctx.persona.inputs?.[name]?.default which only returns the static JSON default, ignoring environment variable overrides. The WorkforceCtx interface (packages/runtime/src/types.ts) does not currently expose resolved input values — it only carries the raw PersonaSpec. There are two possible fixes:
1. (Preferred) Add a resolvedInputs or inputValues field to WorkforceCtx (in packages/runtime/src/types.ts) and have the runner (packages/runtime/src/runner.ts) call resolvePersonaInputs at boot and attach the result. Then the handler reads ctx.inputValues[name] instead.
2. (Quick fix) Change inputDefault to use the same resolution logic as resolvePersonaInputs — read process.env using the input's env field (or the key name as fallback), then fall back to .default. Something like: const spec = ctx.persona.inputs?.[name]; const envName = spec?.env ?? name; const value = process.env[envName] ?? spec?.default;
Was this helpful? React with 👍 or 👎 to provide feedback.
inputDefault previously only returned the static persona JSON default, silently ignoring REPO_URL / GITHUB_OWNER / GITHUB_REPO env vars that the README instructs users to set. Mirror the precedence in resolvePersonaInputs (packages/persona-kit/src/inputs.ts): env var (spec.env ?? name) wins over spec.default. Addresses devin-ai-integration review comment on PR #93.
…t style (#92) * feat(runtime): adopt Relayfile-VFS as the canonical integration-client 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) <[email protected]> * (rebase PR #92 onto post-Track-D main) Track E1: Track E1 — rebase #92 (feat/integrations-vfs) See workforce/docs/plans/deploy-v1-schema-cascade-spec.md * fix(review): address CodeRabbit comments on PR #92 - github.upsertIssue update: preserve number/state/html_url/url so the next call still finds the canonical issue file by number. - github.getPr: use the discovered pull directory segment verbatim instead of re-encoding it (avoids double-escaping slug paths like `123__fix%2Fci`). - request.waitForReceipt: short-circuit in fire-and-forget mode (timeoutMs <= 0) before reading the just-written draft, so a draft payload carrying top-level id/path/created is never reinterpreted as a writeback receipt. - jira.transition: validate that the transition id is non-empty after trimming, throwing a non-retryable WorkforceIntegrationError. - notion.createPage: throw WorkforceIntegrationError instead of a generic Error when parent.database_id is missing, matching the rest of the integration error contract. - weekly-digest README: move RELAYFILE_MOUNT_ROOT in front of `node` (was scoped only to `echo`) and add a prerequisite note that real GitHub writes require the Relayfile writeback worker to be running. * feat(examples): add review-agent + linear-shipper (Relayfile-VFS clients) (#93) * feat(examples): add review-agent + linear-shipper examples (VFS clients) 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) <[email protected]> * fix(examples/linear-shipper): read event.payload, not event itself 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) <[email protected]> * fix(examples/linear-shipper): use a valid PERSONA_INTENT 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) <[email protected]> * fix(persona-kit): reject removed deploy v1 persona keys * (rebase PR #93 — strip traits/sandbox from examples) Track E2: Track E2 — rebase #93 (feat/integrations-vfs-examples) See workforce/docs/plans/deploy-v1-schema-cascade-spec.md * fix(examples/linear-shipper): honor env-var overrides in inputDefault inputDefault previously only returned the static persona JSON default, silently ignoring REPO_URL / GITHUB_OWNER / GITHUB_REPO env vars that the README instructs users to set. Mirror the precedence in resolvePersonaInputs (packages/persona-kit/src/inputs.ts): env var (spec.env ?? name) wins over spec.default. Addresses devin-ai-integration review comment on PR #93. --------- Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]> Co-authored-by: Ricky Schema Cascade <[email protected]> --------- Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]> Co-authored-by: Ricky Schema Cascade <[email protected]>
`ctx.persona.inputs` is `Record<string, string>` (resolved values) on WorkforcePersonaContext; the raw `PersonaInputSpec` with `.env` and `.default` lives at `ctx.persona.inputSpecs`. The earlier env-var- precedence patch on PR #93 read .env / .default off `.inputs`, which only worked while the type was loose. The post-cascade readonly tightening exposed the bug at typecheck time and broke the examples typecheck job. Also fold the runtime-resolved value into the fallback chain so we prefer env > resolved > spec.default — matching `resolvePersonaInputs`. Verified: `pnpm run typecheck` + `pnpm run typecheck:examples` both clean after rebuilding @agentworkforce/deploy dist. Co-Authored-By: Claude Opus 4.7 <[email protected]>
…p-workforce build (#104) * chore(publish): add runtime + deploy + mcp-workforce to the publish allow-list The publish.yml allow-list was last updated when the workspace had 5 packages (persona-kit, workload-router, cli, daytona-runner, agentworkforce). The deploy-v1 cascade shipped 3 more under @agentworkforce/* that the existing cli already depends on: - @agentworkforce/runtime (consumed by deploy, mcp-workforce) - @agentworkforce/deploy (consumed by cli) - @agentworkforce/mcp-workforce (consumed by harness CLIs via MCP) [email protected] already declares `@agentworkforce/[email protected]` as a runtime dep, but deploy was never published — the 0.0.0 on npm is a placeholder, so `npm i agentworkforce` today pulls a stub for `workforce deploy`. The same applies to deploy/mcp-workforce's runtime dep. This change preserves lockstep umbrella semantics and orders the publish in topological order (runtime before deploy/mcp-workforce, deploy before cli, cli before agentworkforce). personas-core stays on publish-personas.yml as before — not added here. Co-Authored-By: Claude Opus 4.7 <[email protected]> * fix(mcp-workforce): align memory scope enum with PersonaMemoryScope mcp-workforce was landed in #91 against an older `PersonaMemoryScope` shape (`session | user | workspace | org | object`). #94 then tightened the type to `workspace | user | global`. Both PRs passed CI independently, but main is now broken at build time because the zod enum in `server.ts` and the runtime `VALID_SCOPES` Set in `tools/memory.ts` still reference the removed literals. Aligning both call sites to the canonical persona-kit shape: - `MEMORY_SCOPE_ENUM` → z.enum(['workspace', 'user', 'global']) - `VALID_SCOPES` → new Set(['workspace', 'user', 'global']) - memory.save tool description updated to match The default scope stays `workspace`. Callers that previously passed `'session'`/`'org'`/`'object'` will now get a validation error from the zod schema before the runtime check — preferable to silently mapping them to a different scope. Verified: `pnpm -F @agentworkforce/mcp-workforce typecheck` + `build` + `test` (23/23) all pass. Co-Authored-By: Claude Opus 4.7 <[email protected]> * fix(publish): sync release-notes packageOrder with expanded allow-list CodeRabbit + Devin both flagged that the `packageOrder` array used to sort release-note entries was not updated alongside the publish allow-list, so `runtime` / `deploy` / `mcp-workforce` would have `indexOf === -1` and sort first (or in an arbitrary order depending on the sort impl). Mirror the topological order from "Resolve target packages": persona-kit → runtime → workload-router → deploy → mcp-workforce → daytona-runner → cli → agentworkforce Co-Authored-By: Claude Opus 4.7 <[email protected]> * fix(examples): linear-shipper read spec metadata from inputSpecs `ctx.persona.inputs` is `Record<string, string>` (resolved values) on WorkforcePersonaContext; the raw `PersonaInputSpec` with `.env` and `.default` lives at `ctx.persona.inputSpecs`. The earlier env-var- precedence patch on PR #93 read .env / .default off `.inputs`, which only worked while the type was loose. The post-cascade readonly tightening exposed the bug at typecheck time and broke the examples typecheck job. Also fold the runtime-resolved value into the fallback chain so we prefer env > resolved > spec.default — matching `resolvePersonaInputs`. Verified: `pnpm run typecheck` + `pnpm run typecheck:examples` both clean after rebuilding @agentworkforce/deploy dist. Co-Authored-By: Claude Opus 4.7 <[email protected]> * fix(persona-kit): make integration-source fixtures pass the schema test `emit-schema.test` failed on main because PR #97 (IntegrationConfig.source discriminator) added three new fixtures but they were missing two schema-required fields (`onEvent` for cloud personas, `skills`) and the test's hardcoded expected-filename list wasn't updated. Three small fixes: 1. `emit-schema.test.ts`: add the three new fixture names to the expected-filenames deepEqual. 2. `integration-source-{deployer,workspace,service-account}.json`: add `"onEvent": "./agent.ts"` and `"skills": []` to each, matching the pattern used in `full.json` / `cron-only.json`. The fixtures still exercise their intended IntegrationSource shapes (no-source default-inject, explicit `workspace`, explicit `workspace_service_account`) — only the cross-cutting required-for-cloud fields were added. Verified: `pnpm -F @agentworkforce/persona-kit test` → 162/162 pass. Co-Authored-By: Claude Opus 4.7 <[email protected]> --------- Co-authored-by: Ricky Schema Cascade <[email protected]> Co-authored-by: Claude Opus 4.7 <[email protected]>
Summary
Spec reference
Source spec: workforce/docs/plans/deploy-v1-schema-cascade-spec.md
Track section: Track E2 — rebase #93 (feat/integrations-vfs-examples)
Final signoff
SIGNOFF_FINAL: COMPLETE Track-E2
Final gate (typecheck + tests)
Self-reflection report
Known gaps after this PR
Co-Authored-By: Ricky deploy-v1 schema cascade [email protected]