Skip to main content
The Capabilities API gives you typed utilities to declare what permissions your plugin needs, validate them at runtime, and produce actionable diagnostics when a capability is missing or misconfigured.

Import

import {
  createCapabilityBundle,
  createProcessCapabilityBundle,
  createFilesystemCapabilityBundle,
  createWorkflowCapabilityBundle,
  describeCapability,
  parseMissingCapabilityError,
  requireProcessScopeCapability,
  requireFilesystemScopeCapability,
  requireWorkflowProcessCapabilities,
} from "@anikitenko/fdo-sdk";

Types

PluginCapability

The full union of capability strings the FDO host recognizes:
type FilesystemScopeCapability = `system.fs.scope.${string}`;
type ProcessScopeCapability    = `system.process.scope.${string}`;

type PluginCapability =
  | "storage.json"
  | "sudo.prompt"
  | "system.hosts.write"
  | "system.process.exec"
  | FilesystemScopeCapability
  | ProcessScopeCapability;
ValueCategoryEffect
"storage.json"storagePersistent JSON key-value store
"sudo.prompt"sudoElevated privilege prompts
"system.hosts.write"hostsHosts-file mutation via host
"system.process.exec"processScoped process execution
"system.fs.scope.<id>"filesystem-scopeScoped filesystem mutation
"system.process.scope.<id>"process-scopeScoped process execution under a named policy

CapabilityCategory

type CapabilityCategory =
  | "storage"
  | "sudo"
  | "hosts"
  | "filesystem-scope"
  | "process"
  | "process-scope"
  | "unknown";

CapabilityDescriptor

Returned by describeCapability. Provides human-readable metadata about a capability.
type CapabilityDescriptor = {
  capability: string;
  label: string;
  description: string;
  category: CapabilityCategory;
};

MissingCapabilityDiagnostic

Returned by parseMissingCapabilityError. Contains everything you need to surface a user-facing error when a capability is not granted.
type MissingCapabilityDiagnostic = {
  capability: PluginCapability | string;
  action: string;          // What the plugin was trying to do
  category: CapabilityCategory;
  label: string;           // Human-readable capability name
  description: string;     // What the capability allows
  remediation: string;     // How to fix the missing capability
};

Bundle builders

createCapabilityBundle

Deduplicates and sorts an array of capabilities. Use this when assembling a PluginInitRequest.capabilities list.
createCapabilityBundle(capabilities: PluginCapability[]): PluginCapability[]
const caps = createCapabilityBundle([
  "system.process.exec",
  "system.process.scope.docker-cli",
  "system.process.exec", // deduplicated
]);
// → ["system.process.exec", "system.process.scope.docker-cli"]

createProcessCapabilityBundle

Returns the canonical capability pair needed to execute scoped processes under a named scope. Normalizes the scope id (lowercase, alphanumeric/dash/dot only).
createProcessCapabilityBundle(scopeId: string): PluginCapability[]
const caps = createProcessCapabilityBundle("kubectl");
// → ["system.process.exec", "system.process.scope.kubectl"]
Throws if scopeId contains no alphanumeric characters after normalization.

createFilesystemCapabilityBundle

Returns the capability pair needed for scoped filesystem mutation: system.hosts.write plus the scoped system.fs.scope.<id> capability.
createFilesystemCapabilityBundle(scopeId: string): PluginCapability[]
const caps = createFilesystemCapabilityBundle("my-plugin-data");
// → ["system.fs.scope.my-plugin-data", "system.hosts.write"]
Throws if scopeId contains no alphanumeric characters after normalization.

createWorkflowCapabilityBundle

Alias for createProcessCapabilityBundle. Workflows require the same process execution capabilities.
createWorkflowCapabilityBundle(scopeId: string): PluginCapability[]
const caps = createWorkflowCapabilityBundle("deploy-workflow");
// → ["system.process.exec", "system.process.scope.deploy-workflow"]

Introspection

describeCapability

Returns a CapabilityDescriptor for any capability string — including unknown or future capabilities.
describeCapability(capability: PluginCapability | string): CapabilityDescriptor
const desc = describeCapability("system.process.exec");
// {
//   capability: "system.process.exec",
//   label: "Scoped Tool Execution",
//   description: "Allows host-mediated execution of allowlisted operational tools...",
//   category: "process"
// }

const scopeDesc = describeCapability("system.process.scope.kubectl");
// {
//   capability: "system.process.scope.kubectl",
//   label: "Process Scope: kubectl",
//   description: "Allows scoped process execution inside the \"kubectl\" host policy.",
//   category: "process-scope"
// }

parseMissingCapabilityError

Parses a thrown error (or error string) that matches the FDO missing-capability error pattern. Returns a MissingCapabilityDiagnostic if the error is a capability error, or null otherwise.
parseMissingCapabilityError(error: unknown): MissingCapabilityDiagnostic | null
try {
  // some SDK call that requires a capability
} catch (err) {
  const diag = parseMissingCapabilityError(err);
  if (diag) {
    console.error(`Missing: ${diag.label}`);
    console.error(`Remediation: ${diag.remediation}`);
  }
}
The parsed object includes:
FieldDescription
capabilityThe missing capability string
actionWhat the plugin was trying to do
categoryCapability category
labelHuman-readable name
descriptionWhat the capability allows
remediationSteps to fix the issue

Runtime guards

These functions throw a structured error if the required capability has not been granted. Call them before any privileged operation in your handler or render logic.

requireProcessScopeCapability

requireProcessScopeCapability(scopeId: string, action: string): void
Throws if system.process.scope.<scopeId> is not in the granted set.
requireProcessScopeCapability("kubectl", "list Kubernetes pods");

requireFilesystemScopeCapability

requireFilesystemScopeCapability(scopeId: string, action: string): void
Throws if system.fs.scope.<scopeId> is not in the granted set.
requireFilesystemScopeCapability("my-plugin-data", "write plugin config file");

requireWorkflowProcessCapabilities

Checks both system.process.exec and the scoped process capability for a given scope id. Use this before dispatching any workflow action.
requireWorkflowProcessCapabilities(scopeId: string, action: string): void
requireWorkflowProcessCapabilities("deploy-workflow", "run deployment workflow");

Full example

import {
  createProcessCapabilityBundle,
  parseMissingCapabilityError,
  requireProcessScopeCapability,
} from "@anikitenko/fdo-sdk";

// Declare capabilities in plugin init
const capabilities = createProcessCapabilityBundle("kubectl");
// Pass to PluginInitRequest: { capabilities }

// Guard before use
function runKubectl() {
  try {
    requireProcessScopeCapability("kubectl", "execute kubectl commands");
    // proceed with the privileged action
  } catch (err) {
    const diag = parseMissingCapabilityError(err);
    if (diag) {
      // Surface to user
      return `Error: ${diag.label} is required. ${diag.remediation}`;
    }
    throw err;
  }
}
Scope ids are normalized to lowercase alphanumeric with dashes and dots only. Spaces and special characters are replaced with -. Make sure the scope id in your plugin matches exactly what is configured in the host PluginRegistry.configureCapabilities() call.