[rig-tasks] Add 10 rig samples — 2026-07-28 - #253
Conversation
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 — no blocking issues, but several interface honesty and correctness gaps worth addressing before these samples become reference material.
📋 Key Themes & Highlights
Key Themes
- Unused parameters in tool schemas (275, 278):
keyininferTypeandvalueinanonymizeValueare declared but never read. This makes the tool contract misleading — callers believe the handler uses those inputs. - Correctness gap in CSV parsing (279):
parseCSVRowsilently corrupts rows containing quoted commas. At minimum, a comment should warn readers. - Regex matches commented code (277):
extractInterfaceswill matchinterfacetokens inside block comments, generating phantom type guards. - Missing
p.*intents in 276: The git hook installer tells the LLM to "write" and "chmod +x" in prose, but never declares those operations asp.write/p.bashintents — the sample doesn't demonstrate the primitives it implies.
Positive Highlights
- ✅ Good variety of
addonsusage:repair()on output-sensitive agents,steering()on open-ended classification. - ✅ Subagent delegation in 274 is cleanly structured with a dedicated
branchAnalyzeragent. - ✅
p.readOptionalusage in 275 is a good showcase of the optional-read primitive. - ✅ Async
defineToolhandlers (276, 277) correctly use dynamicimport()withnode:prefix.
🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 34.9 AIC · ⌖ 4.62 AIC · ⊞ 6.3K
Comment /matt to run again
| description: "Return an anonymized replacement for a field value based on its name and type.", | ||
| parameters: s.object({ fieldName: s.string, value: s.unknown, fieldType: s.string }), | ||
| handler({ fieldName, fieldType }) { | ||
| const name = fieldName.toLowerCase(); |
There was a problem hiding this comment.
[/codebase-design] The value parameter is declared in the tool schema (s.unknown) but silently ignored by the handler — only fieldName and fieldType drive the output.
This creates a misleading contract: callers assume the actual value influences anonymization, but it does not. For example, a nested object value still gets a flat "[REDACTED]" string.
💡 Suggested fix
Either remove value from the parameter schema, or use it for type-aware defaults:
if (Array.isArray(value)) return [];
if (typeof value === 'object' && value !== null) return {};| const inferType = defineTool("inferType", { | ||
| description: "Infer the type of an environment variable value using regex patterns.", | ||
| parameters: s.object({ key: s.string, value: s.string }), | ||
| handler({ value }) { |
There was a problem hiding this comment.
[/codebase-design] The key parameter is declared in inferType's schema but never used — the handler only operates on value.
Removing it from the schema keeps the interface honest and avoids confusing future readers who might expect key-based heuristics (e.g. DATABASE_URL → url even when the value is empty).
💡 Minimal fix
parameters: s.object({ value: s.string }),
handler({ value }) {Or use key as a fallback: if value is empty but the key name contains URL, return "url".
| const parseCSVRow = defineTool("parseCSVRow", { | ||
| description: "Split a CSV line into trimmed cell values.", | ||
| parameters: s.object({ line: s.string, delimiter: s.string }), | ||
| handler({ line, delimiter }) { |
There was a problem hiding this comment.
[/codebase-design] parseCSVRow splits on a bare delimiter without handling quoted fields — a value like "Smith, Jr." will be split into two cells, corrupting the table.
This is a correctness gap: the sample is named a CSV converter but doesn't handle the most basic CSV quoting rule. Either add a caveat in the description ("assumes no quoted fields"), or handle the common case.
💡 Simple quoted-field guard
handler({ line, delimiter }) {
// naive split — does not handle quoted fields
return { cells: line.split(delimiter).map((cell: string) => cell.trim()) };
}For a more robust approach, use a state-machine or the existing node:readline CSV parsing.
| description: "Extract interface names from a TypeScript source file.", | ||
| parameters: s.object({ filePath: s.path }), | ||
| async handler({ filePath }) { | ||
| const { readFile } = await import("node:fs/promises"); |
There was a problem hiding this comment.
[/codebase-design] The interface-extraction regex /interface\s+(\w+)/g will match interfaces inside block comments (/* interface Foo */) and string literals, producing phantom guard functions.
For a sample intended to demonstrate real extraction this is a misleading pattern. Add a comment noting the limitation, or filter out comment lines before matching.
💡 Quick mitigation
// Strip single-line and block comments before matching
const stripped = content.replace(/\/\/.*$/gm, '').replace(/\/\*[\s\S]*?\*\//g, '');
const matches = [...stripped.matchAll(/interface\s+(\w+)/g)];| First call checkHooksDir to verify the directory exists. | ||
| For each hook in input.hooks: | ||
| - If .git/hooks exists, write the script to .git/hooks/<name> using a write operation, then run chmod +x via bash. | ||
| - If .git/hooks does not exist, add the hook name to skippedHooks. |
There was a problem hiding this comment.
[/codebase-design] The instructions say "write the script to .git/hooks/<name> using a write operation" and "run chmod +x via bash", but these are in-prompt natural-language instructions to the LLM — there are no p.write or p.bash intents to anchor them.
Without those, the agent must hallucinate file I/O rather than using declared prompt intents. This undermines the sample's value as a teaching example for rig's p.* primitives. Consider adding explicit p.write and a p.bash intent in the instructions template.
💡 Example
instructions: p`...
For each hook: ${p.write("${hook.name}", "${hook.script}")} then ${p.bash("chmod +x .git/hooks/${hook.name}")}(Adapt to the actual rig template tag syntax for dynamic values.)
Summary
Added 10 new rig sample files to
skills/rig/samples/.Typecheck failures
No failures — all 10 tasks passed typecheck.
Tasks run