Skills kanboard
install
source · Clone the upstream repo
git clone https://github.com/openclaw/skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/openclaw/skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/bivex/kanboard-skill" ~/.claude/skills/clawdbot-skills-kanboard && rm -rf "$T"
manifest:
skills/bivex/kanboard-skill/SKILL.mdsource content
Kanboard Skill
Overview
Kanboard uses JSON-RPC 2.0 over HTTP POST. All calls go to a single endpoint.
Auth modes
| Mode | User | Password |
|---|---|---|
| Application API | | |
| User API | | |
Application API skips permission checks and has no session. Use it for automation. User API respects project permissions; required for "My…" procedures.
Core Helper
Always use this shell function to call the API:
kb() { local method="$1" local params="${2:-{}}" local user="${KANBOARD_USER:-jsonrpc}" local pass="${KANBOARD_PASS:-$KANBOARD_API_TOKEN}" curl -s -X POST \ -u "$user:$pass" \ -H "Content-Type: application/json" \ -d "{\"jsonrpc\":\"2.0\",\"method\":\"$method\",\"id\":1,\"params\":$params}" \ "${KANBOARD_URL}/jsonrpc.php" | jq . }
Check for errors in every response:
# Always verify result is not null/false result=$(kb getMe | jq '.result') if [ "$result" = "null" ] || [ "$result" = "false" ]; then echo "Error: $(kb getMe | jq -r '.error.message // "unknown error"')" fi
Projects
# List all projects kb getAllProjects # Get single project by ID kb getProjectById '{"project_id": 1}' # Get project by name kb getProjectByName '{"name": "My Project"}' # Create project kb createProject '{"name": "New Project", "description": "Optional description"}' # Update project kb updateProject '{"id": 1, "name": "Renamed", "description": "Updated"}' # Remove project (irreversible) kb removeProject '{"project_id": 1}' # Enable / disable project kb enableProject '{"project_id": 1}' kb disableProject '{"project_id": 1}' # Get project activity feed kb getProjectActivity '{"project_id": 1}'
Board & Columns
# Get full board (columns + tasks) for a project kb getBoard '{"project_id": 1}' # List columns kb getColumns '{"project_id": 1}' # Get single column kb getColumn '{"column_id": 5}' # Create column kb addColumn '{"project_id": 1, "title": "In Review", "task_limit": 3}' # Update column kb updateColumn '{"column_id": 5, "title": "Review", "task_limit": 5}' # Remove column kb removeColumn '{"column_id": 5}' # Change column position kb changeColumnPosition '{"project_id": 1, "column_id": 5, "position": 2}'
Tasks
# Create task (minimum required: title + project_id) kb createTask '{ "title": "Fix login bug", "project_id": 1, "column_id": 2, "swimlane_id": 1, "color_id": "red", "priority": 2, "due_date": "2025-12-31", "description": "Detailed description here", "owner_id": 3, "tags": ["bug", "urgent"] }' # Get task by ID kb getTask '{"task_id": 42}' # Get task by reference (external ref) kb getTaskByReference '{"project_id": 1, "reference": "EXT-123"}' # List all tasks in a project (status: 1=open, 2=closed) kb getAllTasks '{"project_id": 1, "status_id": 1}' # Search tasks with advanced query kb searchTasks '{"project_id": 1, "query": "assignee:me status:open"}' # Update task kb updateTask '{ "id": 42, "title": "Fix login bug (updated)", "column_id": 3, "color_id": "green", "priority": 1, "due_date": "2025-11-30" }' # Move task to another column/swimlane/position kb moveTaskToColumn '{ "project_id": 1, "task_id": 42, "column_id": 3, "position": 1, "swimlane_id": 1 }' # Move task to another project kb moveTaskToProject '{ "task_id": 42, "project_id": 2, "swimlane_id": 1, "column_id": 1, "category_id": 0 }' # Duplicate task to another project kb duplicateTaskToProject '{ "task_id": 42, "project_id": 2 }' # Close / Open task kb closeTask '{"task_id": 42}' kb openTask '{"task_id": 42}' # Remove task (irreversible) kb removeTask '{"task_id": 42}' # Get task color list kb getTaskColors
Task color IDs
yellow, blue, green, purple, red, orange, grey, brown, deep_orange, dark_grey, pink, teal, cyan, lime, light_green, amber
Subtasks
# List subtasks for a task kb getAllSubtasks '{"task_id": 42}' # Create subtask kb createSubtask '{ "task_id": 42, "title": "Write unit tests", "user_id": 3, "time_estimated": 4 }' # Update subtask (status: 0=todo, 1=in-progress, 2=done) kb updateSubtask '{ "id": 10, "task_id": 42, "status": 1, "time_spent": 2 }' # Remove subtask kb removeSubtask '{"subtask_id": 10}'
Comments
# List comments for a task kb getAllComments '{"task_id": 42}' # Create comment kb createComment '{ "task_id": 42, "user_id": 1, "content": "This is a **markdown** comment." }' # Update comment kb updateComment '{"id": 7, "content": "Updated comment text."}' # Remove comment kb removeComment '{"comment_id": 7}'
Swimlanes
# List swimlanes for a project kb getSwimlanes '{"project_id": 1}' # Get active swimlanes only kb getActiveSwimlanes '{"project_id": 1}' # Create swimlane kb addSwimlane '{"project_id": 1, "name": "Team Alpha"}' # Update swimlane kb updateSwimlane '{"swimlane_id": 3, "name": "Team Beta"}' # Remove swimlane kb removeSwimlane '{"project_id": 1, "swimlane_id": 3}' # Change swimlane position kb changeSwimlanePosition '{"project_id": 1, "swimlane_id": 3, "position": 1}'
Categories
# List categories for a project kb getAllCategories '{"project_id": 1}' # Create category kb createCategory '{"project_id": 1, "name": "Backend"}' # Update category kb updateCategory '{"id": 5, "name": "Backend & API"}' # Remove category kb removeCategory '{"category_id": 5}'
Users
# List all users (Application API only) kb getAllUsers # Get user by ID kb getUserById '{"user_id": 3}' # Get user by username kb getUserByName '{"username": "alice"}' # Create user kb createUser '{ "username": "bob", "password": "S3cur3P@ss", "name": "Bob Smith", "email": "bob@example.com", "role": "app-user" }' # Roles: app-admin | app-manager | app-user # Update user kb updateUser '{"id": 3, "name": "Bob Jones", "email": "bob.jones@example.com"}' # Disable / Enable user kb disableUser '{"user_id": 3}' kb enableUser '{"user_id": 3}' # Remove user kb removeUser '{"user_id": 3}' # Current user (User API only) kb getMe kb getMyProjects kb getMyDashboard kb getMyActivityStream kb getMyCalendar kb getMyNotifications
Project Permissions
# List project users kb getProjectUsers '{"project_id": 1}' # Add user to project kb addProjectUser '{ "project_id": 1, "user_id": 3, "role": "project-member" }' # Roles: project-manager | project-member | project-viewer # Change user role in project kb changeProjectUserRole '{"project_id": 1, "user_id": 3, "role": "project-manager"}' # Remove user from project kb removeProjectUser '{"project_id": 1, "user_id": 3}' # Add/remove group to project kb addProjectGroup '{"project_id": 1, "group_id": 2, "role": "project-member"}' kb removeProjectGroup '{"project_id": 1, "group_id": 2}'
Tags
# Get all tags for a project kb getTagsByProject '{"project_id": 1}' # Create tag kb createTag '{"project_id": 1, "tag": "urgent"}' # Update tag kb updateTag '{"id": 4, "tag": "critical"}' # Remove tag kb removeTag '{"tag_id": 4}' # Get tags for a task kb getTaskTags '{"task_id": 42}' # Assign tags to a task (replaces existing tags) kb setTaskTags '{"project_id": 1, "task_id": 42, "tags": ["bug", "urgent"]}'
Task Links (Internal)
# Get link types kb getAllLinks # Get links for a task kb getAllTaskLinks '{"task_id": 42}' # Create task link kb createTaskLink '{ "task_id": 42, "opposite_task_id": 55, "link_id": 1 }' # Common link_id: 1=relates to, 2=blocks, 3=is blocked by, 4=duplicates, 5=is duplicated by # Remove task link kb removeTaskLink '{"task_link_id": 8}'
Application
# Get app version kb getVersion # Get app timezone kb getTimezone # Get app default language kb getDefaultLanguage # Get current datetime kb now # Get available board column types kb getDefaultTaskColors
Common Workflows
Create project with full setup
# 1. Create project project_id=$(kb createProject '{"name":"Sprint 1"}' | jq '.result') # 2. Add columns kb addColumn "{\"project_id\": $project_id, \"title\": \"Backlog\"}" kb addColumn "{\"project_id\": $project_id, \"title\": \"In Progress\", \"task_limit\": 3}" kb addColumn "{\"project_id\": $project_id, \"title\": \"Review\"}" kb addColumn "{\"project_id\": $project_id, \"title\": \"Done\"}" # 3. Add swimlane kb addSwimlane "{\"project_id\": $project_id, \"name\": \"Team Alpha\"}" # 4. Show board kb getBoard "{\"project_id\": $project_id}"
Move task through workflow
task_id=42 project_id=1 # Get column IDs first columns=$(kb getColumns "{\"project_id\": $project_id}" | jq '.result') in_progress_col=$(echo $columns | jq '[.[] | select(.title=="In Progress")][0].id') # Move task kb moveTaskToColumn "{ \"project_id\": $project_id, \"task_id\": $task_id, \"column_id\": $in_progress_col, \"position\": 1 }"
Create task with subtasks
# Create parent task task_id=$(kb createTask '{ "title": "Implement feature X", "project_id": 1, "priority": 2 }' | jq '.result') # Add subtasks kb createSubtask "{\"task_id\": $task_id, \"title\": \"Write spec\"}" kb createSubtask "{\"task_id\": $task_id, \"title\": \"Implement\"}" kb createSubtask "{\"task_id\": $task_id, \"title\": \"Write tests\"}" kb createSubtask "{\"task_id\": $task_id, \"title\": \"Code review\"}"
Bulk close completed tasks
project_id=1 # Get all open tasks, close those tagged "done" kb getAllTasks "{\"project_id\": $project_id, \"status_id\": 1}" \ | jq -r '.result[] | select(.tags[]? == "done") | .id' \ | while read task_id; do kb closeTask "{\"task_id\": $task_id}" echo "Closed task $task_id" done
Error Handling
# Robust call wrapper kb_safe() { local result result=$(kb "$@") local error=$(echo "$result" | jq -r '.error // empty') if [ -n "$error" ]; then echo "❌ API Error: $(echo "$result" | jq -r '.error.message')" >&2 return 1 fi echo "$result" | jq '.result' } # Usage kb_safe getAllProjects kb_safe getTask '{"task_id": 99999}' # returns error if not found
Setup & Configuration
Add to your OpenClaw environment:
# Required export KANBOARD_URL="https://kanboard.example.com" export KANBOARD_API_TOKEN="your_token_from_settings_page" # Optional (for User API / "My…" procedures) export KANBOARD_USER="your_username" export KANBOARD_PASS="your_password_or_personal_token"
Getting your API token:
- Log in to Kanboard as admin
- Go to Settings → API
- Copy the token shown there
Personal API token (User API):
- Click your profile avatar → My Profile
- Click "Generate a new API token" in the API section
- Use as
with your username asKANBOARD_PASSKANBOARD_USER
Notes
- All dates use
format or Unix timestampsYYYY-MM-DD - Task
: 0=low, 1=normal, 2=high, 3=urgentpriority - Kanboard supports batch requests — multiple JSON-RPC calls in one HTTP request (useful for bulk ops)
for tasks: 1=open, 2=closedstatus_id- API endpoint is always
<KANBOARD_URL>/jsonrpc.php