Operational steps that need a real shell session. Each item is independent — knock them off in any order. All commands assume cd /home/eric/code/agentclip-app unless noted.
1. Refresh gh token to allow workflow pushes (blocks U19/U20)
gh auth refresh -s workflow
This unblocks pushing .github/workflows/*.yml files. Once done, ping me and I'll ship U19 (api-ci + web-ci GitHub Actions) and U20 (Lighthouse CI gate).
2. Confirm 1Password vault item exists
In 1Password, create item agentclip in vault Personal with these fields:
DJANGO_SECRET_KEY — python -c "import secrets; print(secrets.token_urlsafe(50))"
DATABASE_URL — the Neon connection string with ?sslmode=require
R2_ACCESS_KEY_ID — Cloudflare R2 token id
R2_SECRET_ACCESS_KEY — Cloudflare R2 token secret
R2_BUCKET — the bucket name (e.g. agentclip-media)
R2_ENDPOINT — https://<account-id>.r2.cloudflarestorage.com
R2_PUBLIC_HOST — cdn.agentclip.dev (the Cloudflare Worker route fronting R2)
WEB_DEPLOY_PLACEHOLDER — any value; satisfies the placeholder field in bin/.env.web.template
(Field names are referenced verbatim in bin/.env.api.template and bin/.env.web.template.)
3. Bootstrap Fly apps (one-time)
fly auth login
fly apps create agentclip-api
fly apps create agentclip-web
4. Push secrets from 1Password to Fly's vault
eval $(op signin) # if not already
bin/sync-secrets.sh api
bin/sync-secrets.sh web
5. First deploy
cd api && fly deploy --remote-only
cd ../web && fly deploy --remote-only
Each takes 2–5 minutes. The Django container runs manage.py migrate on startup, so the Neon DB will be schema-applied automatically.
6. Custom domains + SSL
fly certs add agentclip.dev --app agentclip-web
fly certs add www.agentclip.dev --app agentclip-web
fly certs add api.agentclip.dev --app agentclip-api
7. Cloudflare DNS
For each subdomain, add an A/AAAA record pointing at the Fly app hostname (fly ips list --app <app> shows the v4 + v6 IPs):
| Domain |
Target |
Proxy |
agentclip.dev |
agentclip-web Fly IPs |
Proxied (orange cloud) |
www.agentclip.dev |
same |
Proxied |
api.agentclip.dev |
agentclip-api Fly IPs |
Proxied |
cdn.agentclip.dev |
R2 bucket via Worker route |
(Cloudflare Worker, separate setup) |
8. Seed the gallery on prod
fly ssh console --app agentclip-api --command 'python manage.py seed_gallery'
9. Smoke test
curl -s -o /dev/null -w '%{http_code}\n' https://agentclip.dev/ # 200
curl -s -o /dev/null -w '%{http_code}\n' https://api.agentclip.dev/api/schema/ # 200
curl -s -o /dev/null -w '%{http_code}\n' https://api.agentclip.dev/api/v1/gallery/ # 200
curl -s -o /dev/null -w '%{http_code}\n' https://agentclip.dev/install.md # 200, text/markdown
10. Final cutover
This issue tracks the operational bring-up. Code-side work continues on main and lands via PR / direct push.
Operational steps that need a real shell session. Each item is independent — knock them off in any order. All commands assume
cd /home/eric/code/agentclip-appunless noted.1. Refresh
ghtoken to allow workflow pushes (blocks U19/U20)This unblocks pushing
.github/workflows/*.ymlfiles. Once done, ping me and I'll ship U19 (api-ci + web-ci GitHub Actions) and U20 (Lighthouse CI gate).2. Confirm 1Password vault item exists
In 1Password, create item
agentclipin vaultPersonalwith these fields:DJANGO_SECRET_KEY—python -c "import secrets; print(secrets.token_urlsafe(50))"DATABASE_URL— the Neon connection string with?sslmode=requireR2_ACCESS_KEY_ID— Cloudflare R2 token idR2_SECRET_ACCESS_KEY— Cloudflare R2 token secretR2_BUCKET— the bucket name (e.g.agentclip-media)R2_ENDPOINT—https://<account-id>.r2.cloudflarestorage.comR2_PUBLIC_HOST—cdn.agentclip.dev(the Cloudflare Worker route fronting R2)WEB_DEPLOY_PLACEHOLDER— any value; satisfies the placeholder field inbin/.env.web.template(Field names are referenced verbatim in
bin/.env.api.templateandbin/.env.web.template.)3. Bootstrap Fly apps (one-time)
4. Push secrets from 1Password to Fly's vault
5. First deploy
Each takes 2–5 minutes. The Django container runs
manage.py migrateon startup, so the Neon DB will be schema-applied automatically.6. Custom domains + SSL
7. Cloudflare DNS
For each subdomain, add an
A/AAAArecord pointing at the Fly app hostname (fly ips list --app <app>shows the v4 + v6 IPs):agentclip.devagentclip-webFly IPswww.agentclip.devapi.agentclip.devagentclip-apiFly IPscdn.agentclip.dev8. Seed the gallery on prod
fly ssh console --app agentclip-api --command 'python manage.py seed_gallery'9. Smoke test
10. Final cutover
git tag -a v0.1.0 -m 'v0.1.0' && git push --tagsagentclip-pythoncd ~/code/agentclip && uv build && uv publishThis issue tracks the operational bring-up. Code-side work continues on
mainand lands via PR / direct push.