Files
kandev/docs/decisions/2026-08-11-composer-access-authenticated-webhooks.md
T
João Salavisa 6033d5717c feat(plugins): add voice extraction host APIs (#2548)
Co-authored-by: Kandev Agent <agent@kandev.dev>
2026-08-12 11:14:50 +02:00

3.0 KiB

ADR-2026-08-11-composer-access-authenticated-webhooks: Composer Access and Authenticated Webhooks

Status: accepted Date: 2026-08-11 Area: frontend, backend, protocol, security

Context

Voice Mode currently reaches private editor handles and native submit callbacks in four composer families, while plugin slots receive identifiers only. Plugin UI already calls its backend through webhooks, but declarations cannot distinguish public integration ingress from authenticated Kandev UI calls and all requests share a 4 MiB cap. Voice transcription needs authenticated UI access and at least 10 MiB while keeping its OpenAI key in plugin-owned secret settings.

Decision

Kandev exposes a typed, mounted-composer capability only through composer slot props. The capability adapts insertion, focus, state, and submission to the owning surface's existing editor/form code; it does not expose draft contents or let plugins synthesize outbound messages. Task chat, Quick Chat, task creation, and new-session creation each supply an adapter to the same public shape.

Kandev extends each webhook declaration with access: public|authenticated and max_body_bytes. Existing declarations default to public and 4 MiB. Authenticated webhooks require the normal Kandev identity and same-origin browser checks; their configured limit may be raised to a 16 MiB host ceiling. Both modes continue through the existing HandleWebhook RPC, with request cancellation propagated through its context.

Plugin localization is deferred to a separate prerequisite. It is required before core Voice Mode can be removed, but it is independent of composer access and authenticated backend invocation.

Consequences

Plugins can augment native composers without duplicating message construction or form behavior. A plugin UI can use the existing webhook API for a larger authenticated upload without adding a route, frontend API, protobuf method, or token lifecycle. Plugin authors must deliberately classify each webhook; older manifests retain their current behavior.

Alternatives Considered

  • Expose drafts and editor handles through host.store. Rejected because drafts are local React state, editor implementations differ, and a global mutable handle would outlive or target the wrong composer during navigation.
  • Let plugins send messages through api_write:messages. Rejected because it bypasses the native submit and form behavior this extraction must preserve.
  • Add a separate browser-action route and RPC. Rejected because access mode and body size are properties of the existing UI-to-plugin webhook relay; a second transport duplicates it.
  • Raise every webhook to 16 MiB. Rejected because existing public webhook callers do not need the larger exposure. Limits remain declaration-specific and bounded by the host ceiling.
  • Add host localization in this package. Rejected because locale/catalog ownership is independent of the two host blockers addressed here and can be designed as a separate prerequisite.