skip to content

deepwork

Multi-agent workflows on iii with the kanban board as the task list: one lead per ticket with its own sub-agents, parallel waves, independent verify and review, and bounded rounds. Code goals get a dev flow: approved design and plan, test-first tickets in a git worktree, a branch review and a finish you choose.

kitbyiiiverifiedlicense: Apache-2.0latest0.2.1
install
$iii trigger directory::download-kit kit=iii/deepwork
4 installs4 in 7d3 today30 days

exact versions are immutable; every profile and skill is stored by its sha-256, so updates show exactly what changed.

Deepwork Worker

deepwork-worker
agents/deepwork-worker.md

Hidden leaf: does one phase of the kanban ticket named in its task, posts one comment on it, writes one result document with state::compare-and-set, then stops. Never edits ticket fields. Base of every work tier (`deepwork-worker*`, `deepwork-impl*`).

model
inherited
effort
medium
extends
defaultbuilt-in
icon
terminal
color
blue
visibility
hidden from the picker
preloaded skills0

no skills preloaded.

preloaded functions5
  • kanban::ticket::getkanban0.1.22schema

    Read one ticket with its comments and activity, its parent, its live subtasks and their progress. The id accepts the internal uuid or the human-readable key.

    request
    • idstringrequired

      Ticket uuid or human-readable key (KAN-1, case-insensitive).

    response
    • activityobject[]
      • actorstringrequired
      • atstringrequired
      • changesobject[]
        • fieldstringrequired
        • fromunknownrequired
        • tounknownrequired
      • comment_idstring
      • idstringrequired
      • seqinteger· uint64requiredmin 0
      • ticket_idstringrequired
      • typestringrequired

        ticket.created | ticket.updated | ticket.moved | ticket.deleted | ticket.restored | comment.created

    • assigneestring

      Agent profile id.

    • childrenobject[]required

      Live subtasks by ticket number.

      • assigneestring
      • deleted_atstring
      • idstringrequired
      • keystringrequired
      • prioritystringrequired
      • project_idstring
      • release_idstring
      • statusstringrequired
      • titlestringrequired
    • commentsobject[]
      • authorstringrequired

        Agent profile id, or `user`.

      • bodystringrequired
      • created_atstringrequired
      • idstringrequired
      • parent_idstring

        Set for a reply; replies stay one level deep.

      • ticket_idstringrequired
    • created_atstringrequired
    • created_bystring
    • deleted_atstring

      Set when soft-deleted; the row stays on disk.

    • descriptionstring
    • idstringrequired

      Internal uuid.

    • keystringrequired

      Human-readable id, e.g. KAN-1.

    • labelsstring[]
    • orderinteger· uint64min 0

      Position inside its column.

    • parentany of

      The parent, deleted or not; `null` for a ticket that is not a subtask.

      any of (2)
      variant 1
      • assigneestring
      • deleted_atstring
      • idstringrequired
      • keystringrequired
      • prioritystringrequired
      • project_idstring
      • release_idstring
      • statusstringrequired
      • titlestringrequired
      variant 2
      valuenull
    • parent_idstring

      Uuid of the parent ticket. One level deep: a parent has no parent.

    • prioritystringrequired
    • progressobjectrequired

      Live children in the done column over live children that are not canceled.

      • doneinteger· uint64requiredmin 0
      • totalinteger· uint64requiredmin 0
    • project_idstring

      Uuid of the project (several tickets, independent of the release).

    • release_idstring

      Uuid of the release.

    • statusstringrequired

      Column id.

    • titlestringrequired
    • updated_atstringrequired
  • kanban::comment::createkanban0.1.22schema

    Comment on a ticket, or reply to a comment by passing parent_id. Returns the new comment and the ticket (only its compact row with compact).

    request
    • authorstring

      Agent profile id, or `user`. Defaults to `user`.

    • bodystringrequired

      Comment body. Markdown is rendered in the console.

    • compactboolean

      Return the ticket as its compact row (key, title, status, priority, assignee, comment_count) instead of the full ticket.

    • parent_idstring

      Comment id to reply to; replies stay one level deep.

    • ticket_idstringrequired

      Ticket uuid or human-readable key (KAN-1, case-insensitive).

    response
    • commentobjectrequired
      • authorstringrequired

        Agent profile id, or `user`.

      • bodystringrequired
      • created_atstringrequired
      • idstringrequired
      • parent_idstring

        Set for a reply; replies stay one level deep.

      • ticket_idstringrequired
    • ticketany ofrequired

      What a ticket write returns: the full ticket, or its compact row when the request asked for `compact`.

      any of (2)
      variant 1
      • activityobject[]
        … expand 8 nested
        • actorstringrequired
        • atstringrequired
        • changesobject[]
          … expand 3 nested
          • fieldstringrequired
          • fromunknownrequired
          • tounknownrequired
        • comment_idstring
        • idstringrequired
        • seqinteger· uint64requiredmin 0
        • ticket_idstringrequired
        • typestringrequired

          ticket.created | ticket.updated | ticket.moved | ticket.deleted | ticket.restored | comment.created

      • assigneestring

        Agent profile id.

      • childrenobject[]required

        Live subtasks by ticket number.

        … expand 9 nested
        • assigneestring
        • deleted_atstring
        • idstringrequired
        • keystringrequired
        • prioritystringrequired
        • project_idstring
        • release_idstring
        • statusstringrequired
        • titlestringrequired
      • commentsobject[]
        … expand 6 nested
        • authorstringrequired

          Agent profile id, or `user`.

        • bodystringrequired
        • created_atstringrequired
        • idstringrequired
        • parent_idstring

          Set for a reply; replies stay one level deep.

        • ticket_idstringrequired
      • created_atstringrequired
      • created_bystring
      • deleted_atstring

        Set when soft-deleted; the row stays on disk.

      • descriptionstring
      • idstringrequired

        Internal uuid.

      • keystringrequired

        Human-readable id, e.g. KAN-1.

      • labelsstring[]
      • orderinteger· uint64min 0

        Position inside its column.

      • parentany of

        The parent, deleted or not; `null` for a ticket that is not a subtask.

        … expand 2 nested
        any of (2)
        variant 1
        • assigneestring
        • deleted_atstring
        • idstringrequired
        • keystringrequired
        • prioritystringrequired
        • project_idstring
        • release_idstring
        • statusstringrequired
        • titlestringrequired
        variant 2
        valuenull
      • parent_idstring

        Uuid of the parent ticket. One level deep: a parent has no parent.

      • prioritystringrequired
      • progressobjectrequired

        Live children in the done column over live children that are not canceled.

        … expand 2 nested
        • doneinteger· uint64requiredmin 0
        • totalinteger· uint64requiredmin 0
      • project_idstring

        Uuid of the project (several tickets, independent of the release).

      • release_idstring

        Uuid of the release.

      • statusstringrequired

        Column id.

      • titlestringrequired
      • updated_atstringrequired
      variant 2
      • assigneestring
      • comment_countinteger· uint64requiredmin 0
      • keystringrequired
      • prioritystringrequired
      • statusstringrequired
      • titlestringrequired
  • state::compare-and-setstate0.22.19schema

    Atomically set a value only if it currently equals `expected` (omit `expected` to mean 'only if absent'). Returns { swapped, current }; on a miss `current` is the stored value, so the caller can recompute and retry.

    request
    • expectedunknown

      The value the caller believes is there. Omit to mean "expect absent" — the set-if-absent form.

    • keystringrequired
    • scopestringrequired
    • valueunknownrequired
    response
    • currentunknown

      What is actually stored, when the swap did not happen.

    • swappedbooleanrequired
  • shell::execide0.12.32schema

    Run a command in the foreground and return its full output. Put the program in `command` (string) and arguments in `args` (string[]), never argv in `command`. Host-only cwd/env/stdin reject S210 on a sandbox target. Errors return { code, message }; common: S216 host exec error, S300 VM boot failed, S200 in-VM failure.

    request
    • argsstring[]

      Arguments, in order (all strings). Omit/null to tokenize `command` shell-words style; pass an array (even empty) to use it verbatim.

    • commandstringrequired

      Program name (PATH-resolved) or path to an executable, as a string; put arguments in `args`.

    • cwdstring

      Working directory (host only, S210 on sandbox); jail-confined like shell::fs::* paths (S215 on escape), must be an existing directory.

    • envobject

      Per-call env values (host only, S210 on sandbox); exec-hijacking keys (PATH, IFS, HOME, LD_*/DYLD_*, …) reject the whole call S210.

    • stdinstring

      Bytes written to the program's stdin, then EOF (host only, S210 on sandbox); omit to leave stdin at /dev/null.

    • targetall of

      Where to run the command. Defaults to the host worker; pass `{ kind: "sandbox", sandbox_id }` to forward the call to a microVM.

      all of (1)
      variant 1
      one of (2)
      variant 1
      • kindstringrequiredenum: host
      variant 2
      • kindstringrequiredenum: sandbox
      • sandbox_idstring· uuidrequired
    • timeout_msinteger· uint64min 0

      Per-call timeout in milliseconds, capped at the configured max; negative or fractional values fall back to the default.

    response
    • duration_msinteger· uint64requiredmin 0
    • exit_codeinteger· int32
    • stderrstringrequired
    • stderr_truncatedbooleanrequired
    • stdoutstringrequired
    • stdout_truncatedbooleanrequired
    • timed_outbooleanrequired
  • coder::read-fileide0.12.32schema

    Read a file. stat: true probes size/mtime/total_lines without content; line_from/line_to (1-based, inclusive) read a window of a file of any size; numbered: true prefixes absolute line numbers; paths[] (XOR path) batch-reads. Paths: relative to the primary root or absolute inside an allowed root (see coder::info).

    request
    • encodingall of

      Content encoding for full reads; `base64` returns the exact file bytes (encoded length is budgeted). C210 with stat/window/numbered.

      all of (1)
      variant 1
      one of (2)
      variant 1
      valuestringenum: text
      variant 2
      valuestringenum: base64
    • line_frominteger· uint64min 1

      First line (1-based, >= 1) of a windowed read; windows keep files over max_read_bytes readable slice by slice. `path` mode only.

    • line_tointeger· uint64min 1

      Last line of the window, 1-based inclusive, >= `line_from`; omit to read from `line_from` to EOF. `path` mode only.

    • max_output_bytesinteger· uint64min 0

      Full-read byte budget (returned bytes, clamped to max_read_bytes); over budget fails C218 naming size/total_lines. C210 with a window.

    • numberedboolean

      Prefix each line with its absolute 1-based file line number (`N→`), matching coder::update-file line ops; C210 with `stat`. `path` mode only.

    • pathstring

      Single file to read; XOR with `paths` (C210 if both or neither is set).

    • pathsany of[]

      Batch of files to read in one call (bare path strings or window objects), processed in order against batch_read_budget_bytes; XOR with `path`.

      any of (2)
      variant 1
      valuestring
      variant 2
      • line_frominteger· uint64min 1

        First line of the window, 1-based inclusive (>= 1); defaults to 1 when only `line_to` is set.

      • line_tointeger· uint64min 1

        Last line of the window, 1-based inclusive, >= `line_from`; omit to read to EOF.

      • numberedboolean

        Prefix this entry's lines with their absolute 1-based line numbers (`N→`); prefix bytes count toward the batch budget.

      • pathstringrequired

        File to read.

      • statboolean

        Metadata probe for this entry: size/mode/mtime plus total_lines, content null, no budget consumed; C210 with a window or `numbered`.

    • statboolean

      Metadata probe: size/mode/mtime plus total_lines/is_utf8, no content; C210 with line_from/line_to/numbered/max_output_bytes.

    response
    • contentstring

      File content as a UTF-8 string — the whole file, or just the requested window when `line_from`/`line_to` was given (window lines keep their newline terminators). Binary content is returned with invalid bytes replaced by U+FFFD; request `encoding: "base64"` when exact bytes matter (content is then the file's bytes base64-encoded). **Single-path mode only; null when the request used `paths[]`.**

    • is_utf8boolean

      Whether `content` survived UTF-8 conversion without losing bytes. Reflects the RETURNED content only: a clean window inside an otherwise-binary file is still `true`. **Single-path mode only; null when the request used `paths[]`.**

    • lines_returnedinteger· uint64min 0

      Number of lines in `content`. For full reads this equals the file's total line count. **Single-path mode only; null when the request used `paths[]`.**

    • modeinteger· uint32min 0

      Unix permission bits (lower 9 bits of `st_mode`), e.g. 0o644. **Single-path mode only; null when the request used `paths[]`.**

    • more_linesboolean

      True when the file has content beyond what `content` includes: the window ended before EOF, or the byte budget cut the window short. Always false for full reads. **Single-path mode only; null when the request used `paths[]`.**

    • mtimeinteger· int64

      Last-modified time as a Unix epoch in seconds. **Single-path mode only; null when the request used `paths[]`.**

    • pathstring

      Canonical absolute path of the file read (resolved through the jail). **Single-path mode only; null when the request used `paths[]`.**

    • resultsobject[]

      Per-entry results for a batch `paths[]` request. **Present only when the request used `paths[]`; null in single-path mode.**

      • contentstring

        File content as a UTF-8 string — the whole file or the requested window. Binary bytes are replaced by U+FFFD (`is_utf8: false`). `null` on failure.

      • errorany of

        Structured error — present only when `success: false`.

        any of (2)
        variant 1
        • codestringrequired

          Stable error code, e.g. "C211". See the README error table.

        • messagestringrequired

          Human/LLM-readable message: problem + actual values + corrective next call.

        variant 2
        valuenull
      • is_utf8boolean

        Whether `content` survived UTF-8 conversion without losing bytes. `null` on failure.

      • lines_returnedinteger· uint64min 0

        Number of lines returned in `content`. `null` on failure.

      • modeinteger· uint32min 0

        Unix permission bits (lower 9 bits of `st_mode`), e.g. 0o644. `null` on failure.

      • more_linesboolean

        `true` when the file has content beyond what `content` includes (window ended before EOF, or byte budget cut the window short). `null` on failure.

      • mtimeinteger· int64

        Last-modified time as a Unix epoch in seconds. `null` on failure.

      • pathstringrequired

        Canonical absolute path of the file (resolved through the jail). If resolution failed, this echoes the caller's input verbatim.

      • sizeinteger· uint64min 0

        Size of the FILE in bytes (from metadata). `null` on failure or when the entry budget was exhausted before the file was opened.

      • successbooleanrequired

        `true` when the read succeeded (content/metadata fields are populated); `false` when an error occurred (only `error` is set).

      • total_linesinteger· uint64min 0

        Total lines in the file; present when the stream reached EOF during this entry's read. `null` when not traversed or on failure.

    • revisionstring

      Opaque identity of the file's exact bytes. Present for complete single-path reads only; pass it as `expected_revision` to `coder::create-file` for a conflict-safe whole-file overwrite.

    • sizeinteger· uint64min 0

      Size of the FILE in bytes (from metadata) — not the size of `content`; in windowed mode the two differ. **Single-path mode only; null when the request used `paths[]`.**

    • total_linesinteger· uint64min 0

      Total number of lines in the file. Present only when the read traversed the whole file: always for full reads; for windowed reads only when the stream naturally reached EOF within the byte cap. Never computed by forcing an extra full scan — absent means the file was not fully traversed. **Single-path mode only; null when the request used `paths[]`.**

system prompt

4,106 bytes
agents/deepwork-worker.md

Deepwork Worker

You do exactly one phase of one kanban ticket for a deepwork lead, then stop.

  1. Read first. Call kanban::ticket::get on your ticket at the start of every task, a Retry included, even if an earlier read is in your transcript: comments added since then steer this attempt. Its description is your brief; comments by authors other than deepwork* are human notes. If kanban::ticket::get fails, write failed with summary ticket read failed: (never blocked for this) and stop. A Retry: line in your task carries the reasons the last attempt was rejected. If an earlier task is still in your transcript, the newest task wins.
  2. Scope. Do only the Deliverable; Out of scope is binding. If you are blocked on a question only a human can answer, write blocked with a question instead of doing half the work. A missing input that another ticket produces is failed with summary waiting for , not blocked. If a call you need is denied, write blocked with question: "allow ".
  3. Finish.
    • Post one kanban::comment::create {"ticket_id":"","author":"","body":": ≤40 words","compact":true} on your own ticket. If it fails, continue.
    • Then make one state::compare-and-set to the exact scope and key in your task, with a non-null object as the value. Never pass expected.
    • swapped:false: if current.item is your key, it is already written: stop. Otherwise a sibling took your key: make one more state::compare-and-set to the same scope with key .dup, the same value and no expected, then stop whatever it returns. Never retry with expected.
  4. Result document, at most 1 KB not counting result, new_items and loose_ends (each brief ≤ ~400 B; list at most the count your brief allows). item is the exact key in your task (tests, code or work), not the ticket key:
    {"item":"<the key in your task, e.g. code>","status":"done|blocked|failed","summary":"≤60 words; say what was NOT verified","result":<the brief's Result schema, or null>,"evidence":["<check>: <observed>"],"new_items":[{"title":"…","brief":"Deliverable / Acceptance + Verify lines / Out of scope","after":["<title of another new item, or a ticket key, whose output it needs>"]}],"loose_ends":[{"title":"…","brief":"…"}],"question":"only when blocked"}
    new_items is work the goal still needs; loose_ends is what you noticed but the goal does not need (a bug, a skipped refactor, a parked question): it goes to Backlog. Never leave either only as a TODO comment. Put long evidence in a file and give its path.
  5. Rules. Never change ticket status, labels, assignee, title or description: the orchestrator owns them. Write before the Deadline in your task; a result written after it is lost. If the work cannot finish by then, write failed with the reason instead of starting it. A stop does not end shell::exec_bg jobs: don't leave one running past your write (shell::kill it first). Call shell::exec as {command, args[]}; never put a whole shell line in command. With a Worktree: in your task, work only inside it (cwd and every path) and never run git push, merge, rebase, reset, checkout, switch, stash, clean, restore, revert, rm -r, tag, worktree or branch: siblings share the worktree. Ignore the claim, done-watch and cron steps in kanban/tickets/*. After the write, end your turn with exactly one line, : written, and nothing else.