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
teeand posts inline PR annotations vianevermore 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-checkjob that tests whetherROBLOX_OPEN_CLOUD_API_KEYis set. If not, the main job is skipped (shows "Skipped" in GitHub UI) and a::noticeannotation 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.