Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Community registry

The template registry has two tiers in one repo, behind one trust gate (PR review into master):

  • builtin — the first-party set, compiled into the binary (offline bootstrap; everything on the registry page).
  • community — packages under templates/community/ at the repo root. They are not in the binary: the CLI discovers and installs them over the GitHub API, so a template merged today is installable by every rflow binary already in the wild.
rflow templates ls --community                    # the remote index
rflow new --template community/large-approval-alert
rflow add workflow community/large-approval-alert

The interactive rflow new picker also ends with a "community template (fetched from the registry)" entry that fetches the index and lists the community ids.

The trust model

Distribution is pinned, never live — trust never attaches to a branch, only to reviewed, hashed content:

  1. PR-reviewed. The only way into the registry is a PR merged into master. A community package is reviewable by construction: manifest, typed inputs, YAML templates and (surface-verified) ABI files — no code, no hooks.
  2. SHA-pinned. Every install resolves the branch to a COMMIT first, then fetches index.json and every package file at that commit (raw.githubusercontent.com/<owner>/<repo>/<commit>/…). A force-pushed or rewritten history cannot change what anyone installs.
  3. Hash-verified. index.json pins a sha256 for EVERY file of every package (snapshots and READMEs included). Each downloaded byte is re-hashed before it is kept; a mismatch aborts the install and keeps nothing. Verified downloads are cached (~/.rflow/cache, override with RFLOW_CACHE_DIR) and re-hashed on every use — a tampered cache file is re-downloaded, never trusted. Set GITHUB_TOKEN to raise the API rate limit.
  4. Immutable versions. CI refuses any change to a published package's files without a template_version bump — and enforces the same rules against the base branch, so regenerating index.json inside a PR cannot smuggle in a rewrite. Version downgrades fail. Removing an id fails: templates retire via deprecated: true in the manifest (still installable, labeled in ls/show, installs with a warning).
  5. The full local gate re-runs at install. Before anything renders, the installing CLI runs the community doctor profile, verifies every declared interface surface, and prints a provenance banner (registry, commit, risk, author). Merged review is necessary, not sufficient — your own binary re-proves the package.

Install UX

community/<id> is explicit; a plain id that no builtin claims also falls back to the community index. Builtin names are reserved — a community package can never shadow one. Every community install prints its provenance before rendering:

community template 'large-approval-alert' v1.0.0 (risk: monitor_only)
  registry: github:joshstevens19/rflow@master
  commit:   3f2a9c…
  author:   rflow maintainers

Forks and private registries

--registry github:owner/repo[@branch] points the SAME mechanism at any fork — the org-internal/private sharing story with zero extra machinery:

rflow templates ls --community --registry github:acme/rflow-templates
rflow new --template community/acme-vault-alert --registry github:acme/rflow-templates

Non-default registries are loudly labeled UNTRUSTED — nothing in them was reviewed by the rflow maintainers — and require an explicit confirmation (--yes in scripts, a prompt on a TTY).

Lock provenance

Community installs extend .rflow/template-lock.yaml with the full provenance — what was installed, from where, pinned to which commit, hashing to what:

templates:
  - id: large-approval-alert
    template_version: 1.0.0
    rflow_version: 0.1.0
    installed_at: "2026-08-08T12:00:00Z"
    answers:
      network: ethereum
      # …
    source: community
    registry: github:joshstevens19/rflow@master
    commit: 3f2a9c1d…
    files:
      template.yaml: 6797d64b…   # sha256 per packaged file
      rflow.yaml.tmpl: bc7c730b…

Builtin installs keep the exact pre-community entry shape — none of the new keys appear.

Declared interfaces

A template bundling an opaque ABI blob is unreviewable — and a poisoned ABI encodes different calldata. interfaces: in template.yaml fixes that: the manifest declares the EXACT function/event signatures the workflows use, and whatever the ABI source yields must carry those signatures (checked by recomputed selectors and topic0s) or the template fails doctor and refuses to install.

interfaces:
  token:
    abi:
      wellknown: erc20            # curated builtin standard - ships NO blob;
    functions: []                 # the install materializes abis/token.json
    events:
      - "Approval(address,address,uint256)"
 
  pool:
    abi:
      fetch:                      # resolved at install time from TYPED inputs
        address_from: pool_address   # an input of type address
        network_from: network        # an input of type network
    functions:
      - "getUserAccountData(address)"
 
  settlement:
    abi:
      file: settlement            # bundled abis/settlement.json - acceptable
    functions:                    # ONLY because it is machine-verified
      - "fill(bytes32,bytes,bytes)"
    events:
      - "Open(bytes32,(address,uint256))"

Exactly one source per interface — wellknown: (curated builtin standards: erc20 and friends), fetch: (from typed address/network inputs, never literals), or file: (a bundled blob, verified against the declaration). fetch:/file: interfaces must declare a non-empty surface — an unverifiable declaration is refused.

endpoints: declares HTTP egress the same way — a fixed host: or a host_from: input, plus which requires.secrets entry travels there:

endpoints:
  report:
    host_from: report_host
    secret: REPORT_HMAC

rflow templates show <id> prints the complete call + egress surface before anything installs.

Submitting a template

The process is deliberately boring, like an EIP — one directory, one PR, one mechanical review:

# 1. scaffold a compliant skeleton (inside a checkout of the rflow repo)
rflow templates scaffold my-vault-alert
 
# 2. fill it in: template.yaml (author:, inputs, interfaces), rflow.yaml.tmpl,
#    README.md, answers.sample.yaml - then generate the snapshot
rflow templates snapshot my-vault-alert --dir templates/community/my-vault-alert
 
# 3. regenerate the index (this also runs the community doctor gate over
#    every package) and prove it is current
rflow templates index
rflow templates index --dir . --check
 
# 4. open the PR - CI re-runs the whole gate, one maintainer approval merges

The scaffolded skeleton passes the full community doctor profile the moment its snapshot exists, so you start from green. The full checklist lives in templates/community/SUBMITTING.md.

Note: RFLOW_REGENERATE_TEMPLATE_SNAPSHOTS=1 cargo test -p rflow_core regenerate_template_snapshots only regenerates the EMBEDDED first-party snapshots — community packages regenerate with rflow templates snapshot.

The community profile

CI (and every install) enforces the first-party doctor checks PLUS the community rules — all mechanical, none advisory:

rulewhy
author: is mandatoryan EIP-style process puts a name on every proposal
no command: steps, anywhere in the step treea community template may not ship arbitrary execution
no literal addresses in prepares_tx / money_moving templatesdestinations are typed inputs the installer answers (the zero address stays allowed as a placeholder)
every bundled ABI blob is covered by a file: interfacethe blob is machine-verified against the declared signatures — better, ship no blob (wellknown: / fetch:)
typed inputs for every installer choice; defaults validateanswers are type-checked before rendering
outputs.files equals exactly what the package producesmaterialized interface ABIs (abis/<name>.json) count as produced
sample render passes rflow validate and matches the committed snapshotbyte for byte
a docs page exists for docs.pagechecked in-repo by CI (skipped by installing binaries)

Deprecated templates (deprecated: true) stay in the catalog and stay installable — the index is immutable — but are labeled in ls/show and install with a warning.