The @dtoolkit/sdk package provides typed HTTP clients for the four dtoolkit services that expose REST APIs: dbrain (memory), dops (observability), dwork (project management), and dproxy (model invocation). Each client wraps a shared HttpClient base with Bearer token authentication, configurable timeouts, and structured error handling via SdkError.
npm install @dtoolkit/sdk
import { DBrainClient, DWorkClient, DProxyClient, DOpsClient } from ' @dtoolkit/sdk ' ;
const brain = new DBrainClient ( ' http://localhost:7878 ' , ' your-token ' );
const work = new DWorkClient ( ' http://localhost:7881 ' , ' your-token ' );
const proxy = new DProxyClient ( ' http://localhost:7880 ' , ' your-token ' );
const ops = new DOpsClient ( ' http://localhost:7883 ' , ' your-token ' );
Each client supports two constructor signatures:
const client = new DBrainClient ( ' http://localhost:7878 ' , ' your-token ' );
// Options object (supports timeoutMs)
const client = new DBrainClient ( {
baseUrl : ' http://localhost:7878 ' ,
All clients throw SdkError on non-2xx responses. The error includes the HTTP status code, response body, and request path.
import { SdkError } from ' @dtoolkit/sdk ' ;
await brain . getEntity ( ' nonexistent ' );
if (err instanceof SdkError ) {
console . error ( ` HTTP ${ err . status } on ${ err . path } : ${ err . body } ` );
Typed client for the dbrain REST API (default port 7878).
new DBrainClient (baseUrl: string, token: string)
new DBrainClient (options: DBrainClientOptions)
Option Type Required Description baseUrlstringYes dbrain server URL (e.g., http://localhost:7878) tokenstringYes Bearer token for authentication timeoutMsnumberNo Request timeout in milliseconds
Method Signature Description health()() => Promise<HealthResponse>Server health, entity/fact/conversation counts, brain type connect()() => Promise<ConnectResponse>MCP connection config, permissions, and CLAUDE.md content
Method Signature Description listEntities(filters?)(filters?: { category?: string; type?: string }) => Promise<EntityRow[]>List all entities, optionally filtered by category or type getEntity(id)(id: string) => Promise<EntityWithFacts>Get a single entity with all its facts createEntity(entity)(entity: { id, name, type, category, metadata? }) => Promise<{...}>Create a new entity archiveEntity(id)(id: string) => Promise<{ id, status }>Archive (soft-delete) an entity
Method Signature Description listFacts(entityId, filters?)(entityId: string, filters?: { tier?: string }) => Promise<FactRow[]>List facts for an entity, optionally filtered by tier addFact(entityId, fact)(entityId: string, fact: { id, fact, category?, timestamp?, source?, relatedEntities? }) => Promise<{...}>Add a fact to an entity bumpFact(id)(id: string) => Promise<{ id, bumped }>Touch a fact to keep it in the hot tier
Method Signature Description search(query, options?)(query: string, options?: { limit?, entityId?, tier? }) => Promise<SearchResult[]>Full-text search across facts searchFederated(query, options?)(query: string, options?: { limit?, entityId?, tier? }) => Promise<FederatedSearchResponse>Search across local and connected brains memorySummary()() => Promise<MemorySummaryRow[]>Per-entity breakdown of hot/warm/cold fact counts
Method Signature Description listConversations(filters?)(filters?: { source?, limit? }) => Promise<ConversationSummary[]>List conversations getConversation(id)(id: string) => Promise<ConversationWithMessages>Get conversation with all messages startConversation(source, id?)(source: string, id?: string) => Promise<{...}>Start a new conversation sendMessages(conversationId, messages)(id: string, messages: Array<{ role, content }>) => Promise<Array<{...}>>Add messages to a conversation listMessages(conversationId, filters?)(id: string, filters?: { since?, processed? }) => Promise<Message[]>List messages with optional filters pendingMessages()() => Promise<PendingMessages>Get unprocessed message counts
Method Signature Description listDocuments()() => Promise<DocumentListItem[]>List all workspace documents getDocument(key)(key: string) => Promise<Document>Get document by key putDocument(key, doc)(key: string, doc: { title, content }) => Promise<{...}>Create or update a document deleteDocument(key)(key: string) => Promise<{ key, deleted }>Delete a document
Method Signature Description createApiKey(params)(params: { userId, userName, permissions? }) => Promise<ApiKeyCreateResponse>Create an API key (shared brains only) listApiKeys()() => Promise<ApiKeyListItem[]>List all API keys revokeApiKey(id)(id: string) => Promise<{ id, revoked }>Revoke an API key listConnections()() => Promise<ConnectionStatus[]>List connected brains with online status shareFact(factId, targetBrain?)(factId: string, targetBrain?: string) => Promise<ShareResult>Share a fact to a connected brain
import { DBrainClient } from ' @dtoolkit/sdk ' ;
const brain = new DBrainClient ( ' http://localhost:7878 ' , ' dtk_abc123 ' );
await brain . createEntity ({
await brain . addFact ( ' project-acme ' , {
fact: ' Uses React 19 with Vite 7 and pnpm workspaces ' ,
// Search across all facts
const results = await brain . search ( ' React workspace ' );
for ( const r of results) {
console . log ( ` [ ${ r . entity . name } ] ${ r . fact . fact } (score: ${ r . score } ) ` );
// Federated search (includes connected brains)
const federated = await brain . searchFederated ( ' deployment strategy ' );
console . log ( ` Local: ${ federated . federation . local } , Remote: ${ federated . federation . remote } ` );
Typed client for the dwork REST API (default port 7881).
new DWorkClient (baseUrl: string, token: string)
new DWorkClient (options: DWorkClientOptions)
Option Type Required Description baseUrlstringYes dwork server URL (e.g., http://localhost:7881) tokenstringYes Bearer token for authentication timeoutMsnumberNo Request timeout in milliseconds
Method Signature Description health()() => Promise<DWorkHealthResponse>Server health with project/task/doc counts overview()() => Promise<DWorkOverview>Global overview: all projects with task breakdowns by status and priority whatToDoNext(project?)(project?: string) => Promise<DWorkTask[]>AI-ranked next tasks
Method Signature Description listProjects(status?)(status?: string) => Promise<DWorkProjectSummary[]>List projects with task count summaries getProject(slug)(slug: string) => Promise<DWorkProject>Get full project details including README and tech stack createProject(project)(project: { slug, name, description?, source_path? }) => Promise<DWorkProject>Scaffold a new project updateProject(slug, changes)(slug: string, changes: { name?, description?, status?, source_path? }) => Promise<DWorkProject>Update project metadata deleteProject(slug)(slug: string) => Promise<{ deleted, slug }>Delete a project
Method Signature Description listTasks(project, filters?)(project: string, filters?: { status?, priority? }) => Promise<DWorkTask[]>List tasks for a project addTask(project, task)(project: string, task: { title, type?, priority?, status?, estimate?, deadline?, detail?, detail_doc? }) => Promise<DWorkTask>Add a task to a project updateTask(id, changes)(id: string, changes: { title?, status?, priority?, type?, estimate?, deadline?, detail?, project? }) => Promise<{...}>Update a task deleteTask(id)(id: string) => Promise<{ deleted, id }>Delete a task
Method Signature Description listDocs(project, type?)(project: string, type?: string) => Promise<DWorkDoc[]>List docs for a project getDoc(id)(id: string) => Promise<DWorkDoc>Get a doc with content addDoc(project, doc)(project: string, doc: { title, body, type }) => Promise<DWorkDoc>Add a doc to a project updateDoc(id, changes)(id: string, changes: { title?, body?, type? }) => Promise<{...}>Update a doc deleteDoc(id)(id: string) => Promise<{ deleted, id }>Delete a doc
Method Signature Description search(query, options?)(query: string, options?: { project?, limit? }) => Promise<DWorkSearchResult[]>Full-text search across tasks and docs sync(project)(project: string) => Promise<DWorkSyncResult>Sync markdown files to the SQLite index
Method Signature Description listGraphs()() => Promise<DWorkGraph[]>List all uploaded code graphs getGraph(name)(name: string) => Promise<DWorkGraph>Get graph metadata uploadGraph(name, dbBuffer)(name: string, dbBuffer: Uint8Array) => Promise<DWorkGraphUploadResult>Upload a codegraph-sdk database deleteGraph(name)(name: string) => Promise<void>Delete a graph linkGraphProjects(name, slugs)(name: string, slugs: string[]) => Promise<{ linked }>Link a graph to projects graphStats(name)(name: string) => Promise<DWorkGraphStats>Node/edge/file counts by kind and language searchGraphNodes(name, query, opts?)(name: string, query: string, opts?: { kind?, limit? }) => Promise<DWorkGraphSearchResult[]>Search for nodes in a graph getGraphNode(name, nodeId)(name: string, nodeId: string) => Promise<DWorkGraphNode>Get full node details getGraphCallers(name, nodeId, depth?)(name: string, nodeId: string, depth?: number) => Promise<Array<{...}>>Trace callers of a node getGraphImpact(name, nodeId, depth?)(name: string, nodeId: string, depth?: number) => Promise<DWorkGraphSubgraph>Impact analysis: what does this node affect? traceGraphPath(name, from, to)(name: string, from: string, to: string) => Promise<{ path }>Find the shortest path between two nodes graphDeadCode(name, kinds?)(name: string, kinds?: string) => Promise<DWorkGraphNode[]>Find unreferenced nodes (dead code) graphCircularDependencies(name)(name: string) => Promise<string[][]>Detect circular dependency chains
Method Signature Description createApiKey(params)(params: { userId, userName, permissions? }) => Promise<DWorkApiKeyCreateResponse>Create an API key listApiKeys()() => Promise<DWorkApiKeyListItem[]>List API keys revokeApiKey(id)(id: string) => Promise<{ id, revoked }>Revoke an API key
import { DWorkClient } from ' @dtoolkit/sdk ' ;
const work = new DWorkClient ( ' http://localhost:7881 ' , ' dtk_abc123 ' );
const projects = await work . listProjects ( ' active ' );
for ( const p of projects) {
console . log ( ` ${ p . name } : ${ p . taskCounts . todo ?? 0 } todo, ${ p . taskCounts . done ?? 0 } done ` );
await work . addTask ( ' my-project ' , {
title: ' Implement user auth ' ,
// Get the global overview
const overview = await work . overview ();
console . log ( ` ${ overview . totalProjects } projects, ${ overview . totalTasks } tasks ` );
Typed client for the dproxy REST API (default port 7880). All endpoints are under the /v1 prefix.
new DProxyClient (baseUrl: string, token ?: string)
new DProxyClient (options: DProxyClientOptions)
Option Type Required Description baseUrlstringYes dproxy server URL (e.g., http://localhost:7880) tokenstringNo Bearer token for authentication
Method Signature Description health()() => Promise<DProxyHealthResponse>Server health, active provider, version
Method Signature Description ask(prompt, options?)(prompt: string, options?: AskOptions) => Promise<AskResponse>Execute a prompt and get the full response askStream(prompt, options?)(prompt: string, options?: AskOptions) => AsyncGenerator<AdapterStreamEvent>Stream a prompt response via SSE
AskOptions :
Field Type Description provider'claude' | 'codex' | 'gemini' | 'opencode'Provider to use (default: claude) modelstringModel override maxTurnsnumberMaximum agentic turns maxBudgetUsdnumberCost cap in USD systemPromptstringCustom system prompt memoryboolean | string[]Include memory context (all or specific keys) filesInputFile[]Files to include in context sessionIdstringSession ID for multi-turn conversations continueSessionbooleanContinue an existing session saveHistorybooleanPersist to history
Method Signature Description listHistory(limit?)(limit?: number) => Promise<HistoryEntry[]>List prompt history getHistory(id)(id: string) => Promise<HistoryEntry>Get a single history entry searchHistory(query)(query: string) => Promise<HistoryEntry[]>Search history by query clearHistory(before?)(before?: string) => Promise<{ removed }>Clear history entries
Method Signature Description listMemoryKeys()() => Promise<string[]>List all memory keys getMemory(key)(key: string) => Promise<string>Get memory content by key setMemory(key, content)(key: string, content: string) => Promise<void>Create or update a memory entry deleteMemory(key)(key: string) => Promise<void>Delete a memory entry searchMemory(query)(query: string) => Promise<MemorySearchResult[]>Search across memory entries
Method Signature Description listTemplates()() => Promise<TemplateDefinition[]>List all prompt templates getTemplate(name)(name: string) => Promise<TemplateDefinition>Get a template by name saveTemplate(name, template)(name: string, template: TemplateDefinition) => Promise<void>Create or update a template runTemplate(name, options?)(name: string, options?: TemplateRunOptions) => Promise<AskResponse>Execute a template with variable substitution deleteTemplate(name)(name: string) => Promise<void>Delete a template
Method Signature Description getConfig()() => Promise<unknown>Get the full dproxy config getConfigValue(key)(key: string) => Promise<unknown>Get a single config value setConfigValue(key, value)(key: string, value: string) => Promise<void>Set a config value
import { DProxyClient } from ' @dtoolkit/sdk ' ;
const proxy = new DProxyClient ( ' http://localhost:7880 ' , ' dtk_abc123 ' );
const response = await proxy . ask ( ' Explain the builder pattern in 3 sentences ' , {
console . log (response . text );
console . log ( ` Cost: $ ${ response . costUsd } , Duration: ${ response . durationMs } ms ` );
for await ( const event of proxy . askStream ( ' Write a haiku about TypeScript ' )) {
if (event . type === ' text ' ) {
process . stdout . write (event . text );
Typed client for the dops REST API (default port 7883).
new DOpsClient (baseUrl: string, token: string)
new DOpsClient (options: DOpsClientOptions)
Option Type Required Description baseUrlstringYes dops server URL (e.g., http://localhost:7883) tokenstringYes Bearer token for authentication timeoutMsnumberNo Request timeout in milliseconds
Method Signature Description health()() => Promise<DOpsHealthResponse>Server health, session/event/tool counts, pricing
Method Signature Description createSession(session)(session: DOpsCreateSession) => Promise<{ id }>Create a new observability session endSession(id, data?)(id: string, data?: DOpsEndSession) => Promise<{ updated, id }>Mark a session as completed/failed/abandoned listSessions(filters?)(filters?: DOpsSessionFilters) => Promise<DOpsSessionRow[]>List sessions (filter by source, model, status, date range, limit/offset) getSession(id)(id: string) => Promise<DOpsSessionDetail>Full session detail with token usage, tool calls, and errors
Method Signature Description ingestEvent(event)(event: DOpsEvent) => Promise<{ id }>Ingest a single event ingestBatch(events)(events: DOpsEvent[]) => Promise<{ ingested }>Batch-ingest events (up to 1000) recordToolCall(toolCall)(toolCall: DOpsToolCall) => Promise<{ id }>Record a tool invocation with success/failure and duration recordTokenUsage(usage)(usage: DOpsTokenUsage) => Promise<{ id }>Record token usage per model (input, output, cache read/write) recordError(error)(error: DOpsError) => Promise<{ id }>Record an error linked to a session
Method Signature Description timeseries(filters?)(filters?: DOpsTimeSeriesFilters) => Promise<DOpsTimeSeriesBucket[]>Token usage over time (1h or 15m intervals) toolStats(filters?)(filters?: DOpsStatsFilters) => Promise<DOpsToolStat[]>Per-tool stats: call count, success rate, avg duration modelStats(filters?)(filters?: DOpsDateFilters) => Promise<DOpsModelStat[]>Stats by model: sessions, input/output tokens, cache sourceStats(filters?)(filters?: DOpsDateFilters) => Promise<DOpsSourceStat[]>Stats by source: sessions and token counts
import { DOpsClient } from ' @dtoolkit/sdk ' ;
const ops = new DOpsClient ( ' http://localhost:7883 ' , ' dtk_abc123 ' );
const { id } = await ops . createSession ( {
model : ' claude-sonnet-4-6 ' ,
metadata : { project : ' my-app ' },
await ops . recordTokenUsage ({
model: ' claude-sonnet-4-6 ' ,
await ops . recordToolCall ({
await ops . endSession (id, { status: ' completed ' });
const tools = await ops . toolStats ( { from : ' 2025-01-01 ' } );
console . log ( ` ${ t . tool_name } : ${ t . total } calls, ${ t . success } ok ` );
The examples/ directory in the dtoolkit repo contains ready-to-run TypeScript scripts for every SDK client:
Example Client What it covers dbrain.tsDBrainClientHealth, entity CRUD, facts, search, memory summary, conversations, federation dproxy.tsDProxyClientBatch ask, streaming, system prompts, file attachments, history, memory dwork.tsDWorkClientProjects, tasks, docs, search, overview dops.tsDOpsClientSessions, token usage, tool calls, errors, analytics queries demo.tsAll clients Combined smoke test
Run all examples with zero config:
The setup script creates temporary servers, runs the demo, and cleans up automatically.
The SDK re-exports all response types for use in your own code:
EntityRow, EntityWithFacts, FactRow, SearchResult,
FederatedSearchResponse, HealthResponse, ConversationSummary,
DOpsHealthResponse, DOpsSessionRow, DOpsSessionDetail,
DOpsToolStat, DOpsModelStat, DOpsSourceStat, DOpsTimeSeriesBucket,
DWorkProject, DWorkTask, DWorkDoc, DWorkOverview, DWorkSearchResult,
DWorkGraph, DWorkGraphNode, DWorkGraphStats,
AskOptions, AskResponse, DProxyHealthResponse, ProviderName,
AdapterStreamEvent, AdapterUsage,