name: ‘step-03-scaffold-framework’ description: ‘Create framework scaffold with adaptive orchestration (agent-team, subagent, or sequential)’ nextStepFile: ‘{skill-root}/steps-c/step-04-docs-and-scripts.md’ knowledgeIndex: ‘./resources/tea-index.csv’
Generate the test directory structure, configuration files, fixtures, factories, helpers, and sample tests using deterministic mode selection with runtime fallback.
{communication_language}CRITICAL: Follow this sequence exactly. Do not skip, reorder, or improvise.
const parseBooleanFlag = (value, defaultValue = true) => {
if (typeof value === 'string') {
const normalized = value.trim().toLowerCase();
if (['false', '0', 'off', 'no'].includes(normalized)) return false;
if (['true', '1', 'on', 'yes'].includes(normalized)) return true;
}
if (value === undefined || value === null) return defaultValue;
return Boolean(value);
};
const orchestrationContext = {
config: {
execution_mode: config.tea_execution_mode || 'auto', // "auto" | "subagent" | "agent-team" | "sequential"
capability_probe: parseBooleanFlag(config.tea_capability_probe, true), // supports booleans and "false"/"true" strings
},
timestamp: new Date().toISOString().replace(/[:.]/g, '-'),
};
const normalizeUserExecutionMode = (mode) => {
if (typeof mode !== 'string') return null;
const normalized = mode.trim().toLowerCase().replace(/[-_]/g, ' ').replace(/\s+/g, ' ');
if (normalized === 'auto') return 'auto';
if (normalized === 'sequential') return 'sequential';
if (normalized === 'subagent' || normalized === 'sub agent' || normalized === 'subagents' || normalized === 'sub agents') {
return 'subagent';
}
if (normalized === 'agent team' || normalized === 'agent teams' || normalized === 'agentteam') {
return 'agent-team';
}
return null;
};
const normalizeConfigExecutionMode = (mode) => {
if (mode === 'subagent') return 'subagent';
if (mode === 'auto' || mode === 'sequential' || mode === 'subagent' || mode === 'agent-team') {
return mode;
}
return null;
};
// Explicit user instruction in the active run takes priority over config.
const explicitModeFromUser = normalizeUserExecutionMode(runtime.getExplicitExecutionModeHint?.() || null);
const requestedMode = explicitModeFromUser || normalizeConfigExecutionMode(orchestrationContext.config.execution_mode) || 'auto';
const probeEnabled = orchestrationContext.config.capability_probe;
const supports = { subagent: false, agentTeam: false };
if (probeEnabled) {
supports.subagent = runtime.canLaunchSubagents?.() === true;
supports.agentTeam = runtime.canLaunchAgentTeams?.() === true;
}
let resolvedMode = requestedMode;
if (requestedMode === 'auto') {
if (supports.agentTeam) resolvedMode = 'agent-team';
else if (supports.subagent) resolvedMode = 'subagent';
else resolvedMode = 'sequential';
} else if (probeEnabled && requestedMode === 'agent-team' && !supports.agentTeam) {
resolvedMode = supports.subagent ? 'subagent' : 'sequential';
} else if (probeEnabled && requestedMode === 'subagent' && !supports.subagent) {
resolvedMode = 'sequential';
}
Resolution precedence:
agent team => agent-team; subagent => subagent; sequential; auto)tea_execution_mode from configUse {detected_stack} from Step 1 to determine directory layout.
If {detected_stack} is frontend or fullstack:
{test_dir}/e2e/{test_dir}/support/fixtures/{test_dir}/support/helpers/{test_dir}/support/page-objects/ (optional)If {detected_stack} is backend or fullstack:
Create the idiomatic test directory for the detected language:
tests/ with conftest.py, tests/unit/, tests/integration/, tests/api/src/test/java/ mirroring src/main/java/ package structure, with unit/, integration/, api/ sub-packages*_test.go files alongside source files (Go convention), plus testdata/ for fixturestests/ project with Unit/, Integration/, Api/ directoriesspec/ with spec/unit/, spec/integration/, spec/api/, spec/support/tests/ for integration tests, inline #[cfg(test)] modules for unit testsIf config.tea_use_pactjs_utils is enabled and runtime is Node.js/TypeScript (i.e., {detected_stack} is frontend or fullstack, or {detected_stack} is backend with Node.js/TypeScript runtime):
Create Node.js/TypeScript contract testing directory structure per pact-consumer-framework-setup.md:
tests/contract/consumer/ — consumer contract test files (.pacttest.ts extension)tests/contract/support/ — pact config, provider state factories, consumer helpers shimscripts/ — shell scripts (env-setup.sh, publish-pact.sh, can-i-deploy.sh, record-deployment.sh).github/actions/detect-breaking-change/ — PR checkbox-driven breaking change detection.github/workflows/contract-test-consumer.yml — consumer CDC CI workflowIf {detected_stack} is frontend or fullstack:
Create playwright.config.ts or cypress.config.ts with:
BASE_URL)retain-on-failure-and-retries, screenshot only-on-failure, video retain-on-failureUse TypeScript if use_typescript: true.
If {detected_stack} is backend or fullstack:
Create the idiomatic test config for the detected framework:
pyproject.toml [tool.pytest.ini_options] or pytest.ini with markers, test paths, coverage settingsbuild.gradle/pom.xml test configuration with JUnit 5 dependencies, Surefire/Failsafe pluginsMakefile test targets.csproj test project with xUnit and coverlet dependencies.rspec config file with spec_helper.rb and rails_helper.rb (if Rails)Create .env.example with TEST_ENV, BASE_URL, API_URL.
Stack-conditional environment files:
If {detected_stack} is frontend or fullstack (Node.js):
.nvmrc using current LTS Node (prefer Node 24+)If {detected_stack} is backend:
Create the idiomatic version file for the detected language:
.python-version with current stable Python (prefer 3.12+).java-version or JAVA_HOME documentation in .env.examplego.mod (no additional file needed)global.json with SDK version if not already present.ruby-version with current stable RubyRead {config_source} and use {knowledgeIndex} to load fragments based on config.tea_use_playwright_utils:
If Playwright Utils enabled:
overview.md, fixtures-composition.md, auth-session.md, api-request.md, recurse.md, log.md, burn-in.md, network-error-monitor.md, data-factories.md{detected_stack} is frontend or fullstack, also load intercept-network-call.md@seontechnologies/playwright-utilsIf disabled:
fixture-architecture.md, data-factories.md, network-first.md, playwright-config.md, test-quality.mdIf Pact.js Utils enabled (config.tea_use_pactjs_utils):
pact-consumer-framework-setup.md (CRITICAL: load this for directory structure, scripts, CI workflow, and PactV4 patterns — includes fileParallelism: false + pool: 'forks' + singleFork: true, determinism gate, and jq publish normalization)pactjs-utils-overview.md, pactjs-utils-consumer-helpers.md (one-interaction-per-it() rule), pactjs-utils-provider-verifier.md (same pool: 'forks' + singleFork rule applies to consumer AND provider), pactjs-utils-request-filter.md, contract-testing.mdpact-broker-webhooks.md — when scaffolding the provider repo and any CI step that depends on can-i-deploy@seontechnologies/pactjs-utils and @pact-foundation/pactjq is available on CI runners (default on ubuntu-latest; document brew install jq for macOS dev machines) — required by scripts/check-pact-determinism.sh and scripts/publish-pact.shIf Pact.js Utils disabled but contract testing relevant:
contract-testing.mdIf Pact MCP enabled (config.tea_pact_mcp is "mcp"):
pact-mcp.mdImplement:
mergeTestsIf {detected_stack} is frontend or fullstack:
Create example tests in {test_dir}/e2e/ demonstrating:
If {detected_stack} is backend or fullstack:
Create example tests in the idiomatic location for the detected language:
tests/test_example.py with pytest fixtures, parametrize, and factory usagesrc/test/java/.../ExampleTest.java with JUnit 5 annotations, @BeforeEach setupexample_test.go alongside source with table-driven tests and testify assertionstests/ExampleTests.cs with xUnit [Fact]/[Theory] and fixture injectionspec/example_spec.rb with RSpec describe/context/it and factory_botCreate helpers for:
If config.tea_use_pactjs_utils is enabled and runtime is Node.js/TypeScript (i.e., {detected_stack} is frontend or fullstack, or {detected_stack} is backend with Node.js/TypeScript runtime):
Create Node.js/TypeScript contract test samples per pact-consumer-framework-setup.md:
addInteraction() builder + createProviderState + real consumer code with URL injection (.pacttest.ts extension). One addInteraction() per it() block — never chain multiple interactions in a single test (PactV4 FFI drops them non-deterministically; see pactjs-utils-consumer-helpers.md Example 6).pact-config.ts), provider state factories (provider-states.ts), local consumer-helpers shim (consumer-helpers.ts)vitest.config.pact.ts with fileParallelism: false AND pool: 'forks' + poolOptions.forks.singleFork: true (both required — fileParallelism: false prevents shared pact JSON corruption from parallel workers; forks pool + singleFork prevents the Pact Rust FFI from leaking state across files and flaking on Linux CI. See pact-consumer-framework-setup.md Example 2). Do NOT copy settings from unit config.vitest.config.contract.ts with pool: 'forks' + poolOptions.forks.singleFork: true (same rule as consumer; required for message providers and multi-file HTTP providers; see pactjs-utils-provider-verifier.md Example 7).env-setup.sh, check-pact-determinism.sh (primary defense against non-deterministic pact generation), publish-pact.sh (with jq -S interaction sort normalization), can-i-deploy.sh, record-deployment.sh in scripts/test:pact:consumer (determinism gate — runs check-pact-determinism.sh with 3 runs) and test:pact:consumer:run (inner single-pass vitest invocation). CI and local both call npm run test:pact:consumer for 1:1 parity.contract-test-consumer.yml with detect-breaking-change actiontest:pact:consumer (determinism gate), test:pact:consumer:run (inner single-pass vitest), publish:pact, can:i:deploy:consumer, record:consumer:deployment/pacts/ and pact-logs/For this step, treat these work units as parallelizable when resolvedMode is agent-team or subagent:
In parallel-capable modes, runtime decides worker scheduling and concurrency.
If resolvedMode is sequential, execute sections 1→5 in order.
Regardless of mode, outputs must be identical in structure and quality.
Save this step’s accumulated work to {outputFile}.
{outputFile} does not exist (first save), create it with YAML frontmatter: ---
stepsCompleted: ['step-03-scaffold-framework']
lastStep: 'step-03-scaffold-framework'
lastSaved: '{date}'
---
Then write this step’s output below the frontmatter.
{outputFile} already exists, update:
'step-03-scaffold-framework' to stepsCompleted array (only if not already present)lastStep: 'step-03-scaffold-framework'lastSaved: '{date}'Load next step: {nextStepFile}