@cdmbase/cdecli-agent-client
TypeScript client for the cdecli-agent Go HTTP server.
Ships in the same repo as the agent server (src/serve/cdecli_exec.go) so the
wire protocol and client move together — every protocol change lands as one PR.
Install
yarn add @cdmbase/cdecli-agent-client
# optional: enable HTTP keep-alive on Node
yarn add undici
Why
A thin, dependency-light wrapper around the cdecli-agent wire protocol
(POST /v1/cdecli/exec). Owns the sentinel parser, auth header logic, and
credential-key picker so callers don't re-implement them.
Layers
CdecliAgentClient ← transport (fetch + headers + JSON)
│
├─ CdecliConnectorClient ← cdecli connector run/install/list/actions
├─ CdecliAgentChatClient ← cdecli agent --skill … --mode … -m … (native session/chat protocol)
├─ CdecliAgentRunnerClient ← cdecli agent -m … run as a child cdecli via /v1/cdecli/exec
└─ CdecliSearchClient ← cdecli connector search …
Usage
import {
CdecliAgentClient,
CdecliConnectorClient,
} from '@cdmbase/cdecli-agent-client';
const transport = new CdecliAgentClient({
endpoint: process.env.CDECLI_AGENT_ENDPOINT ?? 'https://your-cdecli-agent.example.com',
});
const connectors = new CdecliConnectorClient(transport);
const result = await connectors.runAction({
userToken: userJwt, // bearer for per-user $HOME isolation
connector: 'github',
action: 'GITHUB_LIST_ISSUES',
params: { repo: 'owner/repo' },
credentialId: 'fb-cred-id', // optional vault lookup
});
if (result.successful) {
console.log(result.data);
} else {
console.error(result.error);
}
Agent chat with a skill
The SDK equivalent of
cdecli agent --endpoint https://cdecli-agent.cdebase.dev \
--skill yantra-video-studio --no-tui --mode auto \
-m "$(cat birthday-brief.txt)" > run.log
is CdecliAgentChatClient. It speaks the agent's native protocol - the same
one the CLI uses when it delegates to a remote agent: POST /v1/agent/session
creates a session with the skill pre-activated, then POST /v1/agent/chat
streams the turn as server-sent events with the permission mode attached.
There is no TUI to turn off and no child cdecli process.
import { readFile } from 'node:fs/promises';
import { CdecliAgentClient, CdecliAgentChatClient } from '@cdmbase/cdecli-agent-client';
const transport = new CdecliAgentClient({ endpoint: 'https://cdecli-agent.cdebase.dev' });
const agent = new CdecliAgentChatClient(transport);
const result = await agent.run({
userToken: userJwt, // --token / auth.json access token
skill: 'yantra-video-studio', // --skill
permissionMode: 'auto', // --mode auto (unattended)
message: await readFile('birthday-brief.txt', 'utf8'), // -m
onChunk: (text) => process.stdout.write(text), // the streamed reply
onStatus: (status) => console.error(`[${status}]`),
});
console.log(result.sessionId, result.text.length, result.outputs);
run()creates the session and sends one turn; passsessionIdto continue an existing session (createSession,chat,cancel, andcloseSessionare also exposed for multi-turn control).- One skill is activated per session, as on the CLI's delegated path. The
skill must already exist on the agent (
GET /v1/skills); the SDK does not push local skill folders the way the CLI does. permissionModeis the--modevocabulary:ask | edit | plan | auto | bypass(yolo=bypass).autois what an unattended job wants.onEventreceives every decoded event (delta,output,status,tool_call,tool_result,tool_input_delta,ask_user,error,done). A clarifying question the agent parks on arrives asask_userwith the decoded payload, and is stripped from the visible text; answer it with anotherchat()on the same session.- A server-side failure rejects with
CdecliAgentChatError, which keeps thesessionIdand thepartialTextstreamed before the error. - Sessions are pinned to the pod that created them: the client replays the ingress's sticky cookie per session, so a shared transport can serve many users without pinning them all to one pod.
CdecliAgentRunnerClient.run() remains for callers that want a child
cdecli agent -m … on the agent through /v1/cdecli/exec; it now also
accepts permissionMode (--mode).
Wire contract
Matches src/serve/cdecli_exec.go::ExecRequest in this repo. Accepts either
args (argv) or shell_command (POSIX line). Response shape is
{ stdout, stderr, exit_code, error? }.
Drift policy: every change to the Go ExecRequest / ExecResponse struct
in src/serve/cdecli_exec.go must update src/types.ts in the same PR.
HTTP keep-alive
On Node, the default fetchImpl uses a process-wide undici.Agent
(connections: 128, keepAliveTimeout: 30s) shared across all tenants. JWTs
and session ids live in per-request headers, so pooling is safe.
Disable with CDECLI_AGENT_KEEPALIVE=0.
Development
cd packages/cdecli-agent-client
yarn install
yarn build
yarn test
This package is standalone — not part of any workspace. It pulls its own
node_modules and is published independently of the Go binary.