feat(notes): add workspace notes and guided AI setup - #3
Merged
Conversation
createNoteStore, the card-indicator cache, and the modal factory take a (scope, scopeId) pair instead of a hardcoded "task" scope (taskId remains a working alias, so every existing task surface is unaffected). Registers a new sidebar-workspace-actions button that opens the same note modal scoped to the active workspace instead of a task, inert on hosts that don't carry that slot yet.
The enhance webhook's 412 body now carries a stable, machine-readable code (agent_unset/agent_missing/agent_disabled/agent_unavailable), classified from the host's real FailedPrecondition message, plus the raw message as detail. The UI maps each code to its own guided-setup action button (Settings > Plugins > Notes for unset/missing, Settings > Utility Agents for disabled) instead of one message pointing everyone at the same page regardless of which setting is actually missing. An older server that omits code still gets today's plain-message behavior.
README documents the new sidebar workspace-notes button and the two-step Enhance with AI setup (select an agent, then enable it with a model under Settings > Utility Agents), including the Enabled asymmetry between kandev's own prompt enhancement and plugin utility-agent calls.
agent_unavailable is by definition a FailedPrecondition the plugin could not classify, but its message named Settings > Plugins > Notes anyway. That is reachable today, not hypothetically: host_utility.go has a fourth wording, "configured utility agent %q has no usable agent profile", fired when an agent is selected and enabled but its model/profile is still unbound - the state every built-in utility agent ships in. Following the README's own two-step setup lands there, and the message sent the user back to the page they had already used correctly, with no action button. The message now quotes the host's own wording instead of guessing a remedy, which is the degradation the classifier was designed for: a missing button, not a wrong instruction. Routing that case to its own code and action button is left to the author - C1 fixes the code set at four, so adding a fifth is a scope decision, not a QA fix. Also fixes the workspace note editor showing "Jot a note about this task..." under a modal titled "Workspace notes - <label>". Verified against a real host (isolated instance, plugin 0.3.0 installed via the real install API): all four states reproduced before and after, the three classified ones unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
host_utility.go has a fourth FailedPrecondition wording, "configured utility agent %q has no usable agent profile", fired when an agent is selected and enabled but its model/agent profile is still unbound. That is not an edge case: every built-in utility agent ships that way, so it is the state a user lands in immediately after completing the README's two documented setup steps. It previously fell through to agent_unavailable, which rendered no guided-setup button at all - the one case most likely to need it. It now has its own agent_unconfigured_profile code and a "Finish setting up the agent" action pointing at Settings > Utility Agents. Kept separate from agent_disabled deliberately: same page, different control, and telling someone to enable an agent they just enabled is the dead end this mapping exists to remove. agent_unavailable now means only "a cause this plugin could not identify" and keeps quoting the host's own wording. This widens C1's four-code enumeration to five, approved by the author after QA confirmed the gap live. Verified end to end on an isolated instance with the real 0.3.0 package: the repro now returns agent_unconfigured_profile with the correct message, the served bundle carries the new action, and unset/missing/ disabled/400 are unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The "Added" bullet still enumerated four codes (unset/missing/disabled/unavailable) after bbb3160 added agent_unconfigured_profile in the same release. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The QA pass recorded the plugin-webhook auth finding as "tracked nowhere" after the original subtask was deleted. A replacement task (51781b28-0580-48e7-ac31-a732b07e3ddb) exists and is in progress, so the claim is false and would have shipped verbatim into both PR descriptions. Restore the citation and correct the release-trigger note to list all three files the prepare job rewrites. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
All three repos (kdlbs/kandev, yattdev/kandev, yattdev/kandev-plugin-notes) are public and the webhook auth issue is unpatched upstream, so the PR-bound notes no longer carry its file, line, mechanism or blame attribution. The entry keeps the finding's existence, its irrelevance to this branch, and a pointer to tracking task 51781b28; it now directs the disclosure to a private upstream channel instead of an @-mention in a public PR. Flagged in the file as a QA call the author can veto. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
yattdev
marked this pull request as ready for review
August 18, 2026 01:19
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
This updates
kandev-plugin-notesfor workspace-scoped notes and fixes the dead-endEnhance with AIsetup path. It reuses the existing notes editor surface, preserves task-note behavior, and makes configuration failures point to the correct settings page.Changes
(scope, scopeId)pairs while preserving task-note callers.0.3.0and update the README and changelog for workspace notes and AI setup.Motivation
Users need a workspace-level scratchpad that does not require creating a task, and the existing AI enhance error collapsed distinct setup failures into one wrong remedy. These changes add the missing workspace scope and make the AI setup path diagnosable and actionable.
Testing
go test ./...node --test "ui/**/*.test.mjs"git diff 777992c..HEAD -- manifest.yaml ui/ server/ Makefileis emptyBreaking Changes
None.
QA handoff
QA fixes worth reviewer attention
None this pass. No defect was found in either PR's changes, so nothing was fixed and no commit was added. Both worktrees are unchanged and clean (plugin
3044930, host0f8c8f4cb).Earlier QA passes contributed two documentation commits that remain relevant to reviewers:
.kandev/review-notes.mdcarried the file, line, mechanism and blamed author for an authentication weakness that is still unpatched inkdlbs/kandev. All three repos involved are public, so publishing it in a PR description would have disclosed it and would also have notified the blamed author by @-mention on a public thread — the wrong channel for a security issue. The entry now keeps the finding's existence, its irrelevance to this branch, and a pointer to its tracking task, and directs the disclosure upstream privately. Commit3044930.9681dd3.Assumptions made during QA
3044930. Confirm?kdlbs/kandev, or direct contact with the maintainers) rather than by @-mentioning the blamed author in a public PR. Confirm?v0.3.0tag, not by dispatching the release workflow manually. The branch's hand-set0.3.0inmanifest.yaml/Makefileand the hand-written## [0.3.0]CHANGELOG section are correct for the tag-push path (prepareis skipped;publishbuilds straight from this metadata). A manualworkflow_dispatchinstead computesmax(manifest, latest tag)and bumps past it, so the defaultpatchchoice publishes 0.3.1, rewrites the version inmanifest.yaml,Makefileand theREADME.mdtarball name, and prepends a generated## [0.3.1]section above the hand-written## [0.3.0]one — two changelog entries for one set of changes, and no 0.3.0 release at all. Notepreparealso hard-requiresrefs/heads/main, so a dispatch cannot run from this branch anyway. Nothing in the code depends on the number, so this is a release-time choice, not a defect. Confirm the tag-push path?Pre-existing issues found (out of scope, tasks created)
A pre-existing authentication weakness in the host's plugin-webhook routing, confirmed live during an earlier QA pass. Pre-existing and not introduced by either PR; the code it lives in is untouched by this branch. Tracked in task
51781b28-0580-48e7-ac31-a732b07e3ddb, which holds the location, mechanism, reproduction, blame and three suggested remedies. That task is now the only record of the detail, so it should not be closed without action. Deliberately not described further here — see the assumptions above.One e2e test in the host repo fails before this branch touches anything.
apps/web/e2e/tests/plugins/plugin-task-panel.spec.ts:247("useNotesValue discards a stale storage read that resolves after a newer one") fails deterministically — 5 runs, 0 passes. It fails at the panel-mount step, before reaching the stale-read behavior it is named for, which points at a timing assumption that does not hold on a slower machine rather than a product defect. Proven not to be this branch's doing by reverting each of the branch's two shipped host changes independently and re-running: it fails identically in all three configurations. Tracked in taskd059af5a-73a6-41c9-afeb-a8a6a7a96ac4. cc @yattdev — introduced in345ea1216("feat(plugins): add task panel, menu, and storage hooks", #2152).Enhance with AIaccepts an empty result and lets Accept wipe the note.enhanceNotevalidates that the returned content is a string but not that it is non-empty, so a utility agent returning""(or whitespace only) produces an empty preview whose Accept button replaces the user's note with nothing, autosaved, with no undo. Pre-existing — both lines predate this branch's base commit — and out of scope here, but directly adjacent to subtask C's work. One-line fix suggested in the task. Tracked in task410a7934-52a4-4752-9cf9-c636a3bf485a. cc @yattdev — introduced in4c84eb9("feat: markdown toolbar, AI-assisted proofreading, and a fixed-size note modal").QA verification performed this pass
No shipped byte has moved since the last full live verification (
git diff 777992c..HEAD -- manifest.yaml ui/ server/ Makefileis empty; host unchanged at0f8c8f4cb; both trees clean). This pass therefore targeted surface the earlier rounds had not attacked, rather than re-running identical binaries:plugin-sidebar-workspace-actions.spec.ts3/3, and the fulle2e/tests/plugins/directory 31 passed / 1 failed / 2 skipped (the one failure is the pre-existing test above). The e2e fixture package was rebuilt from source for this run.apps/web/app/settings/file existence, which stopped being sufficient when this app migrated from Next.js to a Vite SPA./settings/utility-agentsis a static route (apps/web/src/settings-routes.tsx:166);/settings/plugins/kandev-plugin-notesmatches the dynamic/^\/settings\/plugins\/([^/]+)$/branch and rendersPluginDetailPage. Neither button navigates to a dead page.code(number, null, object, array) degrades toundefinedand renders no action button;enhanceErrorActionreturnsnullfor junk, wrong case, and trailing whitespace; oddscopeIdvalues thread through to the right storage calls. C5's robustness holds well beyond what is asserted in the suite..kandev/by construction, not by inspecting one build:make package/package-hostbuild a fresh$(STAGE)from explicitcpofmanifest.yamlandui/bundle.jsonly, so the result is independent of what the working tree contains. That matters because.kandev/review-notes.mdhas changed content since it was last checked withtar tzf.go test -count=1 ./...ok (cache bypassed), pluginnode --test96/96, hostgo test ./internal/plugins/...ok across all 9 packages, host full vitest 10416 passed / 4 skipped / 0 failed across 1299 files.apps/web/distrebuilt from restored source, branch e2e re-verified 3/3, and both worktrees confirmed clean.make packagecross-compile; hostapp-sidebar-new-task-item.test.tsx24/24; version strings agree acrossmanifest.yaml,MakefileandCHANGELOG.md(all 0.3.0), which is the release job's own consistency check.One caveat stated plainly: this pass did not repeat the manual browser walkthrough of B3-B5 (typing a workspace note, watching the icon flip live, cross-tab edit). Those were verified live in an earlier pass against an artifact this pass proved byte-identical, so the result carries over — but it is inherited evidence, not something re-observed today.