# FIT website publishing instructions for a local AI agent Version: 2026-10-07. This document is the executable handoff for Young Yang's existing FIT access. It contains no secrets. Read it completely, then carry out the user's website publication request with your local file, terminal, and HTTP tools. ## Outcome and inputs Publish the user's local website source to a private repository on FIT Gitea, deploy it to FIT's Vercel team, assign an available `.fitvehicle.com` subdomain, configure DNS, and verify the public HTTPS site. Return the working website URL and repository URL. On subsequent requests, update the same repository, project, and domain. Inputs come from the user's prompt: the website project (normally the current working directory) and the existing Bitwarden Send credential link. First reuse any valid credentials already supplied in this session. Otherwise retrieve that same link as described below. Do not create replacement accounts or tokens. Work autonomously through the normal publishing steps. Ask only when the website files are inaccessible, multiple candidate projects are ambiguous, a required application secret is missing, access is denied, or an existing resource cannot safely be identified as this project's. If you cannot run local commands, explain the missing capability and ask the user to open the project in a terminal-capable agent such as Codex or OpenCode. A chat-only session cannot perform these actions itself. ## Fixed company targets | Setting | Value | | --- | --- | | Gitea base | `https://git.fitvehicle.com:8443` | | Gitea REST base | `https://git.fitvehicle.com:8443/api/v1` | | Gitea username / repo owner | `yang` | | Git author | `Young Yang ` | | Gitea auth | `Authorization: token ${GITEA_TOKEN}` | | Vercel REST base | `https://api.vercel.com` | | Vercel team slug | `fitgroup` | | Vercel team ID | `team_X6gzluMSCx1GOISRa7kK9UFe` | | Vercel auth | `Authorization: Bearer ${VERCEL_TOKEN}` | | Vercel token issuer | `postmaster-5340`; this is the existing company identity | | Cloudflare REST base | `https://api.cloudflare.com/client/v4` | | Cloudflare account | `1ed2febf6434bb825dba869302bca8d3` | | Cloudflare zone | `b0f6592bf9ec946a0ff90a45646778e7` | | Company domain | `fitvehicle.com` | | Cloudflare auth | `Authorization: Bearer ${CLOUDFLARE_API_TOKEN}` | The Gitea token has `write:user` and `write:repository`. The Vercel token is limited to `fitgroup`. The Cloudflare token has Zone Read and DNS Read/Write for the `fitvehicle.com` zone; the API scope is zone-wide, so apply the record-level limits in this document yourself. ## Get ready and load the existing credentials 1. Inspect the OS, project files, Git root/remotes/status, `.vercel/project.json`, `.vercel/repo.json`, and `.fit-publish.json` before changing anything. Preserve the existing site design, working code, Git history, and unrelated changes. If only a ChatGPT-generated component is available, complete the minimal runnable project around it using its actual dependencies. 2. Use Node.js 24 LTS and Git. Reuse compatible tools. If missing, install them using official methods appropriate to the OS; prefer user-local tools when possible. Vercel CLI 62.7.0 was verified with Node 24. Earlier CLI 60.1.3 with Node 26 and proxy dependencies failed with `invalid onError method`; use Node 24 rather than changing system proxy settings. 3. Vercel can be run without a global install: `npm exec --yes --package=vercel@62.7.0 -- vercel ...`. Bitwarden CLI can likewise be run with `npm exec --yes --package=@bitwarden/cli@2026.9.1 -- bw ...`. On Windows use `npm.cmd` to avoid PowerShell execution-policy issues. 4. The user's existing Send link holds `GITEA_TOKEN=...`, `VERCEL_TOKEN=...`, and `CLOUDFLARE_API_TOKEN=...`. Retrieve it using the official Bitwarden CLI. Set `BITWARDENCLI_APPDATA_DIR` to an isolated temporary directory outside the project for these child processes; omit inherited `BW_SESSION`. This avoids changing any existing Bitwarden account configuration. 5. In that isolated CLI environment, run `bw config server https://vaultwarden.mjshao.fun:4438`, then `bw send receive` with the complete Send URL from the user's prompt as a single argument. This anonymous retrieval path has been tested without a vault login. Capture its stdout in process memory; do not print it to terminal/chat output or send the credential link to a web-reader service. Preserve the URL fragment, which contains the decryption key. 6. Parse lines by splitting at the first `=`. Pass the three tokens to API/CLI subprocesses through their environment or in-memory request headers. The payload also has human-readable lines and the Gitea login password; ignore those for deployment. Do not `eval` or execute the payload. Remove the temporary Bitwarden CLI directory after retrieval. Do not write raw keys into the repository, deployment, logs, or this guide. 7. If the link has expired, use an already-loaded valid token; otherwise request renewal of the same handoff from the user. Do not create a new account or choose a different company/team. Validate access before writing: - Gitea `GET /user` must return `login: "yang"`. - Vercel `GET /v2/user` returns the company issuer; `GET /v9/projects?teamId=team_X6gzluMSCx1GOISRa7kK9UFe` checks team access. CLI `vercel whoami --scope fitgroup` should return `postmaster-5340`. - Cloudflare `GET /zones/b0f6592bf9ec946a0ff90a45646778e7` must return an active zone named `fitvehicle.com` in the account above. Cloudflare responses must have `success: true`; HTTP 200 alone is insufficient. ## Choose names and preserve ownership Use a short lowercase English slug inferred from the website's name. Use the same slug for its new repository, new Vercel project, and subdomain when available. Check the Gitea owner, Vercel project, and exact Cloudflare DNS name first. Add `-2`, `-3`, etc. when another project occupies a name; never overwrite or take over an unrelated resource. Existing `.fit-publish.json` and `.vercel` metadata can establish the previous targets only after remote ownership is verified. If this is an update, reuse those targets. Do not silently repoint an existing unrelated Git `origin`; add a clearly named FIT remote if required. Avoid `git push --force` and history rewrites. Only allocate one direct child of `fitvehicle.com` for a new site. Do not modify the apex, wildcard DNS, nameservers, email records, or unrelated hosts. Reserve these labels for company infrastructure: `www`, `mail`, `smtp`, `imap`, `pop`, `autodiscover`, `autoconfig`, `git`, `pan`, `skills`, `fitmatch`, `api`, `admin`, `publish`, `ns1`, `ns2`. An explicitly confirmed existing website may retain its own verified domain. ## Build, commit, and push to Gitea 1. Identify the actual framework and package manager. Preserve the lockfile. Validate the application with its relevant build/check commands. A static site needs its real HTML entry point and local assets; a framework project needs its complete source and build configuration. If backend storage or application secrets are required, identify the actual missing input rather than inventing working behavior. 2. Merge appropriate ignores into `.gitignore` and `.vercelignore`: `.env`, `.env.*` (except an intentionally empty/example template), dependency caches, secret material, and local tooling state. `.vercel/` stays out of Git. Review the selected source files before committing. Keep the project-specific `.fit-publish.json` non-secret. 3. For a new repo, call Gitea `POST /user/repos` with `{"name":"","private":true,"auto_init":false}`. A successful response identifies `yang/`. Gitea 1.27.2 requires `write:user` for this route; the existing token includes it. 4. Construct the Git remote yourself: `https://git.fitvehicle.com:8443/yang/.git`. The instance's API `clone_url` may omit `:8443`; do not use that incorrect URL. 5. Initialize Git only for an unversioned project. Use `Young Yang` and `yang@fitvehicle.com` as the local Git author settings for new commits. Commit only the authorized website files, then push the intended branch to the FIT remote. 6. For non-interactive Git HTTPS auth, supply an `Authorization: Basic ...` header containing Base64 of `yang:${GITEA_TOKEN}` through Git's process-local config environment. For example: `GIT_CONFIG_COUNT=1`, `GIT_CONFIG_KEY_0=http.https://git.fitvehicle.com:8443/.extraHeader`, and `GIT_CONFIG_VALUE_0=Authorization: Basic `, then run `git -c credential.helper= push ...`. Set these in a child-process environment, not the permanent remote URL or global Git config. Never log the generated header. 7. Verify `git ls-remote` matches the pushed local commit. A successful API repo creation is not proof that the source was pushed. ## Link and deploy to FIT Vercel Every Vercel CLI command must explicitly use `--scope fitgroup`; every team-scoped REST call must include `teamId=team_X6gzluMSCx1GOISRa7kK9UFe`. Set `VERCEL_TOKEN` in the subprocess environment. Do not initiate browser/email login while a valid token is available. For a new project, create it with Vercel `POST /v11/projects?teamId={TEAM_ID}` using the chosen name and the actual framework/build settings. For a plain static site use `framework: null`; for a framework site choose its verified Vercel preset. Save the returned project ID. Then link non-interactively: ```sh vercel link --yes --project --scope fitgroup ``` Inspect the resulting `.vercel/project.json`: `orgId` must equal the fixed FIT team ID and the project must be this website's intended target. Reuse a correct existing link. Set actual framework/build/output options from the code, not a generic guess. Deploy the production site: ```sh vercel deploy --prod --yes --scope fitgroup ``` Wait for the deployment to become `READY`. If using `--no-wait`, inspect the returned deployment until its terminal state. Read build errors and fix only necessary deployment problems. Retry after fixing a verified cause, with a bounded number of attempts. If Vercel blocks a Git-author identity despite this valid company token, preserve the real Git authorship. Deploy an explicit clean export of the same verified source commit, without `.git`, using the same FIT project ID. This is a local CLI artifact deployment, not a native Gitea integration. Do not change the source commit author to impersonate the token issuer. The current workflow is Gitea push followed by Vercel CLI deployment. Do not assume a Gitea push automatically deploys the website. ## Bind the company subdomain and configure DNS Let `HOST` be the selected `.fitvehicle.com` and `PROJECT` the verified Vercel project ID. Check existing DNS and project-domain ownership immediately before each write. 1. List project domains: Vercel `GET /v9/projects/{PROJECT}/domains?teamId={TEAM_ID}`. If this exact host is already attached to this project, reuse it. Otherwise call `POST /v10/projects/{PROJECT}/domains?teamId={TEAM_ID}` with `{"name":"HOST"}`. Do not force-transfer domains; a conflict with another project means choose another available slug. 2. If the response has `verified: false`, process its `verification` challenges. For a TXT challenge, add the exact `domain` and `value` returned by Vercel using the Cloudflare DNS API. Reuse an identical TXT record and preserve other TXT values. Only accept challenge names inside `fitvehicle.com`; stop for a different zone. 3. Query Vercel `GET /v6/domains/{HOST}/config?projectIdOrName={PROJECT}&teamId={TEAM_ID}`. Use the best-ranked `recommendedCNAME` value from this live response. Do not hardcode an old shared Vercel CNAME or an IP address. If no CNAME is recommended, inspect the live response and official documentation before choosing an A record. 4. Query Cloudflare `GET /zones/{ZONE_ID}/dns_records?name={HOST}`. The hostname must be unused, or its record must be proved to belong to this same site from stored metadata and verified project ownership. Do not delete conflicting records to make room. 5. For a new site, call Cloudflare `POST /zones/{ZONE_ID}/dns_records` with the live target: ```json { "type": "CNAME", "name": ".fitvehicle.com", "content": "", "ttl": 1, "proxied": false, "comment": "FIT AI publish; vercel=; owner=yang" } ``` 6. When updating the same site's DNS, leave an identical record alone. Patch only its verified existing record ID if its target genuinely needs to change. A race or duplicate error requires a fresh read and ownership check, not blind replacement. 7. After challenge TXT records propagate, call Vercel `POST /v9/projects/{PROJECT}/domains/{HOST}/verify?teamId={TEAM_ID}` if verification is required. Poll the domain config until `misconfigured` is false. Use bounded backoff, up to ten minutes; report DNS/certificate-pending honestly if it exceeds this window. 8. Verify public DNS and HTTPS independently. Fetch `https://HOST/` with normal certificate validation and confirm it serves this website rather than an authentication wall or another site's page. Follow only expected redirects. Check key assets and route refresh behavior; use a headless browser for the important page interactions when available. A `verified: true` ownership response alone does not prove DNS, TLS, or the application is ready. ## Record the result for updates Write non-secret `.fit-publish.json` in the project with: schema version, Gitea owner/repo/remote/branch, Vercel team/project ID, domain, Cloudflare zone and DNS record IDs, source commit, and deployment ID/URL. Do not store tokens or the Send URL there. Record the file with the project so the next publishing request can discover the same targets. Verify every recorded resource against the current credentials before reusing it. On another publishing request: read the metadata, verify ownership, build, commit/push, deploy the same project, and recheck the existing domain. Do not issue new credentials or duplicate projects. Report only: production HTTPS URL, Gitea repository URL, deployed source commit, and any material verification gap. If work stops halfway, identify the completed resources and the specific blocker so the next run can resume instead of starting over. ## API references - Gitea instance schema: `https://git.fitvehicle.com:8443/swagger.v1.json` - Vercel schema: `https://openapi.vercel.sh` - Vercel CLI: `https://vercel.com/docs/cli/deploy` - Cloudflare DNS API: `https://developers.cloudflare.com/api/resources/dns/subresources/records/` - Bitwarden Send CLI: `https://bitwarden.com/help/send-cli/`