envoke

module
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 23, 2026 License: MIT

README

envoke

CI Release

Run a shell script automatically when you cd into — or out of — a directory.

Activate a virtualenv the moment you step into a project. Switch kubectl context per repo. Export project-scoped secrets and have them vanish the moment you leave. One static binary, every major shell, nothing runs until you say so.

Full documentation →

Quickstart

brew install neirda24/tap/envoke
echo 'eval "$(envoke shell-init zsh)"' >> ~/.zshrc   # bash, fish, tcsh, powershell also supported
# ~/.envokerc
enter ~/Projects/([^/]+)
    source "$ENVOKE_DIR/venv/bin/activate"

leave ~/Projects/([^/]+)
    deactivate
envoke allow          # review the config once, approve it
cd ~/Projects/my-app  # venv activates, automatically

Full walkthrough in Getting Started, more config examples in Configuration.

Why envoke

  • Predictable matching — path patterns compile to Go's RE2 engine: linear-time, so a pathological pattern can't stall your shell.
  • Segment-based matching — ~/foo never accidentally matches ~/foobar.
  • One file, or one per project — patterns in ~/.envokerc cover whole trees of repos you don't own, and an envokerc.d directory splits rules per project. A config committed inside a repo joins in by a symlink you create, with patterns written relative to it (enter ./src).
  • Nothing runs unapproved, and nothing is discovered — envoke only loads configs from your own config directory, and each sits inert until envoke allow reviews and trusts it; any further edit revokes trust until you re-approve.
  • One binary, every shell — bash, zsh, fish, tcsh, and PowerShell hooks are all generated by envoke shell-init, not hand-maintained per shell.
  • Dry-run first — envoke debug <from> shows exactly what would fire on the way from there to where you are, without ever executing anything.
  • An off switch that isn't your rc file — envoke disable/enable, or ENVOKE_DISABLE for one terminal. And eval "$(envoke reload)" applies a freshly approved config where you're standing.
vs. ondir / direnv

envoke is a spiritual rewrite of ondir — same enter/leave-by-path-pattern idea. ondir is feature-complete by its own maintainer's account and still does the job, but it hasn't seen a release in years; envoke picks up the same model on a few specific points (regex engine choice, path matching semantics, a trust/approval step) and extends shell support beyond bash/zsh. direnv solves an adjacent problem: one .envrc per directory, found by walking into it, shaped around environment variables with automatic load/unload and a large stdlib — rather than arbitrary scripts pattern-matched across a whole tree.

Point-by-point: envoke vs. direnv (patterns across a tree vs. per-directory files, and when to use which) and Design Notes (vs. ondir).

What you can do with it

  • Activate/deactivate a Python (or any) virtualenv per project
  • Switch kubectl context / AWS_PROFILE / gcloud config per directory tree
  • Export and unset project-scoped API keys or feature flags
  • Swap Node/Ruby/Go toolchain versions per project
  • Tighten umask for a sensitive tree, restore it on the way out

Installation

brew install neirda24/tap/envoke                          # Homebrew (macOS/Linux)
scoop bucket add neirda24 https://github.com/Neirda24/scoop-bucket && scoop install envoke  # Scoop (Windows)
go install github.com/Neirda24/envoke/cmd/envoke@latest   # Go toolchain

Or grab a prebuilt binary, .deb, or .rpm from Releases for macOS/Linux/Windows (amd64/arm64) — each release's checksums.txt is cosign-signed, see the release notes to verify.

Status

Early development. Implemented and tested end-to-end against real interpreters: the matching engine, all five shell integrations, the envokerc.d fragment directory (relative patterns, symlinked project configs), the trust mechanism (allow, revoke, list, prune), the disable/enable off switch, reload, non-interactive exec, and debug dry-run diagnostics. Packaging is live: Homebrew, Scoop, GitHub Releases, and .deb/.rpm packages, each release carrying a per-archive SBOM and cosign-signed checksums.

Every command, flag, environment variable and exit code is listed in the Reference.

Contributing

See CONTRIBUTING.md.

License

MIT

Directories

Path Synopsis
cmd
envoke command
Command envoke runs shell scripts when you cd into or out of a directory.
Command envoke runs shell scripts when you cd into or out of a directory.
internal
config
Package config parses envoke config files into a set of enter/leave blocks, each pairing a path pattern with a shell script body.
Package config parses envoke config files into a set of enter/leave blocks, each pairing a path pattern with a shell script body.
configset
Package configset assembles the set of configs envoke acts on and loads each one exactly once.
Package configset assembles the set of configs envoke acts on and loads each one exactly once.
envoke
Package envoke wires the config, trust, matcher and executor packages together into the core enter/leave loop used for non-interactive execution (`envoke exec`).
Package envoke wires the config, trust, matcher and executor packages together into the core enter/leave loop used for non-interactive execution (`envoke exec`).
executor
Package executor runs a matched enter/leave block's script.
Package executor runs a matched enter/leave block's script.
fsperm
Package fsperm answers one question, in one place: can anyone other than the owner write this path?
Package fsperm answers one question, in one place: can anyone other than the owner write this path?
matcher
Package matcher resolves which enter/leave config blocks fire for a directory change, including ondir-style traverse behavior: jumping straight from /a to /a/x/y/z still fires the rules for the intermediate directories /a/x and /a/x/y, not just the destination.
Package matcher resolves which enter/leave config blocks fire for a directory change, including ondir-style traverse behavior: jumping straight from /a to /a/x/y/z still fires the rules for the intermediate directories /a/x and /a/x/y, not just the destination.
shellinit
Package shellinit generates the shell hook code printed by `envoke shell-init <shell>`, meant to be eval'd/sourced from the user's shell rc file (e.g.
Package shellinit generates the shell hook code printed by `envoke shell-init <shell>`, meant to be eval'd/sourced from the user's shell rc file (e.g.
state
Package state holds envoke's on-disk runtime state: where it lives, and the one flag stored there that isn't a trust record — whether envoke is switched off.
Package state holds envoke's on-disk runtime state: where it lives, and the one flag stored there that isn't a trust record — whether envoke is switched off.
trust
Package trust implements envoke's config trust store: a config file must be explicitly approved with Allow before shell-hook will act on it, and any change to the file's content — even whitespace — revokes that trust until Allow runs again: envoke must never auto-execute a new or modified config.
Package trust implements envoke's config trust store: a config file must be explicitly approved with Allow before shell-hook will act on it, and any change to the file's content — even whitespace — revokes that trust until Allow runs again: envoke must never auto-execute a new or modified config.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL