mise-configuration
Configure environment via mise [env] SSoT. TRIGGERS - mise env, mise.toml, environment variables, centralize config, Python venv, mise templates.
Installation
Follow the repository instructions for this skill and your agent. Review the files and dependencies before adding it to your workflow.
View source ↗GuidesSkill instructions
mise Configuration as Single Source of Truth
Use mise [env] as centralized configuration with backward-compatible defaults.
Core Principle
Define all configurable values in .mise.toml [env] section. Scripts read via environment variables with fallback defaults. Same code path works WITH or WITHOUT mise installed.
Key insight: mise auto-loads [env] values when shell has mise activate configured. Scripts using os.environ.get("VAR", "default") pattern work identically whether mise is present or not.
Quick Reference
Language Patterns
| Language | Pattern | Notes |
|---|---|---|
| Python | os.environ.get("VAR", "default") |
Returns string, cast if int |
| Bash | ${VAR:-default} |
Standard POSIX expansion |
| JavaScript | process.env.VAR || "default" |
Falsy check, watch for "0" |
| Go | os.Getenv("VAR") with default |
Empty string if unset |
| Rust | std::env::var("VAR").unwrap_or() |
Returns Result<String> |
Special Directives
| Directive | Purpose | Example |
|---|---|---|
_.file |
Load from .env files | _.file = ".env" |
_.path |
Extend PATH | _.path = ["bin", "node_modules/.bin"] |
_.source |
Execute bash scripts | _.source = "./scripts/env.sh" |
_.python.venv |
Auto-create Python venv | _.python.venv = { path = ".venv", create = true } |
Python Venv Auto-Creation (Critical)
Auto-create and activate Python virtual environments:
[env]
_.python.venv = { path = ".venv", create = true }
This pattern is used in ALL projects. When entering the directory with mise activated:
- Creates
.venvif it doesn't exist - Activates the venv automatically
- Works with
uvfor fast venv creation
Alternative via [settings]:
[settings]
python.uv_venv_auto = true
Monorepo Workspace Pattern
For Python monorepos using uv workspaces, the venv is created at the workspace root. Sub-packages share the root venv.
# Root mise.toml
[env]
_.python.venv = { path = ".venv", create = true }
Hoisted Dev Dependencies (PEP 735)
Dev dependencies (pytest, ruff, jupyterlab, etc.) should be hoisted to workspace root pyproject.toml using [dependency-groups]:
# SSoT-OK: example workspace configuration
# Root pyproject.toml
[tool.uv.workspace]
members = ["packages/*"]
[dependency-groups]
dev = [
"pytest>=<version>",
"ruff>=<version>",
"jupyterlab>=<version>",
]
Why hoist? Sub-package [dependency-groups] are NOT automatically installed by uv sync from root. Hoisting ensures:
- Single command:
uv sync --group dev - No "unnecessary package" warnings
- Unified dev environment across all packages
Reference: bootstrap-monorepo.md for complete workspace setup
Special Directives
Load from .env Files (_.file)
[env]
# Single file
_.file = ".env"
# Multiple files with options
_.file = [
".env",
{ path = ".env.secrets", redact = true }
]
Extend PATH (_.path)
[env]
_.path = [
"{{config_root}}/bin",
"{{config_root}}/node_modules/.bin",
"scripts"
]
Source Bash Scripts (_.source)
[env]
_.source = "./scripts/env.sh"
_.source = { path = ".secrets.sh", redact = true }
Lazy Evaluation (tools = true)
By default, env vars resolve BEFORE tools install. Use tools = true to access tool-generated paths:
[env]
# Access PATH after tools are set up
GEM_BIN = { value = "{{env.GEM_HOME}}/bin", tools = true }
# Load .env files after tool setup
_.file = { path = ".env", tools = true }
Template Syntax (Tera)
mise uses Tera templating. Delimiters: {{ }} expressions, {% %} statements, {# #} comments.
Built-in Variables
| Variable | Description |
|---|---|
{{config_root}} |
Directory containing .mise.toml |
{{cwd}} |
Current working directory |
{{env.VAR}} |
Environment variable |
{{mise_bin}} |
Path to mise binary |
{{mise_pid}} |
mise process ID |
{{xdg_cache_home}} |
XDG cache directory |
{{xdg_config_home}} |
XDG config directory |
{{xdg_data_home}} |
XDG data directory |
Functions
[env]
# Get env var with fallback
NODE_VER = "{{ get_env(name='NODE_VERSION', default='20') }}"
# Execute shell command
TIMESTAMP = "{{ exec(command='date +%Y-%m-%d') }}"
# System info
ARCH = "{{ arch() }}" # x64, arm64
OS = "{{ os() }}" # linux, macos, windows
CPUS = "{{ num_cpus() }}"
# File operations
VERSION = "{{ read_file(path='VERSION') | trim }}"
HASH = "{{ hash_file(path='config.json', len=8) }}"
Filters
[env]
# Case conversion
SNAKE = "{{ name | snakecase }}"
KEBAB = "{{ name | kebabcase }}"
CAMEL = "{{ name | lowercamelcase }}"
# String manipulation
TRIMMED = "{{ text | trim }}"
UPPER = "{{ text | upper }}"
REPLACED = "{{ text | replace(from='old', to='new') }}"
# Path operations
ABSOLUTE = "{{ path | absolute }}"
BASENAME = "{{ path | basename }}"
DIRNAME = "{{ path | dirname }}"
Conditionals
[env]
{% if env.DEBUG %}
LOG_LEVEL = "debug"
{% else %}
LOG_LEVEL = "info"
{% endif %}
Required & Redacted Variables
Required Variables
Enforce variable definition with helpful messages:
[env]
DATABASE_URL = { required = true }
API_KEY = { required = "Get from https://example.com/api-keys" }
Redacted Variables
Hide sensitive values from output:
[env]
SECRET = { value = "my_secret", redact = true }
_.file = { path = ".env.secrets", redact = true }
# Pattern-based redactions
redactions = ["*_TOKEN", "*_KEY", "PASSWORD"]
[settings] Section
[settings]
experimental = true # Enable experimental features
python.uv_venv_auto = true # Auto-create venv with uv
[tools] Version Pinning
Pin tool versions for reproducibility:
[tools]
python = "3.11" # minimum baseline; use 3.12, 3.13 as needed
node = "latest"
uv = "latest"
# With options
rust = { version = "1.75", profile = "minimal" }
min_version: Enforce mise version compatibility:
min_version = "2024.9.5"
Implementation Steps
- Identify hardcoded values - timeouts, paths, thresholds, feature flags
-
Create
.mise.toml- add[env]section with documented variables -
Add venv auto-creation -
_.python.venv = { path = ".venv", create = true } - Update scripts - use env vars with original values as defaults
-
Add ADR reference - comment:
# ADR: 2025-12-08-mise-env-centralized-config - Test without mise - verify script works using defaults
-
Test with mise - verify activated shell uses
.mise.tomlvalues
GitHub Token Multi-Account Patterns (MANDATORY for Multi-Account Setups) {#github-token-multi-account-patterns}
For multi-account GitHub setups, mise [env] provides per-directory token configuration that overrides gh CLI's global authentication.
Token Storage
Store tokens in a centralized, secure location:
mkdir -p ~/.claude/.secrets
chmod 700 ~/.claude/.secrets
# Create token files (one per account)
gh auth login # authenticate as account
gh auth token > ~/.claude/.secrets/gh-token-accountname
chmod 600 ~/.claude/.secrets/gh-token-*
Per-Directory Configuration
# ~/.claude/.mise.toml (terrylica account)
[env]
GH_TOKEN = "{{ read_file(path=config_root ~ '/.secrets/gh-token-terrylica') | trim }}"
GITHUB_TOKEN = "{{ read_file(path=config_root ~ '/.secrets/gh-token-terrylica') | trim }}"
GH_ACCOUNT = "terrylica" # For human reference only
# ~/eon/.mise.toml (terrylica account - different directory)
[env]
GH_TOKEN = "{{ read_file(path=env.HOME ~ '/.claude/.secrets/gh-token-terrylica') | trim }}"
GITHUB_TOKEN = "{{ read_file(path=env.HOME ~ '/.claude/.secrets/gh-token-terrylica') | trim }}"
GH_ACCOUNT = "terrylica"
Variable Naming Convention
| Variable | Usage Context | Example |
|---|---|---|
GH_TOKEN |
mise [env], Doppler, verification tasks | .mise.toml, shell scripts |
GITHUB_TOKEN |
npm scripts, GitHub Actions, semantic-release | package.json, workflows |
Rule: Always set BOTH variables in mise [env] pointing to the same token file. Different tools check different variable names.
Alternative: 1Password Integration
For enhanced security with automatic token rotation:
[env]
GH_TOKEN = "{{ op_read('op://Engineering/GitHub Token/credential') }}"
With caching for performance:
[env]
GH_TOKEN = "{{ cache(key='gh_token', duration='1h', run='op read op://Engineering/GitHub Token/credential') }}"
Verification
/usr/bin/env bash << 'MISE_EOF'
for dir in ~/.claude ~/eon ~/own ~/scripts ~/459ecs; do
cd "$dir" && eval "$(mise hook-env -s bash)" && echo "$dir → $GH_ACCOUNT"
done
MISE_EOF
ADR Reference: GitHub Multi-Account Authentication
SSH ControlMaster Warning: If using multi-account SSH, ensure
ControlMaster nois set for GitHub hosts in~/.ssh/config. Cached connections can authenticate with the wrong account. See semantic-release authentication for troubleshooting.
Anti-Patterns
| Anti-Pattern | Why | Instead |
|---|---|---|
mise exec -- script.py |
Forces mise dependency | Use env vars with defaults |
Secrets in .mise.toml |
Visible in repo | Use Doppler or redact = true |
| No defaults in scripts | Breaks without mise | Always provide fallback |
| Mixing env/tools resolution | Order matters | Use tools = true for tool-dependent vars |
Task Orchestration Integration
When you detect workflow opportunities during mise configuration, prescriptively invoke the mise-tasks skill.
Detection Triggers
- Multi-step workflows (test + build + deploy)
- Repeatable project commands (lint, format, release)
- Dependency chains (db-migrate depends on db-init)
- File-tracked builds (sources/outputs caching)
Prescriptive AI Reminder
PRESCRIPTIVE: When detecting multi-step project workflows, invoke
mise-tasksskill to generate appropriate[tasks]definitions with dependency management.
Example: From Environment to Tasks
Step 1: Configure environment (this skill):
[env]
DATABASE_URL = "postgresql://localhost/mydb"
_.python.venv = { path = ".venv", create = true }
Step 2: Define tasks (mise-tasks skill):
[tasks.test]
depends = ["lint"]
run = "pytest tests/"
[tasks.deploy]
depends = ["test", "build"]
run = "deploy.sh"
Tasks automatically inherit [env] values.
Additional Resources
For complete code patterns and examples, see: references/patterns.md
For task orchestration, see: mise-tasks skill - Dependencies, arguments, file tracking, watch mode
ADR Reference: When implementing mise configuration, create an ADR at docs/adr/YYYY-MM-DD-mise-env-centralized-config.md in your project.
Examples
Read the usage examples in the source repository.
View source ↗Source history
- Indexed on
- 2026-01-20
- Index updated
- 2026-02-02
- Branch
- main
Index and sync dates describe this directory. View the source repository for code history.
GitHub ↗chat Comments (0)
Sign in to join the discussion and leave a comment.
No comments yet. Be the first to share your thoughts!