Work through tasks on a kanban board stored in OpenViking (viking://agent/kanban/<board>/, one markdown file per task). Use when the user says "ov kanban", "kanban", "看板", asks to put a task on the board, hand off the current work, continue a task another agent started, or run an unattended task loop. A board holds many tasks; each task file is the handoff itself - a frontmatter header (id, status, owner, board) plus Goal, Context, Decisions, Progress, Next, Questions, Log - and its process detail is folded into an archive file instead of being summarized away, so any agent with the `ov` CLI can resume it and drill down when needed.
74
93%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Low
Low-risk findings worth noting
A board is a directory in OpenViking that holds many tasks. A task is one
markdown file. The file is both the ticket and the handoff: whoever reads it
can continue the work without the previous conversation. OpenViking stores
it, indexes it (find/grep), and shares it across every agent and user of
the account. There is no other state.
<root>/<board>/<id>.md the task: header + current state, rewritten every turn
<root>/<board>/archive/<id>.md its folded detail: append-only, never rewritten<root> is viking://agent/kanban. Probe it once per session with
ov stat viking://agent/kanban (or ov mkdir when it does not exist yet);
if the server answers PERMISSION_DENIED (older servers block writes under
viking://agent except skills), use viking://resources/kanban instead.
$OV_KANBAN_ROOT, when set, overrides the probe. The protocol is identical,
only the root changes.<board> is the isolation unit (a project, repo, or team). It is a plain
directory: ov acl on it decides who may read or take tasks. Create one
with ov mkdir <root>/<board> and ov mkdir <root>/<board>/archive
(write --mode create needs the parent directory to exist).<id> is YYYY-MM-DD-short-slug, unique inside the board.Use the ov CLI (works from any agent that has a shell). If the OpenViking
MCP tools list, read, write, grep are registered, they are
equivalent; never fall back to raw HTTP. Prefer the CLI for writes: a
write that runs into the MCP client timeout has usually still landed, so
read the file back before writing again.
Detail is folded, not compressed: a lower layer holds the full text the upper layer points to. Read top-down and stop at the first layer that answers the question.
| layer | what it holds | how to read |
|---|---|---|
| boards | one abstract per board | ov ls <root> |
| board view | title, status, owner, updated of every task | the ov grep below |
| task | current state, enough to continue the work | ov read <root>/<board>/<id>.md |
| archive | everything folded out of the task, verbatim | ov grep '<keyword>' -u <root>/<board>/archive/<id>.md, then ov read |
ov grep '^(title|status|owner|updated):' -u <root>/<board> -x <root>/<board>/archive -o jsonOpen the archive only when a Decisions or Progress line needs its
history or evidence. ov find "<topic>" -u <root> locates related tasks
across boards.
Copy references/task-template.md. Header:
| field | values |
|---|---|
id | YYYY-MM-DD-short-slug, equals the file name |
title | one line |
status | open · in_progress · needs_user · blocked · done · cancelled |
owner | agent id currently holding the task, empty when handed off |
board | the board directory name |
updated | output of date +%Y-%m-%dT%H:%M:%S%z, set on every write |
Body sections, in this order: Goal (done criteria checklist), Context
(cwd/repo/branch, key files or URIs, constraints), Decisions (dated, with
why; user answers land here), Progress (verified only, one line per item
with its evidence), Next (ordered checklist; first unchecked box is the
next action), Questions (concrete questions for the user; non-empty means
status: needs_user), Log (one dated line per turn, the last 10).
The file is the truth. If it disagrees with the live repo, trust the repo,
fix the file, and say so in Log.
Write the body in the task's main language: the language the user gave the task in, or the one an existing task already uses. Header keys and status values stay English.
The task file stays short enough to read in one call. Text leaves it by moving to the archive, never by deletion or by a shorter rewrite:
Log lines beyond the last 10;Next steps and Decisions that a later turn replaced;Progress line keeps the result, the archive keeps the rest.Append one entry per turn: a ### <updated> <agent id> heading, the status
change as from -> to when there is one, then the moved text verbatim.
ov write <root>/<board>/archive/<id>.md --append --from-file ./entry.md --waitCreate the archive with --mode create the first time. A turn that moves
nothing out and keeps the status writes no entry.
Every turn is bounded: pick, claim, one slice, verify, write back, stop.
ov grep above). Take the task the
user named, else an open one, else an in_progress one whose updated
is older than 2 hours (stale claim). Skip in_progress tasks another
agent updated recently.ov read the file. Set status: in_progress,
owner: <your agent id>, updated: now, add a Log line, write back
(step 5). Agent id is $OV_KANBAN_AGENT if set, else <tool>@<host>
(e.g. codex@mbp).Next, or more while it stays
one coherent, verifiable piece of work. Read Context and Decisions
first; they are the contract from earlier turns and the user.Progress, with its evidence.ov write <root>/<board>/<id>.md --from-file ./task.md --waitCONFLICT (path busy) wait a few seconds and retry once; on
ALREADY_EXISTS when creating (--mode create) pick another id. Then
choose the exit state:
in_progress;owner, set status: open, make sure Next is precise enough for a
cold reader;Questions,
set status: needs_user, clear owner, then ask the user in the
current session if there is one and stop;blocked,
name what unblocks it in Next;Goal boxes ticked with evidence → done;cancelled, clear owner, record who
decided and why in Decisions.Creating a task is the same write with --mode create and status: open;
fill Goal and Context from the user's request and put the first concrete
step in Next.
Answering a needs_user task: record the answer in Decisions, clear
Questions, set status: open, write back. The next turn picks it up.
codex exec by default, any CLI via
OV_KANBAN_CMD) until no runnable task is left or the tick budget is
spent, and notifies through herdr when it stops. needs_user tasks are
not runnable, so the loop drains around them and stops when only those
remain.
bash references/loop.sh <board> 5 /path/to/repoov tui. Nothing is tool-specific except
the agent id in owner.needs_user gate: name the person and the
exact action in Questions, clear owner, stop. When they report back,
record the outcome in Decisions and set status: open.Next and setting the later one blocked.Progress without evidence, never mark done with an
unchecked Goal box.9d9bc85
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.