diff --git a/.env.example b/.env.example
new file mode 100644
index 00000000..e31290af
--- /dev/null
+++ b/.env.example
@@ -0,0 +1,96 @@
+# BrainSait AI Platform - Environment Configuration
+# Copy this file to .env and fill in your values
+
+# ============================================
+# REQUIRED: Core Configuration
+# ============================================
+
+# GitHub Token for Models API access
+GITHUB_TOKEN=your_github_personal_access_token
+
+# Database password (use a strong password!)
+DB_PASSWORD=your_secure_database_password
+
+# ============================================
+# REQUIRED: API Security
+# ============================================
+
+# Master API key for admin operations
+BRAINSAIT_API_KEY=your_master_api_key_here
+
+# JWT Secret for user authentication
+JWT_SECRET=your_jwt_secret_minimum_32_characters
+
+# ============================================
+# OPTIONAL: Payment Integration (Stripe)
+# ============================================
+
+# Stripe API Keys (for monetization)
+STRIPE_SECRET_KEY=sk_test_your_stripe_secret_key
+STRIPE_PUBLISHABLE_KEY=pk_test_your_stripe_publishable_key
+STRIPE_WEBHOOK_SECRET=whsec_your_webhook_secret
+
+# Stripe Price IDs for subscription tiers
+STRIPE_PRICE_PRO=price_xxxxxxxxxxxxx
+STRIPE_PRICE_ENTERPRISE=price_xxxxxxxxxxxxx
+
+# ============================================
+# OPTIONAL: Monitoring & Analytics
+# ============================================
+
+# Grafana admin password
+GRAFANA_PASSWORD=your_grafana_admin_password
+
+# Sentry DSN for error tracking
+SENTRY_DSN=https://xxxx@sentry.io/xxxxx
+
+# ============================================
+# OPTIONAL: Email (for notifications)
+# ============================================
+
+# SMTP Configuration
+SMTP_HOST=smtp.sendgrid.net
+SMTP_PORT=587
+SMTP_USER=apikey
+SMTP_PASSWORD=your_sendgrid_api_key
+SMTP_FROM=noreply@brainsait.ai
+
+# ============================================
+# OPTIONAL: Cloud Storage (for audit logs)
+# ============================================
+
+# AWS S3 (or compatible)
+AWS_ACCESS_KEY_ID=your_aws_access_key
+AWS_SECRET_ACCESS_KEY=your_aws_secret_key
+AWS_REGION=me-south-1
+S3_BUCKET=brainsait-audit-logs
+
+# ============================================
+# OPTIONAL: Domain-Specific Settings
+# ============================================
+
+# Arabic Market
+ARABIC_DEFAULT_MODEL=openai/gpt-4o
+ARABIC_TRANSLATION_API=your_translation_api_key
+
+# Healthcare (HIPAA)
+HIPAA_AUDIT_ENABLED=true
+PHI_ENCRYPTION_KEY=your_32_byte_encryption_key_here
+
+# ============================================
+# Application Settings
+# ============================================
+
+# Log level: debug, info, warn, error
+LOG_LEVEL=info
+
+# Server port
+PORT=8080
+
+# Environment: development, staging, production
+ENVIRONMENT=development
+
+# Rate limiting (requests per minute)
+RATE_LIMIT_FREE=60
+RATE_LIMIT_PRO=600
+RATE_LIMIT_ENTERPRISE=6000
diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md
index f741ab43..87084b5f 100644
--- a/.github/copilot-instructions.md
+++ b/.github/copilot-instructions.md
@@ -27,18 +27,35 @@ This repository implements the GitHub Models CLI extension (`gh models`), enabli
3. Azure client converts to `azuremodels.ChatCompletionOptions` and makes API calls
4. Results are formatted using terminal-aware table printers from `command.Config`
+### Generate Command (PromptPex)
+- **Location**: `cmd/generate/` - self-contained implementation of test generation
+- **Key files**: `pipeline.go` (orchestration), `prompts.go` (phase prompts), `evaluators.go` (test evaluation)
+- **Flow**: Intent → InputSpec → OutputRules → InverseOutputRules → Tests → Evaluation
+- **Session state**: `types.go` defines `PromptPexContext` - serialized to JSON for resumability
+- **Cleanup**: `cleaner.go` handles post-generation test refinement and deduplication
+
## Developer Workflows
### Building & Testing
- **Local build**: `make build` or `script/build` (creates `gh-models` binary)
- **Cross-platform**: `script/build all|windows|linux|darwin` for release builds
+ - Builds for windows/amd64, linux/amd64, android/arm64, android/amd64, darwin/amd64, darwin/arm64
- **Testing**: `make check` runs format, vet, tidy, and tests. Use `go test ./...` directly for faster iteration
- **Quality gates**: `make check` - required before commits
+- **Integration tests**: `make integration` - builds binary and runs tests against live endpoints (requires `gh auth login`)
+ - Located in `integration/` directory with separate go.mod
+ - Tests gracefully skip when authentication unavailable
+ - CI runs these via `.github/workflows/integration.yml`
### Authentication & Setup
- Extension requires `gh auth login` before use - unauthenticated clients show helpful error messages
- Client initialization pattern in `cmd/root.go`: check token, create appropriate client (authenticated vs unauthenticated)
+### Release Process
+- Create git tag: `git tag v0.0.x main && git push origin tag v0.0.x`
+- This triggers `.github/workflows/release.yml` for production builds
+- Users install with `gh extension install github/gh-models` (pulls latest release, not latest commit)
+
## Prompt File Conventions
### Structure (.prompt.yml)
@@ -62,13 +79,21 @@ evaluators:
- **JSON Schema**: Use `responseFormat: json_schema` with `jsonSchema` field containing strict JSON schema
- **Templates**: All message content supports `{{variable}}` substitution from `testData` entries
+### PromptPex Test Generation
+- **Command**: `gh models generate` - implements [PromptPex](https://github.com/microsoft/promptpex) methodology
+- **Effort levels**: `min` (quick validation), `low` (limits to 3 rules), `medium` (better coverage), `high` (complex inputs, more tokens)
+- **Custom instructions**: Use `--instruction-{phase}` flags for intent, inputspec, outputrules, inverseoutputrules, tests
+- **Session persistence**: `--session-file` to save/load generation state
+- **Documentation**: See `cmd/generate/README.md` and https://microsoft.github.io/promptpex/reference/test-generation/
+
## Testing Patterns
-### Command Tests
+### Unit Tests (Command Tests)
- **Location**: `cmd/{command}/{command}_test.go`
- **Pattern**: Create mock client via `azuremodels.NewMockClient()`, inject into `command.Config`
- **Structure**: Table-driven tests with subtests using `t.Run()`
- **Assertions**: Use `testify/require` for cleaner error messages
+- **Run**: `make test` or `go test -race -cover ./...`
### Mock Usage
```go
@@ -76,6 +101,14 @@ client := azuremodels.NewMockClient()
cfg := command.NewConfig(new(bytes.Buffer), new(bytes.Buffer), client, true, 80)
```
+### Integration Tests
+- **Location**: `integration/integration_test.go` (separate go.mod)
+- **Pattern**: Execute compiled binary via `exec.Command()` with timeout protection
+- **Prerequisites**: Binary must exist (`make build` first)
+- **Authentication**: Tests skip gracefully when `gh auth` unavailable
+- **Focus**: Verify basic functionality, command execution, output format - not full feature testing
+- **Run**: `make integration` (combines `make check`, `make build`, and integration tests)
+
## Integration Points
### GitHub Authentication
diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml
new file mode 100644
index 00000000..d6c39af2
--- /dev/null
+++ b/.github/workflows/docker-build.yml
@@ -0,0 +1,63 @@
+name: Build and Push Docker Image
+
+on:
+ push:
+ branches: [main]
+ tags: ['v*']
+ pull_request:
+ branches: [main]
+ workflow_dispatch:
+
+env:
+ REGISTRY: docker.io
+ IMAGE_NAME: brainsait/api
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ packages: write
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+
+ - name: Log in to Docker Hub
+ if: github.event_name != 'pull_request'
+ uses: docker/login-action@v3
+ with:
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
+
+ - name: Extract metadata
+ id: meta
+ uses: docker/metadata-action@v5
+ with:
+ images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
+ tags: |
+ type=ref,event=branch
+ type=ref,event=pr
+ type=semver,pattern={{version}}
+ type=semver,pattern={{major}}.{{minor}}
+ type=sha,prefix=
+ type=raw,value=latest,enable={{is_default_branch}}
+
+ - name: Build and push Docker image
+ uses: docker/build-push-action@v5
+ with:
+ context: .
+ file: ./Dockerfile.api
+ push: ${{ github.event_name != 'pull_request' }}
+ tags: ${{ steps.meta.outputs.tags }}
+ labels: ${{ steps.meta.outputs.labels }}
+ cache-from: type=gha
+ cache-to: type=gha,mode=max
+ platforms: linux/amd64,linux/arm64
+
+ - name: Image digest
+ if: github.event_name != 'pull_request'
+ run: echo "Image pushed with digest ${{ steps.docker_build.outputs.digest }}"
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
new file mode 100644
index 00000000..cb99a895
--- /dev/null
+++ b/.vscode/extensions.json
@@ -0,0 +1,5 @@
+{
+ "recommendations": [
+ "ms-azuretools.vscode-docker"
+ ]
+}
\ No newline at end of file
diff --git a/BRAINSAIT_CUSTOMIZATION.md b/BRAINSAIT_CUSTOMIZATION.md
new file mode 100644
index 00000000..b863a2fc
--- /dev/null
+++ b/BRAINSAIT_CUSTOMIZATION.md
@@ -0,0 +1,452 @@
+# BrainSait AI Platform - Customization Guide
+
+> Transform `gh-models` into a branded, monetizable AI platform for targeted domains.
+
+## ✅ Legal Status
+
+**MIT License allows:**
+- ✅ Commercial use
+- ✅ Modification & rebranding
+- ✅ Distribution
+- ✅ Monetization
+- ⚠️ Must include original license & copyright
+
+---
+
+## 🐳 1. Containerization
+
+### Dockerfile
+
+```dockerfile
+# Build stage
+FROM golang:1.23-alpine AS builder
+WORKDIR /app
+COPY go.mod go.sum ./
+RUN go mod download
+COPY . .
+RUN CGO_ENABLED=0 GOOS=linux go build -o brainsait-models main.go
+
+# Runtime stage
+FROM alpine:3.19
+RUN apk --no-cache add ca-certificates
+WORKDIR /root/
+COPY --from=builder /app/brainsait-models .
+EXPOSE 8080
+ENTRYPOINT ["./brainsait-models"]
+```
+
+### Docker Compose (with API wrapper)
+
+```yaml
+version: '3.8'
+services:
+ brainsait-api:
+ build: .
+ ports:
+ - "8080:8080"
+ environment:
+ - GITHUB_TOKEN=${GITHUB_TOKEN}
+ - BRAINSAIT_API_KEY=${BRAINSAIT_API_KEY}
+ restart: unless-stopped
+
+ redis:
+ image: redis:alpine
+ ports:
+ - "6379:6379"
+ volumes:
+ - redis-data:/data
+
+ postgres:
+ image: postgres:15-alpine
+ environment:
+ POSTGRES_DB: brainsait
+ POSTGRES_USER: admin
+ POSTGRES_PASSWORD: ${DB_PASSWORD}
+ volumes:
+ - postgres-data:/var/lib/postgresql/data
+
+volumes:
+ redis-data:
+ postgres-data:
+```
+
+---
+
+## 🏷️ 2. Branding Customization
+
+### Files to Modify:
+
+| File | Changes |
+|------|---------|
+| `cmd/root.go` | Update command names, descriptions |
+| `internal/azuremodels/legal.go` | Update NOTICE |
+| `go.mod` | Change module name |
+| `README.md` | Complete rebrand |
+
+### Example: cmd/root.go changes
+
+```go
+// Before
+cmd := &cobra.Command{
+ Use: "models",
+ Short: "GitHub Models extension",
+ Long: heredoc.Docf(`
+ GitHub Models CLI extension...
+ `, "`"),
+}
+
+// After
+cmd := &cobra.Command{
+ Use: "brainsait",
+ Short: "BrainSait AI Platform",
+ Long: heredoc.Docf(`
+ BrainSait AI Platform - Enterprise AI for Healthcare, Arabic Markets & Developers.
+
+ Powered by advanced language models with domain-specific optimizations.
+ `, "`"),
+}
+```
+
+---
+
+## 🎯 3. Domain-Specific Customizations
+
+### 3.1 Arabic Speakers Market 🌍
+
+**Create: `prompts/arabic/`**
+
+```yaml
+# prompts/arabic/medical_ar.prompt.yml
+name: "Arabic Medical Assistant"
+model: "openai/gpt-4o"
+messages:
+ - role: system
+ content: |
+ أنت مساعد طبي متخصص باللغة العربية.
+ قدم معلومات طبية دقيقة وواضحة.
+ استخدم المصطلحات الطبية العربية الفصحى.
+
+ - role: user
+ content: "{{query}}"
+testData:
+ - query: "ما هي أعراض مرض السكري؟"
+ - query: "كيف أتعامل مع ارتفاع ضغط الدم؟"
+```
+
+**Add RTL support in output:**
+
+```go
+// pkg/util/rtl.go
+package util
+
+import (
+ "strings"
+ "unicode"
+)
+
+func IsArabic(s string) bool {
+ for _, r := range s {
+ if unicode.Is(unicode.Arabic, r) {
+ return true
+ }
+ }
+ return false
+}
+
+func FormatRTL(s string) string {
+ if IsArabic(s) {
+ return "\u200F" + s + "\u200F" // RTL marks
+ }
+ return s
+}
+```
+
+### 3.2 Healthcare & Insurance 🏥
+
+**Create: `prompts/healthcare/`**
+
+```yaml
+# prompts/healthcare/insurance_claim.prompt.yml
+name: "Insurance Claim Analyzer"
+model: "openai/gpt-4o"
+messages:
+ - role: system
+ content: |
+ You are a healthcare insurance claims analyst.
+ Analyze claims for:
+ - Medical necessity
+ - Coding accuracy (ICD-10, CPT)
+ - Policy coverage alignment
+ - Potential fraud indicators
+
+ IMPORTANT: Never provide definitive coverage decisions.
+ Always recommend human review for final determination.
+
+ - role: user
+ content: |
+ Analyze this claim:
+ {{claim_details}}
+
+ Policy: {{policy_type}}
+testData:
+ - claim_details: "Emergency room visit, diagnosis: chest pain"
+ policy_type: "PPO Standard"
+```
+
+**HIPAA Compliance additions:**
+
+```go
+// internal/compliance/hipaa.go
+package compliance
+
+import (
+ "crypto/aes"
+ "log"
+)
+
+type AuditLog struct {
+ Timestamp time.Time
+ UserID string
+ Action string
+ DataAccessed string
+ IPAddress string
+}
+
+func LogPHIAccess(log AuditLog) error {
+ // Implement HIPAA-compliant audit logging
+}
+
+func SanitizePHI(input string) string {
+ // Remove/mask potential PHI before sending to external APIs
+}
+```
+
+### 3.3 Developer Tools 💻
+
+**Create: `prompts/developer/`**
+
+```yaml
+# prompts/developer/code_review.prompt.yml
+name: "Code Review Assistant"
+model: "openai/gpt-4o"
+messages:
+ - role: system
+ content: |
+ You are an expert code reviewer. Analyze code for:
+ - Security vulnerabilities
+ - Performance issues
+ - Best practices adherence
+ - Potential bugs
+
+ Provide specific, actionable feedback with examples.
+
+ - role: user
+ content: |
+ Review this {{language}} code:
+ ```{{language}}
+ {{code}}
+ ```
+testData:
+ - language: "go"
+ code: "func main() { fmt.Println(\"hello\") }"
+```
+
+---
+
+## 💰 4. Monetization Architecture
+
+### API Gateway Layer
+
+```go
+// cmd/api/main.go
+package main
+
+import (
+ "github.com/gin-gonic/gin"
+ "github.com/brainsait/platform/internal/billing"
+ "github.com/brainsait/platform/internal/auth"
+)
+
+func main() {
+ r := gin.Default()
+
+ // Middleware
+ r.Use(auth.APIKeyMiddleware())
+ r.Use(billing.UsageTracker())
+ r.Use(billing.RateLimiter())
+
+ // Routes
+ r.POST("/v1/chat", handlers.Chat)
+ r.POST("/v1/eval", handlers.Eval)
+ r.POST("/v1/generate", handlers.Generate)
+
+ // Admin
+ r.GET("/admin/usage", handlers.GetUsage)
+ r.GET("/admin/billing", handlers.GetBilling)
+
+ r.Run(":8080")
+}
+```
+
+### Billing Service
+
+```go
+// internal/billing/tracker.go
+package billing
+
+type UsageTier struct {
+ Name string
+ MonthlyCredits int
+ PricePerCredit float64
+ Features []string
+}
+
+var Tiers = map[string]UsageTier{
+ "free": {
+ Name: "Free",
+ MonthlyCredits: 100,
+ PricePerCredit: 0,
+ Features: []string{"basic_models", "community_support"},
+ },
+ "pro": {
+ Name: "Professional",
+ MonthlyCredits: 10000,
+ PricePerCredit: 0.001,
+ Features: []string{"all_models", "priority_support", "arabic_prompts"},
+ },
+ "enterprise": {
+ Name: "Enterprise",
+ MonthlyCredits: -1, // unlimited
+ PricePerCredit: 0,
+ Features: []string{"all_models", "dedicated_support", "custom_models", "hipaa", "on_premise"},
+ },
+}
+
+func TrackUsage(userID string, credits int) error {
+ // Track API usage against user's plan
+}
+```
+
+### Stripe Integration
+
+```go
+// internal/billing/stripe.go
+package billing
+
+import (
+ "github.com/stripe/stripe-go/v76"
+ "github.com/stripe/stripe-go/v76/subscription"
+)
+
+func CreateSubscription(customerID, priceID string) (*stripe.Subscription, error) {
+ params := &stripe.SubscriptionParams{
+ Customer: stripe.String(customerID),
+ Items: []*stripe.SubscriptionItemsParams{
+ {Price: stripe.String(priceID)},
+ },
+ }
+ return subscription.New(params)
+}
+```
+
+---
+
+## 📊 5. Database Schema
+
+```sql
+-- Users
+CREATE TABLE users (
+ id UUID PRIMARY KEY,
+ email VARCHAR(255) UNIQUE NOT NULL,
+ api_key VARCHAR(64) UNIQUE NOT NULL,
+ tier VARCHAR(50) DEFAULT 'free',
+ created_at TIMESTAMP DEFAULT NOW()
+);
+
+-- Usage tracking
+CREATE TABLE usage_logs (
+ id SERIAL PRIMARY KEY,
+ user_id UUID REFERENCES users(id),
+ endpoint VARCHAR(100),
+ credits_used INT,
+ model_used VARCHAR(100),
+ domain VARCHAR(50), -- 'arabic', 'healthcare', 'developer'
+ timestamp TIMESTAMP DEFAULT NOW()
+);
+
+-- Billing
+CREATE TABLE billing_records (
+ id SERIAL PRIMARY KEY,
+ user_id UUID REFERENCES users(id),
+ stripe_subscription_id VARCHAR(100),
+ amount_cents INT,
+ status VARCHAR(50),
+ period_start DATE,
+ period_end DATE
+);
+```
+
+---
+
+## 🚀 6. Quick Start
+
+### Step 1: Fork & Clone
+```bash
+gh repo fork github/gh-models --clone=true
+cd gh-models
+git remote rename origin upstream
+```
+
+### Step 2: Rebrand
+```bash
+# Update module name
+sed -i '' 's/github.com\/github\/gh-models/github.com\/brainsait\/platform/g' go.mod
+find . -name "*.go" -exec sed -i '' 's/github.com\/github\/gh-models/github.com\/brainsait\/platform/g' {} \;
+```
+
+### Step 3: Build Container
+```bash
+docker build -t brainsait-platform:latest .
+docker run -p 8080:8080 -e GITHUB_TOKEN=$GITHUB_TOKEN brainsait-platform:latest
+```
+
+### Step 4: Deploy
+```bash
+# Google Cloud Run
+gcloud run deploy brainsait-api --source . --region=me-central1
+
+# Or Kubernetes
+kubectl apply -f k8s/deployment.yaml
+```
+
+---
+
+## 📈 Revenue Projections
+
+| Vertical | Target Market Size | Year 1 Goal |
+|----------|-------------------|-------------|
+| Arabic Speakers | 400M+ speakers | 1,000 users |
+| Healthcare/Insurance | $4T industry | 50 enterprise clients |
+| Developers | 27M+ worldwide | 5,000 users |
+
+**Estimated ARR (Year 1):** $150K - $500K
+
+---
+
+## ⚠️ Important Considerations
+
+1. **Model Access**: GitHub Models is in preview; consider alternative model providers for production
+2. **Compliance**: Healthcare requires HIPAA BAA with model providers
+3. **Data Residency**: Arabic market may require local data hosting
+4. **Support**: Plan for Arabic-speaking support staff
+
+---
+
+## Next Steps
+
+1. [ ] Fork repository
+2. [ ] Create BrainSait organization on GitHub
+3. [ ] Set up cloud infrastructure
+4. [ ] Build MVP for one vertical first (recommend: Developers)
+5. [ ] Validate with beta customers
+6. [ ] Iterate and expand to other verticals
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 00000000..7e12440d
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,59 @@
+# BrainSait AI Platform - Production Dockerfile
+# Multi-stage build for minimal image size
+
+# ============================================
+# Stage 1: Build
+# ============================================
+FROM golang:1.23-alpine AS builder
+
+# Install build dependencies
+RUN apk add --no-cache git ca-certificates tzdata
+
+WORKDIR /app
+
+# Cache dependencies
+COPY go.mod go.sum ./
+RUN go mod download
+
+# Copy source code
+COPY . .
+
+# Build binary with optimizations
+RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \
+ -ldflags="-w -s -X main.version=$(git describe --tags --always)" \
+ -o brainsait-models \
+ main.go
+
+# ============================================
+# Stage 2: Runtime
+# ============================================
+FROM alpine:3.19
+
+# Security: run as non-root user
+RUN addgroup -g 1000 brainsait && \
+ adduser -u 1000 -G brainsait -s /bin/sh -D brainsait
+
+# Install runtime dependencies
+RUN apk --no-cache add ca-certificates tzdata
+
+WORKDIR /app
+
+# Copy binary from builder
+COPY --from=builder /app/brainsait-models .
+
+# Copy domain-specific prompts (if any)
+COPY --from=builder /app/examples ./prompts
+
+# Set ownership
+RUN chown -R brainsait:brainsait /app
+
+# Switch to non-root user
+USER brainsait
+
+# Health check
+HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
+ CMD ./brainsait-models list || exit 1
+
+# Default command
+ENTRYPOINT ["./brainsait-models"]
+CMD ["--help"]
diff --git a/Dockerfile.api b/Dockerfile.api
new file mode 100644
index 00000000..a9dfa686
--- /dev/null
+++ b/Dockerfile.api
@@ -0,0 +1,72 @@
+# BrainSait API Server Dockerfile
+# Multi-stage build for optimized production image
+
+# ================================
+# Stage 1: Build
+# ================================
+FROM golang:1.22-alpine AS builder
+
+# Install build dependencies
+RUN apk add --no-cache git ca-certificates tzdata
+
+WORKDIR /app
+
+# Copy go mod files
+COPY go.mod go.sum ./
+RUN go mod download
+
+# Copy source code
+COPY . .
+
+# Build CLI binary
+RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
+ go build -ldflags="-w -s" -o /app/bin/gh-models .
+
+# Build API server binary
+RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
+ go build -ldflags="-w -s" -o /app/bin/brainsait-api ./cmd/api
+
+# ================================
+# Stage 2: Production
+# ================================
+FROM alpine:3.19
+
+# Install runtime dependencies
+RUN apk add --no-cache ca-certificates tzdata curl wget
+
+# Create non-root user
+RUN addgroup -g 1000 brainsait && \
+ adduser -u 1000 -G brainsait -s /bin/sh -D brainsait
+
+WORKDIR /app
+
+# Copy binaries from builder
+COPY --from=builder /app/bin/gh-models /usr/local/bin/
+COPY --from=builder /app/bin/brainsait-api /usr/local/bin/
+
+# Copy example prompts
+COPY --from=builder /app/examples /app/examples
+
+# Copy i18n locales
+COPY --from=builder /app/internal/i18n/locales /app/locales
+
+# Set ownership
+RUN chown -R brainsait:brainsait /app
+
+# Switch to non-root user
+USER brainsait
+
+# Environment variables
+ENV PORT=8080
+ENV LOG_LEVEL=info
+ENV ENVIRONMENT=production
+
+# Expose API port
+EXPOSE 8080
+
+# Health check
+HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
+ CMD wget -q --spider http://localhost:8080/health || exit 1
+
+# Default command - run API server
+CMD ["brainsait-api"]
diff --git a/README.md b/README.md
index 9e06e0c9..a2fab279 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,17 @@ Use the GitHub Models service from the CLI!
This repository implements the GitHub Models CLI extension (`gh models`), enabling users to interact with AI models via the `gh` CLI. The extension supports inference, prompt evaluation, model listing, and test generation.
+### BrainSait AI Platform
+
+This repository also includes **BrainSait** - a complete AI platform for building domain-specific AI agents:
+
+- 🌍 **Arabic Assistant** - Multi-agent system for Arabic speakers (translation, writing, research)
+- 🏥 **Healthcare Insurance** - HIPAA-compliant claims analysis, prior auth, coding, appeals
+- 💻 **Developer Assistant** - Code review, architecture, debugging, testing, DevOps
+- 🔍 **SQL Analyst** - Natural language to SQL with data analysis
+
+See [compose-agents/](./compose-agents/) for Docker Compose-based multi-agent systems powered by [Docker Compose for Agents](https://github.com/docker/compose-for-agents).
+
## Using
### Prerequisites
diff --git a/agents/README.md b/agents/README.md
new file mode 100644
index 00000000..f6e3a6d1
--- /dev/null
+++ b/agents/README.md
@@ -0,0 +1,164 @@
+# BrainSait AI Agents
+
+Pre-built AI agents powered by [Docker cagent](https://github.com/docker/cagent) for specialized domains.
+
+## Quick Start
+
+### Install cagent
+
+```bash
+# macOS/Linux
+brew install docker/tap/cagent
+
+# Or download from releases
+curl -L https://github.com/docker/cagent/releases/latest/download/cagent-$(uname -s)-$(uname -m) -o cagent
+chmod +x cagent
+sudo mv cagent /usr/local/bin/
+```
+
+### Set up GitHub Token
+
+```bash
+export GITHUB_TOKEN=$(gh auth token)
+# Or use your personal access token
+export GITHUB_TOKEN=ghp_xxxxx
+```
+
+### Run an Agent
+
+```bash
+# Arabic Language Assistant
+cagent run agents/brainsait-arabic.yaml
+
+# Healthcare Insurance Analyst
+cagent run agents/brainsait-healthcare.yaml
+
+# Developer Assistant
+cagent run agents/brainsait-developer.yaml
+```
+
+## Available Agents
+
+### 🌍 Arabic Language Assistant (`brainsait-arabic.yaml`)
+
+Specialized AI assistant for Arabic speakers:
+- **Fluent Arabic** - Modern Standard Arabic and dialects
+- **Translation** - Arabic ↔ English translation
+- **Cultural awareness** - Respects Arab/Islamic culture
+- **Technical help** - Explains concepts in Arabic
+
+**Commands:**
+- `/translate` - Translate text to Arabic
+- `/explain` - Explain in Arabic
+- `/summarize` - Summarize content in Arabic
+
+### 🏥 Healthcare Insurance Analyst (`brainsait-healthcare.yaml`)
+
+HIPAA-aware assistant for healthcare insurance:
+- **Claims Analysis** - Review claims for completeness
+- **Prior Authorization** - PA requirements and documentation
+- **Medical Coding** - ICD-10, CPT, HCPCS verification
+- **Appeals Support** - Help with denial appeals
+
+**Commands:**
+- `/analyze-claim` - Analyze insurance claim
+- `/check-auth` - Check PA requirements
+- `/appeal-help` - Draft appeal letter
+- `/code-check` - Verify medical codes
+
+**Multi-agent team:**
+- `claims_analyst` - Claims processing specialist
+- `prior_auth_specialist` - Prior authorization expert
+- `coding_expert` - Medical coding specialist
+
+### 💻 Developer Assistant (`brainsait-developer.yaml`)
+
+AI development team for software engineering:
+- **Code Review** - Quality, security, performance
+- **Architecture** - System design and decisions
+- **Debugging** - Troubleshooting and fixes
+- **Testing** - Test generation and strategies
+- **DevOps** - CI/CD and deployment
+
+**Commands:**
+- `/review` - Review code
+- `/explain` - Explain code
+- `/refactor` - Suggest improvements
+- `/test` - Generate tests
+- `/doc` - Generate documentation
+
+**Multi-agent team:**
+- `code_reviewer` - Senior code reviewer
+- `architect` - Software architect
+- `debugger` - Debugging specialist
+- `tester` - QA engineer
+- `devops` - DevOps engineer
+
+## Integration with BrainSait API
+
+These agents use GitHub Models as the LLM provider, which integrates seamlessly with the BrainSait API:
+
+```yaml
+providers:
+ github:
+ type: openai
+ base_url: https://models.inference.ai.azure.com
+ api_key: ${GITHUB_TOKEN}
+```
+
+To use BrainSait API instead:
+
+```yaml
+providers:
+ brainsait:
+ type: openai
+ base_url: https://api.brainsait.ai/v1
+ api_key: ${BRAINSAIT_API_KEY}
+```
+
+## MCP Tools
+
+Agents use Docker MCP (Model Context Protocol) servers for extended capabilities:
+
+| Tool | Description |
+|------|-------------|
+| `docker:duckduckgo` | Web search |
+| `docker:github-official` | GitHub integration |
+| `docker:filesystem` | File operations |
+
+Configure MCP servers in Docker Desktop's MCP Toolkit.
+
+## Creating Custom Agents
+
+1. Copy an existing agent as template
+2. Modify the instruction and tools
+3. Test with `cagent run your-agent.yaml`
+4. Share via Git or Docker Hub
+
+Example minimal agent:
+
+```yaml
+agents:
+ root:
+ model: github-gpt4o
+ description: "My Custom Agent"
+ instruction: |
+ You are a helpful assistant specialized in...
+
+models:
+ github-gpt4o:
+ provider: github
+ model: openai/gpt-4o
+
+providers:
+ github:
+ type: openai
+ base_url: https://models.inference.ai.azure.com
+ api_key: ${GITHUB_TOKEN}
+```
+
+## Support
+
+- **Documentation**: https://docs.brainsait.ai/agents
+- **Issues**: https://github.com/github/gh-models/issues
+- **Discord**: https://discord.gg/brainsait
diff --git a/agents/brainsait-arabic.yaml b/agents/brainsait-arabic.yaml
new file mode 100644
index 00000000..edcc42d6
--- /dev/null
+++ b/agents/brainsait-arabic.yaml
@@ -0,0 +1,73 @@
+#!/usr/bin/env cagent run
+
+# BrainSait Arabic Language AI Agent
+# Specialized assistant for Arabic speakers
+
+agents:
+ root:
+ model: github-gpt4o
+ description: "مساعد ذكاء اصطناعي متخصص باللغة العربية - BrainSait Arabic Assistant"
+ instruction: |
+ أنت مساعد ذكاء اصطناعي متخصص يتحدث العربية الفصحى واللهجات المختلفة.
+
+ قواعد أساسية:
+ - تحدث دائماً باللغة العربية إلا إذا طلب المستخدم غير ذلك
+ - استخدم الأرقام العربية (١، ٢، ٣) عند الكتابة بالعربية
+ - احترم الثقافة العربية والإسلامية في ردودك
+ - كن مهذباً ومحترماً دائماً
+ - قدم معلومات دقيقة وموثوقة
+
+ You are a specialized AI assistant fluent in Modern Standard Arabic
+ and various Arabic dialects. You can help with:
+ - Translation between Arabic and English
+ - Arabic language learning
+ - Cultural questions about the Arab world
+ - Technical explanations in Arabic
+ - Document analysis and summarization
+
+ toolsets:
+ - type: mcp
+ ref: docker:duckduckgo
+ instruction: |
+ Use web search to find relevant Arabic content and resources.
+ Prefer Arabic language sources when available.
+
+ - type: mcp
+ ref: docker:github-official
+ instruction: |
+ Help users with GitHub repositories and code in Arabic.
+
+ commands:
+ translate: "ترجم النص التالي إلى العربية"
+ explain: "اشرح بالعربية"
+ summarize: "لخص المحتوى التالي بالعربية"
+
+ translator:
+ model: github-gpt4o
+ description: "مترجم متخصص - Arabic-English Translator"
+ instruction: |
+ أنت مترجم محترف متخصص في الترجمة بين العربية والإنجليزية.
+
+ قواعد الترجمة:
+ - حافظ على المعنى الأصلي
+ - استخدم مصطلحات دقيقة
+ - راعِ السياق الثقافي
+ - وضح المصطلحات التقنية عند الحاجة
+
+models:
+ github-gpt4o:
+ provider: github
+ model: openai/gpt-4o
+ max_tokens: 8192
+
+ github-gpt4o-mini:
+ provider: github
+ model: openai/gpt-4o-mini
+ max_tokens: 4096
+
+# Provider configurations
+providers:
+ github:
+ type: openai
+ base_url: https://models.inference.ai.azure.com
+ api_key: ${GITHUB_TOKEN}
diff --git a/agents/brainsait-developer.yaml b/agents/brainsait-developer.yaml
new file mode 100644
index 00000000..b6705e4f
--- /dev/null
+++ b/agents/brainsait-developer.yaml
@@ -0,0 +1,143 @@
+#!/usr/bin/env cagent run
+
+# BrainSait Developer Agent
+# Multi-agent development team for software engineering
+
+agents:
+ root:
+ model: github-gpt4o
+ description: "BrainSait Developer Assistant - Your AI Development Team"
+ instruction: |
+ You are the lead of an AI development team that helps developers with:
+ - Code review and analysis
+ - Architecture design and decisions
+ - Debugging and troubleshooting
+ - Documentation generation
+ - Testing and quality assurance
+ - DevOps and deployment
+
+ You can delegate tasks to specialized team members:
+ - code_reviewer: For in-depth code analysis
+ - architect: For system design questions
+ - debugger: For troubleshooting issues
+ - tester: For testing strategies
+ - devops: For CI/CD and deployment
+
+ Always provide practical, actionable advice with code examples when relevant.
+
+ toolsets:
+ - type: mcp
+ ref: docker:github-official
+ instruction: |
+ Access GitHub repositories, issues, PRs, and actions.
+ Use for code search, repo analysis, and GitHub operations.
+
+ - type: mcp
+ ref: docker:duckduckgo
+ instruction: |
+ Search for documentation, Stack Overflow answers, and best practices.
+
+ - type: mcp
+ ref: docker:filesystem
+ instruction: |
+ Read and analyze local code files.
+ tools: ["read_file", "write_file", "list_directory"]
+
+ commands:
+ review: "Review this code for issues and improvements"
+ explain: "Explain how this code works"
+ refactor: "Suggest refactoring for this code"
+ test: "Generate tests for this code"
+ doc: "Generate documentation for this code"
+
+ code_reviewer:
+ model: github-gpt4o
+ description: "Senior Code Reviewer"
+ instruction: |
+ You are a senior code reviewer with expertise in multiple languages.
+
+ When reviewing code, check for:
+ 1. Code quality and readability
+ 2. Potential bugs and edge cases
+ 3. Performance issues
+ 4. Security vulnerabilities
+ 5. Best practices and design patterns
+ 6. Test coverage gaps
+
+ Provide specific, actionable feedback with examples.
+ Rate severity: Critical, Major, Minor, Suggestion
+
+ architect:
+ model: github-gpt4o
+ description: "Software Architect"
+ instruction: |
+ You are a software architect with experience in:
+ - Microservices and distributed systems
+ - API design (REST, GraphQL, gRPC)
+ - Database design and optimization
+ - Cloud architecture (AWS, Azure, GCP)
+ - Scalability and performance
+
+ Provide architecture recommendations with:
+ - Clear diagrams (ASCII/Mermaid)
+ - Trade-off analysis
+ - Migration strategies
+ - Cost considerations
+
+ debugger:
+ model: github-gpt4o
+ description: "Debugging Specialist"
+ instruction: |
+ You are an expert debugger who helps identify and fix issues.
+
+ Debugging approach:
+ 1. Understand the expected vs actual behavior
+ 2. Identify potential root causes
+ 3. Suggest diagnostic steps
+ 4. Provide fix recommendations
+ 5. Explain how to prevent similar issues
+
+ Ask clarifying questions when needed.
+
+ tester:
+ model: github-gpt4o-mini
+ description: "QA and Testing Expert"
+ instruction: |
+ You are a QA engineer specializing in:
+ - Unit testing (Jest, pytest, Go testing)
+ - Integration testing
+ - E2E testing (Playwright, Cypress)
+ - Test-driven development
+ - Coverage analysis
+
+ Generate comprehensive test cases and explain testing strategies.
+
+ devops:
+ model: github-gpt4o-mini
+ description: "DevOps Engineer"
+ instruction: |
+ You are a DevOps engineer with expertise in:
+ - CI/CD pipelines (GitHub Actions, GitLab CI)
+ - Docker and Kubernetes
+ - Infrastructure as Code (Terraform, Pulumi)
+ - Monitoring and observability
+ - Security best practices
+
+ Help with deployment, automation, and infrastructure.
+
+models:
+ github-gpt4o:
+ provider: github
+ model: openai/gpt-4o
+ max_tokens: 8192
+
+ github-gpt4o-mini:
+ provider: github
+ model: openai/gpt-4o-mini
+ max_tokens: 4096
+
+providers:
+ github:
+ type: openai
+ base_url: https://models.inference.ai.azure.com
+ api_key: ${GITHUB_TOKEN}
diff --git a/agents/brainsait-healthcare.yaml b/agents/brainsait-healthcare.yaml
new file mode 100644
index 00000000..833ba116
--- /dev/null
+++ b/agents/brainsait-healthcare.yaml
@@ -0,0 +1,106 @@
+#!/usr/bin/env cagent run
+
+# BrainSait Healthcare Insurance Agent
+# HIPAA-aware assistant for healthcare insurance analysis
+
+agents:
+ root:
+ model: github-gpt4o
+ description: "BrainSait Healthcare Insurance Analyst - Claims and Prior Authorization Assistant"
+ instruction: |
+ You are a specialized healthcare insurance AI assistant designed to help with:
+ - Insurance claim analysis and processing
+ - Prior authorization requests and documentation
+ - Medical coding verification (ICD-10, CPT, HCPCS)
+ - Coverage determination and policy interpretation
+ - Appeals and denial management
+
+ IMPORTANT COMPLIANCE GUIDELINES:
+ - Never store or retain any PHI (Protected Health Information)
+ - Do not make final coverage decisions - only provide analysis
+ - Always recommend human review for complex cases
+ - Reference relevant regulations when applicable
+ - Maintain professional, objective tone
+
+ You have access to tools for document analysis and research.
+ Use them to provide accurate, well-researched responses.
+
+ toolsets:
+ - type: mcp
+ ref: docker:duckduckgo
+ instruction: |
+ Search for medical coding information, CMS guidelines,
+ payer policies, and clinical references.
+
+ - type: mcp
+ ref: docker:filesystem
+ instruction: |
+ Read and analyze uploaded claim documents and EOBs.
+ tools: ["read_file", "list_directory"]
+
+ commands:
+ analyze-claim: "Analyze this insurance claim for completeness and accuracy"
+ check-auth: "Review prior authorization requirements for this procedure"
+ appeal-help: "Help draft an appeal for this denied claim"
+ code-check: "Verify medical codes and suggest alternatives"
+
+ claims_analyst:
+ model: github-gpt4o
+ description: "Claims Processing Specialist"
+ instruction: |
+ You specialize in analyzing healthcare insurance claims.
+
+ For each claim, evaluate:
+ 1. Completeness of required fields
+ 2. Accuracy of diagnosis and procedure codes
+ 3. Medical necessity documentation
+ 4. Timely filing compliance
+ 5. Coordination of benefits issues
+
+ Provide a structured analysis with recommendations.
+
+ prior_auth_specialist:
+ model: github-gpt4o
+ description: "Prior Authorization Expert"
+ instruction: |
+ You are an expert in prior authorization requirements and processes.
+
+ Help users by:
+ 1. Identifying PA requirements for specific procedures
+ 2. Reviewing clinical documentation for adequacy
+ 3. Suggesting additional documentation if needed
+ 4. Explaining appeal options for denials
+
+ Reference CMS and major payer guidelines when applicable.
+
+ coding_expert:
+ model: github-gpt4o-mini
+ description: "Medical Coding Specialist"
+ instruction: |
+ You are a certified medical coding specialist (CPC/CCS equivalent).
+
+ Expertise areas:
+ - ICD-10-CM/PCS diagnosis and procedure codes
+ - CPT and HCPCS Level II codes
+ - Modifier usage and sequencing
+ - Medical necessity criteria
+ - Bundling and unbundling rules
+
+ Always cite coding guidelines and explain your reasoning.
+
+models:
+ github-gpt4o:
+ provider: github
+ model: openai/gpt-4o
+ max_tokens: 8192
+
+ github-gpt4o-mini:
+ provider: github
+ model: openai/gpt-4o-mini
+ max_tokens: 4096
+
+providers:
+ github:
+ type: openai
+ base_url: https://models.inference.ai.azure.com
+ api_key: ${GITHUB_TOKEN}
diff --git a/awesome-ospo.html b/awesome-ospo.html
new file mode 100644
index 00000000..ce4fadb4
--- /dev/null
+++ b/awesome-ospo.html
@@ -0,0 +1,3747 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ todogroup/awesome-ospo: Curated list of awesome tools for managing open source programs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ / ... /
+ todogroup /
+ awesome-ospo /
+
+
+
+
+
+
+ Clear Command Palette
+
+
+
+
+
+
+ Tip:
+ Type # to search pull requests
+
+
+ Type ? for help and tips
+
+
+
+
+
+
+ Tip:
+ Type # to search issues
+
+
+ Type ? for help and tips
+
+
+
+
+
+
+ Tip:
+ Type # to search discussions
+
+
+ Type ? for help and tips
+
+
+
+
+
+
+ Tip:
+ Type ! to search projects
+
+
+ Type ? for help and tips
+
+
+
+
+
+
+ Tip:
+ Type @ to search teams
+
+
+ Type ? for help and tips
+
+
+
+
+
+
+ Tip:
+ Type @ to search people and organizations
+
+
+ Type ? for help and tips
+
+
+
+
+
+
+ Tip:
+ Type > to activate command mode
+
+
+ Type ? for help and tips
+
+
+
+
+
+
+ Tip:
+ Go to your accessibility settings to change your keyboard shortcuts
+
+
+ Type ? for help and tips
+
+
+
+
+
+
+ Tip:
+ Type author:@me to search your content
+
+
+ Type ? for help and tips
+
+
+
+
+
+
+ Tip:
+ Type is:pr to filter to pull requests
+
+
+ Type ? for help and tips
+
+
+
+
+
+
+ Tip:
+ Type is:issue to filter to issues
+
+
+ Type ? for help and tips
+
+
+
+
+
+
+ Tip:
+ Type is:project to filter to projects
+
+
+ Type ? for help and tips
+
+
+
+
+
+
+ Tip:
+ Type is:open to filter to open content
+
+
+ Type ? for help and tips
+
+
+
+
+
+
+ We’ve encountered an error and some results aren't available at this time. Type a new search or try again later.
+
+
+
+ No results matched your search
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Search for issues and pull requests
+
+ #
+
+
+
+ Search for issues, pull requests, discussions, and projects
+
+ #
+
+
+
+ Search for organizations, repositories, and users
+
+ @
+
+
+
+ Search for projects
+
+ !
+
+
+
+ Search for files
+
+ /
+
+
+
+ Activate command mode
+
+ >
+
+
+
+ Search your issues, pull requests, and discussions
+
+ # author:@me
+
+
+
+ Search your issues, pull requests, and discussions
+
+ # author:@me
+
+
+
+ Filter to pull requests
+
+ # is:pr
+
+
+
+ Filter to issues
+
+ # is:issue
+
+
+
+ Filter to discussions
+
+ # is:discussion
+
+
+
+ Filter to projects
+
+ # is:project
+
+
+
+ Filter to open issues, pull requests, and discussions
+
+ # is:open
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ You can’t perform that action at this time.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cmd/api/main.go b/cmd/api/main.go
new file mode 100644
index 00000000..40194a4c
--- /dev/null
+++ b/cmd/api/main.go
@@ -0,0 +1,63 @@
+// Package main provides the HTTP API server for BrainSait AI Platform
+package main
+
+import (
+ "context"
+ "log"
+ "net/http"
+ "os"
+ "os/signal"
+ "syscall"
+ "time"
+
+ "github.com/github/gh-models/internal/api"
+ "github.com/github/gh-models/internal/billing"
+)
+
+func main() {
+ // Load configuration
+ cfg := api.LoadConfig()
+
+ // Initialize billing service
+ billingService := billing.NewService(cfg.StripeSecretKey, cfg.StripeWebhookSecret)
+
+ // Initialize API server
+ server := api.NewServer(cfg, billingService)
+
+ // Setup routes
+ router := server.SetupRoutes()
+
+ // Create HTTP server
+ srv := &http.Server{
+ Addr: ":" + cfg.Port,
+ Handler: router,
+ ReadTimeout: 30 * time.Second,
+ WriteTimeout: 60 * time.Second,
+ IdleTimeout: 120 * time.Second,
+ }
+
+ // Start server in goroutine
+ go func() {
+ log.Printf("🚀 BrainSait API Server starting on port %s", cfg.Port)
+ log.Printf("📍 Environment: %s", cfg.Environment)
+ if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
+ log.Fatalf("Failed to start server: %v", err)
+ }
+ }()
+
+ // Graceful shutdown
+ quit := make(chan os.Signal, 1)
+ signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
+ <-quit
+
+ log.Println("⏳ Shutting down server...")
+
+ ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
+ defer cancel()
+
+ if err := srv.Shutdown(ctx); err != nil {
+ log.Fatalf("Server forced to shutdown: %v", err)
+ }
+
+ log.Println("✅ Server stopped gracefully")
+}
diff --git a/compose-agents/README.md b/compose-agents/README.md
new file mode 100644
index 00000000..485fff86
--- /dev/null
+++ b/compose-agents/README.md
@@ -0,0 +1,245 @@
+# BrainSait Compose Agents
+
+Multi-agent AI systems built with [Docker Compose for Agents](https://github.com/docker/compose-for-agents).
+
+## Overview
+
+BrainSait provides pre-built, domain-specific AI agent systems that run locally using Docker Model Runner or in the cloud with OpenAI-compatible APIs.
+
+## Available Agent Systems
+
+| Agent System | Description | Framework | Models |
+|--------------|-------------|-----------|--------|
+| [Arabic Assistant](./arabic-assistant/) | Arabic language translation, writing, and research | Google ADK | qwen3 |
+| [Healthcare Insurance](./healthcare-insurance/) | Claims analysis, PA, coding, appeals | Google ADK | qwen3 |
+| [Developer Assistant](./developer-assistant/) | Code review, architecture, debugging, testing, DevOps | Google ADK | qwen3 |
+| [SQL Analyst](./sql-analyst/) | Natural language to SQL with data analysis | LangGraph | qwen3 |
+
+## Prerequisites
+
+- **Docker Desktop 4.43.0+** with Model Runner enabled
+- **GPU recommended** for running local models (or use [Docker Offload](https://www.docker.com/products/docker-offload/))
+- **MCP Toolkit** enabled in Docker Desktop settings
+
+## Quick Start
+
+### 1. Choose an Agent System
+
+```bash
+cd compose-agents/developer-assistant
+```
+
+### 2. Configure Secrets (if required)
+
+```bash
+# Copy example env file
+cp mcp.env.example .mcp.env
+
+# Edit with your tokens
+nano .mcp.env
+```
+
+### 3. Start the Agent System
+
+```bash
+docker compose up --build
+```
+
+### 4. Access the Web Interface
+
+Open [http://localhost:8080](http://localhost:8080) in your browser.
+
+## Using OpenAI Instead of Local Models
+
+To use OpenAI models instead of running locally:
+
+1. Create a secret file:
+
+```bash
+echo "sk-your-openai-key" > secret.openai-api-key
+```
+
+2. Start with OpenAI configuration:
+
+```bash
+docker compose -f compose.yaml -f compose.openai.yaml up
+```
+
+## Using GitHub Models
+
+To use GitHub Models as the LLM provider:
+
+```bash
+# Set your GitHub token
+export GITHUB_TOKEN=$(gh auth token)
+
+# Start with GitHub Models
+docker compose -f compose.yaml -f compose.github.yaml up
+```
+
+## Architecture
+
+```
+┌─────────────────────────────────────────────────────────────┐
+│ User Interface (Port 8080) │
+└─────────────────────────────────────────────────────────────┘
+ │
+ ▼
+┌─────────────────────────────────────────────────────────────┐
+│ Agent Framework │
+│ (Google ADK / LangGraph / CrewAI) │
+└─────────────────────────────────────────────────────────────┘
+ │
+ ┌───────────────┼───────────────┐
+ ▼ ▼ ▼
+ ┌──────────┐ ┌──────────┐ ┌──────────┐
+ │ Agent 1 │ │ Agent 2 │ │ Agent N │
+ └──────────┘ └──────────┘ └──────────┘
+ │ │ │
+ └───────────────┼───────────────┘
+ ▼
+┌─────────────────────────────────────────────────────────────┐
+│ MCP Gateway │
+│ (Tool orchestration & security) │
+└─────────────────────────────────────────────────────────────┘
+ │
+ ┌───────────────┼───────────────┐
+ ▼ ▼ ▼
+ ┌──────────┐ ┌──────────┐ ┌──────────┐
+ │ DuckDuck │ │ GitHub │ │ Postgres │
+ │ Go │ │ Official │ │ MCP │
+ └──────────┘ └──────────┘ └──────────┘
+ │
+ ▼
+┌─────────────────────────────────────────────────────────────┐
+│ Docker Model Runner │
+│ (Local LLM inference engine) │
+└─────────────────────────────────────────────────────────────┘
+```
+
+## Creating Custom Agent Systems
+
+### 1. Create Directory Structure
+
+```bash
+mkdir -p my-agent/agents
+```
+
+### 2. Create Agent Definition
+
+```python
+# my-agent/agents/agent.py
+from google.adk.agents import Agent
+
+root_agent = Agent(
+ name="my_agent",
+ description="My custom agent",
+ instruction="""You are a helpful assistant...""",
+ model="qwen3",
+)
+```
+
+### 3. Create Compose File
+
+```yaml
+# my-agent/compose.yaml
+services:
+ agent:
+ build: .
+ ports:
+ - 8080:8080
+ environment:
+ - MCP_SERVER_URL=http://mcp-gateway:8811/sse
+ depends_on:
+ - mcp-gateway
+ models:
+ qwen3:
+ endpoint_var: MODEL_RUNNER_URL
+ model_var: MODEL_RUNNER_MODEL
+
+ mcp-gateway:
+ image: docker/mcp-gateway:latest
+ use_api_socket: true
+ command:
+ - --transport=sse
+ - --servers=duckduckgo
+
+models:
+ qwen3:
+ model: ai/qwen3:14B-Q6_K
+```
+
+### 4. Create Dockerfile
+
+```dockerfile
+FROM python:3.12-slim
+WORKDIR /app
+RUN pip install google-adk httpx uvicorn
+COPY agents/ ./agents/
+CMD ["python", "-m", "google.adk.cli", "web", "--agents-dir", "agents", "--host", "0.0.0.0", "--port", "8080"]
+```
+
+### 5. Run Your Agent
+
+```bash
+cd my-agent
+docker compose up --build
+```
+
+## MCP Tools Reference
+
+| Server | Tools | Description |
+|--------|-------|-------------|
+| duckduckgo | search, fetch_content | Web search |
+| github-official | read_file, list_repos, search_code | GitHub integration |
+| filesystem | read_file, write_file, list_directory | File operations |
+| postgres | query | PostgreSQL database |
+| brave | search | Brave search engine |
+| wikipedia-mcp | search, get_article | Wikipedia access |
+
+## Integration with BrainSait CLI
+
+These agent systems complement the `gh models` CLI:
+
+```bash
+# Generate tests for your prompts
+gh models generate my-prompt.yml
+
+# Evaluate prompt performance
+gh models eval my-prompt.yml
+
+# Run inference
+gh models run my-prompt.yml
+```
+
+## Troubleshooting
+
+### Model Runner Not Starting
+
+Ensure Docker Desktop has Model Runner enabled:
+
+1. Open Docker Desktop settings
+2. Go to "Features in development"
+3. Enable "Docker Model Runner"
+
+### Out of Memory
+
+Reduce context size in compose.yaml:
+
+```yaml
+models:
+ qwen3:
+ model: ai/qwen3:4B-Q4_0 # Smaller model
+ context_size: 4096 # Smaller context
+```
+
+### MCP Gateway Connection Failed
+
+Check that MCP Toolkit is enabled in Docker Desktop:
+
+1. Settings → Features in development → Enable MCP Toolkit
+2. Restart Docker Desktop
+
+## License
+
+Apache 2.0 OR MIT (dual-licensed)
diff --git a/compose-agents/arabic-assistant/Dockerfile b/compose-agents/arabic-assistant/Dockerfile
new file mode 100644
index 00000000..c066adbd
--- /dev/null
+++ b/compose-agents/arabic-assistant/Dockerfile
@@ -0,0 +1,20 @@
+# BrainSait Arabic Assistant Agent
+FROM python:3.12-slim
+
+WORKDIR /app
+
+# Install dependencies
+RUN pip install --no-cache-dir \
+ google-adk \
+ httpx \
+ uvicorn
+
+# Copy agent code
+COPY agents/ ./agents/
+
+# Set environment
+ENV PYTHONUNBUFFERED=1
+ENV LANGUAGE=ar
+
+# Run the agent
+CMD ["python", "-m", "google.adk.cli", "web", "--agents-dir", "agents", "--host", "0.0.0.0", "--port", "8080"]
diff --git a/compose-agents/arabic-assistant/agents/__init__.py b/compose-agents/arabic-assistant/agents/__init__.py
new file mode 100644
index 00000000..d327e772
--- /dev/null
+++ b/compose-agents/arabic-assistant/agents/__init__.py
@@ -0,0 +1,4 @@
+# BrainSait Arabic Assistant Agents
+from .agent import root_agent
+
+__all__ = ["root_agent"]
diff --git a/compose-agents/arabic-assistant/agents/agent.py b/compose-agents/arabic-assistant/agents/agent.py
new file mode 100644
index 00000000..5e0ffc0d
--- /dev/null
+++ b/compose-agents/arabic-assistant/agents/agent.py
@@ -0,0 +1,75 @@
+"""BrainSait Arabic Language Assistant - Multi-Agent System"""
+
+from google.adk.agents import SequentialAgent, Agent
+
+# Arabic Translator Agent
+translator_agent = Agent(
+ name="translator",
+ description="Translates text between Arabic and English with cultural context",
+ instruction="""أنت مترجم محترف متخصص في الترجمة بين العربية والإنجليزية.
+
+مسؤولياتك:
+- ترجمة النصوص مع الحفاظ على المعنى والسياق الثقافي
+- التعامل مع اللهجات العربية المختلفة (المصرية، الخليجية، الشامية، المغاربية)
+- توضيح المصطلحات الثقافية عند الحاجة
+- الحفاظ على الأسلوب والنبرة الأصلية للنص
+
+قواعد الترجمة:
+1. استخدم العربية الفصحى المعاصرة
+2. احترم السياق الثقافي والديني
+3. وضح المصطلحات التي لا يمكن ترجمتها مباشرة
+4. قدم بدائل للعبارات الاصطلاحية""",
+ model="qwen3",
+)
+
+# Arabic Content Writer Agent
+writer_agent = Agent(
+ name="writer",
+ description="Creates high-quality Arabic content for various purposes",
+ instruction="""أنت كاتب محتوى عربي محترف.
+
+تخصصاتك:
+- كتابة المقالات والتقارير
+- إنشاء محتوى تسويقي
+- صياغة الرسائل الرسمية والتجارية
+- تحرير وتدقيق النصوص العربية
+
+أسلوبك:
+1. لغة عربية سليمة وفصيحة
+2. أسلوب واضح ومباشر
+3. مراعاة الجمهور المستهدف
+4. الالتزام بقواعد الكتابة العربية""",
+ model="qwen3",
+)
+
+# Arabic Research Agent
+researcher_agent = Agent(
+ name="researcher",
+ description="Researches topics and provides Arabic summaries",
+ instruction="""أنت باحث متخصص في جمع وتحليل المعلومات.
+
+مهامك:
+- البحث عن المعلومات من مصادر موثوقة
+- تلخيص المحتوى باللغة العربية
+- التحقق من صحة المعلومات
+- تقديم المراجع والمصادر
+
+منهجيتك:
+1. استخدم مصادر متعددة ومتنوعة
+2. ميز بين الحقائق والآراء
+3. قدم المعلومات بشكل منظم
+4. أشر إلى أي تحفظات أو قيود""",
+ model="qwen3",
+)
+
+# Main Arabic Assistant - Sequential Agent
+arabic_assistant = SequentialAgent(
+ name="arabic_assistant",
+ description=(
+ "مساعد عربي شامل يجمع بين الترجمة والكتابة والبحث "
+ "لخدمة المستخدمين الناطقين بالعربية"
+ ),
+ sub_agents=[translator_agent, writer_agent, researcher_agent],
+)
+
+root_agent = arabic_assistant
diff --git a/compose-agents/arabic-assistant/compose.github.yaml b/compose-agents/arabic-assistant/compose.github.yaml
new file mode 100644
index 00000000..5f9b7ef1
--- /dev/null
+++ b/compose-agents/arabic-assistant/compose.github.yaml
@@ -0,0 +1,12 @@
+# GitHub Models Configuration
+# Use this with: docker compose -f compose.yaml -f compose.github.yaml up
+
+services:
+ arabic-agent:
+ environment:
+ - MODEL_RUNNER_URL=https://models.inference.ai.azure.com
+ - MODEL_RUNNER_MODEL=openai/gpt-4o-mini
+ - GITHUB_TOKEN=${GITHUB_TOKEN}
+
+# Override to use GitHub Models instead of local Docker Model Runner
+# No local model needed when using GitHub Models API
diff --git a/compose-agents/arabic-assistant/compose.yaml b/compose-agents/arabic-assistant/compose.yaml
new file mode 100644
index 00000000..bda5bae0
--- /dev/null
+++ b/compose-agents/arabic-assistant/compose.yaml
@@ -0,0 +1,34 @@
+# BrainSait Arabic Language Assistant
+# Multi-agent system for Arabic speakers using Docker Model Runner
+
+services:
+ arabic-agent:
+ build:
+ context: .
+ ports:
+ - 8080:8080
+ environment:
+ - MCP_SERVER_URL=http://mcp-gateway:8811/sse
+ - LANGUAGE=ar
+ - CULTURE=arab
+ depends_on:
+ - mcp-gateway
+ models:
+ qwen3:
+ endpoint_var: MODEL_RUNNER_URL
+ model_var: MODEL_RUNNER_MODEL
+
+ mcp-gateway:
+ image: docker/mcp-gateway:latest
+ use_api_socket: true
+ command:
+ - --transport=sse
+ - --servers=duckduckgo,wikipedia-mcp
+ - --tools=search,fetch_content
+
+models:
+ qwen3:
+ model: ai/qwen3:14B-Q6_K
+ context_size: 8192
+ runtime_flags:
+ - --no-prefill-assistant
diff --git a/compose-agents/developer-assistant/Dockerfile b/compose-agents/developer-assistant/Dockerfile
new file mode 100644
index 00000000..efa13ddc
--- /dev/null
+++ b/compose-agents/developer-assistant/Dockerfile
@@ -0,0 +1,25 @@
+# BrainSait Developer Assistant
+FROM python:3.12-slim
+
+WORKDIR /app
+
+# Install system dependencies
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ git \
+ && rm -rf /var/lib/apt/lists/*
+
+# Install Python dependencies
+RUN pip install --no-cache-dir \
+ google-adk \
+ httpx \
+ uvicorn \
+ gitpython
+
+# Copy agent code
+COPY agents/ ./agents/
+
+# Set environment
+ENV PYTHONUNBUFFERED=1
+
+# Run the agent
+CMD ["python", "-m", "google.adk.cli", "web", "--agents-dir", "agents", "--host", "0.0.0.0", "--port", "8080"]
diff --git a/compose-agents/developer-assistant/agents/__init__.py b/compose-agents/developer-assistant/agents/__init__.py
new file mode 100644
index 00000000..b47a1801
--- /dev/null
+++ b/compose-agents/developer-assistant/agents/__init__.py
@@ -0,0 +1,4 @@
+# BrainSait Developer Assistant Agents
+from .agent import root_agent
+
+__all__ = ["root_agent"]
diff --git a/compose-agents/developer-assistant/agents/agent.py b/compose-agents/developer-assistant/agents/agent.py
new file mode 100644
index 00000000..f80f1ce0
--- /dev/null
+++ b/compose-agents/developer-assistant/agents/agent.py
@@ -0,0 +1,306 @@
+"""BrainSait Developer Assistant - Multi-Agent System"""
+
+from google.adk.agents import SequentialAgent, Agent
+
+# Code Reviewer Agent
+code_reviewer = Agent(
+ name="code_reviewer",
+ description="Senior code reviewer for quality, security, and best practices",
+ instruction="""You are a senior code reviewer with expertise in multiple programming languages.
+
+REVIEW FOCUS AREAS:
+1. Code Quality
+ - Clean code principles (SOLID, DRY, KISS)
+ - Naming conventions and readability
+ - Function/method complexity
+ - Error handling patterns
+
+2. Security
+ - Input validation
+ - SQL injection prevention
+ - XSS vulnerabilities
+ - Authentication/authorization issues
+ - Sensitive data exposure
+ - Dependency vulnerabilities
+
+3. Performance
+ - Algorithm efficiency
+ - Memory usage
+ - Database query optimization
+ - Caching opportunities
+ - Async/concurrent patterns
+
+4. Testing
+ - Test coverage
+ - Test quality and assertions
+ - Edge cases and error scenarios
+ - Mock usage
+
+REVIEW OUTPUT FORMAT:
+```
+## Code Review Summary
+
+### Critical Issues 🔴
+- [Issue description with line reference]
+
+### Warnings ⚠️
+- [Warning description]
+
+### Suggestions 💡
+- [Improvement suggestions]
+
+### Positive Aspects ✅
+- [Good practices observed]
+
+### Recommended Actions
+1. [Action item]
+```""",
+ model="qwen3",
+)
+
+# Software Architect Agent
+architect = Agent(
+ name="architect",
+ description="Software architect for system design and architecture decisions",
+ instruction="""You are a software architect with expertise in system design.
+
+ARCHITECTURE RESPONSIBILITIES:
+1. System Design
+ - Microservices vs monolith decisions
+ - Service boundaries and communication
+ - Data flow and state management
+ - API design (REST, GraphQL, gRPC)
+
+2. Technology Selection
+ - Language and framework recommendations
+ - Database choices (SQL, NoSQL, NewSQL)
+ - Message queues and event systems
+ - Cloud services and infrastructure
+
+3. Scalability & Reliability
+ - Horizontal vs vertical scaling
+ - Load balancing strategies
+ - Caching layers
+ - Disaster recovery planning
+
+4. Design Patterns
+ - Creational patterns (Factory, Builder, Singleton)
+ - Structural patterns (Adapter, Facade, Proxy)
+ - Behavioral patterns (Observer, Strategy, Command)
+ - Architectural patterns (MVC, CQRS, Event Sourcing)
+
+OUTPUT FORMAT:
+```
+## Architecture Recommendation
+
+### Problem Statement
+[Summary of the design challenge]
+
+### Proposed Solution
+[Architecture diagram description]
+
+### Components
+- [Component 1]: [Purpose]
+- [Component 2]: [Purpose]
+
+### Trade-offs
+- Pros: [Benefits]
+- Cons: [Drawbacks]
+
+### Implementation Roadmap
+1. [Phase 1]
+2. [Phase 2]
+```""",
+ model="qwen3",
+)
+
+# Debugging Specialist Agent
+debugger = Agent(
+ name="debugger",
+ description="Debugging specialist for troubleshooting and fixing issues",
+ instruction="""You are a debugging specialist with expertise in troubleshooting.
+
+DEBUGGING METHODOLOGY:
+1. Reproduce the Issue
+ - Identify exact steps to reproduce
+ - Note environment conditions
+ - Gather error messages and stack traces
+
+2. Isolate the Problem
+ - Binary search through code changes
+ - Add logging/breakpoints strategically
+ - Check recent changes in git history
+ - Test with minimal reproduction case
+
+3. Analyze Root Cause
+ - Trace execution flow
+ - Examine variable states
+ - Check boundary conditions
+ - Review external dependencies
+
+4. Fix and Verify
+ - Implement targeted fix
+ - Add regression tests
+ - Verify in all affected scenarios
+ - Document the fix
+
+COMMON BUG PATTERNS:
+- Off-by-one errors
+- Null/undefined references
+- Race conditions
+- Memory leaks
+- Incorrect type handling
+- API contract violations
+
+OUTPUT FORMAT:
+```
+## Bug Analysis
+
+### Issue Description
+[What's happening vs expected behavior]
+
+### Root Cause
+[Identified cause with evidence]
+
+### Suggested Fix
+```language
+[Code fix]
+```
+
+### Testing Recommendation
+[How to verify the fix]
+```""",
+ model="qwen3",
+)
+
+# Test Engineer Agent
+tester = Agent(
+ name="tester",
+ description="QA engineer for test generation and testing strategies",
+ instruction="""You are a QA engineer with expertise in software testing.
+
+TESTING RESPONSIBILITIES:
+1. Unit Testing
+ - Test individual functions/methods
+ - Mock external dependencies
+ - Cover edge cases and error paths
+ - Achieve high code coverage
+
+2. Integration Testing
+ - Test component interactions
+ - API endpoint testing
+ - Database integration tests
+ - Service-to-service communication
+
+3. E2E Testing
+ - User journey testing
+ - Cross-browser compatibility
+ - Mobile responsiveness
+ - Performance under load
+
+4. Test Design
+ - Boundary value analysis
+ - Equivalence partitioning
+ - Decision table testing
+ - State transition testing
+
+TESTING BEST PRACTICES:
+- AAA pattern (Arrange, Act, Assert)
+- One assertion per test (when practical)
+- Descriptive test names
+- Independent and isolated tests
+- Fast execution time
+
+OUTPUT FORMAT:
+```
+## Test Plan
+
+### Test Scope
+[What's being tested]
+
+### Test Cases
+| ID | Description | Input | Expected Output |
+|----|-------------|-------|-----------------|
+| T1 | [Name] | [In] | [Out] |
+
+### Generated Test Code
+```language
+[Test implementation]
+```
+```""",
+ model="qwen3",
+)
+
+# DevOps Engineer Agent
+devops = Agent(
+ name="devops",
+ description="DevOps engineer for CI/CD, deployment, and infrastructure",
+ instruction="""You are a DevOps engineer with expertise in CI/CD and infrastructure.
+
+DEVOPS RESPONSIBILITIES:
+1. CI/CD Pipelines
+ - Build automation
+ - Test automation
+ - Deployment automation
+ - Release management
+
+2. Infrastructure as Code
+ - Terraform/Pulumi
+ - Docker/Kubernetes
+ - Cloud formation
+ - Ansible/Chef/Puppet
+
+3. Monitoring & Observability
+ - Metrics collection (Prometheus)
+ - Log aggregation (ELK, Loki)
+ - Distributed tracing (Jaeger)
+ - Alerting (PagerDuty, OpsGenie)
+
+4. Security & Compliance
+ - Secret management
+ - Network security
+ - Access control
+ - Compliance automation
+
+DEPLOYMENT STRATEGIES:
+- Blue-green deployment
+- Canary releases
+- Rolling updates
+- Feature flags
+
+OUTPUT FORMAT:
+```
+## DevOps Recommendation
+
+### Current State
+[Assessment of current setup]
+
+### Proposed Solution
+
+#### Pipeline Configuration
+```yaml
+[CI/CD config]
+```
+
+#### Infrastructure Code
+```hcl
+[IaC snippet]
+```
+
+### Monitoring Setup
+[Observability recommendations]
+```""",
+ model="qwen3",
+)
+
+# Main Developer Assistant - Sequential Agent
+developer_assistant = SequentialAgent(
+ name="developer_assistant",
+ description=(
+ "Comprehensive developer assistant combining code review, architecture, "
+ "debugging, testing, and DevOps expertise for complete software development lifecycle support"
+ ),
+ sub_agents=[code_reviewer, architect, debugger, tester, devops],
+)
+
+root_agent = developer_assistant
diff --git a/compose-agents/developer-assistant/compose.github.yaml b/compose-agents/developer-assistant/compose.github.yaml
new file mode 100644
index 00000000..9f71446f
--- /dev/null
+++ b/compose-agents/developer-assistant/compose.github.yaml
@@ -0,0 +1,9 @@
+# GitHub Models Configuration
+# Use with: docker compose -f compose.yaml -f compose.github.yaml up
+
+services:
+ developer-agent:
+ environment:
+ - MODEL_RUNNER_URL=https://models.inference.ai.azure.com
+ - MODEL_RUNNER_MODEL=openai/gpt-4o-mini
+ - GITHUB_TOKEN=${GITHUB_TOKEN}
diff --git a/compose-agents/developer-assistant/compose.yaml b/compose-agents/developer-assistant/compose.yaml
new file mode 100644
index 00000000..7e8ba2c6
--- /dev/null
+++ b/compose-agents/developer-assistant/compose.yaml
@@ -0,0 +1,42 @@
+# BrainSait Developer Assistant
+# Multi-agent system for software development
+
+services:
+ developer-agent:
+ build:
+ context: .
+ ports:
+ - 8080:8080
+ environment:
+ - MCP_SERVER_URL=http://mcp-gateway:8811/sse
+ depends_on:
+ - mcp-gateway
+ volumes:
+ - ./workspace:/workspace
+ models:
+ qwen3:
+ endpoint_var: MODEL_RUNNER_URL
+ model_var: MODEL_RUNNER_MODEL
+
+ mcp-gateway:
+ image: docker/mcp-gateway:latest
+ use_api_socket: true
+ command:
+ - --transport=sse
+ - --servers=github-official,filesystem,duckduckgo
+ - --tools=search,read_file,write_file,list_directory
+ secrets:
+ - github-token
+ environment:
+ - GITHUB_PERSONAL_ACCESS_TOKEN_FILE=/run/secrets/github-token
+
+models:
+ qwen3:
+ model: ai/qwen3:14B-Q6_K
+ context_size: 32768
+ runtime_flags:
+ - --no-prefill-assistant
+
+secrets:
+ github-token:
+ file: ./github_token
diff --git a/compose-agents/developer-assistant/github_token b/compose-agents/developer-assistant/github_token
new file mode 100644
index 00000000..1aca2697
--- /dev/null
+++ b/compose-agents/developer-assistant/github_token
@@ -0,0 +1,2 @@
+# Add your GitHub personal access token here
+# Get one from: https://github.com/settings/tokens
diff --git a/compose-agents/healthcare-insurance/Dockerfile b/compose-agents/healthcare-insurance/Dockerfile
new file mode 100644
index 00000000..2f4ea540
--- /dev/null
+++ b/compose-agents/healthcare-insurance/Dockerfile
@@ -0,0 +1,21 @@
+# BrainSait Healthcare Insurance Analyst
+FROM python:3.12-slim
+
+WORKDIR /app
+
+# Install dependencies
+RUN pip install --no-cache-dir \
+ google-adk \
+ httpx \
+ uvicorn \
+ psycopg2-binary
+
+# Copy agent code
+COPY agents/ ./agents/
+
+# Set environment
+ENV PYTHONUNBUFFERED=1
+ENV HIPAA_COMPLIANT=true
+
+# Run the agent
+CMD ["python", "-m", "google.adk.cli", "web", "--agents-dir", "agents", "--host", "0.0.0.0", "--port", "8080"]
diff --git a/compose-agents/healthcare-insurance/agents/__init__.py b/compose-agents/healthcare-insurance/agents/__init__.py
new file mode 100644
index 00000000..78afab98
--- /dev/null
+++ b/compose-agents/healthcare-insurance/agents/__init__.py
@@ -0,0 +1,4 @@
+# BrainSait Healthcare Insurance Agents
+from .agent import root_agent
+
+__all__ = ["root_agent"]
diff --git a/compose-agents/healthcare-insurance/agents/agent.py b/compose-agents/healthcare-insurance/agents/agent.py
new file mode 100644
index 00000000..3c04d4dd
--- /dev/null
+++ b/compose-agents/healthcare-insurance/agents/agent.py
@@ -0,0 +1,169 @@
+"""BrainSait Healthcare Insurance Analyst - Multi-Agent System"""
+
+from google.adk.agents import SequentialAgent, Agent
+
+# Claims Analyst Agent
+claims_analyst = Agent(
+ name="claims_analyst",
+ description="Analyzes healthcare insurance claims for completeness and accuracy",
+ instruction="""You are a healthcare insurance claims analyst with expertise in:
+
+RESPONSIBILITIES:
+- Review claims for completeness and required documentation
+- Verify patient eligibility and coverage
+- Identify potential issues before processing
+- Ensure compliance with payer guidelines
+
+HIPAA COMPLIANCE:
+- Never expose PHI (Protected Health Information) unnecessarily
+- Use minimum necessary standard for all data access
+- Log all access to patient records
+- Report any potential HIPAA violations
+
+CLAIM REVIEW CHECKLIST:
+1. Patient demographics and eligibility verification
+2. Provider credentialing status
+3. Service codes (CPT, ICD-10, HCPCS) validation
+4. Medical necessity documentation
+5. Prior authorization requirements
+6. Timely filing compliance
+7. Coordination of benefits check
+
+OUTPUT FORMAT:
+- Claim Status: [APPROVED/PENDING/DENIED/NEEDS_REVIEW]
+- Issues Found: [List any problems]
+- Required Actions: [Next steps]
+- Compliance Notes: [Any regulatory concerns]""",
+ model="qwen3",
+)
+
+# Prior Authorization Specialist Agent
+prior_auth_specialist = Agent(
+ name="prior_auth_specialist",
+ description="Handles prior authorization requirements and documentation",
+ instruction="""You are a prior authorization specialist with expertise in:
+
+RESPONSIBILITIES:
+- Determine prior authorization requirements for services
+- Gather and organize required documentation
+- Track authorization status and deadlines
+- Communicate with providers about PA requirements
+
+PA WORKFLOW:
+1. Check if service requires prior authorization
+2. Verify current authorization status
+3. Identify required clinical documentation
+4. Review medical necessity criteria
+5. Submit authorization request
+6. Track and follow up on pending requests
+
+COMMON PA REQUIREMENTS:
+- Advanced imaging (MRI, CT, PET)
+- Specialty medications
+- Durable medical equipment
+- Surgical procedures
+- Specialty referrals
+- Genetic testing
+
+OUTPUT FORMAT:
+- PA Required: [YES/NO]
+- Authorization Status: [APPROVED/PENDING/DENIED/NOT_SUBMITTED]
+- Required Documentation: [List]
+- Deadline: [Date if applicable]
+- Next Steps: [Actions needed]""",
+ model="qwen3",
+)
+
+# Medical Coding Expert Agent
+coding_expert = Agent(
+ name="coding_expert",
+ description="Validates and optimizes medical coding for claims",
+ instruction="""You are a certified medical coding expert with expertise in:
+
+CODING SYSTEMS:
+- ICD-10-CM/PCS (Diagnosis codes)
+- CPT (Procedure codes)
+- HCPCS (Healthcare Common Procedure Coding System)
+- DRG (Diagnosis Related Groups)
+- Revenue codes
+
+RESPONSIBILITIES:
+- Validate code accuracy and specificity
+- Identify coding errors and omissions
+- Suggest compliant code optimizations
+- Ensure documentation supports codes
+- Check modifier usage
+
+CODING COMPLIANCE:
+- Never suggest upcoding or unbundling
+- Ensure codes match documentation
+- Follow LCD/NCD requirements
+- Apply correct modifiers
+- Check bundling edits (NCCI)
+
+OUTPUT FORMAT:
+- Code Review Status: [VALID/INVALID/NEEDS_REVIEW]
+- Issues Found: [List coding problems]
+- Suggested Corrections: [If applicable]
+- Documentation Notes: [Support requirements]""",
+ model="qwen3",
+)
+
+# Appeals Specialist Agent
+appeals_specialist = Agent(
+ name="appeals_specialist",
+ description="Handles claim denials and appeals process",
+ instruction="""You are a healthcare appeals specialist with expertise in:
+
+RESPONSIBILITIES:
+- Review denial reasons and determine appeal strategy
+- Gather supporting documentation for appeals
+- Draft appeal letters with proper argumentation
+- Track appeal deadlines and status
+- Analyze denial patterns for process improvement
+
+APPEAL LEVELS:
+1. First-level appeal (internal review)
+2. Second-level appeal (external review)
+3. Independent external review
+4. State insurance department complaint
+5. Legal action (if necessary)
+
+COMMON DENIAL REASONS:
+- Medical necessity not established
+- Prior authorization not obtained
+- Service not covered
+- Out-of-network provider
+- Timely filing exceeded
+- Duplicate claim
+- Coding errors
+
+APPEAL LETTER STRUCTURE:
+1. Patient and claim identification
+2. Denial reason being appealed
+3. Medical necessity justification
+4. Supporting clinical documentation
+5. Relevant policy citations
+6. Requested action
+
+OUTPUT FORMAT:
+- Appeal Recommendation: [YES/NO]
+- Appeal Level: [1st/2nd/External]
+- Key Arguments: [List]
+- Required Documentation: [List]
+- Deadline: [Date]""",
+ model="qwen3",
+)
+
+# Main Healthcare Analyst - Sequential Agent
+healthcare_analyst = SequentialAgent(
+ name="healthcare_analyst",
+ description=(
+ "Comprehensive healthcare insurance analyst that combines claims analysis, "
+ "prior authorization, medical coding, and appeals expertise to provide "
+ "complete claim lifecycle management"
+ ),
+ sub_agents=[claims_analyst, prior_auth_specialist, coding_expert, appeals_specialist],
+)
+
+root_agent = healthcare_analyst
diff --git a/compose-agents/healthcare-insurance/compose.github.yaml b/compose-agents/healthcare-insurance/compose.github.yaml
new file mode 100644
index 00000000..fd1cf351
--- /dev/null
+++ b/compose-agents/healthcare-insurance/compose.github.yaml
@@ -0,0 +1,9 @@
+# GitHub Models Configuration
+# Use with: docker compose -f compose.yaml -f compose.github.yaml up
+
+services:
+ healthcare-agent:
+ environment:
+ - MODEL_RUNNER_URL=https://models.inference.ai.azure.com
+ - MODEL_RUNNER_MODEL=openai/gpt-4o-mini
+ - GITHUB_TOKEN=${GITHUB_TOKEN}
diff --git a/compose-agents/healthcare-insurance/compose.yaml b/compose-agents/healthcare-insurance/compose.yaml
new file mode 100644
index 00000000..d67a1a9a
--- /dev/null
+++ b/compose-agents/healthcare-insurance/compose.yaml
@@ -0,0 +1,58 @@
+# BrainSait Healthcare Insurance Analyst
+# Multi-agent system for healthcare claims processing
+
+services:
+ healthcare-agent:
+ build:
+ context: .
+ ports:
+ - 8080:8080
+ environment:
+ - MCP_SERVER_URL=http://mcp-gateway:8811/sse
+ - HIPAA_COMPLIANT=true
+ depends_on:
+ - mcp-gateway
+ - database
+ models:
+ qwen3:
+ endpoint_var: MODEL_RUNNER_URL
+ model_var: MODEL_RUNNER_MODEL
+
+ database:
+ image: postgres:16-alpine
+ environment:
+ POSTGRES_USER: healthcare
+ POSTGRES_PASSWORD: secure_password
+ POSTGRES_DB: claims
+ volumes:
+ - healthcare_data:/var/lib/postgresql/data
+ healthcheck:
+ test: [CMD-SHELL, pg_isready -U healthcare -d claims]
+ interval: 5s
+ timeout: 3s
+ retries: 10
+
+ mcp-gateway:
+ image: docker/mcp-gateway:latest
+ use_api_socket: true
+ command:
+ - --transport=sse
+ - --secrets=/run/secrets/database-url
+ - --servers=postgres,duckduckgo
+ - --tools=query,search
+ secrets:
+ - database-url
+
+models:
+ qwen3:
+ model: ai/qwen3:14B-Q6_K
+ context_size: 16384
+ runtime_flags:
+ - --no-prefill-assistant
+
+secrets:
+ database-url:
+ file: ./postgres_url
+
+volumes:
+ healthcare_data:
diff --git a/compose-agents/healthcare-insurance/postgres_url b/compose-agents/healthcare-insurance/postgres_url
new file mode 100644
index 00000000..ffcac169
--- /dev/null
+++ b/compose-agents/healthcare-insurance/postgres_url
@@ -0,0 +1 @@
+postgres://healthcare:secure_password@database:5432/claims
\ No newline at end of file
diff --git a/compose-agents/sql-analyst/Dockerfile b/compose-agents/sql-analyst/Dockerfile
new file mode 100644
index 00000000..e38e9c1a
--- /dev/null
+++ b/compose-agents/sql-analyst/Dockerfile
@@ -0,0 +1,17 @@
+# BrainSait SQL Analyst
+FROM python:3.12-slim
+
+WORKDIR /app
+
+RUN pip install --no-cache-dir \
+ langgraph \
+ langchain-core \
+ httpx \
+ uvicorn \
+ psycopg2-binary
+
+COPY agent.py ./
+
+ENV PYTHONUNBUFFERED=1
+
+CMD ["python", "agent.py"]
diff --git a/compose-agents/sql-analyst/agent.py b/compose-agents/sql-analyst/agent.py
new file mode 100644
index 00000000..13c09307
--- /dev/null
+++ b/compose-agents/sql-analyst/agent.py
@@ -0,0 +1,248 @@
+"""BrainSait SQL Analyst - LangGraph Agent for Natural Language to SQL"""
+
+import os
+import json
+from typing import TypedDict, Annotated, Sequence
+from langgraph.graph import StateGraph, END
+from langchain_core.messages import HumanMessage, AIMessage, BaseMessage
+import httpx
+import uvicorn
+from fastapi import FastAPI, Request
+from fastapi.responses import HTMLResponse, JSONResponse
+from fastapi.staticfiles import StaticFiles
+
+# State definition
+class AgentState(TypedDict):
+ messages: Annotated[Sequence[BaseMessage], lambda x, y: x + y]
+ question: str
+ sql_query: str
+ query_result: str
+ final_answer: str
+
+
+# LLM client
+class LLMClient:
+ def __init__(self):
+ self.base_url = os.environ.get("MODEL_RUNNER_URL", "http://localhost:8080/v1")
+ self.model = os.environ.get("MODEL_RUNNER_MODEL", "ai/qwen3:14B-Q6_K")
+
+ async def chat(self, messages: list[dict], system_prompt: str = None) -> str:
+ async with httpx.AsyncClient() as client:
+ payload = {
+ "model": self.model,
+ "messages": messages,
+ "temperature": 0.1,
+ }
+ if system_prompt:
+ payload["messages"] = [{"role": "system", "content": system_prompt}] + payload["messages"]
+
+ response = await client.post(
+ f"{self.base_url}/chat/completions",
+ json=payload,
+ timeout=120.0
+ )
+ response.raise_for_status()
+ return response.json()["choices"][0]["message"]["content"]
+
+
+# MCP client for database queries
+class MCPClient:
+ def __init__(self):
+ self.mcp_url = os.environ.get("MCP_SERVER_URL", "http://mcp-gateway:8811/sse")
+
+ async def query(self, sql: str) -> str:
+ async with httpx.AsyncClient() as client:
+ response = await client.post(
+ self.mcp_url.replace("/sse", "/tools/query"),
+ json={"sql": sql},
+ timeout=60.0
+ )
+ if response.status_code == 200:
+ return json.dumps(response.json(), indent=2)
+ return f"Error: {response.text}"
+
+
+llm = LLMClient()
+mcp = MCPClient()
+
+
+# Agent nodes
+async def understand_question(state: AgentState) -> dict:
+ """Understand the user's question and identify required data."""
+ system_prompt = """You are a SQL expert. Analyze the user's question and identify:
+1. What data they're looking for
+2. What tables might be relevant
+3. Any filters or aggregations needed
+
+Respond with a brief analysis."""
+
+ messages = [{"role": "user", "content": state["question"]}]
+ response = await llm.chat(messages, system_prompt)
+
+ return {
+ "messages": [AIMessage(content=f"Analysis: {response}")]
+ }
+
+
+async def generate_sql(state: AgentState) -> dict:
+ """Generate SQL query based on the question."""
+ system_prompt = """You are a SQL expert for PostgreSQL. Generate a SQL query to answer the user's question.
+
+Rules:
+- Use only SELECT statements (no INSERT, UPDATE, DELETE)
+- Include appropriate JOINs if needed
+- Add LIMIT 100 to prevent large result sets
+- Format the query nicely
+
+Respond with ONLY the SQL query, no explanation."""
+
+ messages = [{"role": "user", "content": state["question"]}]
+ sql_query = await llm.chat(messages, system_prompt)
+
+ # Clean up the query
+ sql_query = sql_query.strip()
+ if sql_query.startswith("```"):
+ sql_query = sql_query.split("```")[1]
+ if sql_query.startswith("sql"):
+ sql_query = sql_query[3:]
+ sql_query = sql_query.strip()
+
+ return {
+ "sql_query": sql_query,
+ "messages": [AIMessage(content=f"Generated SQL:\n```sql\n{sql_query}\n```")]
+ }
+
+
+async def execute_query(state: AgentState) -> dict:
+ """Execute the SQL query against the database."""
+ result = await mcp.query(state["sql_query"])
+
+ return {
+ "query_result": result,
+ "messages": [AIMessage(content=f"Query Result:\n{result}")]
+ }
+
+
+async def generate_answer(state: AgentState) -> dict:
+ """Generate a natural language answer from the query results."""
+ system_prompt = """You are a data analyst. Given the user's question and the query results,
+provide a clear, natural language answer. Include relevant numbers and insights."""
+
+ messages = [
+ {"role": "user", "content": f"Question: {state['question']}\n\nQuery Results:\n{state['query_result']}"}
+ ]
+ answer = await llm.chat(messages, system_prompt)
+
+ return {
+ "final_answer": answer,
+ "messages": [AIMessage(content=answer)]
+ }
+
+
+# Build the graph
+def build_graph():
+ workflow = StateGraph(AgentState)
+
+ workflow.add_node("understand", understand_question)
+ workflow.add_node("generate_sql", generate_sql)
+ workflow.add_node("execute", execute_query)
+ workflow.add_node("answer", generate_answer)
+
+ workflow.set_entry_point("understand")
+ workflow.add_edge("understand", "generate_sql")
+ workflow.add_edge("generate_sql", "execute")
+ workflow.add_edge("execute", "answer")
+ workflow.add_edge("answer", END)
+
+ return workflow.compile()
+
+
+# FastAPI app
+app = FastAPI(title="BrainSait SQL Analyst")
+graph = build_graph()
+
+
+@app.get("/", response_class=HTMLResponse)
+async def index():
+ return """
+
+
+
+ BrainSait SQL Analyst
+
+
+
+ 🔍 BrainSait SQL Analyst
+ Ask questions about your data in natural language.
+
+
+
+ Ask
+
+
+
+
+
+
+
+ """
+
+
+@app.post("/query")
+async def query(request: Request):
+ data = await request.json()
+ question = data.get("question", "")
+
+ initial_state = {
+ "messages": [HumanMessage(content=question)],
+ "question": question,
+ "sql_query": "",
+ "query_result": "",
+ "final_answer": ""
+ }
+
+ result = await graph.ainvoke(initial_state)
+
+ return JSONResponse({
+ "question": question,
+ "sql_query": result["sql_query"],
+ "result": result["query_result"],
+ "answer": result["final_answer"]
+ })
+
+
+if __name__ == "__main__":
+ uvicorn.run(app, host="0.0.0.0", port=8080)
diff --git a/compose-agents/sql-analyst/compose.github.yaml b/compose-agents/sql-analyst/compose.github.yaml
new file mode 100644
index 00000000..f9b4b0b3
--- /dev/null
+++ b/compose-agents/sql-analyst/compose.github.yaml
@@ -0,0 +1,9 @@
+# GitHub Models Configuration
+# Use with: docker compose -f compose.yaml -f compose.github.yaml up
+
+services:
+ agent:
+ environment:
+ - MODEL_RUNNER_URL=https://models.inference.ai.azure.com
+ - MODEL_RUNNER_MODEL=openai/gpt-4o-mini
+ - GITHUB_TOKEN=${GITHUB_TOKEN}
diff --git a/compose-agents/sql-analyst/compose.yaml b/compose-agents/sql-analyst/compose.yaml
new file mode 100644
index 00000000..5fd17c2f
--- /dev/null
+++ b/compose-agents/sql-analyst/compose.yaml
@@ -0,0 +1,58 @@
+# BrainSait SQL Analyst
+# LangGraph-based natural language to SQL agent
+
+services:
+ database:
+ image: postgres:16-alpine
+ environment:
+ POSTGRES_USER: analyst
+ POSTGRES_PASSWORD: analyst_password
+ POSTGRES_DB: analytics
+ volumes:
+ - ./init.sql:/docker-entrypoint-initdb.d/init.sql
+ - analytics_data:/var/lib/postgresql/data
+ healthcheck:
+ test: [CMD-SHELL, pg_isready -U analyst -d analytics]
+ interval: 5s
+ timeout: 3s
+ retries: 10
+
+ agent:
+ build: .
+ ports:
+ - 8080:8080
+ environment:
+ - MCP_SERVER_URL=http://mcp-gateway:8811/sse
+ - DATABASE_DIALECT=PostgreSQL
+ depends_on:
+ database:
+ condition: service_healthy
+ mcp-gateway:
+ condition: service_started
+ models:
+ qwen3:
+ endpoint_var: MODEL_RUNNER_URL
+ model_var: MODEL_RUNNER_MODEL
+
+ mcp-gateway:
+ image: docker/mcp-gateway:latest
+ use_api_socket: true
+ command:
+ - --transport=sse
+ - --secrets=/run/secrets/database-url
+ - --servers=postgres
+ - --tools=query
+ secrets:
+ - database-url
+
+models:
+ qwen3:
+ model: ai/qwen3:14B-Q6_K
+ context_size: 16384
+
+secrets:
+ database-url:
+ file: ./postgres_url
+
+volumes:
+ analytics_data:
diff --git a/compose-agents/sql-analyst/init.sql b/compose-agents/sql-analyst/init.sql
new file mode 100644
index 00000000..c125b3ee
--- /dev/null
+++ b/compose-agents/sql-analyst/init.sql
@@ -0,0 +1,148 @@
+-- BrainSait SQL Analyst - Sample Analytics Database
+
+-- Products table
+CREATE TABLE products (
+ id SERIAL PRIMARY KEY,
+ name VARCHAR(255) NOT NULL,
+ category VARCHAR(100),
+ price DECIMAL(10,2),
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+);
+
+-- Customers table
+CREATE TABLE customers (
+ id SERIAL PRIMARY KEY,
+ name VARCHAR(255) NOT NULL,
+ email VARCHAR(255) UNIQUE,
+ country VARCHAR(100),
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+);
+
+-- Orders table
+CREATE TABLE orders (
+ id SERIAL PRIMARY KEY,
+ customer_id INTEGER REFERENCES customers(id),
+ total_amount DECIMAL(10,2),
+ status VARCHAR(50) DEFAULT 'pending',
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+);
+
+-- Order items table
+CREATE TABLE order_items (
+ id SERIAL PRIMARY KEY,
+ order_id INTEGER REFERENCES orders(id),
+ product_id INTEGER REFERENCES products(id),
+ quantity INTEGER,
+ unit_price DECIMAL(10,2)
+);
+
+-- Sample data: Products
+INSERT INTO products (name, category, price) VALUES
+ ('Laptop Pro 15', 'Electronics', 1299.99),
+ ('Wireless Mouse', 'Electronics', 49.99),
+ ('USB-C Hub', 'Electronics', 79.99),
+ ('Standing Desk', 'Furniture', 599.99),
+ ('Ergonomic Chair', 'Furniture', 449.99),
+ ('Monitor 27"', 'Electronics', 399.99),
+ ('Keyboard Mechanical', 'Electronics', 149.99),
+ ('Desk Lamp', 'Furniture', 89.99),
+ ('Webcam HD', 'Electronics', 129.99),
+ ('Headphones', 'Electronics', 199.99);
+
+-- Sample data: Customers
+INSERT INTO customers (name, email, country) VALUES
+ ('John Smith', 'john@example.com', 'USA'),
+ ('Maria Garcia', 'maria@example.com', 'Spain'),
+ ('Ahmed Hassan', 'ahmed@example.com', 'Egypt'),
+ ('Yuki Tanaka', 'yuki@example.com', 'Japan'),
+ ('Emma Wilson', 'emma@example.com', 'UK'),
+ ('Mohammed Ali', 'mo@example.com', 'UAE'),
+ ('Lisa Chen', 'lisa@example.com', 'China'),
+ ('Hans Mueller', 'hans@example.com', 'Germany'),
+ ('Sarah Johnson', 'sarah@example.com', 'USA'),
+ ('Carlos Rodriguez', 'carlos@example.com', 'Mexico');
+
+-- Sample data: Orders (last 3 months)
+INSERT INTO orders (customer_id, total_amount, status, created_at) VALUES
+ (1, 1349.98, 'completed', NOW() - INTERVAL '5 days'),
+ (2, 599.99, 'completed', NOW() - INTERVAL '10 days'),
+ (3, 249.98, 'completed', NOW() - INTERVAL '15 days'),
+ (4, 1749.97, 'completed', NOW() - INTERVAL '20 days'),
+ (5, 449.99, 'completed', NOW() - INTERVAL '25 days'),
+ (6, 879.98, 'completed', NOW() - INTERVAL '30 days'),
+ (7, 1299.99, 'completed', NOW() - INTERVAL '35 days'),
+ (8, 329.98, 'shipped', NOW() - INTERVAL '3 days'),
+ (9, 649.98, 'shipped', NOW() - INTERVAL '2 days'),
+ (10, 199.99, 'pending', NOW() - INTERVAL '1 day'),
+ (1, 449.99, 'completed', NOW() - INTERVAL '45 days'),
+ (3, 1299.99, 'completed', NOW() - INTERVAL '50 days'),
+ (5, 279.98, 'completed', NOW() - INTERVAL '55 days'),
+ (7, 599.99, 'completed', NOW() - INTERVAL '60 days'),
+ (9, 849.98, 'completed', NOW() - INTERVAL '65 days');
+
+-- Sample data: Order items
+INSERT INTO order_items (order_id, product_id, quantity, unit_price) VALUES
+ (1, 1, 1, 1299.99),
+ (1, 2, 1, 49.99),
+ (2, 4, 1, 599.99),
+ (3, 2, 2, 49.99),
+ (3, 7, 1, 149.99),
+ (4, 1, 1, 1299.99),
+ (4, 5, 1, 449.99),
+ (5, 5, 1, 449.99),
+ (6, 6, 1, 399.99),
+ (6, 3, 1, 79.99),
+ (6, 10, 2, 199.99),
+ (7, 1, 1, 1299.99),
+ (8, 7, 1, 149.99),
+ (8, 9, 1, 129.99),
+ (8, 2, 1, 49.99),
+ (9, 4, 1, 599.99),
+ (9, 2, 1, 49.99),
+ (10, 10, 1, 199.99),
+ (11, 5, 1, 449.99),
+ (12, 1, 1, 1299.99),
+ (13, 3, 2, 79.99),
+ (13, 8, 1, 89.99),
+ (13, 2, 1, 49.99),
+ (14, 4, 1, 599.99),
+ (15, 6, 1, 399.99),
+ (15, 5, 1, 449.99);
+
+-- Create useful views
+CREATE VIEW monthly_sales AS
+SELECT
+ DATE_TRUNC('month', o.created_at) as month,
+ COUNT(DISTINCT o.id) as order_count,
+ SUM(o.total_amount) as total_sales,
+ COUNT(DISTINCT o.customer_id) as unique_customers
+FROM orders o
+WHERE o.status IN ('completed', 'shipped')
+GROUP BY DATE_TRUNC('month', o.created_at)
+ORDER BY month DESC;
+
+CREATE VIEW product_performance AS
+SELECT
+ p.id,
+ p.name,
+ p.category,
+ COUNT(oi.id) as times_ordered,
+ SUM(oi.quantity) as total_quantity,
+ SUM(oi.quantity * oi.unit_price) as total_revenue
+FROM products p
+LEFT JOIN order_items oi ON p.id = oi.product_id
+GROUP BY p.id, p.name, p.category
+ORDER BY total_revenue DESC;
+
+CREATE VIEW customer_segments AS
+SELECT
+ c.id,
+ c.name,
+ c.country,
+ COUNT(o.id) as order_count,
+ SUM(o.total_amount) as total_spent,
+ MAX(o.created_at) as last_order
+FROM customers c
+LEFT JOIN orders o ON c.id = o.customer_id
+GROUP BY c.id, c.name, c.country
+ORDER BY total_spent DESC;
diff --git a/compose-agents/sql-analyst/postgres_url b/compose-agents/sql-analyst/postgres_url
new file mode 100644
index 00000000..34786ad4
--- /dev/null
+++ b/compose-agents/sql-analyst/postgres_url
@@ -0,0 +1 @@
+postgres://analyst:analyst_password@database:5432/analytics
\ No newline at end of file
diff --git a/compose-agents/start.sh b/compose-agents/start.sh
new file mode 100644
index 00000000..357a2ff0
--- /dev/null
+++ b/compose-agents/start.sh
@@ -0,0 +1,134 @@
+#!/bin/bash
+# BrainSait Compose Agents - Quick Start Script
+
+set -e
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
+# Colors
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+BLUE='\033[0;34m'
+YELLOW='\033[1;33m'
+NC='\033[0m' # No Color
+
+print_header() {
+ echo -e "${BLUE}╔════════════════════════════════════════════════════════════╗${NC}"
+ echo -e "${BLUE}║${NC} ${GREEN}BrainSait Multi-Agent AI Platform${NC} ${BLUE}║${NC}"
+ echo -e "${BLUE}╚════════════════════════════════════════════════════════════╝${NC}"
+ echo ""
+}
+
+print_menu() {
+ echo -e "${YELLOW}Available Agent Systems:${NC}"
+ echo ""
+ echo " 1) 🌍 Arabic Assistant - Translation, writing, research in Arabic"
+ echo " 2) 🏥 Healthcare Insurance - Claims analysis, PA, coding, appeals"
+ echo " 3) 💻 Developer Assistant - Code review, architecture, debugging"
+ echo " 4) 🔍 SQL Analyst - Natural language to SQL queries"
+ echo ""
+ echo " q) Quit"
+ echo ""
+}
+
+check_docker() {
+ if ! command -v docker &> /dev/null; then
+ echo -e "${RED}Error: Docker is not installed.${NC}"
+ echo "Please install Docker Desktop: https://www.docker.com/products/docker-desktop/"
+ exit 1
+ fi
+
+ if ! docker info &> /dev/null; then
+ echo -e "${RED}Error: Docker daemon is not running.${NC}"
+ echo "Please start Docker Desktop."
+ exit 1
+ fi
+}
+
+check_github_token() {
+ if [ -z "$GITHUB_TOKEN" ]; then
+ echo -e "${YELLOW}GitHub token not set.${NC}"
+
+ # Try to get from gh CLI
+ if command -v gh &> /dev/null; then
+ export GITHUB_TOKEN=$(gh auth token 2>/dev/null)
+ if [ -n "$GITHUB_TOKEN" ]; then
+ echo -e "${GREEN}✓ Using GitHub token from gh CLI${NC}"
+ return 0
+ fi
+ fi
+
+ echo ""
+ echo "To use GitHub Models, set your token:"
+ echo " export GITHUB_TOKEN=\$(gh auth token)"
+ echo " # or"
+ echo " export GITHUB_TOKEN=ghp_xxxxx"
+ echo ""
+ return 1
+ fi
+ echo -e "${GREEN}✓ GitHub token configured${NC}"
+ return 0
+}
+
+run_agent() {
+ local agent_dir=$1
+ local agent_name=$2
+ local use_github=${3:-false}
+
+ echo ""
+ echo -e "${GREEN}Starting $agent_name...${NC}"
+ echo ""
+
+ cd "$SCRIPT_DIR/$agent_dir"
+
+ if [ "$use_github" = true ] && [ -f "compose.github.yaml" ]; then
+ echo "Using GitHub Models..."
+ docker compose -f compose.yaml -f compose.github.yaml up --build
+ else
+ echo "Using Docker Model Runner (local)..."
+ docker compose up --build
+ fi
+}
+
+main() {
+ print_header
+ check_docker
+
+ local has_token=false
+ if check_github_token; then
+ has_token=true
+ fi
+
+ echo ""
+
+ while true; do
+ print_menu
+ read -p "Select an agent (1-4, or q to quit): " choice
+
+ case $choice in
+ 1)
+ run_agent "arabic-assistant" "Arabic Language Assistant" $has_token
+ ;;
+ 2)
+ run_agent "healthcare-insurance" "Healthcare Insurance Analyst" $has_token
+ ;;
+ 3)
+ run_agent "developer-assistant" "Developer Assistant" $has_token
+ ;;
+ 4)
+ run_agent "sql-analyst" "SQL Analyst" $has_token
+ ;;
+ q|Q)
+ echo ""
+ echo -e "${GREEN}Goodbye!${NC}"
+ exit 0
+ ;;
+ *)
+ echo -e "${RED}Invalid selection. Please try again.${NC}"
+ echo ""
+ ;;
+ esac
+ done
+}
+
+main "$@"
diff --git a/db/init.sql b/db/init.sql
new file mode 100644
index 00000000..76a23a79
--- /dev/null
+++ b/db/init.sql
@@ -0,0 +1,221 @@
+-- BrainSait AI Platform - Database Schema
+-- PostgreSQL 15+
+
+-- Enable extensions
+CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
+CREATE EXTENSION IF NOT EXISTS "pgcrypto";
+
+-- ============================================
+-- Users & Authentication
+-- ============================================
+CREATE TABLE users (
+ id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
+ email VARCHAR(255) UNIQUE NOT NULL,
+ name VARCHAR(255),
+ api_key VARCHAR(64) UNIQUE NOT NULL DEFAULT encode(gen_random_bytes(32), 'hex'),
+ tier VARCHAR(50) DEFAULT 'free' CHECK (tier IN ('free', 'pro', 'enterprise')),
+ organization VARCHAR(255),
+ domain VARCHAR(50) DEFAULT 'general' CHECK (domain IN ('general', 'arabic', 'healthcare', 'developer')),
+ language VARCHAR(10) DEFAULT 'en',
+ is_active BOOLEAN DEFAULT true,
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
+ updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
+);
+
+-- Index for API key lookups (critical for performance)
+CREATE INDEX idx_users_api_key ON users(api_key) WHERE is_active = true;
+CREATE INDEX idx_users_email ON users(email);
+
+-- ============================================
+-- Usage Tracking
+-- ============================================
+CREATE TABLE usage_logs (
+ id BIGSERIAL PRIMARY KEY,
+ user_id UUID REFERENCES users(id) ON DELETE CASCADE,
+ endpoint VARCHAR(100) NOT NULL,
+ method VARCHAR(10) DEFAULT 'POST',
+ model_used VARCHAR(100),
+ domain VARCHAR(50),
+ tokens_input INT DEFAULT 0,
+ tokens_output INT DEFAULT 0,
+ credits_used INT DEFAULT 1,
+ latency_ms INT,
+ status_code INT,
+ error_message TEXT,
+ metadata JSONB DEFAULT '{}',
+ ip_address INET,
+ user_agent TEXT,
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
+);
+
+-- Partitioning by month for better performance
+CREATE INDEX idx_usage_user_time ON usage_logs(user_id, created_at DESC);
+CREATE INDEX idx_usage_domain ON usage_logs(domain, created_at DESC);
+
+-- ============================================
+-- Billing & Subscriptions
+-- ============================================
+CREATE TABLE subscriptions (
+ id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
+ user_id UUID UNIQUE REFERENCES users(id) ON DELETE CASCADE,
+ stripe_customer_id VARCHAR(100),
+ stripe_subscription_id VARCHAR(100),
+ plan VARCHAR(50) NOT NULL DEFAULT 'free',
+ status VARCHAR(50) DEFAULT 'active' CHECK (status IN ('active', 'canceled', 'past_due', 'trialing')),
+ monthly_credits INT DEFAULT 100,
+ credits_used INT DEFAULT 0,
+ current_period_start DATE,
+ current_period_end DATE,
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
+ updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
+);
+
+CREATE INDEX idx_subscriptions_stripe ON subscriptions(stripe_customer_id);
+
+-- ============================================
+-- Invoices
+-- ============================================
+CREATE TABLE invoices (
+ id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
+ user_id UUID REFERENCES users(id) ON DELETE CASCADE,
+ stripe_invoice_id VARCHAR(100),
+ amount_cents INT NOT NULL,
+ currency VARCHAR(3) DEFAULT 'USD',
+ status VARCHAR(50) DEFAULT 'pending',
+ period_start DATE,
+ period_end DATE,
+ paid_at TIMESTAMP WITH TIME ZONE,
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
+);
+
+-- ============================================
+-- Prompts Library
+-- ============================================
+CREATE TABLE prompts (
+ id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
+ user_id UUID REFERENCES users(id) ON DELETE SET NULL,
+ name VARCHAR(255) NOT NULL,
+ description TEXT,
+ domain VARCHAR(50) DEFAULT 'general',
+ language VARCHAR(10) DEFAULT 'en',
+ content JSONB NOT NULL, -- Store .prompt.yml as JSON
+ is_public BOOLEAN DEFAULT false,
+ is_featured BOOLEAN DEFAULT false,
+ usage_count INT DEFAULT 0,
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
+ updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
+);
+
+CREATE INDEX idx_prompts_domain ON prompts(domain) WHERE is_public = true;
+CREATE INDEX idx_prompts_language ON prompts(language);
+
+-- ============================================
+-- API Rate Limiting
+-- ============================================
+CREATE TABLE rate_limits (
+ id SERIAL PRIMARY KEY,
+ user_id UUID REFERENCES users(id) ON DELETE CASCADE,
+ endpoint VARCHAR(100),
+ requests_count INT DEFAULT 0,
+ window_start TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
+ window_size_seconds INT DEFAULT 60,
+ max_requests INT DEFAULT 60
+);
+
+CREATE UNIQUE INDEX idx_rate_limits_user_endpoint ON rate_limits(user_id, endpoint);
+
+-- ============================================
+-- Audit Log (HIPAA Compliance)
+-- ============================================
+CREATE TABLE audit_logs (
+ id BIGSERIAL PRIMARY KEY,
+ user_id UUID REFERENCES users(id) ON DELETE SET NULL,
+ action VARCHAR(100) NOT NULL,
+ resource_type VARCHAR(100),
+ resource_id VARCHAR(255),
+ details JSONB DEFAULT '{}',
+ ip_address INET,
+ user_agent TEXT,
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
+);
+
+CREATE INDEX idx_audit_user ON audit_logs(user_id, created_at DESC);
+CREATE INDEX idx_audit_action ON audit_logs(action, created_at DESC);
+
+-- ============================================
+-- Functions & Triggers
+-- ============================================
+
+-- Auto-update updated_at timestamp
+CREATE OR REPLACE FUNCTION update_updated_at_column()
+RETURNS TRIGGER AS $$
+BEGIN
+ NEW.updated_at = NOW();
+ RETURN NEW;
+END;
+$$ language 'plpgsql';
+
+CREATE TRIGGER update_users_updated_at
+ BEFORE UPDATE ON users
+ FOR EACH ROW
+ EXECUTE FUNCTION update_updated_at_column();
+
+CREATE TRIGGER update_subscriptions_updated_at
+ BEFORE UPDATE ON subscriptions
+ FOR EACH ROW
+ EXECUTE FUNCTION update_updated_at_column();
+
+CREATE TRIGGER update_prompts_updated_at
+ BEFORE UPDATE ON prompts
+ FOR EACH ROW
+ EXECUTE FUNCTION update_updated_at_column();
+
+-- ============================================
+-- Views
+-- ============================================
+
+-- User usage summary
+CREATE VIEW user_usage_summary AS
+SELECT
+ u.id,
+ u.email,
+ u.tier,
+ u.domain,
+ s.monthly_credits,
+ s.credits_used,
+ (s.monthly_credits - s.credits_used) as credits_remaining,
+ COUNT(ul.id) as total_requests,
+ SUM(ul.tokens_input + ul.tokens_output) as total_tokens
+FROM users u
+LEFT JOIN subscriptions s ON u.id = s.user_id
+LEFT JOIN usage_logs ul ON u.id = ul.user_id
+ AND ul.created_at >= s.current_period_start
+GROUP BY u.id, u.email, u.tier, u.domain, s.monthly_credits, s.credits_used;
+
+-- Daily usage analytics
+CREATE VIEW daily_usage_analytics AS
+SELECT
+ DATE(created_at) as date,
+ domain,
+ model_used,
+ COUNT(*) as request_count,
+ SUM(tokens_input) as total_input_tokens,
+ SUM(tokens_output) as total_output_tokens,
+ AVG(latency_ms) as avg_latency_ms,
+ COUNT(CASE WHEN status_code >= 400 THEN 1 END) as error_count
+FROM usage_logs
+WHERE created_at >= NOW() - INTERVAL '30 days'
+GROUP BY DATE(created_at), domain, model_used
+ORDER BY date DESC;
+
+-- ============================================
+-- Seed Data: Default Tiers
+-- ============================================
+INSERT INTO users (email, name, tier, domain, api_key) VALUES
+ ('system@brainsait.ai', 'System', 'enterprise', 'general', 'system_internal_key_do_not_use'),
+ ('demo@brainsait.ai', 'Demo User', 'pro', 'developer', 'demo_api_key_for_testing_only');
+
+-- Add default subscription for demo user
+INSERT INTO subscriptions (user_id, plan, monthly_credits, current_period_start, current_period_end)
+SELECT id, 'pro', 10000, DATE_TRUNC('month', NOW()), DATE_TRUNC('month', NOW()) + INTERVAL '1 month'
+FROM users WHERE email = 'demo@brainsait.ai';
diff --git a/deploy/.env.production.template b/deploy/.env.production.template
new file mode 100644
index 00000000..6027860c
--- /dev/null
+++ b/deploy/.env.production.template
@@ -0,0 +1,91 @@
+# BrainSait Production Environment Configuration
+# Copy to .env and fill in your values
+
+# ===========================================
+# Core Configuration
+# ===========================================
+BRAINSAIT_ENV=production
+BRAINSAIT_PORT=8080
+BRAINSAIT_DEBUG=false
+
+# ===========================================
+# Docker Registry
+# ===========================================
+DOCKER_REGISTRY=docker.io
+DOCKER_USERNAME=brainsait
+VERSION=latest
+
+# ===========================================
+# Authentication
+# ===========================================
+# GitHub Token for Models API
+GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxx
+
+# API Key Encryption Secret (generate with: openssl rand -hex 32)
+API_KEY_SECRET=your-api-key-secret-here
+
+# ===========================================
+# Database
+# ===========================================
+DB_PASSWORD=your-secure-database-password
+DATABASE_URL=postgres://brainsait:${DB_PASSWORD}@postgres:5432/brainsait?sslmode=disable
+
+# ===========================================
+# Redis
+# ===========================================
+REDIS_URL=redis://redis:6379
+
+# ===========================================
+# Stripe Billing
+# ===========================================
+STRIPE_SECRET_KEY=sk_live_xxxxxxxxxxxxxxxxxxxx
+STRIPE_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxxxxxxxxx
+STRIPE_PUBLISHABLE_KEY=pk_live_xxxxxxxxxxxxxxxxxxxx
+
+# Stripe Price IDs (create in Stripe Dashboard)
+STRIPE_PRICE_DEVELOPER=price_xxxxxxxxxxxx
+STRIPE_PRICE_TEAM=price_xxxxxxxxxxxx
+STRIPE_PRICE_ENTERPRISE=price_xxxxxxxxxxxx
+
+# ===========================================
+# Cloudflare Tunnel
+# ===========================================
+CF_TUNNEL_TOKEN=your-cloudflare-tunnel-token
+
+# ===========================================
+# Domains (via Cloudflare)
+# ===========================================
+DOMAIN_API=api.brainsait.ai
+DOMAIN_DOCS=docs.brainsait.ai
+DOMAIN_APP=app.brainsait.ai
+
+# ===========================================
+# CORS
+# ===========================================
+CORS_ORIGINS=https://brainsait.ai,https://app.brainsait.ai,https://docs.brainsait.ai
+
+# ===========================================
+# Monitoring
+# ===========================================
+GRAFANA_PASSWORD=your-grafana-admin-password
+
+# ===========================================
+# Email (for notifications)
+# ===========================================
+SMTP_HOST=smtp.sendgrid.net
+SMTP_PORT=587
+SMTP_USER=apikey
+SMTP_PASSWORD=your-sendgrid-api-key
+SMTP_FROM=noreply@brainsait.ai
+
+# ===========================================
+# Rate Limiting
+# ===========================================
+RATE_LIMIT_REQUESTS=100
+RATE_LIMIT_WINDOW_SECONDS=60
+
+# ===========================================
+# Logging
+# ===========================================
+LOG_LEVEL=info
+LOG_FORMAT=json
diff --git a/deploy/README.md b/deploy/README.md
new file mode 100644
index 00000000..288e64bd
--- /dev/null
+++ b/deploy/README.md
@@ -0,0 +1,301 @@
+# BrainSait Deployment Guide
+
+This guide covers the complete deployment workflow for the BrainSait AI Platform.
+
+## Overview
+
+The deployment process follows these steps:
+
+1. **Build** - Create Docker images locally
+2. **Push** - Upload images to Docker Hub
+3. **Deploy** - Pull and run images on a remote VM
+4. **Expose** - Use Cloudflare Tunnel to expose services
+
+## Prerequisites
+
+- Docker and Docker Compose installed locally
+- Docker Hub account
+- Remote VM (Ubuntu 22.04 LTS recommended)
+- Cloudflare account with a domain
+- GitHub Personal Access Token (for GitHub Models API)
+- Stripe account (for billing)
+
+## Quick Start
+
+### 1. Build Images Locally
+
+```bash
+# Build the main CLI image
+docker build -t brainsait/brainsait-ai:latest .
+
+# Build the API server image
+docker build -f Dockerfile.api -t brainsait/brainsait-ai-api:latest .
+```
+
+### 2. Push to Docker Hub
+
+```bash
+# Login to Docker Hub
+docker login
+
+# Push images
+./deploy/docker-hub-push.sh
+```
+
+Or manually:
+
+```bash
+docker push brainsait/brainsait-ai:latest
+docker push brainsait/brainsait-ai-api:latest
+```
+
+### 3. Setup Remote VM
+
+SSH into your VM and run:
+
+```bash
+# Download and run setup script
+curl -fsSL https://raw.githubusercontent.com/your-org/brainsait/main/deploy/vm-setup.sh | bash
+```
+
+Or manually:
+
+```bash
+# Install Docker
+curl -fsSL https://get.docker.com | sh
+sudo usermod -aG docker $USER
+
+# Install Docker Compose
+sudo apt install -y docker-compose-plugin
+
+# Install Cloudflared
+curl -L --output cloudflared.deb https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
+sudo dpkg -i cloudflared.deb
+```
+
+### 4. Configure Environment
+
+```bash
+cd /opt/brainsait
+cp .env.template .env
+nano .env
+```
+
+Required environment variables:
+
+| Variable | Description |
+|----------|-------------|
+| `GITHUB_TOKEN` | GitHub PAT with models access |
+| `STRIPE_API_KEY` | Stripe secret key |
+| `STRIPE_WEBHOOK_SECRET` | Stripe webhook signing secret |
+| `DB_PASSWORD` | PostgreSQL password |
+| `GRAFANA_PASSWORD` | Grafana admin password |
+
+### 5. Start Services
+
+```bash
+docker-compose up -d
+
+# Check status
+docker-compose ps
+docker-compose logs -f api
+```
+
+### 6. Setup Cloudflare Tunnel
+
+```bash
+# Login to Cloudflare
+cloudflared tunnel login
+
+# Create tunnel
+cloudflared tunnel create brainsait-tunnel
+
+# Configure DNS routes
+cloudflared tunnel route dns brainsait-tunnel api.yourdomain.com
+cloudflared tunnel route dns brainsait-tunnel docs.yourdomain.com
+
+# Install as service
+sudo cloudflared service install
+
+# Start tunnel
+sudo systemctl start cloudflared
+sudo systemctl enable cloudflared
+```
+
+## Architecture
+
+```
+┌──────────────────────────────────────────────────────────────┐
+│ Cloudflare Edge │
+│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
+│ │ api.domain │ │docs.domain │ │ grafana.domain │ │
+│ └──────┬──────┘ └──────┬──────┘ └──────────┬──────────┘ │
+└─────────┼────────────────┼────────────────────┼──────────────┘
+ │ │ │
+ ▼ ▼ ▼
+┌─────────────────────────────────────────────────────────────┐
+│ Cloudflare Tunnel │
+└─────────────────────────────────────────────────────────────┘
+ │
+ ▼
+┌─────────────────────────────────────────────────────────────┐
+│ Remote VM │
+│ ┌─────────────────────────────────────────────────────┐ │
+│ │ Docker Network │ │
+│ │ ┌─────────┐ ┌──────────┐ ┌───────┐ ┌─────────┐ │ │
+│ │ │ API │──│ Postgres │ │ Redis │ │Prometheus│ │ │
+│ │ │ :8080 │ │ :5432 │ │ :6379 │ │ :9090 │ │ │
+│ │ └─────────┘ └──────────┘ └───────┘ └─────────┘ │ │
+│ │ ┌─────────┐ │ │
+│ │ │ Grafana │ │ │
+│ │ │ :3001 │ │ │
+│ │ └─────────┘ │ │
+│ └─────────────────────────────────────────────────────┘ │
+└─────────────────────────────────────────────────────────────┘
+```
+
+## API Endpoints
+
+Once deployed, the following endpoints are available:
+
+### Public Endpoints
+
+| Endpoint | Method | Description |
+|----------|--------|-------------|
+| `/health` | GET | Health check |
+| `/v1/chat` | POST | Chat completion |
+| `/v1/chat/stream` | POST | Streaming chat |
+| `/v1/models` | GET | List available models |
+| `/v1/models/{id}` | GET | Get model details |
+| `/v1/prompts` | GET | List prompt templates |
+| `/v1/prompts/{domain}` | GET | Domain-specific prompts |
+
+### Authenticated Endpoints
+
+| Endpoint | Method | Description |
+|----------|--------|-------------|
+| `/v1/user` | GET | Get user profile |
+| `/v1/user/usage` | GET | Get usage statistics |
+| `/v1/billing/checkout` | POST | Create Stripe checkout |
+| `/v1/billing/portal` | POST | Create billing portal |
+
+## Monitoring
+
+### Grafana Dashboards
+
+Access Grafana at `https://grafana.yourdomain.com` with:
+- Username: `admin`
+- Password: (from `GRAFANA_PASSWORD` in .env)
+
+### Prometheus Metrics
+
+The API server exposes metrics at `/metrics`:
+- Request counts and latency
+- Token usage
+- Error rates
+
+## Backup & Recovery
+
+### Automated Backups
+
+The VM setup configures daily PostgreSQL backups at 2 AM:
+
+```bash
+# Manual backup
+/opt/brainsait/backup.sh
+
+# View backups
+ls -la /opt/brainsait/backups/
+```
+
+### Restore from Backup
+
+```bash
+# Stop services
+docker-compose down
+
+# Restore database
+gunzip < backups/db_YYYYMMDD_HHMMSS.sql.gz | \
+ docker exec -i brainsait-postgres psql -U brainsait brainsait
+
+# Start services
+docker-compose up -d
+```
+
+## Troubleshooting
+
+### Check Service Status
+
+```bash
+# Container status
+docker-compose ps
+
+# Container logs
+docker-compose logs -f api
+docker-compose logs -f postgres
+
+# Tunnel status
+sudo systemctl status cloudflared
+```
+
+### Common Issues
+
+**API not responding:**
+```bash
+# Check health
+curl http://localhost:8080/health
+
+# Check logs
+docker-compose logs api
+```
+
+**Database connection failed:**
+```bash
+# Check PostgreSQL
+docker-compose logs postgres
+docker exec -it brainsait-postgres psql -U brainsait -d brainsait
+```
+
+**Tunnel not working:**
+```bash
+# Check tunnel status
+cloudflared tunnel info brainsait-tunnel
+
+# Check tunnel logs
+sudo journalctl -u cloudflared -f
+```
+
+## Scaling
+
+### Horizontal Scaling
+
+To run multiple API instances:
+
+```yaml
+# In docker-compose.yml
+services:
+ api:
+ deploy:
+ replicas: 3
+```
+
+### Load Balancing
+
+Cloudflare automatically load balances across tunnel instances.
+
+## Security Checklist
+
+- [ ] Use strong passwords in `.env`
+- [ ] Enable Cloudflare Access for admin endpoints
+- [ ] Configure firewall (only allow ports 22, 80, 443)
+- [ ] Enable automatic security updates
+- [ ] Set up SSL certificate rotation
+- [ ] Enable audit logging
+- [ ] Configure rate limiting in Cloudflare
+
+## Support
+
+For issues or questions:
+- GitHub Issues: https://github.com/your-org/brainsait/issues
+- Documentation: https://docs.brainsait.com
+- Email: support@brainsait.com
diff --git a/deploy/cloudflare/config.yml b/deploy/cloudflare/config.yml
new file mode 100644
index 00000000..f8e674ac
--- /dev/null
+++ b/deploy/cloudflare/config.yml
@@ -0,0 +1,38 @@
+# Cloudflare Tunnel Configuration for BrainSait
+# This file configures how traffic routes through the tunnel
+
+tunnel: brainsait-tunnel
+credentials-file: /etc/cloudflared/credentials.json
+
+# Route traffic to local services
+ingress:
+ # API Gateway - main endpoint
+ - hostname: api.brainsait.com
+ service: http://localhost:8080
+ originRequest:
+ connectTimeout: 30s
+ noTLSVerify: false
+
+ # Documentation site
+ - hostname: docs.brainsait.com
+ service: http://localhost:8081
+
+ # Monitoring dashboards (internal access only)
+ - hostname: metrics.brainsait.com
+ service: http://localhost:3000
+ originRequest:
+ # Require Cloudflare Access authentication
+ access:
+ required: true
+ teamName: brainsait
+
+ # Grafana dashboards
+ - hostname: grafana.brainsait.com
+ service: http://localhost:3001
+ originRequest:
+ access:
+ required: true
+ teamName: brainsait
+
+ # Catch-all rule (required)
+ - service: http_status:404
diff --git a/deploy/cloudflare/tunnel-setup.sh b/deploy/cloudflare/tunnel-setup.sh
new file mode 100644
index 00000000..b5710bc1
--- /dev/null
+++ b/deploy/cloudflare/tunnel-setup.sh
@@ -0,0 +1,114 @@
+#!/bin/bash
+# Cloudflare Tunnel Setup Script for BrainSait
+# Prerequisites: cloudflared CLI installed and authenticated
+
+set -e
+
+TUNNEL_NAME="${TUNNEL_NAME:-brainsait-tunnel}"
+DOMAIN="${DOMAIN:-brainsait.com}"
+
+echo "🌐 BrainSait Cloudflare Tunnel Setup"
+echo "======================================"
+
+# Check if cloudflared is installed
+if ! command -v cloudflared &> /dev/null; then
+ echo "❌ cloudflared CLI not found. Installing..."
+
+ # Detect OS and install
+ if [[ "$OSTYPE" == "darwin"* ]]; then
+ brew install cloudflare/cloudflare/cloudflared
+ elif [[ -f /etc/debian_version ]]; then
+ curl -L --output cloudflared.deb https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
+ sudo dpkg -i cloudflared.deb
+ rm cloudflared.deb
+ elif [[ -f /etc/redhat-release ]]; then
+ curl -L --output cloudflared.rpm https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-x86_64.rpm
+ sudo rpm -i cloudflared.rpm
+ rm cloudflared.rpm
+ else
+ echo "❌ Unsupported OS. Please install cloudflared manually."
+ exit 1
+ fi
+fi
+
+echo "✅ cloudflared installed: $(cloudflared --version)"
+
+# Login to Cloudflare (if not already)
+echo ""
+echo "📝 Step 1: Authenticate with Cloudflare"
+if [ ! -f ~/.cloudflared/cert.pem ]; then
+ echo "Opening browser for authentication..."
+ cloudflared tunnel login
+else
+ echo "Already authenticated"
+fi
+
+# Create tunnel
+echo ""
+echo "📝 Step 2: Create tunnel '$TUNNEL_NAME'"
+if cloudflared tunnel list | grep -q "$TUNNEL_NAME"; then
+ echo "Tunnel '$TUNNEL_NAME' already exists"
+ TUNNEL_ID=$(cloudflared tunnel list | grep "$TUNNEL_NAME" | awk '{print $1}')
+else
+ cloudflared tunnel create "$TUNNEL_NAME"
+ TUNNEL_ID=$(cloudflared tunnel list | grep "$TUNNEL_NAME" | awk '{print $1}')
+ echo "Created tunnel with ID: $TUNNEL_ID"
+fi
+
+# Configure DNS routes
+echo ""
+echo "📝 Step 3: Configure DNS routes"
+
+configure_dns() {
+ local subdomain=$1
+ local hostname="${subdomain}.${DOMAIN}"
+
+ if cloudflared tunnel route dns "$TUNNEL_NAME" "$hostname" 2>/dev/null; then
+ echo "✅ Configured: $hostname"
+ else
+ echo "⚠️ Route may already exist for: $hostname"
+ fi
+}
+
+configure_dns "api"
+configure_dns "docs"
+configure_dns "metrics"
+configure_dns "grafana"
+
+# Create credentials directory
+echo ""
+echo "📝 Step 4: Setup credentials"
+sudo mkdir -p /etc/cloudflared
+sudo cp ~/.cloudflared/${TUNNEL_ID}.json /etc/cloudflared/credentials.json
+sudo chmod 600 /etc/cloudflared/credentials.json
+
+# Copy configuration
+echo ""
+echo "📝 Step 5: Install configuration"
+sudo cp "$(dirname "$0")/config.yml" /etc/cloudflared/config.yml
+sudo sed -i "s/brainsait-tunnel/$TUNNEL_ID/g" /etc/cloudflared/config.yml 2>/dev/null || \
+sudo sed -i '' "s/brainsait-tunnel/$TUNNEL_ID/g" /etc/cloudflared/config.yml
+
+# Install as service
+echo ""
+echo "📝 Step 6: Install as system service"
+sudo cloudflared service install
+
+echo ""
+echo "======================================"
+echo "✅ Cloudflare Tunnel Setup Complete!"
+echo ""
+echo "Tunnel ID: $TUNNEL_ID"
+echo "Endpoints configured:"
+echo " - https://api.${DOMAIN} -> localhost:8080 (API)"
+echo " - https://docs.${DOMAIN} -> localhost:8081 (Docs)"
+echo " - https://metrics.${DOMAIN} -> localhost:3000 (Metrics)"
+echo " - https://grafana.${DOMAIN} -> localhost:3001 (Grafana)"
+echo ""
+echo "Commands:"
+echo " Start: sudo systemctl start cloudflared"
+echo " Stop: sudo systemctl stop cloudflared"
+echo " Status: sudo systemctl status cloudflared"
+echo " Logs: sudo journalctl -u cloudflared -f"
+echo ""
+echo "Manual run: cloudflared tunnel run $TUNNEL_NAME"
diff --git a/deploy/deploy.sh b/deploy/deploy.sh
new file mode 100644
index 00000000..7f483eb3
--- /dev/null
+++ b/deploy/deploy.sh
@@ -0,0 +1,247 @@
+#!/bin/bash
+# BrainSait Deployment Script
+# Builds, pushes to Docker Hub, and deploys to remote VM with Cloudflare Tunnel
+
+set -e
+
+# Configuration
+DOCKER_REGISTRY="${DOCKER_REGISTRY:-docker.io}"
+DOCKER_USERNAME="${DOCKER_USERNAME:-brainsait}"
+IMAGE_NAME="${IMAGE_NAME:-brainsait-ai}"
+VERSION="${VERSION:-latest}"
+REMOTE_HOST="${REMOTE_HOST:-}"
+REMOTE_USER="${REMOTE_USER:-root}"
+CF_TUNNEL_TOKEN="${CF_TUNNEL_TOKEN:-}"
+
+# Colors for output
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+NC='\033[0m' # No Color
+
+log_info() {
+ echo -e "${GREEN}[INFO]${NC} $1"
+}
+
+log_warn() {
+ echo -e "${YELLOW}[WARN]${NC} $1"
+}
+
+log_error() {
+ echo -e "${RED}[ERROR]${NC} $1"
+}
+
+# Check required environment variables
+check_requirements() {
+ log_info "Checking requirements..."
+
+ if [ -z "$DOCKER_USERNAME" ]; then
+ log_error "DOCKER_USERNAME is required"
+ exit 1
+ fi
+
+ if [ -z "$REMOTE_HOST" ]; then
+ log_error "REMOTE_HOST is required for deployment"
+ exit 1
+ fi
+
+ # Check if Docker is installed
+ if ! command -v docker &> /dev/null; then
+ log_error "Docker is not installed"
+ exit 1
+ fi
+
+ log_info "All requirements met"
+}
+
+# Build Docker image
+build_image() {
+ log_info "Building Docker image..."
+
+ docker build \
+ --platform linux/amd64 \
+ -t "$DOCKER_REGISTRY/$DOCKER_USERNAME/$IMAGE_NAME:$VERSION" \
+ -t "$DOCKER_REGISTRY/$DOCKER_USERNAME/$IMAGE_NAME:latest" \
+ -f Dockerfile \
+ .
+
+ log_info "Docker image built successfully"
+}
+
+# Push to Docker Hub
+push_image() {
+ log_info "Pushing image to Docker Hub..."
+
+ # Login to Docker Hub
+ if [ -n "$DOCKER_PASSWORD" ]; then
+ echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
+ else
+ log_warn "DOCKER_PASSWORD not set, assuming already logged in"
+ fi
+
+ docker push "$DOCKER_REGISTRY/$DOCKER_USERNAME/$IMAGE_NAME:$VERSION"
+ docker push "$DOCKER_REGISTRY/$DOCKER_USERNAME/$IMAGE_NAME:latest"
+
+ log_info "Image pushed successfully"
+}
+
+# Deploy to remote VM
+deploy_remote() {
+ log_info "Deploying to remote VM ($REMOTE_HOST)..."
+
+ # Create deployment script
+ DEPLOY_SCRIPT=$(cat <<'EOF'
+#!/bin/bash
+set -e
+
+# Pull latest images
+docker-compose pull
+
+# Stop existing containers
+docker-compose down
+
+# Start new containers
+docker-compose up -d
+
+# Clean up old images
+docker image prune -f
+
+# Check health
+sleep 10
+curl -f http://localhost:8080/health || exit 1
+
+echo "Deployment successful!"
+EOF
+)
+
+ # Copy docker-compose and .env files
+ scp docker-compose.yml "$REMOTE_USER@$REMOTE_HOST:~/brainsait/"
+ scp .env.production "$REMOTE_USER@$REMOTE_HOST:~/brainsait/.env"
+
+ # Execute deployment
+ ssh "$REMOTE_USER@$REMOTE_HOST" "cd ~/brainsait && $DEPLOY_SCRIPT"
+
+ log_info "Remote deployment completed"
+}
+
+# Setup Cloudflare Tunnel
+setup_cloudflare_tunnel() {
+ log_info "Setting up Cloudflare Tunnel..."
+
+ if [ -z "$CF_TUNNEL_TOKEN" ]; then
+ log_warn "CF_TUNNEL_TOKEN not set, skipping tunnel setup"
+ return
+ fi
+
+ # Create cloudflared config on remote
+ CF_CONFIG=$(cat < /etc/cloudflared/config.yml"
+
+ # Install and start cloudflared
+ ssh "$REMOTE_USER@$REMOTE_HOST" << 'REMOTE_EOF'
+# Install cloudflared if not present
+if ! command -v cloudflared &> /dev/null; then
+ curl -L --output cloudflared.deb https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
+ sudo dpkg -i cloudflared.deb
+ rm cloudflared.deb
+fi
+
+# Setup tunnel as service
+sudo cloudflared service install $CF_TUNNEL_TOKEN
+
+# Start tunnel
+sudo systemctl start cloudflared
+sudo systemctl enable cloudflared
+REMOTE_EOF
+
+ log_info "Cloudflare Tunnel configured"
+}
+
+# Print usage
+usage() {
+ cat << EOF
+BrainSait Deployment Script
+
+Usage: $0 [command]
+
+Commands:
+ build Build Docker image only
+ push Push image to Docker Hub
+ deploy Deploy to remote VM
+ tunnel Setup Cloudflare Tunnel
+ all Run all steps (default)
+
+Environment Variables:
+ DOCKER_USERNAME Docker Hub username (required)
+ DOCKER_PASSWORD Docker Hub password (for push)
+ IMAGE_NAME Docker image name (default: brainsait-ai)
+ VERSION Image version tag (default: latest)
+ REMOTE_HOST Remote VM hostname/IP (required for deploy)
+ REMOTE_USER Remote VM user (default: root)
+ CF_TUNNEL_TOKEN Cloudflare Tunnel token
+
+Examples:
+ # Build and push
+ DOCKER_USERNAME=myuser VERSION=v1.0.0 $0 build push
+
+ # Full deployment
+ DOCKER_USERNAME=myuser REMOTE_HOST=server.example.com $0 all
+EOF
+}
+
+# Main
+main() {
+ if [ $# -eq 0 ]; then
+ set -- "all"
+ fi
+
+ for cmd in "$@"; do
+ case "$cmd" in
+ build)
+ build_image
+ ;;
+ push)
+ push_image
+ ;;
+ deploy)
+ check_requirements
+ deploy_remote
+ ;;
+ tunnel)
+ setup_cloudflare_tunnel
+ ;;
+ all)
+ check_requirements
+ build_image
+ push_image
+ deploy_remote
+ setup_cloudflare_tunnel
+ ;;
+ -h|--help|help)
+ usage
+ exit 0
+ ;;
+ *)
+ log_error "Unknown command: $cmd"
+ usage
+ exit 1
+ ;;
+ esac
+ done
+
+ log_info "All tasks completed successfully!"
+}
+
+main "$@"
diff --git a/deploy/docker-compose.production.yml b/deploy/docker-compose.production.yml
new file mode 100644
index 00000000..f03404eb
--- /dev/null
+++ b/deploy/docker-compose.production.yml
@@ -0,0 +1,165 @@
+# BrainSait Production Docker Compose
+# For deployment on remote VM with Cloudflare Tunnel
+
+version: '3.8'
+
+services:
+ # Main API Server
+ api:
+ image: ${DOCKER_REGISTRY:-docker.io}/${DOCKER_USERNAME:-brainsait}/brainsait-ai:${VERSION:-latest}
+ container_name: brainsait-api
+ restart: unless-stopped
+ ports:
+ - "8080:8080"
+ environment:
+ - BRAINSAIT_ENV=production
+ - BRAINSAIT_PORT=8080
+ - GITHUB_TOKEN=${GITHUB_TOKEN}
+ - STRIPE_SECRET_KEY=${STRIPE_SECRET_KEY}
+ - STRIPE_WEBHOOK_SECRET=${STRIPE_WEBHOOK_SECRET}
+ - DATABASE_URL=postgres://brainsait:${DB_PASSWORD}@postgres:5432/brainsait?sslmode=disable
+ - REDIS_URL=redis://redis:6379
+ - CORS_ORIGINS=${CORS_ORIGINS:-https://brainsait.ai,https://app.brainsait.ai}
+ depends_on:
+ postgres:
+ condition: service_healthy
+ redis:
+ condition: service_started
+ healthcheck:
+ test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
+ interval: 30s
+ timeout: 10s
+ retries: 3
+ start_period: 40s
+ networks:
+ - brainsait-network
+ logging:
+ driver: "json-file"
+ options:
+ max-size: "10m"
+ max-file: "3"
+
+ # PostgreSQL Database
+ postgres:
+ image: postgres:15-alpine
+ container_name: brainsait-postgres
+ restart: unless-stopped
+ environment:
+ - POSTGRES_USER=brainsait
+ - POSTGRES_PASSWORD=${DB_PASSWORD}
+ - POSTGRES_DB=brainsait
+ volumes:
+ - postgres-data:/var/lib/postgresql/data
+ - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready -U brainsait"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+ networks:
+ - brainsait-network
+ logging:
+ driver: "json-file"
+ options:
+ max-size: "10m"
+ max-file: "3"
+
+ # Redis Cache
+ redis:
+ image: redis:7-alpine
+ container_name: brainsait-redis
+ restart: unless-stopped
+ command: redis-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru
+ volumes:
+ - redis-data:/data
+ networks:
+ - brainsait-network
+ logging:
+ driver: "json-file"
+ options:
+ max-size: "10m"
+ max-file: "3"
+
+ # Cloudflare Tunnel (for exposing services)
+ cloudflared:
+ image: cloudflare/cloudflared:latest
+ container_name: brainsait-tunnel
+ restart: unless-stopped
+ command: tunnel --no-autoupdate run
+ environment:
+ - TUNNEL_TOKEN=${CF_TUNNEL_TOKEN}
+ networks:
+ - brainsait-network
+ depends_on:
+ - api
+ logging:
+ driver: "json-file"
+ options:
+ max-size: "10m"
+ max-file: "3"
+
+ # Documentation Server
+ docs:
+ image: nginx:alpine
+ container_name: brainsait-docs
+ restart: unless-stopped
+ ports:
+ - "8081:80"
+ volumes:
+ - ./docs/public:/usr/share/nginx/html:ro
+ networks:
+ - brainsait-network
+ logging:
+ driver: "json-file"
+ options:
+ max-size: "10m"
+ max-file: "3"
+
+ # Prometheus Metrics
+ prometheus:
+ image: prom/prometheus:latest
+ container_name: brainsait-prometheus
+ restart: unless-stopped
+ ports:
+ - "9090:9090"
+ volumes:
+ - ./deploy/prometheus.yml:/etc/prometheus/prometheus.yml:ro
+ - prometheus-data:/prometheus
+ command:
+ - '--config.file=/etc/prometheus/prometheus.yml'
+ - '--storage.tsdb.path=/prometheus'
+ - '--storage.tsdb.retention.time=15d'
+ networks:
+ - brainsait-network
+
+ # Grafana Dashboard
+ grafana:
+ image: grafana/grafana:latest
+ container_name: brainsait-grafana
+ restart: unless-stopped
+ ports:
+ - "3000:3000"
+ environment:
+ - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD:-admin}
+ - GF_USERS_ALLOW_SIGN_UP=false
+ volumes:
+ - grafana-data:/var/lib/grafana
+ - ./deploy/grafana/provisioning:/etc/grafana/provisioning:ro
+ depends_on:
+ - prometheus
+ networks:
+ - brainsait-network
+
+volumes:
+ postgres-data:
+ driver: local
+ redis-data:
+ driver: local
+ prometheus-data:
+ driver: local
+ grafana-data:
+ driver: local
+
+networks:
+ brainsait-network:
+ driver: bridge
diff --git a/deploy/docker-hub-push.sh b/deploy/docker-hub-push.sh
new file mode 100644
index 00000000..d478d3c0
--- /dev/null
+++ b/deploy/docker-hub-push.sh
@@ -0,0 +1,77 @@
+#!/bin/bash
+# Docker Hub Push Script for BrainSait
+# Builds multi-architecture images and pushes to Docker Hub
+
+set -e
+
+# Configuration
+DOCKER_USER="${DOCKER_USER:-brainsait}"
+IMAGE_NAME="${IMAGE_NAME:-brainsait-ai}"
+VERSION="${VERSION:-$(git describe --tags --always 2>/dev/null || echo 'latest')}"
+PLATFORMS="${PLATFORMS:-linux/amd64,linux/arm64}"
+
+echo "🐳 BrainSait Docker Build & Push"
+echo "=================================="
+echo "User: $DOCKER_USER"
+echo "Image: $IMAGE_NAME"
+echo "Version: $VERSION"
+echo "Platforms: $PLATFORMS"
+echo ""
+
+# Check if logged into Docker Hub
+if ! docker info 2>/dev/null | grep -q "Username"; then
+ echo "📝 Please login to Docker Hub:"
+ docker login
+fi
+
+# Setup buildx for multi-platform builds
+echo ""
+echo "🔧 Setting up Docker Buildx..."
+if ! docker buildx inspect brainsait-builder &>/dev/null; then
+ docker buildx create --name brainsait-builder --driver docker-container --bootstrap
+fi
+docker buildx use brainsait-builder
+
+# Build and push main application image
+echo ""
+echo "🏗️ Building and pushing ${DOCKER_USER}/${IMAGE_NAME}:${VERSION}..."
+
+cd "$(dirname "$0")/.."
+
+docker buildx build \
+ --platform "$PLATFORMS" \
+ --tag "${DOCKER_USER}/${IMAGE_NAME}:${VERSION}" \
+ --tag "${DOCKER_USER}/${IMAGE_NAME}:latest" \
+ --push \
+ --file Dockerfile \
+ .
+
+echo "✅ Pushed: ${DOCKER_USER}/${IMAGE_NAME}:${VERSION}"
+echo "✅ Pushed: ${DOCKER_USER}/${IMAGE_NAME}:latest"
+
+# Build and push API server image (if separate Dockerfile exists)
+if [ -f "Dockerfile.api" ]; then
+ echo ""
+ echo "🏗️ Building and pushing ${DOCKER_USER}/${IMAGE_NAME}-api:${VERSION}..."
+
+ docker buildx build \
+ --platform "$PLATFORMS" \
+ --tag "${DOCKER_USER}/${IMAGE_NAME}-api:${VERSION}" \
+ --tag "${DOCKER_USER}/${IMAGE_NAME}-api:latest" \
+ --push \
+ --file Dockerfile.api \
+ .
+
+ echo "✅ Pushed: ${DOCKER_USER}/${IMAGE_NAME}-api:${VERSION}"
+fi
+
+echo ""
+echo "=================================="
+echo "✅ Docker Hub Push Complete!"
+echo ""
+echo "Pull commands:"
+echo " docker pull ${DOCKER_USER}/${IMAGE_NAME}:${VERSION}"
+echo " docker pull ${DOCKER_USER}/${IMAGE_NAME}:latest"
+echo ""
+echo "Run command:"
+echo " docker run -p 8080:8080 ${DOCKER_USER}/${IMAGE_NAME}:${VERSION}"
diff --git a/deploy/prometheus.yml b/deploy/prometheus.yml
new file mode 100644
index 00000000..ff695fdd
--- /dev/null
+++ b/deploy/prometheus.yml
@@ -0,0 +1,36 @@
+global:
+ scrape_interval: 15s
+ evaluation_interval: 15s
+
+rule_files:
+ # - "first_rules.yml"
+ # - "second_rules.yml"
+
+scrape_configs:
+ # Prometheus self-monitoring
+ - job_name: 'prometheus'
+ static_configs:
+ - targets: ['localhost:9090']
+
+ # BrainSait API
+ - job_name: 'brainsait-api'
+ static_configs:
+ - targets: ['api:8080']
+ metrics_path: /metrics
+ scheme: http
+
+ # Redis
+ - job_name: 'redis'
+ static_configs:
+ - targets: ['redis:6379']
+
+ # PostgreSQL (requires pg_exporter)
+ # - job_name: 'postgres'
+ # static_configs:
+ # - targets: ['postgres-exporter:9187']
+
+alerting:
+ alertmanagers:
+ - static_configs:
+ - targets:
+ # - alertmanager:9093
diff --git a/deploy/vm-setup.sh b/deploy/vm-setup.sh
new file mode 100644
index 00000000..b9386302
--- /dev/null
+++ b/deploy/vm-setup.sh
@@ -0,0 +1,248 @@
+#!/bin/bash
+# VM Setup Script for BrainSait Production Deployment
+# Designed for Ubuntu 22.04 LTS
+
+set -e
+
+echo "🖥️ BrainSait VM Setup"
+echo "======================"
+
+# Configuration
+BRAINSAIT_USER="${BRAINSAIT_USER:-brainsait}"
+DOCKER_USER="${DOCKER_USER:-brainsait}"
+IMAGE_NAME="${IMAGE_NAME:-brainsait-ai}"
+DOMAIN="${DOMAIN:-brainsait.com}"
+
+# Update system
+echo ""
+echo "📦 Step 1: System Update"
+sudo apt update && sudo apt upgrade -y
+
+# Install Docker
+echo ""
+echo "📦 Step 2: Install Docker"
+if ! command -v docker &> /dev/null; then
+ curl -fsSL https://get.docker.com -o get-docker.sh
+ sudo sh get-docker.sh
+ rm get-docker.sh
+
+ # Add current user to docker group
+ sudo usermod -aG docker $USER
+ echo "⚠️ You may need to log out and back in for docker group membership"
+fi
+
+# Install Docker Compose
+echo ""
+echo "📦 Step 3: Install Docker Compose"
+if ! command -v docker-compose &> /dev/null; then
+ sudo apt install -y docker-compose-plugin
+fi
+
+# Install cloudflared
+echo ""
+echo "📦 Step 4: Install Cloudflared"
+if ! command -v cloudflared &> /dev/null; then
+ curl -L --output cloudflared.deb https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
+ sudo dpkg -i cloudflared.deb
+ rm cloudflared.deb
+fi
+
+# Create application directory
+echo ""
+echo "📁 Step 5: Create Application Directory"
+sudo mkdir -p /opt/brainsait
+sudo chown $USER:$USER /opt/brainsait
+cd /opt/brainsait
+
+# Create docker-compose file
+echo ""
+echo "📝 Step 6: Create Docker Compose Configuration"
+cat > docker-compose.yml << 'DOCKER_COMPOSE'
+version: '3.8'
+
+services:
+ # Main API Service
+ api:
+ image: ${DOCKER_USER:-brainsait}/${IMAGE_NAME:-brainsait-ai}:${VERSION:-latest}
+ container_name: brainsait-api
+ restart: unless-stopped
+ ports:
+ - "8080:8080"
+ environment:
+ - GITHUB_TOKEN=${GITHUB_TOKEN}
+ - STRIPE_API_KEY=${STRIPE_API_KEY}
+ - STRIPE_WEBHOOK_SECRET=${STRIPE_WEBHOOK_SECRET}
+ - DATABASE_URL=postgres://brainsait:${DB_PASSWORD}@postgres:5432/brainsait?sslmode=disable
+ - REDIS_URL=redis://redis:6379
+ - LOG_LEVEL=info
+ - ENVIRONMENT=production
+ depends_on:
+ - postgres
+ - redis
+ healthcheck:
+ test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080/health"]
+ interval: 30s
+ timeout: 10s
+ retries: 3
+
+ # PostgreSQL Database
+ postgres:
+ image: postgres:15-alpine
+ container_name: brainsait-postgres
+ restart: unless-stopped
+ volumes:
+ - postgres_data:/var/lib/postgresql/data
+ environment:
+ - POSTGRES_USER=brainsait
+ - POSTGRES_PASSWORD=${DB_PASSWORD}
+ - POSTGRES_DB=brainsait
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready -U brainsait"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+
+ # Redis Cache
+ redis:
+ image: redis:7-alpine
+ container_name: brainsait-redis
+ restart: unless-stopped
+ volumes:
+ - redis_data:/data
+ command: redis-server --appendonly yes
+ healthcheck:
+ test: ["CMD", "redis-cli", "ping"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+
+ # Prometheus Monitoring
+ prometheus:
+ image: prom/prometheus:latest
+ container_name: brainsait-prometheus
+ restart: unless-stopped
+ ports:
+ - "127.0.0.1:9090:9090"
+ volumes:
+ - ./prometheus.yml:/etc/prometheus/prometheus.yml
+ - prometheus_data:/prometheus
+ command:
+ - '--config.file=/etc/prometheus/prometheus.yml'
+ - '--storage.tsdb.path=/prometheus'
+ - '--web.console.libraries=/usr/share/prometheus/console_libraries'
+ - '--web.console.templates=/usr/share/prometheus/consoles'
+
+ # Grafana Dashboards
+ grafana:
+ image: grafana/grafana:latest
+ container_name: brainsait-grafana
+ restart: unless-stopped
+ ports:
+ - "127.0.0.1:3001:3000"
+ volumes:
+ - grafana_data:/var/lib/grafana
+ environment:
+ - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
+ - GF_USERS_ALLOW_SIGN_UP=false
+ depends_on:
+ - prometheus
+
+volumes:
+ postgres_data:
+ redis_data:
+ prometheus_data:
+ grafana_data:
+DOCKER_COMPOSE
+
+# Create prometheus config
+cat > prometheus.yml << 'PROMETHEUS'
+global:
+ scrape_interval: 15s
+ evaluation_interval: 15s
+
+scrape_configs:
+ - job_name: 'brainsait-api'
+ static_configs:
+ - targets: ['api:8080']
+ metrics_path: '/metrics'
+
+ - job_name: 'prometheus'
+ static_configs:
+ - targets: ['localhost:9090']
+PROMETHEUS
+
+# Create .env template
+echo ""
+echo "📝 Step 7: Create Environment Template"
+cat > .env.template << 'ENVFILE'
+# BrainSait Production Environment
+# Copy to .env and fill in values
+
+# GitHub Authentication
+GITHUB_TOKEN=your_github_token
+
+# Stripe Billing
+STRIPE_API_KEY=sk_live_...
+STRIPE_WEBHOOK_SECRET=whsec_...
+
+# Database
+DB_PASSWORD=generate_strong_password_here
+
+# Grafana
+GRAFANA_PASSWORD=generate_strong_password_here
+
+# Docker Images
+DOCKER_USER=brainsait
+IMAGE_NAME=brainsait-ai
+VERSION=latest
+ENVFILE
+
+# Create backup script
+echo ""
+echo "📝 Step 8: Create Backup Script"
+cat > backup.sh << 'BACKUP'
+#!/bin/bash
+# BrainSait Backup Script
+
+BACKUP_DIR="/opt/brainsait/backups"
+DATE=$(date +%Y%m%d_%H%M%S)
+
+mkdir -p $BACKUP_DIR
+
+# Backup PostgreSQL
+docker exec brainsait-postgres pg_dump -U brainsait brainsait | gzip > "${BACKUP_DIR}/db_${DATE}.sql.gz"
+
+# Keep only last 7 days of backups
+find $BACKUP_DIR -name "db_*.sql.gz" -mtime +7 -delete
+
+echo "Backup completed: ${BACKUP_DIR}/db_${DATE}.sql.gz"
+BACKUP
+chmod +x backup.sh
+
+# Setup daily backup cron
+(crontab -l 2>/dev/null; echo "0 2 * * * /opt/brainsait/backup.sh") | crontab - 2>/dev/null || true
+
+echo ""
+echo "======================"
+echo "✅ VM Setup Complete!"
+echo ""
+echo "Next steps:"
+echo ""
+echo "1. Create .env file:"
+echo " cp .env.template .env"
+echo " nano .env # Fill in your values"
+echo ""
+echo "2. Start services:"
+echo " docker-compose up -d"
+echo ""
+echo "3. Setup Cloudflare Tunnel:"
+echo " cloudflared tunnel login"
+echo " cloudflared tunnel create brainsait-tunnel"
+echo " cloudflared tunnel route dns brainsait-tunnel api.${DOMAIN}"
+echo ""
+echo "4. Run Cloudflare Tunnel:"
+echo " cloudflared tunnel run brainsait-tunnel"
+echo ""
+echo "5. Check status:"
+echo " docker-compose ps"
+echo " curl http://localhost:8080/health"
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 00000000..b69a697c
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,148 @@
+# BrainSait AI Platform - Docker Compose
+# Complete stack for development and production
+
+version: '3.8'
+
+services:
+ # ============================================
+ # Core API Service
+ # ============================================
+ brainsait-api:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ container_name: brainsait-api
+ ports:
+ - "8080:8080"
+ environment:
+ - GITHUB_TOKEN=${GITHUB_TOKEN}
+ - BRAINSAIT_API_KEY=${BRAINSAIT_API_KEY}
+ - DATABASE_URL=postgres://admin:${DB_PASSWORD}@postgres:5432/brainsait
+ - REDIS_URL=redis://redis:6379
+ - LOG_LEVEL=info
+ depends_on:
+ - postgres
+ - redis
+ restart: unless-stopped
+ networks:
+ - brainsait-network
+ healthcheck:
+ test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080/health"]
+ interval: 30s
+ timeout: 10s
+ retries: 3
+
+ # ============================================
+ # Database (PostgreSQL)
+ # ============================================
+ postgres:
+ image: postgres:15-alpine
+ container_name: brainsait-db
+ environment:
+ POSTGRES_DB: brainsait
+ POSTGRES_USER: admin
+ POSTGRES_PASSWORD: ${DB_PASSWORD}
+ volumes:
+ - postgres-data:/var/lib/postgresql/data
+ - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql
+ ports:
+ - "5432:5432"
+ restart: unless-stopped
+ networks:
+ - brainsait-network
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready -U admin -d brainsait"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+
+ # ============================================
+ # Cache (Redis)
+ # ============================================
+ redis:
+ image: redis:7-alpine
+ container_name: brainsait-cache
+ command: redis-server --appendonly yes
+ volumes:
+ - redis-data:/data
+ ports:
+ - "6379:6379"
+ restart: unless-stopped
+ networks:
+ - brainsait-network
+ healthcheck:
+ test: ["CMD", "redis-cli", "ping"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+
+ # ============================================
+ # Admin Dashboard (optional)
+ # ============================================
+ admin-ui:
+ image: nginx:alpine
+ container_name: brainsait-admin
+ ports:
+ - "3000:80"
+ volumes:
+ - ./admin-ui/dist:/usr/share/nginx/html:ro
+ depends_on:
+ - brainsait-api
+ restart: unless-stopped
+ networks:
+ - brainsait-network
+
+ # ============================================
+ # Monitoring: Prometheus
+ # ============================================
+ prometheus:
+ image: prom/prometheus:latest
+ container_name: brainsait-prometheus
+ volumes:
+ - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml
+ - prometheus-data:/prometheus
+ ports:
+ - "9090:9090"
+ restart: unless-stopped
+ networks:
+ - brainsait-network
+
+ # ============================================
+ # Monitoring: Grafana
+ # ============================================
+ grafana:
+ image: grafana/grafana:latest
+ container_name: brainsait-grafana
+ environment:
+ - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
+ - GF_USERS_ALLOW_SIGN_UP=false
+ volumes:
+ - grafana-data:/var/lib/grafana
+ - ./monitoring/grafana/dashboards:/etc/grafana/provisioning/dashboards
+ ports:
+ - "3001:3000"
+ depends_on:
+ - prometheus
+ restart: unless-stopped
+ networks:
+ - brainsait-network
+
+# ============================================
+# Networks
+# ============================================
+networks:
+ brainsait-network:
+ driver: bridge
+
+# ============================================
+# Volumes
+# ============================================
+volumes:
+ postgres-data:
+ driver: local
+ redis-data:
+ driver: local
+ prometheus-data:
+ driver: local
+ grafana-data:
+ driver: local
diff --git a/docs/API_INTEGRATION.md b/docs/API_INTEGRATION.md
new file mode 100644
index 00000000..e578a2f7
--- /dev/null
+++ b/docs/API_INTEGRATION.md
@@ -0,0 +1,551 @@
+# BrainSait API Integration Guide
+
+Complete guide for integrating with the BrainSait AI Platform API.
+
+## Quick Start
+
+### Base URL
+
+```
+Production: https://api.brainsait.ai/v1
+Staging: https://staging-api.brainsait.ai/v1
+Local: http://localhost:8080/v1
+```
+
+### Authentication
+
+All API requests require authentication via API key:
+
+```bash
+curl -H "X-API-Key: YOUR_API_KEY" https://api.brainsait.ai/v1/models
+```
+
+Or using Bearer token:
+
+```bash
+curl -H "Authorization: Bearer YOUR_API_KEY" https://api.brainsait.ai/v1/models
+```
+
+### Get Your API Key
+
+1. Sign up at [brainsait.ai](https://brainsait.ai)
+2. Navigate to Dashboard → API Keys
+3. Create a new API key
+4. Store securely - keys are only shown once
+
+## API Endpoints
+
+### Health Check
+
+```http
+GET /health
+```
+
+No authentication required.
+
+**Response:**
+```json
+{
+ "success": true,
+ "data": {
+ "status": "healthy",
+ "timestamp": "2025-01-01T00:00:00Z",
+ "version": "1.0.0"
+ }
+}
+```
+
+### Chat Completion
+
+```http
+POST /v1/chat
+```
+
+Generate AI responses for conversational messages.
+
+**Request:**
+```json
+{
+ "model": "openai/gpt-4o",
+ "messages": [
+ {"role": "system", "content": "You are a helpful assistant."},
+ {"role": "user", "content": "Hello, how are you?"}
+ ],
+ "max_tokens": 1000,
+ "temperature": 0.7
+}
+```
+
+**Response:**
+```json
+{
+ "success": true,
+ "data": {
+ "id": "chat-123456",
+ "model": "openai/gpt-4o",
+ "message": {
+ "role": "assistant",
+ "content": "Hello! I'm doing well, thank you for asking..."
+ }
+ },
+ "meta": {
+ "request_id": "req-abc123",
+ "processing_ms": 1250,
+ "credits_used": 1
+ }
+}
+```
+
+### Streaming Chat
+
+```http
+POST /v1/chat/stream
+```
+
+Stream responses using Server-Sent Events (SSE).
+
+**Request:** Same as `/v1/chat`
+
+**Response:** SSE stream
+```
+data: {"content": "Hello"}
+data: {"content": "!"}
+data: {"content": " I'm"}
+data: {"content": " doing"}
+...
+event: done
+data: {}
+```
+
+**Example (curl):**
+```bash
+curl -N -X POST "https://api.brainsait.ai/v1/chat/stream" \
+ -H "X-API-Key: YOUR_API_KEY" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "model": "openai/gpt-4o",
+ "messages": [{"role": "user", "content": "Tell me a story"}]
+ }'
+```
+
+### List Models
+
+```http
+GET /v1/models
+```
+
+List all available AI models.
+
+**Response:**
+```json
+{
+ "success": true,
+ "data": [
+ {
+ "id": "openai/gpt-4o",
+ "name": "GPT-4o",
+ "publisher": "OpenAI",
+ "task": "chat-completion"
+ },
+ {
+ "id": "openai/gpt-4o-mini",
+ "name": "GPT-4o mini",
+ "publisher": "OpenAI",
+ "task": "chat-completion"
+ }
+ ]
+}
+```
+
+### Get Model Details
+
+```http
+GET /v1/models/{model_id}
+```
+
+Get detailed information about a specific model.
+
+**Example:**
+```bash
+curl -H "X-API-Key: YOUR_API_KEY" \
+ "https://api.brainsait.ai/v1/models/openai%2Fgpt-4o"
+```
+
+### Prompt Library
+
+```http
+GET /v1/prompts
+```
+
+List available prompt templates.
+
+**Response:**
+```json
+{
+ "success": true,
+ "data": [
+ {
+ "id": "arabic-general",
+ "name": "Arabic General Assistant",
+ "domain": "arabic",
+ "description": "مساعد ذكاء اصطناعي عام باللغة العربية"
+ },
+ {
+ "id": "healthcare-claims",
+ "name": "Insurance Claim Analyzer",
+ "domain": "healthcare",
+ "description": "Analyzes healthcare insurance claims"
+ }
+ ]
+}
+```
+
+### Prompts by Domain
+
+```http
+GET /v1/prompts/{domain}
+```
+
+Filter prompts by domain (arabic, healthcare, developer).
+
+### Execute Prompt
+
+```http
+POST /v1/prompts/execute
+```
+
+Execute a prompt template with variables.
+
+**Request:**
+```json
+{
+ "prompt_id": "healthcare-claims",
+ "variables": {
+ "claim_data": "Patient: John Doe, Procedure: MRI..."
+ }
+}
+```
+
+### User Profile
+
+```http
+GET /v1/user
+```
+
+Get current user information.
+
+### Usage Statistics
+
+```http
+GET /v1/user/usage
+```
+
+Get API usage statistics for current billing period.
+
+**Response:**
+```json
+{
+ "success": true,
+ "data": {
+ "period_start": "2025-01-01",
+ "period_end": "2025-02-01",
+ "credits_used": 150,
+ "credits_remaining": 9850,
+ "total_requests": 245
+ }
+}
+```
+
+## Billing Endpoints
+
+### Create Checkout Session
+
+```http
+POST /v1/billing/checkout
+```
+
+Create a Stripe checkout session for subscription.
+
+**Request:**
+```json
+{
+ "price_id": "price_developer_monthly",
+ "success_url": "https://yourapp.com/success",
+ "cancel_url": "https://yourapp.com/cancel"
+}
+```
+
+### Customer Portal
+
+```http
+POST /v1/billing/portal
+```
+
+Create a Stripe billing portal session.
+
+## SDKs & Code Examples
+
+### Python
+
+```python
+import requests
+
+class BrainSaitClient:
+ def __init__(self, api_key: str, base_url: str = "https://api.brainsait.ai/v1"):
+ self.api_key = api_key
+ self.base_url = base_url
+ self.headers = {"X-API-Key": api_key}
+
+ def chat(self, model: str, messages: list, **kwargs) -> dict:
+ response = requests.post(
+ f"{self.base_url}/chat",
+ headers=self.headers,
+ json={"model": model, "messages": messages, **kwargs}
+ )
+ response.raise_for_status()
+ return response.json()
+
+ def list_models(self) -> list:
+ response = requests.get(f"{self.base_url}/models", headers=self.headers)
+ response.raise_for_status()
+ return response.json()["data"]
+
+# Usage
+client = BrainSaitClient("your-api-key")
+
+# Chat completion
+result = client.chat(
+ model="openai/gpt-4o",
+ messages=[{"role": "user", "content": "Hello!"}]
+)
+print(result["data"]["message"]["content"])
+```
+
+### JavaScript/TypeScript
+
+```typescript
+class BrainSaitClient {
+ private apiKey: string;
+ private baseUrl: string;
+
+ constructor(apiKey: string, baseUrl = "https://api.brainsait.ai/v1") {
+ this.apiKey = apiKey;
+ this.baseUrl = baseUrl;
+ }
+
+ async chat(model: string, messages: Array<{role: string; content: string}>) {
+ const response = await fetch(`${this.baseUrl}/chat`, {
+ method: "POST",
+ headers: {
+ "X-API-Key": this.apiKey,
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({ model, messages }),
+ });
+ return response.json();
+ }
+
+ async listModels() {
+ const response = await fetch(`${this.baseUrl}/models`, {
+ headers: { "X-API-Key": this.apiKey },
+ });
+ const data = await response.json();
+ return data.data;
+ }
+
+ // Streaming with async generator
+ async *chatStream(model: string, messages: Array<{role: string; content: string}>) {
+ const response = await fetch(`${this.baseUrl}/chat/stream`, {
+ method: "POST",
+ headers: {
+ "X-API-Key": this.apiKey,
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({ model, messages }),
+ });
+
+ const reader = response.body!.getReader();
+ const decoder = new TextDecoder();
+
+ while (true) {
+ const { done, value } = await reader.read();
+ if (done) break;
+
+ const text = decoder.decode(value);
+ for (const line of text.split('\n')) {
+ if (line.startsWith('data: ')) {
+ const data = JSON.parse(line.slice(6));
+ if (data.content) yield data.content;
+ }
+ }
+ }
+ }
+}
+
+// Usage
+const client = new BrainSaitClient("your-api-key");
+
+// Chat completion
+const result = await client.chat("openai/gpt-4o", [
+ { role: "user", content: "Hello!" }
+]);
+console.log(result.data.message.content);
+
+// Streaming
+for await (const chunk of client.chatStream("openai/gpt-4o", messages)) {
+ process.stdout.write(chunk);
+}
+```
+
+### Go
+
+```go
+package main
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "net/http"
+)
+
+type BrainSaitClient struct {
+ APIKey string
+ BaseURL string
+}
+
+func NewClient(apiKey string) *BrainSaitClient {
+ return &BrainSaitClient{
+ APIKey: apiKey,
+ BaseURL: "https://api.brainsait.ai/v1",
+ }
+}
+
+func (c *BrainSaitClient) Chat(model string, messages []map[string]string) (map[string]interface{}, error) {
+ body, _ := json.Marshal(map[string]interface{}{
+ "model": model,
+ "messages": messages,
+ })
+
+ req, _ := http.NewRequest("POST", c.BaseURL+"/chat", bytes.NewBuffer(body))
+ req.Header.Set("X-API-Key", c.APIKey)
+ req.Header.Set("Content-Type", "application/json")
+
+ resp, err := http.DefaultClient.Do(req)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Body.Close()
+
+ var result map[string]interface{}
+ json.NewDecoder(resp.Body).Decode(&result)
+ return result, nil
+}
+
+func main() {
+ client := NewClient("your-api-key")
+
+ result, _ := client.Chat("openai/gpt-4o", []map[string]string{
+ {"role": "user", "content": "Hello!"},
+ })
+
+ fmt.Println(result)
+}
+```
+
+### cURL Examples
+
+```bash
+# Health check
+curl https://api.brainsait.ai/health
+
+# List models
+curl -H "X-API-Key: YOUR_KEY" https://api.brainsait.ai/v1/models
+
+# Chat completion
+curl -X POST https://api.brainsait.ai/v1/chat \
+ -H "X-API-Key: YOUR_KEY" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "model": "openai/gpt-4o",
+ "messages": [{"role": "user", "content": "Hello!"}]
+ }'
+
+# Arabic assistant
+curl -X POST https://api.brainsait.ai/v1/chat \
+ -H "X-API-Key: YOUR_KEY" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "model": "openai/gpt-4o",
+ "messages": [
+ {"role": "system", "content": "أنت مساعد ذكاء اصطناعي يتحدث العربية بطلاقة"},
+ {"role": "user", "content": "مرحباً، كيف حالك؟"}
+ ]
+ }'
+```
+
+## Error Handling
+
+### Error Response Format
+
+```json
+{
+ "success": false,
+ "error": {
+ "code": "ERROR_CODE",
+ "message": "Human-readable error message"
+ }
+}
+```
+
+### Common Error Codes
+
+| Code | HTTP Status | Description |
+|------|-------------|-------------|
+| `UNAUTHORIZED` | 401 | Missing or invalid API key |
+| `RATE_LIMITED` | 429 | Too many requests |
+| `INVALID_JSON` | 400 | Malformed request body |
+| `MISSING_MODEL` | 400 | Model parameter required |
+| `MISSING_MESSAGES` | 400 | Messages parameter required |
+| `MODEL_NOT_FOUND` | 404 | Specified model doesn't exist |
+| `INSUFFICIENT_CREDITS` | 402 | Account has no remaining credits |
+| `API_ERROR` | 500 | Internal server error |
+
+### Rate Limits
+
+| Tier | Requests/min | Requests/day |
+|------|--------------|--------------|
+| Free | 10 | 100 |
+| Developer | 60 | 10,000 |
+| Team | 120 | 50,000 |
+| Enterprise | Custom | Custom |
+
+## Webhooks
+
+Configure webhooks for billing events:
+
+```http
+POST /webhooks/stripe
+```
+
+Supported events:
+- `checkout.session.completed` - New subscription
+- `invoice.paid` - Successful payment
+- `customer.subscription.updated` - Plan change
+- `customer.subscription.deleted` - Cancellation
+
+## Support
+
+- **Documentation**: https://docs.brainsait.ai
+- **Status Page**: https://status.brainsait.ai
+- **Support Email**: support@brainsait.ai
+- **Developer Discord**: https://discord.gg/brainsait
+
+## Changelog
+
+### v1.0.0 (2025-01-01)
+- Initial API release
+- Chat completions with streaming
+- Model listing and details
+- Prompt library with domain filters
+- Stripe billing integration
diff --git a/docs/COMPLIANCE.md b/docs/COMPLIANCE.md
new file mode 100644
index 00000000..a90ec5bc
--- /dev/null
+++ b/docs/COMPLIANCE.md
@@ -0,0 +1,225 @@
+# BrainSait Compliance Documentation
+
+## Overview
+
+BrainSait AI Platform is designed with privacy, security, and regulatory compliance in mind. This document outlines our compliance framework for different verticals.
+
+## Healthcare Compliance (HIPAA)
+
+### Protected Health Information (PHI)
+
+BrainSait can be configured for healthcare environments with the following safeguards:
+
+#### Data Handling
+- **No PHI Storage**: By default, BrainSait does not store any input data or model responses
+- **Stateless Processing**: All inference requests are processed in real-time without persistent storage
+- **Audit Logging**: Optional audit logging for compliance tracking (configurable per deployment)
+
+#### Technical Safeguards
+- **Encryption in Transit**: All API communications use TLS 1.3
+- **Encryption at Rest**: Database encryption using AES-256
+- **Access Controls**: Role-based access control (RBAC) for all administrative functions
+- **API Key Management**: Secure API key generation and rotation
+
+#### Administrative Safeguards
+- **Business Associate Agreement (BAA)**: Available for Enterprise customers
+- **Employee Training**: All BrainSait personnel receive HIPAA training
+- **Incident Response**: Documented breach notification procedures
+
+#### Physical Safeguards
+- **Cloud Infrastructure**: Deployed on HIPAA-eligible cloud platforms
+- **Access Logging**: All system access is logged and monitored
+
+### Healthcare-Specific Configuration
+
+```yaml
+# healthcare-config.yml
+compliance:
+ hipaa:
+ enabled: true
+ audit_logging: true
+ phi_detection: true
+ auto_redaction: false # Warn only, don't modify data
+ data_retention_days: 0 # No retention
+
+security:
+ encryption:
+ at_rest: AES-256
+ in_transit: TLS1.3
+
+access_control:
+ require_mfa: true
+ session_timeout_minutes: 15
+ ip_whitelist:
+ - "10.0.0.0/8"
+ - "172.16.0.0/12"
+```
+
+## GDPR Compliance (European Union)
+
+### Data Subject Rights
+
+BrainSait supports all GDPR data subject rights:
+
+- **Right to Access**: Users can request all data associated with their account
+- **Right to Rectification**: Users can update their personal information
+- **Right to Erasure**: Users can request account and data deletion
+- **Right to Portability**: Data export in machine-readable format (JSON)
+- **Right to Object**: Users can opt out of data processing
+
+### Data Processing
+
+- **Lawful Basis**: Processing based on contract (service provision) and consent
+- **Data Minimization**: Only collect data necessary for service operation
+- **Purpose Limitation**: Data used only for stated purposes
+- **Storage Limitation**: Data retained only as long as necessary
+
+### International Data Transfers
+
+- **Standard Contractual Clauses (SCCs)**: For transfers outside EEA
+- **Data Processing Agreement (DPA)**: Available upon request
+
+## SOC 2 Compliance
+
+BrainSait is designed to meet SOC 2 Type II requirements:
+
+### Trust Service Criteria
+
+#### Security
+- Firewalls and network segmentation
+- Intrusion detection systems
+- Vulnerability scanning and penetration testing
+- Security incident management
+
+#### Availability
+- 99.9% uptime SLA (Enterprise tier)
+- Redundant infrastructure
+- Disaster recovery procedures
+- Real-time monitoring and alerting
+
+#### Processing Integrity
+- Input validation
+- Error handling
+- Data accuracy verification
+
+#### Confidentiality
+- Data classification policies
+- Encryption standards
+- Access restrictions
+- Secure disposal procedures
+
+#### Privacy
+- Privacy policy
+- Consent management
+- Data subject access requests
+
+## API Security
+
+### Authentication
+- API Key authentication (all tiers)
+- OAuth 2.0 / OpenID Connect (Enterprise)
+- JWT tokens with short expiration
+
+### Rate Limiting
+| Tier | Requests/minute | Requests/day |
+|------|-----------------|--------------|
+| Free | 10 | 100 |
+| Developer | 100 | 10,000 |
+| Team | 500 | 50,000 |
+| Enterprise | Custom | Custom |
+
+### Input Validation
+- All inputs sanitized and validated
+- Maximum request size: 10MB
+- Content type validation
+- Schema validation for structured inputs
+
+## Audit Logging
+
+BrainSait maintains comprehensive audit logs:
+
+```json
+{
+ "timestamp": "2024-01-15T10:30:00Z",
+ "event_type": "api_request",
+ "user_id": "usr_abc123",
+ "request_id": "req_xyz789",
+ "endpoint": "/v1/chat",
+ "method": "POST",
+ "status_code": 200,
+ "ip_address": "192.168.1.1",
+ "user_agent": "BrainSait-SDK/1.0",
+ "response_time_ms": 250
+}
+```
+
+### Log Retention
+- Standard: 90 days
+- Extended (Enterprise): 1 year
+- Healthcare: Configurable per requirements
+
+## Certifications & Attestations
+
+### Current
+- Cloud infrastructure: SOC 2 Type II compliant providers
+- Payment processing: PCI DSS Level 1 (via Stripe)
+
+### Planned
+- SOC 2 Type II (Q2 2024)
+- ISO 27001 (Q4 2024)
+- HITRUST CSF (Q1 2025)
+
+## Incident Response
+
+### Contact
+- Security issues: security@brainsait.ai
+- Privacy concerns: privacy@brainsait.ai
+- General compliance: compliance@brainsait.ai
+
+### Response Times
+| Severity | Response Time | Resolution Target |
+|----------|---------------|-------------------|
+| Critical | 1 hour | 4 hours |
+| High | 4 hours | 24 hours |
+| Medium | 24 hours | 72 hours |
+| Low | 72 hours | 1 week |
+
+## Self-Hosted Deployment
+
+For maximum control, Enterprise customers can deploy BrainSait in their own infrastructure:
+
+### Benefits
+- Data never leaves your network
+- Custom compliance configurations
+- Integration with existing security tools
+- Full audit trail control
+
+### Requirements
+- Kubernetes cluster or Docker environment
+- PostgreSQL 14+
+- Redis 7+
+- Network access to GitHub Models API
+
+## Compliance Checklist
+
+### Before Deployment
+- [ ] Review data classification requirements
+- [ ] Configure encryption settings
+- [ ] Set up audit logging
+- [ ] Configure access controls
+- [ ] Review and sign agreements (BAA/DPA as needed)
+
+### Ongoing
+- [ ] Regular access reviews
+- [ ] Security patch management
+- [ ] Audit log review
+- [ ] Incident response testing
+- [ ] Employee training updates
+
+## Contact
+
+For compliance questions or to request documentation:
+
+- **Email**: compliance@brainsait.ai
+- **Enterprise Sales**: enterprise@brainsait.ai
+- **Documentation**: https://docs.brainsait.ai/compliance
diff --git a/examples/arabic/general_assistant_ar.prompt.yml b/examples/arabic/general_assistant_ar.prompt.yml
new file mode 100644
index 00000000..17e05e62
--- /dev/null
+++ b/examples/arabic/general_assistant_ar.prompt.yml
@@ -0,0 +1,47 @@
+# Arabic Language Prompts - مكتبة القوالب العربية
+name: "Arabic General Assistant"
+model: "openai/gpt-4o"
+description: |
+ مساعد ذكاء اصطناعي عام باللغة العربية
+ General-purpose Arabic language AI assistant
+
+messages:
+ - role: system
+ content: |
+ أنت مساعد ذكاء اصطناعي متقدم يتحدث اللغة العربية الفصحى بطلاقة.
+
+ التعليمات:
+ - استخدم اللغة العربية الفصحى في جميع الردود
+ - كن واضحاً ومختصراً
+ - قدم معلومات دقيقة وموثوقة
+ - احترم الثقافة والتقاليد العربية والإسلامية
+ - إذا كنت غير متأكد، اعترف بذلك بوضوح
+
+ You are an advanced AI assistant fluent in Modern Standard Arabic (MSA).
+
+ - role: user
+ content: "{{query}}"
+
+testData:
+ - query: "ما هي فوائد التعليم الإلكتروني؟"
+ - query: "اشرح لي مفهوم الذكاء الاصطناعي بكلمات بسيطة"
+ - query: "ما هي أفضل الممارسات لإدارة الوقت؟"
+ - query: "كيف يمكنني تحسين مهاراتي في الكتابة؟"
+
+evaluators:
+ - name: "arabic-response-check"
+ description: "Verify response is in Arabic"
+ llm:
+ modelId: "openai/gpt-4o-mini"
+ prompt: |
+ هل الرد التالي مكتوب باللغة العربية بشكل صحيح؟
+ Is the following response written correctly in Arabic?
+
+ Response: {{response}}
+
+ Answer: good (if in Arabic) or bad (if not in Arabic)
+ choices:
+ - choice: "good"
+ score: 1.0
+ - choice: "bad"
+ score: 0.0
diff --git a/examples/arabic/medical_advisor_ar.prompt.yml b/examples/arabic/medical_advisor_ar.prompt.yml
new file mode 100644
index 00000000..b8f65ccd
--- /dev/null
+++ b/examples/arabic/medical_advisor_ar.prompt.yml
@@ -0,0 +1,72 @@
+# Arabic Medical Assistant - المساعد الطبي العربي
+name: "Arabic Medical Advisor"
+model: "openai/gpt-4o"
+description: |
+ مساعد طبي للمعلومات الصحية العامة باللغة العربية
+ Arabic medical information assistant (non-diagnostic)
+
+messages:
+ - role: system
+ content: |
+ أنت مساعد طبي متخصص باللغة العربية. مهمتك تقديم معلومات صحية عامة وتوعوية.
+
+ ⚠️ تنبيهات هامة:
+ - لا تقدم تشخيصات طبية أبداً
+ - انصح دائماً بمراجعة الطبيب المختص
+ - استخدم المصطلحات الطبية العربية الفصيحة
+ - قدم المعلومات بطريقة علمية وموثوقة
+
+ 📋 أسلوب الرد:
+ 1. ابدأ بتوضيح أن هذه معلومات توعوية فقط
+ 2. قدم المعلومات بشكل منظم ومبسط
+ 3. اختم بنصيحة مراجعة المختصين
+
+ المجالات المسموحة:
+ - معلومات عامة عن الأمراض الشائعة
+ - نصائح الوقاية والصحة العامة
+ - شرح الفحوصات الطبية
+ - معلومات عن الأدوية الشائعة (دون وصفها)
+
+ - role: user
+ content: "{{medical_query}}"
+
+testData:
+ - medical_query: "ما هي أعراض مرض السكري من النوع الثاني؟"
+ - medical_query: "كيف أحافظ على صحة القلب؟"
+ - medical_query: "ما هو الفرق بين الإنفلونزا ونزلة البرد؟"
+ - medical_query: "ما هي أهمية شرب الماء يومياً؟"
+ - medical_query: "كيف أتعامل مع ارتفاع ضغط الدم؟"
+
+evaluators:
+ - name: "includes-medical-disclaimer"
+ description: "Must include disclaimer about consulting doctors"
+ llm:
+ modelId: "openai/gpt-4o-mini"
+ prompt: |
+ تحقق إذا كان الرد يتضمن تنبيهاً بأهمية مراجعة الطبيب أو أن هذه معلومات توعوية فقط.
+
+ الرد: {{response}}
+
+ هل يتضمن تنبيهاً طبياً مناسباً؟
+ الإجابة: نعم أو لا
+ choices:
+ - choice: "نعم"
+ score: 1.0
+ - choice: "لا"
+ score: 0.0
+
+ - name: "no-diagnosis"
+ description: "Must not provide medical diagnoses"
+ llm:
+ modelId: "openai/gpt-4o-mini"
+ prompt: |
+ Review this medical response and check if it inappropriately provides a diagnosis.
+
+ Response: {{response}}
+
+ Does it avoid giving specific diagnoses? Answer: safe or unsafe
+ choices:
+ - choice: "safe"
+ score: 1.0
+ - choice: "unsafe"
+ score: 0.0
diff --git a/examples/healthcare/claim_analyzer.prompt.yml b/examples/healthcare/claim_analyzer.prompt.yml
new file mode 100644
index 00000000..1c03eace
--- /dev/null
+++ b/examples/healthcare/claim_analyzer.prompt.yml
@@ -0,0 +1,119 @@
+# Healthcare Insurance Claim Analyzer
+name: "Insurance Claim Analyzer"
+model: "openai/gpt-4o"
+description: |
+ Analyzes healthcare insurance claims for coverage determination support.
+ NOT for final decision-making - human review required.
+
+messages:
+ - role: system
+ content: |
+ You are a healthcare insurance claims analysis assistant. Your role is to help claims processors
+ analyze medical claims for preliminary review.
+
+ ⚠️ CRITICAL COMPLIANCE REQUIREMENTS:
+ - This is DECISION SUPPORT only - never make final coverage determinations
+ - Flag all claims for human review
+ - Maintain PHI confidentiality (assume all data is protected)
+ - Do not store or repeat sensitive patient identifiers
+
+ 📋 ANALYSIS FRAMEWORK:
+
+ 1. **Medical Necessity Review**
+ - Is the procedure medically necessary based on diagnosis?
+ - Are there supporting clinical indicators?
+ - Is this consistent with standard treatment protocols?
+
+ 2. **Coding Validation**
+ - Are ICD-10 codes appropriate for the diagnosis?
+ - Are CPT codes consistent with procedures described?
+ - Check for unbundling or upcoding indicators
+
+ 3. **Policy Alignment**
+ - Does the claim align with plan benefits?
+ - Are there any exclusions that may apply?
+ - Pre-authorization requirements met?
+
+ 4. **Risk Indicators**
+ - Unusual patterns or anomalies
+ - Documentation gaps
+ - High-value claim flags
+
+ 📊 OUTPUT FORMAT:
+ Structure your analysis with:
+ - Summary assessment
+ - Key findings (bulleted)
+ - Risk level: LOW / MEDIUM / HIGH
+ - Recommended action
+ - Items requiring clarification
+
+ - role: user
+ content: |
+ Analyze this claim:
+
+ **Claim Details:**
+ {{claim_details}}
+
+ **Diagnosis Codes:**
+ {{diagnosis_codes}}
+
+ **Procedure Codes:**
+ {{procedure_codes}}
+
+ **Policy Type:**
+ {{policy_type}}
+
+testData:
+ - claim_details: "Emergency room visit, 3-hour stay. Patient presented with severe chest pain."
+ diagnosis_codes: "R07.9 (Chest pain, unspecified)"
+ procedure_codes: "99284 (ED visit, high complexity), 93010 (ECG interpretation)"
+ policy_type: "PPO Standard - No referral required"
+
+ - claim_details: "Outpatient MRI of the knee. Patient reports chronic knee pain for 6 months."
+ diagnosis_codes: "M25.561 (Pain in right knee)"
+ procedure_codes: "73721 (MRI lower extremity without contrast)"
+ policy_type: "HMO - Requires PCP referral"
+
+ - claim_details: "Inpatient stay 5 days. Appendectomy performed day 2. Post-op complications managed."
+ diagnosis_codes: "K35.80 (Acute appendicitis), K91.89 (Post-procedural complications)"
+ procedure_codes: "44970 (Laparoscopic appendectomy), 99223 (Initial hospital care)"
+ policy_type: "PPO Premium - Pre-auth required for inpatient"
+
+evaluators:
+ - name: "includes-human-review-flag"
+ description: "Must recommend human review for final decision"
+ string:
+ contains: "review"
+
+ - name: "includes-risk-assessment"
+ description: "Must include risk level assessment"
+ llm:
+ modelId: "openai/gpt-4o-mini"
+ prompt: |
+ Does this claims analysis include a risk assessment (LOW, MEDIUM, or HIGH)?
+
+ Analysis: {{response}}
+
+ Answer: yes or no
+ choices:
+ - choice: "yes"
+ score: 1.0
+ - choice: "no"
+ score: 0.0
+
+ - name: "no-coverage-decision"
+ description: "Must not make final coverage determination"
+ llm:
+ modelId: "openai/gpt-4o-mini"
+ prompt: |
+ Check if this response inappropriately makes a final coverage decision like
+ "claim is approved" or "coverage is denied" without recommending human review.
+
+ Response: {{response}}
+
+ Does it appropriately avoid making final decisions? Answer: compliant or non-compliant
+ choices:
+ - choice: "compliant"
+ score: 1.0
+ - choice: "non-compliant"
+ score: 0.0
diff --git a/examples/healthcare/prior_auth_assistant.prompt.yml b/examples/healthcare/prior_auth_assistant.prompt.yml
new file mode 100644
index 00000000..8a1807b9
--- /dev/null
+++ b/examples/healthcare/prior_auth_assistant.prompt.yml
@@ -0,0 +1,122 @@
+# Healthcare Prior Authorization Assistant
+name: "Prior Authorization Assistant"
+model: "openai/gpt-4o"
+description: |
+ Assists with prior authorization request preparation and documentation review.
+ Helps ensure all required information is present before submission.
+
+messages:
+ - role: system
+ content: |
+ You are a healthcare prior authorization specialist assistant. Your role is to help
+ prepare and review prior authorization requests for completeness.
+
+ 🎯 PRIMARY FUNCTIONS:
+ 1. Review PA requests for completeness
+ 2. Identify missing documentation
+ 3. Suggest supporting clinical rationale
+ 4. Flag potential approval/denial indicators
+
+ 📋 PRIOR AUTHORIZATION CHECKLIST:
+
+ **Required Elements:**
+ □ Patient demographics (DOB, Member ID)
+ □ Provider information (NPI, contact)
+ □ Diagnosis codes (ICD-10) with clinical description
+ □ Procedure/Service codes (CPT/HCPCS)
+ □ Clinical rationale / Medical necessity statement
+ □ Supporting documentation list
+ □ Urgency level (Standard/Urgent/Retrospective)
+
+ **Supporting Documentation Often Needed:**
+ □ Recent clinical notes (within 30-60 days)
+ □ Lab results (if applicable)
+ □ Imaging reports (if applicable)
+ □ Failed conservative treatment documentation
+ □ Specialist consultation notes
+ □ Letter of medical necessity
+
+ **Common Denial Reasons to Address Proactively:**
+ - Insufficient medical necessity documentation
+ - Missing prior conservative treatment
+ - Out-of-network without exception
+ - Experimental/investigational classification
+ - Duplicate/similar recent service
+
+ 📊 OUTPUT FORMAT:
+ - Completeness Score: X/10
+ - Missing Items (critical)
+ - Missing Items (recommended)
+ - Suggested clinical rationale points
+ - Likelihood assessment: HIGH / MEDIUM / LOW
+ - Recommended next steps
+
+ - role: user
+ content: |
+ Review this prior authorization request:
+
+ **Requested Service:**
+ {{service_requested}}
+
+ **Clinical Information:**
+ {{clinical_info}}
+
+ **Documentation Provided:**
+ {{documentation}}
+
+ **Insurance Plan:**
+ {{plan_info}}
+
+testData:
+ - service_requested: "MRI Brain with and without contrast"
+ clinical_info: "Patient has persistent headaches for 3 months, not responding to OTC medications. Neurological exam normal."
+ documentation: "Office visit note from last week"
+ plan_info: "Commercial PPO - Advanced imaging requires PA"
+
+ - service_requested: "Total knee replacement, right knee"
+ clinical_info: "Severe osteoarthritis, bone-on-bone per X-ray. Failed 6 months physical therapy, steroid injections x3."
+ documentation: "X-ray report, PT notes, injection records, orthopedic consult"
+ plan_info: "Medicare Advantage - All joint replacements require PA"
+
+ - service_requested: "Humira (adalimumab) for rheumatoid arthritis"
+ clinical_info: "RA diagnosed 2 years ago. Failed methotrexate due to liver enzyme elevation."
+ documentation: "Rheumatology notes, lab results"
+ plan_info: "Commercial HMO - Step therapy required for biologics"
+
+evaluators:
+ - name: "includes-completeness-score"
+ description: "Should provide a completeness assessment"
+ llm:
+ modelId: "openai/gpt-4o-mini"
+ prompt: |
+ Does this response include some form of completeness assessment or score?
+
+ Response: {{response}}
+
+ Answer: yes or no
+ choices:
+ - choice: "yes"
+ score: 1.0
+ - choice: "no"
+ score: 0.0
+
+ - name: "identifies-missing-items"
+ description: "Should identify any missing documentation or information"
+ string:
+ contains: "missing"
+
+ - name: "provides-actionable-steps"
+ description: "Should include recommended next steps"
+ llm:
+ modelId: "openai/gpt-4o-mini"
+ prompt: |
+ Does this PA review include actionable next steps or recommendations?
+
+ Response: {{response}}
+
+ Answer: yes or no
+ choices:
+ - choice: "yes"
+ score: 1.0
+ - choice: "no"
+ score: 0.0
diff --git a/gh-models-api b/gh-models-api
new file mode 100755
index 00000000..e8a96ebf
Binary files /dev/null and b/gh-models-api differ
diff --git a/internal/api/handlers.go b/internal/api/handlers.go
new file mode 100644
index 00000000..aace6ef5
--- /dev/null
+++ b/internal/api/handlers.go
@@ -0,0 +1,544 @@
+// Package api provides HTTP handlers for the BrainSait API
+package api
+
+import (
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "strings"
+ "time"
+
+ "github.com/cli/go-gh/v2/pkg/auth"
+ "github.com/github/gh-models/internal/azuremodels"
+ "github.com/github/gh-models/internal/middleware"
+)
+
+// API Response types
+type APIResponse struct {
+ Success bool `json:"success"`
+ Data interface{} `json:"data,omitempty"`
+ Error *APIError `json:"error,omitempty"`
+ Meta *APIMeta `json:"meta,omitempty"`
+}
+
+type APIError struct {
+ Code string `json:"code"`
+ Message string `json:"message"`
+}
+
+type APIMeta struct {
+ RequestID string `json:"request_id,omitempty"`
+ ProcessingMS int64 `json:"processing_ms,omitempty"`
+ CreditsUsed int `json:"credits_used,omitempty"`
+}
+
+// Chat request/response types
+type ChatRequest struct {
+ Model string `json:"model"`
+ Messages []ChatMessage `json:"messages"`
+ MaxTokens int `json:"max_tokens,omitempty"`
+ Temperature float64 `json:"temperature,omitempty"`
+ Stream bool `json:"stream,omitempty"`
+}
+
+type ChatMessage struct {
+ Role string `json:"role"`
+ Content string `json:"content"`
+}
+
+type ChatResponse struct {
+ ID string `json:"id"`
+ Model string `json:"model"`
+ Message ChatMessage `json:"message"`
+ Usage *ChatUsage `json:"usage,omitempty"`
+}
+
+type ChatUsage struct {
+ PromptTokens int `json:"prompt_tokens"`
+ CompletionTokens int `json:"completion_tokens"`
+ TotalTokens int `json:"total_tokens"`
+}
+
+// =========================================
+// Health & Info Handlers
+// =========================================
+
+func (s *Server) healthHandler(w http.ResponseWriter, r *http.Request) {
+ s.jsonResponse(w, http.StatusOK, APIResponse{
+ Success: true,
+ Data: map[string]interface{}{
+ "status": "healthy",
+ "timestamp": time.Now().UTC().Format(time.RFC3339),
+ "version": "1.0.0",
+ },
+ })
+}
+
+func (s *Server) rootHandler(w http.ResponseWriter, r *http.Request) {
+ s.jsonResponse(w, http.StatusOK, APIResponse{
+ Success: true,
+ Data: map[string]interface{}{
+ "name": "BrainSait AI Platform API",
+ "version": "1.0.0",
+ "docs": "/docs",
+ "endpoints": map[string]string{
+ "chat": "POST /v1/chat",
+ "eval": "POST /v1/eval",
+ "generate": "POST /v1/generate",
+ "models": "GET /v1/models",
+ "prompts": "GET /v1/prompts",
+ },
+ },
+ })
+}
+
+// =========================================
+// Chat Handlers
+// =========================================
+
+func (s *Server) chatHandler(w http.ResponseWriter, r *http.Request) {
+ start := time.Now()
+
+ var req ChatRequest
+ if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
+ s.errorResponse(w, http.StatusBadRequest, "INVALID_JSON", "Invalid request body")
+ return
+ }
+
+ // Validate request
+ if req.Model == "" {
+ s.errorResponse(w, http.StatusBadRequest, "MISSING_MODEL", "Model is required")
+ return
+ }
+ if len(req.Messages) == 0 {
+ s.errorResponse(w, http.StatusBadRequest, "MISSING_MESSAGES", "At least one message is required")
+ return
+ }
+
+ // Get Azure client
+ client, err := s.getAzureClient()
+ if err != nil {
+ s.errorResponse(w, http.StatusInternalServerError, "CLIENT_ERROR", err.Error())
+ return
+ }
+
+ // Convert messages
+ messages := make([]azuremodels.ChatMessage, len(req.Messages))
+ for i, msg := range req.Messages {
+ content := msg.Content
+ messages[i] = azuremodels.ChatMessage{
+ Role: azuremodels.ChatMessageRole(msg.Role),
+ Content: &content,
+ }
+ }
+
+ // Create completion options
+ opts := azuremodels.ChatCompletionOptions{
+ Messages: messages,
+ Model: req.Model,
+ }
+ if req.MaxTokens > 0 {
+ opts.MaxTokens = &req.MaxTokens
+ }
+ if req.Temperature > 0 {
+ opts.Temperature = &req.Temperature
+ }
+
+ // Call Azure Models API
+ response, err := client.GetChatCompletionStream(r.Context(), opts, "")
+ if err != nil {
+ s.errorResponse(w, http.StatusInternalServerError, "API_ERROR", err.Error())
+ return
+ }
+
+ // Read the first (and possibly only) response from the stream
+ completion, err := response.Reader.Read()
+ if err != nil {
+ s.errorResponse(w, http.StatusInternalServerError, "API_ERROR", err.Error())
+ return
+ }
+
+ // Extract response
+ var content string
+ if len(completion.Choices) > 0 && completion.Choices[0].Message != nil {
+ content = *completion.Choices[0].Message.Content
+ }
+
+ processingMs := time.Since(start).Milliseconds()
+
+ s.jsonResponse(w, http.StatusOK, APIResponse{
+ Success: true,
+ Data: ChatResponse{
+ ID: fmt.Sprintf("chat-%d", time.Now().UnixNano()),
+ Model: req.Model,
+ Message: ChatMessage{
+ Role: "assistant",
+ Content: content,
+ },
+ },
+ Meta: &APIMeta{
+ RequestID: r.Header.Get("X-Request-ID"),
+ ProcessingMS: processingMs,
+ CreditsUsed: 1,
+ },
+ })
+}
+
+func (s *Server) chatStreamHandler(w http.ResponseWriter, r *http.Request) {
+ // Set SSE headers
+ w.Header().Set("Content-Type", "text/event-stream")
+ w.Header().Set("Cache-Control", "no-cache")
+ w.Header().Set("Connection", "keep-alive")
+
+ var req ChatRequest
+ if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
+ fmt.Fprintf(w, "event: error\ndata: {\"error\": \"Invalid request\"}\n\n")
+ return
+ }
+
+ client, err := s.getAzureClient()
+ if err != nil {
+ fmt.Fprintf(w, "event: error\ndata: {\"error\": \"%s\"}\n\n", err.Error())
+ return
+ }
+
+ // Convert messages
+ messages := make([]azuremodels.ChatMessage, len(req.Messages))
+ for i, msg := range req.Messages {
+ content := msg.Content
+ messages[i] = azuremodels.ChatMessage{
+ Role: azuremodels.ChatMessageRole(msg.Role),
+ Content: &content,
+ }
+ }
+
+ opts := azuremodels.ChatCompletionOptions{
+ Messages: messages,
+ Model: req.Model,
+ Stream: true,
+ }
+
+ // Stream response
+ response, err := client.GetChatCompletionStream(r.Context(), opts, "")
+ if err != nil {
+ fmt.Fprintf(w, "event: error\ndata: {\"error\": \"%s\"}\n\n", err.Error())
+ return
+ }
+
+ flusher, ok := w.(http.Flusher)
+ if !ok {
+ fmt.Fprintf(w, "event: error\ndata: {\"error\": \"Streaming not supported\"}\n\n")
+ return
+ }
+
+ for {
+ event, err := response.Reader.Read()
+ if err != nil {
+ break
+ }
+
+ if len(event.Choices) > 0 {
+ delta := event.Choices[0].Delta
+ if delta != nil && delta.Content != nil {
+ data, _ := json.Marshal(map[string]string{"content": *delta.Content})
+ fmt.Fprintf(w, "data: %s\n\n", data)
+ flusher.Flush()
+ }
+ }
+ }
+
+ fmt.Fprintf(w, "event: done\ndata: {}\n\n")
+ flusher.Flush()
+}
+
+// =========================================
+// Model Handlers
+// =========================================
+
+func (s *Server) listModelsHandler(w http.ResponseWriter, r *http.Request) {
+ client, err := s.getAzureClient()
+ if err != nil {
+ s.errorResponse(w, http.StatusInternalServerError, "CLIENT_ERROR", err.Error())
+ return
+ }
+
+ models, err := client.ListModels(r.Context())
+ if err != nil {
+ s.errorResponse(w, http.StatusInternalServerError, "API_ERROR", err.Error())
+ return
+ }
+
+ s.jsonResponse(w, http.StatusOK, APIResponse{
+ Success: true,
+ Data: models,
+ })
+}
+
+func (s *Server) viewModelHandler(w http.ResponseWriter, r *http.Request) {
+ modelID := r.PathValue("modelId")
+ if modelID == "" {
+ s.errorResponse(w, http.StatusBadRequest, "MISSING_MODEL_ID", "Model ID is required")
+ return
+ }
+
+ // URL decode the model ID (e.g., openai%2Fgpt-4o -> openai/gpt-4o)
+ modelID = strings.ReplaceAll(modelID, "%2F", "/")
+
+ client, err := s.getAzureClient()
+ if err != nil {
+ s.errorResponse(w, http.StatusInternalServerError, "CLIENT_ERROR", err.Error())
+ return
+ }
+
+ // First list models to find the one we're looking for
+ models, err := client.ListModels(r.Context())
+ if err != nil {
+ s.errorResponse(w, http.StatusInternalServerError, "API_ERROR", err.Error())
+ return
+ }
+
+ // Find the model by name
+ var modelSummary *azuremodels.ModelSummary
+ for _, model := range models {
+ if model.HasName(modelID) {
+ modelSummary = model
+ break
+ }
+ }
+
+ if modelSummary == nil {
+ s.errorResponse(w, http.StatusNotFound, "MODEL_NOT_FOUND", fmt.Sprintf("Model %s not found", modelID))
+ return
+ }
+
+ // Get detailed model info
+ model, err := client.GetModelDetails(r.Context(), modelSummary.Registry, modelSummary.Name, modelSummary.Version)
+ if err != nil {
+ s.errorResponse(w, http.StatusNotFound, "MODEL_NOT_FOUND", err.Error())
+ return
+ }
+
+ s.jsonResponse(w, http.StatusOK, APIResponse{
+ Success: true,
+ Data: model,
+ })
+}
+
+// =========================================
+// Eval Handler
+// =========================================
+
+func (s *Server) evalHandler(w http.ResponseWriter, r *http.Request) {
+ // TODO: Implement eval logic using the eval package
+ s.jsonResponse(w, http.StatusOK, APIResponse{
+ Success: true,
+ Data: map[string]string{
+ "message": "Evaluation endpoint - implementation pending",
+ },
+ })
+}
+
+// =========================================
+// Generate Handler
+// =========================================
+
+func (s *Server) generateHandler(w http.ResponseWriter, r *http.Request) {
+ // TODO: Implement generate logic using the generate package
+ s.jsonResponse(w, http.StatusOK, APIResponse{
+ Success: true,
+ Data: map[string]string{
+ "message": "Generate endpoint - implementation pending",
+ },
+ })
+}
+
+// =========================================
+// Prompt Library Handlers
+// =========================================
+
+func (s *Server) listPromptsHandler(w http.ResponseWriter, r *http.Request) {
+ // Return available prompt templates
+ prompts := []map[string]interface{}{
+ {
+ "id": "arabic-general",
+ "name": "Arabic General Assistant",
+ "domain": "arabic",
+ "description": "مساعد ذكاء اصطناعي عام باللغة العربية",
+ },
+ {
+ "id": "arabic-medical",
+ "name": "Arabic Medical Advisor",
+ "domain": "arabic",
+ "description": "مساعد طبي للمعلومات الصحية العامة",
+ },
+ {
+ "id": "healthcare-claims",
+ "name": "Insurance Claim Analyzer",
+ "domain": "healthcare",
+ "description": "Analyzes healthcare insurance claims",
+ },
+ {
+ "id": "healthcare-pa",
+ "name": "Prior Authorization Assistant",
+ "domain": "healthcare",
+ "description": "Assists with prior authorization requests",
+ },
+ {
+ "id": "developer-review",
+ "name": "Code Review Assistant",
+ "domain": "developer",
+ "description": "Expert code review and analysis",
+ },
+ }
+
+ s.jsonResponse(w, http.StatusOK, APIResponse{
+ Success: true,
+ Data: prompts,
+ })
+}
+
+func (s *Server) listPromptsByDomainHandler(w http.ResponseWriter, r *http.Request) {
+ domain := r.PathValue("domain")
+ // Filter prompts by domain
+ // TODO: Implement database query
+
+ s.jsonResponse(w, http.StatusOK, APIResponse{
+ Success: true,
+ Data: map[string]string{
+ "domain": domain,
+ "message": "Domain-specific prompts",
+ },
+ })
+}
+
+func (s *Server) executePromptHandler(w http.ResponseWriter, r *http.Request) {
+ // Execute a prompt template with provided variables
+ s.jsonResponse(w, http.StatusOK, APIResponse{
+ Success: true,
+ Data: map[string]string{
+ "message": "Prompt execution endpoint",
+ },
+ })
+}
+
+// =========================================
+// User Handlers
+// =========================================
+
+func (s *Server) getUserHandler(w http.ResponseWriter, r *http.Request) {
+ userID := r.Context().Value(middleware.UserIDKey)
+
+ s.jsonResponse(w, http.StatusOK, APIResponse{
+ Success: true,
+ Data: map[string]interface{}{
+ "user_id": userID,
+ "tier": "pro",
+ "domain": "developer",
+ },
+ })
+}
+
+func (s *Server) getUsageHandler(w http.ResponseWriter, r *http.Request) {
+ s.jsonResponse(w, http.StatusOK, APIResponse{
+ Success: true,
+ Data: map[string]interface{}{
+ "period_start": time.Now().Format("2006-01-01"),
+ "period_end": time.Now().AddDate(0, 1, 0).Format("2006-01-01"),
+ "credits_used": 150,
+ "credits_remaining": 9850,
+ "total_requests": 245,
+ },
+ })
+}
+
+// =========================================
+// Billing Handlers
+// =========================================
+
+func (s *Server) createCheckoutHandler(w http.ResponseWriter, r *http.Request) {
+ var req struct {
+ PriceID string `json:"price_id"`
+ SuccessURL string `json:"success_url"`
+ CancelURL string `json:"cancel_url"`
+ }
+
+ if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
+ s.errorResponse(w, http.StatusBadRequest, "INVALID_JSON", "Invalid request")
+ return
+ }
+
+ session, err := s.billing.CreateCheckoutSession(req.PriceID, req.SuccessURL, req.CancelURL)
+ if err != nil {
+ s.errorResponse(w, http.StatusInternalServerError, "STRIPE_ERROR", err.Error())
+ return
+ }
+
+ s.jsonResponse(w, http.StatusOK, APIResponse{
+ Success: true,
+ Data: map[string]string{
+ "checkout_url": session.URL,
+ },
+ })
+}
+
+func (s *Server) createPortalHandler(w http.ResponseWriter, r *http.Request) {
+ var req struct {
+ CustomerID string `json:"customer_id"`
+ ReturnURL string `json:"return_url"`
+ }
+
+ if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
+ s.errorResponse(w, http.StatusBadRequest, "INVALID_JSON", "Invalid request")
+ return
+ }
+
+ session, err := s.billing.CreatePortalSession(req.CustomerID, req.ReturnURL)
+ if err != nil {
+ s.errorResponse(w, http.StatusInternalServerError, "STRIPE_ERROR", err.Error())
+ return
+ }
+
+ s.jsonResponse(w, http.StatusOK, APIResponse{
+ Success: true,
+ Data: map[string]string{
+ "portal_url": session.URL,
+ },
+ })
+}
+
+func (s *Server) stripeWebhookHandler(w http.ResponseWriter, r *http.Request) {
+ // Handle Stripe webhook events
+ // TODO: Implement webhook signature verification and event handling
+ w.WriteHeader(http.StatusOK)
+}
+
+// =========================================
+// Helper Methods
+// =========================================
+
+func (s *Server) getAzureClient() (azuremodels.Client, error) {
+ token := s.config.GitHubToken
+ if token == "" {
+ token, _ = auth.TokenForHost("github.com")
+ }
+ if token == "" {
+ return nil, fmt.Errorf("no GitHub token available")
+ }
+ return azuremodels.NewDefaultAzureClient(token)
+}
+
+func (s *Server) jsonResponse(w http.ResponseWriter, status int, data interface{}) {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(status)
+ json.NewEncoder(w).Encode(data)
+}
+
+func (s *Server) errorResponse(w http.ResponseWriter, status int, code, message string) {
+ s.jsonResponse(w, status, APIResponse{
+ Success: false,
+ Error: &APIError{
+ Code: code,
+ Message: message,
+ },
+ })
+}
diff --git a/internal/api/server.go b/internal/api/server.go
new file mode 100644
index 00000000..2a641c7c
--- /dev/null
+++ b/internal/api/server.go
@@ -0,0 +1,109 @@
+// Package api provides the HTTP API server implementation
+package api
+
+import (
+ "net/http"
+ "os"
+
+ "github.com/github/gh-models/internal/billing"
+ "github.com/github/gh-models/internal/middleware"
+)
+
+// Config holds the API server configuration
+type Config struct {
+ Port string
+ Environment string
+ GitHubToken string
+ StripeSecretKey string
+ StripeWebhookSecret string
+ JWTSecret string
+ DatabaseURL string
+ RedisURL string
+}
+
+// LoadConfig loads configuration from environment variables
+func LoadConfig() *Config {
+ return &Config{
+ Port: getEnv("PORT", "8080"),
+ Environment: getEnv("ENVIRONMENT", "development"),
+ GitHubToken: os.Getenv("GITHUB_TOKEN"),
+ StripeSecretKey: os.Getenv("STRIPE_SECRET_KEY"),
+ StripeWebhookSecret: os.Getenv("STRIPE_WEBHOOK_SECRET"),
+ JWTSecret: os.Getenv("JWT_SECRET"),
+ DatabaseURL: os.Getenv("DATABASE_URL"),
+ RedisURL: getEnv("REDIS_URL", "redis://localhost:6379"),
+ }
+}
+
+func getEnv(key, defaultValue string) string {
+ if value := os.Getenv(key); value != "" {
+ return value
+ }
+ return defaultValue
+}
+
+// Server represents the API server
+type Server struct {
+ config *Config
+ billing *billing.Service
+}
+
+// NewServer creates a new API server instance
+func NewServer(cfg *Config, billingService *billing.Service) *Server {
+ return &Server{
+ config: cfg,
+ billing: billingService,
+ }
+}
+
+// SetupRoutes configures all API routes
+func (s *Server) SetupRoutes() http.Handler {
+ mux := http.NewServeMux()
+
+ // Health check (no auth)
+ mux.HandleFunc("GET /health", s.healthHandler)
+ mux.HandleFunc("GET /", s.rootHandler)
+
+ // API v1 routes
+ mux.HandleFunc("POST /v1/chat", s.withMiddleware(s.chatHandler))
+ mux.HandleFunc("POST /v1/chat/stream", s.withMiddleware(s.chatStreamHandler))
+ mux.HandleFunc("POST /v1/eval", s.withMiddleware(s.evalHandler))
+ mux.HandleFunc("POST /v1/generate", s.withMiddleware(s.generateHandler))
+ mux.HandleFunc("GET /v1/models", s.withMiddleware(s.listModelsHandler))
+ mux.HandleFunc("GET /v1/models/{modelId}", s.withMiddleware(s.viewModelHandler))
+
+ // Prompt library
+ mux.HandleFunc("GET /v1/prompts", s.withMiddleware(s.listPromptsHandler))
+ mux.HandleFunc("GET /v1/prompts/{domain}", s.withMiddleware(s.listPromptsByDomainHandler))
+ mux.HandleFunc("POST /v1/prompts/execute", s.withMiddleware(s.executePromptHandler))
+
+ // User management
+ mux.HandleFunc("GET /v1/user", s.withMiddleware(s.getUserHandler))
+ mux.HandleFunc("GET /v1/user/usage", s.withMiddleware(s.getUsageHandler))
+
+ // Billing (Stripe)
+ mux.HandleFunc("POST /v1/billing/checkout", s.withMiddleware(s.createCheckoutHandler))
+ mux.HandleFunc("POST /v1/billing/portal", s.withMiddleware(s.createPortalHandler))
+ mux.HandleFunc("POST /webhooks/stripe", s.stripeWebhookHandler)
+
+ // Apply global middleware
+ handler := middleware.CORS(mux)
+ handler = middleware.Logger(handler)
+ handler = middleware.Recovery(handler)
+
+ return handler
+}
+
+// withMiddleware applies authentication and rate limiting
+func (s *Server) withMiddleware(next http.HandlerFunc) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ // Apply auth middleware
+ middleware.APIKeyAuth(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ // Apply rate limiting
+ middleware.RateLimit(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ // Apply usage tracking
+ middleware.UsageTracker(http.HandlerFunc(next)).ServeHTTP(w, r)
+ })).ServeHTTP(w, r)
+ })).ServeHTTP(w, r)
+ }
+}
diff --git a/internal/billing/stripe.go b/internal/billing/stripe.go
new file mode 100644
index 00000000..5cab63b2
--- /dev/null
+++ b/internal/billing/stripe.go
@@ -0,0 +1,161 @@
+// Package billing provides Stripe integration for BrainSait
+package billing
+
+import (
+ "fmt"
+ "os"
+)
+
+// Service handles Stripe payment operations
+type Service struct {
+ secretKey string
+ webhookSecret string
+}
+
+// NewService creates a new Billing Service
+func NewService(secretKey, webhookSecret string) *Service {
+ if secretKey == "" {
+ secretKey = os.Getenv("STRIPE_SECRET_KEY")
+ }
+ if webhookSecret == "" {
+ webhookSecret = os.Getenv("STRIPE_WEBHOOK_SECRET")
+ }
+
+ return &Service{
+ secretKey: secretKey,
+ webhookSecret: webhookSecret,
+ }
+}
+
+// Pricing tiers for BrainSait
+type PricingTier struct {
+ ID string `json:"id"`
+ Name string `json:"name"`
+ Description string `json:"description"`
+ PriceID string `json:"price_id,omitempty"`
+ Amount int64 `json:"amount"`
+ Currency string `json:"currency"`
+ Interval string `json:"interval,omitempty"`
+ Features []string `json:"features"`
+}
+
+// GetPricingTiers returns available pricing plans
+func (s *Service) GetPricingTiers() []PricingTier {
+ return []PricingTier{
+ {
+ ID: "free",
+ Name: "Free",
+ Description: "Get started with basic features",
+ Amount: 0,
+ Currency: "usd",
+ Features: []string{
+ "100 API calls/month",
+ "Community support",
+ "Basic models access",
+ },
+ },
+ {
+ ID: "developer",
+ Name: "Developer",
+ Description: "For individual developers",
+ PriceID: os.Getenv("STRIPE_PRICE_DEVELOPER"),
+ Amount: 2900, // $29.00
+ Currency: "usd",
+ Interval: "month",
+ Features: []string{
+ "10,000 API calls/month",
+ "Email support",
+ "All models access",
+ "Prompt evaluation",
+ "Basic analytics",
+ },
+ },
+ {
+ ID: "team",
+ Name: "Team",
+ Description: "For small teams",
+ PriceID: os.Getenv("STRIPE_PRICE_TEAM"),
+ Amount: 9900, // $99.00
+ Currency: "usd",
+ Interval: "month",
+ Features: []string{
+ "50,000 API calls/month",
+ "Priority support",
+ "All models access",
+ "Prompt evaluation",
+ "Test generation",
+ "Advanced analytics",
+ "Team management",
+ },
+ },
+ {
+ ID: "enterprise",
+ Name: "Enterprise",
+ Description: "For large organizations",
+ PriceID: os.Getenv("STRIPE_PRICE_ENTERPRISE"),
+ Amount: 49900, // $499.00
+ Currency: "usd",
+ Interval: "month",
+ Features: []string{
+ "Unlimited API calls",
+ "24/7 support",
+ "All models access",
+ "Prompt evaluation",
+ "Test generation",
+ "Advanced analytics",
+ "Team management",
+ "Custom integrations",
+ "SLA guarantee",
+ "Dedicated success manager",
+ },
+ },
+ }
+}
+
+// CheckoutSession represents a Stripe checkout session
+type CheckoutSession struct {
+ ID string `json:"id"`
+ URL string `json:"url"`
+}
+
+// PortalSession represents a Stripe billing portal session
+type PortalSession struct {
+ ID string `json:"id"`
+ URL string `json:"url"`
+}
+
+// CreateCheckoutSession creates a Stripe checkout session
+// This is a stub - actual Stripe integration requires the stripe-go package
+func (s *Service) CreateCheckoutSession(priceID, successURL, cancelURL string) (*CheckoutSession, error) {
+ if s.secretKey == "" {
+ return nil, fmt.Errorf("Stripe secret key not configured")
+ }
+
+ // TODO: Implement actual Stripe checkout session creation
+ // This requires: go get github.com/stripe/stripe-go/v78
+
+ return &CheckoutSession{
+ ID: "cs_test_placeholder",
+ URL: successURL + "?session_id=cs_test_placeholder",
+ }, nil
+}
+
+// CreatePortalSession creates a Stripe billing portal session
+func (s *Service) CreatePortalSession(customerID, returnURL string) (*PortalSession, error) {
+ if s.secretKey == "" {
+ return nil, fmt.Errorf("Stripe secret key not configured")
+ }
+
+ // TODO: Implement actual Stripe portal session creation
+
+ return &PortalSession{
+ ID: "bps_test_placeholder",
+ URL: returnURL + "?portal_session=bps_test_placeholder",
+ }, nil
+}
+
+// HandleWebhook processes Stripe webhook events
+func (s *Service) HandleWebhook(payload []byte, signature string) error {
+ // TODO: Implement webhook verification and handling
+ return nil
+}
diff --git a/internal/i18n/i18n.go b/internal/i18n/i18n.go
new file mode 100644
index 00000000..6aa2d99d
--- /dev/null
+++ b/internal/i18n/i18n.go
@@ -0,0 +1,178 @@
+// Package i18n provides internationalization support for BrainSait CLI
+package i18n
+
+import (
+ "embed"
+ "encoding/json"
+ "fmt"
+ "os"
+ "strings"
+)
+
+//go:embed locales/*.json
+var localesFS embed.FS
+
+// Locale represents a language locale
+type Locale struct {
+ Code string `json:"code"`
+ Name string `json:"name"`
+ NativeName string `json:"native_name"`
+ Direction string `json:"direction"` // "ltr" or "rtl"
+ Messages map[string]string `json:"messages"`
+}
+
+// I18n manages internationalization
+type I18n struct {
+ currentLocale string
+ locales map[string]*Locale
+ fallback string
+}
+
+// NewI18n creates a new I18n instance
+func NewI18n() *I18n {
+ i := &I18n{
+ locales: make(map[string]*Locale),
+ fallback: "en",
+ }
+
+ // Load embedded locales
+ i.loadEmbeddedLocales()
+
+ // Detect system locale
+ i.detectLocale()
+
+ return i
+}
+
+// loadEmbeddedLocales loads all locale files from embedded filesystem
+func (i *I18n) loadEmbeddedLocales() {
+ entries, err := localesFS.ReadDir("locales")
+ if err != nil {
+ return
+ }
+
+ for _, entry := range entries {
+ if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".json") {
+ continue
+ }
+
+ data, err := localesFS.ReadFile("locales/" + entry.Name())
+ if err != nil {
+ continue
+ }
+
+ var locale Locale
+ if err := json.Unmarshal(data, &locale); err != nil {
+ continue
+ }
+
+ i.locales[locale.Code] = &locale
+ }
+}
+
+// detectLocale detects the system locale
+func (i *I18n) detectLocale() {
+ // Check environment variables
+ for _, envVar := range []string{"BRAINSAIT_LANG", "LANG", "LANGUAGE", "LC_ALL", "LC_MESSAGES"} {
+ if lang := os.Getenv(envVar); lang != "" {
+ // Parse locale (e.g., "en_US.UTF-8" -> "en")
+ lang = strings.Split(lang, ".")[0]
+ lang = strings.Split(lang, "_")[0]
+ lang = strings.ToLower(lang)
+
+ if _, ok := i.locales[lang]; ok {
+ i.currentLocale = lang
+ return
+ }
+ }
+ }
+
+ // Default to English
+ i.currentLocale = "en"
+}
+
+// SetLocale sets the current locale
+func (i *I18n) SetLocale(code string) error {
+ code = strings.ToLower(code)
+ if _, ok := i.locales[code]; !ok {
+ return fmt.Errorf("locale %s not found", code)
+ }
+ i.currentLocale = code
+ return nil
+}
+
+// GetLocale returns the current locale
+func (i *I18n) GetLocale() string {
+ return i.currentLocale
+}
+
+// T translates a message key
+func (i *I18n) T(key string, args ...interface{}) string {
+ locale, ok := i.locales[i.currentLocale]
+ if !ok {
+ locale = i.locales[i.fallback]
+ }
+
+ if locale == nil {
+ return key
+ }
+
+ msg, ok := locale.Messages[key]
+ if !ok {
+ // Try fallback
+ if fallbackLocale, ok := i.locales[i.fallback]; ok {
+ msg, ok = fallbackLocale.Messages[key]
+ if !ok {
+ return key
+ }
+ } else {
+ return key
+ }
+ }
+
+ if len(args) > 0 {
+ return fmt.Sprintf(msg, args...)
+ }
+ return msg
+}
+
+// IsRTL returns true if current locale is right-to-left
+func (i *I18n) IsRTL() bool {
+ locale, ok := i.locales[i.currentLocale]
+ if !ok {
+ return false
+ }
+ return locale.Direction == "rtl"
+}
+
+// AvailableLocales returns all available locales
+func (i *I18n) AvailableLocales() []Locale {
+ var locales []Locale
+ for _, locale := range i.locales {
+ locales = append(locales, *locale)
+ }
+ return locales
+}
+
+// Global instance
+var defaultI18n = NewI18n()
+
+// T translates using the global instance
+func T(key string, args ...interface{}) string {
+ return defaultI18n.T(key, args...)
+}
+
+// SetLocale sets the locale for the global instance
+func SetLocale(code string) error {
+ return defaultI18n.SetLocale(code)
+}
+
+// GetLocale returns the current locale for the global instance
+func GetLocale() string {
+ return defaultI18n.GetLocale()
+}
+
+// IsRTL returns true if current locale is RTL
+func IsRTL() bool {
+ return defaultI18n.IsRTL()
+}
diff --git a/internal/i18n/locales/ar.json b/internal/i18n/locales/ar.json
new file mode 100644
index 00000000..a294485d
--- /dev/null
+++ b/internal/i18n/locales/ar.json
@@ -0,0 +1,54 @@
+{
+ "code": "ar",
+ "name": "Arabic",
+ "native_name": "العربية",
+ "direction": "rtl",
+ "messages": {
+ "app.name": "منصة برين سايت للذكاء الاصطناعي",
+ "app.description": "تفاعل مع نماذج الذكاء الاصطناعي عبر GitHub Models",
+
+ "cmd.run.short": "تشغيل الاستدلال مع نموذج لغوي",
+ "cmd.run.long": "تشغيل الاستدلال مع نموذج لغوي باستخدام ملف موجه أو إدخال مباشر",
+ "cmd.run.example": "gh models run openai/gpt-4o -p \"اشرح الحوسبة الكمية\"",
+
+ "cmd.list.short": "عرض النماذج المتاحة",
+ "cmd.list.long": "عرض جميع نماذج الذكاء الاصطناعي المتاحة من GitHub Models",
+
+ "cmd.view.short": "عرض تفاصيل النموذج",
+ "cmd.view.long": "عرض معلومات مفصلة حول نموذج معين",
+
+ "cmd.eval.short": "تقييم الموجهات",
+ "cmd.eval.long": "تقييم الموجهات مقابل حالات الاختبار والمقيمين",
+
+ "cmd.generate.short": "توليد حالات الاختبار",
+ "cmd.generate.long": "توليد حالات اختبار للموجهات باستخدام منهجية PromptPex",
+
+ "error.auth_required": "المصادقة مطلوبة. يرجى تشغيل 'gh auth login' أولاً.",
+ "error.model_not_found": "النموذج '%s' غير موجود",
+ "error.invalid_prompt": "ملف موجه غير صالح: %s",
+ "error.rate_limited": "تم تجاوز حد الطلبات. يرجى المحاولة لاحقاً.",
+ "error.api_error": "خطأ في API: %s",
+
+ "success.inference_complete": "تم الاستدلال بنجاح",
+ "success.eval_complete": "اكتمل التقييم: %d نجح، %d فشل",
+ "success.generate_complete": "تم توليد %d حالة اختبار",
+
+ "prompt.enter_message": "أدخل رسالتك:",
+ "prompt.select_model": "اختر نموذجاً:",
+ "prompt.confirm_action": "هل أنت متأكد؟ (نعم/لا)",
+
+ "output.model_name": "النموذج",
+ "output.publisher": "الناشر",
+ "output.description": "الوصف",
+ "output.context_window": "نافذة السياق",
+ "output.max_tokens": "الحد الأقصى للرموز",
+ "output.response": "الرد",
+ "output.tokens_used": "الرموز المستخدمة",
+ "output.latency": "زمن الاستجابة",
+
+ "billing.current_plan": "الخطة الحالية",
+ "billing.usage_this_month": "الاستخدام هذا الشهر",
+ "billing.credits_remaining": "الرصيد المتبقي",
+ "billing.upgrade_prompt": "قم بالترقية للحصول على المزيد من الميزات"
+ }
+}
diff --git a/internal/i18n/locales/en.json b/internal/i18n/locales/en.json
new file mode 100644
index 00000000..c70c23bc
--- /dev/null
+++ b/internal/i18n/locales/en.json
@@ -0,0 +1,54 @@
+{
+ "code": "en",
+ "name": "English",
+ "native_name": "English",
+ "direction": "ltr",
+ "messages": {
+ "app.name": "BrainSait AI Platform",
+ "app.description": "Interact with AI models via GitHub Models",
+
+ "cmd.run.short": "Run inference with a language model",
+ "cmd.run.long": "Run inference with a language model using a prompt file or direct input",
+ "cmd.run.example": "gh models run openai/gpt-4o -p \"Explain quantum computing\"",
+
+ "cmd.list.short": "List available models",
+ "cmd.list.long": "List all available AI models from GitHub Models",
+
+ "cmd.view.short": "View model details",
+ "cmd.view.long": "View detailed information about a specific model",
+
+ "cmd.eval.short": "Evaluate prompts",
+ "cmd.eval.long": "Evaluate prompts against test cases and evaluators",
+
+ "cmd.generate.short": "Generate test cases",
+ "cmd.generate.long": "Generate test cases for prompts using PromptPex methodology",
+
+ "error.auth_required": "Authentication required. Please run 'gh auth login' first.",
+ "error.model_not_found": "Model '%s' not found",
+ "error.invalid_prompt": "Invalid prompt file: %s",
+ "error.rate_limited": "Rate limit exceeded. Please try again later.",
+ "error.api_error": "API error: %s",
+
+ "success.inference_complete": "Inference completed successfully",
+ "success.eval_complete": "Evaluation completed: %d passed, %d failed",
+ "success.generate_complete": "Generated %d test cases",
+
+ "prompt.enter_message": "Enter your message:",
+ "prompt.select_model": "Select a model:",
+ "prompt.confirm_action": "Are you sure? (y/n)",
+
+ "output.model_name": "Model",
+ "output.publisher": "Publisher",
+ "output.description": "Description",
+ "output.context_window": "Context Window",
+ "output.max_tokens": "Max Output Tokens",
+ "output.response": "Response",
+ "output.tokens_used": "Tokens Used",
+ "output.latency": "Latency",
+
+ "billing.current_plan": "Current Plan",
+ "billing.usage_this_month": "Usage This Month",
+ "billing.credits_remaining": "Credits Remaining",
+ "billing.upgrade_prompt": "Upgrade to get more features"
+ }
+}
diff --git a/internal/middleware/middleware.go b/internal/middleware/middleware.go
new file mode 100644
index 00000000..0c1efb3d
--- /dev/null
+++ b/internal/middleware/middleware.go
@@ -0,0 +1,199 @@
+// Package middleware provides HTTP middleware for the BrainSait API
+package middleware
+
+import (
+ "context"
+ "crypto/rand"
+ "encoding/hex"
+ "log"
+ "net/http"
+ "strings"
+ "sync"
+ "time"
+)
+
+// Context keys
+type contextKey string
+
+const (
+ UserIDKey contextKey = "user_id"
+ RequestIDKey contextKey = "request_id"
+ APIKeyKey contextKey = "api_key"
+)
+
+// APIKeyAuth middleware validates API keys (simplified for now)
+func APIKeyAuth(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ apiKey := r.Header.Get("X-API-Key")
+ if apiKey == "" {
+ authHeader := r.Header.Get("Authorization")
+ if strings.HasPrefix(authHeader, "Bearer ") {
+ apiKey = strings.TrimPrefix(authHeader, "Bearer ")
+ }
+ }
+
+ if apiKey == "" {
+ http.Error(w, `{"success":false,"error":{"code":"UNAUTHORIZED","message":"API key required"}}`, http.StatusUnauthorized)
+ return
+ }
+
+ // TODO: Validate API key against database
+ // For now, accept any non-empty key
+ ctx := context.WithValue(r.Context(), UserIDKey, "user-from-api-key")
+ ctx = context.WithValue(ctx, APIKeyKey, apiKey)
+ next.ServeHTTP(w, r.WithContext(ctx))
+ })
+}
+
+// RateLimit middleware implements simple rate limiting
+func RateLimit(next http.Handler) http.Handler {
+ var (
+ mu sync.Mutex
+ requests = make(map[string]int)
+ lastReset = time.Now()
+ )
+
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ mu.Lock()
+
+ // Reset every minute
+ if time.Since(lastReset) > time.Minute {
+ requests = make(map[string]int)
+ lastReset = time.Now()
+ }
+
+ key := r.Header.Get("X-API-Key")
+ if key == "" {
+ key = r.RemoteAddr
+ }
+
+ requests[key]++
+ count := requests[key]
+ mu.Unlock()
+
+ if count > 100 { // 100 requests per minute
+ http.Error(w, `{"success":false,"error":{"code":"RATE_LIMITED","message":"Rate limit exceeded"}}`, http.StatusTooManyRequests)
+ return
+ }
+
+ next.ServeHTTP(w, r)
+ })
+}
+
+// UsageTracker middleware tracks API usage
+func UsageTracker(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ // TODO: Track usage in database
+ next.ServeHTTP(w, r)
+ })
+}
+
+// Logger middleware logs all HTTP requests
+func Logger(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ start := time.Now()
+
+ // Create response wrapper to capture status code
+ wrapped := &responseWriter{ResponseWriter: w, statusCode: http.StatusOK}
+
+ next.ServeHTTP(wrapped, r)
+
+ log.Printf(
+ "[%s] %s %s %d %v",
+ r.Method,
+ r.URL.Path,
+ r.RemoteAddr,
+ wrapped.statusCode,
+ time.Since(start),
+ )
+ })
+}
+
+// responseWriter wraps http.ResponseWriter to capture status code
+type responseWriter struct {
+ http.ResponseWriter
+ statusCode int
+}
+
+func (rw *responseWriter) WriteHeader(code int) {
+ rw.statusCode = code
+ rw.ResponseWriter.WriteHeader(code)
+}
+
+// RequestID middleware adds a unique request ID to each request
+func RequestID(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ requestID := r.Header.Get("X-Request-ID")
+ if requestID == "" {
+ requestID = generateRequestID()
+ }
+
+ w.Header().Set("X-Request-ID", requestID)
+ ctx := context.WithValue(r.Context(), RequestIDKey, requestID)
+ next.ServeHTTP(w, r.WithContext(ctx))
+ })
+}
+
+// CORS middleware handles Cross-Origin Resource Sharing
+func CORS(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ origin := r.Header.Get("Origin")
+ if origin != "" {
+ w.Header().Set("Access-Control-Allow-Origin", origin)
+ w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
+ w.Header().Set("Access-Control-Allow-Headers", "Accept, Authorization, Content-Type, X-API-Key, X-Request-ID")
+ w.Header().Set("Access-Control-Max-Age", "86400")
+ }
+
+ // Handle preflight requests
+ if r.Method == http.MethodOptions {
+ w.WriteHeader(http.StatusNoContent)
+ return
+ }
+
+ next.ServeHTTP(w, r)
+ })
+}
+
+// Recovery middleware recovers from panics
+func Recovery(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ defer func() {
+ if err := recover(); err != nil {
+ log.Printf("Panic recovered: %v", err)
+ http.Error(w, `{"success":false,"error":{"code":"INTERNAL_ERROR","message":"Internal server error"}}`, http.StatusInternalServerError)
+ }
+ }()
+ next.ServeHTTP(w, r)
+ })
+}
+
+// Secure middleware adds security headers
+func Secure(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("X-Content-Type-Options", "nosniff")
+ w.Header().Set("X-Frame-Options", "DENY")
+ w.Header().Set("X-XSS-Protection", "1; mode=block")
+ w.Header().Set("Referrer-Policy", "strict-origin-when-cross-origin")
+ w.Header().Set("Content-Security-Policy", "default-src 'self'")
+
+ next.ServeHTTP(w, r)
+ })
+}
+
+// generateRequestID creates a unique request identifier
+func generateRequestID() string {
+ bytes := make([]byte, 16)
+ rand.Read(bytes)
+ return hex.EncodeToString(bytes)
+}
+
+// Chain chains multiple middleware together
+func Chain(middlewares ...func(http.Handler) http.Handler) func(http.Handler) http.Handler {
+ return func(final http.Handler) http.Handler {
+ for i := len(middlewares) - 1; i >= 0; i-- {
+ final = middlewares[i](final)
+ }
+ return final
+ }
+}