Prompt: publish a static site from ci with the ird cli
Have an agent wire your CI pipeline (GitHub Actions or GitLab CI) to
publish a static site to the ird IPFS gateway on every push: an API key
kept in the CI secret store, the ird CLI run non-interactively, the
build pinned, the IPNS name re-pointed, the previous root unpinned, and
the job failing loudly on any error — with a working YAML snippet.
Needs: the ird CLI, logged in with your account (ird keys refuses API keys); an IPNS name + hostname already created for the site (the static-site-ipfs prompt); write access to the repo's CI settings
Costs: hourly per MB pinned plus per MB served (credits_prices → recurring.ipfs-pin-hourly); creating the key and publishing the name have no price-book line
Group: hosting
Paste everything below the line into a fresh conversation. Fill in the
FILL IN block first.
Task
Produce a CI job that publishes FOLDER to HOST on every push to BRANCH
with a dedicated API key. Creating the key and the name happens once, by
hand; CI only pins and publishes.
FILL IN
HOST: docs.example.ro # hostname of an existing IPNS name (ipns_list shows it active)
CI: github # github | gitlab
BRANCH: main # pushes to this branch publish
BUILD: npm ci && npm run build # produces FOLDER
FOLDER: ./dist # index.html at its root
KEY_NAME: ci-docs-202609 # API key name: job + creation month
Non-negotiable rules
- The key is shown once and never stored in the repo.
ird keys
create takes a name and nothing else — no scopes — so the key is
account-wide. Relay it to me in step B, then never repeat it (files,
YAML, logs, deliverable).
- Non-interactive means
--json --yes --no-input. --no-input
makes a prompt fail the job instead of hanging it; --yes answers
confirmations, so the script runs only the commands listed here.
- Fail on anything.
set -euo pipefail, an empty CID aborts, the
new root is fetched by CID before the name moves, the previous root
is unpinned only after a successful publish.
- No first-time setup from CI.
ipns_list must already show HOST
active; otherwise stop — the static-site-ipfs prompt comes first.
Steps
A. Baseline. ird whoami (session); ird ipfs ipns ls --json —
HOST present and active. One key per job.
B. Key. ird keys create KEY_NAME. Show me the key once and where it
goes: GitHub → repository Settings → Secrets → Actions; GitLab →
Settings → CI/CD → Variables, masked and protected. Name: IRD_API_KEY.
C. CLI in the job. The CLI help doesn't document distribution:
install ird the way its docs describe, pinned to a version; the job's
first check is ird whoami --json --no-input — it must name my account.
D. Deploy script (deploy.sh, committed, executable):
#!/usr/bin/env bash
set -euo pipefail
HOST="docs.example.ro"; FOLDER="./dist"
IRD="ird --json --yes --no-input"
PREV=$($IRD ipfs ipns ls | jq -r --arg h "$HOST" '.names[] | select(.label==$h) | .target_cid')
$IRD ipfs add "$FOLDER" --name "site:$HOST"
PIN=$($IRD ipfs pins --search "site:$HOST" --status pinned --limit 100 | jq -c '.pins | sort_by(.created_at) | last')
CID=$(jq -r '.cid // empty' <<<"$PIN"); URL=$(jq -r '.gateway_url // empty' <<<"$PIN")
[ -n "$CID" ] || { echo "no pinned site:$HOST" >&2; exit 1; }
[ "$CID" = "$PREV" ] && { echo "unchanged $CID"; exit 0; }
curl -fsS "$URL/index.html" -o /dev/null
$IRD ipfs ipns publish "$HOST" "$CID"
[ -n "$PREV" ] && [ "$PREV" != null ] && $IRD ipfs unpin "$PREV"
echo "published $CID"
ird ipfs add --json field names are undocumented, so the script
reads the new pin back from ird ipfs pins --json (cid,
gateway_url, created_at, as shown).
E. Pipeline. GitHub Actions (.github/workflows/publish.yml):
name: publish
on: { push: { branches: [main] } }
jobs:
publish:
runs-on: ubuntu-latest
env: { IRD_API_KEY: ${{ secrets.IRD_API_KEY }} }
steps:
- uses: actions/checkout@v4
- run: npm ci && npm run build
- run: <install ird — step C>
- run: ird version && ird whoami --json --no-input
- run: ./deploy.sh
GitLab CI (.gitlab-ci.yml):
publish:
stage: deploy
image: node:20
rules: [{ if: $CI_COMMIT_BRANCH == "main" }]
script:
- npm ci && npm run build
- <install ird — step C>
- ird version && ird whoami --json --no-input
- ./deploy.sh
The CLI reads IRD_API_KEY from the environment; no --api-key on the
command line (logs).
F. First run and verify. Push to BRANCH. Then ird ipfs ipns ls
--json — target_cid equals the job's CID; ird ipfs pins --search
site:HOST --json — exactly one pinned entry; curl -sI https://HOST
returns 200 once the DNSLink cache expires. A second push with no
changes must exit 0 with unchanged.
G. Rotation. Every 90 days: new key, replace the secret, run a
build, then ird keys revoke <old id> — it stops working immediately.
Leak: revoke first (the api-keys-automation prompt).
Deliverable
KEY_NAME and its id (never the key), the secret's location, deploy.sh
and the pipeline file, the first run's CID, the pin list for
site:HOST, and the rotation date.