Kanboard
Interact with Kanboard project management via JSON-RPC API. Use when working with Kanboard tasks, projects, boards, columns, swimlanes, comments, subtasks, a...
Like a lobster shell, security has layers — review code before you run it.
License
Runtime requirements
KANBOARD_URLrequiredKANBOARD_API_TOKENrequiredSKILL.md
Kanboard Skill
Overview
Kanboard uses JSON-RPC 2.0 over HTTP POST. All calls go to a single endpoint.
Make sure you have follow parameter to to access Kanboard:
- KANBOARD_URL, the server url.
- KANBOARD_API_TOKEN, the access api token.
Auth modes
Application API skips permission checks and has no session. Use it for automation.
Here is an example of curl:
curl "${KANBOARD_URL}/jsonrpc.php" -u "jsonrpc:$token" -H "Content-Type: application/json" -d "{\"jsonrpc\":\"2.0\",\"method\":\"$method\",\"id\":1,\"params\":$params}"
Core Helper
Always use this shell function to call the API:
kb() {
local method="$1"
local params="${2:-{}}"
local token="${KANBOARD_PASS:-$KANBOARD_API_TOKEN}"
curl -s -X POST \
-u "jsonrpc:$token" \
-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 moveTaskPosition "{
\"project_id\": $project_id,
\"task_id\": $task_id,
\"column_id\": $in_progress_col,
\"position\": 1,
\"swimlane_id\": 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
Setup & Configuration
Add to your OpenClaw environment:
# Required
export KANBOARD_URL="https://kanboard.example.com"
export KANBOARD_API_TOKEN="your_token_from_settings_page"
Getting your API token:
- Log in to Kanboard as admin
- Go to Settings → API
- Copy the token shown there
Notes
- Kanboard use Http basic auth, pass token by --user/-u parameter. You must not set token at http header.
- All dates use
YYYY-MM-DDformat or Unix timestamps - Task
priority: 0=low, 1=normal, 2=high, 3=urgent - Kanboard supports batch requests — multiple JSON-RPC calls in one HTTP request (useful for bulk ops)
status_idfor tasks: 1=open, 2=closed- API endpoint is always
<KANBOARD_URL>/jsonrpc.php
Files
1 totalComments
Loading comments…
