Skip to main content
Functions and classes exported by this package.

getPlatformPaths()

Get OS-appropriate paths for CAAMP’s global directories. Signature
() => PlatformPaths
Returns — Resolved platform paths Example
const paths = getPlatformPaths();
console.log(paths.data); // e.g. "/home/user/.local/share/agents"

getSystemInfo()

Get a cached system information snapshot. Signature
() => SystemInfo
Returns — Cached system info object Example
const info = getSystemInfo();
console.log(`Running on ${info.platform}/${info.arch}`);

_resetPlatformPathsCache()

Invalidate the path and system info caches. Use in tests after mutating AGENTS_HOME env var. Signature
() => void

getPlatformLocations()

Resolves platform-specific directory locations for the current OS. Signature
() => PlatformLocations
Returns — Platform-specific directory locations Example
const locations = getPlatformLocations();
console.log(locations.config); // e.g., "/home/user/.config"

getAgentsHome()

Returns the global agents home directory path. Signature
() => string
Returns — The absolute path to the global agents home directory Example
const home = getAgentsHome();
// e.g., "/home/user/.local/share/caamp"

getProjectAgentsDir(projectRoot)

Returns the project-local .agents directory path. Signature
(projectRoot?: string) => string
Parameters
NameTypeDescription
projectRoot: stringThe project root directory, defaults to process.cwd()
Returns — The absolute path to the project’s .agents directory Example
const dir = getProjectAgentsDir("/home/user/my-project");
// returns "/home/user/my-project/.agents"

resolveProjectPath(relativePath, projectDir)

Resolves a relative path against a project directory. Signature
(relativePath: string, projectDir?: string) => string
Parameters
NameTypeDescription
relativePathstringThe relative path to resolve
projectDir: stringThe project root directory, defaults to process.cwd()
Returns — The resolved absolute path Example
const path = resolveProjectPath(".agents/config.toml", "/home/user/project");
// returns "/home/user/project/.agents/config.toml"

getCanonicalSkillsDir()

Returns the canonical skills storage directory path. Signature
() => string
Returns — The absolute path to the canonical skills directory Example
const dir = getCanonicalSkillsDir();
// e.g., "/home/user/.local/share/caamp/skills"

getLockFilePath()

Returns the path to the CAAMP lock file. Signature
() => string
Returns — The absolute path to the .caamp-lock.json file Example
const lockPath = getLockFilePath();
// e.g., "/home/user/.local/share/caamp/.caamp-lock.json"

getAgentsMcpDir(scope, projectDir)

Gets the MCP directory within the .agents/ standard structure. Signature
(scope?: PathScope, projectDir?: string) => string
Parameters
NameTypeDescription
scope: PathScope"global" for ~/.agents/mcp/, "project" for <project>/.agents/mcp/
projectDir: stringProject root (defaults to process.cwd())
Returns — The absolute path to the MCP directory Example
const globalMcp = getAgentsMcpDir("global");
const projectMcp = getAgentsMcpDir("project", "/home/user/project");

getAgentsMcpServersPath(scope, projectDir)

Gets the MCP servers.json path within the .agents/ standard structure. Signature
(scope?: PathScope, projectDir?: string) => string
Parameters
NameTypeDescription
scope: PathScope"global" for ~/.agents/mcp/servers.json, "project" for <project>/.agents/mcp/servers.json
projectDir: stringProject root (defaults to process.cwd())
Returns — The absolute path to the servers.json file Example
const serversPath = getAgentsMcpServersPath("global");
// e.g., "/home/user/.agents/mcp/servers.json"

getAgentsInstructFile(scope, projectDir)

Gets the primary AGENTS.md instruction file path within .agents/. Signature
(scope?: PathScope, projectDir?: string) => string
Parameters
NameTypeDescription
scope: PathScope"global" for ~/.agents/AGENTS.md, "project" for <project>/.agents/AGENTS.md
projectDir: stringProject root (defaults to process.cwd())
Returns — The absolute path to the AGENTS.md file Example
const agentsFile = getAgentsInstructFile("project", "/home/user/project");
// returns "/home/user/project/.agents/AGENTS.md"

getAgentsConfigPath(scope, projectDir)

Gets the config.toml path within the .agents/ standard structure. Signature
(scope?: PathScope, projectDir?: string) => string
Parameters
NameTypeDescription
scope: PathScope"global" for ~/.agents/config.toml, "project" for <project>/.agents/config.toml
projectDir: stringProject root (defaults to process.cwd())
Returns — The absolute path to the config.toml file Example
const configPath = getAgentsConfigPath("global");
// e.g., "/home/user/.agents/config.toml"

getAgentsWikiDir(scope, projectDir)

Gets the wiki directory within the .agents/ standard structure. Signature
(scope?: PathScope, projectDir?: string) => string
Parameters
NameTypeDescription
scope: PathScope"global" or "project"
projectDir: stringProject root (defaults to process.cwd())
Returns — The absolute path to the wiki directory Example
const wikiDir = getAgentsWikiDir("project", "/home/user/project");
// returns "/home/user/project/.agents/wiki"

getAgentsSpecDir(scope, projectDir)

Gets the spec directory within the .agents/ standard structure. Signature
(scope?: PathScope, projectDir?: string) => string
Parameters
NameTypeDescription
scope: PathScope"global" or "project"
projectDir: stringProject root (defaults to process.cwd())
Returns — The absolute path to the spec directory Example
const specDir = getAgentsSpecDir("global");
// e.g., "/home/user/.agents/spec"

getAgentsLinksDir(scope, projectDir)

Gets the links directory within the .agents/ standard structure. Signature
(scope?: PathScope, projectDir?: string) => string
Parameters
NameTypeDescription
scope: PathScope"global" or "project"
projectDir: stringProject root (defaults to process.cwd())
Returns — The absolute path to the links directory Example
const linksDir = getAgentsLinksDir("project", "/home/user/project");
// returns "/home/user/project/.agents/links"

resolveRegistryTemplatePath(template)

Resolves a registry template path by substituting platform variables. Signature
(template: string) => string
Parameters
NameTypeDescription
templatestringThe template string containing $VARIABLE placeholders
Returns — The resolved absolute path with all variables expanded Example
const path = resolveRegistryTemplatePath("$HOME/.config/claude/settings.json");
// e.g., "/home/user/.config/claude/settings.json"

resolveProviderConfigPath(provider, scope, projectDir)

Resolves the configuration file path for a provider at the given scope. Signature
(provider: Provider, scope: PathScope, projectDir?: string) => string | null
Parameters
NameTypeDescription
providerProviderThe provider whose config path to resolve
scopePathScopeWhether to resolve global or project config path
projectDir: stringThe project root directory, defaults to process.cwd()
Returns — The resolved config file path, or null if unavailable for the given scope Example
const configPath = resolveProviderConfigPath(provider, "project", "/home/user/project");
if (configPath) {
  console.log("Config at:", configPath);
}

resolvePreferredConfigScope(provider, useGlobalFlag)

Determines the preferred configuration scope for a provider. Signature
(provider: Provider, useGlobalFlag?: boolean) => PathScope
Parameters
NameTypeDescription
providerProviderThe provider to determine scope for
useGlobalFlag: booleanOptional flag to force global scope
Returns — The preferred path scope for configuration Example
const scope = resolvePreferredConfigScope(provider, false);
// returns "project" if provider has configPathProject, otherwise "global"

resolveProviderSkillsDir(provider, scope, projectDir)

Resolves the skills directory path for a provider at the given scope. Signature
(provider: Provider, scope: PathScope, projectDir?: string) => string
Parameters
NameTypeDescription
providerProviderThe provider whose skills directory to resolve
scopePathScopeWhether to resolve global or project skills path
projectDir: stringThe project root directory, defaults to process.cwd()
Returns — The resolved skills directory path Example
const skillsDir = resolveProviderSkillsDir(provider, "global");
// e.g., "/home/user/.claude/skills"

resolveProviderSkillsDirs(provider, scope, projectDir)

Gets all target directories for skill installation based on provider precedence. Signature
(provider: Provider, scope: PathScope, projectDir?: string) => string[]
Parameters
NameTypeDescription
providerProviderProvider to resolve paths for
scopePathScopeWhether to resolve global or project paths
projectDir: stringProject directory for project-scope resolution
Returns — Array of target directories for symlink creation Example
const dirs = resolveProviderSkillsDirs(provider, "project", "/home/user/project");
for (const dir of dirs) {
  console.log("Install skill to:", dir);
}

resolveProviderProjectPath(provider, projectDir)

Resolves a provider’s project-level path against a project directory. Signature
(provider: Provider, projectDir?: string) => string
Parameters
NameTypeDescription
providerProviderThe provider whose project path to resolve
projectDir: stringThe project root directory, defaults to process.cwd()
Returns — The resolved absolute path for the provider’s project directory Example
const projectPath = resolveProviderProjectPath(provider, "/home/user/project");
// e.g., "/home/user/project/.claude"

resolveProvidersRegistryPath(startDir)

Locates the providers registry.json file by searching up from a start directory. Signature
(startDir: string) => string
Parameters
NameTypeDescription
startDirstringThe directory to start searching from
Returns — The absolute path to the found providers/registry.json file Throws
  • Error if providers/registry.json cannot be found within 8 parent levels
Example
const registryPath = resolveProvidersRegistryPath(__dirname);
// e.g., "/home/user/caamp/providers/registry.json"

normalizeSkillSubPath(path)

Normalizes a skill sub-path by cleaning separators and removing SKILL.md suffix. Signature
(path: string | undefined) => string | undefined
Parameters
NameTypeDescription
pathstring | undefinedThe raw skill sub-path to normalize
Returns — The normalized path, or undefined if the input is empty or falsy Example
const normalized = normalizeSkillSubPath("skills/my-skill/SKILL.md");
// returns "skills/my-skill"

buildSkillSubPathCandidates(marketplacePath, parsedPath)

Builds a list of candidate sub-paths for skill file resolution. Signature
(marketplacePath: string | undefined, parsedPath: string | undefined) => (string | undefined)[]
Parameters
NameTypeDescription
marketplacePathstring | undefinedThe sub-path from the marketplace listing
parsedPathstring | undefinedThe sub-path parsed from the source URL
Returns — A deduplicated array of candidate sub-paths Example
const candidates = buildSkillSubPathCandidates("skills/my-skill", undefined);
// returns ["skills/my-skill", ".agents/skills/my-skill", ".claude/skills/my-skill"]

getAllProviders()

Retrieve all registered providers with resolved platform paths. Providers are lazily loaded from providers/registry.json on first call and cached for subsequent calls. Signature
() => Provider[]
Returns — Array of all provider definitions Example
const providers = getAllProviders();
console.log(`${providers.length} providers registered`);

getProvider(idOrAlias)

Look up a provider by its ID or any of its aliases. Signature
(idOrAlias: string) => Provider | undefined
Parameters
NameTypeDescription
idOrAliasstringProvider ID (e.g. "claude-code") or alias (e.g. "claude")
Returns — The matching provider, or undefined if not found Example
const provider = getProvider("claude");
// Returns the claude-code provider via alias resolution

resolveAlias(idOrAlias)

Resolve an alias to its canonical provider ID. If the input is already a canonical ID (or unrecognized), it is returned as-is. Signature
(idOrAlias: string) => string
Parameters
NameTypeDescription
idOrAliasstringProvider ID or alias to resolve
Returns — The canonical provider ID Example
resolveAlias("claude"); // "claude-code"
resolveAlias("claude-code"); // "claude-code"
resolveAlias("unknown"); // "unknown"

getProvidersByPriority(priority)

Filter providers by their priority tier. Signature
(priority: ProviderPriority) => Provider[]
Parameters
NameTypeDescription
priorityProviderPriorityPriority level to filter by ("primary", "high", "medium", or "low")
Returns — Array of providers matching the given priority Example
const highPriority = getProvidersByPriority("high");
console.log(highPriority.map(p => p.toolName));

getPrimaryProvider()

Get the single primary harness provider, if any is registered. Signature
() => Provider | undefined
Returns — The primary provider, or undefined if none is registered Example
const primary = getPrimaryProvider();
if (primary) {
  console.log(`Primary harness: ${primary.toolName}`);
}

getProvidersByStatus(status)

Filter providers by their lifecycle status. Signature
(status: ProviderStatus) => Provider[]
Parameters
NameTypeDescription
statusProviderStatusStatus to filter by ("active", "beta", "deprecated", or "planned")
Returns — Array of providers matching the given status Example
const active = getProvidersByStatus("active");
console.log(`${active.length} active providers`);

getProvidersByInstructFile(file)

