Skip to main content

Template Conventions

Generated and templated files (Luau scripts, Rojo projects, etc.) follow a consistent layout across CLI tools.

Directory layout

All template files live in a templates/ directory at the root of the tool package that owns them:

tools/nevermore-cli/templates/
batch-test-runner.luau # Batch test execution script
game-template/ # Game scaffolding
nevermore-library-package-template/ # Package scaffolding
nevermore-service-package-template/ # Service package scaffolding
plugin-template/ # Plugin scaffolding

tools/studio-bridge/templates/ # Studio bridge plugin template

Placeholder pattern

Templates use {{PLACEHOLDER}} syntax for values filled in at runtime. The double-brace pattern is distinct from Lua/Luau syntax, making placeholders easy to find and unlikely to collide with real code.

Example from batch-test-runner.luau:

local packageSlugs = {{PACKAGE_SLUGS}}

Replaced at runtime with:

local packageSlugs = { "maid", "blend", "roguehumanoid" }

Resolving template paths

Use resolveTemplatePath from @quenty/nevermore-template-helpers to resolve template paths at runtime. It finds the calling package's root (via package.json) and appends templates/<name>:

import { resolveTemplatePath } from '@quenty/nevermore-template-helpers';

const templatePath = resolveTemplatePath(import.meta.url, 'batch-test-runner.luau');

This works regardless of where the compiled JS ends up relative to the source.

CI workflows

Game and plugin templates include GitHub Actions workflows for linting, testing, and deployment. These use npx @quenty/nevermore-cli (not building from source) since the CLI is published to npm as a public package.

  • Linting — Each linter job pipes output through tee and posts inline PR annotations via nevermore tools post-lint-results. Since templates have node available in every job, annotations are posted inline (no artifact relay needed).
  • Tests / Deploy — These workflows use a config-check job that tests whether ROBLOX_OPEN_CLOUD_API_KEY is set. If not, the main job is skipped (shows "Skipped" in GitHub UI) and a ::notice annotation explains setup. This means newly scaffolded projects have zero failing workflows until the user deliberately enables testing/deploy.

All ${{ }} GitHub Actions expressions are written as $\{{ }} in template files to prevent Handlebars from interpreting them during scaffolding.