Configuration reference
Shine stores global runtime state under ~/.shine/ and creates ~/.shine/config.toml when global
configuration is first needed. Configuration and manifest replacement does not delete the old file
before renaming the staged file, including on Windows; a failed rename preserves the existing file.
On Unix, when SUDO_USER identifies the invoking user, Shine resolves that user's home through
the system account database, including macOS Directory Services. Home-relative configuration and
path expansion therefore use the invoking user's home rather than sudo's root HOME.
Interactive lifecycle Plan confirmation can authorize the listed external code for that operation only,
without saving trust. Automation and --yes require an existing grant. Shell live always requires
Development trust; explicit --run-generators inspection also requires a grant.
Common global fields
presets_dir = "~/dotfiles/shine-presets"
# External shell presets default to snapshot; use live only for preset development.
external_shell_mode = "live"
presets_overlay_git = "https://example.com/team/shine-overlay.git"
presets_overlay_git_branch = "main"
app_default_dest_root = "~/.config"
sync_terminal_theme = true
gpg_recipients = ["user@example.com", "team-backup@example.com"]
secret_backend = "age"
age_recipients = ["age1tag1qexample...", "age1qteammate..."]
age_identity = "~/.shine/age/identity.txt"
age_identities = ["C:/Users/<user>/AppData/Local/age-plugin-phone/identity-....txt"]
[env]
HTTP_PROXY_PORT = "6152"
SOCKS5_PROXY_PORT = "6153"
PROXY_HOST = "127.0.0.1"
PROXY_NO_PROXY = "localhost,127.0.0.1,::1"
IMAGE_QUALITY = "80"
IMAGE_MAX_WIDTH = "1920"
IMAGE_MAX_HEIGHT = "1080"
MY_API_TOKEN = { value = "<token>", description = "Token for the internal API" }
[[env_proxy]]
command = "gh"
with = ["GH_TOKEN"]
# Defaults to true; false forwards without decrypting or injecting values.
enabled = false
| Field | Purpose |
|---|---|
presets_dir | Replace built-in presets with a complete external preset directory |
external_shell_mode | External shell deployment mode; snapshot by default, optionally live |
presets_overlay_git | Git overlay URL shallow-cloned and mirrored under ~/.shine/overlay/ |
presets_overlay_git_branch | Tracked overlay branch; omit for the remote default branch |
app_default_dest_root | Default root for legacy application presets without a destination |
sync_terminal_theme | Enable automatic terminal theme synchronization in managed Unix profiles; defaults on |
gpg_recipients | Default GPG recipients for shine env secret encrypt |
secret_backend | Default secret backend; gpg when omitted |
age_recipients | Default encryption recipients for age |
age_identity | Identity file for age: ciphertext; may default to ~/.shine/age/identity.txt |
age_identities | Additional identity-file paths, merged after age_identity and deduplicated |
[env] | Values used by templates and shell helpers |
[[env_proxy]] | Transparent command rule: bare command, injected KEY or KEY=ALIAS list in with, and optional enabled defaulting to true |
Legacy gpg_key_id and workspace [env.encryption].recipient accept only one recipient. Normal
configuration reads never rewrite them. Preview and apply conversion to gpg_recipients with
shine state migrate --dry-run and shine state migrate. The same migration converts legacy
age1se... recipients to age 1.3 native age1tag... recipients; this removes the Secure Enclave
plugin requirement from encrypting computers but makes targeting testable by someone who knows the
recipient. env run and env secret seal prompt to migrate an old workspace when needed.
Phone recipients are not converted by state migrate. After upgrading and verifying tag support in the plugin and phone app, export with age-plugin-phone recipients -i <IDENTITY_STUB> --recipient-type tag, replace the corresponding age_recipients value, and reseal while retaining an independent recovery recipient.
When a command reads malformed trust.toml or ssh-secret-broker.toml, TOML parse errors
identify the file without printing stored contents. A failed parse does not repair or rewrite it.
External-code trust
External App hooks, generators, artifacts, Sys install scripts, executable profile content, and
every external Shell command use target-scoped grants stored in
the owner-only ~/.shine/trust.toml file. Do not edit this file or place grants in project
configuration. Review and manage the current snapshot with:
shine trust inspect app/example
shine trust grant app/example
shine trust list
shine trust revoke app/example
shine trust inspect shell/tools/my-command
shine trust grant preset
shine trust grant app/example --development
A snapshot grant applies only to the reviewed target, capability, source layers, and
complete effective category snapshot. An explicitly
requested --development grant keeps trusting code edits from the displayed local source while
the target, capability, and source directory/layer remain unchanged.
This is long-term authorization of future source content, not continuing code review.
Permission-table presence does not control code classification or grant eligibility.
A grant does not replace the Plan shown for each operation. Retired allow_app_hooks and
allow_sys_code fields are ignored and removed on the next configuration save.
The preset target batches the current active snapshot for review or enrollment but persists
separate grants for each target. New targets and capabilities require authorization; development
grants additionally fail closed when their local source changes.
Trust grants written by schema v1 remain listable and revocable but require review again.
Environment entry formats and descriptions
[env] in global and project configuration, plus every shine.env.toml override, accepts a string or
a detailed value:
[env]
PLAIN_VALUE = "example"
DETAILED_VALUE = { value = "example", description = "Example value used by build tasks" }
- A string suits a value that needs no explanation.
- Detailed
valuebehaves like a string inenv get, template replacement, secret encrypt/export, andenv run --with. descriptionappears only inshine env listand is never passed to templates or children.- Inline descriptions override the same key in the preset
<presets>/env.tomlcatalog. shine env setpreserves the description of an existing detailed entry.- Strings and detailed entries containing only
valueinherit lower-layer descriptions. An explicitdescriptionreplaces the inherited description; an empty string clears it and disables catalog fallback. Value and description sources are tracked separately. - Invalid numbers, arrays, or tables without a string
valuereport file and key instead of being ignored.
Project configuration
Shine searches upward from the current directory for the nearest shine.config.toml. It is a sparse
layer over global configuration: omitted fields inherit, and relative paths resolve from the file
that declares them.
[[env_proxy]] follows the same layering. A project rule replaces a global rule with the same
command; unrelated global rules remain. Prefer shine env proxy install, enable, and disable so
configuration remains consistent with the shim under ~/.shine/bin/.
Shine 0.40.0 stopped recognizing project config.toml and .env.toml; rename them to
shine.config.toml and shine.env.toml. Ordinary files with the old names are ignored.
It also stopped automatically migrating global ~/.shine/env.toml. Before upgrading, load it once
with v0.39. After upgrading, move it to ~/.shine/shine.env.toml, manually merging an existing
destination. Detection of the old file stops normal configuration loading with recovery instructions
instead of silently dropping active values.
Directory and source precedence
Relative --config-dir, SHINE_CONFIG_DIR, and SHINE_PRESETS paths are resolved against the
invoking working directory before lifecycle planning or script execution. Child working-directory
changes do not change the selected runtime roots.
SHINE_CONFIG_DIR has the highest priority. It changes the global configuration and runtime root
and, outside a project, fixes the preset directory at $SHINE_CONFIG_DIR/presets/; SHINE_PRESETS
and a global presets_dir do not override it.
When a project shine.config.toml is active, SHINE_CONFIG_DIR still selects the runtime root, but
an explicit SHINE_PRESETS or project presets_dir can select the preset source. An inherited
global presets_dir cannot override $SHINE_CONFIG_DIR/presets/.
Without SHINE_CONFIG_DIR, the base preset directory is selected in this order:
SHINE_PRESETS;- project
shine.config.tomlpresets_dir; - global
config.tomlpresets_dir; - default
~/.shine/presets/.
An external preset or overlay root may be a symbolic link. Shine resolves that root before capture and uses the resolved source for development trust; retargeting it requires review again. A broken root link is an error. Symbolic links inside the preset tree remain excluded from the snapshot. Special entries such as FIFOs, sockets, and devices fail snapshot capture with an error; Shine does not read them as preset files.
External shell categories default to snapshot: Shine copies them to
~/.shine/installed/shell/. On Unix, snapshots retain captured executable flags for scripts and
helpers without copying ownership or privileged mode bits. Permission-only changes, including
missing executable flags in an older installed snapshot, appear in shine update and are repaired
by shine upgrade. After source edits, inspect with shine update and apply with
shine upgrade. Set external_shell_mode = "live" only for development; source content takes effect
on the next invocation, but changes to target, runtime, transforms, or env still require
shine upgrade to rebuild managed entries. Live mode requires an explicit development trust grant;
snapshot trust cannot authorize a launcher that reads mutable source. Existing live launchers are
preserved, and status marks those missing development trust for review.
After upgrading Shine, run shine update and shine upgrade to refresh existing transformed Live
Bun commands. Their refreshed entries use the installation's configuration directory for both
rendering and declared environment values, even when the caller sets a different SHINE_CONFIG_DIR.
Project configuration and shine.env.toml overrides still follow the caller's working directory.
The refreshed PowerShell entries preserve empty arguments and literal --, including on Windows
PowerShell 5.1.
This change covers Live Bun commands with transforms, including commands without declared env;
raw Live commands, native/source commands and snapshot commands keep their existing launch behavior.
An overlay replaces files at matching relative paths over the chosen base instead of replacing the
whole tree. presets_overlay_dir and presets_overlay_git are mutually exclusive; use
shine preset overlay link to configure them safely. presets_overlay_git and
presets_overlay_git_branch are global-only keys in config.toml; run overlay link --git
outside any Shine project. Projects can use presets_overlay_dir for a local overlay.
A Git overlay becomes active after the link command clones it, or after a successful
shine preset pull when configured manually. Later pulls forcibly mirror its checkout, so never
edit ~/.shine/overlay/ directly.
Environment value precedence
Later layers override earlier values:
- built-in defaults (runtime fallback only);
- active overlay
shine.env.toml(shared baseline); - global
config.toml[env]; - global
shine.env.toml; - project
shine.config.toml[env]; - project
shine.env.toml.
Every installation uses this order. SHINE_CONFIG_DIR selects the global runtime root; paths are
not fixed to ~/.shine/. Loading or saving unrelated settings never expands built-in defaults into
files. Existing entries remain explicit, including historical entries equal to old defaults; delete
an entry from its selected layer to inherit again. A lone shine.env.toml does not define a project.
Only the nearest shine.config.toml defines the project root and its env file; ancestor projects are
not merged.
Use shine env explain KEY for the value source, description source, override chain, and default
write target. It hides all values unless --reveal is given and never decrypts. env get keeps its
single-value output. See the environment guide for manual upgrade and
rollback steps.
An override file has no [env] header:
HTTP_PROXY_PORT = "7890"
PROXY_HOST = { value = "127.0.0.1", description = "Local proxy host" }
Workspace environments
shine.workspace.toml declares modes, ordered environment sources, and shared encryption
recipients:
version = 2
[env]
modes = ["development", "production"]
default_mode = "development"
override_process_env = false
files = [
".env.shine.toml",
".env.local.shine.toml",
".env.{mode}.shine.toml",
".env.{mode}.local.shine.toml",
]
[env.encryption]
gpg_recipients = ["user@example.com", "team-backup@example.com"]
# Or use age:
# backend = "age"
# age_recipients = ["age1tag1qexample...", "age1qteammate..."]
Sources merge in list order. Current process variables win by default;
env.override_process_env = true lets workspace values replace them.
For shine env secret seal and shine env run, encryption settings resolve from command-line
arguments, then [env.encryption], then global ~/.shine/config.toml. Global configuration is useful
for personal defaults; commit project-team GPG or age recipient lists here. Recipients are public-key
information. Never commit private identity files or machine-local identity paths such as
age_identity/age_identities.
Each source uses this structure:
version = 1
[plain]
PUBLIC_VALUE = "example"
[secret]
EXISTING_SECRET = true
PROMPT_ON_SEAL = false
PLAINTEXT_TO_SEAL = "<value to seal>"
[payload]
data = "<GPG ciphertext managed by Shine>"
shine env secret seal merges pending values into the encrypted payload and changes sealed entries
to true. shine env run merges [plain] and decrypted values in source order. With usable recipients and only single-backend policy/sources, it also maintains an encrypted,
mode-specific cache.
shine env run --with KEY[=ALIAS] injects a value from current Shine [env], preferring
KEY_SECRET and then KEY. Explicit injection overrides workspace and process values.
Managed directories
~/.shine/
├── config.toml
├── shine.env.toml
├── app-manifest.toml
├── shell-manifest.toml
├── proxy-manifest.toml
├── tasks.toml
├── bin/
├── http/
├── installed/
├── overlay/
├── rendered/
└── presets/
├── app/
├── shell/
└── sys/
Do not delete manifests manually and expect Shine to rediscover old installations. Prefer the
corresponding uninstall --dry-run and uninstall commands.
Hybrid workspace encryption
env.encryption.backend = "hybrid" requires both workspace gpg_recipients and
age_recipients, each with a nonblank entry. GPG entries must be locally available
full 40-hex primary public-key fingerprints. Global recipients are not merged.
Merely configuring both lists does not enable hybrid.
Set hybrid_decrypt_backend = "gpg" or "age" in global config.toml.
Local workspace operations may override this field in shine.config.local.toml
next to the workspace; an absent file or field inherits the global preference.
Shared shine.config.toml cannot override or save it. Ignore the personal file in
Git; it accepts only this field and rejects malformed or unknown fields. The
preference neither changes single-backend routing nor grants secret release.
SSH broker does not accept remote personal configuration. Global secret_backend
still accepts only gpg or age.
Hybrid compilation caches use the final selected backend and its workspace recipient list. Configuration changes re-evaluate cache validity without switching to another backend. See the environment guide.
Workspace file groups
Workspace version 3 adds the file_groups.<name>.files array. Each entry requires ciphertext source and plaintext target. Groups must be nonempty; names contain only letters, digits, hyphens, and underscores. Paths support {mode} and resolve relative to the workspace directory. env.files may be omitted when groups are present. Version 2 does not accept file groups. Encryption reuses [env.encryption], without group-specific or environment-specific policies. See temporary secret files.