Filter providers that use a specific instruction file. Multiple providers often share the same instruction file (e.g. many use "AGENTS.md"). Signature
(file: string) => Provider[]
Parameters
NameTypeDescription
filestringInstruction file name (e.g. "CLAUDE.md", "AGENTS.md")
Returns — Array of providers that use the given instruction file Example
const claudeProviders = getProvidersByInstructFile("CLAUDE.md");
console.log(claudeProviders.map(p => p.id));

getInstructionFiles()

Get the set of all unique instruction file names across all providers. Signature
() => string[]
Returns — Array of unique instruction file names (e.g. ["CLAUDE.md", "AGENTS.md", "GEMINI.md"]) Example
const files = getInstructionFiles();
// ["CLAUDE.md", "AGENTS.md", "GEMINI.md"]

getProviderCount()

Get the total number of registered providers. Signature
() => number
Returns — Count of providers in the registry Example
console.log(`Registry has ${getProviderCount()} providers`);

getRegistryVersion()

Get the semantic version string of the provider registry. Signature
() => string
Returns — Version string from providers/registry.json (e.g. "2.0.0") Example
console.log(`Registry version: ${getRegistryVersion()}`);

getProvidersByHookEvent(event)

Filter providers that support a specific hook event. Signature
(event: HookEvent) => Provider[]
Parameters
NameTypeDescription
eventHookEventHook event to filter by (e.g. "onToolComplete")
Returns — Array of providers whose hooks capability includes the given event Example
const providers = getProvidersByHookEvent("onToolComplete");
console.log(providers.map(p => p.id));

getCommonHookEvents(providerIds)

Get hook events common to all specified providers. If providerIds is provided, returns the intersection of their supported events. If providerIds is undefined or empty, uses all providers. Signature
(providerIds?: string[]) => HookEvent[]
Parameters
NameTypeDescription
providerIds: string[]Optional array of provider IDs to intersect
Returns — Array of hook events supported by ALL specified providers Example
const common = getCommonHookEvents(["claude-code", "gemini-cli"]);
console.log(`${common.length} common hook events`);

providerSupports(provider, dotPath)

Check whether a provider supports a specific capability via dot-path query. The dot-path addresses a value inside provider.capabilities. For boolean fields the provider “supports” the capability when the value is true. For non-boolean fields the provider “supports” it when the value is neither null nor undefined (and, for arrays, non-empty). Signature
(provider: Provider, dotPath: string) => boolean
Parameters
NameTypeDescription
providerProviderProvider to inspect
dotPathstringDot-delimited capability path (e.g. "spawn.supportsSubagents", "hooks.supported")
Returnstrue when the provider has the specified capability Example
const claude = getProvider("claude-code");
providerSupports(claude!, "spawn.supportsSubagents"); // true
providerSupports(claude!, "hooks.supported"); // true (non-empty array)

getSpawnCapableProviders()

Filter providers that support spawning subagents. Signature
() => Provider[]
Returns — Array of providers where capabilities.spawn.supportsSubagents === true Example
const spawnCapable = getSpawnCapableProviders();
console.log(spawnCapable.map(p => p.id));

getProvidersBySpawnCapability(flag)

Filter providers by a specific boolean spawn capability flag. Signature
(flag: keyof Omit<ProviderSpawnCapability, "spawnMechanism" | "spawnCommand">) => Provider[]
Parameters
NameTypeDescription
flagkeyof Omit<ProviderSpawnCapabilityOne of the four boolean flags on ProviderSpawnCapability ("supportsSubagents", "supportsProgrammaticSpawn", "supportsInterAgentComms", "supportsParallelSpawn")
Returns — Array of providers where the specified flag is true Example
const parallel = getProvidersBySpawnCapability("supportsParallelSpawn");
console.log(parallel.map(p => p.id));

resetRegistry()

Reset cached registry data, forcing a reload on next access. Signature
() => void
Example
resetRegistry();
// Next call to getAllProviders() will re-read registry.json

getProvidersBySkillsPrecedence(precedence)

Filter providers by their skills precedence value. Signature
(precedence: SkillsPrecedence) => Provider[]
Parameters
NameTypeDescription
precedenceSkillsPrecedenceSkills precedence to filter by
Returns — Array of providers matching the given precedence Example
const vendorOnly = getProvidersBySkillsPrecedence("vendor-only");
console.log(vendorOnly.map(p => p.id));

getEffectiveSkillsPaths(provider, scope, projectDir)

Get the effective skills paths for a provider, ordered by precedence. Signature
(provider: Provider, scope: PathScope, projectDir?: string) => Array<{ path: string; source: string; scope: string; }>
Parameters
NameTypeDescription
providerProviderProvider to resolve paths for
scopePathScopeWhether to resolve global or project paths
projectDir: stringProject directory for project-scope resolution
Returns — Ordered array of paths with source and scope metadata Example
const provider = getProvider("claude-code")!;
const paths = getEffectiveSkillsPaths(provider, "global");
for (const p of paths) {
  console.log(`${p.source} (${p.scope}): ${p.path}`);
}

buildSkillsMap()

Build a full skills map for all providers. Signature
() => Array<{ providerId: string; toolName: string; precedence: SkillsPrecedence; paths: { global: string | null; project: string | null; }; }>
Returns — Array of skills map entries with provider ID, tool name, precedence, and paths Example
const skillsMap = buildSkillsMap();
for (const entry of skillsMap) {
  console.log(`${entry.providerId}: ${entry.precedence}`);
}

getProviderCapabilities(idOrAlias)

Get capabilities for a provider by ID or alias. Signature
(idOrAlias: string) => ProviderCapabilities | undefined
Parameters
NameTypeDescription
idOrAliasstringProvider ID or alias
Returns — The provider’s capabilities, or undefined if not found Example
const caps = getProviderCapabilities("claude-code");
if (caps?.spawn.supportsSubagents) {
  console.log("Supports subagent spawning");
}

providerSupportsById(idOrAlias, capabilityPath)

Check if a provider supports a capability using ID/alias lookup. Convenience wrapper that resolves the provider first, then delegates to the provider-level providerSupports. Signature
(idOrAlias: string, capabilityPath: string) => boolean
Parameters
NameTypeDescription
idOrAliasstringProvider ID or alias
capabilityPathstringDot-path into capabilities (e.g. “spawn.supportsSubagents”)
Returns — true if the provider supports the capability, false otherwise Example
if (providerSupportsById("claude-code", "spawn.supportsSubagents")) {
  console.log("Claude Code supports subagent spawning");
}

buildInjectionContent(template)

Build injection content from a structured template. Produces a string suitable for injection between CAAMP markers. References are output as @ lines, content blocks are appended as-is. Signature
(template: InjectionTemplate) => string
Parameters
NameTypeDescription
templateInjectionTemplateTemplate defining references and content
Returns — Formatted injection content string Example
const content = buildInjectionContent({
  references: ["\@AGENTS.md"],
});

parseInjectionContent(content)

Parse injection content back into template form. Lines starting with @ are treated as references. All other non-empty lines are treated as content blocks. Signature
(content: string) => InjectionTemplate
Parameters
NameTypeDescription
contentstringRaw injection content string
Returns — Parsed InjectionTemplate Example
const template = parseInjectionContent("\@AGENTS.md\n\@.cleo/config.json");

generateInjectionContent(options)

Generate a standard CAAMP injection block for instruction files. Produces markdown content suitable for injection between CAAMP markers. Optionally includes MCP server and custom content sections. Signature
(options?: { mcpServerName?: string; customContent?: string; }) => string
Parameters
NameTypeDescription
options: { mcpServerName?: string; customContent?: string; }Optional configuration for the generated content
Returns — Generated markdown string Example
const content = generateInjectionContent({ mcpServerName: "filesystem" });

generateSkillsSection(skillNames)

Generate a skills discovery section for instruction files. Signature
(skillNames: string[]) => string
Parameters
NameTypeDescription
skillNamesstring[]Array of skill names to list
Returns — Markdown string listing installed skills Example
const section = generateSkillsSection(["code-review", "testing"]);

getInstructFile(provider)

Get the correct instruction file name for a provider. Signature
(provider: Provider) => string
Parameters
NameTypeDescription
providerProviderProvider registry entry
Returns — Instruction file name Example
const fileName = getInstructFile(provider);
// "CLAUDE.md"

groupByInstructFile(providers)

Group providers by their instruction file name. Useful for determining which providers share the same instruction file (e.g. multiple providers using AGENTS.md). Signature
(providers: Provider[]) => Map<string, Provider[]>
Parameters
NameTypeDescription
providersProvider[]Array of providers to group
Returns — Map from instruction file name to array of providers using that file Example
const groups = groupByInstructFile(getAllProviders());
for (const [file, providers] of groups) {
  console.log(`${file}: ${providers.map(p => p.id).join(", ")}`);
}

checkInjection(filePath, expectedContent)

Check the status of a CAAMP injection block in an instruction file. Returns the injection status: - "missing" - File does not exist - "none" - File exists but has no CAAMP markers - "current" - CAAMP block exists and matches expected content (or no expected content given) - "outdated" - CAAMP block exists but differs from expected content Signature
(filePath: string, expectedContent?: string) => Promise<InjectionStatus>
Parameters
NameTypeDescription
filePathstringAbsolute path to the instruction file
expectedContent: stringOptional expected content to compare against
Returns — The injection status Example
const status = await checkInjection("/project/CLAUDE.md", expectedContent);
if (status === "outdated") {
  console.log("CAAMP injection needs updating");
}

inject(filePath, content)

Inject content into an instruction file between CAAMP markers. Behavior depends on the file state: - File does not exist: creates the file with the injection block → "created" - File exists without markers: prepends the injection block → "added" - File exists with multiple markers (duplicates): consolidates into single block → "consolidated" - File exists with markers, content differs: replaces the block → "updated" - File exists with markers, content matches: no-op → "intact" This function is idempotent — calling it multiple times with the same content will not modify the file after the first write. Signature
(filePath: string, content: string) => Promise<"created" | "added" | "consolidated" | "updated" | "intact">
Parameters
NameTypeDescription
filePathstringAbsolute path to the instruction file
contentstringContent to inject between CAAMP markers
Returns — Action taken: "created", "added", "consolidated", "updated", or "intact" Example
const action = await inject("/project/CLAUDE.md", "## My Config\nSome content");
console.log(`File ${action}`); // "created" on first call, "intact" on subsequent

removeInjection(filePath)

Remove the CAAMP injection block from an instruction file. If removing the block would leave the file empty, the file is deleted entirely. Signature
(filePath: string) => Promise<boolean>
Parameters
NameTypeDescription
filePathstringAbsolute path to the instruction file
Returnstrue if a CAAMP block was found and removed, false otherwise Example
const removed = await removeInjection("/project/CLAUDE.md");

checkAllInjections(providers, projectDir, scope, expectedContent)

Check injection status across all providers’ instruction files. Deduplicates by file path since multiple providers may share the same instruction file (e.g. many providers use AGENTS.md). Signature
(providers: Provider[], projectDir: string, scope: "project" | "global", expectedContent?: string) => Promise<InjectionCheckResult[]>
Parameters
NameTypeDescription
providersProvider[]Array of providers to check
projectDirstringAbsolute path to the project directory
scope"project" | "global"Whether to check project or global instruction files
expectedContent: stringOptional expected content to compare against
Returns — Array of injection check results, one per unique instruction file Example
const results = await checkAllInjections(providers, "/project", "project", expected);
const outdated = results.filter(r => r.status === "outdated");

injectAll(providers, projectDir, scope, content)

Inject content into all providers’ instruction files. Deduplicates by file path to avoid injecting the same file multiple times. Signature
(providers: Provider[], projectDir: string, scope: "project" | "global", content: string) => Promise<Map<string, "created" | "added" | "consolidated" | "updated" | "intact">>
Parameters
NameTypeDescription
providersProvider[]Array of providers to inject into
projectDirstringAbsolute path to the project directory
scope"project" | "global"Whether to target project or global instruction files
contentstringContent to inject between CAAMP markers
Returns — Map of file path to action taken ("created", "added", "consolidated", "updated", or "intact") Example
const results = await injectAll(providers, "/project", "project", content);
for (const [file, action] of results) {
  console.log(`${file}: ${action}`);
}

ensureProviderInstructionFile(providerId, projectDir, options)

Ensure a provider’s instruction file exists with the correct CAAMP block. This is the canonical API for adapters and external packages to manage provider instruction files. Instead of directly creating/modifying CLAUDE.md, GEMINI.md, etc., callers should use this function to delegate instruction file management to CAAMP. The instruction file name is resolved from CAAMP’s provider registry (single source of truth), not hardcoded by the caller. Signature
(providerId: string, projectDir: string, options: EnsureProviderInstructionFileOptions) => Promise<EnsureProviderInstructionFileResult>
Parameters
NameTypeDescription
providerIdstringProvider ID from the registry (e.g. "claude-code", "gemini-cli")
projectDirstringAbsolute path to the project directory
optionsEnsureProviderInstructionFileOptionsReferences, content, and scope configuration
Returns — Result with file path, action taken, and provider metadata Throws
  • Error if the provider ID is not found in the registry
