JGen Chenile code generator

Using JGen

Releases and versions

JGen's own version line, which Chenile versions each release builds against and targets, and what changed in each release.

How JGen is versioned

JGen is released on its own cadence, separately from Chenile. Up to 2.1.35, JGen and Chenile shared a version number; from 2.5.1 on, JGen has its own.

  • Only released Chenile. A JGen release is built against a Chenile version that is already on Maven Central, never an unreleased one.
  • Generated projects target a released Chenile. The default chenileVersion in JGen’s configuration is the latest released Chenile. Change it with a config file (jgen -e myconfig, then -c). A blueprint that needs a newer Chenile declares sinceVersion and refuses an older chenileVersion.
  • jgen --version prints JGen’s version, the Chenile version generated projects target by default, and the Chenile version JGen was built with.
  • Maven coordinates: from 2.5.1, JGen’s libraries are published as org.chenile.jgen:jgen-base and org.chenile.jgen:jgen-ext-pebble. Standalone blueprints and extensions compile against these.
  • stm-cli is versioned and released separately too: see stm-cli.
JGen Built with Chenile Generates Chenile (default) Maven group Status
2.5.1 2.1.35 2.1.35 org.chenile.jgen in development
2.1.35 2.1.35 2.1.35 org.chenile released October 31, 2026

Install or upgrade with brew upgrade ajapros/jgen-tap/jgen, or see Install.

2.5.1 in development

Not released yet. The first JGen release on its own version line. It contains everything merged since 2.1.35.

Versioning and coordinates

  • Version line: JGen moves from 2.1.35 to 2.5.1. It is built with Chenile 2.1.35, and generated projects target Chenile 2.1.35 by default.
  • Maven coordinates: the libraries move from org.chenile:jgen-base to org.chenile.jgen:jgen-base (and org.chenile.jgen:jgen-ext-pebble). Standalone blueprints generated by jgen-blueprint use the new coordinates and the JGen version that generated them. Existing standalone blueprints should change their jgen-base dependency to org.chenile.jgen:jgen-base:2.5.1.
  • jgen --version now also shows both Chenile versions.
  • stm-cli is no longer built here. It has its own repository and releases, and installs from the same tap: brew install ajapros/jgen-tap/stm-cli. make all and setpath.sh in chenile-gen now cover JGen only.

new blueprints in their own Git repository

The jgen-blueprint blueprint has a new input, standaloneRepo. With y it generates a self-contained blueprint project and makes it a local Git repository on branch main with one commit, ready to push. The project has its own groupId and version, jgen-base as a provided dependency, a README, a .gitignore and a release workflow that attaches the jar to a GitHub release for jgen -g github:owner/repo. JGen prints the remaining steps: create the GitHub repository, add the remote, push, tag.

Every generated blueprint now also has a working starter template, a corrected init hook and a test that generates from it.

Blueprints get a fifth hook point, finalHook. It runs last, after the generation record is written, and suits work outside the file tree.

_DoT_ for dotfiles in templates

A new template convention: every _DoT_ in a file or folder name becomes a dot, so _DoT_gitignore is generated as .gitignore and _DoT_github/workflows as .github/workflows. Maven drops dotfiles from blueprint jars, so this is how a blueprint ships them. It runs right after __key__ placeholders (as the dot path tag, below). See the template reference.

GITHUB_REPOSITORY and PATTERN validation rules

Two new input validation rules:

  • GITHUB_REPOSITORY accepts owner/repo and follows GitHub’s naming limits. The jgen-blueprint blueprint now uses it for githubRepository, instead of a check in its hook.
  • PATTERN with pattern and patternMessage covers a format specific to one blueprint. The whole value must match, and the message is what users see. The pattern is checked when the blueprint loads.

Error messages for every rule now say what a valid value looks like. See input validation.

generated projects as Git repositories

Any blueprint can now have JGen make its output a local Git repository, with no code:

  • Turning it on: set the input initGit to true, either as a prompt or from a hook. JGen then runs git init on branch main, adds everything and makes one commit. This is a new pipeline step, git-initializer, which runs after the generation record is written.
  • Connecting to GitHub: a blueprint that names a GITHUB_REPOSITORY input in its new gitRepositoryField property also gets that repository as the origin remote, ready to push.
  • Remote style: SSH by default, or HTTPS when the config has gitRemoteProtocol set to https.
  • Commit message: gitCommitMessage sets it.
  • What it never does: create the GitHub repository or push.

jgen-blueprint now uses this feature for standalone blueprint projects.

Homebrew installs find their Java

The Homebrew formula depends on openjdk@25, which Homebrew does not put on the PATH. In 2.1.35 the jgen launcher only found Java through JAVA_HOME or the PATH. It now also looks in Homebrew’s openjdk@25 location, so brew install ajapros/jgen-tap/jgen works on a machine with no other Java.

template-only blueprints

