返回 Skill 列表
extension
分类: 开发与工程无需 API Key

mise-configuration

通过mise [env] SSoT配置环境。触发器 - mise env, mise.toml, 环境变量, 集中配置, Python venv, mise 模板。

person作者: jakexiaohubgithub

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:

  1. Creates .venv if it doesn't exist
  2. Activates the venv automatically
  3. Works with uv for fast venv creation

Alternative via [settings]:

[settings]
python.uv_venv_auto = true

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

  1. Identify hardcoded values - timeouts, paths, thresholds, feature flags
  2. Create .mise.toml - add [env] section with documented variables
  3. Add venv auto-creation - _.python.venv = { path = ".venv", create = true }
  4. Update scripts - use env vars with original values as defaults
  5. Add ADR reference - comment: # ADR: 2025-12-08-mise-env-centralized-config
  6. Test without mise - verify script works using defaults
  7. Test with mise - verify activated shell uses .mise.toml values

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 no is 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-tasks skill 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.