Customize presets
Use an overlay for a small number of customizations. Use an external presets_dir when you need to
maintain a complete preset collection.
These modes have different fallback rules:
- with the built-in base, an overlay replaces matching paths and every unmatched path still comes from the embedded preset;
- a full external
presets_diris authoritative for app and shell categories. Missing content is not silently borrowed from the binary.
Shine prints Preset Source, optional Presets Overlay, and external shell deployment mode so you
can tell which model is active before interpreting list, update, or install output.
Create a preset with AI
Shine ships the portable Agent Skill at skills/shine-preset-author/ in its source and crate
package. Register that directory with your AI client's native skill installer or skills-directory
mechanism, then ask in ordinary language for an app configuration, shell command, system bootstrap,
or customization of a built-in category. Shine does not detect or edit Codex, Claude, Cursor, or
other client configuration.
The skill checks that the installed Shine supports static validation, selects the matching author reference, scaffolds from the current binary, validates the result as JSON, and performs only an isolated dry-run. It never links or activates the category and never runs hooks, artifacts, generators, installation scripts, or a real bootstrap. The skill instructions are English for cross-client portability, but questions and the final report follow the user's language.
You can use the same flow without an AI client:
mkdir -p my-presets/app/my-editor
cd my-presets/app/my-editor
shine preset new app
# Add config files and edit shine.toml.
shine preset validate . --format json
shine preset lint . --format json
shine preset plan . --platform macos --format json
shine preset test . --format json
The default scaffold does not add an empty permission table. Use the option below to add the unrestricted author statement:
shine preset new app --unrestricted
shine preset new shell --unrestricted
shine preset new sys --unrestricted
All arbitrary code is unisolated whether this option is present or absent. The option does not skip trust, Plan review, administrator authorization, ownership checks, or explicit environment inputs.
Use shell or sys in preset new for the other kinds. To customize an embedded category, enter
the repository or overlay root and run shine preset copy <kind>/<name>; the command creates the
kind/category path.
Path progress messages for preset new, preset copy, and preset export escape terminal control
characters. File locations and the existing --force replacement rules are unchanged.
Repeated-link notices also escape controls in the source path; they keep the existing link unchanged.
preset validate also accepts a repository root, one category directory, or its shine.toml. Root
validation scans only direct category directories below app/, shell/, and sys/; an empty root
is invalid. It evaluates the macOS, Linux, and Windows declarations on any host, verifies referenced
files and locked Bun dependency policy, and reports compatible metadata-free app/shell categories
with a legacy_metadata warning. It does not load active source/overlay settings, initialize config,
check for updates, write files, access the network, or execute preset code.
The default output is text. --format json is available for tools and CI. Validation errors exit
with status 1; warnings do not.
Text validation, lint, and authoring-plan reports escape control characters in paths, identifiers,
diagnostics, and permission labels. JSON reports retain the original field values.
Diagnostic codes identify the failed check, independently of category names or message wording.
For example, a missing referenced file reports missing_reference, while a rejected Bun dependency
declaration reports bun_dependency_policy.
Run shine preset schema --format json when authoring tools need the exact report and fixture
formats supported by the installed version. Continue to use preset validate as the acceptance
check for App, Shell, and Sys metadata.
Run preset lint after validation to find author-quality and portability issues. Warnings are
advisory by default; CI can add --deny-warnings after reviewing them.
If lint cannot load or validate the input, its text hint includes the original PATH; run that
preset validate command from the same directory to inspect the failure. For a non-UTF-8 PATH
or one containing control characters,
the text explains that the copyable command is omitted; reuse the original argument with
preset validate. JSON reports keep their path-independent diagnostic messages.
Lint checks each platform's applicable resources, including PowerShell commands on Windows;
App categories or files intentionally unavailable on an OS are skipped for that OS.
Then run preset plan for each target platform. It previews a hypothetical first installation and
shows actions, permissions, and blockers without changing the machine. A blocker commonly means the
preview lacks a required environment value, trust decision, command, or administrator state; the
report is authoring feedback, not approval for a real installation.
Add shine.test.toml when the category needs repeatable cross-platform expectations. Tests describe
the starting conditions and expected results without running setup code. Runnable App, Shell, and
Sys examples are available under examples/presets. preset test accepts one category, not a
repository root.
Declared files and receipts share the planner's virtual directories on every host, including
Windows. Use relative file bases and receipt placeholders such as ${HOME} for portable cases.
Text reports escape control characters in case names so each result stays on one row.
JSON reports preserve the original names; pass/fail results and exit codes are the same in both formats.
When you need a distributable artifact, pack the reviewed category outside its source tree:
shine preset pack . --output ../../my-editor.shine-preset.tar.gz --format json
The returned hash identifies the bundle. shine.test.toml remains author-only and is not included.
A pack-policy failure must be fixed in the source; --force only replaces the output file and never
bypasses validation or policy. The output directory is checked after resolving symbolic links and
parent components (..); it must remain outside the category, even with --force.
Existing ancestors must be directories: a path such as file/../bundle.tar.gz fails with
output_write_failed when file is a regular file, without creating or replacing a bundle.
Without --force, an output created by another process during packing is preserved and the command
fails with output_exists.
Check App code before execution
Shine automatically checks App Bun generators, script hooks, artifacts and teardown scripts,
including resolvable local JavaScript/TypeScript dependencies. A definite difference between the
code and its declarations, or a supported-source parse failure, blocks execution. Fix the reported
file and position: declare the intended behavior accurately, or change the script to fit its
declarations. Trust, --yes, and opaque_code = "unrestricted" do not bypass this check.
Run shine preset lint <PATH> to examine all App code entries, including generators whose inputs
are absent. preset plan and preset test examine only entries selected by their hypothetical
inputs. Their reports show that scope; skipped entries are not reported as matches. These checks
do not run scripts, download dependencies, or read real environment values.
Coverage gaps, such as dynamic targets, package dependencies, subprocess effects and unsupported languages, are advisory. Declarations not corroborated by the analyzed source are also advisory and appear in detailed review. Neither means the code is safe or fully analyzed. Reports without diagnostics add no ordinary output; existing trust and approval checks still apply.
For SOURCE=TARGET environment mappings, declare the source name and its plain/secret
sensitivity; the script reads the target name. Only documented fixed variables are exempt, not
arbitrary names beginning with SHINE_. Never put environment values or URL credentials in a
capability declaration. Source locations use one-based lines and UTF-8 byte columns.
Tool consumers should read preset schema again after upgrading: lint reports use schema 2,
author Plan reports schema 3, and fixture reports schema 2. Fixture input schema 1 is unchanged;
expect.analysis_diagnostic_codes can assert diagnostic codes alongside ready. A correctly
expected blocked case can pass, but cancellation or command-wide budget exhaustion cannot become
a successful negative test. complete = false identifies incomplete author reports, and fixture
reports list unfinished_cases. Lifecycle Plan/approval/review contracts use schema 3; obtain a
new review instead of reusing an older approval.
Migrate a 1.x source
Preview the active external source and overlay, or name a repository, category, or manifest:
shine preset migrate --dry-run
shine preset migrate ./my-presets --dry-run
shine preset migrate ./my-presets
The migrator shows unified metadata diffs and confirmation defaults to No. It edits only
shine.toml, validates the candidate, rechecks source hashes, and creates a complete private backup
set before writing. Payloads, scripts, values, runtime manifests, and trust grants are untouched.
Text backup paths escape terminal controls; backup contents and JSON report identifiers are unchanged.
Exact released 1.x built-in metadata may be rebased when its executable identity is unchanged;
legacy Apps may receive current metadata without adding capability statements. Missing optional
capability tables do not require migration, including for opaque code; external-code trust remains
a separate review. Sys v1 dispatchers still require manual migration.
--yes is appropriate only after review and still prints text diffs. JSON is a versioned report
without contents or diffs; use --format json --dry-run for inspection or combine JSON apply with
--yes. A managed Git overlay is diagnosed but never changed—run the explicit-path command in its
upstream checkout, commit there, and pull the mirror again.
Describe capabilities and required inputs
Permission schema v1/v2 tables are optional author capability statements. App statements belong to
the category root, each Shell [[files]] command can have [files.permissions], and each Sys
[[items]] target can have [items.permissions]. Shine validates any table you provide, but a
missing or empty table does not hide or confine arbitrary code. Supported App code still needs
accurate declarations for statically identified behavior. Unsupported versions, unknown
fields, invalid identities, and duplicates are errors.
[permissions]
schema_version = 1
administrator = true
filesystem = [
{ access = ["read", "write"], base = "home", path = ".config/example" },
{ access = ["execute"], base = "preset", path = "build.ts" },
]
network = [{ scope = "host", host = "api.example.com" }]
commands = ["bun"]
environment = [{ name = "API_TOKEN", sensitivity = "secret" }]
system = [{ capability = "split-dns", resource = "private-domain" }]
Permission schema v2 supports the unrestricted author statement:
[permissions]
schema_version = 2
opaque_code = "unrestricted"
For Shell and Sys categories, use permission_defaults to apply one declaration to entries that
do not provide their own target-local override:
[permission_defaults]
schema_version = 2
opaque_code = "unrestricted"
[[files]]
source = "foo.sh"
target = "foo"
[[files]]
source = "bar.sh"
target = "bar"
Defaults are resolved separately for each command or Sys item; a targeted operation does not inherit capabilities from unrelated entries. An entry-level permission table replaces the default for that entry.
Filesystem bases are home, shine, data-dir, preset, or absolute; non-absolute paths are
normalized relative paths, with . meaning the selected base root. Commands contain one program
identity without arguments. Environment entries contain names and plain/secret sensitivity,
never values or ciphertext. Do not repeat commands, script paths, ordinary destinations, or fixed
package providers already present in typed metadata. Declare statically identified App script
effects; additional statements can help reviewers understand intended effects.
opaque_code = "unrestricted" is optional review metadata. Core automatically marks App hooks,
generators and artifacts, installed or sourced Shell commands, and Sys scripts/profile code as
unisolated even when this field or the whole table is absent. It never forwards environment values
or grants elevation. Environment allowlists and plain/secret sensitivity, plus Administrator
requirements, remain explicit because Shine enforces those managed injection/elevation contracts.
The security Plan presents Shine's derived operations, unverified author statements, and code/trust
boundaries separately. A statement is not an authorization grant or proof that script behavior is
complete. Arbitrary code runs with the access already available to its process; Shine does not add a
runtime sandbox or intercept every later Shell command invocation.
Static App data files are reviewed as file operations. Names beginning with generator:, hook:,
or artifact: do not by themselves request code execution or external-code consent.
Interactive lifecycle operations can authorize the listed external code when you confirm the Plan.
This authorization applies only to that operation and captured snapshot; it saves no persistent grant.
The confirmation includes code delivered for later execution, such as installed Shell commands.
Automation and --yes require an existing matching grant; --yes cannot supply human code consent.
Explicit info/update --run-generators evaluation also requires a grant; use interactive
shine app refresh when you want to approve a generator for one operation.
For persistent authorization, inspect and grant the target:
shine trust inspect <TARGET>
shine trust grant <TARGET>
shine trust grant <TARGET> --development
Snapshot trust binds the target, capability, and complete effective category snapshot, including
logical paths, exact bytes, source layers, and captured Unix executable flags. Changing category
content or whether a file is executable requires renewed snapshot authorization. Existing snapshot
grants for categories containing executable files may require review again after upgrading.
Author statements appear in review and affect the Plan, but are not separately compared as trust identity.
Editing statements in shine.toml still changes the snapshot bytes.
The snapshot excludes node_modules; trust does not constrain interpreters, PATH tools, dependencies,
downloads, or runtime side effects.
Development trust is long-term authorization of future code from the displayed local source for the
specified target and capability. Source directory/layer changes and new targets or capabilities need
new authorization. It does not mean continuing code review. Shell live deployment requires this mode.
When live deployment is blocked, review the target with shine trust inspect <TARGET> before
choosing shine trust grant <TARGET> --development. If you do not want to authorize future code
changes, set external_shell_mode = "snapshot" and review again; ordinary snapshot trust cannot
authorize live deployment.
opaque_code = "unrestricted" does not enable development trust. trust list,
trust inspect, and the security Plan label active development trust; the private local trust store
owns the grant, so a Preset cannot distribute or enable it.
The default trust list view groups capabilities with the same security scope into one row and
shows whether each stored grant is current. Use trust list --verbose for capability names, local
development-source labels, and stale-grant review guidance.
Trust command output escapes control characters in targets, source labels, and author capability
statements. Stored identities remain unchanged. For a target containing control characters, review
hints omit copyable commands; pass the original target argument to trust inspect or trust grant.
Every external Shell command uses the canonical shell/<CATEGORY>/<COMMAND> trust target. Use
preset to inspect or trust every executable target
in the current active Preset snapshot; Shine still stores a separate target-local grant in the
selected mode for each target. Revoking preset clears every stored Preset trust grant:
shine trust inspect preset
shine trust grant preset
shine trust grant preset --development
shine trust revoke preset
Trust-store schema v2 uses this complete-category boundary. Older v1 grants remain visible and revocable, but show that re-review is required and cannot authorize a new operation. A successful grant replaces the old record for the same target and capability.
AI tools may generate and statically validate Presets, but cannot approve their own code. Review the actual generated changes through a trusted human interface. A changed snapshot invalidates the approval. Development trust for an AI-writable directory permits future AI edits for enrolled targets. An AI with unrestricted terminal access can grant trust or execute scripts directly; its tool host must enforce that authority boundary.
From source folders to installed capabilities
Any tool or process that places a preset folder on a machine can be the synchronization layer. Shine does not require Git or provide general-purpose folder synchronization. It turns selected source files into installed capabilities: it creates managed command entries, resolves local values, keeps an installed snapshot by default, reports pending changes, and removes only what it owns.
The built-in shell/image-tools/ category is a complete example. It exposes three image commands
through this metadata:
description = "Personal image workflow commands."
[[files]]
source = "compress.ts"
target = "img-compress"
runtime = "bun"
platforms = ["unix", "windows"]
env = ["IMAGE_QUALITY"]
[[files]]
source = "resize.ts"
target = "img-resize"
runtime = "bun"
platforms = ["unix", "windows"]
env = ["IMAGE_QUALITY", "IMAGE_MAX_WIDTH", "IMAGE_MAX_HEIGHT"]
[[files]]
source = "convert.ts"
target = "img-convert"
runtime = "bun"
platforms = ["unix", "windows"]
env = ["IMAGE_QUALITY"]
The category includes three entry files plus a shared implementation using
Bun.Image. It compresses, resizes, and converts JPEG, PNG,
and WebP without ImageMagick, Sharp, or another image library. Every machine that runs the commands
needs Bun 1.3.14 or newer in PATH; Shine does not bundle Bun. The commands detect a missing
Bun.Image API and print an upgrade hint.
Install the category or one command, then use the same lifecycle as any other shell preset:
shine info shell/image-tools
shine install shell/image-tools/img-compress
img-compress photo.jpg screenshots/
img-resize --width 1280 --output-dir ./resized photos/
img-convert --format webp --quality 75 --output-dir ./webp hero.png gallery/
shine info shell/image-tools --diff
shine upgrade shell/image-tools
shine shell uninstall image-tools/img-compress --dry-run
Each command accepts multiple file or directory inputs. A directory scan processes direct JPEG,
PNG, and WebP children only; it never recurses. Without --output-dir, output stays beside its
source as photo.compressed.jpg, photo.resized.jpg, or the selected conversion extension. An
output directory flattens the selected inputs, so duplicate target names fail explicitly. Existing
files also fail unless --force is present, and source images are never modified in place.
Conflicts include case and Unicode-equivalent names, directory aliases, and outputs that refer to
an input through a hard link. --force does not permit replacing an input image.
Batch processing continues after an individual failure and returns a nonzero status if any item
failed. The first 20 failures appear in the terminal. If there are more, the complete list is also
written to a uniquely named image-tools-errors-*.log under --output-dir, or the current directory
when no output directory was supplied.
IMAGE_QUALITY, IMAGE_MAX_WIDTH, and IMAGE_MAX_HEIGHT default to 80, 1920, and 1080.
Command options override them for one invocation; changing the Shine values keeps the preference on
that machine. In the default snapshot mode, changing a copied or external source still requires
shine upgrade before the installed command changes. This is the boundary between synchronizing a
script file and operating it as a reusable personal capability.
Override selected files with an overlay
An overlay replaces base-preset files at the same relative path and can add new categories:
shine preset overlay link ~/dotfiles/shine-overlay --create
shine preset overlay info
shine preset overlay unlink
Local preset link and preset overlay link paths, including resolved symlink targets, must be
valid UTF-8. An invalid path or a required non-UTF-8 home expansion fails instead of linking a
differently spelled directory; --create does not bypass this check.
Unlink removes overlay settings from the active configuration; it does not delete source files.
Removing a project override can restore an inherited global overlay. Run shine preset overlay info
to inspect the effective overlay afterward.
For example, app/starship/starship.toml overrides the file at the same path in the base source;
other presets continue to use the base source.
Mirror an overlay from Git
Shine can manage a local mirror of a read-only overlay repository used by multiple devices:
Git-managed overlays are global settings. Run the following commands outside any Shine project:
neither the current directory nor its ancestors may contain a shine.config.toml.
Inside a Shine project, overlay link --git is rejected before
changing the configuration or mirror. For a project-specific overlay, clone the repository yourself
and use shine preset overlay link <PATH> from the project instead.
shine preset overlay link --git https://example.com/team/shine-overlay.git --branch main
shine preset pull
shine preset overlay info
The link command shallow-clones the repository under ~/.shine/overlay/. Later pulls
mirror that directory to the latest state of the remote branch. overlay info reports managed
directory presence. Git source, branch, directory and retained-checkout messages escape terminal
control characters.
It is a disposable cache: the next
pull discards local edits. Make changes and push them in an upstream checkout, then synchronize each
device with shine preset pull, shine update --pull, or shine upgrade --pull.
Relinking with a different Git URL switches the existing mirror to that repository. Without
--branch, each sync follows the configured remote's default branch. A failed fetch preserves
the previous checkout.
The managed overlay must be a standalone Git checkout at that directory. Shine refuses ordinary directories, linked checkouts, and linked Git metadata without changing their contents. Move an unexpected directory aside before retrying. After a successful fetch, synchronization discards tracked edits, untracked and ignored files, and nested repositories in the managed mirror, even when the remote commit is unchanged. Keep local customizations in a manually linked overlay instead. Git overlay checkout paths must be representable as UTF-8. Unsupported paths are rejected before cloning rather than redirected to a different path containing replacement characters.
To customize one built-in category, copy it at the overlay root instead of exporting everything. For example, copy Surge before editing its local proxy, group, and rule files:
cd ~/dotfiles/shine-overlay
shine preset copy app/surge
The command accepts complete app/<name>, shell/<name>, or sys/<name> categories. Existing files
are overwritten only with --force. The overlay replaces only paths you keep, so delete copied files
you do not customize and let them continue to come from the built-in version. See
Manage application configuration for the remaining Surge
steps.
Export the complete preset collection
shine preset link ~/dotfiles/shine-presets --create
shine preset export
Export includes built-in presets plus overrides and additions from the active overlay. It does not copy files that exist only in the external base directory; the progress message identifies whether an overlay is included. Copy still extracts the pristine built-in category.
Activation hints use a <PATH> placeholder and show the destination separately with display escapes.
Supply the actual path as one argument, quoting it for your shell; the escaped display is not a
ready-to-run shell argument.
Both preset copy and preset export reject linked or special output files and linked
subdirectories, including with --force. Choose an ordinary directory tree for the output.
Without --force, existing regular files are preserved even when another copy runs concurrently.
After linking an external directory, install, list, and update read from it. Command output
identifies the active preset source.
Choose how external shell presets are deployed
External shell presets use snapshot mode by default. During installation, Shine copies the
effective category under ~/.shine/installed/shell/ and commands execute the managed copy. After
editing the source, run shine update to inspect changes and shine upgrade to apply them. This gives
shell scripts the same review-before-update flow as application configuration. update reports
legacy direct-link installations, and upgrade migrates them.
For preset development, explicitly enable live mode when linking the source:
shine preset link ~/dotfiles/shine-presets --live
In live mode, ordinary shell and Bun source changes take effect on the next invocation. Files with
transforms are rendered atomically before each call; a rendering failure aborts that call rather
than executing stale output. Changes to entry metadata such as target, runtime, transforms, or
env still require shine upgrade to rebuild the managed entry. Restore snapshot mode by running
shine preset link <PATH> without --live, or use shine preset unlink.
If a linked overlay or live preset directory is moved, link the new path and run shine update.
Snapshot deployments stay current when their effective relative files and bytes are unchanged.
Live deployments report the old and new source paths because shine upgrade must repoint their
managed command entries; this relocation is shown separately from content changes.
Use locked packages in external Bun presets
Built-in Bun presets remain self-contained. External presets and overlays may use ordinary registry
packages by committing both package.json and bun.lock in the same physical category directory as
the effective script:
shell/my-tools/
├── shine.toml
├── package.json
├── bun.lock
├── command.ts
└── shared.ts
This convention also applies to Bun app artifact, teardown, and generator scripts under
app/<category>/. Both files are required. Shine rejects a lone manifest or lock and, in this first
version, any trustedDependencies declaration. An overlay declaration applies only when
the overlay supplies the effective script; adding package files beside an inherited built-in script
does not enable dependencies for it.
Shine runs built-in and unlocked external scripts with bun --no-install. A locked external script
runs with bun --install=fallback, so its first actual execution may download missing packages.
list and info never fetch dependencies. Shine does not run bun install, copy node_modules, or
own Bun's global cache and virtual store; uninstalling Shine or a preset does not clear those shared
caches.
For snapshot Shell presets, package or lock changes appear in shine update and take effect after
shine upgrade. In live mode they are read on the next command invocation, while status still
reports that the installed command should be refreshed. Fully offline machines need the relevant
Bun cache already populated, or a bundled/vendored script. Native extensions, workspaces, file:,
link:, and dependencies requiring lifecycle scripts are not guaranteed in this version.
To migrate an external script that currently relies on Bun's implicit installation, create its
category-local package.json, generate bun.lock with the repository's Bun version, commit both,
and test from an empty Bun cache. Without the pair, bare package imports now fail instead of being
downloaded automatically.
You can also select the source through an environment variable:
SHINE_PRESETS=~/dotfiles/shine-presets shine preset export
Create a commit-ready preset repository
cd ~/dotfiles/shine-presets
shine init
This creates shine.config.toml and sets presets_dir to the current directory. Shine searches from
the working directory upward for the nearest project configuration, so commands work in its
subdirectories. Use shine init --yes in non-interactive scripts.
Pull Git-managed sources
When the external preset directory or a manually linked overlay is a Git worktree, pull sources alone or pull before inspecting or applying configuration:
shine preset pull
shine update --pull
shine upgrade --pull
Shine locates the repositories containing the base presets and active overlay. If both sources are in
one repository it pulls only once; non-Git sources are skipped. Git repository root detection preserves
directory-name whitespace, including trailing spaces on systems that support them. update --pull
and upgrade --pull reload configuration after pulling, so an updated shine.config.toml affects later steps.
Every repository processed must meet these conditions before any pull begins:
- the worktree has no tracked or untracked changes;
HEADis on a branch, not detached;- the current branch has an upstream.
These sources use git pull --ff-only. Shine never stashes, rebases, resets, or resolves conflicts.
Validation stops before modifying any repository. These restrictions do not apply to an overlay
managed with --git, which is intentionally disposable. Git must be available in PATH.
Create category metadata
Generate a shine.toml template in an application, shell, or sys category directory:
shine preset new app
shine preset new shell
shine preset new sys
Existing files require --force. Category metadata is a preset-author interface; after editing it,
first run shine preset validate . --format json, then use the relevant isolated installation
--dry-run command. Shell install dry-run resolves intended command links without creating files,
links, manifests, snapshots, rendered files, or profile edits.
Give an application file its own destination
An application category has a default dest, but an explicit [[files]] entry may override that
root. target stays relative to the selected root:
dest = "~/.config/my-app"
[[files]]
source = "config.toml"
target = "config.toml"
[[files]]
source = "shared/rules.list"
target = "rules/provider.list"
dest = { base = "data-dir", path = "com.example.my-app" }
The override accepts the same absolute string or platform mapping as category destinations.
Mappings accept exact macos, linux, and windows keys plus unix as a macOS/Linux fallback;
an exact key wins when both are present. A missing branch omits that category or file on the
corresponding OS. platforms arrays on explicit App and Shell files use the same four selectors,
combine them with OR semantics, and must not be empty. The structured data-dir form is file-only
and resolves the platform's user
application-data root: %APPDATA% on Windows, Application Support on macOS, and XDG_DATA_HOME
(or ~/.local/share) on Linux. path and target must be relative and cannot contain ...
Legacy App presets without shine.toml still support a # shine-dest: full destination path
on the first line, or immediately after a shebang. The path must be absolute after home expansion
and cannot contain ... Replace parent components with an explicit destination before retrying.
Shine rejects two entries that resolve to the same destination before writing anything. If a later
metadata revision moves an already managed source, shine upgrade moves it only when the old copy
is unmodified and the new destination is free. Otherwise both locations are left untouched for the
user to resolve.
Shell entries with an optional runtime
runtime selects the runtime for a shell preset command entry; it does not add an interactive shell.
Without it, entries use native .sh or .ps1 files. The only configurable alternative today is
bun:
[[files]]
source = "my-tool.ts"
target = "my-tool"
runtime = "bun"
platforms = ["unix", "windows"]
env = ["API_URL", "SERVICE_TOKEN=API_TOKEN"]
Supported extensions are .ts, .js, .mts, and .mjs. Shine creates a managed entry without an
extension, which users invoke as my-tool. Existing native .sh and .ps1 entries remain
compatible.
Every device that runs the command needs Bun in PATH. Shine does not install Bun or manage
node_modules; external categories may opt into Bun-managed locked packages as described above.
runtime = "bun" cannot be combined with needs_source = true.
The optional env list applies only to Bun entries. Each item is KEY or SOURCE=TARGET. The entry
injects values through shine env run --no-workspace --with ..., preferring SOURCE_SECRET and then
plain SOURCE. When env is declared, the machine must also have shine in PATH. Declare only key
names in metadata—never values or ciphertext.
Future runtimes will be documented here with their values, file types, prerequisites, and limits.
Python, Node, and Deno are not currently valid runtime values.
Author a system bootstrap item
A sys category is one OS directory such as sys/ubuntu/. Every executable sys preset declares
version = 2, then describes ordinary ensure-present software with detection and a fixed provider:
version = 2
[[items]]
id = "mise"
label = "mise"
description = "Install mise without managing its versions."
[items.detect]
kind = "command"
command = "mise"
version_args = ["--version"]
[items.install]
kind = "package"
provider = "homebrew" # homebrew-cask, apt, or winget are also supported
package = "mise"
[[items.shell]]
shells = ["bash", "zsh"]
phase = "post"
when_command = "mise"
eval = ["mise", "activate", "{shell}"]
[profiles.recommended]
items = ["mise"]
Detection supports command, path, and any command/path probes. Package installs are fixed
ensure-present actions: Shine owns argv, elevation, proxy handling, timeout, output limits, and the
post-install detection, but never upgrades the package. A complex item may use
[items.install] kind = "script", path = "install/<item>.sh"; the script handles only that item,
returns a normal exit code. Every init item must declare both detect and install; there is no
platform-wide dispatcher fallback. Version 1 manifests are rejected before detection or profile
writes; see the v2 migration guide.
Shell integrations accept exactly one of path, env, eval, source, aliases, or fragment.
Use profile/base.pre.sh and profile/base.post.sh only for OS-wide content; put complex item logic
in profile/<item>.sh. Phase, optional priority, manifest order, and declaration order determine
stable composition. Named [profiles.*] tables select bootstrap items; they do not define shell
content or disable integrations outside the selection.
External sys install scripts and executable profile content (eval, source, fragments, and base
files) require either human confirmation of the current lifecycle Plan or an existing matching grant; the
project config and Preset cannot authorize themselves. A snapshot grant is invalidated by changed
category content or source layer; an explicit development grant accepts code edits only from its
enrolled source. If trust is missing during bootstrap preflight, no installer has run
yet. Static detection, package metadata, PATH, env, and aliases remain available without a grant.
Validate with
shine sys list, shine sys info <ITEM>, and shine sys bootstrap <ITEM> --dry-run.
Application artifact runtimes
An application's [artifact] can also use Bun for cross-platform apply and teardown scripts:
[artifact]
script = "build.ts"
teardown = "unbuild.ts"
runtime = "bun"
env = ["PROFILE_PATH", "API_TOKEN"]
The default is native, which executes the script directly. bun accepts only .ts, .js, .mts,
or .mjs and requires Bun on the machine. env is the only Shine [env] allowlist passed to the
artifact and supports SOURCE=TARGET aliases; declare each source and sensitivity again under the
category's [permissions].environment. Listed sources are forwarded only when configured; missing
optional values are omitted. Fixed application path variables are added separately. To
run an artifact automatically after installation or upgrade actually changes files, declare
post_install or post_upgrade; external presets require human confirmation of the lifecycle Plan
or a matching grant. Hooks cannot recursively invoke artifact lifecycle commands; use the supported
artifact configuration and explicit artifact operation instead.