fix: rewrite agents to the real runtime VFS API#19
Conversation
…x.<provider>)
These agents called a ctx.github/ctx.linear/ctx.slack/ctx.notion client API that
does not exist on WorkforceCtx — 33 TS2339 errors, and the `if (!ctx.linear)`
guards would have thrown at runtime (the agents were never functional). Rewrote
all 7 to the real VFS helpers (writeJsonFile/readJsonFile/draftFile/
encodeSegment/resolveMountRoot), mirroring examples/{review-agent,linear-shipper,
notion-essay-pr}: provider reads/writes go through canonical VFS paths and
writeback receipts. Control flow + ctx.harness/llm/files/sandbox/memory/log
preserved. tsc clean (0 errors); no ctx.<provider> references remain.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
📝 WalkthroughWalkthroughSeven agents (granola, hn-monitor, linear, repo-hygiene, review, spotify-releases, vendor-monitor) are refactored to route integration requests through a VFS relay mechanism. Instead of calling ChangesVFS relay migration for agent integrations
Sequence Diagram(s)sequenceDiagram
participant LinearAgent
participant VFS as VFS Relay
participant LinearAPI as Linear API
LinearAgent->>VFS: writeJsonFile(linear/createIssue)
VFS->>LinearAPI: Create issue request
LinearAPI-->>VFS: receipt {issueId, issueUrl}
VFS-->>LinearAgent: return receipt
LinearAgent->>VFS: writeJsonFile(linear/comment)
VFS->>LinearAPI: Post PR-link comment
LinearAPI-->>VFS: receipt
VFS-->>LinearAgent: return receipt
sequenceDiagram
participant ReviewAgent
participant VFS as VFS Relay
participant GithubAPI as GitHub API
ReviewAgent->>VFS: writeJsonFile(/pulls/N/comment)
VFS->>GithubAPI: Post PR comment
GithubAPI-->>VFS: receipt
VFS-->>ReviewAgent: return receipt
ReviewAgent->>VFS: writeJsonFile(/pulls/N/merge.json)
VFS->>GithubAPI: Merge PR (squash method)
GithubAPI-->>VFS: receipt {merged: true}
VFS-->>ReviewAgent: return receipt?.merged
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request refactors several agents to migrate from direct integration clients on ctx (such as ctx.linear, ctx.slack, ctx.github, and ctx.notion) to a Virtual File System (VFS) approach using readJsonFile and writeJsonFile from @agentworkforce/runtime. Feedback on the changes highlights potential runtime crashes in linear/agent.ts and repo-hygiene/agent.ts if readJsonFile returns null or undefined, recommending the addition of guard checks to handle missing files or VFS read failures safely.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| const issue = await readJsonFile<LinearIssue>( | ||
| client, | ||
| 'linear', | ||
| 'getIssue', | ||
| `/linear/issues/${encodeSegment(issueId)}.json` | ||
| ); |
There was a problem hiding this comment.
The readJsonFile call can return null or undefined if the issue is not found or the VFS read fails. We should add a guard check to prevent a potential runtime crash when passing issue to parseRepo(issue).
const issue = await readJsonFile<LinearIssue>(\n client,\n 'linear',\n 'getIssue',\n \`/linear/issues/${encodeSegment(issueId)}.json\`\n );\n if (!issue) {\n ctx.log('warn', 'linear-implementer.issue-not-found', { issueId });\n return;\n }| const details = await readJsonFile<GithubPrMeta>( | ||
| client, | ||
| 'github', | ||
| 'getPr', | ||
| `/github/repos/${encodeSegment(pr.owner)}/${encodeSegment(pr.repo)}/pulls/${pr.number}/meta.json` | ||
| ); |
There was a problem hiding this comment.
The readJsonFile call can return null or undefined if the file is missing or the VFS read fails. We should add a guard check to prevent a potential runtime crash when accessing details.diff.
const details = await readJsonFile<GithubPrMeta>(\n client,\n 'github',\n 'getPr',\n \`/github/repos/${encodeSegment(pr.owner)}/${encodeSegment(pr.repo)}/pulls/${pr.number}/meta.json\`\n );\n if (!details) {\n ctx.log('warn', 'repo-hygiene.pr-details-not-found', { pr });\n return;\n }There was a problem hiding this comment.
🧹 Nitpick comments (1)
linear/agent.ts (1)
57-62: 💤 Low valueConsider handling readJsonFile failures gracefully.
If the Linear issue doesn't exist or the VFS read fails,
readJsonFilemay throw or return unexpected data. Theissue.titleaccess on Line 75 assumes the issue was successfully fetched.💡 Optional: wrap readJsonFile in try-catch
- const issue = await readJsonFile<LinearIssue>( - client, - 'linear', - 'getIssue', - `/linear/issues/${encodeSegment(issueId)}.json` - ); + let issue: LinearIssue; + try { + issue = await readJsonFile<LinearIssue>( + client, + 'linear', + 'getIssue', + `/linear/issues/${encodeSegment(issueId)}.json` + ); + } catch (err) { + ctx.log?.('warn', 'linear.issue-read-failed', { issueId, error: String(err) }); + return; + }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@linear/agent.ts` around lines 57 - 62, The call to readJsonFile that sets const issue should be made resilient: wrap the readJsonFile(...) call in a try-catch (or handle its Promise rejection) inside the surrounding function, catch errors from readJsonFile/encodeSegment, log or surface the error, and ensure you validate that the returned issue is non-null and has expected fields (e.g., issue.title) before using them; update any downstream code that assumes issue.title (in this file/function) to handle a missing issue by returning early, throwing a clear error, or using a safe fallback.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@linear/agent.ts`:
- Around line 57-62: The call to readJsonFile that sets const issue should be
made resilient: wrap the readJsonFile(...) call in a try-catch (or handle its
Promise rejection) inside the surrounding function, catch errors from
readJsonFile/encodeSegment, log or surface the error, and ensure you validate
that the returned issue is non-null and has expected fields (e.g., issue.title)
before using them; update any downstream code that assumes issue.title (in this
file/function) to handle a missing issue by returning early, throwing a clear
error, or using a safe fallback.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: b3bfb5b7-e744-4142-b752-546f34c4fc78
📒 Files selected for processing (7)
granola/agent.tshn-monitor/agent.tslinear/agent.tsrepo-hygiene/agent.tsreview/agent.tsspotify-releases/agent.tsvendor-monitor/agent.ts
There was a problem hiding this comment.
1 issue found across 7 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="granola/agent.ts">
<violation number="1" location="granola/agent.ts:59">
P2: PR-link comment can be dropped when `createIssue` receipt arrives late because `issueId` is captured once and never refreshed.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| // the Linear create lands. Without a receipt we can't link the issue or | ||
| // address a follow-up comment, so log and continue with the implementation. | ||
| const issueUrl = created.receipt?.url; | ||
| const issueId = created.receipt?.id ?? created.receipt?.identifier; |
There was a problem hiding this comment.
P2: PR-link comment can be dropped when createIssue receipt arrives late because issueId is captured once and never refreshed.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At granola/agent.ts, line 59:
<comment>PR-link comment can be dropped when `createIssue` receipt arrives late because `issueId` is captured once and never refreshed.</comment>
<file context>
@@ -33,18 +44,44 @@ export default defineAgent({
+ // the Linear create lands. Without a receipt we can't link the issue or
+ // address a follow-up comment, so log and continue with the implementation.
+ const issueUrl = created.receipt?.url;
+ const issueId = created.receipt?.id ?? created.receipt?.identifier;
+ if (!issueUrl) {
+ ctx.log('warn', 'granola-prospect.issue.no-receipt', { draftPath: created.path });
</file context>
These agents used a
ctx.<provider>client API (ctx.linear.createIssue,ctx.github.comment,ctx.slack.post, …) that does not exist onWorkforceCtx— 33 TS2339 errors, and theif (!ctx.linear) throwguards would have thrown at runtime, so the agents were never functional.Rewrote all 7 to the real
@agentworkforce/runtimeVFS API (writeJsonFile/readJsonFile/draftFile/encodeSegment/resolveMountRoot), using the canonical adapter VFS paths and writeback receipts — modeled onexamples/{review-agent,linear-shipper,notion-essay-pr}. Control flow and the realctx.harness/llm/files/sandbox/memory/logusage are preserved.tsc --noEmitis clean (0 errors); noctx.<provider>references remain.🤖 Generated with Claude Code
Summary by cubic
Rewrote all seven agents to use the real
@agentworkforce/runtimeVFS API instead of non-existentctx.<provider>calls, fixing 33 TS errors and runtime crashes. Agents now interact with GitHub, Linear, Slack, and Notion via Relayfile and are functional.Bug Fixes
ctx.github/ctx.linear/ctx.slack/ctx.notioncalls with VFS helpers (writeJsonFile,readJsonFile,draftFile,encodeSegment,resolveMountRoot).tscis clean (0 errors).Refactors
vfsClient()helper to supplyrelayfileMountRoot.ctx.harness/llm/files/sandbox/memory/logusage.Written for commit 8ef61ac. Summary will update on new commits.