AGENTS.md

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

  1. Default dirs: /usr/share/keld, /etc/keld, ~/.config/keld
  2. In each dir: config.toml then sorted conf.d/*.toml
  3. KELD_CONFIG_PATHS env var (colon-separated, supports globs)
  4. KELD_CONFIG_FILE replaces 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 := tt copy before parallel subtest
  • Use t.TempDir() and t.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 of tea.NewProgram(m, opts...)
  • tea.RequestBackgroundColor for theme detection
  • tea.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

  1. Make changes
  2. mise run check - full validation
  3. Test manually: keld --show-command --preset <preset> <command>