-
Notifications
You must be signed in to change notification settings - Fork 0
[rig-tasks] Add 10 rig samples — 2026-07-25 #111
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 |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| # 78 - Build Log Analyzer | ||
|
|
||
| ```rig | ||
| import { agent, p, s } from "rig"; | ||
| import { repair } from "rig/addons"; | ||
|
|
||
| // Agent role: run the build and analyze the output for errors, warnings, and success status. | ||
| const buildLogAnalyzer = agent({ | ||
| model: "small", | ||
| instructions: p`Run the build command and analyze its output: ${p.bash("npm run build 2>&1 || true")}. Extract all errors and warnings with their severity and file location if available. Determine whether the build succeeded overall.`, | ||
| output: s.object({ | ||
| errors: s.array(s.object({ | ||
| message: s.string, | ||
| file: s.optional(s.string), | ||
| severity: s.enum("error", "warning", "info"), | ||
| })), | ||
| buildSucceeded: s.boolean, | ||
| summary: s.string, | ||
| }), | ||
| maxTurns: 5, | ||
| addons: repair(), | ||
| }); | ||
|
|
||
| export default buildLogAnalyzer; | ||
| ``` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| # 79 - Ts Type Alias Mapper | ||
|
|
||
| ```rig | ||
| import { agent, p, s, defineTool } from "rig"; | ||
|
|
||
| const categorizeAlias = defineTool("categorizeAlias", { | ||
| description: "Categorize a TypeScript type alias definition by its kind using regex", | ||
| parameters: s.object({ definition: s.string }), | ||
| handler({ definition }) { | ||
| const trimmed = definition.trim(); | ||
| if (/=\s*\w+\s*\|/.test(trimmed)) return { kind: "union" }; | ||
| if (/=\s*\w+\s*&/.test(trimmed)) return { kind: "intersection" }; | ||
| if (/=\s*\{[^}]*\[[^\]]+\]/.test(trimmed)) return { kind: "mapped" }; | ||
| if (/=\s*(string|number|boolean|null|undefined|never|any|unknown)\s*$/.test(trimmed)) return { kind: "primitive" }; | ||
| return { kind: "other" }; | ||
| }, | ||
| }); | ||
|
|
||
| // Agent role: scan TypeScript files for type alias declarations and categorize each one. | ||
| const tsTypeAliasMapper = agent({ | ||
| model: "small", | ||
| instructions: p`Find all TypeScript files: ${p.bash("find . -name '*.ts' -not -path '*/node_modules/*' -not -path '*/.git/*'")} and scan their contents: ${p.bash("grep -rn 'type [A-Z]' --include='*.ts' --exclude-dir=node_modules --exclude-dir=.git . 2>/dev/null || true")}. Use the categorizeAlias tool to classify each type alias. For each alias, also record whether it is exported (starts with 'export type').`, | ||
| output: s.record(s.object({ | ||
| kind: s.enum("primitive", "union", "intersection", "mapped", "other"), | ||
| exported: s.boolean, | ||
| })), | ||
| tools: [categorizeAlias], | ||
| }); | ||
|
|
||
| export default tsTypeAliasMapper; | ||
| ``` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| # 80 - Git Contributor Mapper | ||
|
|
||
| ```rig | ||
| import { agent, p, s } from "rig"; | ||
|
|
||
| // Agent role: map git contributors to their commit counts, primary work areas, and role classification. | ||
| const gitContributorMapper = agent({ | ||
| model: "small", | ||
| instructions: p`Analyze git contributors using: ${p.bash("git shortlog -sn --no-merges")} and ${p.bash("git log --no-merges --name-only --pretty=format:'%an' | head -500")}. For each contributor, count their commits, identify which directories they primarily touch, and classify their role as core (many commits across many files), peripheral (few commits or limited scope), or single-file.`, | ||
| output: s.record(s.object({ | ||
| commitCount: s.number, | ||
| primaryAreas: s.array(s.string), | ||
| role: s.enum("core", "peripheral", "single-file"), | ||
| })), | ||
| }); | ||
|
|
||
| export default gitContributorMapper; | ||
| ``` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| # 81 - Markdown Doc Summarizer | ||
|
|
||
| ```rig | ||
| import { agent, p, s } from "rig"; | ||
|
|
||
| // Agent role: summarize each top-level section of the README, then compile into a full report. | ||
| const sectionSummarizer = agent({ | ||
| name: "sectionSummarizer", | ||
| model: "nano", | ||
| instructions: p`Summarize the section of documentation provided in the input.`, | ||
| input: s.object({ heading: s.string, content: s.string }), | ||
| output: s.object({ heading: s.string, summary: s.string }), | ||
| }); | ||
|
|
||
| // Agent role: read the project README, delegate per-section summarization, and write the final report. | ||
| const markdownDocSummarizer = agent({ | ||
| model: "small", | ||
| instructions: p`Read the README: ${p.readOptional("README.md", "No README found.")}. Identify each top-level heading (##) and its content. Delegate summarization of each section to the sectionSummarizer agent. Compile all summaries into a report and write it to summaries/README-summary.md via ${p.writeOutput("reportPath", "summaries/README-summary.md")}.`, | ||
| output: s.object({ | ||
| sections: s.array(s.object({ heading: s.string, summary: s.string })), | ||
| reportPath: s.string, | ||
| }), | ||
| agents: { sectionSummarizer }, | ||
| }); | ||
|
|
||
| export default markdownDocSummarizer; | ||
| ``` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| # 82 - Workspace Config Drift | ||
|
|
||
| ```rig | ||
| import { agent, p, s, defineTool } from "rig"; | ||
| import { repair } from "rig/addons"; | ||
|
|
||
| const parseJson = defineTool("parseJson", { | ||
| description: "Parse a JSON string and return it, or report a parse error", | ||
| parameters: s.object({ content: s.string, filename: s.string }), | ||
| handler({ content, filename }) { | ||
| try { | ||
| const parsed = JSON.parse(content); | ||
| return { ok: true, parsed }; | ||
| } catch (e) { | ||
| return { ok: false, error: String(e), filename }; | ||
| } | ||
| }, | ||
| }); | ||
|
|
||
| // Agent role: detect drift in workspace config files by reading them and comparing against known defaults. | ||
| const workspaceConfigDrift = agent({ | ||
| model: "small", | ||
| instructions: p`Read project config files: ${p.readOptional("tsconfig.json", "{}")} (tsconfig.json), ${p.readOptional(".eslintrc.json", "{}")} (.eslintrc.json), ${p.readOptional(".prettierrc", "{}")} (.prettierrc). Use the parseJson tool to parse each file. For each config, identify fields that deviate from sensible defaults and report them as drifted. Assign status ok if no drift, warning for minor issues, error for significant mismatches.`, | ||
| output: s.record(s.object({ | ||
| driftedFields: s.array(s.string), | ||
| status: s.enum("ok", "warning", "error"), | ||
| })), | ||
| tools: [parseJson], | ||
| maxTurns: 4, | ||
| addons: repair(), | ||
| }); | ||
|
|
||
| export default workspaceConfigDrift; | ||
| ``` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| # 83 - Commit Format Suggester | ||
|
|
||
| ```rig | ||
| import { agent, p, s } from "rig"; | ||
| import { repair, steering } from "rig/addons"; | ||
|
|
||
| // Agent role: review recent git commits and suggest conventional-format rewrites for each one. | ||
| const commitFormatSuggester = agent({ | ||
| model: "small", | ||
| instructions: p`Review recent git commits: ${p.bash("git log --oneline -20 --no-merges")}. For each commit, check whether its message follows conventional commit format (type: description). Suggest a rewritten message in conventional format. Classify each commit as one of: feat, fix, chore, docs, test, refactor, style. Write the full report to commit-report.md via ${p.writeOutput("reportWritten", "commit-report.md")}.`, | ||
| output: s.array(s.object({ | ||
| hash: s.string, | ||
| original: s.string, | ||
| suggested: s.string, | ||
| category: s.enum("feat", "fix", "chore", "docs", "test", "refactor", "style"), | ||
| })), | ||
| maxTurns: 5, | ||
| addons: [steering(), repair()], | ||
|
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] 💡 SuggestionAdd a targeted steering message, as in sample 76: addons: [steering({ message: "Follow conventional commit format strictly: type(scope): imperative description." }), repair()], |
||
| }); | ||
|
|
||
| export default commitFormatSuggester; | ||
| ``` | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| # 84 - Json Schema Migration | ||
|
|
||
| ```rig | ||
| import { agent, p, s } from "rig"; | ||
|
|
||
| // Agent role: analyze two JSON schema files to identify structural changes and produce a migration plan. | ||
| const diffAnalyzer = agent({ | ||
| name: "diffAnalyzer", | ||
| model: "nano", | ||
| instructions: p`Analyze the structural differences between the two JSON schemas provided in the input and list each change type (add, remove, modify, rename) with the JSON path and whether it is a breaking change.`, | ||
| input: s.object({ oldSchema: s.string, newSchema: s.string }), | ||
| output: s.array(s.object({ | ||
| changeType: s.enum("add", "remove", "modify", "rename"), | ||
| path: s.string, | ||
| description: s.string, | ||
| breakingChange: s.boolean, | ||
| })), | ||
| }); | ||
|
|
||
| // Agent role: read two JSON schema files and coordinate a migration plan using the diffAnalyzer subagent. | ||
| const jsonSchemaMigration = agent({ | ||
| model: "small", | ||
| input: s.object({ oldSchemaPath: s.path, newSchemaPath: s.path }), | ||
| instructions: p`Read the old schema at ${p.readInput("oldSchemaPath")} and new schema at ${p.readInput("newSchemaPath")}. Pass both to the diffAnalyzer subagent to identify all changes and whether each is a breaking change.`, | ||
| output: s.array(s.object({ | ||
| changeType: s.enum("add", "remove", "modify", "rename"), | ||
| path: s.string, | ||
| description: s.string, | ||
| breakingChange: s.boolean, | ||
| })), | ||
| agents: { diffAnalyzer }, | ||
| }); | ||
|
|
||
| export default jsonSchemaMigration; | ||
| ``` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| # 85 - Dockerfile Security Audit | ||
|
|
||
| ```rig | ||
| import { agent, p, s, defineTool } from "rig"; | ||
|
|
||
| const checkSecurityPattern = defineTool("checkSecurityPattern", { | ||
| description: "Check a Dockerfile line for known security anti-patterns", | ||
| parameters: s.object({ line: s.string, lineNumber: s.number }), | ||
|
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 💡 FixSplit into separate findings: if (/^USER\s+root\s*$/i.test(line.trim())) {
findings.push({ severity: "critical", message: "Running as root user", rule: "no-root-user" });
}
if (/^RUN.*--no-check/.test(line)) {
findings.push({ severity: "high", message: "Package install skips integrity check", rule: "no-skip-check" });
} |
||
| handler({ line, lineNumber }) { | ||
| const findings: Array<{ severity: string; message: string; rule: string }> = []; | ||
| if (/^USER\s+root\s*$/i.test(line.trim()) || /^RUN.*&&.*&&.*--no-check/.test(line)) { | ||
| findings.push({ severity: "critical", message: "Running as root user", rule: "no-root-user" }); | ||
| } | ||
| if (/ADD\s+/.test(line) && !/ADD\s+https?:\/\//.test(line)) { | ||
| findings.push({ severity: "medium", message: "Prefer COPY over ADD for local files", rule: "prefer-copy" }); | ||
| } | ||
| if (/FROM\s+\S+:latest/.test(line)) { | ||
| findings.push({ severity: "high", message: "Avoid :latest tag for reproducibility", rule: "no-latest-tag" }); | ||
| } | ||
| if (/ENV\s+\w*(KEY|SECRET|PASSWORD|TOKEN)\w*\s*=/.test(line)) { | ||
| findings.push({ severity: "critical", message: "Secret embedded in ENV instruction", rule: "no-secrets-in-env" }); | ||
| } | ||
| return { lineNumber, findings }; | ||
| }, | ||
| }); | ||
|
|
||
| // Agent role: audit a Dockerfile for security issues by scanning each instruction for known anti-patterns. | ||
| const dockerfileSecurityAudit = agent({ | ||
| model: "small", | ||
| input: s.object({ dockerfilePath: s.path }), | ||
| instructions: p`Read the Dockerfile at ${p.readInput("dockerfilePath")}. Use the checkSecurityPattern tool on each instruction line to detect security issues. Compile all findings with their severity, line number, rule, and message.`, | ||
| output: s.object({ | ||
| findings: s.array(s.object({ | ||
| severity: s.enum("critical", "high", "medium", "low"), | ||
| lineNumber: s.number, | ||
| message: s.string, | ||
| rule: s.string, | ||
| })), | ||
| passes: s.boolean, | ||
| }), | ||
| tools: [checkSecurityPattern], | ||
| }); | ||
|
|
||
| export default dockerfileSecurityAudit; | ||
| ``` | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| # 86 - Npm Audit Simplifier | ||
|
|
||
| ```rig | ||
| import { agent, p, s } from "rig"; | ||
| import { repair } from "rig/addons"; | ||
|
|
||
| // Agent role: run npm audit, parse the JSON output, and produce a simplified vulnerability report. | ||
| const npmAuditSimplifier = agent({ | ||
| model: "small", | ||
| instructions: p`Run ${p.bash("npm audit --json 2>/dev/null || echo '{}'")} to get the vulnerability report. Parse the JSON and group vulnerabilities by severity level (critical, high, moderate, low, info). Count the total number of vulnerabilities. Provide a one-sentence recommendation for remediation.`, | ||
| output: s.object({ | ||
| vulnerabilitiesByLevel: s.record(s.array(s.string)), | ||
| totalCount: s.number, | ||
| recommendation: s.string, | ||
| }), | ||
| maxTurns: 5, | ||
| addons: repair(), | ||
| }); | ||
|
|
||
| export default npmAuditSimplifier; | ||
| ``` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| # 87 - Git Stash Inventory | ||
|
|
||
| ```rig | ||
| import { agent, p, s } from "rig"; | ||
|
|
||
| // Agent role: inventory all git stashes with their descriptions, changed files, and staleness classification. | ||
| const gitStashInventory = agent({ | ||
| model: "small", | ||
| instructions: p`List all git stashes: ${p.bash("git stash list 2>/dev/null || echo 'No stashes found'")}. For each stash entry shown, show its changed files: ${p.bash("git stash show --name-only 2>/dev/null || true")}. For each stash, classify its staleness as: fresh (< 1 week), aging (1-4 weeks), stale (1-3 months), ancient (> 3 months) based on the date shown in the stash list.`, | ||
|
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] 💡 FixThe agent needs to iterate over stash refs. Use a command that iterates, or note in the instructions that the agent should call git stash list --format='%gd' | xargs -I{} sh -c 'echo "---{}"; git stash show --name-only {} 2>/dev/null'Or simplify to a single p.bash that already includes the stash ref loop. |
||
| output: s.array(s.object({ | ||
| stashRef: s.string, | ||
| description: s.string, | ||
| changedFiles: s.array(s.string), | ||
| staleness: s.enum("fresh", "aging", "stale", "ancient"), | ||
| })), | ||
| }); | ||
|
|
||
| export default gitStashInventory; | ||
| ``` | ||
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]
p.writeOutput("reportWritten", ...)declares a write intent but the output schema iss.array(s.object(...))— there is noreportWrittenfield in the schema to capture the written path. The harness needs a corresponding string field in the output schema.💡 Fix
Wrap in
s.objectand add thereportWrittenfield, matching the pattern from samples 76 and 81: