Code Apps and Registry operator runbook
Operate Cuitty Code Apps, Registry, SpiceDB, and Airflow in self-hosted deployments.
This runbook covers local and self-hosted operation for Code Apps, App Market, Code Registry, SpiceDB authorization, and Airflow execution.
Required services
| Service | Purpose | Local default |
|---|---|---|
| Cuitty Git API | REST API, git HTTP, app, registry, and callback endpoints | http://localhost:4351 |
| Cuitty Git frontend | Browser UI | http://localhost:4350 |
| Cuitty Auth | OAuth/OIDC sign-in | http://localhost:7705 |
| Database | Persistent metadata and run state | Deployment-specific |
| SpiceDB | Relationship authorization | http://localhost:50051 |
| Airflow | App run orchestration | http://localhost:8080 |
| Registry artifact storage | Package tarballs, crates, wheels, and image layers | Deployment-specific |
| Object storage | Optional backing storage for large artifacts and logs | Deployment-specific |
Startup order
- Start the database.
- Start SpiceDB.
- Load the SpiceDB schema.
- Start Cuitty Auth.
- Start Airflow.
- Run Cuitty Git API migrations, then start the API.
- Start the Cuitty Git frontend.
Environment variables
PUBLIC_API_URL=http://localhost:4351
PUBLIC_CUITTY_AUTH_URL=http://localhost:7705
AUTH_ISSUER=http://localhost:7705
AUTH_CLIENT_ID=cuitty-git
CUITTY_PUBLIC_URL=http://localhost:4350
CUITTY_GIT_SECRET_KEY=dev-secret-change-me
SPICEDB_ENDPOINT=http://localhost:50051
SPICEDB_PRESHARED_KEY=dev-secret
AIRFLOW_URL=http://localhost:8080
AIRFLOW_USERNAME=airflow
AIRFLOW_PASSWORD=airflow
CUITTY_APP_EXECUTION_MODE=airflow
CUITTY_APP_RUN_CALLBACK_SECRET=dev-callback-secret
REGISTRY_STORAGE_URL=file:///var/lib/cuitty/registry
Migrations
Run migrations before traffic reaches a new API build:
cargo run -p git-server -- migrate
Verify the API starts with the expected database URL and no pending migration errors.
SpiceDB checks
zed schema write spicedb/schema.zed
zed permission check user:alice read repository:acme/demo
zed permission check user:alice view package:acme/npm/acme-widget
zed permission check user:alice install app_listing:acme/review-bot
Inspect failed authorization relationship writes:
SELECT id, operation_kind, resource_kind, resource_id, status, attempts, last_error
FROM authz_outbox
WHERE status IN ('pending', 'processing', 'failed_retryable', 'failed_terminal')
ORDER BY created_at ASC
LIMIT 50;
Registry client smoke checks
npm config set @acme:registry http://localhost:4351/api/v1/npm/
npm publish --registry http://localhost:4351/api/v1/npm/
npm install @acme/button --registry http://localhost:4351/api/v1/npm/
[registries.cuitty]
index = "sparse+http://localhost:4351/api/v1/cargo/index/"
cargo publish --registry cuitty
twine upload --repository-url http://localhost:4351/api/v1/pypi/ dist/*
docker push localhost:4351/acme/image:tag
Airflow checks
Submit or trigger an app run, then confirm the run has an Airflow DAG ID and DAG run ID. Reconcile submitted runs when callbacks are delayed:
curl -X POST http://localhost:4351/api/v1/apps/runs/reconcile -H "Authorization: Bearer $CUITTY_TOKEN"
Callback failures usually mean the timestamp is stale, the x-cuitty-signature HMAC is wrong, or Airflow is signing with a different secret than CUITTY_APP_RUN_CALLBACK_SECRET.
Playwright E2E
From the Cuitty Git tests directory, run the mocked market, registry, and social specs:
bun run test:e2e:apps-registry -- --project=chromium
bun run test:e2e:apps-registry:headed
The specs set browser auth state and mock API responses by path, so they cover both direct API calls on http://localhost:4351/api/v1/... and frontend-proxied calls on http://localhost:4350/api/v1/....
Failure modes and recovery
- SpiceDB unavailable: pause security-expanding app, registry, and transfer writes; restore SpiceDB; drain the authz outbox.
- Authz outbox backlog: inspect
last_error, reset staleprocessingrows topendingonly after confirming no dispatcher is active, and restart the dispatcher. - Airflow DAG submission failure: check
AIRFLOW_URL, credentials, DAG ID derivation, API logs, and Airflow scheduler/webserver logs. - App run stuck in
submittedorrunning: poll Airflow for the DAG run ID, check task logs, verify callback delivery, and run reconciliation. - npm publish succeeds but artifact is missing: check package version records, artifact storage, API logs, and upload temp directories.
- Private package returns
404versus403:404can be correct when the caller lacks view permission;403means the caller can see the resource but lacks the requested operation permission.