Chat Agent Feature Checklist
Frozen acceptance boundary for chatagent product orchestration and Web UI remediation (C+T3).
Regression and PRs are judged against this list plus the linked tests. If behavior exists in code but is missing here, update this document before changing code.
Related engine docs: README, Architecture. Maintainer guides: internal/server/chatagent/AGENTS.md, pkg/agent/AGENTS.md.
Dual-channel SSE protocol
Both channels use chatagent.StreamEvent JSON (type discriminator) from internal/server/chatagent/protocol.go.
| Channel | Message send (primary turn stream) | Live event subscribe | Subscribe filter |
|---|---|---|---|
| REST | POST /chatagent/sessions/:id/messages — full SSE (delta / thinking / tool / turn_trace / … / done) |
GET /chatagent/sessions/:id/events |
confirm, confirm_resolved, canceled, mode_change, run_complete |
| Web | POST /service/web/agents/:id/messages — turn execution; UI may use fetch/SSE depending on handler |
GET /service/web/agents/:id/events |
Same subset (chatagent_web_stream.go) |
Event shape (StreamEvent) is shared. Both /events subscribers use the same type filter (not full deltas). Primary turn tokens come from the messages/send path (REST StreamAPIRun), not from /events.
1. Platform DM chat
| ID | Behavior | Entry | Edge cases | Tests |
|---|---|---|---|---|
| P-01 | Bind/create chat session for platform DM and run agent turn | internal/server/chatagent_handler.go → Service.Run |
Closed session rejected; disabled agent | chatagent service/handler unit tests |
| P-02 | Slack: stream placeholder + SlackStreamSink updates |
Slack platform only | Placeholder send failure → non-streaming fallback | slack_sink_test.go, handler stream tests |
| P-03 | Non-Slack: single reply after run completes | Other platforms | Persist assistant message failure surfaces user-visible error | handler tests |
| P-04 | Persist assistant message to store | After successful Run |
DB error | handler tests |
2. REST API (/chatagent/*)
Auth: ScopeChatAgentChat. Owner checks on session-scoped routes.
| ID | Behavior | Entry | Edge cases | Tests |
|---|---|---|---|---|
| R-01 | Agent info | GET /chatagent/info |
Disabled → 503 | chatagent_http_test.go, BDD chat HTTP |
| R-02 | List / create / close sessions | GET|POST /chatagent/sessions, DELETE …/:id |
Closed → not found for owner ops; create body workspace (empty = config root, one first-level subdir); nested / hidden / missing dir → 400 and no leftover active session |
unit + chat_agent_chat_spec_test.go |
| R-03 | List messages / plans / todos | GET …/messages, GET …/plans, GET …/todos |
Empty history; user rows may include attachments[]; missing session workspace dir still lists history |
unit HTTP tests |
| R-03a | Session trajectory | GET …/trajectory |
Old sessions omit SYSTEM/CONTEXT when no turn_trace; owner 404/403 same as messages |
trajectory_test.go, chatagent_http_test.go |
| R-04 | Send message (full SSE stream) | POST …/messages JSON {text, attachments?} |
Empty text and no attachments → 400; run in flight 409; max 8 attachments; MIME allowlist; model missing modality → 400; turn_trace is primary-channel only (not /events) |
chat_agent_chat_spec_test.go, multimodal unit tests, protocol_test.go |
| R-04a | Upload session media | POST …/media multipart |
Strict MIME allowlist; binds (session_id, owner); requires media public base when FS signing needed |
media upload tests |
| R-04b | Modality gate | Before run | Audio/video Reject until catalog marks ModalityAudioIn/ModalityVideoIn; unknown models allow image only |
modality reject tests |
| R-05 | Subscribe session events | GET …/events |
Client disconnect; buffered hub | session_events_test.go |
| R-06 | Confirm / cancel run | POST …/confirm, POST …/cancel |
Unknown confirm 404; already resolved 409 | confirm unit + BDD plan mode |
| R-07 | Session mode get/set | GET|PUT …/mode |
Plan vs normal | chat_agent_chat_spec_test.go, plan mode tests |
| R-08 | Clear session permission grants | DELETE …/permission-grants |
permission session tests | |
| R-09 | Permissions get/put/delete | GET|PUT|DELETE /chatagent/permissions |
Invalid config | HTTP + permission tests |
| R-09a | Approval mode get/put/delete | GET|PUT|DELETE /chatagent/approval |
Invalid mode | approval store/API + hook mode matrix |
| R-10 | Context usage / compact | GET …/context, POST …/compact |
Compaction no-op; missing session workspace dir → 400 (no fallback to config root) | context_usage tests, agents page context |
| R-11 | Export session | GET …/export |
export tests | |
| R-12 | Resolve resource URI | GET /chatagent/resources |
plan://, file:// |
chat_agent_spec_test.go resources It |
| R-13 | Scheduled tasks CRUD + runs | /chatagent/scheduled-tasks… |
One-shot complete; cancel | scheduled_api_test.go, chat_agent_scheduled_task_spec_test.go |
| R-14 | Session model / thinking settings | GET|PUT …/settings; create body model / thinking_level / workspace; AgentInfo.selectable_models |
Unknown model / invalid level → 400; empty fields → runtime yaml/default; PUT workspace → 400 (immutable after create) |
settings_test.go, chatagent_http_test.go |
3. Web chat UI (/service/web/agents/*)
| ID | Behavior | Entry | Edge cases | Tests |
|---|---|---|---|---|
| W-01 | Agents home: composer + session list | GET /service/web/agents |
Unauthenticated → login; composer workspace options SSR from config root + first-level non-hidden subdirs | agents_page_spec_test.go |
| W-01a | Session list: auto title, last-message preview, day groups, pin/archive, status filters | GET /service/web/agents/list?filter=; POST|DELETE …/:id/pin|archive |
Default hides archived; running / needs_approval from runtime gates | agents_webservice_test.go, helpers/day-group unit tests |
| W-02 | Create session (+ optional pending prompt) | POST /service/web/agents |
?prompt= / sessionStorage pending key; create body workspace (empty = config root); nested / hidden / missing dir → 400 and no leftover active session |
agents page + JS pending prompt; agents_webservice_test.go |
| W-03 | Chat page hydrate history | GET /service/web/agents/:id |
Closed session; missing session workspace dir still renders history | agents page |
| W-04 | Send message / cancel / confirm | Web posts under /agents/:id/… |
Approval once/always/reject; reopen page replays pending confirm; run_complete reloads history; empty text OK when attachments present |
chat BDD helpers; unit confirm; pending SSR |
| W-04a | Composer media (upload + paste image) | Two-step: upload media then send with file_ids |
MIME allowlist; max 8; modality Reject / missing public_base_url surfaced in UI |
chatagent-chat.js + media unit/HTTP tests |
| W-05 | Context ring + popover | GET …/context + JS |
Token window zero; Skills list collapsed until opened | agents_page_spec_test.go context It |
| W-06 | Streaming markdown + tool cards + thinking + todo panel | public/js/chatagent-*.js |
Open code fence delay; tool upsert; tool/thinking collapse; codeblock chrome; jump-to-bottom | chat BDD stream done; chatagent_message_test.go |
| W-11 | HTML artifact preview (present_html) |
tools/htmlpreview, chatagent-html.js, tool card iframe sandbox="allow-scripts" (no allow-same-origin) + injected CSP meta |
256KB cap; same id latest iframe only; superseded cards drop Preview/Source; no new SSE type (html/artifact_id/call_id on existing tool events); plan mode allowed; not on subagent/pipeline |
htmlpreview tests, transform redact test, event_stream_test.go, memory_registry_test.go, pipeline_run_test.go, chatagent_message_test.go |
| W-10 | Trajectory view | Chat | Trajectory on the thread; GET …/trajectory; Duration gantt + Preview/Raw inspector |
?view=trajectory; composer stays; no SYSTEM/CONTEXT without turn_trace; thread.js forwards turn_trace SSE |
agents_page_spec_test.go, chatagent_message_test.go, agents_webservice_test.go |
| W-07 | Close session | DELETE /service/web/agents/:id |
agents page | |
| W-08 | Model + thinking controls | Composer + thread settings bar; GET|PUT …/settings |
localStorage defaults; empty DB falls back to yaml chat_model; workspace picker is create-time only (thread shows read-only label; PUT workspace → 400) |
agents page + chatagent-chat.js |
| W-09 | Approval flow UX | Nav/Home pending-approval badge; docked session approval bar; Allow once / Always allow matching copy | Badge count from runtime gates; always button only when pattern suggested; auto-mode escalate hides Always | session_activity_test.go, helpers/home/message unit tests; GET /service/web/approval-badge |
| W-09d | Auto approval mode | Permissions page mode selector; flagged tools reviewed by aux LLM; deny circuit breaker | Autonomous ignores auto; reviewer fail → escalate | pkg/agent/approval, approval_hook_test.go |
| W-12 | Outbound MCP tools | chat_agent.mcp_servers; tools mcp_<server>_<tool>; permission mcp.<name> |
No self /mcp; stdio YAML only; DCG skipped |
tools/mcp, pkg/agent/permission MCP tests |
| W-09e | Tool loop detection | chat_agent.loop_detection; generic/no-progress/ping-pong warn→block via doom_loop; global + post-compaction Terminate |
Blocked calls not recorded; overflow-retry compaction arms post-compaction only | pkg/agent/loopdetect, loopdetect_hook_test.go |
| W-09a | Background attention for approval | Tab title ● Needs approval while confirm pending; desktop Notification when tab is hidden (permission via user gesture) |
Permission denied/default is silent; focus tab on notification click; clear title on resolve | public/js/app.js, public/js/chatagent-approval.js |
| W-09b | Approval inbox + deferred external | Framework agent.approval via GatewaySend (inapp ± default); open session / resolve / cancel marks read and cancels deferred |
Plan mode still blocks send_notification; ConfirmGate not persisted |
approval_notify.go, confirm_test.go; Inbox /service/web/inbox* |
| W-09c | Inbox UI | Global bell + /service/web/inbox; unread default; deep-link open marks read |
System inapp channel immutable; open redirect only /service/web/* |
inbox_webservice.go / inbox_webservice_test.go |
4. Permissions UI
| ID | Behavior | Entry | Edge cases | Tests |
|---|---|---|---|---|
| Q-01 | Permissions page render | GET /service/web/chatagent-settings |
chatagent_permissions_webservice_test.go |
|
| Q-02 | Save form / JSON / reset | POST …, POST …/reset |
Field validation errors | same |
| Q-03 | REST permissions parity | /chatagent/permissions |
Defaults when empty | BDD permissions It |
5. Skills / Memory / Subagents / Scheduled (Web admin)
| ID | Behavior | Entry | Edge cases | Tests |
|---|---|---|---|---|
| A-01 | Skills CRUD + files + zip import + enable/disable | /service/web/agent-skills… |
Enable/disable; Import zip | agent skills webservice tests / pages |
| A-02 | Memory facts list/upsert/delete | /service/web/agent-memory… |
Scope isolation; pin | memory webservice tests |
| A-02b | Session summaries browse/search/retry | /service/web/agent-session-summaries… |
Archive-only generation | session summary tests |
| A-03 | Subagents CRUD + tasks | /service/web/agent-subagents… |
Seed defaults on enable | subagent specs/tests |
| A-04 | Scheduled tasks list/detail/state | /service/web/agent-scheduled-tasks… |
Pause/resume | agent_scheduled_tasks_page_spec_test.go |
| A-05 | Session inspect UI | /service/web/agent-sessions… |
Entry payload, events, confirm, todos | agent_sessions_page_spec_test.go |
6. Orchestration capabilities
| ID | Behavior | Entry | Edge cases | Tests |
|---|---|---|---|---|
| O-01 | Interactive Service.Run / RunAPI |
service.go |
Session lock; harness pool reuse | service_test.go, BDD |
| O-02 | Plan mode blocks writes until confirm/normal | mode + permission hooks | Return to normal allows write | chat_agent_spec_test.go plan It |
| O-03 | Confirm gate (once / always / reject) | confirm.go |
Pattern suggest | confirm tests + BDD |
| O-04 | Harness pool TTL / config hash refresh | harness_pool.go |
Evict on close/abort; missing session workspace dir hard-fails harness create (no fallback to config root) | harness-related tests |
| O-05 | Session title generation | title.go |
LLM disabled for tests; media-only turns use [image]/[audio]/[video] placeholders |
title_test.go, BDD title wait helpers |
| O-05a | Multimodal user turns | RunRequest.Attachments → MediaPart (file_id); provider-aware URL or Binary hydrate |
Session-scoped ownership; re-sign/hydrate per run; tool-model strip media parts | transform + service multimodal tests |
| O-06 | Manual + automatic compaction | CompactSession, ctxmgr |
compaction / context tests | |
| O-08 | Pipeline agent step (ephemeral) | pipeline_run.go / RunPipelineAgent |
Tools/skills allowlist; memory default off | pipeline_run_test.go, ephemeral_run_test.go |
| O-09 | Scheduled autonomous run + delivery | scheduled_run.go, scheduler |
Isolated session; permission policy | chat_agent_scheduled_task_spec_test.go, scheduled_* tests |
| O-10 | Skills tool / memory tool / delegate_subagent tool / todo tools / present_html | registry + tools | Allowlists for subagents; present_html not on subagent/pipeline | skills/memory/subagent/todo/htmlpreview tests |
| O-11 | Sensors / progress / usage recording | sensors, progress, usage_record | unit tests | |
| O-12 | Prompt cache | prompt_cache.go |
Invalidation on config change | prompt_cache_test.go |
| O-13 | Persist turn_trace |
executeRun after prompt assembly, h.Session().Append |
Skip RunKindPipeline; one node per Run; publish SSE when API publisher is set |
service.go / trajectory persist tests |
7. Out of scope / non-goals for this remediation
- Rewriting
pkg/agentloop/harness core - Merging
/chatagentand/service/web/agentsroute prefixes - Desktop agent protocol (
pkg/types/agent.go/internal/server/agent.go) - Public HTML artifact share URLs, workspace HTML export,
get_html, right-hand canvas
QA self-test (manual)
Use after each vertical slice and before freeze sign-off.
- Platform: send one DM (Slack if available) — streaming or final reply, message persisted.
- Web: create session from
/service/web/agents, send a turn, see SSE done and history hydrate. - Approval: trigger a gated tool — Allow once; repeat with Always allow matching; Deny path. Confirm Nav/Home badge count and docked approval bar. With the tab in background, confirm tab title shows
● Needs approvaland (if Notification permission granted) a desktop notification; resolve clears the title. - Plan mode: set plan → blocked write → switch normal → write works.
- Compact: call compact on a long session; context ring updates.
- Scheduled: create one-shot task, wait for completed + run row.
- Skills: toggle/enable a skill and confirm agent can
read_skill. - Knowledge: create a markdown doc in Agent Knowledge; confirm agent can
search_knowledgethenget_knowledgeby path. - Memory: fact CRUD via UI or
memory_*tools; session summaries via archive + search tool. - Subagent: run a delegate_subagent tool delegation; progress/tool events appear.
- Permissions: save form, reset to defaults; session grants clear; Knowledge key defaults to allow.
- Export: download/export session JSONL or documented format.
- Title: first user message eventually updates session title (or test-disabled path).
- REST smoke:
POST /chatagent/sessions/:id/messagesSSE reachesdone;GET …/eventsreceives hub events when a run publishes. - Multimodal: upload an image via
POST …/media, send with attachments (optional empty text) on a vision-capable model; history shows attachment; audio/video on unmarked models returns 400. - Workspace: create a session from a first-level subdirectory on the composer picker; thread shows a read-only workspace label; changing it via settings is rejected. Delete that subdirectory and confirm history still loads while a new run fails.
Appendix A — Schedule / stream duplication audit (WS-B)
See chatagent-remediation-audit.md.
Appendix B — chatagent ↔ pkg/agent boundary audit (WS-C)
See chatagent-remediation-audit.md.
Maintainer guides: internal/server/chatagent/AGENTS.md, internal/modules/web/AGENTS.md (chatagent JS guardrails).
Warranty note
Regressions introduced directly by this remediation are in scope for fix within two weeks of checklist freeze. Checklist gaps discovered later require updating this document before code changes.