No description
Find a file
dunemask b7e5bdffd4
Some checks failed
ci / check (push) Has been cancelled
[FEATURE] heph: podman, podman-kube + process backends (#5)
## Summary

Extends the pluggable-backend seam (Strategy + registry) from **2 kinds to 5**: `k8s | compose | podman | podman-kube | process`. `up.ts` and the verb dispatch stay backend-agnostic — each new kind is one registry entry + a validate hook.

### Backends
- **podman** — engine-parameterize the compose backend into `makeComposeBackend(engine, kind)`. `ComposeBackend` = docker engine (behavior byte-identical); `PodmanBackend` = podman engine, project root `~/.heph/podman-compose/`. Two-step availability check (podman + compose provider).
- **podman-kube** — pure k8s-YAML render run via `podman kube play` (no cluster/operator/CRDs). Play order is the dependency gate: infra → jobs (waited) → app group. Caddy Deployment w/ hostPort for routing (kube play ignores Ingress); pod-name aardvark DNS parity; `DOPPLER_TOKEN` injected only in-memory via stdin play (on-disk YAML token-free).
- **process** — bare host processes via process-compose. New per-service schema block `process: {command, cwd?}`. Source services run from the host toolchain (no image build); infra runs via `docker run --network host`. Per-project unix socket, host-port pool from :18080, host `doppler run` wrap, Caddy proxy. Fastest inner loop.

### Tooling
- Vendor **process-compose v1.120.0** into the Garden-style tools registry (auto-download to `~/.heph/tools/`, sha256-verified). `ensureToolInteractive` gates on an opt-in TTY prompt; non-interactive throws a `heph doctor --install-tools` hint (never silently downloads).
- Container engines (docker/podman) are **detect-and-guide** in `heph doctor` (`enginePrompt`), never auto-installed.
- Shared R5 floor `assertComposeSupported(eff, kind)` parameterized so rejects name the actually-selected backend.

### Tests
Per-backend render/validate suites + **backend-swap parity** (selection, validate consistency, render parity, CR-vs-local parity, project-dir isolation), backend-contract completeness (all 5 kinds implement the full `Backend` type), up.ts step-order (isolated child process), IO round-trips incl. the token-never-on-disk guarantee, process-compose registry + engine-prompt. **heph 750 tests (690 pass / 60 opt-in skip / 0 fail), operator 147 / 0 fail**, tsc + biome clean.

### Self-review fixes (adversarial review)
- **kube (major):** `waitContainersReady` counted pod-infra/init-wait helpers as satisfying "ready", returning before app containers started. Now gates on the count of long-running Deployments actually written (drift-proof).
- **process:** reserve author-pinned PORTs so a pin inside the pool can't collide; heph owns PORT for non-pinned source services (override to assigned port so app-bind == heph-route); doppler-wrap a source command under `sh -c` so compound commands stay inside the injected env, with shq-quoted project/config.

### Caveats
- Backends are unit/parity-tested only (podman + process-compose not installed in CI) — no live integration run.
- Deferred (docs/27): process backend has no Deployment→service manifest translation; kube single-container translate only.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: dunemask <elijah@apprabbit.com>
Reviewed-on: #5
Co-authored-by: dunemask <dunemask@noreply.forgejo.dunemask.dev>
Co-committed-by: dunemask <dunemask@noreply.forgejo.dunemask.dev>
2026-07-23 21:13:25 +00:00
.github/workflows [FEATURE] phase A complete: local mode, nuke, dashboard, integration tests 2026-04-29 20:24:01 -06:00
docs [FEATURE] heph: podman, podman-kube + process backends (#5) 2026-07-23 21:13:25 +00:00
heph [FEATURE] heph: podman, podman-kube + process backends (#5) 2026-07-23 21:13:25 +00:00
operator [FEATURE] heph: new verbs (wait/dev/snapshot/registry/show --resolved/doctor --check-crd) + bug fixes 2026-05-21 08:22:51 -06:00
spike [FEATURE] eph v0.1.0: ephemeral k8s env orchestrator 2026-04-27 16:14:52 -06:00
tests/integration [FIX] heph: bulletproof compose teardown (label fallback + clean project dir) 2026-07-07 12:59:57 -06:00
web [CHORE] Biome Format 2026-05-08 15:05:00 -06:00
.gitignore [FEATURE] phase A complete: local mode, nuke, dashboard, integration tests 2026-04-29 20:24:01 -06:00
AGENTS.md [FEATURE] heph: podman, podman-kube + process backends (#5) 2026-07-23 21:13:25 +00:00
biome.json [CHORE] Biome Format 2026-05-08 15:05:00 -06:00
bun.lock [CHORE] Biome Format 2026-05-08 15:05:00 -06:00
CHANGELOG.md [CHORE] Biome Format 2026-05-08 15:05:00 -06:00
CLAUDE.md [CHORE] phase 9: rename eph → heph + add architecture/navigation docs 2026-04-29 15:28:16 -06:00
package.json [FEATURE] heph G4a: compose I/O layer + docker-backed integration test 2026-07-06 17:24:51 -06:00
README.md [FEATURE] Targets & Deps & Extras (#3) 2026-05-13 23:40:09 +00:00

hephaestus

Spin up ephemeral Kubernetes environments per branch / PR / experiment. Cluster-agnostic. Free tools only. AI-driven CLI surface.

CLI binary is heph (and heph-mcp for the MCP server).

what it does

heph create pr-156 --target backend --source api:~/wt/api-PR156

→ writes .heph/envs/pr-156.yaml overlay (target: backend) → auto-creates a k3d cluster + embedded registry if none (~14s) → resolves the backend target's closure (services + manifests + charts + jobs) → builds source-built service images, pushes, applies → deploys infra services (postgres etc.) before pre-deploy jobs → wires a Cloudflare quick-tunnel; prints https://<random>.trycloudflare.com → syncs your source dir into the pod (sub-second hot reload) → heartbeats TTL so an in-cluster janitor cleans it up after 1h idle → tears itself down if you rm -rf the source dir

install

prerequisites:

tool required for
bun ≥ 1.2 yes runtime
docker yes image builds
kubectl yes apply manifests
k3d ≥ 5.6 only for cluster: auto / k3d:* local cluster + registry
helm only if you use charts: (helm releases) helm install/upgrade

setup:

git clone <this-repo>
cd hephaestus/heph
bun install
bun link            # makes `heph` and `heph-mcp` available on PATH

verify:

heph --help

quickstart

create heph.yaml in your project root (see heph/examples/heph.yaml):

project: myapp
cluster: auto
registry: auto
share: auto
ttl: 1h

image:
  base: oven/bun:1.2-alpine
  setup: ["sh -c '[ -f package.json ] && bun install --no-save || true'"]

services:
  api:
    kind: service
    source: ./services/api
    port: 3000
    cmd: [bun, run, server.ts]
    dependencies: [postgres]
    env:
      DATABASE_URL: postgres://app:app@postgres:5432/app?sslmode=disable
  postgres:
    kind: service
    image: postgres:16-alpine
    port: 5432
    env: { POSTGRES_USER: app, POSTGRES_PASSWORD: app, POSTGRES_DB: app }

targets:
  default:
    services: [api, postgres]

then:

heph create dev --target default
heph url dev          # https://<random>.trycloudflare.com
heph status dev       # pods, ttl, expires, url
heph logs dev api -f
heph shell dev api
heph down dev

docs

read in order. each file is one topic, AI-readable.

00-overview what + why
01-stack tools used (and rejected)
02-config-schema base + overlay model, merge rules
03-cli every command + flag
04-lifecycle TTL, heartbeat, janitor, source-watcher
05-sharing the five share modes
06-gotchas traps caught in the spike
07-spike-results timing numbers
08-next-steps what's done, what's deferred
09-research-summary landscape + decisions log

what's in the box

heph/                  CLI source (laptop-bound: build, sync, CR ops)
  src/
    cli/               command dispatch + each verb
    config/            schema (zod) + merge engine + global config
    cluster/           k3d auto-create / BYO context
    registry/          k3d push/pull split discovery
    build/             Dockerfile rendering, content-hash skip
    sync/              fs.watch → mtime-diff → tar → kubectl exec
    lifecycle/         TTL parsing, heartbeat (patches CR.spec.lastSeen)
    operator/          CR builder + apply + detection
    bootstrap/         tier-1 cluster reconcile (cert-manager, reflector)
    tls/               TLS provider × CA registry + auto-injection
    template/          ${var} substitution for manifests
    manifests/         raw + sealed-secret + sops + age apply paths (tier-1 + tier-2)
    charts/            helm chart apply path (tier-1 + tier-2)
    services/          apply-infra: prebuilt-image runtime services
    jobs/              pre/post-deploy Job render + apply
    slug/              readable + random slug generators
    mcp/server.ts      MCP server: one tool per CLI verb
  examples/heph.yaml   reference config
operator/              NestJS+Bun in-cluster operator
  src/
    environment/       CRD types + watch loop + reconcile
    render/            pure-fn manifest renderer
    apply/             server-side apply via k8s API
    share/             cloudflared / lan / ingress / tunnel / tailnet
    janitor/           interval-based TTL expiry
    webhook/           mutating admission webhook
    k8s/               typed k8s API clients (DI)
  manifests/           CRD + RBAC + Deployment + Webhook YAML
web/                   reserved (Vite + Chakra dashboard, v0.3+)
spike/                 original bash POC (kept for reference)
docs/                  AI-readable design + ops docs

MCP

bun run mcp (or installed bin heph-mcp) starts an MCP stdio server. Exposes one tool per CLI verb (heph_create, heph_up, heph_down, heph_touch, heph_url, heph_status, heph_logs, heph_patch, heph_ls, heph_show) plus heph://overlay/<name> resources for each overlay file.

To wire up Claude Desktop, add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):

{
  "mcpServers": {
    "eph": {
      "command": "heph-mcp",
      "cwd": "/absolute/path/to/your/project-with-heph.yaml"
    }
  }
}

Then in Claude: "spin up an env for branch foo with postgres" → calls heph_create.

The server's cwd must contain the heph.yaml you want to operate on. To operate on multiple projects, register one mcpServers entry per project with distinct names (e.g. eph-myapp, eph-otherapp).

status

v0.1.0 surface complete. acceptance criteria all green:

  • heph create deploys a working multi-service env
  • URL reachable from outside (Cloudflare quick-tunnel)
  • rm -rf source → teardown
  • TTL expiry → janitor cleanup (verified at 8min wall clock for ttl=6m)
  • N concurrent envs without collision

post-v0.1.0 deferrals are listed at the bottom of docs/08-next-steps.md.