App-karr
view release on metacpan or search on metacpan
use strict;
use warnings;
our $VERSION = '0.600';
use App::karr::SyncGuard;
use App::karr::Dispatch qw( dispatch );
# Push insurance, flushed at the last safe moment (ticket #37).
#
# App::karr::Role::SyncLifecycle arms an App::karr::SyncGuard for every writing
# command and stashes it on the command object, so that a body dying before
# sync_after still pushes what it wrote. On this CLI that never fired: the run
# below is wrapped in an eval, the handler exits, and MooX::Cmd's command chain
# holds the command object -- so the guard was first reaped in global
# destruction, where App::karr::Git refuses to work at all (#34) and the guard
# can do nothing but print "run karr sync".
#
# END is the fix: it runs before global destruction with the interpreter still
# whole, and unlike the error handler it also covers the exit() calls inside
# command bodies and the option-parse exits from App::karr::Role::ExitCodes.
# This stays in the executable rather than moving into App::karr::Dispatch: it
# is a process-lifecycle hook, and an in-process host that calls dispatch()
# repeatedly must flush after EACH call, not once at interpreter shutdown.
#
# $? is localized because the exit code is a documented contract (see EXIT CODES
# below) and the push may shell out to `git` on App::karr::Git's CLI-fallback
# path, whose open3/waitpid would otherwise overwrite it. flush_armed is
# documented never to die, which is the other half of protecting that contract:
# an exception here would abort perl's END queue and set its own exit status.
END {
local $?;
App::karr::SyncGuard->flush_armed;
}
# Everything between program start and App::karr->new_with_cmd -- the
# character/octet boundary, the record of the caller's argv, the empty-argument
# and dashed-option rewrites, and the central exit-code handler (ADR 0002) --
# lives in App::karr::Dispatch, so this executable and the in-process test
# runner (t/lib/TestKarr.pm) share one dispatch path rather than two copies.
dispatch(@ARGV);
__END__
=pod
=encoding UTF-8
=head1 NAME
karr - Kanban Assignment & Responsibility Registry
=head1 VERSION
version 0.600
=head1 SYNOPSIS
karr init --name "My Project"
karr create "Fix login bug" --priority high
karr move 1 in-progress --claim swift-fox
karr board
karr backup > karr-backup.yml
=head1 DESCRIPTION
F<karr> is the primary command line interface for L<App::karr>. It manages a
Git-native kanban board whose canonical state lives in C<refs/karr/*>, plus
optional helper payloads in non-protected refs outside that namespace.
Run it from inside a Git repository. Commands discover the repository root,
pull the current board refs, and read and write task cards directly against
those refs -- no board files ever touch the work tree for an ordinary
command. C<karr materialize> and C<karr import> are the two bridge commands
that write and read a disposable, gitignored F<tasks/> plus F<config.yml>
view instead, for kanban-md interop and for grepping the board as files.
The script is the best starting point when you want to understand the CLI as a
user. For architecture notes, Docker background, and Perl-facing examples, see
L<App::karr>.
=head1 CLI WORKFLOW
A typical session looks like this:
=over 4
=item 1.
Create the board once with L<App::karr::Cmd::Init>.
=item 2.
Add and inspect tasks with L<App::karr::Cmd::Create>,
L<App::karr::Cmd::List>, L<App::karr::Cmd::Show>, and
L<App::karr::Cmd::Board>.
=item 3.
Progress work with L<App::karr::Cmd::Move>, L<App::karr::Cmd::Edit>,
L<App::karr::Cmd::Pick>, and L<App::karr::Cmd::Handoff>.
=item 4.
Export, restore, or remove board state with L<App::karr::Cmd::Backup>,
L<App::karr::Cmd::Restore>, and L<App::karr::Cmd::Destroy>.
=back
=head1 COMMANDS
=head2 Board Setup And Configuration
=over 4
=item * L<App::karr::Cmd::Init>
Creates the initial board in C<refs/karr/*> and can install the bundled
project skill for Claude Code.
=item * L<App::karr::Cmd::Config>
Shows or updates writable board settings such as the board name, defaults, and
=head1 EXIT CODES
F<karr>'s primary callers are agents scripting the CLI, for whom C<$?> is part
of the interface. The exit code is therefore a stable contract (see
F<docs/adr/0002-exit-code-contract.md>):
=over 4
=item * B<0> -- success, including no-op successes such as re-archiving a task
that is already archived.
=item * B<1> -- runtime failure: a task id was not found, the board is missing,
a Git or sync operation failed, a destructive command was refused for want of
C<--yes>, or a batch committed partial work but at least one item failed.
=item * B<2> -- usage error: an unknown command, an unknown option, an invalid
option value, or a surplus or missing positional argument.
=back
The C<1>-versus-C<2> split is what lets a scripting agent tell "I called this
wrong" apart from "the operation failed". This deviates deliberately from
kanban-md, which exits C<1> for everything.
=head1 DOCKER USAGE
The CLI works well through the published Docker image. A common alias is:
alias karr='docker run --rm -it -w /work -e HOME=/home/karr \
-v "$(pwd):/work" \
-v "$HOME/.gitconfig:/home/karr/.gitconfig:ro" \
-v "$HOME/.claude:/home/karr/.claude" \
-v "$HOME/.codex:/home/karr/.codex" \
raudssus/karr:latest'
That keeps the current repository mounted at F</work> and lets the default
image adapt its runtime uid and gid to the owner of the mounted workspace. The
CLI syntax stays the same after that:
karr board
karr skill install --agent codex --global --force
If you prefer a fixed non-root runtime, use C<raudssus/karr:user> instead. That
image defaults to uid and gid C<1000:1000> and is intended as the predictable
base for downstream custom images. Custom fixed-user derivatives can override
C<KARR_UID> and C<KARR_GID> at build time.
=head1 EXAMPLES
Initialize a new board and install the project-local Claude Code skill:
karr init --name "HandyIntelligence Prototype" --claude-skill
Claim and start the next task for a generated agent:
NAME=$(karr agentname)
karr pick --claim "$NAME" --move in-progress
Export the board before trying a destructive restore:
karr backup > karr-backup.yml
karr restore --yes < karr-backup.yml
=head1 SEE ALSO
L<App::karr>, L<App::karr::Task>, L<App::karr::BoardStore>,
L<App::karr::Git>, L<App::karr::Cmd::Init>, L<App::karr::Cmd::Skill>,
L<App::karr::Cmd::Backup>, L<App::karr::Cmd::Restore>
=head1 SUPPORT
=head2 Issues
Please report bugs and feature requests on GitHub at
L<https://github.com/Getty/karr/issues>.
=head2 IRC
Join C<#langertha> on C<irc.perl.org> or message Getty directly.
=head1 CONTRIBUTING
Contributions are welcome! Please fork the repository and submit a pull request.
=head1 AUTHOR
Torsten Raudssus <getty@cpan.org>
=head1 COPYRIGHT AND LICENSE
This software is Copyright (c) 2026 by Torsten Raudssus <torsten@raudssus.de> L<https://raudssus.de/>.
This is free software, licensed under:
The Artistic License 2.0 (GPL Compatible)
=cut
( run in 0.562 second using v1.01-cache-2.11-cpan-4ef0a570458 )