-
Notifications
You must be signed in to change notification settings - Fork 33
Expand file tree
/
Copy path.env.example
More file actions
214 lines (198 loc) · 12.4 KB
/
Copy path.env.example
File metadata and controls
214 lines (198 loc) · 12.4 KB
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# patina environment reference — copy to .env and fill only what you use.
# .env is gitignored; never commit real values.
# ---------------------------------------------------------------------------
# CLI / local LLM provider keys (openai-http backend, quality:live harness)
# Lookup order: PATINA_API_KEY first, then the provider-specific key
# (src/auth.js HTTP_KEY_ENV_VARS). `--provider <name>` presets live in
# src/providers.js: openai, gemini, groq, kimi, moonshot, together.
# ---------------------------------------------------------------------------
# PATINA_API_KEY= # generic key, wins over provider-specific vars
# OPENAI_API_KEY= # default openai-http backend (gpt-5.5)
# GEMINI_API_KEY= # --provider gemini (gemini-2.5-pro)
# GROQ_API_KEY= # --provider groq
# TOGETHER_API_KEY= # --provider together
# KIMI_API_KEY= # --provider kimi (kimi-k2.5, api.moonshot.ai)
# MOONSHOT_API_KEY= # --provider moonshot (same endpoint as kimi)
# PATINA_API_KEY_FILE= # or read any key from a file (recommended for CI)
# Local subscription CLIs (claude / codex / gemini / kimi) need no key here —
# a logged-in seat is the credential. See also PATINA_LIVE_* and
# PATINA_LIVE_JUDGE_* (fixed-judge scoring) in tests/quality/README.md.
# ---------------------------------------------------------------------------
# Hosted playground / API service (Vercel `/api/rewrite`)
# Server-side only. The browser never sees these. All tiers fail closed:
# missing config / KV / HMAC secret is denied before any provider is called.
# ---------------------------------------------------------------------------
# Upstash-compatible REST KV — required in production for the quota + admission
# guard. Without it (production posture) every metered request is rejected 503.
# KV_REST_API_URL=https://your-kv.upstash.io
# KV_REST_API_TOKEN=your-kv-rest-token
# Free tier: the service's own provider key (rate-limited by IP) + HMAC secret
# that signs quota/subject KV keys (raw keys/licenses are never stored).
#
# Model choice (owner-approved 2026-07-26): gemini-3.6-flash. The prior default
# gpt-4.1-mini measured an AI-score improvement of only 0.2 across 22 fixtures
# — it returns the input nearly unchanged, so free traffic received no real
# rewrite while still scoring high on meaning preservation. gemini-3.6-flash
# measured 13.0. See docs/operations/serving-engine-cost-20260725.md.
# PATINA_FREE_API_KEY=your-provider-key
# PATINA_FREE_PROVIDER=gemini
# PATINA_FREE_MODEL=gemini-3.6-flash
# PATINA_QUOTA_HMAC_SECRET=your-long-random-secret
# --- Pro tier ($9.99/mo USD, Lemon Squeezy license-gated) -------------------
# Caller sends `Authorization: Bearer <license_key>`; the server validates it
# against Lemon Squeezy's validate-only endpoint (POST /v1/licenses/validate),
# never stores the raw key, and meters per-license by an HMAC subject.
# --- License provider ------------------------------------------------------
# Which vendor gates the Pro tier. Defaults to lemonsqueezy so an existing
# deployment cannot change gate behavior by upgrading. Both providers share the
# same fail-closed security core; cache and lock keys are provider-namespaced,
# so switching never serves a decision cached under the other vendor.
# PATINA_LICENSE_PROVIDER=lemonsqueezy # or: polar
#
# Polar identity (PATINA_LICENSE_PROVIDER=polar). Both are REQUIRED — a missing
# value fails closed rather than skipping the corresponding check.
# POLAR_ORGANIZATION_ID= # required; pins the org a key must belong to
# POLAR_PRO_BENEFIT_ID= # required; without it ANY benefit's key in
# # the same org would entitle the paid tier
# POLAR_SERVER=sandbox # omit for production
# PATINA_POLAR_VALIDATE_RPM=10 # default 10. Measured: ~5 rapid validate
# # calls draw 429 with retry-after 21s, so
# # this ceiling is far below the observed
# # break point. The positive cache means a
# # seat validates about once per cache TTL.
# PATINA_POLAR_TIMEOUT_MS / _CACHE_TTL_MS / _NEGATIVE_CACHE_TTL_MS / _LOCK_WAIT_MS
# # same meaning as the PATINA_LS_* pair below
# Lemon Squeezy identity — the validate response meta MUST match these.
# LS_STORE_ID=425473 # required
# LS_PRO_VARIANT_ID=1875389 # required (Pro subscription variant)
# LS_PRO_PRODUCT_ID=1199625 # optional extra pin (meta.product_id)
# Pro provider key. REQUIRED in production — if absent the Pro path fails closed
# (503) and NEVER spends the free key on paid traffic.
# PATINA_PRO_API_KEY=your-pro-provider-key
# HMAC secret for license subjects/KV keys. Required in production; falls back
# to PATINA_QUOTA_HMAC_SECRET when unset.
# PATINA_LICENSE_HMAC_SECRET=your-long-random-secret
# Pro provider/model — REQUIRED in production (missing values fail pro requests
# closed with 503; no silent fallback to the free provider/model). Outside
# production they fall back to PATINA_FREE_PROVIDER/MODEL, then the preset.
# Both must be on the PROVIDER_PRESETS allowlist.
#
# Model choice (owner-approved 2026-07-26; evidence re-established 2026-07-27):
# gemini-3.6-flash, replacing claude-sonnet-5. Rerun on 22 live-quality
# fixtures after fixing a broken fidelity rubric and a harness prompt that
# omitted the persona (docs/operations/serving-engine-cost-20260725.md): the
# two engines both score 20/22 with MPS 90.4 vs 91.5. Quality is level; the
# case is cost and latency — $0.030 vs $0.156 per rewrite, 8.3s vs 27.7s.
# PATINA_PRO_PROVIDER=gemini
# PATINA_PRO_MODEL=gemini-3.6-flash
#
# Previous pin, kept for rollback:
# PATINA_PRO_PROVIDER=claude
# PATINA_PRO_MODEL=claude-sonnet-5
# --- Prompt caching (Anthropic only, opt-in) --------------------------------
# The rewrite prompt is ~99.7% fixed prefix (pattern catalog + profile + voice)
# with only the user text after the data fence, so it caches almost perfectly.
# Anthropic's OpenAI-compat endpoint ignores cache_control, so this flag routes
# paid calls through the native /v1/messages adapter with a cached prefix.
#
# Measured 2026-07-25 (ko web prompt, claude-sonnet-5): 34,254 cacheable prefix
# tokens; second identical call read 34,254/34,254 from cache and halved latency
# (25.2s -> 12.0s). Cost per request: $0.126 uncached, $0.151 on a cache miss
# (+20%, the 5m write surcharge), $0.033 on a hit (-74%).
#
# Break-even hit rate is 21.7%, i.e. roughly 3 requests/hour per language
# variant (the 5-minute ephemeral TTL refreshes on each hit). Below that this
# flag is a ~20% input surcharge; above it, savings approach 74%.
# PATINA_ANTHROPIC_NATIVE_CACHE=1
#
# Thinking stays at the provider default (ON for sonnet-5) because a measured
# A/B showed thinking-off rewrites amputate content. Set to 0 only for
# experiments, never to cut cost on the paid path.
# PATINA_ANTHROPIC_THINKING=1
# Pro limits (per-license). Defaults shown.
# PATINA_PRO_MAX_CHARS=20000
# PATINA_PRO_REQ_PER_DAY=200
# PATINA_PRO_MAX_CONCURRENT=3
# PATINA_PRO_REQ_PER_MONTH=100 # per-license monthly REQUEST cap (primary margin control: cost tracks request count, not chars)
# PATINA_PRO_CHARS_PER_MONTH=50000 # secondary bound — per-license monthly total-char cap (margin defense; 50k default owner-approved 2026-07-29, see docs/operations/pro-margin-decision-20260729.md)
# Lemon Squeezy validate tunables. Defaults shown (ms). Cache TTL bounds the
# revocation-propagation latency; validate fetch fails closed on timeout.
# PATINA_LS_CACHE_TTL_MS=300000 # positive (valid) result cache
# PATINA_LS_NEGATIVE_CACHE_TTL_MS=60000 # negative (denied) result cache
# PATINA_LS_TIMEOUT_MS=2500 # LS validate fetch abort deadline
# PATINA_LS_VALIDATE_RPM=50 # outbound cap (LS hard limit is 60/min)
# PATINA_LS_LOCK_POLL_INTERVAL_MS=150 # follower cache-poll cadence while the winner validates
# PATINA_LS_LOCK_WAIT_MS=3500 # follower poll budget (default min(lock TTL, timeout+1s))
# Escape hatch: let Pro fall back to PATINA_FREE_API_KEY when PATINA_PRO_API_KEY
# is unset. Honored in ALL postures when 'true' (including production) — so leave
# it unset in production to keep the fail-closed 503. Outside production the
# free-key fallback is already on without this flag.
# PATINA_PRO_ALLOW_FREE_KEY=true
# --- Pro pack delivery (api/packs.js) --------------------------------------
# Read-only fine-grained GitHub PAT scoped to the PRIVATE pack repo (contents:
# read). Without it the endpoint fails closed with 503 PACKS_UNAVAILABLE.
# PATINA_PACKS_GITHUB_TOKEN=
# PATINA_PACKS_REPO=devswha/patina-pro-packs
# PATINA_PACKS_REF=main
# PATINA_PACKS_CACHE_TTL_MS=300000 # upstream (GitHub) KV cache TTL
# PATINA_PACKS_REQ_PER_DAY=200 # per-license daily download cap
# CLI side (patina pack): the pro license key and optional endpoint override.
# PATINA_LICENSE_KEY=
# PATINA_PACKS_URL=https://patina.vibetip.help/api/packs
# --- Browser checkout launch config (generated at deploy time) ----------------
# These are build/deploy inputs only. `npm run launch-config:generate` writes the
# public, non-secret playground/launch-config.js; do not set checkout secrets here.
# Safe default: checkout is disabled unless this is exactly "true".
# PATINA_PRO_CHECKOUT_ENABLED=false
#
# Enabled checkout additionally requires an exact source-controlled binding in
# scripts/checkout-evidence-bindings.mjs. Environment values never authorize a
# checkout URL. Adding a binding requires reviewed immutable PAY-STG/PAY-B
# evidence and a human-supplied exact Lemon Squeezy URL; keep checkout disabled
# until that review is complete.
# PATINA_DEPLOYMENT_CHANNEL=staging
# PATINA_PRO_CHECKOUT_URL=
# PATINA_PRO_GATE_EVIDENCE_ID=
#
# Payment-provider dashboard/API credentials and monitor/webhook credentials are
# server-only operational secrets. Keep them in the hosting secret manager, never
# in the browser config, repository, logs, support tickets, or this example file.
#
# --- Private Pro monitor (Vercel Cron `/api/pro-monitor`) -------------------
# Server-only operational configuration. Store the secret values below in the
# hosting secret manager; never expose secrets to the browser, generated launch
# config, logs, tickets, Discord payloads, or OBS receipts.
#
# Telemetry and monitor state use a dedicated strict Upstash REST KV, isolated
# from quota/admission `KV_REST_API_URL` and `KV_REST_API_TOKEN`.
# PATINA_OBSERVABILITY_REST_API_URL=https://your-observability.upstash.io
# PATINA_OBSERVABILITY_REST_API_TOKEN=your-observability-rest-token
# CRON_SECRET=long-random-vercel-cron-secret
# PATINA_DEPLOYMENT_CHANNEL=production
# PATINA_PUBLIC_BASE_URL=https://patina.example.com
# PATINA_PUBLIC_BASE_URL_SHA256=64-lowercase-hex-sha256-of-exact-url
# PATINA_SYNTHETIC_PRO_LICENSE=synthetic-pro-license-key
# PATINA_SYNTHETIC_OBSERVER_SECRET=long-random-server-only-observer-secret
# PATINA_VERCEL_LOG_QUERY_URL=https://aggregate-query.example.com/patina
# PATINA_VERCEL_LOG_QUERY_URL_SHA256=64-lowercase-hex-sha256-of-exact-url
# PATINA_VERCEL_LOG_QUERY_TOKEN=read-only-aggregate-query-token
# PATINA_ALERT_DISCORD_WEBHOOK=https://discord.com/api/webhooks/...
# VERCEL_GIT_COMMIT_SHA=0123456789abcdef0123456789abcdef01234567
#
# The monitor sends exactly one `x-patina-synthetic-observer` header whose value
# is PATINA_SYNTHETIC_OBSERVER_SECRET. The rewrite boundary verifies and strips
# it before the runner; it is never forwarded, logged, or durable telemetry.
#
# Vercel invokes `/api/pro-monitor` every 15 minutes (see `vercel.json`). The
# external read-only aggregate query service is mandatory, URL-SHA256 pinned,
# and returns only exact integer `numberSafety`, `entitlementNonOk`,
# `entitlementTotal`, and `monitorDrop` counts scoped to channel/tier/window:
# it never returns raw Vercel logs. Missing, unpinned, or unavailable service
# keeps checkout disabled and makes the monitor return 503.
#
# The whole monitor has one <=55-second deadline, including every network read,
# incrementally read response body (capped at 64 KiB), synthetic request, Discord
# attempt, and the real 1-second then 2-second retry backoff. `VERCEL_GIT_COMMIT_SHA`
# is Vercel-provided deployment binding, not a secret, and must be exactly 40
# lowercase hexadecimal characters. Missing/malformed binding or incomplete
# evidence makes the monitor return 503 without issuing an OBS receipt.