kitout--config PATH Path to config file (required when both ./kitout.yaml and home config exist)
--verbose Show status progress and stream subprocess output during apply or upgrade
--quiet Reduce output
--color Force colored output
--no-color Disable colored output
--json Print machine-readable JSON output
--yes Bypass apply confirmations for risky changesThese flags are currently parsed by the root command and by implemented
subcommands. doctor, status, apply, and upgrade use --config when it is passed.
Without --config, they use ./kitout.yaml only when no home config exists,
use ~/.config/kitout/kitout.yaml only when no local config exists, and fail
with guidance when both files exist. init writes ./kitout.yaml in the
current directory by default; pass --home to create the home config instead.
Human
output colors status, progress, and action markers when stdout is an interactive terminal;
redirected output remains plain text by default, --color forces ANSI color,
and --no-color disables ANSI color markers. Human output includes both
symbols and text labels so status remains readable without color. status,
apply, upgrade, and doctor print a short startup line before slower checks begin so
command startup does not look stuck. status --verbose prints a progress line
before each resource status check. For batched Homebrew status checks, default
status output prints one coarse tap-list line, one package-list line, and one
cask-list line instead of per-resource Checking ... lines. apply prints a
progress line before each non-Homebrew resource status check and before each
resource apply starts. For batched Homebrew status checks, default apply
output prints one coarse inspection line for taps, one for formulae, and one for
casks instead of per-resource Checking ... lines. upgrade uses the same
batched Homebrew formula and cask inspection style before selecting outdated
managed items. During human kitout apply and kitout upgrade runs,
--verbose renders each resource status check, renders each subprocess command
before it starts, and streams that subprocess stdout and stderr as it runs.
--verbose does not stream output for --dry-run, --json, or --quiet
runs. --json and --quiet currently affect context, status, apply,
upgrade, doctor, and explain.
For mutation commands whose output is only diagnostic, failure reports retain
the final 64 KiB of each output stream and explicitly mark truncated output.
Use --verbose to stream complete logs. Commands whose output Kitout parses,
including asdf installs and public-key extraction, retain complete capture.
When running from a private setup repo that contains kitout.yaml, pass
--config ./kitout.yaml if a home config also exists. Kitout prints the selected
path before running checks.
Config deprecation warnings are non-fatal. Human status, apply, and
upgrade render them once on stderr after the selected config is loaded. JSON
output includes them under config.warnings. doctor reports a deprecated but
otherwise valid config as a warn Config item.
Implicit dependency checks and first-class resources resolve external tools such
as brew, git, and xcode-select from trusted system locations instead of
the caller's ambient PATH. Absolute executable paths used by implicit checks
must also be under trusted system or Homebrew command roots. Explicit shell
resources still run through the user PATH because those commands are
intentionally listed in config and require apply confirmation.
Creates a starter config file and, when requested, repo-local agent guidance.
kitout init
kitout init --home
kitout init --agents
kitout init --no-agents-warning
kitout init --config ./kitout.yaml
kitout init --config ~/.config/kitout/kitout.yaml
kitout init --config ./kitout.yaml --agents
kitout init --config ./kitout.yaml --no-agents-warningBehavior:
- without
--config, create or use./kitout.yamlin the current directory - with
--home, create or use~/.config/kitout/kitout.yaml - reject combining
--homeand--config - create parent config directory if missing
- refuse to overwrite existing config unless
--forceis passed - write a starter config that validates and can be checked by
statuswithout manual edits - with
--agents, create or updateAGENTS.mdwith compact Kitout guidance for coding agents - with
--no-agents-warning, create or update.kitout/agent-guidance.yamlsodoctordoes not warn about a missing repo-localAGENTS.md - when
--agentsis passed and the config already exists, leave the config unchanged and still create or updateAGENTS.md - when
--no-agents-warningis passed and the config already exists, leave the config unchanged and still create or update the repo-local preference - reject combining
--agentsand--no-agents-warning - place generated
AGENTS.mdat the nearest Git repo root when the config is inside a repo; otherwise place it next to the selected config - preserve existing
AGENTS.mdcontent by appending or refreshing only the marked Kitout section - keep only deterministic directory resources active by default, including the parent directory for real Codex skill copies
- keep package, repo, copy, symlink, security, system, SSH key, and login-shell examples commented until the user customizes them
Prints agent-friendly context for the selected config without checking live resource state or applying changes.
kitout context
kitout context --config ./kitout.yaml
kitout context --config ./kitout.yaml --jsonBehavior:
- load and validate the selected config file
- print the selected config path and config directory
- summarize safe read-only commands an agent may use for evidence gathering
- summarize commands that require explicit user approval
- list declared managed resource IDs in config execution order
- include guidance for dotfiles repos, shell commands, dry-run, and secrets
- never call resource
StatusorApply
Example human output:
Kitout agent context
Config: /Users/example/code/setup/kitout.yaml
Config directory: /Users/example/code/setup
Schema: version 1
Safe read-only commands:
- kitout context --config /Users/example/code/setup/kitout.yaml
- kitout status --config /Users/example/code/setup/kitout.yaml
- kitout apply --config /Users/example/code/setup/kitout.yaml --dry-run
- kitout upgrade --config /Users/example/code/setup/kitout.yaml --dry-run
Requires explicit user approval:
- kitout apply --config /Users/example/code/setup/kitout.yaml
- kitout upgrade --config /Users/example/code/setup/kitout.yaml
- configured shell resources
Managed resources:
- directory:/Users/example/code
- symlink:/Users/example/.zshrc
- shell:Enable Corepack
Agent guidance:
- Edit files in the setup repo or declared source paths, not managed targets in $HOME.
- Run status and dry-run commands before recommending a real apply or upgrade.Checks configured resources.
kitout status
kitout status --json
kitout status --verbose
kitout status --config ./kitout.yamlCurrent behavior:
- load and validate the selected config file
- print a startup line naming the selected config before status checks begin
- by default, show one progress line before batched Homebrew tap, package, and cask list fetches
- with
--verbose, show a progress line before each resource status check - build resources from config in stable execution order
- check resource status through the engine planner
- batch Homebrew tap, installed, and outdated checks across Homebrew resources during planning
- render resource details and summary counts
- render non-blocking advisories such as Homebrew formula or cask updates
- return
0when all resources are satisfied or skipped - return
1when changes are needed - return
2for config validation, parse, or unknown-field errors - return
3for config read failures or failed/unknown resources - when
--jsonis passed, print machine-readable plan output
Example human output:
Kitout is checking your Mac setup...
Config: /Users/example/.config/kitout/kitout.yaml
> Fetching Homebrew tap list...
> Fetching Homebrew package list...
> Fetching Homebrew cask list...
Results:
✓ satisfied brew_tap: vwall/kitout satisfied
✓ satisfied brew: git satisfied
✓ satisfied brew: go satisfied
i brew: go: formula update available for go
fix: Run `brew upgrade go` when you want to update it.
! missing cask: ghostty missing
✓ satisfied directory: /Users/example/code satisfied
- skip repo: /Users/example/code/app skipped by config
× fail shell: setup failed: command failed
Summary: 4 satisfied, 1 missing, 1 failed, 1 skipped
2 resources need attention
1 advisoryExit behavior:
0 all resources satisfied
1 status found resources needing attention
2 validation error
3 runtime errorApplies needed changes.
kitout apply
kitout apply --dry-run
kitout apply --yes
kitout apply --verboseBehavior:
- load and validate config
- print a startup line naming the selected config before status checks begin
- show a progress line before each non-Homebrew resource status check
- show one Homebrew tap, formula, and cask inspection line for batched status checks
- run status checks
- build plan
- stop later apply actions when a blocking prerequisite, currently FileVault, cannot be satisfied
- leave failed or unknown resources unapplied, but continue with other planned missing or changed resources when they are not blocked by a prerequisite
- require confirmation before implemented risky actions, currently security
changes, system prerequisite installers, SSH key generation, shell commands,
login-shell changes, copy replacements, and symlink replacements, unless
--yesis passed - apply missing or changed resources in stable order
- show a progress line before each resource apply starts, so long-running commands such as Homebrew installs do not look stuck
- by default, capture subprocess output and include a compact stderr/stdout summary when a subprocess fails
- with
--verbose, render each subprocess command and stream its stdout and stderr while it runs - render summary
- return
0when apply completed successfully - return
2for validation, parse, unknown-field, or flag errors - return
3for config read failures or interrupted planning/execution - return
4for failed/unknown resources or partial apply failures
Shows intended changes without making changes.
Example output:
[dry-run] Kitout is running in dry-run mode. No changes will be made.
Config: /Users/example/.config/kitout/kitout.yaml
> Inspecting Homebrew taps...
> Inspecting Homebrew casks...
> Checking copy: /Users/example/.codex/skills/nuxt-practices...
> Checking symlink: /Users/example/.zshrc...
[dry-run] Previewing planned changes:
dry-run Would add Homebrew tap vwall/kitout
dry-run Would install cask ghostty
dry-run Would copy to /Users/example/.codex/skills/nuxt-practices
dry-run Would replace symlink /Users/example/.zshrc
[dry-run] No changes made because --dry-run was used.
No shell commands will run without explicit approval.Upgrades outdated managed Homebrew formulae and casks. This command is separate
from apply: apply installs missing formulae and casks, while upgrade
refreshes installed managed formulae and casks only when Homebrew reports an
available update.
kitout upgrade
kitout upgrade --dry-run
kitout upgrade brew:git
kitout upgrade cask:ghostty
kitout upgrade --only brew
kitout upgrade --only cask
kitout upgrade --jsonBehavior:
- load and validate config
- inspect only managed
brew.packagesandbrew.casks - show one Homebrew formula and cask inspection line for batched status checks
- treat installed outdated formulae and casks as planned upgrade actions
- skip missing formulae and casks with guidance to run
kitout applyfirst - leave current formulae and casks unchanged
- run
brew upgrade <name>for outdated managed formulae - run
brew upgrade --cask <name>for outdated managed casks - when resource IDs are passed, inspect and upgrade only those configured managed resources
- reject unknown, unsupported, or
--only-excluded resource IDs before running Homebrew commands - with
--only brew, inspect and upgrade only managed formulae - with
--only cask, inspect and upgrade only managed casks - with
--dry-run, show planned upgrades without runningbrew upgrade - with
--verbose, render each subprocess command and stream its stdout and stderr while it runs - return
0when upgrade completed successfully or no upgrades are needed - return
2for validation, parse, unknown-field, or flag errors - return
3for config read failures, dry-run planning failures, or interrupted planning/execution - return
4for resource upgrade failures
Example dry-run output:
[dry-run] Kitout is checking managed Homebrew upgrades. No changes will be made.
Config: /Users/example/.config/kitout/kitout.yaml
> Inspecting Homebrew packages...
> Inspecting Homebrew casks...
[dry-run] Previewing managed upgrades:
dry-run Would upgrade formula go
dry-run Would upgrade cask ghostty
- Skipping cask: rectangle: cask is missing; run `kitout apply` first
[dry-run] No upgrades made because --dry-run was used.Checks local prerequisites and common problems.
Homebrew freshness is checked by inspecting the local Homebrew repository's last
commit timestamp. A stale metadata warning tells the user to consider
brew update, but Kitout does not run brew update or upgrade packages
automatically.
kitout doctorChecks:
- supported OS
- CPU architecture
- Xcode Command Line Tools
- Homebrew installation
- Homebrew install path for the current CPU architecture
- Homebrew metadata freshness
- Git installation
- shell environment
- config file validity
- write permissions for configured filesystem targets
- repo-local
AGENTS.mdpresence when the selected config is inside a Git repo and.kitout/agent-guidance.yamlhas not disabled the warning
If the command is interrupted, doctor stops dispatching checks and reports the execution error separately instead of treating canceled commands as missing prerequisites.
Current output:
Kitout is checking local prerequisites...
Config: /Users/me/.config/kitout/kitout.yaml
Doctor:
ok: macOS running on macOS
ok: CPU architecture running on Apple Silicon
ok: Xcode Command Line Tools /Library/Developer/CommandLineTools
ok: Homebrew Homebrew 4.0.0
ok: Homebrew path Homebrew prefix is /opt/homebrew
ok: Homebrew freshness Homebrew metadata looks current; last updated today
ok: Git git version 2.45.0
ok: Shell environment SHELL and PATH look usable
ok: Config config is valid
ok: Path permissions no configured filesystem write targets
10 total, 10 ok, 0 warnings, 0 failedExplains one configured resource by ID.
kitout explain --config ./kitout.yaml 'symlink:/Users/example/.zshrc'
kitout explain --config ./kitout.yaml --json 'shell:Enable Corepack'Behavior:
- load and validate the selected config file
- find the requested resource ID
- run status for only that resource
- report state, planned action, details, and apply safety
- identify whether apply would require explicit user approval
- return
2when the resource ID is not configured - return
3when the requested resource fails or cannot be inspected
Example human output:
Resource: symlink:/Users/example/.zshrc
Type: symlink
Config: /Users/example/code/setup/kitout.yaml
Current state:
state: changed
action: apply
message: symlink points elsewhere
Details:
replace: false
source: /Users/example/code/setup/home/.zshrc
target: /Users/example/.zshrc
Apply safety:
would_apply: true
requires_approval: true (symlink replacement may remove an existing target)Prints version metadata.
kitout versionCurrent output:
kitout dev
commit unknown
built unknownRelease and local build artifacts should set version, commit, and built
metadata at build time.
Default output should be concise and readable.
JSON output should be stable enough for tests and automation.
Status, apply, upgrade, doctor, context, and explain all use the same
envelope: command, ok, optional config, one command-specific payload, and
optional error. upgrade --dry-run uses the plan payload. A real
upgrade --json run uses the upgrade payload with the same summary and item
shape as apply.
Example status output:
{
"command": "status",
"ok": true,
"config": {
"path": "/Users/example/.config/kitout/kitout.yaml",
"valid": true
},
"plan": {
"summary": {
"total": 1,
"satisfied": 0,
"missing": 1,
"changed": 0,
"failed": 0,
"skipped": 0,
"unknown": 0,
"to_apply": 1
},
"items": [
{
"resource_id": "directory:/Users/example/code",
"type": "directory",
"state": "missing",
"action": "apply",
"message": "directory is missing"
}
]
}
}Example context payload:
{
"command": "context",
"ok": true,
"config": {
"path": "/Users/example/code/setup/kitout.yaml",
"valid": true
},
"context": {
"schema_version": 1,
"config_dir": "/Users/example/code/setup",
"safe_commands": [
{
"command": "kitout status --config /Users/example/code/setup/kitout.yaml --json",
"reason": "Return current resource state in stable JSON."
}
],
"requires_approval": [
{
"command": "kitout apply --config /Users/example/code/setup/kitout.yaml",
"reason": "Applies changes to the user's machine."
}
],
"resources": [
{
"resource_id": "symlink:/Users/example/.zshrc",
"type": "symlink",
"label": "symlink: /Users/example/.zshrc",
"details": {
"source": "/Users/example/code/setup/home/.zshrc",
"target": "/Users/example/.zshrc",
"replace": "false"
}
}
],
"guidance": [
"Edit files in the setup repo or declared source paths, not managed targets in $HOME."
]
}
}Example explain payload:
{
"command": "explain",
"ok": true,
"config": {
"path": "/Users/example/code/setup/kitout.yaml",
"valid": true
},
"explain": {
"resource": {
"resource_id": "shell:Enable Corepack",
"type": "shell",
"label": "shell: Enable Corepack",
"details": {
"name": "Enable Corepack",
"command": "corepack enable",
"when": "missing-command:pnpm"
}
},
"status": {
"resource_id": "shell:Enable Corepack",
"type": "shell",
"state": "missing",
"action": "apply",
"message": "command should run",
"details": {
"name": "Enable Corepack",
"command": "corepack enable",
"when": "missing-command:pnpm"
}
},
"safety": {
"would_apply": true,
"requires_approval": true,
"reason": "shell resources run explicit configured commands during apply"
}
}
}Interactive confirmation is required for implemented risky changes unless
--yes is passed.
Risky changes currently include:
- replacing copy targets
- replacing symlink targets
- changing security settings
- starting system prerequisite installers
- generating SSH keys
- changing the current user's login shell
- running shell commands
Safe changes may apply without confirmation:
- installing a missing package
- creating a missing directory
- creating a missing copy target
- cloning a missing repo
Dry-run only renders the plan, so it does not ask for confirmation.
Every command should have useful examples.
Avoid help text that only repeats the command name.