PluginsReference
Plugin Project Structure
Standard directory layout for plugin projects
Plugin Project Structure
A typical plugin project has a simple structure:
index.ts
package.json
bun.lockb
tsconfig.json
Dockerfile
.dockerignore
.gitignore
cyan.yaml
README.md
Always commit bun.lockb to ensure reproducible builds across environments.
Required Files
index.ts
The entry point containing plugin logic:
index.ts
import { StartPluginWithLambda } from '@atomicloud/cyan-sdk';StartPluginWithLambda(async (input) => {const { directory, config } = input;// Plugin logic herereturn { directory };});
main.py
from atomicloud_cyan_sdk import start_plugin_with_fn, PluginInput, PluginOutput@start_plugin_with_fnasync def main(input: PluginInput) -> PluginOutput:directory = input.directoryconfig = input.config# Plugin logic herereturn {'directory': directory}
Plugin.cs
using Atomicloud.Cyan.Sdk;[PluginMain]public static class Plugin{public static async Task<PluginOutput> Main(PluginInput input){var directory = input.Directory;var config = input.Config;// Plugin logic herereturn new PluginOutput { Directory = directory };}}
package.json
Dependencies for the plugin:
package.json
{"name": "my-plugin","module": "index.ts","type": "module","devDependencies": {"bun-types": "latest"},"peerDependencies": {"typescript": "^5.0.0"},"dependencies": {"@atomicloud/cyan-sdk": "latest"}}
Dockerfile
Container definition:
Dockerfile
FROM oven/bun:1.0.11WORKDIR /appLABEL cyanprint.dev=trueCOPY package.json .COPY bun.lockb .RUN bun installCOPY . .CMD [ "bun", "run", "index.ts" ]
Optional Files
.dockerignore
Exclude unnecessary files from the Docker build:
.dockerignore
node_modules.idea.vscode
README.md
Documentation for your plugin:
README.md
# My PluginDescription of what the plugin does.## Configuration| Option | Type | Default | Description ||--------|------|---------|-------------|| `option1` | `boolean` | `true` | Description |## Usageplugins:- name: org/my-pluginconfig:option1: false
cyan.yaml
Plugin metadata file:
cyan.yaml
username: your-usernamename: my-plugindescription: A plugin that does somethingproject: https://example.comsource: https://example.comtags: []readme: README.md
Multiple Files
For complex plugins, organize code into multiple files:
index.ts
git.ts
npm.ts
files.ts
package.json
bun.lockb
tsconfig.json
Dockerfile
index.ts
index.ts
import { StartPluginWithLambda } from '@atomicloud/cyan-sdk';import { initGit } from './lib/git';import { installDeps } from './lib/npm';import { createFiles } from './lib/files';import type { PluginConfig } from './types/config';StartPluginWithLambda(async (input) => {const { directory, config } = input;const cfg = config as PluginConfig;await initGit(directory, cfg);await installDeps(directory, cfg);await createFiles(directory, cfg);return { directory };});
main.py
from atomicloud_cyan_sdk import start_plugin_with_fn, PluginInput, PluginOutputfrom lib.git import init_gitfrom lib.npm import install_depsfrom lib.files import create_files@start_plugin_with_fnasync def main(input: PluginInput) -> PluginOutput:directory = input.directoryconfig = input.configawait init_git(directory, config)await install_deps(directory, config)await create_files(directory, config)return {'directory': directory}
Plugin.cs
using Atomicloud.Cyan.Sdk;using System.Text.Json;[PluginMain]public static class Plugin{public static async Task<PluginOutput> Main(PluginInput input){var directory = input.Directory;var config = JsonSerializer.Deserialize<PluginConfig>(input.Config.ToString());await GitHelper.InitGit(directory, config);await NpmHelper.InstallDeps(directory, config);await FileHelper.CreateFiles(directory, config);return new PluginOutput { Directory = directory };}}
lib/git.ts
lib/git.ts
import { $ } from 'bun';export async function initGit(directory: string, config: { git?: boolean }) {if (config.git) {await $`git -C ${directory} init`.quiet();await $`git -C ${directory} add .`.quiet();}}
lib/git.py
import subprocessasync def init_git(directory: str, config: dict):if config.get('git'):subprocess.run(['git', '-C', directory, 'init'], capture_output=True)subprocess.run(['git', '-C', directory, 'add', '.'], capture_output=True)
GitHelper.cs
using System.Diagnostics;public static class GitHelper{public static async Task InitGit(string directory, PluginConfig config){if (config?.Git == true){Process.Start("git", $"-C {directory} init")?.WaitForExit();Process.Start("git", $"-C {directory} add .")?.WaitForExit();}}}