parakh-testing
workflow
claude_code
Created by Prasham Trivedi
Copy This Prompt
export const meta = {
name: 'parakh-testing',
description: 'End-to-end API testing via Parakh: resolve/refresh spec, design cases, run them in parallel, judge evidence, write testEvidence.md',
whenToUse: 'API / backend contract testing of a deployed feature with Parakh evidence collection',
phases: [
{ title: 'Setup', detail: 'find/refresh spec, endpoints, credentials' },
{ title: 'Plan', detail: 'design thorough test cases for the feature' },
{ title: 'Run', detail: 'per case: run_test -> judge evidence (pipeline)' },
{ title: 'Report', detail: 'assemble testEvidence.md' },
],
}
// args: { baseUrl, docsUrl?, feature, outputDir }
// baseUrl - deployed API base (NOT localhost), e.g. https://beta-siteinspection.prashamhtrivedi.app
// docsUrl - API docs URL to save/update the spec from (optional if a matching spec already exists)
// feature - feature description or path to a taskWalkthrough.md to test end to end
// outputDir- where to write testEvidence.md (e.g. a taskNotes/<task> dir)
const A = args || {}
if (!A.baseUrl || !A.feature) return { error: 'Pass args.baseUrl (deployed, not localhost) and args.feature.' }
const OUT = A.outputDir || '.'
const SETUP = {
type: 'object', additionalProperties: false, required: ['specId', 'baseUrl', 'endpoints', 'credentialsRef'],
properties: {
specId: { type: 'string' },
baseUrl: { type: 'string' },
endpoints: { type: 'array', items: { type: 'string' } },
credentialsRef: { type: 'string', description: 'existing credential identifier reused, or empty if none needed' },
},
}
const PLAN = {
type: 'object', additionalProperties: false, required: ['planText', 'cases'],
properties: {
planText: { type: 'string', description: 'plaintext test plan (goes into testEvidence.md)' },
cases: {
type: 'array',
items: {
type: 'object', additionalProperties: false, required: ['name', 'intent', 'code'],
properties: {
name: { type: 'string' },
intent: { type: 'string', description: 'what this case proves (write-then-GET confirmation)' },
code: { type: 'string', description: 'the code/payload to pass to run_test' },
},
},
},
},
}
const RESULT = {
type: 'object', additionalProperties: false, required: ['name', 'evidenceId', 'passed', 'detail'],
properties: {
name: { type: 'string' },
evidenceId: { type: 'string' },
passed: { type: 'boolean' },
detail: { type: 'string', description: 'curl + body + result summary, verbatim, API keys obfuscated' },
},
}
const SETUP_PROMPT = `You are using the Parakh MCP server (https://parakh.prashamhtrivedi.app/mcp). Confirm it is reachable.
Target API base (deployed, NOT localhost): ${A.baseUrl}
${A.docsUrl ? `API docs URL: ${A.docsUrl}` : ''}
Resolve the spec:
1. get_spec() to list saved specs; list_endpoints on each to find one whose baseUrl matches the target.
2. If a match exists: update_spec to refresh from the docs URL. If not: save_spec from the docs URL.
3. Check manage_credentials on the chosen spec — REUSE existing credentials, do not recreate them.
Return the spec id, confirmed base url, the endpoint list, and the reused credential reference (empty if none).`
phase('Setup')
const setup = await agent(SETUP_PROMPT, { label: 'setup', phase: 'Setup', schema: SETUP, model: 'sonnet' })
if (!setup) return { error: 'Parakh setup failed (spec/endpoints could not be resolved).' }
phase('Plan')
const plan = await agent(
`Design thorough end-to-end API test cases for this feature, covering it completely.
Feature (or walkthrough to read): ${A.feature}
Spec id: ${setup.specId}. Base: ${setup.baseUrl}. Endpoints: ${JSON.stringify(setup.endpoints)}.
First think in plaintext (the test plan), then turn it into concrete cases. Each case should WRITE data then call GET APIs to confirm the write step by step — that confirmation is the evidence. Provide the code to pass to run_test for each case.`,
{ label: 'plan', phase: 'Plan', schema: PLAN }
)
if (!plan || !plan.cases.length) return { error: 'No test cases were designed.' }
log(`${plan.cases.length} test cases planned.`)
log('Note: cases run in parallel — if any cases mutate shared state in a way that conflicts, they should be merged into one ordered case.')
phase('Run')
// Pipeline: run then judge each case independently. run_test produces Parakh evidence.
const results = await pipeline(
plan.cases,
c => agent(
`Run this Parakh test case with the run_test tool, then fetch its evidence with get_results.
Case: ${c.name}
Intent: ${c.intent}
Code:\n${c.code}\nUse credential ref "${setup.credentialsRef}" if needed. Return the evidence id and a verbatim curl+body+result detail (obfuscate only keys/passwords/tokens).`,
{ label: `run:${c.name}`, phase: 'Run', schema: RESULT, model: 'sonnet' }
),
(res, c) => agent(
`Judge this Parakh evidence against the case's intent. Did the write-then-GET confirmation actually prove the feature works? Be strict.
Intent: ${c.intent}
Evidence detail:\n${res.detail}`,
{ label: `judge:${c.name}`, phase: 'Run', schema: { type: 'object', additionalProperties: false, required: ['verified', 'note'], properties: { verified: { type: 'boolean' }, note: { type: 'string' } } } }
).then(j => ({ ...res, verified: j ? j.verified : false, judgeNote: j ? j.note : '' }))
)
const ev = results.filter(Boolean)
phase('Report')
const report = await agent(
`Write testEvidence.md to "${OUT}/testEvidence.md" in EXACTLY this structure:
# Test evidence document
<one-liner of what is tested>
## Test Plan
${plan.planText}
## Test Code
<the code from each case>
## Evidence
<for each case: the verbatim curl+body+result with its Parakh evidence id; obfuscate only keys/passwords/tokens>
## Summary
<a markdown table: case | evidence id | passed | judge note>
If "${OUT}" contains a taskWalkthrough.md, also append a link to this evidence file there.
CASES + EVIDENCE DATA:
${JSON.stringify({ plan: plan.cases, evidence: ev }, null, 2)}`,
{ label: 'write-evidence', phase: 'Report', model: 'sonnet' }
)
return {
outputFile: `${OUT}/testEvidence.md`,
total: ev.length,
passed: ev.filter(e => e.passed && e.verified).length,
report,
}
Workflow Details
- Phases: None
Format Availability
Workflows are available in Claude Code format only and are delivered as-is. They cannot be converted to Codex or Gemini.
Actions
(Clears cached conversions and forces re-processing)