FlickDocumentation
flkr

Continuous integration

Publish Flick views from GitHub Actions using a delegated PKI credential.

Run flkr publish on merges to main to deploy your app’s Flick views. A delegate credential authorizes the job to publish specific view URIs under your app’s trust root until its expiration.

The runner signs publications with the delegate private key and sends its Biscuit. Flick verifies the grant against the public key published for your trust root.

Set up your trust root

Complete Public-key infrastructure first: declare the trust-root URL in Swift, publish its public key through HTTPS or DNS, and save the root private key in 1Password.

1. Create a publishing credential

With flkr installed, run this on your Mac from the app’s Xcode project directory:

flkr delegate --expires-in-days 365

By default, flkr reads the root key at op://Private/Flick SDK Root Authority/password and creates a delegate key pair. Its signed Biscuit authorizes that pair to publish the app’s currently declared view URIs.

The grant expires after 365 days by default. Set --expires-in-days to choose another lifetime.

The command writes flick.credentials.json and adds that default filename to .gitignore. The JSON contains the delegate private key, its Biscuit, and the trust-root and expiration metadata needed for publishing.

2. Save the credential in GitHub

In your app’s repository, open Settings → Secrets and variables → Actions → New repository secret. Name it FLICK_PUBLISHING_CREDENTIAL_JSON and paste the entire file as its value.

Or use the GitHub CLI from that repository:

gh secret set FLICK_PUBLISHING_CREDENTIAL_JSON < flick.credentials.json

3. Add the publish workflow

The job compiles your Flick sources against the generated app API. Commit that API alongside flicks/src/, its package files, and its lockfile. This example uses npm:

Repository layout
MyApp/
├── .github/workflows/publish-flicks.yml
├── MyApp.xcodeproj
├── MyApp/
│   └── MyApp+Flick.swift
├── generated/
│   ├── manifest.json
│   ├── package.json
│   └── src/
│       ├── index.js
│       └── index.d.ts
└── flicks/
    ├── package.json
    ├── package-lock.json
    ├── tsconfig.json
    └── src/
        └── card.tsx

After changing the Swift integration, run flkr locally and commit the refreshed generated/ files. --host ./generated tells CI to use that snapshot, keeping the publish job independent of an Xcode build.

Compiler access

The publish job needs access to a Flick compiler and its S3-compatible runtime store. Contact hi@flick.fyi to arrange access for CI.

Add the supplied values under Settings → Secrets and variables → Actions:

GitHub settingNameValue
VariableFLKR_TSGO_URLCompiler URL reachable from the runner
SecretFLKR_TSGO_PRIVATE_KEYCompiler request-signing key
VariableRUNTIME_AWS_ENDPOINT_URL_S3Shared runtime store’s S3 endpoint
VariableRUNTIME_AWS_REGIONStore region, or auto for a service that uses it
SecretRUNTIME_AWS_ACCESS_KEY_IDShared runtime store access key
SecretRUNTIME_AWS_SECRET_ACCESS_KEYShared runtime store secret key

The store credentials need read and write access to crayon-blobs/runtime/. The delegate credential authorizes app publications; these additional credentials authorize compilation and shared-runtime storage.

GitHub Actions

Save this file at the repository root. It publishes on changes to the Flick sources or generated API on main, and supports a manual run from the Actions tab.

.github/workflows/publish-flicks.yml
name: Publish Flicks

on:
  push:
    branches: [main]
    paths:
      - 'flicks/**'
      - 'generated/**'
      - '.github/workflows/publish-flicks.yml'
  workflow_dispatch:

permissions:
  contents: read

concurrency:
  group: publish-flicks
  cancel-in-progress: false

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7

      - uses: actions/setup-node@v7
        with:
          node-version: '24'
          package-manager-cache: false

      - name: Install flkr and view dependencies
        run: |
          npm install --global @flickfyi/flkr
          npm ci --prefix flicks

      - name: Publish all declared views
        env:
          FLICK_PUBLISHING_CREDENTIAL_JSON: ${{ secrets.FLICK_PUBLISHING_CREDENTIAL_JSON }}
          FLKR_TSGO_URL: ${{ vars.FLKR_TSGO_URL }}
          FLKR_TSGO_PRIVATE_KEY: ${{ secrets.FLKR_TSGO_PRIVATE_KEY }}
          RUNTIME_AWS_ENDPOINT_URL_S3: ${{ vars.RUNTIME_AWS_ENDPOINT_URL_S3 }}
          RUNTIME_AWS_REGION: ${{ vars.RUNTIME_AWS_REGION }}
          RUNTIME_AWS_ACCESS_KEY_ID: ${{ secrets.RUNTIME_AWS_ACCESS_KEY_ID }}
          RUNTIME_AWS_SECRET_ACCESS_KEY: ${{ secrets.RUNTIME_AWS_SECRET_ACCESS_KEY }}
        run: |
          umask 077
          printf '%s' "$FLICK_PUBLISHING_CREDENTIAL_JSON" > "$RUNNER_TEMP/flick.credentials.json"
          flkr publish --host ./generated --credential "$RUNNER_TEMP/flick.credentials.json"

Open Actions → Publish Flicks to inspect a run. A successful run prints Published card for the example above. Your app receives the publication under its declared trust root.

Every declared view must have an implementation in flicks/src/. Views publish one at a time: if a later publication fails, the job fails and earlier successful publications remain deployed.

To publish one view, add its URI from generated/manifest.json:

flkr publish --host ./generated --credential "$RUNNER_TEMP/flick.credentials.json" \
  --view 'apple:bundle-id:com.acme.myapp/myApp#views/card'

Renew the credential

Renew before the JSON’s expiresAt date, or after adding or renaming views. A credential’s grant contains the view URIs present when it was issued.

From the app’s project directory, create a replacement in a temporary directory and update the same secret:

credential_dir="$(mktemp -d)"
flkr delegate --expires-in-days 365 --output "$credential_dir/flick.credentials.json"
gh secret set FLICK_PUBLISHING_CREDENTIAL_JSON < "$credential_dir/flick.credentials.json"

The next run uses the replacement credential. Both grants remain valid until their expiration while the root public key remains authorized.

Troubleshooting

ErrorFix
Publishing credential has expiredGenerate a new credential and update the GitHub secret
Credential trust root does not matchGenerate the credential for the trust-root URL in this app’s generated API
Missing view implementationsAdd an implementation for every declared view, or select one with --view
No discovered root authorizes this publicationCheck the public-key discovery document, view grant, and credential expiration
Compiler connection failureSet FLKR_TSGO_URL to a service reachable from GitHub; flkr defaults to a local compiler
Shared runtime publication requires …Set the named runtime-store variable or secret in the repository