NAME

App::karr::Foundation - Single-shot foundation daemon — periodic agent execution across karr boards

VERSION

version 0.301

SYNOPSIS

# Typical cron entry — run every 5 minutes
*/5 * * * * /path/to/karr-foundation

# Force a run regardless of board state
karr-foundation --force

# Preview what would run
karr-foundation --dry-run --verbose

# Read-only overview of every board (no agent runs)
karr-foundation --status

DESCRIPTION

karr-foundation is a single-shot, idempotent CLI meant to be invoked periodically (cron, systemd-timer, while-loop). It scans configured karr boards, detects changes or open work, and drains each board by invoking the configured agent command repeatedly until no actionable task remains.

Config file: ~/.config/karr-foundation/config.yml (or --config).

dirs:
  - /path/to/repo1
  - /path/to/repo2

scan:
  - /path/to/parent-dir   # finds all direct subdirs that have a .karr file

Per-repo .karr file:

claude: true              # synthesize the canonical claude command (opt-in)
claude_bin: claude        # binary for claude: true (default: claude)
claude_max_turns: 30      # --max-turns for claude: true (default: 30)
claude_permission_mode: bypassPermissions   # (default: bypassPermissions)
prompt: >-                # agent instruction, exposed as $PROMPT
  Use the karr-coordinator skill: pick the next actionable task and move it.
command: claude -p "$PROMPT"   # explicit command; wins over claude: true
on_idle: skip             # 'skip' (default) | 'always-run'
max_runtime: 1800         # seconds: per-command SIGKILL (0 = no limit)
drain: true               # loop until drained (default) | false for single run
max_attempts: 2           # stalls on one task before auto-block (default: 2)
max_iterations: 50        # hard cap on drain iterations (default: 50)
cooldown_base: 1          # cooldown minutes at level 0 (default: 1)
cooldown_max: 64          # cooldown ceiling in minutes (default: 64)
error_patterns:           # extra case-insensitive substrings → common-error
  - my custom api error

claude, claude_bin, claude_max_turns, claude_permission_mode, command and prompt/default_prompt may also be set globally in the config file; the per-repo .karr value wins.

Coordinator and overview. Agent execution is opt-in — a board runs an agent only via command or claude: true. When no board has an agent configured, the default action is a read-only overview of every board (status counts, in-progress/blocked tasks, lock and cooldown state); a human can use foundation purely to coordinate their own work. --status forces the overview regardless of configuration.

Live output. When run interactively (TTY) or with --verbose, the agent's output is streamed to the terminal in real time as foundation reads it; it is always appended to .karr.log regardless of TTY. To shape what is shown, the command may emit stream-json and filter it, e.g.:

command: >-
  claude -p "$PROMPT"
    --output-format stream-json --verbose --include-partial-messages
    --permission-mode bypassPermissions --max-turns 10
  2>&1 | jq -r 'select(.type == "stream_event") | .event.delta.text // empty'

Set max_runtime: 0 in .karr to disable the per-run timeout entirely (agent runs until completion with no SIGKILL).

Drain semantics. Each iteration runs command once, then classifies the result from what foundation can observe — exit code, board ref movement, and the run's captured output:

  • progress — the board changed; keep draining.

  • stall — a task the agent claimed / left in-progress did not move. That task's attempt counter is bumped; at max_attempts it is auto-blocked (blocked: auto-block: no progress after N attempts (foundation)) so it drops out of the actionable set and the drain can finish. The agent may always set a better reason itself with karr edit --block; the auto-block is a fallback.

  • common-error — a non-zero/timeout exit or a error_patterns match (rate limit, auth, network, 5xx, …). No task is penalized; the repo enters an exponential cooldown (cooldown_base × 2^level minutes, capped at cooldown_max, reset on the next clean run) and is skipped until it expires.

  • idle — the agent did nothing and grabbed nothing; stop.

All state files are gitignored: .karr.state (board hash, per-task attempts, cooldown, last error), .karr.lock, .karr.log.

SUPPORT

Issues

Please report bugs and feature requests on GitHub at https://github.com/Getty/karr/issues.

IRC

Join #langertha on irc.perl.org or message Getty directly.

CONTRIBUTING

Contributions are welcome! Please fork the repository and submit a pull request.

AUTHOR

Torsten Raudssus <getty@cpan.org>

COPYRIGHT AND LICENSE

This software is copyright (c) 2026 by Torsten Raudssus <torsten@raudssus.de> https://raudssus.de/.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.