Skip to main content

Installation

Add the CLI Proxy API SDK to your Go project:
go get github.com/router-for-me/CLIProxyAPI/v6
The SDK requires Go 1.21 or later.

Quick Start Example

Here’s a complete minimal example to embed the proxy in your application:
main.go
package main

import (
    "context"
    "fmt"
    "os"
    "os/signal"
    "syscall"

    "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy"
    "github.com/router-for-me/CLIProxyAPI/v6/sdk/config"
)

func main() {
    // Load configuration from file
    cfg, err := config.LoadConfig("config.yaml")
    if err != nil {
        fmt.Fprintf(os.Stderr, "Failed to load config: %v\n", err)
        os.Exit(1)
    }

    // Build the service
    svc, err := cliproxy.NewBuilder().
        WithConfig(cfg).
        WithConfigPath("config.yaml").
        Build()
    if err != nil {
        fmt.Fprintf(os.Stderr, "Failed to build service: %v\n", err)
        os.Exit(1)
    }

    // Set up graceful shutdown
    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()

    sigChan := make(chan os.Signal, 1)
    signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)

    go func() {
        <-sigChan
        fmt.Println("\nReceived shutdown signal...")
        cancel()
    }()

    // Run the service (blocks until context is cancelled)
    fmt.Println("Starting CLI Proxy API server...")
    if err := svc.Run(ctx); err != nil && err != context.Canceled {
        fmt.Fprintf(os.Stderr, "Service error: %v\n", err)
        os.Exit(1)
    }

    fmt.Println("Service stopped gracefully")
}

Configuration File

Create a basic config.yaml file:
config.yaml
host: 127.0.0.1
port: 8080
auth_dir: ./auth
log_level: info

# Optional: Add API keys for providers
gemini_key:
  - api_key: "your-gemini-api-key"

claude_key:
  - api_key: "your-claude-api-key"

codex_key:
  - api_key: "your-openai-api-key"
See the Configuration Reference for all available options.

Running Your Application

1

Build your application

Compile your Go application:
go build -o myapp
2

Create configuration

Ensure your config.yaml file is in the same directory or specify a different path.
3

Run the application

Start your application:
./myapp
You should see:
Starting CLI Proxy API server...
API server started successfully on: 127.0.0.1:8080
4

Test the API

Make a test request:
curl http://localhost:8080/v1/models

Understanding the Code

Loading Configuration

cfg, err := config.LoadConfig("config.yaml")
The LoadConfig function reads your YAML configuration and returns a *config.Config struct.

Building the Service

svc, err := cliproxy.NewBuilder().
    WithConfig(cfg).
    WithConfigPath("config.yaml").
    Build()
The builder pattern allows you to configure the service with:
  • WithConfig: Sets the configuration object
  • WithConfigPath: Sets the path for file watching (automatic reload)
  • Build(): Creates the service instance

Running the Service

if err := svc.Run(ctx); err != nil {
    // Handle error
}
The Run method:
  • Starts the HTTP server
  • Initializes authentication providers
  • Starts file watchers for config and auth changes
  • Blocks until the context is cancelled
  • Returns when shutdown is complete

Graceful Shutdown

The example includes graceful shutdown handling:
// Create cancellable context
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

// Listen for shutdown signals
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)

go func() {
    <-sigChan
    cancel() // Cancel context to stop service
}()

// Run will return when context is cancelled
svc.Run(ctx)
When the service receives a shutdown signal:
  1. Context is cancelled
  2. HTTP server stops accepting new requests
  3. Existing requests are completed
  4. File watchers are stopped
  5. Authentication providers are cleaned up
  6. Run() returns

Common Patterns

Using Environment Variables

import "github.com/joho/godotenv"

func main() {
    // Load .env file
    godotenv.Load()
    
    // Get config path from environment
    configPath := os.Getenv("CONFIG_PATH")
    if configPath == "" {
        configPath = "config.yaml"
    }
    
    cfg, err := config.LoadConfig(configPath)
    // ...
}

Custom Port Binding

cfg, _ := config.LoadConfig("config.yaml")

// Override port from configuration
if port := os.Getenv("PORT"); port != "" {
    if p, err := strconv.Atoi(port); err == nil {
        cfg.Port = p
    }
}

svc, _ := cliproxy.NewBuilder().
    WithConfig(cfg).
    // ...

Multiple Services

You can run multiple proxy instances in the same process:
// Production service
prodCfg, _ := config.LoadConfig("prod-config.yaml")
prodSvc, _ := cliproxy.NewBuilder().
    WithConfig(prodCfg).
    WithConfigPath("prod-config.yaml").
    Build()

// Development service on different port
devCfg, _ := config.LoadConfig("dev-config.yaml")
devCfg.Port = 8081
devSvc, _ := cliproxy.NewBuilder().
    WithConfig(devCfg).
    WithConfigPath("dev-config.yaml").
    Build()

// Run both
go prodSvc.Run(ctx)
go devSvc.Run(ctx)

// Wait...

Error Handling

Common errors and how to handle them:

Configuration Errors

cfg, err := config.LoadConfig("config.yaml")
if err != nil {
    // File not found, invalid YAML, etc.
    log.Fatalf("Config error: %v", err)
}

Build Errors

svc, err := cliproxy.NewBuilder().
    WithConfig(cfg).
    WithConfigPath("config.yaml").
    Build()
if err != nil {
    // Missing required configuration
    log.Fatalf("Build error: %v", err)
}

Runtime Errors

if err := svc.Run(ctx); err != nil {
    if err == context.Canceled {
        // Normal shutdown
        log.Println("Service stopped")
    } else {
        // Unexpected error
        log.Fatalf("Runtime error: %v", err)
    }
}

Next Steps

Embedding Guide

Learn about builder options, hooks, and advanced configuration

Configuration

Explore all configuration options

Advanced Features

Implement custom executors and translators

Access Control

Add custom authentication

Build docs developers (and LLMs) love