The stack, top to bottom
Interface
Python · reasoning
Python · learning
The seam
Backends
Rust · hot paths
why one wheelSeveral native wheels side by side invite DLL collisions on Windows. One PyO3 wheel re-exports everything and avoids the problem.
Sultaan is a single monorepo. Rust handles the hot paths (the model backend contract, Candle inference and tokenizers); Python handles orchestration (the command line, the agent, retrieval, memory, training and evaluation). Everything ships as one Python wheel.
Interface
Python · reasoning
Python · learning
The seam
Backends
Rust · hot paths
why one wheelSeveral native wheels side by side invite DLL collisions on Windows. One PyO3 wheel re-exports everything and avoids the problem.
Every model call goes through a single Backend protocol, mirrored by a Rust trait in sultaan-core that acts as the versioned FFI contract. Two backends exist from day one: llama.cpp for quantised GGUF files and Candle for safetensors. The hello-world base model is Qwen2.5-0.5B-Instruct, and both backends generate text from it.
The Candle backend implements Qwen2 generation on CPU. CUDA and Metal feature flags exist in the crate but are not the default. A third backend would need its own decision record.
uv run sultaan generate --backend llamacpp "Hello, who are you?"
uv run sultaan generate --backend candle "Hello, who are you?"
The agent is a small loop owned by the project: a system message, the user turn, tool calls and tool results, with tools registered as plain data classes. It deliberately uses no agent framework. Tools today are a Python REPL, retrieval over a document folder and a knowledge-graph lookup. A Docker sandbox with CPU, memory and time quotas is in the codebase for running untrusted code, but no command uses it by default yet; making it the default is planned session S2. A session-scoped circuit breaker stops runaway loops.
uv run sultaan agent --rag ./docs --verify "What does ADR 0017 decide?"
uv run sultaan kg add facts.db Paris capital_of France
uv run sultaan agent --kg facts.db "What is Paris the capital of?"
SOUL.md identity file that shapes the system message.open itemThe cloud-host guard is a deny-list today. Tightening it to an allow-list of local and private addresses is on the next-sessions list.
Answers can be checked by a model-free grounding verifier, which binds each claim to its best-supporting source, and by span and figure checks written with the standard library only. The evaluation page covers how the verifier is tested.
Every decision that outlives one change gets an architecture decision record (context, decision, consequences, alternatives). Accepted records are never rewritten; changes arrive as addenda or new records.
| No. | Decision | Area |
|---|---|---|
| 0001 | Hybrid Python and Rust | foundation |
| 0002 | Candle and llama.cpp from day one | inference |
| 0003 | uv and maturin toolchain | foundation |
| 0004 | DVC for model and data versioning | foundation |
| 0005 | aim for experiment tracking (later superseded) | tracking |
| 0006 | Candle Qwen2 implementation | inference |
| 0007 | Agent loop architecture | agent |
| 0008 | Move to Phase 1 | phase |
| 0009 | Defer aim, prefer mlflow | tracking |
| 0010 | Perplexity baseline | evaluation |
| 0011 | SOUL.md identity-file parser | memory |
| 0012 | Training stack | training |
| 0013 | Evaluation suite expansion | evaluation |
| 0014 | Phase 2 partial override for mem0 | memory |
| 0015 | Phase 1 ratified, move to Phase 2; Phase 3 confirmed as north star | phase |
| 0016 | Phase 3 pretraining stack | training |
| 0017 | Hybrid retrieval for RAG | retrieval |
| 0018 | Docker sandbox | agent |
| 0019 | Knowledge graph on SQLite | retrieval |
| 0020 | Grounding verifier | verification |
| 0021 | Training-run hardening, gate and provenance | training |
| 0022 | Data mixture bandit | training |
| 0023 | Span and figure verifier suite | verification |
| 0024 | Knowledge-graph trust tiers | retrieval |
| 0025 | Typed memory facts and coverage | memory |
| 0026 | First-contact run | training |