Typed Rust SDK for the Torrust Tracker Deployer, enabling other Rust projects and AI agents to programmatically manage deployment environments without shelling out to the CLI.
The SDK exposes a Deployer facade that encapsulates dependency wiring and
provides one method per deployment operation. It sits in the Presentation
Layer alongside the CLI — both share the same Application-layer command
handlers.
| Problem | How the SDK helps |
|---|---|
| CLI-only access — programmatic consumers must parse stdout/stderr | Returns typed Result<T, E> values |
| No composability — CLI commands are atomic, no mid-workflow branching | Consumers call individual operations and branch on results |
| Fragile integration — shelling out breaks on output format changes | Stable Rust API with semver guarantees |
| AI agent friction — agents must generate CLI strings and parse text | Agents call Rust methods, get structured data, match on typed errors |
Presentation Layer
├── CLI delivery (input/ → dispatch/ → controllers/ → views/)
└── SDK delivery (packages/sdk/)
│
▼
Application Layer (command_handlers/) ← SHARED, unchanged
│
▼
Domain Layer (environment/, template/, topology/, ...)
The SDK depends on the Application and Domain layers. It does NOT depend on the CLI presentation code.
The SDK lives in packages/sdk/ as a workspace
member. See packages/sdk/README.md for
quick-start usage, examples, and API reference.
Decisions that shaped the SDK design. For full ADR details, see docs/decisions/sdk-*.md.
SDK consumers should not need to understand the internal dependency graph.
The Deployer struct encapsulates wiring and exposes one method per
command handler.
Deployer::builder().working_dir(path).build() — sensible defaults,
optional customization. Follows standard Rust conventions.
Existing domain and application types are re-exported from the SDK module. No SDK-specific wrapper types. Avoids duplication and conversion overhead.
The three-level architecture (Handlers → Steps → Actions) exposes only
command handlers (Level 1) through the SDK. Steps remain pub(crate).
They are coupled to infrastructure internals and would create a brittle API.
Operations take &EnvironmentName and return () or simple result types.
No phantom typestate at the SDK layer. This supports the primary use case:
AI agents and automation that resume from any state across process restarts.
See SDK Presentation Layer Interface Design.
- SDK Presentation Layer Interface Design — name-based vs typestate design
- SDK Discarded: Scoped Environment Guard — why RAII auto-cleanup was rejected
- SDK Discarded: Typestate at SDK Layer — why compile-time ordering was rejected
- SDK Discarded: Fluent Interface — why method chaining was rejected
SDK tests use only the public API (torrust_tracker_deployer_sdk::*) and
exercise local operations against temporary workspaces. No infrastructure
required. See SDK Testing Strategy.
Current Phase: Complete (v1)
Implemented:
Deployerfacade with builder- All 14 operations (create, show, list, exists, validate, destroy, purge, provision, configure, release, run, test, create-from-file, exists)
EnvironmentCreationConfigtyped builder- Curated re-exports in
lib.rs SdkErrorunified error typeClone + Send + Syncsupport- 5 runnable examples
- 13 integration tests
- Separate
packages/sdk/workspace crate
Ideas identified during development. Not prioritized — implement when real-world usage creates demand.
- Configurable lock timeout — expose
.lock_timeout(Duration)onDeployerBuilder(currently hard-coded at 30 seconds) create_environment_from_json(&str)convenience — symmetric withcreate_environment_from_file#[non_exhaustive]on public enums — prevent downstream breakage when adding variants toSdkError,CreateEnvironmentFromFileError, etc.
tracinginstrumentation —#[instrument]spans on SDK methods for automatic structured loggingDeployerBuilder::data_directory()override — custom data path instead ofworking_dir.join("data")- Render operation — expose the CLI
rendercommand through the SDK - Idempotent deploy example — use
exists()+show()to skip completed stages - Custom progress listener example — richer
CommandProgressListenerfor UIs/dashboards
- Feature flag gating —
sdkcargo feature to gate the SDK module for CLI-only consumers - Extract to independent crate — independent versioning, crates.io publishing (wait for API stability and community adoption)