Skip to content

Latest commit

 

History

History
341 lines (262 loc) · 30.3 KB

deployment.md

File metadata and controls

341 lines (262 loc) · 30.3 KB

Cloudflare deployment

Current release: v0.5.1

Observed November 13, 2026 UTC: PR #37 is merged and v0.5.1 is deployed at 100%, adding trip progress and safe cancellation (v0.5.0) with the generation fix. v0.5.0 (Worker bcca9620-3e4d-42be-bb1e-44acf95cce3a) failed every generation and was rolled back to v0.4.7 before v0.5.1; do not redeploy it.

  • Release source and PR merge: 238f05ceee4984261cffcbe9d48e92088c19fca6.
  • Production Worker: 62bc3afe-fb1f-474f-b2de-765ac1fdfeb5.
  • Immutable image: sha256:50cb0c37d75184b4576e091d8aed362d03543c672f47ce4074edd9350ad656e2.
  • Rollback Worker: 42d1aede-d6f5-4e0b-a226-32617cab2c9e (v0.4.7).

The release report owns the v0.5.0 incident, rollback, identities, cancellation acceptance and limitations. All four database-derived BUILD-04 outcomes pass for this release integration. Two sequential browser sessions used 77.1 seconds; zero active browsers remained.

Previous release: v0.4.7

Observed November 13, 2026 UTC: PR #27 is merged and v0.4.7 is deployed at 100%. The Release workflow passed exact-source CI, upload, owner-authorized production approval, promotion, trigger deployment and release publication. The two-leg acceptance ran on the promoted production Worker.

  • Release source and PR merge: 553a41ff8ceee658779196f2856b4cebc3ae241f.
  • Production Worker: 42d1aede-d6f5-4e0b-a226-32617cab2c9e.
  • Immutable image: sha256:0ec30d9ff5256ea8a3dc737ac3d9e86c0b4ce2853f7593f1cf5d83972cef2389.
  • Rollback Worker: 2226a90f-baba-4123-9022-d1ac8e137890 (v0.4.6).

The release report owns the incident, identities, local and production evidence, and limitations. All four database-derived BUILD-04 outcomes pass for this release integration. Two sequential browser sessions used 95.5 seconds; zero active browsers remained.

Previous release: v0.4.6

Observed November 12, 2026 UTC: PR #24 is merged and v0.4.6 is deployed at 100%. The Release workflow passed exact-source CI, upload, owner-authorized production approval, promotion, trigger deployment and release publication. The exact uploaded image passed the two-leg acceptance and final product validator before promotion.

  • Release source: 3c257da34faf637a4c8c70cb2e3799cb54e11347.
  • PR merge: 85b7f1f911c1830f1a55e4aba25abea381f4fbb7.
  • Production Worker: 2226a90f-baba-4123-9022-d1ac8e137890.
  • Immutable image: sha256:c75bb04e64b4118caec27a623663da1e68c3e32871ddb79371de4a92c859455d.
  • Rollback Worker: c569ec9f-ca03-48ee-a0fe-6aab246ed23e (v0.4.5).

The release report owns identities, exact-image evidence, production verification, usage, cleanup and limitations. All four database-derived BUILD-04 outcomes pass for this release integration; product validation passed 458 tests, Ruff and dead-code checks with three Postgres-only skips. Two sequential browser sessions used 151.080 telemetry seconds and two FlightAware requests; zero active browsers remained. Temporary acceptance resources were removed. Verified aircraft support remains 0/51, and INT-412–414 remain open.

Authenticated production health is pending completion of the renewed Access sign-in.

Previous release: v0.4.5

Observed November 12, 2026 UTC (November 11 in New York): PR #23 is merged and v0.4.5 is deployed to production at 100% traffic. The Release workflow passed exact-source CI, image upload, the owner-authorized production gate, promotion, trigger deployment and release publication. The exact uploaded image passed staged acceptance and final product validation before the production environment was approved.

  • Release/merge source: f434f85bd63cfd92d0ab136668a91895d6ba4d9f.
  • Production Worker: c569ec9f-ca03-48ee-a0fe-6aab246ed23e.
  • Immutable image: sha256:3554b740b1ac4cc28d635fc5dd91f80e9aa6db7e7de9461d12b81207dfe6fab8.
  • Rollback Worker: 74da7217-f7bf-45b0-b3b4-a0115c335b9d (v0.4.4).

