Use when defining or modifying MPS generators — author a generator module, add or edit root/reduction/weaving/pattern mapping rules, attach template macros ($COPY_SRC, $LOOP, $IF, $PROPERTY, $REF, $SWITCH, $MAP_SRC, $WEAVE, $INSERT, $LABEL, $TRACE, $VAR), wire mapping labels, build template switches, write pre/post mapping scripts, navigate `genContext`, or debug "rule didn't fire", missing references, empty output, infinite reduction loops, and generated-Java compile failures.
78
100%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
A generator transforms models written in the source language into models of one or more target languages (usually BaseLanguage or another DSL). It is a separate MPS module — a generator module — owned by the language and driven by templates: target-language code snippets annotated with macros.
A generator translates from the problem domain (source language) toward the implementation domain, often as a cascade: each generator lowers the abstraction level by producing its target language, which becomes the next generator's input, until a base language (usually BaseLanguage) is reached and TextGen emits plain text.
A generator definition has a stable part and a variable part:
Solution the language declares as a runtime module — as MPS-authored source or a bundled JAR), not as a template.Idiomatic generators keep the stable part out of the templates and emit thin code that calls into the runtime solution. Before adding rules, decide how much is stable: see the architecture ladder in references/cookbook.md and the stable-vs-variable split + wiring in mps-aspect-accessories/references/runtime-solutions.md (worked example: the Kaja language + its JavaKaja runtime).
source_gen/. If a bug appears in generated Java, the fix almost always belongs in a template, macro body, or concept behavior. Patch generated output only when explicitly told to.applicableConcept must be a structure-model node ref (r:<modelUUID>(<lang>.structure)/<nodeId>), never the c:<langUUID>/<conceptId> form. Wrong form → silent Unresolved reference: c:.... See references/rule-consequences.md.TemplateDeclaration used as a reduction target requires at least one TemplateFragment on the produced subtree, or the rule fires and emits nothing.references/module-structure.md). Adding a class to the wrong one yields "cannot resolve" in generated Java or unusable concepts in templates.smodelAttribute child role, and co-located macros are chained in child order — order is semantics. $IF$ before $LOOP$ gates the whole loop in the outer context; $LOOP$ before $IF$ evaluates the condition per iteration. The $LOOP$ + $COPY_SRC$ pair is order-insensitive only because $COPY_SRC$ is terminal — don't generalize. See references/macro-catalog.md.DismissTopMappingRule, a marker subconcept, or $COPY_SRC$.mps_mcp_get_project_structure(moduleKind="Language") and find yours by name: each language entry carries a generators array (unconditional — not gated on includeDependencies) listing every owned generator's name and reference. Prefer this over startingPoint="<language-name>" — a language and its owned generator share a base name, so a name starting point can resolve to the generator module instead, and then the generators array is never emitted. (If you already hold the language's persistent reference, startingPoint="<reference>" resolves by id and is also unambiguous.) To go the other direction, each generator entry carries a sourceLanguage field (only when includeDependencies=true) with the owning language's name and reference; follow it with mps_mcp_get_project_structure(startingPoint="<sourceLanguage.reference>", includeModels=true). If no generator exists yet: mps_mcp_create_module(type="generator", parentLanguage="<lang>").template/main@generator.mps (the generator model stereotype — name@generator; see aspect-model-stereotypes.md for all model identifiers), add the used languages you target (jetbrains.mps.devkit.templates is the quickest umbrella) and ensure the target language is also a module generate-into dependency on the language .mpl (see references/module-structure.md).MappingConfiguration root (mps_mcp_create_root_node with the FQN in references/concept-fqns.md).Root_MappingRule for whole-root mapping;Reduction_MappingRule for in-place rewrites (inline RuleConsequence or TemplateDeclarationReference);Weaving_MappingRule to add content into an already-generated container.smodelAttribute children. Mark the produced subtree with TemplateFragment (or RootTemplateAnnotation on a target root).
RootTemplateAnnotation alone does NOT register a root mapping. It only marks a target root as a template; a Root_MappingRule (step 4) whose template reference points to that annotated root is also required. Without the rule, generation silently produces no output for that root — MAKE still reports success.MappingConfiguration; tag writers (labelDeclaration ref or $LABEL$ macro); read with genContext.get/pick output <label> for (<input>) inside $REF$ or other queries.mps_mcp_check_root_node_problems on the MappingConfiguration and every template (re-run with onlyNodesWithProblems = false if siblings look "missing").mps_mcp_alter_nodes MAKE over the generator and a sample model; read the generated text (see Reading generator output below). Use the Generator Tracer / $TRACE$ macros to bisect misgenerated fragments.If MPS MCP tools are unavailable, do not hand-edit serialized .mps files unless explicitly asked — inspect only and report.
After a MAKE, generators write Java (and TextGen artifacts like .xml, .scxml) to the owning module's source_gen/ directory. No mps_mcp_* tool reads this output — but the MPS MCP server exposes the same generic IDE file tools, so generated text is readable over MCP today. Don't drop to a raw shell find/cat.
Path convention. Output lands at <module-dir>/source_gen/<model-namespace>/<java-package>/<File>.java, where the model namespace's dots become directory separators. Example: model Kaja.sandbox in solution Kajak.sandbox → samples/robot_Kaja/solutions/Kajak.sandbox/source_gen/Kaja/sandbox/sandbox/Karel.java (trailing sandbox/ is the Java package). TextGen artifacts (.scxml, etc.) follow the same layout. A module may override its output root, so if source_gen/ is not beside the module descriptor, check the module's output path.
Tools. Use the generic IDE file tools (exposed by the MPS MCP server, also by IDEA's; pass projectPath to disambiguate) — not mps_mcp_*:
find_files_by_glob — discover what was generated, e.g. project-root-relative **/Kajak.sandbox/source_gen/**/*.java. Note this matches only .java; use list_directory_tree to also see TextGen artifacts (.scxml, trace.info, …).list_directory_tree — browse the output directory.read_file — read a specific generated file (output is line-capped; use its max_lines/start_line args for large files).Staleness. On-disk source_gen/ reflects the last MAKE. Re-run MAKE before reading so the output matches the current model, otherwise you may read stale text.
mps-aspect-generation-plan — priorities, checkpoints, plan contributions; pair this with priority-ordering questions.mps-aspect-textgen — converting the final model to plain text (last pipeline stage).mps-aspect-behavior — put non-trivial per-concept logic in behavior methods called from macros.mps-model-manipulation — smodel-access idioms (SPropertyAccess, SLinkAccess, Node_GetChildrenOperation) inside query bodies.mps-quotations — quotation/anti-quotation syntax for building nodes inside $INSERT$ and $MAP_SRC$.mapperFunction.mps-baselanguage — host language for macro query bodies and RulesFunctions_* helpers.references/module-structure.md — read when setting up a generator or fixing "cannot resolve"/missing-concept issues.TemplateDeclarationReference, Inline*, AbandonInput, DismissTop) + the critical applicableConcept ref-form gotcha: references/rule-consequences.md.references/macro-catalog.md — read before attaching any macro.$MAP_SRC$ in depth (replace input, mapperFunction, postMapperFunction, label-on-site): references/macro-map-src.md.$REF$ / ReferenceMacro in depth (label-based and name-based forms, return types): references/macro-reference.md.$WEAVE$, $VAR$, $TRACE$, $LABEL$, $INSERT$: references/macros-rare.md.IfMacro_Condition, SourceSubstituteMacro_*, etc.): references/query-bodies.md.get vs pick vs get list: references/mapping-labels.md.contextNodeQuery, when to use vs. reductions: references/weaving-rules.md.extends across generator modules: references/template-switches.md.references/pattern-rules.md.modifiesModel: references/mapping-scripts.md.references/utility-models.md.genContext operations catalog (every GenerationContextOp_* with editor alias and purpose): references/generation-context.md.references/algorithm.md.references/cookbook.md.references/common-failures.md.MappingConfiguration blueprint: references/concept-fqns.md.RulesFunctions_*, utility models: references/calling-into-generator.md.52c9d63
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.