Running locally, with nothing on disk

Binding a directory to a project's environment, running a command with its values, and exactly what orca protects.

A directory is bound to one project's environment once. After that, every command started through orca run gets that environment's values as environment variables — nothing is written to disk, and a teammate who clones the repository and signs in gets the same result with no setup of their own.

Binding a directory

$ orca link --project payments --env local
Bound this directory to payments/local on api.orcakey.sh (orca.json).
It holds no secrets; commit it.

Leave out --project or --env at a terminal and orca link lists what you can see and asks for a number, rather than making you type a name from memory.

orca.json holds three names and nothing else:

{ "host": "api.orcakey.sh", "project": "payments", "environment": "local" }

Names, not ids: a file one developer commits works for another, and for the same names on a different deployment. It is found by walking up from the current directory to the nearest one, so every directory beneath it shares the binding. There is no layering of more than one environment — a key several projects need is a reference, below, not a second binding.

Running a command

$ orca run -- dotnet run
$ orca run -- npm run dev
$ orca run -- aspire run

The -- is required: everything after it is the command, untouched, so orca run -- dotnet run --launch-profile https is never ambiguous about whose --launch-profile that is. Without a binding, or to run against a different one, name the environment directly: orca run --env ID -- CMD.

The binding everywhere else

Inside a bound directory, the other commands use the binding too. orca key list, set, generate, rotate and schedule act on the bound environment when --env is left out, and say which one: Using payments/local (/src/payments/orca.json). orca auth login signs in to the binding's deployment, so after cloning a repository nothing else needs typing. orca auth status adds where the directory is bound and which file says so. An explicit --env or --host always wins.

The .NET double-underscore convention

ASP.NET Core's configuration binder reads Section:Key from an environment variable named Section__Key, because : is not legal in most shells' variable names. Store the value as ConnectionStrings__Default, and builder.Configuration.GetConnectionString("Default") reads it with no code change and nothing in appsettings.json — orca run only sets the variable; the convention is .NET's own.

A key shared by many projects

Keep it once, in a project the others can reference — often called shared — and point at it from each project that needs it:

$ printf '${shared.local.OPENAI_KEY}' | orca key set OPENAI_KEY --env $E

orca run resolves the reference locally exactly as any other consumer does: the process receives the resolved value, never the ${...} text. Change the shared key once, and the next run of every project that references it picks up the new value — no edit in any of them. If a reference cannot be resolved (the developer cannot reveal it, or it no longer exists), nothing starts, and the message names which reference and why.

When a shell variable is already set

The environment's value wins over one already exported in your shell. orca run names what it replaced, on its error stream, so "my override isn't working" has a visible answer:

$ DATABASE_URL=mine orca run -- printenv DATABASE_URL
Replacing from payments/local: DATABASE_URL
postgres://...

An environment with no keys says so instead, and still runs: payments/local has no keys; running with nothing added.

When it will not start

  • No binding, and no --env: how to bind, with orca link.
  • Not signed in to the binding's deployment: the sign-in command for it.
  • A project or environment name that does not exist: the names that do, and orca link to bind again.
  • An environment that is gone, or not yours to read: exactly that. The two are one answer, as they are everywhere else in orcakey.sh.
  • A reference that cannot be resolved: the server's own reason, naming the reference.
  • A deployment that cannot be reached: that there is no offline copy to fall back on.

Every one of these exits 1 before the command starts. A partial set of values is never used: either every value resolves, or nothing runs.

Once the command starts, its exit status is orca run's exit status, because orca run becomes the command: it replaces its own process rather than starting a child. Ctrl-C, kill and a process manager's stop reach the command directly, and no orca process is left behind holding a copy of the values. A command that does not exist exits 127, and one that cannot be executed exits 126, as they would in a shell.

orca run is not available on Windows yet, and says so.

What is protected, exactly

A value never touches disk, never appears in orca run's own output, and never lands in the command's arguments, where ps could show it to every other account on the machine. It exists only inside the command you started, and inside anything that command itself goes on to start.

That command, and everything it spawns, can read the values it was given — that is the point: this replaces .env files and dotnet user-secrets, not a way to run code without trusting it with its own configuration. OrcaKey encrypts values at rest and in transit, and the deployment can decrypt them: that is how it resolves a reference and hands this run its values at all. Each key revealed for the run is written to the audit log once, against the person signed in.