Generates focused E2E test cases for a user-defined topic through a validated multi-step pipeline. Each step runs in an isolated subagent and must pass deterministic validation before the next step begins. When scenarios already exist in Autonoma, fetches context from the API and runs only Step 3 scoped to the topic. On a first run, executes the full 4-step pipeline with Step 3 focused. Use when you want targeted test coverage for a specific feature or domain.
How this skill is triggered — by the user, by Claude, or both
Slash command
/autonoma-test-planner:generate-adhoc-testsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
You are orchestrating a focused test generation pipeline. Each step runs as an isolated subagent.
You are orchestrating a focused test generation pipeline. Each step runs as an isolated subagent. Every step MUST complete successfully and pass validation before the next step begins. Do NOT skip steps. Do NOT proceed if validation fails.
By default, after each step (1, 2, and 3), you MUST present the summary and then ask the user for
confirmation using the AskUserQuestion tool. This creates an interactive
UI prompt that makes it clear the user needs to respond before the pipeline continues.
After calling AskUserQuestion, wait for the user's response.
Only proceed to the next step after they confirm.
Auto-advance mode: If the environment variable AUTONOMA_AUTO_ADVANCE is set to true,
skip the AskUserQuestion calls and automatically proceed to the next step after presenting
the summary. The summaries are still displayed — only the confirmation prompt is skipped.
Resolve the focus prompt from the user's input (the text after the command name):
FOCUS_PROMPT="<the user's focus description>"
FOCUS_SLUG=$(echo "$FOCUS_PROMPT" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-\|-$//g')
echo "Focus: $FOCUS_PROMPT"
echo "Slug: $FOCUS_SLUG"
If no focus description was provided, list top-level route/feature directories in the codebase,
call AskUserQuestion with 3–4 suggested focus areas plus an "Other" option, wait for the user's
response, then derive FOCUS_SLUG from their answer.
Create the output directory and save the project root (subagents change working directory, so we need an absolute path reference):
AUTONOMA_ROOT="$(pwd)"
echo "$AUTONOMA_ROOT" > /tmp/autonoma-project-root
mkdir -p autonoma/skills autonoma/qa-tests
The plugin root path (where hooks, validators, and helper scripts live) is persisted to /tmp/autonoma-plugin-root automatically by the PostToolUse validation hook on the first Write. All bash snippets that need plugin-local files read it back:
PLUGIN_ROOT=$(cat /tmp/autonoma-plugin-root 2>/dev/null || echo '')
Read the environment variables. These are required for reporting progress back to Autonoma:
AUTONOMA_API_KEY — your Autonoma API keyAUTONOMA_PROJECT_ID — your Autonoma project IDAUTONOMA_API_URL — Autonoma API base URLAUTONOMA_AUTO_ADVANCE — (optional) set to true to skip user confirmation prompts between stepsBefore creating the record, derive a clean human-readable application name from the repository. Look at the git remote URL, the directory name, and any package.json / pyproject.toml / README.md to infer what the product is actually called. Prefer the product name over the repo slug (e.g. "My App" not "my-app-v2-final"). Store it in APP_NAME.
Create the generation record so the dashboard can track progress in real time:
RESPONSE=$(curl -s -w "\nHTTP_STATUS:%{http_code}" -X POST "${AUTONOMA_API_URL}/v1/setup/setups" \
-H "Authorization: Bearer ${AUTONOMA_API_KEY}" \
-H "Content-Type: application/json" \
-d "{\"applicationId\":\"${AUTONOMA_PROJECT_ID}\",\"repoName\":\"${APP_NAME}\"}")
HTTP_STATUS=$(echo "$RESPONSE" | grep -o "HTTP_STATUS:[0-9]*" | cut -d: -f2)
BODY=$(echo "$RESPONSE" | sed '/HTTP_STATUS:/d')
echo "Setup API response (HTTP $HTTP_STATUS): $BODY"
GENERATION_ID=$(echo "$BODY" | python3 -c "import json,sys; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || echo '')
mkdir -p autonoma
echo "$GENERATION_ID" > "autonoma/.generation-id-${FOCUS_SLUG}"
echo "Generation ID: $GENERATION_ID"
If GENERATION_ID is empty, log the HTTP status and response body above for debugging, then continue anyway — reporting is best-effort and must never block test generation.
Check whether scenarios with active recipes already exist in Autonoma for this application:
AUTONOMA_ROOT=$(cat /tmp/autonoma-project-root 2>/dev/null || echo '.')
GENERATION_ID=$(cat "$AUTONOMA_ROOT/autonoma/.generation-id-${FOCUS_SLUG}" 2>/dev/null || echo '')
HAS_SCENARIOS="no"
SCENARIOS_RESPONSE=""
if [ -n "$GENERATION_ID" ]; then
SCENARIOS_RESPONSE=$(curl -s "${AUTONOMA_API_URL}/v1/setup/setups/${GENERATION_ID}/scenarios" \
-H "Authorization: Bearer ${AUTONOMA_API_KEY}")
HAS_SCENARIOS=$(echo "$SCENARIOS_RESPONSE" | python3 -c "
import json, sys
data = json.loads(sys.stdin.read())
active = [s for s in data.get('scenarios', []) if s.get('hasActiveRecipe')]
print('yes' if active else 'no')
" 2>/dev/null || echo "no")
fi
echo "Has active scenarios: $HAS_SCENARIOS"
If HAS_SCENARIOS=yes — scenarios and tests already exist. Fetch context from the API and run only Step 3:
AUTONOMA_ROOT=$(cat /tmp/autonoma-project-root 2>/dev/null || echo '.')
GENERATION_ID=$(cat "$AUTONOMA_ROOT/autonoma/.generation-id-${FOCUS_SLUG}" 2>/dev/null || echo '')
EXISTING_CONTEXT=$(curl -s "${AUTONOMA_API_URL}/v1/setup/applications/${AUTONOMA_PROJECT_ID}/test-suite" \
-H "Authorization: Bearer ${AUTONOMA_API_KEY}")
SCENARIOS_CONTEXT=$(echo "$SCENARIOS_RESPONSE" | python3 -c "
import json, sys
data = json.loads(sys.stdin.read())
lines = ['## Available Scenarios', '']
for s in data.get('scenarios', []):
status = 'active' if s.get('hasActiveRecipe') else 'no recipe'
lines.append(f\"- **{s['name']}** ({status})\")
print('\n'.join(lines))
" 2>/dev/null || echo "")
TESTS_CONTEXT=$(echo "$EXISTING_CONTEXT" | python3 -c "
import json, sys
data = json.loads(sys.stdin.read())
tests = data.get('tests', [])
lines = [f'## Existing Tests ({len(tests)} total)', '']
for t in tests:
lines.append(f\"- {t['name']} (slug: {t['slug']})\")
print('\n'.join(lines))
" 2>/dev/null || echo "")
SKILLS_CONTEXT=$(echo "$EXISTING_CONTEXT" | python3 -c "
import json, sys
data = json.loads(sys.stdin.read())
skills = data.get('skills', [])
lines = [f'## Available Skills ({len(skills)} total)', '']
for s in skills:
lines.append(f\"- {s['name']}: {s['description']}\")
print('\n'.join(lines))
" 2>/dev/null || echo "")
Skip to Step 3: Generate Focused E2E Test Cases and pass the fetched context inline in the subagent task — do not run Steps 1, 2, or 4.
If HAS_SCENARIOS=no — this is a first run. Continue with the full pipeline below (Steps 1 through 4).
Report step start:
AUTONOMA_ROOT=$(cat /tmp/autonoma-project-root 2>/dev/null || echo '.')
GENERATION_ID=$(cat "$AUTONOMA_ROOT/autonoma/.generation-id-${FOCUS_SLUG}" 2>/dev/null || echo '')
echo "GENERATION_ID=${GENERATION_ID:-<empty>}"
[ -n "$GENERATION_ID" ] && curl -f -X POST "${AUTONOMA_API_URL}/v1/setup/setups/${GENERATION_ID}/events" \
-H "Authorization: Bearer ${AUTONOMA_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"type":"step.started","data":{"step":0,"name":"Knowledge Base"}}' || true
[ -n "$GENERATION_ID" ] && curl -f -X POST "${AUTONOMA_API_URL}/v1/setup/setups/${GENERATION_ID}/events" \
-H "Authorization: Bearer ${AUTONOMA_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"type":"log","data":{"message":"Analyzing codebase structure and identifying features..."}}' || true
Spawn the kb-generator subagent with the following task:
Analyze the codebase and generate the knowledge base. Write the output to
autonoma/AUTONOMA.mdand create skill files inautonoma/skills/. The file MUST have YAML frontmatter with app_name, app_description, core_flows (feature/description/core table), feature_count, and skill_count. You MUST also writeautonoma/features.json— a machine-readable inventory of every feature discovered. It must have: features array (each with name, type, path, core), total_features, total_routes, total_api_routes. Fetch the latest instructions from https://docs.agent.autonoma.app/llms/test-planner/step-1-knowledge-base.txt first.
After the subagent completes:
autonoma/AUTONOMA.md and autonoma/features.json exist and are non-emptyReport step complete and upload skills:
AUTONOMA_ROOT=$(cat /tmp/autonoma-project-root 2>/dev/null || echo '.')
GENERATION_ID=$(cat "$AUTONOMA_ROOT/autonoma/.generation-id-${FOCUS_SLUG}" 2>/dev/null || echo '')
echo "GENERATION_ID=${GENERATION_ID:-<empty>}"
SKILL_COUNT=$(ls "$AUTONOMA_ROOT/autonoma/skills/"*.md 2>/dev/null | wc -l | tr -d ' ')
[ -n "$GENERATION_ID" ] && curl -f -X POST "${AUTONOMA_API_URL}/v1/setup/setups/${GENERATION_ID}/events" \
-H "Authorization: Bearer ${AUTONOMA_API_KEY}" \
-H "Content-Type: application/json" \
-d "{\"type\":\"log\",\"data\":{\"message\":\"Knowledge base complete. Generated ${SKILL_COUNT} skills. Uploading to dashboard...\"}}" || true
[ -n "$GENERATION_ID" ] && curl -f -X POST "${AUTONOMA_API_URL}/v1/setup/setups/${GENERATION_ID}/events" \
-H "Authorization: Bearer ${AUTONOMA_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"type":"step.completed","data":{"step":0,"name":"Knowledge Base"}}' || true
[ -n "$GENERATION_ID" ] && python3 -c "
import os, json, sys
root = open('/tmp/autonoma-project-root').read().strip() if os.path.exists('/tmp/autonoma-project-root') else '.'
skills = []
d = os.path.join(root, 'autonoma/skills')
if os.path.isdir(d):
for f in os.listdir(d):
if f.endswith('.md'):
with open(os.path.join(d, f)) as fh:
skills.append({'name': f, 'content': fh.read()})
print(json.dumps({'skills': skills}))
" | curl -f -X POST "${AUTONOMA_API_URL}/v1/setup/setups/${GENERATION_ID}/artifacts" \
-H "Authorization: Bearer ${AUTONOMA_API_KEY}" \
-H "Content-Type: application/json" \
-d @- || true
AUTONOMA_AUTO_ADVANCE is not true: Call AskUserQuestion with:
AUTONOMA_AUTO_ADVANCE=true: Skip the prompt and proceed directly to Step 2.Report step start:
AUTONOMA_ROOT=$(cat /tmp/autonoma-project-root 2>/dev/null || echo '.')
GENERATION_ID=$(cat "$AUTONOMA_ROOT/autonoma/.generation-id-${FOCUS_SLUG}" 2>/dev/null || echo '')
echo "GENERATION_ID=${GENERATION_ID:-<empty>}"
[ -n "$GENERATION_ID" ] && curl -f -X POST "${AUTONOMA_API_URL}/v1/setup/setups/${GENERATION_ID}/events" \
-H "Authorization: Bearer ${AUTONOMA_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"type":"step.started","data":{"step":1,"name":"Scenarios"}}' || true
[ -n "$GENERATION_ID" ] && curl -f -X POST "${AUTONOMA_API_URL}/v1/setup/setups/${GENERATION_ID}/events" \
-H "Authorization: Bearer ${AUTONOMA_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"type":"log","data":{"message":"Mapping data model and designing test data environments..."}}' || true
Before spawning the Step 2 subagent, fetch the SDK discover artifact and save it to autonoma/discover.json.
This step requires these environment variables:
AUTONOMA_SDK_ENDPOINT — full URL of the customer's SDK endpointAUTONOMA_SHARED_SECRET — the HMAC shared secret used by the SDK endpointIf either variable is missing, stop and tell the user that Step 2 now requires SDK discover access. Do not suggest skipping ahead, reordering the pipeline, or continuing without a working Environment Factory endpoint. State plainly that the endpoint and both environment variables are mandatory prerequisites for Step 2.
Fetch and validate the artifact:
AUTONOMA_ROOT=$(cat /tmp/autonoma-project-root 2>/dev/null || echo '.')
mkdir -p "$AUTONOMA_ROOT/autonoma"
BODY='{"action":"discover"}'
SIG=$(echo -n "$BODY" | openssl dgst -sha256 -hmac "$AUTONOMA_SHARED_SECRET" | sed 's/.*= //')
RESPONSE=$(curl -sS -w "\nHTTP_STATUS:%{http_code}" -X POST "$AUTONOMA_SDK_ENDPOINT" \
-H "Content-Type: application/json" \
-H "x-signature: $SIG" \
-d "$BODY")
HTTP_STATUS=$(echo "$RESPONSE" | grep -o "HTTP_STATUS:[0-9]*" | cut -d: -f2)
DISCOVER_BODY=$(echo "$RESPONSE" | sed '/HTTP_STATUS:/d')
if [ "$HTTP_STATUS" != "200" ]; then
echo "SDK discover failed (HTTP $HTTP_STATUS): $DISCOVER_BODY"
exit 1
fi
printf '%s\n' "$DISCOVER_BODY" > "$AUTONOMA_ROOT/autonoma/discover.json"
python3 "$(cat /tmp/autonoma-plugin-root)/hooks/validators/validate_discover.py" "$AUTONOMA_ROOT/autonoma/discover.json"
If the fetch fails or validation fails, stop the pipeline at Step 2. Do not suggest skipping ahead. Tell the user to provide a working SDK endpoint and correct shared secret, then rerun the command.
Spawn the scenario-generator subagent with the following task:
Read the knowledge base from
autonoma/AUTONOMA.md,autonoma/skills/, and the SDK discover artifact fromautonoma/discover.json. Generate test data scenarios. Write the output toautonoma/scenarios.md. The file MUST have YAML frontmatter with scenario_count, scenarios summary, entity_types, discover metadata, and variable_fields. Prefer fixed, reviewable seed values by default. If a field needs uniqueness, prefer a planner-chosen hardcoded literal plus a discriminator before introducing a variable placeholder. Use variable fields only for truly dynamic values such as backend-generated or time-based fields.generatoris optional and must not default tofaker. Fetch the latest instructions from https://docs.agent.autonoma.app/llms/test-planner/step-2-scenarios.txt first.
After the subagent completes:
autonoma/discover.json and autonoma/scenarios.md exist and are non-emptyautonoma/discover.json using the plugin's validator (path saved in /tmp/autonoma-plugin-root)scenarios.md frontmatter format automaticallyReport step complete:
AUTONOMA_ROOT=$(cat /tmp/autonoma-project-root 2>/dev/null || echo '.')
GENERATION_ID=$(cat "$AUTONOMA_ROOT/autonoma/.generation-id-${FOCUS_SLUG}" 2>/dev/null || echo '')
echo "GENERATION_ID=${GENERATION_ID:-<empty>}"
[ -n "$GENERATION_ID" ] && curl -f -X POST "${AUTONOMA_API_URL}/v1/setup/setups/${GENERATION_ID}/events" \
-H "Authorization: Bearer ${AUTONOMA_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"type":"log","data":{"message":"Scenarios generated from SDK discover. Preserved standard/empty/large plus schema metadata, keeping variable fields minimal and intentional."}}' || true
[ -n "$GENERATION_ID" ] && curl -f -X POST "${AUTONOMA_API_URL}/v1/setup/setups/${GENERATION_ID}/events" \
-H "Authorization: Bearer ${AUTONOMA_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"type":"step.completed","data":{"step":1,"name":"Scenarios"}}' || true
AUTONOMA_AUTO_ADVANCE is not true: Call AskUserQuestion with:
AUTONOMA_AUTO_ADVANCE=true: Skip the prompt and proceed directly to Step 3.Report step start:
AUTONOMA_ROOT=$(cat /tmp/autonoma-project-root 2>/dev/null || echo '.')
GENERATION_ID=$(cat "$AUTONOMA_ROOT/autonoma/.generation-id-${FOCUS_SLUG}" 2>/dev/null || echo '')
echo "GENERATION_ID=${GENERATION_ID:-<empty>}"
[ -n "$GENERATION_ID" ] && curl -f -X POST "${AUTONOMA_API_URL}/v1/setup/setups/${GENERATION_ID}/events" \
-H "Authorization: Bearer ${AUTONOMA_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"type":"step.started","data":{"step":2,"name":"Focused E2E Tests"}}' || true
[ -n "$GENERATION_ID" ] && curl -f -X POST "${AUTONOMA_API_URL}/v1/setup/setups/${GENERATION_ID}/events" \
-H "Authorization: Bearer ${AUTONOMA_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"type":"log","data":{"message":"Generating focused E2E test cases..."}}' || true
Spawn the focused-test-case-generator subagent with the following task (substitute the actual
values for FOCUS_PROMPT, FOCUS_SLUG, and — when coming from the API-fetch path — the context
variables SCENARIOS_CONTEXT, TESTS_CONTEXT, and SKILLS_CONTEXT before spawning):
FOCUS_PROMPT: <the user's focus description> FOCUS_SLUG:
(API-fetch path only — omit this block when running the full pipeline) Context fetched from the Autonoma API (use this instead of reading local files): <SCENARIOS_CONTEXT> <TESTS_CONTEXT> <SKILLS_CONTEXT>
Read the knowledge base from
autonoma/AUTONOMA.md, skills fromautonoma/skills/, and scenarios fromautonoma/scenarios.md(if they exist and no inline context was provided above). Generate E2E test cases focused exclusively on the topic described in FOCUS_PROMPT. Write tests toautonoma/qa-tests/{FOCUS_SLUG}/. You MUST createautonoma/qa-tests/{FOCUS_SLUG}/INDEX.mdwith frontmatter containing total_tests, total_folders, folder breakdown, and coverage_correlation. Each test file MUST have frontmatter with title, description, criticality, scenario, and flow. Treat scenario data as fixture input only. Do not generate tests whose purpose is to verify scenario counts, seeded inventories, or Environment Factory correctness. Only reference scenario data when it is needed to test a real user-facing app behavior within the focus area. Fetch the latest instructions from https://docs.agent.autonoma.app/llms/test-planner/step-3-e2e-tests.txt first.
After the subagent completes:
autonoma/qa-tests/${FOCUS_SLUG}/INDEX.md exists and is non-emptyReport step complete and upload test cases:
AUTONOMA_ROOT=$(cat /tmp/autonoma-project-root 2>/dev/null || echo '.')
GENERATION_ID=$(cat "$AUTONOMA_ROOT/autonoma/.generation-id-${FOCUS_SLUG}" 2>/dev/null || echo '')
echo "GENERATION_ID=${GENERATION_ID:-<empty>}"
TEST_COUNT=$(find "$AUTONOMA_ROOT/autonoma/qa-tests/${FOCUS_SLUG}" -name '*.md' ! -name 'INDEX.md' 2>/dev/null | wc -l | tr -d ' ')
[ -n "$GENERATION_ID" ] && curl -f -X POST "${AUTONOMA_API_URL}/v1/setup/setups/${GENERATION_ID}/events" \
-H "Authorization: Bearer ${AUTONOMA_API_KEY}" \
-H "Content-Type: application/json" \
-d "{\"type\":\"log\",\"data\":{\"message\":\"Generated ${TEST_COUNT} focused test cases. Uploading to dashboard...\"}}" || true
[ -n "$GENERATION_ID" ] && curl -f -X POST "${AUTONOMA_API_URL}/v1/setup/setups/${GENERATION_ID}/events" \
-H "Authorization: Bearer ${AUTONOMA_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"type":"step.completed","data":{"step":2,"name":"Focused E2E Tests"}}' || true
[ -n "$GENERATION_ID" ] && python3 -c "
import os, json
proj_root = open('/tmp/autonoma-project-root').read().strip() if os.path.exists('/tmp/autonoma-project-root') else '.'
qa_dir = os.path.join(proj_root, 'autonoma/qa-tests/${FOCUS_SLUG}')
test_cases = []
for root, dirs, files in os.walk(qa_dir):
for f in files:
if f.endswith('.md') and f != 'INDEX.md':
path = os.path.join(root, f)
folder = os.path.relpath(root, qa_dir)
with open(path) as fh:
content = fh.read()
entry = {'name': f, 'content': content}
if folder != '.':
entry['folder'] = '${FOCUS_SLUG}/' + folder
test_cases.append(entry)
print(json.dumps({'testCases': test_cases}))
" | curl -f -X POST "${AUTONOMA_API_URL}/v1/setup/setups/${GENERATION_ID}/artifacts" \
-H "Authorization: Bearer ${AUTONOMA_API_KEY}" \
-H "Content-Type: application/json" \
-d @- || true
AUTONOMA_AUTO_ADVANCE is not true: Call AskUserQuestion with:
AUTONOMA_AUTO_ADVANCE=true: Skip the prompt and proceed directly to Step 4 (or stop here if coming from the API-fetch path).If coming from the API-fetch path (scenarios already existed), stop here after uploading. Step 4 is not needed.
Report step start:
AUTONOMA_ROOT=$(cat /tmp/autonoma-project-root 2>/dev/null || echo '.')
GENERATION_ID=$(cat "$AUTONOMA_ROOT/autonoma/.generation-id-${FOCUS_SLUG}" 2>/dev/null || echo '')
echo "GENERATION_ID=${GENERATION_ID:-<empty>}"
[ -n "$GENERATION_ID" ] && curl -f -X POST "${AUTONOMA_API_URL}/v1/setup/setups/${GENERATION_ID}/events" \
-H "Authorization: Bearer ${AUTONOMA_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"type":"step.started","data":{"step":3,"name":"Environment Factory"}}' || true
[ -n "$GENERATION_ID" ] && curl -f -X POST "${AUTONOMA_API_URL}/v1/setup/setups/${GENERATION_ID}/events" \
-H "Authorization: Bearer ${AUTONOMA_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"type":"log","data":{"message":"Implementing or completing the Environment Factory and validating planned scenarios..."}}' || true
This step requires these environment variables:
AUTONOMA_SDK_ENDPOINT — full URL of the customer's SDK endpointAUTONOMA_SHARED_SECRET — the HMAC shared secret used by the SDK endpointIf either variable is missing, stop and tell the user that Step 4 requires SDK endpoint access for preflight validation. State plainly that both environment variables are mandatory.
Spawn the env-factory-generator subagent with the following task:
Read
autonoma/discover.jsonandautonoma/scenarios.md. Implement or complete the Autonoma Environment Factory in the project's backend so it can support the planned scenarios with the current SDK contract, then validate the planned scenarios against that implementation. Fetch the latest instructions from https://docs.agent.autonoma.app/llms/test-planner/step-4-implement-scenarios.txt and https://docs.agent.autonoma.app/llms/guides/environment-factory.txt first. Preserve the existing discover integration if it already works, and finishup/downbehavior usingAUTONOMA_SHARED_SECRETandAUTONOMA_SIGNING_SECRET. Smoke-test the discover -> up -> down lifecycle in-session after implementing. Then validatestandard,empty, andlarge, and write approved recipes toautonoma/scenario-recipes.json. The recipe file must match the current setup API schema: top-levelversion: 1,source,validationMode,recipes; each recipe must usename,description,create, andvalidationwithstatus: "validated", a validmethod,phase: "ok", and optionalup_ms/down_ms. Do not use the old shape with top-levelscenarios,generatedAt, or per-recipevalidated/timing. Whencreateuses{{token}}placeholders, include avariablesfield per recipe that defines how each token is resolved. Allowed strategies:literal,derived,faker. Persistedcreatemust remain tokenized — never store resolved concrete values. After writing the recipe file, run the preflight helper to validate all recipes against the live SDK endpoint before uploading:python3 "$(cat /tmp/autonoma-plugin-root)/hooks/preflight_scenario_recipes.py" autonoma/scenario-recipes.jsonThe preflight must pass for all three scenarios before Step 4 is considered complete.
After the subagent completes:
autonoma/scenario-recipes.json exists and is non-emptyAUTONOMA_ROOT=$(cat /tmp/autonoma-project-root 2>/dev/null || echo '.')
python3 "$(cat /tmp/autonoma-plugin-root)/hooks/preflight_scenario_recipes.py" "$AUTONOMA_ROOT/autonoma/scenario-recipes.json"
If preflight fails, do NOT proceed to upload. Report the failure to the user and stop. 4. Present the results to the user — endpoint location, what was implemented or fixed, smoke-test results, per-scenario preflight results 5. Report which environment variables the backend now requires 6. Report any backend issues that still need manual attention
Report step complete:
AUTONOMA_ROOT=$(cat /tmp/autonoma-project-root 2>/dev/null || echo '.')
GENERATION_ID=$(cat "$AUTONOMA_ROOT/autonoma/.generation-id-${FOCUS_SLUG}" 2>/dev/null || echo '')
echo "GENERATION_ID=${GENERATION_ID:-<empty>}"
[ -n "$GENERATION_ID" ] && curl -f -X POST "${AUTONOMA_API_URL}/v1/setup/setups/${GENERATION_ID}/events" \
-H "Authorization: Bearer ${AUTONOMA_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"type":"log","data":{"message":"Uploading validated scenario recipes to setup..."}}' || true
if [ -n "$GENERATION_ID" ]; then
RECIPE_PATH="$AUTONOMA_ROOT/autonoma/scenario-recipes.json"
if ! python3 -c "import json; json.load(open('$RECIPE_PATH'))" 2>/dev/null; then
echo "ERROR: scenario-recipes.json is not valid JSON. Step 4 cannot complete."
exit 1
fi
UPLOAD_RESPONSE=$(curl -s -w "\nHTTP_STATUS:%{http_code}" -X POST "${AUTONOMA_API_URL}/v1/setup/setups/${GENERATION_ID}/scenario-recipe-versions" \
-H "Authorization: Bearer ${AUTONOMA_API_KEY}" \
-H "Content-Type: application/json" \
-d @"$RECIPE_PATH")
UPLOAD_STATUS=$(echo "$UPLOAD_RESPONSE" | grep -o "HTTP_STATUS:[0-9]*" | cut -d: -f2)
UPLOAD_BODY=$(echo "$UPLOAD_RESPONSE" | sed '/HTTP_STATUS:/d')
echo "Scenario recipe upload response (HTTP $UPLOAD_STATUS): $UPLOAD_BODY"
if [ "$UPLOAD_STATUS" != "200" ] && [ "$UPLOAD_STATUS" != "201" ]; then
echo "ERROR: Recipe upload failed (HTTP $UPLOAD_STATUS). Step 4 cannot complete."
exit 1
fi
fi
[ -n "$GENERATION_ID" ] && curl -f -X POST "${AUTONOMA_API_URL}/v1/setup/setups/${GENERATION_ID}/events" \
-H "Authorization: Bearer ${AUTONOMA_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"type":"log","data":{"message":"Environment Factory implementation and scenario validation completed."}}' || true
[ -n "$GENERATION_ID" ] && curl -f -X POST "${AUTONOMA_API_URL}/v1/setup/setups/${GENERATION_ID}/events" \
-H "Authorization: Bearer ${AUTONOMA_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"type":"step.completed","data":{"step":3,"name":"Environment Factory"}}' || true
After all steps complete, summarize:
autonoma/qa-tests/{FOCUS_SLUG}/)npx claudepluginhub autonoma-ai/test-planner-plugin --plugin autonoma-test-plannerProvides a checklist for code reviews covering functionality, security, performance, maintainability, tests, and quality. Use for pull requests, audits, team standards, and developer training.