This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This is a C++ REST API server that wraps the stable-diffusion.cpp library, providing HTTP endpoints for Stable Diffusion image generation. The server is built with a modular architecture featuring three main components: HTTP Server, Generation Queue, and Model Manager.
# Create build directory and configure
mkdir build && cd build
cmake ..
# Build the project (parallel build)
cmake --build . --parallel
# Install (optional)
cmake --install .
# Build with CUDA support (default: ON)
cmake -DSD_CUDA_SUPPORT=ON ..
# Build without CUDA
cmake -DSD_CUDA_SUPPORT=OFF ..
# Debug build
cmake -DCMAKE_BUILD_TYPE=Debug ..
# Release build (default)
cmake -DCMAKE_BUILD_TYPE=Release ..
# Clean build artifacts
cd build
cmake --build . --target clean
# Or delete build directory entirely
rm -rf build
mkdir build && cd build
cmake ..
cmake --build . --parallel
Required Parameters:
Both --models-dir and --checkpoints are required.
# Basic usage with required parameters
./stable-diffusion-rest-server --models-dir /path/to/models --checkpoints checkpoints
# The above resolves checkpoints to: /path/to/models/checkpoints
# Using absolute path for checkpoints
./stable-diffusion-rest-server --models-dir /path/to/models --checkpoints /absolute/path/to/checkpoints
# With custom port and host
./stable-diffusion-rest-server --models-dir /path/to/models --checkpoints checkpoints --host 0.0.0.0 --port 8080
# With verbose logging
./stable-diffusion-rest-server --models-dir /path/to/models --checkpoints checkpoints --verbose
# With optional model directories (relative paths)
./stable-diffusion-rest-server --models-dir /path/to/models --checkpoints checkpoints --lora-dir lora --vae-dir vae
# With optional model directories (absolute paths)
./stable-diffusion-rest-server --models-dir /path/to/models --checkpoints checkpoints --lora-dir /other/lora --vae-dir /other/vae
The server supports multiple authentication methods:
# No authentication (default)
./stable-diffusion-rest-server --models-dir /path/to/models --checkpoints checkpoints --auth-method none
# JWT authentication
./stable-diffusion-rest-server --models-dir /path/to/models --checkpoints checkpoints --auth-method jwt
# API key authentication
./stable-diffusion-rest-server --models-dir /path/to/models --checkpoints checkpoints --auth-method apikey
# PAM authentication
./stable-diffusion-rest-server --models-dir /path/to/models --checkpoints checkpoints --auth-method pam --pam-service-name stable-diffusion-rest
# Optional authentication (guest access allowed)
./stable-diffusion-rest-server --models-dir /path/to/models --checkpoints checkpoints --auth-method optional --enable-guest-access
PAM Authentication Setup:
sudo apt-get install libpam0g-dev/etc/pam.d/stable-diffusion-restcmake -DENABLE_PAM_AUTH=ON ..See PAM_AUTHENTICATION.md for detailed PAM setup instructions.
Path Resolution Logic:
--models-dir--models-dir /data/models --checkpoints checkpoints → /data/models/checkpoints--models-dir /data/models --checkpoints /other/checkpoints → /other/checkpointsHTTP Server (src/server.cpp, include/server.h)
registerEndpoints()setupCORS()Generation Queue (src/generation_queue.cpp, include/generation_queue.h)
JobInfo structuresenqueueRequest(), getQueueStatus(), cancelJob()Model Manager (src/model_manager.cpp, include/model_manager.h)
cancelScan()Server::serverThreadFunction())g_running flag for graceful shutdownModel types are bit flags (can be combined):
enum class ModelType {
LORA = 1, CHECKPOINT = 2, VAE = 4, PRESETS = 8,
PROMPTS = 16, NEG_PROMPTS = 32, TAESD = 64,
ESRGAN = 128, CONTROLNET = 256, UPSCALER = 512,
EMBEDDING = 1024
};
Supported file extensions by type:
.safetensors, .pt, .ckpt.json, .yaml, .yml.txt, .json.pth, .ptPOST /api/v1/generate - General image generationPOST /api/v1/text2img - Text-to-image generationPOST /api/v1/img2img - Image-to-image generationPOST /api/v1/controlnet - ControlNet generationGET /api/v1/models - List all available modelsGET /api/v1/models/{type} - List models by typeGET /api/v1/models/{id} - Get model detailsPOST /api/v1/models/load - Load a modelPOST /api/v1/models/unload - Unload a modelPOST /api/v1/models/scan - Rescan models directoryGET /api/v1/queue - Get queue statusGET /api/v1/jobs/{id} - Get job statusDELETE /api/v1/jobs/{id} - Cancel a jobDELETE /api/v1/queue - Clear queueGET /api/v1/health - Health checkGET /api/v1/status - API statusGET /api/v1/system - System capabilitiesDependencies are managed in cmake/FindDependencies.cmake using CMake's FetchContent:
The stable-diffusion.cpp library is downloaded and built automatically via ExternalProject_Add() in the root CMakeLists.txt. The specific git tag is pinned to master-334-d05e46c.
Both GenerationQueue and ModelManager use the Pimpl (Pointer to Implementation) idiom:
class GenerationQueue {
private:
class Impl;
std::unique_ptr<Impl> pImpl;
};
All implementation details are in the .cpp files, not headers. When modifying these classes, update the inner Impl class definition in the .cpp file.
g_server allows signal handler to trigger graceful shutdowng_running atomic flag and calls server->stop()The server requires explicit configuration of model directories:
Required Parameters:
--models-dir: Base directory for models (required)--checkpoints: Checkpoints directory (required)Optional Parameters:
--lora-dir, --vae-dir, --controlnet-dir, etc. (optional)Path Resolution:
/absolute/path/to/models) are used as-ischeckpoints) are resolved relative to --models-dirresolveDirectoryPath() function in main.cpp handles this logicThe GenerationRequest structure in generation_queue.h contains all parameters from stable-diffusion.cpp's CLI including:
include/server.hsrc/server.cppServer::registerEndpoints()sendJsonResponse() and sendErrorResponse() for consistent responsesModelType in model_manager.hmodelTypeToString() and stringToModelType() in model_manager.cppServerConfig struct if a new directory parameter is neededGenerationRequest struct in generation_queue.hServer::validateGenerationParameters()StableDiffusionWrapper to pass new parameters to underlying librarystd::shared_mutex - multiple readers OR single writerstd::mutex and std::condition_variablestd::lock_guard, std::unique_lock, std::shared_lock)std::atomic<bool> for g_running, m_isRunningThe stable-diffusion.cpp library is built as an external project. Include directories and libraries are configured via the sd-cpp interface target:
target_link_libraries(stable-diffusion-rest-server PRIVATE
sd-cpp
ggml
ggml-base
ggml-cpu
${DEPENDENCY_LIBRARIES}
)
When accessing stable-diffusion.cpp APIs, include from the installed headers:
#include <stable-diffusion.h>#include <ggml.h>The wrapper class StableDiffusionWrapper (stable_diffusion_wrapper.cpp/h) encapsulates all interactions with the stable-diffusion.cpp library.
The server includes an automatic model architecture detection system that analyzes checkpoint files to determine their type and required auxiliary models.
The system can detect the following architectures:
| Architecture | Required Files | Command-Line Flags |
|---|---|---|
| SD 1.5 | VAE (optional) | --vae vae-ft-mse-840000-ema-pruned.safetensors |
| SD 2.1 | VAE (optional) | --vae vae-ft-ema-560000.safetensors |
| SDXL Base/Refiner | VAE (optional) | --vae sdxl_vae.safetensors |
| Flux Schnell | VAE, CLIP-L, T5XXL | --vae ae.safetensors --clip-l clip_l.safetensors --t5xxl t5xxl_fp16.safetensors |
| Flux Dev | VAE, CLIP-L, T5XXL | --vae ae.safetensors --clip-l clip_l.safetensors --t5xxl t5xxl_fp16.safetensors |
| Flux Chroma | VAE, T5XXL | --vae ae.safetensors --t5xxl t5xxl_fp16.safetensors |
| SD3 | VAE, CLIP-L, CLIP-G, T5XXL | --vae sd3_vae.safetensors --clip-l clip_l.safetensors --clip-g clip_g.safetensors --t5xxl t5xxl_fp16.safetensors |
| Qwen2-VL | Qwen2VL, Qwen2VL-Vision | --qwen2vl qwen2vl.safetensors --qwen2vl-vision qwen2vl_vision.safetensors |
File Format Support:
Detection Method:
double_blocks, single_blocks tensorsjoint_blocks tensorsconditioner, text_encoder_2 tensorsAPI Integration:
/api/models endpointrequired_models array listing needed auxiliary filesmissing_models array if dependencies are not foundDuring model scanning (model_manager.cpp):
if (detectedType == ModelType::CHECKPOINT) {
ModelDetectionResult detection = ModelDetector::detectModel(info.fullPath);
info.architecture = detection.architectureName;
info.recommendedVAE = detection.recommendedVAE;
info.recommendedWidth = std::stoi(detection.suggestedParams["width"]);
// ... parse other recommended parameters
// Build required models list
if (detection.needsVAE) {
info.requiredModels.push_back("VAE: " + detection.recommendedVAE);
}
}
{
"name": "chroma-unlocked-v50-Q8_0.gguf",
"type": "checkpoint",
"architecture": "Flux Chroma (Unlocked)",
"recommended_vae": "ae.safetensors",
"recommended_width": 1024,
"recommended_height": 1024,
"recommended_steps": 20,
"recommended_sampler": "euler",
"required_models": [
"VAE: ae.safetensors",
"T5XXL: t5xxl_fp16.safetensors"
],
"missing_models": [],
"has_missing_dependencies": false
}
A standalone test binary can be built to test model detection:
cd build
cmake -DBUILD_MODEL_DETECTOR_TEST=ON ..
cmake --build . --target test_model_detector
# Run tests
./src/test_model_detector /data/SD_MODELS/checkpoints
The server will automatically use the correct parameters when loading models based on detected architecture. For architectures requiring multiple auxiliary models (Flux, SD3, Qwen), the server will:
See MODEL_DETECTION.md for complete documentation on the detection system.
The project includes a Next.js-based web UI located in /webui that provides a modern interface for interacting with the REST API.
# Build Web UI manually
cd webui
npm install
npm run build
# Build via CMake (automatically copies to build directory)
cmake --build build --target webui-build
The built UI is automatically copied to build/webui/ and served by the REST API server at /ui/.
/webui/components/ui//webui/app/text2img/page.tsx - Text-to-image generation/webui/app/img2img/page.tsx - Image-to-image generation/webui/app/upscaler/page.tsx - Image upscaling/webui/app/models/page.tsx - Model management/webui/app/queue/page.tsx - Queue statusMain Layout (/webui/components/main-layout.tsx)
Sidebar and ModelStatusBar componentsSidebar (/webui/components/sidebar.tsx)
Model Status Bar (/webui/components/model-status-bar.tsx)
left-64 to avoid overlapping sidebarPrompt Textarea (/webui/components/prompt-textarea.tsx)
<lora:name:weight>) and embedding namesThe WebUI uses a specific z-index hierarchy to ensure proper stacking:
Sidebar: z-40 (always on top for navigation)
Model Status Bar: z-35 (visible but doesn't block sidebar)
Autocomplete Dropdowns: z-30 (below sidebar to allow navigation)
Main Content: z-0 (default)
Important: When adding new floating/fixed elements, respect this hierarchy to avoid blocking the sidebar navigation.
All generation pages (text2img, img2img, upscaler) use localStorage to persist form state across navigation.
Implementation (/webui/lib/hooks.ts):
// Custom hook for localStorage persistence
const [formData, setFormData] = useLocalStorage('page-form-data', defaultValues);
Keys used:
text2img-form-data - Text-to-image form stateimg2img-form-data - Image-to-image form stateupscaler-form-data - Upscaler form stateBehavior:
The WebUI communicates with the REST API via /webui/lib/api.ts:
import { apiClient } from '@/lib/api';
// Examples
const models = await apiClient.getModels('checkpoint');
const job = await apiClient.text2img(formData);
const status = await apiClient.getJobStatus(jobId);
Base URL Configuration: The API base URL is configured in /webui/.env.local and defaults to the server's configured endpoint.
Making UI Changes:
cd webui
npm run dev # Start development server on port 3000
Building for Production:
# Via CMake (recommended)
cmake --build build --target webui-build
# Or manually
cd webui && npm run build
Testing:
http://localhost:3000http://localhost:8080/ui/Issue: Sidebar menu items not clickable
Issue: Form state lost on navigation
useLocalStorage hookuseState with useLocalStorage for form dataIssue: Status bar not visible
left offset to avoid sidebarThe server dynamically generates /ui/config.js with runtime configuration:
window.__SERVER_CONFIG__ = {
apiUrl: 'http://localhost:8080',
apiBasePath: '/api',
host: 'localhost',
port: 8080,
uiVersion: 'a1b2c3d4' // Git commit hash
};
This allows the WebUI to adapt to different server configurations without rebuilding.
The WebUI implements a comprehensive caching strategy with git-based versioning to improve performance and ensure users always see the latest version.
Build Process:
cmake --build build --target webui-build, the git commit hash is extractedA version.json file is generated in /webui/public/ with:
{
"version": "a1b2c3d4", // Short git hash (8 chars)
"buildTime": "2025-11-02T18:00:00Z"
}
This file is copied to the build output and served at /ui/version.json
Server Implementation (src/server.cpp:294-380):
version.json on startup to get current UI versionconfig.js as uiVersionStatic Assets (JS, CSS, images, fonts):
Cache-Control: public, max-age=31536000, immutable
ETag: "a1b2c3d4"
immutable flag tells browser file will never changeHTML Files:
Cache-Control: public, max-age=0, must-revalidate
ETag: "a1b2c3d4"
config.js (Dynamic Configuration):
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: 0
Component: /webui/components/version-checker.tsx
The VersionChecker component:
/ui/version.json on mountwindow.__SERVER_CONFIG__.uiVersionUser Experience:
First Load (Cache Miss):
# Open browser DevTools → Network tab
# Load page → See all assets with Status 200
# Check Response Headers for Cache-Control and ETag
Reload (Cache Hit):
# Reload page → See assets with Status 200 (from disk cache)
# Or Status 304 (Not Modified) if revalidating
After Rebuild (Cache Invalidation):
# Rebuild UI: cmake --build build --target webui-build
# Restart server
# Reload page → Version checker shows update notification
# Click Refresh → All assets redownloaded with new ETag
Development (npm run dev):
localhost:3000Production (served by REST server):
/ui/build/webui/Issue: UI not showing latest changes after rebuild
Issue: Version checker not showing update notification
window.__SERVER_CONFIG__ existsIssue: Assets returning 304 even after version change
The server includes comprehensive PAM (Pluggable Authentication Modules) authentication support for integration with system authentication backends.
The PAM authentication system consists of several components:
PamAuth Class (include/pam_auth.h, src/pam_auth.cpp)
UserManager Integration (include/user_manager.h, src/user_manager.cpp)
authenticatePam() method#ifdef ENABLE_PAM_AUTHAuthMiddleware Integration (include/auth_middleware.h, src/auth_middleware.cpp)
Build System Integration (CMakeLists.txt, cmake/FindPAM.cmake)
ENABLE_PAM_AUTH optionCreate a PAM service file at /etc/pam.d/stable-diffusion-rest:
# Basic PAM configuration for stable-diffusion-rest
auth sufficient pam_unix.so try_first_pass nullok_secure
auth required pam_deny.so
account sufficient pam_unix.so
account required pam_deny.so
password sufficient pam_unix.so nullok_use_authtok nullok_secure md5 shadow
password required pam_deny.so
session required pam_limits.so
session required pam_unix.so
PAM support is conditionally compiled based on the ENABLE_PAM_AUTH flag:
#ifdef ENABLE_PAM_AUTH
// PAM-specific code
PamAuthResult PamAuth::authenticateInternal(const std::string& username, const std::string& password);
#else
// Stub implementations when PAM is not enabled
PamAuthResult PamAuth::authenticateInternal(const std::string& username, const std::string& password) {
PamAuthResult result;
result.success = false;
result.errorMessage = "PAM authentication not available (compiled without PAM support)";
result.errorCode = "PAM_NOT_AVAILABLE";
return result;
}
#endif
The system provides comprehensive error handling for PAM authentication:
| Error Code | Description | PAM Error |
|---|---|---|
| AUTHENTICATION_FAILED | Invalid credentials | PAM_AUTH_ERR |
| USER_NOT_FOUND | User does not exist | PAM_USER_UNKNOWN |
| CREDENTIAL_EXPIRED | Password expired | PAM_CRED_EXPIRED |
| ACCOUNT_EXPIRED | Account expired | PAM_ACCT_EXPIRED |
| PASSWORD_CHANGE_REQUIRED | Password change needed | PAM_NEW_AUTHTOK_REQD |
| MAX_TRIES_EXCEEDED | Too many failed attempts | PAM_MAXTRIES |
| AUTHENTICATION_UNAVAILABLE | PAM service unavailable | PAM_AUTHINFO_UNAVAIL |
Test PAM configuration with pamtester:
# Install pamtester
sudo apt-get install pamtester
# Test authentication
sudo pamtester stable-diffusion-rest username authenticate
# Test account management
sudo pamtester stable-diffusion-rest username acct_mgmt
pamtester to validate PAM service/var/log/auth.log or journalctlFor detailed PAM authentication setup instructions, see PAM_AUTHENTICATION.md.