Plugin SDK Core V1 and Secrets Local Provider Extraction Signet announced Plugin SDK Core V1 and Secrets Local Provider Extraction, introducing a daemon-owned plugin host for bundled TypeScript core plugins with a manifest and registry model. The release extracts local encrypted secrets behind a provider interface while preserving existing user data and API behavior, laying groundwork for future marketplace support without implementing it in V1. Plugin SDK Core V1 and Secrets Local Provider Extraction Problem The broader Plugin SDK planning epic defines the destination: Signet plugins as cross-surface capability modules that can extend daemon, CLI, MCP, dashboard, SDK, connectors, and prompt lifecycle surfaces. That full destination is intentionally larger than a first implementation. If we try to implement TypeScript plugins, Rust sidecars, marketplace install, dynamic UI mounting, prompt composition, and every secret provider at once, the PR becomes an everything-bagel and the trust boundary gets blurry. V1 should prove the architecture with the smallest useful slice: - a daemon-owned plugin host for bundled TypeScript core plugins, - a manifest and registry model that will survive marketplace support later, - prompt contribution plumbing with visibility and disable behavior, - surface metadata plumbing for CLI/MCP/dashboard/connectors without requiring dynamic loading everywhere yet, signet.secrets represented as a privileged core plugin,- the current local encrypted secrets implementation extracted behind a local provider interface without changing existing user data. Goals - Add a plugin host skeleton owned by the daemon. - Support bundled TypeScript core plugin manifests. - Persist plugin registry and lifecycle state. - Expose plugin status and diagnostics through daemon API. - Support append/context prompt contributions with provenance, token budgets, ordering, and disable behavior. - Add a surface metadata registry for daemon, CLI, MCP, dashboard, SDK, and connector contributions. - Represent Signet Secrets as the first privileged bundled core plugin. - Extract local secret storage behind a provider interface while preserving secrets.enc byte-for-byte unless a user writes a new/updated secret. - Keep existing /api/secrets/ , CLI, MCP, dashboard, and SDK behavior working. - Store marketplace-ready manifest metadata without implementing marketplace install. Non-Goals - No marketplace install, review, ranking, payments, or public discovery. - No third-party plugin execution. - No Rust sidecar execution in V1. - No WASI runtime. - No native dynamic-library plugin loading. - No dynamic dashboard panel rendering from arbitrary plugin code. - No dynamic CLI command loading from arbitrary plugin code. - No Bitwarden, Vault, AWS, GCP, Azure, pass/gopass, or env provider implementation. - No secret store format migration. - No raw secret read endpoint. - No plugin-authored mutation of user prompts beyond append/context contributions. - No removal of legacy secrets compatibility routes. Architecture Daemon +-- plugin host | +-- manifest validator | +-- registry store | +-- lifecycle state | +-- capability grants | +-- surface metadata registry | +-- prompt contribution registry | +-- health/status diagnostics | +-- bundled core plugins | +-- signet.secrets | +-- existing API/CLI/MCP/dashboard/connectors +-- continue calling existing compatibility surfaces +-- can read plugin status/metadata where useful V1 does not make every Signet surface dynamically plugin-rendered. Instead, it creates the host and metadata contract those surfaces will later consume. Existing first-party surfaces remain hand-wired where necessary, but they are associated with the plugin that owns them. Plugin Manifest Contract V1 manifests are data contracts, not arbitrary execution permissions. Required fields: interface PluginManifestV1 { readonly id: string; readonly name: string; readonly version: string; readonly publisher: string; readonly description: string; readonly runtime: PluginRuntimeV1; readonly compatibility: PluginCompatibilityV1; readonly trustTier: PluginTrustTier; readonly capabilities: readonly string ; readonly surfaces: PluginSurfaceDeclarationsV1; readonly marketplace?: PluginMarketplaceMetadataV1; readonly docs: PluginDocsMetadataV1; } Runtime in V1: interface PluginRuntimeV1 { readonly language: "typescript" | "rust"; readonly kind: "bundled-module" | "sidecar" | "wasi" | "host-managed"; readonly entry?: string; readonly protocol?: string; } V1 only executes: language=typescript kind=bundled-module trustTier=core V1 can also activate host-managed verified/core plugin metadata when the implementation is native Signet code and no external plugin runtime is executed. Rust, sidecar, and WASI manifest fields are accepted for forward-compatible metadata and status reporting, but those plugins enter blocked with an unsupported-runtime reason until later specs implement execution. Validation rules: id is stable and globally unique. version is SemVer. publisher is required. compatibility.signet and compatibility.pluginApi are required.- Every declared surface must map to at least one declared capability. - Every declared capability must have docs metadata. - Only Signet-owned bundled metadata can mark a plugin as trustTier=core . - Unsupported runtimes are recorded but not started. Registry and Persistence Contract The daemon persists plugin state. The implementation may use SQLite or a JSON file in V1, but it must expose the same logical fields. Logical record: interface PluginRegistryRecordV1 { readonly id: string; readonly name: string; readonly version: string; readonly publisher: string; readonly source: "bundled" | "local" | "marketplace"; readonly trustTier: "core" | "verified" | "community" | "local-dev"; readonly enabled: boolean; readonly state: "installed" | "blocked" | "active" | "degraded" | "disabled"; readonly stateReason?: string; readonly grantedCapabilities: readonly string ; readonly pendingCapabilities: readonly string ; readonly surfaces: PluginSurfaceSummaryV1; readonly health?: PluginHealthV1; readonly installedAt: string; readonly updatedAt: string; } Persistence rules: - Bundled core plugins are discovered on daemon startup. - Discovery is idempotent. - Removing a bundled plugin from the binary marks it unavailable; it does not delete plugin-owned user data. - Disabled plugins do not contribute prompts or active surface metadata. - Blocked plugins expose a clear stateReason . - Degraded plugins remain registered and visible in diagnostics. Lifecycle Contract V1 states: php installed - blocked | disabled | active - degraded Rules: - Unsupported runtime means blocked . - Missing dependency means blocked . - Health failure means degraded . - User/admin disable means disabled . disabled removes prompt contributions and active surface metadata. degraded does not crash the daemon.- Core plugins may be non-removable but can still report degraded/disabled where safe. Capability and Grant Contract Capabilities are declared by a manifest and granted by host policy. For V1: - bundled core plugins may receive bundled grants, - unsupported plugins receive no grants, - marketplace/local installs are metadata-only and cannot execute, - capability checks are enforced for plugin-owned daemon routes where the host mounts them, - compatibility routes may continue using existing auth while recording their owning plugin in diagnostics. Required signet.secrets capabilities: secrets:list secrets:write secrets:delete secrets:exec secrets:providers:list secrets:providers:configure prompt:contribute:user-prompt-submit mcp:tool cli:command dashboard:panel sdk:client connector:capability The grant model must distinguish: declaredCapabilities = grantedCapabilities Even for bundled plugins, diagnostics should show both. Surface Metadata Registry V1 stores and exposes surface metadata. It does not require every consumer to be fully dynamic yet. Surface metadata includes: interface PluginSurfaceSummaryV1 { readonly daemonRoutes: readonly PluginRouteSummaryV1 ; readonly cliCommands: readonly PluginCommandSummaryV1 ; readonly mcpTools: readonly PluginToolSummaryV1 ; readonly dashboardPanels: readonly PluginDashboardSummaryV1 ; readonly sdkClients: readonly PluginSdkSummaryV1 ; readonly connectorCapabilities: readonly PluginConnectorSummaryV1 ; readonly promptContributions: readonly PluginPromptSummaryV1 ; } Rules: - Disabled plugins have no active surface metadata. - Blocked plugins can show planned surfaces but not active surfaces. - Existing first-party CLI/MCP/dashboard surfaces may remain hand-wired but should be represented in metadata under signet.secrets . - Surface metadata includes docs/help text. - Surface metadata never includes secret values or provider tokens. Prompt Contribution Contract V1 supports static prompt contributions from bundled core plugins. Contribution shape: interface PromptContributionV1 { readonly id: string; readonly pluginId: string; readonly target: "system" | "session-start" | "user-prompt-submit"; readonly mode: "append" | "context"; readonly priority: number; readonly maxTokens: number; readonly content: string; } Ordering bands: | Priority band | Owner | |---|---| | 0-99 | Signet core invariants | | 100-199 | user identity | | 200-299 | runtime/connectors | | 300-399 | memory | | 400-499 | plugin advisory context | Rules: - V1 plugin contributions default to 400-499 . - Contributions are append/context only. - Contributions cannot suppress or replace user identity files. - Contributions are clipped to maxTokens before global prompt clipping. - Prompt diagnostics list included and excluded contributions. - Disabling the owning plugin removes the contribution without daemon restart if the prompt registry is re-read at request time, or after daemon restart if V1 implementation chooses startup-only registry loading. The chosen behavior must be documented. Required Secrets contribution: When the user provides credentials or a task requires reusable credentials, prefer storing them in Signet Secrets rather than chat, memory, logs, or source files. Use secret exec or provider-backed secret references when commands need credentials. Plugin Diagnostics API V1 adds daemon diagnostics endpoints. Exact paths may be adjusted to match route organization, but the response contracts must be stable. Required endpoints: GET /api/plugins GET /api/plugins/:id GET /api/plugins/:id/diagnostics GET /api/plugins/prompt-contributions GET /api/plugins response: interface PluginListResponseV1 { readonly plugins: readonly PluginRegistryRecordV1 ; } GET /api/plugins/prompt-contributions response: interface PromptContributionListResponseV1 { readonly contributions: readonly PromptContributionV1 ; readonly activeCount: number; } Rules: - Diagnostics never include raw secret values. - Diagnostics identify disabled/blocked/degraded reasons. - Diagnostics identify active prompt contributors by plugin ID. - Diagnostics identify compatibility routes owned by plugins. Secrets Plugin V1 signet.secrets is a bundled privileged core plugin. It owns metadata for: /api/secrets/ routes, signet secret CLI commands,- Signet MCP secret tools, - dashboard Secrets settings panel, - SDK secret helpers, - connector-visible secret capabilities, - Secrets prompt contribution. V1 implementation may keep route/controller code in its current package layout if the plugin host records signet.secrets as the owner. The important V1 change is the capability boundary and local provider extraction, not a cosmetic file move. Local Secrets Provider Extraction The current local encrypted store becomes a provider implementation under signet.secrets . Provider interface: interface LocalSecretProviderV1 { readonly id: "local"; list ctx: SecretContextV1 : Promise