LogoCyanPrint

Tutorial 1 - Blank Template

Create your first CyanPrint template from scratch

Tutorial 1: Blank Template

Create a minimal working template from scratch and test it with cyanprint try.

Prerequisites

  • Docker installed and running
  • CyanPrint CLI installed
  • Choose one runtime:
    • TypeScript: Node.js 18+ and Bun
    • Python: Python 3.11+ and pip
    • C#: .NET 8 SDK

Create project structure

mkdir my-first-template && cd my-first-template
mkdir -p cyan templates
echo "# My Project" > templates/README.md

Create cyan.yaml

cyan.yaml
username: myuser
name: my-first-template
description: My first CyanPrint template
build:
registry: docker.io
images:
blob:
image: myuser/my-first-template-blob
dockerfile: cyan/Dockerfile
template:
image: myuser/my-first-template
dockerfile: cyan/template.Dockerfile

Create template logic

Create cyan/index.ts:

cyan/index.ts
import { startTemplateWithFn, GlobType } from '@atomicloud/cyan-sdk';
startTemplateWithFn(async (i, d) => {
const name = await i.text('What is your project name?', 'myuser/my-first-template/name');
return {
processors: [{
name: 'cyan/default',
files: [{ root: 'templates', glob: '**/*', exclude: [], type: GlobType.Copy }],
config: { vars: { name } }
}]
};
});

Create cyan/package.json:

cyan/package.json
{
"name": "my-first-template",
"type": "module",
"dependencies": {
"@atomicloud/cyan-sdk": "latest"
}
}

Create cyan/Dockerfile and cyan/template.Dockerfile:

cyan/Dockerfile
FROM oven/bun:1.1.31
WORKDIR /app
LABEL cyanprint.dev=true
COPY package.json bun.lockb* ./
RUN bun install
COPY . .
CMD ["bun", "run", "index.ts"]

Install dependencies:

cd cyan && bun install && cd ..

Create cyan/index.py:

cyan/index.py
from cyanprintsdk import start_template_with_fn, GlobType
from cyanprintsdk.domain.core.cyan import Cyan, CyanProcessor, CyanGlob
async def my_template(i, d):
name = await i.text("What is your project name?", "myuser/my-first-template/name")
return Cyan(
processors=[
CyanProcessor(
name="cyan/default",
files=[
CyanGlob(root="templates", glob="**/*", exclude=[], type=GlobType.Copy)
],
config={"vars": {"name": name}}
)
]
)
start_template_with_fn(my_template)

Create cyan/requirements.txt:

cyan/requirements.txt
cyanprintsdk>=1.0.0

Create cyan/Dockerfile and cyan/template.Dockerfile:

cyan/Dockerfile
FROM python:3.11-slim
WORKDIR /app
LABEL cyanprint.dev=true
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "index.py"]

Install dependencies:

cd cyan && pip install -r requirements.txt && cd ..

Create cyan/Program.cs:

cyan/Program.cs
using sulfone_helium;
using sulfone_helium.Domain.Core;
CyanEngine.StartTemplate(args, async (i, d) =>
{
var name = await i.Text("What is your project name?", "myuser/my-first-template/name");
return new Cyan
{
Processors =
[
new CyanProcessor
{
Name = "cyan/default",
Files =
[
new CyanGlob
{
Root = "templates",
Glob = "**/*",
Exclude = [],
Type = GlobType.Copy
}
],
Config = new { vars = new { name } }
}
]
};
});

Create cyan/my-first-template.csproj:

cyan/my-first-template.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AtomiCloud.CyanPrint" Version="*" />
</ItemGroup>
</Project>

Create cyan/Dockerfile and cyan/template.Dockerfile:

cyan/Dockerfile
FROM mcr.microsoft.com/dotnet/sdk:8.0
WORKDIR /app
LABEL cyanprint.dev=true
COPY *.csproj .
RUN dotnet restore
COPY . .
CMD ["dotnet", "run"]

Install dependencies:

cd cyan && dotnet restore && cd ..

Test your template

cyanprint try template . ./test-output

This builds the Docker image, starts the coordinator, prompts for your questions, and generates the project.

Check the output:

cat ./test-output/README.md

Project Structure

cyan.yaml
index.ts
package.json
Dockerfile
template.Dockerfile
README.md

Key Concepts

PartDescription
startTemplateWithFnEntry point - starts template server on port 5550
iInquirer - ask user questions (text, select, etc.)
dDeterminism - access deterministic values
processorsList of file processors to run
PartDescription
start_template_with_fnEntry point - starts template server on port 5550
iInquirer - ask user questions (text, select, etc.)
dDeterminism - access deterministic values
processorsList of file processors to run
PartDescription
CyanEngine.StartTemplateEntry point - starts template server on port 5550
iInquirer - ask user questions (Text, Select, etc.)
dDeterminism - access deterministic values
ProcessorsList of file processors to run

GlobType.Copy copies files without variable substitution—perfect for static files.

Next Steps