Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 50 additions & 3 deletions databricks-builder-app/.env.example
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
# Copy this file to .env.local and fill in your values
# Databricks Builder App - Environment Configuration
# ==================================================
#
# For LOCAL DEVELOPMENT: Copy this file to .env.local and fill in your values
# For DEPLOYMENT: Copy app.yaml.example to app.yaml and configure there
#
# This file is for local development only. When deploying to Databricks Apps,
# use app.yaml for environment configuration instead.

# =============================================================================
# Databricks Configuration
# Databricks Configuration (Local Development)
# =============================================================================
# Workspace URL and personal access token for local development
# Workspace URL and personal access token
# In production (Databricks Apps), authentication is handled automatically via
# the service principal's OAuth credentials - no token needed.
DATABRICKS_HOST=https://your-workspace.cloud.databricks.com
DATABRICKS_TOKEN=dapi...

Expand Down Expand Up @@ -66,3 +75,41 @@ CLAUDE_CODE_STREAM_CLOSE_TIMEOUT=3600000

# Anthropic API key (optional - uses Databricks model serving by default)
# ANTHROPIC_API_KEY=sk-ant-...

# =============================================================================
# DEPLOYMENT TO DATABRICKS APPS
# =============================================================================
#
# To deploy this app to Databricks Apps:
#
# 1. Prerequisites:
# - Databricks CLI installed and configured (databricks auth login)
# - A Lakebase instance created in your workspace
#
# 2. Create the app:
# databricks apps create <your-app-name>
#
# 3. Configure app.yaml:
# cp app.yaml.example app.yaml
# # Edit app.yaml with your Lakebase instance name and LLM settings
#
# 4. Add Lakebase as an app resource:
# databricks apps add-resource <your-app-name> \
# --resource-type database \
# --resource-name lakebase \
# --database-instance <your-lakebase-instance-name>
#
# 5. Grant table permissions to the app's service principal:
# (Run this SQL in a notebook or SQL editor after first deployment)
#
# GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public
# TO `<service-principal-id>`;
# GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public
# TO `<service-principal-id>`;
# ALTER DEFAULT PRIVILEGES IN SCHEMA public
# GRANT ALL ON TABLES TO `<service-principal-id>`;
#
# 6. Deploy:
# ./scripts/deploy.sh <your-app-name>
#
# For more details, see the README.md
4 changes: 4 additions & 0 deletions databricks-builder-app/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ skills/
# Projects directory (local development)
projects/

# Packages (copied from sibling dirs during deployment)
packages/

# Conda environment (for Databricks Apps deployment)
conda-env/

Expand All @@ -15,6 +18,7 @@ __pycache__/

# Environment
.env.local
app.yaml

# Node (client)
client/node_modules/
Expand Down
41 changes: 0 additions & 41 deletions databricks-builder-app/app.yaml

This file was deleted.

99 changes: 99 additions & 0 deletions databricks-builder-app/app.yaml.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# Databricks Apps configuration for Builder App
# Copy this file to app.yaml and customize for your deployment
#
# Prerequisites:
# 1. Create the app: databricks apps create <your-app-name>
# 2. Add Lakebase as a resource (see instructions below)
# 3. Configure your LLM provider settings

command:
- "uvicorn"
- "server.app:app"
- "--host"
- "0.0.0.0"
- "--port"
- "$DATABRICKS_APP_PORT"

env:
# =============================================================================
# Application Settings
# =============================================================================
- name: ENV
value: "production"
- name: PROJECTS_BASE_DIR
value: "./projects"
- name: PYTHONPATH
value: "/app/python/source_code/packages"

# =============================================================================
# Skills Configuration
# =============================================================================
# Comma-separated list of skills to enable
- name: ENABLED_SKILLS
value: "agent-bricks,aibi-dashboards,asset-bundles,databricks-app-apx,databricks-app-python,databricks-config,databricks-docs,databricks-jobs,databricks-python-sdk,databricks-unity-catalog,mlflow-evaluation,spark-declarative-pipelines,synthetic-data-generation,unstructured-pdf-generation"
- name: SKILLS_ONLY_MODE
value: "false"

# =============================================================================
# Database Configuration (Lakebase)
# =============================================================================
# IMPORTANT: You must add Lakebase as an app resource for database connectivity.
#
# Steps:
# 1. Create a Lakebase instance in your workspace (if not exists)
# 2. Add it as an app resource:
# databricks apps add-resource <app-name> \
# --resource-type database \
# --resource-name lakebase \
# --database-instance <your-lakebase-instance-name>
#
# When added as a resource, Databricks automatically sets:
# - PGHOST, PGPORT, PGUSER, PGPASSWORD, PGDATABASE
#
# You only need to specify the instance name for OAuth token generation:
- name: LAKEBASE_INSTANCE_NAME
value: "<your-lakebase-instance-name>"
- name: LAKEBASE_DATABASE_NAME
value: "databricks_postgres"

