App-karr
view release on metacpan or search on metacpan
.claude/skills/karr-foundation-cli/SKILL.md view on Meta::CPAN
prompt: >- # agent instruction, exposed to the command 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'
drain: true # loop until drained (default) | false for single run
max_runtime: 1800 # seconds: per-command SIGKILL (0 = no timeout)
max_attempts: 2 # stalls on one task before auto-block (default: 2)
max_iterations: 50 # hard cap on drain iterations / drain budget (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`, the `claude_*` knobs, `command` and `prompt` may also be
set globally in `config.yml` (`default_command` / `default_prompt`); the per-repo
`.karr` value wins.
## Board-level disable
A board can opt out of automated agent runs in **its own karr state**, not in the
local `.karr` file:
```bash
cd /path/to/repo
karr disable --reason "abandoned driver, backlog parked"
karr enable # allow agent runs again
```
The flag is `foundation.enabled` in `refs/karr/config`, so it syncs with the
board â every foundation instance on every machine honours it. That is the
difference to `.karr`, which is local machine state and cannot express "this
board is parked" for the whole fleet.
**Precedence â absolute.** A disabled board is skipped **whole**: the flag is
checked before the agent command is resolved and before the drain decision, so
there is no drain, no auto-block and no agent run. It wins over `--command`, the
config's `default_command`, the `.karr` `command` and `claude: true`, and
`--force` does **not** override it. Disabled means disabled.
This closes the gap where a global `default_command` in `config.yml` turned
every discovered board into an agent board with no way for a repo to opt out.
Use it for a repository whose backlog is parked rather than abandoned, so an
automation host that drains every discovered board leaves this one alone.
The same state is readable and writable through `karr config`:
```bash
karr config get foundation.enabled # -> 0 or 1
karr config set foundation.enabled false # true/false, yes/no, on/off, 1/0
karr config set foundation.reason "why"
```
`karr disable` without `--reason` clears any previously stored reason. When
every discovered board is disabled (or has no agent), `karr-foundation` falls
back to the overview instead of draining.
## Overview
`karr-foundation --status` (and the default when no board has an agent) prints a
read-only dashboard of every board: status counts, in-progress/blocked tasks,
and disabled/lock/cooldown state. No agent is run â usable by a human to
coordinate work.
```
dbio-informix
7 tasks [disabled]
backlog:5 review:2
disabled: abandoned driver, backlog parked
```
`disabled` leads the flag list and the `disabled:` line carries the reason
(`no reason given` when none was stored). The `agent` flag is suppressed for a
disabled board, because that agent will never run there.
## Options
```bash
karr-foundation --config PATH # custom config file
karr-foundation --force # run even if no board change / open tasks
karr-foundation --dry-run --verbose # preview without executing
karr-foundation --status # read-only overview of every board, no runs
```
Agent output streams to the terminal when run interactively (TTY) or with
`--verbose`, and is always appended to `.karr.log`.
## Drain loop semantics
Each iteration runs `command` once, then classifies result:
| Outcome | Meaning | Action |
|---------|---------|--------|
| **progress** | board changed | keep draining |
| **stall** | a task *this run's agent engaged* didn't move | bump attempt counter; auto-block after `max_attempts` |
| **common-error** | bad exit, timeout, or an error pattern in a run that moved *nothing* | exponential backoff, no task penalty |
| **idle** | agent did nothing, grabbed nothing | stop |
**What a run did is asked before what it printed.** A run that exited 0 and
moved the board is progress whatever scrolled past it, and is never
reclassified by its own transcript; the output is scanned only for a run that
moved nothing at all â which is what a rate-limited or unauthenticated agent
looks like. A pattern seen in a run that *did* move the board is noted in
`.karr.log` and otherwise ignored. The default patterns are narrow to match: a
symptom word counts next to a failure word on the same line (`network error`,
`invalid credentials`, `quota exceeded`), and an HTTP status only where
something adjacent marks it as one (`API error: 429`, `429 Too Many Requests`)
â not in a diffstat, a byte count or a line number. Before that, an agent
printing its own board tripped the scan on a backlog title and throttled a
healthy board to one run per hour (#160).
### Auto-block
When a task is stuck after `max_attempts`, foundation marks it blocked with:
```
blocked: auto-block: no progress after N attempts (foundation)
```
Agent can override with `karr edit --block "reason"`.
**Engaged** means foundation can prove the agent worked that card during *this*
drain: it runs the command with `KARR_ROLE=agent`, so the agent's `karr` writes
land in the board's activity log under the `agent` identity, and only tasks
named there â unclaimed, or held under a claim name the agent itself wrote
with â can be penalized. A card somebody else holds is never auto-blocked,
nor is one the agent merely left claimed in an earlier run (that is what
`claim_timeout` and `karr unlock` are for). Without that evidence â an agent
command that never calls `karr` â foundation auto-blocks **nothing** rather
than guess (#158).
### Exponential cooldown
On common-error: repo waits `cooldown_base à 2^level` minutes (capped at `cooldown_max`).
Level resets on next clean (non-error) run, which also drops `last_error` from
`.karr.state` â it describes the last run, not a past one.
## State files (gitignored)
```
.karr.state # board hash, per-task attempts, cooldown, last error
.karr.lock # PID lock (prevents concurrent runs)
.karr.log # run log
```
## Environment
During agent execution foundation sets:
- `KARR_REPO` â the repo path
- `KARR_ROLE=agent` â so nested `karr` calls log under the `agent` identity
(`refs/karr/log/agent/<email>`); a human defaults to `user`
- `PROMPT` â the resolved agent instruction (`prompt` / `default_prompt` /
built-in default), referenced as `$PROMPT` in the command template
## Cron example
```bash
# Every 5 minutes, all repos
*/5 * * * * karr-foundation
# With verbose logging to syslog
*/5 * * * * karr-foundation --verbose 2>&1 | logger -t karr-foundation
```
## Enabling agent runs for a repo fleet
Each repo needs a `.karr` file with a command that invokes an agent on the
next available task. Example:
```yaml
command: claude -p "Use karr CLI to pick next task, implement it fully, hand off or close"
on_idle: skip
drain: true
max_runtime: 900
max_attempts: 2
cooldown_base: 2
cooldown_max: 32
```
To initialize karr in a repo:
```bash
cd /path/to/repo
karr init --name my-project
karr create "Example task" --priority high
```
( run in 1.300 second using v1.01-cache-2.11-cpan-788537b7465 )