You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs(deployments/basilica): embedding the lifecycle in your app (#232)
Adds an "Embedding in your app (skip GitHub Actions)" section covering
the alternative integration mode for apps that already have a worker /
queue and don't want the Actions wrapper.
Covers:
- Why skip the workflow (no public log surface, lower latency, native
error handling, app-owned trigger semantics)
- Distribution options (vendor, submodule, future pip-installable,
reimplement against basilica-sdk directly)
- Library API at a glance with a complete provision example,
subsequent status / update / deprovision shapes
- Subprocess invocation for language-agnostic callers (Node / Go /
Rust / Ruby)
- Async wrapping (asyncio.to_thread adapter for FastAPI / Starlette)
- Background-worker pattern (Celery / RQ / dramatiq / etc.) — the
recommended production shape with idempotent re-entry, retries,
state persistence
- Error handling table (ValueError / RuntimeError / TimeoutError
semantics + when to retry)
- Secret handling without the workflow (direct dict-passing, never
serialised to logs)
- BASILICA_API_TOKEN auth + rotation
- When to still use the workflow (no worker yet, audit, ops, prototype)
No code changes; documentation-only.
Copy file name to clipboardExpand all lines: deployments/basilica/README.md
+264Lines changed: 264 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -290,6 +290,270 @@ tenant-supplied values).
290
290
Basilica. Treat the Basilica account as a trust boundary; revoke + rotate
291
291
any tenant key that leaks if the account is compromised.
292
292
293
+
## Embedding in your app (skip GitHub Actions)
294
+
295
+
The GitHub Actions workflow is a convenience wrapper around `lifecycle.py`.
296
+
If your app already has a worker / queue / scheduler, you can drive
297
+
provisioning directly and skip the workflow entirely. Reasons you might
298
+
want this:
299
+
300
+
- **Zero public log surface** — workflow runs in a public repo leak
301
+
tenant IDs, URLs, and timestamps; in-process leaves no public trace.
302
+
- **Lower latency** — no Actions runner cold-start (typically 10–30s of
303
+
startup before the CLI even runs).
304
+
- **Tighter secret handling** — bearers never leave the app's process or
305
+
its secret store; nothing rides through GitHub's webhook surface.
306
+
- **Native error handling** — Python exceptions instead of parsing
307
+
step-output JSON.
308
+
- **Your app's auth/RBAC/idempotency** wraps the trigger — no
309
+
duplicate dispatch issues.
310
+
311
+
### Dependency footprint
312
+
313
+
Just two pip packages:
314
+
315
+
```bash
316
+
pip install basilica-sdk PyYAML
317
+
```
318
+
319
+
`PyYAML`is only needed if you load configs from YAML files; if you
320
+
construct `TenantSpec` directly in code, you can drop it.
321
+
322
+
### Distribution options
323
+
324
+
| Option | When |
325
+
|---|---|
326
+
| **Vendor** `deployments/basilica/{__init__,lifecycle,cli}.py` + `configs/examples/*.yaml` into your app's repo | Simplest; ~700 LoC total. Lets your app evolve the library independently. Pin the upstream commit in a comment for traceability |
327
+
| **Git submodule / subtree** | If you want upstream changes to flow in semi-automatically |
328
+
| **`pip install git+https://github.com/techlab-innov/llmtrace.git`** | Not currently set up — the repo isn't packaged as a pip-installable; would need a top-level `pyproject.toml` exposing `deployments.basilica`. Open an issue if you want this |
329
+
| **Re-implement using `basilica-sdk` directly** in your app's language (Node, Go, Rust, etc.) | If your app isn't Python. The Python library is ~400 LoC of wrapping; the underlying SDK is what does the work. See `lifecycle.py:213-249` (`_create_component`) for the minimum shape |
| `TimeoutError` | `startup_timeout_seconds` elapsed without ready | 5xx; check Basilica's UI for stuck deployment; consider a manual `deprovision` to clean up |
506
+
507
+
The CLI maps both `RuntimeError` and `TimeoutError` to exit code 3 with
508
+
the message in the JSON output. From a subprocess caller, key on the exit
509
+
code rather than parsing the error string.
510
+
511
+
### Secret handling without the workflow
512
+
513
+
When the workflow runs, the `Inject tenant secrets` step + `::add-mask::`
514
+
machinery exists to keep per-tenant values out of public logs. In your
515
+
app, you can do better: keep the values in process memory, pass them
516
+
directly into the `ComponentSpec.env` dict, and never serialise them to
517
+
anywhere except the Basilica API call itself.
518
+
519
+
Recommended pattern:
520
+
521
+
1. Stripe webhook arrives with `tenant_id` + plan.
522
+
2. App fetches per-tenant secrets from its store (Vault / AWS Secrets
523
+
Manager / encrypted Postgres column).
524
+
3. Worker builds `ComponentSpec.env` with the resolved values.
525
+
4. `lifecycle.provision()` ships them once to Basilica's
526
+
`create_deployment`.
527
+
5. The values are never logged. (Basilica stores them as deployment
528
+
env — that's the boundary the Basilica account owns.)
529
+
530
+
No environment variables, no `${VAR}` substitution layer, no GitHub
531
+
secrets. Just dict-passing. This is the cleanest secret-flow path you
532
+
can build.
533
+
534
+
### Auth — how the app holds `BASILICA_API_TOKEN`
535
+
536
+
The token is the only platform-side credential. Store it the same way
537
+
your app stores its other infrastructure secrets (env var, secret
538
+
manager, IAM-role-derived). Pass it to `make_client(api_key=...)`
539
+
explicitly, or set `BASILICA_API_TOKEN` in the worker's env and let
540
+
`make_client()`pick it up.
541
+
542
+
Rotate periodically. Compromised token = whoever holds it can list /
543
+
read / modify / delete every tenant's deployment. Treat it like a root
544
+
key.
545
+
546
+
### When to still use the workflow
547
+
548
+
- You don't have a worker infrastructure yet and want to get a first
549
+
tenant up without writing one.
550
+
- You want GitHub's audit log of every dispatch (in addition to your
551
+
app's own log) — useful for compliance.
552
+
- You want operators to fire ad-hoc lifecycle ops via the `gh` CLI from
553
+
their laptop.
554
+
- You're in early prototyping and the workflow's 25-minute timeout is a
555
+
useful safety net.
556
+
293
557
## Provider examples
294
558
295
559
Per-tenant `tenant_secrets` shape for each provider. The proxy forwards
0 commit comments