{
  "schemaVersion": "1.0",
  "item": {
    "slug": "kanboard-skill",
    "name": "Kanboard Skill",
    "source": "tencent",
    "type": "skill",
    "category": "开发工具",
    "sourceUrl": "https://clawhub.ai/bivex/kanboard-skill",
    "canonicalUrl": "https://clawhub.ai/bivex/kanboard-skill",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/kanboard-skill",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=kanboard-skill",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "SKILL.md"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-04-30T16:55:25.780Z",
      "expiresAt": "2026-05-07T16:55:25.780Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=network",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=network",
        "contentDisposition": "attachment; filename=\"network-1.0.0.zip\"",
        "redirectLocation": null,
        "bodySnippet": null
      },
      "scope": "source",
      "summary": "Source download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this source.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/kanboard-skill"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/kanboard-skill",
    "agentPageUrl": "https://openagent3.xyz/skills/kanboard-skill/agent",
    "manifestUrl": "https://openagent3.xyz/skills/kanboard-skill/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/kanboard-skill/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "Overview",
        "body": "Kanboard uses JSON-RPC 2.0 over HTTP POST. All calls go to a single endpoint."
      },
      {
        "title": "Auth modes",
        "body": "ModeUserPasswordApplication APIjsonrpc$KANBOARD_API_TOKENUser API$KANBOARD_USER$KANBOARD_PASS\n\nApplication API skips permission checks and has no session. Use it for automation.\nUser API respects project permissions; required for \"My…\" procedures."
      },
      {
        "title": "Core Helper",
        "body": "Always use this shell function to call the API:\n\nkb() {\n  local method=\"$1\"\n  local params=\"${2:-{}}\"\n  local user=\"${KANBOARD_USER:-jsonrpc}\"\n  local pass=\"${KANBOARD_PASS:-$KANBOARD_API_TOKEN}\"\n\n  curl -s -X POST \\\n    -u \"$user:$pass\" \\\n    -H \"Content-Type: application/json\" \\\n    -d \"{\\\"jsonrpc\\\":\\\"2.0\\\",\\\"method\\\":\\\"$method\\\",\\\"id\\\":1,\\\"params\\\":$params}\" \\\n    \"${KANBOARD_URL}/jsonrpc.php\" | jq .\n}\n\nCheck for errors in every response:\n\n# Always verify result is not null/false\nresult=$(kb getMe | jq '.result')\nif [ \"$result\" = \"null\" ] || [ \"$result\" = \"false\" ]; then\n  echo \"Error: $(kb getMe | jq -r '.error.message // \"unknown error\"')\"\nfi"
      },
      {
        "title": "Projects",
        "body": "# List all projects\nkb getAllProjects\n\n# Get single project by ID\nkb getProjectById '{\"project_id\": 1}'\n\n# Get project by name\nkb getProjectByName '{\"name\": \"My Project\"}'\n\n# Create project\nkb createProject '{\"name\": \"New Project\", \"description\": \"Optional description\"}'\n\n# Update project\nkb updateProject '{\"id\": 1, \"name\": \"Renamed\", \"description\": \"Updated\"}'\n\n# Remove project (irreversible)\nkb removeProject '{\"project_id\": 1}'\n\n# Enable / disable project\nkb enableProject  '{\"project_id\": 1}'\nkb disableProject '{\"project_id\": 1}'\n\n# Get project activity feed\nkb getProjectActivity '{\"project_id\": 1}'"
      },
      {
        "title": "Board & Columns",
        "body": "# Get full board (columns + tasks) for a project\nkb getBoard '{\"project_id\": 1}'\n\n# List columns\nkb getColumns '{\"project_id\": 1}'\n\n# Get single column\nkb getColumn '{\"column_id\": 5}'\n\n# Create column\nkb addColumn '{\"project_id\": 1, \"title\": \"In Review\", \"task_limit\": 3}'\n\n# Update column\nkb updateColumn '{\"column_id\": 5, \"title\": \"Review\", \"task_limit\": 5}'\n\n# Remove column\nkb removeColumn '{\"column_id\": 5}'\n\n# Change column position\nkb changeColumnPosition '{\"project_id\": 1, \"column_id\": 5, \"position\": 2}'"
      },
      {
        "title": "Tasks",
        "body": "# Create task (minimum required: title + project_id)\nkb createTask '{\n  \"title\":      \"Fix login bug\",\n  \"project_id\": 1,\n  \"column_id\":  2,\n  \"swimlane_id\": 1,\n  \"color_id\":   \"red\",\n  \"priority\":   2,\n  \"due_date\":   \"2025-12-31\",\n  \"description\": \"Detailed description here\",\n  \"owner_id\":   3,\n  \"tags\":       [\"bug\", \"urgent\"]\n}'\n\n# Get task by ID\nkb getTask '{\"task_id\": 42}'\n\n# Get task by reference (external ref)\nkb getTaskByReference '{\"project_id\": 1, \"reference\": \"EXT-123\"}'\n\n# List all tasks in a project (status: 1=open, 2=closed)\nkb getAllTasks '{\"project_id\": 1, \"status_id\": 1}'\n\n# Search tasks with advanced query\nkb searchTasks '{\"project_id\": 1, \"query\": \"assignee:me status:open\"}'\n\n# Update task\nkb updateTask '{\n  \"id\":         42,\n  \"title\":      \"Fix login bug (updated)\",\n  \"column_id\":  3,\n  \"color_id\":   \"green\",\n  \"priority\":   1,\n  \"due_date\":   \"2025-11-30\"\n}'\n\n# Move task to another column/swimlane/position\nkb moveTaskToColumn '{\n  \"project_id\":  1,\n  \"task_id\":     42,\n  \"column_id\":   3,\n  \"position\":    1,\n  \"swimlane_id\": 1\n}'\n\n# Move task to another project\nkb moveTaskToProject '{\n  \"task_id\":        42,\n  \"project_id\":     2,\n  \"swimlane_id\":    1,\n  \"column_id\":      1,\n  \"category_id\":    0\n}'\n\n# Duplicate task to another project\nkb duplicateTaskToProject '{\n  \"task_id\":    42,\n  \"project_id\": 2\n}'\n\n# Close / Open task\nkb closeTask '{\"task_id\": 42}'\nkb openTask  '{\"task_id\": 42}'\n\n# Remove task (irreversible)\nkb removeTask '{\"task_id\": 42}'\n\n# Get task color list\nkb getTaskColors"
      },
      {
        "title": "Task color IDs",
        "body": "yellow, blue, green, purple, red, orange, grey, brown, deep_orange, dark_grey, pink, teal, cyan, lime, light_green, amber"
      },
      {
        "title": "Subtasks",
        "body": "# List subtasks for a task\nkb getAllSubtasks '{\"task_id\": 42}'\n\n# Create subtask\nkb createSubtask '{\n  \"task_id\":  42,\n  \"title\":    \"Write unit tests\",\n  \"user_id\":  3,\n  \"time_estimated\": 4\n}'\n\n# Update subtask (status: 0=todo, 1=in-progress, 2=done)\nkb updateSubtask '{\n  \"id\":      10,\n  \"task_id\": 42,\n  \"status\":  1,\n  \"time_spent\": 2\n}'\n\n# Remove subtask\nkb removeSubtask '{\"subtask_id\": 10}'"
      },
      {
        "title": "Comments",
        "body": "# List comments for a task\nkb getAllComments '{\"task_id\": 42}'\n\n# Create comment\nkb createComment '{\n  \"task_id\": 42,\n  \"user_id\": 1,\n  \"content\": \"This is a **markdown** comment.\"\n}'\n\n# Update comment\nkb updateComment '{\"id\": 7, \"content\": \"Updated comment text.\"}'\n\n# Remove comment\nkb removeComment '{\"comment_id\": 7}'"
      },
      {
        "title": "Swimlanes",
        "body": "# List swimlanes for a project\nkb getSwimlanes '{\"project_id\": 1}'\n\n# Get active swimlanes only\nkb getActiveSwimlanes '{\"project_id\": 1}'\n\n# Create swimlane\nkb addSwimlane '{\"project_id\": 1, \"name\": \"Team Alpha\"}'\n\n# Update swimlane\nkb updateSwimlane '{\"swimlane_id\": 3, \"name\": \"Team Beta\"}'\n\n# Remove swimlane\nkb removeSwimlane '{\"project_id\": 1, \"swimlane_id\": 3}'\n\n# Change swimlane position\nkb changeSwimlanePosition '{\"project_id\": 1, \"swimlane_id\": 3, \"position\": 1}'"
      },
      {
        "title": "Categories",
        "body": "# List categories for a project\nkb getAllCategories '{\"project_id\": 1}'\n\n# Create category\nkb createCategory '{\"project_id\": 1, \"name\": \"Backend\"}'\n\n# Update category\nkb updateCategory '{\"id\": 5, \"name\": \"Backend & API\"}'\n\n# Remove category\nkb removeCategory '{\"category_id\": 5}'"
      },
      {
        "title": "Users",
        "body": "# List all users (Application API only)\nkb getAllUsers\n\n# Get user by ID\nkb getUserById '{\"user_id\": 3}'\n\n# Get user by username\nkb getUserByName '{\"username\": \"alice\"}'\n\n# Create user\nkb createUser '{\n  \"username\": \"bob\",\n  \"password\": \"S3cur3P@ss\",\n  \"name\":     \"Bob Smith\",\n  \"email\":    \"bob@example.com\",\n  \"role\":     \"app-user\"\n}'\n# Roles: app-admin | app-manager | app-user\n\n# Update user\nkb updateUser '{\"id\": 3, \"name\": \"Bob Jones\", \"email\": \"bob.jones@example.com\"}'\n\n# Disable / Enable user\nkb disableUser '{\"user_id\": 3}'\nkb enableUser  '{\"user_id\": 3}'\n\n# Remove user\nkb removeUser '{\"user_id\": 3}'\n\n# Current user (User API only)\nkb getMe\nkb getMyProjects\nkb getMyDashboard\nkb getMyActivityStream\nkb getMyCalendar\nkb getMyNotifications"
      },
      {
        "title": "Project Permissions",
        "body": "# List project users\nkb getProjectUsers '{\"project_id\": 1}'\n\n# Add user to project\nkb addProjectUser '{\n  \"project_id\": 1,\n  \"user_id\":    3,\n  \"role\":       \"project-member\"\n}'\n# Roles: project-manager | project-member | project-viewer\n\n# Change user role in project\nkb changeProjectUserRole '{\"project_id\": 1, \"user_id\": 3, \"role\": \"project-manager\"}'\n\n# Remove user from project\nkb removeProjectUser '{\"project_id\": 1, \"user_id\": 3}'\n\n# Add/remove group to project\nkb addProjectGroup    '{\"project_id\": 1, \"group_id\": 2, \"role\": \"project-member\"}'\nkb removeProjectGroup '{\"project_id\": 1, \"group_id\": 2}'"
      },
      {
        "title": "Tags",
        "body": "# Get all tags for a project\nkb getTagsByProject '{\"project_id\": 1}'\n\n# Create tag\nkb createTag '{\"project_id\": 1, \"tag\": \"urgent\"}'\n\n# Update tag\nkb updateTag '{\"id\": 4, \"tag\": \"critical\"}'\n\n# Remove tag\nkb removeTag '{\"tag_id\": 4}'\n\n# Get tags for a task\nkb getTaskTags '{\"task_id\": 42}'\n\n# Assign tags to a task (replaces existing tags)\nkb setTaskTags '{\"project_id\": 1, \"task_id\": 42, \"tags\": [\"bug\", \"urgent\"]}'"
      },
      {
        "title": "Task Links (Internal)",
        "body": "# Get link types\nkb getAllLinks\n\n# Get links for a task\nkb getAllTaskLinks '{\"task_id\": 42}'\n\n# Create task link\nkb createTaskLink '{\n  \"task_id\":        42,\n  \"opposite_task_id\": 55,\n  \"link_id\":        1\n}'\n# Common link_id: 1=relates to, 2=blocks, 3=is blocked by, 4=duplicates, 5=is duplicated by\n\n# Remove task link\nkb removeTaskLink '{\"task_link_id\": 8}'"
      },
      {
        "title": "Application",
        "body": "# Get app version\nkb getVersion\n\n# Get app timezone\nkb getTimezone\n\n# Get app default language\nkb getDefaultLanguage\n\n# Get current datetime\nkb now\n\n# Get available board column types\nkb getDefaultTaskColors"
      },
      {
        "title": "Create project with full setup",
        "body": "# 1. Create project\nproject_id=$(kb createProject '{\"name\":\"Sprint 1\"}' | jq '.result')\n\n# 2. Add columns\nkb addColumn \"{\\\"project_id\\\": $project_id, \\\"title\\\": \\\"Backlog\\\"}\"\nkb addColumn \"{\\\"project_id\\\": $project_id, \\\"title\\\": \\\"In Progress\\\", \\\"task_limit\\\": 3}\"\nkb addColumn \"{\\\"project_id\\\": $project_id, \\\"title\\\": \\\"Review\\\"}\"\nkb addColumn \"{\\\"project_id\\\": $project_id, \\\"title\\\": \\\"Done\\\"}\"\n\n# 3. Add swimlane\nkb addSwimlane \"{\\\"project_id\\\": $project_id, \\\"name\\\": \\\"Team Alpha\\\"}\"\n\n# 4. Show board\nkb getBoard \"{\\\"project_id\\\": $project_id}\""
      },
      {
        "title": "Move task through workflow",
        "body": "task_id=42\nproject_id=1\n\n# Get column IDs first\ncolumns=$(kb getColumns \"{\\\"project_id\\\": $project_id}\" | jq '.result')\nin_progress_col=$(echo $columns | jq '[.[] | select(.title==\"In Progress\")][0].id')\n\n# Move task\nkb moveTaskToColumn \"{\n  \\\"project_id\\\": $project_id,\n  \\\"task_id\\\":    $task_id,\n  \\\"column_id\\\":  $in_progress_col,\n  \\\"position\\\":   1\n}\""
      },
      {
        "title": "Create task with subtasks",
        "body": "# Create parent task\ntask_id=$(kb createTask '{\n  \"title\":      \"Implement feature X\",\n  \"project_id\": 1,\n  \"priority\":   2\n}' | jq '.result')\n\n# Add subtasks\nkb createSubtask \"{\\\"task_id\\\": $task_id, \\\"title\\\": \\\"Write spec\\\"}\"\nkb createSubtask \"{\\\"task_id\\\": $task_id, \\\"title\\\": \\\"Implement\\\"}\"\nkb createSubtask \"{\\\"task_id\\\": $task_id, \\\"title\\\": \\\"Write tests\\\"}\"\nkb createSubtask \"{\\\"task_id\\\": $task_id, \\\"title\\\": \\\"Code review\\\"}\""
      },
      {
        "title": "Bulk close completed tasks",
        "body": "project_id=1\n\n# Get all open tasks, close those tagged \"done\"\nkb getAllTasks \"{\\\"project_id\\\": $project_id, \\\"status_id\\\": 1}\" \\\n  | jq -r '.result[] | select(.tags[]? == \"done\") | .id' \\\n  | while read task_id; do\n      kb closeTask \"{\\\"task_id\\\": $task_id}\"\n      echo \"Closed task $task_id\"\n    done"
      },
      {
        "title": "Error Handling",
        "body": "# Robust call wrapper\nkb_safe() {\n  local result\n  result=$(kb \"$@\")\n  local error=$(echo \"$result\" | jq -r '.error // empty')\n  if [ -n \"$error\" ]; then\n    echo \"❌ API Error: $(echo \"$result\" | jq -r '.error.message')\" >&2\n    return 1\n  fi\n  echo \"$result\" | jq '.result'\n}\n\n# Usage\nkb_safe getAllProjects\nkb_safe getTask '{\"task_id\": 99999}'  # returns error if not found"
      },
      {
        "title": "Setup & Configuration",
        "body": "Add to your OpenClaw environment:\n\n# Required\nexport KANBOARD_URL=\"https://kanboard.example.com\"\nexport KANBOARD_API_TOKEN=\"your_token_from_settings_page\"\n\n# Optional (for User API / \"My…\" procedures)\nexport KANBOARD_USER=\"your_username\"\nexport KANBOARD_PASS=\"your_password_or_personal_token\"\n\nGetting your API token:\n\nLog in to Kanboard as admin\nGo to Settings → API\nCopy the token shown there\n\nPersonal API token (User API):\n\nClick your profile avatar → My Profile\nClick \"Generate a new API token\" in the API section\nUse as KANBOARD_PASS with your username as KANBOARD_USER"
      },
      {
        "title": "Notes",
        "body": "All dates use YYYY-MM-DD format or Unix timestamps\nTask priority: 0=low, 1=normal, 2=high, 3=urgent\nKanboard supports batch requests — multiple JSON-RPC calls in one HTTP request (useful for bulk ops)\nstatus_id for tasks: 1=open, 2=closed\nAPI endpoint is always <KANBOARD_URL>/jsonrpc.php"
      }
    ],
    "body": "Kanboard Skill\nOverview\n\nKanboard uses JSON-RPC 2.0 over HTTP POST. All calls go to a single endpoint.\n\nAuth modes\nMode\tUser\tPassword\nApplication API\tjsonrpc\t$KANBOARD_API_TOKEN\nUser API\t$KANBOARD_USER\t$KANBOARD_PASS\n\nApplication API skips permission checks and has no session. Use it for automation. User API respects project permissions; required for \"My…\" procedures.\n\nCore Helper\n\nAlways use this shell function to call the API:\n\nkb() {\n  local method=\"$1\"\n  local params=\"${2:-{}}\"\n  local user=\"${KANBOARD_USER:-jsonrpc}\"\n  local pass=\"${KANBOARD_PASS:-$KANBOARD_API_TOKEN}\"\n\n  curl -s -X POST \\\n    -u \"$user:$pass\" \\\n    -H \"Content-Type: application/json\" \\\n    -d \"{\\\"jsonrpc\\\":\\\"2.0\\\",\\\"method\\\":\\\"$method\\\",\\\"id\\\":1,\\\"params\\\":$params}\" \\\n    \"${KANBOARD_URL}/jsonrpc.php\" | jq .\n}\n\n\nCheck for errors in every response:\n\n# Always verify result is not null/false\nresult=$(kb getMe | jq '.result')\nif [ \"$result\" = \"null\" ] || [ \"$result\" = \"false\" ]; then\n  echo \"Error: $(kb getMe | jq -r '.error.message // \"unknown error\"')\"\nfi\n\nProjects\n# List all projects\nkb getAllProjects\n\n# Get single project by ID\nkb getProjectById '{\"project_id\": 1}'\n\n# Get project by name\nkb getProjectByName '{\"name\": \"My Project\"}'\n\n# Create project\nkb createProject '{\"name\": \"New Project\", \"description\": \"Optional description\"}'\n\n# Update project\nkb updateProject '{\"id\": 1, \"name\": \"Renamed\", \"description\": \"Updated\"}'\n\n# Remove project (irreversible)\nkb removeProject '{\"project_id\": 1}'\n\n# Enable / disable project\nkb enableProject  '{\"project_id\": 1}'\nkb disableProject '{\"project_id\": 1}'\n\n# Get project activity feed\nkb getProjectActivity '{\"project_id\": 1}'\n\nBoard & Columns\n# Get full board (columns + tasks) for a project\nkb getBoard '{\"project_id\": 1}'\n\n# List columns\nkb getColumns '{\"project_id\": 1}'\n\n# Get single column\nkb getColumn '{\"column_id\": 5}'\n\n# Create column\nkb addColumn '{\"project_id\": 1, \"title\": \"In Review\", \"task_limit\": 3}'\n\n# Update column\nkb updateColumn '{\"column_id\": 5, \"title\": \"Review\", \"task_limit\": 5}'\n\n# Remove column\nkb removeColumn '{\"column_id\": 5}'\n\n# Change column position\nkb changeColumnPosition '{\"project_id\": 1, \"column_id\": 5, \"position\": 2}'\n\nTasks\n# Create task (minimum required: title + project_id)\nkb createTask '{\n  \"title\":      \"Fix login bug\",\n  \"project_id\": 1,\n  \"column_id\":  2,\n  \"swimlane_id\": 1,\n  \"color_id\":   \"red\",\n  \"priority\":   2,\n  \"due_date\":   \"2025-12-31\",\n  \"description\": \"Detailed description here\",\n  \"owner_id\":   3,\n  \"tags\":       [\"bug\", \"urgent\"]\n}'\n\n# Get task by ID\nkb getTask '{\"task_id\": 42}'\n\n# Get task by reference (external ref)\nkb getTaskByReference '{\"project_id\": 1, \"reference\": \"EXT-123\"}'\n\n# List all tasks in a project (status: 1=open, 2=closed)\nkb getAllTasks '{\"project_id\": 1, \"status_id\": 1}'\n\n# Search tasks with advanced query\nkb searchTasks '{\"project_id\": 1, \"query\": \"assignee:me status:open\"}'\n\n# Update task\nkb updateTask '{\n  \"id\":         42,\n  \"title\":      \"Fix login bug (updated)\",\n  \"column_id\":  3,\n  \"color_id\":   \"green\",\n  \"priority\":   1,\n  \"due_date\":   \"2025-11-30\"\n}'\n\n# Move task to another column/swimlane/position\nkb moveTaskToColumn '{\n  \"project_id\":  1,\n  \"task_id\":     42,\n  \"column_id\":   3,\n  \"position\":    1,\n  \"swimlane_id\": 1\n}'\n\n# Move task to another project\nkb moveTaskToProject '{\n  \"task_id\":        42,\n  \"project_id\":     2,\n  \"swimlane_id\":    1,\n  \"column_id\":      1,\n  \"category_id\":    0\n}'\n\n# Duplicate task to another project\nkb duplicateTaskToProject '{\n  \"task_id\":    42,\n  \"project_id\": 2\n}'\n\n# Close / Open task\nkb closeTask '{\"task_id\": 42}'\nkb openTask  '{\"task_id\": 42}'\n\n# Remove task (irreversible)\nkb removeTask '{\"task_id\": 42}'\n\n# Get task color list\nkb getTaskColors\n\nTask color IDs\n\nyellow, blue, green, purple, red, orange, grey, brown, deep_orange, dark_grey, pink, teal, cyan, lime, light_green, amber\n\nSubtasks\n# List subtasks for a task\nkb getAllSubtasks '{\"task_id\": 42}'\n\n# Create subtask\nkb createSubtask '{\n  \"task_id\":  42,\n  \"title\":    \"Write unit tests\",\n  \"user_id\":  3,\n  \"time_estimated\": 4\n}'\n\n# Update subtask (status: 0=todo, 1=in-progress, 2=done)\nkb updateSubtask '{\n  \"id\":      10,\n  \"task_id\": 42,\n  \"status\":  1,\n  \"time_spent\": 2\n}'\n\n# Remove subtask\nkb removeSubtask '{\"subtask_id\": 10}'\n\nComments\n# List comments for a task\nkb getAllComments '{\"task_id\": 42}'\n\n# Create comment\nkb createComment '{\n  \"task_id\": 42,\n  \"user_id\": 1,\n  \"content\": \"This is a **markdown** comment.\"\n}'\n\n# Update comment\nkb updateComment '{\"id\": 7, \"content\": \"Updated comment text.\"}'\n\n# Remove comment\nkb removeComment '{\"comment_id\": 7}'\n\nSwimlanes\n# List swimlanes for a project\nkb getSwimlanes '{\"project_id\": 1}'\n\n# Get active swimlanes only\nkb getActiveSwimlanes '{\"project_id\": 1}'\n\n# Create swimlane\nkb addSwimlane '{\"project_id\": 1, \"name\": \"Team Alpha\"}'\n\n# Update swimlane\nkb updateSwimlane '{\"swimlane_id\": 3, \"name\": \"Team Beta\"}'\n\n# Remove swimlane\nkb removeSwimlane '{\"project_id\": 1, \"swimlane_id\": 3}'\n\n# Change swimlane position\nkb changeSwimlanePosition '{\"project_id\": 1, \"swimlane_id\": 3, \"position\": 1}'\n\nCategories\n# List categories for a project\nkb getAllCategories '{\"project_id\": 1}'\n\n# Create category\nkb createCategory '{\"project_id\": 1, \"name\": \"Backend\"}'\n\n# Update category\nkb updateCategory '{\"id\": 5, \"name\": \"Backend & API\"}'\n\n# Remove category\nkb removeCategory '{\"category_id\": 5}'\n\nUsers\n# List all users (Application API only)\nkb getAllUsers\n\n# Get user by ID\nkb getUserById '{\"user_id\": 3}'\n\n# Get user by username\nkb getUserByName '{\"username\": \"alice\"}'\n\n# Create user\nkb createUser '{\n  \"username\": \"bob\",\n  \"password\": \"S3cur3P@ss\",\n  \"name\":     \"Bob Smith\",\n  \"email\":    \"bob@example.com\",\n  \"role\":     \"app-user\"\n}'\n# Roles: app-admin | app-manager | app-user\n\n# Update user\nkb updateUser '{\"id\": 3, \"name\": \"Bob Jones\", \"email\": \"bob.jones@example.com\"}'\n\n# Disable / Enable user\nkb disableUser '{\"user_id\": 3}'\nkb enableUser  '{\"user_id\": 3}'\n\n# Remove user\nkb removeUser '{\"user_id\": 3}'\n\n# Current user (User API only)\nkb getMe\nkb getMyProjects\nkb getMyDashboard\nkb getMyActivityStream\nkb getMyCalendar\nkb getMyNotifications\n\nProject Permissions\n# List project users\nkb getProjectUsers '{\"project_id\": 1}'\n\n# Add user to project\nkb addProjectUser '{\n  \"project_id\": 1,\n  \"user_id\":    3,\n  \"role\":       \"project-member\"\n}'\n# Roles: project-manager | project-member | project-viewer\n\n# Change user role in project\nkb changeProjectUserRole '{\"project_id\": 1, \"user_id\": 3, \"role\": \"project-manager\"}'\n\n# Remove user from project\nkb removeProjectUser '{\"project_id\": 1, \"user_id\": 3}'\n\n# Add/remove group to project\nkb addProjectGroup    '{\"project_id\": 1, \"group_id\": 2, \"role\": \"project-member\"}'\nkb removeProjectGroup '{\"project_id\": 1, \"group_id\": 2}'\n\nTags\n# Get all tags for a project\nkb getTagsByProject '{\"project_id\": 1}'\n\n# Create tag\nkb createTag '{\"project_id\": 1, \"tag\": \"urgent\"}'\n\n# Update tag\nkb updateTag '{\"id\": 4, \"tag\": \"critical\"}'\n\n# Remove tag\nkb removeTag '{\"tag_id\": 4}'\n\n# Get tags for a task\nkb getTaskTags '{\"task_id\": 42}'\n\n# Assign tags to a task (replaces existing tags)\nkb setTaskTags '{\"project_id\": 1, \"task_id\": 42, \"tags\": [\"bug\", \"urgent\"]}'\n\nTask Links (Internal)\n# Get link types\nkb getAllLinks\n\n# Get links for a task\nkb getAllTaskLinks '{\"task_id\": 42}'\n\n# Create task link\nkb createTaskLink '{\n  \"task_id\":        42,\n  \"opposite_task_id\": 55,\n  \"link_id\":        1\n}'\n# Common link_id: 1=relates to, 2=blocks, 3=is blocked by, 4=duplicates, 5=is duplicated by\n\n# Remove task link\nkb removeTaskLink '{\"task_link_id\": 8}'\n\nApplication\n# Get app version\nkb getVersion\n\n# Get app timezone\nkb getTimezone\n\n# Get app default language\nkb getDefaultLanguage\n\n# Get current datetime\nkb now\n\n# Get available board column types\nkb getDefaultTaskColors\n\nCommon Workflows\nCreate project with full setup\n# 1. Create project\nproject_id=$(kb createProject '{\"name\":\"Sprint 1\"}' | jq '.result')\n\n# 2. Add columns\nkb addColumn \"{\\\"project_id\\\": $project_id, \\\"title\\\": \\\"Backlog\\\"}\"\nkb addColumn \"{\\\"project_id\\\": $project_id, \\\"title\\\": \\\"In Progress\\\", \\\"task_limit\\\": 3}\"\nkb addColumn \"{\\\"project_id\\\": $project_id, \\\"title\\\": \\\"Review\\\"}\"\nkb addColumn \"{\\\"project_id\\\": $project_id, \\\"title\\\": \\\"Done\\\"}\"\n\n# 3. Add swimlane\nkb addSwimlane \"{\\\"project_id\\\": $project_id, \\\"name\\\": \\\"Team Alpha\\\"}\"\n\n# 4. Show board\nkb getBoard \"{\\\"project_id\\\": $project_id}\"\n\nMove task through workflow\ntask_id=42\nproject_id=1\n\n# Get column IDs first\ncolumns=$(kb getColumns \"{\\\"project_id\\\": $project_id}\" | jq '.result')\nin_progress_col=$(echo $columns | jq '[.[] | select(.title==\"In Progress\")][0].id')\n\n# Move task\nkb moveTaskToColumn \"{\n  \\\"project_id\\\": $project_id,\n  \\\"task_id\\\":    $task_id,\n  \\\"column_id\\\":  $in_progress_col,\n  \\\"position\\\":   1\n}\"\n\nCreate task with subtasks\n# Create parent task\ntask_id=$(kb createTask '{\n  \"title\":      \"Implement feature X\",\n  \"project_id\": 1,\n  \"priority\":   2\n}' | jq '.result')\n\n# Add subtasks\nkb createSubtask \"{\\\"task_id\\\": $task_id, \\\"title\\\": \\\"Write spec\\\"}\"\nkb createSubtask \"{\\\"task_id\\\": $task_id, \\\"title\\\": \\\"Implement\\\"}\"\nkb createSubtask \"{\\\"task_id\\\": $task_id, \\\"title\\\": \\\"Write tests\\\"}\"\nkb createSubtask \"{\\\"task_id\\\": $task_id, \\\"title\\\": \\\"Code review\\\"}\"\n\nBulk close completed tasks\nproject_id=1\n\n# Get all open tasks, close those tagged \"done\"\nkb getAllTasks \"{\\\"project_id\\\": $project_id, \\\"status_id\\\": 1}\" \\\n  | jq -r '.result[] | select(.tags[]? == \"done\") | .id' \\\n  | while read task_id; do\n      kb closeTask \"{\\\"task_id\\\": $task_id}\"\n      echo \"Closed task $task_id\"\n    done\n\nError Handling\n# Robust call wrapper\nkb_safe() {\n  local result\n  result=$(kb \"$@\")\n  local error=$(echo \"$result\" | jq -r '.error // empty')\n  if [ -n \"$error\" ]; then\n    echo \"❌ API Error: $(echo \"$result\" | jq -r '.error.message')\" >&2\n    return 1\n  fi\n  echo \"$result\" | jq '.result'\n}\n\n# Usage\nkb_safe getAllProjects\nkb_safe getTask '{\"task_id\": 99999}'  # returns error if not found\n\nSetup & Configuration\n\nAdd to your OpenClaw environment:\n\n# Required\nexport KANBOARD_URL=\"https://kanboard.example.com\"\nexport KANBOARD_API_TOKEN=\"your_token_from_settings_page\"\n\n# Optional (for User API / \"My…\" procedures)\nexport KANBOARD_USER=\"your_username\"\nexport KANBOARD_PASS=\"your_password_or_personal_token\"\n\n\nGetting your API token:\n\nLog in to Kanboard as admin\nGo to Settings → API\nCopy the token shown there\n\nPersonal API token (User API):\n\nClick your profile avatar → My Profile\nClick \"Generate a new API token\" in the API section\nUse as KANBOARD_PASS with your username as KANBOARD_USER\nNotes\nAll dates use YYYY-MM-DD format or Unix timestamps\nTask priority: 0=low, 1=normal, 2=high, 3=urgent\nKanboard supports batch requests — multiple JSON-RPC calls in one HTTP request (useful for bulk ops)\nstatus_id for tasks: 1=open, 2=closed\nAPI endpoint is always <KANBOARD_URL>/jsonrpc.php"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/bivex/kanboard-skill",
    "publisherUrl": "https://clawhub.ai/bivex/kanboard-skill",
    "owner": "bivex",
    "version": "1.0.0",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/kanboard-skill",
    "downloadUrl": "https://openagent3.xyz/downloads/kanboard-skill",
    "agentUrl": "https://openagent3.xyz/skills/kanboard-skill/agent",
    "manifestUrl": "https://openagent3.xyz/skills/kanboard-skill/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/kanboard-skill/agent.md"
  }
}