stack-scaler
Skill4 starsChanged 2 months agoApache-2.0View on GitHub
Step-by-step guide for extending the Eitr codebase to support a new programming language and/or E2E test automation tool. Covers the full pipeline from CLI questionnaire through plan.ts generator registry to template generation and tests.
In this repository22 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- llms.txtllms.txt
- architecture-doc-writerSkill
- ast-template-engineerSkill
- axis-closure-matrixSkill
- commit-writerSkill
- framework-quality-auditSkill
- protocol-123Skill
- protocol-456Skill
- sdd-plan-writerSkill
- stack-scalerSkill
- strategic-architecture-advisorSkill
- architecture-doc-writerSkill
- ast-template-engineerSkill
- axis-closure-matrixSkill
- commit-writerSkill
- framework-quality-auditSkill
- protocol-123Skill
- protocol-456Skill
- sdd-plan-writerSkill
- strategic-architecture-advisorSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
13 rules. About 0 are common, 5 are distinctive, and 8 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈5
Distinctive · estimate
This author's own choices. Worth a look.
8
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 14
Every step is isolated: you must modify 0 existing generators.
- Very specific: line 20
Missing File Rule: If a required file (e.g. schema.ts or generate.ts) is missing, you must immediately abort and output EXACTLY: ERROR: …
- Very specific: line 21
Test Failure Rule: If npm test fails after your changes, you must revert the modifications and output EXACTLY: ERROR: Tests failed, changes …
- Distinctive: line 28
Before touching any file, understand the full data flow:
- Very specific: line 49
Write template render functions under packages/engine/src/plan/templates/<lang>/.
- Very specific: line 139
Add a new class below PlaywrightTsGenerator.
- Distinctive: line 198
Create a dedicated subdirectory for the new stack templates.
- Very specific: line 231
If you add >0 new AI rule templates, implement the corresponding native render functions so that planSharedScaffold in …
- Very specific: line 242
Add PROJECT_FILES_<LANG> and CREATE_IF_ABSENT_<LANG> constants and a new describe block that mirrors the existing TypeScript block:
- Very specific: line 262
Add packages/engine/test/python-templates.test.ts (or equivalent) with:
- Very specific: line 265
Verify base_page.py contains async def, and 0 assert keywords.
- Distinctive: line 271
Add a test that:
- Distinctive: line 290
Before opening a PR, verify 100% of items:
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Eitr Stack Scaler
Purpose
This skill guides you through adding support for a new language + automation tool combination
to the Eitr generator. After following it, running eitr init and selecting the new combination
will produce a project that successfully executes >0 tests.
Every step is isolated: you must modify 0 existing generators.
Boundary Constraints & Edge Cases
- Missing File Rule: If a required file (e.g.
schema.tsorgenerate.ts) is missing, you must immediately abort and output EXACTLY:ERROR: Required file not found. - Test Failure Rule: If
npm testfails after your changes, you must revert the modifications and output EXACTLY:ERROR: Tests failed, changes reverted. - Never Modify Existing: You must make 0 changes to existing
TargetGeneratorimplementations.
Architecture Overview
Before touching any file, understand the full data flow:
eitr init
└─ packages/cli/src/questionnaire/schema.ts ← declares question choices
└─ packages/cli/src/questionnaire/driver.ts ← filters tools by language
└─ .eitr/init.json ← persisted answers
eitr generate
└─ packages/cli/src/commands/generate.ts ← reads init.json, guards unsupported combos,
│ runs recon, builds StackProfile, calls plan()
└─ packages/engine/src/plan/plan.ts ← dispatches to the correct TargetGenerator
└─ packages/engine/src/plan/templates/<lang>/ ← pure render functions (no I/O)
└─ packages/engine/src/apply/apply.ts ← writes files to disk (already works for all)The changes needed for a new combination are:
- Register the tool in the questionnaire
schema.ts. - Lift the guard in
generate.ts. - Implement a
TargetGeneratorclass and register it inplan.ts. - Write template render functions under
packages/engine/src/plan/templates/<lang>/. - Add >2 unit tests.
Step 1 — Questionnaire: Register the new language and tool
File: packages/cli/src/questionnaire/schema.ts
1a. Add the language (if new)
// LANGUAGE_CHOICES array — add the new entry
const LANGUAGE_CHOICES: readonly Choice[] = [
{ label: 'TypeScript', value: 'typescript' },
{ label: 'Python', value: 'python' }, // ← example
// ...
];1b. Add the automation tool (if new)
// AUTOMATION_TOOL_CHOICES array
const AUTOMATION_TOOL_CHOICES: readonly Choice[] = [
{ label: 'Playwright', value: 'playwright' },
{ label: 'pytest', value: 'pytest' }, // ← example
// ...
];1c. Add the default output directory
export function defaultOutputDirForAutomationTool(tool?: string): string {
switch ((tool ?? '').toLowerCase()) {
case 'pytest':
return 'PytestTests'; // ← example
// ...
}
}1d. Wire tool–language compatibility
export function isToolSupportedByLanguage(tool: string, language: string): boolean {
// Playwright and Selenium work with any language — they stay as-is.
switch (language) {
case 'python':
return tool === 'pytest' || tool === 'playwright' || tool === 'selenium';
// ...
}
}Step 2 — CLI Generate: Lift the unsupported-combo guard
File: packages/cli/src/commands/generate.ts
The current guard (lines ~91–96) rejects any combination that is not typescript + playwright.
Extend it to allow the new combo:
const SUPPORTED: Array<{ language: string; automationTool: string }> = [
{ language: 'typescript', automationTool: 'playwright' },
{ language: 'python', automationTool: 'pytest' }, // ← add new entry
];
const supported = SUPPORTED.some((s) => s.language === language && s.automationTool === tool);
if (!supported) {
process.stderr.write(
`eitr generate: generation for "${language}" + "${tool}" is not implemented yet.\n`,
);
return 1;
}Important: Do NOT remove the existing guard logic. Simply extend the supported list.
Step 3 — Engine: Implement a TargetGenerator
File: packages/engine/src/plan/plan.ts
3a. Create the class
Add a new class below PlaywrightTsGenerator. You must edit 0 existing classes.
/**
* Generator for <Language> + <Tool> (e.g. Python + pytest).
* Isolated from the TypeScript generator: shares 0 code paths.
*/
export class PytestPythonGenerator implements TargetGenerator {
readonly language = 'python';
readonly automationTool = 'pytest';
plan(profile: StackProfile, opts: PlanOptions): FileDescriptor[] {
const baseUrl = opts.baseUrl ?? DEFAULT_BASE_URL;
const projectName = opts.projectName ?? 'pytest-tests';
const ciCd = opts.ciCd ?? 'none';
const files: FileDescriptor[] = [
// ── config ──────────────────────────────────────────────────────────
{
path: 'pytest.ini',
writePolicy: 'create-if-absent',
provenance: { origin: 'project' },
source: { kind: 'inline', text: renderPytestIni({ baseUrl, projectName }) },
},
// ── conftest ────────────────────────────────────────────────────────
{
path: 'conftest.py',
writePolicy: 'create-if-absent',
provenance: { origin: 'project' },
source: { kind: 'inline', text: renderPytestConftest() },
},
// ── base components ─────────────────────────────────────────────────
{
path: 'components/base/base_page.py',
writePolicy: 'create-if-absent',
provenance: { origin: 'base' },
source: { kind: 'inline', text: renderPythonBasePage() },
},
// ... add all other files
];
return files;
}
}3b. Register it in the TARGET_GENERATORS registry
export const TARGET_GENERATORS: TargetGenerator[] = [
new PlaywrightTsGenerator(),
new PytestPythonGenerator(), // ← append; never reorder existing entries
];Step 4 — Templates: Write render functions
Create a dedicated subdirectory for the new stack templates.
Path: packages/engine/src/plan/templates/<lang>/
Example layout for Python + pytest:
packages/engine/src/plan/templates/python/
pytest-ini.ts → renderPytestIni()
conftest.ts → renderPytestConftest()
base-page.ts → renderPythonBasePage()
button.ts → renderPythonButton()
text-input.ts → renderPythonTextInput()
page-readme.ts → renderPythonPageReadme()Template authoring rules
- Pure functions only — 0 fs calls, 0 fetch calls, 0 side effects.
- Language conventions — use
snake_casefor Python,camelCasefor JS/TS, etc. - Method Safety Contract — enforce in every base class template:
- Actions → return
None(Python) /Promise<void>(TS). - Producers →
@property(Python) / getter (TS) returning component instance. - Snapshot reads →
_now()suffix (Python) /Now()suffix (TS). - 0 assertions inside component or page classes.
- Actions → return
- AI rules — Generate native
.claude/,.cursor/,.devin/,.codex/, or.agents/skills/files. The stack-scaler rule must NOT be included.
Step 5 — Native AI Rules Templates
File: packages/engine/src/plan/templates/ai-rules.ts
If you add >0 new AI rule templates, implement the corresponding native render functions
so that planSharedScaffold in packages/engine/src/plan/shared.ts generates them for each supported AI assistant.
Step 6 — Unit Tests
6a. Snapshot test
File: packages/engine/test/plan.snapshot.test.ts
Add PROJECT_FILES_<LANG> and CREATE_IF_ABSENT_<LANG> constants and a new describe block
that mirrors the existing TypeScript block:
describe('plan() snapshot — Python + pytest', () => {
it('emits a complete project for python + pytest', () => {
const paths = plan(baselineStackProfile('/fake'), {
...planOptions(),
language: 'python',
automationTool: 'pytest',
})
.files.map((f) => f.path)
.sort();
expect(paths).toEqual(PYTHON_PROJECT_FILES.sort());
});
});6b. Template unit tests
Add packages/engine/test/python-templates.test.ts (or equivalent) with:
- Snapshot or string-contains checks for each render function.
- Verify
base_page.pycontainsasync def, and 0assertkeywords.
6c. CLI guard test
File: packages/cli/test/generate.test.ts
Add a test that:
- Writes
init.jsonwith{ language: 'python', automationTool: 'pytest' }. - Asserts
runGenerate(...)returns0. - Asserts
conftest.pyexists in the output directory.
Step 7 — Build & Verify
npm run build # must compile with 0 TypeScript errors
npm test # 100% of tests must passChecklist
Before opening a PR, verify 100% of items:
schema.ts: new language and/or tool choice added to all relevant arraysschema.ts:isToolSupportedByLanguage()updatedschema.ts:defaultOutputDirForAutomationTool()updatedgenerate.ts: supported-combo guard extended (0 existing entries removed)plan.ts: newTargetGeneratorclass added below existing onesplan.ts: class appended toTARGET_GENERATORS(0 reordering)- Templates directory created under
packages/engine/src/plan/templates/<lang>/ - 100% of render functions contain 0 I/O calls
- Method Safety Contract enforced in base page template
- Snapshot test extended with new language block
- CLI generate test covers the new combo (exit 0, files written)
npm run build— 0 errorsnpm test— 100% of tests pass- 100% of existing tests pass with 0 modifications
Examples
Good Example
// Adding a new combo (0 existing entries modified or removed)
const SUPPORTED: Array<{ language: string; automationTool: string }> = [
{ language: 'typescript', automationTool: 'playwright' },
{ language: 'python', automationTool: 'pytest' },
];Bad Example
// Modifying existing combo (Violation: changed existing entry instead of appending)
const SUPPORTED: Array<{ language: string; automationTool: string }> = [
{ language: 'python', automationTool: 'pytest' },
];Language-specific conventions reference
| Language | Naming | Config file | Fixture pattern | Test file prefix |
| TypeScript | camelCase | playwright.config.ts | fixtures.ts | *.spec.ts |
| Python | snake_case | pytest.ini | conftest.py | test_*.py |
| Java | camelCase | pom.xml | JUnit @BeforeEach | *Test.java |
| C# | PascalCase | *.csproj | NUnit [SetUp] | *Tests.cs |
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

