diff --git a/skills/rig/samples.md b/skills/rig/samples.md index 6774e1a..769cafd 100644 --- a/skills/rig/samples.md +++ b/skills/rig/samples.md @@ -2,7 +2,7 @@ Generated by `npm run sample:catalog`; do not edit the inventory by hand. -700 samples: 642 Markdown programs and 58 TypeScript fixtures. +703 samples: 645 Markdown programs and 58 TypeScript fixtures. Every sample has one primary **pattern bucket**, a **topic cluster**, and a normalized task **family**. Buckets come from program syntax, not filenames. A workflow with tools stays in workflows; a coordinator with tools stays in delegation. Markdown and TypeScript versions are kept separately because they exercise different launcher contracts; provider integration fixtures are also intentional. @@ -13,11 +13,11 @@ Legacy filenames are stable identifiers, not an authoritative description of the | Bucket | Samples | Read when | |--------|---------|-----------| | [Schema-first agents](#schemas) | 61 | Typed caller inputs and constrained outputs without workspace intents. | -| [Prompt context and side effects](#context) | 73 | Reading or discovering workspace context and declaring output side effects. | +| [Prompt context and side effects](#context) | 75 | Reading or discovering workspace context and declaring output side effects. | | [Runtime and addons](#runtime) | 43 | Invocation options, engines, timeouts, repair, steering, and addon hooks. | | [Custom tools](#tools) | 423 | Model-callable deterministic operations, parsing, and Node.js APIs. | | [Model-driven delegation](#delegation) | 56 | Named specialists coordinated by a model-driven root agent. | -| [Deterministic workflows](#workflows) | 44 | Explicit sequencing, bounded fan-out, pipelines, budgets, and nested workflows. | +| [Deterministic workflows](#workflows) | 45 | Explicit sequencing, bounded fan-out, pipelines, budgets, and nested workflows. | Use `node scripts/sample-catalog.ts --json` for the complete inventory with role comments, task families, and exercised APIs. For a focused search, append `--family ` or `--bucket `; bucket keys are `schemas`, `context`, `runtime`, `tools`, `delegation`, and `workflows`. @@ -128,6 +128,7 @@ For a focused search, append `--family ` or `--bucket `; bucket keys | config-normalizer | [23-schema-inference.ts](../../src/samples/23-schema-inference.ts) | | dependency-license-audit | [29-bug-report-draft.ts](../../src/samples/29-bug-report-draft.ts) | | dependency-upgrade-plan | [28-license-check.ts](../../src/samples/28-license-check.ts) | +| env-typed-config-provenance | [562-env-typed-config-provenance.md](samples/562-env-typed-config-provenance.md) | | environment-report | [35-call-options.ts](../../src/samples/35-call-options.ts) | | extract-package-scripts | [08-extract-package-scripts.md](samples/08-extract-package-scripts.md), [08-extract-package-scripts.ts](../../src/samples/08-extract-package-scripts.ts) | | monorepo-package-map | [32-command-planner.ts](../../src/samples/32-command-planner.ts) | @@ -162,6 +163,7 @@ For a focused search, append `--family ` or `--bucket `; bucket keys | Family | Samples | |--------|---------| | bash-each | [59-bash-each.ts](../../src/samples/59-bash-each.ts) | +| bashraw-bom-budget | [561-bashraw-bom-budget.md](samples/561-bashraw-bom-budget.md) | | code-owner-suggestion | [46-prompt-intent-inspection.ts](../../src/samples/46-prompt-intent-inspection.ts) | | dep-license-auditor | [154-dep-license-auditor-v2.md](samples/154-dep-license-auditor-v2.md) | | genaiscript-list-files-port | [61-genaiscript-list-files-port.md](samples/61-genaiscript-list-files-port.md) | @@ -648,6 +650,7 @@ For a focused search, append `--family ` or `--bucket `; bucket keys | git-reflog-classifier | [469-git-reflog-classifier.md](samples/469-git-reflog-classifier.md) | | parallel-branch-analysis | [414-parallel-branch-analysis.md](samples/414-parallel-branch-analysis.md) | | parallel-branch-analysis-workflow | [360-parallel-branch-analysis-workflow.md](samples/360-parallel-branch-analysis-workflow.md), [412-parallel-branch-analysis-workflow.md](samples/412-parallel-branch-analysis-workflow.md) | +| parallel-branch-timeout-holes | [563-parallel-branch-timeout-holes.md](samples/563-parallel-branch-timeout-holes.md) | | parallel-git-stats-workflow | [430-parallel-git-stats-workflow.md](samples/430-parallel-git-stats-workflow.md) | | sequential-commit-classifier-workflow | [380-sequential-commit-classifier-workflow.md](samples/380-sequential-commit-classifier-workflow.md), [436-sequential-commit-pipeline.md](samples/436-sequential-commit-pipeline.md) | diff --git a/skills/rig/samples/561-bashraw-bom-budget.md b/skills/rig/samples/561-bashraw-bom-budget.md new file mode 100644 index 0000000..73ab23b --- /dev/null +++ b/skills/rig/samples/561-bashraw-bom-budget.md @@ -0,0 +1,27 @@ +# 561 - Bashraw Bom Budget + +```rig +import { agent, p, s } from "rig"; + +// Agent role: audit a synthetic nested bill of materials against per-assembly cost budgets. +const bomBudgetAuditor = agent({ + model: "small", + maxTurns: 3, + instructions: p`Synthetic BOM lines are id|part|qty|unit_cost|budget. Ids use dotted nesting such as ASM-1.2.3. The awk step uses a regex with literal backslashes to keep only valid ids and total cost per top-level assembly: +${p.bashRaw`printf 'ASM-1|frame|2|10.00|100\nASM-1.1|bolt|40|0.25|100\nASM-1.2.1|gear|3|22.50|100\nASM-2|panel|4|8.00|60\nASM-2.1|clip|20|1.10|60\nbad id|junk|1|1|1\nASM-3|motor|1|45.00|50\nASM-3.1.2|wire|9|0.80|50\n' | awk -F'|' '$1 ~ /^[A-Z]+\\-[0-9]+(\\.[0-9]+)*$/ { split($1, a, "."); t[a[1]] += $3 * $4; b[a[1]] = $5; l[a[1]] = l[a[1]] " " $1 } END { for (k in t) printf "%s total=%.2f budget=%s lines:%s\n", k, t[k], b[k], l[k] }' | sort`} +Return one entry per top-level assembly. Set overBudget true when total exceeds budget, and list its line ids as nested components.`, + output: s.object({ + assemblies: s.array(s.object({ + assembly: s.nonEmptyString, + total: s.number, + budget: s.number, + overBudget: s.boolean, + components: s.array(s.object({ id: s.nonEmptyString, depth: s.int })), + })), + overBudgetCount: s.int, + summary: s.string, + }), +}); + +export default bomBudgetAuditor; +``` diff --git a/skills/rig/samples/562-env-typed-config-provenance.md b/skills/rig/samples/562-env-typed-config-provenance.md new file mode 100644 index 0000000..255cdf1 --- /dev/null +++ b/skills/rig/samples/562-env-typed-config-provenance.md @@ -0,0 +1,37 @@ +# 562 - Env Typed Config Provenance + +```rig +import { agent, p, s } from "rig"; + +// Agent role: resolve typed ecology survey config from env vars, reporting default provenance and converting units to metric. +const ecologyConfig = agent({ + model: "small", + maxTurns: 4, + instructions: p`Resolve the survey configuration for a synthetic ecology field study from environment variables. An empty value means the variable is unset, so use the default and mark its source as "default"; a non-empty value is used verbatim with source "env". + +SITE_ID (default "wetland-north-07"): ${p.env("SURVEY_SITE_ID", "")} +HABITAT (default "wetland"; allowed: wetland, forest, grassland, tundra): ${p.env("SURVEY_HABITAT", "")} +TRANSECT_LENGTH (default "330 ft"; value then unit): ${p.env("SURVEY_TRANSECT_LENGTH", "")} +WATER_TEMP (default "68 F"; value then unit): ${p.env("SURVEY_WATER_TEMP", "")} +PLOT_AREA (default "2.5 acre"; value then unit): ${p.env("SURVEY_PLOT_AREA", "")} + +Synthetic nested catalog of unit conversions: length (ft->m x0.3048, mi->m x1609.344), temperature (F->C (F-32)/1.8, K->C K-273.15), area (acre->ha x0.404686, ft2->m2 x0.092903). Convert each measurement to metric (m, C, ha), rounding to 2 decimals, and report the original value text, the converted number, the metric unit, and the source for every field. Set defaultedCount to the number of fields whose source is "default".`, + output: s.object({ + siteId: s.object({ value: s.nonEmptyString, source: s.enum("env", "default") }), + habitat: s.object({ + value: s.enum("wetland", "forest", "grassland", "tundra"), + source: s.enum("env", "default"), + }), + measurements: s.array(s.object({ + name: s.enum("transectLength", "waterTemp", "plotArea"), + original: s.nonEmptyString, + metricValue: s.number, + metricUnit: s.enum("m", "C", "ha"), + source: s.enum("env", "default"), + })), + defaultedCount: s.int, + }), +}); + +export default ecologyConfig; +``` diff --git a/skills/rig/samples/563-parallel-branch-timeout-holes.md b/skills/rig/samples/563-parallel-branch-timeout-holes.md new file mode 100644 index 0000000..98307b3 --- /dev/null +++ b/skills/rig/samples/563-parallel-branch-timeout-holes.md @@ -0,0 +1,54 @@ +# 563 - Parallel Branch Timeout Holes + +```rig +import { p, s, workflow } from "rig"; + +const reading = s.object({ + meterId: s.string, + source: s.string, + kwh: s.number, + conflictNote: s.string, +}); + +// Workflow role: reconcile energy meter readings from conflicting nested catalogs in parallel, each branch with its own timeout, and report null holes. +const energyMeterReconciler = workflow({ + meta: { + name: "parallel-branch-timeout-holes", + description: "Per-branch timeouts inside parallel() leave null holes for slow energy-usage sources", + phases: ["Read", "Report"], + }, + body: async ({ call, parallel, phase }) => { + phase("Read"); + const sources = [ + { name: "utility-billing", catalog: "catalog/billing/north: meter M-17 = 412 kWh, meter M-18 = 380 kWh", timeout: 20_000 }, + { name: "smart-meter-feed", catalog: "catalog/iot/hub-2: meter M-17 = 398 kWh, meter M-18 = 391 kWh", timeout: 20_000 }, + { name: "manual-survey", catalog: "catalog/field/legacy: meter M-17 = 450 kWh, meter M-18 missing (very long handwritten ledger)", timeout: 1_500 }, + ]; + const results = await parallel( + sources.map((src) => () => + call.json( + p`Source ${src.name} (nested catalog entry): ${src.catalog}. Extract the reading for meter M-17 and note in conflictNote how it may conflict with other sources such as utility-billing (412) or smart-meter-feed (398).`, + reading, + { label: src.name, timeout: src.timeout }, + ), + ), + ); + phase("Report"); + const present = results.flatMap((r, i) => (r ? [{ ...r, branch: sources[i]!.name }] : [])); + const holes = results.flatMap((r, i) => (r === null ? [sources[i]!.name] : [])); + return call.json( + p`Reconcile energy usage for meter M-17 from these readings: ${JSON.stringify(present)}. Branches that timed out or failed (null holes): ${JSON.stringify(holes)}. Pick a reconciled kWh, explain the conflict, and list the missing sources.`, + s.object({ + meterId: s.string, + reconciledKwh: s.number, + conflictExplanation: s.string, + missingSources: s.array(s.string), + holeCount: s.int, + }), + { label: "reconcile" }, + ); + }, +}); + +export default energyMeterReconciler; +```