Migration Guide
This guide covers all breaking changes since v0.1.0 up to the current v0.10.0 release.
Upgrading to v0.10.0 (from v0.9.x)
This historical guide stops at v0.5.0. The v0.10.0 upgrade record lives on the
Upgrading page and in the root
MIGRATION.md file, which
together cover every behavioral change, Rust API change, schema migration, configuration
change and the operator upgrade checklist for v0.9.x → v0.10.0. The intervening 0.6 through 0.9
changes are recorded in
CHANGELOG.md, not in this
guide.
Token usage carriers
Every token-usage carrier now reports the full prompt/completion split plus optional
cache-read/cache-write/reasoning sub-counts, instead of a single bare count
(ACCT-01/ACCT-02/ACCT-03). PaladinResult.usage, NodeExecutionRecord.usage,
TraceEvent::NodeFinished.usage, TraceEvent::RunFinished.usage, StreamingResponse.usage,
ChunkMetadata.usage, and the HTTP ExecuteResponse.usage all replace their former
token_count/total_tokens field with a TokenUsage. TokenUsage::from_total is deleted
outright, with no deprecated replacement — use TokenUsage::new(prompt, completion) plus the
with_cache_read/with_cache_write/with_reasoning builders instead. See
MIGRATION.md §9.2
for the full per-type register.
Token primitives
Two duplications in the token-counting/window-resolution primitives are collapsed to one each
(PRIM-01…PRIM-04). TokenCounterPort gained fn is_exact(&self) -> bool { false }, so
Commissary::new/Commissary::from_port no longer take a caller-supplied is_exact_counter: bool argument — Commissary now reads exactness live from the injected counter's is_exact().
The legacy fallible garrison::TokenCounter trait and its TokenCounterFactory are removed
outright with no deprecated replacement; TiktokenCounter survives as the sole implementor of
TokenCounterPort, now the workspace's only counting contract. Both Commissary::new's window
resolution and HistoryTrimmer::resolve_limit now call the same shared
paladin_llm::window::resolve_context_window function in place of two independent precedence
walks. See MIGRATION.md §9.2
for the full per-type register.
Separately, in v0.10.0 (Phase 33, COMM-01…03), RagRetrievalService::retrieve_context
and retrieve_context_with_timeout change their return type to a result struct
carrying the Commissary's shed record, and format_for_prompt changes its parameter
to that struct; a new with_token_counter builder mirrors
PaladinExecutionService::with_token_counter. Read .memories and .shed off the
returned result rather than the old Vec. See the paladin-memory | RagRetrievalService
and paladin-memory | retrieve_context_with_timeout rows in
MIGRATION.md §9.2.
Table of Contents
- Upgrading to v0.10.0 (from v0.9.x)
- Migrating to v0.5.0 (from v0.4.x)
- Migrating to v0.4.x (from v0.3.x)
- Migrating to v0.2.0 (from v0.1.x)
- Migrating to v0.1.0 (Feature Flag Reorganization)
- Migration Scenarios
- Testing Your Migration
Migrating to v0.5.0 (from v0.4.x)
No user-facing breaking changes. v0.5.0 is the documentation-overhaul release (Milestone 11):
the full MDBook was published to GitHub Pages, new orchestration / content-processing / bridge
guides and a crate-map reference were added, and all documentation examples are now compile-verified
against the workspace. No public API changed — bump your dependency from 0.4 to 0.5 and rebuild.
The historical version = "0.4" snippets below remain valid for the 0.3 → 0.4 migration they
document; for v0.5.0 simply substitute "0.5".
Migrating to v0.4.x (from v0.3.x)
No user-facing breaking changes in v0.4.0–v0.4.3. Internal module renames only:
paladin-contentmodule rename (v0.4.0):crates/paladin-content/src/use_cases/was renamed tocrates/paladin-content/src/services/. If you importpaladin_content::use_cases::*directly, update topaladin_content::services::*.
Migrating to v0.2.0 (from v0.1.x)
v0.2.0 contains two categories of breaking changes:
1. Module Path Rename: use_cases → services
src/application/use_cases/ was renamed to src/application/services/. All import paths changed:
| Old path | New path |
|---|---|
paladin::application::use_cases::paladin::* | paladin::application::services::paladin::* |
paladin::application::use_cases::battalion::* | paladin::application::services::battalion::* |
paladin::application::use_cases::arsenal::* | paladin::application::services::arsenal::* |
paladin::application::use_cases::content::* | paladin::application::services::content::* |
paladin::application::use_cases::herald::* | paladin::application::services::herald::* |
paladin::application::use_cases::orchestration::* | paladin::application::services::orchestration::* |
paladin::application::use_cases::sanctum::* | paladin::application::services::sanctum::* |
Fix: Replace ::use_cases:: with ::services:: in all import paths.
# Find affected imports
grep -r "use_cases" src/
# Replace
find src/ -name "*.rs" -exec sed -i 's/use_cases/services/g' {} +
2. Removed Short-path Aliases
Zero-consumer pub use re-export aliases were removed from src/lib.rs. These had no workspace consumers; all underlying types are unchanged.
Fix: Replace paladin::<Type> short paths with crate-level import paths (paladin_ports::, paladin_core::, paladin_battalion::, etc.). See STABLE_API.md for the canonical import paths.
Migrating to v0.1.0 (Feature Flag Reorganization)
This section covers the original feature-flag reorganization that happened at v0.1.0.
The Change
Old Default Features (pre-v0.1.0):
default = ["redis-queue", "s3-storage", "openai-embeddings"]
New Default Features (v0.1.0+):
default = ["llm-openai"]
Impact
If you were relying on default features to provide:
- ❌ Redis queue adapter (
redis-queue) - ❌ S3/MinIO storage adapter (
s3-storage) - ❌ OpenAI embeddings (
openai-embeddings)
These are no longer enabled by default and must be explicitly added to your Cargo.toml.
Who Is Affected?
You are affected if:
- You use Redis queues in your code
- You use S3/MinIO file storage in your code
- You use OpenAI embeddings in your code
- Your
Cargo.tomldoes NOT explicitly list features, relying only on:[dependencies] paladin-ai = "0.4" # No features = default features
You are NOT affected if:
- ✅ You already explicitly list all required features in
Cargo.toml - ✅ You only use core Paladin orchestration (agents, battalions)
- ✅ You use
features = ["full"]for development
Quick Fix
Option 1: Restore Old Behavior (Recommended for Migration)
Add the old default features explicitly:
[dependencies]
paladin-ai = { version = "0.4", features = ["llm-openai", "redis-queue", "s3-storage", "openai-embeddings"] }
This maintains exact functionality while being explicit about requirements.
Option 2: Use the full Feature (Development/Testing)
Enable all features:
[dependencies]
paladin-ai = { version = "0.4", features = ["full"] }
Warning: This includes ALL optional features. For production, explicitly list only what you need.
Option 3: Minimal Migration (Production Recommended)
Add only the features you actually use:
[dependencies]
# Example: Only need Redis queue
paladin-ai = { version = "0.4", features = ["redis-queue"] }
# Example: Only need S3 storage
paladin-ai = { version = "0.4", features = ["s3-storage"] }
# Example: Need both
paladin-ai = { version = "0.4", features = ["redis-queue", "s3-storage"] }
Migration Scenarios
Scenario 1: Production API Server with Storage
Before:
[dependencies]
paladin-ai = "0.4" # Implicitly got redis-queue, s3-storage, openai-embeddings
After:
[dependencies]
paladin-ai = { version = "0.4", features = ["llm-openai", "redis-queue", "s3-storage", "web-server"] }
Why: Explicitly declares infrastructure dependencies. Adds web-server if you use REST APIs.
Scenario 2: Content Processing Pipeline
Before:
[dependencies]
paladin-ai = "0.4"
Your code uses:
- PDF extraction
- Web scraping
- S3 storage
- Redis queues
After:
[dependencies]
paladin-ai = { version = "0.4", features = [
"llm-openai", # Default LLM provider
"content-processing", # PDF, scraping, RSS, tokenization
"redis-queue", # Async job queue
"s3-storage" # File storage
] }
Scenario 3: Multi-Provider Agent Orchestration
Before:
[dependencies]
paladin-ai = "0.4"
Your code uses:
- Multiple LLM providers (OpenAI, Anthropic, DeepSeek)
- No storage or queues
After:
[dependencies]
paladin-ai = { version = "0.4", default-features = false, features = ["llm-all"] }
Why: default-features = false removes the default llm-openai, then llm-all adds all providers.
Scenario 4: Microservice with Notifications
Before:
[dependencies]
paladin-ai = "0.4"
Your code uses:
- Email notifications
- Web API
- S3 storage
After:
[dependencies]
paladin-ai = { version = "0.4", features = [
"llm-openai", # LLM provider
"web-server", # REST API
"notifications", # Email with templates
"s3-storage" # File storage
] }
Scenario 5: Development Environment
Before:
[dependencies]
paladin-ai = "0.4"
[dev-dependencies]
# Additional test deps...
After:
[dependencies]
# Production - minimal features
paladin-ai = { version = "0.4", features = ["llm-openai", "redis-queue"] }
[dev-dependencies]
# Development - all features for testing
paladin-ai = { version = "0.4", features = ["full"] }
What Changed
Feature Flag Reorganization
| Category | Old Behavior | New Behavior |
|---|---|---|
| Default Features | redis-queue, s3-storage, openai-embeddings | llm-openai only |
| LLM Providers | Implicit (always included) | Explicit flags: llm-openai, llm-anthropic, llm-deepseek |
| Content Processing | Always included | content-processing flag gates pdf-extract, scraper, etc. |
| Web Server | Always included | web-server flag gates actix-web, axum |
| Notifications | Always included | notifications flag gates lettre, handlebars |
| Vision | Implicit | vision flag for multimodal capabilities |
New Convenience Flags
| Flag | Equivalent To | Purpose |
|---|---|---|
llm-all | llm-openai + llm-anthropic + llm-deepseek | All LLM providers |
full | All optional features | Development/testing |
Why This Change
Benefits
- Smaller Binaries - Default build is ~40% smaller (10-14 MB vs 25-35 MB)
- Faster Compile Times - Default build compiles ~60% faster (40-60s vs 3-5 min)
- Clearer Dependencies - Explicit about what your application actually uses
- Better Modularity - Pick only the LLM providers you need
- Security - Smaller attack surface by excluding unused dependencies
Philosophy
Old Approach: "Include everything by default, users opt-out if needed"
- ❌ Slow compilation for simple use cases
- ❌ Large binaries even for minimal deployments
- ❌ Unclear what features are actually required
New Approach: "Start minimal, opt-in to what you need"
- ✅ Fast iteration for core orchestration development
- ✅ Explicit about infrastructure dependencies
- ✅ Production builds include only necessary code
Testing Your Migration
Step 1: Update Cargo.toml
Apply one of the migration scenarios above.
Step 2: Verify Compilation
# Clean build to ensure no cached artifacts
cargo clean
# Build with your new features
cargo build
# Check for missing features (look for errors like):
# error[E0433]: failed to resolve: use of undeclared crate or module `redis`
Step 3: Run Tests
# Run all tests with your feature set
cargo test
# If you have integration tests requiring services:
cargo test --features integration-tests
Step 4: Check for Warnings
# Ensure no clippy warnings about unused dependencies
cargo clippy --all-targets -- -D warnings
Step 5: Verify Runtime Behavior
Test critical paths that use:
- Redis queues (if using
redis-queue) - S3 storage (if using
s3-storage) - Email notifications (if using
notifications) - Web APIs (if using
web-server)
Common Migration Errors
Error 1: Unresolved Import
error[E0432]: unresolved import `paladin::infrastructure::adapters::queue::redis`
Cause: Missing redis-queue feature
Fix:
paladin-ai = { version = "0.4", features = ["redis-queue"] }
Error 2: Missing Adapter Struct
error[E0433]: failed to resolve: use of undeclared type `MinioAdapter`
Cause: Missing s3-storage feature
Fix:
paladin-ai = { version = "0.4", features = ["s3-storage"] }
Error 3: Content Type Detection Missing
error[E0425]: cannot find function `detect_content_type` in this scope
Cause: Missing s3-storage feature (function is feature-gated)
Fix:
paladin-ai = { version = "0.4", features = ["s3-storage"] }
Error 4: PDF Extraction Failed
error[E0433]: failed to resolve: use of undeclared crate `pdf_extract`
Cause: Missing content-processing feature
Fix:
paladin-ai = { version = "0.4", features = ["content-processing"] }
Rollback Plan
If you need to temporarily revert to old behavior while planning migration:
Option 1: Pin to Old Version
[dependencies]
paladin = "0.0.x" # Use specific pre-v0.1.0 version
Check available versions:
cargo search paladin
Option 2: Use Full Features
[dependencies]
paladin-ai = { version = "0.4", features = ["full"] }
This includes everything and more, allowing time for proper migration planning.
Getting Help
Documentation
- Feature Flags Reference: Feature Flags
- Configuration Guide: Configuration Guide
- Changelog: CHANGELOG
Support Channels
- GitHub Issues: Report migration problems
- GitHub Discussions: Ask migration questions
- Examples: Check examples/ for feature-annotated examples
Checklist
Use this checklist to track your migration:
- Read this migration guide
- Identify which features your code uses
-
Update
Cargo.tomlwith explicit features -
Run
cargo clean && cargo build -
Run
cargo test -
Run
cargo clippy --all-targets -- -D warnings - Test critical runtime paths
- Update CI/CD workflows if needed
- Document feature requirements in your README
- Deploy to staging and verify
- Deploy to production
Timeline
| Version | Status | Default Features |
|---|---|---|
| < 0.1.0 | Old | redis-queue, s3-storage, openai-embeddings |
| 0.1.0 | Released | llm-openai only |
| 0.10.0 | Current | llm-openai, llm-anthropic, llm-deepseek |
| Future | Planned | May add more granular LLM provider features |
Feedback
This migration guide is a living document. If you encounter migration scenarios not covered here, please:
- Open a GitHub issue describing your use case
- Submit a PR to add your scenario to this guide
- Share your experience in GitHub Discussions
Your feedback helps improve Paladin for everyone! 🛡️
CLI Feature Isolation (Milestone 4 — Epic 3)
What Changed
The application::cli module and the paladin-cli binary are now gated behind the cli feature flag. The following dependencies are now optional and only compiled when cli is enabled:
clap(CLI argument parsing)dialoguer(interactive prompts)indicatif(progress bars)console(terminal styling)serde_yaml(YAML config parsing)
Who Is Affected?
Library consumers: No impact. The cli feature was never part of the default feature set. Library builds are unaffected.
paladin-cli binary users: The binary now requires --features cli to compile:
# Before (always compiled):
cargo build --bin paladin-cli
# After (requires cli feature):
cargo build --bin paladin-cli --features cli
full feature users: No change — full already includes cli.
Migration
If you directly import from paladin::application::cli (uncommon — internal use only):
# Cargo.toml — add the cli feature
[dependencies]
paladin-ai = { version = "0.4", features = ["cli"] }
Or add cli to your own feature re-export:
[features]
my-cli = ["paladin/cli"]