view release on metacpan or search on metacpan
.claude/skills/kanban-issues-karr-cli/SKILL.md view on Meta::CPAN
```
### List tasks
```bash
karr list # the open cards
karr list --status todo,in-progress # filter by status
karr list --priority high,critical # filter by priority
karr list --tag backend # filter by tag
karr list --class expedite # filter by class of service
karr list --blocked # only the blocked cards
karr list --not-blocked # only the unblocked ones
karr list --archived # the archive, and nothing else
karr list -s "search term" # search title/body/tags
karr list --sort priority --reverse # sort and reverse
karr list --sort priority -n 5 --json # the five most urgent open cards
karr list --claimed-by agent-1 # filter by claim owner
karr list --unclaimed # only what no live claim holds
karr list --compact # one-line output (agent-friendly)
karr list --json # JSON output
```
.claude/skills/kanban-issues-karr-cli/SKILL.md view on Meta::CPAN
arbitrary ones put in order -- that is the "what next" call, instead of pulling
the whole board and cutting it locally.
`--unclaimed` is "what is free right now" -- `claimed_by` unset or empty, or a
claim older than the board's `claim_timeout`. It is the question `karr pick`
answers by *taking* the card, so this is how to see the free work without
touching it, and it uses the very test `pick` uses. It is not the opposite of
`--claimed-by NAME`: that one is an exact match on the field and matches an
expired claim too, so the two overlap on "cards NAME no longer holds" and
passing both is a usage error. Since it asks about the claim and nothing else,
a blocked card nobody holds is still listed -- `--blocked --unclaimed` is a
real triage query.
### Show task
```bash
karr show ID
karr show # most recently updated task
karr show --last 5 # the 5 most recent
karr show --me # the task you most recently acted on (re-orient)
karr show --agent NAME # the task most recently claimed by NAME
.claude/skills/kanban-issues-karr-cli/SKILL.md view on Meta::CPAN
karr edit ID --title "New title"
karr edit ID --priority high --add-tag urgent
karr edit ID --add-depends-on 2,3 # append dependency ids (no duplicates; ids must exist, no self-reference)
karr edit ID --remove-depends-on 4 # absent ids are a no-op (cleanup after a deleted dependency)
karr edit ID --add-needs other-repo#7 # append a cross-board dependency (see below)
karr edit ID --remove-needs other-repo#7 # absent references are a no-op
karr edit ID --body "New description"
karr edit ID -a "Appended note" # append to body
karr edit ID --claim agent-1 # claim
karr edit ID --release # release claim
karr edit ID --block "Waiting on API" # mark blocked
karr edit ID --unblock # clear blocked
```
An unknown or non-numeric id given to `--depends-on`/`--add-depends-on` rejects
the whole invocation before anything is written (usage error, exit 2); a
self-reference (`karr edit 5 --add-depends-on 5`) fails only that id, the rest
of the batch proceeds, and the command exits 1. Taking up a card whose
dependencies are unfinished warns on move/pick but is never blocked.
### Delete task
```bash
karr delete ID # asks first
karr delete ID --yes # skip confirmation
karr delete ID,ID,ID --yes # a batch
```
Before an id goes, `delete` names on STDERR every card on this board that
.claude/skills/kanban-issues-karr-cli/SKILL.md view on Meta::CPAN
### Pick next task (multi-agent)
```bash
karr pick --claim agent-1 # pick highest priority available
karr pick --claim agent-1 --status todo --move in-progress
karr pick --claim agent-1 --tags backend
karr pick --claim agent-1 --compact # stop after the assignment line
```
Atomically finds and claims the next available task. Respects claim timeouts, blocked state, and class-of-service priority ordering (expedite > fixed-date > standard > intangible); where two `fixed-date` cards meet, the due date is asked before prior...
### Unlock a stuck task
```bash
karr unlock # list the pick locks currently held
karr unlock ID # break one
karr unlock --all # break all of them
```
`karr pick` takes a lock ref and gives it back inside the same command, so normally there is nothing here to see. An agent that dies mid-pick leaves one behind. Locks expire on their own after `lock_timeout` (default `5m`, board config); this is how ...
.claude/skills/kanban-issues-karr-cli/SKILL.md view on Meta::CPAN
```
A reference is `BOARD#ID`: the other board's **name** and a task id. Never a
path -- the card is shared state and two clones of the same fleet have
different directories. karr turns the name into a directory from
`--board NAME=PATH` or from the fleet config
(`~/.config/karr-foundation/config.yml`, `--fleet-config` to point elsewhere),
matching the repository's directory basename.
`--resolve` settles a link whose far card has reached one of the **far** board's
own terminal statuses, and lifts the `blocked` flag when a card's last link
settles, printing the reason it lifted. A far card that does not exist settles
nothing. A board this machine cannot place is reported, not fatal.
Like `depends_on`, a cross-board link blocks nothing by itself: `pick` hands the
card over and says what it waits on. The `blocked` flag is what keeps the card
out of `pick` and out of karr-foundation's selection -- the link is the fact,
`blocked` is the decision.
### Config
```bash
karr config # show all config values
karr config get KEY # get a single value
karr config set KEY VALUE # set a writable value
karr config show --defaults # karr's defaults, no board read
karr config --json # JSON output
karr config show --compact # key=value per line, no padding
.claude/skills/kanban-issues-karr-cli/SKILL.md view on Meta::CPAN
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"
```
### Context (board summary for embedding)
```bash
karr context # print markdown summary
karr context --write-to AGENTS.md # create/update file with sentinels
karr context --sections blocked,overdue # filter sections
karr context --days 14 # lookback for recently-completed
karr context --activity-limit 10 # other agents' log entries in Recent Activity
karr context --json # JSON output
karr context --compact # board_name and the four counts, key=value
```
Generates a markdown summary with sections: In Progress, Blocked, Overdue, Recently Completed, Recent Activity (other agents' log entries, newest first, bounded by `--activity-limit`, default 5). `--sections` takes the slugs `in-progress,blocked,over...
### Skill management
```bash
karr skill install # install skill for detected agents
karr skill install --agent claude-code # install for specific agent
karr skill install --global # install globally (~/)
karr skill install --force # force reinstall
karr skill check # check if installed skills are current
karr skill update # update outdated skills
.claude/skills/kanban-issues-karr-cli/SKILL.md view on Meta::CPAN
is kept separately in `refs/karr/meta/next-id`.
## Decision tree: which command?
1. **Need a board?** â `karr init`
2. **New work item?** â `karr create "Title" --priority high`
3. **What's on the board?** â `karr board` or `karr list`
4. **Starting work?** â `karr pick --claim NAME --move in-progress`
5. **Done with task, hand to review?** â `karr handoff ID --claim NAME --note "reason"`
6. **Done with task, close it?** â `karr edit ID --release && karr move ID done`
7. **Blocked?** â `karr edit ID --block "reason"`
8. **Need details?** â `karr show ID`
9. **Soft-delete?** â `karr archive ID`
10. **Board snapshot for agent context?** â `karr context --write-to AGENTS.md`
11. **Check/change config?** â `karr config` / `karr config set KEY VALUE`
12. **Install agent skills?** â `karr skill install`
13. **Need a full board snapshot?** â `karr backup` / `karr restore --yes`
14. **Need shared non-task workflow data?** â `karr set-refs` / `karr get-refs`
15. **Board should never be drained by an automation host?** â `karr disable --reason "why"`
16. **Need to remove the board completely?** â `karr destroy --yes`
17. **Overview of every board under a directory?** â `karr dashboard`
lib/API/Docker/Role/HTTP.pm view on Meta::CPAN
# Asked with nothing in between, because $@ and $! are the whole of the
# evidence and both are global.
#
# $@ rather than errno: IO::Socket writes 'connect: timeout' there, and only
# there, when its own select() ran out -- measured, against a host that drops
# SYNs, where $! is ETIMEDOUT, which the kernel also produces on its own after
# two minutes with no Timeout set at all.
#
# EAGAIN is the second shape and belongs to unix:// alone. Measured against a
# listener whose backlog is full: with no Timeout the connect blocks
# indefinitely (still blocked after 8s), and with one it fails at once with
# EAGAIN, because IO::Socket does the timed connect non-blocking and an
# AF_UNIX connect has no in-progress state to wait on. So on that transport
# the option does not wait, it refuses -- but a connect that failed with
# EAGAIN is still one the bound ended, and reporting it as anything else would
# name a cause the caller cannot act on.
sub _connect_expired {
my ($self, $timeout) = @_;
return 0 unless $timeout;
return 1 if defined $@ && $@ =~ /connect: timeout\z/;
lib/API/Docker/Role/HTTP.pm view on Meta::CPAN
# matter is sysread rather than read: IO::Socket::SSL's sysread is a single
# Net::SSLeay::read, one record, while its read is ssl_read_all on a blocking
# socket, which is the same fill semantics this is here to get away from.
#
# A short positive read is never an end of stream and never an expiry. Over
# TLS it is the normal case, one plaintext record at a time; over a plain
# socket it is whatever the kernel had. Both are data.
#
# SSL_WANT_READ and SSL_WANT_WRITE are deliberately not retried. On a blocking
# socket they arrive as EWOULDBLOCK (IO::Socket::SSL's _skip_rw_error does
# `$! ||= EWOULDBLOCK`) and mean the underlying receive would have blocked --
# which, with SO_RCVTIMEO in force, is the bound firing and nothing else.
# Retrying would be a busy loop on WANT_READ and could not make progress on
# WANT_WRITE in any case, so they are reported as the timeout they are.
sub _pull {
my ($self, $sock, $ctx) = @_;
my $buf = $self->_read_buffer($sock);
while (1) {
# errno immediately before, errno immediately after, nothing in between:
lib/API/Docker/Role/HTTP.pm view on Meta::CPAN
=item * C<headers> names are validated, not sanitised; see
L</"Header names are rejected, header values are stripped">
=back
=head2 Bounding a request that never ends
Nothing above stops a request waiting forever. C<Connection: close> asks the
daemon to hang up when it is done, and the readers wait for that -- so a
daemon that has nothing more to send and does not hang up leaves the client
blocked with no way out. That is not hypothetical: attaching to a container
that has B<already exited> answers, delivers the buffered frames and then
holds the connection open indefinitely on rootless Podman (karr k52), and
C</containers/{id}/stats> opened on a running container does not end when that
container exits on Docker -- it degrades into zero-filled readings and keeps
going (karr k59).
L</read_timeout> bounds that:
# Give up after two seconds of silence rather than waiting forever.
my $frames = $docker->containers->using(read_timeout => 2)->attach($id);
lib/API/Docker/Role/HTTP.pm view on Meta::CPAN
=over
=item * C<tcp://> -- a real bound. Against a host that drops SYNs, an unbounded
connect waits for the kernel's own timeout, which on Linux is over two
minutes; C<< connect_timeout => 2 >> gave up after 2.00s. This is the case the
option exists for.
=item * C<unix://> -- a bound, but it does not wait. A connect to a Unix socket
whose listen backlog is full blocks: measured against a listener with
C<< Listen => 1 >> and nobody accepting, still blocked after 8 seconds. With a
C<connect_timeout> set it fails at once instead, with C<EAGAIN> -- because
C<IO::Socket> performs a timed connect non-blocking, and an C<AF_UNIX> connect
has no in-progress state to wait on. So the hang is gone, at the price of not
tolerating even a momentary backlog. A socket path that does not exist is
C<ENOENT> either way and is not affected.
=item * TLS -- bounds the TCP connect only. The handshake that follows it runs
on the connected socket, before L</read_timeout>'s C<SO_RCVTIMEO> is applied,
and is not covered by either.
lib/API/Docker/Type/SwarmInfo.pm view on Meta::CPAN
use namespace::clean;
docker node_id => Str, wire => 'NodeID';
docker node_addr => Str;
docker local_node_state => Str,
enum => [ '', 'inactive', 'pending', 'active', 'error', 'locked' ];
docker control_available => Bool;
docker error => Str;
docker remote_managers => [ 'PeerNode' ];
lib/API/Docker/Type/SwarmInfo.pm view on Meta::CPAN
name would produce C<NodeId>.
=head2 node_addr
IP address at which this node can be reached by other nodes in the swarm.
The daemon defaults it to .
=head2 local_node_state
Current local status of this node. The swagger enumerates the empty string,
C<inactive>, C<pending>, C<active>, C<error> and C<locked>.
=head2 control_available
Undocumented upstream. A boolean, defaulted to C<false> upstream and C<true>
in the example, standing beside L</local_node_state> and L</managers>.
Measured against Podman 5.8.4 (API 1.44), C<GET /info> answers a complete
C<Swarm> block -- C<ControlAvailable> C<false>, C<LocalNodeState>
C<inactive> -- on an engine running no swarm at all.
=head2 error
t/connect_timeout.t view on Meta::CPAN
my $err = $@;
ok !(ref $err && $err->isa('API::Docker::Error::Timeout')),
'not turned into a timeout by having a connect_timeout set';
like "$err", qr/Cannot connect to Unix socket/,
'the diagnosis is the one the caller can act on';
};
# ---------------------------------------------------------------------------
# The one end-to-end assertion. An AF_UNIX connect blocks in exactly one
# situation -- the listener's backlog is full and nobody is accepting --
# measured with Listen => 1 and no accept: still blocked after 8 seconds. So
# the backlog is filled here, and then the bound has something to bound.
subtest 'the real socket: a connect that would block raises the timeout'
=> sub {
my $dir = tempdir(CLEANUP => 1);
my $path = $dir . '/backlog.sock';
my $srv = IO::Socket::UNIX->new(Local => $path, Listen => 1)
or plan skip_all => "cannot listen on a Unix socket here: $!";
# Filled with the same bounded connect the code under test uses, so this
# loop cannot be the thing that hangs. Nothing ever accepts on $srv.
t/connect_timeout.t view on Meta::CPAN
Peer => $path, Type => SOCK_STREAM, Timeout => 1);
unless ($c) {
$full = ($! == Errno::EAGAIN() || $! == Errno::EWOULDBLOCK()) ? 1 : 0;
last;
}
push @held, $c;
}
plan skip_all => 'the listen backlog does not fill the way this platform '
. 'was measured to' unless $full;
my $blocked = API::Docker->new(
host => 'unix://' . $path,
api_version => '1.41',
connect_timeout => 1,
);
# The alarm is the harness's own bound, not the one under test: without the
# Timeout on the constructor this connect blocks forever, and a test that
# hangs reports nothing. With it, the alarm never fires.
my $t0 = time;
eval {
local $SIG{ALRM} = sub { die "the connect was never bounded at all\n" };
alarm 10;
$blocked->get('/probe');
alarm 0;
1;
};
my $err = $@;
alarm 0;
my $elapsed = time - $t0;
isa_ok $err, 'API::Docker::Error::Timeout';
is ref $err && $err->phase, 'connect',
'the phase says the daemon was never reached';
t/spec_to_type.t view on Meta::CPAN
subtest 'stage has nothing left to write' => sub {
# The end state of karr k79 step 5: every class the spec calls for is in
# lib/, so the generator's creating half has no work. A number other than
# zero here means the spec grew a definition and nobody noticed -- which is
# the drift checker's report, arrived at from the other side.
my $out = qx{$^X \Q$SCRIPT\E --stage \Q$stage\E/nothing 2>&1};
like $out, qr/rendered\s+0 class\(es\)/,
'no class in the spec is missing from lib/';
unlike $out, qr/NEEDS A/,
'and nothing is blocked waiting for a name or an abstract';
};
subtest 'a name with a run of capitals must be in the map' => sub {
# Silently guessing is how `device_i_ds` would reach a hundred classes at
# once: the derivation produces it, and it survives the round-trip check
# that catches every other bad name.
my $names = File::Spec->catfile($stage, 'names.yaml');
open my $in, '<', File::Spec->catfile($ROOT, 'maint', 'spec-to-type-names.yaml')
or die $!;
open my $out, '>', $names or die $!;