Enhancement Category
Developer experience
Problem or Use Case
Currently, CPE is only usable as a CLI tool. Developers who want to build applications with AI-powered code analysis, conversation management, or MCP integration must either:
- Shell out to the
cpe binary (brittle, hard to integrate, loses type safety)
- Reimplement CPE's core functionality from scratch
- Fork and modify CPE directly (maintenance burden)
This limits CPE's usefulness in several scenarios:
- Building custom AI assistants - developers building their own CLI tools or applications want CPE's conversation management, storage, and model abstraction
- Embedding in larger applications - web servers, desktop apps, or other Go programs that want to leverage CPE's capabilities
- Creating specialized tooling - custom CI/CD integrations, code review bots, or development workflow automation
- Testing and experimentation - programmatic access makes it easier to build benchmarks, test suites, or research tools
Proposed Solution
Expose CPE's core functionality as a public Go SDK that can be imported as a module. The SDK should support all current CLI operations programmatically:
Core API Surface
import "github.com/spachava753/cpe/sdk"
// Configuration - two approaches
// Option 1: Load from file (like CLI)
cfg, err := sdk.LoadConfig("./cpe.yaml")
// Option 2: Programmatic configuration
cfg := &sdk.Config{
Models: []sdk.ModelConfig{
{
Ref: "sonnet",
ID: "claude-3-5-sonnet-20241022",
Type: "anthropic",
ApiKeyEnv: "ANTHROPIC_API_KEY",
},
},
MCPServers: map[string]sdk.MCPServerConfig{...},
Defaults: sdk.Defaults{
Model: "sonnet",
CodeMode: &sdk.CodeModeConfig{Enabled: true},
},
}
Conversation & Storage Management
// Initialize storage (SQLite-backed, like .cpeconvo)
storage, err := sdk.NewDialogStorage(ctx, "./my-conversations.db")
defer storage.Close()
// Create a new conversation
conv := sdk.NewConversation(storage)
// Or resume from a specific message ID (branching/forking)
conv, err := sdk.ResumeConversation(storage, "abc123")
// List all conversation trees
trees, err := storage.ListConversations(ctx)
// Get full dialog history for a branch
dialog, msgIDs, err := storage.GetDialogForMessage(ctx, "abc123")
Generation & Agent Execution
// Create a generator from config
gen, err := sdk.NewGenerator(ctx, cfg, sdk.GeneratorOptions{
ModelRef: "sonnet",
SystemPrompt: customPrompt, // or use cfg.Defaults.SystemPromptPath
})
defer gen.Close()
// Single-turn generation (no storage)
response, err := gen.Generate(ctx, dialog, &sdk.GenOpts{
Temperature: 0.7,
MaxTokens: 4096,
})
// Multi-turn with automatic storage
result, err := conv.Send(ctx, gen, sdk.UserMessage{
Text: "Analyze this code",
Files: []string{"main.go"}, // Multimodal: files
Images: [][]byte{screenshotBytes}, // Multimodal: images
})
// Access the response
fmt.Println(result.Text)
fmt.Println(result.MessageID) // For continuation/forking
// Incognito mode (no storage)
result, err := sdk.GenerateIncognito(ctx, gen, dialog)
MCP Integration
// Initialize MCP connections from config
mcpState, err := sdk.InitializeMCP(ctx, cfg.MCPServers)
defer mcpState.Close()
// Create generator with MCP tools
gen, err := sdk.NewGenerator(ctx, cfg, sdk.GeneratorOptions{
MCPState: mcpState,
CodeMode: true, // Enable code mode for tool execution
})
// Or manually call MCP tools
result, err := mcpState.CallTool(ctx, "server_name", "tool_name", map[string]any{
"param": "value",
})
Streaming Support
// Stream responses with callbacks
err := gen.GenerateStream(ctx, dialog, opts, func(chunk sdk.StreamChunk) error {
switch chunk.Type {
case sdk.ChunkText:
fmt.Print(chunk.Text)
case sdk.ChunkToolCall:
fmt.Printf("Calling tool: %s\n", chunk.ToolName)
case sdk.ChunkToolResult:
fmt.Printf("Tool result: %s\n", chunk.Result)
}
return nil
})
Package Structure
github.com/spachava753/cpe/
├── sdk/ # Public SDK package
│ ├── config.go # Configuration types and loading
│ ├── storage.go # DialogStorage interface and implementation
│ ├── conversation.go # High-level conversation management
│ ├── generator.go # Generator creation and options
│ ├── mcp.go # MCP state and tool calling
│ └── types.go # Public types (Message, Dialog, etc.)
├── internal/ # Internal implementation (existing)
│ ├── agent/
│ ├── config/
│ ├── storage/
│ └── ...
└── cmd/ # CLI (uses sdk internally)
Alternatives Considered
-
Keep CLI-only: Users can shell out to cpe, but this is slow, lossy (no type safety), and hard to integrate properly.
-
Export internal packages directly: Making internal/ packages public would work but violates Go conventions and exposes implementation details that may change.
-
Separate repository: A separate cpe-sdk repo would add maintenance burden and versioning complexity.
-
gRPC/HTTP server mode: Adding a server mode would enable language-agnostic access but adds network overhead and deployment complexity for Go users.
The proposed SDK approach provides the cleanest API while reusing existing internal implementations.
Impact Scope
Power users / advanced workflows
Additional Context
Key Design Considerations
-
Configuration flexibility: Support both file-based config (for CLI parity) and programmatic config (for embedded use). The internal/config package already has good separation that can be exposed.
-
Storage abstraction: The current DialogStorage interface in internal/commands/generate.go is already well-abstracted. Expose this with perhaps a factory function for SQLite (default) or allow users to implement their own.
-
Conversation forking: The tree-based message storage already supports this perfectly. The SDK should make it easy to:
- List conversation trees
- Resume from any message ID
- Create branches by continuing from historical messages
-
Multimodal support: The gai.Block system already handles text, images, audio, video. The SDK should provide helpers for common cases (file paths, byte arrays).
-
Interruption handling: Consider exposing the partial-save behavior for interrupted generations.
-
Middleware/hooks: Allow users to add custom middleware (logging, metrics, etc.) to the generator pipeline.
Migration Path
The CLI (cmd/) would be refactored to use the SDK internally, ensuring feature parity and that the SDK is truly complete. This also serves as a reference implementation.
Related Components
internal/storage/dialog_storage.go - conversation storage (expose as SDK interface)
internal/config/ - configuration loading (expose config types)
internal/agent/generator.go - generator creation (expose as SDK factory)
internal/mcp/ - MCP integration (expose state management)
internal/commands/generate.go - generation flow (reference for SDK conversation API)
Enhancement Category
Developer experience
Problem or Use Case
Currently, CPE is only usable as a CLI tool. Developers who want to build applications with AI-powered code analysis, conversation management, or MCP integration must either:
cpebinary (brittle, hard to integrate, loses type safety)This limits CPE's usefulness in several scenarios:
Proposed Solution
Expose CPE's core functionality as a public Go SDK that can be imported as a module. The SDK should support all current CLI operations programmatically:
Core API Surface
Conversation & Storage Management
Generation & Agent Execution
MCP Integration
Streaming Support
Package Structure
Alternatives Considered
Keep CLI-only: Users can shell out to
cpe, but this is slow, lossy (no type safety), and hard to integrate properly.Export internal packages directly: Making
internal/packages public would work but violates Go conventions and exposes implementation details that may change.Separate repository: A separate
cpe-sdkrepo would add maintenance burden and versioning complexity.gRPC/HTTP server mode: Adding a server mode would enable language-agnostic access but adds network overhead and deployment complexity for Go users.
The proposed SDK approach provides the cleanest API while reusing existing internal implementations.
Impact Scope
Power users / advanced workflows
Additional Context
Key Design Considerations
Configuration flexibility: Support both file-based config (for CLI parity) and programmatic config (for embedded use). The
internal/configpackage already has good separation that can be exposed.Storage abstraction: The current
DialogStorageinterface ininternal/commands/generate.gois already well-abstracted. Expose this with perhaps a factory function for SQLite (default) or allow users to implement their own.Conversation forking: The tree-based message storage already supports this perfectly. The SDK should make it easy to:
Multimodal support: The
gai.Blocksystem already handles text, images, audio, video. The SDK should provide helpers for common cases (file paths, byte arrays).Interruption handling: Consider exposing the partial-save behavior for interrupted generations.
Middleware/hooks: Allow users to add custom middleware (logging, metrics, etc.) to the generator pipeline.
Migration Path
The CLI (
cmd/) would be refactored to use the SDK internally, ensuring feature parity and that the SDK is truly complete. This also serves as a reference implementation.Related Components
internal/storage/dialog_storage.go- conversation storage (expose as SDK interface)internal/config/- configuration loading (expose config types)internal/agent/generator.go- generator creation (expose as SDK factory)internal/mcp/- MCP integration (expose state management)internal/commands/generate.go- generation flow (reference for SDK conversation API)