Skip to content
dtoolkit

dproxy — Transport

dproxy is the universal CLI adapter in dtoolkit. It provides a single interface for invoking AI coding agents across multiple providers — Claude Code, Codex CLI, Gemini CLI, and OpenCode — without changing your workflow. Whether you need a one-shot prompt, an interactive REPL, or a REST API for programmatic access, dproxy handles provider differences behind a unified abstraction.

AI coding CLIs each have their own invocation patterns, streaming formats, and context conventions. dproxy normalizes all of this into one tool:

  • One CLI, four providers — switch between Claude Code, Codex, Gemini, and OpenCode with a single --provider flag
  • Context pipeline — automatically assembles prompts from chat history, workspace context, memory, and life/PARA data
  • REST API — expose the same capabilities over HTTP with SSE streaming for real-time output
  • Template system — define reusable prompt templates for common tasks
  • History and memory — persistent conversation logs and memory snippets across sessions

Data is stored in ~/.dproxy/ (config.json, history.jsonl, memory/, templates/).

install
pnpm add @dtoolkit/dproxy

Or install globally:

install
pnpm add -g @dtoolkit/dproxy

Then initialize your configuration:

terminal
dproxy init

dproxy supports four AI coding CLI providers. Each provider has a corresponding adapter package that handles the specifics of invocation, streaming format, and output parsing.

ProviderAdapter PackageStreaming FormatDefault
Claude Code@dtoolkit/adapter-claudestream-json + deltasYes
Codex CLI@dtoolkit/adapter-codexJSONL streamingNo
Gemini CLI@dtoolkit/adapter-geministream-jsonNo
OpenCode@dtoolkit/adapter-opencodeJSONL streamingNo

Switch providers with the --provider flag on any command:

terminal
dproxy ask "Explain this function" --provider claude
dproxy ask "Explain this function" --provider codex
dproxy ask "Explain this function" --provider gemini
dproxy ask "Explain this function" --provider opencode

Send a one-shot prompt and get a response. This is the most common command for scripting and quick questions.

terminal
dproxy ask "What does this regex do: ^(?=.*[A-Z])(?=.*\d).{8,}$"

Pipe input from other commands:

terminal
cat src/lib/runner.ts | dproxy ask "Review this file for bugs"

With a specific provider:

terminal
dproxy ask "Generate unit tests for this module" --provider gemini

Start a conversational REPL session with persistent context across turns:

terminal
dproxy chat
terminal
dproxy chat --provider codex

The REPL maintains conversation state for the duration of the session. History is persisted to ~/.dproxy/history.jsonl.

Launch a Fastify HTTP server that exposes the full CLI functionality over REST:

terminal
dproxy serve
terminal
dproxy serve --port 7880

The default port is 7880. See the REST API section for endpoint details.

Browse and search conversation history:

terminal
dproxy history

View and manage memory snippets that are injected into the context pipeline:

terminal
dproxy memory

dproxy template — Manage prompt templates

Section titled “dproxy template — Manage prompt templates”

Create, list, and use reusable prompt templates:

terminal
dproxy template

See the Templates section for details.

Set up the ~/.dproxy/ directory and default configuration:

terminal
dproxy init
CommandPurposeKey Flags
askSingle-shot prompt execution--provider, piped stdin
chatInteractive REPL session--provider
serveLaunch REST API server--port
historyBrowse conversation history
memoryManage memory snippets
templateManage prompt templates
initInitialize configuration

One of dproxy’s most valuable features is its automatic context assembly. Before every prompt is sent to a provider, dproxy builds a rich context from multiple sources in priority order:

  1. Day chat log — Recent conversation history from the current day, providing continuity across interactions.

  2. Workspace bootstrap — Project-level context gathered from the current working directory (README, CLAUDE.md, package.json, etc.).

  3. Memory snippets — Persistent memory fragments stored in ~/.dproxy/memory/, surfaced by relevance to the current prompt.

  4. Life/PARA context — Broader personal and organizational context following the PARA method (Projects, Areas, Resources, Archives).

This pipeline means your prompts carry relevant context without you needing to manually paste files or repeat background information. The context builder (src/lib/context-builder.ts) assembles everything into a unified prompt before handing it to the resolved adapter.

