This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Envoke is a CLI tool that resolves environment variables from a declarative YAML configuration file (envoke.yaml). It supports multiple value sources (literal, command execution, shell scripts, Jinja2 templates with variable interpolation), tag-based conditional inclusion, named overrides for per-variable source alternatives, topologically sorts variables to resolve dependencies, and outputs portable .env-format lines by default.
This project uses mise as a task runner. Install mise first, then tools via mise install.
| Task | Command |
|---|---|
| Build (release) | mise run build |
| Run tests | mise run test |
| Format code | mise run fmt |
| Format check | mise run fmt:check |
| Lint | mise run clippy |
| All CI checks | mise run ci |
| Install locally | mise run install |
Run a single test: cargo nextest run -E 'test(test_name)'
Formatting uses nightly features (rustfmt.toml has style_edition = "2024"). Use mise run fmt:nightly / mise run fmt:check:nightly when stable rustfmt doesn't support the options.
The codebase is a single Rust binary with five modules:
main.rs-- CLI (clap) with a subcommand grammar:render(aliasr) prints/writes resolved vars,exec(aliasx) execs a command with them overlaid,meta <environments|tags|overrides|all>enumerates config dimensions,schemaprints the JSON Schema,completions <SHELL>prints shell completions (viaclap_complete). Global flags (-c/--config,-q/--quiet,--no-parallel,-t/--tag,--all-tags,-O/--override) are declared withglobal = trueon the root and may appear before or after the subcommand; the repeatable-t/--tagand-O/--overridehave last-write-wins semantics when split across the subcommand boundary.render-only flags:-o/--output,-f/--format(presets: dotenv [default], shell-export, json, yaml, k8s-secret, github-actions, terraform-tfvars),--template.execcollects a trailing-- <command>...via claplast = true+num_args = 1..+allow_hyphen_values. BothrenderandexecreadENVOKE_ENVas a fallback for the<env>positional.config.rs-- Data model:Config(top-level),Variable(per-env sources + optional default/description/tags/overrides),Override(alternative default/envs sources),Sourceenum (literal/cmd/sh/template/skip). Theskipvariant is a unit variant; its YAML surface is the bare stringskip(notskip: true). DerivesJsonSchemaviaschemars.resolve.rs-- Core logic.resolve_all()picks per-environment sources (with default fallback and override 4-level fallback chain), topologically sorts via Kahn's algorithm, resolves values in dependency order. Literals and templates run on the main thread;cmd:/sh:sources run in a bounded worker pool (MAX_EXTERNAL_JOBS = 8) built onstd::thread::scope+mpsc+Mutex<Receiver>— no new deps.--no-parallelcollapses to sequential resolution in topological order. Template rendering usesminijinjawith all built-in filters,urlencode,shell_escape, anddotenv_escape(both imported fromrender.rs). ATemplateMetastruct provides ametaobject (withenvironment,tags,overrides,timestamp) to value source templates.render.rs-- Output rendering via minijinja templates. ExposesRenderContext/Metastructs (Meta includestimestamp,invocation,invocation_args,environment,config_file,tags,overrides), aFormatenum (derivesclap::ValueEnum) holding the seven built-in presets (Dotenvis the default),render_format()for preset dispatch,render_custom()for--template, and twopub(crate)filters:shell_escape(escapes'as'\''for POSIX single-quoted strings) anddotenv_escape(returns a fully-quoted.envtoken — single-quoted when safe, else double-quoted with conservative escapes\\,\",\$,\n;$never expands at the consumer). All filters (built-ins,urlencode,shell_escape,dotenv_escape) are available in both variable and output templates. Built-in templates (shell-export.j2,dotenv.j2,json.j2,yaml.j2,k8s-secret.j2,github-actions.j2,terraform-tfvars.j2) live insrc/templates/and are compiled in viainclude_str!.exec.rs-- Subprocess exec for theenvoke exec <env> -- <cmd>subcommand.exec_command()builds astd::process::Commandwith overlay semantics (inherit parent env, layer resolved vars on top viaCommand::env— noenv_clear). On Unix, callsCommandExt::execto replace envoke's process image; on other platforms, spawns, waits, and propagates the exit code.error.rs--ResolveErrorwith structuredResolveErrorKindvariants (8 types including cycle detection with chain and conflicting overrides).
- Clippy pedantic lints are enabled as warnings (
[lints.clippy] pedantic = "warn") - Rustfmt:
imports_granularity = "Item",group_imports = "StdExternalCrate", Unix newlines - Rust edition 2024