Example
const result = await ensureProviderInstructionFile("claude-code", "/project", {
  references: ["\@AGENTS.md"],
});

ensureAllProviderInstructionFiles(providerIds, projectDir, options)

Ensure instruction files for multiple providers at once. Deduplicates by file path — providers sharing the same instruction file (e.g. many providers use AGENTS.md) are only written once. Signature
(providerIds: string[], projectDir: string, options: EnsureProviderInstructionFileOptions) => Promise<EnsureProviderInstructionFileResult[]>
Parameters
NameTypeDescription
providerIdsstring[]Array of provider IDs from the registry
projectDirstringAbsolute path to the project directory
optionsEnsureProviderInstructionFileOptionsReferences, content, and scope configuration
Returns — Array of results, one per unique instruction file Throws
  • Error if any provider ID is not found in the registry
Example
const results = await ensureAllProviderInstructionFiles(
  ["claude-code", "cursor", "gemini-cli"],
  "/project",
  { references: ["\@AGENTS.md"] },
);

setVerbose(v)

Enable or disable verbose (debug) logging mode. When enabled, debug messages are written to stderr. Signature
(v: boolean) => void
Parameters
NameTypeDescription
vbooleantrue to enable verbose mode, false to disable
Example
setVerbose(true);

setQuiet(q)

Enable or disable quiet mode. When enabled, info and warning messages are suppressed. Errors are always shown. Signature
(q: boolean) => void
Parameters
NameTypeDescription
qbooleantrue to enable quiet mode, false to disable
Example
setQuiet(true);

debug(args)

Log a debug message to stderr when verbose mode is enabled. Signature
(...args: unknown[]) => void
Parameters
NameTypeDescription
argsunknown[]Values to log (forwarded to console.error)
Example
debug("Loading config from", filePath);

info(args)

Log an informational message to stdout. Signature
(...args: unknown[]) => void
Parameters
NameTypeDescription
argsunknown[]Values to log (forwarded to console.log)
Example
info("Installed 3 skills");

warn(args)

Log a warning message to stderr. Signature
(...args: unknown[]) => void
Parameters
NameTypeDescription
argsunknown[]Values to log (forwarded to console.warn)
Example
warn("Deprecated option used");

error(args)

Log an error message to stderr. Signature
(...args: unknown[]) => void
Parameters
NameTypeDescription
argsunknown[]Values to log (forwarded to console.error)
Example
error("Failed to install skill:", err.message);

isVerbose()

Check if verbose (debug) logging is currently enabled. Signature
() => boolean
Returnstrue if verbose mode is active Example
if (isVerbose()) {
  console.error("Extra debug info");
}

isQuiet()

Check if quiet mode is currently enabled. Signature
() => boolean
Returnstrue if quiet mode is active Example
if (!isQuiet()) {
  console.log("Status message");
}

setHuman(h)

Enable or disable human-readable output mode. When enabled, commands output human-readable format instead of JSON. Signature
(h: boolean) => void
Parameters
NameTypeDescription
hbooleantrue to enable human mode, false to disable
Example
setHuman(true);

isHuman()

Check if human-readable output mode is currently enabled. Signature
() => boolean
Returnstrue if human mode is active Example
if (isHuman()) {
  console.log("Human readable output");
} else {
  console.log(JSON.stringify(data));
}

detectProvider(provider)

Detect if a single provider is installed on the system. Checks each detection method configured for the provider (binary, directory, appBundle, flatpak) and returns which methods matched. Signature
(provider: Provider) => DetectionResult
Parameters
NameTypeDescription
providerProviderThe provider to detect
Returns — Detection result with installation status and matched methods Example
const provider = getProvider("claude-code")!;
const result = detectProvider(provider);
if (result.installed) {
  console.log(`Claude Code found via: ${result.methods.join(", ")}`);
}

detectProjectProvider(provider, projectDir)

Detect if a provider has project-level config in the given directory. Signature
(provider: Provider, projectDir: string) => boolean
Parameters
NameTypeDescription
providerProviderProvider to check for project-level config
projectDirstringAbsolute path to the project directory
Returnstrue if the provider has a config file in the project directory Example
const provider = getProvider("claude-code")!;
const hasProjectConfig = detectProjectProvider(provider, "/home/user/my-project");

detectAllProviders(options)

Detect all registered providers and return their installation status. Runs detection for every provider in the registry. Signature
(options?: DetectionCacheOptions) => DetectionResult[]
Parameters
NameTypeDescription
options: DetectionCacheOptionsCache control options
Returns — Array of detection results for all providers Example
const results = detectAllProviders({ forceRefresh: true });
const installed = results.filter(r => r.installed);
console.log(`${installed.length} agents detected`);

getInstalledProviders(options)

Get only providers that are currently installed on the system. Convenience wrapper that filters detectAllProviders results to only those with installed === true. Signature
(options?: DetectionCacheOptions) => Provider[]
Parameters
NameTypeDescription
options: DetectionCacheOptionsCache control options passed through to detection
Returns — Array of installed provider definitions Example
const installed = getInstalledProviders({ forceRefresh: true });
console.log(installed.map(p => p.toolName).join(", "));

detectProjectProviders(projectDir, options)

Detect all providers and enrich results with project-level presence. Extends detectAllProviders by also checking whether each provider has a project-level config file in the given directory. Signature
(projectDir: string, options?: DetectionCacheOptions) => DetectionResult[]
Parameters
NameTypeDescription
projectDirstringAbsolute path to the project directory to check
options: DetectionCacheOptionsCache control options passed through to detection
Returns — Array of detection results with projectDetected populated Example
const results = detectProjectProviders("/home/user/my-project", { forceRefresh: true });
for (const r of results) {
  if (r.projectDetected) {
    console.log(`${r.provider.toolName} has project config`);
  }
}

resetDetectionCache()

Reset the detection result cache, forcing fresh detection on next call. Signature
() => void
Example
resetDetectionCache();
// Next detectAllProviders() call will bypass cache
const fresh = detectAllProviders();

installToCanonical(sourcePath, skillName)

Copy skill files to the canonical location. Signature
(sourcePath: string, skillName: string) => Promise<string>
Parameters
NameTypeDescription
sourcePathstringAbsolute path to the source skill directory to copy
skillNamestringName for the skill (used as the subdirectory name)
Returns — Absolute path to the canonical installation directory Example
const canonicalPath = await installToCanonical("/tmp/my-skill", "my-skill");
console.log(`Installed to: ${canonicalPath}`);

installSkill(sourcePath, skillName, providers, isGlobal, projectDir)

Install a skill from a local path to the canonical location and link to agents. Signature
(sourcePath: string, skillName: string, providers: Provider[], isGlobal: boolean, projectDir?: string) => Promise<SkillInstallResult>
Parameters
NameTypeDescription
sourcePathstringLocal path to the skill directory to install
skillNamestringName for the installed skill
providersProvider[]Target providers to link the skill to
isGlobalbooleanWhether to link to global or project skill directories
projectDir: stringProject directory (defaults to process.cwd())
Returns — Install result with linked agents and any errors Example
const result = await installSkill("/tmp/my-skill", "my-skill", providers, true, "/my/project");
if (result.success) {
  console.log(`Linked to: ${result.linkedAgents.join(", ")}`);
}

removeSkill(skillName, providers, isGlobal, projectDir)

Remove a skill from the canonical location and all agent symlinks. Signature
(skillName: string, providers: Provider[], isGlobal: boolean, projectDir?: string) => Promise<{ removed: string[]; errors: string[]; }>
Parameters
NameTypeDescription
skillNamestringName of the skill to remove
providersProvider[]Providers to unlink the skill from
isGlobalbooleanWhether to target global or project skill directories
projectDir: stringProject directory (defaults to process.cwd())
Returns — Object with arrays of successfully removed provider IDs and error messages Example
const { removed, errors } = await removeSkill("my-skill", providers, true, "/my/project");
console.log(`Removed from: ${removed.join(", ")}`);

listCanonicalSkills()

List all skills installed in the canonical skills directory. Signature
() => Promise<string[]>
Returns — Array of skill names Example
const skills = await listCanonicalSkills();
// ["my-skill", "another-skill"]

selectProvidersByMinimumPriority(providers, minimumPriority)

Filters providers by minimum priority and returns them in deterministic tier order. Signature
(providers: Provider[], minimumPriority?: ProviderPriority) => Provider[]
Parameters
NameTypeDescription
providersProvider[]The full list of providers to filter
minimumPriority: ProviderPriorityThe minimum priority threshold, defaults to "low" (include all)
Returns — A filtered and sorted array of providers meeting the priority threshold Example
const highPriority = selectProvidersByMinimumPriority(allProviders, "high");
// returns only providers with priority "high"

installBatchWithRollback(options)

Installs multiple skills across filtered providers with rollback. Signature
(options: BatchInstallOptions) => Promise<BatchInstallResult>
Parameters
NameTypeDescription
optionsBatchInstallOptionsThe batch installation options including providers, operations, and scope
Returns — A result object indicating success, applied counts, and any rollback information Example
const result = await installBatchWithRollback({
  minimumPriority: "high",
  skills: [{ sourcePath: "/path/to/skill", skillName: "my-skill" }],
});
if (!result.success) {
  console.error("Failed:", result.error);
}

updateInstructionsSingleOperation(providers, content, scope, projectDir)

Updates instruction files across providers as a single operation. Signature
(providers: Provider[], content: string, scope?: Scope, projectDir?: string) => Promise<InstructionUpdateSummary>
Parameters
NameTypeDescription
providersProvider[]The providers whose instruction files to update
contentstringThe instruction content to inject
scope: ScopeThe scope for instruction updates, defaults to "project"
projectDir: stringThe project root directory, defaults to process.cwd()
Returns — A summary of updated files and actions taken per file Example
const summary = await updateInstructionsSingleOperation(
  providers,
  "## CAAMP Config\nUse these MCP servers...",
  "project",
);
console.log(`Updated ${summary.updatedFiles} files`);

resolveFormat(options)

Resolves output format based on flags and defaults. Signature
(options: FormatOptions) => "json" | "human"
Parameters
NameTypeDescription
optionsFormatOptionsFormat resolution options
Returns"json" or "human" Throws
  • Error if format flags conflict
Example
const format = resolveFormat({ jsonFlag: true });

buildEnvelope(operation, mvi, result, error, page, sessionId, warnings)

Builds a standard LAFS envelope. Signature
<T>(operation: string, mvi: MVILevel, result: T | null, error: LAFSErrorShape | null, page?: LAFSPage | null, sessionId?: string, warnings?: LAFSWarning[]) => LAFSEnvelope<T>
Parameters
NameTypeDescription
operationstringOperation identifier (e.g., "skills.list", "doctor.check")
mviMVILevelMachine-Verified Instruction disclosure level
resultT | nullOperation result data (null if error)
errorLAFSErrorShape | nullError details (null if success)
page: LAFSPage | nullPagination info (null if not applicable)
sessionId: stringOptional session identifier
warnings: LAFSWarning[]Optional array of warnings to attach
Returns — LAFS-compliant envelope Example
const envelope = buildEnvelope(
  "skills.list",
  "full",
  { skills: [], count: 0 },
  null,
);

emitError(operation, mvi, code, message, category, details, exitCode)

Emits a JSON error envelope to stderr and exits the process. Signature
(operation: string, mvi: MVILevel, code: string, message: string, category: LAFSErrorCategory, details?: Record<string, unknown>, exitCode?: number) => never
Parameters
NameTypeDescription
operationstringOperation identifier
mviMVILevelMachine-Verified Instruction disclosure level
codestringError code
messagestringError message
categoryLAFSErrorCategoryError category from LAFS protocol
details: Record<stringAdditional error details
exitCode: numberProcess exit code (default: 1)
Example
emitError(
  "skills.install",
  "full",
  "E_SKILL_NOT_FOUND",
  "Skill not found",
  "NOT_FOUND",
  { skillName: "my-skill" },
  1,
);

emitJsonError(operation, mvi, code, message, category, details)

Emits a JSON error envelope without exiting (for catch blocks). Signature
(operation: string, mvi: MVILevel, code: string, message: string, category: LAFSErrorCategory, details?: Record<string, unknown>) => void
Parameters
NameTypeDescription
operationstringOperation identifier
mviMVILevelMachine-Verified Instruction disclosure level
codestringError code
messagestringError message
categoryLAFSErrorCategoryError category from LAFS protocol
details: Record<stringAdditional error details
Example
try {
  await riskyOperation();
} catch (err) {
  emitJsonError("operation", "full", "E_FAILED", "Operation failed", "INTERNAL", {});
  process.exit(1);
}

