Staging and production
Create an environment in the console, push to it by name, and grant the role that lets someone read it.
A project starts with one environment called development. Staging and production are more of the
same shape: a name inside your project, holding its own version of every key. Reaching one is a
permission question, answered by the roles someone granted you on the project's Access page.
Create the environment
An environment is created in the console. Open your project and use its environment list, which shows each environment with how many keys it holds.
The command line creates only the first one. penv push on a schema with no @penv= header
creates the project with a single development environment and writes the slug into the header.
Anything after that is a console action, or POST /api/v1/orgs/{org}/projects at the moment you
create the project, whose body carries the environment names you want.
Push to it by name
penv push --env staging--env picks the environment this command writes to. Everything else about push is unchanged: it
sends every key with its decorators and the value your local .env holds, and it deletes .env
when the write succeeds.
Two flags are worth knowing before you point one at a live environment:
--org <slug>says which workspace owns a project penv is about to create. It matters only on the first push of a repository.--prunedeletes cloud keys the schema no longer lists. A coding agent session is refused it outright, so a person has to run it.
--prune deletes values. Open the environment in the console and read the key list first, because
the version history of a deleted key goes with it.
Which environment a command reads
--env, then PENV_ENV, then development. That order holds for every command that touches the
cloud.
| Where you are | What you get |
|---|---|
Local mode, no @penv= header | development only. Every other name is refused with exit code 6. |
| Cloud mode, signed in as a person | Whatever your role assignments reach. |
| Cloud mode, a machine credential | The one environment that credential is bound to. |
An identity asking for an environment it holds nothing on gets 403 forbidden from the server,
which penv reports as environment_refused and exit code 6, naming the address it was refused:
penv: this identity may not read acme/api-gateway/production.
Ask the console for a role on that environment, or pick another with --env.Who may read production
There is no separate unlock for production. It is reached the same way staging is: someone grants
you a role scoped to that project or that environment on the project's Access page, and the server
answers your reads from that grant. That page lists who holds which role and where, and grants or
revokes those grants. Granting one needs member:role_assign at the scope you are granting.
| What you want to do | Permission you need |
|---|---|
| See the Access page | member:read at that project |
| Grant or revoke a role there | member:role_assign at the target scope |
| Read values in an environment | secret:reveal at that environment |
| List keys and decorators without values | secret:read at that environment |
penv pull and penv run read values, so they need secret:reveal. A read that asks for
decorators alone (?values=false on the API) needs only secret:read, which is how a build can
validate a schema without opening anything.
Every value opened this way writes one row in the record of who did what, carrying the credential and, when a coding agent is driving, the harness and session that opened it.
Do it in order
- Open your project in the console and create the environment.
- Grant yourself, or the person who needs it, a role scoped to that environment on the Access page.
- Put the values in a local
.envfor that environment, or set them one at a time withpenv set KEY --env staging. penv checkuntil it printsok.penv push --env staging.penv run --env staging -- <your command>to prove the environment resolves.- Repeat for
productiononce someone withmember:role_assignhas granted you a role there.