Skip to content

Runtime extensions API

Connector, agent, skill, harness, plugin, and secret endpoints.

Back to HTTP API overview.

Connectors ingest documents from external sources on a schedule or on demand. Currently only the filesystem provider is operational; github-docs and gdrive are registered but not yet functional.

GET requests to connector endpoints are open. POST, DELETE, and mutation requests require admin permission (or connectors for operators).

List all registered connectors.

Response

{
"connectors": [
{
"id": "uuid",
"status": "idle",
"config_json": "{...}",
"cursor_json": "{...}",
"last_sync_at": "2026-02-21T09:00:00.000Z",
"last_error": null
}
],
"count": 1
}

Register a new connector. Requires admin permission.

Request body

{
"provider": "filesystem",
"displayName": "My Notes",
"settings": {
"rootPath": "/home/nicholai/notes",
"glob": "**/*.md"
}
}

provider must be filesystem, github-docs, or gdrive.

Response

{ "id": "uuid" }

Returns 201.

Get a single connector’s details and current state.

Trigger an incremental sync for a filesystem connector. The sync runs in the background — poll GET /api/connectors/:id for status updates. Requires admin permission.

Response

{ "status": "syncing" }

Returns { "status": "syncing", "message": "Already syncing" } if a sync is already running.

Trigger a full resync, discarding the cursor. Requires ?confirm=true query parameter as a safety guard. Requires admin permission.

Response

{ "status": "syncing" }

Remove a connector from the registry. Requires admin permission.

Query parameters

Parameter Description
cascade true — also soft-delete documents from this connector

Response

{ "deleted": true }

Lightweight health check for a connector, including document count.

Response

{
"id": "uuid",
"status": "idle",
"lastSyncAt": "2026-02-21T09:00:00.000Z",
"lastError": null,
"documentCount": 142
}

Multi-agent endpoints for managing the agent roster. All agents share one SQLite database; memories are scoped by agent_id and visibility. The read policy controls which other agents’ global memories each agent can see.

List all registered agents. Requires no permission (local mode) or recall.

Response

{
"agents": [
{
"id": "default",
"name": "default",
"read_policy": "shared",
"policy_group": null,
"created_at": "2026-03-24T00:00:00.000Z",
"updated_at": "2026-03-24T00:00:00.000Z"
},
{
"id": "alice",
"name": "alice",
"read_policy": "isolated",
"policy_group": null,
"created_at": "2026-03-24T12:00:00.000Z",
"updated_at": "2026-03-24T12:00:00.000Z"
}
]
}

read_policy is one of:

  • isolated — agent sees only its own memories
  • shared — agent sees all visibility=global memories from any agent
  • group — agent sees visibility=global memories from agents in the same policy_group

Get a single agent by name. Returns 404 if not found.

Response — same shape as a single entry in GET /api/agents.

Register a new agent. Requires remember permission.

Request body

{
"name": "alice",
"read_policy": "isolated",
"policy_group": null
}

Only name is required. read_policy defaults to "isolated".

Response — the created agent record.

Remove an agent from the roster. Memories owned by the agent are marked visibility='archived' (not deleted). Requires admin permission.

Query parameters

Parameter Description
purge Set to true to permanently delete all memories where agent_id = name.

Response

{ "success": true, "purged": false }

List all installed skills from $SIGNET_WORKSPACE/skills/. Each skill must have a SKILL.md with YAML frontmatter.

Response

{
"skills": [
{
"name": "browser-use",
"description": "Browser automation skill",
"version": "1.0.0",
"author": "browser-use",
"license": "MIT",
"user_invocable": true,
"arg_hint": "<url>",
"path": "/home/user/.agents/skills/browser-use"
}
],
"count": 3
}

Search the skills.sh registry for installable skills.

Query parameters

Parameter Description
q Search query string (required)

Response

{
"results": [
{
"name": "browser-use",
"description": "browser-use/browser-use@browser-use (32.6K installs)",
"installed": false
}
]
}

Get a single skill’s metadata and full SKILL.md content.

Response

{
"name": "browser-use",
"description": "...",
"version": "1.0.0",
"path": "/home/user/.agents/skills/browser-use",
"content": "---\ndescription: ...\n---\n\n# Browser Use\n..."
}

Returns 400 for invalid names (path traversal). Returns 404 if not installed.

Install a skill via the configured package manager (bun, npm, or pnpm). Runs skills add <pkg> --global --yes. Times out after 60 seconds.

Request body

{
"name": "browser-use",
"source": "browser-use/browser-use@browser-use"
}

name is required. source overrides the install package name if provided.

Response

