- Home
- Documentation
- configuration
- SDK
SDK
The SDK is the in-process integration surface for @f5xc-salesdemos/xcsh.
Use it when you want direct access to agent state, event streaming, tool wiring, and session control from your own Bun/Node process.
If you need cross-language/process isolation, use RPC mode instead.
Installation
Section titled “Installation”bun add @f5xc-salesdemos/xcshEntry points
Section titled “Entry points”@f5xc-salesdemos/xcsh exports the SDK APIs from the package root (and also via @f5xc-salesdemos/xcsh/sdk).
Core exports for embedders:
createAgentSessionSessionManagerSettingsAuthStorageModelRegistrydiscoverAuthStorage- Discovery helpers (
discoverExtensions,discoverSkills,discoverContextFiles,discoverPromptTemplates,discoverSlashCommands,discoverCustomTSCommands,discoverMCPServers) - Tool factory surface (
createTools,BUILTIN_TOOLS, tool classes)
Quick start (auto-discovery defaults)
Section titled “Quick start (auto-discovery defaults)”import { createAgentSession } from "@f5xc-salesdemos/xcsh";
const { session, modelFallbackMessage } = await createAgentSession();
if (modelFallbackMessage) { process.stderr.write(`${modelFallbackMessage}\n`);}
const unsubscribe = session.subscribe(event => { if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") { process.stdout.write(event.assistantMessageEvent.delta); }});
await session.prompt("Summarize this repository in 3 bullets.");unsubscribe();await session.dispose();What createAgentSession() discovers by default
Section titled “What createAgentSession() discovers by default”createAgentSession() follows “provide to override, omit to discover”.
If omitted, it resolves:
cwd:getProjectDir()agentDir:~/.xcsh/agent(viagetAgentDir())authStorage:discoverAuthStorage(agentDir)modelRegistry:new ModelRegistry(authStorage)+await refresh()settings:await Settings.init({ cwd, agentDir })sessionManager:SessionManager.create(cwd)(file-backed)- skills/context files/prompt templates/slash commands/extensions/custom TS commands
- built-in tools via
createTools(...) - MCP tools (enabled by default)
- LSP integration (enabled by default)
Required vs optional inputs
Section titled “Required vs optional inputs”Typically you must provide only what you want to control:
- Must provide: nothing for a minimal session
- Usually provide explicitly in embedders:
sessionManager(if you need in-memory or custom location)authStorage+modelRegistry(if you own credential/model lifecycle)modelormodelPattern(if deterministic model selection matters)settings(if you need isolated/test config)
Session manager behavior (persistent vs in-memory)
Section titled “Session manager behavior (persistent vs in-memory)”AgentSession always uses a SessionManager; behavior depends on which factory you use.
File-backed (default)
Section titled “File-backed (default)”import { createAgentSession, SessionManager } from "@f5xc-salesdemos/xcsh";
const { session } = await createAgentSession({ sessionManager: SessionManager.create(process.cwd()),});
console.log(session.sessionFile); // absolute .jsonl path- Persists conversation/messages/state deltas to session files.
- Supports resume/open/list/fork workflows.
session.sessionFileis defined.
In-memory
Section titled “In-memory”import { createAgentSession, SessionManager } from "@f5xc-salesdemos/xcsh";
const { session } = await createAgentSession({ sessionManager: SessionManager.inMemory(),});
console.log(session.sessionFile); // undefined- No filesystem persistence.
- Useful for tests, ephemeral workers, request-scoped agents.
- Session methods still work, but persistence-specific behaviors (file resume/fork paths) are naturally limited.
Resume/open/list helpers
Section titled “Resume/open/list helpers”import { SessionManager } from "@f5xc-salesdemos/xcsh";
const recent = await SessionManager.continueRecent(process.cwd());const listed = await SessionManager.list(process.cwd());const opened = listed[0] ? await SessionManager.open(listed[0].path) : null;Model and auth wiring
Section titled “Model and auth wiring”createAgentSession() uses ModelRegistry + AuthStorage for model selection and API key resolution.
Explicit wiring
Section titled “Explicit wiring”import { createAgentSession, discoverAuthStorage, ModelRegistry, SessionManager,} from "@f5xc-salesdemos/xcsh";
const authStorage = await discoverAuthStorage();const modelRegistry = new ModelRegistry(authStorage);await modelRegistry.refresh();
const available = modelRegistry.getAvailable();if (available.length === 0) throw new Error("No authenticated models available");
const { session } = await createAgentSession({ authStorage, modelRegistry, model: available[0], thinkingLevel: "medium", sessionManager: SessionManager.inMemory(),});Selection order when model is omitted
Section titled “Selection order when model is omitted”When no explicit model/modelPattern is provided:
- restore model from existing session (if restorable + key available)
- settings default model role (
default) - first available model with valid auth
If restore fails, modelFallbackMessage explains fallback.
Auth priority
Section titled “Auth priority”AuthStorage.getApiKey(...) resolves in this order:
- runtime override (
setRuntimeApiKey) - stored credentials in
agent.db - provider environment variables
- custom-provider resolver fallback (if configured)
Event subscription model
Section titled “Event subscription model”Subscribe with session.subscribe(listener); it returns an unsubscribe function.
const unsubscribe = session.subscribe(event => { switch (event.type) { case "agent_start": case "turn_start": case "tool_execution_start": break; case "message_update": if (event.assistantMessageEvent.type === "text_delta") { process.stdout.write(event.assistantMessageEvent.delta); } break; }});AgentSessionEvent includes core AgentEvent plus session-level events:
auto_compaction_start/auto_compaction_endauto_retry_start/auto_retry_endttsr_triggeredtodo_reminder
Prompt lifecycle
Section titled “Prompt lifecycle”session.prompt(text, options?) is the primary entry point.
Behavior:
- optional command/template expansion (
/commands, custom commands, file slash commands, prompt templates) - if currently streaming:
- requires
streamingBehavior: "steer" | "followUp" - queues instead of throwing work away
- requires
- if idle:
- validates model + API key
- appends user message
- starts agent turn
Related APIs:
sendUserMessage(content, { deliverAs? })steer(text, images?)followUp(text, images?)sendCustomMessage({ customType, content, ... }, { deliverAs?, triggerTurn? })abort()
Tools and extension integration
Section titled “Tools and extension integration”Built-ins and filtering
Section titled “Built-ins and filtering”- Built-ins come from
createTools(...)andBUILTIN_TOOLS. toolNamesacts as an allowlist for built-ins.customToolsand extension-registered tools are still included.- Hidden tools (for example
submit_result) are opt-in unless required by options.
const { session } = await createAgentSession({ toolNames: ["read", "grep", "find", "write"], requireSubmitResultTool: true,});Extensions
Section titled “Extensions”extensions: inlineExtensionFactory[]additionalExtensionPaths: load extra extension filesdisableExtensionDiscovery: disable automatic extension scanningpreloadedExtensions: reuse already loaded extension set
Runtime tool set changes
Section titled “Runtime tool set changes”AgentSession supports runtime activation updates:
getActiveToolNames()getAllToolNames()setActiveToolsByName(names)refreshMCPTools(mcpTools)
System prompt is rebuilt to reflect active tool changes.
Discovery helpers
Section titled “Discovery helpers”Use these when you want partial control without recreating internal discovery logic:
discoverAuthStorage(agentDir?)discoverExtensions(cwd?)discoverSkills(cwd?, _agentDir?, settings?)discoverContextFiles(cwd?, _agentDir?)discoverPromptTemplates(cwd?, agentDir?)discoverSlashCommands(cwd?)discoverCustomTSCommands(cwd?, agentDir?)discoverMCPServers(cwd?)buildSystemPrompt(options?)
Subagent-oriented options
Section titled “Subagent-oriented options”For SDK consumers building orchestrators (similar to task executor flow):
outputSchema: passes structured output expectation into tool contextrequireSubmitResultTool: forcessubmit_resulttool inclusiontaskDepth: recursion-depth context for nested task sessionsparentTaskPrefix: artifact naming prefix for nested task outputs
These are optional for normal single-agent embedding.
createAgentSession() return value
Section titled “createAgentSession() return value”type CreateAgentSessionResult = { session: AgentSession; extensionsResult: LoadExtensionsResult; setToolUIContext: (uiContext: ExtensionUIContext, hasUI: boolean) => void; mcpManager?: MCPManager; modelFallbackMessage?: string; lspServers?: Array<{ name: string; status: "ready" | "error"; fileTypes: string[]; error?: string }>;};Use setToolUIContext(...) only if your embedder provides UI capabilities that tools/extensions should call into.
Minimal controlled embed example
Section titled “Minimal controlled embed example”import { createAgentSession, discoverAuthStorage, ModelRegistry, SessionManager, Settings,} from "@f5xc-salesdemos/xcsh";
const authStorage = await discoverAuthStorage();const modelRegistry = new ModelRegistry(authStorage);await modelRegistry.refresh();
const settings = Settings.isolated({ "compaction.enabled": true, "retry.enabled": true,});
const { session } = await createAgentSession({ authStorage, modelRegistry, settings, sessionManager: SessionManager.inMemory(), toolNames: ["read", "grep", "find", "edit", "write"], enableMCP: false, enableLsp: true,});
session.subscribe(event => { if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") { process.stdout.write(event.assistantMessageEvent.delta); }});
await session.prompt("Find all TODO comments in this repo and propose fixes.");await session.dispose();