script-builder
Generate durable, re-runnable validation scripts from testing intent. Supports TypeScript, Python, Bash with auto-detection, enforces context-optimal PASS/FAIL + /tmp log output, and auto-documents scripts in CLAUDE.md. Triggers on phrases like "turn this into a script", "I want to test/validate X end-to-end", "wrap this in a re-runnable script", or whenever an agent needs durable validation instead of throwaway commands.
How do I install this agent skill?
npx skills add https://github.com/desplega-ai/ai-toolbox --skill script-builderIs this agent skill safe to install?
- Gen Agent Trust Hubwarn
This skill generates and executes custom validation scripts based on user intent and session history. While it provides structured templates and user confirmation steps, the automated generation and execution of code—combined with the ability to persistently modify project-wide agent instructions (CLAUDE.md)—creates a surface for command execution and indirect prompt injection.
- Socketpass
No alerts
- Snykpass
Risk: LOW · No issues
What does this agent skill do?
script-builder
You are converting testing/validation intent into a durable, re-runnable script committed to the target project's scripts/ directory. The output is context-optimal: a single PASS/FAIL line + /tmp log path on success, full verbose output redirected to a timestamped log file, and an <important if> block in CLAUDE.md/AGENTS.md so future agents discover the script when the relevant testing intent recurs.
Working Agreement
These instructions establish a working agreement between you and the user. The key principles are:
-
AskUserQuestion is your primary communication tool - Whenever you need to ask the user anything (clarifications, preferences, decisions, confirmations), use the AskUserQuestion tool. Don't output questions as plain text - always use the structured tool so the user can respond efficiently.
-
Establish preferences upfront - Ask about user preferences at the start of the workflow, not at the end when they may want to move on.
-
Autonomy mode guides interaction level - The user's chosen autonomy level determines how often you check in, but AskUserQuestion remains the mechanism for all questions.
When to Use
This skill activates when:
- User invokes
/script-buildercommand - Another skill references
**OPTIONAL SUB-SKILL:** desplega:script-builder - A
planning,qa, orverifyingflow needs a re-runnable validation script that doesn't yet exist - The user expresses intent to "turn X into a script", "wrap this validation into something reusable", or "I want to test X end-to-end" with no existing script
Autonomy Mode
Adapt your behavior based on the autonomy mode:
| Mode | Behavior |
|---|---|
| Autopilot | Detect mode, draft, syntax-check, document, and (if escalation tier) run + iterate without intermediate confirmations. Pause only at hard blockers or destructive side-effects. |
| Critical (Default) | Confirm at each tier boundary (after draft, before doc edit, before run). Use AskUserQuestion for fix application during iterate loop. |
| Verbose | Confirm before each step. Show every diff. Walk through detection reasoning out loud. |
The autonomy mode is passed by the invoking command. If not specified, default to Critical.
Process Steps
Step 1: Detect Mode (Retrospective vs Forward-Declared)
Decide silently — do not ask the user "which mode?". Use the following heuristics:
- Scan recent session tool-use history (the last ~20 tool calls in the current conversation) for test/validation-shaped activity:
curl/fetchcalls,bun run/python/pytest, database queries,qa-usebrowser actions, repeatedgrep/log inspection of a single endpoint or table. If ≥2 such actions targeting the same area exist → retrospective mode. - Parse the user's invocation message for cues:
- Narrative cues → retrospective: "we just figured out", "turn this into a script", "wrap that in", "that thing we just did".
- Intent cues → forward-declared: "I want to test", "validate that", "smoke check", "check before deploy".
- Fallback: when ambiguous, default to forward-declared.
Retrospective first action: summarize the observed activity back to the user as plain text (≤6 lines: what was probed, against what, with what success signal), then go to Step 3 with a confirmation prompt instead of Q&A.
Forward first action: skip directly to Step 3's Q&A.
Step 2: Scan Existing Scripts for Overlap
Resolve the scripts directory in this order:
- Check
CLAUDE.mdfor a<!-- script-builder:dir=<path> -->marker. If present, use that path. - If
scripts/exists at the repo root, use it. - Use AskUserQuestion with options:
scripts/ (Recommended) | custom path | skip dir persistence for this run.
Edge case — directory absent: if the resolved path doesn't exist, skip the dedup scan, print a one-line note (No existing scripts directory at <path> — proceeding to intent gathering), and remember to optionally offer to create the directory before Step 5.
When the directory exists:
- List files in the scripts directory (top-level only for v1).
- For each file, read the top of the file (header comment) and capture the file-name tokens.
- Read
CLAUDE.md/AGENTS.mdfor<important if="...">blocks that point at scripts in this directory and capture the trigger phrases. - Fuzzy-match the current intent string against (file-name tokens ∪ header keywords ∪ trigger phrases). A "plausible match" is shared keyword + same area noun (e.g.,
auth,health,webhook). - If ≥1 plausible match → use AskUserQuestion with options:
Reuse <name> as-is | Extend <name> | Generate new anyway.
Never silently skip dedup on borderline matches — surface and let the user decide. The Extend branch appends a sub-command/flag to the existing script (do not create a new file); document the new flag in the script's header comment and the existing <important if> block.
Step 3: Gather Intent
Both modes converge on the same internal intent structure: { what, success_signal, failure_signal, inputs, env, side_effects }.
Forward mode — use AskUserQuestion (one or two questions, not five):
| Question | Options |
|---|---|
| "What are we validating, and what's the success signal?" | [Free text — collect what + success signal in one answer] |
| "Any required env vars, inputs, or side-effects to flag (e.g., writes to prod, costs money)?" | [Free text — optional; skip if forward intent already specified them] |
Retrospective mode — present the summary from Step 1 and use AskUserQuestion with: That's the flow | Close but fix X | Start over. On Close but fix X, ask for the correction inline; on Start over, fall through to forward-mode Q&A.
Persist the resolved intent in working memory (do not write to disk yet).
Step 4: Detect Language
Priority order — first match wins, with override paths:
- TypeScript —
package.json+tsconfig.jsonexist.- Bun if
bun.lockorbunfig.tomlis present. - else tsx if
tsxappears inpackage.jsondevDependencies. - else compiled Node (note in script header: requires
tscbuild).
- Bun if
- Python —
pyproject.tomloruv.lockorrequirements.txtexists.- uv if
uv.lockexists orpyproject.tomlhas[tool.uv]configured (sets{{UV_METADATA}}). - else vanilla python3 (
{{UV_METADATA}}substituted with empty string).
- uv if
- Both TS and Python detected — count source files in
src//top-level and ask AskUserQuestion tiebreaker with the dominant one Recommended. Cargo.toml/go.modonly → fall back to bash (note: TS/Python/Bash only in v1).- Nothing matched → bash.
Task-driven override: if the gathered intent is clearly shell-y ("verify three docker containers respond", "tail this log file for an error"), propose bash even in a TS/Python project.
Confirm via AskUserQuestion with the detected language as the first option (Recommended). Skip in Autopilot.
Step 5: Draft the Script
- Pick the template:
cc-plugin/base/skills/script-builder/templates/{typescript.ts.tmpl|python.py.tmpl|bash.sh.tmpl}. - Resolve substitution markers from gathered intent:
{{SCRIPT_NAME}}← proposed file-name stem (see naming table).{{WHAT}}/{{WHEN}}/{{ENV}}/{{EXAMPLE}}← intent fields.{{UV_METADATA}}← per Step 4.
- Generate
{{TEST_BODY}}from the intent. Keep it minimal: a single concrete probe + assertion, not a battery. Re-read the templates' README (templates/README.md) for the contract — the body must respect the PASS/FAIL surface. Throw/raise/exit 1on failure; let the template's outer try/trap convert it into the FAIL line. - Propose a file name matching the intent shape — see the prefix table below. Use AskUserQuestion with the proposed name first (Recommended) and
custom nameas the alternative.
Naming conventions (advisory — skill proposes, user overrides):
| Prefix | When | Example |
|---|---|---|
e2e-* | End-to-end flows across multiple components | e2e-auth-flow.ts |
check-* | Idempotent single-probe verifications | check-db-boundary.sh |
smoke-* | Minimal-viability post-deploy checks | smoke-prod-api.ts |
measure-* | Performance / size / token measurements | measure-tool-tokens.ts |
seed-* / generate-* | Data seeding or artifact generation (rare for validation) | seed-api-keys.sh |
If the intent doesn't match any prefix cleanly, propose a free-form name like validate-<area>.<ext>.
- Write the file to the resolved scripts directory. Make it executable (
chmod +x).
Step 6: Syntax/Type-Check
Run the appropriate checker:
| Language | Checker (in priority order) |
|---|---|
| TypeScript | bunx tsc --noEmit <file> if Bun present, else npx tsc --noEmit <file> |
| Python | python3 -m py_compile <file> (always) + ruff check <file> if ruff is on PATH |
| Bash | shellcheck <file> if available, else bash -n <file> |
On success: log a single line (syntax check OK) and proceed to Step 7.
On failure:
- Print the error (≤10 lines, not the full output).
- Propose a concrete one-edit fix (the exact
Edityou'd apply). - Use AskUserQuestion with
Apply fix | Investigate | Stop.- Apply fix → edit the script and re-run the checker (loop, no hardcoded cap).
- Investigate → drop into discussion with the user; do not auto-apply anything.
- Stop → leave script in place at its path; print the path; do not delete.
Step 7: Document the Script
Auto-edit the target project's CLAUDE.md and/or AGENTS.md so future agents discover this script when the matching intent recurs.
Block template (the literal markdown the skill emits):
<important if="[TRIGGER: e.g., you are testing the auth flow]">
## [Area] validation
Run `scripts/<name>` to [one-liner]. Requires [env/deps]. Example: `<cmd>`. Full log at `/tmp/<name>-*.log`.
Generated/maintained via `/script-builder`.
</important>
Behavior:
- Target file selection: edit
CLAUDE.mdandAGENTS.mdif both exist; edit only what exists. Never create either file from scratch — if neither exists, print a one-line note (No CLAUDE.md or AGENTS.md found — script generated but not documented) and skip this step. - Placement heuristic: search the file for the first heading matching
Test|Testing|Validation|Scripts(case-insensitive). If found, append the new block within/after that section. Otherwise, append a new## Scripts for testing & validationsection near the end of the file but before any heading matchingLicense|Acknowledg|Maintain|Contributors. - Idempotency: if a block referencing
scripts/<name>already exists (i.e., a prior/script-builderrun for the same script name), update it in place — replace the entire<important if=...>...</important>block, do not append a duplicate. - Scripts-dir marker: if Step 2 resolved the scripts directory by user choice (not from an existing marker), insert
<!-- script-builder:dir=<path> -->near the top ofCLAUDE.md(after the title) so subsequent runs are silent. Skip if the marker already exists. - Show the diff: run the equivalent of
git diff CLAUDE.md AGENTS.mdand print a 5-line summary of what changed. Never auto-stage — the user commits.
Step 8: Offer Escalation
After the doc edit, decide whether to proceed to the run-and-iterate tier.
| Autonomy | Behavior |
|---|---|
| Autopilot | Auto-escalate to Step 9 unless the intent flagged side-effects (writes to prod, sends real money, mutates a shared resource). On flagged side-effects, fall through to Critical behavior. |
| Critical (Default) | Use AskUserQuestion: `Run it now to confirm it works |
| Verbose | Same as Critical, plus offer the proposed run command for review before executing. |
If the user picks "I'll run it myself later" or "Just generate, don't run" → skip directly to Step 10.
Step 9: Iterate on Failures (Escalated Tier Only)
A bounded-by-the-human loop. Never auto-apply a fix outside Autopilot.
- Run the script with the proposed example invocation (no
--verbose, no--json). Capture exit code andtail -n 40of the/tmplog. - If exit code 0 → report PASS (echo the script's PASS line) and proceed to Step 10.
- If exit code non-zero:
- Summarize the failure in 1–3 lines: error class (timeout / 4xx / 5xx / assertion / dependency-missing / etc.) + likely cause (grep the log for known signatures:
ECONNREFUSED,Traceback,non-zero exit,command not found, etc.). - Propose a concrete diff — the exact
Edityou would apply to the script. Show old → new. - Use AskUserQuestion:
Apply fix | Investigate differently | Stop.- Apply fix → edit the script, log the change, loop back to (1).
- Investigate differently → drop into discussion; do not auto-apply.
- Stop → leave the script in place, print its path; do not revert.
- Summarize the failure in 1–3 lines: error class (timeout / 4xx / 5xx / assertion / dependency-missing / etc.) + likely cause (grep the log for known signatures:
No hardcoded retry cap — the human is the implicit bound.
Side-effect flag: if the intent declared side-effects (Step 3) and Autopilot is active, surface a one-line WARNING: this script <does X> against <target> before the first run and require explicit confirmation via AskUserQuestion even in Autopilot mode.
Step 10: Handoff
How the skill exits depends on how it was invoked:
Invoked as a sub-skill (from planning, qa, verifying):
Return control to the parent skill with a structured summary: { script_path, status: "pass"|"fail"|"unrun", log_path?, doc_files_edited: [...] }.
Invoked directly (/script-builder):
Use AskUserQuestion: Run it with /qa | Run /verify-plan | Commit the script and doc changes | Done.
- Run with /qa → invoke
desplega:qawith the script path as the source. - Run /verify-plan → invoke
desplega:verifyingif a plan path is in current context. - Commit → propose a commit message (
feat(scripts): add scripts/<name> for <area> validation) and stage only the generated script + the CLAUDE.md/AGENTS.md edits. Do not auto-commit; show the proposedgit addandgit commitcommands and require user confirmation. - Done → print the script path + log path (if escalation ran) and exit.
Abort path (Stop selected at any earlier gate): leave the generated script in place, leave any CLAUDE.md/AGENTS.md edit in place if Step 7 ran, and print a one-liner: Aborted. Script: <path>. Doc edits: <files or "none">. Re-run /script-builder or git checkout to discard. Do not git restore on the user's behalf.
Learning Capture
OPTIONAL SUB-SKILL: If significant insights, patterns, gotchas, or decisions emerged during this workflow, consider using desplega:learning to capture them via /learning capture. Focus on learnings that would help someone else in a future session.
How can the creator link this skill?
Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.
<a href="https://skillzs.dev/skills/desplega-ai/ai-toolbox/script-builder">View script-builder on skillZs</a>