The release report owns exact-image acceptance, source/image identity, usage, cleanup, replay limitations and rollback details. The database-derived record passes all four BUILD-04 outcomes. Final product validation passed: 458 tests, Ruff and dead-code checks; three Postgres-only tests were skipped. Controlled and actual-model evaluations remain distinct; the original WF-025 failures and the separate explicit sequence supplement are retained in the evaluation report.

Post-promotion deployment metadata shows 100%, the tag resolves to the release source, and public production health returns 401 without authentication. An authenticated production health rerun was unavailable because Realm's browser host was disconnected. Authenticated health and the two-leg trip were verified on the exact release image at isolated staging; those observations are not represented as a successful authenticated production request.

All four authorized Browserbase sessions across PR/release acceptance completed sequentially in 223.875 seconds total, with four FlightAware requests and zero active browsers afterward. Temporary staging resources were removed. Estimates retain SUSPECT warnings; simulator import, aircraft accuracy and independent profile references remain unverified. Verified aircraft support is 0/51; INT-412–414 remain open.

Previous release: v0.4.4

Observed November 11, 2026 UTC (November 10 in New York): PR #22 is merged and v0.4.4 is serving production at 100% traffic. The Release workflow passed CI, image upload, the existing owner-authorized production gate, promotion, trigger deployment and release publication.

  • Release/merge source: eef57bcaec856b1bd56bc9b1a1a2f992b67fb61f.
  • Production Worker: 74da7217-f7bf-45b0-b3b4-a0115c335b9d.
  • Immutable image: sha256:3db056ca9cb6eba027332ea9caa3534fb91798d71fb8471d08d6bee9f779f657.
  • Rollback Worker: 06401807-3277-4077-b921-dc98ca348e08 (v0.4.3).

The exact uploaded image passed a two-leg A20N trip on isolated staging before promotion. The release report records source/image identity, paired LangSmith evaluations, usage, limitations and cleanup. Its database-derived record passes all BUILD-04 outcomes. Final local product validation passed: 401 tests, Ruff and dead-code checks; three Postgres-only tests were skipped. Controlled and actual-model replay each passed all 28 cases; the original eight definitions are preserved.

Authenticated production health returned status=ok, version=0.4.4, database=true and paid_operations_enabled=true through the existing Access/Worker path. Public unauthenticated health returned 401. Post-promotion inventory showed zero active browsers and no sessions beyond the four authorized acceptance sessions. Those sessions totaled 254.685 seconds; FlightAware usage totaled four requests. Temporary staging resources were removed. Simulator import, numerical thrust accuracy and a fresh OAuth consent journey remain unverified; verified aircraft support remains zero.

Previous release: v0.4.3

Observed November 11, 2026 UTC (November 10 in New York): PR #21 is merged and v0.4.3 is deployed to production at 100% traffic. The Release workflow completed successfully, including CI, immutable image upload, owner-authorized production approval, promotion, trigger deployment and release publication.

  • Release source: 710513f5d6c868a90e1aa8041dbcf689c0c476c0.
  • PR merge: 7cecc73024b958a7a554edbea839208fa0cd3304.
  • Production Worker version: 06401807-3277-4077-b921-dc98ca348e08.
  • Immutable image: sha256:776b92ad22032475baa2d0f24da1e93c9811741c6830f4677511e93a1a3b6bd2.
  • Previous production version, available for rollback: 42be74fa-87e9-4226-a3a5-debaec360173 (v0.4.2).

The exact uploaded image passed a two-leg A20N trip on temporary staging before promotion. The release report records acceptance, workflow evaluations, browser usage, cleanup and production observations. The database-derived acceptance record passes all four BUILD-04 outcomes for the release source. Local product validation passed: 305 tests, Ruff and dead-code checks; three Postgres-only tests were skipped locally.

Post-promotion reads confirmed the tagged version at 100%, the matching Git tag/release, HTTP 401 for unauthenticated production health, and zero active Browserbase sessions. No additional production flight generation or public Access OAuth client journey was run. The live flight evidence belongs to the exact image on staging, rather than a production runtime request. Aircraft thrust accuracy and simulator import remain unverified.

Previous release: v0.4.2

Observed November 10, 2026 UTC (November 9 in New York): PR #20 is merged and v0.4.2 is deployed to production at 100% traffic. The Release workflow completed successfully, including Python/Worker CI, image upload, owner-authorized production approval, promotion and release publication.

  • Release source: f9769901dde443fab96b459855ac21e007d0c96a.
  • Production Worker version: 42be74fa-87e9-4226-a3a5-debaec360173.
  • Immutable image: sha256:2f9ab7989ffa433b5e0880537cd4df64eea93a178a8618f8467fcd82f5526235.
  • Previous production version, available for rollback: 758f18dd-4c55-4df1-9017-8939e9eeddb1 (v0.4.1).