outputSuccess(operation, mvi, result, page, sessionId, warnings)

Outputs a successful LAFS envelope to stdout. Signature
<T>(operation: string, mvi: MVILevel, result: T, page?: LAFSPage, sessionId?: string, warnings?: LAFSWarning[]) => void
Parameters
NameTypeDescription
operationstringOperation identifier
mviMVILevelMachine-Verified Instruction disclosure level
resultTOperation result data
page: LAFSPageOptional pagination info
sessionId: stringOptional session identifier
warnings: LAFSWarning[]Optional warnings to attach
Example
outputSuccess("skills.list", "full", { skills: [], count: 0 });

handleFormatError(error, operation, mvi, jsonFlag)

Handles format resolution errors consistently. Signature
(error: unknown, operation: string, mvi: MVILevel, jsonFlag: boolean | undefined) => never
Parameters
NameTypeDescription
errorunknownThe error that occurred during format resolution
operationstringOperation identifier
mviMVILevelMachine-Verified Instruction disclosure level
jsonFlagboolean | undefinedWhether --json flag was explicitly set
Returns — never (exits process) Example
try {
  format = resolveFormat({ jsonFlag: opts.json, humanFlag: opts.human });
} catch (error) {
  handleFormatError(error, "skills.list", "full", opts.json);
}

LAFSCommandError

Structured error class for LAFS-compliant command failures with error codes and recovery hints. Signature
typeof LAFSCommandError

emitSuccess(operation, result, mvi)

Emits a successful LAFS result envelope to stdout. Signature
<T>(operation: string, result: T, mvi?: MVILevel) => void
Parameters
NameTypeDescription
operationstringThe LAFS operation identifier
resultTThe result payload to include in the envelope
mvi: MVILevelThe minimum viable information level, defaults to “standard”
Example
emitSuccess("advanced.providers", { providers: [...] });

emitError(operation, error, mvi)

Emits a failed LAFS error envelope to stderr. Signature
(operation: string, error: unknown, mvi?: MVILevel) => void
Parameters
NameTypeDescription
operationstringThe LAFS operation identifier
errorunknownThe error to serialize, either a LAFSCommandError or generic Error/unknown
mvi: MVILevelThe minimum viable information level, defaults to “standard”
Example
emitError("advanced.apply", new LAFSCommandError("E_VALIDATION", "bad input", "fix it"));

runLafsCommand(command, mvi, action)

