aio-kanban

star 3

Markdown-based kanban board for AI agent task management. Board is a pure index (`.kanban/board.md`), every task lives in its own file (`.kanban/tasks/T-NNN-slug.md`). Use to init the board, add tasks, move them across Backlog/Todo/Doing/Done/Blocked, or archive completed work.

aiocean By aiocean schedule Updated 6/4/2026

name: aio-kanban description: | Markdown-based kanban board for AI agent task management. Board is a pure index (.kanban/board.md), every task lives in its own file (.kanban/tasks/T-NNN-slug.md). Use to init the board, add tasks, move them across Backlog/Todo/Doing/Done/Blocked, or archive completed work. when_to_use: kanban, board, tasks, backlog, show board, what's next, task status, add task, init kanban, sprint, todo list, track progress, move task, prioritize, plan work, archive, show tasks, current tasks, prioritize tasks, archive done, delete task, remove task, confirm delete effort: medium argument-hint: "init | status | add | archive"</h2> <p>!<code>bash "${CLAUDE_PLUGIN_ROOT}/skills/aio-kanban/scripts/kanban-status.sh" 2>/dev/null</code></p> <h2>Kanban Protocol (v3 — index + per-task files)</h2> <p><strong>Board</strong> is a flat index at <code>.kanban/board.md</code>. Each line points to a task file. <strong>Tasks</strong> live at <code>.kanban/tasks/T-NNN-slug.md</code> with full body (description, criteria, notes).</p> <p>Follow this protocol exactly. Do NOT adapt or invent your own format.</p> <hr> <h2>Init</h2> <p>If auto-status above shows "not initialized":</p> <pre><code class="language-bash">mkdir -p .kanban/archive .kanban/tasks cat > .kanban/board.md << 'BOARD' # Kanban Board <!-- Updated: YYYY-MM-DD --> ## Backlog ## Todo ## Doing ## Done ## Blocked BOARD </code></pre> <p>Then inject the kanban guide into CLAUDE.md:</p> <pre><code class="language-bash">bash "${CLAUDE_PLUGIN_ROOT}/skills/aio-kanban/scripts/kanban-inject.sh" </code></pre> <hr> <h2>Formats — MUST use verbatim</h2> <h3>Board line (one per task)</h3> <pre><code>- [T-NNN](tasks/T-NNN-slug.md) Title — priority/effort </code></pre> <p>Example:</p> <pre><code>- [T-052](tasks/T-052-rate-limit.md) Rate limit per endpoint — high/S </code></pre> <h3>Task file (<code>.kanban/tasks/T-NNN-slug.md</code>)</h3> <pre><code class="language-markdown"># T-NNN: Title > One-line description - **priority**: critical | high | medium | low - **effort**: XS | S | M | L ## Criteria - [ ] Acceptance criterion 1 - [ ] Acceptance criterion 2 ## Notes (free-form section — design sketches, links, discussion) </code></pre> <p>Optional fields (add below <code>- **effort**</code>):</p> <ul> <li><code>- **depends**: T-NNN</code></li> <li><code>- **branch**: feat/branch-name</code></li> <li><code>- **completed**: YYYY-MM-DD</code> (added when moved to Done)</li> <li><code>- **blocked-by**: reason</code> (added when moved to Blocked)</li> </ul> <p><strong>ID rule</strong>: <code>T-NNN</code>, zero-padded, monotonic. NEVER reuse. <strong>Slug rule</strong>: kebab-case from title, lowercase, alphanumeric+hyphen only, max 40 chars.</p> <hr> <h2>Workflow Rules</h2> <ol> <li><strong>Add a task</strong>:<ul> <li>Pick next ID: highest existing T-NNN + 1.</li> <li>Generate slug from title (kebab-case, ≤40 chars).</li> <li>Create file <code>.kanban/tasks/T-NNN-slug.md</code> with format above.</li> <li>Insert board line under <strong>## Backlog</strong> in <code>.kanban/board.md</code>.</li> </ul> </li> <li><strong>Refine</strong>: move the board line to <strong>## Todo</strong> when criteria are defined.</li> <li><strong>Start</strong>: move the board line to <strong>## Doing</strong>, add <code>- **branch**: ...</code> to the task file. NEVER exceed 2 in Doing.</li> <li><strong>Complete</strong>: ALL criteria checkboxes checked → move board line to <strong>## Done</strong>, add <code>- **completed**: YYYY-MM-DD</code> to task file.</li> <li><strong>Block</strong>: move to <strong>## Blocked</strong>, add <code>- **blocked-by**: ...</code> to task file. Review daily.</li> <li><strong>Archive</strong>: monthly, cut Done lines AND their task files to <code>.kanban/archive/YYYY-MM/</code> (board lines into <code>archive/YYYY-MM/board.md</code>, task files into <code>archive/YYYY-MM/tasks/</code>).</li> <li><strong>Update timestamp</strong>: every board write updates <code><!-- Updated: YYYY-MM-DD --></code>.</li> </ol> <hr> <h2>Why index + per-task files</h2> <p>A flat board grows unbounded — task notes, design sketches, discussion all pile into one file. The index split keeps the board scannable (one line per task) while letting each task grow freely in its own file. Sub-agents and the <code>aio-kanban-monitor</code> skill rely on this split.</p> <hr> <h2>Session Protocol</h2> <ul> <li><strong>Start</strong>: Read <code>.kanban/board.md</code>. For tasks in Doing, open their task files. Check Blocked.</li> <li><strong>End</strong>: Update <code>.kanban/board.md</code> — move completed task lines, note blockers, update <code><!-- Updated: --></code> timestamp.</li> </ul> <hr> <h2>Companion: auto-dispatch</h2> <p>The <code>aio-kanban-monitor</code> skill watches <code>.kanban/board.md</code> and auto-spawns a sub-agent for any task in a chosen column whose content matches a free-text goal. See its SKILL.md for details.</p> <hr> <h2>Companion: <code>aiokan</code> terminal UI (optional)</h2> <p>This plugin ships a Go TUI at <code>${CLAUDE_PLUGIN_ROOT}/skills/aio-kanban/tui/</code> so a human can watch and steer the same board beside the agent — vim keys + mouse, in any terminal pane.</p> <p><strong>Two panes</strong>: the left lists every task grouped by status (Backlog → Blocked); the right renders the selected task's markdown body live (glamour). It reads and writes the <strong>exact</strong> <code>.kanban/</code> format above (board lines relocated verbatim, Done stamps <code>completed</code>, Blocked stamps <code>blocked-by</code>, timestamp refreshed), with atomic writes and a staleness guard so it never clobbers an edit the agent makes while it is open.</p> <p>Install it globally once:</p> <pre><code class="language-bash">cd "${CLAUDE_PLUGIN_ROOT}/skills/aio-kanban/tui" && go install . </code></pre> <p>Then run <code>aiokan</code> from any repo with a <code>.kanban/board.md</code>. Keys: <code>j/k</code> select · <code>shift+↑/↓</code> move status · <code>tab</code> focus preview · <code>d</code> delete (confirm modal, removes card + file) · <code>r</code> reload · <code>q</code> quit; mouse click selects, wheel scrolls the focused pane. Full docs in that folder's <code>README.md</code>. Requires Go 1.26+; the board protocol works fully without it.</p> </article> </div> <!-- Right: Metadata & Command Sidebar --> <div class="w-full lg:w-80 shrink-0 flex flex-col gap-6" data-astro-cid-7zzsworf> <!-- Install Card --> <div class="p-6 rounded-xl bg-surface-container border border-border/80 flex flex-col gap-4 shadow-sm" data-astro-cid-7zzsworf> <span class="text-xs font-bold uppercase tracking-widest text-on-surface-variant/60 font-mono" data-astro-cid-7zzsworf>Install via CLI</span> <div class="flex flex-col gap-2" data-astro-cid-7zzsworf> <div id="detail-install-cmd" class="font-mono text-[11px] p-3 rounded-lg bg-black/40 border border-border select-all break-all text-primary font-bold leading-relaxed" data-astro-cid-7zzsworf> npx skills add https://github.com/aiocean/claude-plugins --skill aio-kanban </div> <button id="detail-copy-btn" class="w-full py-2.5 rounded-lg bg-primary hover:bg-primary-hover text-on-primary font-sans font-bold text-sm shadow transition-all active:scale-95 flex items-center justify-center gap-1.5" data-astro-cid-7zzsworf> <span class="material-symbols-outlined text-[16px]" data-astro-cid-7zzsworf>content_copy</span> <span data-astro-cid-7zzsworf>Copy Command</span> </button> </div> </div> <!-- Details & Stats Card --> <div class="p-6 rounded-xl bg-surface-container border border-border/80 flex flex-col gap-4 shadow-sm text-on-surface" data-astro-cid-7zzsworf> <span class="text-xs font-bold uppercase tracking-widest text-on-surface-variant/60 font-sans" data-astro-cid-7zzsworf>Repository Details</span> <div class="flex flex-col gap-3.5" data-astro-cid-7zzsworf> <div class="flex justify-between items-center text-sm" data-astro-cid-7zzsworf> <span class="text-on-surface-variant/70 flex items-center gap-1.5" data-astro-cid-7zzsworf> <span class="material-symbols-outlined text-[16px] text-on-surface-variant/60" data-astro-cid-7zzsworf>star</span> Stars </span> <span class="font-mono font-bold text-on-surface" data-astro-cid-7zzsworf>3</span> </div> <div class="flex justify-between items-center text-sm" data-astro-cid-7zzsworf> <span class="text-on-surface-variant/70 flex items-center gap-1.5" data-astro-cid-7zzsworf> <span class="material-symbols-outlined text-[16px] text-on-surface-variant/60" data-astro-cid-7zzsworf>call_split</span> Forks </span> <span class="font-mono font-bold text-on-surface" data-astro-cid-7zzsworf>1</span> </div> <div class="flex justify-between items-center text-sm" data-astro-cid-7zzsworf> <span class="text-on-surface-variant/70 flex items-center gap-1.5" data-astro-cid-7zzsworf> <span class="material-symbols-outlined text-[16px] text-on-surface-variant/60" data-astro-cid-7zzsworf>navigation</span> Branch </span> <span class="font-mono bg-surface border border-border px-2 py-0.5 rounded text-[11px] text-on-surface-variant" data-astro-cid-7zzsworf>main</span> </div> <div class="flex justify-between items-start text-sm" data-astro-cid-7zzsworf> <span class="text-on-surface-variant/70 flex items-center gap-1.5 mt-0.5" data-astro-cid-7zzsworf> <span class="material-symbols-outlined text-[16px] text-on-surface-variant/60" data-astro-cid-7zzsworf>article</span> Path </span> <span class="font-mono bg-surface border border-border px-2 py-0.5 rounded text-[11px] text-on-surface-variant truncate max-w-[150px]" title="SKILL.md" data-astro-cid-7zzsworf>SKILL.md</span> </div> </div> </div> <!-- Occupations Tag Card --> <!-- Related Creators Card --> <div class="p-6 rounded-xl bg-surface-container border border-border/80 flex flex-col gap-3 shadow-sm" data-astro-cid-7zzsworf> <span class="text-xs font-bold uppercase tracking-widest text-on-surface-variant/60 font-sans" data-astro-cid-7zzsworf>More from Creator</span> <div class="flex items-center gap-2" data-astro-cid-7zzsworf> <img class="w-8 h-8 rounded-full border border-border" src="https://avatars.githubusercontent.com/u/73604319?v=4" alt="aiocean" onerror="this.src='https://avatars.githubusercontent.com/u/9919?v=4'" data-astro-cid-7zzsworf> <div class="flex flex-col min-w-0" data-astro-cid-7zzsworf> <span class="font-bold text-sm truncate text-on-surface" data-astro-cid-7zzsworf>aiocean</span> <a href="/?creator=aiocean" class="text-xs text-primary hover:underline font-semibold transition-all" data-astro-cid-7zzsworf>Explore all skills →</a> </div> </div> </div> </div> </div> </div> </div> <script> const copyBtn = document.getElementById("detail-copy-btn"); const installCmd = document.getElementById("detail-install-cmd"); if (copyBtn && installCmd) { copyBtn.addEventListener("click", () => { const cmd = installCmd.textContent.trim(); navigator.clipboard.writeText(cmd).then(() => { const originalText = copyBtn.innerHTML; copyBtn.innerHTML = ` <span class="material-symbols-outlined text-[16px]">check</span> <span>Copied!</span> `; copyBtn.style.background = "#10b981"; copyBtn.style.borderColor = "#10b981"; setTimeout(() => { copyBtn.innerHTML = originalText; copyBtn.style.background = ""; copyBtn.style.borderColor = ""; }, 1500); }); }); } </script> </div> <!-- Footer --> <footer class="border-t border-border bg-surface-container-low text-on-surface-variant py-8 px-gutter mt-16 rounded-xl"> <div class="max-w-container-max mx-auto flex flex-col md:flex-row justify-between items-center gap-6"> <div class="flex items-center gap-2"> <div class="w-6 h-6 rounded bg-primary bg-opacity-20 flex items-center justify-center"> <span class="material-symbols-outlined text-primary text-sm">code_blocks</span> </div> <span class="font-bold text-on-surface text-sm">SkillMD</span> </div> <div class="flex flex-wrap justify-center gap-6 text-sm"> <a href="/about" class="hover:text-primary transition-colors">About Us</a> <a href="/contact" class="hover:text-primary transition-colors">Contact Us</a> <a href="/privacy" class="hover:text-primary transition-colors">Privacy Policy</a> <a href="/terms" class="hover:text-primary transition-colors">Terms of Service</a> <a href="/support" class="hover:text-primary transition-colors">Support</a> </div> <div class="text-xs text-on-surface-variant/80"> © 2026 SkillMD. All rights reserved. </div> </div> </footer> </main> <!-- Script for Theme Toggle, Mobile Menu, and Sidebar Filter Redirection --> <script> // Theme setup const savedTheme = localStorage.getItem("theme") || "dark"; function applyTheme(theme) { document.documentElement.classList.remove("dark", "green", "dracula", "nord"); if (theme === "dark") { document.documentElement.classList.add("dark"); } else if (theme === "green") { document.documentElement.classList.add("dark", "green"); } else if (theme === "dracula") { document.documentElement.classList.add("dark", "dracula"); } else if (theme === "nord") { document.documentElement.classList.add("dark", "nord"); } document.documentElement.setAttribute("data-theme", theme); const themeMoon = document.getElementById("theme-moon"); const themeSun = document.getElementById("theme-sun"); const themeLeaf = document.getElementById("theme-leaf"); const themeDracula = document.getElementById("theme-dracula"); const themeNord = document.getElementById("theme-nord"); if (themeMoon && themeSun && themeLeaf && themeDracula && themeNord) { themeMoon.style.display = theme === "dark" ? "inline" : "none"; themeSun.style.display = theme === "light" ? "inline" : "none"; themeLeaf.style.display = theme === "green" ? "inline" : "none"; themeDracula.style.display = theme === "dracula" ? "inline" : "none"; themeNord.style.display = theme === "nord" ? "inline" : "none"; } } applyTheme(savedTheme); const themeToggleBtn = document.getElementById("theme-toggle-btn"); if (themeToggleBtn) { themeToggleBtn.addEventListener("click", () => { const currentTheme = document.documentElement.getAttribute("data-theme") || "dark"; let newTheme = "dark"; if (currentTheme === "dark") { newTheme = "light"; } else if (currentTheme === "light") { newTheme = "green"; } else if (currentTheme === "green") { newTheme = "dracula"; } else if (currentTheme === "dracula") { newTheme = "nord"; } else { newTheme = "dark"; } applyTheme(newTheme); localStorage.setItem("theme", newTheme); }); } // Mobile menu toggle and sidebar logic const mobileMenuToggle = document.getElementById("mobile-menu-toggle"); const sidebarMenu = document.getElementById("sidebar-menu"); const sidebarOverlay = document.getElementById("sidebar-overlay"); function isMobile() { return window.innerWidth < 768; // 768px is the 'md' breakpoint in Tailwind } function openSidebar() { if (sidebarMenu) { sidebarMenu.classList.remove("-translate-x-full"); } if (sidebarOverlay) { sidebarOverlay.classList.remove("hidden"); } } function closeSidebar() { if (sidebarMenu && isMobile()) { sidebarMenu.classList.add("-translate-x-full"); } if (sidebarOverlay) { sidebarOverlay.classList.add("hidden"); } } if (mobileMenuToggle && sidebarMenu) { mobileMenuToggle.addEventListener("click", (e) => { e.stopPropagation(); if (isMobile()) { const isClosed = sidebarMenu.classList.contains("-translate-x-full"); if (isClosed) { openSidebar(); } else { closeSidebar(); } } }); document.addEventListener("click", (e) => { if (isMobile()) { if (!sidebarMenu.contains(e.target) && !mobileMenuToggle.contains(e.target)) { closeSidebar(); } } }); if (sidebarOverlay) { sidebarOverlay.addEventListener("click", () => { if (isMobile()) { closeSidebar(); } }); } // Collapse sidebar when clicking a filter button, creator button, or nav item inside it sidebarMenu.addEventListener("click", (e) => { if (isMobile()) { const clickTarget = e.target.closest("button, a"); if (clickTarget) { closeSidebar(); } } }); // Sync sidebar state on window resize window.addEventListener("resize", () => { if (!isMobile()) { // Desktop: sidebar should be visible, no overlay if (sidebarMenu) { sidebarMenu.classList.remove("-translate-x-full"); } if (sidebarOverlay) { sidebarOverlay.classList.add("hidden"); } } else { // Mobile: start collapsed if (sidebarMenu) { sidebarMenu.classList.add("-translate-x-full"); } if (sidebarOverlay) { sidebarOverlay.classList.add("hidden"); } } }); } // If not on homepage, redirect on sidebar filter click const isHomepage = window.location.pathname === "/"; document.querySelectorAll("#occupation-filters .filter-btn").forEach(btn => { btn.addEventListener("click", (e) => { const occ = e.currentTarget.getAttribute("data-occupation"); if (!isHomepage) { window.location.href = occ ? `/?occupation=${encodeURIComponent(occ)}` : "/"; } }); }); document.querySelectorAll("#creator-filters .creator-btn").forEach(btn => { btn.addEventListener("click", (e) => { const creator = e.currentTarget.getAttribute("data-creator"); if (!isHomepage) { window.location.href = `/?creator=${encodeURIComponent(creator)}`; } }); }); </script> </body> </html>