198 lines
11 KiB
Markdown
198 lines
11 KiB
Markdown
# Architecture Patterns
|
|
|
|
**Domain:** Platform engineering agent (Hermes Agent configuration)
|
|
**Researched:** 2026-06-14
|
|
|
|
## Recommended Architecture
|
|
|
|
The v1.1 features are additive — they extend an existing Hermes Agent deployment without modifying Hermes core. The architecture is a **plugin + script + configuration** layer around Hermes' built-in extension points.
|
|
|
|
```
|
|
┌─────────────────────────────────────────┐
|
|
│ Telegram Gateway │
|
|
│ (already active, TELEGRAM_HOME_CHANNEL) │
|
|
└────────────┬────────────────────────────┘
|
|
│
|
|
┌────────────▼────────────────────────────┐
|
|
│ Hermes Agent Runtime │
|
|
│ ┌────────────────────────────────────┐ │
|
|
│ │ Hindsight Memory Provider │ │
|
|
│ │ (local embedded PostgreSQL daemon)│ │
|
|
│ │ auto_retain: true │ │
|
|
│ │ auto_recall: true │ │
|
|
│ │ memory_mode: hybrid │ │
|
|
│ └────────────────────────────────────┘ │
|
|
│ ┌────────────────────────────────────┐ │
|
|
│ │ Built-in Memory (fallback) │ │
|
|
│ │ MEMORY.md + USER.md │ │
|
|
│ └────────────────────────────────────┘ │
|
|
│ ┌────────────────────────────────────┐ │
|
|
│ │ Plugin Hook System │ │
|
|
│ │ on_session_start → repo cloning │ │
|
|
│ │ pre_llm_call → context injection │ │
|
|
│ └────────────────────────────────────┘ │
|
|
└──────────────────────────────────────────┘
|
|
│
|
|
┌─────────────────────┼─────────────────────┐
|
|
│ │ │
|
|
┌─────────▼─────────┐ ┌────────▼────────┐ ┌─────────▼─────────┐
|
|
│ Docker Terminal │ │ Cron Jobs │ │ Session Storage │
|
|
│ (repo workspace) │ │ (reporting, │ │ (state.db) │
|
|
│ DEFAULT_REPOS │ │ archiving) │ │ │
|
|
│ cloned via hook │ │ │ │ export_session() │
|
|
└───────────────────┘ └─────────────────┘ │ delete_session() │
|
|
└───────────────────┘
|
|
│
|
|
┌────────▼─────────┐
|
|
│ Archive Storage │
|
|
│ ~/.hermes/ │
|
|
│ archive/sessions/│
|
|
└──────────────────┘
|
|
```
|
|
|
|
### Component Boundaries
|
|
|
|
| Component | Responsibility | Communicates With |
|
|
|-----------|---------------|-------------------|
|
|
| **Hindsight Provider** | Cross-session memory with knowledge graph, entity resolution, semantic recall | Hermes agent loop (pre-turn recall, post-turn retain), local PostgreSQL, OpenRouter (LLM extraction) |
|
|
| **Repo Clone Hook** | On session start, clones DEFAULT_REPOS into workspace | Docker terminal (via `terminal` tool or subprocess), filesystem |
|
|
| **Daily Report Skill** | Instructs agent what data to gather and how to format the daily summary | SessionDB (via `state.db` queries or `session_search`), Telegram (via `send_message`), Jira API (via ngn-jira skill) |
|
|
| **Session Archive Script** | Exports stale sessions to JSON, deletes from live DB | SessionDB API (`export_session`, `delete_session`), archive filesystem |
|
|
| **Built-in Memory** | Always-active fallback for critical facts | Agent system prompt (frozen at session start) |
|
|
|
|
### Data Flow
|
|
|
|
#### Session Start (Default Repos)
|
|
```
|
|
User sends first message
|
|
→ `on_session_start` hook fires
|
|
→ Repo clone plugin checks /workspace/
|
|
→ Missing repos cloned via git (needs credential mount)
|
|
→ `pre_llm_call` hook fires (is_first_turn=True)
|
|
→ Plugin injects "Cloned repos: rai-ops, rai-deployment, rai-devtools" as context
|
|
→ Agent sees repos available in workspace
|
|
```
|
|
|
|
#### Memory Flow (Hindsight)
|
|
```
|
|
Agent turn completes
|
|
→ Built-in memory save (MEMORY.md / USER.md)
|
|
→ Hindsight auto_retain: conversation turn + entity extraction
|
|
→ Stored in local PostgreSQL with knowledge graph
|
|
|
|
Next turn (any session)
|
|
→ Hindsight auto_recall: semantic search for relevant memories
|
|
→ Results injected as context into the turn
|
|
→ Agent sees recalled facts from any past session
|
|
```
|
|
|
|
#### Daily Report Flow
|
|
```
|
|
Cron tick at 09:00
|
|
→ Scheduler loads daily-report skill
|
|
→ Creates fresh AIAgent session
|
|
→ Skill prompt instructs agent to:
|
|
1. Query state.db for recent sessions
|
|
2. Query hindsight for relevant cross-session facts
|
|
3. Query Jira for open/updated tickets
|
|
4. Format as Telegram-friendly summary
|
|
→ Agent produces report
|
|
→ Delivered to TELEGRAM_HOME_CHANNEL
|
|
```
|
|
|
|
#### Session Archive Flow
|
|
```
|
|
Cron tick on Sunday 06:00
|
|
→ No-agent script runs
|
|
→ Queries state.db for sessions inactive >30d
|
|
→ For each: export_session() → write JSON → delete_session()
|
|
→ Summary of archived sessions delivered to Telegram
|
|
```
|
|
|
|
## Patterns to Follow
|
|
|
|
### Pattern 1: Plugin Hook for Session Initialization
|
|
**What:** Use Hermes' plugin hook system (`ctx.register_hook("on_session_start", handler)`) to run initialization logic when a new session begins.
|
|
**When:** Any setup that should happen exactly once per session, before the agent processes any user message.
|
|
**Example:**
|
|
```python
|
|
def clone_default_repos(session_id, model, platform, **kwargs):
|
|
repos = ["rai-ops", "rai-deployment", "rai-devtools"]
|
|
for repo in repos:
|
|
path = f"/workspace/{repo}"
|
|
if not os.path.exists(path):
|
|
subprocess.run(["git", "clone", f"github.com/rai-apps/{repo}", path])
|
|
|
|
def register(ctx):
|
|
ctx.register_hook("on_session_start", clone_default_repos)
|
|
```
|
|
|
|
### Pattern 2: Skill-Backed Cron Jobs
|
|
**What:** Cron jobs that load a skill before executing. The skill provides structured instructions; the cron prompt is the task.
|
|
**When:** Recurring tasks that benefit from agent reasoning but follow a repeatable structure.
|
|
**Example:**
|
|
```bash
|
|
hermes cron create "0 9 * * *" \
|
|
--skill daily-report \
|
|
--deliver telegram:-100474440517 \
|
|
--name "Daily Platform Report"
|
|
```
|
|
The skill (`daily-report/SKILL.md`) contains the report template. The cron job's prompt is just "Generate today's report."
|
|
|
|
### Pattern 3: No-Agent Script for Deterministic Automation
|
|
**What:** Cron jobs with `no_agent=True` that run a script directly, skipping the LLM entirely.
|
|
**When:** Tasks where the output is fully determined by script logic — archiving, data gathering, threshold checks.
|
|
**Example:**
|
|
```bash
|
|
hermes cron create "0 6 * * 0" \
|
|
--no-agent \
|
|
--script archive-stale-sessions.py \
|
|
--deliver telegram:-100474440517 \
|
|
--name "Weekly Session Archive"
|
|
```
|
|
|
|
### Pattern 4: Export-Before-Delete for Data Safety
|
|
**What:** Before removing any data from the live system, export it to an archive file first.
|
|
**When:** Any destructive operation on session data, files, or state.
|
|
**Example:**
|
|
```python
|
|
data = db.export_session(session_id)
|
|
archive_path = archive_dir / f"{session_id}.json"
|
|
archive_path.write_text(json.dumps(data, indent=2))
|
|
db.delete_session(session_id)
|
|
```
|
|
|
|
## Anti-Patterns to Avoid
|
|
|
|
### Anti-Pattern 1: Monkey-Patching Hermes Core
|
|
**What:** Modifying `~/.hermes/hermes-agent/` source files to add custom behavior.
|
|
**Why bad:** Hermes updates overwrite changes. The agent auto-updates. Custom patches break silently and are unrecoverable.
|
|
**Instead:** Use documented extension points: plugin hooks, shell hooks, skills, cron jobs.
|
|
|
|
### Anti-Pattern 2: Direct `state.db` Schema Queries in Production Scripts
|
|
**What:** Writing SQL queries against `~/.hermes/state.db` that depend on internal schema details.
|
|
**Why bad:** Schema changes between releases without notice (currently v11, has gone through 11 migrations). Queries break after `hermes update`.
|
|
**Instead:** Use `SessionDB` API methods (`export_session()`, `create_session()`, `get_messages()`). Fall back to direct SQL only in controlled scripts that are tested after each Hermes update.
|
|
|
|
### Anti-Pattern 3: Storing Credentials in Workspace Files
|
|
**What:** Writing GitHub tokens or SSH keys into the Docker container's workspace.
|
|
**Why bad:** If the agent is compromised (prompt injection), credentials in workspace files can be exfiltrated via `read_file` or `terminal` output.
|
|
**Instead:** Mount credentials read-only at the Docker level (`docker_volumes: [path:path:ro]`). Use `docker_forward_env` for environment variable-based credentials.
|
|
|
|
## Scalability Considerations
|
|
|
|
| Concern | At 1 user | At 10 users (future team) | Notes |
|
|
|---------|-----------|---------------------------|-------|
|
|
| Hindsight DB | <1GB PostgreSQL | 5-50GB PostgreSQL | Local embedded mode is single-user. For teams, switch to cloud mode or self-hosted Hindsight. |
|
|
| Session archive | ~100 sessions/year | ~1,000 sessions/year | JSON files are tiny (~50KB each). Storage is negligible. |
|
|
| Cron report LLM cost | 1 report/day ~1K tokens | 10 reports/day ~10K tokens | Cost scales linearly with users. Consider no-agent mode for data sections. |
|
|
| Repo clones | 3 repos per session | Same (shared workspaces) | Container persistence means clones survive across sessions in the same container. |
|
|
|
|
## Sources
|
|
|
|
- Hermes Agent docs: Hook system (`website/docs/user-guide/features/hooks.md`)
|
|
- Hermes Agent docs: Cron system (`website/docs/user-guide/features/cron.md`)
|
|
- Hermes Agent docs: Session storage (`website/docs/developer-guide/session-storage.md`)
|
|
- Hermes Agent source: `hermes_state.py`, `agent/curator.py`, `hermes_cli/hooks.py`
|
|
- ngn-agent `config.yaml` and `initial-plan.md`
|