Runs an async action and emits the result as a LAFS success or error envelope. Signature
<T>(command: string, mvi: MVILevel, action: () => Promise<T>) => Promise<void>
Parameters
NameTypeDescription
commandstringThe LAFS operation identifier
mviMVILevelThe minimum viable information level
action(The async function to execute
Returns — Resolves when the action completes and output is emitted Example
await runLafsCommand("advanced.batch", "standard", async () => {
  return { installed: 3 };
});

parsePriority(value)

Parses and validates a provider priority tier string. Signature
(value: string) => ProviderPriority
Parameters
NameTypeDescription
valuestringThe priority string to parse
Returns — The validated ProviderPriority value Example
const tier = parsePriority("high"); // "high"

resolveProviders(options)

Resolves the set of target providers from CLI targeting options. Signature
(options: ProviderTargetOptions) => Provider[]
Parameters
NameTypeDescription
optionsProviderTargetOptionsThe provider targeting options from the CLI
Returns — An array of resolved Provider objects Example
const providers = resolveProviders({ all: true });

readJsonFile(path)

Reads and parses a JSON file from disk. Signature
(path: string) => Promise<unknown>
Parameters
NameTypeDescription
pathstringAbsolute or relative path to the JSON file
Returns — The parsed JSON value Example
const data = await readJsonFile("./operations.json");

readSkillOperations(path)

Reads and validates a JSON file containing skill batch operations. Signature
(path: string) => Promise<SkillBatchOperation[]>
Parameters
NameTypeDescription
pathstringPath to the JSON file containing an array of skill operations
Returns — An array of validated SkillBatchOperation objects Example
const ops = await readSkillOperations("./skill-ops.json");

readTextInput(inlineContent, filePath)

Reads text input from either inline content or a file path, enforcing mutual exclusivity. Signature
(inlineContent: string | undefined, filePath: string | undefined) => Promise<string | undefined>
Parameters
NameTypeDescription
inlineContentstring | undefinedInline text content from the —content flag, or undefined
filePathstring | undefinedPath to a content file from the —content-file flag, or undefined
Returns — The text content string, or undefined if no input was provided Example
const content = await readTextInput(undefined, "./content.txt");

registerAdvancedBatch(parent)

Registers the advanced batch subcommand for rollback-capable batch install of skills. Signature
(parent: Command) => void
Parameters
NameTypeDescription
parentCommandThe parent advanced Command to attach the batch subcommand to
Example
caamp advanced batch --skills-file skills.json
caamp advanced batch --skills-file skills.json --min-tier medium

registerAdvancedInstructions(parent)

Registers the advanced instructions subcommand for single-operation instruction updates. Signature
(parent: Command) => void
Parameters
NameTypeDescription
parentCommandThe parent advanced Command to attach the instructions subcommand to
Example
caamp advanced instructions --content "Custom block" --all
caamp advanced instructions --content-file block.md --min-tier high

registerAdvancedProviders(parent)

Registers the advanced providers subcommand for selecting providers by priority tier. Signature
(parent: Command) => void
Parameters
NameTypeDescription
parentCommandThe parent advanced Command to attach the providers subcommand to
Example
caamp advanced providers --min-tier high
caamp advanced providers --all --details

registerAdvancedCommands(program)

Registers the advanced command group with providers, batch, and instructions subcommands. Signature
(program: Command) => void
Parameters
NameTypeDescription
programCommandThe root Commander program to attach the advanced command group to
Example
caamp advanced batch --skills-file skills.json
caamp advanced instructions --content "## Setup" --all

deepMerge(target, source)

Deep merge two objects, with source values winning on conflict. Recursively merges nested plain objects. Arrays and non-object values from source overwrite target values. Signature
(target: Record<string, unknown>, source: Record<string, unknown>) => Record<string, unknown>
Parameters
NameTypeDescription
targetRecord<stringBase object to merge into
sourceRecord<stringObject with values that take precedence
Returns — A new merged object (does not mutate inputs) Example
const merged = deepMerge({ a: 1, b: { c: 2 } }, { b: { d: 3 } });
// { a: 1, b: { c: 2, d: 3 } }

setNestedValue(obj, keyPath, key, value)

Set a nested value using a dot-notation key path. Signature
(obj: Record<string, unknown>, keyPath: string, key: string, value: unknown) => Record<string, unknown>
Parameters
NameTypeDescription
objRecord<stringRoot object to modify
keyPathstringDot-separated path to the parent key (e.g. "mcpServers")
keystringFinal key name for the value
valueunknownValue to set at the nested location
Returns — A new object with the value set at the specified path Example
const result = setNestedValue({}, "a.b", "c", 42);
// { a: { b: { c: 42 } } }

getNestedValue(obj, keyPath)

Get a nested value from an object using a dot-notation key path. Signature
(obj: Record<string, unknown>, keyPath: string) => unknown
Parameters
NameTypeDescription
objRecord<stringObject to traverse
keyPathstringDot-separated key path (e.g. "mcpServers" or "a.b.c")
Returns — The value at the key path, or undefined if not found Example
getNestedValue({ a: { b: { c: 42 } } }, "a.b.c"); // 42
getNestedValue({ a: 1 }, "a.b"); // undefined

ensureDir(filePath)

Ensure that the parent directories of a file path exist. Creates directories recursively if they do not exist. Signature
(filePath: string) => Promise<void>
Parameters
NameTypeDescription
filePathstringAbsolute path to a file (parent directories will be created)
Example
await ensureDir("/path/to/new/dir/file.json");
// /path/to/new/dir/ now exists

readJsonConfig(filePath)

Read and parse a JSON or JSONC config file. Signature
(filePath: string) => Promise<Record<string, unknown>>
Parameters
NameTypeDescription
filePathstringAbsolute path to the JSON/JSONC file
Returns — Parsed config object Example
const config = await readJsonConfig("/home/user/.config/claude/settings.json");

writeJsonConfig(filePath, configKey, serverName, serverConfig)

Write a server config entry to a JSON/JSONC file, preserving comments. Signature
(filePath: string, configKey: string, serverName: string, serverConfig: unknown) => Promise<void>
Parameters
NameTypeDescription
filePathstringAbsolute path to the JSON/JSONC file
configKeystringDot-notation key path to the servers section (e.g. "mcpServers")
serverNamestringName/key for the server entry
serverConfigunknownServer configuration object to write
Example
await writeJsonConfig("/path/to/config.json", "mcpServers", "my-server", { command: "node" });

removeJsonConfig(filePath, configKey, serverName)

Remove a server entry from a JSON/JSONC config file. Signature
(filePath: string, configKey: string, serverName: string) => Promise<boolean>
Parameters
NameTypeDescription
filePathstringAbsolute path to the JSON/JSONC file
configKeystringDot-notation key path to the servers section
serverNamestringName/key of the server entry to remove
Returnstrue if the entry was removed, false if the file or entry was not found Example
const removed = await removeJsonConfig("/path/to/config.json", "mcpServers", "old-server");

readTomlConfig(filePath)

Read and parse a TOML config file. Signature
(filePath: string) => Promise<Record<string, unknown>>
Parameters
NameTypeDescription
filePathstringAbsolute path to the TOML file
Returns — Parsed config object Example
const config = await readTomlConfig("/path/to/config.toml");

writeTomlConfig(filePath, configKey, serverName, serverConfig)

Write a server config entry to a TOML file. Signature
(filePath: string, configKey: string, serverName: string, serverConfig: unknown) => Promise<void>
Parameters
NameTypeDescription
filePathstringAbsolute path to the TOML file
configKeystringDot-notation key path to the servers section
serverNamestringName/key for the server entry
serverConfigunknownServer configuration object to write
Example
await writeTomlConfig("/path/to/config.toml", "mcpServers", "my-server", { command: "node" });

removeTomlConfig(filePath, configKey, serverName)

Remove a server entry from a TOML config file. Signature
(filePath: string, configKey: string, serverName: string) => Promise<boolean>
Parameters
NameTypeDescription
filePathstringAbsolute path to the TOML file
configKeystringDot-notation key path to the servers section
serverNamestringName/key of the server entry to remove
Returnstrue if the entry was removed, false if the file or entry was not found Example
const removed = await removeTomlConfig("/path/to/config.toml", "mcpServers", "old-server");

readYamlConfig(filePath)

Read and parse a YAML config file. Signature
(filePath: string) => Promise<Record<string, unknown>>
Parameters
NameTypeDescription
filePathstringAbsolute path to the YAML file
Returns — Parsed config object Example
const config = await readYamlConfig("/path/to/config.yaml");

writeYamlConfig(filePath, configKey, serverName, serverConfig)

Write a server config entry to a YAML file. Signature
(filePath: string, configKey: string, serverName: string, serverConfig: unknown) => Promise<void>
Parameters
NameTypeDescription
filePathstringAbsolute path to the YAML file
configKeystringDot-notation key path to the servers section
serverNamestringName/key for the server entry
serverConfigunknownServer configuration object to write
Example
await writeYamlConfig("/path/to/config.yaml", "mcpServers", "my-server", { command: "node" });

removeYamlConfig(filePath, configKey, serverName)

Remove a server entry from a YAML config file. Signature
(filePath: string, configKey: string, serverName: string) => Promise<boolean>
Parameters
NameTypeDescription
filePathstringAbsolute path to the YAML file
configKeystringDot-notation key path to the servers section
serverNamestringName/key of the server entry to remove
Returnstrue if the entry was removed, false if the file or entry was not found Example
const removed = await removeYamlConfig("/path/to/config.yaml", "mcpServers", "old-server");

readConfig(filePath, format)

Read and parse a config file in the specified format. Dispatches to the appropriate format handler (JSON/JSONC, YAML, or TOML). Signature
(filePath: string, format: ConfigFormat) => Promise<Record<string, unknown>>
Parameters
NameTypeDescription
filePathstringAbsolute path to the config file
formatConfigFormatConfig file format
Returns — Parsed config object Throws
  • If the file cannot be read or the format is unsupported
Example
const config = await readConfig("/path/to/config.json", "jsonc");

writeConfig(filePath, format, key, serverName, serverConfig)

Write a server entry to a config file, preserving existing content. Dispatches to the appropriate format handler. For JSONC files, comments are preserved using jsonc-parser. Signature
(filePath: string, format: ConfigFormat, key: string, serverName: string, serverConfig: unknown) => Promise<void>
Parameters
NameTypeDescription
filePathstringAbsolute path to the config file
formatConfigFormatConfig file format
keystringDot-notation key path to the servers section (e.g. "mcpServers")
serverNamestringName/key for the server entry
serverConfigunknownServer configuration object to write
Throws
  • If the format is unsupported
Example
await writeConfig("/path/to/config.json", "jsonc", "mcpServers", "my-server", config);

removeConfig(filePath, format, key, serverName)

Remove a server entry from a config file in the specified format. Signature
(filePath: string, format: ConfigFormat, key: string, serverName: string) => Promise<boolean>
Parameters
NameTypeDescription
filePathstringAbsolute path to the config file
formatConfigFormatConfig file format
keystringDot-notation key path to the servers section
serverNamestringName/key of the server entry to remove
Returnstrue if the entry was removed, false otherwise Throws
  • If the format is unsupported
Example
const removed = await removeConfig("/path/to/config.json", "jsonc", "mcpServers", "my-server");

registerConfigCommand(program)

Registers the config command group with show and path subcommands for viewing provider configurations. Signature
(program: Command) => void
Parameters
NameTypeDescription
programCommandThe root Commander program to attach the config command group to
Example
caamp config show claude-code --global
caamp config path cursor project

readLockFile()

Read and parse the CAAMP lock file from disk. Signature
() => Promise<CaampLockFile>
Returns — Parsed lock file contents Example
const lock = await readLockFile();
console.log(Object.keys(lock.mcpServers));

writeLockFile(lock)

Write the lock file atomically under a process lock guard. Signature
(lock: CaampLockFile) => Promise<void>
Parameters
NameTypeDescription
lockCaampLockFileLock file data to persist
Example
const lock = await readLockFile();
lock.mcpServers["my-server"] = entry;
await writeLockFile(lock);

updateLockFile(updater)

Safely read-modify-write the lock file under a process lock guard. Signature
(updater: (lock: CaampLockFile) => void | Promise<void>) => Promise<CaampLockFile>
Parameters
NameTypeDescription
updater(lock: CaampLockFileCallback that modifies the lock object (may be async)
Returns — The updated lock file contents after the write Example
const updated = await updateLockFile((lock) => {
  lock.mcpServers["new-server"] = entry;
});

getCaampVersion()

Retrieve the current CAAMP package version from the nearest package.json. Signature
() => string
Returns — The semver version string (e.g. "1.8.1") Example
const version = getCaampVersion();
console.log(`CAAMP v${version}`);

registerDoctorCommand(program)

Registers the doctor command for diagnosing configuration issues and overall system health. Signature
(program: Command) => void
Parameters
NameTypeDescription
programCommandThe root Commander program to attach the doctor command to
Example
caamp doctor --human
caamp doctor --json

registerInstructionsCheck(parent)

Registers the instructions check subcommand for verifying injection status across providers. Signature
(parent: Command) => void
Parameters
NameTypeDescription
parentCommandThe parent instructions Command to attach the check subcommand to
Example
caamp instructions check --human
caamp instructions check --agent claude-code

registerInstructionsInject(parent)

Registers the instructions inject subcommand for injecting instruction blocks into provider files. Signature
(parent: Command) => void
Parameters
NameTypeDescription
parentCommandThe parent instructions Command to attach the inject subcommand to
Example
caamp instructions inject --all --global
caamp instructions inject --agent claude-code --dry-run

registerInstructionsUpdate(parent)

Registers the instructions update subcommand for refreshing all instruction file injections. Signature
(parent: Command) => void
Parameters
NameTypeDescription
parentCommandThe parent instructions Command to attach the update subcommand to
Example
caamp instructions update --yes
caamp instructions update --global --json

registerInstructionsCommands(program)

Registers the instructions command group with inject, check, and update subcommands. Signature
(program: Command) => void
Parameters
NameTypeDescription
programCommandThe root Commander program to attach the instructions command group to
Example
caamp instructions inject --all
caamp instructions check --human
caamp instructions update --yes

resetHookMappings()

Reset the cached hook mappings data. Signature
() => void
Example
import { resetHookMappings, getHookMappingsVersion } from "./normalizer.js";

// Force a fresh load from disk
resetHookMappings();
const version = getHookMappingsVersion();

getCanonicalEvent(event)

Get the canonical event definition (category, description, canBlock). Signature
(event: CanonicalHookEvent) => CanonicalEventDefinition
Parameters
NameTypeDescription
eventCanonicalHookEventThe canonical event name to look up.
Returns — The event definition containing category, description, and canBlock flag. Example
import { getCanonicalEvent } from "./normalizer.js";

const def = getCanonicalEvent("PreToolUse");
console.log(def.category);  // "tool"
console.log(def.canBlock);  // true

getAllCanonicalEvents()

Get all canonical event definitions. Signature
() => Record<CanonicalHookEvent, CanonicalEventDefinition>
Returns — A record mapping every canonical event name to its definition. Example
import { getAllCanonicalEvents } from "./normalizer.js";

const events = getAllCanonicalEvents();
for (const [name, def] of Object.entries(events)) {
  console.log(`${name}: ${def.description}`);
}

getCanonicalEventsByCategory(category)

Get canonical events filtered by category. Signature
(category: HookCategory) => CanonicalHookEvent[]
Parameters
NameTypeDescription
categoryHookCategoryThe hook category to filter by (e.g. "session", "tool").
Returns — Array of canonical event names that belong to the specified category. Example
import { getCanonicalEventsByCategory } from "./normalizer.js";

const toolEvents = getCanonicalEventsByCategory("tool");
// ["PreToolUse", "PostToolUse", "PostToolUseFailure"]

getProviderHookProfile(providerId)

Get the full hook profile for a provider. Signature
(providerId: string) => ProviderHookProfile | undefined
Parameters
NameTypeDescription
providerIdstringThe provider identifier (e.g. "claude-code", "gemini-cli").
Returns — The provider’s hook profile, or undefined if not found. Example
import { getProviderHookProfile } from "./normalizer.js";

const profile = getProviderHookProfile("claude-code");
if (profile) {
  console.log(profile.hookSystem); // "config"
  console.log(profile.experimental); // false
}

getMappedProviderIds()

Get all provider IDs that have hook mappings. Signature
() => string[]
Returns — Array of provider ID strings. Example
import { getMappedProviderIds } from "./normalizer.js";

const ids = getMappedProviderIds();
// ["claude-code", "gemini-cli", "cursor", "kimi", ...]

toNative(canonical, providerId)

Translate a CAAMP canonical event name to the provider’s native name. Signature
(canonical: CanonicalHookEvent, providerId: string) => string | null
Parameters
NameTypeDescription
canonicalCanonicalHookEventThe CAAMP canonical event name to translate.
providerIdstringThe target provider identifier.
Returns — The native event name, or null if unsupported. Example
import { toNative } from "./normalizer.js";

toNative("PreToolUse", "claude-code");   // "PreToolUse"
toNative("PreToolUse", "gemini-cli");    // "BeforeTool"
toNative("PreToolUse", "cursor");        // "preToolUse"
toNative("PreToolUse", "kimi");          // null

toCanonical(nativeName, providerId)

Translate a provider-native event name to the CAAMP canonical name. Signature
(nativeName: string, providerId: string) => CanonicalHookEvent | null
Parameters
NameTypeDescription
nativeNamestringThe provider-native event name to look up.
providerIdstringThe provider identifier to search within.
Returns — The canonical event name, or null if no mapping exists. Example
import { toCanonical } from "./normalizer.js";

toCanonical("BeforeTool", "gemini-cli");     // "PreToolUse"
toCanonical("stop", "cursor");               // "ResponseComplete"
toCanonical("UserPromptSubmit", "claude-code"); // "PromptSubmit"

toNativeBatch(canonicals, providerId)

Batch-translate multiple canonical events to native names for a provider. Signature
(canonicals: CanonicalHookEvent[], providerId: string) => NormalizedHookEvent[]
Parameters
NameTypeDescription
canonicalsCanonicalHookEvent[]Array of canonical event names to translate.
providerIdstringThe target provider identifier.
Returns — Array of normalized events (only supported ones included). Example
import { toNativeBatch } from "./normalizer.js";

const events = toNativeBatch(
  ["PreToolUse", "PostToolUse", "ConfigChange"],
  "claude-code",
);
// Returns NormalizedHookEvent[] for supported events only

supportsHook(canonical, providerId)

Check if a provider supports a specific canonical hook event. Signature
(canonical: CanonicalHookEvent, providerId: string) => boolean
Parameters
NameTypeDescription
canonicalCanonicalHookEventThe canonical event name to check.
providerIdstringThe provider identifier to check against.
Returnstrue if the provider supports this canonical event, false otherwise. Example
import { supportsHook } from "./normalizer.js";

supportsHook("PreToolUse", "claude-code"); // true
supportsHook("PreToolUse", "kimi");        // false

getHookSupport(canonical, providerId)

Get full hook support details for a canonical event on a provider. Signature
(canonical: CanonicalHookEvent, providerId: string) => HookSupportResult
Parameters
NameTypeDescription
canonicalCanonicalHookEventThe canonical event name to query.
providerIdstringThe provider identifier to query against.
Returns — Support result including native name and optional notes. Example
import { getHookSupport } from "./normalizer.js";

const result = getHookSupport("PreToolUse", "claude-code");
console.log(result.supported); // true
console.log(result.native);    // "PreToolUse"

getSupportedEvents(providerId)

Get all supported canonical events for a provider. Signature
(providerId: string) => CanonicalHookEvent[]
Parameters
NameTypeDescription
providerIdstringThe provider identifier to query.
Returns — Array of canonical event names the provider supports. Example
import { getSupportedEvents } from "./normalizer.js";

const events = getSupportedEvents("claude-code");
// ["SessionStart", "SessionEnd", "PreToolUse", ...]

getUnsupportedEvents(providerId)

Get all unsupported canonical events for a provider. Signature
(providerId: string) => CanonicalHookEvent[]
Parameters
NameTypeDescription
providerIdstringThe provider identifier to query.
Returns — Array of canonical event names the provider does not support. Example
import { getUnsupportedEvents } from "./normalizer.js";

const missing = getUnsupportedEvents("kimi");
// Returns all canonical events (kimi has no hook support)

getProvidersForEvent(canonical)

Get providers that support a specific canonical event. Signature
(canonical: CanonicalHookEvent) => string[]
Parameters
NameTypeDescription
canonicalCanonicalHookEventThe canonical event name to search for.
Returns — Array of provider IDs that support this event. Example
import { getProvidersForEvent } from "./normalizer.js";

const providers = getProvidersForEvent("PreToolUse");
// ["claude-code", "gemini-cli", "cursor"]

getCommonEvents(providerIds)

Get canonical events common to all specified providers. Signature
(providerIds: string[]) => CanonicalHookEvent[]
Parameters
NameTypeDescription
providerIdsstring[]Array of provider IDs to intersect.
Returns — Array of canonical events supported by all specified providers. Example
import { getCommonEvents } from "./normalizer.js";

const common = getCommonEvents(["claude-code", "gemini-cli"]);
// Returns only events both providers support

getProviderSummary(providerId)

Get a summary of hook support for a provider. Signature
(providerId: string) => ProviderHookSummary | undefined
Parameters
NameTypeDescription
providerIdstringThe provider identifier to summarize.
Returns — The hook support summary, or undefined if the provider is not found. Example
import { getProviderSummary } from "./normalizer.js";

const summary = getProviderSummary("claude-code");
if (summary) {
  console.log(`${summary.coverage}% coverage`);
  console.log(`${summary.supportedCount}/${summary.totalCanonical} events`);
}

buildHookMatrix(providerIds)

Build a cross-provider hook support matrix. Signature
(providerIds?: string[]) => CrossProviderMatrix
Parameters
NameTypeDescription
providerIds: string[]Optional array of provider IDs to include. Defaults to all mapped providers.
Returns — The cross-provider matrix with events, providers, and mapping data. Example
import { buildHookMatrix } from "./normalizer.js";

const matrix = buildHookMatrix(["claude-code", "gemini-cli"]);
for (const event of matrix.events) {
  for (const provider of matrix.providers) {
    console.log(`${event} @ ${provider}: ${matrix.matrix[event][provider].supported}`);
  }
}

getHookSystemType(providerId)

Get the hook system type for a provider. Signature
(providerId: string) => HookSystemType
Parameters
NameTypeDescription
providerIdstringThe provider identifier to query.
Returns — The hook system type ("config", "plugin", or "none"). Example
import { getHookSystemType } from "./normalizer.js";

getHookSystemType("claude-code"); // "config"
getHookSystemType("unknown");     // "none"

getHookConfigPath(providerId)

Get the resolved hook config path for a provider. Signature
(providerId: string) => string | null
Parameters
NameTypeDescription
providerIdstringThe provider identifier to query.
Returns — The resolved filesystem path, or null if not available. Example
import { getHookConfigPath } from "./normalizer.js";

const path = getHookConfigPath("claude-code");
// "/home/user/.claude/settings.json" (resolved from template)

getProviderOnlyEvents(providerId)

Get provider-only events (native events with no canonical mapping). Signature
(providerId: string) => string[]
Parameters
NameTypeDescription
providerIdstringThe provider identifier to query.
Returns — Array of native event names unique to this provider. Example
import { getProviderOnlyEvents } from "./normalizer.js";

const extras = getProviderOnlyEvents("claude-code");
// Returns any events specific to Claude Code with no canonical equivalent

translateToAll(canonical, providerIds)

Translate a canonical event to native names across multiple providers. Signature
(canonical: CanonicalHookEvent, providerIds: string[]) => Record<string, string>
Parameters
NameTypeDescription
canonicalCanonicalHookEventThe canonical event name to translate.
providerIdsstring[]Array of provider IDs to translate for.
Returns — Record mapping provider IDs to their native event names (supported only). Example
import { translateToAll } from "./normalizer.js";

const result = translateToAll("PreToolUse", ["claude-code", "gemini-cli", "kimi"]);
// { "claude-code": "PreToolUse", "gemini-cli": "BeforeTool" }
// (kimi excluded — unsupported)

resolveNativeEvent(nativeName)

Find the best canonical match for a native event name across all providers. Signature
(nativeName: string) => Array<{ providerId: string; canonical: CanonicalHookEvent; }>
Parameters
NameTypeDescription
nativeNamestringThe provider-native event name to resolve.
Returns — Array of matches, each containing the provider ID and canonical event name. Example
import { resolveNativeEvent } from "./normalizer.js";

const matches = resolveNativeEvent("BeforeTool");
// [{ providerId: "gemini-cli", canonical: "PreToolUse" }]

getHookMappingsVersion()

Get the version of the hook mappings data. Signature
() => string
Returns — The semver version string of the loaded hook mappings data. Example
import { getHookMappingsVersion } from "./normalizer.js";

const version = getHookMappingsVersion();
console.log(`Hook mappings v${version}`);

registerProvidersCommand(program)

Registers the providers command group with list, detect, show, skills-map, hooks, and capabilities subcommands. Signature
(program: Command) => void
Parameters
NameTypeDescription
programCommandThe root Commander program to attach the providers command group to
Example
caamp providers list --tier high
caamp providers detect --project
caamp providers show claude-code

getRulesByCategory(category)

Get audit rules filtered by category. Signature
(category: string) => AuditRule[]
Parameters
NameTypeDescription
categorystringCategory name to filter by
Returns — Array of rules matching the given category Example
const piRules = getRulesByCategory("prompt-injection");
console.log(`${piRules.length} prompt injection rules`);

getRulesBySeverity(severity)

Get audit rules filtered by severity level. Signature
(severity: AuditSeverity) => AuditRule[]
Parameters
NameTypeDescription
severityAuditSeveritySeverity level to filter by
Returns — Array of rules matching the given severity Example
const criticalRules = getRulesBySeverity("critical");
console.log(`${criticalRules.length} critical rules`);

getCategories()

Get all unique rule categories. Signature
() => string[]
Returns — Array of unique category name strings Example
const categories = getCategories();
// ["prompt-injection", "command-injection", "data-exfiltration", ...]

scanFile(filePath, rules)

Scan a single file against security audit rules. Signature
(filePath: string, rules?: AuditRule[]) => Promise<AuditResult>
Parameters
NameTypeDescription
filePathstringAbsolute path to the file to scan
rules: AuditRule[]Custom rules to scan against (defaults to the built-in 46+ rules)
Returns — Audit result with findings, score, and pass/fail status Example
const result = await scanFile("/path/to/SKILL.md");
console.log(`Score: ${result.score}/100, Passed: ${result.passed}`);

scanDirectory(dirPath)

Scan a directory of skills for security issues. Signature
(dirPath: string) => Promise<AuditResult[]>
Parameters
NameTypeDescription
dirPathstringAbsolute path to the skills directory to scan
Returns — Array of audit results, one per scanned SKILL.md Example
import { getCanonicalSkillsDir } from "../../paths/standard.js";

const results = await scanDirectory(getCanonicalSkillsDir());
const failing = results.filter(r => !r.passed);

toSarif(results)

Convert audit results to SARIF 2.1.0 format (Static Analysis Results Interchange Format). Signature
(results: AuditResult[]) => object
Parameters
NameTypeDescription
resultsAuditResult[]Array of audit results to convert
Returns — SARIF 2.1.0 JSON object Example
const results = await scanDirectory("/path/to/skills");
const sarif = toSarif(results);
writeFileSync("audit.sarif", JSON.stringify(sarif, null, 2));

registerSkillsAudit(parent)

Registers the skills audit subcommand for security scanning skill files. Signature
(parent: Command) => void
Parameters
NameTypeDescription
parentCommandThe parent skills Command to attach the audit subcommand to
Example
caamp skills audit ./my-skill/SKILL.md
caamp skills audit ./skills-dir --sarif

parseSource(input)

Parse and classify a source string into a typed ParsedSource. Signature
(input: string) => ParsedSource
Parameters
NameTypeDescription
inputstringRaw source string to classify
Returns — Parsed source with type, value, and inferred name Example
parseSource("owner/repo");
// { type: "github", value: "https://github.com/owner/repo", inferredName: "repo", ... }

parseSource("https://mcp.example.com/sse");
// { type: "remote", value: "https://mcp.example.com/sse", inferredName: "example" }

parseSource("@modelcontextprotocol/server-filesystem");
// { type: "package", value: "@modelcontextprotocol/server-filesystem", inferredName: "filesystem" }

isMarketplaceScoped(input)

Check if a source string looks like a marketplace scoped name (@author/name). Signature
(input: string) => boolean
Parameters
NameTypeDescription
inputstringSource string to check
Returnstrue if the input matches the @scope/name pattern Example
isMarketplaceScoped("@anthropic/my-skill"); // true
isMarketplaceScoped("my-skill");             // false
isMarketplaceScoped("owner/repo");           // false

recordSkillInstall(skillName, scopedName, source, sourceType, agents, canonicalPath, isGlobal, projectDir, version)

Record a skill installation in the lock file. Signature
(skillName: string, scopedName: string, source: string, sourceType: SourceType, agents: string[], canonicalPath: string, isGlobal: boolean, projectDir?: string, version?: string) => Promise<void>
Parameters
NameTypeDescription
skillNamestringSkill name
scopedNamestringScoped name (may include marketplace scope)
sourcestringOriginal source string
sourceTypeSourceTypeClassified source type
agentsstring[]Provider IDs the skill was linked to
canonicalPathstringAbsolute path to the canonical installation
isGlobalbooleanWhether this is a global installation
projectDir: stringProject directory (for project-scoped installs)
version: stringVersion string or commit SHA
Example
import { getCanonicalSkillsDir } from "../paths/standard.js";
import { join } from "node:path";

await recordSkillInstall(
  "my-skill", "my-skill", "owner/repo", "github",
  ["claude-code"], join(getCanonicalSkillsDir(), "my-skill"), true,
);

removeSkillFromLock(skillName)

Remove a skill entry from the lock file. Signature
(skillName: string) => Promise<boolean>
Parameters
NameTypeDescription
skillNamestringName of the skill to remove
Returnstrue if the entry was found and removed, false if not found Example
const removed = await removeSkillFromLock("my-skill");
console.log(removed ? "Removed" : "Not found");

getTrackedSkills()

Get all skills tracked in the lock file. Signature
() => Promise<Record<string, LockEntry>>
Returns — Record of skill name to lock entry Example
const skills = await getTrackedSkills();
for (const [name, entry] of Object.entries(skills)) {
  console.log(`${name}: ${entry.source}`);
}

checkSkillUpdate(skillName)

Check if a skill has updates available by comparing the installed version against the latest remote commit SHA. Signature
(skillName: string) => Promise<{ hasUpdate: boolean; currentVersion?: string; latestVersion?: string; status: "up-to-date" | "update-available" | "unknown"; }>
Parameters
NameTypeDescription
skillNamestringName of the installed skill to check
Returns — Object with update status, current version, and latest version Example
const update = await checkSkillUpdate("my-skill");
if (update.hasUpdate) {
  console.log(`Update available: ${update.currentVersion} -> ${update.latestVersion}`);
}

checkAllSkillUpdates()

Check for updates across all tracked skills. Signature
() => Promise<Record<string, { hasUpdate: boolean; currentVersion?: string; latestVersion?: string; status: "up-to-date" | "update-available" | "unknown"; }>>
Returns — Object mapping skill names to their update status Example
const updates = await checkAllSkillUpdates();
for (const [name, status] of Object.entries(updates)) {
  if (status.hasUpdate) {
    console.log(`${name}: ${status.currentVersion} -> ${status.latestVersion}`);
  }
}

registerSkillsCheck(parent)

Registers the skills check subcommand for checking available skill updates. Signature
(parent: Command) => void
Parameters
NameTypeDescription
parentCommandThe parent skills Command to attach the check subcommand to
Example
caamp skills check --human
caamp skills check --json

NetworkError

Structured error for network failures with categorized kind. Signature
typeof NetworkError

fetchWithTimeout(url, init, timeoutMs)

Fetch a URL with an automatic timeout via AbortSignal.timeout. Signature
(url: string, init?: RequestInit, timeoutMs?: number) => Promise<Response>
Parameters
NameTypeDescription
urlstringURL to fetch
init: RequestInitOptional RequestInit options forwarded to fetch
timeoutMs: numberTimeout in milliseconds (defaults to DEFAULT_FETCH_TIMEOUT_MS)
Returns — The Response object from the fetch call Throws
  • NetworkError on timeout or network failure
Example
const response = await fetchWithTimeout("https://api.example.com/data", undefined, 5000);

ensureOkResponse(response, url)

Assert that a Response has an OK status, throwing on failure. Signature
(response: Response, url: string) => Response
Parameters
NameTypeDescription
responseResponseFetch Response to validate
urlstringOriginal request URL (included in the error)
Returns — The same Response if status is OK Throws
  • NetworkError when response.ok is false
Example
const res = await fetchWithTimeout(url);
ensureOkResponse(res, url);

formatNetworkError(error)

Format a network error into a user-friendly message string. Signature
(error: unknown) => string
Parameters
NameTypeDescription
errorunknownThe caught error value
Returns — Human-readable error description Example
try {
  await fetchWithTimeout(url);
} catch (err) {
  console.error(formatNetworkError(err));
}

SkillsMPAdapter

Marketplace adapter for the agentskills.in API. Signature
typeof SkillsMPAdapter
Methods Search for skills by query string.
(query: string, limit?: number) => Promise<MarketplaceResult[]>

getSkill()

Look up a specific skill by its scoped name.
(scopedName: string) => Promise<MarketplaceResult | null>

SkillsShAdapter

Marketplace adapter for the skills.sh API. Signature
typeof SkillsShAdapter
Methods

search()

Search for skills by query string.
(query: string, limit?: number) => Promise<MarketplaceResult[]>

getSkill()

Look up a specific skill by its scoped name.
(scopedName: string) => Promise<MarketplaceResult | null>

MarketplaceUnavailableError

Error thrown when all marketplace sources fail to respond. Signature
typeof MarketplaceUnavailableError

MarketplaceClient

Unified marketplace client that aggregates results from multiple marketplace adapters. Queries all configured marketplaces in parallel, deduplicates results by scoped name, and sorts by star count. Signature
typeof MarketplaceClient
Example
const client = new MarketplaceClient();
const results = await client.search("filesystem");
for (const r of results) {
  console.log(`${r.scopedName} (${r.stars} stars)`);
}
Methods

search()

Search all marketplaces and return deduplicated, sorted results. Queries all adapters in parallel and deduplicates by scopedName, keeping the entry with the highest star count. Results are sorted by stars descending.
(query: string, limit?: number) => Promise<MarketplaceResult[]>

getSkill()

Get a specific skill by its scoped name from any marketplace. Tries each adapter in order and returns the first match.
(scopedName: string) => Promise<MarketplaceResult | null>

tokenizeCriteriaValue(value)

Splits a comma-separated criteria string into normalized tokens. Signature
(value: string) => string[]
Parameters
NameTypeDescription
valuestringThe comma-separated string to tokenize
Returns — An array of trimmed, lowercased, non-empty tokens Example
const tokens = tokenizeCriteriaValue("React, TypeScript, svelte");
// returns ["react", "typescript", "svelte"]

validateRecommendationCriteria(input)

Validates recommendation criteria input for correctness and consistency. Signature
(input: RecommendationCriteriaInput) => RecommendationValidationResult
Parameters
NameTypeDescription
inputRecommendationCriteriaInputThe raw recommendation criteria to validate
Returns — A validation result indicating success or listing all issues Example
const result = validateRecommendationCriteria({
  query: "gitbook",
  mustHave: "api",
  exclude: "legacy",
});
if (!result.valid) {
  console.error(result.issues);
}

normalizeRecommendationCriteria(input)

Normalizes raw recommendation criteria into a consistent tokenized form. Signature
(input: RecommendationCriteriaInput) => NormalizedRecommendationCriteria
Parameters
NameTypeDescription
inputRecommendationCriteriaInputThe raw recommendation criteria to normalize
Returns — Normalized criteria with tokenized, sorted, deduplicated terms Example
const criteria = normalizeRecommendationCriteria({
  query: "GitBook API",
  mustHave: "sync, api",
  prefer: ["modern"],
});
// criteria.queryTokens => ["api", "gitbook"]
// criteria.mustHave => ["api", "sync"]

scoreSkillRecommendation(skill, criteria, options)

Computes a recommendation score for a single skill against normalized criteria. Signature
(skill: MarketplaceResult, criteria: NormalizedRecommendationCriteria, options?: RecommendationOptions) => RankedSkillRecommendation
Parameters
NameTypeDescription
skillMarketplaceResultThe marketplace skill result to score
criteriaNormalizedRecommendationCriteriaThe normalized recommendation criteria to score against
options: RecommendationOptionsOptional scoring configuration including weights and markers
Returns — A ranked recommendation with score, reasons, and tradeoffs Example
const criteria = normalizeRecommendationCriteria({ query: "gitbook" });
const ranked = scoreSkillRecommendation(marketplaceSkill, criteria, {
  includeDetails: true,
});
console.log(ranked.score, ranked.reasons);

recommendSkills(skills, criteriaInput, options)

Validates, normalizes, scores, and ranks a list of skills against criteria. Signature
(skills: MarketplaceResult[], criteriaInput: RecommendationCriteriaInput, options?: RecommendationOptions) => RecommendSkillsResult
Parameters
NameTypeDescription
skillsMarketplaceResult[]The array of marketplace skill results to rank
criteriaInputRecommendationCriteriaInputThe raw recommendation criteria from the user
options: RecommendationOptionsOptional configuration for scoring and result limiting
Returns — The normalized criteria and ranked skill recommendations Throws
  • Error with code and issues properties when criteria are invalid
Example
const result = recommendSkills(
  marketplaceResults,
  { query: "gitbook", mustHave: "api", exclude: "legacy" },
  { top: 5, includeDetails: true },
);
for (const rec of result.ranking) {
  console.log(rec.skill.name, rec.score);
}

formatSkillRecommendations(result, opts)

Format skill recommendation results for display or serialization. Signature
(result: RecommendSkillsResult, opts: { mode: "human" | "json"; details?: boolean; }) => string | Record<string, unknown>
Parameters
NameTypeDescription
resultRecommendSkillsResultThe recommendation result to format
opts{ mode: "human" | "json"; details?: boolean; }Formatting options including output mode and detail level
Returns — Formatted string for human mode, or a structured object for JSON mode Example
const result = await recommendSkills("testing", { taskType: "test-writing" });
const output = formatSkillRecommendations(result, { mode: "human" });
console.log(output);

searchSkills(query, options)

Search for skills via marketplace APIs. Signature
(query: string, options?: SearchSkillsOptions) => Promise<import("/mnt/projects/cleocode/packages/caamp/src/index").MarketplaceResult[]>
Parameters
NameTypeDescription
querystringSearch query string (must be non-empty)
options: SearchSkillsOptionsSearch options including result limit
Returns — Array of marketplace skill entries matching the query Example
const results = await searchSkills("test runner", { limit: 10 });
console.log(`Found ${results.length} skills`);

recommendSkills(query, criteria, options)

Search and rank skills based on query and recommendation criteria. Signature
(query: string, criteria: Omit<RecommendationCriteriaInput, "query">, options?: RecommendSkillsQueryOptions) => Promise<RecommendSkillsResult>
Parameters
NameTypeDescription
querystringSearch query string
criteriaOmit<RecommendationCriteriaInputRecommendation criteria (task type, context, preferences)
options: RecommendSkillsQueryOptionsOptions for limiting and tuning results
Returns — Ranked recommendation results with scores and reasons Example
const result = await recommendSkills("testing", { taskType: "test-writing" });
const best = result.ranking[0];
console.log(`Top pick: ${best.skill.scopedName} (score: ${best.score})`);

registerSkillsFind(parent)

Registers the skills find subcommand for searching marketplaces and recommending skills. Signature
(parent: Command) => void
Parameters
NameTypeDescription
parentCommandThe parent skills Command to attach the find subcommand to
Example
caamp skills find "testing framework"
caamp skills find --recommend --must-have typescript --prefer vitest

registerSkillsInit(parent)

Registers the skills init subcommand for scaffolding new SKILL.md templates. Signature
(parent: Command) => void
Parameters
NameTypeDescription
parentCommandThe parent skills Command to attach the init subcommand to
Example
caamp skills init my-skill
caamp skills init --dir ./skills/new-skill

loadLibraryFromModule(root)

Load a SkillLibrary from a module (index.js) at the given root directory. Signature
(root: string) => SkillLibrary
Parameters
NameTypeDescription
rootstringAbsolute path to the library root (must contain index.js or package.json with main)
Returns — A validated SkillLibrary instance Throws
  • If the module cannot be loaded or does not implement SkillLibrary
Example
const library = loadLibraryFromModule("/home/user/.agents/libraries/cleocode-skills");
console.log(`Loaded v${library.version} with ${library.listSkills().length} skills`);

buildLibraryFromFiles(root)

Build a SkillLibrary from raw files in a directory. Signature
(root: string) => SkillLibrary
Parameters
NameTypeDescription
rootstringAbsolute path to the library root directory
Returns — A SkillLibrary instance backed by filesystem reads Throws
  • If skills.json is not found at the root
Example
const library = buildLibraryFromFiles("/home/user/.agents/libraries/cleocode-skills");
const coreSkills = library.getCoreSkills();
console.log(`Core skills: ${coreSkills.map(s => s.name).join(", ")}`);

registerSkillLibrary(library)

Registers a SkillLibrary instance directly as the active catalog. Signature
(library: SkillLibrary) => void
Parameters
NameTypeDescription
librarySkillLibraryA SkillLibrary implementation to use as the catalog
Example
const library = buildLibraryFromFiles("/path/to/skills");
registerSkillLibrary(library);

registerSkillLibraryFromPath(root)

Registers a skill library by loading it from a directory path. Signature
(root: string) => void
Parameters
NameTypeDescription
rootstringAbsolute path to the skill library root directory
Throws
  • Error if the library cannot be loaded from the given path
Example
registerSkillLibraryFromPath("/home/user/.agents/skill-library");
const skills = listSkills();

clearRegisteredLibrary()

Clears the registered skill library instance. Signature
() => void
Example
clearRegisteredLibrary();
// isCatalogAvailable() will now return false unless auto-discovery succeeds

isCatalogAvailable()

Checks whether a skill library is available for use. Signature
() => boolean
Returns — True if a skill library is registered or discoverable, false otherwise Example
if (isCatalogAvailable()) {
  const skills = listSkills();
}

getSkills()

Returns all skill entries from the catalog. Signature
() => SkillLibraryEntry[]
Returns — An array of all skill library entries Example
const allSkills = getSkills();
console.log(`Found ${allSkills.length} skills`);

getManifest()

Returns the parsed skill library manifest. Signature
() => SkillLibraryManifest
Returns — The skill library manifest object Example
const manifest = getManifest();
console.log(manifest.version);

listSkills()

Lists all available skill names in the catalog. Signature
() => string[]
Returns — An array of skill name strings Example
const names = listSkills();
// e.g., ["ct-orchestrator", "ct-dev-workflow", "ct-validator"]

getSkill(name)

Gets skill metadata by name from the catalog. Signature
(name: string) => SkillLibraryEntry | undefined
Parameters
NameTypeDescription
namestringThe unique skill name to look up
Returns — The skill entry if found, or undefined Example
const skill = getSkill("ct-orchestrator");
if (skill) {
  console.log(skill.category);
}

getSkillPath(name)

Resolves the absolute path to a skill’s SKILL.md file. Signature
(name: string) => string
Parameters
NameTypeDescription
namestringThe unique skill name to resolve
Returns — The absolute path to the skill’s SKILL.md file Example
const path = getSkillPath("ct-orchestrator");
// e.g., "/home/user/.agents/skill-library/skills/ct-orchestrator/SKILL.md"

getSkillDir(name)

Resolves the absolute path to a skill’s directory. Signature
(name: string) => string
Parameters
NameTypeDescription
namestringThe unique skill name to resolve
Returns — The absolute path to the skill’s directory Example
const dir = getSkillDir("ct-orchestrator");
// e.g., "/home/user/.agents/skill-library/skills/ct-orchestrator"

readSkillContent(name)

Reads a skill’s SKILL.md content as a string. Signature
(name: string) => string
Parameters
NameTypeDescription
namestringThe unique skill name to read
Returns — The full text content of the skill’s SKILL.md file Example
const content = readSkillContent("ct-orchestrator");
console.log(content.substring(0, 100));

getCoreSkills()

Returns all skills marked as core in the catalog. Signature
() => SkillLibraryEntry[]
Returns — An array of core skill entries Example
const coreSkills = getCoreSkills();
console.log(`${coreSkills.length} core skills available`);

getSkillsByCategory(category)

Returns skills filtered by category. Signature
(category: SkillLibraryEntry["category"]) => SkillLibraryEntry[]
Parameters
NameTypeDescription
categorySkillLibraryEntry["category"]The category to filter by
Returns — An array of skill entries in the specified category Example
const planningSkills = getSkillsByCategory("planning");

getSkillDependencies(name)

Gets the direct dependency names for a skill. Signature
(name: string) => string[]
Parameters
NameTypeDescription
namestringThe unique skill name to query dependencies for
Returns — An array of direct dependency skill names Example
const deps = getSkillDependencies("ct-task-executor");
// e.g., ["ct-orchestrator"]

resolveDependencyTree(names)

Resolves the full dependency tree for a set of skill names. Signature
(names: string[]) => string[]
Parameters
NameTypeDescription
namesstring[]The skill names to resolve dependencies for
Returns — A deduplicated array of all required skill names including transitive dependencies Example
const allDeps = resolveDependencyTree(["ct-task-executor", "ct-validator"]);
// includes all transitive dependencies

listProfiles()

Lists all available profile names in the catalog. Signature
() => string[]
Returns — An array of profile name strings Example
const profiles = listProfiles();
// e.g., ["default", "minimal", "full"]

getProfile(name)

Gets a profile definition by name from the catalog. Signature
(name: string) => SkillLibraryProfile | undefined
Parameters
NameTypeDescription
namestringThe unique profile name to look up
Returns — The profile definition if found, or undefined Example
const profile = getProfile("default");
if (profile) {
  console.log(profile.skills);
}

resolveProfile(name)

Resolves a profile to its full skill list including inherited skills. Signature
(name: string) => string[]
Parameters
NameTypeDescription
namestringThe profile name to resolve
Returns — A deduplicated array of all skill names required by the profile Example
const skills = resolveProfile("default");
// includes all skills from extended profiles and their dependencies

listSharedResources()

Lists all available shared resource names in the catalog. Signature
() => string[]
Returns — An array of shared resource name strings Example
const resources = listSharedResources();
// e.g., ["testing-framework-config.md", "error-handling.md"]

getSharedResourcePath(name)

Gets the absolute path to a shared resource file. Signature
(name: string) => string | undefined
Parameters
NameTypeDescription
namestringThe shared resource name to resolve
Returns — The absolute path to the resource file, or undefined if not found Example
const path = getSharedResourcePath("testing-framework-config.md");

readSharedResource(name)

Reads a shared resource file’s content as a string. Signature
(name: string) => string | undefined
Parameters
NameTypeDescription
namestringThe shared resource name to read
Returns — The text content of the resource, or undefined if not found Example
const content = readSharedResource("testing-framework-config.md");
if (content) {
  console.log(content);
}

listProtocols()

Lists all available protocol names in the catalog. Signature
() => string[]
Returns — An array of protocol name strings Example
const protocols = listProtocols();
// e.g., ["research", "implementation", "contribution"]

getProtocolPath(name)

Gets the absolute path to a protocol file. Signature
(name: string) => string | undefined
Parameters
NameTypeDescription
namestringThe protocol name to resolve
Returns — The absolute path to the protocol file, or undefined if not found Example
const path = getProtocolPath("research");

readProtocol(name)

Reads a protocol file’s content as a string. Signature
(name: string) => string | undefined
Parameters
NameTypeDescription
namestringThe protocol name to read
Returns — The text content of the protocol, or undefined if not found Example
const content = readProtocol("research");
if (content) {
  console.log(content);
}

validateSkillFrontmatter(name)

Validates a single skill’s frontmatter against the schema. Signature
(name: string) => SkillLibraryValidationResult
Parameters
NameTypeDescription
namestringThe skill name to validate
Returns — A validation result indicating success or listing errors Example
const result = validateSkillFrontmatter("ct-orchestrator");
if (!result.valid) {
  console.error(result.errors);
}

validateAll()

Validates all skills in the catalog and returns results per skill. Signature
() => Map<string, SkillLibraryValidationResult>
Returns — A map of skill names to their validation results Example
const results = validateAll();
for (const [name, result] of results) {
  if (!result.valid) console.error(`${name}: invalid`);
}

getDispatchMatrix()

Gets the dispatch matrix from the skill library manifest. Signature
() => SkillLibraryDispatchMatrix
Returns — The dispatch matrix object from the manifest Example
const matrix = getDispatchMatrix();
console.log(matrix);

getVersion()

Returns the skill library version string. Signature
() => string
Returns — The library version string Example
const version = getVersion();
// e.g., "1.0.0"

getLibraryRoot()

Returns the absolute path to the skill library root directory. Signature
() => string
Returns — The absolute path to the library root Example
const root = getLibraryRoot();
// e.g., "/home/user/.agents/skill-library"

parseSkillFile(filePath)

Parse a SKILL.md file and extract its frontmatter metadata. Signature
(filePath: string) => Promise<SkillMetadata | null>
Parameters
NameTypeDescription
filePathstringAbsolute path to the SKILL.md file
Returns — Parsed metadata, or null if invalid Example
const meta = await parseSkillFile("/path/to/SKILL.md");
if (meta) {
  console.log(`${meta.name}: ${meta.description}`);
}

discoverSkill(skillDir)

Discover a single skill at a given directory path. Signature
(skillDir: string) => Promise<SkillEntry | null>
Parameters
NameTypeDescription
skillDirstringAbsolute path to a skill directory (containing SKILL.md)
Returns — Skill entry with metadata, or null if no valid SKILL.md exists Example
import { getCanonicalSkillsDir } from "../paths/standard.js";
import { join } from "node:path";

const skill = await discoverSkill(join(getCanonicalSkillsDir(), "my-skill"));
if (skill) {
  console.log(`Found: ${skill.name}`);
}

discoverSkills(rootDir)

Scan a directory for skill subdirectories, each containing a SKILL.md file. Signature
(rootDir: string) => Promise<SkillEntry[]>
Parameters
NameTypeDescription
rootDirstringAbsolute path to a skills root directory to scan
Returns — Array of discovered skill entries Example
import { getCanonicalSkillsDir } from "../paths/standard.js";

const skills = await discoverSkills(getCanonicalSkillsDir());
console.log(`Found ${skills.length} skills`);

discoverSkillsMulti(dirs)

Discover skills across multiple directories. Signature
(dirs: string[]) => Promise<SkillEntry[]>
Parameters
NameTypeDescription
dirsstring[]Array of absolute paths to skills directories to scan
Returns — Deduplicated array of discovered skill entries Example
const skills = await discoverSkillsMulti(["/home/user/.agents/skills", "./project-skills"]);
console.log(`Found ${skills.length} unique skills`);

cloneRepo(owner, repo, ref, subPath)

Clone a GitHub repo to a temp directory. Signature
(owner: string, repo: string, ref?: string, subPath?: string) => Promise<GitFetchResult>
Parameters
NameTypeDescription
ownerstringGitHub repository owner (user or organization)
repostringGitHub repository name
ref: stringBranch or tag to clone (defaults to the repo’s default branch)
subPath: stringSubdirectory within the repo to target
Returns — Object with local path and cleanup function Example
const { localPath, cleanup } = await cloneRepo("anthropics", "courses", "main", "skills");
try {
  console.log(`Cloned to: ${localPath}`);
} finally {
  await cleanup();
}

fetchRawFile(owner, repo, path, ref)

Fetch a specific file from GitHub using the raw API. Signature
(owner: string, repo: string, path: string, ref?: string) => Promise<string | null>
Parameters
NameTypeDescription
ownerstringGitHub repository owner
repostringGitHub repository name
pathstringFile path within the repository
ref: stringBranch or tag to fetch from (defaults to "main")
Returns — File content as a string, or null if the file cannot be fetched Example
const content = await fetchRawFile("owner", "repo", "skills/my-skill/SKILL.md");
if (content) {
  console.log(content);
}

repoExists(owner, repo)

Check if a GitHub repo exists. Signature
(owner: string, repo: string) => Promise<boolean>
Parameters
NameTypeDescription
ownerstringGitHub repository owner
repostringGitHub repository name
Returnstrue if the repository exists and is accessible Example
const exists = await repoExists("anthropics", "courses");
console.log(exists ? "Repo found" : "Repo not found");

cloneGitLabRepo(owner, repo, ref, subPath)

Clone a GitLab repo to a temp directory. Signature
(owner: string, repo: string, ref?: string, subPath?: string) => Promise<GitFetchResult>
Parameters
NameTypeDescription
ownerstringGitLab repository owner (user or group)
repostringGitLab repository name
ref: stringBranch or tag to clone (defaults to the repo’s default branch)
subPath: stringSubdirectory within the repo to target
Returns — Object with local path and cleanup function Example
const { localPath, cleanup } = await cloneGitLabRepo("mygroup", "skills-repo");
try {
  console.log(`Cloned to: ${localPath}`);
} finally {
  await cleanup();
}

fetchGitLabRawFile(owner, repo, path, ref)

Fetch a specific file from GitLab using the raw API. Signature
(owner: string, repo: string, path: string, ref?: string) => Promise<string | null>
Parameters
NameTypeDescription
ownerstringGitLab repository owner (user or group)
repostringGitLab repository name
pathstringFile path within the repository
ref: stringBranch or tag to fetch from (defaults to "main")
Returns — File content as a string, or null if the file cannot be fetched Example
const content = await fetchGitLabRawFile("mygroup", "skills", "my-skill/SKILL.md");
if (content) {
  console.log(content);
}

registerSkillsInstall(parent)

Registers the skills install subcommand for installing skills from various sources. Signature
(parent: Command) => void
Parameters
NameTypeDescription
parentCommandThe parent skills Command to attach the install subcommand to
Example
caamp skills install owner/repo
caamp skills install @author/skill-name --agent claude-code
caamp skills install --profile recommended --all

registerSkillsList(parent)

Registers the skills list subcommand for listing installed skills. Signature
(parent: Command) => void
Parameters
NameTypeDescription
parentCommandThe parent skills Command to attach the list subcommand to
Example
caamp skills list --human
caamp skills list --agent claude-code --global

registerSkillsRemove(parent)

Registers the skills remove subcommand for removing installed skills. Signature
(parent: Command) => void
Parameters
NameTypeDescription
parentCommandThe parent skills Command to attach the remove subcommand to
Example
caamp skills remove my-skill
caamp skills remove --yes

registerSkillsUpdate(parent)

Registers the skills update subcommand for updating all outdated skills. Signature
(parent: Command) => void
Parameters
NameTypeDescription
parentCommandThe parent skills Command to attach the update subcommand to
Example
caamp skills update --yes
caamp skills update --json

validateSkill(filePath)

Validate a SKILL.md file against the Agent Skills standard. Signature
(filePath: string) => Promise<ValidationResult>
Parameters
NameTypeDescription
filePathstringAbsolute path to the SKILL.md file to validate
Returns — Validation result with issues and parsed metadata Example
const result = await validateSkill("/path/to/SKILL.md");
console.log(result.valid ? "Valid" : `${result.issues.length} issues found`);

registerSkillsValidate(parent)

Registers the skills validate subcommand for validating SKILL.md file format. Signature
(parent: Command) => void
Parameters
NameTypeDescription
parentCommandThe parent skills Command to attach the validate subcommand to
Example
caamp skills validate ./my-skill/SKILL.md
caamp skills validate --json

registerSkillsCommands(program)

Registers the skills command group with all skill management subcommands. Signature
(program: Command) => void
Parameters
NameTypeDescription
programCommandThe root Commander program to attach the skills command group to
Example
caamp skills install owner/repo
caamp skills list --human
caamp skills find "testing"

isCaampOwnedSkill(skillName)

Check whether a skill name is reserved by CAAMP (ct-* prefix). Signature
(skillName: string) => boolean
Parameters
NameTypeDescription
skillNamestringSkill name to check
Returnstrue if the skill name starts with ct- Example
isCaampOwnedSkill("ct-research-agent"); // true
isCaampOwnedSkill("my-custom-skill");   // false

checkSkillIntegrity(skillName, providers, scope, projectDir)

Check the integrity of a single installed skill. Signature
(skillName: string, providers: Provider[], scope?: "global" | "project", projectDir?: string) => Promise<SkillIntegrityResult>
Parameters
NameTypeDescription
skillNamestringName of the skill to check
providersProvider[]Providers to check symlinks for
scope: "global" | "project"Whether to check global or project links
projectDir: stringProject directory (for project scope)
Returns — Integrity check result Example
const result = await checkSkillIntegrity("ct-research-agent", providers, "global");
if (result.status !== "intact") {
  console.log(`Issue: ${result.issue}`);
}

checkAllSkillIntegrity(providers, scope, projectDir)

Check integrity of all tracked skills. Signature
(providers: Provider[], scope?: "global" | "project", projectDir?: string) => Promise<Map<string, SkillIntegrityResult>>
Parameters
NameTypeDescription
providersProvider[]Providers to check symlinks for
scope: "global" | "project"Whether to check global or project links
projectDir: stringProject directory (for project scope)
Returns — Map of skill name to integrity result Example
const results = await checkAllSkillIntegrity(providers);
for (const [name, result] of results) {
  console.log(`${name}: ${result.status}`);
}

shouldOverrideSkill(skillName, incomingSource, existingEntry)

Resolve a skill name conflict where a user-installed skill collides with a CAAMP-owned (ct-*) skill. Signature
(skillName: string, incomingSource: string, existingEntry: LockEntry | undefined) => boolean
Parameters
NameTypeDescription
skillNamestringSkill name to check
incomingSourcestringSource of the incoming skill installation
existingEntryLockEntry | undefinedExisting lock entry, if any
Returnstrue if the incoming installation should proceed Example
const proceed = shouldOverrideSkill("ct-research-agent", "library", existingEntry);
if (proceed) {
  // Safe to install/override
}

validateInstructionIntegrity(providers, projectDir, scope, expectedContent)

Validate instruction file injection status across all providers. Signature
(providers: Provider[], projectDir: string, scope: "project" | "global", expectedContent?: string) => Promise<Array<{ file: string; providerId: string; issue: string; }>>
Parameters
NameTypeDescription
providersProvider[]Providers to check
projectDirstringProject directory
scope"project" | "global"Whether to check global or project files
expectedContent: stringExpected CAAMP block content
Returns — Array of file paths with issues Example
const issues = await validateInstructionIntegrity(providers, process.cwd(), "project");
for (const issue of issues) {
  console.log(`${issue.providerId}: ${issue.issue} (${issue.file})`);
}

resolveCantImports(content, projectRoot)

Resolve *.cant references in instruction file content. Scans each line for directives pointing to .cant files. For each match, reads and parses the .cant file, converts its definitions to markdown, and replaces the line with the generated content. Lines that don’t match the .cant import pattern are left unchanged. Signature
(content: string, projectRoot: string) => ResolvedImports
Parameters
NameTypeDescription
contentstringRaw instruction file content
projectRootstringAbsolute path to the project root directory
Returns — Resolved content, imported file list, and any errors Example
const result = resolveCantImports(
  '@import .cleo/agents/core-agent.cant',
  '/home/user/project',
);
console.log(result.resolvedContent);
// ## Agent: core-agent
// - **Model**: opus
// ...

cantToMarkdown(cantContent)

Convert a .cant file’s content to markdown equivalent. Parses the frontmatter to determine the document kind, then converts the body into structured markdown that providers can consume (headings, bullet lists, code blocks). Signature
(cantContent: string) => string
Parameters
NameTypeDescription
cantContentstringRaw .cant file content
Returns — Markdown representation of the .cant definitions Example
const md = cantToMarkdown(`---
kind: agent
version: 1
---

agent ops-lead:
  model: opus
  prompt: "Coordinate operations"
`);
// Returns markdown with ## Agent: ops-lead heading

discoverWellKnown(domain)

Discover skills from a well-known URL. Signature
(domain: string) => Promise<WellKnownSkill[]>
Parameters
NameTypeDescription
domainstringDomain name to query (e.g. "example.com")
Returns — Array of discovered skill entries Example
const skills = await discoverWellKnown("example.com");
for (const skill of skills) {
  console.log(`${skill.name}: ${skill.url}`);
}