Objective
Rebuild local generated infrastructure so one app owns one complete Minikube cluster, named by the canonical app slug, and all app-owned infrastructure runs inside that cluster in clean Kubernetes namespaces.
Current unwanted model:
Docker host
├── minikube # shared by all apps
└── <slug> # Supabase CLI / Compose group
├── supabase_db_<slug>
├── supabase_auth_<slug>
├── supabase_storage_<slug>
└── ...
Target model:
Docker host
└── <slug> # Minikube profile / app-owned cluster
└── Kubernetes
├── namespace: app
│ └── app-runtime
├── namespace: supabase
│ ├── postgres
│ ├── auth
│ ├── rest
│ ├── storage
│ ├── realtime
│ ├── gateway
│ ├── studio
│ └── other required Supabase workloads
└── namespace: <other-infra-adapter>
└── adapter-owned workloads
A second app creates a second isolated cluster:
Docker host
├── uwm
│ ├── namespace: app
│ └── namespace: supabase
└── chess
├── namespace: app
└── namespace: supabase
The cluster is the app ownership boundary. Kubernetes namespaces are the provider/adapter ownership boundaries inside the app.
Hard requirements
- No legacy path.
- No deprecation layer.
- No compatibility aliases or fallback behavior.
- Remove the shared default Minikube profile
minikube.
- Remove host-level Supabase runtime ownership through
supabase start / supabase stop.
- Do not leave a hybrid architecture with app runtime in Kubernetes and Supabase beside it in Docker Compose.
- Canonical app slug is the Minikube profile identity.
- Generated app runtime belongs in namespace
app.
- Supabase-owned workloads belong in namespace
supabase.
- Future self-hosted infrastructure adapters own their own deterministic namespaces.
- External SaaS such as Stripe is not deployed as local provider containers; only Ankhorage-owned integration workloads, if any, belong in an internal namespace.
- Update every downstream dependency and consumer. No stale generated scripts, docs, package versions, or assumptions.
- Strict TypeScript only: no
any, no ts-ignore, no ESLint disables, no weakening strictness.
- One complete PR per affected repository. Do not auto-merge.
Current code paths to replace
Search the entire Ankhorage repository set for all dependencies on:
MINIKUBE_PROFILE
- literal profile
minikube
supabase start
supabase stop
supabase status
SUPABASE_PROJECT_DIR
- host-level Supabase port allocation
supabase_*_<slug> container assumptions
- current Kubernetes namespace assumptions
- Infra Up/Down/Status APIs and scripts
Relevant Infra areas include at least:
src/adapters/minikube/index.ts
src/adapters/minikube/base/index.ts
generateMinikubeInfra
generateMinikubeBaseArtifacts
getUpScript
getDownScript
getStatusScript
getSupabaseLocalEnvScript
- generated
infra/minikube/**
Do not assume this list is exhaustive.
1. Cluster naming and lifecycle
For app slug uwm, all Minikube operations must target:
For app slug chess:
The slug must consistently drive:
- start
- status
- stop
- destructive cleanup
- kubectl context
- image load/build
- port-forward
- diagnostics
- generated docs
No command for one app may target another app's cluster.
2. Namespace model
Minimum namespaces:
The architecture must support later adapter-owned namespaces such as:
payments
monitoring
search
messaging
Do not use the app slug as the Kubernetes namespace just because the cluster used to be shared. The slug now identifies the whole cluster.
3. Kubernetes-native Supabase runtime
Remove host-level Supabase Compose runtime from generated Infra Up. supabase start must no longer own the local runtime.
Implement the selected local Supabase stack as Kubernetes workloads in namespace supabase.
Before implementation, Codex must check the current Supabase changelog and official self-hosting/deployment documentation. Do not copy stale image topology or environment configuration from memory.
Define one canonical source for:
- pinned Supabase images/versions
- Postgres
- Auth
- PostgREST
- Storage
- Realtime
- gateway/API routing
- Studio if included
- analytics/vector/metadata/edge runtime when required
- Secrets and ConfigMaps
- persistent volumes
- readiness/liveness
- service discovery
- startup order
Do not blindly reproduce every container from supabase start if the official self-hosted topology or Ankhorage capability set does not require it.
After Infra Up there must be no host-level runtime containers named like supabase_*_<slug>.
4. Networking
Explicitly separate:
- in-cluster service URLs
- host/browser-accessible development URLs
Example:
app workload -> Supabase gateway through Kubernetes DNS
browser/host -> localhost:<project-specific-port> -> exposed Supabase gateway
Two app clusters must run simultaneously without port collisions.
Choose one canonical exposure mechanism; do not add multiple compatibility fallbacks.
Must remain reachable where applicable:
- Supabase API/Auth gateway
- Storage
- Studio
- generated app runtime
OAuth PKCE/deep-link callbacks must be revalidated.
Never expose service-role/secret credentials to the browser. Public app env receives only the public URL and appropriate public/anon/publishable key.
5. Persistence and database lifecycle
Supabase Postgres must run inside the app cluster under namespace supabase.
Define explicit behavior for:
- Infra Up
- Infra Down
- restart
- app deletion
- destructive reset
Ordinary Down must not accidentally destroy persistent app data unless that is the explicitly documented contract. Destructive cleanup must target only the selected app cluster.
6. Preserve migrations and Auth functionality
The new lifecycle must preserve this sequence:
- start/create app cluster
- deploy Supabase namespace workloads
- wait for database readiness
- apply immutable migrations
- apply generated profile reconciliation when enabled
- verify disabled-profile state when disabled
- apply/verify Supabase Vault integration when selected
- verify schema
- resolve public/runtime endpoints and keys
- wire generated app env/config
- build/load/deploy application
Must continue to work:
- email/password sign-up
- email/password sign-in
- persisted sessions
- OAuth PKCE when configured
auth.users
- generated
public.profiles
- Storage
- Supabase Vault
The Supabase CLI may still be used as a migration/development tool where appropriate, but never as owner of a separate host-level runtime stack.
7. App namespace
Move generated application Kubernetes resources to namespace app:
- Deployment
- Service
- ConfigMaps
- Secrets
- image pull secrets
- rollout/scaling
- status
- port-forward
Update every generated kubectl -n ... command accordingly.
8. Rewrite Infra lifecycle
Infra Up
resolve canonical slug
-> ensure Minikube profile <slug> is running
-> select <slug> kubectl context
-> create required namespaces
-> deploy adapter-owned infrastructure
-> wait for readiness
-> run migrations/reconciliation
-> expose required local endpoints
-> resolve public/runtime env
-> build/load app image
-> deploy app namespace
-> wait for readiness
-> report URLs and health
Infra Status
Must report only the target app:
- Minikube profile state
app namespace health
supabase namespace health
- database connectivity
- migration/profile state
- endpoint availability
- required config/secrets
Do not use host-level supabase status as runtime detection.
Infra Down / Delete
Operate only on minikube -p <slug>. Stopping/deleting uwm must never affect chess.
9. Delete obsolete host-stack code
Remove, not deprecate:
- generated
supabase start
- generated
supabase stop --no-backup
- unconditional stale-stack retry
- host-level Supabase runtime detection
- host-level per-app Compose ownership
- obsolete port-preflight logic
- obsolete
SUPABASE_PROJECT_DIR runtime ownership assumptions
- docs/tests for the old architecture
If a Supabase project directory remains useful for migrations/config authoring, clearly separate authoring from runtime ownership.
10. Adapter composition
The architecture must generalize as:
<app-slug> cluster
├── app
├── <infra-adapter-a>
├── <infra-adapter-b>
└── ...
Each self-hosted adapter may contribute only what it owns:
- namespace
- Kubernetes resources
- dependencies/order
- readiness
- public endpoint requirements
- Secrets/ConfigMaps
Keep this model minimal and deterministic. Do not invent a large new plugin framework unless the existing architecture already has the correct extension point.
11. Downstream dependency updates
This issue is not complete when only @ankhorage/infra compiles.
Inspect and update at minimum:
ankhorage/infra
Primary implementation, tests, docs, changeset.
ankhorage/studio
Update released @ankhorage/infra dependency plus any host assumptions, status parsing, port-forward/runtime diagnostics, generated paths and smoke tests. No fallback to old Infra behavior.
ankhorage/templates
Verify generated apps consume the new endpoint/env contract; update only as required.
ankhorage/contracts
Change only if the canonical manifest genuinely needs explicit new adapter/namespace/runtime metadata. Do not add compatibility fields.
ankhorage/ankh, orchestrator, CLI and other consumers
Search for all Minikube profile, Infra lifecycle, generated file and runtime URL assumptions.
For every published repo changed:
- complete PR
- Changeset
- release in dependency order
- downstream dependency bump only after upstream release
- lockfile update
- full validation
Final implementation must work with released packages, not only local workspace links.
Codex execution phases
Phase A — inventory and design proof
Before editing:
- map Studio -> Infra -> generated scripts -> Minikube/Supabase current call chain
- search all repos for old lifecycle assumptions
- check current official Supabase changelog/docs
- identify required self-hosted Supabase workload graph
- define namespaces
- define startup/readiness order
- define host/browser endpoint exposure and collision avoidance
- define persistence semantics
Document this map in the Infra PR description.
Phase B — complete Infra rewrite
Implement the new architecture fully in ankhorage/infra. Do not create a halfway hybrid state.
Phase C — release Infra
Run gates, review, merge, release new @ankhorage/infra version.
Phase D — update consumers
One complete PR per affected repo, in dependency order, consuming released upstream versions.
Phase E — clean-state end-to-end proof
Create uwm, Infra Up, then create chess, Infra Up.
Expected Docker-level ownership:
Not:
minikube
uwm -> host Supabase Compose containers
chess -> host Supabase Compose containers
Inside each cluster, verify namespaces and pods independently.
Then prove lifecycle isolation:
Down uwm -> chess remains healthy
Up uwm -> chess unchanged
Delete/reset uwm -> chess unchanged
Required acceptance criteria
Cluster ownership
Namespace ownership
Runtime ownership
Supabase/Auth
Security/env
App runtime
Diagnostics/performance
Automated tests
Add focused tests for at least:
- slug -> Minikube profile
- no shared profile default
app and supabase namespace generation
- no generated
supabase start
- no host stale-stack retry
- Up/Down/Status target
-p <slug> only
- distinct profiles for two apps
- adapter namespace composition
- networking/public endpoint generation
- secrets/public env separation
- migration/profile/Vault ordering
- cleanup isolation
Add opt-in integration tests for actual Minikube/Kubernetes/Supabase startup where CI cost is too high, but document and run them for final verification.
Validation gates
Run canonical gates in every modified repo, including where available:
bun run build
bun run test
bun run typecheck
bun run lint
bun run format:check
bun run knip
bun run docs
Also run Changeset/package validation and npm pack --dry-run for published packages where appropriate.
Do not claim completion from unit tests alone.
Definition of done
Complete only when:
uwm creates Minikube profile/container uwm.
uwm contains namespaces app and supabase.
- Supabase workloads run inside
supabase.
- No separate host Supabase Compose group exists for
uwm.
chess creates a separate independent Minikube cluster.
- Up/Down/Status/Delete are isolated by slug.
- Fresh generated app sign-up/sign-in works.
- Existing migrations, profile reconciliation, Vault, Storage and OAuth are verified.
- Every affected repo consumes the released dependency chain.
- All old shared-cluster/host-Supabase runtime code is removed, not deprecated.
- Documentation describes only the new architecture.
- Final clean-state report includes Docker containers, Minikube profiles, namespaces, pods, endpoints, auth proof and lifecycle-isolation proof.
Codex final report
Explicitly report:
- repositories changed
- PRs created
- released versions/dependency order
- old architecture removed
- new cluster/namespace ownership model
- clean-state commands used
- Docker state after one app and two apps
- namespace/pod listings
- proof no host-level
supabase_*_<slug> runtime containers remain
- sign-up/sign-in proof
- isolation proof between two apps
- all validation results
- any remaining limitation stated explicitly
Objective
Rebuild local generated infrastructure so one app owns one complete Minikube cluster, named by the canonical app slug, and all app-owned infrastructure runs inside that cluster in clean Kubernetes namespaces.
Current unwanted model:
Target model:
A second app creates a second isolated cluster:
The cluster is the app ownership boundary. Kubernetes namespaces are the provider/adapter ownership boundaries inside the app.
Hard requirements
minikube.supabase start/supabase stop.app.supabase.any, nots-ignore, no ESLint disables, no weakening strictness.Current code paths to replace
Search the entire Ankhorage repository set for all dependencies on:
MINIKUBE_PROFILEminikubesupabase startsupabase stopsupabase statusSUPABASE_PROJECT_DIRsupabase_*_<slug>container assumptionsRelevant Infra areas include at least:
src/adapters/minikube/index.tssrc/adapters/minikube/base/index.tsgenerateMinikubeInfragenerateMinikubeBaseArtifactsgetUpScriptgetDownScriptgetStatusScriptgetSupabaseLocalEnvScriptinfra/minikube/**Do not assume this list is exhaustive.
1. Cluster naming and lifecycle
For app slug
uwm, all Minikube operations must target:For app slug
chess:The slug must consistently drive:
No command for one app may target another app's cluster.
2. Namespace model
Minimum namespaces:
The architecture must support later adapter-owned namespaces such as:
Do not use the app slug as the Kubernetes namespace just because the cluster used to be shared. The slug now identifies the whole cluster.
3. Kubernetes-native Supabase runtime
Remove host-level Supabase Compose runtime from generated Infra Up.
supabase startmust no longer own the local runtime.Implement the selected local Supabase stack as Kubernetes workloads in namespace
supabase.Before implementation, Codex must check the current Supabase changelog and official self-hosting/deployment documentation. Do not copy stale image topology or environment configuration from memory.
Define one canonical source for:
Do not blindly reproduce every container from
supabase startif the official self-hosted topology or Ankhorage capability set does not require it.After Infra Up there must be no host-level runtime containers named like
supabase_*_<slug>.4. Networking
Explicitly separate:
Example:
Two app clusters must run simultaneously without port collisions.
Choose one canonical exposure mechanism; do not add multiple compatibility fallbacks.
Must remain reachable where applicable:
OAuth PKCE/deep-link callbacks must be revalidated.
Never expose service-role/secret credentials to the browser. Public app env receives only the public URL and appropriate public/anon/publishable key.
5. Persistence and database lifecycle
Supabase Postgres must run inside the app cluster under namespace
supabase.Define explicit behavior for:
Ordinary Down must not accidentally destroy persistent app data unless that is the explicitly documented contract. Destructive cleanup must target only the selected app cluster.
6. Preserve migrations and Auth functionality
The new lifecycle must preserve this sequence:
Must continue to work:
auth.userspublic.profilesThe Supabase CLI may still be used as a migration/development tool where appropriate, but never as owner of a separate host-level runtime stack.
7. App namespace
Move generated application Kubernetes resources to namespace
app:Update every generated
kubectl -n ...command accordingly.8. Rewrite Infra lifecycle
Infra Up
Infra Status
Must report only the target app:
appnamespace healthsupabasenamespace healthDo not use host-level
supabase statusas runtime detection.Infra Down / Delete
Operate only on
minikube -p <slug>. Stopping/deletinguwmmust never affectchess.9. Delete obsolete host-stack code
Remove, not deprecate:
supabase startsupabase stop --no-backupSUPABASE_PROJECT_DIRruntime ownership assumptionsIf a Supabase project directory remains useful for migrations/config authoring, clearly separate authoring from runtime ownership.
10. Adapter composition
The architecture must generalize as:
Each self-hosted adapter may contribute only what it owns:
Keep this model minimal and deterministic. Do not invent a large new plugin framework unless the existing architecture already has the correct extension point.
11. Downstream dependency updates
This issue is not complete when only
@ankhorage/infracompiles.Inspect and update at minimum:
ankhorage/infraPrimary implementation, tests, docs, changeset.
ankhorage/studioUpdate released
@ankhorage/infradependency plus any host assumptions, status parsing, port-forward/runtime diagnostics, generated paths and smoke tests. No fallback to old Infra behavior.ankhorage/templatesVerify generated apps consume the new endpoint/env contract; update only as required.
ankhorage/contractsChange only if the canonical manifest genuinely needs explicit new adapter/namespace/runtime metadata. Do not add compatibility fields.
ankhorage/ankh, orchestrator, CLI and other consumersSearch for all Minikube profile, Infra lifecycle, generated file and runtime URL assumptions.
For every published repo changed:
Final implementation must work with released packages, not only local workspace links.
Codex execution phases
Phase A — inventory and design proof
Before editing:
Document this map in the Infra PR description.
Phase B — complete Infra rewrite
Implement the new architecture fully in
ankhorage/infra. Do not create a halfway hybrid state.Phase C — release Infra
Run gates, review, merge, release new
@ankhorage/infraversion.Phase D — update consumers
One complete PR per affected repo, in dependency order, consuming released upstream versions.
Phase E — clean-state end-to-end proof
Create
uwm, Infra Up, then createchess, Infra Up.Expected Docker-level ownership:
Not:
Inside each cluster, verify namespaces and pods independently.
Then prove lifecycle isolation:
Required acceptance criteria
Cluster ownership
minikubeclusterNamespace ownership
appnamespace existssupabasenamespace exists when selectedsupabaseappRuntime ownership
supabase_*_<slug>host runtime containerssupabase startSupabase/Auth
Security/env
App runtime
appDiagnostics/performance
Automated tests
Add focused tests for at least:
appandsupabasenamespace generationsupabase start-p <slug>onlyAdd opt-in integration tests for actual Minikube/Kubernetes/Supabase startup where CI cost is too high, but document and run them for final verification.
Validation gates
Run canonical gates in every modified repo, including where available:
bun run build bun run test bun run typecheck bun run lint bun run format:check bun run knip bun run docsAlso run Changeset/package validation and
npm pack --dry-runfor published packages where appropriate.Do not claim completion from unit tests alone.
Definition of done
Complete only when:
uwmcreates Minikube profile/containeruwm.uwmcontains namespacesappandsupabase.supabase.uwm.chesscreates a separate independent Minikube cluster.Codex final report
Explicitly report:
supabase_*_<slug>runtime containers remain