Create Kandev Plugin
Build Kandev runtime plugins from the official template and current public
contracts. Keep plugin source outside the Kandev monorepo and prove the packaged
artifact against a disposable development instance before publishing it.
Start with the canonical plugin authoring guide.
Use this skill for the repository workflow after choosing a recipe there:
choose recipe → edit manifest → implement → validate → package → smoke test.
The guide owns the complete hook/Host matrix; this skill keeps the repository
and verification procedure concise.
Establish The Boundary
- Invoke this skill only when the user intends to create, change, fix, test,
package, release, or submit a Kandev runtime plugin. A passing mention of
plugins, a generic extension request, or the presence of plugin host code in
the Kandev monorepo is not sufficient.
- Confirm the artifact: a Kandev runtime plugin ships a
manifest.yaml, a
platform executable built with the Go pluginsdk, and optionally a native
UI bundle. Agent instruction packages, MCP servers, and other products that
also use the word "plugin" are outside this skill.
- Classify the work as a new plugin, an existing plugin change, a Kandev host
or SDK dependency required by the plugin, or a marketplace-only change.
- Keep each production plugin in one dedicated repository. For an official
plugin, use a public
kdlbs/kandev-plugin-<slug> repository. For a community
plugin, use the author's public repository. Do not add a production plugin
implementation to kdlbs/kandev; the in-tree plugin fixture is test support,
not a starter location.
- Keep host API, SDK, registry runtime, and plugin-loader changes in the Kandev
repository. If the plugin needs a missing host capability, treat that as a
separate Kandev change with its own tests and compatibility review.
Resolve The Owning Repository
Resolve the plugin repository before editing, especially for bug reports:
- Start with repository information in the request, issue, pull request, or
current task. Otherwise match the manifest
id and repo_url against the
official catalog entry or the installed plugin metadata. Do not infer that a
similarly named fixture or host package in kdlbs/kandev owns the bug.
- Check the repositories already materialized for the current task and locate
the worktree whose manifest id matches the target plugin.
- When running as a Kandev task and the repository is not attached, discover
and call
add_branch_to_task_kandev with exactly one of repository_url,
repository_id, or local_path. It defaults to the current task and can
find or add a repository to the workspace, then materialize its branch as a
separate worktree.
add_branch_to_task_kandev only works with the Worktree executor. For other
executors, or when the task tool is unavailable, ask to attach the repository
or create a related task that explicitly targets it. Do not clone a nested
repository inside the Kandev monorepo worktree.
- Change the working directory to the plugin worktree and read its local agent
instructions, manifest, build files, tests, and release workflow. For a bug,
reproduce and fix the behavior there with
/fix and /tdd, then retain this
skill's artifact verification. If the fix also needs a Kandev host or SDK
change, keep the two repository deliverables and verification steps explicit.
Understand The Runtime Model
Treat a plugin as two independently loaded surfaces joined by the manifest:
package tarball -> validate + extract -> supervised plugin executable <-> Host gRPC
|-------> static UI bundle -> browser plugin registry
Kandev event bus -> bounded per-plugin delivery queue -> OnEvent
external or UI request -> declared webhook route -> HandleWebhook
- Kandev owns the executable lifecycle. It starts the declared host-platform
binary with the install directory as its working directory, injects a fresh
Host connection on every start, and supervises crashes and failed health
checks. Do not launch a second long-running server from the plugin.
KANDEV_PLUGIN_DATA_DIR is the plugin-owned durable file directory. It
survives restarts and version upgrades and is deleted on uninstall. Host
state is the better fit for small JSON objects that should participate in
Kandev backups.
- Install attempts to activate the plugin immediately. Disable preserves its
config, state, secrets, versions, and data; uninstall removes them. A config
update restarts an active plugin, so load configuration during startup.
- The UI bundle is served from the extracted package and does not pass through
the plugin process. Its
initialize and optional destroy hooks may run
repeatedly as a plugin is disabled and re-enabled in the same browser tab.
- Capabilities gate Host API methods; they are not an operating-system or
browser sandbox. The plugin executable inherits Kandev's process environment,
and the UI runs as same-origin JavaScript with host store access. Treat
installation as privileged code execution and hold official plugins to
dependency, credential, and data-access review.
Choose the narrowest surface that satisfies the behavior:
| Need |
Surface |
Contract to design for |
| React to Kandev activity |
OnEvent |
Retryable best-effort delivery, bounded in-memory queues, and possible loss require idempotency and reconciliation for critical workflows. |
| Receive an external call or relay a UI request |
HandleWebhook |
Only declared keys are routed; validate method, authentication, and provider signatures inside the plugin. |
| Store small structured data |
Host state |
Values are JSON objects keyed by scope and key; there is no transaction or compare-and-swap API. |
| Store files or use a plugin-managed database |
KANDEV_PLUGIN_DATA_DIR |
The plugin owns schema, locking, migrations, and recovery. |
| Read Kandev entities |
Typed Host readers plus api_read |
Use opaque pagination cursors and stable SDK DTOs; never query Kandev's database or internal HTTP API. |
| Mutate Kandev entities |
Typed Host writers |
api_write:tasks gates Tasks().Create/Update; api_write:messages gates Messages().Send. A missing mutation requires a separate Host API change. |
| Notify another plugin |
Host.EmitEvent |
Events are published as plugin.<id>.<name>; keep names and payloads versionable. |
| Add native interface |
UI registry and host.ui |
Use host-owned React and components so themes, contexts, portals, and mobile behavior remain compatible. |
Read The Current Contracts
Read these sources before designing the plugin:
docs/public/plugins-authoring.md for the supported backend, Host API,
native UI, recipes, packaging, install, and iteration workflow.
docs/public/plugins-manifest.md for the authoritative manifest fields,
capability gates, and event vocabulary.
docs/public/plugins-marketplace.md when publishing or updating a catalog
entry.
- The current
kdlbs/kandev-plugin-template repository, including its
README.md, Makefile, tests, and release workflow.
Marketplace attribution: The manifest author is independent from GitHub
repository ownership or organization. Never infer author kandev from a
kdlbs/kandev-plugin-* repository. Read and preserve the manifest author,
verify repo_url separately, and require an explicit contributor identity when
an externally maintained plugin is released.
Prefer the public authoring docs and current template over old examples. The
frontend contract pair is docs/plans/plugins/PLUGIN-API.md plus
apps/web/lib/plugins/types.ts; concrete UI exports are in
apps/web/lib/plugins/host-api.ts. The backend contract is
apps/backend/pkg/pluginsdk plus apps/backend/proto/kandev/plugin/v1/plugin.proto.
Read docs/plans/plugins/GRPC-CONTRACT.md when changing the wire contract or
when the public docs do not answer a low-level compatibility question.
The frontend and backend matrices in docs/public/plugins-authoring.md,
together with apps/web/lib/plugins/types.ts and apps/backend/pkg/pluginsdk,
are the authoritative record of what exists today. Read them rather than
asserting from memory that a hook is missing, and do not publish a signature
they do not declare.
When debugging a contract discrepancy, verify it at the implementation
boundary: manifest and package rules live under
apps/backend/internal/plugins/manifest and pkgtar; runtime, Host, webhook,
and delivery behavior live under apps/backend/internal/plugins; native UI
loading and registration live under apps/web/lib/plugins.
When Adding Or Changing A Hook
Treat a new hook, Host method, capability, manifest field, or mounted UI slot as
a contract change. Do not implement the runtime surface and leave author docs
for later. In the same change:
- Update the implementation boundary and its focused tests.
- Update the authoritative contract source:
- frontend:
docs/plans/plugins/PLUGIN-API.md plus
apps/web/lib/plugins/types.ts; update host-api.ts, registry.ts, or
the mounted component when the concrete surface changes;
- backend:
apps/backend/pkg/pluginsdk,
apps/backend/proto/kandev/plugin/v1/plugin.proto, and the manifest model
or validator when applicable; update docs/plans/plugins/GRPC-CONTRACT.md
for wire-level changes.
- Update
docs/public/plugins-authoring.md in the same change: add the hook to
the frontend or backend matrix, document inputs/props, capability and
lifecycle/cleanup behavior, and add a copy-pasteable recipe or maintained
fixture link. Adding the row to the matrix is the update — do not introduce
a separate "unavailable" list anywhere.
- Update
docs/public/plugins-manifest.md for capability/manifest changes and
update docs/public/plugins.md, docs/plugins-example.md, or the relevant
ADR when their claims or links change. Keep the public guide as a summary;
never create a second schema or type definition in prose.
When a public plugin page benefits from an architecture, lifecycle, data-flow,
or trust-boundary visual, use /diagram-design and its
references/kandev-public-docs.md integration guide. Publish a reviewed
local image with precise alt text and nearby explanatory prose.
- Recheck the root/backend/web
AGENTS.md authority pointers and this skill if
the source-of-truth locations or author workflow changed.
- Run the focused implementation tests plus
node --test scripts/validate-public-docs.test.mjs,
node scripts/validate-public-docs.mjs, and a stale-reference search. Report
the exact commands and results.
A hook absent from the relevant frontend/backend matrix and its corresponding
authoritative contract source does not exist yet; point the author at the
nearest supported recipe instead of publishing a speculative signature, and
do not record the gap as a durable list entry in this skill or an
AGENTS.md — the matrix and the contract sources are the only place
absence or presence is tracked. If the hook is implemented but the
matrix, recipe, fixture, or authoritative contract is missing, the plugin
change is not documentation complete.
Create A New Repository
Skip this section for changes to an existing plugin after resolving its owning
repository above.
- Derive a lowercase plugin id and repository name. For an official plugin,
use the full
kandev-plugin-<slug> value for both. Keep the manifest id,
Go module, Makefile binary and package names, UI registration id, release
asset name, and catalog id synchronized as the template documents.
- Create the repository from
kdlbs/kandev-plugin-template; do not hand-roll
files that the template already maintains.
- For official plugins, create or target
kdlbs/kandev-plugin-<slug> and set
repo_url to that public repository. Do not publish to the organization or
mutate repository settings unless the user requested that external action.
- Inspect repository-local instructions before editing. Replace template
identity and example behavior without deleting its packaging, test, or
release safeguards.
- Materialize the plugin as a sibling of the Kandev checkout, or update the
template's
go.mod replacement deliberately. Until the SDK is a standalone
module, the default replace resolves ../kandev/apps/backend.
If the requested repository does not exist and cannot be created with the
available GitHub tooling, stop after producing a precise repository bootstrap
request. Do not silently substitute a directory in the Kandev monorepo.
Implement With Least Privilege
- Write concrete behavior examples and failure cases before implementation.
Use
/tdd for backend and manifest logic.
- Declare only the capabilities the plugin exercises. Treat
api_read,
state, secrets, event subscriptions, and webhooks as permission
boundaries rather than descriptive metadata.
- Embed
pluginsdk.UnimplementedPlugin, override only required methods, and
access Kandev through the injected Host API. The Host can be unavailable
during construction and isolated tests, so resolve it when handling work.
Honor context cancellation and do not reach into Kandev internal packages,
its database, or undocumented REST endpoints.
- Make event handling idempotent by
EventID. Kandev makes one attempt plus
three retries after 5s, 15s, and 45s, using the same event id. Delivery is
sequential per plugin, but its queue and error-state buffer are bounded and
in memory; backend restarts and sustained overload can lose events. Add a
source-of-truth reconciliation path when missing an event is unacceptable.
- Keep operator credentials in
config_schema secret fields or the Host
secret APIs. GetConfig returns the plugin's own secret values in cleartext,
so never commit real credentials or log complete config objects.
- For a UI bundle, use
host.jsx, host.ui, host.store, and
host.api.fetch as documented. Do not bundle another React or Radix runtime.
Make initialize repeatable and use destroy to remove timers,
subscriptions, and side effects; Kandev revokes registered routes, slots,
handlers, styles, and navigation separately. Use /mobile-parity for
interaction design and /e2e for user-visible flows.
- API v2 webhook routes require a real Kandev caller identity by default. API
v1 keeps omitted access public for compatibility, so new plugins must use
API v2. Follow
docs/public/plugins-authoring.md for the current body-size and route
limits. Kandev rejects undeclared keys and, unless the manifest declares
webhooks[].public: true, rejects anonymous callers with 401 before your
handler runs. Only mark a webhook public when it is genuinely third-party
ingress (a provider callback, an SSO initiate/callback pair) that your own
handler authenticates — Kandev does not enforce the manifest's informational
method field or verify that a public webhook's own auth is correct.
Validate method and signature before side effects, return status codes from
100 through 599, and avoid reflecting unsafe headers or bodies.
- Keep package paths and platform declarations synchronized. Build every
executable declared in
runtime.executables; include .exe for Windows.
Verify The Artifact
Run the plugin repository's own formatting, tests, and lint commands first,
then verify the artifact rather than only the source tree:
- Run the plugin repository's tests, vet/lint, and build. Build a host-only
package with the template's
make package-host target for the local loop.
- Confirm the archive contains
manifest.yaml, the current host executable,
optional UI assets, and the generated internal checksums.txt. Never author
the internal checksum file by hand.
- Install the archive into a disposable dev Kandev instance, enable it, and
exercise every declared capability. Cover config validation, permission
failures, lifecycle restart, events or webhooks, and native UI registration
as applicable.
- Exercise the failure guarantees that matter to this plugin: duplicate event
delivery, handler cancellation, missing or invalid webhook authentication,
unavailable dependencies, denied Host calls, and corrupt state. For native
UI, run initialize/destroy twice and verify one plugin's initialization
failure does not break the host or another plugin.
- Verify an upgrade preserves Host state and the data directory when the
plugin owns either. Verify disable preserves operator data and uninstall
removes it when lifecycle behavior is part of the change.
- Bump the manifest version or uninstall the existing version before
reinstalling; Kandev rejects reinstalling the same id and version.
- Before release, run the repository's full cross-platform package workflow
and confirm its release asset name is
<id>-<version>.tar.gz.
There is no standalone exhaustive package checker in this branch. plugin-pack
stages files and generates checksums; install-time pkgtar.Install validates the
manifest, archive safety, checksums, managed runtime, and host executable. These
checks do not execute plugin code or prove browser/module behavior, so the
disposable-instance smoke test remains required.
Do not test with a developer's primary instance, database, or credentials.
Report commands run, artifact name, host platform tested, and any platform or
integration path not exercised.
Publish When Requested
- Keep source public before submitting an official marketplace entry.
- Tag the version through the repository's release workflow. Confirm the
GitHub Release contains the required plugin tarball; the release-level
tarball digest file is optional under the current marketplace contract.
- For the official catalog, add the repository pointer to
plugin-registry/plugins.yaml in kdlbs/kandev only after a valid latest
release exists. Keep catalog id equal to manifest id; leave featured
to maintainers.
- Verify the registry build resolves the latest release and package asset.
Catalog categories are free-form discovery tags and are distinct from the
manifest category enum.
- For an official plugin, review dependencies, release provenance, requested
capabilities, filesystem and network use, secret handling, and UI store
access. Internal package checksums detect corruption but do not prove
provenance; release-level digests are advisory and signature verification is
not wired by default in the shipped product.
Publishing, tagging, creating organization repositories, and marketplace
submission are external side effects. Perform only the actions the user asked
for, while completing local implementation and verification independently.
1---2name: create-kandev-plugin3description: Create, modify, debug, test, package, or publish a Kandev runtime plugin in its dedicated repository. Use only when the requested work targets a Kandev plugin implementation or its release and marketplace lifecycle, including fixing a bug in an existing plugin. Do not use for agent skills, MCP servers, general integrations, or Kandev host, SDK, loader, and registry changes that do not also change a plugin.4---56# Create Kandev Plugin78Build Kandev runtime plugins from the official template and current public9contracts. Keep plugin source outside the Kandev monorepo and prove the packaged10artifact against a disposable development instance before publishing it.1112Start with the [canonical plugin authoring guide](../../../docs/public/plugins-authoring.md).13Use this skill for the repository workflow after choosing a recipe there:14choose recipe → edit manifest → implement → validate → package → smoke test.15The guide owns the complete hook/Host matrix; this skill keeps the repository16and verification procedure concise.1718## Establish The Boundary19201. Invoke this skill only when the user intends to create, change, fix, test,21 package, release, or submit a Kandev runtime plugin. A passing mention of22 plugins, a generic extension request, or the presence of plugin host code in23 the Kandev monorepo is not sufficient.242. Confirm the artifact: a Kandev runtime plugin ships a `manifest.yaml`, a25 platform executable built with the Go `pluginsdk`, and optionally a native26 UI bundle. Agent instruction packages, MCP servers, and other products that27 also use the word "plugin" are outside this skill.283. Classify the work as a new plugin, an existing plugin change, a Kandev host29 or SDK dependency required by the plugin, or a marketplace-only change.304. Keep each production plugin in one dedicated repository. For an official31 plugin, use a public `kdlbs/kandev-plugin-<slug>` repository. For a community32 plugin, use the author's public repository. Do not add a production plugin33 implementation to `kdlbs/kandev`; the in-tree plugin fixture is test support,34 not a starter location.355. Keep host API, SDK, registry runtime, and plugin-loader changes in the Kandev36 repository. If the plugin needs a missing host capability, treat that as a37 separate Kandev change with its own tests and compatibility review.3839## Resolve The Owning Repository4041Resolve the plugin repository before editing, especially for bug reports:42431. Start with repository information in the request, issue, pull request, or44 current task. Otherwise match the manifest `id` and `repo_url` against the45 official catalog entry or the installed plugin metadata. Do not infer that a46 similarly named fixture or host package in `kdlbs/kandev` owns the bug.472. Check the repositories already materialized for the current task and locate48 the worktree whose manifest id matches the target plugin.493. When running as a Kandev task and the repository is not attached, discover50 and call `add_branch_to_task_kandev` with exactly one of `repository_url`,51 `repository_id`, or `local_path`. It defaults to the current task and can52 find or add a repository to the workspace, then materialize its branch as a53 separate worktree.544. `add_branch_to_task_kandev` only works with the Worktree executor. For other55 executors, or when the task tool is unavailable, ask to attach the repository56 or create a related task that explicitly targets it. Do not clone a nested57 repository inside the Kandev monorepo worktree.585. Change the working directory to the plugin worktree and read its local agent59 instructions, manifest, build files, tests, and release workflow. For a bug,60 reproduce and fix the behavior there with `/fix` and `/tdd`, then retain this61 skill's artifact verification. If the fix also needs a Kandev host or SDK62 change, keep the two repository deliverables and verification steps explicit.6364## Understand The Runtime Model6566Treat a plugin as two independently loaded surfaces joined by the manifest:6768```text69package tarball -> validate + extract -> supervised plugin executable <-> Host gRPC70 |-------> static UI bundle -> browser plugin registry71Kandev event bus -> bounded per-plugin delivery queue -> OnEvent72external or UI request -> declared webhook route -> HandleWebhook73```7475- Kandev owns the executable lifecycle. It starts the declared host-platform76 binary with the install directory as its working directory, injects a fresh77 Host connection on every start, and supervises crashes and failed health78 checks. Do not launch a second long-running server from the plugin.79- `KANDEV_PLUGIN_DATA_DIR` is the plugin-owned durable file directory. It80 survives restarts and version upgrades and is deleted on uninstall. Host81 state is the better fit for small JSON objects that should participate in82 Kandev backups.83- Install attempts to activate the plugin immediately. Disable preserves its84 config, state, secrets, versions, and data; uninstall removes them. A config85 update restarts an active plugin, so load configuration during startup.86- The UI bundle is served from the extracted package and does not pass through87 the plugin process. Its `initialize` and optional `destroy` hooks may run88 repeatedly as a plugin is disabled and re-enabled in the same browser tab.89- Capabilities gate Host API methods; they are not an operating-system or90 browser sandbox. The plugin executable inherits Kandev's process environment,91 and the UI runs as same-origin JavaScript with host store access. Treat92 installation as privileged code execution and hold official plugins to93 dependency, credential, and data-access review.9495Choose the narrowest surface that satisfies the behavior:9697| Need | Surface | Contract to design for |98| --- | --- | --- |99| React to Kandev activity | `OnEvent` | Retryable best-effort delivery, bounded in-memory queues, and possible loss require idempotency and reconciliation for critical workflows. |100| Receive an external call or relay a UI request | `HandleWebhook` | Only declared keys are routed; validate method, authentication, and provider signatures inside the plugin. |101| Store small structured data | Host state | Values are JSON objects keyed by scope and key; there is no transaction or compare-and-swap API. |102| Store files or use a plugin-managed database | `KANDEV_PLUGIN_DATA_DIR` | The plugin owns schema, locking, migrations, and recovery. |103| Read Kandev entities | Typed Host readers plus `api_read` | Use opaque pagination cursors and stable SDK DTOs; never query Kandev's database or internal HTTP API. |104| Mutate Kandev entities | Typed Host writers | `api_write:tasks` gates `Tasks().Create/Update`; `api_write:messages` gates `Messages().Send`. A missing mutation requires a separate Host API change. |105| Notify another plugin | `Host.EmitEvent` | Events are published as `plugin.<id>.<name>`; keep names and payloads versionable. |106| Add native interface | UI registry and `host.ui` | Use host-owned React and components so themes, contexts, portals, and mobile behavior remain compatible. |107108## Read The Current Contracts109110Read these sources before designing the plugin:1111121. `docs/public/plugins-authoring.md` for the supported backend, Host API,113 native UI, recipes, packaging, install, and iteration workflow.1142. `docs/public/plugins-manifest.md` for the authoritative manifest fields,115 capability gates, and event vocabulary.1163. `docs/public/plugins-marketplace.md` when publishing or updating a catalog117 entry.1184. The current `kdlbs/kandev-plugin-template` repository, including its119 `README.md`, `Makefile`, tests, and release workflow.120121**Marketplace attribution:** The manifest `author` is independent from GitHub122repository ownership or organization. Never infer author `kandev` from a123`kdlbs/kandev-plugin-*` repository. Read and preserve the manifest author,124verify `repo_url` separately, and require an explicit contributor identity when125an externally maintained plugin is released.126127Prefer the public authoring docs and current template over old examples. The128frontend contract pair is `docs/plans/plugins/PLUGIN-API.md` plus129`apps/web/lib/plugins/types.ts`; concrete UI exports are in130`apps/web/lib/plugins/host-api.ts`. The backend contract is131`apps/backend/pkg/pluginsdk` plus `apps/backend/proto/kandev/plugin/v1/plugin.proto`.132Read `docs/plans/plugins/GRPC-CONTRACT.md` when changing the wire contract or133when the public docs do not answer a low-level compatibility question.134135The frontend and backend matrices in `docs/public/plugins-authoring.md`,136together with `apps/web/lib/plugins/types.ts` and `apps/backend/pkg/pluginsdk`,137are the authoritative record of what exists today. Read them rather than138asserting from memory that a hook is missing, and do not publish a signature139they do not declare.140141When debugging a contract discrepancy, verify it at the implementation142boundary: manifest and package rules live under143`apps/backend/internal/plugins/manifest` and `pkgtar`; runtime, Host, webhook,144and delivery behavior live under `apps/backend/internal/plugins`; native UI145loading and registration live under `apps/web/lib/plugins`.146147## When Adding Or Changing A Hook148149Treat a new hook, Host method, capability, manifest field, or mounted UI slot as150a contract change. Do not implement the runtime surface and leave author docs151for later. In the same change:1521531. Update the implementation boundary and its focused tests.1542. Update the authoritative contract source:155 - frontend: `docs/plans/plugins/PLUGIN-API.md` plus156 `apps/web/lib/plugins/types.ts`; update `host-api.ts`, `registry.ts`, or157 the mounted component when the concrete surface changes;158 - backend: `apps/backend/pkg/pluginsdk`,159 `apps/backend/proto/kandev/plugin/v1/plugin.proto`, and the manifest model160 or validator when applicable; update `docs/plans/plugins/GRPC-CONTRACT.md`161 for wire-level changes.1623. Update `docs/public/plugins-authoring.md` in the same change: add the hook to163 the frontend or backend matrix, document inputs/props, capability and164 lifecycle/cleanup behavior, and add a copy-pasteable recipe or maintained165 fixture link. Adding the row to the matrix is the update — do not introduce166 a separate "unavailable" list anywhere.1674. Update `docs/public/plugins-manifest.md` for capability/manifest changes and168 update `docs/public/plugins.md`, `docs/plugins-example.md`, or the relevant169 ADR when their claims or links change. Keep the public guide as a summary;170 never create a second schema or type definition in prose.171 When a public plugin page benefits from an architecture, lifecycle, data-flow,172 or trust-boundary visual, use `/diagram-design` and its173 `references/kandev-public-docs.md` integration guide. Publish a reviewed174 local image with precise alt text and nearby explanatory prose.1755. Recheck the root/backend/web `AGENTS.md` authority pointers and this skill if176 the source-of-truth locations or author workflow changed.1776. Run the focused implementation tests plus178 `node --test scripts/validate-public-docs.test.mjs`,179 `node scripts/validate-public-docs.mjs`, and a stale-reference search. Report180 the exact commands and results.181182A hook absent from the relevant frontend/backend matrix and its corresponding183authoritative contract source does not exist yet; point the author at the184nearest supported recipe instead of publishing a speculative signature, and185do not record the gap as a durable list entry in this skill or an186`AGENTS.md` — the matrix and the contract sources are the only place187absence or presence is tracked. If the hook is implemented but the188matrix, recipe, fixture, or authoritative contract is missing, the plugin189change is not documentation complete.190191## Create A New Repository192193Skip this section for changes to an existing plugin after resolving its owning194repository above.1951961. Derive a lowercase plugin id and repository name. For an official plugin,197 use the full `kandev-plugin-<slug>` value for both. Keep the manifest `id`,198 Go module, Makefile binary and package names, UI registration id, release199 asset name, and catalog id synchronized as the template documents.2002. Create the repository from `kdlbs/kandev-plugin-template`; do not hand-roll201 files that the template already maintains.2023. For official plugins, create or target `kdlbs/kandev-plugin-<slug>` and set203 `repo_url` to that public repository. Do not publish to the organization or204 mutate repository settings unless the user requested that external action.2054. Inspect repository-local instructions before editing. Replace template206 identity and example behavior without deleting its packaging, test, or207 release safeguards.2085. Materialize the plugin as a sibling of the Kandev checkout, or update the209 template's `go.mod` replacement deliberately. Until the SDK is a standalone210 module, the default `replace` resolves `../kandev/apps/backend`.211212If the requested repository does not exist and cannot be created with the213available GitHub tooling, stop after producing a precise repository bootstrap214request. Do not silently substitute a directory in the Kandev monorepo.215216## Implement With Least Privilege2172181. Write concrete behavior examples and failure cases before implementation.219 Use `/tdd` for backend and manifest logic.2202. Declare only the capabilities the plugin exercises. Treat `api_read`,221 `state`, `secrets`, event subscriptions, and webhooks as permission222 boundaries rather than descriptive metadata.2233. Embed `pluginsdk.UnimplementedPlugin`, override only required methods, and224 access Kandev through the injected Host API. The Host can be unavailable225 during construction and isolated tests, so resolve it when handling work.226 Honor context cancellation and do not reach into Kandev internal packages,227 its database, or undocumented REST endpoints.2284. Make event handling idempotent by `EventID`. Kandev makes one attempt plus229 three retries after 5s, 15s, and 45s, using the same event id. Delivery is230 sequential per plugin, but its queue and error-state buffer are bounded and231 in memory; backend restarts and sustained overload can lose events. Add a232 source-of-truth reconciliation path when missing an event is unacceptable.2335. Keep operator credentials in `config_schema` secret fields or the Host234 secret APIs. `GetConfig` returns the plugin's own secret values in cleartext,235 so never commit real credentials or log complete config objects.2366. For a UI bundle, use `host.jsx`, `host.ui`, `host.store`, and237 `host.api.fetch` as documented. Do not bundle another React or Radix runtime.238 Make `initialize` repeatable and use `destroy` to remove timers,239 subscriptions, and side effects; Kandev revokes registered routes, slots,240 handlers, styles, and navigation separately. Use `/mobile-parity` for241 interaction design and `/e2e` for user-visible flows.2427. API v2 webhook routes require a real Kandev caller identity by default. API243 v1 keeps omitted access public for compatibility, so new plugins must use244 API v2. Follow245 `docs/public/plugins-authoring.md` for the current body-size and route246 limits. Kandev rejects undeclared keys and, unless the manifest declares247 `webhooks[].public: true`, rejects anonymous callers with 401 before your248 handler runs. Only mark a webhook `public` when it is genuinely third-party249 ingress (a provider callback, an SSO initiate/callback pair) that your own250 handler authenticates — Kandev does not enforce the manifest's informational251 `method` field or verify that a public webhook's own auth is correct.252 Validate method and signature before side effects, return status codes from253 100 through 599, and avoid reflecting unsafe headers or bodies.2548. Keep package paths and platform declarations synchronized. Build every255 executable declared in `runtime.executables`; include `.exe` for Windows.256257## Verify The Artifact258259Run the plugin repository's own formatting, tests, and lint commands first,260then verify the artifact rather than only the source tree:2612621. Run the plugin repository's tests, vet/lint, and build. Build a host-only263 package with the template's `make package-host` target for the local loop.2642. Confirm the archive contains `manifest.yaml`, the current host executable,265 optional UI assets, and the generated internal `checksums.txt`. Never author266 the internal checksum file by hand.2673. Install the archive into a disposable dev Kandev instance, enable it, and268 exercise every declared capability. Cover config validation, permission269 failures, lifecycle restart, events or webhooks, and native UI registration270 as applicable.2714. Exercise the failure guarantees that matter to this plugin: duplicate event272 delivery, handler cancellation, missing or invalid webhook authentication,273 unavailable dependencies, denied Host calls, and corrupt state. For native274 UI, run initialize/destroy twice and verify one plugin's initialization275 failure does not break the host or another plugin.2765. Verify an upgrade preserves Host state and the data directory when the277 plugin owns either. Verify disable preserves operator data and uninstall278 removes it when lifecycle behavior is part of the change.2796. Bump the manifest version or uninstall the existing version before280 reinstalling; Kandev rejects reinstalling the same id and version.2817. Before release, run the repository's full cross-platform package workflow282 and confirm its release asset name is `<id>-<version>.tar.gz`.283284There is no standalone exhaustive package checker in this branch. `plugin-pack`285stages files and generates checksums; install-time `pkgtar.Install` validates the286manifest, archive safety, checksums, managed runtime, and host executable. These287checks do not execute plugin code or prove browser/module behavior, so the288disposable-instance smoke test remains required.289290Do not test with a developer's primary instance, database, or credentials.291Report commands run, artifact name, host platform tested, and any platform or292integration path not exercised.293294## Publish When Requested2952961. Keep source public before submitting an official marketplace entry.2972. Tag the version through the repository's release workflow. Confirm the298 GitHub Release contains the required plugin tarball; the release-level299 tarball digest file is optional under the current marketplace contract.3003. For the official catalog, add the repository pointer to301 `plugin-registry/plugins.yaml` in `kdlbs/kandev` only after a valid latest302 release exists. Keep catalog `id` equal to manifest `id`; leave `featured`303 to maintainers.3044. Verify the registry build resolves the latest release and package asset.305 Catalog categories are free-form discovery tags and are distinct from the306 manifest category enum.3075. For an official plugin, review dependencies, release provenance, requested308 capabilities, filesystem and network use, secret handling, and UI store309 access. Internal package checksums detect corruption but do not prove310 provenance; release-level digests are advisory and signature verification is311 not wired by default in the shipped product.312313Publishing, tagging, creating organization repositories, and marketplace314submission are external side effects. Perform only the actions the user asked315for, while completing local implementation and verification independently.