# Configuration Layers
The configuration layers system provides hierarchical config resolution, allowing settings to be overridden at different levels—from project-specific to machine-specific to user defaults—without modifying core files.
---
## Quick Start
```bash
# Initialize machine-specific config
blackdot config init machine my-laptop
# Set a machine-specific value
blackdot config set machine vault.backend 1password
# View where a setting comes from
blackdot config show vault.backend
# See merged config from all layers
blackdot config merged
```
---
## Overview
### Layer Hierarchy
Settings resolve from highest to lowest priority:
```mermaid
flowchart TB
subgraph Resolution["Configuration Resolution"]
direction TB
Q[/"blackdot config get vault.backend"/]
Q --> E{{"1. Environment
BLACKDOT_VAULT_BACKEND"}}
E -->|not set| P{{"2. Project
.blackdot.json"}}
P -->|not set| M{{"3. Machine
~/.config/blackdot/machine.json"}}
M -->|not set| U{{"4. User
~/.config/blackdot/config.json"}}
U -->|not set| D{{"5. Default
Built-in"}}
E -->|"found"| R1[/"Return value"/]
P -->|"found"| R2[/"Return value"/]
M -->|"found"| R3[/"Return value"/]
U -->|"found"| R4[/"Return value"/]
D --> R5[/"Return default"/]
end
style E fill:#ff6b6b,color:#fff
style P fill:#feca57,color:#000
style M fill:#48dbfb,color:#000
style U fill:#1dd1a1,color:#000
style D fill:#c8d6e5,color:#000
```
**Priority order:** Environment → Project → Machine → User → Default
| Priority | Layer | Location | Scope |
|----------|-------|----------|-------|
| 1 (highest) | **Session** | `BLACKDOT_*` env vars | Current shell only |
| 2 | **Project** | `.blackdot.json` in repo | This project |
| 3 | **Machine** | `~/.config/blackdot/machine.json` | This computer |
| 4 | **User** | `~/.config/blackdot/config.json` | All machines |
| 5 (lowest) | **Default** | Built into CLI | Fallback |
### File Locations
| Layer | Location | Git Tracked | Purpose |
|-------|----------|-------------|---------|
| Session | Environment | N/A | Temporary overrides |
| Project | `.blackdot.json` (project root) | Yes | Project-specific settings |
| Machine | `~/.config/blackdot/machine.json` | No | Machine-specific settings |
| User | `~/.config/blackdot/config.json` | No | User preferences |
| Defaults | `internal/config/config.go` | Yes | Built-in defaults |
---
## Commands
### `blackdot config get [default]`
Get a configuration value with layered resolution.
```bash
blackdot config get vault.backend
# Output: bitwarden
blackdot config get shell.theme "default"
# Output: default (if not set)
```
### `blackdot config set `
Set a configuration value in a specific layer.
```bash
# Set in user config
blackdot config set user vault.backend bitwarden
# Set in machine config
blackdot config set machine vault.backend 1password
# Set in project config (current directory)
blackdot config set project features.vault false
```
### `blackdot config show `
Show the value from all layers to understand where settings come from.
```bash
blackdot config show vault.backend
```
Output:
```
Configuration layers for: vault.backend
env: (not set)
project: (not set)
machine: 1password
user: bitwarden
resolved: 1password
```
### `blackdot config list`
Show all layer locations and their status.
```bash
blackdot config list
```
Output:
```
Configuration Layers
═══════════════════════════════════════════════════════════════
Layer Locations:
───────────────────────────────────────────────────────────────
env: BLACKDOT_* environment variables
project: .blackdot.json (not found in current directory)
machine: ~/.config/blackdot/machine.json ✓
user: ~/.config/blackdot/config.json ✓
Priority: env > project > machine > user > default
```
### `blackdot config merged`
Show the merged configuration from all layers.
```bash
blackdot config merged
```
### `blackdot config init [id]`
Initialize a configuration layer.
```bash
# Initialize machine config
blackdot config init machine work-macbook
# Initialize project config in current directory
blackdot config init project
```
### `blackdot config edit [layer]`
Open a config file in your editor.
```bash
# Edit user config (default)
blackdot config edit
# Edit machine config
blackdot config edit machine
# Edit project config
blackdot config edit project
```
---
## Configuration Examples
### Machine Config (`machine.json`)
Machine-specific settings that don't travel between computers:
```json
{
"version": 1,
"machine_id": "work-macbook-2024",
"vault": {
"backend": "1password"
},
"paths": {
"workspace": "~/Code",
"blackdot_dir": "~/Code/blackdot"
},
"features": {
"claude_integration": false
},
"packages": {
"tier": "full",
"extras": ["docker", "kubernetes-cli"]
},
"shell": {
"theme": "work",
"prompt_context": "work"
}
}
```
### Project Config (`.blackdot.json`)
Project-specific settings that travel with the repository:
```json
{
"version": 1,
"features": {
"vault": false,
"templates": true
},
"shell": {
"auto_activate_venv": true,
"node_version_file": ".nvmrc"
},
"hooks": {
"directory_change": [
{ "command": "source .env", "if_exists": ".env" }
]
},
"aliases": {
"dev": "npm run dev",
"test": "npm test"
}
}
```
### User Config (`config.json`)
Default preferences for all machines:
```json
{
"version": 3,
"vault": {
"backend": "bitwarden",
"auto_sync": false
},
"features": {
"vault": true,
"workspace_symlink": true
},
"setup": {
"completed": ["symlinks", "packages"]
}
}
```
---
## Use Cases
### Work vs Personal Machine
Configure different vault backends for different machines:
```bash
# On work laptop
blackdot config init machine work-macbook
blackdot config set machine vault.backend 1password
blackdot config set machine features.claude_integration false
# On personal desktop
blackdot config init machine home-desktop
blackdot config set machine vault.backend bitwarden
blackdot config set machine packages.tier full
```
### Project-Specific Settings
Set up auto-activation and aliases for a specific project:
```bash
cd ~/projects/webapp
blackdot config init project
# The .blackdot.json file is created
# Edit to add project-specific aliases and settings
```
### Temporary Override
Override settings for the current session only:
```bash
# Override vault backend for this session
export BLACKDOT_VAULT_BACKEND=pass
blackdot vault pull # Uses pass instead of configured backend
# Override feature for testing
export BLACKDOT_FEATURES_VAULT=false
blackdot doctor
```
### CI/CD Environments
Use environment variables to configure behavior in CI:
```bash
# In CI pipeline
export BLACKDOT_VAULT_BACKEND=none
export BLACKDOT_FEATURES_TEMPLATES=false
./install.sh
```
---
## Environment Variable Override
Any configuration key can be overridden via environment variable:
| Config Key | Environment Variable |
|------------|---------------------|
| `vault.backend` | `BLACKDOT_VAULT_BACKEND` |
| `features.vault` | `BLACKDOT_FEATURES_VAULT` |
| `shell.theme` | `BLACKDOT_SHELL_THEME` |
| `packages.tier` | `BLACKDOT_PACKAGES_TIER` |
Pattern: `config.key.name` → `BLACKDOT_CONFIG_KEY_NAME`
---
## State vs Configuration
The blackdot system distinguishes between **state** (what happened) and **configuration** (what should happen):
| Data Type | Example | Layer-Aware | Why |
|-----------|---------|-------------|-----|
| Setup state | `setup.completed[]` | No | Machine reality doesn't vary |
| Preferences | `vault.backend` | Yes | Can differ by machine |
| Feature state | `features.vault` | Yes | Can be overridden per-project |
**State management** (setup wizard state in `internal/cli/setup.go`) always uses direct access to track what has happened on this specific machine. Configuration layers handle preferences that can vary.
---
## Integration with Features
The [Feature Registry](features.md) uses configuration layers to resolve feature state:
```bash
# Default: claude_integration disabled
# User config: features.claude_integration = true
# Machine config: features.claude_integration = false (work laptop)
# Result: claude_integration is DISABLED on this machine
blackdot features status claude_integration
# Shows: disabled (via machine config)
```
---
## Best Practices
### What Goes Where
| Setting Type | Recommended Layer | Reason |
|--------------|------------------|--------|
| Default preferences | User | Applies everywhere |
| Work-specific settings | Machine | Stays on work machine |
| Project dependencies | Project | Travels with code |
| Temporary testing | Environment | Session-only |
### Security
- **Project configs are git-tracked** – Don't put secrets in `.blackdot.json`
- **Machine configs are local** – Safe for machine-specific settings
- **Environment vars are transient** – Good for CI/CD overrides
- **Secrets** – Use the [Vault System](vault-README.md) for secrets
### Debugging
When a setting isn't what you expect:
```bash
# See all layers for a setting
blackdot config show vault.backend
# Check environment
env | grep BLACKDOT_
# See merged result
blackdot config merged | jq '.vault'
```
---
## Troubleshooting
### Setting Not Taking Effect
```bash
# Check layer resolution
blackdot config show
# A higher-priority layer may be overriding
```
### Project Config Not Found
```bash
# Project config must be named .blackdot.json
# Must be in current directory or parent
ls -la .blackdot.json
```
### Machine Config Not Initialized
```bash
# Initialize machine config first
blackdot config init machine $(hostname -s)
```
---
## Related Documentation
- [Feature Registry](features.md) - Feature enable/disable system
- [State Management](state-management.md) - Setup wizard state tracking
- [CLI Reference](cli-reference.md) - All blackdot commands