cd /news/developer-tools/plugin-sdk-core-v1-and-secrets-local… · home topics developer-tools article
[ARTICLE · art-33356] src=signetai.sh ↗ pub= topic=developer-tools verified=true sentiment=· neutral

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.

read13 min views1 publishedJun 18, 2026

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 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 .
  • No dynamic dashboard panel rendering from arbitrary plugin code.
  • No dynamic CLI command 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

andcompatibility.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:

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 . 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<readonly SecretDescriptorV1[]>;
  put(name: string, value: string, ctx: SecretContextV1): Promise<void>;
  delete(name: string, ctx: SecretContextV1): Promise<boolean>;
  resolve(ref: SecretRefV1, ctx: SecretContextV1): Promise<ResolvedSecretV1>;
  health(ctx: SecretContextV1): Promise<SecretProviderHealthV1>;
}

Compatibility invariant:

Existing $SIGNET_WORKSPACE/.secrets/secrets.enc files remain valid without
migration, re-encryption, relocation, or user action.

V1 must preserve:

file:   $SIGNET_WORKSPACE/.secrets/secrets.enc
format: version 1 JSON wrapper with per-secret ciphertext
crypto: libsodium secretbox
key:    BLAKE2b-256 of signet:secrets:{machine-id}

Rules:

  • Startup must not rewrite secrets.enc

. - Listing secrets must not decrypt every value unless necessary.

  • Resolve happens only inside the daemon/plugin/provider boundary.
  • Command execution redacts resolved values from stdout/stderr.
  • Corrupt or machine-mismatched stores fail clearly and are never overwritten automatically.
  • Writes may update secrets.enc

using the existing format. - Existing bare names keep working as local references.

Secrets Compatibility Routes #

Existing routes remain available:

GET    /api/secrets
POST   /api/secrets/:name
DELETE /api/secrets/:name
POST   /api/secrets/exec
GET    /api/secrets/exec/:jobId
POST   /api/secrets/:name/exec
GET    /api/secrets/1password/status
POST   /api/secrets/1password/connect
DELETE /api/secrets/1password/connect
GET    /api/secrets/1password/vaults
POST   /api/secrets/1password/import

V1 does not need to convert 1Password into a provider, but it must not regress 1Password behavior. If 1Password remains on the current implementation path, the plugin diagnostics should mark it as compatibility-owned by signet.secrets

and future-provider pending.

Secret Reference and Alias V1 #

V1 must support:

OPENAI_API_KEY == local://OPENAI_API_KEY

Provider-qualified syntax for future providers may be accepted in parsers, but only local://

is required to resolve in V1.

Resolution order in V1:

local://NAME

  • bare NAME

as local compatibility lookup

User-defined aliases may be deferred. If implemented in V1, they must follow the broader planning spec rules: provider-qualified target, audit event, and loop rejection.

Audit Events V1 #

V1 must emit audit or structured diagnostic events for:

plugin.discovered
plugin.enabled
plugin.disabled
plugin.blocked
plugin.degraded
plugin.health_failed
prompt.contribution_added
prompt.contribution_removed
secret.listed
secret.stored
secret.deleted
secret.resolved_for_exec
secret.exec_started
secret.exec_completed

Rules:

  • Secret values are never logged.
  • Command stdout/stderr are not audit payloads.
  • Event payloads include plugin ID, timestamp, result, and agent scope where available.
  • Secret names may be included only where current API behavior already exposes them or policy allows them.

Rollback and Degraded Mode #

V1 rollback depends on not rewriting user data.

Rules:

  • The plugin host migration does not rewrite secrets.enc

. - If plugin registry fails, the daemon should still be able to mount existing secrets routes through the local provider compatibility path.

  • If signet.secrets

is degraded, diagnostics must say whether local secrets are available, unavailable, or blocked by key mismatch/corruption. - If prompt contribution fails, prompt-submit continues without plugin contributions and records degraded diagnostics.

  • Disabling signet.secrets

removes prompt guidance and connector/MCP advertising, but must not delete stored secrets.

Implementation Phases #

Phase 1: Host and Registry

  • Add manifest types and validation.
  • Add plugin registry persistence.
  • Discover bundled core plugins at startup.
  • Add /api/plugins