A blueprint with no Java hooks no longer needs a jar. You lay out the repository like a jar’s resources (src/main/resources/META-INF/blueprint.json plus the template folder) and push a version tag.

  • Using it from GitHub: jgen -g github:owner/repo@tag downloads the source archive at that tag when the release has no blueprint jar, or when the tag has no release at all.
  • Trust and hashes: these work as for jars. The hash covers the blueprint’s files, so it stays stable if GitHub re-packs the tag.
  • Java hooks are refused: a descriptor that declares an initHook is rejected, because it needs Java classes. JavaScript hooks (below) are allowed.
  • Local folders: dir:<folder> uses a template-only blueprint from your disk while you write it.

See template-only blueprints.

blueprint catalogs

You can now use blueprints by short name: jgen -g terraform, terraform@1.2.0, or acme/terraform for a specific catalog. jgen --search [text] lists matches by name, description or tag.

  • Official catalog: ajapros/jgen-catalog is built in and searched first. Its entries are reviewed, so the sources it lists are trusted without a prompt.
  • Team catalogs: add your own in ~/.jgen/settings.json. They go through the normal trust prompt unless you mark them trusted.
  • Version pins: a catalog can pin versions to SHA-256 hashes, which JGen enforces.
  • Caching: catalogs are cached for an hour and work offline.
  • Installed blueprints still win: if a blueprint with the same name is installed, JGen uses it.

See blueprint catalogs.

blueprint hooks in JavaScript

Blueprint hooks can now be JavaScript files instead of Java classes. blueprint.json lists them under scripts, by hook name (postInputCapture, childBlueprintInputs, postProcess, final). JGen runs them with GraalJS, which ships inside JGen.

  • No build: a blueprint whose hooks are scripts is still a template-only blueprint, usable straight from GitHub, a catalog or dir:.
  • What scripts get: inputs as JSON, a jgen object with naming helpers and access to declared FILE inputs, and in postProcess and final a project object to read, write, move and delete files in the generated project.
  • Sandbox: no Java classes, no network, processes, threads or environment, no files outside the project, and a statement limit against runaway loops.
  • Checked early: scripts compile when the blueprint loads, so syntax errors and missing functions show up before any prompt.
  • Mixing: a script runs after a Java hook of the same kind.

See scripting hooks.

path tags, and adding your own

The rules for file and folder names (.filelist, __key__, _DoT_, %%key=value%%) used to be four separate pipeline steps. They are now path tags, applied in order by one step, path-tag-processor.

  • Same output: existing blueprints generate exactly what they did. The old step classes remain, deprecated, for anyone who built a chain of their own.
  • Conditional folders merge: a sub-folder of a %%key=value%% folder that already exists in the parent is now merged into it. It used to be silently dropped.
  • New tags without changing JGen: implement PathTag, list it in META-INF/services/org.chenile.jgen.template.tags.PathTag and drop the jar in the blueprints folder. Its order decides where it runs. Built-in tags can’t be replaced, and duplicate names are an error.
  • Regeneration: the generation record lists the extension tags that were active (in its extensions field), and jgen -r refuses to regenerate when one is missing.

See path tags.

extensions for other template and target languages

JGen can now be extended for very different uses without forking it. There are three extension points, all installed by dropping a jar in the blueprints folder (discovered with ServiceLoader):

  • Template engines. The render step picks the engine by file extension. Mustache stays built in, and a new module, jgen-ext-pebble, adds Pebble (.peb, Twig and Jinja syntax), which ships with the CLI and the portal. JGen’s Pebble doesn’t escape output, and a missing value renders as empty.
  • Language packs. Packs add validation rules and template helpers for a target language. Blueprints name a pack’s rules in validation like built-in ones. An unknown rule name is still rejected when the field is read. The built-in packs are:
    • python: PYTHON_MODULE, PYTHON_PACKAGE and PYPI_PROJECT;
    • node: NPM_PACKAGE and JS_IDENTIFIER.
  • Path tags, as described above.
  • Shared helpers. Template helpers now reach every engine and JavaScript hook: capitalize, uncapitalize, camelCase, pascalCase, snakeCase, upperSnakeCase and kebabCase, plus any pack’s. In Mustache they are lambdas ({{#snakeCase}}{{entity}}{{/snakeCase}}), and in Pebble filters.
  • requires. A blueprint lists the extensions it needs, with optional minimum versions ("pebble", "terraform@1.2"), and is refused when they are missing.
  • Records and regeneration. The generation record’s new extensions field lists the added extensions a project depended on, and jgen -r needs them installed.
  • Listing them. jgen --extensions lists everything installed.
  • Safety. Names are unique across all kinds, so built-ins can’t be replaced. Engines can’t share a file extension, and packs can’t redefine built-in rules or existing helpers.

See Extending JGen.

2.1.35

Released October 31, 2026, as part of Chenile 2.1.35. It brought:

  • one validator for blueprint inputs;
  • generation records and jgen -r;
  • blueprints from GitHub;
  • installs with Homebrew and JBang.

See the Chenile 2.1.35 release notes.

Earlier JGen versions were released with Chenile; see chenile.org release notes.