App-karr
view release on metacpan or search on metacpan
ex/README.md view on Meta::CPAN
karr backup > karr-backup.yml # ganzes Board als YAML
karr restore --yes < karr-backup.yml
karr destroy --yes
```
`karr sync` synchronizes `refs/karr/*` with the remote â without flags first
fetch, then push, plus one delete refspec for each ref that this clone has
deleted and not yet published (read off the tombstones under
`refs/karr-local/deleted/`). The push does **no prune**: a remote ref this clone
has never seen is another agent's card and not leftover â pruning it is the way
a card has actually been lost once.
After that, the same command does the same for `refs/karr-foundation/*`, the
shared namespace of `karr-foundation` (chain, run logs, questions mailbox). One
command for both, because a second one would be a second thing you could forget
â and the forgetting would be silent. The board half runs first, and the fleet
half never alone: the board identity and wipe refusals are what protects the
fleet refs against a swapped remote, because this namespace has none of its own.
`restore` is deliberately destructive â it first deletes the current
`refs/karr/*` and then plays in the snapshot. `destroy` removes the board
completely. If a remote exists, both also prune there.
### 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
( run in 1.740 second using v1.01-cache-2.11-cpan-d01c6094234 )