lace-app-sdk
Clone the repo & run locally
Graduated apps are real git repos. Clone them, run them locally against an emulator, and push them back through the same release pipeline.
Clone
terminalbash
lace-app clone acme.field_intake
cd field_intake
ls -la
# app/ lace_app_manifest.json LaceApp.yaml compose.yaml ui/ tests/
lace-app clone <app> [--dir DIR]— mints a short-lived git credential viaGET /v1/apps/{app_id}/git-credentialand clones with an ephemeral helper.- Never stores a raw GitHub token — the helper is scoped to the single
git cloneinvocation. - If credential minting fails, it degrades to a plain
git cloneso advanced git setups still work.
Run locally — lace-app dev
terminalbash
lace-app dev --port 8080
# → boots compose.yaml (postgres/minio/nats/redis + api)
# → mounts app/ into the runtime emulator, runs migrations, mounts routes at /apps/<app_id>/api/*
curl http://localhost:8080/apps/acme.field_intake/api/notes | jq
lace-app dev is the local emulator (APB-020). It:
- Reads
compose.yaml(copied fromsrc/lace_app_sdk/templates/lace_compose.yaml) and boots Postgres, MinIO/S3, NATS, and Redis. - Creates a local
.lace/state dir: dev credentials pointer,lace_app_manifest.jsoncache, build artifacts, and a launcher at.lace/_dev_app.py. - Runs migrations via the app's
migration_provider(if declared), registers collections throughAppDataService, and mounts route/agent providers at/apps/<app_id>/api/*. - Watches
app/for changes (reload).
Flags: --port PORT, --dir DIR. Requires the runtime extra for migration-apply: pip install lace-app-sdk[runtime]. Without it, dev still boots but warns about skipped migrations.
What the repo looks like on disk
field_intake/
├── app/
│ ├── __init__.py
│ ├── data.py # AppDataCollectionSchema (typed collections)
│ ├── tools.py # @tool handlers + AppToolDescriptor
│ ├── agents.py # AgentDefinition + AppAgentProvider
│ ├── routes.py # AppRouteProvider (FastAPI routes)
│ └── migrations.py # AppDataMigrations
├── ui/ # federated runtime-UI (if declared)
├── lace_app_manifest.json # canonical manifest (what you publish)
├── LaceApp.yaml # sidecar / deploy descriptor
├── compose.yaml # local dev stack (from templates/lace_compose.yaml)
├── .lace/ # local state: credentials, dev AppState, build cache
└── tests/ # proof-lane fixtures
The local stack
compose.yaml is a slimmed version of the platform's own compose. You can docker compose up it directly, but lace-app dev wraps that plus the emulator bootstrap so routes and agents resolve the same way they do in the sidecar.
| Service | Why it runs locally |
|---|---|
postgres | AppDataService collections + platform stores |
minio | Blob store for put_blob / get_blob + UI bundles |
nats | Event bus for dataset/KG events |
redis | Cache + distributed locks |
api + frontend | Only if you run the full platform; lace-app dev is lighter — just the app sidecar |
Inner-loop workflow
- Edit
app/data.py,app/tools.py,app/agents.py, orapp/routes.py. - Hit
GET /apps/<app_id>/api/noteslocally or use the federated UI at/apps/<app_id>/. - Run proof lanes:
lace-app test(see testing). - Push:
lace-app push(polls CI releases) orlace-app deploy --cloud(direct seal/upload/activate, AFV-016).
Troubleshooting
lace-app devwarns about missing runtime — installpip install lace-app-sdk[runtime]inside the repo or in the sidecar.- Port in use —
lace-app dev --port 8081. - State bleed between apps — each app gets its own
.lace/; wipe it withrm -rf .laceto re-bootstrap.
Next: what gets installed or jump to the SDK itself.