WIP restic wrapper
keld AGENTS.md
4.6 kB · 133 lines
Markdown
at main

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>