Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions .kandev/review-notes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Review notes

These notes cover **both** PRs on `feature/per-workspace-notes-ac1`: this plugin
repo (`yattdev/kandev-plugin-notes`) and the host repo (`yattdev/kandev`). They
live here because `kandev-source` gitignores `/.kandev/` by design, so the file
cannot be committed there — fold the entry below into the host PR description
as well as this one.

## Known issue found during review (out of scope for these PRs)

- **A pre-existing authentication weakness in the host's plugin-webhook
routing.** Confirmed live during QA. Location, mechanism, reproduction, blame,
and three suggested remedies are recorded in task
`51781b28-0580-48e7-ac31-a732b07e3ddb`.

The specifics are deliberately withheld here. `kdlbs/kandev`,
`yattdev/kandev` and this repo are all public and the issue is unpatched
upstream, so a PR description is both the wrong place to publish it and the
wrong channel to notify the blamed author through. Route it upstream
privately — a GitHub security advisory on `kdlbs/kandev`, or a direct message
to the maintainers — rather than by @-mentioning anyone in this PR.

Pre-existing and **not introduced by this branch**; the code it lives in is
untouched by either PR. Observed on `feature/per-workspace-notes-ac1` at
plugin `777992c` / host `0f8c8f4cb`. The author reviewed it this cycle and
decided to ship as-is and track it separately, so nothing on either branch
changes for it.

## Action required by author

- **Confirm the webhook finding's tracking task is the one you want to keep.**
It now lives in task `51781b28-0580-48e7-ac31-a732b07e3ddb`, which carries the
full repro, the cause, and three suggested remedies. An earlier task for the
same finding was opened and then deleted mid-cycle. Because the detail is now
deliberately kept out of this PR text, that task is the **only** record of it
— if it is closed without action, nothing preserves the finding.

- **Veto QA's redaction if you disagree with it.** QA removed the file, line,
mechanism and blame attribution from the entry above because all three repos
are public and the issue is unpatched upstream. That was QA's call, not a
decision you made — if you would rather the PR carry the full description,
revert that hunk; nothing else in the entry changed.

- **Release trigger matters for this branch.** `manifest.yaml` and `Makefile`
are hand-set to `0.3.0` and `CHANGELOG.md` carries a hand-written
`## [0.3.0]` section, which is correct for the tag-push path only: push
`v0.3.0` and `.github/workflows/release.yml` skips its `prepare` job and
publishes 0.3.0 straight from this metadata. Dispatching the same workflow
manually instead computes `max(manifest, latest tag)` and then bumps past it,
so the default `patch` choice would publish **0.3.1**, rewrite the version in
`manifest.yaml`, `Makefile` and the `README.md` tarball name, and prepend a
generated `## [0.3.1]` section above the hand-written
`## [0.3.0]` one, leaving two changelog entries for one set of changes and no
0.3.0 release. Push the tag.
34 changes: 34 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,39 @@
# Changelog

## [0.3.0] - 2026-08-11

### Added

- feat: per-workspace notes — a sidebar button (registered for the host's
`sidebar-workspace-actions` slot, inert on hosts without it) opens the same
note editor/modal scoped to the active workspace instead of a task
- feat: Enhance with AI now returns a stable, machine-readable failure code
(unset/missing/disabled/unconfigured-profile/unavailable) and a guided-setup
action button that
jumps to the correct settings page instead of one message for every cause

### Changed

- `createNoteStore` and the card-indicator cache are now scope-generic
(`scope`/`scopeId` instead of a hardcoded "task"); existing task callers are
unaffected (`taskId` remains a working alias)

### Fixed

- Enhance with AI now recognizes a fifth state: an agent that is selected and
enabled but has **no model or agent profile bound** — the state every
built-in utility agent ships in, and therefore what most people hit right
after following the documented two-step setup. It gets its own
`agent_unconfigured_profile` code and a "Finish setting up the agent" button
pointing at Settings > Utility Agents. Previously it fell through to
`agent_unavailable`, whose message sent the user back to Settings > Plugins >
Notes — the step they had just completed correctly
- `agent_unavailable` now means only "a cause this plugin could not identify".
It names no settings page (any page would be a guess) and quotes the host's
own wording instead
- The workspace note editor no longer shows the task-scoped placeholder
("Jot a note about this task…") under a modal titled "Workspace notes"

## [0.2.3] - 2026-08-11

### Changed
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
.PHONY: build run test fmt vet package package-host clean

BIN := bin/kandev-plugin-notes
VERSION := 0.2.3
VERSION := 0.3.0
STAGE := .build/stage
PKG_OUT := kandev-plugin-notes-$(VERSION).tar.gz

Expand Down
77 changes: 65 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,16 @@ editor and optional AI-assisted proofreading.
overwritten automatically. See "Notes are private to you" below for the
privacy trade-off this makes.
- **Card indicator** — a small glyph on cards that have a note.
- **Workspace notes** — a small book icon beside Quick Terminal and Quick Chat
in the sidebar's New Task row (on a host build that carries the
`sidebar-workspace-actions` slot) opens the same editor, modal, toolbar,
Preview, and Enhance with AI included, scoped to the active **workspace**
instead of a task. Use it for a half-formed idea or a reminder that isn't
worth creating a task to hold. The icon is muted when the workspace has no
note and full-contrast once it does, and flips live (no reload) as the note
is written, emptied, or edited from another tab. A task's note and its
workspace's note are stored and shown independently; the icon is not
rendered without an active workspace.
- **Cross-tab sync** — an edit in one tab shows up in another without a reload.

## If a note won't load
Expand All @@ -81,24 +91,69 @@ otherwise save over an existing note the read never actually saw.

