Skip to content

[rig-tasks] Add 10 rig samples — 2026-07-28 - #253

Merged
pelikhan merged 1 commit into
mainfrom
rig-tasks/2026-07-28-e7b3c5acd5d9136a
Jul 28, 2026
Merged

[rig-tasks] Add 10 rig samples — 2026-07-28#253
pelikhan merged 1 commit into
mainfrom
rig-tasks/2026-07-28-e7b3c5acd5d9136a

Conversation

@github-actions

Copy link
Copy Markdown
Contributor

Summary

Added 10 new rig sample files to skills/rig/samples/.

# File Description Typecheck
1 270-dotfile-inventory-mapper.md Dotfile inventory mapper using p.bash + categorizeDotfile tool pass
2 271-regex-pattern-tester.md Regex pattern test runner with input schema and runRegexTest tool pass
3 272-commit-churn-classifier.md Commit churn classifier using p.bash git log + steering addon pass
4 273-npm-package-size-estimator.md NPM package size estimator with classifySize tool pass
5 274-ts-branch-coverage-analyzer.md TypeScript branch coverage analyzer with subagent delegation pass
6 275-env-variable-type-inferrer.md Env variable type inferrer using p.readOptional + inferType tool pass
7 276-git-hook-installer.md Git hook installer with async defineTool + repair addon pass
8 277-ts-type-guard-generator.md TypeScript type guard generator with async extractInterfaces tool pass
9 278-json-fixture-anonymizer.md JSON fixture anonymizer with s.unknown param in defineTool pass
10 279-csv-to-markdown-table.md CSV to Markdown table converter with parseCSVRow tool + repair pass

Typecheck failures

No failures — all 10 tasks passed typecheck.

Tasks run

  • (reused) Dotfile inventory mapper using p.bash find, repair addon, s.record output with dotfiles + categorySummary
  • (reused) Regex pattern test runner with input s.object, nested arrays, allPassed boolean
  • (reused) Commit churn classifier with steering addon, s.record(s.object) root output
  • (reused) NPM package size estimator with p.bash npm pack --dry-run, classifySize tool
  • (reused) TypeScript branch coverage analyzer with subagent + p.readInput
  • (reused) Env variable type inferrer with p.readOptional, regex-based inferType tool
  • (new) Git hook installer with async defineTool, .git/hooks check, repair addon
  • (new) TypeScript type guard generator with async extractInterfaces, p.readInput, p.write
  • (new) JSON fixture anonymizer with s.unknown defineTool parameter, p.readInput + p.write
  • (new) CSV to Markdown table converter with parseCSVRow tool, s.boolean input, repair addon

Generated by Daily Rig Task Generator · sonnet46 104.3 AIC · ⌖ 9.35 AIC · ⊞ 6.7K ·

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@pelikhan
pelikhan marked this pull request as ready for review July 28, 2026 16:14
@pelikhan
pelikhan merged commit 2c52c4f into main Jul 28, 2026
1 check passed
@github-actions

github-actions Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor Author

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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): key in inferType and value in anonymizeValue are declared but never read. This makes the tool contract misleading — callers believe the handler uses those inputs.
  • Correctness gap in CSV parsing (279): parseCSVRow silently corrupts rows containing quoted commas. At minimum, a comment should warn readers.
  • Regex matches commented code (277): extractInterfaces will match interface tokens 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 as p.write/p.bash intents — the sample doesn't demonstrate the primitives it implies.

Positive Highlights

  • ✅ Good variety of addons usage: repair() on output-sensitive agents, steering() on open-ended classification.
  • ✅ Subagent delegation in 274 is cleanly structured with a dedicated branchAnalyzer agent.
  • p.readOptional usage in 275 is a good showcase of the optional-read primitive.
  • ✅ Async defineTool handlers (276, 277) correctly use dynamic import() with node: 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();

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/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 }) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/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_URLurl 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 }) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/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");

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/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.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant