Roadmap
Phase 3: Ollama RAG — Natural Language over Documentation
The next layer: ask questions in English, get answers sourced from your own documentation.
GET /ask?q=how do I configure 802.1X on a Catalyst switch?
{
"answer": "Use the dot1x system-auth-control command globally...",
"sources": [
"education/certifications/ccnp/dot1x-config",
"case-studies/changes/CR-2026-02-15-dot1x-rollout"
],
"model": "qwen3:30b"
}
Architecture:
| Component | Design |
|---|---|
|
On startup, vectorize all document titles + first 500 chars using Ollama |
|
Query embedding → cosine similarity against corpus → select top-K documents → assemble context → Ollama |
|
|
Config additions |
|
Hardware |
RTX 5090 local inference. No cloud API. No data leaves the machine. |
Why in-memory embeddings: The same reasoning as the DocumentCache. ~3,000 documents × 768-dim float32 = ~9 MB. Fits in RAM trivially. No Chroma, no Pinecone, no Weaviate. numpy cosine similarity over 3,000 vectors completes in microseconds.
Phase 4: Multi-Spoke — Unified Search Across 15 Repositories
The documentation system spans 15 spoke repositories. Today the API indexes only domus-captures. Multi-spoke makes the entire ecosystem queryable through one interface.
What changes:
| Component | Change |
|---|---|
|
Add |
|
|
|
Search gains a |
New endpoint |
|
Why this is a config change: The filesystem-as-database pattern means the data model is the directory structure. Adding a spoke is adding a directory. No schema migration, no index rebuild. The cache loads additional directories at startup.
Phase 5: Event Automation — Webhooks and Filesystem Watcher
The system becomes reactive. File changes trigger cache updates. Events trigger workflows.
Components:
| Component | Design |
|---|---|
|
Background task using |
|
|
|
Event bus: |
systemd service |
|
Tailscale ACL |
Restrict API access to authorized devices. The API already binds to 0.0.0.0 — Tailscale ACLs control which machines can reach port 8080. |
Dependency chain: Phase 5 requires the cache.add_page() / cache.add_partial() methods (already implemented) and the dependency injection pattern (already implemented). The foundation is in place.
Phase 6: Operational Deployment — Always-On API
Make domus-api and the association engine start on boot and stay running. No manual startup ritual.
systemd User Service
mkdir -p ~/.config/systemd/user
cat > ~/.config/systemd/user/domus-api.service << 'EOF'
[Unit]
Description=domus-api — REST API for the domus documentation ecosystem
After=network.target
[Service]
Type=simple
WorkingDirectory=/home/evanusmodestus/atelier/_projects/personal/domus-api
ExecStart=/home/evanusmodestus/atelier/_projects/personal/domus-api/.venv/bin/uvicorn domus_api.main:app --host 0.0.0.0 --port 8080
Restart=on-failure
RestartSec=5
Environment=PATH=/home/evanusmodestus/.local/bin:/usr/bin
[Install]
WantedBy=default.target
EOF
systemctl --user daemon-reload
systemctl --user enable --now domus-api
systemctl --user status domus-api
curl -s localhost:8080/ | jq '{status, pages: .counts.pages}'
journalctl --user -u domus-api -f
systemctl --user restart domus-api
systemctl --user stop domus-api
Shell Aliases
Add to ~/.zshrc or a dots-quantum aliases file:
# domus-api shortcuts
alias api-start='systemctl --user start domus-api'
alias api-stop='systemctl --user stop domus-api'
alias api-restart='systemctl --user restart domus-api'
alias api-status='systemctl --user status domus-api'
alias api-logs='journalctl --user -u domus-api -f'
# Association engine
alias assoc-link='bash ~/atelier/_projects/personal/association-engine/scripts/assoc-link.sh'
# Quick queries
alias api-stats='curl -s localhost:8080/ | jq'
alias api-search='f() { curl -s "localhost:8080/search?q=$1&limit=${2:-10}" | jq "[.results[] | {title, component}]"; }; f'
alias api-assoc='f() { curl -s "localhost:8080/associations/$1" | jq; }; f'
api-status # Is it running?
api-search "802.1X" # Quick search
api-search "certificate" 20 # Search with limit
api-assoc CISSP # Association query
api-assoc python # What does Python connect to?
assoc-link codex bash traps --teaches error-handling
Stow Integration (dots-quantum)
The service file and aliases should be stowed via dots-quantum for reproducibility across machines:
dots-quantum/
├── systemd/
│ └── .config/systemd/user/
│ └── domus-api.service
└── zsh/
└── .config/zsh/
└── aliases-domus.zsh # All domus aliases
cd ~/atelier/_projects/personal/dots-quantum
stow -t ~ systemd
stow -t ~ zsh
Verification Checklist
-
systemctl --user enable --now domus-api— service starts -
Reboot →
curl -s localhost:8080/returns operational -
api-search "security"works from any terminal -
api-assoc CISSPreturns forward + reverse -
assoc-link link test --enables test-targetcreates association -
api-logsshows request activity -
Service file stowed in dots-quantum
-
Aliases stowed in dots-quantum