[rig-tasks] Add 10 rig samples — 2026-07-25 - #136
Conversation
Samples cover git analysis, LOC stats, import cycles, coverage badges, license auditing, test mapping, version drift, author stats, path alias validation, and markdown frontmatter checking. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅ |
There was a problem hiding this comment.
Skills-Based Review 🧠
Applied /codebase-design and /grill-with-docs — commenting on correctness and consistency issues. No changes are strictly blocking, but a few are worth addressing before these samples are used as reference patterns.
📋 Key Themes & Highlights
Key Themes
node:fsimport style (samples 138, 139): Static top-level imports break the established pattern ofawait import("node:fs")inside async handlers. This matters because these samples teach the pattern to future agents.git shortlogfor per-file data (sample 130):git shortlogreturns repo-wide author stats, not per-file contributors. ThetopContributorsfield will contain inaccurate data.s.numbervss.int(sample 130):churnScoreis semantically an integer;s.intshould be used per SKILL.md guidance.p.writeOutputplacement (samples 133, 136): Embedding the side-effect intent mid-sentence in prose reduces readability; idiomatic placement is at the end of the template.- Schema descriptions on keyed records (sample 137):
authorsrecord key format (email) andtopAuthorsemantics benefit from a description string.
Positive Highlights
- ✅ All 10 samples pass typecheck — the pre-commit fix to
repair()arguments was caught and resolved correctly. - ✅ Good mix of addons:
steeringfor constraint enforcement,repairfor parse resilience. - ✅
defineToolis used appropriately as a deterministic helper, not to replace LLM judgment. - ✅
s.enumis used consistently for bounded classifications across all samples. - ✅ Correct use of
p.readOptional(path, "{}")with a JSON-parseable fallback.
🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 60.2 AIC · ⌖ 4.61 AIC · ⊞ 6.3K
Comment /matt to run again
| // Agent role: analyze which files are hot-spots by measuring commit churn and top contributors. | ||
| const gitHotspotAnalyzer = agent({ | ||
| model: "small", | ||
| instructions: p`Analyze file churn in this repository. List all tracked files: ${p.bash("git ls-files --exclude-standard | head -100")}. Get commit counts per file: ${p.bash("git log --follow --name-only --format='' -- . | sort | uniq -c | sort -rn | head -40")}. Get top contributors per file via: ${p.bash("git shortlog -sn --no-merges HEAD~50..HEAD 2>/dev/null || git shortlog -sn --no-merges | head -20")}. For each hot-spot file compute a churnScore 0–100 (based on commit frequency relative to max) and list topContributors.`, |
There was a problem hiding this comment.
[/codebase-design] git shortlog gives overall commit counts per author for the whole repo — it does not provide per-file contributor data. The topContributors field will be populated with repository-wide top committers rather than file-specific ones, making the output semantically incorrect.
💡 Suggestion
Replace with a per-file approach using git log:
git log --format="%ae" -- <file> | sort | uniq -c | sort -rn | head -5Or use defineTool with a per-file git log call so the LLM can query each hot-spot file individually, rather than injecting a single global shortlog that can't be decomposed per-file.
| model: "small", | ||
| instructions: p`Analyze file churn in this repository. List all tracked files: ${p.bash("git ls-files --exclude-standard | head -100")}. Get commit counts per file: ${p.bash("git log --follow --name-only --format='' -- . | sort | uniq -c | sort -rn | head -40")}. Get top contributors per file via: ${p.bash("git shortlog -sn --no-merges HEAD~50..HEAD 2>/dev/null || git shortlog -sn --no-merges | head -20")}. For each hot-spot file compute a churnScore 0–100 (based on commit frequency relative to max) and list topContributors.`, | ||
| output: s.record(s.object({ | ||
| churnScore: s.number, |
There was a problem hiding this comment.
[/grill-with-docs] churnScore is declared as s.number but the instructions constrain it to integer values 0–100. Per SKILL.md, use s.int for integer-valued fields to make the schema contract precise and enable integer validation.
💡 Fix
output: s.record(s.object({
churnScore: s.int, // was s.number
topContributors: s.array(s.string),
})),|
|
||
| ```rig | ||
| import { agent, p, s, defineTool } from "rig"; | ||
| import { existsSync } from "node:fs"; |
There was a problem hiding this comment.
[/grill-with-docs] Top-level import { existsSync } from "node:fs" deviates from the established pattern in existing samples (e.g. 66-ci-workflow-health.md, 119-source-map-analyzer.md), which use await import("node:fs") inside the handler. This inconsistency may cause issues in environments where ESM top-level imports of Node built-ins are restricted.
💡 Suggested fix
const checkAlias = defineTool("checkAlias", {
description: "Check whether a TypeScript path alias target directory exists",
parameters: s.object({ alias: s.string, target: s.string }),
handler: async ({ alias, target }) => {
const { existsSync } = await import("node:fs");
const resolved = target.replace(/\/\*$/, "");
const exists = existsSync(resolved);
return JSON.stringify({ alias, target, exists });
},
});Same fix applies to sample 139 which uses import { readFileSync, existsSync } from "node:fs" at the top level.
|
|
||
| Current README: ${p.readOptional("README.md", "")} | ||
|
|
||
| Parse the coverage summary JSON. Extract per-category percentages for statements, branches, functions, and lines. Compute overallPct as the average. Set rating: green (>=80%), yellow (60–79%), red (<60%). Generate shields.io badge markdown for each category and the overall percentage. Write the badge markdown to the output field badgeMarkdown. Set badgesWritten to true after generating. ${p.writeOutput("badgeMarkdown", "coverage-badges.md")}`, |
There was a problem hiding this comment.
[/grill-with-docs] p.writeOutput("badgeMarkdown", "coverage-badges.md") is embedded mid-sentence in the instructions prose. While it works, the idiomatic pattern (per existing samples like 127-git-commit-annotator.md) places the p.writeOutput at the end of the template string, making the side-effect intent clearly visible and separate from the reasoning instructions.
💡 Suggestion
Move ${p.writeOutput(...)} to a new line at the end of the template:
instructions: p`...Set badgesWritten to true after generating.
${p.writeOutput("badgeMarkdown", "coverage-badges.md")}`,Same pattern applies to sample 136 where p.writeOutput appears inline with via prose.
| firstCommit: s.string, | ||
| lastCommit: s.string, | ||
| })), | ||
| topAuthor: s.string, |
There was a problem hiding this comment.
[/grill-with-docs] topAuthor: s.string is underspecified — it holds an author email, which should use s.string only if no more precise type is available. More importantly, the authors record is keyed by email (from %ae) but the field is named authors with no documentation of the key format in the schema. Consider adding a description to clarify the semantics.
💡 Suggestion
output: s.object({
authors: s.record("keyed by author email", s.object({
commitCount: s.int,
firstCommit: s.string,
lastCommit: s.string,
})),
topAuthor: s.string("email of the author with the most commits"),
totalCommits: s.int,
}),
Summary
Added 10 new rig sample files to
skills/rig/samples/.Typecheck failures
Three tasks initially failed typecheck with
TS2554: Expected 0 arguments, but got 1when callingrepair({ maxTurns: N }). Therepair()addon takes no arguments —maxTurnsbelongs on the agent spec. All three were fixed before writing the sample files.Tasks run