Desired-state infrastructure management from your terminal or an AI agent.
Hypervibe is a desired-state infrastructure orchestrator with two interfaces over one engine: a human/automation-friendly CLI and an MCP server for Codex and Claude. Both use the same specs, reviewed plans, provider adapters, connections, receipts, and audit history.
You: "Deploy my app to staging with a postgres database"
Claude: Creates Railway project, provisions Postgres, wires DATABASE_URL,
deploys your code, sets up health checks, returns the URL.
Infrastructure Providers
- Railway - Deploy apps, Postgres databases, Redis caches, private S3-compatible storage buckets, cron jobs, queues
- Google Cloud - Cloud Run hosting and Cloud SQL Postgres
- Amazon RDS - Managed Postgres with operation-scoped diagnostic ingress
- Supabase - Managed Postgres with direct or pooled connectivity
- Cloudflare - DNS management, domain configuration
- Stripe - Payment integration, webhooks, products
- SendGrid - Email authentication, domain verification
- Twilio - Messaging Services, webhook callbacks, existing-number attachment
- reCAPTCHA convention - Value-free site/secret key slots in every repo-backed project's
.env.example
Secret Managers
- HashiCorp Vault - KV secrets with versioning
- AWS Secrets Manager - Native rotation support
- Doppler - Simple config management
Workloads & Queues
-
Services declare
workloadKind: web | worker | cron. Workers are always-on background consumers (on Cloud Run: internal-only ingress, minimum one instance; they must still listen onPORT). -
queuesin the spec declares named message queues: Cloud Run environments get real Pub/Sub topics + subscriptions (apps receiveQUEUE_TOPIC_*/QUEUE_SUBSCRIPTION_*); Railway environments are postgres-backed (pg-boss model — requires a declared database; apps consume viaDATABASE_URL). Every queue environment getsQUEUE_BACKENDandQUEUE_NAMES. -
storagedeclares named private object buckets and an explicitinjectIntoservice list. Railway is the first storage provider and works with Railway or cross-provider hosting. Selected services receive the standardAWS_ENDPOINT_URL,AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AWS_S3_BUCKET_NAME,AWS_DEFAULT_REGION, andAWS_S3_URL_STYLEvariables; credentials never appear in specs, bindings, plans, or tool output. Bucket deletion is data-bearing and confirmation-gated. -
cache: { provider: "railway", engine: "redis" }declares Redis independently from SQL/document databases. Hypervibe wiresREDIS_URL; cache deletion is data-bearing and confirmation-gated."storage": { "documents": { "provider": "railway", "type": "bucket", "region": "sjc", "injectInto": ["web", "worker", "cron"] } }
regionis physical Railway placement (sjc,iad,ams, orsin). Railway's S3 credentials still expose signing regionauto, which Hypervibe passes through asAWS_DEFAULT_REGION.
Developer Experience
- CLI and MCP parity - Every supported command is available through both interfaces
- Human and JSON output - Readable terminal output by default, stable redacted envelopes with
--json - Natural language - No YAML, no clicking through dashboards
- Auto-wiring - DATABASE_URL connected automatically
- Environment management - Staging, production, PR previews
- Migration support - Run Prisma, Drizzle, TypeORM migrations
- Local development - Generate Docker Compose for local parity
- Secret rotation - Rotate once, propagate to all environments
- Audit trail - Track secret access across deploys
Download the latest installer from
GitHub Releases.
Choose arm64 for Apple Silicon Macs or x86_64 for Intel Macs. Each DMG has
an adjacent .sha256 checksum file.
Published releases are public on the npm registry. Installation does not require GitHub access, a package token, or custom npm registry configuration.
npm install -g @davejohnson/hypervibe@latest
hypervibe --helpThe core desired-state workflow is:
hypervibe spec --file .hypervibe/spec.json
hypervibe plan --env staging
hypervibe apply --plan-id <plan-id>
hypervibe status --env stagingHuman-readable output is the default. Add --json for automation, or
--input <file|-> to supply the complete command input as JSON. Confirmation
prompts are TTY-only; scripts must pass explicit confirmation flags.
To run the current source checkout instead:
git clone https://github.com/davejohnson/hypervibe.git
cd hypervibe
npm ci
npm run build
node dist/index.js --helpcodex mcp add hypervibe -- npx -y @davejohnson/hypervibe@latest
codex mcp listAdd to ~/.claude/settings.json:
{
"mcpServers": {
"hypervibe": {
"command": "npx",
"args": ["-y", "@davejohnson/hypervibe@latest"]
}
}
}Restart Claude Code, then:
You: "Connect to Railway"
Claude: Opens browser for Railway OAuth, saves credentials securely.
You: "Connect Cloudflare with API token xyz..."
Claude: Validates and stores the connection.
You: "Create a new project called my-app with staging and production environments"
You: "Deploy to staging"
You: "Add a Railway custom domain api.myapp.com"
You: "Run database migrations"
Environment custom domains are fully managed for Railway today. Hypervibe
fails closed without changing DNS for Cloud Run, DigitalOcean App Platform,
ECS, Azure Container Apps, and Vercel until their provider attachment and
certificate lifecycles are implemented. GitHub Pages custom domains use the
separate project-level github.pages lifecycle.
Declare delegated secret slots in the spec, then supply local or secret-manager references when planning:
You: "Connect to Vault at https://vault.mycompany.com"
You: "Plan production with DATABASE_URL from vault://secret/myapp/db#url"
Claude: Resolves the value locally, encrypts it into the reviewed plan, and injects it only during hv_apply.
Secret references use the format: provider://path[#key][@version]
┌───────────────┐
│ Hypervibe CLI │
└───────┬───────┘
│
┌───────────────┐ ▼
│ MCP clients ├──► Command registry/context/results
└───────────────┘ │
▼
Spec → Plan → Apply → Status
│
▼
Provider and secret adapters
Hypervibe exposes the same focused operations as canonical hv_* MCP tools and friendly CLI commands. The core is a Terraform-style loop:
hv_spec— declare the desired state (services, database, cache, storage, load balancer, domain, email, messaging, env vars) as a revisioned spechv_plan— observe live infrastructure, diff against the spec, and get an executable planhv_apply planId=...— converge. Stale plans are rejected; destroying data-bearing resources requires explicit confirmationhv_status— see drift between desired and observed state at any time
Around that core: connections (hv_connections), deploy/rollback, logs/errors/health, bounded database diagnostics, secrets, domains/DNS, email, payments, CI, App Store/TestFlight, and local dev tools.
hv_connections and hv_secrets both accept project="name-or-id" to select and validate project context. Provider scope remains separate: it identifies the actual repository, domain, account, or environment covered by a credential.
Their parameter modes are intentionally explicit:
hv_connections # list globally
hv_connections project="my-app" # list; validate project context
hv_connections project="my-app" provider="github" credentialsRef="env:NODE_AUTH_TOKEN"
hv_secrets # list sources globally
hv_secrets project="my-app" # list sources; validate project context
hv_secrets project="my-app" env="staging" # masked hosting-variable names
hv_inspect # provider/capability discovery; no parameters
hv_inspect provider="railway" # provider-account inspection
hv_inspect provider="railway" project="my-app" env="staging" # full live environment
For hv_inspect, any bounded selector requires provider; project plus env never replaces it. For hosting-variable mode, hv_secrets requires an explicit env and does not infer staging from project alone.
- Full generated MCP/CLI catalog:
docs/TOOLS.md - Regenerate after tool changes:
npm run build && npm run docs:tools
hv_db_query can diagnose managed Postgres without asking you to expose it permanently. Railway uses a temporary TCP proxy, Cloud SQL uses a local authenticated connector, and a publicly addressable RDS instance gets a temporary /32 security-group rule for the Hypervibe caller. Supabase normally uses its existing direct endpoint, so no temporary provider resource is needed. Hypervibe releases only access it created; concurrent queries share the same short-lived lease, and every response reports the access mode and cleanup status without returning database credentials or endpoints.
Diagnostic reads run in a PostgreSQL read-only transaction with a 30-second statement timeout. Results are capped at 500 rows and 512 KiB. Mutations still require allowMutations=true, and multi-statement SQL remains blocked.
PostgreSQL services receive the canonical managed variables DATABASE_URL and
DIRECT_URL. Applications with a legacy name can declare a per-service alias;
Hypervibe resolves it inside plan/apply and never writes the database value to
the spec:
{
"services": {
"events-worker": {
"workloadKind": "worker",
"startCommand": "npm run events:worker",
"public": false,
"databaseEnvAliases": {
"POSTGRES_DB_URL": "DATABASE_URL"
}
}
},
"database": {
"provider": "railway",
"engine": "postgres"
}
}hv_plan and hv_status expose the key-only contract and verify that each
declared alias is attached to its target service. inSync describes
configuration convergence; runtimeHealth remains unverified until HTTP
health or worker log/error evidence is checked.
Email sender identity, inbound parsing, delivery events, and mailbox forwarding belong in the environment spec. One environment may declare one default sender, one SendGrid Inbound Parse route, and the account-level delivery-event webhook:
{
"domain": "example.com",
"services": {
"api": { "workloadKind": "web", "public": true }
},
"email": {
"enabled": true,
"sender": {
"address": "hello@example.com",
"name": "Example",
"replyTo": "support@example.com"
},
"inbound": {
"hostname": "inbound.example.com",
"service": "api",
"path": "/webhooks/sendgrid/inbound",
"aliases": ["support", "replies"],
"spamCheck": true,
"sendRaw": false
},
"deliveryEvents": {
"service": "api",
"path": "/webhooks/sendgrid/events",
"events": ["processed", "delivered", "bounce", "dropped"]
},
"forwarding": {
"aliases": {
"support": "owner@example.net",
"billing": "owner@example.net"
},
"catchAll": { "action": "drop" }
}
}
}hv_plan separates runtime-key projection, SendGrid sender/domain
authorization, Cloudflare DNS, inbound-parse creation, delivery events,
forwarding destination verification, aliases, catch-all routing, and domain
validation into reviewable actions. hv_apply installs SENDGRID_API_KEY plus the
declared sender defaults on each service; the inbound target also receives
SENDGRID_INBOUND_HOSTNAME and a JSON SENDGRID_INBOUND_ALIASES value.
SendGrid routes inbound parsing by hostname, not local-part alias. The target
service reads the recipient from the parsed request and dispatches aliases such
as support@inbound.example.com itself. Domain authentication authorizes sender
addresses under domain; without a domain, a declared sender uses SendGrid's
single-sender verification flow and apply remains pending until its verification
email is accepted. Cloudflare destination creation returns pending until the
destination mailbox accepts its verification email; forwarding rules run only
afterward. Because SendGrid exposes one delivery-event webhook per account, the
project spec may declare deliveryEvents in only one environment.
Twilio support deliberately covers the shared setup most applications need: a Messaging Service, optional inbound-message and delivery-status callbacks, the runtime credentials, and optional attachment of an existing phone number.
Collect these values from the same Twilio account or subaccount:
| Hypervibe field | Twilio value | Where to find it |
|---|---|---|
accountSid |
AC... Account SID |
Console Dashboard -> Account Info |
apiKeySid |
SK... Restricted API Key SID |
Settings -> Account settings -> API keys & auth tokens |
apiKeySecret |
API Key Secret | Shown once when that key is created; copy it immediately |
authToken |
Primary Account Auth Token | Console Dashboard -> Account Info -> Show, or the Auth Tokens section of API keys & auth tokens |
messaging.sender.phoneNumberSid |
Optional existing PN... Phone Number SID |
Numbers & Senders -> Phone Numbers; open the SMS-capable number and copy its SID, not its +... phone number |
Do not look for an MG... SID before setup. The spec declares a friendly
service.name; Hypervibe creates or explicitly adopts that Messaging Service,
records its MG... SID, and projects TWILIO_MESSAGING_SERVICE_SID during
apply.
{
"services": {
"api": { "workloadKind": "web", "public": true }
},
"messaging": {
"provider": "twilio",
"services": ["api"],
"service": {
"name": "example-production",
"inbound": {
"service": "api",
"path": "/webhooks/twilio/messages"
},
"deliveryStatus": {
"service": "api",
"path": "/webhooks/twilio/status"
}
},
"sender": {
"phoneNumberSid": "PN0123456789abcdef0123456789abcdef"
}
}
}Create a Restricted API key with these exact Twilio permissions:
twilio/messaging/services/list
twilio/messaging/services/read
twilio/messaging/services/create
twilio/messaging/services/update
twilio/messaging/services.phonenumbers/list
twilio/messaging/services.phonenumbers/create
twilio/messaging/services.phonenumbers/delete
twilio/messaging/messages/create
Keep the four connection values in a local, gitignored env file:
TWILIO_ACCOUNT_SID=ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWILIO_API_KEY_SID=SKxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWILIO_API_KEY_SECRET=replace-with-the-one-time-secret
TWILIO_AUTH_TOKEN=replace-with-the-primary-auth-tokenConnect that file by reference:
hv_connections provider="twilio" credentialsRef="dotenv:/absolute/path/.env" credentialsMap={"accountSid":"TWILIO_ACCOUNT_SID","apiKeySid":"TWILIO_API_KEY_SID","apiKeySecret":"TWILIO_API_KEY_SECRET","authToken":"TWILIO_AUTH_TOKEN"}
hv_plan reviews Messaging Service creation/adoption, sender attachment, and
runtime projection separately. hv_apply derives webhook URLs from the target
service's public binding and projects the Twilio values only to
messaging.services. Moving a number from another sender pool requires exact
action confirmation. Hypervibe does not buy numbers or manage Voice, Verify,
WhatsApp, A2P registration, campaigns, or application message sending.
Complete any A2P 10DLC, toll-free verification, or other regulatory setup in
Twilio before production sending. The primary Auth Token is still required even
when API calls use a restricted key because Twilio uses the account token to
sign inbound and delivery-status webhooks.
Hypervibe treats infrastructure as a repo-backed definition, not as one user's private local state. When run from a git worktree, hv_spec writes the desired infrastructure shape to:
.hypervibe/spec.json
Commit that file with the app. It is the shared source of truth for environments, services, cron jobs, databases, caches, delegated secret ownership, domains, email, messaging, env vars, deploy strategy, and migrations. When a teammate clones the repo and runs hv_spec, hv_plan, or hv_status, Hypervibe reads this file, creates a local project cache if needed, and reports any missing provider connections before apply. The local project_specs table is a revision journal behind this file: if spec.json is edited outside Hypervibe (or pulled with new changes), the next read adopts it as a new revision and says so in a warning.
Hypervibe also maintains non-secret provider identity bindings in:
.hypervibe/bindings.json
This file lets teammates observe and converge the same provider resources instead of planning duplicate projects/services. It is for non-secret IDs such as provider project IDs, environment IDs, service IDs, custom domain bindings, and CI workflow sync metadata. Credentials, tokens, passwords, database URLs, and secret values stay out of the repo and remain local/provider-side.
No Hypervibe user role is required. The current chat task determines which access is needed:
- anyone with the checkout can read the committed desired topology;
- public service URLs in committed bindings can be checked without a hosting provider account;
- exact provider drift, private logs, plans, and applies require a verified provider connection on the machine doing that work.
When a collaborator lacks that connection, Hypervibe should offer two paths: connect credentials they already control, or prepare a value-free handoff naming the provider, scope, environment, and blocked task for the infrastructure owner. It should not assume that every coder belongs in the Railway, GCP, or other provider project. This stays local and repo-backed; it does not require a new Hypervibe web service or shared drift database.
Use a delegated secret slot when a collaborator, customer, or app owner should supply and rotate a runtime or GitHub Actions credential without giving it to the repository owner. The spec records the name, responsible principal, and provider destinations, but never the value:
{
"secrets": {
"ANTHROPIC_API_KEY": {
"ownership": "delegated",
"principal": "github:alice",
"environments": ["production"],
"githubActions": { "repository": true },
"required": true,
"driftPolicy": "preserve"
}
}
}The principal is a non-secret ownership label, not an authenticated Hypervibe
identity. Provider credentials remain the enforcement boundary, but Alice does
not need provider membership merely to own the API key. She can send the key
to the infrastructure owner through an agreed out-of-band channel; the owner
stores it in a local safe reference such as 1Password, a private env file, or
another supported manager and runs the plan/apply. A shared secret-manager
item is the natural repeatable handoff when both people already use one. Give
Alice narrowly scoped provider membership and have her connect her own
credentials only if she needs to apply independently. Changing principal or
a collaborator list in a checkout does not grant a provider role. Without a
hosted control plane, Hypervibe cannot prove that the person supplying a key is
github:alice; do not auto-apply unreviewed spec changes with an owner/admin
credential.
For Anthropic, Alice creates a standard workspace-scoped API key at Claude Platform API keys. Claude subscription billing and Claude API billing are separate, so the Platform account/workspace must have API billing configured. She saves the value locally, outside the repository:
# /Users/alice/.config/hypervibe/friend-app.env
ANTHROPIC_API_KEY=...
If Alice will apply independently, for Railway she creates her own Account API token at Railway account tokens, selects No workspace, and uses only the access granted to her Railway account:
hv_connections provider="railway" credentialsRef="dotenv:/Users/alice/.config/hypervibe/railway.env#HYPERVIBE_RAILWAY_TOKEN"
Then she creates and applies a plan without sending either token through chat:
hv_plan project="friend-app" env="production" secretRefs={"ANTHROPIC_API_KEY":"dotenv:/Users/alice/.config/hypervibe/friend-app.env#ANTHROPIC_API_KEY"}
hv_apply project="friend-app" planId="<planId>"
The value is resolved on Alice's machine, encrypted into that specific plan, injected into every service in the target environment, and never returned by a tool. Hypervibe records only the principal, a SHA-256 value hash, timestamp, and apply receipt in .hypervibe/bindings.json. Ordinary envVars and .env loading cannot overwrite a delegated key. Missing values, out-of-band drift, or a changed principal produce an inspectable but non-executable plan that preserves the live value until a new explicit secretRefs input is supplied.
If a machine or local Hypervibe database is lost, recloning the committed .hypervibe/spec.json and .hypervibe/bindings.json restores the desired shape and accepted hashes. Provider connections must be reconnected and in-flight plans must be recreated; no runtime secret value is recoverable from the repo.
When .env.<environment> or repo .env exists, hv_plan considers it as a local deploy input. Environment-specific files such as .env.production and .env.staging win over .env. Hypervibe does not blindly publish every key. The default policy is envFile.mode: "runtime": Hypervibe syncs high-confidence app runtime keys such as SENDGRID_API_KEY, SESSION_SECRET, *_URL, *_TOKEN, *_SECRET, APP_*, VITE_*, and similar names; it skips provider/control-plane credentials such as RAILWAY_API_TOKEN, GITHUB_TOKEN, and CLOUDFLARE_API_TOKEN; it skips local-looking runtime values such as localhost, 127.0.0.1, 0.0.0.0, host.docker.internal, .local, and .internal; and it reports ignored key names in the plan.
Every repo-backed spec write also creates or non-destructively extends .env.example with RECAPTCHA_SITE_KEY= and RECAPTCHA_SECRET_KEY=. Hypervibe does not connect to reCAPTCHA or validate/store those values. Put the real environment-specific values in .env.staging, .env.production, or another selected env file; hv_plan encrypts them into the persisted plan and hv_apply performs the hosting sync. The site key is public, while the secret key must remain server-side.
Tune this per environment in .hypervibe/spec.json:
{
"envFile": {
"mode": "explicit",
"include": ["SENDGRID_API_KEY", "CUSTOM_WORKER_FLAG"],
"exclude": ["LOCAL_DEBUG_FLAG"]
}
}Modes are runtime (default), all, explicit, and off. Values loaded from the env file are encrypted into the plan and never printed. The plan warning names the env file path and selected keys so the agent can show the user exactly what source is being applied. Generated infrastructure values such as DATABASE_URL still win over stale local .env values.
Use a separate scoped Stripe connection for each named Stripe sandbox and for production. The connection scope is the stable mapping between a Hypervibe environment and Stripe; it defaults to the Hypervibe environment name.
For an existing Stripe dotenv file:
hv_connections provider="stripe" scope="staging" credentialsRef="dotenv:/absolute/path/.env.stripe-sync.staging" credentialsMap={"secretKey":"STRIPE_SECRET_KEY"}
If the file also contains a publishable key:
hv_connections provider="stripe" scope="staging" credentialsRef="dotenv:/absolute/path/.env.stripe-sync.staging" credentialsMap={"secretKey":"STRIPE_SECRET_KEY","publishableKey":"STRIPE_PUBLISHABLE_KEY"}
Repeat with scope="development" for a development sandbox and
scope="production" for Stripe live mode. Sandbox keys begin with sk_test_
or rk_test_ and pk_test_; production server keys begin with sk_live_ or
rk_live_. Restricted rk_ keys are preferred and are accepted in the
secretKey connection field. Open the intended sandbox before revealing its
API keys because each Stripe sandbox has its own isolated key pair and objects.
See Stripe sandbox management
and sandbox API-key access.
Stripe sandbox creation itself is a short Dashboard step because an ordinary sandbox API key cannot create another sandbox or its keys. Everything after that stays in Hypervibe's desired-state loop:
-
In Stripe's account picker choose Switch to sandbox → Create sandbox. Name it for the project or workflow and open it. Copy a restricted
rk_test_key (or an unrestrictedsk_test_key) and the optionalpk_test_key into a gitignored.env.stripe.development. -
Connect that exact sandbox:
hv_connections provider="stripe" scope="development" credentialsRef="dotenv:/absolute/path/.env.stripe.development" credentialsMap={"secretKey":"STRIPE_SECRET_KEY","publishableKey":"STRIPE_PUBLISHABLE_KEY"} -
Declare
payments.stripe.environment: "development", catalog prices, runtime credential projection, and webhooks; runhv_planandhv_apply, then verify the managed CI release withhv_ci_statusandhv_health. -
In the following desired-state revision, add a versioned application seed such as
npm run db:seed:personas -- --dataset=invoice-perfect-v1. The seed owns paired application rows and Stripe test customers/subscriptions; Hypervibe owns only their prerequisites and execution receipt.
For a clean reset, create another named sandbox, replace the two local dotenv
values, and run the same scoped hv_connections call. hv_plan then reviews
recreation of products, prices, environment projection, and webhooks against
the empty target. The old sandbox is untouched and can be deleted in Stripe
after the replacement and fixtures are verified.
Application seeds must use stored provider IDs and deterministic Stripe metadata as durable fixture identity. Stripe idempotency keys protect immediate retries but expire; they do not replace reconciliation. Keep baseline personas stable. Add test-clock personas later as disposable fixtures because deleting a test clock also deletes its associated Stripe test objects.
Then declare the Stripe catalog Hypervibe owns and which hosting services
receive its runtime values. Products and recurring prices are lifecycle
resources: hv_plan observes them, proposes explicit create/update/adopt/
replace/archive actions, and hv_apply records durable provider IDs:
{
"payments": {
"stripe": {
"environment": "staging",
"services": ["web", "cron"],
"credentials": {
"secretKeyEnvVar": "STRIPE_SECRET_KEY",
"publishableKeyEnvVar": "STRIPE_PUBLISHABLE_KEY"
},
"catalog": {
"products": {
"starter": {
"name": "Starter",
"description": "Starter subscription",
"prices": {
"monthly": {
"unitAmount": 1900,
"currency": "usd",
"interval": "month",
"envVar": "STRIPE_STARTER_MONTHLY_PRICE_ID"
},
"yearly": {
"unitAmount": 19000,
"currency": "usd",
"interval": "year",
"envVar": "STRIPE_STARTER_YEARLY_PRICE_ID"
}
}
},
"pro": {
"name": "Pro",
"prices": {
"monthly": {
"unitAmount": 4900,
"currency": "usd",
"interval": "month",
"envVar": "STRIPE_PRO_MONTHLY_PRICE_ID"
}
}
}
}
}
}
}
}Unbound products and prices with exactly matching identity/configuration are offered as confirm-gated adoption actions. Multiple candidates block rather than choosing one. Recurring price amount, currency, and interval are immutable in Stripe; changing one creates a replacement, updates hosting variables, and only then offers a confirm-gated archive of the previous price. Removing a managed price or product likewise removes its hosting projection before archiving it. Unmanaged Stripe objects are untouched.
hv_plan reads Stripe and hosting state, but persists only provider identities,
managed key names, and hashes—not credentials or webhook signing values.
hv_apply resolves the encrypted Stripe connection again and writes runtime
values through the hosting adapter. With CI-triggered branch
deploys, the env update is staged without an independent Railway deploy; the
approved exact-SHA workflow remains the next code release. Stripe-managed keys
cannot also be supplied through envVars, .env includes, delegated secrets,
one-off overrides, or removeEnvVars.
Declare webhook endpoints in the same desired-state section instead of calling an imperative setup command:
{
"payments": {
"stripe": {
"environment": "staging",
"webhooks": {
"billing": {
"url": "https://billing.example.com/api/webhooks/stripe",
"service": "web",
"envVar": "STRIPE_WEBHOOK_SECRET",
"events": [
"checkout.session.completed",
"customer.subscription.updated",
"customer.subscription.deleted",
"invoice.paid",
"invoice.payment_failed"
]
}
}
}
}
}envVar defaults to STRIPE_WEBHOOK_SECRET, and events defaults to the
common SaaS event set when omitted. hv_plan observes endpoint identity and
hosting value hashes. A single existing endpoint with the declared URL and an
observed hosting value becomes an explicit confirm-gated adoption action;
multiple matches are blocked. Creation syncs Stripe's creation-only signing
value to the named service and stores only the endpoint id plus a one-way hash.
Replacement/rotation and deletion are also confirm-gated. If hosting sync
fails, apply rolls the new endpoint back and verifies its absence; an
unverifiable rollback records the endpoint id so a later plan cannot create a
duplicate.
Keep App Store identity, capabilities, TestFlight groups, and the release workflow in each environment's desired state. The server and iOS code may live in the same repository (the v1 workflow is monorepo-first), while release evidence records mobile and server repository/SHA fields separately:
{
"hosting": { "provider": "railway" },
"services": { "api": {} },
"deploy": {
"strategy": "branch",
"trigger": "ci",
"branch": "main"
},
"ios": {
"bundleId": "com.example.app",
"capabilities": ["PUSH_NOTIFICATIONS"],
"testflight": {
"groups": {
"Internal": {
"internal": true,
"testers": ["developer@example.com"]
}
}
},
"release": {
"services": ["api"],
"trigger": "after-server-deploy",
"build": {
"workingDirectory": "apps/ios",
"command": "bundle exec fastlane build",
"ipaPath": "build/Example.ipa",
"requiredSecrets": ["SENTRY_AUTH_TOKEN"]
},
"signing": {
"provider": "match",
"gitBranch": "main"
},
"testflight": {
"groups": ["Internal"],
"usesNonExemptEncryption": false,
"submitForBetaReview": false
}
}
}
}hv_plan/hv_apply reconcile the bundle ID, capabilities, beta groups,
server deploy workflow, iOS release workflow, and its App Store Connect
environment secrets. With signing.provider: "match", the matching GitHub
environment must already contain MATCH_GIT_URL, MATCH_PASSWORD, and
MATCH_GIT_BASIC_AUTHORIZATION. Hypervibe observes those names and scopes the
values to read-only signing preparation; they never enter Hypervibe state or
the project build step. build.requiredSecrets is only for additional secrets
needed by the app-defined build command.
The server workflow uploads signed release evidence only after provider deploy success. The macOS iOS workflow shares the server deploy concurrency group, downloads that evidence, and requires the same repository and full Git SHA. Its build job checks out that exact commit, installs existing Match assets into an ephemeral keychain, runs the project build, validates the IPA, and uploads a short-lived artifact. A fresh release job revalidates the artifact and server evidence before running Hypervibe's embedded Apple upload, processing, compliance, declared-group distribution, optional beta-review, and release-manifest runtime. App Store credentials never enter the project build job, and the release job never checks out or executes project code.
Use signing.provider: "project" when a project intentionally owns its signing
implementation. Versioned App Store metadata/screenshots and local device builds
remain project files; neither becomes an imperative Hypervibe command.
The iOS artifact records separate mobile and server provenance. Inspect these
workflows through hv_ci_status; final hv_appstore_submit also refuses
submission unless the latest successful server and iOS workflow runs have the
same SHA.
Omitting a key from envVars, an env file, or a local secret input means
preserve the provider value. Hypervibe never treats a partial desired map
as permission to delete live variables.
Delete a retired key only through the environment's explicit tombstone list:
{
"envVars": {
"NEW_FEATURE_FLAG": "enabled"
},
"removeEnvVars": ["OLD_FEATURE_FLAG"]
}hv_plan emits one service:<name>:env-remove action per affected service.
The action shows key names but no values, and hv_apply skips it unless that
exact action ID is passed in confirmActions. Railway and GCP Cloud Run both
support these explicit removals. Hypervibe-managed database, queue, storage,
delegated-secret, and source-integration keys cannot be tombstoned; change or
remove the owning resource instead.
Renames require two releases:
- Add the replacement key while keeping the old key. Deploy code that accepts the replacement and temporarily falls back to the old key, then verify it in staging and production.
- In a later spec change, stop supplying the old key and add it to
removeEnvVars. Review and explicitly confirm the removal action.
Hypervibe rejects a removal plan while any service configuration is still
drifting. This prevents a same-release SOME_TOKEN to ANOTHER_TOKEN change
from removing the old value before compatible code is running. A confirmed
removal may reconcile or redeploy the provider's already-compatible current
image, so do not collapse these two releases into one.
Cloud SQL can manage regional availability, backup/PITR retention, named read replicas, and a scheduled isolated restore drill through normal desired state:
{
"github": { "canonicalEnvironment": "production" },
"environments": {
"production": {
"hosting": { "provider": "cloudrun" },
"services": { "web": {} },
"database": {
"provider": "cloudsql",
"resilience": {
"availability": "regional",
"backups": { "retainedBackups": 8, "pitrRetentionDays": 7 },
"replicas": { "analytics": { "region": "us-west1" } },
"restoreDrill": {
"schedule": { "cron": "30 4 * * 1", "timezone": "America/Vancouver" },
"credentialsSecret": "HYPERVIBE_CLOUDSQL_DRILL_CREDENTIALS",
"verificationQuery": "SELECT count(*) FROM users",
"restoreLagMinutes": 10,
"retainFailedInstanceDays": 3
}
}
}
}
}
}The first restore-drill slice supports one GitHub canonical environment per repository. It generates a reviewed scheduled workflow that clones the exact bound primary at the declared point in time, runs the SQL check in a read-only transaction, and deletes the successful clone only after confirming its ownership labels. Failed labeled clones remain briefly for inspection and are collected by a later run. Application database bindings never change.
Use a dedicated GCP service-account JSON key, created or reviewed at
https://console.cloud.google.com/iam-admin/serviceaccounts, and store it in
the repository Actions secret named by credentialsSecret. Scope it to the
single GCP project containing the source instance. The recommended custom role
contains only:
cloudsql.instances.clone
cloudsql.instances.connect
cloudsql.instances.delete
cloudsql.instances.get
cloudsql.instances.list
cloudsql.instances.update
cloudsql.users.update
roles/cloudsql.admin also works but is broader than the drill needs.
Cloud SQL Admin API must be enabled. The connector still needs a network path;
this V1 workflow targets Hypervibe-provisioned Cloud SQL instances with public
IP connectivity. Declare a value-free GitHub Actions destination in
spec.secrets, then supply the local file only to the plan:
{
"secrets": {
"HYPERVIBE_CLOUDSQL_DRILL_CREDENTIALS": {
"principal": "github:infrastructure-owner",
"githubActions": { "repository": true }
}
}
}hv_plan project="example" env="production" secretRefs={"HYPERVIBE_CLOUDSQL_DRILL_CREDENTIALS":"file:/absolute/path/cloudsql-drill-service-account.json"}
hv_plan blocks while the secret name cannot be observed. Once present, the
GitHub infrastructure action is billable and confirmation-gated because each
scheduled run creates a temporary Cloud SQL instance. After the generated PR
is merged, use hv_ci_status to inspect Hypervibe / db-restore-drill-production
runs and their bounded logs.
Do not temporarily change a service releaseCommand just to seed or import production data. Application containers should converge schema during startup. When startup migration is not appropriate, a release command is durable desired deploy configuration for repeatable schema work, such as migrations: { "mode": "releaseCommand", "command": "npm run db:migrate" }.
For fresh environments, declare seed/bootstrap data on the database. This is provider-neutral desired state; it works through the normal plan/apply flow for any supported hosting/database target:
{
"database": {
"provider": "supabase",
"engine": "postgres",
"seedCommand": "npm run db:seed"
}
}hv_plan emits a visible one-shot database seed action. hv_apply runs it after the database exists as a one-off command inside the deployed service environment, then records the command hash plus seededAt on the database component. The command does not run again unless the command changes.
When the same CI-owned plan introduces Stripe runtime variables or creates a
webhook signing secret, Hypervibe converges those resources and unlocks the
reviewed release first, then reports the seed as pending. After that release is
healthy, re-run hv_plan/hv_apply; the unchanged seed command remains planned
and runs against the newly deployed image. This keeps webhook-producing fixture
creation on the application side without racing the Stripe/application boundary.
Hypervibe does not expose an imperative database migration command. Schema
migrations belong in application startup or durable declared release
configuration. Provider-to-provider data moves and database resets must be
modeled as explicit desired-state lifecycle actions before Hypervibe supports
them; they cannot bypass hv_plan/hv_apply. Re-seeding likewise requires a
reviewable desired-state change rather than a generic command runner.
The first load-balancer slice uses Cloudflare in front of two or more
equivalent public web services. The environment domain is the public
hostname; each origin continues to use its provider-issued HTTPS URL and host
header. Declare it through the normal desired-state loop:
{
"domain": "app.example.com",
"services": {
"web-a": { "workloadKind": "web", "public": true },
"web-b": { "workloadKind": "web", "public": true }
},
"loadBalancer": {
"provider": "cloudflare",
"services": ["web-a", "web-b"],
"healthCheckPath": "/health"
}
}hv_plan observes and reconciles three explicit resources: an HTTPS health
monitor, an equal-weight random origin pool, and the zone hostname load
balancer. Pool/topology changes and initial hostname creation are marked
billable. Removing the block plans confirmed deletion of public routing before
the pool and monitor are removed. Same-name resources without durable bindings
are never adopted implicitly; adopting existing Cloudflare load-balancer
resources is outside V1, so those conflicts block until removed or renamed.
Typical team flow:
- One person changes infrastructure through Hypervibe, such as adding a cron service.
- Hypervibe updates
.hypervibe/spec.jsonand, after apply,.hypervibe/bindings.json. - They commit those files.
- Teammates pull, run
hv_plan, and see the same desired shape and provider bindings. - Each teammate connects their own provider credentials locally with
hv_connectionswhen needed.
Recommended default for DNS, custom domains, and email routing: use a Cloudflare Account API Token plus accountId. Cloudflare recommends Account API Tokens for automation credentials that are not associated with a specific user.
Create it from the pre-filled Hypervibe Account API Token template. The link preselects Zone Read, Zone Settings Read, DNS Edit, and Account Settings Read. Choose the target account and narrow the zone resources before creating the token.
Set these permissions and resources:
Permissions:
- Zone -> Zone -> Read
- Zone -> Zone Settings -> Read or Edit
- Zone -> DNS -> Edit
- Load Balancers Read and Load Balancers Write on the target zone (for `loadBalancer`)
- Load Balancing: Monitors and Pools Read and Write on the owning account (for `loadBalancer`)
- Zone -> Email Routing Rules -> Edit (for `email.forwarding`)
- Account -> Email Routing Addresses -> Edit (to create/verify forwarding destinations)
- Account -> Account Settings -> Read (lets Hypervibe auto-resolve accountId)
Zone Resources:
- Include -> Specific zone -> example.com
Use the generated token secret itself as CLOUDFLARE_API_TOKEN; do not use the token name, token id, or legacy Global API Key. New User API Tokens usually start with cfut_; Account API Tokens usually start with cfat_.
Connect without pasting the token into chat. If the values are in an existing .env file, reference the keys directly instead of copying them to a temporary file:
hv_connections provider=cloudflare scope="example.com" credentialsRef="dotenv:/absolute/path/.env" credentialsMap={"apiToken":"CLOUDFLARE_API_TOKEN","accountId":"CLOUDFLARE_ACCOUNT_ID"}
Hypervibe accepts either a raw token or a copied authorization value such as Bearer <token> for Cloudflare.
If Hypervibe needs Cloudflare Registrar/domain purchase, use a User API Token instead because Cloudflare Registrar is not compatible with Account API Tokens. Create it under My Profile -> API Tokens -> Create Token -> Edit zone DNS, add the same zone permissions above, and connect it without accountId:
Open the pre-filled Hypervibe User API Token template, narrow its account and zone selectors, and add Registrar write before creating it. Cloudflare's documented template keys cover Hypervibe's base DNS permissions but not the optional Registrar, Email Routing, or Load Balancing permissions, so add only the optional capabilities the spec uses.
hv_connections provider=cloudflare scope="example.com" credentialsRef="dotenv:/absolute/path/.env#CLOUDFLARE_API_TOKEN"
If the token is valid but Hypervibe cannot confirm zone access during hv_connections, the connection is still saved and verified with a warning; hv_plan/hv_apply will surface any remaining DNS or registrar-specific blockers.
For the current desired-state GitHub model—including generic checks, autofix, pull-request review, code audit, dependency/security controls, declarative GitHub Pages with custom-domain DNS, exact token permissions, and the infrastructure PR flow—see GitHub infrastructure for beginners.
Recommended for a one-token setup: create a classic PAT with repo,
workflow, and read:packages from the
pre-filled combined-token link,
then export it under npm's required variable name:
export NODE_AUTH_TOKEN=ghp_...Then call hv_connections provider=github credentialsRef="env:NODE_AUTH_TOKEN".
For existing .env files, use
credentialsRef="dotenv:/absolute/path/.env#NODE_AUTH_TOKEN". For JSON
credentials, save the JSON to a local file and use
credentialsRef="file:/absolute/path/to/credentials.json". If the user
intentionally wants to enter credentials in chat, credentials={...} is still
accepted.
For GitHub connections, NODE_AUTH_TOKEN, HYPERVIBE_GITHUB_TOKEN, and
HYPERVIBE_GITHUB_PACKAGES_TOKEN are aliases. An explicitly referenced
variable wins. If that variable is absent, Hypervibe accepts one distinct value
from either alias; if different fallback values exist, it blocks instead of
guessing. Prefer NODE_AUTH_TOKEN for the combined token because npm itself
does not know Hypervibe's aliases.
Recommended for CI deploys: a classic PAT with repo, workflow, and read:packages, created by a user with access to the target repositories. Create it from:
https://github.com/settings/tokens/new?scopes=repo,workflow,read:packages&description=Hypervibe%20CI%20deploys
That one token can be used for both:
apiToken: GitHub API work such as writing.github/workflows/*, reading Actions runs/jobs/logs, triggering workflows, and creating repository secrets.packageReadToken: durable GHCR image-pull credentials for Railway image deploys.
For an existing .env file with one token:
NODE_AUTH_TOKEN=ghp_...
Connect it like this:
hv_connections provider=github scope="owner/repo" credentialsRef="dotenv:/absolute/path/.env#NODE_AUTH_TOKEN"
For split credentials, create the repository-management token from the
pre-filled fine-grained link (or the
pre-filled classic API link), and create the classic package token
from the pre-filled read:packages link:
HYPERVIBE_GITHUB_TOKEN=github_pat_... # fine-grained repository permissions above
HYPERVIBE_GITHUB_PACKAGES_TOKEN=ghp_... # scopes: read:packages
Then connect:
hv_connections provider=github scope="owner/repo" credentialsRef="dotenv:/absolute/path/.env" credentialsMap={"apiToken":"HYPERVIBE_GITHUB_TOKEN","packageReadToken":"HYPERVIBE_GITHUB_PACKAGES_TOKEN"}
A token with only read:packages is not enough for Hypervibe CI deploy setup. It can be used as packageReadToken, but the apiToken still needs repo + workflow for classic PATs so Hypervibe can manage workflows and repository secrets.
What hypervibe uses the GitHub token for, and the permission each operation needs:
| Operation | Classic PAT scope | Fine-grained permission |
|---|---|---|
| Propose managed CI/config files through the Hypervibe infrastructure PR | repo (+ workflow for files under .github/workflows/) |
Contents: read/write, Pull requests: read/write, Workflows: read/write |
List/trigger Actions workflows, read runs/jobs/logs (hv_ci_status, hv_ci_trigger) |
repo |
Actions: read/write |
Reconcile declared Actions secrets (spec.secrets.*.githubActions) |
repo |
Secrets: read/write |
Branch protection (github.collaboration.pullRequests) |
repo + repo admin |
Administration: read/write |
Generated push deploys (deploy.trigger: "ci") |
repo + workflow; add Secrets read/write if Hypervibe should sync provider API tokens |
Contents: read/write, Actions: read/write, Secrets: read/write, Environments: read/write |
Manage the Railway GitHub App's repository access for deploy.trigger: "native" selected-repos installs |
repo + repo admin — classic PAT only; GitHub's app-installation APIs do not accept fine-grained PATs |
not supported |
| Private repo source fetch for Cloud Run builds | repo |
Contents: read |
Fine-grained PATs can work for some GitHub API operations when granted the permissions in the table, but GitHub Packages/GHCR package authentication still requires a classic PAT. If you use a fine-grained PAT as apiToken, still provide a classic PAT with read:packages as packageReadToken for Railway GHCR deploys.
deploy.strategy: "branch" defaults to deploy.trigger: "ci". Hypervibe sets up push deploys by writing GitHub Actions workflows that call provider APIs directly; it does not install or depend on provider CLIs.
Provider-native source ownership is exclusive. Only an explicit
deploy.trigger: "native" may keep a repository connected at the hosting
provider. Manual and CI modes stage source reconciliation before every other
mutation: Railway and Azure Container Apps disconnect through their provider
APIs, while Vercel and DigitalOcean block with manual-disconnect guidance.
Unknown source observation blocks for all four providers. After the source-only
plan converges, run hv_plan again to review storage, variable, workflow, or
deployment work separately.
Typical setup:
- Define the environment with
deploy: { strategy: "branch", branch: "main" }or an explicittrigger: "ci". - Run
hv_applyfirst so Hypervibe records provider project, environment, and service ID bindings. - Declare
deploy.strategy="branch"anddeploy.trigger="ci"withhv_spec, then runhv_planandhv_apply. - Check the returned
requiredSecrets,syncedSecrets,manualSecrets, andrequiredVariables. Hypervibe syncs provider API credentials to GitHub Actions secrets when the provider connection is verified and the GitHub token can write repo secrets.
Provider workflow behavior:
| Provider | Generated GitHub Actions deploy path | Usually synced from verified connection | Manual GitHub values when Hypervibe does not already know IDs |
|---|---|---|---|
railway |
Build/push OCI image to GHCR with GitHub's built-in workflow token, update ServiceInstance.source.image via Railway GraphQL, then trigger deploy via Railway GraphQL |
RAILWAY_API_TOKEN; IMAGE_REGISTRY_USERNAME/IMAGE_REGISTRY_TOKEN from the verified GitHub connection |
Variables: RAILWAY_ENVIRONMENT_ID, RAILWAY_SERVICE_IDS |
cloudrun |
Build/push OCI image to Google Artifact Registry, patch Cloud Run services through Google APIs | GCP_SERVICE_ACCOUNT_JSON, GCP_PROJECT_ID, GCP_REGION |
Variable: CLOUDRUN_SERVICE_NAMES; optional variable: GCP_ARTIFACT_REPOSITORY |
Every generated workflow checks the selected environment's committed desired
state before building. Hypervibe stores the last successfully applied
environment contract hash in the environment-scoped GitHub Actions variable
HYPERVIBE_APPLIED_SPEC_HASH. Code-only commits retain the same hash and
continue to auto-deploy to staging. A commit that changes the environment
contract stops before image build until the exact commit is reconciled:
- Check out the target commit.
- Run
hv_planand review the environment plan. - Run
hv_applyso all desired-state actions complete and the final hash marker advances. - Trigger that commit with
hv_ci_trigger, inspect it withhv_ci_status, and verify it withhv_health.
For project-backed checks, hv_health keeps the requested HTTP result separate
and also reports the latest bound deployment status for every declared
environment and service. This lets a healthy staging endpoint surface a failed
production build; provider read failures and pending states remain unknown.
The marker is environment-specific: production-only desired-state changes do not block staging. Production workflows remain manual and enforce the same reconciliation check for the promoted SHA.
After a deploy job fails, the generated workflow runs a separate evidence job
with read-only Actions access. It reads the completed deploy job's last 400 log
lines, applies credential-pattern redaction in addition to GitHub's normal
secret masking, bounds the result to 64 KiB, and retains
hypervibe-deploy-failure.log as an artifact for 14 days. Declare that path on
an external workflow source together with its exact artifact name or narrow
trailing-wildcard failureArtifactPattern when a Hypervibe autofix should
consume deploy evidence. The generated downloader filters by that pattern, so
other artifacts from the source run are ignored. The artifact remains untrusted diagnostic input: generated autofix
workflows cannot change .github/, .hypervibe/, secrets, deployment, auth,
billing, or database schema, and they only open draft pull requests for human
review. Evidence collection runs even though the deploy dependency failed, and
missing or incomplete declared evidence is a successful non-actionable outcome:
autofix stops before model invocation and publishes no patch. Its patch and
summary are staged outside the checkout so the summary cannot enter the patch.
Draft pull requests include the configured agent's diagnosis and verification
summary instead of model-specific boilerplate. A
reconciliation-gate failure explicitly identifies itself as infrastructure
work, so the agent produces no source patch and the operator continues through
hv_plan and hv_apply.
Railway deploy polling retries idempotent reads after bounded network, 429, and
5xx failures. Image updates and deploy-triggering mutations are never replayed
by that retry path. If the read retry budget is exhausted, hv_ci_status
reports a transient Railway API diagnostic rather than inferring an
infrastructure defect from the generated workflow source printed in the log.
During a CI-managed hv_apply, supported hosting adapters keep GitHub Actions
as the application-code release boundary. Railway applies variable changes
with deploys skipped and does not call its service redeploy mutation. For an
existing Cloud Run service or job, Hypervibe applies configuration using the
currently deployed image instead of independently building branch code; the
generated workflow later swaps in the approved commit image. Cloud Run
configuration is revision-scoped, which is why variable removals and
incompatible value transitions still require the two-release process above.
Health checks for this apply pass are deferred to the later CI deployment.
For Railway GHCR deploys, the generated workflow grants packages: write and uses ${{ github.actor }} plus ${{ secrets.GITHUB_TOKEN }} only for the workflow-time image push. The hosting provider also needs durable image-pull credentials because GitHub's workflow token is short-lived and only exists inside the Actions job. Hypervibe syncs those pull credentials into IMAGE_REGISTRY_USERNAME and IMAGE_REGISTRY_TOKEN from the verified GitHub connection when it has a login and a package-read-capable packageReadToken. Do not use ${{ secrets.GITHUB_TOKEN }} for IMAGE_REGISTRY_TOKEN, and do not use a read:packages-only token as the GitHub apiToken.
When Hypervibe syncs GitHub Actions secrets, it records only secret names plus local one-way value hashes. If the local provider token changes later, hv_plan will report the CI deploy action as needing an update and hv_apply will resync the GitHub secret value. Raw secret values are never written to .hypervibe/spec.json, .hypervibe/bindings.json, or tool output.
To repair a stale declared GitHub Actions secret without pasting the token into chat, re-plan from the local source of truth:
hv_plan project="apreskeys.com" env="production" secretRefs={"IMAGE_REGISTRY_TOKEN":"dotenv:/Users/dave/projects/condoshare/.env#GHCR_TOKEN"}
For any Hypervibe-managed GitHub Actions deploy, inspect the workflow and logs through Hypervibe itself. Agents should use hv_ci_status instead of gh, GitHub connectors/apps, browser/UI inspection, or direct GitHub API calls so the verified connection, diagnostics, and audit boundary stay coherent:
hv_ci_status project="apreskeys.com" repo="davejohnson/apreskeys.com" include=["logs"] runId=28272281787
If the logs contain docker buildx imagetools inspect ... ghcr.io ... 403 Forbidden, the workflow has not reached Railway yet. Fix IMAGE_REGISTRY_USERNAME and IMAGE_REGISTRY_TOKEN first; Railway will not show a new deploy attempt until GHCR image verification can read the image.
deploy.trigger: "native" opts into provider-native repo integrations instead. For Railway native push autodeploys, grant the Railway GitHub App access in GitHub:
- Install/open the Railway GitHub App and grant it access to the repo. If it is installed for "Only select repositories", add the target repo.
- Make sure at least one Railway project member has connected GitHub and has contributor access to the repo.
- Accept any pending permission updates for the Railway GitHub App in GitHub.
- After permission changes, wait a few minutes for Railway caches to refresh, then rerun
hv_statusorhv_plan. - If Railway still cannot see the repo, disconnect/reconnect the service source in Railway, refresh Add -> GitHub Repository, or reinstall the Railway GitHub App.
Vault, AWS Secrets Manager, Doppler, 1Password, and Bitwarden are resolve-only. Hypervibe reads a referenced value while building an authorized plan and never writes, deletes, or rotates manager data. 1Password uses a service account token scoped only to required vaults. Bitwarden Secrets Manager uses a machine account access token plus the organization id.
Runtime values from .env.<environment> and .env are still synchronized to
hosting through hv_plan and hv_apply. The environment-specific file wins,
selected values are encrypted into the reviewed plan, and no plaintext value is
returned. The removed secret sync command was the separate imperative path that
mutated hosting without that authorization boundary.
Hypervibe stores data locally:
- Database:
~/.hypervibe/hypervibe.db(SQLite) - Secrets: Encrypted with
~/.hypervibe/.secret-key
No data is sent to external servers except the providers you connect.
You can override the storage location by setting HYPERVIBE_DATA_DIR when launching the MCP server.
Hypervibe has three kinds of state to keep current:
- The installed Hypervibe package in Codex, Claude, or another MCP client.
- Local Hypervibe state in
~/.hypervibe, especially the SQLite database schema and encrypted provider connections. - Repo-backed project state in
.hypervibe/spec.jsonand.hypervibe/bindings.json, which should be committed with the app.
The default install command uses @davejohnson/hypervibe@latest, so users should not need to know or remember a package-upgrade command. When Codex, Claude, or another MCP client restarts the Hypervibe server, npx resolves the latest published package and Hypervibe automatically runs any pending SQLite migrations at startup.
Normal update flow:
- Restart the MCP client/server so
npx -y @davejohnson/hypervibe@lateststarts the newest published package. - In each app repo, pull the latest
.hypervibe/spec.jsonand.hypervibe/bindings.json, then runhv_statusorhv_plan. - Commit any intended changes Hypervibe makes to
.hypervibe/spec.json,.hypervibe/bindings.json, generated CI workflows, or other repo files.
Provider credentials remain local and encrypted. Database component bindings (connection URLs, passwords) are also encrypted at rest. The encryption key lives in ~/.hypervibe/.secret-key (0600); back it up — regenerating it makes previously encrypted data unrecoverable. Set HYPERVIBE_SECRET_KEY (64 hex chars) to supply the key externally (CI, containers). Teammates may still need to run hv_connections for their own Railway, GitHub, Cloudflare, SendGrid, AWS, or GCP access after installing Hypervibe, but ordinary Hypervibe package and SQLite schema upgrades should happen on restart.
workloadKind: "job" was removed from the service spec — it never had run-to-completion deploy semantics. Specs using it fail validation; choose worker (always-on, internal-only on Cloud Run with a minimum of one instance — note Cloud Run workers must still listen on PORT) or cron (scheduled). Railway's observe cannot distinguish web from worker, so kind drift is not detected there.
The provider catalog is intentionally focused. DigitalOcean, Azure Container Apps, Vercel, and AWS ECS on Fargate pass mocked lifecycle and managed exact-SHA/image workflow contracts, but remain behind the provider-conformance live promotion gate and are not advertised as supported yet. Heroku, Render, and Fly are deliberately out of scope. Supported database providers remain supabase, cloudsql, railway, and rds; Azure PostgreSQL, Neon, and DigitalOcean are conformance targets at various pre-support stages. Stored connections for removed providers can still be deleted with hv_connections action="remove".
Redis is a separate cache lifecycle instead of a database component and wires REDIS_URL. Railway, DigitalOcean, Azure Managed Redis, and Amazon ElastiCache have adapter or conformance slices; GCP Memorystore's private-IP lifecycle is implemented, but its Cloud Run full-stack profile remains blocked on declarative VPC egress. PostgreSQL is the only database engine in desired state; MongoDB and MySQL are intentionally outside the core lifecycle.
Providers self-register through the plugin system:
// src/adapters/providers/example/example.adapter.ts
import { providerRegistry } from '../../../domain/registry/provider.registry.js';
export class ExampleAdapter implements IProvider {
// ... implementation
}
providerRegistry.register({
metadata: {
name: 'example',
displayName: 'Example Provider',
category: 'dns',
credentialsSchema: ExampleCredentialsSchema,
// Lifecycle providers also declare databaseEngines/cacheEngines here and
// expose primary or derived lifecycle adapters.
},
factory: (credentials) => new ExampleAdapter(credentials),
});Then import during application provider bootstrap:
import '../adapters/providers/example/example.adapter.js';See docs/provider-conformance.md before adding hosting, database, or cache
support. Provider IDs are extensible, but support is a tested observe/plan/apply/
destroy contract rather than a schema enum.
Releases are one command from a clean, up-to-date main checkout:
npm ci
npm run release -- patchBefore publishing the first public package, the @davejohnson scope must be
available to the npm account and the repository must have an Actions secret
named NPM_TOKEN. Use a granular npm token limited to this package with
publish permission and automation/2FA bypass enabled. The workflow exposes it
only to the npm publish step; GitHub's OIDC token is used to attach public
provenance to the package.
Use minor, major, or an exact stable version such as 0.2.0 instead of
patch. The release command verifies that main exactly matches
origin/main, updates package.json and package-lock.json, runs the full
test/typecheck/build/package-safety suite, creates the release commit and an
annotated vX.Y.Z tag, and atomically pushes both. The tag starts
release.yml; it publishes the public npm package with provenance, builds
native Apple Silicon (arm64) and Intel (x86_64) DMGs on matching GitHub
macOS runners, creates SHA-256 checksum files, and attaches all four files to a
public GitHub Release. By
default the command watches that workflow through gh and fails if any
package, installer, or release job fails.
Preview the next version and git operations without changing anything:
npm run release -- patch --dry-runPass --no-wait only when another process will monitor the GitHub release
workflow. If validation fails before the release commit, the script restores
the original package version files. If the atomic push fails, it keeps the
local release commit and tag and prints the exact retry command.
Local installer builds use an ad-hoc signature by default. Tagged GitHub
releases require the Developer ID Application and App Store Connect secrets
documented in apps/macos/README.md. The release
workflow imports them only into an ephemeral keychain, notarizes and staples
both DMGs, and fails rather than publishing an unsigned installer.
Let LLMs handle the fuzzy stuff. Hypervibe returns raw data and lets your agent interpret it. No complex pattern matching or hardcoded rules—your agent figures out that "prod-us-east" means production.
Simple shortcuts are fine. Exact matches for production, staging, development work instantly. Everything else? Claude handles it.
Two-step flows for safety. Import and destructive operations show you what will happen first, then ask for confirmation.
Apache 2.0 - See LICENSE for details.
Built for Claude Code. Powered by MCP.