While dproxy has its own local memory system (~/.dproxy/memory/), it integrates with the broader dtoolkit memory layer:

  • dbrain provides persistent, searchable memory with tiers and federation
  • dcontext injects dbrain facts into AI CLI sessions at startup
  • dproxy can pull memory from dbrain via the SDK when both are running

The dproxy serve command launches a Fastify REST API that mirrors the full CLI functionality. This is useful for integrating dproxy into other tools, dashboards, or automated workflows.

SettingDefaultDescription
Port7880Configurable via --port flag
AuthBearer tokenSet in ~/.dproxy/config.json
StreamingSSEEnabled via stream: true in request body

All API requests require a Bearer token in the Authorization header:

terminal
curl -H "Authorization: Bearer YOUR_TOKEN" http://localhost:7880/ask \
-X POST \
-H "Content-Type: application/json" \
-d '{"prompt": "Explain dependency injection"}'

To receive streaming responses, set stream: true in your request body. The server responds with Server-Sent Events:

terminal
curl -N -H "Authorization: Bearer YOUR_TOKEN" http://localhost:7880/ask \
-X POST \
-H "Content-Type: application/json" \
-d '{"prompt": "Write a haiku about TypeScript", "stream": true}'

Each SSE event contains an AdapterStreamEvent — the same typed event structure used internally by all adapters.

Pass the provider field in your request body:

terminal
curl -H "Authorization: Bearer YOUR_TOKEN" http://localhost:7880/ask \
-X POST \
-H "Content-Type: application/json" \
-d '{"prompt": "List files in this directory", "provider": "gemini"}'

Templates let you define reusable prompt patterns for common tasks. They are stored in ~/.dproxy/templates/ and can include variable placeholders.

terminal
# List available templates
dproxy template
# Use a template
dproxy ask --template code-review

Templates are simple files with placeholder syntax that gets resolved at invocation time. This avoids repeating long system prompts or detailed instructions for tasks you run frequently — code reviews, test generation, documentation, and similar workflows.

Under the hood, dproxy delegates all provider interaction to adapter packages. Understanding this architecture is useful if you want to extend dproxy or debug provider-specific behavior.

Every adapter implements two core methods:

MethodPurposeReturn Type
stream()Stream tokens as they arriveAsyncGenerator<AdapterStreamEvent>
execute()Run to completion, return full resultPromise<string>

The resolveAdapter() function in src/lib/adapter.ts maps a provider name string to the corresponding adapter instance.

  1. Context building — The context builder assembles ContextBlock[] from all sources (history, workspace, memory, PARA).

  2. Adapter resolutionresolveAdapter() maps the --provider flag to the correct adapter package.

  3. Execution — The adapter’s stream() or execute() method is called, shelling out to the underlying CLI.

  4. Persistence — Results are written to history.jsonl for future reference.

The ContextBlock type from @dtoolkit/core is the universal currency for context in dtoolkit:

interface ContextBlock {
type: string; // e.g., "workspace", "memory", "history"
source: string; // origin identifier
content: string; // the actual context text
}

Every component in dtoolkit that produces or consumes context speaks this contract — from dproxy’s context builder to dcontext’s session injection to dbrain’s memory retrieval. This shared type is what makes the tools composable without tight coupling.

Streaming responses use the AdapterStreamEvent type, also defined in @dtoolkit/core. This provides a consistent event structure regardless of whether the underlying provider uses JSON streaming, JSONL, or another format. The adapter handles the translation.

dproxy sits at the transport layer of the dtoolkit stack:

ProductRoleRelationship to dproxy
dbrainMemorydproxy reads memory for context pipeline
dcontextHooksUses the same adapters for CLI integration
dworkProject managementCan invoke dproxy for AI-assisted sync
dopsObservabilityIngests transcripts from dproxy sessions
@dtoolkit/sdkHTTP clientsDProxyClient provides typed access to the REST API

All configuration lives in ~/.dproxy/config.json:

FieldTypeDescription
defaultProviderstringDefault provider when --provider is omitted
portnumberDefault port for dproxy serve
tokenstringBearer token for REST API authentication
  1. Install dproxy:

    install
    pnpm add -g @dtoolkit/dproxy
  2. Initialize configuration:

    terminal
    dproxy init
  3. Send your first prompt:

    terminal
    dproxy ask "What is the ContextBlock contract in dtoolkit?"
  4. Start an interactive session:

    terminal
    dproxy chat
  5. Launch the REST API:

    terminal
    dproxy serve