Skip to main content

Execution Flow

This page describes the full lifecycle of a capability execution — from invocation to result.

Capability execution flow: agent → manager → side execution → executor → result01 · RESOLVE02 · SPAWN03 · EXECUTE04 · RESULTstartCapability(name, type, params)lookup executor for typelookup capability by namebuild threadContextstartSideExecution(executor, params)spawn child process + env varsWebSocket connect (auto)actionBlockInvocationonActionBlockInvocation()run capability logiccodebolt.fs / terminal / ...actionBlockComplete + resultsideExecutionCompletedresult + additionalContextAGENTParent Agentcodebolt.capabilityMGRCapabilityMgrmanager + registrySIDESideExecMgrprocess managerEXECExecutorchild process · codeboltjsLEGENDRequest / callReturn / asyncResult / completionActive

Starting a capability

An agent starts a capability using the Codebolt JS SDK:

const result = await codebolt.capability.startCapability(
'frontend-refactor', // capabilityName
'skill', // capabilityType
{ file: 'src/App.tsx' }, // params (optional)
30000 // timeout in ms (optional)
);

Internally, this sends a message to the server which resolves to StartCapabilityOptions:

interface StartCapabilityOptions {
capabilityName: string; // name of the capability
capabilityType: string; // type (skill, power, talent, etc.)
threadId: string; // thread to execute in
parentAgentId: string; // parent agent ID
parentAgentInstanceId: string;// parent agent instance ID
params?: Record<string, any>;// additional parameters
timeout?: number; // timeout in ms (optional)
}

Execution lifecycle

startCapability()

├─ 1. Locate executor for the capability type
│ └─ capabilityRegistry.getExecutorForType(type)
│ └─ Error if not found: EXECUTOR_NOT_FOUND

├─ 2. Locate the capability
│ └─ capabilityRegistry.getCapability(name, type)
│ └─ Error if not found: CAPABILITY_NOT_FOUND

├─ 3. Generate unique execution ID
│ └─ Format: cap_<timestamp>_<uuid8>

├─ 4. Build thread context
│ └─ Chat history from the parent thread
│ └─ Project path, agent IDs, metadata

├─ 5. Launch executor via SideExecutionManager
│ └─ Spawns child process with env vars (SOCKET_PORT, IS_SIDE_EXECUTION, etc.)
│ └─ codeboltjs SDK auto-connects and receives params via actionBlockInvocation
│ └─ Same thread ID as parent agent

├─ 6. Emit "capabilityStarted" event

└─ 7. Return execution ID to caller

Execution statuses

StatusDescription
startingExecution is being set up
runningExecutor is actively processing
completedExecution finished successfully
failedExecution encountered an error
timeoutExecution exceeded the time limit
stoppingStop requested, waiting for cleanup
stoppedExecution was manually stopped

Waiting for results

After starting a capability, the caller can await the result:

const executionId = await capabilityManager.startCapability(options);
const result = await capabilityManager.waitForCompletion(executionId);

if (result.success) {
console.log(result.result); // capability output
console.log(result.additionalContext); // extra context from executor
} else {
console.error(result.error);
}

The waitForCompletion() promise resolves when the underlying SideExecution completes, fails, or times out. There is no built-in timeout on the wait — capability executions can be long-running.

Result structure

interface CapabilityExecutionResult {
success: boolean;
executionId: string;
result?: any; // output data (on success)
additionalContext?: Record<string, any>;// extra context from executor
error?: string; // error message (on failure)
}

The result includes a capabilityPath field injected by the manager, allowing the client to resolve resource paths relative to the capability directory.

Thread context

The executor receives the full conversation context from the parent thread:

interface ThreadContext {
threadId: string;
messages: ThreadMessage[]; // chat history
projectPath: string;
agentId: string;
agentInstanceId: string;
metadata: Record<string, any>;
}

Each message includes: messageId, threadId, content, sender, timestamp, templateType, payload.

Stopping executions

// Stop a single execution
await capabilityManager.stopCapability(executionId);

// Stop all executions for a parent agent
await capabilityManager.stopAllForParent(parentAgentInstanceId);

Stopping sets the status to stopping, then delegates to SideExecutionManager to terminate the underlying process. After termination, resources are cleaned up.

Executor matching

When a capability is started, the manager looks up the executor using the capability's type:

capabilityType: "skill" → typeToExecutor map → skill-executor

The type-to-executor mapping is built during registry initialisation. If multiple executors support the same type, the last one registered wins (project-level overrides global, which overrides built-in).

Error codes

CodeWhen
CAPABILITY_NOT_FOUNDNo capability with the given name and type exists
EXECUTOR_NOT_FOUNDNo executor is registered for the capability type
INVALID_CAPABILITY_CONFIGCapability configuration is malformed
INVALID_EXECUTOR_CONFIGExecutor configuration is malformed
EXECUTION_TIMEOUTExecution exceeded the configured timeout
EXECUTION_FAILEDExecutor reported an error during execution
DOWNLOAD_FAILEDFailed to download from marketplace
EXTRACTION_FAILEDFailed to extract downloaded zip
INVALID_REQUESTRequest parameters are invalid
REGISTRY_NOT_INITIALIZEDRegistry has not been initialised yet

See also