Public blueprints collection of Puppetflow flows and snippets, consumed by the in-app store via GitHub.
blueprints/
├── scaffold.js
└── blueprints/
└── [service]/
├── metadata.json # title, namespace, icon, author
├── icon.png # 128×128 px
├── flows/
│ └── [reference].js or [reference].json
└── snippets/
└── [reference].js or [reference].json
- Service: service or domain name (
salesforce,gmail,linkedin...) - Namespace: variable-style identifier, lowercase letters, digits, and underscores. It must not start with a digit.
- Reference: filename without
.js, valid JS identifier (e.g.scrapeProfile) - Title:
// @titleheader in each flow/snippet file - Description:
// @descriptionheader in each flow/snippet file
{
"title": "My Service",
"namespace": "my_service",
"description": "Short description shown in the store",
"category": "scraping",
"color": "green",
"icon": "icon.png",
"author": {
"name": "Your name",
"homepage": "https://yoursite.com"
}
}author and color are optional. title, namespace, description, category, and icon are required. namespace must match ^[a-z_][a-z0-9_]*$. category must be one of: auth, scraping, files, notifications, data. color can be one of green, blue, cyan, purple, pink, orange, amber, slate, white, or a custom six-digit hex color such as #ff4d8d.
Every .js file must start with @title and include @description before the code:
// @title Scrape LinkedIn profile data
// @description Extracts public profile details from a LinkedIn page.
// @input profileUrl [string]: "https://www.linkedin.com/in/example"
// @input includePosts [boolean]: true
// @input maxPosts [number]
async function run($page, $input) { ... }Every Nodal .json flow must contain metadata.title and metadata.description before its graph:
{
"metadata": {
"title": "Scrape LinkedIn profile data",
"description": "Extracts public profile details from a LinkedIn page."
},
"graph": {
"nodes": [],
"edges": []
}
}Declare flow inputs in the leading comment header with:
// @input name [type]: default
namemust be a valid JavaScript identifier.typemust bestring,number,boolean,array,object,null,channel,mailbox-watcher, orai-model.- The default value is optional. A
stringinput without a default is imported as""; other types usenull. - String defaults can be plain text or JSON strings. Array and object defaults must be valid JSON.
- A
nullinput accepts either no default or the explicitnullvalue. - Imported declarations are added automatically to the flow's Flow Inputs.
- Downloads regenerate these declarations from Flow Inputs.
${vars.KEY}references are resolved before export, including secret variables available to the user downloading the flow. Resolved values are written to the downloaded file in plaintext.
Examples:
// @input username [string]: "john@example.com"
// @input retries [number]: 3
// @input enabled [boolean]: true
// @input tags [array]: ["billing", "monthly"]
// @input options [object]: {"includeArchived": false}
// @input model [ai-model]
// @input password [string]
// @input optionalValue [null]: nullFor a Nodal JSON flow, place the same definitions in metadata.inputs:
{
"metadata": {
"title": "Example flow",
"description": "Example Nodal flow.",
"inputs": [
{"name": "username", "type": "string", "default": "john@example.com"},
{"name": "retries", "type": "number", "default": 3},
{"name": "password", "type": "string"},
{"name": "optionalValue", "type": "null", "default": null}
]
},
"graph": {
"nodes": [],
"edges": []
}
}Library flows and snippets can call another snippet from the same blueprint without knowing its installed ID. Use the snippet's catalog convention:
$$<namespace>_<reference>(...)
namespaceis the value from the blueprint'smetadata.json.referenceis the snippet filename without its extension. It is case-sensitive.- The snippet title or label is not used as its reference.
- Characters outside letters, digits, and underscores are converted to underscores when the convention is resolved.
For example, blueprints/metabase/snippets/MetabaseLoginCode.js is referenced from another Metabase item with:
await $$metabase_MetabaseLoginCode(username, password);When imported from the library store, Puppetflow automatically installs the required snippets and replaces symbolic references with their generated IDs. Existing compatible snippets are reused. This resolution also applies to library updates, but not to standalone file imports.
# Validate all blueprints (exit 1 on errors, hook into CI)
npm run validate
# Create a new service
npm run new:service <name>
# Add a flow or snippet to an existing service
npm run new:flow <service> <reference>
npm run new:snippet <service> <reference>- Service name and reference in
kebab-case -
icon.pngprovided (128×128 px) - First line is a descriptive comment (
// ...) - No credentials or secrets in the code
- Tested before merge
-
npm run validatepasses with no errors
