---
title: Code Apps and Registry operator runbook
description: Operate Cuitty Code Apps, Registry, SpiceDB, and Airflow in self-hosted deployments.
section: Code
order: 41
updatedAt: 2026-05-24
slug: code/operator-runbook
---
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

1. Start the database.
2. Start SpiceDB.
3. Load the SpiceDB schema.
4. Start Cuitty Auth.
5. Start Airflow.
6. Run Cuitty Git API migrations, then start the API.
7. Start the Cuitty Git frontend.

## Environment variables

```bash
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:

```bash
cargo run -p git-server -- migrate
```

Verify the API starts with the expected database URL and no pending migration errors.

## SpiceDB checks

```bash
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:

```sql
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

```bash
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/
```

```toml
[registries.cuitty]
index = "sparse+http://localhost:4351/api/v1/cargo/index/"
```

```bash
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:

```bash
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:

```bash
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 stale `processing` rows to `pending` only 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 `submitted` or `running`: 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 `404` versus `403`: `404` can be correct when the caller lacks view permission; `403` means the caller can see the resource but lacks the requested operation permission.

## Related pages

- [Self-Hosted Registry](/docs/code/self-hosted-registry)
- [Cuitty Code Apps](/docs/code/apps)
- [Code App Market](/docs/code/app-market)
- [Code Registry](/docs/code/registry)
- [Authorization with SpiceDB](/docs/code/authz-spicedb)
- [App execution with Airflow](/docs/code/app-execution-airflow)