Ghostable is a serverless CLI for local-first environment management: projects, environments, variables, devices, schema validation, agent guidance, and signed activity records.
Ghostable keeps environment management local-first and repository-backed.
Encrypted value files, public device records, signed policy, signed activity,
environment keys, and access grants live under .ghostable/ and are intended to
be committed to git. Private device keys are stored outside the repository in
the platform's native secret store when available, or in a restrictive
file-backed identity store otherwise.
Ghostable has not completed an external security audit. The repository includes a public security policy, a threat model, and stable test vectors so developers can inspect the claims and reproduce the critical cryptographic checks.
In Ghostable, "zero-knowledge" has a narrow product meaning: plaintext secret
values are encrypted locally before Ghostable writes repository-backed state.
Ghostable does not run a hosted service that receives plaintext project secrets.
This does not mean the local machine, local device identity, shell history,
plaintext .env files, deploy providers, or everyone with repository write
access are automatically trusted or harmless. Review .ghostable/ changes with
the same care as code changes.
Install Ghostable once, then run it inside each project you want to manage.
macOS:
brew tap ghostable-dev/ghostable
brew install --cask ghostableNode/npm projects:
npm install @ghostable/cliThis installs a project-local ghostable binary at
node_modules/.bin/ghostable.
When available, release candidates use npm's next tag:
npm install @ghostable/cli@nextOther platforms can download the matching archive from the
latest release and put
the ghostable binary on PATH.
Ghostable release builds target macOS, Linux, and Windows on both amd64 and
arm64. CI runs the full Linux check suite, native macOS and Windows test,
vet, build, and CLI smoke jobs, and cross-builds every release target from the
GoReleaser matrix.
Hosted CI verifies non-interactive protected-access behavior and the
platform-specific user-confirmation glue. It does not perform a live Touch ID,
Windows Hello, or PAM-backed sudo prompt, because those require an interactive
local user session.
From your project directory:
ghostable setupsetup is interactive. It prompts for project and device details, creates the
default environment, and asks whether to seed that environment from an
existing .env file. Automation can pass --seed-dotenv or
--no-seed-dotenv to make that choice explicit.
make buildghostable env push --env default --file .env --reason "Initial default baseline"
ghostable env pull --env default --file .env
ghostable env diff --env default --file .env
ghostable env diff --from staging --to production
ghostable validate --env default
ghostable hygiene report --env production
ghostable review --env production
ghostable deploy productionMost options can be omitted in an interactive terminal. Ghostable prompts for
project and device details when needed, and creates the default environment
automatically. If .env exists, setup asks whether to seed default from it.
Automation and agents should pass flags, use --seed-dotenv or
--no-seed-dotenv when setup should be non-interactive, and prefer --json.
setupinitializes.ghostable/, a local device record, policy, key metadata files, and a private local device identity.statusprints project, environment, device, and value counts.env list|create|delete|push|sync|pull|clean|run|shell|diff|historymanages environment-level workflows.validatechecks environment values against schema rules.reviewruns changed-code ENV checks and local hard-coded secret scanning.deploy [target] [environment]writes decrypted values to.envor syncs a configured provider target.var push|pull|promote|delete|history|context|annotationmanages a single variable and its key metadata.schema file|rule|keymanages local validation schema files.hygiene report|rotation|suppress|rotatemanages operational hygiene checks, rotation policy, suppressions, and environment encryption key rotation.access create|list|status|approvers|share|grants|revokemanages scoped automation credentials and policy grants.device join|list|statusmanages human device records.agent init|instructions|capabilitiesemits safe instructions and a recommended read-only/dry-run command allowlist for coding agents.
ghostable hygiene report checks stored variables and environment metadata for
operational hygiene issues. Variable rotation reminders are opt-in through
.ghostable/hygiene.yaml; stable config such as APP_DEBUG=false is not
reported as stale unless a rotation rule is configured for that key or
--stale-after is passed explicitly.
Unused-variable checks are also opt-in because framework and platform conventions can use environment values without direct code references:
ghostable hygiene report --env production --unusedSet a project-level rotation rule:
ghostable hygiene rotation set --key STRIPE_SECRET_KEY --days 90Set an environment-specific override:
ghostable hygiene rotation set --env production --key STRIPE_SECRET_KEY --days 60Rotation intervals are always whole days.
List configured rules:
ghostable hygiene rotation listThe policy file uses the same project-default plus environment-override shape as validation rules:
rotation:
keys:
STRIPE_SECRET_KEY:
rotationAfterDays: 90
environments:
production:
keys:
STRIPE_SECRET_KEY:
rotationAfterDays: 60ghostable review is the local review command. By default, it checks changed
code for both ENV usage drift and hard-coded secrets.
When --base is omitted, Ghostable uses the current branch upstream when
available, then origin/main, origin/master, main, master, and finally
HEAD. CI jobs can still pass an explicit --base <ref> for a fixed
comparison point.
For ENV usage drift, it scans changed lines for common ENV access patterns in
PHP/Laravel, JavaScript/TypeScript/Node, Go, Python, Ruby/Rails, Java, C#,
Rust, Swift, and shell/deploy scripts. It compares those references with
encrypted Ghostable values, schema files, .env.example, and signed
.ghostable/ records. GitHub Actions workflow references under .github/ are
ignored because those often come from GitHub Secrets or Vars.
For hard-coded secrets, it scans changed files locally and redacts findings by
default. Use ghostable review --secrets-only when you only want the secret
scan, or ghostable review --env-only when you only want the ENV metadata
checks.
The secret-scanning part of ghostable review uses manifest ignores from:
scan:
ignores:
- .git/**
- node_modules/**
- .ghostable/environments/**/values/**
- .ghostable/environments/**/keys/**Use --json for machine-readable output. --show-values exists for explicit
human debugging, but agents should avoid it unless the user asks.
Production-like environments require local user confirmation before Ghostable
writes, prints, injects, or deploys decrypted values. Environment names and
types containing prod, production, or live are treated as production-like.
Protected local-device commands include:
ghostable env pull --env production
ghostable env run --env production -- <command>
ghostable env shell --env production
ghostable var pull --env production --key APP_KEY --show-values
ghostable deploy production
ghostable deploy laravel-forge production --forge-site example.com
ghostable deploy laravel-vapor production
ghostable deploy laravel-cloud productionOn macOS, Ghostable uses LocalAuthentication and requires Touch ID biometric
verification. On Linux, Ghostable uses the local PAM-backed sudo
confirmation, which can use fingerprint verification when the machine's PAM
stack is configured for it. On Windows, Ghostable asks Windows to verify the
current user with Windows Hello or the machine's configured fallback.
Non-interactive local devices cannot satisfy protected access prompts. CI,
deploy scripts, and agents should use a scoped GHOSTABLE_CI_TOKEN automation
credential instead. Dry runs that do not write or print decrypted values do not
require confirmation.
Remove local plaintext env files after sensitive work:
ghostable env clean --dry-run
ghostable env cleanenv clean removes project-root .env and .env.* files, including
Ghostable backup files. It keeps .env.example files by default; pass
--include-example only when those templates should also be removed.
ghostable deploy production decrypts the selected environment and writes it to
.env unless the project manifest has a provider deployTarget, in which case
the configured provider is used by default. It replaces .env by default so
stale deploy values do not survive between runs. Use --merge when an existing
file should be preserved.
Use the explicit local target when a project has a provider target but a script needs a local env file:
ghostable deploy local productionProvider targets use ghostable deploy <target> [environment] [options]:
ghostable deploy laravel-forge production
ghostable deploy laravel-vapor production
ghostable deploy laravel-cloud productionShort aliases are also accepted:
ghostable deploy forge production
ghostable deploy vapor production
ghostable deploy cloud productionLaravel Vapor deploys selected Ghostable values to Vapor environment variables:
ghostable deploy laravel-vapor production --dry-run
ghostable deploy laravel-vapor productionghostable deploy laravel-vapor requires the vapor CLI on PATH unless
--dry-run is used. Variables are merged into Vapor's temporary
.env.<environment> file and pushed with vapor env:push.
Laravel Cloud deploys selected Ghostable values to Laravel Cloud environment variables using the Laravel Cloud CLI:
ghostable deploy laravel-cloud production --dry-run
ghostable deploy laravel-cloud production --cloud-env productionghostable deploy laravel-cloud requires the cloud CLI on PATH unless
--dry-run is used. It calls cloud environment:variables <environment> with
--action=set for each selected key, so existing Cloud variables with matching
keys are updated and missing keys are added. The Cloud environment defaults to
the Ghostable environment name; use --cloud-env when Laravel Cloud uses a
different environment ID or name.
Laravel Forge deploys selected Ghostable values to a Forge site's environment file using the Laravel Forge CLI:
ghostable deploy laravel-forge production --dry-run --forge-site example.com
ghostable deploy laravel-forge production --forge-site example.comghostable deploy laravel-forge requires the forge CLI on PATH unless
--dry-run is used. It pulls the remote site environment file with
forge env:pull, merges selected Ghostable values into a temporary file, then
pushes the result with forge env:push. Existing Forge variables with matching
keys are updated and missing keys are added. Pass --forge-site with the Forge
site name that should receive the variables.
Deploy systems can use a scoped automation credential instead of a local device identity:
ghostable access create --name deploy-bot --kind deploy --grant production:readerStore the returned token as GHOSTABLE_CI_TOKEN in the deploy system, commit
the updated .ghostable/ files, then run a dry-run before enabling writes:
ghostable deploy production --dry-run --jsonWhen the dry-run is correct, run:
ghostable deploy productionFor Laravel Forge, install Ghostable as an npm package in the project, commit
the .ghostable/ directory, and store the deploy credential outside the
application directory, such as /home/forge/.ghostable-ci-token with 0600
permissions. Then load it in the deploy script after dependencies are installed
but before Laravel commands that read .env:
npm ci
export GHOSTABLE_CI_TOKEN="$(cat "$HOME/.ghostable-ci-token")"
ghostable deploy laravel-forge production --forge-site example.com
npm run build
$FORGE_PHP artisan migrate --forceFor Laravel Cloud, run ghostable deploy laravel-cloud before starting a Cloud
deployment when changed variables should be available to the next deploy.
Committed project files:
.ghostable/ghostable.yaml
.ghostable/policy.json
.ghostable/devices/*.json
.ghostable/environments/<env>/keys/*.json
.ghostable/environments/<env>/values/*.json
.ghostable/events/*.json
.ghostable/hygiene.yaml
.ghostable/schema.yaml
.ghostable/schemas/<env>.yaml
Key metadata position values are sparse sortable ranks, not dense line
numbers. Generated layouts use gaps such as 1000, 2000, and 3000 so a
new key can usually be added without rewriting every existing key metadata
file.
Key annotations are signed plaintext key metadata with explicit string,
number, or bool values. They are intended for non-secret labels that future
custom rules or actions may read.
Value records may include a signed plaintext change.reason so reviewers can
understand why an encrypted value changed without exposing the secret.
Local-only private identity:
macOS: Keychain service dev.ghostable.identity.<project-id>
Windows: Credential Manager target dev.ghostable.identity.<project-id>
Linux/Unix: ${XDG_CONFIG_HOME:-~/.config}/ghostable/identities/<project-id>.json
When GHOSTABLE_KEYSTORE is set, private identity material is written to:
$GHOSTABLE_KEYSTORE/<project-id>.json
That fallback directory is created with 0700 permissions and identity files
are created with 0600 permissions.
Value writes use the Ghostable value schema (ghostable.value.v1) and the core
cryptographic model: Ed25519 device signatures, X25519 grants, HKDF-SHA256 key
derivation, and XChaCha20-Poly1305 value encryption.