# kanban

> File-backed kanban board — tickets, threaded comments, agent assignment, the kanban:change and kanban:comment trigger types, and an injectable console board with agent profiles for planning and review.

| field | value |
|-------|-------|
| version | 0.1.7 |
| type | binary |
| license | Apache-2.0 |
| repo | https://github.com/iii-hq/workers |
| supported_targets | * |
| author | iii |

## installation

```sh
iii trigger compose::add worker=kanban@0.1.7
```

## dependencies

- `console` @ `^1.9.11`
- `harness` @ `^1.8.5`
- `state` @ `^0.22.2`
- `worktree` @ `^0.3.4-rc.1`

## readme

# kanban

Repository-aware multi-worker runs in the Console. The **Kanban** page combines
a root Harness session, native or external child executors, dependency gates,
isolated Git worktrees, review, and explicit landing in one Kanban board.
Existing Harness conversations with child sessions appear automatically, while
runs created from Kanban receive a real root session so every task remains
visible in the Console's native conversation hierarchy.

Harness and the session manager remain the execution source of truth. Kanban
stores only run definitions, task dispatch metadata, dependencies, workspace
references, and review decisions. The worktree Worker owns Git lifecycle and
status. Reactive triggers keep the page current without another scheduler.

## Install

```bash
iii compose add kanban
```

The page appears in the Console as **Kanban** (`#/ext/kanban`). It discovers
available executors from the live function registry. Harness is supported
natively; workers that expose a `::task` function using the durable
`agent_tasks` result contract are added automatically.

## What the page controls

- Select any live run and open its root Harness conversation.
- Create up to 24 tasks in one run and choose an executor for each task.
- Give every task its own managed worktree and branch, or use one shared directory.
- Gate tasks on reviewed prerequisites, then dispatch them automatically.
- Mix native Harness agents with external task-contract executors under one root.
- Dispatch immediately or hold tasks in Ready.
- Open the child session or a Shell rooted in the task worktree.
- Stop supported running tasks, retry failed tasks, and accept reviewed work.
- Inspect live Git status and explicitly queue reviewed work for serialized landing.
- Observe existing parent and child Harness sessions without importing or
  duplicating them.

## Functions

| Function | Purpose |
|---|---|
| `kanban::board` | Return runs, tasks, executor topology, managed-worktree Git status, and capabilities. |
| `kanban::executors::list` | List currently available Harness and task-contract executors. |
| `kanban::runs::create` | Create a root session plus one or more durable tasks, optionally dispatching them immediately. |
| `kanban::tasks::dispatch` | Dispatch a Ready or attention-blocked task. |
| `kanban::tasks::retry` | Retry an attention-blocked task, preserving the claimed session for a managed worktree. |
| `kanban::tasks::stop` | Stop a running task when its executor exposes a stop function. |
| `kanban::tasks::accept` | Move a reviewed task to Done. |
| `kanban::tasks::land` | Queue a reviewed task's worktree for tested, serialized landing. |

## Reactive updates

Bind `kanban::changed` with an empty config and re-read `kanban::board` when it
fires. The trigger is emitted for Kanban state writes and relevant session
creation, status, and metadata events.

```ts
iii.registerTrigger({
  type: 'kanban::changed',
  function_id: 'my-worker::on-kanban-change',
  config: {},
})
```

## Run from source

```bash
pnpm install
pnpm test
pnpm typecheck
pnpm build
III_URL=ws://127.0.0.1:49134 III_NAMESPACE=my-project pnpm start
```

A standalone process must use the same namespace as the Console and Harness.
Set `III_KANBAN_UI_WATCH=1` to serve page assets from `ui/dist` while developing
the injected UI.

## api reference

