727 lines
32 KiB
Markdown
727 lines
32 KiB
Markdown
---
|
|
id: canvases-agent-authored-web-apps-design
|
|
title: Agent-authored web-app canvases system design
|
|
status: draft
|
|
system: canvases
|
|
owners:
|
|
- canvases
|
|
created: 2026-08-26
|
|
last_updated: 2026-09-23
|
|
requirements:
|
|
- REQ-CANVASES-AGENT-WEB-APPS-001
|
|
- REQ-CANVASES-AGENT-WEB-APPS-002
|
|
- REQ-CANVASES-AGENT-WEB-APPS-003
|
|
- REQ-CANVASES-AGENT-WEB-APPS-004
|
|
- REQ-CANVASES-AGENT-WEB-APPS-005
|
|
- REQ-CANVASES-AGENT-WEB-APPS-006
|
|
- REQ-CANVASES-AGENT-WEB-APPS-007
|
|
- REQ-CANVASES-AGENT-WEB-APPS-008
|
|
- REQ-CANVASES-AGENT-WEB-APPS-009
|
|
---
|
|
|
|
# Agent-authored web-app canvases system design
|
|
|
|
## Purpose and boundaries
|
|
|
|
The Canvases system owns the lifecycle that turns an agent-authored task
|
|
application into a workspace application. It owns task creation context,
|
|
promotion, release selection, editing sessions, discovery, and canvas host
|
|
surfaces.
|
|
|
|
The Plugins system owns package validation, browser trust, data access,
|
|
state, events, grants, and runtime tokens. This design uses
|
|
[the plugin web-application contract](../../plugins/system-design/isolated-web-app-contributions.md).
|
|
|
|
See [declarative canvas](collaborative-canvases.md) and
|
|
[marketplace sharing](marketplace-sharing.md).
|
|
|
|
## Requirement mapping
|
|
|
|
| Requirement | Design sections |
|
|
| --------------------------------- | -------------------------------------- |
|
|
| `REQ-CANVASES-AGENT-WEB-APPS-001` | Agent authoring lifecycle, Agent tools |
|
|
| `REQ-CANVASES-AGENT-WEB-APPS-002` | Canvas model, Publish and rollback |
|
|
| `REQ-CANVASES-AGENT-WEB-APPS-003` | Promotion and permissions |
|
|
| `REQ-CANVASES-AGENT-WEB-APPS-004` | Quick Chat editing |
|
|
| `REQ-CANVASES-AGENT-WEB-APPS-005` | Desktop information architecture |
|
|
| `REQ-CANVASES-AGENT-WEB-APPS-006` | Mobile design contract |
|
|
| `REQ-CANVASES-AGENT-WEB-APPS-007` | Host state and recovery, Observability |
|
|
| `REQ-CANVASES-AGENT-WEB-APPS-008` | Authoring admission and limits |
|
|
| `REQ-CANVASES-AGENT-WEB-APPS-009` | Guided canvas task launch |
|
|
|
|
## System relationship
|
|
|
|
```text
|
|
Task or Quick Chat agent
|
|
|
|
|
| create, inspect, publish
|
|
v
|
|
Canvas lifecycle service
|
|
|
|
|
| owns scope and source lineage
|
|
v
|
|
Scoped plugin instance --------------+
|
|
| |
|
|
| active immutable release | effective grants
|
|
v v
|
|
Sandboxed web application <---- Plugin web runtime
|
|
| |
|
|
| HTTP + Server-Sent Events | Host data and state services
|
|
+-----------------------------+
|
|
|
|
|
v
|
|
Tasks, workflows, and events
|
|
```
|
|
|
|
Canvas code does not call a canvas-specific JavaScript object. It uses the
|
|
standard web protocol that the Plugins system owns.
|
|
|
|
## Implementation baseline and feature gate
|
|
|
|
PR #3061's declarative implementation is superseded, not a prerequisite.
|
|
|
|
The runtime flag identity is `features.canvases`. Its environment variable is
|
|
`KANDEV_FEATURES_CANVASES`. The first implementation sets `prod`, `dev`, and
|
|
`e2e` profile defaults to `false`. Focused development and end-to-end tests set
|
|
the environment variable explicitly.
|
|
|
|
The flag requires a restart because it changes MCP tool registration and
|
|
backend composition. When the flag is off, Kandev does not register backend
|
|
canvas entry points. These entry points include MCP, HTTP, WebSocket, SSE,
|
|
background workers, and boot data. The frontend does not register canvas
|
|
routes, navigation, or settings surfaces. Database migrations can run while
|
|
the feature is off. No canvas operation can read or change canvas data.
|
|
|
|
## Canvas model
|
|
|
|
Use a small lifecycle record instead of declarative canvas blocks.
|
|
|
|
### `canvases`
|
|
|
|
- `id`
|
|
- `plugin_instance_id`
|
|
- `workspace_id`
|
|
- nullable `task_id` while task-scoped
|
|
- nullable `origin_task_id` for promoted-canvas provenance
|
|
- `title`
|
|
- `created_by_session_id`
|
|
- nullable `promoted_by_user_id`
|
|
- nullable `promoted_at`
|
|
- nullable `archived_at`
|
|
- `created_at` and `updated_at`
|
|
|
|
The plugin instance owns placement `scope_kind`, effective data scope, active
|
|
release, status, and grants. The canvas service is the only service that
|
|
changes task or workspace placement or authorizes a canvas data-scope change.
|
|
The [workspace preview design](task-canvas-workspace-preview.md) separates
|
|
these scopes for locally requested task canvases.
|
|
|
|
The canvas and plugin instance have a one-to-one relationship. Canvas removal
|
|
removes the plugin instance, runtime tokens, grants, state, pending releases,
|
|
and retained artifacts through the plugin lifecycle service.
|
|
|
|
Task removal removes each task canvas in the same cleanup flow. A promoted
|
|
canvas has no current `task_id`, so task cleanup preserves it. The
|
|
`origin_task_id` can become null after task removal.
|
|
|
|
Workspace removal removes task and promoted canvases, plugin instances,
|
|
grants, state, pending releases, and runtime capabilities. The workspace delete
|
|
transaction records artifact-cleanup jobs before it removes release ownership.
|
|
The plugin cleanup worker removes retained files after commit and retries after
|
|
restart.
|
|
|
|
## Canvas state machine
|
|
|
|
```text
|
|
draft
|
|
| first valid release
|
|
v
|
|
task_active ---- archive ----> archived
|
|
| promote |
|
|
v | restore
|
|
workspace_active <--------------+
|
|
|
|
|
+---- edit draft ---- publish ----> workspace_active
|
|
|
|
|
+---- remove ----------------------> removed
|
|
```
|
|
|
|
A pending release does not change the canvas state. It becomes active after a
|
|
permission approval or disappears after replacement or removal.
|
|
|
|
There is no workspace-to-task demotion in the first delivery.
|
|
|
|
## Authoring admission and limits
|
|
|
|
The canvas service enforces these initial limits before it creates or restores
|
|
a canvas:
|
|
|
|
- 10 non-removed task canvases for one task
|
|
- 100 non-removed canvases for one workspace across task and workspace scopes
|
|
|
|
Archived canvases count toward both limits. Create and restore use the same
|
|
repository transaction and lock as the count. Concurrent operations cannot
|
|
admit more than the limit.
|
|
|
|
The publish service permits 10 attempts for one agent session in a rolling
|
|
five-minute window. One canvas can have only one publish in progress. Publish
|
|
admission reserves plugin artifact bytes before source transfer and validation.
|
|
The plugin runtime also enforces its workspace and installation storage limits.
|
|
|
|
A limit error returns a stable safe code. It does not change the active
|
|
release, grants, state, archive status, or retained release set.
|
|
|
|
## Agent authoring lifecycle
|
|
|
|
The normal flow starts in a task conversation:
|
|
|
|
1. The user asks the task agent to create a canvas.
|
|
2. The agent calls `create_canvas_kandev` with a title and application summary.
|
|
3. The backend derives the task, workspace, session, and user from MCP context.
|
|
4. The service creates a task-scoped canvas and inactive plugin instance.
|
|
5. The tool returns the canvas ID, source directory, manifest scaffold,
|
|
current permission ceiling, and the command to read the bundled authoring
|
|
skill.
|
|
6. The agent reads the version-matched authoring skill through Canvas MCP.
|
|
7. The agent writes source and built assets under the returned directory.
|
|
8. The agent calls `publish_canvas_kandev` with the canvas ID and source path.
|
|
9. Kandev reads that directory through the trusted task execution file API.
|
|
10. The Plugins service validates and stores an immutable release.
|
|
11. The canvas activates when its permissions fit existing grants or its
|
|
recorded [initial creation authority](local-creation-authority.md).
|
|
12. The task client receives a lifecycle event and opens the new canvas.
|
|
|
|
The source directory is workspace-relative and scoped to the current execution.
|
|
The publish service rejects traversal, links, another canvas identity, and a
|
|
directory outside the assigned canvas root.
|
|
|
|
The backend must use the execution file API for local, Docker, and remote
|
|
executors. It must not assume that the agent workspace exists on the Kandev
|
|
host filesystem.
|
|
|
|
Agentctl adds one authenticated streaming tar endpoint for a workspace-relative
|
|
root. The canvas service supplies only the assigned canvas source root. The
|
|
endpoint rejects absolute paths, traversal, links, devices, and files outside
|
|
that root. It permits at most 512 files, 25 MiB of file data, and 30 MiB on the
|
|
wire. Cancellation stops traversal and closes the stream. The backend sends the
|
|
stream directly to the plugin validator and does not make one JSON request for
|
|
each file.
|
|
|
|
## Guided canvas task launch
|
|
|
|
The [guided canvas task launch design](guided-canvas-task-launch.md) owns
|
|
creation entry points, the editable preset, saved-prompt preparation, and
|
|
authoring prompt guidance. It maps the launch requirement and its desktop and
|
|
phone outcomes. The runtime authoring bundle remains below.
|
|
|
|
## Agent authoring guidance
|
|
|
|
### Discovery and creation prompts
|
|
|
|
The shared task prompt uses the
|
|
[agent discovery contract](../../agents/system-design/mcp-tool-discovery-guidance.md).
|
|
When the resolved session profile includes `CapabilityCanvas`, it also includes
|
|
this compact instruction:
|
|
|
|
> For a requested Kandev canvas, discover `create_canvas_kandev`, `read_canvas_authoring_skill_kandev`, and `publish_canvas_kandev`.
|
|
> Create the draft in Kandev before writing application files.
|
|
> Read the authoring skill once and edit only inside the returned source directory.
|
|
> Publish through MCP and report the returned release status.
|
|
> If publication is unsuccessful, report the failure and do not claim that the canvas is published.
|
|
> Files or a successful local build do not create a published Kandev canvas.
|
|
|
|
The optional section is absent when the resolved profile lacks canvas tools.
|
|
This covers canvas requests inside ordinary task conversations, independently
|
|
of the guided task preset.
|
|
|
|
`CanvasTaskCreateLauncher` retains the visible, editable
|
|
`canvases:createCanvasTaskPrompt` preset in the normal `TaskCreateDialog`.
|
|
The locale catalog owns the exact wording. It names discovery, creation,
|
|
assigned-root authoring, live data, the single core skill read, publication,
|
|
and honest outcome reporting. It explains permission review and promotion
|
|
when required, and does not equate local files or a build with publication.
|
|
|
|
The existing selected question capability governs any clarification. The
|
|
preset cannot grant a question tool to an autopilot session that lacks one.
|
|
An application goal already supplied by the user needs no repeated interview.
|
|
|
|
English, Portuguese, and Simplified Chinese catalogs receive equivalent
|
|
wording. Traditional Chinese catalogs use the repository generator. Tool names
|
|
remain literal protocol identifiers. The pseudo-locale uses its generator.
|
|
|
|
The nearest mobile exemplar is the existing full-screen `TaskCreateDialog`
|
|
opened from workspace Canvases settings. This is a content change within that
|
|
surface. Its scroll owner, touch controls, and navigation remain unchanged.
|
|
Focused desktop and mobile tests cover the longer editable prompt and its
|
|
submitted value. Tests inspect the real catalog value before replacing any
|
|
description with mock-agent commands.
|
|
|
|
### Bundled authoring skill
|
|
|
|
Kandev bundles a read-only `kandev-canvas-authoring` system skill in a canvas
|
|
embed that is separate from the Office skill embed. At startup, Kandev writes
|
|
the current skill and its supporting files to
|
|
`<kandev-home>/system-skills/kandev-canvas-authoring/`. A Kandev update replaces
|
|
these Kandev-owned files with the version from the new binary. It does not
|
|
change user-owned skills.
|
|
|
|
Kanban task agents do not receive this skill in `.agents/skills`,
|
|
`.claude/skills`, or another task-workspace skill directory. The Canvas MCP
|
|
server reads the canonical files from the Kandev home directory and returns
|
|
them through `read_canvas_authoring_skill_kandev`. A call without a path returns
|
|
one compact core bundle. The bundle contains the complete normal workflow,
|
|
manifest contract, browser protocol summary, appearance rules, minimal
|
|
scaffold, and exact supporting-file inventory. The optional `path` input reads
|
|
one detailed reference from that inventory.
|
|
|
|
The handler rejects absolute paths, traversal, links, and files outside the
|
|
inventory. It does not return a Kandev host path to the agent. This rule keeps
|
|
local, Docker, and remote executors on one contract without copying the skill
|
|
into the task workspace.
|
|
|
|
`create_canvas_kandev` materializes the version-matched minimal scaffold in the
|
|
assigned source directory. It returns the system-skill slug, version, exact
|
|
scaffold inventory, and an instruction to make at most one core skill-read
|
|
call. Canvas edit Quick Chat prompts give the same instruction. After the core
|
|
read, agents use their native file tools for the scaffold and request a
|
|
detailed reference only when the core bundle directs them to it.
|
|
|
|
Office role and operating skills keep their existing per-task workspace
|
|
deployment. The canvas-authoring read path does not change Office skill
|
|
selection, injection, or synchronization. Office skill discovery and
|
|
`SyncSystemSkills` do not inspect the canvas system-skill directory.
|
|
|
|
The canvas-authoring skill tells the agent to:
|
|
|
|
- use the generated manifest and source directory
|
|
- bundle executable frontend dependencies
|
|
- add a responsive viewport declaration
|
|
- use relative `./_kandev/v1` data, state, action, and event paths
|
|
- keep Kandev domain data as the source of truth
|
|
- store only application-specific shared state in instance state
|
|
- use memory for temporary values; use instance state for shared values and
|
|
do not depend on host browser-storage keys
|
|
- publish after local build checks
|
|
- read validation diagnostics and correct rejected releases
|
|
- use semantic appearance variables and apply live host appearance messages
|
|
|
|
Supporting files include the browser API, manifest, data and state, events and
|
|
recovery, security, and UI pattern references. The scaffold includes a minimal
|
|
no-build HTML application and bundled Kandev-compatible canvas styles. It can
|
|
also include optional build examples without making Node a host-runtime
|
|
dependency.
|
|
|
|
## Agent tools
|
|
|
|
Replace the declarative block tools with these task-aware tools:
|
|
|
|
- `list_canvases_kandev`
|
|
- `read_canvas_authoring_skill_kandev`
|
|
- `create_canvas_kandev`
|
|
- `get_canvas_kandev`
|
|
- `publish_canvas_kandev`
|
|
- `get_canvas_state_kandev`
|
|
- `set_canvas_state_kandev`
|
|
|
|
Task agents can create and publish task canvases for their trusted task. An edit
|
|
Quick Chat session can publish only the canvas that started that session.
|
|
|
|
State tools derive the plugin instance from the canvas. They use the plugin
|
|
state service and revision preconditions. They do not accept another user,
|
|
workspace, task, session, or plugin instance.
|
|
|
|
Agents cannot promote, approve permissions, roll back, archive, restore, or
|
|
remove a canvas. Agents use existing Kandev tools to change tasks and workflows
|
|
that a canvas displays.
|
|
|
|
## Publish and rollback
|
|
|
|
The publish command resolves the source through trusted session context. It
|
|
streams a bounded package to the plugin release validator.
|
|
|
|
If the declaration does not exceed existing grants, the release activates in
|
|
one transaction. The service publishes `canvas.release.activated` after commit.
|
|
|
|
If the declaration needs more permission, the release gets
|
|
`pending_permission` status. The service publishes
|
|
`canvas.release.permission_required`. The active release remains unchanged.
|
|
|
|
Recorded owner-authorized first publication uses
|
|
[the creation authority transaction](local-creation-authority.md) instead.
|
|
The generic publish and manual review paths do not infer that authority.
|
|
|
|
Rollback selects the retained prior valid release. It does not restore old
|
|
grants that the user revoked. If the current grants do not cover the old
|
|
release, rollback needs a permission review.
|
|
|
|
## Promotion and permissions
|
|
|
|
Promotion is a human-only canvas operation. The backend authorizes the current
|
|
user for the canvas workspace before it returns promotion data.
|
|
|
|
The promotion dialog shows:
|
|
|
|
- the canvas title and origin task
|
|
- the active release and source actor
|
|
- each Kandev data read
|
|
- each Kandev data write
|
|
- each event subject
|
|
- shared state access
|
|
- each exact external network origin
|
|
- the change from task placement to workspace placement, with any data-scope
|
|
difference identified separately
|
|
- the new workspace navigation placement
|
|
|
|
The user can cancel without a state change. Confirmation creates any needed
|
|
workspace grants and changes the plugin instance placement scope in one
|
|
transaction. The canvas keeps its ID, plugin instance, active release, state,
|
|
and release history.
|
|
|
|
Promotion publishes one lifecycle event after commit. The task and workspace
|
|
navigation projections then refresh.
|
|
|
|
A release that adds permissions uses the same review component. Removing a
|
|
declaration does not need approval. The effective grant contracts to the new
|
|
declaration after activation.
|
|
|
|
### Readable review surfaces
|
|
|
|
`CanvasReleaseDialog` and `CanvasPromotionDialog` share a permission view model
|
|
and human-readable provenance. Show release creation time, author kind, source
|
|
task title, and source session name when currently authorized. Use an
|
|
unavailable-source label for deleted or inaccessible records. Raw UUIDs stay in
|
|
API identities and action payloads, never headings, accessible labels, or copy.
|
|
Add optional source labels to the HTTP release/promotion projections through
|
|
authorized task/session lookups; avoid client-side lookup waterfalls.
|
|
|
|
Select the pending release by default, otherwise the active release. A compact
|
|
release selector preserves access to retained history. Distinguish Active from
|
|
Previous for valid releases by comparing with `active_release_id`. Render one
|
|
grouped declaration with newly requested rows marked. Use localized semantic
|
|
labels for reads, writes, state, and supported event/resource names; preserve
|
|
exact normalized network origins. Unknown values have a localized unsupported
|
|
permission label and cannot be approved silently. Keep rejection reasons and
|
|
real validation errors separate from normal permission review.
|
|
|
|
On desktop use a viewport-bounded wider dialog (target 48rem maximum width)
|
|
with a fixed title and action footer. The single middle region can scroll;
|
|
remove the 288px cap and repeated declared/missing-permission blocks. Pending
|
|
release actions are Approve and Reject, retained release action is Roll back,
|
|
and current release has Close. Reuse unchanged stale-review safeguards.
|
|
|
|
On phones use the full-height focused surface pattern from `task-layout.tsx`,
|
|
with header/footer and internal scrolling mechanics from
|
|
`mobile-menu-sheet.tsx`. This deep release review warrants a full-height
|
|
surface; the short host action chooser remains an inset bottom drawer.
|
|
Use `useResponsiveBreakpoint`, dynamic viewport height, safe areas, and
|
|
touch-only targets of at least 44px. Desktop controls remain 28px. Share
|
|
selection, actions, loading, and errors between presentations. Dismissal returns
|
|
focus to the opener; a release change during review refreshes the selection and
|
|
disables stale actions. No horizontal document overflow is permitted.
|
|
|
|
## Quick Chat editing
|
|
|
|
The workspace canvas host has an Edit canvas action. It calls a canvas edit
|
|
endpoint instead of invoking a one-shot utility agent.
|
|
|
|
The endpoint performs these steps:
|
|
|
|
1. Authorize the canvas and workspace.
|
|
2. Create a normal Quick Chat session with `origin: canvas_edit` metadata.
|
|
3. Record the target canvas and active release in trusted session metadata.
|
|
4. Materialize the active release source in the Quick Chat workspace.
|
|
5. Open Quick Chat with a prompt that describes the requested edit workflow.
|
|
6. Restrict canvas publish tools to the target canvas.
|
|
|
|
The user describes changes in Quick Chat. The agent edits the materialized
|
|
source, builds static assets, and calls the normal publish tool. The active
|
|
release changes only after validation and permission checks succeed.
|
|
|
|
The Quick Chat workspace remains disposable. The immutable release store owns
|
|
published source. Quick Chat cleanup cannot remove an active or prior release.
|
|
|
|
## Runtime data and state
|
|
|
|
The iframe uses the plugin web protocol. For a task board, the expected data
|
|
flow is:
|
|
|
|
```text
|
|
Initial page load
|
|
-> GET ./_kandev/v1/data/tasks
|
|
-> GET ./_kandev/v1/data/workflows/{id}/steps
|
|
-> read each task.workflow_step_id
|
|
-> render tasks grouped by workflow and workflow step
|
|
|
|
User continues a task
|
|
-> POST ./_kandev/v1/data/tasks/{id}/messages { text: "continue" }
|
|
-> the shared message service queues, resumes, or starts the task session
|
|
-> normal task and session events reach the iframe
|
|
|
|
User moves a card
|
|
-> choose the next ordered workflow step
|
|
-> PATCH ./_kandev/v1/data/tasks/{id} { workflow_step_id: nextStepId }
|
|
-> task service updates the task
|
|
-> task.state_changed event is published
|
|
-> the iframe receives the event through Server-Sent Events
|
|
|
|
Agent moves a task
|
|
-> existing Kandev task MCP tool
|
|
-> task service updates the task
|
|
-> the same event reaches the iframe
|
|
```
|
|
|
|
The task store remains the source of truth. Canvas instance state stores only
|
|
data that has no Kandev domain owner. Examples include saved board filters,
|
|
custom lane definitions, or application annotations.
|
|
|
|
The agent can read and change instance state with the canvas state tools. The
|
|
iframe uses the relative state routes. Both paths use the same revision and
|
|
conflict service.
|
|
|
|
## HTTP API
|
|
|
|
Add owner-authorized canvas endpoints for:
|
|
|
|
- list task canvases
|
|
- list workspace canvases
|
|
- get canvas metadata and host state
|
|
- request a runtime URL
|
|
- get promotion preview
|
|
- confirm promotion
|
|
- get release history
|
|
- approve a pending release
|
|
- roll back a release
|
|
- start an edit Quick Chat session
|
|
- archive, restore, and remove a workspace canvas
|
|
|
|
The first delivery has no manual create, source upload, package import, package
|
|
export, or demotion endpoint.
|
|
|
|
The publish path is agent-facing through MCP. It can use a narrow internal HTTP
|
|
or WebSocket transfer between the backend and agent execution layer. It is not
|
|
a browser upload route.
|
|
|
|
## WebSocket lifecycle events
|
|
|
|
Canvas metadata changes use the existing Kandev WebSocket gateway. Add these
|
|
owner-scoped events:
|
|
|
|
- `canvas.created`
|
|
- `canvas.release.activated`
|
|
- `canvas.release.permission_required`
|
|
- `canvas.promoted`
|
|
- `canvas.archived`
|
|
- `canvas.restored`
|
|
- `canvas.removed`
|
|
|
|
Events contain canvas identity, scope, host state, and release metadata. They
|
|
do not contain source files, HTML, JavaScript, state values, or runtime tokens.
|
|
|
|
Application data updates do not use this channel. The iframe receives its
|
|
declared events through the plugin Server-Sent Events protocol.
|
|
|
|
## Desktop information architecture
|
|
|
|
Keep the first-party Canvases section folded on first use. A direct canvas
|
|
route does not force it open. An explicit user toggle remains in the persisted
|
|
sidebar preference. The section lists active workspace canvases for the active
|
|
workspace. It does not list task canvases.
|
|
|
|
The section contains:
|
|
|
|
- a workspace canvas count
|
|
- one row for each active workspace canvas
|
|
- a settings shortcut
|
|
- an empty setup row that opens the guided task dialog
|
|
|
|
The empty setup row opens the guided task dialog on the current route.
|
|
The separate settings shortcut opens workspace canvas management. The task
|
|
agent creates the canvas after submission; opening the dialog does not create
|
|
canvas metadata. There is no package import or blank canvas builder action.
|
|
|
|
Routes are:
|
|
|
|
- `/canvases/:canvasId` for the focused host surface
|
|
- `/settings/workspaces/:workspaceId/canvases` for workspace canvas management
|
|
|
|
The shared feature-aware workspace tab catalog includes Canvases. The settings
|
|
tree, tab strip, headings, and links derive from this catalog. The Canvases page
|
|
uses `WorkspaceSettingsShell`, shows active and archived workspace canvases,
|
|
and supports open, create through a task, edit, permissions, releases, archive,
|
|
restore, and remove. It does not import packages or create a blank canvas.
|
|
|
|
Wide workspace cards add an active-canvas count tile and include that count in
|
|
the resource total. Narrow cards retain the current readable tile widths and
|
|
omit the canvas tile. The settings tab remains available at every supported
|
|
width. Canvas count requests do not run while the feature is disabled.
|
|
|
|
The task workbench uses one generic canvas panel. The panel receives
|
|
`canvasId`, resolves the active release, and renders the shared web-application
|
|
host. Multiple task canvases use one picker and one panel type.
|
|
|
|
The task workbench watches committed canvas lifecycle invalidations. When the
|
|
active task receives its first activated or pending-permission release, it adds
|
|
and activates `canvas:<canvasId>`. It does not add a duplicate panel or take
|
|
focus for another task. A pending release opens the host recovery state instead
|
|
of an empty iframe. On a phone, the same event navigates to the focused canvas
|
|
route because Dockview is not mounted.
|
|
|
|
Host chrome stays outside the iframe. Desktop chrome shows the title, runtime
|
|
state, Edit, Promote for task canvases, Open full canvas, and an overflow menu.
|
|
Release, permission, promotion, and disabled controls have pointer and keyboard
|
|
help. The mobile action drawer shows equivalent descriptions without hover.
|
|
|
|
Task-entry and reconnect discovery follow the
|
|
[task-entry presentation design](task-entry-presentation.md).
|
|
|
|
The Dockview canvas renderer provides a full-height flex boundary around the
|
|
persistent portal. The shared host and iframe then fill the area below host
|
|
chrome. This change does not alter the direct route or phone viewport formula.
|
|
|
|
## Mobile design contract
|
|
|
|
- **Outcome and entry:** A user opens task canvases from the task mobile
|
|
navigation. A user opens workspace canvases from the workspace mobile menu.
|
|
- **Exemplars:** Use `task-layout.tsx` for full-height composition. Use
|
|
`mobile-picker-sheet.tsx` for the canvas and action picker. Use
|
|
`kanban-with-preview.tsx` for direct phone navigation.
|
|
- **Hierarchy:** Show the canvas title, runtime state, focused application, and
|
|
one primary host action. Put secondary host actions in a visible overflow
|
|
control.
|
|
- **Presentation:** Use a direct `h-dvh` route on phones. Do not mount Dockview
|
|
or a desktop sidebar.
|
|
- **Navigation:** Use one focused canvas. Use an inset bottom drawer to choose
|
|
another canvas or a host action.
|
|
- **Creation:** Keep Create canvas visible on workspace Canvases settings. Open
|
|
the standard full-screen task dialog with the shared canvas preset.
|
|
- **Action help:** Show lifecycle action descriptions inside the action drawer.
|
|
Do not require hover.
|
|
- **Geometry:** Give the iframe the remaining viewport after fixed host chrome.
|
|
Use one host scroll owner, safe-area padding, and 44-pixel host controls.
|
|
- **Application responsibility:** The canvas package owns responsive layout
|
|
inside the iframe. The scaffold and acceptance fixture must support a phone
|
|
viewport without document-level horizontal overflow.
|
|
|
|
Desktop and mobile use the same canvas metadata, plugin instance, active
|
|
release, grants, runtime URL service, and lifecycle actions.
|
|
|
|
## Host state and recovery
|
|
|
|
The shared host component has these states:
|
|
|
|
- `loading_metadata`
|
|
- `pending_first_release`
|
|
- `pending_permission`
|
|
- `loading_runtime`
|
|
- `ready`
|
|
- `offline`
|
|
- `invalid_release`
|
|
- `unavailable`
|
|
- `archived`
|
|
|
|
The iframe can remain visible during an event-stream reconnect. The host shows
|
|
the offline state outside the application. If the runtime token expires, the
|
|
host requests a new URL and reloads the same active release.
|
|
|
|
Receiving a descriptor keeps `loading_runtime` and mounts the frame behind its
|
|
loading cover. `CanvasHostSurface` must mount during this state, not only Ready.
|
|
Only the current [plugin startup acknowledgement](../../plugins/system-design/isolated-web-app-contributions.md#runtime-startup-protocol)
|
|
sets Ready. A failed or absent acknowledgement within 15 seconds tears down the
|
|
frame and exposes Retry and Releases. Do not claim a specific CSP or network
|
|
cause from the generic timeout. Retry, renewal, navigation, and authority
|
|
changes fence old callbacks. Appearance remains applied before reveal.
|
|
|
|
If the release is unavailable, the host offers Edit, Releases, Roll back, or
|
|
Remove according to current permissions. It never loads a rejected artifact.
|
|
|
|
## Authorization
|
|
|
|
Every human endpoint uses current workspace authorization. A foreign and a
|
|
missing canvas return the same not-visible result.
|
|
|
|
Every agent operation derives user, task, workspace, and session from the MCP
|
|
connection. An edit Quick Chat session also verifies its trusted target canvas
|
|
metadata.
|
|
|
|
Task canvases cannot appear in another task. Workspace canvases can serve task
|
|
surfaces only inside their workspace. A task canvas can use approved workspace
|
|
data before promotion under the [workspace preview contract](task-canvas-workspace-preview.md).
|
|
Promotion does not grant undeclared access to tasks, repositories, sessions,
|
|
or external services.
|
|
|
|
The plugin runtime repeats resource authorization for each request. Canvas
|
|
authorization does not replace task or workspace authorization.
|
|
|
|
## Failure handling
|
|
|
|
- A missing task agent disables the create prompt and shows how to start one.
|
|
- A source read error preserves the active release.
|
|
- A package validation error returns safe file and rule diagnostics to the
|
|
authoring agent.
|
|
- A permission increase after initial owner-authorized publication creates a
|
|
pending release.
|
|
- A promotion transaction either changes scope and grants together or changes
|
|
neither.
|
|
- A Quick Chat launch error leaves releases unchanged.
|
|
- A runtime token error reloads through the host before it shows unavailable.
|
|
- A state conflict returns the current revision to the writer.
|
|
- A removed task removes unpromoted canvases through a retryable cleanup path.
|
|
- A removed workspace records artifact cleanup before it removes database
|
|
ownership.
|
|
- A count, rate, or storage rejection preserves the active release.
|
|
|
|
## Observability
|
|
|
|
Add content-free metrics for:
|
|
|
|
- canvas create result
|
|
- source collection and publish result
|
|
- release activation and pending-permission result
|
|
- promotion result
|
|
- edit Quick Chat launch result
|
|
- runtime host state
|
|
- archive, restore, rollback, and removal result
|
|
- canvas count, publish-rate, and artifact-storage admission result
|
|
|
|
Logs can include canvas ID, plugin instance ID, release ID, workspace ID, task
|
|
ID, actor kind, operation, safe result, and duration. Logs omit canvas title,
|
|
prompt, source, application content, state values, package bodies, and runtime
|
|
tokens.
|
|
|
|
## Test strategy
|
|
|
|
- Canvas repository tests cover task cleanup, promoted preservation, scope
|
|
transitions, and release references.
|
|
- Service tests cover trusted agent context, publish authorization, promotion,
|
|
permissions, rollback, edit sessions, workspace removal, and limits.
|
|
- Execution integration tests cover source collection from standalone, Docker,
|
|
and remote streaming archive readers.
|
|
- MCP tests cover tool inventory, trusted context, assigned source roots, state
|
|
conflicts, and forbidden lifecycle actions.
|
|
- Gateway tests cover lifecycle event scope and content limits.
|
|
- Frontend tests cover sidebar filtering, task picker, host state, promotion,
|
|
permission review, release history, Quick Chat launch, task presets,
|
|
workspace tab catalogs, card breakpoints, action help, and panel
|
|
deduplication.
|
|
- Desktop Playwright covers agent creation, live task data, promotion, sidebar
|
|
discovery, task-based creation, automatic panel opening, host geometry,
|
|
editing, a pending permission, activation, and rollback.
|
|
- Mobile Playwright covers task entry, workspace navigation, the focused route,
|
|
task-based creation, bottom drawer help, 44-pixel host controls, safe areas,
|
|
and no host overflow.
|
|
- A test web application covers HTML, CSS, JavaScript, state, task reads,
|
|
task writes, Server-Sent Events, appearance changes, desktop layout, and phone
|
|
layout.
|
|
|
|
## Related decisions
|
|
|
|
- [Plugin-backed web-app canvases](../../../decisions/2026-08-26-plugin-backed-web-app-canvases.md)
|
|
- [Plugin agent tools through Kandev MCP](../../../decisions/2026-08-11-plugin-tools-through-kandev-mcp.md)
|
|
- [Host utility agentctl for sessionless flows](../../../decisions/0002-host-utility-agentctl-for-sessionless-flows.md)
|
|
- [Superseded declarative canvases](../../../decisions/2026-08-25-server-owned-declarative-canvases.md)
|
|
|
|
## Canvas host chrome
|
|
|
|
The [single-header design](canvas-host-chrome.md) defines embedded and standalone
|
|
chrome, status presentation, and shared panel toolbar integration.
|