# tacoshop

A CLI tool for running commands with additional environment variables read from
config files instead of exported or prefixing every call.  Made because I got
sick of forgetting to set/unset something and prefer commandline flags over
environment variables.

Particularly helpful if you're doing a lot torch/triton tweaking.

Instead of:

```s
TORCHINDUCTOR_FORCE_DISABLE_CACHES=1 TRITON_ALWAYS_COMPILE=1 python prog.py
```

You can:

```sh
# TORCHINDUCTOR_FORCE_DISABLE_CACHES always set to 1 by config file,
# TRITON_ALWAYS_COMPILE gets toggle flag from config file!
tacoshop --triton python train.py
```

## Install

Requires Python 3.11+. No runtime dependencies.

```
pip install -e .
```

## Quick start

Generate a starter config with commented-out examples:

```sh
tacoshop init
```

Or create a `tacoshop.toml` in your project directory by hand:

```toml
TORCHINDUCTOR_FORCE_DISABLE_CACHES = 1

[TRITON_ALWAYS_COMPILE]
flag = "--triton"
value = 1
description = "Force Triton to always recompile kernels"

[TORCH_LOGS]
flag = "--logs"
description = "Set torch logging channels (e.g. +dynamo)"
```

Then run your program through tacoshop:

```sh
# Static vars are always set
tacoshop python train.py

# Activate a flag-toggled var
tacoshop --triton python train.py

# Supply a value at the command line
tacoshop --logs "+dynamo" python train.py

# Combine them
tacoshop --triton --logs "+dynamo" python train.py
```

## Config format

### Static variables (always set)

Top-level key-value pairs are set every time tacoshop runs:

```toml
TORCHINDUCTOR_FORCE_DISABLE_CACHES = 1
MY_STRING_VAR = "hello"
```

For more control (description, append mode), use the table form:

```toml
[MY_VAR]
value = 42
description = "Always-on var with a description"
```

### Flag-mapped variables

Table entries with a `flag` field create CLI flags that activate the variable:

```toml
# Boolean toggle — flag activates a preset value
[TRITON_ALWAYS_COMPILE]
flag = "--triton"
value = 1
description = "Force Triton to always recompile kernels"

# Value-required — user supplies the value at the CLI
[TORCH_LOGS]
flag = "--logs"
description = "Set torch logging channels"
```

### Append and prepend modes

Instead of replacing an existing env var, you can add to it. `append = true` adds to the end, `prepend = true` adds to the front. The `separator` field controls the join character (default: empty string). You cannot set both on the same variable.

The separator is inserted between the existing and new values automatically. If the join edge already has the separator, it won't be doubled.

```toml
[TORCH_LOGS]
flag = "--logs"
append = true
separator = ","
description = "Append to torch logging channels"

[PYTHONPATH]
value = "/my/modules"
prepend = true
separator = ":"
description = "Ensure my modules are found first"
```

Given `TORCH_LOGS="+inductor"` and `PYTHONPATH="/existing/path"` in the calling environment:

```sh
tacoshop --logs "+dynamo" python train.py
# TORCH_LOGS="+inductor,+dynamo"   ← appended with "," separator
# PYTHONPATH="/my/modules:/existing/path"  ← prepended with ":" separator
```

Both modes work for static and flag-mapped variables.

### Value types

| TOML type | Env var value |
|-----------|---------------|
| Integer   | `str()` (e.g. `1` → `"1"`) |
| Float     | `str()` (e.g. `3.14` → `"3.14"`) |
| Boolean   | `true` → `"1"`, `false` → `"0"` |
| String    | As-is |

### Classification summary

| Form | Has `flag`? | Has `value`? | Behavior |
|------|-------------|--------------|----------|
| Top-level scalar | — | — | Static, always set |
| Table | Yes | Yes | Flag activates preset value |
| Table | Yes | No | Flag with required CLI value |
| Table | No | Yes | Static (verbose form, allows description/append) |
| Table | No | No | Error |

## Config file discovery

Tacoshop loads config files from up to three locations, lowest to highest priority:

1. **System-wide**: `~/.tacoshop.toml`
2. **Repo-level**: `tacoshop.toml` or `.tacoshop.toml` at the git repository root
3. **Directory-level**: `tacoshop.toml` or `.tacoshop.toml` in the current working directory

At each level, the non-dotfile name is preferred. Higher-priority files overwrite lower-priority ones per variable name. If the git root is the same as the current directory, only one copy is loaded.

Use `tacoshop trace` to see which files were loaded and what they define.  Helpful for making sure everything is set how you expect!

## Usage

### Running a command

```sh
tacoshop [FLAGS...] COMMAND [ARGS...]
```

Tacoshop flags are parsed left to right. The first unrecognized token starts the wrapped command — everything from that point onward is passed through untouched, including the command's own flags:

```sh
tacoshop --triton python train.py --epochs 10 --verbose
#        ^^^^^^^^ tacoshop flag
#                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ command
```

Use `--` to explicitly separate tacoshop flags from the command:

```sh
tacoshop --triton -- python train.py
```

### Built-in flags

| Flag | Description |
|------|-------------|
| `--help`, `-h` | Show help (includes config-defined flags) |
| `--verbose`, `-v` | Print each env var to stderr before running |
| `--dry-run` | Show env vars and command without executing |
| `--version` | Print version |

### Subcommands

**`tacoshop help`** — Show help (same as `--help` / `-h`).

**`tacoshop trace`** — Display all configured variables with a load-order trace showing how each value is set, overwritten, appended, or prepended across config files and the calling environment.

**`tacoshop init`** — Create a `tacoshop.toml` template in the current directory with commented-out examples of each config style. Refuses to overwrite an existing file.

**`tacoshop print COMMAND [ARGS...]`** — Print a copy-pasteable one-liner with env var prefixes, useful for sharing with someone who doesn't have tacoshop:

```sh
$ tacoshop --triton print python train.py
TORCHINDUCTOR_FORCE_DISABLE_CACHES=1 TRITON_ALWAYS_COMPILE=1 python train.py
```

**`tacoshop dumpenv [-o FILE]`** — Export managed env vars as a bash-sourceable shell script. Respects flags: `tacoshop --triton dumpenv` includes the flag-toggled variable in the output. Writes to stdout by default, or to a file with `-o`.

### I/O and exit codes

Tacoshop is transparent: stdin, stdout, and stderr are passed through to the wrapped command. The exit code is forwarded. All tacoshop-internal output goes to stderr so piping and redirection work as expected:

```sh
tacoshop python train.py | tee output.log
tacoshop python -c "exit(42)"; echo $?  # prints 42
```