# =============================================================================
# LLM Provider Configuration
# =============================================================================
# Option 1: Databricks Foundation Models (default)
- name: LLM_PROVIDER
value: "DATABRICKS"
- name: DATABRICKS_MODEL
value: "databricks-meta-llama-3-3-70b-instruct"
- name: DATABRICKS_MODEL_MINI
value: "databricks-gemini-3-flash"

# Option 2: Anthropic Claude (uncomment and add your key)
# - name: ANTHROPIC_API_KEY
# value: "<your-anthropic-api-key>"

# Option 3: Azure OpenAI (uncomment and configure)
# - name: LLM_PROVIDER
# value: "AZURE"
# - name: AZURE_OPENAI_API_KEY
# value: "<your-azure-api-key>"
# - name: AZURE_OPENAI_ENDPOINT
# value: "https://<your-resource>.cognitiveservices.azure.com/"
# - name: AZURE_OPENAI_API_VERSION
# value: "2024-08-01-preview"
# - name: AZURE_OPENAI_DEPLOYMENT
# value: "gpt-4o"
# - name: AZURE_OPENAI_DEPLOYMENT_MINI
# value: "gpt-4o-mini"

# =============================================================================
# Claude SDK Configuration
# =============================================================================
- name: CLAUDE_CODE_STREAM_CLOSE_TIMEOUT
value: "3600000"

# =============================================================================
# Permission Configuration
# =============================================================================
# Grant created resources to this principal (e.g., "account users" for all)
- name: AUTO_GRANT_PERMISSIONS_TO
value: "account users"
98 changes: 98 additions & 0 deletions databricks-builder-app/client/src/components/FunLoader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { useEffect, useState } from 'react';
import { Loader2 } from 'lucide-react';
import { cn } from '@/lib/utils';

// Fun loading messages like Claude Code uses
const FUN_MESSAGES = [
'Thinking...',
'Pondering...',
'Contemplating...',
'Ruminating...',
'Cogitating...',
'Deliberating...',
'Musing...',
'Reflecting...',
'Analyzing...',
'Processing...',
'Computing...',
'Synthesizing...',
'Formulating...',
'Architecting...',
'Strategizing...',
'Investigating...',
'Researching...',
'Exploring...',
'Brainstorming...',
'Ideating...',
];

interface TodoItem {
content: string;
status: 'pending' | 'in_progress' | 'completed';
}

interface FunLoaderProps {
todos?: TodoItem[];
className?: string;
}

export function FunLoader({ todos = [], className }: FunLoaderProps) {
const [messageIndex, setMessageIndex] = useState(() =>
Math.floor(Math.random() * FUN_MESSAGES.length)
);

// Rotate messages every 2.5 seconds
useEffect(() => {
const interval = setInterval(() => {
setMessageIndex((prev) => (prev + 1) % FUN_MESSAGES.length);
}, 2500);
return () => clearInterval(interval);
}, []);

// Calculate progress
const completedCount = todos.filter((t) => t.status === 'completed').length;
const totalCount = todos.length;
const progress = totalCount > 0 ? (completedCount / totalCount) * 100 : 0;
const currentTodo = todos.find((t) => t.status === 'in_progress');

return (
<div className={cn('flex flex-col items-center gap-3', className)}>
{/* Main loader with rotating message */}
<div className="flex items-center gap-3 rounded-xl bg-[var(--color-bg-secondary)] border border-[var(--color-border)]/50 px-4 py-3 shadow-sm">
<Loader2 className="h-5 w-5 animate-spin text-[var(--color-accent-primary)]" />
<span className="text-sm text-[var(--color-text-primary)] font-medium min-w-[120px]">
{FUN_MESSAGES[messageIndex]}
</span>
</div>

{/* Progress section - only show if there are todos */}
{totalCount > 0 && (
<div className="w-full max-w-md space-y-2">
{/* Progress bar */}
<div className="relative h-2 w-full overflow-hidden rounded-full bg-[var(--color-bg-secondary)] border border-[var(--color-border)]/30">
<div
className="absolute inset-y-0 left-0 bg-[var(--color-accent-primary)] transition-all duration-500 ease-out rounded-full"
style={{ width: `${progress}%` }}
/>
</div>

{/* Progress text */}
<div className="flex items-center justify-between text-xs text-[var(--color-text-muted)]">
<span>
{completedCount} of {totalCount} tasks
</span>
<span>{Math.round(progress)}%</span>
</div>

{/* Current task indicator */}
{currentTodo && (
<div className="flex items-center gap-2 text-xs text-[var(--color-text-muted)] bg-[var(--color-bg-secondary)]/50 rounded-md px-2 py-1.5 border border-[var(--color-border)]/30">
<div className="h-1.5 w-1.5 rounded-full bg-[var(--color-accent-primary)] animate-pulse" />
<span className="truncate">{currentTodo.content}</span>
</div>
)}
</div>
)}
</div>
);
}
Loading