Helm7

From a repository to production

Four steps, about ten minutes, and you end up with a web service, a Postgres database, managed auth, a storage bucket and a custom domain on a certificate.

The same four steps are shown twice below: once as CLI commands for a person at a terminal, once as MCP tool calls for an agent. They are the same operations. Nothing is available to one and not the other.

01

Create the Product

Point Helm7 at a repository. It inspects it and proposes a shape.

02

Add the state

Postgres, managed auth and a bucket, each one call.

03

Deploy

Build the current commit and swap traffic once health checks pass.

04

Attach the domain

Create one DNS record and the certificate issues itself.

Before you start

You need a git repository the platform can read, and somewhere to run it. A Product runs in one region, and there are two today: eu-central is Falkenstein and eu-north is Helsinki. There is no US region yet, so pick the one closer to your users and know that neither of them is close to North America.

You do not need an account to try this. An agent can call cloud_init and get a temporary workspace with a scoped key, no email and no card. See for agent operators.

The CLI path

The CLI is not published to a registry yet, so it runs from the repository. Nothing about the API needs it: every command below has an HTTP equivalent, and an agent should use that rather than shelling out.

Identify yourself

git clone https://github.com/maxbeech/helm7 && cd helm7 && npm install
export HELM7_API_KEY=hlm_sk_...
npm run cli -- whoami
# Or without the CLI at all:
curl -H "authorization: Bearer $HELM7_API_KEY" https://www.helm7.com/v1/whoami

whoami is worth the one call. It returns the organisation, the member your key speaks as, its scopes, its capability flags and, for an agent key, its remaining budget and expiry. A key can never exceed what that member can do, so this is your real ceiling.

1. Create the Product

Plan it first. Every mutating command takes --dry-run, which changes nothing and costs nothing.

helm7 init "Acme" \
--repo https://github.com/acme/acme-app \
--region eu-central \
--dry-run
  1. Acme
  2. Plan
Nothing applied
  1. create productAcme eu-central
  2. create environmentproduction
Estimated usage$0.00/month

Inside the $12 Builder minimum, so that is the bill. Largest cost: nothing billable.

Read the plan, then apply it

helm7 init "Acme" --repo https://github.com/acme/acme-app
# The command prints the Product id. Set it once and stop typing it.
export HELM7_PRODUCT=prd_7k2m9x4qw1nv8bz3ct6d

2. Add the state

Postgres sets DATABASE_URL on the environment for you. Auth is GoTrue-compatible and storage is Supabase-Storage-compatible, so an application already written against supabase-js works with a changed URL and key.

helm7 db create --extension pgvector
helm7 auth enable --provider email,google
# Anything your app needs that the platform did not set:
helm7 env set STRIPE_SECRET_KEY=sk_live_... --env production

Secret values are encrypted at rest and are never returned by any endpoint, including the one that sets them. secret_list gives you names and fingerprints and nothing else.

Storage buckets have no command yet. Create one over the API or MCP with storage_create_bucket; the CLI covers what people reach for at a terminal and is smaller than the full surface.

3. Deploy

helm7 deploy --env production
# Returns a deployment id straight away. Watch it:
helm7 logs --service svc_8n4p2v --limit 50

Traffic swaps only once health checks pass, and the previous deployment is kept. If the new one is wrong, helm7 rollback dep_... is a traffic swap and takes seconds. It does not revert database migrations, so if the deployment changed the schema, undo that yourself first.

4. Attach the domain

helm7 domain add acme.com
# Create the record it prints, then check where you stand:
helm7 product inspect $HELM7_PRODUCT
helm7 usage

The domain reads as pending until the DNS record resolves. That is not an error. The certificate issues on its own once it does, usually within a minute.

The MCP path

Same operations, same names, same plans. Point your client at the MCP server and give it a key. The tool list it sees is whatever that key is allowed to use, so a narrow key is also a shorter prompt.

To sign in with your browser instead, run claude mcp add --transport http helm7 https://www.helm7.com/mcp and choose Authenticate. Approving the connection gives the client a key with your own permissions, which you can revoke from the keys page. There are no refresh tokens: the key lasts until you revoke it.

MCP client configuration
{
  "mcpServers": {
    "helm7": {
      "url": "https://www.helm7.com/mcp",
      "headers": { "Authorization": "Bearer hlm_sk_..." }
    }
  }
}
The whole quickstart, as tool calls
whoami {}

product_create {
  "name": "Acme",
  "repo": "https://github.com/acme/acme-app",
  "region": "eu-central",
  "dry_run": true
}

product_create {
  "name": "Acme",
  "repo": "https://github.com/acme/acme-app",
  "region": "eu-central",
  "idempotency_key": "acme-first-run"
}

database_create {
  "productId": "prd_7k2m9x4qw1nv8bz3ct6d",
  "environment": "production",
  "extensions": ["pgvector"]
}

auth_enable {
  "productId": "prd_7k2m9x4qw1nv8bz3ct6d",
  "providers": ["email", "google"]
}

storage_create_bucket {
  "productId": "prd_7k2m9x4qw1nv8bz3ct6d",
  "name": "uploads"
}

deploy {
  "productId": "prd_7k2m9x4qw1nv8bz3ct6d",
  "environment": "production"
}

domain_attach {
  "productId": "prd_7k2m9x4qw1nv8bz3ct6d",
  "hostname": "acme.com"
}

Plan first, always

dry_run returns the changes, the monthly cost and anything irreversible. It is free and has no side effects, so there is no reason to skip it on a change you have not made before.

Use an idempotency key

Replaying the same key returns the original result rather than acting twice. Worth it on anything that creates a resource or spends money.

Expect refusals to be useful

A destructive call without confirm returns the plan and refuses. Errors carry a stable code and a remedy. Branch on the code, never on the message.

When it goes wrong

The build failed

deployment_get extracts the specific reason rather than leaving you to find it in a log tail. If detection picked the wrong build, override it on the service instead of fighting the detector.

The app starts and then dies

service_logs gives you stdout and stderr. Secrets are redacted on a best-effort basis before logs leave the platform, which is a safety net and not a guarantee, so do not deliberately print them.

The domain says pending

The DNS record has not resolved yet. domain_list shows the record it expects. Nothing is broken until the record is right and it is still pending an hour later.

Something else

Email [email protected] with the request_id from the error. Every failure carries one.

Next