Protect environment secrets when using AI agents
When AI agents such as Claude Code or Codex participate in development, secret safety involves more
than excluding .env from Git. An agent may read workspace files, run commands, and inspect output.
Long-lived plaintext secrets in a project can easily reach logs, patches, context, or remote services.
Shine's env secret seal, env run, and age backend reduce this spread by storing ciphertext in
the repository and decrypting values only for the child process that needs them. They are not a
sandbox and do not replace operating-system isolation. Understand the boundary between identity
files, hardware authorization, and agent permissions before use.
Prepare a Shine workspace
A Shine workspace consists of shine.workspace.toml at the project root and the *.shine.toml
environment sources it references. The workspace file declares modes such as development, the
source merge order, and shared encryption recipients. The sources hold ordinary configuration and
secrets. These are project environment files; creating them does not isolate an agent's access.
If the project already has .env files, run the following yourself in a trusted terminal at the
project root. Replace DATABASE_URL with an actual sensitive key; repeat --secret for each one:
shine env workspace init --from-dotenv --secret DATABASE_URL --dry-run
shine env workspace init --from-dotenv --secret DATABASE_URL
This generates shine.workspace.toml and corresponding sources, such as .env.shine.toml from
.env. Initialization only imports values: keys selected with --secret are still plaintext in
[secret] until sealed, and unselected keys remain plaintext in [plain]. Review the classification
before continuing. See initialize a workspace from dotenv
for supported inputs and mode selection. If there are no .env files, follow
layered project environments to create the
workspace and sources manually.
Next, follow use age identities to install the dependencies, set up your local identity, and configure the backend and recipients. Then seal the sources and verify your project command through Shine:
shine env secret seal
shine env run --mode development -- bun run build
Use a mode declared in your workspace and replace bun run build with your project's command.
Neither initialization nor sealing changes the original .env files. Once the project works through
Shine, remove the original secret plaintext from the project yourself, or move it to a location the
agent cannot read. Adding a file to .gitignore prevents accidental Git inclusion; it does not stop
an agent from reading it.
You can commit shine.workspace.toml and shared sources after confirming that sensitive values are
sealed and none remain in [plain]. Keep identities, unsealed plaintext, and personal override
files out of commits; ignore .env.local.shine.toml and .env.*.local.shine.toml. For later changes,
edit the relevant source and seal it again; initialization does not need to be repeated. If another
tool requires dotenv, see export a workspace to dotenv,
including how to handle plaintext produced by --include-secrets.
What Shine environment protection covers
shine env secret seal seals pending secrets in workspace environment files into an encrypted
payload. The repository then contains ciphertext rather than plaintext tokens, passwords, or API
keys.
shine env secret seal
shine env run merges environment files, decrypts secrets, and provides the result only to the
started child process:
shine env run --mode development -- bun run build
This primarily reduces three risks:
- plaintext secrets remaining in project files;
- exporting a secret into an entire shell session merely to run one task;
- an AI agent reading, copying, or committing a plaintext
.envwhile editing code.
An agent permitted to run a command that reads environment variables can still see secrets visible to that command. The boundary is on-demand injection, not protection from an untrusted child.
For an occasional credentialed operation, run the command yourself with one-time env run --with
injection. If a CLI repeatedly needs the same fixed credential variable, a transparent command
proxy can keep the normal invocation:
shine env proxy install gh --with GH_TOKEN
gh pr list
An agent allowed to run gh can still use the injected token and inspect anything the command
reveals. The proxy reduces persistent plaintext and shell-wide exports; it does not make the target
command trusted. See choose one-time injection or a transparent wrapper
for setup, enable/disable behavior, and the Cargo example.
An age identity is decryption authority
With the age backend, age_recipients = ["age1..."] identifies who can decrypt. A personal default
may live in ~/.shine/config.toml; a project team's shared recipient list belongs in
[env.encryption] in the commit-ready shine.workspace.toml.
The following example belongs in the local ~/.shine/config.toml:
secret_backend = "age"
age_recipients = ["age1tag1qexample...", "age1qteammate..."]
age_identity = "~/.shine/age/identity.txt"
For shared project settings, use this separate section in shine.workspace.toml, replacing the
example recipients with actual member recipients. Keep identity paths in local configuration:
[env.encryption]
backend = "age"
age_recipients = ["age1tag1qexample...", "age1qteammate..."]
~/.shine/age/identity.txt is the private decryption identity. Never commit or share it, and do not
put it in a workspace an agent can freely read.
shine env secret identity init
shine env secret identity list
On Unix and macOS, Shine gives generated identity files mode 0600, readable and writable only by
the current user. This blocks other local users, but not an agent, script, or process running as the
same user with permission to read that path. A normal age identity protects repository and transport
ciphertext, not the entire local runtime.
What Touch ID improves
On macOS, create a Secure Enclave and Touch ID identity:
shine env secret identity init --touch-id
age-plugin-se generates the identity. Decryption requires the local Secure Enclave and a Touch ID
or system PIN authorization. Copying its identity file to another machine is normally insufficient
to decrypt.
New Touch ID identities use an age1tag... public recipient, so age 1.3 or newer can encrypt on
other platforms without the Secure Enclave plugin. A tagged recipient is more discoverable:
someone who knows it can test whether a ciphertext targets it.
This makes an identity harder to abuse offline, requires local user authorization, and prevents an agent from decrypting elsewhere with only the file. It is not absolute isolation: an agent able to run a local decrypt command can still trigger the system prompt. Cancel unexpected Touch ID or PIN prompts and inspect the command that caused them.
Collaborating from Windows
Windows members can use a normal age identity in a multi-recipient setup:
shine env secret identity init
shine env secret identity list
Add its age1... recipient alongside macOS Touch ID recipients, then reseal existing workspace
payloads on a machine that can decrypt them. Editing the list alone does not update ciphertext.
Follow Add recipients to existing workspace secrets
before sharing the updated files with the new member.
Windows and macOS users can also experiment with age-plugin-phone
to authorize decryption with biometrics on their phone. The plugin offers a limited technical Beta with Windows/macOS source installation;
macOS remains experimental. Use only synthetic or disposable data and configure
an independent recovery key before using it. For supported devices, usage limitations, and setup
instructions, see experiment with phone authorization on Windows and macOS.
A normal age identity remains suitable for ordinary team development when its file and user-directory permissions are protected. For stable hardware-backed protection on Windows, prefer an organization-approved YubiKey/PIV or GPG with YubiKey workflow.
Choose a secret backend
A rough ordering by isolation strength is:
- GPG with YubiKey or another hardware smart card;
- age with Secure Enclave and Touch ID;
- a normal age identity file;
- plaintext secrets.
Age with Touch ID is often more convenient for team development and staging. For valuable production secrets, long-lived credentials, or strong hardware-isolation requirements, prefer GPG with YubiKey or an organization-approved hardware-backed design.
The experimental phone design aims for hardware-backed, authorization-per-use isolation, but it is not included in this stable-backend ordering until its protocol and release gates are complete.
Permissions for AI agents
Treat an agent as a capable local collaborator, not as an inherently trusted security boundary:
- Never add
~/.shine/age/identity.txt, GPG private keys, or cloud credential files to a workspace. - Do not let an agent keep an interactive shell with high-privilege secrets for long periods.
- Prefer letting the agent edit code and running
shine env runyourself in a trusted terminal. - Use a normal age identity for low-risk development and Touch ID or YubiKey for sensitive work;
limit
age-plugin-phoneto its documented synthetic-data preview. - Cancel unexpected Touch ID, phone biometric, PIN, or YubiKey-touch prompts.
Removing a recipient after an identity leaks, a device becomes untrusted, or a member leaves does not revoke access to historical ciphertext. Reseal or re-encrypt it and rotate the real upstream token when necessary:
shine env secret seal
Do not commit environment files containing unsealed strings. Add personal override files to
.gitignore, and keep only sealed ciphertext in shared files.
Hybrid access boundaries
Hybrid offers GPG or age access to one authenticated data payload. It is not two-person approval and does not combine both identity strengths. Any authorized private-key compromise can expose the secret. Changed, missing, replaced or spliced key wrappers fail format or integrity checks before release. The envelope does not authenticate its author or prevent replay of an entire old file.
Removing a recipient and resealing generates a fresh key and ciphertext. It does not revoke historical access, prevent authorized readers copying values, or rotate upstream credentials. Rotate exposed service credentials at their source. This new envelope protocol has not undergone an independent security audit.