{ "success": true, "name": "browser-use", "output": "..." }

Returns 500 with { "success": false, "error": "..." } on failure.

Uninstall a skill by removing its directory from $SIGNET_WORKSPACE/skills/.

Response

{ "success": true, "name": "browser-use", "message": "Removed browser-use" }

Return usage analytics for skill invocations recorded by the daemon.

Query parameters

Parameter Description
agent_id Optional agent scope override. Defaults to the request-scoped agent or default.
since Optional ISO 8601 UTC timestamp filter, e.g. 2026-03-01T00:00:00Z.
limit Optional max number of top skills to return. Default 10, range 1-100.

Response

{
"totalCalls": 12,
"successRate": 0.917,
"topSkills": [
{
"skillName": "web-search",
"count": 5,
"successCount": 5,
"avgLatencyMs": 184
}
],
"latency": {
"p50": 160,
"p95": 310
}
}

Returns 400 if since is not an ISO 8601 UTC timestamp.

List known harness config file locations and whether each exists on disk.

Response

{
"harnesses": [
{ "name": "Claude Code", "path": "/home/user/.claude/CLAUDE.md", "exists": true },
{ "name": "OpenCode", "path": "/home/user/.config/opencode/AGENTS.md", "exists": false },
{ "name": "OpenClaw (Source)", "path": "/home/user/.agents/AGENTS.md", "exists": true }
]
}

Run the generate-harness-configs.py script from the scripts directory to rebuild all harness config files from source. The script must exist at $SIGNET_WORKSPACE/scripts/generate-harness-configs.py.

Response

{ "success": true, "message": "Configs regenerated successfully", "output": "..." }

Returns 404 if the script is not found.

Plugin diagnostics expose the daemon-owned Plugin SDK V1 registry. The first bundled core plugin is signet.secrets, which owns the existing Secrets API, CLI, MCP, dashboard, SDK, connector, and prompt-contribution surfaces. Diagnostics never include raw secret values.

List registered plugins and their lifecycle state, grants, pending capabilities, and active surface metadata. Active surface metadata is filtered by granted capabilities. Planned surfaces remain visible through plugin diagnostics.

Response

{
"plugins": [
{
"id": "signet.secrets",
"name": "Signet Secrets",
"state": "active",
"enabled": true,
"declaredCapabilities": ["secrets:list", "secrets:exec"],
"grantedCapabilities": ["secrets:list", "secrets:exec"],
"pendingCapabilities": [],
"surfaces": {
"daemonRoutes": [],
"cliCommands": [],
"mcpTools": [],
"dashboardPanels": [],
"sdkClients": [],
"connectorCapabilities": [],
"promptContributions": []
}
}
]
}

Return one plugin registry record. Returns 404 if the plugin is not registered.

Return the registry record, manifest metadata, active surfaces, planned surfaces, prompt contributions, prompt inclusion/exclusion diagnostics, and validation errors for a plugin.

List active prompt contributions from enabled plugins with the required prompt capability grant.

Response

{
"contributions": [
{
"id": "signet.secrets.credential-guidance",
"pluginId": "signet.secrets",
"target": "user-prompt-submit",
"mode": "context",
"priority": 420,
"maxTokens": 80,
"content": "When the user provides credentials..."
}
],
"activeCount": 1
}

List durable plugin audit events from $SIGNET_WORKSPACE/.daemon/plugins/audit-v1.ndjson. Events are newest first, capped to 500 rows, and sensitive fields are redacted before they are written and again when read.

Query parameters

  • pluginId - optional plugin id filter, for example signet.secrets
  • event - optional exact event name filter
  • since / until - optional ISO timestamp bounds
  • limit - optional row limit, default 100, max 500

Response

{
"events": [
{
"id": "m36n9q5a-x4w2k8p1",
"timestamp": "2026-04-16T12:00:00.000Z",
"event": "plugin.enabled",
"pluginId": "signet.secrets",
"result": "ok",
"source": "plugin-host",
"data": {
"state": "active",
"enabled": true
}
}
],
"count": 1
}

Enable or disable a registered plugin.

Request body

{ "enabled": false }

Disabling signet.secrets removes its active prompt and advertised surface metadata. It does not delete stored secrets.

Plugin lifecycle changes emit structured daemon diagnostics including plugin.discovered, plugin.enabled, plugin.disabled, plugin.blocked, plugin.degraded, plugin.health_failed, plugin.capability_denied, prompt.contribution_added, and prompt.contribution_removed. The same events are appended to the durable plugin audit log for diagnostics and support.

