envoke

module
v0.5.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

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.

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

Each of these is written out as a complete enter/leave pair, unwinding included, in Recipes.

Documentation

Install, hook your shell, write a first block Getting Started
Config syntax, path patterns, what a script sees Configuration
Worked examples with their teardown Recipes
Why a block didn't fire Troubleshooting
Every command, flag, variable and exit code Reference
Why envoke allow exists and how it works Trust Model

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.

vs. ondir / direnv

envoke is a spiritual rewrite of ondir — the same enter/leave-by-path-pattern model, picked up on a few specific points (regex engine choice, path matching semantics, a trust/approval step) and extended past bash/zsh to five shells. 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.

Point by point: envoke vs. direnv and Design Notes (vs. ondir).

Status

Early development — the mileage is early, not the feature list. Everything below is implemented and tested end to end against real interpreters:

  • the matching engine — patterns, intermediate directories, ordering;
  • all five shell integrations (bash, zsh, fish, tcsh, PowerShell);
  • 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 — Homebrew, Scoop, GitHub Releases, and .deb/.rpm packages, each release carrying a per-archive SBOM and cosign-signed checksums.

There is no roadmap section here on purpose: if envoke help doesn't list it, it doesn't exist. Every command, flag, environment variable, file and exit code is inventoried 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