CLI Reference
This reference covers all Turnkey CLI commands.
tk - Buck2 Wrapper
tk is the primary Turnkey CLI. It wraps Buck2 with automatic dependency synchronization.
Overview
When using Buck2 with Nix-managed dependencies, certain files must be regenerated when source files change. tk solves this by automatically running sync operations before buck2 commands that read the build graph.
Quick Start
# Use tk just like buck2 - it syncs automatically
tk build //some:target # syncs first, then builds
tk test //some:target # syncs first, then tests
tk run //some:target # syncs first, then runs
# Explicit sync operations
tk sync # manually sync all stale files
tk check # check if files are stale (for CI)
# Skip sync when needed
tk --no-sync build //... # skip sync, run buck2 directly
Command Reference
tk build/run/test/... (Buck2 passthrough)
Most tk commands are passed through to Buck2. Commands that read the build graph automatically sync first:
Sync-first commands (sync before running):
build- Build targetsrun- Run a targettest- Run testsquery- Query the build graphcquery- Configured queryuquery- Unconfigured querytargets- List targetsaudit- Audit the buildbxl- Run BXL scripts
Pass-through commands (no sync):
clean- Clean build artifactskill- Kill Buck2 daemonkillall- Kill all Buck2 processesstatus- Show daemon statuslog- View build logsrage- Generate debug reporthelp- Show helpdocs- Open documentationinit- Initialize a project
Unknown commands default to syncing first (safe default).
tk sync
Explicitly synchronize all stale files.
tk sync # sync stale files
tk sync --verbose # show what's being synced
tk sync --dry-run # show what would be synced without doing it
Exit codes:
0- Success (files synced or nothing to sync)1- Sync failed
tk check
Check if any files are stale without regenerating them. Useful for CI validation.
tk check # check staleness
tk check --verbose # show detailed status
Exit codes:
0- All files up-to-date1- Files are stale (runtk syncto fix)
Example CI usage:
- name: Check files in sync
run: tk check
tk completion
Generate shell completion scripts.
tk completion bash # output bash completion script
tk completion zsh # output zsh completion script
tk completion fish # output fish completion script
Enable completions:
# Bash (add to ~/.bashrc)
eval "$(tk completion bash)"
# Zsh (add to ~/.zshrc)
eval "$(tk completion zsh)"
# Fish (run once)
tk completion fish > ~/.config/fish/completions/tk.fish
tk rules
Manage rules.star files that define Buck2 build targets from source files. This command automatically detects imports from source files and updates the deps list in rules.star.
tk rules check # Check if rules.star files need updates
tk rules sync # Update rules.star files with detected dependencies
tk rules help # Show help
Options:
| Flag | Description |
|---|---|
--all, -a | Process all files (skip staleness detection) |
--force, -f | Same as --all |
--verbose, -v | Show detailed output including skipped files |
--quiet, -q | Suppress output |
--dry-run, -n | Show what would be changed without writing |
Staleness Detection:
By default, only files where source files are newer than rules.star are processed. Use --all or --force to check/sync all files.
Examples:
tk rules check # Check stale rules.star files
tk rules check --all # Check all rules.star files
tk rules sync # Update stale rules.star files
tk rules sync --all # Force update all files
tk rules sync src/cmd/tk # Sync specific directory
tk rules sync --dry-run # Preview changes without writing
Preserving Manual Dependencies:
If you have manual dependencies that shouldn't be auto-detected, use preservation markers in your rules.star:
# turnkey:preserve-start
"//some/manual:dep",
# turnkey:preserve-end
Dependencies within these markers are preserved during sync.
tk Flags
Flags must come before the subcommand:
| Flag | Description |
|---|---|
--no-sync | Skip sync, run Buck2 directly |
--no-local | Skip local target overrides from .turnkey/local.toml |
--verbose, -v | Show what tk is doing |
--dry-run, -n | Show what would be synced without doing it |
--quiet, -q | Suppress non-error output |
--help, -h | Show help |
Examples:
tk --no-sync build //... # skip sync
tk --no-local run //target # skip local overrides
tk --verbose sync # verbose sync
tk -v -n sync # dry-run with verbose output
Configuration
Sync Configuration File
tk reads staleness rules from .turnkey/sync.toml. This file is automatically generated from your Nix configuration.
When you configure dependency files in your flake.nix:
goDepsFilegenerates a Go deps rulerustDepsFilegenerates a Rust deps rulepythonDepsFilegenerates a Python deps rule
Example generated sync.toml:
[[deps]]
name = "go"
sources = ["go.mod", "go.sum"]
target = "go-deps.toml"
generator = ["godeps-gen", "--go-mod", "go.mod", "--go-sum", "go.sum", "--prefetch"]
[[deps]]
name = "rust"
sources = ["Cargo.toml", "Cargo.lock"]
target = "rust-deps.toml"
generator = ["rustdeps-gen", "--cargo-lock", "Cargo.lock"]
Each [[deps]] entry defines:
name- Human-readable name for this rulesources- Files that trigger regeneration when modifiedtarget- The generated filegenerator- Command to regenerate the target
Local Target Overrides
tk supports per-developer local overrides via .turnkey/local.toml. This file is not committed to git, allowing each developer to customize target arguments for their local environment.
Use cases:
- Different network addresses for local development
- Debug flags for specific targets
- Custom ports or configuration
Example .turnkey/local.toml:
# Override args for tk run
[run."//docs/user-manual"]
args = ["-n", "192.168.1.100"]
# Override args for tk build
[build."//src/cmd/server:server"]
args = ["--config=debug"]
# Pattern matching with "..."
[test."//src/..."]
args = ["--verbose", "--timeout=60s"]
How it works:
When you run a command that matches a configured target:
tk run //docs/user-manual
# Becomes: buck2 run //docs/user-manual -- -n 192.168.1.100
The args are injected after --, which passes them to the target binary.
Pattern matching:
Patterns ending with ... match any target with that prefix:
//src/...matches//src:foo,//src/pkg:bar,//src/cmd/tool:main//...matches any target
Disable for a single command:
tk --no-local run //docs/user-manual # skips local.toml
Verbose output:
tk --verbose run //docs/user-manual
# Output: tk: applying local override for run //docs/user-manual: [-n 192.168.1.100]
Shell Integration
buck2 alias to tk:
# In devenv shell, buck2 is aliased to tk
buck2 build //... # actually runs: tk build //...
Disable with:
TURNKEY_NO_ALIAS=1 buck2 build //... # uses raw buck2
tw - Native Tool Wrapper
tw wraps native language tools (go, cargo, uv) to keep dependency files in sync when using standard workflows.
The Problem
When you run go get github.com/foo/bar, Go updates go.mod and go.sum. But Buck2 needs go-deps.toml to know about the new dependency. Without auto-sync, you'd need to manually regenerate it.
The Solution
Turnkey transparently wraps go, cargo, and uv so that dependency sync happens automatically:
go get github.com/foo/bar # Just works - go-deps.toml is auto-updated
How It Works
User runs: go get github.com/foo/bar
│
▼
Shell wrapper (provides 'go' binary)
• Sets TURNKEY_REAL_GO to actual go binary path
• Calls: tw go get github.com/foo/bar
│
▼
tw (turnkey wrapper)
1. Loads .turnkey/sync.toml configuration
2. Finds wrapper rule for 'go'
3. Checks if 'get' is a mutating subcommand → yes
4. Captures SHA256 hashes of go.mod, go.sum
5. Runs the real 'go get' command
6. Compares hashes - detects changes
7. Runs godeps-gen to regenerate go-deps.toml
Supported Tools
| Tool | Mutating Commands | Watch Files | Deps Target |
|---|---|---|---|
go | get, mod | go.mod, go.sum | go-deps.toml |
cargo | add, remove, update | Cargo.toml, Cargo.lock | rust-deps.toml |
uv | add, remove, lock, sync | pyproject.toml, uv.lock | python-deps.toml |
Escape Hatches
Bypass for a Single Command
TURNKEY_NO_WRAP=1 go get github.com/foo/bar
This runs the real go directly, skipping tw entirely.
Disable Sync for a Command
tw --no-sync go get github.com/foo/bar
This runs through tw but skips the sync step even if files change.
Verbose Output
tw -v go get github.com/foo/bar
Shows what tw is doing:
tw: capturing state of [go.mod go.sum]
tw: detected changes in [go.mod go.sum], running sync
Syncing go-deps.toml...
Running: godeps-gen --go-mod go.mod --go-sum go.sum --prefetch
Regenerated go-deps.toml
Non-Mutating Commands
Commands not in mutating_subcommands pass through without any overhead:
go build ./... # No snapshot, no sync check - just runs go build
go version # Direct passthrough
godeps-gen
Generate go-deps.toml from go.mod and go.sum.
Usage
godeps-gen [OPTIONS]
Options
| Option | Description |
|---|---|
--go-mod PATH | Path to go.mod file (default: go.mod) |
--go-sum PATH | Path to go.sum file (default: go.sum) |
--prefetch | Fetch Nix hashes using nix-prefetch-github |
--indirect | Include indirect dependencies (default: true) |
-o, --output PATH | Output file (default: stdout) |
Examples
# Generate with prefetched hashes
godeps-gen --prefetch -o go-deps.toml
# Use custom paths
godeps-gen --go-mod src/go.mod --go-sum src/go.sum -o go-deps.toml
# Quick check without fetching (placeholder hashes)
godeps-gen --no-prefetch
rustdeps-gen
Generate rust-deps.toml from Cargo.lock.
Usage
rustdeps-gen [OPTIONS]
Options
| Option | Description |
|---|---|
--cargo-lock PATH | Path to Cargo.lock file (default: Cargo.lock) |
--no-prefetch | Skip prefetching (produces incorrect hashes) |
-o, --output PATH | Output file (default: stdout) |
Examples
# Generate from default Cargo.lock
rustdeps-gen -o rust-deps.toml
# Use custom path
rustdeps-gen --cargo-lock rust/Cargo.lock -o rust-deps.toml
pydeps-gen
Generate python-deps.toml from Python dependency files.
Usage
pydeps-gen [OPTIONS]
Options
| Option | Description |
|---|---|
--lock PATH | Path to pylock.toml (PEP 751 lock file) - RECOMMENDED |
--pyproject PATH | Path to pyproject.toml |
--requirements PATH | Path to requirements.txt |
-o, --output PATH | Output file (default: stdout) |
--no-prefetch | Skip prefetching (produces placeholder hashes) |
--include-dev | Include dev dependencies |
Input Formats
| Format | Flag | Reproducibility | Notes |
|---|---|---|---|
| pylock.toml (PEP 751) | --lock | Best | Exact versions and URLs |
| pyproject.toml | --pyproject | Varies | Uses latest matching versions |
| requirements.txt | --requirements | Varies | Pin versions with == |
Recommended Workflow
# 1. Generate lock file from pyproject.toml
uv lock
# 2. Export to PEP 751 format
uv export --format pylock.toml -o pylock.toml
# 3. Generate python-deps.toml with Nix hashes
pydeps-gen --lock pylock.toml -o python-deps.toml
Examples
# From PEP 751 lock file (best for reproducibility)
pydeps-gen --lock pylock.toml -o python-deps.toml
# From pyproject.toml (resolves to latest matching versions)
pydeps-gen --pyproject pyproject.toml -o python-deps.toml
# From requirements.txt
pydeps-gen --requirements requirements.txt -o python-deps.toml
# Include dev dependencies
pydeps-gen --lock pylock.toml --include-dev -o python-deps.toml
Troubleshooting
"tk: .buckconfig not found"
tk looks for .buckconfig to find the project root. Make sure you're in a Buck2 project directory.
"tk: failed to load sync config"
The .turnkey/sync.toml file is missing or invalid. Ensure you're in a Turnkey project with proper configuration.
"tk: sync failed: generator command failed"
The generator command failed. Check that:
- The generator command is correct
- Required tools are in PATH
- Source files exist
Sync is slow
If sync takes a long time:
- Use
--prefetchwith godeps-gen to cache downloads - Check if generators are doing unnecessary work
Bypass tk
If you need to use raw Buck2:
# Option 1: --no-sync flag
tk --no-sync build //...
# Option 2: TURNKEY_NO_ALIAS environment variable
TURNKEY_NO_ALIAS=1 buck2 build //...