Secrets are owned by the bundled signet.secrets core plugin. Local secrets are stored encrypted on disk at $SIGNET_WORKSPACE/.secrets/. Values are never returned in ordinary API responses, only names are exposed. Bare names such as OPENAI_API_KEY are compatibility aliases for local provider references such as local://OPENAI_API_KEY. Secrets routes require the matching granted signet.secrets capability. If the plugin is disabled, blocked, or missing a route capability, the route returns a structured plugin-capability error without deleting stored data. Secret operations emit structured daemon diagnostics for listing, storage, deletion, command injection, and command completion. These diagnostics never include raw secret values.

Store or overwrite a secret value.

Request body

{ "value": "sk-abc123..." }

value must be a non-empty string.

Response

{ "success": true, "name": "OPENAI_API_KEY" }

List stored secret names. Values are never included.

Response

{ "secrets": ["OPENAI_API_KEY", "GITHUB_TOKEN"] }

Delete a stored secret.

Response

{ "success": true, "name": "OPENAI_API_KEY" }

Returns 404 if the secret does not exist.

Queue a shell command with multiple secrets injected into the subprocess environment. Callers pass a map of env var names to secret references — never actual values. References can be Signet secret names or direct Bitwarden refs (bw://name/NAME, bw://item/ITEM_ID/password) and 1Password refs (op://vault/item/field). The daemon resolves and injects all values before spawning.

Request body

{
"command": "curl -H 'Authorization: Bearer $OPENAI_API_KEY' https://api.openai.com/v1/models",
"secrets": {
"OPENAI_API_KEY": "OPENAI_API_KEY",
"GITHUB_TOKEN": "GITHUB_TOKEN"
}
}

Both command and secrets are required. The secrets map must contain at least one entry. timeoutMs is optional and defaults to 5 minutes; values are clamped between 1 second and 30 minutes. Secret exec is always queued and the route always returns immediately with HTTP 202; callers poll the job endpoint for the redacted result.

Timed-out commands are terminated by the daemon and finish with code 124 and timedOut: true in the polled job result. The secret exec queue is bounded; saturated queues return 429. Output is redacted before truncation, and timeout cleanup targets the subprocess process group where the platform supports it.

Queued response (202)

{ "id": "uuid", "status": "queued", "createdAt": "...", "timeoutMs": 300000 }

Return the in-memory status for a queued secret exec job. Completed jobs include a redacted result object with stdout, stderr, exit code, timeout, and truncation metadata.

Legacy single-secret variant. Execute a shell command with a single secret injected into the subprocess environment. Prefer /api/secrets/exec for new integrations.

Request body

{
"command": "curl -H 'Authorization: Bearer $OPENAI_API_KEY' https://api.openai.com/v1/models",
"secrets": {
"OPENAI_API_KEY": "OPENAI_API_KEY"
}
}

command is required. secrets is optional — if omitted, the named secret from the URL path is injected under its own name. Like /api/secrets/exec, this legacy endpoint is queued and returns immediately with HTTP 202. Callers poll GET /api/secrets/exec/:jobId for the redacted result.

Queued response (202)

{ "id": "uuid", "status": "queued", "createdAt": "...", "timeoutMs": 300000 }

Return Bitwarden provider status. Bitwarden is opt-in; when it is not connected, existing local Signet secrets remain the active store.

Validate and store a Bitwarden CLI session token from bw unlock --raw. Body: { "session": "...", "activate": true, "folderId": "optional-folder-id" }. If activate is true, future Signet secret writes use Bitwarden as the backing store while internal provider metadata remains local. CLI users should pipe the token with bw unlock --raw | signet secret bitwarden connect --session-stdin rather than passing it as an argument.

Disconnect Bitwarden, remove the stored session/folder metadata, and switch the active provider back to local. Existing local Signet secrets are not deleted.

Switch active provider with { "provider": "local" } or { "provider": "bitwarden" }. Switching to Bitwarden requires a connected session.

List Bitwarden folders visible to the connected CLI session.

Copy existing local Signet secrets into Bitwarden. Defaults to dry-run: { "dryRun": true }. Pass { "dryRun": false, "overwrite": true } to write. Pass deleteLocal: true only when local copies should be removed after successful per-secret migration.

Return 1Password integration status, including whether a service account token is configured and (when available) accessible vaults.

Validate and store a 1Password service account token.

Request body

{ "token": "ops_..." }

Disconnect 1Password integration by removing the stored service account token secret.

List accessible vaults for the connected service account.

Import password-like fields from 1Password vault items into Signet secrets.

Request body

{
"vaults": ["Engineering"],
"prefix": "OP",
"overwrite": false
}