concept-scaffold-gen
ConceptScaffoldGen
Scaffold a concept spec for $ARGUMENTS with annotations, state declarations (groups, enums, records), typed action signatures, capabilities, and a register() action.
When to use: Use when creating a new concept specification from scratch. Generates a .concept file with annotations (@version, @category, @visibility, @gate), purpose, state (with groups, enum types, record types), actions with typed variants, invariants, capabilities block, and a register() action following Jackson's methodology.
Design Principles
- Singularity: Each concept serves exactly one purpose — if the purpose has 'and', it's two concepts.
- Independence: A concept never references another concept's types or calls another concept's actions. Use type parameters and syncs.
- Sufficiency & Necessity: Every state field is needed by at least one action. Every action serves the concept's purpose. No dead state.
- Invariant Completeness: Use all six invariant constructs comprehensively: example (named tests), forall (quantified properties), always (state predicates), never (safety), eventually (liveness), action requires/ensures (contracts). Cover core purpose, error paths, constraints, state transitions, and boundary conditions. Aim for 2-5 invariants per concept.
- Success is ok: The happy-path variant must always be named
ok. Do not use domain-specific success names likecreated,configured,registered,updated. Domain context belongs in the output fields. Exception: actions with multiple distinct success outcomes that syncs need to distinguish (e.g.,ok/missfor cache lookup,clean/conflictsfor merge). - Description Quality: Every variant description must explain the outcome in domain terms — never echo the variant name ('Created.') or use vague text ('Failed.'). Error variants explain what went wrong; ok variants explain what is now true.
Step-by-Step Process
Step 1: Register Generator
Self-register with PluginRegistry so KindSystem can track ConceptConfig → ConceptSpec transformations. Registration is also handled automatically by register-generator-kinds.sync.
Examples: Register the concept scaffold generator
const result = await conceptScaffoldGenHandler.register({}, storage);
Step 2: Preview Changes
Dry-run the generation using Emitter content-addressing to classify each output file as new, changed, or unchanged. No files are written.
Arguments: $0 name (string), $1 typeParam (string), $2 purpose (string), $3 stateFields (statefield[]), $4 actions (actiondef[]), $5 version (int?), $6 gate (bool?), $7 capabilities (string[])
Step 3: Generate Concept Spec
Generate a well formed . concept file with state declarations , typed action signatures , variant returns , and a register ( ) action for PluginRegistry discovery .
Arguments: $0 name (string), $1 typeParam (string), $2 purpose (string), $3 stateFields (statefield[]), $4 actions (actiondef[]), $5 version (int?), $6 gate (bool?), $7 capabilities (string[])
Checklist:
- Concept name is PascalCase?
- Type parameter is a single capital letter?
- Purpose block describes why, not what?
- State fields use correct relation types (set, ->, option, list)?
- Every action has at least one variant?
- register() action is included for PluginRegistry?
- Annotations (@category, @visibility) are present?
- @version annotation included if this is a versioned spec?
- State fields use enum types for fixed value sets?
- State groups organize related fields?
- Capabilities block present for generator/plugin concepts?
- Variant descriptions explain outcomes, not just echo variant names?
- All files written through Emitter (not directly to disk)?
- Source provenance attached to each file?
- Generation step recorded in GenerationPlan?
Examples: Generate a basic concept
clef scaffold concept --name User --actions create,update,delete
Generate with custom state
clef scaffold concept --name Article --param A --category domain
Generate with version and gate
clef scaffold concept --name Approval --version 2 --gate --capabilities search,export
Step 4: Edit the Concept Spec
Refine the generated .concept file: 1. Add annotations: @version(N) for versioning, @gate for async gates, @category("domain") for grouping, @visibility("public"|"internal"). 2. Write a purpose block explaining why the concept exists (not how it works). 3. Design state fields: sets (set T), mappings (T -> Type), option/list wrappers, enum types ({Active | Inactive | Pending}), record types ({key: String, value: String}), state groups for related fields. 4. Define actions with typed params and variant returns. All primitives: String, Int, Float, Bool, Bytes, DateTime, ID. 5. Write invariants comprehensively using all six constructs: example (named conformance tests), forall (quantified properties with given/in), always (state predicates), never (safety properties), eventually (liveness), action requires/ensures (contracts). Use property assertions (d.status = "complete") and when guard clauses. Aim for 2-5 invariants covering: core purpose, error paths, constraint enforcement, state transitions, boundary conditions. 6. Add capabilities block if the concept is a generator or plugin. 7. Add fixtures to every action. CRITICAL: error-case fixtures (names containing empty_, invalid_, duplicate_, missing_, bad_, etc.) MUST include an explicit -> error or -> <specific_variant> annotation. Omitting the arrow defaults to -> ok, generating wrong conformance tests. ok fixtures for non-creator actions need after chains to seed prerequisite data.
Step 5: Generate Tests from Invariants
After writing invariants, generate comprehensive tests using TestGen. Invoke /create-implementation --concept <Name> first to create the handler, then generate tests from invariants: 1. Run TestGen/generate (MCP: test_gen_generate) with concept_ref and language to compile all six invariant construct types into tests:
- example blocks → conformance test vectors (1:1 after/then mapping)
- forall blocks → property-based tests with generated domains
- always blocks → stateful sequence tests checking state predicates
- never blocks → violation-attempt tests trying to reach bad states
- eventually blocks → bounded liveness tests
- requires/ensures → contract-constrained PBT with pre/postconditions
- Review generated test files — they should NOT need manual editing for example/forall/always/never constructs. Contract tests (requires/ensures) may need manual generator tuning for complex domain types. 3. Run
TestGen/coverage(MCP:test_gen_coverage) to verify all invariant constructs have generated tests. Check the construct_coverage breakdown — each kind should show covered > 0. 4. Runnpx vitest run generated/tests/<concept>.*to verify generated tests pass. 5. If coverage gaps exist, add more invariants to the concept spec (go back to the edit step) and re-runTestGen/regenerate.
References
Supporting Materials
Quick Reference
| Input | Type | Purpose |
|---|---|---|
| name | String | PascalCase concept name |
| typeParam | String | Type parameter letter (default: T) |
| purpose | String | Purpose description |
| category | String | Annotation category (domain, devtools, etc.) |
| version | Int | @version annotation number |
| gate | Bool | @gate annotation for async gates |
| stateFields | list StateField | State declarations (with group, enum, record support) |
| actions | list ActionDef | Action signatures with variants |
| capabilities | list String | Capabilities block entries |
| invariants | list String | Invariant steps |
Anti-Patterns
Purpose describes implementation
Purpose block says how the concept works instead of why it exists.
Bad:
purpose {
Store users in a Map<string, User> and provide CRUD operations
via async handler methods.
}
Good:
purpose {
Manage user identity and profile information.
}
Missing variants
Action only has ok variant — no error handling path.
Bad:
action create(name: String) {
-> ok(user: U) { Created. }
}
Good:
action create(name: String) {
-> ok(user: U) { New user registered and ready for profile setup. }
-> duplicate(name: String) { A user with this name already exists. }
-> error(message: String) { Creation failed due to a storage or validation error. }
}
Terse or echo descriptions
Variant descriptions that echo the variant name or use a single generic word — they tell the reader nothing about the actual outcome.
Bad:
action create(name: String) {
-> ok(user: U) { Created. }
-> error(message: String) { Failed. }
}
Good:
action create(name: String) {
-> ok(user: U) { New user registered and ready for authentication setup. }
-> error(message: String) { Creation failed due to a storage or validation error. }
}
Validation
Generate a concept scaffold:
npx tsx cli/src/index.ts scaffold concept --name User --actions create,update,delete
Validate generated concept:
npx tsx cli/src/index.ts check specs/app/user.concept
Generate tests from invariants:
npx tsx cli/src/index.ts test-gen --concept User --language typescript
Run generated invariant tests:
npx vitest run generated/tests/User.*
Check invariant coverage:
npx tsx cli/src/index.ts test-gen --coverage --concept User
Run scaffold generator tests:
npx vitest run tests/scaffold-generators.test.ts
Related Skills
| Skill | When to Use |
|---|---|
/concept-designer |
Design concepts using Jackson's methodology before generating |
/create-handler |
Generate handler implementations for the concept |
/create-sync |
Generate sync rules connecting the concept |
/test-gen |
Generate tests from invariants (TestGen/generate, TestGen/coverage) |
/create-view-query |
For view-layer concepts, compose with QueryProgram/FilterSpec/SortSpec instead of ad-hoc data fetching |
More from itshalffull/concept-oriented-programming-framework
handler-scaffold-gen
Generate TypeScript concept handler ( . handler . ts ) implementation scaffolds from provided configuration including concept name , action signatures , and storage patterns . Defaults to functional ( StorageProgram ) style ; falls back to imperative style only when explicitly requested . Optionally generates a conformance test file
9project-scaffold
Initialize new Clef projects with the standard directory structure , example concept specs , and configuration files
1suite-scaffold-gen
Generate suite manifest ( suite . yaml ) scaffolds and directory structures for new Clef suites from provided configuration
1deploy-scaffold-gen
Generate deployment manifest ( deploy . yaml ) scaffolds from provided configuration including runtimes , concepts , and infrastructure settings
1sync-scaffold-gen
Generate synchronization rule ( . sync ) file scaffolds from provided configuration including trigger patterns , guard conditions , and effect actions
1deployment-validator
Parse and validate deployment manifests against compiled concepts and syncs . Produce deployment plans with transport assignments , runtime mappings , and sync to engine bindings
1