Before promotion, that exact uploaded image passed a two-leg trip through a separate Cloudflare staging Worker, version 43386d6e-0111-423b-8a54-080f333fc15d. The database-derived acceptance record passes all four BUILD-04 outcomes for the release source. Trip v042-20261110T010552Z retained both A20N OFPs and briefings, with takeoff performance, after approval waits. Routes were JCOBY4 SWANN PHLBO4 and PORTT4 PARKE HYPER9, each with 17 navlog entries. Both dispatches used automatic routing without requiring the earlier route-field clarification.

Exactly two Browserbase sessions ran, sequentially, for 42.766 and 50.574 seconds. Both requested a 180-second provider lifetime, had keepAlive=false, and finished COMPLETED. No sessions remained active; reported project usage increased from 62 to 64 browser minutes. The browser policy owns the effective limits. Local repository validation passed with this acceptance record. Queue overflow and timeout failure cases remain controlled-provider test evidence rather than deliberately stranded live browsers.

Staging MCP used an operator-authenticated Container SSH tunnel with internal-token verification; unauthenticated public staging health returned HTTP 401. The public Access OAuth client flow was not rerun. The scheduled staging bootstrap returned skipped without opening a browser. The temporary Worker, schedule, container app, tunnel and SSH key were removed before promotion. Post-promotion checks read deployment/release metadata and browser inventory; public production health rejected unauthenticated access with HTTP 401. No further flight generation was run. Private receipts are retained in Git-ignored artifacts/private/v042-release/, and the workflow retains upload/promotion artifacts.

Initial resource setup (historical)

Status October 31, 2026: nothing has been deployed and the release workflows have not run. Created so far (none are secrets):

  • GitHub repository IntelIP/InfiniteFlightAgent (public), production environment (owner review, main only), variables ACCESS_TEAM_DOMAIN, ACCESS_AUD, ACCESS_ALLOWED_EMAIL, secret CLOUDFLARE_ACCOUNT_ID.

  • Neon project InfiniteFlightDispatcher (summer-fog-90424455, aws-us-east-1, Postgres 18, database neondb).

  • R2 bucket infinite-flight-dispatcher (ENAM).

  • Access application "Infinite Flight Agent MCP" (82c02dde-b5fa-4a48-b518-5c3256608d55) for infinite-flight-dispatcher.hudson-228.workers.dev: managed OAuth with dynamic client registration on, one Allow policy for the owner's email, team domain restless-mouse-67bc.cloudflareaccess.com.

  • Workers Paid was already active on the account.

  • Doppler project infinite-flight-agent, config prd: every key above, with IFD_PAID_OPERATIONS_ENABLED=false. IFD_INTERNAL_TOKEN and IFD_CREDENTIAL_KEY were generated directly into Doppler; DATABASE_URL is the Neon pooled endpoint (connection checked). The R2 keys come from an account API token limited to Object Read & Write on infinite-flight-dispatcher; write, read and delete there succeeded, and listing all buckets or reading two other buckets was denied. Read-only service token github-release-readonly is the GitHub secret DOPPLER_TOKEN; variables DOPPLER_PROJECT and DOPPLER_CONFIG are set.

  • GitHub secret CLOUDFLARE_API_TOKEN: account API token with Workers Scripts Edit, Workers Containers Edit and Account Settings Read (verified active; R2 access refused). Account API tokens cannot be created with CLI OAuth, so it and the R2 token were made in the dashboard.

Still needed: merge to main, the ChatGPT credential import, then the bootstrap release. Owner decision: single-user personal deployment of the open-source app with the owner's own keys and ChatGPT plan. License: GPL-3.0-only (owner decision, October 31, 2026), because the thrust estimator ports GPL-3.0 FlyByWire tables.

Architecture

