Skip to content

Creating a bluprint

A bluprint is any GitHub repo with a bluprint.config.ts at its root. Create one with:

Terminal window
bluprint new

The config is authored with defineConfig, which gives you full type-checking and autocomplete on every option:

bluprint.config.ts
import { defineConfig } from '@reuters-graphics/bluprint';
export default defineConfig({
name: 'My bluprint',
bluprint: '^1.0.0',
files: ['**/*'],
ignores: [],
actions: [],
});

The bluprint’s display name in the CLI. Either a string, or an object with a hint shown beside it in the picker:

name: 'Svelte blog';
name: {
title: 'Svelte blog',
hint: 'SvelteKit + Markdown posts',
}

Globs for which files to scaffold, relative to the repo root. Use ['**/*'] for everything.

files: ['src/**/*', 'package.json', 'README.md'];

Globs to exclude from files. (Files git already ignores are never scaffolded.)

ignores: ['**/*.test.ts', 'internal/**'];

A semver range for the CLI version your bluprint needs. The CLI warns on a mismatch and refuses to run if it’s too old — a safety net when your actions rely on newer features.

bluprint: '^1.0.0';

An array of actions that transform the scaffolded files, run in order. Actions are functions you import from the package:

import {
defineConfig,
prompt,
render,
execute,
} from '@reuters-graphics/bluprint';
export default defineConfig({
name: 'My bluprint',
files: ['**/*'],
ignores: [],
actions: [
prompt({ name: 'projectName', type: 'text', message: 'Project name?' }),
render({ files: ['README.md', 'package.json'] }),
execute('pnpm install', { silent: true }),
],
});

See the Actions guide.

Named subsets of your bluprint a user can scaffold on their own — each with its own files/ignores and optional actions:

parts: {
config: {
title: 'Config files',
hint: 'Just the linters + tsconfig',
files: ['.eslintrc.js', '.prettierrc', 'tsconfig.json'],
ignores: [],
},
}

See the Parts guide.

Actions share a context that prompt and run add values to. By default those custom values are typed unknown. Pass a type argument to defineConfig describing them, and every action’s when, run, and editor callback is typed against it — ctx.projectName autocompletes, narrows, and catches typos:

import { defineConfig, prompt, render } from '@reuters-graphics/bluprint';
interface Context {
projectName: string;
includeCms: boolean;
}
export default defineConfig<Context>({
name: 'Svelte blog',
files: ['**/*'],
ignores: [],
actions: [
prompt({ name: 'projectName', type: 'text', message: 'Project name?' }),
prompt({ name: 'includeCms', type: 'confirm', message: 'Add a CMS?' }),
render({
files: ['svelte.config.js'],
when: (ctx) => ctx.includeCms, // ✅ boolean, not unknown
}),
],
});

The built-in DefaultContext keys (year, dirname, …) are always present on top of what you declare.

A run action’s ctx is typed too, and the object it returns must match keys you’ve declared — so values it contributes are type-safe in later actions. Declare those keys on your Context:

interface Context {
projectName: string;
slug: string; // contributed by the run action below
}
export default defineConfig<Context>({
name: 'Svelte blog',
files: ['**/*'],
ignores: [],
actions: [
prompt({ name: 'projectName', type: 'text', message: 'Project name?' }),
run((ctx) => {
// ctx.projectName is typed; the return must be a Partial<Context>.
return { slug: ctx.projectName.toLowerCase().replace(/\s+/g, '-') };
}),
// Later actions read ctx.slug as a string.
render({ files: ['package.json'] }),
],
});

There’s no publish step. Commit bluprint.config.ts, push to GitHub, and the bluprint is ready — the CLI always pulls the latest from the repo.