The backend container image for Junjo AI Studio
6.5K
Junjo (ι εΊ) - order, sequence, procedure
Junjo AI Studio is an open source, self-hostable AI Agent and Workflow debugging and eval platform for any OpenTelemetry instrumented AI application.
The Junjo Python Libraryβ is a framework for structuring AI logic and enhancing Otel span data to improve observability and developer velocity. Junjo remains decoupled from your LLM implementations and business logic, providing a layer of organization, execution, and telemetry to your existing application.
Gain complete visibility to the state of the application, and every change LLMs make to the application state. Complex, mission critical AI workflows are made transparent and understandable with Junjo.
Junjo AI Studio Workflow Debugging Screenshot
If you want to use Junjo AI Studio rather than modify its source code, start with the Junjo AI Studio Minimal Buildβ repository.
Clone the minimal build repository
git clone https://github.com/mdrideout/junjo-ai-studio-minimal-build.git
cd junjo-ai-studio-minimal-build
Choose setup mode
Recommended:
./scripts/junjo setup
Manual:
cp .env.example .env
Then generate and set secrets:
openssl rand -base64 32
openssl rand -base64 32
Open .env and replace the placeholder values:
your_base64_secret_here in JUNJO_SESSION_SECRET with the first generated valueyour_base64_key_here in JUNJO_SECURE_COOKIE_KEY with the second generated valueFor production deployments, also configure:
JUNJO_ENV=production
JUNJO_PROD_FRONTEND_URL=https://app.example.com
JUNJO_PROD_BACKEND_URL=https://api.example.com
JUNJO_PROD_INGESTION_URL=https://ingestion.example.com
Start all services
docker compose up
Access Junjo AI Studio
Create your first user
Create an API key (for sending telemetry from your Junjo app)
# View logs from all services
docker compose logs -f
# View logs from specific service
docker compose logs -f backend
docker compose logs -f ingestion
docker compose logs -f frontend
# Stop services (keeps data)
docker compose down
# Restart a specific service
docker compose restart backend
# View running containers and their status
docker compose ps
# Stop and remove all data (fresh start)
docker compose down -v
Configure your Junjo Python Libraryβ application using the setup and endpoint guidance from the minimal build repository.
Version compatibility: Junjo AI Studio and the Junjo Python Library must run releases that share the same telemetry contract. Mismatched pairings can still ingest spans, but Junjo AI Studio will not be able to render workflow graphs or match spans to their nodes. When upgrading one, upgrade the other to a matching release.
This repository contains the complete open source Junjo AI Studio codebase. If you want to run or modify the source code in this repository, see Source Developmentβ below.
This source repository is not the hosted deployment template. For operator-managed deployment behind your own reverse proxy, use the minimal build repositoryβ or the deployment example repositoryβ , and provide explicit JUNJO_PROD_* public URLs.
This repository contains the complete open source Junjo AI Studio codebase.
Use the default hot-reload local stack when you want to develop or modify Junjo AI Studio itself:
./scripts/junjo setup
docker compose up --build
Local URLs use the same port numbers inside Docker and on localhost:
JUNJO_BUILD_TARGET=development: frontend http://localhost:26151, backend http://localhost:26154, OTLP grpc://localhost:26155JUNJO_BUILD_TARGET=production: frontend http://localhost:26153, backend http://localhost:26154, OTLP grpc://localhost:26155The port numbers stay the same for same-network containers. Only the hostname changes: use backend:26154 for the backend API and ingestion:26155 for OTLP from another container on this Compose network.
After changing JUNJO_BUILD_TARGET, rerun docker compose up --build so Docker rebuilds the matching image targets. Use -d only when you intentionally want detached containers.
For service-specific development notes, see backend/README.mdβ , frontend/README.mdβ , and ingestion/README.mdβ .
Observability & Debugging:
LLM Playground:
OpenTelemetry Integration:
Multi-Service Architecture:
The Junjo AI Studio is composed of three primary services:
backend)ingestion)frontend)Data Flow (Two-Tier Architecture):
Junjo Python App β Ingestion Service (gRPC) β Arrow IPC WAL
β
βββββββββββ΄ββββββββββ
β β
FlushWAL RPC PrepareHotSnapshot RPC
β β
Parquet files Hot snapshot
(COLD tier) (HOT tier)
β β
βββββββββββ¬ββββββββββ
β
Backend Service (DataFusion)
β
Merged query results
β
Frontend UI
How it works:
recent_cold_paths) to bridge indexing lagrecent_cold_paths) and HOT Parquet files, merging results with deduplication by (trace_id, span_id) (COLD wins)Junjo AI Studio uses a single .env file at the root of the project. All services read from this file.
For a guided setup wizard that writes critical .env values (including memory tuning profiles), run:
./scripts/junjo setup
# === Build & Environment ===========================================
# Build Target: development | production
JUNJO_BUILD_TARGET="development"
# Running Environment: development | production
# (affects cookie security, logging, etc.)
JUNJO_ENV="development"
# === Security (REQUIRED for production) ============================
# Generate both with: openssl rand -base64 32
JUNJO_SESSION_SECRET=your_base64_secret_here
JUNJO_SECURE_COOKIE_KEY=your_base64_key_here
# === CORS ==========================================================
# IMPORTANT: Cannot use "*" with session cookies (credentials=True)
# Default: http://localhost:26151,http://localhost:26153
# Production: Auto-derived from JUNJO_PROD_FRONTEND_URL if not set
# Explicitly set for multiple frontends:
# JUNJO_ALLOW_ORIGINS=https://app.example.com,https://admin.example.com
# === Database Storage ==============================================
# Where database files are stored on your host machine/VM
JUNJO_HOST_DB_DATA_PATH=./.dbdata
# === Logging =======================================================
JUNJO_LOG_LEVEL=info # debug | info | warn | error
JUNJO_LOG_FORMAT=json # json | text
# === LLM API Keys (optional) =======================================
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
GEMINI_API_KEY=...
See .env.example for complete configuration with detailed comments.
Junjo AI Studio stores all database files in a single location that you configure. Simply set where you want the data stored on your host machine, and Docker handles the rest.
For local development, use a relative path:
# .env file
JUNJO_HOST_DB_DATA_PATH=./.dbdata
JUNJO_BUILD_TARGET=development
This stores databases in ./.dbdata directory next to your compose.yaml. Docker creates this directory automatically.
Benefits:
For production deployments with persistent storage (DigitalOcean Volumes, AWS EBS, Google Persistent Disk):
1. Mount your block storage:
# DigitalOcean Droplet example
sudo mount /dev/disk/by-id/scsi-0DO_Volume_junjo /mnt/junjo-data
# AWS EC2 example
sudo mount /dev/xvdf /mnt/junjo-data
# Google Cloud example
sudo mount /dev/disk/by-id/google-junjo-data /mnt/junjo-data
2. Update your .env file:
JUNJO_HOST_DB_DATA_PATH=/mnt/junjo-data
JUNJO_BUILD_TARGET=production
3. Start services:
docker compose up --build
Benefits:
JUNJO_HOST_DB_DATA_PATH variable is the ONLY path you need to configurecompose.yamlJUNJO_HOST_DB_DATA_PATH is not set, it defaults to ./.dbdataJunjo AI Studio uses embedded databases and file-based storage:
| Storage | Purpose | Type |
|---|---|---|
| SQLite | User data, API keys, sessions | Single file |
| Parquet | Span analytics (COLD tier) | Date-partitioned files |
| Arrow IPC WAL | Ingestion buffer (HOT tier) | Directory of IPC segments |
| Hot Snapshot | Real-time query cache | Single Parquet file |
All are stored under JUNJO_HOST_DB_DATA_PATH on your host machine. The backend uses DataFusion to query Parquet files directly.
After starting Junjo AI Studio:
http://localhost:26151 for development, http://localhost:26153 for production)This source repository does not define a complete hosted deployment topology. It defines the production runtime contract:
JUNJO_PROD_FRONTEND_URL, JUNJO_PROD_BACKEND_URL, and JUNJO_PROD_INGESTION_URLBring your own reverse proxy, ingress, or load balancer. For a production compose.yaml example, see the minimal build repositoryβ .
If you route directly to this source repository's Compose services, target frontend:26153, backend:26154, and ingestion:26155.
β οΈ IMPORTANT: The backend API and frontend MUST be deployed on the same domain (sharing the same registrable domain).
Supported configurations:
api.example.com + app.example.com (subdomain + subdomain)api.example.com + example.com (subdomain + apex)example.com + api.example.com (apex + subdomain)app.example.com + service.run.app (different domains - will NOT work)Why? Junjo AI Studio uses session cookies with SameSite=Strict for security (CSRF protection). Cross-domain deployments will cause authentication to fail.
https://github.com/mdrideout/junjo-ai-studio-minimal-buildβ
A minimal, standalone repository with just the core Junjo AI Studio components using pre-built Docker images.
Best for:
https://github.com/mdrideout/junjo-ai-studio-deployment-exampleβ
A complete, production-ready example that includes a Junjo Python Library application alongside the server infrastructure.
Best for:
The READMEβ provides step-by-step deployment instructions.
Junjo AI Studio is built and deployed to Docker Hub with each GitHub release:
Example compose.yaml: junjo-ai-studio-minimal-build/compose.yamlβ
Use these images in the deployment stack you own. For complete working examples, start from the minimal-build or deployment-example repositories.
Junjo AI Studio is designed to be low resource:
The ingestion service stores spans in Parquet files. You can inspect them using Python.
import pyarrow.parquet as pq
# Read cold tier
table = pq.read_table('.dbdata/spans/parquet/')
print(f"Cold tier spans: {table.num_rows}")
# Read hot snapshot
hot = pq.read_table('.dbdata/spans/hot_snapshot.parquet')
print(f"Hot tier spans: {hot.num_rows}")
# SQLite (user data, API keys, sessions)
sqlite3 ./.dbdata/sqlite/junjo.db
.env (see .env.example, e.g. BATCH_SIZE, FLUSH_MAX_MB, FLUSH_MAX_AGE_SECS, BACKPRESSURE_MAX_MB)Junjo AI Studio has comprehensive test coverage across all services. Tests are organized to support both local development and CI/CD pipelines.
# Run all tests (backend, frontend, contract validation, proto validation)
./run-all-tests.sh
This script runs: 0. Proto version checking - Warns if protoc version doesn't match required v30.2
Run everything:
./run-all-tests.sh - Complete test suite for all servicesBackend-specific:
./backend/scripts/run-backend-tests.sh - All backend tests (unit, integration, gRPC)./backend/scripts/validate_rest_api_contracts.sh - Contract tests (schema validation)Frontend-specific:
cd frontend && npm run test:run - All frontend tests (exits after completion)cd frontend && npm test - Frontend tests in watch modecd frontend && npm run test:contracts - Contract tests onlyIndividual services:
Junjo AI Studio uses a centralized root VERSION file for release/app metadata synchronization.
# Sync all managed version fields from VERSION
./scripts/sync-version.sh
# Set a new version and sync everything
./scripts/sync-version.sh 0.80.0
# Verify all managed files are in sync with VERSION
./scripts/check-version-sync.sh
Managed files include backend (pyproject, FastAPI metadata, OpenAPI), ingestion (Cargo.toml/Cargo.lock), and frontend (package.json/package-lock.json).
Release guardrail: Docker publish workflow validates that the GitHub release tag exactly matches VERSION.
Understanding what each validation tool does helps avoid surprises at commit time.
| Validation | run-all-tests.sh | pre-commit hook | CI (GitHub Actions) |
|---|---|---|---|
| Proto version check | β Warns | β Warns | β Enforces |
| Python linting (ruff) | β Fails | β Auto-fixes + fails | β Enforces |
| Backend tests | β Runs all | β | β Enforces |
| Ingestion tests | β Runs all | β | β Enforces |
| Frontend tests | β Runs all | β | β Enforces |
| Contract tests | β Validates | β | β Enforces |
| Proto regeneration | β Regenerates | β Regenerates + stages | β Checks staleness |
| Proto staleness check | β Fails on diff | β (auto-fixes) | β Enforces |
During development (before committing):
# Option 1: Run everything at once (recommended)
./run-all-tests.sh
# Option 2: Run individual validations
cd backend && uv run ruff check app/ # Linting
./backend/scripts/run-backend-tests.sh # Backend tests
cd ingestion && cargo test # Ingestion tests
cd frontend && npm run test:run # Frontend tests
./backend/scripts/validate_rest_api_contracts.sh # Contracts
At commit time:
git commit
# Pre-commit hook runs automatically:
# - Checks proto versions (warns if wrong)
# - Regenerates proto files (stages changes)
# - Runs orphan detection (blocks if missing .proto files)
# - Runs ruff format (auto-fixes Python style)
# - Runs ruff check (blocks if linting errors)
Philosophy:
Why run-all-tests.sh matches pre-commit:
Previously, run-all-tests.sh could pass but pre-commit would fail (orphaned schemas, linting errors). This wasted developer time debugging at commit stage. Now both tools perform the same core validations, with pre-commit adding auto-fixes.
Result: No surprises at commit time. If run-all-tests.sh passes, pre-commit will too (except for auto-fixable style issues).
Junjo AI Studio uses contract testing to prevent frontend/backend API drift. Backend Pydantic schemas are the single source of truth, validated against frontend TypeScript/Zod schemas using OpenAPI-generated mocks.
How it works:
Run contract tests:
./backend/scripts/validate_rest_api_contracts.sh
See backend/scripts/README_SCHEMA_VALIDATION.mdβ for detailed documentation.
Tests run automatically on all PRs via GitHub Actions:
.github/workflows/backend-tests.yml - Backend test suite.github/workflows/rest-api-contract-validation.yml - REST API contract tests.github/workflows/proto-staleness-check.yml - Proto file validation.github/workflows/version-sync-check.yml - Version drift validation against VERSIONContent type
Image
Digest
sha256:d1fbc4f01β¦
Size
147.4 MB
Last updated
10 days ago
docker pull mdrideout/junjo-ai-studio-backend