Skip to content

[rig-tasks] Add 10 rig samples — 2026-07-27 - #208

Merged
pelikhan merged 1 commit into
mainfrom
rig-tasks/2026-07-27-e9249e8b2d3e2479
Jul 27, 2026
Merged

[rig-tasks] Add 10 rig samples — 2026-07-27#208
pelikhan merged 1 commit into
mainfrom
rig-tasks/2026-07-27-e9249e8b2d3e2479

Conversation

@github-actions

Copy link
Copy Markdown
Contributor

Summary

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

# File Description Typecheck
1 190-commit-msg-rewriter.md Commit message rewriter — steering+repair addons, s.array(s.object) with s.enum category pass
2 191-env-key-checker.md .env key cross-checker — p.readOptional x2, defineTool regex extraction pass
3 192-json-schema-migration-planner.md JSON schema migration planner — nano diffAnalyzer subagent, p.readInput pass
4 193-dockerfile-security-auditor.md Dockerfile security auditor — defineTool auditPatterns per line, p.readInput pass
5 194-npm-audit-simplifier.md NPM audit simplifier — p.bash npm audit --json, repair() pass
6 195-git-stash-inventory.md Git stash inventory — two p.bash intents, s.enum staleness pass
7 196-http-endpoint-health-checker.md HTTP endpoint health checker — async defineTool with curl, s.array(s.url) input pass
8 197-git-blame-ownership.md Git blame ownership — defineTool parseBlameOutput with regex, steering pass
9 198-ts-generic-type-extractor.md TypeScript generic type extractor — async defineTool, s.record(...) root output pass
10 199-shell-script-validator.md Shell script validator — async defineTool, s.record(s.object(...)) root output pass

Typecheck failures

No failures this run — all 10 samples passed typecheck.

Tasks run

  • (reused) Commit message rewriter using p.bash git log, steering+repair addons
  • (reused) .env file key cross-checker using p.readOptional x2, defineTool
  • (reused) JSON schema migration planner with nano diffAnalyzer subagent
  • (reused) Dockerfile security auditor with defineTool pattern-matching
  • (reused) NPM audit simplifier using p.bash npm audit --json, repair addon
  • (reused) Git stash inventory analyzer using p.bash git stash list/show
  • (new) HTTP endpoint health checker with async defineTool curl, input s.array(s.url), repair
  • (new) Git blame ownership analyzer with defineTool parseBlameOutput regex, steering
  • (new) TypeScript generic type extractor with async defineTool, s.record root output, repair
  • (new) Shell script validator with async defineTool validateScript, steering, s.record root output

Generated by Daily Rig Task Generator · sonnet46 97.4 AIC · ⌖ 11.5 AIC · ⊞ 6.7K ·

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

github-actions Bot commented Jul 27, 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 /grill-with-docs, /codebase-design, and /diagnosing-bugs — requesting changes.

📋 Key Themes & Highlights

Key Themes

  • Numbering collision (blocking): All 10 new samples (190–199) duplicate numbers already used by an existing batch in this repo. Must be renumbered to 200–209 before merging.
  • Input not threaded through (197): gitBlameOwnership declares a filePath input but the p.bash instruction ignores it, always running blame on the entire working tree.
  • Shell injection risk (196): checkEndpoint interpolates a caller-supplied URL directly into the shell string passed to execSync.
  • Stash iteration bug (195): The second p.bash intent has no stash ref, so only stash@{0} is ever inspected regardless of how many stashes exist.
  • Regex gap (198): extractGenerics misses lowercase-starting type params (Array<string>, Promise<void>, etc.).
  • Duplicated schema (192): Outer agent and diffAnalyzer share an identical output schema with no higher-level value added.

Positive Highlights

  • ✅ Great variety of patterns: async defineTool, p.readOptional, p.readInput, p.inputField, s.record root output, steering+repair combos
  • ✅ Defensive bash commands throughout (2>/dev/null fallbacks)
  • ✅ All 10 samples pass typecheck
  • 193-dockerfile-security-auditor is a particularly clean per-line tool pattern

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 52.7 AIC · ⌖ 4.56 AIC · ⊞ 6.3K
Comment /matt to run again

