Compare commits
5 Commits
v7.0.0
...
census/her
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc9b20ce73 | ||
| 1b8b784b09 | |||
|
|
56a56d7f18 | ||
| d3368a5a9d | |||
|
|
1614ef5d66 |
24
.gitea/workflows/smoke.yml
Normal file
24
.gitea/workflows/smoke.yml
Normal file
@@ -0,0 +1,24 @@
|
||||
name: Smoke Test
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches: [main]
|
||||
jobs:
|
||||
smoke:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- name: Parse check
|
||||
run: |
|
||||
find . -name '*.yml' -o -name '*.yaml' | grep -v .gitea | xargs -r python3 -c "import sys,yaml; [yaml.safe_load(open(f)) for f in sys.argv[1:]]"
|
||||
find . -name '*.json' | xargs -r python3 -m json.tool > /dev/null
|
||||
find . -name '*.py' | xargs -r python3 -m py_compile
|
||||
find . -name '*.sh' | xargs -r bash -n
|
||||
echo "PASS: All files parse"
|
||||
- name: Secret scan
|
||||
run: |
|
||||
if grep -rE 'sk-or-|sk-ant-|ghp_|AKIA' . --include='*.yml' --include='*.py' --include='*.sh' 2>/dev/null | grep -v .gitea; then exit 1; fi
|
||||
echo "PASS: No secrets"
|
||||
477
docs/hermes-agent-census.md
Normal file
477
docs/hermes-agent-census.md
Normal file
@@ -0,0 +1,477 @@
|
||||
# Hermes Agent — Feature Census
|
||||
|
||||
**Epic:** [#290 — Know Thy Agent: Hermes Feature Census](https://forge.alexanderwhitestone.com/Timmy_Foundation/hermes-agent/issues/290)
|
||||
**Date:** 2026-04-11
|
||||
**Source:** Timmy_Foundation/hermes-agent (fork of NousResearch/hermes-agent)
|
||||
**Upstream:** NousResearch/hermes-agent (last sync: 2026-04-07, 499 commits merged in PR #201)
|
||||
**Codebase:** ~200K lines Python (335 source files), 470 test files
|
||||
|
||||
---
|
||||
|
||||
## 1. Feature Matrix
|
||||
|
||||
### 1.1 Memory System
|
||||
|
||||
| Feature | Status | File:Line | Notes |
|
||||
|---------|--------|-----------|-------|
|
||||
| **`add` action** | ✅ Exists | `tools/memory_tool.py:457` | Append entry to MEMORY.md or USER.md |
|
||||
| **`replace` action** | ✅ Exists | `tools/memory_tool.py:466` | Find by substring, replace content |
|
||||
| **`remove` action** | ✅ Exists | `tools/memory_tool.py:475` | Find by substring, delete entry |
|
||||
| **Dual stores (memory + user)** | ✅ Exists | `tools/memory_tool.py:43-45` | MEMORY.md (2200 char limit) + USER.md (1375 char limit) |
|
||||
| **Entry deduplication** | ✅ Exists | `tools/memory_tool.py:128-129` | Exact-match dedup on load |
|
||||
| **Injection/exfiltration scanning** | ✅ Exists | `tools/memory_tool.py:85` | Blocks prompt injection, role hijacking, secret exfil |
|
||||
| **Frozen snapshot pattern** | ✅ Exists | `tools/memory_tool.py:119-135` | Preserves LLM prefix cache across session |
|
||||
| **Atomic writes** | ✅ Exists | `tools/memory_tool.py:417-436` | tempfile.mkstemp + os.replace |
|
||||
| **File locking (fcntl)** | ✅ Exists | `tools/memory_tool.py:137-153` | Exclusive lock for concurrent safety |
|
||||
| **External provider plugin** | ✅ Exists | `agent/memory_manager.py` | Supports 1 external provider (Honcho, Mem0, Hindsight, etc.) |
|
||||
| **Provider lifecycle hooks** | ✅ Exists | `agent/memory_provider.py:55-66` | on_memory_write, prefetch, sync_turn, on_session_end, on_pre_compress, on_delegation |
|
||||
| **Session search (past conversations)** | ✅ Exists | `tools/session_search_tool.py:492` | FTS5 search across SQLite message store |
|
||||
| **Holographic memory** | 🔌 Plugin slot | Config `memory.provider` | Accepted as external provider name, not built-in |
|
||||
| **Engram integration** | ❌ Not present | — | Not in codebase; Engram is a Timmy Foundation project |
|
||||
| **Trust system** | ❌ Not present | — | No trust scoring on memory entries |
|
||||
|
||||
### 1.2 Tool System
|
||||
|
||||
| Feature | Status | File:Line | Notes |
|
||||
|---------|--------|-----------|-------|
|
||||
| **Central registry** | ✅ Exists | `tools/registry.py:290` | Module-level singleton, all tools self-register |
|
||||
| **47 static tools** | ✅ Exists | See full list below | Organized in 21+ toolsets |
|
||||
| **Dynamic MCP tools** | ✅ Exists | `tools/mcp_tool.py` | Runtime registration from MCP servers (17 in live instance) |
|
||||
| **Tool approval system** | ✅ Exists | `tools/approval.py` | Manual/smart/off modes, dangerous command detection |
|
||||
| **Toolset composition** | ✅ Exists | `toolsets.py:404` | Composite toolsets (e.g., `debugging = terminal + web + file`) |
|
||||
| **Per-platform toolsets** | ✅ Exists | `toolsets.py` | `hermes-cli`, `hermes-telegram`, `hermes-discord`, etc. |
|
||||
| **Skill management** | ✅ Exists | `tools/skill_manager_tool.py:747` | Create, patch, delete skill documents |
|
||||
| **Mixture of Agents** | ✅ Exists | `tools/mixture_of_agents_tool.py:553` | Route through 4+ frontier LLMs |
|
||||
| **Subagent delegation** | ✅ Exists | `tools/delegate_tool.py:963` | Isolated contexts, up to 3 parallel |
|
||||
| **Code execution sandbox** | ✅ Exists | `tools/code_execution_tool.py:1360` | Python scripts with tool access |
|
||||
| **Image generation** | ✅ Exists | `tools/image_generation_tool.py:694` | FLUX 2 Pro |
|
||||
| **Vision analysis** | ✅ Exists | `tools/vision_tools.py:606` | Multi-provider vision |
|
||||
| **Text-to-speech** | ✅ Exists | `tools/tts_tool.py:974` | Edge TTS, ElevenLabs, OpenAI, NeuTTS |
|
||||
| **Speech-to-text** | ✅ Exists | Config `stt.*` | Local Whisper, Groq, OpenAI, Mistral Voxtral |
|
||||
| **Home Assistant** | ✅ Exists | `tools/homeassistant_tool.py:456-483` | 4 HA tools (list, state, services, call) |
|
||||
| **RL training** | ✅ Exists | `tools/rl_training_tool.py:1376-1394` | 10 Tinker-Atropos tools |
|
||||
| **Browser automation** | ✅ Exists | `tools/browser_tool.py:2137-2211` | 10 tools (navigate, click, type, scroll, screenshot, etc.) |
|
||||
| **Gitea client** | ✅ Exists | `tools/gitea_client.py` | Gitea API integration |
|
||||
| **Cron job management** | ✅ Exists | `tools/cronjob_tools.py:508` | Scheduled task CRUD |
|
||||
| **Send message** | ✅ Exists | `tools/send_message_tool.py:1036` | Cross-platform messaging |
|
||||
|
||||
#### Complete Tool List (47 static)
|
||||
|
||||
| # | Tool | Toolset | File:Line |
|
||||
|---|------|---------|-----------|
|
||||
| 1 | `read_file` | file | `tools/file_tools.py:832` |
|
||||
| 2 | `write_file` | file | `tools/file_tools.py:833` |
|
||||
| 3 | `patch` | file | `tools/file_tools.py:834` |
|
||||
| 4 | `search_files` | file | `tools/file_tools.py:835` |
|
||||
| 5 | `terminal` | terminal | `tools/terminal_tool.py:1783` |
|
||||
| 6 | `process` | terminal | `tools/process_registry.py:1039` |
|
||||
| 7 | `web_search` | web | `tools/web_tools.py:2082` |
|
||||
| 8 | `web_extract` | web | `tools/web_tools.py:2092` |
|
||||
| 9 | `vision_analyze` | vision | `tools/vision_tools.py:606` |
|
||||
| 10 | `image_generate` | image_gen | `tools/image_generation_tool.py:694` |
|
||||
| 11 | `text_to_speech` | tts | `tools/tts_tool.py:974` |
|
||||
| 12 | `skills_list` | skills | `tools/skills_tool.py:1357` |
|
||||
| 13 | `skill_view` | skills | `tools/skills_tool.py:1367` |
|
||||
| 14 | `skill_manage` | skills | `tools/skill_manager_tool.py:747` |
|
||||
| 15 | `browser_navigate` | browser | `tools/browser_tool.py:2137` |
|
||||
| 16 | `browser_snapshot` | browser | `tools/browser_tool.py:2145` |
|
||||
| 17 | `browser_click` | browser | `tools/browser_tool.py:2154` |
|
||||
| 18 | `browser_type` | browser | `tools/browser_tool.py:2162` |
|
||||
| 19 | `browser_scroll` | browser | `tools/browser_tool.py:2170` |
|
||||
| 20 | `browser_back` | browser | `tools/browser_tool.py:2178` |
|
||||
| 21 | `browser_press` | browser | `tools/browser_tool.py:2186` |
|
||||
| 22 | `browser_get_images` | browser | `tools/browser_tool.py:2195` |
|
||||
| 23 | `browser_vision` | browser | `tools/browser_tool.py:2203` |
|
||||
| 24 | `browser_console` | browser | `tools/browser_tool.py:2211` |
|
||||
| 25 | `todo` | todo | `tools/todo_tool.py:260` |
|
||||
| 26 | `memory` | memory | `tools/memory_tool.py:544` |
|
||||
| 27 | `session_search` | session_search | `tools/session_search_tool.py:492` |
|
||||
| 28 | `clarify` | clarify | `tools/clarify_tool.py:131` |
|
||||
| 29 | `execute_code` | code_execution | `tools/code_execution_tool.py:1360` |
|
||||
| 30 | `delegate_task` | delegation | `tools/delegate_tool.py:963` |
|
||||
| 31 | `cronjob` | cronjob | `tools/cronjob_tools.py:508` |
|
||||
| 32 | `send_message` | messaging | `tools/send_message_tool.py:1036` |
|
||||
| 33 | `mixture_of_agents` | moa | `tools/mixture_of_agents_tool.py:553` |
|
||||
| 34 | `ha_list_entities` | homeassistant | `tools/homeassistant_tool.py:456` |
|
||||
| 35 | `ha_get_state` | homeassistant | `tools/homeassistant_tool.py:465` |
|
||||
| 36 | `ha_list_services` | homeassistant | `tools/homeassistant_tool.py:474` |
|
||||
| 37 | `ha_call_service` | homeassistant | `tools/homeassistant_tool.py:483` |
|
||||
| 38-47 | `rl_*` (10 tools) | rl | `tools/rl_training_tool.py:1376-1394` |
|
||||
|
||||
### 1.3 Session System
|
||||
|
||||
| Feature | Status | File:Line | Notes |
|
||||
|---------|--------|-----------|-------|
|
||||
| **Session creation** | ✅ Exists | `gateway/session.py:676` | get_or_create_session with auto-reset |
|
||||
| **Session keying** | ✅ Exists | `gateway/session.py:429` | platform:chat_type:chat_id[:thread_id][:user_id] |
|
||||
| **Reset policies** | ✅ Exists | `gateway/session.py:610` | none / idle / daily / both |
|
||||
| **Session switching (/resume)** | ✅ Exists | `gateway/session.py:825` | Point key at a previous session ID |
|
||||
| **Session branching (/branch)** | ✅ Exists | CLI commands.py | Fork conversation history |
|
||||
| **SQLite persistence** | ✅ Exists | `hermes_state.py:41-94` | sessions + messages + FTS5 search |
|
||||
| **JSONL dual-write** | ✅ Exists | `gateway/session.py:891` | Backward compatibility with legacy format |
|
||||
| **WAL mode concurrency** | ✅ Exists | `hermes_state.py:157` | Concurrent read/write with retry |
|
||||
| **Context compression** | ✅ Exists | Config `compression.*` | Auto-compress when context exceeds ratio |
|
||||
| **Memory flush on reset** | ✅ Exists | `gateway/run.py:632` | Reviews old transcript before auto-reset |
|
||||
| **Token/cost tracking** | ✅ Exists | `hermes_state.py:41` | input, output, cache_read, cache_write, reasoning tokens |
|
||||
| **PII redaction** | ✅ Exists | Config `privacy.redact_pii` | Hash user IDs, strip phone numbers |
|
||||
|
||||
### 1.4 Plugin System
|
||||
|
||||
| Feature | Status | File:Line | Notes |
|
||||
|---------|--------|-----------|-------|
|
||||
| **Plugin discovery** | ✅ Exists | `hermes_cli/plugins.py:5-11` | User (~/.hermes/plugins/), project, pip entry-points |
|
||||
| **Plugin manifest (plugin.yaml)** | ✅ Exists | `hermes_cli/plugins.py` | name, version, requires_env, provides_tools, provides_hooks |
|
||||
| **Lifecycle hooks** | ✅ Exists | `hermes_cli/plugins.py:55-66` | 9 hooks (pre/post tool_call, llm_call, api_request; on_session_start/end/finalize/reset) |
|
||||
| **PluginContext API** | ✅ Exists | `hermes_cli/plugins.py:124-233` | register_tool, inject_message, register_cli_command, register_hook |
|
||||
| **Plugin management CLI** | ✅ Exists | `hermes_cli/plugins_cmd.py:1-690` | install, update, remove, enable, disable |
|
||||
| **Project plugins (opt-in)** | ✅ Exists | `hermes_cli/plugins.py` | Requires HERMES_ENABLE_PROJECT_PLUGINS env var |
|
||||
| **Pip plugins** | ✅ Exists | `hermes_cli/plugins.py` | Entry-point group: hermes_agent.plugins |
|
||||
|
||||
### 1.5 Config System
|
||||
|
||||
| Feature | Status | File:Line | Notes |
|
||||
|---------|--------|-----------|-------|
|
||||
| **YAML config** | ✅ Exists | `hermes_cli/config.py:259-619` | ~120 config keys across 25 sections |
|
||||
| **Schema versioning** | ✅ Exists | `hermes_cli/config.py` | `_config_version: 14` with migration support |
|
||||
| **Provider config** | ✅ Exists | Config `providers.*`, `fallback_providers` | Per-provider overrides, fallback chains |
|
||||
| **Credential pooling** | ✅ Exists | Config `credential_pool_strategies` | Key rotation strategies |
|
||||
| **Auxiliary model config** | ✅ Exists | Config `auxiliary.*` | 8 separate side-task models (vision, compression, etc.) |
|
||||
| **Smart model routing** | ✅ Exists | Config `smart_model_routing.*` | Route simple prompts to cheap model |
|
||||
| **Env var management** | ✅ Exists | `hermes_cli/config.py:643-1318` | ~80 env vars across provider/tool/messaging/setting categories |
|
||||
| **Interactive setup wizard** | ✅ Exists | `hermes_cli/setup.py` | Guided first-run configuration |
|
||||
| **Config migration** | ✅ Exists | `hermes_cli/config.py` | Auto-migrates old config versions |
|
||||
|
||||
### 1.6 Gateway
|
||||
|
||||
| Feature | Status | File:Line | Notes |
|
||||
|---------|--------|-----------|-------|
|
||||
| **18 platform adapters** | ✅ Exists | `gateway/platforms/` | Telegram, Discord, Slack, WhatsApp, Signal, Mattermost, Matrix, HomeAssistant, Email, SMS, DingTalk, API Server, Webhook, Feishu, Wecom, Weixin, BlueBubbles |
|
||||
| **Message queuing** | ✅ Exists | `gateway/run.py:507` | Queue during agent processing, media placeholder support |
|
||||
| **Agent caching** | ✅ Exists | `gateway/run.py:515` | Preserve AIAgent instances per session for prompt caching |
|
||||
| **Background reconnection** | ✅ Exists | `gateway/run.py:527` | Exponential backoff for failed platforms |
|
||||
| **Authorization** | ✅ Exists | `gateway/run.py:1826` | Per-user allowlists, DM pairing codes |
|
||||
| **Slash command interception** | ✅ Exists | `gateway/run.py` | Commands handled before agent (not billed) |
|
||||
| **ACP server** | ✅ Exists | `acp_adapter/server.py:726` | VS Code / Zed / JetBrains integration |
|
||||
| **Cron scheduler** | ✅ Exists | `cron/scheduler.py:850` | Full job scheduler with cron expressions |
|
||||
| **Batch runner** | ✅ Exists | `batch_runner.py:1285` | Parallel batch processing |
|
||||
| **API server** | ✅ Exists | `gateway/platforms/api_server.py` | OpenAI-compatible HTTP API |
|
||||
|
||||
### 1.7 Providers (20 supported)
|
||||
|
||||
| Provider | ID | Key Env Var |
|
||||
|----------|----|-------------|
|
||||
| Nous Portal | `nous` | `NOUS_BASE_URL` |
|
||||
| OpenRouter | `openrouter` | `OPENROUTER_API_KEY` |
|
||||
| Anthropic | `anthropic` | (standard) |
|
||||
| Google AI Studio | `gemini` | `GOOGLE_API_KEY`, `GEMINI_API_KEY` |
|
||||
| OpenAI Codex | `openai-codex` | (standard) |
|
||||
| GitHub Copilot | `copilot` / `copilot-acp` | (OAuth) |
|
||||
| DeepSeek | `deepseek` | `DEEPSEEK_API_KEY` |
|
||||
| Kimi / Moonshot | `kimi-coding` | `KIMI_API_KEY` |
|
||||
| Z.AI / GLM | `zai` | `GLM_API_KEY`, `ZAI_API_KEY` |
|
||||
| MiniMax | `minimax` | `MINIMAX_API_KEY` |
|
||||
| MiniMax (China) | `minimax-cn` | `MINIMAX_CN_API_KEY` |
|
||||
| Alibaba / DashScope | `alibaba` | `DASHSCOPE_API_KEY` |
|
||||
| Hugging Face | `huggingface` | `HF_TOKEN` |
|
||||
| OpenCode Zen | `opencode-zen` | `OPENCODE_ZEN_API_KEY` |
|
||||
| OpenCode Go | `opencode-go` | `OPENCODE_GO_API_KEY` |
|
||||
| Qwen OAuth | `qwen-oauth` | (Portal) |
|
||||
| AI Gateway | `ai-gateway` | (Nous) |
|
||||
| Kilo Code | `kilocode` | (standard) |
|
||||
| Ollama (local) | — | First-class via auxiliary wiring |
|
||||
| Custom endpoint | `custom` | user-provided URL |
|
||||
|
||||
### 1.8 UI / UX
|
||||
|
||||
| Feature | Status | File:Line | Notes |
|
||||
|---------|--------|-----------|-------|
|
||||
| **Skin/theme engine** | ✅ Exists | `hermes_cli/skin_engine.py` | 7 built-in skins, user YAML skins |
|
||||
| **Kawaii spinner** | ✅ Exists | `agent/display.py` | Animated faces, configurable verbs/wings |
|
||||
| **Rich banner** | ✅ Exists | `banner.py` | Logo, hero art, system info |
|
||||
| **Prompt_toolkit input** | ✅ Exists | `cli.py` | Autocomplete, history, syntax |
|
||||
| **Streaming output** | ✅ Exists | Config `display.streaming` | Optional streaming |
|
||||
| **Reasoning display** | ✅ Exists | Config `display.show_reasoning` | Show/hide chain-of-thought |
|
||||
| **Cost display** | ✅ Exists | Config `display.show_cost` | Show $ in status bar |
|
||||
| **Voice mode** | ✅ Exists | Config `voice.*` | Ctrl+B record, auto-TTS, silence detection |
|
||||
| **Human delay simulation** | ✅ Exists | Config `human_delay.*` | Simulated typing delay |
|
||||
|
||||
### 1.9 Security
|
||||
|
||||
| Feature | Status | File:Line | Notes |
|
||||
|---------|--------|-----------|-------|
|
||||
| **Tirith security scanning** | ✅ Exists | `tools/tirith_security.py` | Pre-exec code scanning |
|
||||
| **Secret redaction** | ✅ Exists | Config `security.redact_secrets` | Auto-strip secrets from output |
|
||||
| **Memory injection scanning** | ✅ Exists | `tools/memory_tool.py:85` | Blocks prompt injection in memory |
|
||||
| **URL safety** | ✅ Exists | `tools/url_safety.py` | URL reputation checking |
|
||||
| **Command approval** | ✅ Exists | `tools/approval.py` | Manual/smart/off modes |
|
||||
| **OSV vulnerability check** | ✅ Exists | `tools/osv_check.py` | Open Source Vulnerabilities DB |
|
||||
| **Conscience validator** | ✅ Exists | `tools/conscience_validator.py` | SOUL.md alignment checking |
|
||||
| **Shield detector** | ✅ Exists | `tools/shield/detector.py` | Jailbreak/crisis detection |
|
||||
|
||||
---
|
||||
|
||||
## 2. Architecture Overview
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Entry Points │
|
||||
├──────────┬──────────┬──────────┬──────────┬─────────────┤
|
||||
│ CLI │ Gateway │ ACP │ Cron │ Batch Runner│
|
||||
│ cli.py │gateway/ │acp_apt/ │ cron/ │batch_runner │
|
||||
│ 8620 ln │ run.py │server.py │sched.py │ 1285 ln │
|
||||
│ │ 7905 ln │ 726 ln │ 850 ln │ │
|
||||
└────┬─────┴────┬─────┴──────────┴──────┬───┴─────────────┘
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ AIAgent (run_agent.py, 9423 ln) │
|
||||
│ ┌──────────────────────────────────────────────────┐ │
|
||||
│ │ Core Conversation Loop │ │
|
||||
│ │ while iterations < max: │ │
|
||||
│ │ response = client.chat(tools, messages) │ │
|
||||
│ │ if tool_calls: handle_function_call() │ │
|
||||
│ │ else: return response │ │
|
||||
│ └──────────────────────┬───────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌──────────────────────▼───────────────────────────┐ │
|
||||
│ │ model_tools.py (577 ln) │ │
|
||||
│ │ _discover_tools() → handle_function_call() │ │
|
||||
│ └──────────────────────┬───────────────────────────┘ │
|
||||
└─────────────────────────┼───────────────────────────────┘
|
||||
│
|
||||
┌────────────────────▼────────────────────┐
|
||||
│ tools/registry.py (singleton) │
|
||||
│ ToolRegistry.register() → dispatch() │
|
||||
└────────────────────┬────────────────────┘
|
||||
│
|
||||
┌─────────┬───────────┼───────────┬────────────────┐
|
||||
▼ ▼ ▼ ▼ ▼
|
||||
┌────────┐┌────────┐┌──────────┐┌──────────┐ ┌──────────┐
|
||||
│ file ││terminal││ web ││ browser │ │ memory │
|
||||
│ tools ││ tool ││ tools ││ tool │ │ tool │
|
||||
│ 4 tools││2 tools ││ 2 tools ││ 10 tools │ │ 3 actions│
|
||||
└────────┘└────────┘└──────────┘└──────────┘ └────┬─────┘
|
||||
│
|
||||
┌──────────▼──────────┐
|
||||
│ agent/memory_manager │
|
||||
│ ┌──────────────────┐│
|
||||
│ │BuiltinProvider ││
|
||||
│ │(MEMORY.md+USER.md)│
|
||||
│ ├──────────────────┤│
|
||||
│ │External Provider ││
|
||||
│ │(optional, 1 max) ││
|
||||
│ └──────────────────┘│
|
||||
└─────────────────────┘
|
||||
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ Session Layer │
|
||||
│ SessionStore (gateway/session.py, 1030 ln) │
|
||||
│ SessionDB (hermes_state.py, 1238 ln) │
|
||||
│ ┌───────────┐ ┌─────────────────────────────┐ │
|
||||
│ │sessions.js│ │ state.db (SQLite + FTS5) │ │
|
||||
│ │ JSONL │ │ sessions │ messages │ fts │ │
|
||||
│ └───────────┘ └─────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────┘
|
||||
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ Gateway Platform Adapters │
|
||||
│ telegram │ discord │ slack │ whatsapp │ signal │
|
||||
│ matrix │ email │ sms │ mattermost│ api │
|
||||
│ homeassistant │ dingtalk │ feishu │ wecom │ ... │
|
||||
└─────────────────────────────────────────────────┘
|
||||
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ Plugin System │
|
||||
│ User ~/.hermes/plugins/ │ Project .hermes/ │
|
||||
│ Pip entry-points (hermes_agent.plugins) │
|
||||
│ 9 lifecycle hooks │ PluginContext API │
|
||||
└─────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Key dependency chain:**
|
||||
```
|
||||
tools/registry.py (no deps — imported by all tool files)
|
||||
↑
|
||||
tools/*.py (each calls registry.register() at import time)
|
||||
↑
|
||||
model_tools.py (imports tools/registry + triggers tool discovery)
|
||||
↑
|
||||
run_agent.py, cli.py, batch_runner.py, environments/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Recent Development Activity (Last 30 Days)
|
||||
|
||||
### Activity Summary
|
||||
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| Total commits (since 2026-03-12) | ~1,750 |
|
||||
| Top contributor | Teknium (1,169 commits) |
|
||||
| Timmy Foundation commits | ~55 (Alexander Whitestone: 21, Timmy Time: 22, Bezalel: 12) |
|
||||
| Key upstream sync | PR #201 — 499 commits from NousResearch/hermes-agent (2026-04-07) |
|
||||
|
||||
### Top Contributors (Last 30 Days)
|
||||
|
||||
| Contributor | Commits | Focus Area |
|
||||
|-------------|---------|------------|
|
||||
| Teknium | 1,169 | Core features, bug fixes, streaming, browser, Telegram/Discord |
|
||||
| teknium1 | 238 | Supplementary work |
|
||||
| 0xbyt4 | 117 | Various |
|
||||
| Test | 61 | Testing |
|
||||
| Allegro | 49 | Fleet ops, CI |
|
||||
| kshitijk4poor | 30 | Features |
|
||||
| SHL0MS | 25 | Features |
|
||||
| Google AI Agent | 23 | MemPalace plugin |
|
||||
| Timmy Time | 22 | CI, fleet config, merge coordination |
|
||||
| Alexander Whitestone | 21 | Memory fixes, browser PoC, docs, CI, provider config |
|
||||
| Bezalel | 12 | CI pipeline, devkit, health checks |
|
||||
|
||||
### Key Upstream Changes (Merged in Last 30 Days)
|
||||
|
||||
| Change | PR | Impact |
|
||||
|--------|----|--------|
|
||||
| Browser provider switch (Browserbase → Browser Use) | upstream #5750 | Breaking change in browser tooling |
|
||||
| notify_on_complete for background processes | upstream #5779 | New feature for async workflows |
|
||||
| Interactive model picker (Telegram + Discord) | upstream #5742 | UX improvement |
|
||||
| Streaming fix after tool boundaries | upstream #5739 | Bug fix |
|
||||
| Delegate: share credential pools with subagents | upstream | Security improvement |
|
||||
| Permanent command allowlist on startup | upstream #5076 | Bug fix |
|
||||
| Paginated model picker for Telegram | upstream | UX improvement |
|
||||
| Slack thread replies without @mentions | upstream | Gateway improvement |
|
||||
| Supermemory memory provider (added then removed) | upstream | Experimental, rolled back |
|
||||
| Background process management overhaul | upstream | Major feature |
|
||||
|
||||
### Timmy Foundation Contributions (Our Fork)
|
||||
|
||||
| Change | PR | Author |
|
||||
|--------|----|--------|
|
||||
| Memory remove action bridge fix | #277 | Alexander Whitestone |
|
||||
| Browser integration PoC + analysis | #262 | Alexander Whitestone |
|
||||
| Memory budget enforcement tool | #256 | Alexander Whitestone |
|
||||
| Memory sovereignty verification | #257 | Alexander Whitestone |
|
||||
| Memory Architecture Guide | #263, #258 | Alexander Whitestone |
|
||||
| MemPalace plugin creation | #259, #265 | Google AI Agent |
|
||||
| CI: duplicate model detection | #235 | Alexander Whitestone |
|
||||
| Kimi model config fix | #225 | Bezalel |
|
||||
| Ollama provider wiring fix | #223 | Alexander Whitestone |
|
||||
| Deep Self-Awareness Epic | #215 | Bezalel |
|
||||
| BOOT.md for repo | #202 | Bezalel |
|
||||
| Upstream sync (499 commits) | #201 | Alexander Whitestone |
|
||||
| Forge CI pipeline | #154, #175, #187 | Bezalel |
|
||||
| Gitea PR & Issue automation skill | #181 | Bezalel |
|
||||
| Development tools for wizard fleet | #166 | Bezalel |
|
||||
| KNOWN_VIOLATIONS justification | #267 | Manus AI |
|
||||
|
||||
---
|
||||
|
||||
## 4. Overlap Analysis
|
||||
|
||||
### What We're Building That Already Exists
|
||||
|
||||
| Timmy Foundation Planned Work | Hermes-Agent Already Has | Verdict |
|
||||
|------------------------------|--------------------------|---------|
|
||||
| **Memory system (add/remove/replace)** | `tools/memory_tool.py` with all 3 actions | **USE IT** — already exists, we just needed the `remove` fix (PR #277) |
|
||||
| **Session persistence** | SQLite + JSONL dual-write system | **USE IT** — battle-tested, FTS5 search included |
|
||||
| **Gateway platform adapters** | 18 adapters including Telegram, Discord, Matrix | **USE IT** — don't rebuild, contribute fixes |
|
||||
| **Config management** | Full YAML config with migration, env vars | **USE IT** — extend rather than replace |
|
||||
| **Plugin system** | Complete with lifecycle hooks, PluginContext API | **USE IT** — write plugins, not custom frameworks |
|
||||
| **Tool registry** | Centralized registry with self-registration | **USE IT** — register new tools via existing pattern |
|
||||
| **Cron scheduling** | `cron/scheduler.py` + `cronjob` tool | **USE IT** — integrate rather than duplicate |
|
||||
| **Subagent delegation** | `delegate_task` with isolated contexts | **USE IT** — extend for fleet coordination |
|
||||
|
||||
### What We Need That Doesn't Exist
|
||||
|
||||
| Timmy Foundation Need | Hermes-Agent Status | Action |
|
||||
|----------------------|---------------------|--------|
|
||||
| **Engram integration** | Not present | Build as external memory provider plugin |
|
||||
| **Holographic fact store** | Accepted as provider name, not implemented | Build as external memory provider |
|
||||
| **Fleet orchestration** | Not present (single-agent focus) | Build on top, contribute patterns upstream |
|
||||
| **Trust scoring on memory** | Not present | Build as extension to memory tool |
|
||||
| **Multi-agent coordination** | delegate_tool supports parallel (max 3) | Extend for fleet-wide dispatch |
|
||||
| **VPS wizard deployment** | Not present | Timmy Foundation domain — build independently |
|
||||
| **Gitea CI/CD integration** | Minimal (gitea_client.py exists) | Extend existing client |
|
||||
|
||||
### Duplication Risk Assessment
|
||||
|
||||
| Risk | Level | Details |
|
||||
|------|-------|---------|
|
||||
| Memory system duplication | 🟢 LOW | We were almost duplicating memory removal (PR #278 vs #277). Now resolved. |
|
||||
| Config system duplication | 🟢 LOW | Using hermes config directly via fork |
|
||||
| Gateway duplication | 🟡 MEDIUM | Our fleet-ops patterns may partially overlap with gateway capabilities |
|
||||
| Session management duplication | 🟢 LOW | Using hermes sessions directly |
|
||||
| Plugin system duplication | 🟢 LOW | We write plugins, not a parallel system |
|
||||
|
||||
---
|
||||
|
||||
## 5. Contribution Roadmap
|
||||
|
||||
### What to Build (Timmy Foundation Own)
|
||||
|
||||
| Item | Rationale | Priority |
|
||||
|------|-----------|----------|
|
||||
| **Engram memory provider** | Sovereign local memory (Go binary, SQLite+FTS). Must be ours. | 🔴 HIGH |
|
||||
| **Holographic fact store** | Our architecture for knowledge graph memory. Unique to Timmy. | 🔴 HIGH |
|
||||
| **Fleet orchestration layer** | Multi-wizard coordination (Allegro, Bezalel, Ezra, Claude). Not upstream's problem. | 🔴 HIGH |
|
||||
| **VPS deployment automation** | Sovereign wizard provisioning. Timmy-specific. | 🟡 MEDIUM |
|
||||
| **Trust scoring system** | Evaluate memory entry reliability. Research needed. | 🟡 MEDIUM |
|
||||
| **Gitea CI/CD integration** | Deep integration with our forge. Extend gitea_client.py. | 🟡 MEDIUM |
|
||||
| **SOUL.md compliance tooling** | Conscience validator exists (`tools/conscience_validator.py`). Extend it. | 🟢 LOW |
|
||||
|
||||
### What to Contribute Upstream
|
||||
|
||||
| Item | Rationale | Difficulty |
|
||||
|------|-----------|------------|
|
||||
| **Memory remove action fix** | Already done (PR #277). ✅ | Done |
|
||||
| **Browser integration analysis** | Useful for all users (PR #262). ✅ | Done |
|
||||
| **CI stability improvements** | Reduce deps, increase timeout (our commit). ✅ | Done |
|
||||
| **Duplicate model detection** | CI check useful for all forks (PR #235). ✅ | Done |
|
||||
| **Memory sovereignty patterns** | Verification scripts, budget enforcement. Useful broadly. | Medium |
|
||||
| **Engram provider adapter** | If Engram proves useful, offer as memory provider option. | Medium |
|
||||
| **Fleet delegation patterns** | If multi-agent coordination patterns generalize. | Hard |
|
||||
| **Wizard health monitoring** | If monitoring patterns generalize to any agent fleet. | Medium |
|
||||
|
||||
### Quick Wins (Next Sprint)
|
||||
|
||||
1. **Verify memory remove action** — Confirm PR #277 works end-to-end in our fork
|
||||
2. **Test browser tool after upstream switch** — Browserbase → Browser Use (upstream #5750) may break our PoC
|
||||
3. **Update provider config** — Kimi model references updated (PR #225), verify no remaining stale refs
|
||||
4. **Engram provider prototype** — Start implementing as external memory provider plugin
|
||||
5. **Fleet health integration** — Use gateway's background reconnection patterns for wizard fleet
|
||||
|
||||
---
|
||||
|
||||
## Appendix A: File Counts by Directory
|
||||
|
||||
| Directory | Files | Lines |
|
||||
|-----------|-------|-------|
|
||||
| `tools/` | 70+ .py files | ~50K |
|
||||
| `gateway/` | 20+ .py files | ~25K |
|
||||
| `agent/` | 10 .py files | ~10K |
|
||||
| `hermes_cli/` | 15 .py files | ~20K |
|
||||
| `acp_adapter/` | 9 .py files | ~8K |
|
||||
| `cron/` | 3 .py files | ~2K |
|
||||
| `tests/` | 470 .py files | ~80K |
|
||||
| **Total** | **335 source + 470 test** | **~200K + ~80K** |
|
||||
|
||||
## Appendix B: Key File Index
|
||||
|
||||
| File | Lines | Purpose |
|
||||
|------|-------|---------|
|
||||
| `run_agent.py` | 9,423 | AIAgent class, core conversation loop |
|
||||
| `cli.py` | 8,620 | CLI orchestrator, slash command dispatch |
|
||||
| `gateway/run.py` | 7,905 | Gateway main loop, platform management |
|
||||
| `tools/terminal_tool.py` | 1,783 | Terminal orchestration |
|
||||
| `tools/web_tools.py` | 2,082 | Web search + extraction |
|
||||
| `tools/browser_tool.py` | 2,211 | Browser automation (10 tools) |
|
||||
| `tools/code_execution_tool.py` | 1,360 | Python sandbox |
|
||||
| `tools/delegate_tool.py` | 963 | Subagent delegation |
|
||||
| `tools/mcp_tool.py` | ~1,050 | MCP client |
|
||||
| `tools/memory_tool.py` | 560 | Memory CRUD |
|
||||
| `hermes_state.py` | 1,238 | SQLite session store |
|
||||
| `gateway/session.py` | 1,030 | Session lifecycle |
|
||||
| `cron/scheduler.py` | 850 | Job scheduler |
|
||||
| `hermes_cli/config.py` | 1,318 | Config system |
|
||||
| `hermes_cli/plugins.py` | 611 | Plugin system |
|
||||
| `hermes_cli/skin_engine.py` | 500+ | Theme engine |
|
||||
351
docs/sovereign-stack.md
Normal file
351
docs/sovereign-stack.md
Normal file
@@ -0,0 +1,351 @@
|
||||
# Sovereign Stack: Replacing Homebrew with Mature Open-Source Tools
|
||||
|
||||
> Issue: #589 | Research Spike | Status: Complete
|
||||
|
||||
## Executive Summary
|
||||
|
||||
Homebrew is a macOS-first tool that has crept into our Linux server workflows. It
|
||||
runs as a non-root user, maintains its own cellar under /home/linuxbrew, and pulls
|
||||
pre-built binaries from a CDN we do not control. For a foundation building sovereign
|
||||
AI infrastructure, that is the wrong dependency graph.
|
||||
|
||||
This document evaluates the alternatives, gives copy-paste install commands, and
|
||||
lands on a recommended stack for the Timmy Foundation.
|
||||
|
||||
---
|
||||
|
||||
## 1. Package Managers: apt vs dnf vs pacman vs Nix vs Guix
|
||||
|
||||
| Criterion | apt (Debian/Ubuntu) | dnf (Fedora/RHEL) | pacman (Arch) | Nix | GNU Guix |
|
||||
|---|---|---|---|---|---|
|
||||
| Maturity | 25+ years | 20+ years | 20+ years | 20 years | 13 years |
|
||||
| Reproducible builds | No | No | No | Yes (core) | Yes (core) |
|
||||
| Declarative config | Partial (Ansible) | Partial (Ansible) | Partial (Ansible) | Yes (NixOS/modules) | Yes (Guix System) |
|
||||
| Rollback | Manual | Manual | Manual | Automatic | Automatic |
|
||||
| Binary cache trust | Distro mirrors | Distro mirrors | Distro mirrors | cache.nixos.org or self-host | ci.guix.gnu.org or self-host |
|
||||
| Server adoption | Very high (Ubuntu, Debian) | High (RHEL, Rocky, Alma) | Low | Growing | Niche |
|
||||
| Learning curve | Low | Low | Low | High | High |
|
||||
| Supply-chain model | Signed debs, curated repos | Signed rpms, curated repos | Signed pkg.tar, rolling | Content-addressed store | Content-addressed store, fully bootstrappable |
|
||||
|
||||
### Recommendation for servers
|
||||
|
||||
**Primary: apt on Debian 12 or Ubuntu 24.04 LTS**
|
||||
|
||||
Rationale: widest third-party support, long security maintenance windows, every
|
||||
AI tool we ship already has .deb or pip packages. If we need reproducibility, we
|
||||
layer Nix on top rather than replacing the base OS.
|
||||
|
||||
**Secondary: Nix as a user-space tool on any Linux**
|
||||
|
||||
```bash
|
||||
# Install Nix (multi-user, Determinate Systems installer — single command)
|
||||
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install
|
||||
|
||||
# After install, use nix-env or flakes
|
||||
nix profile install nixpkgs#ripgrep
|
||||
nix profile install nixpkgs#ffmpeg
|
||||
|
||||
# Pin a flake for reproducible dev shells
|
||||
nix develop github:timmy-foundation/sovereign-shell
|
||||
```
|
||||
|
||||
Use Nix when you need bit-for-bit reproducibility (CI, model training environments).
|
||||
Use apt for general server provisioning.
|
||||
|
||||
---
|
||||
|
||||
## 2. Containers: Docker vs Podman vs containerd
|
||||
|
||||
| Criterion | Docker | Podman | containerd (standalone) |
|
||||
|---|---|---|---|
|
||||
| Daemon required | Yes (dockerd) | No (rootless by default) | No (CRI plugin) |
|
||||
| Rootless support | Experimental | First-class | Via CRI |
|
||||
| OCI compliant | Yes | Yes | Yes |
|
||||
| Compose support | docker-compose | podman-compose / podman compose | N/A (use nerdctl) |
|
||||
| Kubernetes CRI | Via dockershim (removed) | CRI-O compatible | Native CRI |
|
||||
| Image signing | Content Trust | sigstore/cosign native | Requires external tooling |
|
||||
| Supply chain risk | Docker Hub defaults, rate-limited | Can use any OCI registry | Can use any OCI registry |
|
||||
|
||||
### Recommendation for agent isolation
|
||||
|
||||
**Podman — rootless, daemonless, Docker-compatible**
|
||||
|
||||
```bash
|
||||
# Debian/Ubuntu
|
||||
sudo apt update && sudo apt install -y podman
|
||||
|
||||
# Verify rootless
|
||||
podman info | grep -i rootless
|
||||
|
||||
# Run an agent container (no sudo needed)
|
||||
podman run -d --name timmy-agent \
|
||||
--security-opt label=disable \
|
||||
-v /opt/timmy/models:/models:ro \
|
||||
-p 8080:8080 \
|
||||
ghcr.io/timmy-foundation/agent-server:latest
|
||||
|
||||
# Compose equivalent
|
||||
podman compose -f docker-compose.yml up -d
|
||||
```
|
||||
|
||||
Why Podman:
|
||||
- No daemon = smaller attack surface, no single point of failure.
|
||||
- Rootless by default = containers do not run as root on the host.
|
||||
- Docker CLI alias works: `alias docker=podman` for migration.
|
||||
- Systemd integration for auto-start without Docker Desktop nonsense.
|
||||
|
||||
---
|
||||
|
||||
## 3. Python: uv vs pip vs conda
|
||||
|
||||
| Criterion | pip + venv | uv | conda / mamba |
|
||||
|---|---|---|---|
|
||||
| Speed | Baseline | 10-100x faster (Rust) | Slow (conda), fast (mamba) |
|
||||
| Lock files | pip-compile (pip-tools) | uv.lock (built-in) | conda-lock |
|
||||
| Virtual envs | venv module | Built-in | Built-in (envs) |
|
||||
| System Python needed | Yes | No (downloads Python itself) | No (bundles Python) |
|
||||
| Binary wheels | PyPI only | PyPI only | Conda-forge (C/C++ libs) |
|
||||
| Supply chain | PyPI (improving PEP 740) | PyPI + custom indexes | conda-forge (community) |
|
||||
| For local inference | Works but slow installs | Best for speed | Best for CUDA-linked libs |
|
||||
|
||||
### Recommendation for local inference
|
||||
|
||||
**uv — fast, modern, single binary**
|
||||
|
||||
```bash
|
||||
# Install uv
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
|
||||
# Create a project with a specific Python version
|
||||
uv init timmy-inference
|
||||
cd timmy-inference
|
||||
uv python install 3.12
|
||||
uv venv
|
||||
source .venv/bin/activate
|
||||
|
||||
# Install inference stack (fast)
|
||||
uv pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121
|
||||
uv pip install transformers accelerate vllm
|
||||
|
||||
# Or use pyproject.toml with uv.lock for reproducibility
|
||||
uv add torch transformers accelerate vllm
|
||||
uv lock
|
||||
```
|
||||
|
||||
Use conda only when you need pre-built CUDA-linked packages that PyPI does not
|
||||
provide (rare now that PyPI has manylinux CUDA wheels). Otherwise, uv wins on
|
||||
speed, simplicity, and supply-chain transparency.
|
||||
|
||||
---
|
||||
|
||||
## 4. Node: fnm vs nvm vs volta
|
||||
|
||||
| Criterion | nvm | fnm | volta |
|
||||
|---|---|---|---|
|
||||
| Written in | Bash | Rust | Rust |
|
||||
| Speed (shell startup) | ~200ms | ~1ms | ~1ms |
|
||||
| Windows support | No | Yes | Yes |
|
||||
| .nvmrc support | Native | Native | Via shim |
|
||||
| Volta pin support | No | No | Native |
|
||||
| Install method | curl script | curl script / cargo | curl script / cargo |
|
||||
|
||||
### Recommendation for tooling
|
||||
|
||||
**fnm — fast, minimal, just works**
|
||||
|
||||
```bash
|
||||
# Install fnm
|
||||
curl -fsSL https://fnm.vercel.app/install | bash -s -- --skip-shell
|
||||
|
||||
# Add to shell
|
||||
eval "$(fnm env --use-on-cd)"
|
||||
|
||||
# Install and use Node
|
||||
fnm install 22
|
||||
fnm use 22
|
||||
node --version
|
||||
|
||||
# Pin for a project
|
||||
echo "22" > .node-version
|
||||
```
|
||||
|
||||
Why fnm: nvm's Bash overhead is noticeable on every shell open. fnm is a single
|
||||
Rust binary with ~1ms startup. It reads the same .nvmrc files, so no project
|
||||
changes needed.
|
||||
|
||||
---
|
||||
|
||||
## 5. GPU: CUDA Toolkit Installation Without Package Manager
|
||||
|
||||
NVIDIA's apt repository adds a third-party GPG key and pulls ~2GB of packages.
|
||||
For sovereign infrastructure, we want to control what goes on the box.
|
||||
|
||||
### Option A: Runfile installer (recommended for servers)
|
||||
|
||||
```bash
|
||||
# Download runfile from developer.nvidia.com (select: Linux > x86_64 > Ubuntu > 22.04 > runfile)
|
||||
# Example for CUDA 12.4:
|
||||
wget https://developer.download.nvidia.com/compute/cuda/12.4.0/local_installers/cuda_12.4.0_550.54.14_linux.run
|
||||
|
||||
# Install toolkit only (skip driver if already present)
|
||||
sudo sh cuda_12.4.0_550.54.14_linux.run --toolkit --silent
|
||||
|
||||
# Set environment
|
||||
export CUDA_HOME=/usr/local/cuda-12.4
|
||||
export PATH=$CUDA_HOME/bin:$PATH
|
||||
export LD_LIBRARY_PATH=$CUDA_HOME/lib64:$LD_LIBRARY_PATH
|
||||
|
||||
# Persist
|
||||
echo 'export CUDA_HOME=/usr/local/cuda-12.4' | sudo tee /etc/profile.d/cuda.sh
|
||||
echo 'export PATH=$CUDA_HOME/bin:$PATH' | sudo tee -a /etc/profile.d/cuda.sh
|
||||
echo 'export LD_LIBRARY_PATH=$CUDA_HOME/lib64:$LD_LIBRARY_PATH' | sudo tee -a /etc/profile.d/cuda.sh
|
||||
```
|
||||
|
||||
### Option B: Containerized CUDA (best isolation)
|
||||
|
||||
```bash
|
||||
# Use NVIDIA container toolkit with Podman
|
||||
sudo apt install -y nvidia-container-toolkit
|
||||
|
||||
podman run --rm --device nvidia.com/gpu=all \
|
||||
nvcr.io/nvidia/cuda:12.4.0-base-ubuntu22.04 \
|
||||
nvidia-smi
|
||||
```
|
||||
|
||||
### Option C: Nix CUDA (reproducible but complex)
|
||||
|
||||
```nix
|
||||
# flake.nix
|
||||
{
|
||||
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
|
||||
outputs = { self, nixpkgs }: {
|
||||
devShells.x86_64-linux.default = nixpkgs.legacyPackages.x86_64-linux.mkShell {
|
||||
buildInputs = with nixpkgs.legacyPackages.x86_64-linux; [
|
||||
cudaPackages_12.cudatoolkit
|
||||
cudaPackages_12.cudnn
|
||||
python312
|
||||
python312Packages.torch
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
**Recommendation: Runfile installer for bare-metal, containerized CUDA for
|
||||
multi-tenant / CI.** Avoid NVIDIA's apt repo to reduce third-party key exposure.
|
||||
|
||||
---
|
||||
|
||||
## 6. Security: Minimizing Supply-Chain Risk
|
||||
|
||||
### Threat model
|
||||
|
||||
| Attack vector | Homebrew risk | Sovereign alternative |
|
||||
|---|---|---|
|
||||
| Upstream binary tampering | High (pre-built bottles from CDN) | Build from source or use signed distro packages |
|
||||
| Third-party GPG key compromise | Medium (Homebrew taps) | Only distro archive keys |
|
||||
| Dependency confusion | Medium (random formulae) | Curated distro repos, lock files |
|
||||
| Lateral movement from daemon | High (Docker daemon as root) | Rootless Podman |
|
||||
| Unvetted Python packages | Medium (PyPI) | uv lock files + pip-audit |
|
||||
| CUDA supply chain | High (NVIDIA apt repo) | Runfile + checksum verification |
|
||||
|
||||
### Hardening checklist
|
||||
|
||||
1. **Pin every dependency** — use uv.lock, package-lock.json, flake.lock.
|
||||
2. **Audit regularly** — `pip-audit`, `npm audit`, `osv-scanner`.
|
||||
3. **No Homebrew on servers** — use apt + Nix for reproducibility.
|
||||
4. **Rootless containers** — Podman, not Docker.
|
||||
5. **Verify downloads** — GPG-verify runfiles, check SHA256 sums.
|
||||
6. **Self-host binary caches** — Nix binary cache on your own infra.
|
||||
7. **Minimal images** — distroless or Chainguard base images for containers.
|
||||
|
||||
```bash
|
||||
# Audit Python deps
|
||||
pip-audit -r requirements.txt
|
||||
|
||||
# Audit with OSV (covers all ecosystems)
|
||||
osv-scanner --lockfile uv.lock
|
||||
osv-scanner --lockfile package-lock.json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Recommended Sovereign Stack for Timmy Foundation
|
||||
|
||||
```
|
||||
Layer Tool Why
|
||||
──────────────────────────────────────────────────────────────────
|
||||
OS Debian 12 / Ubuntu LTS Stable, 5yr security support
|
||||
Package manager apt + Nix (user-space) apt for base, Nix for reproducible dev shells
|
||||
Containers Podman (rootless) Daemonless, rootless, OCI-native
|
||||
Python uv 10-100x faster than pip, built-in lock
|
||||
Node.js fnm 1ms startup, .nvmrc compatible
|
||||
GPU Runfile installer No third-party apt repo needed
|
||||
Security audit pip-audit + osv-scanner Cross-ecosystem vulnerability scanning
|
||||
```
|
||||
|
||||
### Quick setup script (server)
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
echo "==> Updating base packages"
|
||||
sudo apt update && sudo apt upgrade -y
|
||||
|
||||
echo "==> Installing system packages"
|
||||
sudo apt install -y podman curl git build-essential
|
||||
|
||||
echo "==> Installing Nix"
|
||||
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install --no-confirm
|
||||
|
||||
echo "==> Installing uv"
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
|
||||
echo "==> Installing fnm"
|
||||
curl -fsSL https://fnm.vercel.app/install | bash -s -- --skip-shell
|
||||
|
||||
echo "==> Setting up shell"
|
||||
cat >> ~/.bashrc << 'EOF'
|
||||
# Sovereign stack
|
||||
export PATH="$HOME/.local/bin:$PATH"
|
||||
eval "$(fnm env --use-on-cd)"
|
||||
EOF
|
||||
|
||||
echo "==> Done. Run 'source ~/.bashrc' to activate."
|
||||
```
|
||||
|
||||
### What this gives us
|
||||
|
||||
- No Homebrew dependency on any server.
|
||||
- Reproducible environments via Nix flakes + uv lock files.
|
||||
- Rootless container isolation for agent workloads.
|
||||
- Fast Python installs for local model inference.
|
||||
- Minimal supply-chain surface: distro-signed packages + content-addressed Nix store.
|
||||
- Easy onboarding: one script to set up any new server.
|
||||
|
||||
---
|
||||
|
||||
## Migration path from current setup
|
||||
|
||||
1. **Phase 1 (now):** Stop installing Homebrew on new servers. Use the setup script above.
|
||||
2. **Phase 2 (this quarter):** Migrate existing servers. Uninstall linuxbrew, reinstall tools via apt/uv/fnm.
|
||||
3. **Phase 3 (next quarter):** Create a Timmy Foundation Nix flake for reproducible dev environments.
|
||||
4. **Phase 4 (ongoing):** Self-host a Nix binary cache and PyPI mirror for air-gapped deployments.
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- Nix: https://nixos.org/
|
||||
- Podman: https://podman.io/
|
||||
- uv: https://docs.astral.sh/uv/
|
||||
- fnm: https://github.com/Schniz/fnm
|
||||
- CUDA runfile: https://developer.nvidia.com/cuda-downloads
|
||||
- pip-audit: https://github.com/pypa/pip-audit
|
||||
- OSV Scanner: https://github.com/google/osv-scanner
|
||||
|
||||
---
|
||||
|
||||
*Document prepared for issue #589. Practical recommendations based on current
|
||||
tooling as of April 2026.*
|
||||
Reference in New Issue
Block a user