## Notes are private to you — except when you ask AI to enhance one

Each note is stored per **user**, per **task**, under the plugin's own key
(`("task", <taskId>, "note")`) via Kandev's per-user plugin storage
(`capabilities.user_state`). Two people looking at the same task each see their
own note; nobody else can read yours, and the agent working the task cannot
Each note is stored per **user**, per **task or workspace** (whichever you
opened), under the plugin's own key (`(scope, id, "note")`, `scope` being
`"task"` or `"workspace"`) via Kandev's per-user plugin storage
(`capabilities.user_state`). Two people looking at the same task or workspace
each see their own note; nobody else can read yours, and no task's agent can
read or write it.

**The one exception is the "Enhance with AI" button.** Clicking it sends the
note's current markdown to the utility agent configured for this plugin
(**Settings > Plugins > Notes**) via a one-shot completion
(`capabilities.agent_invoke` / `Host.InvokeUtilityAgent`) — that content
leaves the "nobody else can read it" boundary for that one request. If no
utility agent is configured, the button shows a clear, non-fatal message
instead of failing silently. Skip the button entirely to keep a note fully
private.
leaves the "nobody else can read it" boundary for that one request. See
"Setting up Enhance with AI" below for what has to be configured first, and
what each failure message means. Skip the button entirely to keep a note
fully private.

If you want the task's own agent to see something, put it in the task
If you want a task's own agent to see something, put it in the task
description or say it in chat. This is a scratchpad, not a shared field.

## Setting up Enhance with AI

"Enhance with AI" needs **two separate settings**, both satisfied, before it
can run:

1. **Select an agent for this plugin** — Settings > Plugins > Notes,
`config_schema.utility_agent`. This is what tells the plugin which
utility agent to ask.
2. **Enable that agent, with a model** — Settings > Utility Agents. Selecting
an agent in step 1 does not enable it; a newly-added utility agent starts
disabled with no model chosen.

Both steps are required because **a disabled utility agent is usable by
kandev's own built-in features (e.g. task-create prompt enhancement) but not
by any plugin**, including this one. Kandev's own prompt-enhancement path
does not check `Enabled`; this plugin's request goes through
`Host.InvokeUtilityAgent`, which does. That asymmetry is host behavior this
plugin cannot change — clicking Enhance with an agent selected-but-disabled
fails exactly like having no agent selected at all, and the two failures now
say so explicitly rather than both pointing back at Settings > Plugins > Notes:

| Situation | Message points you to |
| --- | --- |
| No agent ever selected | Settings > Plugins > Notes |
| Selected agent was since deleted | Settings > Plugins > Notes |
| Selected agent exists but is disabled | **Settings > Utility Agents** ("Enable the agent") |
| Selected and enabled, but no model / agent profile bound | **Settings > Utility Agents** ("Finish setting up the agent") |
| Any other setup problem the plugin can't identify | no page named; the host's own wording is quoted instead |
| A real execution failure (the agent ran and failed) | no settings link — try again |

For the first four, **Dismiss** is joined by a second action button that
jumps straight to the right page for that cause, so there's no need to guess
which setting is missing.

The fourth row is the one most people hit, because **every built-in utility
agent ships with no model bound**: completing steps 1 and 2 above still leaves
it unconfigured. It is called out separately from "disabled" on purpose —
both are fixed on the same page but by different controls, and being told to
enable an agent you just enabled is the dead end this plugin exists to avoid.

The fifth row is the honest fallback: a `FailedPrecondition` this plugin does
not recognize (for example after a host rephrase). It names no page, because
any page it named would be a guess, and quotes the host's own wording instead.

## Install

Until the first release is published, install by sideload — build a package and
Expand All @@ -113,9 +168,7 @@ curl -F "package=@kandev-plugin-notes-<version>.tar.gz" \
Sideloaded plugins register disabled/unverified; enable it in
**Settings > Plugins**. Reinstalling the same version returns 409 — bump the
version in `manifest.yaml` (and `Makefile`) first. To use "Enhance with AI",
also pick a utility agent for this plugin under **Settings > Plugins > Notes**
(`config_schema.utility_agent`) — without one, the button surfaces a
not-configured message rather than failing.
see "Setting up Enhance with AI" above — it's a two-step setup, not one.

## Development

Expand Down
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ require (
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/oklog/run v1.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect
golang.org/x/net v0.56.0 // indirect
golang.org/x/sys v0.46.0 // indirect
golang.org/x/text v0.39.0 // indirect
Expand All @@ -33,3 +34,5 @@ require (
// layout this path assumes, and what changes once pkg/pluginsdk ships as its
// own versioned module.
replace github.com/kandev/kandev => ../kandev/apps/backend

tool github.com/kandev/kandev/cmd/plugin-pack
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
Expand Down Expand Up @@ -36,6 +38,8 @@ github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA=
github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
Expand Down
4 changes: 2 additions & 2 deletions manifest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
# (/api/plugins/<id>/...). Keep the three in sync when bumping version.
id: "kandev-plugin-notes"
api_version: 1
version: "0.2.3"
version: "0.3.0"
display_name: "Notes"
description: "A private, per-user scratchpad note on any task: a dockview/mobile panel, markdown editing with a formatting toolbar, AI-assisted proofreading, and a kanban card shortcut."
description: "A private, per-user scratchpad note on any task or workspace: a dockview/mobile panel, a sidebar workspace-notes button, markdown editing with a formatting toolbar, AI-assisted proofreading with guided setup, and a kanban card shortcut."
author: "yattdev"
categories: ["tools"]
repo_url: "https://github.com/yattdev/kandev-plugin-notes"
Expand Down
Loading
Loading