-
Notifications
You must be signed in to change notification settings - Fork 0
[rig-claude] Improve Claude dynamic-workflow compatibility for rig #344
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,64 +1,39 @@ | ||
| # 360 - Parallel Branch Analysis Workflow | ||
|
|
||
| Uses `parallel(thunks)` — rig's equivalent of `parallel(thunks)` in Claude | ||
| dynamic workflows. `parallel` respects the shared concurrency limiter and | ||
| converts failures to `null` holes. Use it instead of `Promise.all` when porting | ||
| a Claude dynamic workflow. | ||
|
|
||
| ```rig | ||
| import { agent, p, s, workflow } from "rig"; | ||
|
|
||
| // Agent role: analyze git branch count and classify active vs stale branches. | ||
| const branchHealthAgent = agent({ | ||
| model: "small", | ||
| instructions: p`Analyze git branches and classify active vs stale. | ||
|
|
||
| Branch list: | ||
| ${p.bash("git branch -a 2>/dev/null || echo ''")} | ||
| const metric = s.object({ label: s.string, value: s.number }); | ||
|
|
||
| Count totalBranches (all branches listed). List activeBranches as local branch names (lines not starting with "remotes/"). | ||
| staleCount = totalBranches - activeBranches.length.`, | ||
| output: s.object({ | ||
| totalBranches: s.int, | ||
| staleCount: s.int, | ||
| activeBranches: s.array(s.string), | ||
| }), | ||
| }); | ||
| // Agent role: measure branch staleness as a labeled metric. | ||
| const branchAgent = agent({ model: "small", output: metric, | ||
| instructions: p`Count stale/total branches.\n${p.bash("git branch -a 2>/dev/null || echo ''")}` }); | ||
|
|
||
| // Agent role: analyze git commit frequency over the last 30 days. | ||
| const commitFrequencyAgent = agent({ | ||
| model: "small", | ||
| instructions: p`Analyze git commit frequency over the last 30 days. | ||
| // Agent role: measure average commits per day over the last 30 days. | ||
| const commitAgent = agent({ model: "small", output: metric, | ||
| instructions: p`Count commits per day.\n${p.bash("git log --since='30 days ago' --format='%h' 2>/dev/null | wc -l || echo 0")}` }); | ||
|
|
||
| Commit dates: | ||
| ${p.bash("git log --since='30 days ago' --format='%ad' --date=short 2>/dev/null || echo ''")} | ||
|
|
||
| totalCommits = number of non-empty lines. activeDays = number of unique dates. | ||
| averagePerDay = totalCommits / 30.`, | ||
| output: s.object({ | ||
| totalCommits: s.int, | ||
| activeDays: s.int, | ||
| averagePerDay: s.number, | ||
| }), | ||
| }); | ||
|
|
||
| // Workflow role: run branch health and commit frequency agents, then synthesize an overall health rating. | ||
| const parallelBranchAnalysisWorkflow = workflow({ | ||
| meta: { name: "parallelBranchAnalysis", description: "Parallel branch and commit analysis", phases: ["Analyze", "Synthesize"] }, | ||
| body: async ({ call, phase }) => { | ||
| phase("Analyze"); | ||
| const [branchHealth, commitFrequency] = await Promise.all([ | ||
| call(branchHealthAgent, "analyze branch health"), | ||
| call(commitFrequencyAgent, "analyze commit frequency"), | ||
| // Workflow role: run branch and commit agents in parallel, then synthesize a health rating. | ||
| const analysis = workflow({ | ||
| meta: { name: "repoHealth", description: "Parallel repo health analysis", phases: ["Measure", "Rate"] }, | ||
| body: async ({ call, parallel, phase }) => { | ||
| phase("Measure"); | ||
| const [branches, commits] = await parallel([ | ||
| () => call(branchAgent, "measure"), | ||
| () => call(commitAgent, "measure"), | ||
| ]); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [/grill-with-docs] The PR's stated teaching goal is that 💡 SuggestionAdd a brief inline guard to make the null-hole pattern explicit: const [branches, commits] = await parallel([
() => call(branchAgent, "measure"),
() => call(commitAgent, "measure"),
]);
// branches or commits may be null if an agent failed
if (!branches || !commits) return "insufficient-data";This turns the sample into a real demonstration of the failure-semantic difference versus |
||
|
|
||
| phase("Synthesize"); | ||
| const overallHealth = await call.json( | ||
| `Given branchHealth=${JSON.stringify(branchHealth)} and commitFrequency=${JSON.stringify(commitFrequency)}, | ||
| classify overallHealth as "healthy" (averagePerDay >= 1 and staleCount < 3), | ||
| "needs-attention" (averagePerDay < 1 or staleCount >= 3), or "critical" (averagePerDay < 0.1 or staleCount >= 10).`, | ||
| phase("Rate"); | ||
| return call.json( | ||
| `branches=${JSON.stringify(branches)} commits=${JSON.stringify(commits)}. Rate as "healthy", "needs-attention", or "critical".`, | ||
| s.enum("healthy", "needs-attention", "critical"), | ||
| ); | ||
|
|
||
| return { branchHealth, commitFrequency, overallHealth }; | ||
| }, | ||
| }); | ||
|
|
||
| export default parallelBranchAnalysisWorkflow; | ||
|
|
||
| export default analysis; | ||
| ``` | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[/grill-with-docs]
metricschema declareslabel: s.string, but neither agent instruction tells the model what value to put there — only numeric counting is described. This risks repair loops or silently hallucinated label values.💡 Suggestion
Either drop the
labelfield (the caller already knows which agent produced which slot), or explicitly instruct each agent to set it:A schema field with no prompt instruction is a latent repair-loop.