1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# REST → JSONL driven by typed run parameters (#444).
#
# The `params:` block declares this pipeline's *trigger-time* surface: the few
# values that change per run, each with a type, a requirement, and (optionally)
# a default. Everywhere else in the config they are referenced as
# `${param.NAME}`, bound before the config is parsed — so a param can never
# alter the document's structure and never reaches a connector unresolved.
#
# Run it directly, supplying the required params:
#
# faucet run cli/examples/rest_to_jsonl_templated.yaml \
# --param tenant_id=acme --param since=2026-01-01
#
# Validate it in CI without inventing values (required params bind to
# type-shaped placeholders):
#
# faucet validate cli/examples/rest_to_jsonl_templated.yaml
#
# Or register it **once** and trigger by id thereafter — the register-once /
# trigger-by-id model. The registry rides the run-history backends, so point
# `faucet serve --history` at the same URL to trigger the very same template
# over HTTP or MCP:
#
# faucet template register cli/examples/rest_to_jsonl_templated.yaml \
# --store sqlite:./faucet-templates.db --tag dev
# faucet template launch tenant-sync --version dev # make it live
# faucet template run tenant-sync --store sqlite:./faucet-templates.db \
# --param tenant_id=acme # runs `stable`
#
# Versions auto-increment on every register — and a register **moves nobody**.
# `launch` is the one step that changes what an unpinned run gets, so a nightly
# can land while `stable` stays put; `rollback` re-launches the previous one.
# Three channels are derived (`stable` = the launched version and the default
# selector, `previous`, `newest`) and six are assignable with `promote`
# (dev / test / staging / pre-prod / canary / prod), so a scheduled job can ride
# `--version prod` while newer versions land behind it.
#
# faucet serve --history sqlite:./faucet-templates.db --auth-token "$TOKEN"
# curl -sX POST localhost:8080/v1/templates/tenant-sync/runs \
# -H "Authorization: Bearer $TOKEN" \
# -d '{"params":{"tenant_id":"acme","since":"2026-01-01"}}'
#
# `faucet template` and the `/v1/templates*` endpoints need a build with the
# `templates` feature (included in `--features full`), plus
# `serve-history-sqlite` / `serve-history-postgres` for a persistent registry.
# The `params:` block itself is always available.
version: 1
name: tenant-sync
params:
# No default ⇒ the caller must supply it. `faucet validate` binds a
# placeholder so the config still checks out in CI.
tenant_id:
type: string
required: true
description: Tenant whose events to sync
# A default makes the param optional. Defaults are ordinary config scalars, so
# `default: "${env:SINCE}"` would work too.
since:
type: string
default: "1970-01-01"
description: Only fetch events at or after this date
# A whole-scalar `${param.page_size}` keeps the declared type, so this lands
# in the connector config as the number 500 — not the string "500".
page_size:
type: int
default: 500
description: Records per page
# `secret: true` registers the value for redaction the moment it is bound, so
# it never reaches a log line, an error message, an API response, or the audit
# log. It is never persisted with the template either — only the token
# reference below would be, if you sourced it from the server instead.
api_token:
type: string
required: true
secret: true
description: Bearer token for the events API
pipeline:
source:
type: rest
config:
url: "https://api.example.com/tenants/${param.tenant_id}/events?since=${param.since}"
auth:
type: bearer
config:
token: "${param.api_token}"
pagination:
type: page_number
config:
page_param: page
size_param: per_page
size: "${param.page_size}"
records_path: "$.data"
sink:
type: jsonl
config:
# `${param.*}` works in any config value, including a path.
path: "./out/${param.tenant_id}/events.jsonl"