Boards API
Boards are daemon-owned visual or structured work surfaces. Revisions are immutable and can be referenced fromSubmitInputRequest.input_items with board_reference.
Boards
GET /v1/boards returns BoardView[].
Query parameters:
query, filtering by board id or display name substringowner_session_id, restricting results to one owning session
POST /v1/boards creates a board:
GET /v1/boards/{board_id} returns one board.
PUT /v1/boards/{board_id} updates mutable board fields:
Revisions
GET /v1/boards/{board_id}/revisions returns immutable BoardRevisionView[].
POST /v1/boards/{board_id}/revisions creates one revision:
render_asset_id must reference a readable daemon asset whose media type is an image.
state_asset_id, when present, must reference a readable application/json asset using the
versioned board-state envelope:
schema_version values are 1, "1", and "kheish.board_state.v1".
board_id and previous_revision_id are optional, but when supplied they must match the
target board and submitted parent revision. Content fields such as canvas, elements,
strokes, layers, assets, metadata, payload, or note keep empty or placeholder
states from being accepted as valid board state.
When assets contains daemon asset ids such as "asset-42" or nested objects with asset-id
values, those ids are validated as readable daemon assets when the revision is created and
again during startup repair. The same protection applies to known asset reference fields embedded
anywhere in the state JSON, such as asset_id, asset_ids, image_asset_id, and
image_asset_ids. They are exposed by GET /v1/assets/{asset_id}/references as hard
boards/state_embedded_asset references, so asset delete/GC and observation retention cannot
remove assets still embedded in a board state.
Revision creation is linear and uses previous_revision_id as the compare-and-swap base.
Concurrent writers from the same parent produce one successful revision and one 409
problem response with domain: "boards" and code: "board_revision_conflict".
client_revision_id is optional and scoped to the target board. Repeating the same
client_revision_id with the same payload returns the original immutable revision, including after
restart; reusing it with a different payload returns domain: "boards" and
code: "board_revision_idempotency_conflict".
Invalid state assets return domain: "boards" and code: "board_state_invalid".
Unreadable render assets return domain: "boards" and code: "board_asset_missing".
GET /v1/boards/{board_id}/revisions/{revision_id} returns one revision.
At startup the daemon revalidates persisted board revisions before exposing them. The repair path
requires the render asset to still be a readable image, rechecks raw asset integrity, replays the
same versioned board-state validation used at revision creation, and verifies the parent chain.
Invalid revisions are quarantined and board summaries are rebuilt from the remaining valid history.
The current durable repair contract is strictly linear: persisted histories with multiple roots,
forked children, cycles, or unreachable nodes are quarantined as invalid topology, and board
summaries use the single reachable chain tip rather than timestamp order.