diagnostics. - Add lifecycle states and health status.

Phase 2: Prompt and Surface Metadata

  • Add prompt contribution registry.
  • Add prompt contribution diagnostics.
  • Add surface metadata registry.
  • Represent existing Secrets CLI/MCP/dashboard/SDK/connectors in metadata.

Phase 3: Secrets Plugin Metadata

  • Register signet.secrets

as bundled core plugin. - Associate existing secrets routes and surfaces with signet.secrets

. - Add Secrets prompt contribution.

  • Add enable/disable behavior for prompt and advertised surfaces.

Phase 4: Local Provider Extraction

  • Extract current local secret store behind provider interface.
  • Preserve existing encryption and file format.
  • Add compatibility fixtures for existing secrets.enc

. - Keep all existing secrets routes passing.

Phase 5: Guardrails and Docs

  • Add audit events.
  • Add docs/help metadata.
  • Add CLI setup selection for bundled core plugins. Existing installs default signet.secrets

to enabled; new interactive installs explain Signet Secrets and ask whether to enable it. - Add degraded-mode tests.

  • Update docs/API.md

,docs/SECRETS.md

,docs/SDK.md

,docs/MCP.md

, and dashboard docs where behavior or ownership changed.

Validation and Tests #

Required tests:

  • manifest validation rejects invalid IDs, versions, missing docs metadata, and unsupported active runtimes.
  • bundled signet.secrets

is discovered idempotently. /api/plugins

listssignet.secrets

with expected state, capabilities, grants, and surfaces.- disabling signet.secrets

removes its prompt contribution. - prompt diagnostics list active contributions with plugin provenance.

  • prompt contribution clipping respects maxTokens

. - plugin health failure reports degraded state without crashing daemon.

  • unsupported Rust sidecar manifest enters blocked state in V1.
  • v1 secrets.enc

fixture remains readable by local provider. - startup does not rewrite existing secrets.enc

. - storing a new local secret writes the existing format.

  • corrupt secrets.enc

fails clearly and is not overwritten. - machine-mismatched secrets.enc

fails clearly and is not overwritten. /api/secrets/*

compatibility routes preserve existing behavior.execWithSecrets

injects resolved local values and redacts stdout/stderr.- ordinary API/MCP/dashboard/SDK responses do not include raw secret values.

  • 1Password compatibility routes do not regress.
  • setup registry tests prove new installs can persist signet.secrets

enabled or disabled without disturbing unrelated plugin registry entries.

Required local commands before PR:

bun test platform/daemon/src/secrets*.test.ts
bun test platform/daemon/src/plugin*.test.ts
bun run typecheck
bun run lint

The exact test filenames may differ, but the PR must include regression tests for the contracts above.

Documentation Updates #

When implemented, update:

docs/API.md

for plugin diagnostics routes and secrets ownership notes.docs/SECRETS.md

forsignet.secrets

, local provider compatibility, and the no-raw-secret-read invariant.docs/SDK.md

to remove or correct any implication that ordinary SDK callers can retrieve raw secret values.docs/MCP.md

to state that secret tools use injection/listing only and are plugin-owned.docs/DASHBOARD.md

to describe plugin-owned Secrets settings and provider status.docs/specs/INDEX.md

anddocs/specs/dependencies.yaml

when status changes.

Success Criteria #

This spec is complete when:

signet.secrets

appears as a bundled core plugin in daemon diagnostics.- Existing secrets routes, CLI, MCP, dashboard, and SDK behavior continue to work.

  • Existing local secrets.enc

fixtures pass without migration. - Secrets prompt contribution appears only when signet.secrets

is enabled. - Plugin registry and surface metadata are visible through diagnostics.

  • Unsupported Rust/sidecar plugin metadata is blocked cleanly rather than executed or ignored silently.
  • Tests prove secret values are not exposed through ordinary responses.
  • Docs describe the plugin-owned Secrets architecture and compatibility guarantees.
  • CLI setup enables signet.secrets

by default for existing installs, prompts new interactive installs in a Core plugins section, and supports non-interactive opt-out without deleting stored secrets.

── more in #developer-tools 4 stories · sorted by recency
── more on @signet 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/plugin-sdk-core-v1-a…] indexed:0 read:13min 2026-06-18 ·