AGENTS.md
Keld is a friendly TOML-configured wrapper around restic (a backup tool). It provides:
- Layered configuration with presets and command-specific overrides
- Interactive menu when invoked without arguments (BubbleTea v2)
- Split preset syntax (
home@cloud) for composable configurations - Passthrough of arbitrary flags to restic
This project uses jujutsu for version control. Before starting work, check jj st. If there's existing work in progress, run jj new -m "..." to create a new
working copy with a good, imperative, kernel-commit-style description. DO NOT
follow or read ANY skills or use ANY tools related to Conventional Commits.
Essential Commands
All tasks are managed via mise (see mise.toml):
mise run vuln
mise run vet
mise run install
# Check formatting without modifying
mise run fmt:check
# Run full check suite (fmt:check, vet, lint, vuln, build, test)
mise run check
Freely check the --help output of various restic commands as you work, so
we can be absolutely certain we're writing a good, up-to-date wrapper. Any time
our code differs from restic proper, PLEASE FLAG IT TO ME!
Config System
Section Merge Order
Config sections are merged in ascending priority order. For
keld home@cloud backup:
[global] → [global.backup] → [@cloud] → [@cloud.backup] →
[home@] → [home@.backup] → [home@cloud] → [home@cloud.backup] →
CLI overrides
Config File Discovery
- Default dirs:
/usr/share/keld,/etc/keld,~/.config/keld - In each dir:
config.tomlthen sortedconf.d/*.toml KELD_CONFIG_PATHSenv var (colon-separated, supports globs)KELD_CONFIG_FILEreplaces all above if set
Special Config Keys
| Key | Purpose |
|---|---|
_arguments |
Positional args passed to restic (array or space-separated string) |
_workdir |
Directory to chdir before exec |
_command |
Restic subcommand (allows aliasing) |
_pre_hooks |
Backup-only shell commands run before restic backup |
_post_hooks |
Backup-only shell commands run after restic backup is attempted |
*.environ |
Section suffix for environment variables |
FOO_COMMAND |
In .environ: executed via sh -c, stdout sets FOO |
Interpolation
Values can reference other sections: cache-dir = "${vars.cache-root}/cache"
Split Presets
Presets with @ are split: home@cloud → applies [@cloud], [home@],
then [home@cloud]
See examples/keld/config.toml for comprehensive examples.
Code Patterns & Conventions
Test Patterns
- Table-driven tests with
t.Parallel() - Testdata embedded as string constants (see
resolveFixtureTOML) tt := ttcopy before parallel subtest- Use
t.TempDir()andt.Setenv()for isolation
Important Gotchas
Config Merge Behavior
- Later files override earlier at section granularity
- Within a file, later sections override earlier
- Nested tables (sub-commands) are not merged across sections—only leaf keys
- Multi-line strings become repeated flags (split on
\n)
Restic Process Supervision
restic.Run() supervises restic as a child process. This allows Keld to run
post-backup hooks after restic exits and preserve restic's numeric exit code for
callers.
Test Isolation
Tests modify DefaultConfigDirs global. Always restore with t.Cleanup():
original := DefaultConfigDirs
DefaultConfigDirs = []string{tmpDir}
t.Cleanup(func() { DefaultConfigDirs = original })
BubbleTea v2
Using v2 API (not v1). Key differences:
tea.NewProgram(m)instead oftea.NewProgram(m, opts...)tea.RequestBackgroundColorfor theme detectiontea.NewView()instead of returning strings
Environment Variables
| Variable | Purpose |
|---|---|
KELD_CONFIG_FILE |
Single config file (highest priority) |
KELD_CONFIG_PATHS |
Colon-separated additional config paths |
KELD_DRYRUN |
Set to enable dry-run mode |
KELD_EXECUTABLE |
Override restic binary path |
Development Workflow
- Make changes
mise run check- full validation- Test manually:
keld --show-command --preset <preset> <command>