@@ -0,0 +1,21 @@
# 190 - Commit Msg Rewriter

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.

[/grill-with-docs] Numbering collision: sample numbers 190–199 are already taken by an existing batch in this repo (e.g. 190-git-tag-timeline-reporter.md, 191-service-health-probe.md, etc.).

Two samples sharing the same numeric prefix make it impossible to reference samples by ID and can break sample-runner tooling. Renumber this batch to the next free range (200–209) before merging.

const gitBlameOwnership = agent({
model: "small",
input: s.object({ filePath: s.path }),
instructions: p`Run git blame on the file: ${p.bash("git blame --line-porcelain HEAD -- . 2>/dev/null | head -500 || echo ''")}. Use parseBlameOutput on the porcelain output. Compute per-author percentage from line counts. Identify the top author.`,

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 p.bash instruction hardcodes HEAD -- . instead of using the declared filePath input, so the agent always blames the entire working tree rather than the file the caller specified.

The input field declares { filePath: s.path } but the prompt never threads it through. Use p.bash(git blame --line-porcelain HEAD -- ${p.inputField('filePath')}) (or construct the command string with the field reference) so the tool actually targets the requested file.

const start = Date.now();
try {
const code = execSync(
`curl -o /dev/null -s -w '%{http_code}' --max-time 5 "${url}"`,

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.

[/diagnosing-bugs] The URL is interpolated directly into the shell string passed to execSync, which allows shell injection if a caller supplies a URL containing shell metacharacters (e.g. `(example.com/redacted)

💡 Safer approach

Pass the URL via an environment variable so the shell never parses it:

const code = execSync(
  `curl -o /dev/null -s -w '%{http_code}' --max-time 5 "$TARGET_URL"`,
  { encoding: 'utf8', env: { ...process.env, TARGET_URL: url } },
).trim();

Or use spawnSync with an args array to avoid a shell entirely.

// Agent role: inventory all git stashes, listing changed files and classifying staleness.
const gitStashInventory = agent({
model: "small",
instructions: p`List all stashes: ${p.bash("git stash list 2>/dev/null || echo 'no stashes'")}. For each stash ref, show changed files: ${p.bash("git stash show --name-only 2>/dev/null || true")}. Classify staleness: fresh (< 1 week), aging (1–4 weeks), stale (1–3 months), ancient (> 3 months).`,

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 second p.bash call (git stash show --name-only) has no stash ref argument, so it always inspects stash@{0} regardless of how many stashes exist. The agent is given a list of stash refs from the first intent but has no way to expand each one programmatically via a prompt intent.

Consider using a defineTool (e.g. showStash(ref)) that runs git stash show --name-only \<ref\> for each ref returned by the first call, matching the pattern used in sample 197.

async handler({ filePath }) {
const { readFile } = await import("node:fs/promises");
const content = await readFile(filePath, "utf8").catch(() => "");
const matches = content.match(/<[A-Z][A-Za-z]*(?:,\s*[A-Z][A-Za-z]*)*>/g) ?? [];

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 regex /<[A-Z][A-Za-z]*(?:,\s*[A-Z][A-Za-z]*)*>/g only matches generics whose type parameters start with an uppercase letter, so it silently skips common real-world forms like Array<string>, Promise<void>, Map<string, number>, and Record<keyof T, unknown>.

If this is intentional (only user-defined type params), add a comment explaining the design choice. If not, widen to /<[A-Za-z][A-Za-z0-9]*(?:,\s*[A-Za-z][A-Za-z0-9]*)*>/g and acknowledge false-positive risk from HTML-like content.

breakingChange: s.boolean,
})),
agents: { diffAnalyzer },
});

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 outer agent's output schema is an exact copy of the diffAnalyzer subagent's output. If the subagent's output evolves, both schemas need to be updated in sync, which is fragile.

Since the outer agent is essentially a passthrough that delegates to diffAnalyzer, consider having it return a higher-level migrationPlan object (steps, summary, breakingChangeCount) rather than the raw diff array — giving the outer agent distinct value and a single source-of-truth schema.

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