Automation Playbook
Use this page when you want agentic help around FPF Reference without collapsing every job into one agent.
What this page is
This is the public operating model for FPF Reference automation. It explains the roles, what each role may do, what evidence it should produce, and where user approval is required.
It is not a list of private automation records, thread IDs, local paths, account credentials, or personal scheduling details.
Methodology
Keep role, capability, promise, work, and evidence separate.
- Role: what stance the automation takes.
- Capability: what the automation can technically inspect or change.
- Promise: what the automation is expected to provide.
- Work: what an actual run did.
- Evidence: URLs, commands, PRs, discussions, checks, screenshots, or logs that prove the work.
The main safety rule is simple: discovery roles stay read-only, implementation roles make PRs, and merge or publishing authority stays explicit.
Verification profiles
Use profile-based gates so small work stays small without lowering assurance for production or security surfaces.
Agents start with the smallest admissible profile and escalate when the touched surface or claim requires it. Workflow trigger changes, path filters, or monitor cadence/backoff changes should be separate measured PRs unless the current task is explicitly about automation behavior.
Role map
Workflow
Access and authority
For purchases, subscriptions, billing changes, account changes, or external publishing, the automation may prepare the flow and draft the copy. The user performs or explicitly approves the final action.
Vercel MCP Evidence Loop
Vercel MCP is the Vercel control-plane server at https://mcp.vercel.com; FPF Reference MCP is this product's public lookup server at https://mcp.fpf.sh/api/mcp/fpf_reference/mcp. Keep those roles separate in prompts and evidence packets.
Use Vercel MCP when a run needs current Vercel project/deployment facts that are awkward to prove from local files alone:
fpf-reference-mcpdeployment status, build logs, runtime logs, and protected preview access;fpf-shdeployment status and preview rendering access;- Vercel documentation lookup for changed platform behavior.
Default prompt boundary:
For project-scoped operations, use the project-specific URLs documented in the operator packaging section on the MCP origin so the team/project context is explicit.
Operational CLI Workflows
This section adopts the composition pattern from Vercel's CLI workflows for agents: a workflow is a complete command sequence with the reasoning between steps, not a pile of isolated commands. Agents and operators should follow a workflow end to end instead of improvising command order, and should reuse these sequences as templates for novel situations.
Shared rules:
- Read before write. Inspection commands are always admissible; mutating Vercel actions (deploy, promote, alias, rollback) stay behind the access table above and require the role-specific approval it defines.
- Every workflow ends with evidence. Production-affecting workflows end with the production evidence packet.
- Commands run from the repo root. Direct
vercelCLI calls use the pinned version and team scope the repo scripts use (npx --yes vercel@54.7.1 ... --scope "$FPF_VERCEL_SCOPE"). - Prefer the guarded repo scripts over hand-rolled
vercelinvocations: the scripts bundle validation, staged deploys, smoke, aliasing, and automatic rollback that a bare CLI call skips.
Deploy both production surfaces from the CLI
bun run deploy:validate— proves the committedpublished/current/**surface is coherent and the local content-quality gate passes before anything is built. Failing here is cheap; failing after an alias move is not.bun run deploy:prod— the guarded end-to-end path. It builds both surfaces, records the previous production and canonical-domain deployments as rollback targets, ships a staged production deployment per project, then promotes and explicitly aliasesfpf.shandmcp.fpf.sh, and only then runs the sync, content, and production smoke checks against the canonical domains. The guard is automatic rollback, not a pre-promotion gate: if any post-alias check fails, the script restores the previous project production deployment and re-aliases the previous canonical deployment. Approval and evidence must account for the short exposure window between aliasing and a failed check.bun run smoke:production -- --format markdown --fail-on-breachandbun run bench:mcp:qa -- --name mcp-production --url https://mcp.fpf.sh/api/mcp/fpf_reference/mcp --format markdown— independent post-alias verification that the canonical domains serve the new behavior, not just that a deployment exists. Keep--fail-on-breach: without it the smoke command exits zero even when it reports a breach.- Fill the production evidence packet: deployment URLs, alias targets, rollback target, smoke/QA output excerpts.
Per-surface deploys (bun run vercel:website:deploy:prod, bun run vercel:mcp:deploy:prod) are not guarded the same way: they validate and build, but the deploy step is a bare prebuilt vercel deploy --prod with no recorded rollback targets, no post-alias checks, and no automatic rollback. Prefer bun run deploy:prod even when only one surface changed. If a per-surface deploy is unavoidable, record the current production and canonical-domain deployments first, run step 3 immediately after, and be ready to execute the rollback workflow below by hand.
Debug hosted MCP production errors
curl -sS -w '\nhttp_status=%{http_code}\n' https://mcp.fpf.sh/api/fpf/status— classify first, with the HTTP status printed explicitly. A200withstatus: okand consistent hashes points at a route- or tool-level fault; a non-200or inconsistent runtime points at the deployment itself.npx --yes vercel@54.7.1 inspect mcp.fpf.sh --scope "$FPF_VERCEL_SCOPE"— confirm which deployment actually serves the canonical domain before reading any logs, so the investigation targets the right build.- Read runtime and build logs for that deployment — via the Vercel MCP evidence loop above (read-only) or a historical query such as
npx --yes vercel@54.7.1 logs --deployment <deployment-url> --status-code 5xx --since 1h --expand --scope "$FPF_VERCEL_SCOPE"— to find the failing route and error shape. In the pinned CLI,logsqueries request history by default and streams live only with--follow, so the already-failed requests are readable after the fact; narrow with--query,--level, or--request-idas needed. - Reproduce locally:
bun run startplus the failing JSON-RPC call, orbun run bench:mcp:qapointed at the failing surface. A fault that does not reproduce locally usually implicates packaging, so compare withbun run vercel:mcp:buildoutput next. - Fix, then ship a preview with
bun run vercel:mcp:deployand verify the failing call against the preview URL before touching production. - Publish through the deploy workflow above and close with the evidence packet, including the original failing output and the passing rerun.
Roll back a bad production deployment
Rollback is a mutating action: it needs explicit operator approval per the access table.
- Identify the two rollback targets separately — they can differ after an alias-only hotfix, and
deploy:prodrecords them as distinct values. Project production target:npx --yes vercel@54.7.1 ls fpf-reference-mcp --environment production --status READY --scope "$FPF_VERCEL_SCOPE"(orfpf-sh); the environment and status filters match howdeploy:prodrecords this target, and without them previews, failed builds, or in-progress deployments can masquerade as "last good". Canonical-domain target: the deployment the domain served before the incident, from the deploy evidence packet (recorded there viavercel inspectof the domain). The bad deployment is itself the newestREADYproduction entry in thelsoutput — skip it and take the previous entry, or trust the evidence packet's recorded targets over the listing. - Restore the project production target:
npx --yes vercel@54.7.1 promote <previous-project-production-url> --yes --local-config vercel.mcp.json --scope "$FPF_VERCEL_SCOPE"(website:vercel.json) — this mirrors the automatic rollback indeploy:prod, which restores project production first so the bad deployment does not stay the project's production target and become the next recorded rollback target. - Restore the canonical domain:
npx --yes vercel@54.7.1 alias set <previous-domain-deployment-url> mcp.fpf.sh --scope "$FPF_VERCEL_SCOPE"(orfpf.sh) — canonical domains are aliased explicitly in this repo, so users are back on the known-good deployment only once the alias moves. Use the domain's own recorded target here, not the project production URL from step 2. bun run smoke:production -- --format markdown --fail-on-breach— prove the rollback restored user-visible behavior with a command that actually fails on breach; do not stop at the CLI reporting success.- Record the evidence packet with the restored deployment URL, the bad deployment URL kept as an audit record, and the follow-up fix owner.
Investigate a spend or function-duration breach
-
bun run monitor:vercel:spend -- --format markdown --fail-on-breach— rerun the guardrail first, in the same failing form the scheduled monitor uses (without--fail-on-breachthe command exits zero even on a breach, so a script or agent would sail past a blind or breached guard). It distinguishesbreach,config_error,metrics_unavailable, andexpected_blocked_traffic. The first three all require operator action — the monitor marks them operator-action-required and exits nonzero under--fail-on-breach. Aconfig_error(missing token) ormetrics_unavailablewindow means the guardrail itself is blind and must be repaired, not ignored. Only blocked legacy-route traffic is benign: it is expected, not a spend problem. -
For a breach, attribute the error rows before touching anything. Runtime logs expire within hours, so use the metrics API, which retains days and is what the monitor itself queries:
Compare the nonzero buckets against
gh run listtimestamps to separate self-inflicted monitor traffic from external callers, and against total route volume (--group-by request_path, no filter) to judge whether the errors are a tail rate or a systematic break. The platform-errors threshold is a tail budget calibrated against measured volume (2026-07-31 calibration: ~18.5k invocations/day, 0.027% timeout tail, worst 375m window 3 → budget 10); if volume shifts by an order of magnitude, recalibrate the budget with this query rather than absorbing daily flapping or muting the alarm. -
Check the bundle and route shape locally:
bun run bench:vercel:function-sizeafterbun run vercel:mcp:build, since function-duration spikes often follow packaging regressions. -
Land the guardrail or fix as its own measured PR (P4 surface), and let the monitor close its issue after a clean window rather than closing it by hand.
Diagnose stale published content
bun run monitor:sync— compares upstream FPF HEAD with hosted status and reports drift hours against the SLO. It does not check worker state: verify separately that no sync worker is active withgh run list --workflow sync-fpf.yml, treatingqueued,in_progress,waiting,pending, orrequestedruns as active — the same check the scheduled monitor performs before dispatching.bun run monitor:content -- --mode live --format markdown— checks that curated pages and generated route pages on production still cohere with the published snapshot, separating "site is up" from "site is current".- If upstream is ahead and no sync worker is active, trigger
sync-fpf.yml(dispatch or manual run) instead of hand-publishing; the worker owns validation, preview, and the publication PR. - Evidence: drift hours, the upstream/hosted source-hash pair, and the triggered workflow run URL.
Merge policy
Implementation and merge authority are separate.
A PR may be merged by the review/merge role only when:
- required CI and branch-protection checks are green;
- the PR is not draft and is mergeable;
- there is no unresolved blocking review or requested change on the current head;
- validation evidence is sufficient for the changed surface;
- the PR has independent approval for the current head.
If any condition is missing, the role should report the exact blocker rather than waiting silently.
Executive Production Checklist
Use this checklist before declaring FPF Reference production healthy, after a deploy, after an incident fix, and in any manager brief.
Done means each claim has current evidence. Do not treat a green local build, a successful deploy, or a healthy API endpoint as enough by itself.
-
User-visible surfaces
https://fpf.sh/returns200and renders the FPF Reference site.https://mcp.fpf.sh/returns200and renders the FPF Reference MCP connection page.https://mcp.fpf.sh/connect-mcpreturns200and shows the canonicalfpf_referenceendpoint.
-
MCP protocol surface
https://mcp.fpf.sh/api/fpf/statusreturns200withstatus: ok.GET https://mcp.fpf.sh/api/mcp/fpf_reference/mcpreturns405with the JSON-RPC disabled payload, not a Vercel404.- JSON-RPC initialize and one tool call succeed against
https://mcp.fpf.sh/api/mcp/fpf_reference/mcp. - The public tool list is limited to the intended public tools.
-
Publication freshness
- Hosted status
publication.sourceHash,runtime.sourceHash, andruntime.currentSourceHashmatch. - Hosted status reports
runtime.snapshotConsistent: trueandfreshness.freshnessBasis: source_hash_match. - Treat
freshness.upstreamCurrentness: unknownas expected until an external monitor compares the hosted publication to the intended upstream/current artifact. - The upstream ref in hosted status matches the committed
published/current/manifest.jsonfor the release being claimed.
- Hosted status
-
Deployment ownership
vercel inspect fpf.shpoints to thefpf-shproduction deployment.vercel inspect mcp.fpf.shpoints to thefpf-reference-mcpproduction deployment.- Canonical domains are explicitly aliased after deploy; project production promotion alone is not treated as proof.
-
Route shape
- Website output remains static-only and has no MCP function routes.
- MCP output routes
/,/connect-mcp,/api/fpf/status, and the canonical MCP JSON-RPC path through the MCP function. - Legacy compatibility routes are either blocked intentionally or documented with a current mitigation reason.
-
Quality gates
- The closest focused tests for the changed surface pass.
bun run checkpasses for code changes.- The closest deploy or build command for the changed surface passes.
- GitHub PR checks are green before the fix is treated as merged product state.
-
Cost and risk controls
- MCP function bundle size remains within the configured threshold.
- Vercel spend monitor has no current function-duration, legacy-route, or error-code breach.
- The rollback target is known before production alias changes.
-
Evidence packet
- Record exact commands, URLs, status codes, deployment URL, PR URL, and merge commit.
- Separate ability from performance: what the system can do, what was actually observed, and what remains unproven.
- State residual uncertainty explicitly, especially when relying on cached responses, local DNS, or pending external checks.
Production evidence packet template
Use this packet for production-affecting PRs, deploys, incident fixes, and manager briefs. It is intentionally stricter than "HTTP 200" or "status: ok" evidence: it separates availability, semantic correctness, freshness/currentness, route naming, live behavior, and cost/risk guardrails.
Do not include raw user questions, prompts, answer text, selectors, markdown bodies, session IDs, IPs, or user identifiers.
fpf.sh Sync QA and Monitoring
The production sync loop uses FPF as a quality model:
B.5.1keeps the worker and monitor separate:sync-fpf.ymloperates the publication PR;fpf-sync-monitor.ymlobserves production state and triggers recovery.A.10andG.6define the evidence: upstream SHA, upstream commit date, manifestupstreamRef, source hash, hosted runtime freshness, CI run URL, Vercel preview, and Playwright preview.B.3,E.19, andE.21define gates and characteristics: source/ref coherence, runtime freshness, recoverability, traceability, and max drift are checked separately.
Operational defaults:
sync-fpf.ymlacceptsfpf-origin-updatedandfpf-sync-updateddispatches or manual runs, closes superseded sync PRs, opens a current PR, runs validation/build/preview, then auto-merges only after the review window and required evidence pass.fpf-sync-monitor.ymlpolls daily (11:47 UTC), runsbun run monitor:sync, triggerssync-fpf.ymlwhen upstream is ahead and no sync worker is queued or running, and fails the monitor ifmcp.fpf.shexceeds the drift SLO or the hosted runtime is stale. If a current generated PR already exists, the dispatch is a retry path for CI and merge eligibility rather than a duplicate PR path.- The default drift SLO is 26 hours. Drift is measured as the time since the oldest upstream commit that could already have been published — not the age of upstream HEAD, which resets on every upstream push and can never breach. The sync worker runs twice daily, so the healthy worst case is ~13h; past 26h, two consecutive slots failed.
vercel-spend-monitor.ymlpolls Vercel metrics every 6 hours withbun run monitor:vercel:spend, failing when Function Duration exceeds the configured GB-hour window, the legacy MCP route reaches Functions again, function error-code rows exceed the tail budget (10 per window; legacy-route isolation stays zero-tolerance), credentials are missing, or metrics are unavailable. It reports expected blocked legacy traffic separately so operators do not treat blocked traffic as a spend breach. It prefers the repo secretVERCEL_SPEND_MONITOR_TOKENand falls back toVERCEL_TOKEN.
Publishing and outreach packets
Off-GitHub publishing is prepared as a draft packet. The packet should include:
- channel and audience;
- promise being made;
- product ability that supports the promise;
- observed performance or evidence;
- caveat that should stay visible;
- canonical links;
- suggested call to action;
- approval needed before sending or publishing.
Medium or Substack draft packet
Short social post packet
One-to-one outreach packet
Approval checklist
Before anything leaves GitHub or a local draft:
- The channel is named.
- The audience is named.
- The claim is backed by current evidence.
- The caveat is visible.
- The user has approved the exact copy or the exact destination.
- No private repo, account, credential, thread, or local-machine detail is included.
Done condition
The automation system is healthy when each role can answer:
- what it inspected;
- what it changed, if anything;
- what evidence supports the result;
- what it cannot do without approval;
- who owns the next action.