LogoCyanPrint
Plugins

Plugin Development

Create post-processing plugins for CyanPrint templates

Plugin Development

Plugins run after file generation, enabling post-processing like running commands or modifying files. While processors transform file content, plugins perform operations on the generated project.

What is a Plugin?

A plugin is a Docker container that:

  1. Receives directory containing all generated files
  2. Runs operations on the directory (commands, file modifications)
  3. Returns directory path for the next step

Plugins are the final step in the generation pipeline - they run after all processors have completed.

Plugin Architecture

Components

ComponentPurposeExamples
Entry PointPlugin logicStartPluginWithLambda
CyanPluginInputInput from systemDirectory, config
PluginOutputReturn valueDirectory path
Shell/BunCommand execution$ from bun, exec

What Plugins Can Do

Plugins have full access to the generated project directory:

CapabilityExample
Initialize gitgit init, git add .
Install dependenciesnpm install, bun install
Run formattersprettier --write ., biome format .
Set up hookshusky install
Create symlinksLink config files
Build stepsnpm run build
File modificationsEdit generated files

Plugins are the only component that can execute shell commands. Processors are stateless file transformers only.

Learning Path

Start Here: Tutorials

Build your first plugin step by step:

How-To Guides

Task-oriented guides for common scenarios:

View all How-To Guides

Reference

Technical documentation for the SDK:

View all Reference Docs

Explanation

Deep dives into plugin concepts:

View all Explanations

Quick Example

Here's a minimal plugin that initializes git and installs dependencies:

import { StartPluginWithLambda } from '@atomicloud/cyan-sdk';
import { $ } from 'bun';
StartPluginWithLambda(async (input) => {
const { directory, config } = input;
const cfg = config as { installDeps?: boolean };
// Initialize git repository
await $`git -C ${directory} init`.quiet();
// Optionally install dependencies
if (cfg.installDeps) {
await $`cd ${directory} && npm install`.quiet();
}
return { directory };
});
import asyncio
import subprocess
from cyanprintsdk.plugin import start_plugin_with_fn
from cyanprintsdk.protocol import PluginInput, PluginOutput
async def run_plugin(input: PluginInput) -> PluginOutput:
cfg = input.config or {}
directory = input.directory
# Initialize git repository
subprocess.run(['git', 'init'], cwd=directory, capture_output=True)
# Optionally install dependencies
if cfg.get('installDeps'):
subprocess.run(['npm', 'install'], cwd=directory, capture_output=True)
return PluginOutput(directory=directory)
plugin_main = start_plugin_with_fn(run_plugin)
using CyanPrintSDK;
using System.Diagnostics;
public static class Plugin
{
[PluginMain]
public static async Task<PluginOutput> Run(PluginInput input)
{
var cfg = input.Config;
var directory = input.Directory;
// Initialize git repository
await RunCommand("git", "init", directory);
// Optionally install dependencies
if (cfg.TryGetValue("installDeps", out var installDeps) && installDeps == "true")
{
await RunCommand("npm", "install", directory);
}
return new PluginOutput { Directory = directory };
}
private static Task RunCommand(string cmd, string args, string cwd)
{
var psi = new ProcessStartInfo(cmd, args) { WorkingDirectory = cwd };
Process.Start(psi)?.WaitForExit();
return Task.CompletedTask;
}
}

Next Steps