Repository navigation
First tagged GitHub Release of agentic-hosting.
Squash-merged in #157 (eb0bb9da).
[0.6.0] - 2026-10-15
Added
ahcCLI client: cross-platform command-line tool (install:curl -fsSL https://agentic.hosting/install-cli.sh | bash). Commands:deploy(Docker images or git repos, with build log streaming),service,env(create, exec, stop, delete),db,build,status(exit codes for CI),snapshot, andregister/key.AH_ADMIN_TOKEN: an operator token (comma-separated for rotation) required forPOST /v1/auth/recover,POST /v1/tenants/{id}/reactivateandPATCH /v1/tenants/{id}/quotas. Send it asX-Admin-Token, or in the old bootstrap-token slot.scripts/bootstrap-stack.sh: installer for a fresh Ubuntu host. It generates the master key, bootstrap token and a separate admin token. Seedocs/ops/fresh-install.md.- Mac mini setup:
scripts/bootstrap-macmini.shand the first-run guide indocs/ops/macmini.md, plus the OpenRouter agent example inexamples/openrouter-agent/. - Documentation site: Astro docs in
docs-site/covering the live/v1/API and operations, with a GitHub Pages workflow at.github/workflows/docs.yml. InstaBox compatibility findings are indocs/investigations/. - Agent onboarding:
llms.txtandllms-full.txtat the repo root (also served at/llms.txton the docs site) and a standalone skill atskills/agentic-hosting/SKILL.md. - Usage metering collector: samples CPU and memory of running services every 60s into the metering database.
AH_METER_DB_PATHis honored when set. - MIT license at the repository root (Copyright 2026 Dennison Bertram), with a license badge and License section in the README.
- README demo GIF of the local
ah --devloop: register a tenant, deploy from git, tail logs, and see the service running (docs/assets/demo.gif).
Changed
- Master key rotation no longer invalidates API keys. API key hashes now use a dedicated HMAC key stored encrypted in the new
server_secretstable (seeded from the current master key, so existing keys keep working).ah rotate-keyre-encrypts it and applies state migrations first. - Service, database and environment quotas are enforced atomically (the count is inside the INSERT), so concurrent creates can no longer exceed
max_services,max_databasesormax_environments.tenant_quotas.api_rate_limitis now enforced per tenant (burst 2x, cached 30s with the auth lookup). - Long routes (log follow, build logs, DB/kanban/environment create, sync, exec) leave the global 200-request throttle and get a per-tenant cap of 4 concurrent requests (429 beyond). Write deadlines are 60s per request, renewed per write on streaming routes. The server-wide 30s
WriteTimeoutis removed, so log follow, exec and sync are no longer cut off. - Idempotency middleware serializes concurrent requests with the same key (waiters replay the first response) and evicts the tenant's oldest entry at the per-tenant cap instead of skipping storage.
- Health
?fresh=trueis limited to one live probe per 10s, concurrent probes share one result, and the disk check uses the configured data directory. ah backupkeeps the newest 10 state and 10 metering backups separately, opens the source database read-only, and accepts relative paths.- Garbage collection keeps tenant networks younger than 15 minutes or with stopped containers, and removes unused built and snapshot images (over 1h old, unreferenced) and anonymous volumes. Container ownership is checked by ID across all tables.
- Databases are pulled before start and get memory and pids limits,
no-new-privilegesand a reduced capability set. ah.servicecan write to/etc/traefik/dynamic.- Docs (README, homepage, Claude skill and commands,
website/install.sh) now match the live API. The audit list is indocs-site/CORRECTIONS.md.
Fixed
scripts/bootstrap-stack.shbuilds the website image from the repository root. The website Dockerfile copiesdocs-site/andllms*.txtfrom the root, so building withwebsite/as the context failed. The website container now serves the docs site athttps://agentic.hosting/docs/.- Database delete no longer has a 30s limit. Postgres deletes returned 500 under gVisor because container stop and volume wipe exceeded the request timeout. Delete cleanup now runs detached from the request, with a 1 minute budget for container stop and remove, 5 minutes for the volume wipe and 1 minute for volume removal.
POST /v1/auth/recoverhonorsX-Bootstrap-Token. Previously only the body field was read, so a bootstrap token sent in the header got 401. All three token slots now go through the same check, and bootstrap tokens get 403 consistently whenAH_ADMIN_TOKENis set.- Reconciler: crashes are counted from Docker
RestartCountacross ticks so the circuit breaker trips; crashed services stay watched and return to running; unhealthy containers are restarted instead of stopped; status updates are compare-and-swap; not-found detection uses typed errors instead of matching "404"; failed environment lease stops are retried. - Service lifecycle: the circuit breaker opens only after the container is stopped and removed;
Restartmarks the rowrestartingbefore stopping, so the reconciler no longer counts phantom crashes; deploys and restarts never overwrite an open circuit or reuse the old restart baseline;Deleteaborts if the container cannot be removed. Build-triggered deploys take the per-service lock, refuse when the circuit breaker is open, and fall back to name-based cleanup of the old container. /redeployworks for services with no container (after a failed deploy, failed restart or circuit reset). Deleting a service with snapshots works. Snapshot restore skips the registry pull when the image is local. Failed restarts no longer leave deployments stuck asdeploying. Rename keeps thePORToverride in the Traefik route.- Failed
/restartand/redeployreturn 502deploy failed: <reason>instead of 500. - Builds: cancel cancels the build context, never overwrites a finished build, and a cancelled build no longer deploys. Cancelling a build that is already deploying returns 409. Deployment cancel works only for
pendingrows, and cancel and status updates can no longer overwrite each other. Build log streams no longer leak subscribers, hang, or repeat a line from the initial snapshot; lines over 256KB no longer hang a build; logs are written in batches instead of one UPDATE per line. - Environments: claimed warm-pool containers are renamed to the tenant environment name and kept by GC; pool refill no longer blocks
Acquire, prunes rows that point to missing containers, and GC removesah-pool-volumes andah.type=warm-poolcontainers;Create()acquires pre-warmed containers (creation is under 200ms when the pool has capacity); exec timeouts are enforced and settimed_out; tenant suspend stops environments and previews on a detached 5-minute context and no longer marks an environment stopped when the Docker stop failed;Createre-checks that the tenant is active; failed warm-pool adoption cleans up on a detached context; workspace sync is killed in-container after its timeout; previews are capped at 5 per environment. - Databases and kanban: Redis create no longer fails (the readiness check now authenticates); a NULL
container_idno longer causes 500 on Get, Delete or reconcile;RunDatabasefalls back to a cached image when the pull fails; failed (re)starts remove the new container (volume kept); suspension also removes database containers of failed rows; a failed kanban can be re-created (its volume is deleted only if setup never completed), and a kanban setup failure isfailed, notready; tenant reactivation restarts databases and kanban from their stored volumes and credentials, and skips tenants that are no longer active. - Volume wipe:
WipeVolumeoverwrites each file with exactly its own size instead of writing until the disk is full. It uses pinned, pulledbusybox:1.36under gVisor with no network, dropped capabilities and memory/pids limits, and is force-removed on timeout. - Image pulls now return pull-stream errors, and
RemoveContainerremoves anonymous volumes. ahc: uses the server's real statuses (databaseready, service and buildfailed), fails deploys on failed builds, merges environment and file config per field and saves it atomically (0600), honors long exec and create timeouts, propagatesenv execexit codes, and verifies the installer download againstchecksums.txt.ahc register --savewrites~/.ah/config.jsonwith theurlandkeyfields thatahclient.LoadConfigreads (it wrote~/.ahc/config.jsonwithapi_keyandserver_url).ah rotate-key --dry-runno longer applies migrations, and the rotation total counts the API key hash key.install-cli.shno longer errors on its temp-dir trap underset -u.--listen-addr ::1works (IPv6 host:port join).- Metering:
memory_mb_avgis a real average (it was a sum); CPU baselines are keyed by container and advance only after a successful write; stats calls are bounded to 10s; a missing container is logged once. Idempotency cleanup keeps in-flight entries. Short routes share one throttle pool of 200, and streaming routes clear a stale write deadline. The rate limiter's get-or-create is atomic (fixes a data race).
Security
- With
AH_ADMIN_TOKENset, bootstrap tokens get 403 on recover, reactivate and quota update, and keep working for tenant registration. If it is unset, bootstrap tokens are still accepted for those routes, with a startup warning (deprecated, to be removed). - Requests with an invalid token no longer consume the global 20/hour budget, the startup log no longer prints rejected-token characters, and a key revoked during an auth DB read can no longer be re-cached as active.
ValidateImagetakes the tenant ID:localhostregistries are rejected, and local-registry refs must be the caller's ownah/<tenant>-build orsnapshots/<tenant>:image.- Service names starting with
env-are reserved for environment preview hosts.
Removed
scripts/deploy.sh,scripts/status.sh,scripts/logs.shandscripts/db-provision.sh. Useahc.
Upgrade notes
- Two new state migrations run on first start:
state_020_server_secretsandstate_020_restart_count. Back up first withah backup. - Set
AH_ADMIN_TOKEN(at least 32 characters per token; a shorter token stops startup) in/etc/default/ah. Without it the service starts but accepts bootstrap tokens for recover, reactivate and quota update and logs a deprecation warning. - Service names starting with
env-and images fromlocalhost/registries are rejected. - Deleting a service now also deletes its snapshots.
- Cancelling a build returns 409 once it is deploying, and deployment cancel works only for pending deployments.
- Failed deploys (
/restart,/redeploy) return 502 instead of 500. scripts/deploy.sh,status.sh,logs.shanddb-provision.share gone; switch toahc deploy,ahc status,ahc build logsandahc db provision.
Install the CLI:
curl -fsSL https://agentic.hosting/install-cli.sh | bash