MCP client (ChatGPT / Claude / Codex)
  │  HTTPS, Cloudflare Access managed OAuth (owner's email only)
  ▼
Cloudflare Access ── rejects unauthenticated requests at the edge
  │  Cf-Access-Jwt-Assertion
  ▼
Worker  infinite-flight-dispatcher            deploy/cloudflare/src/index.ts
  • verifies the Access JWT against the team JWKS (iss = team domain, aud = ACCESS_AUD),
    optional ACCESS_ALLOWED_EMAIL; missing config → 503, no token → 401, bad token → 403
  • forwards only /mcp and /health (all methods, streamed both ways)
  • strips the Access JWT and cookies, adds X-IFD-Internal-Token
  ▼
Durable Object "dispatcher" (DispatcherContainer, durable_object scheduling policy)
  • starts one container (standard-1, internet on, 15 min inactivity timeout)
    with secrets as environment variables
  • restarts it when secrets, the paid-operations flag, or the image change
  ▼
Container  repo-root Dockerfile → uv run --locked --no-dev ifd-serve on 0.0.0.0:8080
  └─► OpenAI (ChatGPT plan), FlightAware AeroAPI, SimBrief, Browserbase, Neon, R2, LangSmith

Cloudflare Access does the OAuth for MCP clients; the Worker does not implement OAuth. The Worker's JWT check exists so a deleted or misconfigured Access application fails closed.

Resources the owner creates

Resource Notes
Cloudflare Workers Paid plan Required for Containers
Access application for the Worker hostname Self-hosted app with managed OAuth for MCP clients enabled; one Allow policy containing only the owner's email. Copy the team domain (https://<team>.cloudflareaccess.com) and the application AUD tag
Cloudflare API token Workers Scripts and Containers edit permissions, scoped to the one account
Neon project and database Pooled connection string → DATABASE_URL
R2 bucket and S3 API token Bucket-scoped read/write token → R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY; plus R2_ACCOUNT_ID, R2_BUCKET
Doppler project and config Holds DATABASE_URL, IFD_CREDENTIAL_KEY, IFD_INTERNAL_TOKEN (random, 32+ bytes), AEROAPI_KEY, BROWSERBASE_API_KEY, BROWSERBASE_SIMBRIEF_CONTEXT_ID, SIMBRIEF_USERID, NAVIGRAPH_USERNAME, NAVIGRAPH_PASSWORD (automatic SimBrief sign-in), LANGSMITH_API_KEY, LANGSMITH_PROJECT, LANGSMITH_TRACING, the four R2_* values, and IFD_PAID_OPERATIONS_ENABLED ("false" until the first validation passes). Create a read-only service token for that config
GitHub repository secrets CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID, DOPPLER_TOKEN
GitHub repository variables DOPPLER_PROJECT, DOPPLER_CONFIG, ACCESS_TEAM_DOMAIN, ACCESS_AUD, ACCESS_ALLOWED_EMAIL (optional)
GitHub environment production Required reviewer: the owner. Gates promotion and bootstrap

DATABASE_URL, IFD_CREDENTIAL_KEY, and IFD_INTERNAL_TOKEN are required: scripts/sync-secrets.sh and Wrangler's secrets.required check refuse to upload without them. IFD_PAID_OPERATIONS_ENABLED is a Worker secret rather than a [vars] entry so the emergency stop can change it without new code; a missing value is passed to the container as "false".

Workflows

  • ci.yml: pull requests, pushes to main, and release checks. Python: uv sync --locked, pytest, ruff, dead-code check. Worker: npm ci, wrangler types --check, tsc --noEmit, auth-gate unit tests (node --test).
  • release.yml (manual): refuses anything but the current main commit, runs CI on it, syncs secrets from Doppler into a temporary file, then wrangler versions upload --secrets-file … builds the image with Docker and uploads a version with no traffic. The version id is in the job summary, and each job uploads a release-* evidence artifact (Wrangler output, wrangler versions view of the candidate, deployment status before and after, commit and version id). With promote=true, the production environment approval gates wrangler versions deploy <id>@100% -y, followed by wrangler triggers deploy to apply the daily cron (version uploads do not change triggers). The cron still calls the container's legacy keep-alive route, which now returns skipped and opens no browser; SimBrief sign-in happens on demand during browser work. The release takes its name from the version in pyproject.toml: the guard job requires a matching CHANGELOG.md section and refuses a version already tagged on another commit. The uploaded Worker version is tagged vX.Y.Z, and promotion publishes the vX.Y.Z Git tag and GitHub Release with that changelog section as its notes.
  • emergency-stop.yml (manual, type STOP): sets IFD_PAID_OPERATIONS_ENABLED=false with wrangler secret put.

scripts/sync-secrets.sh can also be run locally (DOPPLER_PROJECT=… DOPPLER_CONFIG=… scripts/sync-secrets.sh). Without arguments it is a dry run that checks the required keys and lists the names it would sync; --apply pushes them with wrangler secret bulk, which deploys a new version of the current code immediately. It prints key names only.

First deploy

  1. Create the resources above with IFD_PAID_OPERATIONS_ENABLED=false in Doppler.
  2. Import ChatGPT-plan credentials (below).
  3. Run Release with bootstrap=true and approve production. A first upload must use wrangler deploy: wrangler versions upload cannot create a Worker or apply the Durable Object migration. This version takes traffic immediately, behind Access, with paid operations off. The first container provisioning can take several minutes.
  4. Validate: from an Access-authenticated browser open https://<worker-host>/health (expect 200 JSON); without Access, expect a block or 401/403. Connect one MCP client and make one call, such as a flight lookup.
  5. Set IFD_PAID_OPERATIONS_ENABLED=true in Doppler when ready, then release again.

Later releases: run Release with promote=true, review the uploaded version while production approval is held, then approve promotion of that recorded version. promote=false supports upload-only preparation. Version preview URLs are not generated for Workers with Durable Objects; the recorded v0.4.2 and v0.4.3 acceptance runs used separate temporary Workers with the exact uploaded images before production approval. Durable Object–managed containers do not take part in image rollouts; the Worker restarts the running container on its next request when the image or secrets differ from what it started with, ending any in-flight stream.

Notes from Condere's release process

Read from Products/Condere on October 31, 2026 (apps/mcp/docs/release-policy.md, .buildkite/release.yml, .buildkite/scripts/release-prepare.sh, docs/cloud-run.md, docs/environment-policy.md). Condere deploys to Google Cloud Run through Buildkite rather than Cloudflare, so the practices transfer but the commands do not. These are observations and proposals, not decisions. Condere's own write-up is Products/Condere/docs/release-playbook.md (draft, covering main at 1dfc2379). It reports that the trusted Buildkite release path is fully written but has never run end to end: no candidate has been prepared, accepted, promoted, or rolled back. Treat it as a design. The deployment that has actually run in production is the spin-off's, recorded in the shared deployment-playbook.md.

Already matched here:

  • Prepare a candidate with no traffic; live acceptance and promotion are separate gates.
  • A paid-operations kill switch that fails closed: the Worker passes anything other than "true" as "false". Condere's runtime keeps a compatibility default of enabled when the value is missing, so it binds the switch explicitly on every deploy.
  • Doppler is the operator source of truth, and runtime secrets are copied into the platform's secret store (Secret Manager there, Worker secrets here). The container never holds a DOPPLER_TOKEN.
  • A documented emergency stop and rollback. Condere's stop targets job names that its new release no longer creates. Ours cannot drift this way: the stop and the release both use deploy/cloudflare/wrangler.toml, so they target the same Worker.

Gaps found, and their state:

  1. Release only the exact origin/main commit. Condere's prepare script refuses anything other than a trusted, non-PR build whose HEAD equals origin/main. Closed: release.yml now fails unless dispatched from main at its current head.
  2. Keep release evidence. Condere saves preflight.json, previous.json (traffic before), candidate.json, and verification.json as build artifacts and fails if the candidate does not match. Closed: each release job uploads the Wrangler output, wrangler deployments status before and after, the candidate's wrangler versions view, and the commit and version id.
  3. Pin the image by digest. Condere deploys repository@sha256:… and records commit, digest, and acceptance source in the runtime environment. Wrangler builds and pushes our image during versions upload and pins it in the version; the evidence artifact keeps the version record. Whether that record shows the image digest is unverified until the first real upload.
  4. Secret sync should default to a dry run. Condere documented this pattern (sync_doppler_gcp_secrets.sh, list keys unless --apply), but that script was removed on 2026-08-24 and its syncs are now manual. Closed: scripts/sync-secrets.sh is now a dry run unless given --apply.
  5. Approve before preparing. Condere puts a manual block step before candidate preparation as well as before promotion. Our upload runs without approval; that is acceptable only while it cannot take traffic or spend.
  6. Before enabling paid work: one bounded live run with retained usage receipts (AeroAPI result sets, Browserbase minutes, ChatGPT plan usage), stop on uncertain cost, and pin the exercised version before moving traffic.

Checked against the shared playbook's pitfalls (AgenticEngineering/openwiki/deployment-playbook.md, the executed Condere spin-off deployment):

  • R2 checksums: fixed. artifacts.py now sets request_checksum_calculation and response_checksum_validation to when_required; R2 rejects botocore's default CRC checksums.
  • R2 key scope: at creation, round-trip an object in our bucket and confirm another bucket returns AccessDenied. The playbook observed an all-bucket key.
  • Neon pooler: verified. Our locks are transaction-scoped (pg_advisory_xact_lock) and every connection disables server-side prepared statements. The playbook sends DDL and the LangGraph checkpointer to the direct endpoint; here the full Postgres suite (57 tests, including checkpointer setup and the credential refresh lock) passed through the pooled endpoint of a throwaway branch of the new project on October 31, 2026.
  • Long MCP tool calls: closed. approve_dispatch can take about two minutes (Browserbase generation), and the playbook observed client timeouts. Agent turns now run in a background thread; a tool returns its result within 25 seconds or status: running, and the client polls turn_status. A container restart loses the in-memory turn (the checkpoint survives), and turn_status then reports not_found.
  • Cloudflare API token: CLI OAuth cannot mint API tokens; create the release token in the dashboard.
  • Rotating refresh token: handled. ifd-credentials import --move gives the deployment its own host id, removes the local session, and refreshes under a database lock.
  • Per-process limits: the AeroAPI rate limiter is in memory. That is correct while the Durable Object runs one container; it needs a database slot if more instances run.

Open owner decisions this raises:

  • CI provider. Condere's repository CI and release run on Buildkite, using workload identity federation instead of stored cloud keys. This repository uses GitHub Actions. Either works with Wrangler. Buildkite would match the portfolio; GitHub Actions avoids another agent queue for a single-user app.
  • Doppler layout. Condere uses one Doppler project per deployable with dev/stg/prd configs (intelip-agent-mcp, intelip_api). This deployment follows that pattern with its own infinite-flight-agent project, created after the October 31 consolidation freed slots.

Kill switch and emergency stop

  • Paid operations flag: IFD_PAID_OPERATIONS_ENABLED=false stops spending inside the Python server. Run Emergency stop, then also set it to false in Doppler, or the next release restores the old value.
  • Limits: wrangler secret put fails if an uploaded version is waiting for promotion (Wrangler refuses to edit secrets when the latest version is not deployed). Use the Cloudflare dashboard (Worker → Settings → Variables and Secrets → deploy) in that case, and do not leave uploads unpromoted. Requests already running continue until they finish; the container restarts with the new value on the next request. The flag does not revoke keys: for a leaked or compromised key, rotate it at the provider (OpenAI, AeroAPI, Browserbase, Neon, R2, LangSmith), update Doppler, and release.
  • Full stop: disable the Access application's Allow policy or the Worker route in the dashboard. Every request is then rejected at the edge.

Rollback

npx wrangler rollback <version-id> (or npx wrangler versions deploy <version-id>@100% -y) from deploy/cloudflare. Rollback cannot cross a Durable Object migration. Rolling back restores that version's code, secrets, and image reference; the Worker restarts the container on the next request.

Costs to watch

  • Cloudflare Containers: billed for CPU, memory, and disk while the instance runs (standard-1: 1/2 vCPU, 4 GiB); the 15-minute inactivity timeout limits idle time. Workers Paid base fee and request/Durable Object usage.
  • Browserbase session minutes (each SimBrief generation opens a cloud browser).
  • FlightAware AeroAPI per-result-set charges.
  • ChatGPT plan limits: the five-hour limit is shared with every app on the plan, including Codex.
  • Neon compute hours and R2 storage/operations (small at single-user volume).

ChatGPT-plan credentials

The OAuth callback goes to 127.0.0.1, so Sign in with ChatGPT runs locally (uv run ifd-login). Then import the resulting credential once into the deployment with ifd-credentials import (Python side; uses IFD_CREDENTIAL_KEY and DATABASE_URL). After import the deployed host owns refreshes; stop using the same credential locally. This follows OpenAI's self-hosted VM guidance: complete OAuth locally with the same client and user, transfer the protected credential over a secure channel, keep a stable host id on the server, and let the server own refreshes. OpenAI notes that host-specific usage attribution and revocation for transferred sessions are not yet available. Confirm the ChatGPT-plan terms permit this personal hosted use before enabling it.

Initial local checks (historical)

The container image builds for linux/amd64 and was run locally: /health returns ok, /mcp returns 401 without the internal token, an MCP client lists the two tools, and plan_flight returns paid_operations_disabled with the switch off. wrangler deploy --dry-run was validated only with a placeholder registry image. Those were pre-deployment checks. The resource setup above and current release record supersede their original deployment status.