Code Generation — act101 Agent Skill
Generate boilerplate code from existing types using AST-aware code generation. Use when creating constructors, getters/setters, builders, equals/hash methods, JSON serialization, toString, interface implementations, test stubs, or any repetitive code derived from existing class/struct definitions. Supports batch generation for maximum efficiency.
Code Generation with act
Generate boilerplate from existing type definitions. All generation operations are CLI-based — invoke via shell commands. This skill is the authoritative reference for code generation patterns. Other skills (code_porting, architectural_refactoring, code_refactoring) delegate here for boilerplate generation.
Rules
-
Classify before acting. Before writing boilerplate by hand, determine if a generator can produce it. Data types (DTOs, models, value objects) → generators. Business logic → manual/LLM. Interface stubs →
generate-impl. If a generator exists for the task, use it — it produces correct, language-appropriate code without consuming LLM tokens. -
Discover structure first. Before generating, use
skeletonandsymbolsto understand the target type's fields and structure. Don't guess field names — read them from the AST. The generator needs an existing type with fields defined to work from. -
Batch independent generators. All generators targeting the same type are independent — run them in parallel. A batch of 8 generators completes in wall-clock time of the slowest single operation instead of 8 sequential calls with round-trip overhead.
-
Order: type → generate → logic. The base type with fields must exist first (generators need field definitions to work from). Run generators after the type exists. Write business logic last. For porting workflows: scaffold → batch generate → translate logic.
-
Preview before commit. Always preview generated code before applying, especially when running generators for the first time on a language you haven't verified.
-
Validate after generation. Run
diagnosticsafter committing a generation batch to catch any issues. Follow withimport_organizeto clean up any new imports. -
Don't generate what the language provides natively. Rust has derive macros (
#[derive(PartialEq, Hash, Debug)]). Python has dataclasses. C# has records. When the language has a native mechanism that provides the same functionality, prefer it. The generator is for languages that require explicit boilerplate. -
Generate tests last.
generate-testsshould run after all other boilerplate is in place — it needs to see the full API to produce useful stubs.
Available Generators
| Generator | What it Creates | Input |
|---|---|---|
generate-constructor |
Constructor from fields | Class/struct name |
generate-impl |
Interface/trait implementation stubs | Class + interface name |
generate-accessors |
Getters and setters | Class + field names |
generate-builder |
Builder pattern | Class/struct name |
generate-equals |
Equality comparison method | Class/struct name |
generate-hash |
Hash code method | Class/struct name |
generate-to-string |
String representation | Class/struct name |
generate-from-json |
JSON deserialization | Class/struct name |
generate-to-json |
JSON serialization | Class/struct name |
generate-tests |
Test stubs for methods | Class/function name |
generate-docstring |
Documentation comments | Symbol name |
generate-init |
__init__ method (Python) |
Class name |
generate-repr |
__repr__ method (Python) |
Class name |
generate-mapped-type |
Mapped type utilities (TypeScript) | Type name |
generate-type-guard |
Type guard function (TypeScript) | Type name |
generate-operator-overloads |
Operator overloads (C++, C#, Python) | Class name |
generate-rule-of-five |
Rule-of-five methods (C++) | Class name |
Batch Generation Pattern
When creating a new data model with full boilerplate, invoke generators in parallel for maximum speed. Each generator is independent — they can all run concurrently.
Example: Full data model boilerplate
Given a class file with fields already defined:
# These are independent — run in parallel (all at once)
act refactor generate-constructor User --file src/models/user.ts
act refactor generate-accessors User --file src/models/user.ts --fields name,email,age
act refactor generate-equals User --file src/models/user.ts
act refactor generate-hash User --file src/models/user.ts
act refactor generate-to-string User --file src/models/user.ts
act refactor generate-to-json User --file src/models/user.ts
act refactor generate-from-json User --file src/models/user.ts
act refactor generate-builder User --file src/models/user.ts
Then sequentially:
# After all generators complete, organize imports
act refactor import-organize --file src/models/user.ts
# Generate test stubs last (depends on generated methods)
act refactor generate-tests User --file src/models/user.ts
Why batch?
Each act invocation is fast (~50ms). But when called from an AI agent via MCP/shell, each invocation has overhead (tool call round-trip). Running 8 generators in parallel completes in wall-clock time of the slowest single operation (~100ms) instead of 8 sequential calls (~800ms + round-trip overhead).
For agents: When you need to generate multiple boilerplate methods for a class, invoke all independent generators in a single batch of parallel tool calls.
Common Recipes
New Service Class
- Write the minimal class with method signatures (the base type must exist for generators to target)
- Batch in parallel:
generate-impl ServiceClass IServiceInterface,generate-constructor ServiceClass generate-tests ServiceClass— create test stubsimport-organizeon the file
New DTO / Data Transfer Object
- Write the class with fields only (generators need the field definitions to work from)
- Batch in parallel:
generate-constructor,generate-accessors,generate-equals,generate-hash,generate-to-json,generate-from-json,generate-to-string generate-builderif the DTO has many fieldsgenerate-tests
New API Response Type
- Write the type with fields (generators need the field definitions)
- Batch in parallel:
generate-from-json,generate-to-json,generate-equals generate-tests
Post-Scaffold Boilerplate (Porting Integration)
When porting data types from another language (see code_porting skill):
- Scaffold the target-language type using
port scaffold(or write the type with fields manually) - Classify: data type → generators, business logic → LLM translation
- Batch in parallel: all applicable generators for the data type
- Validate with
diagnostics - Move on to business logic translation
This step produces 80–150 lines of correct, language-appropriate code per data type without consuming any LLM tokens.
When Other Skills Call This Skill
code_porting: After scaffolding a target file, classify each symbol. Data types get batch-generated here. Business logic gets LLM-translated.architectural_refactoring: After extracting interfaces at seams, usegenerate-implfor implementation stubs.code_refactoring: Afterextract-classcreates a new type, use generators to add boilerplate.
Language-Specific Recipes
See language-recipes.md for Python dataclass generation, Rust derive macros, Go struct methods, C# record patterns, and more.
Note: Language support is actively expanding. If a generator fails for a language, it may not yet be supported. Run
scripts/language-operation-matrix.shto check current status per language.