```json
{
  "functions": [
    {
      "description": "Project Harness session trees, executor topology, managed worktrees, and Git status into durable runs.",
      "metadata": {},
      "name": "kanban::board",
      "request_schema": {
        "properties": {},
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "capabilities": {
            "properties": {},
            "type": "object"
          },
          "executors": {
            "items": {
              "properties": {},
              "type": "object"
            },
            "type": "array"
          },
          "models": {
            "items": {
              "properties": {},
              "type": "object"
            },
            "type": "array"
          },
          "runs": {
            "items": {
              "properties": {},
              "type": "object"
            },
            "type": "array"
          },
          "tasks": {
            "items": {
              "properties": {},
              "type": "object"
            },
            "type": "array"
          }
        },
        "required": [
          "runs",
          "tasks",
          "executors",
          "models",
          "capabilities"
        ],
        "type": "object"
      }
    },
    {
      "description": "List live executors that satisfy the Kanban task contract, including Harness when available.",
      "metadata": {},
      "name": "kanban::executors::list",
      "request_schema": {
        "properties": {},
        "type": "object"
      },
      "response_schema": {
        "items": {
          "properties": {},
          "type": "object"
        },
        "type": "array"
      }
    },
    {
      "description": "List live tool-capable models usable by top-level Harness child tasks.",
      "metadata": {},
      "name": "kanban::models::list",
      "request_schema": {
        "properties": {},
        "type": "object"
      },
      "response_schema": {
        "items": {
          "properties": {},
          "type": "object"
        },
        "type": "array"
      }
    },
    {
      "description": "Internal completion sink for task-contract executors.",
      "metadata": {
        "internal": true
      },
      "name": "kanban::on-agent-task",
      "request_schema": {
        "properties": {},
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "status": {
            "type": "string"
          },
          "task_id": {
            "type": "string"
          },
          "updated": {
            "type": "boolean"
          }
        },
        "required": [
          "updated"
        ],
        "type": "object"
      }
    },
    {
      "description": "Internal completion sink for Harness tasks.",
      "metadata": {
        "internal": true
      },
      "name": "kanban::on-harness-completed",
      "request_schema": {
        "properties": {},
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "status": {
            "type": "string"
          },
          "task_id": {
            "type": "string"
          },
          "updated": {
            "type": "boolean"
          }
        },
        "required": [
          "updated"
        ],
        "type": "object"
      }
    },
    {
      "description": "Internal refresh sink for Harness session-tree changes.",
      "metadata": {
        "internal": true
      },
      "name": "kanban::on-session-changed",
      "request_schema": {
        "properties": {},
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "updated": {
            "type": "boolean"
          }
        },
        "required": [
          "updated"
        ],
        "type": "object"
      }
    },
    {
      "description": "Internal refresh sink for managed worktree landing outcomes.",
      "metadata": {
        "internal": true
      },
      "name": "kanban::on-worktree-changed",
      "request_schema": {
        "properties": {},
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "land_status": {
            "type": "string"
          },
          "task_id": {
            "type": "string"
          },
          "updated": {
            "type": "boolean"
          }
        },
        "required": [
          "updated"
        ],
        "type": "object"
      }
    },
    {
      "description": "Create a durable run with one or more tasks and optionally dispatch them immediately.",
      "metadata": {},
      "name": "kanban::runs::create",
      "request_schema": {
        "properties": {
          "auto_dispatch": {
            "type": "boolean"
          },
          "base_ref": {
            "type": [
              "string",
              "null"
            ]
          },
          "cwd": {
            "type": [
              "string",
              "null"
            ]
          },
          "goal": {
            "type": [
              "string",
              "null"
            ]
          },
          "isolation": {
            "enum": [
              "shared",
              "worktree_per_task"
            ],
            "type": "string"
          },
          "repo_path": {
            "type": [
              "string",
              "null"
            ]
          },
          "target_branch": {
            "type": [
              "string",
              "null"
            ]
          },
          "tasks": {
            "items": {
              "properties": {
                "cwd": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "depends_on": {
                  "items": {
                    "type": "string"
                  },
                  "type": "array"
                },
                "executor": {
                  "type": "string"
                },
                "instruction": {
                  "type": "string"
                },
                "key": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "model": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "profile": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "title": {
                  "type": [
                    "string",
                    "null"
                  ]
                }
              },
              "required": [
                "instruction",
                "executor"
              ],
              "type": "object"
            },
            "maxItems": 24,
            "minItems": 1,
            "type": "array"
          },
          "title": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "tasks"
        ],
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "run": {
            "properties": {},
            "type": "object"
          },
          "tasks": {
            "items": {
              "properties": {},
              "type": "object"
            },
            "type": "array"
          }
        },
        "required": [
          "run",
          "tasks"
        ],
        "type": "object"
      }
    },
    {
      "description": "Accept a reviewed task and move it to Done.",
      "metadata": {},
      "name": "kanban::tasks::accept",
      "request_schema": {
        "properties": {
          "task_id": {
            "type": "string"
          }
        },
        "required": [
          "task_id"
        ],
        "type": "object"
      },
      "response_schema": {
        "properties": {},
        "type": "object"
      }
    },
    {
      "description": "Dispatch one ready or attention-blocked task to its live executor.",
      "metadata": {},
      "name": "kanban::tasks::dispatch",
      "request_schema": {
        "properties": {
          "task_id": {
            "type": "string"
          }
        },
        "required": [
          "task_id"
        ],
        "type": "object"
      },
      "response_schema": {
        "properties": {},
        "type": "object"
      }
    },
    {
      "description": "Queue reviewed work for tested, serialized landing onto the run target branch.",
      "metadata": {},
      "name": "kanban::tasks::land",
      "request_schema": {
        "properties": {
          "keep": {
            "type": "boolean"
          },
          "target_branch": {
            "type": [
              "string",
              "null"
            ]
          },
          "task_id": {
            "type": "string"
          },
          "test_cmd": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "task_id"
        ],
        "type": "object"
      },
      "response_schema": {
        "properties": {},
        "type": "object"
      }
    },
    {
      "description": "Retry an attention-blocked task, preserving the claimed session for managed worktrees.",
      "metadata": {},
      "name": "kanban::tasks::retry",
      "request_schema": {
        "properties": {
          "model": {
            "type": [
              "string",
              "null"
            ]
          },
          "profile": {
            "type": [
              "string",
              "null"
            ]
          },
          "task_id": {
            "type": "string"
          }
        },
        "required": [
          "task_id"
        ],
        "type": "object"
      },
      "response_schema": {
        "properties": {},
        "type": "object"
      }
    },
    {
      "description": "Stop a running task when its executor exposes a stop function.",
      "metadata": {},
      "name": "kanban::tasks::stop",
      "request_schema": {
        "properties": {
          "task_id": {
            "type": "string"
          }
        },
        "required": [
          "task_id"
        ],
        "type": "object"
      },
      "response_schema": {
        "properties": {},
        "type": "object"
      }
    },
    {
      "description": "Serve the injectable Kanban Console page assets.",
      "metadata": {
        "internal": true
      },
      "name": "kanban::ui-content",
      "request_schema": {
        "properties": {
          "path": {
            "type": "string"
          }
        },
        "required": [
          "path"
        ],
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "content": {
            "type": "string"
          },
          "content_type": {
            "type": "string"
          }
        },
        "required": [
          "content",
          "content_type"
        ],
        "type": "object"
      }
    }
  ],
  "triggers": [
    {
      "description": "Fires when a Kanban run or task changes. Bind with an empty config.",
      "invocation_schema": {},
      "metadata": {},
      "name": "kanban::changed",
      "return_schema": {}
    }
  ]
}
```
