App-karr

 view release on metacpan or  search on metacpan

ex/README.md  view on Meta::CPAN

### Helper refs

Not every shared state is a card. `karr set-refs` and `karr get-refs` put
arbitrary payloads into refs outside of `refs/karr/*`:

```bash
karr set-refs superpowers/spec/1234.md draft ready
karr set-refs superpowers/spec/1234.md < design.md    # mehrzeilig über stdin
karr get-refs superpowers/spec/1234.md
```

The arguments after the ref are joined with a space, so they're a single-line
payload. A document comes via stdin: without a content argument, `karr set-refs
REF < file` stores the file verbatim, and `karr get-refs REF > file` returns it
unchanged. Good for planning blobs, generated specs, agent scratch state,
workflow metadata you want synced through Git without modeling it as a card.

Protected namespaces are locked: branches, tags, remotes, stash, `refs/karr/*`
and `refs/karr-local/*` (where `karr pick` keeps its process-local locks).
`refs/karr-foundation/chain/*`, `.../log/*` and `.../questions/*` are
**read-only** for `set-refs` — those are written by `karr-foundation` with
schema and compare-and-swap — while `get-refs` reads them freely. That's exactly
how you look at a step, a run log or a question.

### Skills

The distribution ships a `karr` skill, installable locally in the repository or
globally in the home directory:

```bash
karr skill install
karr skill install --agent claude-code
karr skill install --agent codex --global --force
karr skill check --global
karr skill update
```

Targets are `claude-code`, `codex` and `cursor`.

### Characters inside, octets only at the edge

A rule that has no command line but affects every output: everything between the
CLI entry point and the Git ref blob is a Perl **character** string.
`App::karr::Encoding` owns every crossing — `@ARGV`, STDOUT/STDERR, ref reading
and writing, YAML, JSON — and nothing else may encode or decode directly. Boards
written before this rule are detected via `refs/karr/meta/encoding` and repaired
on read; `karr repair` migrates them permanently. The reason this is worth
mentioning at all: a double-encoded UTF-8 in a card title is the bug nobody
notices until the board has been broken for months.

---

## 4. `karr-foundation` — the coordinator

A board is half the battle. `karr-foundation` is the other half and the reason
why `karr` isn't just a file-based kanban.

It's a single-shot, idempotent companion binary. It watches **many**
repositories, decides per board whether there's work there, and lets the
configured agent command run until the board stops moving. Cron, a systemd
timer or a `while` loop point at it; every tick is complete in itself.

And it has two operating modes, each useful on its own:

| If you want | you call | you get |
|---|---|---|
| a picture of every board | `karr-foundation --status` | status counters, in-progress/blocked cards, lock, cooldown, agent state, open questions — read-only, an agent is never started |
| agents to work the boards | `karr-foundation` | one agent per repository, per the `.karr` file in it. If there is no `.karr` anywhere, it prints the overview instead |

**Agent execution is opt-in.** That isn't reticence but the security design: a
default that suddenly starts four agents on an operator's laptop would be a
surprise, and the surprise would land on a machine, not in a review.

### What a tick does

In order — and the order is the interesting part. (The hub commands `ask`,
`answer` and `chain` come before it and never discover a board: a question is
fleet state in the hub and has nothing to do with which repositories this
machine drains.)

1. **Discover repositories.** From `dirs:` (explicit list) and `scan:` (direct
   children of a directory that have a `.karr` file or are themselves a karr
   board). A repository reachable both ways is processed **once**, not twice —
   deduplicated over the canonical filesystem path, because the same thing can
   appear as a string, with a trailing slash, or as a symlink and its target.
   If nothing is found at all, that's a runtime error with exit code `1`.
2. **`--status`?** Then print the overview and be done.
3. **Is an agent even running anywhere?** Per board it's resolved once whether
   it is disabled and which command (and which named agent) would run. If the
   answer is "none" everywhere, `karr-foundation` prints the overview — with a
   line saying why, and how to turn it on.
4. **Pull the fleet namespace.** `refs/karr-foundation/*` from the hub, and
   before anything reads it, so this tick's limits are the fleet's current ones
   and not the ones this machine happened to fetch last. An ordinary tick writes
   **nothing** back there.
5. **Install signal handling.** `SIGTERM`/`SIGINT`/`SIGHUP` take every running
   agent along: first `TERM`, then `KILL` to the **process group** of the
   agent. Without it the agent would remain behind as an orphan at `init`, while
   the `.karr.lock` names a dead PID — and the next cron tick would read the
   dead PID as free and start a second agent on the same board.
6. **Work the boards**, serially or concurrently (see `concurrent:` below).

Per repository, in exactly this order:

1. Is there a board here at all? (`.karr` file or `refs/karr/config`)
2. **Is the board disabled?** — first, before everything else.
3. Resolve the agent command. None? Skipped.
4. Is the `.karr.lock` held? Then someone is already working on it.
5. Is the board in cooldown?
6. Is the named agent currently down?
7. Pull `refs/karr/*` — and then check the disabling **again**, because the
   pull may have just brought in the flag from another machine.
8. Is there reason to run? (`--force`, or the board has moved since the last
   tick, or there are workable cards, or `on_idle: always-run`)
9. Take the lock (`flock(2)`), drain, run `on_drained`, release the lock.
10. Advance cooldown and agent availability, write `.karr.state`.

### Where the pieces live — and which ones travel

This table is the most important of the section because it makes the design
decision visible:



( run in 1.054 second using v1.01-cache-2.11-cpan-ad66724bd6a )