diff --git a/specs/06-Decision-Records/ADR-031-hermes-agent-telegram-devops-bridge.md b/specs/06-Decision-Records/ADR-031-hermes-agent-telegram-devops-bridge.md index e5c7f9fc..bb872c45 100644 --- a/specs/06-Decision-Records/ADR-031-hermes-agent-telegram-devops-bridge.md +++ b/specs/06-Decision-Records/ADR-031-hermes-agent-telegram-devops-bridge.md @@ -1,29 +1,47 @@ -# ADR-031: NAP-DMS Integration Strategy (Hermes Agent & Telegram Bridge) +# ADR-031: Hermes Agent — Autonomous Dev Orchestrator & Telegram DevOps Bridge (v2.0) ## Status - **Status:** Draft - **Date:** 2026-05-28 +- **Version:** 2.0 (2026-05-29 — grill-with-docs: Orchestration as primary concern) - **Deciders:** NAP-DMS Architecture Team +- **Supersedes:** ADR-031 v1.1 (DevOps Bridge only) -### Locked Decisions During Grill +### Locked Decisions (v1.x — DevOps Bridge Foundation) -ข้อตกลงด้านล่างถูกล็อคระหว่าง grill session แล้ว แต่ ADR-031 ยังอยู่ในสถานะ Draft จนกว่า scope และ rollout plan จะ stable: +ข้อตกลงด้านล่างถูกล็อคตั้งแต่ v1.x และยังคงบังคับใช้ใน v2.0: -* **Hermes role:** Hermes เป็น Developer Operations Agent / Integration Assistant เท่านั้น ไม่ใช่ production DMS service และไม่ใช่ AI inference boundary ของ DMS -* **Database access:** Hermes เชื่อม MariaDB ได้เฉพาะ read-only account หรือ read-only replica สำหรับ schema inspection, metadata diagnostics, และ query verification เท่านั้น -* **Document storage:** Hermes ห้าม mount, browse, หรืออ่าน permanent document storage ของ production โดยตรง หากต้องตรวจเอกสารจริงต้องผ่าน DMS Backend API +* **Hermes role:** Hermes เป็น Developer Operations Agent / Autonomous Dev Orchestrator ไม่ใช่ production DMS service และไม่ใช่ AI inference boundary ของ DMS +* **Database access:** Hermes เชื่อม MariaDB ได้เฉพาะ read-only account สำหรับ schema inspection, metadata diagnostics เท่านั้น +* **Document storage:** Hermes ห้าม mount, browse, หรืออ่าน permanent document storage ของ production โดยตรง * **Telegram scope:** Hermes Telegram ใช้สำหรับ DevOps commands เท่านั้น ไม่ใช่ production DMS command channel -* **DMS Telegram:** Telegram command สำหรับ query/mutate เอกสารจริงเป็น future separate ADR/spec และต้อง enforce ADR-009/016/019/023A -* **Hermes proxy:** `hermes proxy` เป็น Developer AI Proxy only สำหรับ coding/devops assistance ไม่ใช่ DMS AI runtime หรือ document intelligence path -* **Telegram writes:** Telegram write actions ต้องมี explicit confirmation; forbidden actions เช่น push ไป `main`/`master`, production deploy, schema migration execution, direct DB writes, และ storage delete ห้ามทำผ่าน Telegram -* **Schema rollout:** ADR-031 rollout ไม่เพิ่มหรือแก้ production DMS schema รวมถึงไม่สร้าง `user_telegram_mapping` +* **DMS Telegram:** Telegram command สำหรับ query/mutate เอกสารจริงเป็น future separate ADR/spec +* **Hermes proxy:** `hermes proxy` เป็น Developer AI Proxy only ไม่ใช่ DMS AI runtime +* **Telegram writes:** ต้องมี explicit confirmation; push `main`/`master`, production deploy, schema migration, direct DB writes, storage delete ห้ามทุกกรณี +* **Schema rollout:** ADR-031 ไม่เพิ่มหรือแก้ production DMS schema + +### Locked Decisions (v2.0 — Orchestration Layer) + +ข้อตกลงใหม่จาก grill session 2026-05-29: + +* **Cloud AI Exception:** Hermes Orchestrator layer อนุญาต Cloud AI API (Claude/GPT-4o) ได้ — เป็น exception จาก ADR-023A ที่ใช้เฉพาะ DevOps/Dev Orchestration layer เท่านั้น ไม่ใช่ DMS document processing +* **Data Classification (Dev-Out Policy):** Code, Config, ADR, Stack trace ส่ง Cloud AI ได้ — Production runtime data จาก DB query (document content, user info, project business data) ห้ามส่งออกทุกกรณี +* **Dev Qdrant:** Separate Qdrant instance บน ASUSTOR สำหรับ codebase embedding โดยเฉพาะ — ห้ามใช้ Qdrant instance เดียวกับ DMS document RAG (ADR-023A) +* **SOUL.md:** Hermes working journal อยู่ใน container เท่านั้น (`/volume1/docker/hermes/SOUL.md`) ไม่ sync กลับ repo +* **Context Source:** Hermes ดึง project context จาก `specs/06-Decision-Records/CONTEXT-ADR-031.md` + `AGENTS.md` โดยตรง ไม่ใช้ Obsidian หรือ external knowledge base +* **Sub-agent Delegation:** Hermes orchestrate โดย (1) Cloud sub-agents ใช้ model เล็กกว่า (Claude Haiku/GPT-4o-mini) สำหรับ code generation tasks และ (2) MCP invocations ไปยัง Windsurf/agy ที่มีอยู่แล้ว +* **Git Identity:** Hermes ใช้ Gitea service account (`hermes-bot`) push เฉพาะ `hermes/*` branches — ห้าม push ตรง `main`/`develop` ทุกกรณี — ทุก change ต้องผ่าน PR ที่ human approve ## Context -การตั้งค่าระบบ **Hermes Agent** ในโปรเจกต์ **NAP-DMS (LCBP3)** เวอร์ชัน 1.9.0 เพื่อเชื่อมต่อกับโครงสร้างพื้นฐานเดิมและขยายขีดความสามารถผ่าน Telegram Bridge สำหรับการแจ้งเตือนและการสั่งงานผ่านระบบ Command +การตั้งค่าระบบ **Hermes Agent** ในโปรเจกต์ **NAP-DMS (LCBP3)** เพื่อทำหน้าที่เป็น **Autonomous Development Loop Orchestrator** — ควบคุมงาน AI Coding ทั้งหมด วาง Roadmap จ่ายงานให้ sub-agents ตรวจสอบผลลัพธ์ และสร้าง PR สำหรับ human review -Hermes Agent ถูกนิยามเป็น **Developer Operations Agent / Integration Assistant** สำหรับงานพัฒนา, ตรวจสอบ, ประสานเครื่องมือ, และช่วยสั่งงาน DevOps เท่านั้น ไม่ใช่ production DMS service และไม่ใช่ AI inference boundary ของ DMS ตาม ADR-023/ADR-023A +ใน v2.0 Hermes มี 2 primary roles: +1. **Autonomous Dev Orchestrator** (primary) — คุม development loop ตั้งแต่ requirement จนถึง PR +2. **Telegram DevOps Bridge** (subsystem) — DevOps commands, CI status, Gitea notifications + +Hermes ไม่ใช่ production DMS service และไม่ใช่ DMS AI inference boundary (ADR-023/ADR-023A) แต่ได้รับ **Cloud AI exception** สำหรับ dev orchestration layer โดยเฉพาะ พร้อม Data Classification Policy ที่ชัดเจน ## Decision @@ -58,6 +76,166 @@ Hermes Agent ถูกนิยามเป็น **Developer Operations Agent / --- +## Orchestration Architecture (v2.0 — Primary Concern) + +### Overview: Autonomous Development Loop + +Hermes ทำหน้าที่เป็น "Lead Developer" / "Conductor" ที่คุม development loop ทั้งหมด โดยไม่ลงไปเขียนโค้ดทุกบรรทัดเอง แต่วางแผน จ่ายงาน ตรวจสอบผลลัพธ์ และสร้าง PR: + +``` +[Developer / Telegram Command] + │ + ▼ +┌─────────────────────────────────────────┐ +│ Hermes Orchestrator (Flagship Cloud AI) │ +│ Claude / GPT-4o │ +│ Context: CONTEXT-ADR-031.md + AGENTS.md │ +│ Memory: SOUL.md (container-local) │ +│ Search: Dev Qdrant (ASUSTOR) │ +└──────────┬──────────────────────────────┘ + │ + ┌───────┴────────┐ + ▼ ▼ +[Cloud Sub-agents] [MCP Tool Invocations] +Claude Haiku / Windsurf / agy / Codex +GPT-4o-mini (existing tools, no new models) + │ ▼ + └────────┬─────── + ▼ + [Self-Correction Loop] + npm run lint / jest / tsc + → Error? Re-delegate to sub-agent + → Pass? Continue + │ + ▼ + [Git: hermes/* branch] + hermes-bot commits + Creates PR → Human Review & Approve +``` + +### Step 1: Requirement & Context Assembly + +Hermes โหลด context แบบ **selective** ตาม task type เพื่อลด token ที่ส่งไป Cloud AI: + +| Task Type | Context ที่โหลด | +|-----------|----------------| +| DevOps / CI / Git | `CONTEXT-ADR-031.md` + `AGENTS.md` | +| DMS feature coding | `CONTEXT-ADR-031.md` + `AGENTS.md` + `CONTEXT.md` | +| Schema / DB work | `CONTEXT-ADR-031.md` + `AGENTS.md` + `CONTEXT.md` + schema SQL (read-only) | +| Bug fix / refactor | `CONTEXT-ADR-031.md` + `AGENTS.md` + Dev Qdrant (code patterns) | + +**Sources:** +- `specs/06-Decision-Records/CONTEXT-ADR-031.md` — agent rules, project identity, tooling, infra paths +- `CONTEXT.md` (root) — domain terminology (Correspondence, RFA, Workflow Engine, AI concepts) — โหลดเฉพาะ DMS feature tasks +- `AGENTS.md` — TypeScript rules, forbidden patterns (no `any`, no `parseInt` on UUID), ADR references +- Dev Qdrant (ASUSTOR) — semantic code search หา reference patterns จาก codebase embeddings + +**ห้ามดึง** production runtime data (DB query results, document content, user data) เข้า cloud AI context + +### Step 2: Semantic Code Search (Dev Qdrant) + +Hermes ใช้ Qdrant instance แยก (บน ASUSTOR, ไม่ใช่ DMS Qdrant) ทำ semantic search หา reference patterns ใน codebase: + +```yaml +# docker-compose.hermes-qdrant.yml (ASUSTOR — แยกจาก DMS) +services: + hermes-qdrant: + image: qdrant/qdrant:latest + container_name: hermes-qdrant + volumes: + - hermes_qdrant_data:/qdrant/storage + ports: + - "6334:6333" # port แยกจาก DMS Qdrant (:6333) + deploy: + resources: + limits: + memory: 2G +``` + +Collection: `lcbp3_code_chunks` — indexed by `repoName` + `moduleName` (ไม่ใช่ `projectPublicId` ซึ่งเป็น DMS document isolation) + +### Step 3: Sub-agent Delegation + +Hermes แตกงานเป็น tasks แล้ว delegate ผ่าน 2 channels: + +**Channel A — Cloud Sub-agents (Code Generation):** +``` +Orchestrator (Claude/GPT-4o) + → "เขียน NestJS service สำหรับ X" + → Sub-agent (Claude Haiku / GPT-4o-mini) + → Returns code diff + → Orchestrator validates against AGENTS.md rules +``` + +**Channel B — MCP Tool Invocations (File Execution):** +``` +Orchestrator + → MCP hermes-tools: bash/git operations บน ASUSTOR + → MCP mariadb: schema lookup (read-only) + → MCP gitea: PR/issue management + → Triggers Windsurf/agy ถ้า complex scaffolding needed +``` + +**Data Classification Enforcement:** +| ส่งได้ | ห้ามส่ง | +|--------|---------| +| Code snippets, patterns | Production DB query results | +| ADR/spec content | Document content (title, body) | +| Stack traces, error output | User data, project names from DB | +| Config files, tsconfig | API keys, tokens, passwords | +| Schema structure (column names) | Storage paths ที่มี PII | + +### Step 4: Self-Correction Loop + +โค้ดที่ sub-agent ส่งกลับมาต้องผ่าน validation ก่อนใช้: + +```bash +# Hermes runs via MCP hermes-tools +npm run lint # ESLint — ต้องผ่านทุก rule +npx tsc --noEmit # TypeScript strict mode +npm test -- --passWithNoTests # Jest tests ที่เกี่ยวข้อง +``` + +ถ้าพบ error → Hermes วิเคราะห์ output → ส่งกลับให้ sub-agent แก้ไข (max 3 iterations) +ถ้า iteration > 3 → หยุดและแจ้ง developer ผ่าน Telegram + +### Step 5: Git Identity & PR Flow + +``` +hermes-bot commits → hermes/feat-{task-id} branch + ├─ git config user.name "Hermes Bot" + ├─ git config user.email "hermes-bot@np-dms.work" + ├─ commit message: "feat(hermes): {task description}\n\nOrchestrated by Hermes ADR-031 v2.0" + └─ push → Gitea → Create PR → assign to developer +``` + +**Git Identity Rules:** +- Service account: `hermes-bot` (Gitea, least privilege, write token เฉพาะ feature branches) +- Branch pattern: `hermes/feat-*`, `hermes/fix-*`, `hermes/refactor-*` +- ห้าม push ตรง `main`, `develop`, `release/*` ทุกกรณี +- PR ต้องผ่าน CI (lint + test) ก่อน merge +- Human ต้อง review และ approve ก่อน merge เสมอ — ห้าม auto-merge + +### SOUL.md — Hermes Working Journal + +`/volume1/docker/hermes/SOUL.md` เก็บ per-session working memory ของ Hermes: + +```markdown +## Session 2026-05-29T10:30 +Task: scaffold correspondence search feature +Context loaded: CONTEXT-ADR-031.md, backend/src/modules/correspondence/ +Sub-agents delegated: 2 code generation calls +Iterations: 1 (lint pass first try) +PR created: hermes/feat-correspondence-search → #142 +Status: DONE +``` + +- ไม่ commit ลง repo — อยู่ใน container volume เท่านั้น +- Hermes อ่าน SOUL.md ต้น session เพื่อ resume context +- Rotate ทุก 30 วัน หรือ manual clear + +--- + ## Implementation Details ### 1. Infrastructure Configuration @@ -801,6 +979,7 @@ ADR-031 ต้อง rollout แบบเป็น stage เพื่อลด - ADR-016: Security & Authentication - ADR-019: Hybrid Identifier Strategy (UUIDv7) - ADR-023/ADR-023A: Unified AI Architecture และ AI isolation boundary +- ADR-031 v2.0: Cloud AI exception สำหรับ Hermes dev orchestration layer (ดู Locked Decisions v2.0) --- @@ -812,3 +991,5 @@ ADR-031 ต้อง rollout แบบเป็น stage เพื่อลด | 2026-05-28 | 1.1.0 | Added sections 4–6 from CONTEXT-ADR-031-Added-2: Hermes Interface Modes, agy+Hermes MCP Integration, Deploy Prerequisites; fixed port conflict (hermes proxy :8766, not :8765) | | 2026-05-29 | 1.1.1 | Aligned with CONTEXT-ADR-031.md grill-with-docs: fixed monorepo structure (flat layout), corrected file paths, updated repo URL to git.np-dms.work, added AGENTS.md v1.9.7 reference | | 2026-05-29 | 1.1.2 | Linked root CONTEXT.md with specs/CONTEXT-ADR-031.md; fixed setup-context.sh paths; updated Windsurf/agy/Hermes symlink targets | +| 2026-05-29 | 2.0.0 | **v2.0 Rewrite** — grill-with-docs: Orchestration as primary concern; Added Autonomous Dev Loop architecture; Cloud AI exception (Data Classification Policy C); Separate Dev Qdrant on ASUSTOR; SOUL.md container-local journal; Sub-agent delegation (Cloud+MCP); Git identity hermes-bot + hermes/* branches + PR-only flow | +| 2026-05-29 | 2.0.1 | Step 1 context assembly: เพิ่ม `CONTEXT.md` (root domain terminology) เป็น selective context source สำหรับ DMS feature coding และ Schema/DB work tasks | diff --git a/specs/200-fullstacks/231-hermes-agent/checklists/requirements.md b/specs/200-fullstacks/231-hermes-agent/checklists/requirements.md new file mode 100644 index 00000000..92914812 --- /dev/null +++ b/specs/200-fullstacks/231-hermes-agent/checklists/requirements.md @@ -0,0 +1,38 @@ +# Specification Quality Checklist: Hermes Agent — Autonomous Dev Orchestrator & Telegram DevOps Bridge + +**Purpose**: Validate specification completeness and quality before proceeding to planning +**Created**: 2026-05-29 +**Feature**: [spec.md](../spec.md) + +## Content Quality + +- [x] No implementation details (languages, frameworks, APIs) +- [x] Focused on user value and business needs +- [x] Written for non-technical stakeholders +- [x] All mandatory sections completed + +## Requirement Completeness + +- [x] No [NEEDS CLARIFICATION] markers remain (ADR-031 v2.0 provides all decisions locked) +- [x] Requirements are testable and unambiguous +- [x] Success criteria are measurable (SC-001 through SC-010) +- [x] Success criteria are technology-agnostic (no implementation details) +- [x] All acceptance scenarios are defined (US1–US5, 5 scenarios each) +- [x] Edge cases are identified (10 edge cases) +- [x] Scope is clearly bounded (Out of Scope section present) +- [x] Dependencies and assumptions identified (Assumptions section present) + +## Feature Readiness + +- [x] All functional requirements have clear acceptance criteria (FR-001 through FR-020) +- [x] User scenarios cover primary flows (Orchestration, Telegram Read, Telegram Write, Proxy, Staged Rollout) +- [x] Feature meets measurable outcomes defined in Success Criteria +- [x] No implementation details leak into specification + +## Notes + +- Spec derived from ADR-031 v2.0 (2026-05-29) — Locked Decisions are authoritative +- Cloud AI exception scope clearly bounded to dev orchestration layer only +- Failure isolation (SC-004) is the most critical non-functional requirement +- Staged rollout (FR-015, SC-007) is prerequisite to any production deployment +- All items pass — spec is ready for clarification and planning phases diff --git a/specs/200-fullstacks/231-hermes-agent/contracts/hermes-api.yaml b/specs/200-fullstacks/231-hermes-agent/contracts/hermes-api.yaml new file mode 100644 index 00000000..d20dcb8b --- /dev/null +++ b/specs/200-fullstacks/231-hermes-agent/contracts/hermes-api.yaml @@ -0,0 +1,339 @@ +openapi: 3.0.3 +info: + title: Hermes Agent API + description: | + Hermes Agent — Autonomous Dev Orchestrator & Telegram DevOps Bridge + Feature: 231-hermes-agent | ADR-031 v2.0 + + IMPORTANT: + - All endpoints are LAN/VPN-only (never public internet) + - Telegram webhook endpoint is the only exception (via reverse proxy with TLS) + - Authentication: X-API-Key header for all non-webhook endpoints + - All responses include transactionId for traceability + version: 1.0.0 + contact: + name: NAP-DMS Architecture Team + +servers: + - url: http://{ASUSTOR_IP}:8080/api/v1 + description: Hermes Agent API (LAN/VPN only) + variables: + ASUSTOR_IP: + default: "192.168.10.X" + +security: + - ApiKeyAuth: [] + +components: + securitySchemes: + ApiKeyAuth: + type: apiKey + in: header + name: X-API-Key + description: HERMES_PROXY_API_KEY — stored in ASUSTOR secret store + + schemas: + TransactionId: + type: string + format: uuid + description: UUIDv7 transaction identifier (ADR-019) + example: "019505a1-7c3e-7000-8000-abc123def456" + + HermesStatus: + type: object + properties: + status: + type: string + enum: [HEALTHY, DEGRADED, DOWN] + version: + type: string + uptime: + type: number + queues: + type: object + properties: + notification: + type: object + properties: + waiting: { type: number } + active: { type: number } + failed: { type: number } + orchestration: + type: object + properties: + waiting: { type: number } + active: { type: number } + failed: { type: number } + soulMdLastEntry: + type: string + description: ISO datetime of last SOUL.md session entry + timestamp: + type: string + format: date-time + + OperationsLogEntry: + type: object + properties: + id: + $ref: '#/components/schemas/TransactionId' + operatorIdentity: + type: string + commandType: + type: string + enum: [TELEGRAM_INBOUND, TELEGRAM_OUTBOUND, ORCHESTRATION_TASK, GIT_WRITE, PROXY_REQUEST] + targetSystem: + type: string + commandSummary: + type: string + description: Redacted command description + status: + type: string + enum: [PENDING, IN_PROGRESS, COMPLETED, FAILED, REJECTED] + createdAt: + type: string + format: date-time + completedAt: + type: string + format: date-time + nullable: true + errorClassification: + type: string + nullable: true + + OrchestrationTaskRequest: + type: object + required: [description, taskType, telegramChatId] + properties: + description: + type: string + description: Coding task description (no production data) + taskType: + type: string + enum: [DEVOPS, DMS_FEATURE, SCHEMA_DB, BUG_FIX] + telegramChatId: + type: string + description: Chat ID for progress/result notifications + + OrchestrationTaskResponse: + type: object + properties: + taskId: + $ref: '#/components/schemas/TransactionId' + status: + type: string + enum: [QUEUED, CONTEXT_LOADING, SUB_AGENT_DELEGATED, SELF_CORRECTION, PR_CREATED, DONE, ESCALATED, FAILED] + prUrl: + type: string + nullable: true + description: Gitea PR URL (populated when status=PR_CREATED or DONE) + branchName: + type: string + nullable: true + + TelegramWebhookPayload: + type: object + properties: + message: + type: object + properties: + from: + type: object + properties: + id: { type: integer } + username: { type: string } + text: { type: string } + chat: + type: object + properties: + id: { type: integer } + + ErrorResponse: + type: object + properties: + error: + type: string + message: + type: string + transactionId: + $ref: '#/components/schemas/TransactionId' + +paths: + /health: + get: + summary: Hermes health check + description: Returns current health status of Hermes Agent and its subsystems + security: [] + operationId: getHealth + tags: [System] + responses: + '200': + description: Health status + content: + application/json: + schema: + $ref: '#/components/schemas/HermesStatus' + + /telegram/webhook: + post: + summary: Telegram webhook inbound handler + description: | + Receives Telegram Bot webhook updates. + MUST be behind reverse proxy with TLS. + MUST verify X-Telegram-Bot-Api-Secret-Token header. + DevOps commands only — no DMS document operations. + security: [] + operationId: handleTelegramWebhook + tags: [Telegram] + parameters: + - name: X-Telegram-Bot-Api-Secret-Token + in: header + required: true + schema: + type: string + description: Telegram webhook secret for request verification + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/TelegramWebhookPayload' + responses: + '200': + description: Webhook processed (command dispatched or acknowledged) + content: + application/json: + schema: + type: object + properties: + transactionId: + $ref: '#/components/schemas/TransactionId' + status: + type: string + enum: [DISPATCHED, REJECTED, ACKNOWLEDGED] + '401': + description: Invalid webhook secret token + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '429': + description: Rate limit exceeded + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /orchestration/tasks: + post: + summary: Submit autonomous coding task + description: | + Submit a coding task for Hermes to orchestrate via sub-agents. + NEVER include production document content, DB query results, or secrets in task description. + operationId: submitOrchestrationTask + tags: [Orchestration] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/OrchestrationTaskRequest' + responses: + '202': + description: Task queued successfully + content: + application/json: + schema: + $ref: '#/components/schemas/OrchestrationTaskResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /orchestration/tasks/{taskId}: + get: + summary: Get orchestration task status + operationId: getOrchestrationTask + tags: [Orchestration] + parameters: + - name: taskId + in: path + required: true + schema: + $ref: '#/components/schemas/TransactionId' + responses: + '200': + description: Task status + content: + application/json: + schema: + $ref: '#/components/schemas/OrchestrationTaskResponse' + '404': + description: Task not found + + /operations/logs: + get: + summary: Query Hermes operations log + description: Returns paginated DevOps operations log entries. Admin only. + operationId: getOperationsLog + tags: [Operations] + parameters: + - name: limit + in: query + schema: + type: integer + default: 50 + maximum: 200 + - name: offset + in: query + schema: + type: integer + default: 0 + - name: status + in: query + schema: + type: string + enum: [PENDING, IN_PROGRESS, COMPLETED, FAILED, REJECTED] + - name: commandType + in: query + schema: + type: string + responses: + '200': + description: Operations log entries + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/OperationsLogEntry' + total: + type: integer + offset: + type: integer + + /operations/logs/{transactionId}: + get: + summary: Get specific operation by transactionId + description: Used by Telegram /status command to track DevOps transactions + operationId: getOperationByTransactionId + tags: [Operations] + parameters: + - name: transactionId + in: path + required: true + schema: + $ref: '#/components/schemas/TransactionId' + responses: + '200': + description: Operation details + content: + application/json: + schema: + $ref: '#/components/schemas/OperationsLogEntry' + '404': + description: Transaction not found diff --git a/specs/200-fullstacks/231-hermes-agent/data-model.md b/specs/200-fullstacks/231-hermes-agent/data-model.md new file mode 100644 index 00000000..6507b17d --- /dev/null +++ b/specs/200-fullstacks/231-hermes-agent/data-model.md @@ -0,0 +1,149 @@ +// File: specs/200-fullstacks/231-hermes-agent/data-model.md +// Change Log: +// - 2026-05-29: Initial data model for Hermes Agent + +# Data Model: Hermes Agent + +**Feature**: 231-hermes-agent | **Date**: 2026-05-29 + +> **Important**: Hermes ไม่เพิ่มหรือแก้ DMS production schema ทุกกรณี (ADR-031, FR-017) +> Data model นี้ทั้งหมดอยู่ใน **Hermes-owned storage** (SQLite / container volume) ไม่ใช่ DMS MariaDB + +--- + +## 1. HermesOperationsLog (SQLite table: `hermes_operations_log`) + +บันทึก inbound/outbound DevOps operations ทุก transaction ของ Hermes + +| Field | Type | Constraints | Description | +|-------|------|-------------|-------------| +| `id` | TEXT (UUIDv7) | PRIMARY KEY | Transaction ID — ใช้ UUIDv7 ตาม ADR-019 | +| `operator_identity` | TEXT | NOT NULL | Telegram user ID หรือ CLI session identity | +| `command_type` | TEXT | NOT NULL | เช่น `TELEGRAM_INBOUND`, `TELEGRAM_OUTBOUND`, `ORCHESTRATION_TASK`, `GIT_WRITE` | +| `target_system` | TEXT | NOT NULL | เช่น `TELEGRAM`, `GITEA`, `CLOUD_AI`, `DEV_QDRANT` | +| `command_summary` | TEXT | NOT NULL | Redacted command description (ห้ามมี secret/token/sensitive path) | +| `status` | TEXT | NOT NULL | `PENDING` / `IN_PROGRESS` / `COMPLETED` / `FAILED` / `REJECTED` | +| `created_at` | DATETIME | NOT NULL DEFAULT CURRENT_TIMESTAMP | | +| `completed_at` | DATETIME | NULLABLE | | +| `error_classification` | TEXT | NULLABLE | เช่น `AUTH_FAILURE`, `RATE_LIMIT`, `FORBIDDEN_ACTION`, `EXTERNAL_API_ERROR` | +| `gitea_token_identity` | TEXT | NULLABLE | Token scope/identity สำหรับ Git write actions (ไม่ใช่ token value) | +| `target_repo` | TEXT | NULLABLE | สำหรับ Git write actions | +| `target_branch` | TEXT | NULLABLE | สำหรับ Git write actions | + +**Retention**: 90 วัน แล้ว archive/delete ตาม DevOps log policy +**Access**: Read เฉพาะ admin/operator ที่จำเป็น +**Redaction**: `command_summary` ต้องผ่าน secret scanner ก่อน insert + +--- + +## 2. HermesRateLimitState (Redis key pattern) + +| Key Pattern | Value | TTL | Description | +|-------------|-------|-----|-------------| +| `hermes:telegram:{telegramUserId}` | INT (request count) | 60s | Rate limit counter per user; expire ทุก 60 วินาที | + +--- + +## 3. HermesBullMQJobs (Redis via `hermes-notification-queue`) + +### Job: `telegram-devops-outbound` + +| Field | Type | Description | +|-------|------|-------------| +| `transactionId` | string (UUIDv7) | Reference ID for tracking | +| `chatId` | string | Telegram chat ID | +| `message` | string | Outbound message text (ไม่มี secret/PII) | +| `retryCount` | number | Current retry count (max 3) | + +--- + +## 4. HermesOrchestrationTask (Redis via `hermes-orchestration-queue`) + +### Job: `orchestration-task` + +| Field | Type | Description | +|-------|------|-------------| +| `taskId` | string (UUIDv7) | Task tracking ID | +| `taskType` | `DEVOPS` / `DMS_FEATURE` / `SCHEMA_DB` / `BUG_FIX` | กำหนด context loading strategy | +| `description` | string | Task description (no production data) | +| `contextSources` | string[] | Context files to load | +| `maxIterations` | number | Self-correction loop limit (default: 3) | +| `telegramChatId` | string | สำหรับ progress/result notification | +| `createdAt` | string (ISO 8601) | | + +--- + +## 5. SOUL.md (Container File: `/volume1/docker/hermes/SOUL.md`) + +ไม่ใช่ DB table แต่เป็น plain Markdown file working journal ใน container volume + +**Structure per session entry**: +```markdown +## Session {ISO_DATETIME} +Task: {task description} +TaskType: {DEVOPS|DMS_FEATURE|SCHEMA_DB|BUG_FIX} +Context loaded: {comma-separated context files} +Sub-agents delegated: {count} code generation calls +Iterations: {count} ({result of last iteration}) +PR created: {branch} → #{pr_number} +Status: {DONE|ESCALATED|FAILED} +``` + +**File management**: +- Read at session start for context resumption +- Append only (never overwrite previous entries) +- Rotate (clear and archive) every 30 days or manual clear +- Never synced to repo — container volume only + +--- + +## 6. DevQdrantCollection (`lcbp3_code_chunks` on ASUSTOR:6334) + +| Field | Type | Description | +|-------|------|-------------| +| `id` | string (UUID) | Chunk ID | +| `repoName` | string | Repository name (e.g., `lcbp3`) | +| `moduleName` | string | Module path (e.g., `backend/src/modules/correspondence`) | +| `filePath` | string | Relative file path | +| `chunkIndex` | number | Chunk position in file | +| `content` | string | Code chunk text | +| `vector` | float[] | nomic-embed-text embedding (768 dimensions) | + +> **ไม่ใช้ `projectPublicId` filter** (ซึ่งเป็น DMS document isolation key) — ใช้ `repoName` + `moduleName` แทน ตาม ADR-031 v2.0 + +--- + +## Entity Relationships + +``` +HermesAgent + ├── orchestrates → HermesOrchestrationTask (via hermes-orchestration-queue) + │ ├── delegates → HermesSubAgent (Cloud AI: Claude Haiku / GPT-4o-mini) + │ ├── searches → DevQdrantCollection (code patterns) + │ └── records → SOUL.md (session journal) + └── bridges → HermesTelegramGateway + ├── validates → HermesRateLimitState (Redis) + ├── records → HermesOperationsLog (SQLite) + └── dispatches → HermesBullMQJobs (hermes-notification-queue) + └── sends → Telegram API +``` + +--- + +## State Transitions: HermesOperationsLog.status + +``` +PENDING → IN_PROGRESS → COMPLETED + → FAILED + → REJECTED (allowlist/rate-limit/forbidden-action check) +``` + +## State Transitions: HermesOrchestrationTask + +``` +QUEUED → CONTEXT_LOADING → SUB_AGENT_DELEGATED + → SELF_CORRECTION (max 3 iterations) + → PR_CREATED → DONE + → ESCALATED (>3 iterations, notify Developer) + → FAILED +``` diff --git a/specs/200-fullstacks/231-hermes-agent/plan.md b/specs/200-fullstacks/231-hermes-agent/plan.md new file mode 100644 index 00000000..c17afe31 --- /dev/null +++ b/specs/200-fullstacks/231-hermes-agent/plan.md @@ -0,0 +1,258 @@ +// File: specs/200-fullstacks/231-hermes-agent/plan.md +// Change Log: +// - 2026-05-29: Initial implementation plan for Hermes Agent (ADR-031 v2.0) + +# Implementation Plan: Hermes Agent — Autonomous Dev Orchestrator & Telegram DevOps Bridge + +**Branch**: `231-hermes-agent` | **Date**: 2026-05-29 | **Spec**: [spec.md](./spec.md) +**Input**: Feature specification from `specs/200-fullstacks/231-hermes-agent/spec.md` + +--- + +## Summary + +Hermes Agent เป็น standalone NestJS service รันบน ASUSTOR Docker ทำหน้าที่ 2 บทบาทหลัก: +1. **Autonomous Dev Orchestrator** — รับ coding task, delegate ไป Cloud AI sub-agents, รัน self-correction loop, push PR via hermes-bot +2. **Telegram DevOps Bridge** — webhook handler สำหรับ DevOps commands พร้อม allowlist + rate-limit + operations log + +Hermes ไม่แตะ DMS production schema หรือ DMS production services ทุกกรณี (FR-017, ADR-031) + +--- + +## Technical Context + +**Language/Version**: TypeScript 5.x / Node.js 22 LTS +**Primary Dependencies**: +- NestJS 10 (framework) +- BullMQ 5 (queue: hermes-notification-queue + hermes-orchestration-queue) +- `@anthropic-ai/sdk` + `openai` npm packages (Cloud AI clients) +- `better-sqlite3` (hermes_operations_log SQLite) +- `ioredis` (rate limiting + BullMQ) +- `@qdrant/js-client-rest` (Dev Qdrant client) +- `node-telegram-bot-api` or `telegraf` (Telegram Bot SDK) +- `simple-git` (Git operations via hermes-bot) +- `uuid` v7 (UUIDv7 generation — ADR-019) + +**Storage**: +- SQLite (`/volume1/docker/hermes/data/ops.db`) — HermesOperationsLog +- Redis (hermes-redis container) — BullMQ queues + rate limiting +- Dev Qdrant (hermes-qdrant container, port 6334) — codebase embeddings +- File volume (`/volume1/docker/hermes/SOUL.md`) — SOUL.md working journal + +**Testing**: Jest (unit + integration); no E2E browser tests required + +**Target Platform**: ASUSTOR NAS (Linux ARM/x86) — Docker container, non-Swarm +**Performance Goals**: +- Telegram read-only commands: ≤ 10s response (SC-003) +- Coding task PR creation: ≤ 30 min typical (SC-001) +- Self-correction loop: ≤ 3 iterations (SC-002) + +**Constraints**: +- CPU ≤ 2.0 cores, RAM ≤ 4096MB (ASUSTOR resource limits) +- LAN/VPN-only exposure (except Telegram webhook via reverse proxy) +- ห้ามใช้ DMS production Redis, DMS Qdrant, DMS audit_logs +- Cloud AI: ห้ามส่ง production DB query results, document content, user data +- Port 8766 สำหรับ hermes proxy เท่านั้น (ห้ามใช้ 8765 ที่ PaddleOCR ใช้อยู่) + +**Scale/Scope**: Single DevOps team tool (2-5 concurrent users); not production DMS service + +--- + +## Constitution Check + +_GATE: Must pass before Phase 0 research. Re-check after Phase 1 design._ + +| Rule | Status | Notes | +|------|--------|-------| +| ADR-019: UUIDv7, no parseInt | ✅ PASS | transactionId ใช้ UUIDv7; ไม่มี parseInt บน UUID | +| ADR-016: Auth/RBAC | ✅ PASS | API Key auth + Telegram allowlist; webhook secret verification | +| ADR-007: Error handling | ✅ PASS | BullMQ retry 3x exponential backoff; ADR-007 error classification | +| ADR-008: BullMQ | ✅ PASS | `hermes-notification-queue` + `hermes-orchestration-queue` | +| ADR-023/023A: AI boundary | ✅ PASS | Cloud AI exception (ADR-031 v2.0 Locked) สำหรับ dev orchestration; ไม่ใช่ DMS document path | +| ADR-009: No migration | ✅ PASS | ไม่มี DMS schema delta; Hermes-owned SQLite ไม่ใช่ DMS DB | +| No `any` TypeScript | ✅ PASS | strict mode; all types explicit | +| No `console.log` | ✅ PASS | NestJS Logger ทั้งหมด | +| Forbidden patterns | ✅ PASS | ไม่มี parseInt(UUID), ไม่ expose INT PK, ไม่มี inline notification | +| File headers | ✅ PASS | ทุก TypeScript file เริ่มด้วย `// File: ...` | +| Data Classification | ✅ PASS | Code/Config/ADR ส่ง Cloud AI ได้; Production data ห้ามส่งออก | +| Failure isolation | ✅ PASS | Hermes ไม่ใช่ DMS dependency; DMS ทำงานได้โดยไม่มี Hermes | + +**No constitution violations. Proceed.** + +--- + +## Project Structure + +### Documentation (this feature) + +```text +specs/200-fullstacks/231-hermes-agent/ +├── spec.md # Feature specification +├── plan.md # This file +├── research.md # Phase 0 output +├── data-model.md # Phase 1 output +├── quickstart.md # Phase 1 output +├── contracts/ +│ └── hermes-api.yaml # OpenAPI contract +└── tasks.md # Phase 2 output +``` + +### Source Code (new Hermes stack — NOT part of backend/ or frontend/) + +```text +hermes/ +├── src/ +│ ├── orchestrator/ +│ │ ├── orchestrator.module.ts +│ │ ├── orchestrator.service.ts # Autonomous dev loop +│ │ ├── context-loader.service.ts # Selective context loading +│ │ ├── sub-agent.service.ts # Cloud AI delegation +│ │ ├── self-correction.service.ts # Lint/tsc/test loop (max 3 iter) +│ │ └── soul.service.ts # SOUL.md journal management +│ ├── integrations/ +│ │ ├── telegram/ +│ │ │ ├── telegram.module.ts +│ │ │ ├── hermes-telegram-gateway.ts # Inbound webhook handler +│ │ │ ├── hermes-telegram-dispatcher.ts # BullMQ outbound worker +│ │ │ ├── hermes-devops-command-router.ts # Command routing +│ │ │ └── telegram-rate-limiter.service.ts +│ │ ├── gitea/ +│ │ │ ├── gitea.module.ts +│ │ │ └── gitea.service.ts # Gitea API (read-only + write-with-confirmation) +│ │ └── mcp/ +│ │ ├── mcp.module.ts +│ │ └── mcp-server.service.ts # Exposes hermes MCP tools endpoint +│ ├── proxy/ +│ │ ├── proxy.module.ts +│ │ └── proxy.service.ts # hermes proxy (OpenAI-compatible, port 8766) +│ ├── operations/ +│ │ ├── operations.module.ts +│ │ ├── operations-log.service.ts # SQLite hermes_operations_log +│ │ └── operations.controller.ts # /operations/logs API +│ ├── qdrant/ +│ │ ├── qdrant.module.ts +│ │ └── dev-qdrant.service.ts # Dev Qdrant client (port 6334) +│ ├── health/ +│ │ ├── health.module.ts +│ │ └── health.controller.ts # /health endpoint +│ ├── common/ +│ │ ├── guards/ +│ │ │ ├── api-key.guard.ts # X-API-Key validation +│ │ │ └── telegram-allowlist.guard.ts # Allowlist check +│ │ ├── interceptors/ +│ │ │ └── transaction.interceptor.ts # Auto-inject transactionId +│ │ └── utils/ +│ │ ├── uuid.util.ts # UUIDv7 generation (ADR-019) +│ │ └── secret-redactor.util.ts # Redact secrets from log payload +│ ├── config/ +│ │ └── hermes.config.ts # All env vars typed +│ ├── app.module.ts +│ └── main.ts +├── test/ +│ ├── unit/ +│ │ ├── telegram-gateway.spec.ts +│ │ ├── command-router.spec.ts +│ │ ├── orchestrator.spec.ts +│ │ └── secret-redactor.spec.ts +│ └── integration/ +│ └── staged-rollout.spec.ts +├── specs/ # Docker compose + config +│ └── 04-Infrastructure-OPS/ +│ └── 04-00-docker-compose/ +│ └── ASUSTOR/ +│ └── hermes/ +│ ├── docker-compose.hermes.yml +│ ├── docker-compose.hermes-redis.yml +│ ├── docker-compose.hermes-qdrant.yml +│ ├── hermes.redis.conf +│ └── .env.example # เฉพาะ placeholder ห้าม commit secret จริง +├── .env.example +├── Dockerfile +├── nest-cli.json +├── package.json +└── tsconfig.json +``` + +**Structure Decision**: Standalone NestJS project (`hermes/`) แยกจาก `backend/` และ `frontend/` ทั้งหมด เพราะ Hermes ไม่ใช่ DMS production service และมี deploy target แยก (ASUSTOR NAS) รวมถึงมี Redis/SQLite/Qdrant ของตัวเอง + +--- + +## Implementation Phases + +### Phase 1: Setup & Infrastructure Foundation + +- สร้าง `hermes/` project structure (NestJS + TypeScript strict) +- Docker Compose files (hermes agent + hermes-redis + hermes-qdrant) +- Config module (typed env vars + secrets validation) +- HealthController + basic API Key guard + +### Phase 2: Core Foundational Services + +- OperationsLogService (SQLite + create/read/update) +- SecretRedactorUtil (scan + redact sensitive patterns) +- UuidUtil (UUIDv7 generation) +- TransactionInterceptor (auto-inject transactionId per request) + +### Phase 3: US1 — Autonomous Dev Orchestrator (P1) + +- ContextLoaderService (selective context loading by task type) +- SubAgentService (Claude Haiku/GPT-4o-mini delegation) +- SelfCorrectionService (lint/tsc/test loop, max 3 iterations) +- OrchestratorService (main development loop coordination) +- OrchestratorController (POST /orchestration/tasks, GET /orchestration/tasks/:id) +- SoulService (SOUL.md read/append/rotate) +- DevQdrantService (hermes-qdrant client, code chunk search) + +### Phase 4: US2 — Telegram Read-only Commands (P2) + +- TelegramRateLimiterService (Redis-based, 10 req/min/user) +- HermesTelegramGateway (webhook verification, allowlist check, rate limit) +- HermesDevOpsCommandRouter (route read-only commands: /status, /ci_status, /repo_summary) +- GiteaService (read-only: repos, issues, PRs, CI status) +- HermesTelegramDispatcher (BullMQ worker, hermes-notification-queue, retry 3x backoff) + +### Phase 5: US3 — Telegram Write-with-Confirmation (P3) + +- Write action confirmation flow (HermesDevOpsCommandRouter extension) +- GiteaService write methods (create branch/issue/PR/trigger CI — write token scope) +- Forbidden action blocklist enforcement +- hermes-bot Git identity integration (simple-git + hermes-bot service account) +- Branch pattern validation (hermes/{feat,fix,refactor}-*) +- Operations log write action recording (token identity, target repo/branch) + +### Phase 6: US4 — Developer AI Proxy (P4) + +- ProxyService (OpenAI-compatible API, port 8766) +- Secret payload detection middleware (reject if production data detected) +- MCP server endpoint (/mcp) for agy + Windsurf integration +- HermesMemoryMcpTool (expose DMS context for agy recall) +- HermesToolsMcpTool (expose bash/git execution capability) + +### Phase 7: US5 — Staged Rollout Tooling (P5) + +- Stage acceptance gate checklist scripts (PowerShell/bash) +- Monitoring alerts (DevOps warning vs. production outage separation) +- Failure isolation verification tests +- Rollback documentation finalization + +### Phase 8: Polish & Cross-Cutting + +- Structured logging with NestJS Logger (no console.log) +- JSDoc for all public classes (Thai comments per AGENTS.md) +- Secret scan validation in CI pipeline +- Docker resource limit verification script +- SOUL.md rotation cron job + +--- + +## Key Technical Decisions + +| Decision | Choice | Rationale | +|----------|--------|-----------| +| Hermes stack | Standalone NestJS | แยกจาก DMS backend; same tooling; ทีมรู้จักดี | +| Cloud AI | Anthropic SDK + OpenAI SDK | ADR-031 Cloud AI Exception; model flexibility | +| Operations log | SQLite (better-sqlite3) | Simple, no external service, queryable | +| Rate limiting | Redis-based (ioredis) | Stateless container-safe; shares hermes-redis | +| Git operations | simple-git | Lightweight; TypeScript-native | +| Dev Qdrant | Port 6334 (ASUSTOR) | แยกจาก DMS Qdrant port 6333 (QNAP) | +| Telegram SDK | telegraf or node-telegram-bot-api | ต้อง verify ตอน implementation (ADR-031 note) | diff --git a/specs/200-fullstacks/231-hermes-agent/quickstart.md b/specs/200-fullstacks/231-hermes-agent/quickstart.md new file mode 100644 index 00000000..872a773a --- /dev/null +++ b/specs/200-fullstacks/231-hermes-agent/quickstart.md @@ -0,0 +1,200 @@ +// File: specs/200-fullstacks/231-hermes-agent/quickstart.md +// Change Log: +// - 2026-05-29: Initial quickstart / verification guide for Hermes Agent staged rollout + +# Quickstart: Hermes Agent Staged Rollout + +**Feature**: 231-hermes-agent | **Date**: 2026-05-29 + +--- + +## Prerequisites + +- [ ] ASUSTOR NAS with Docker support (ADM + Docker add-on) +- [ ] ASUSTOR IP confirmed (default: `192.168.10.X` — run `df -h` to confirm share paths) +- [ ] Gitea `hermes-bot` service account created with read-only token (write token created separately for Stage 4) +- [ ] Telegram bot created via @BotFather → bot token available +- [ ] Cloud AI API keys (Claude/Anthropic + OpenAI) stored in ASUSTOR secret store +- [ ] inter-VLAN routing confirmed: ASUSTOR → QNAP (MariaDB :3306, Gitea :3000) — required for Stage 2+ + +--- + +## Stage 0 — Documentation Only (Architecture Team approval required) + +**Goal**: ADR boundary reviewed, locked decisions captured, no deploy files applied + +Verification gate: +- [ ] ADR-031 v2.0 reviewed and all Locked Decisions confirmed +- [ ] No SQL delta files created +- [ ] No docker-compose files applied to ASUSTOR + +✅ **Gate passed** → advance to Stage 1 + +--- + +## Stage 1 — Hermes Container LAN-only (DevOps/Admin approval) + +```bash +# บน ASUSTOR shell (SSH ก่อน) +ssh admin@ + +# ขึ้น stack (hermes-redis + hermes-agent) +cd /volume1/docker/hermes +docker compose -f docker-compose.hermes.yml up -d + +# Verify resource limits enforce จริง +docker inspect hermes_agent_lcbp3 | grep -E '"Memory"|"NanoCpus"' +docker stats hermes_agent_lcbp3 --no-stream +``` + +Verification gate: +- [ ] Container running: `docker ps | grep hermes_agent_lcbp3` +- [ ] LAN/VPN-only: Hermes `:8080`, `:8766`, `/mcp` ไม่ accessible จาก public internet +- [ ] Redis แยกจาก DMS: `docker network inspect lcbp3 | grep hermes-redis` (ต้องอยู่ใน network แยก หรือ isolate ด้วย ACL) +- [ ] CPU ≤ 2.0 cores, RAM ≤ 4096MB enforce จาก `docker inspect` + +✅ **Gate passed** → advance to Stage 2 + +--- + +## Stage 2 — Read-only Diagnostics (DBA/Security + DevOps approval) + +```bash +# ทดสอบ MariaDB read-only connection (ไม่ควร write ได้) +docker exec hermes_agent_lcbp3 node -e " + const mysql = require('mysql2'); + const conn = mysql.createConnection({ + host: process.env.HERMES_MARIADB_READONLY_HOST, + user: process.env.HERMES_MARIADB_READONLY_USER, + password: process.env.HERMES_MARIADB_READONLY_PASSWORD, + database: process.env.HERMES_MARIADB_READONLY_DATABASE + }); + conn.query('SHOW TABLES', (err, rows) => { console.log(rows); conn.end(); }); +" + +# ทดสอบ write ต้องล้มเหลว +# (INSERT statement should return error with read-only user) +``` + +Verification gate: +- [ ] Read-only DB grant verified: SELECT pass, INSERT/UPDATE/DELETE fail +- [ ] Masked/redacted fields verified: no document content, user passwords, storage paths in query results +- [ ] Gitea read-only token verified: GET repos/issues/PRs pass, POST/PATCH/DELETE fail +- [ ] No direct storage mount: `docker inspect hermes_agent_lcbp3 | grep Mounts` — no permanent storage paths + +✅ **Gate passed** → advance to Stage 3 + +--- + +## Stage 3 — Telegram Read-only DevOps (DevOps/Security approval) + +```bash +# ทดสอบ webhook secret verification +curl -X POST http://localhost:8080/api/v1/telegram/webhook \ + -H "X-Telegram-Bot-Api-Secret-Token: WRONG_SECRET" \ + -H "Content-Type: application/json" \ + -d '{"message":{"from":{"id":123},"text":"/status","chat":{"id":123}}}' \ + # ต้องได้ 401 Unauthorized + +# ทดสอบ allowlist rejection +curl -X POST http://localhost:8080/api/v1/telegram/webhook \ + -H "X-Telegram-Bot-Api-Secret-Token: ${HERMES_TELEGRAM_WEBHOOK_SECRET}" \ + -H "Content-Type: application/json" \ + -d '{"message":{"from":{"id":999999999},"text":"/status","chat":{"id":999999999}}}' \ + # ต้องได้ rejected (user ไม่อยู่ใน allowlist) + +# ทดสอบ /ci_status จาก authorized user +# (ส่งผ่าน Telegram จริง หรือ simulate ด้วย authorized user ID) +``` + +Verification gate: +- [ ] Telegram allowlist verified: non-allowlisted user rejected 100% +- [ ] Webhook secret verified: wrong secret → 401 +- [ ] Rate limit verified: >10 requests/minute from same user → rejected +- [ ] `hermes_operations_log` captures inbound/outbound transactions with transactionId +- [ ] `/ci_status`, `/repo_summary`, `/status`, `/audit_summary` return correct data + +✅ **Gate passed** → advance to Stage 4 + +--- + +## Stage 4 — Write-with-Confirmation DevOps (Architecture + Security + Repo Owner approval) + +```bash +# ทดสอบ forbidden action blocker +# ส่งคำสั่ง "push to main" ผ่าน Telegram +# ต้องได้ rejection message โดยไม่มีการดำเนินการใดๆ + +# ทดสอบ confirmation flow +# ส่ง "เตรียม branch proposal สำหรับ fix/test-issue" +# → Hermes แสดง summary + ขอ confirmation +# → ยืนยัน +# → ตรวจสอบ Gitea: branch hermes/fix-test-issue ถูกสร้าง +# → ตรวจสอบ hermes_operations_log: มี entry พร้อม transactionId + +# ทดสอบ hermes-bot token scope +git -c http.extraHeader="Authorization: token ${HERMES_BOT_WRITE_TOKEN}" \ + push gitea-origin main +# ต้องได้ 403 Forbidden (branch protection + token scope block) +``` + +Verification gate: +- [ ] Explicit confirmation flow verified: write action requires confirmation before executing +- [ ] Forbidden action blocklist verified: push main/develop, production deploy, schema migration, direct DB write → rejected +- [ ] Branch protection + Gitea token scope verified: hermes-bot cannot push to main/develop +- [ ] `hermes_operations_log` records token identity, target repo/branch for all write actions + +✅ **Gate passed** → advance to Stage 5 + +--- + +## Stage 5 — Developer AI Proxy (Architecture + Security approval) + +```powershell +# บน Windows PowerShell — ทดสอบ hermes proxy +$env:OPENAI_BASE_URL = "http://:8766/v1" +$env:OPENAI_API_KEY = "" + +# ทดสอบ basic coding request (no production data) +codex "scaffold NestJS module for health check" +# ต้องได้ response พร้อม DMS context + +# ทดสอบ secret payload rejection +# ส่ง payload ที่มี "password: secret123" หรือ storage path +# ต้องได้ rejected + redact ใน log +``` + +Verification gate: +- [ ] Proxy LAN/VPN-only: port 8766 ไม่ accessible จาก public internet +- [ ] No secrets/document payload: test payload ที่มี token/password/storage path ถูก reject และ redact ใน log +- [ ] Proxy ไม่ wired เข้า DMS AI runtime หรือ DMS document intelligence path +- [ ] Wrong API key → 401 + +✅ **All stages complete** → Hermes fully operational + +--- + +## Rollback Procedures + +| Stage | Rollback | +|-------|---------| +| Stage 1 | `docker compose -f docker-compose.hermes.yml down`; verify DMS production unaffected | +| Stage 2 | Revoke DB/Gitea read-only credentials via Gitea admin; disable MCP servers; confirm no storage mount | +| Stage 3 | `curl -X DELETE "https://api.telegram.org/bot{TOKEN}/deleteWebhook"`; revoke bot token if needed | +| Stage 4 | Revoke Gitea write token via Gitea admin; disable write commands in Hermes config | +| Stage 5 | Unset `OPENAI_BASE_URL` on all clients; stop hermes proxy; revoke proxy API key | + +--- + +## Health Check Endpoints + +```bash +# Hermes health (Stage 1+) +curl http://:8080/api/v1/health + +# hermes proxy health (Stage 5) +curl http://:8766/v1/models + +# Dev Qdrant health (if deployed) +curl http://:6334/healthz +``` diff --git a/specs/200-fullstacks/231-hermes-agent/research.md b/specs/200-fullstacks/231-hermes-agent/research.md new file mode 100644 index 00000000..dbb4314b --- /dev/null +++ b/specs/200-fullstacks/231-hermes-agent/research.md @@ -0,0 +1,103 @@ +// File: specs/200-fullstacks/231-hermes-agent/research.md +// Change Log: +// - 2026-05-29: Phase 0 research — all unknowns resolved from ADR-031 v2.0 + +# Research: Hermes Agent + +**Feature**: 231-hermes-agent | **Date**: 2026-05-29 + +--- + +## R-001: Hermes Stack / Runtime + +**Decision**: NestJS (TypeScript) บน Node.js 22 — เช่นเดียวกับ DMS backend เพื่อ reuse tooling, tsconfig, ESLint, Jest +**Rationale**: ทีมรู้จัก NestJS ดีแล้ว; BullMQ ใช้ร่วม npm package ได้; TypeScript strict mode enforce ตาม AGENTS.md +**Alternatives considered**: +- Python FastAPI — reuse Ollama/ML code แต่ทีมหลักเป็น TypeScript/NestJS +- Go — performance ดีกว่าแต่ไม่มี BullMQ native และทีมไม่คุ้นเคย + +--- + +## R-002: Cloud AI Provider & Model Selection + +**Decision**: Claude Sonnet (orchestration) / Claude Haiku (sub-agents) เป็น primary; GPT-4o / GPT-4o-mini เป็น fallback +**Rationale**: ADR-031 v2.0 Locked Decision — Cloud AI Exception สำหรับ dev orchestration layer โดยเฉพาะ; ใช้ model ขนาดเล็กกว่าสำหรับ sub-agents เพื่อลด cost +**Alternatives considered**: +- Ollama only (Gemma4/gemma2) — ไม่ได้รับ exception จาก ADR-023A สำหรับ dev orchestration; context window จำกัด; ไม่เหมาะกับ orchestration workload ขนาดใหญ่ +- GPT-4o only — ราคาสูงกว่าถ้าใช้ทุก request + +--- + +## R-003: Dev Qdrant Isolation + +**Decision**: Separate Qdrant instance บน ASUSTOR port 6334 (container: `hermes-qdrant`); collection `lcbp3_code_chunks` indexed by `repoName` + `moduleName` +**Rationale**: ADR-031 v2.0 Locked — ห้ามใช้ Qdrant instance เดียวกับ DMS document RAG (port 6333 บน QNAP ADR-023A); separation ป้องกัน cross-contamination +**Alternatives considered**: +- Shared DMS Qdrant — ปฏิเสธ: ADR-031 v2.0 explicit lock; DMS Qdrant ใช้ `projectPublicId` filter สำหรับ document isolation ซึ่งไม่เหมาะกับ code chunks + +--- + +## R-004: BullMQ Queue Architecture + +**Decision**: `hermes-notification-queue` เป็น queue หลักสำหรับ outbound Telegram; `hermes-orchestration-queue` สำหรับ async dev tasks; ใช้ Redis instance แยก (`hermes-redis` container) +**Rationale**: ADR-031 Redis Isolation Policy — ห้ามใช้ DMS production Redis (อาจ evict DMS BullMQ/lock/cache keys ถ้าใช้ `allkeys-lru`); queue names ขึ้นต้น `hermes-` +**Alternatives considered**: +- Shared DMS Redis — ปฏิเสธ: ADR-031 explicit policy; ถ้าจำเป็นต้องแชร์ต้องมี keyPrefix แยก, DB index แยก, ACL user แยก + +--- + +## R-005: hermes_operations_log Storage + +**Decision**: SQLite database ภายใน Hermes container volume (`/volume1/docker/hermes/data/ops.db`) — เริ่มต้นง่าย, ไม่ต้อง external service, เพียงพอสำหรับ DevOps audit trail +**Rationale**: ADR-031 — ต้องอยู่ใน Hermes-owned storage เท่านั้น; ไม่ใช่ DMS `audit_logs`; single-operator DevOps tool ไม่ต้องการ high-concurrency DB +**Alternatives considered**: +- Postgres volume ภายใน Hermes stack — option ถ้า ops volume เติบโต แต่ SQLite เพียงพอสำหรับ Stage 1-4 +- Structured log files + ship to log collector — viable แต่ SQLite ง่ายกว่าสำหรับ query ด้วย `/status ` + +--- + +## R-006: SOUL.md เป็น Session Memory + +**Decision**: Plain Markdown file ภายใน container volume `/volume1/docker/hermes/SOUL.md`; Hermes อ่านต้น session และ append per-session entry; rotate ทุก 30 วัน +**Rationale**: ADR-031 v2.0 Locked — ไม่ sync ลง repo ทุกกรณี; container-local เท่านั้น; ไม่ใช้ Obsidian หรือ external knowledge base +**Alternatives considered**: +- Redis-based session memory — volatile และ restart ทำให้ข้อมูลหาย +- Gitea wiki/issue — sync ลง repo ซึ่งขัดกับ ADR-031 locked decision + +--- + +## R-007: Telegram Webhook Security + +**Decision**: Verify `X-Telegram-Bot-Api-Secret-Token` header ทุก request; enforce allowlist (`HERMES_TELEGRAM_ALLOWED_USER_IDS`); Redis-based rate limit 10 req/min/user; expose webhook เฉพาะ LAN หรือผ่าน reverse proxy ที่มี TLS + Telegram secret verification +**Rationale**: ป้องกัน spoofed requests; ป้องกัน unauthorized DevOps access; ป้องกัน spam/DoS ตาม ADR-031 security requirements +**Alternatives considered**: +- IP allowlist only — ไม่เพียงพอถ้า Telegram ใช้ dynamic IPs +- No rate limiting — risk ของ spam/DoS จาก compromised Telegram account + +--- + +## R-008: Git Identity & PR Flow + +**Decision**: `hermes-bot` Gitea service account (least privilege); write token scope: create branch/issue/PR/trigger CI เท่านั้น (ไม่ใช่ admin token); branch pattern `hermes/{feat,fix,refactor}-*`; ห้าม push main/develop; ต้องผ่าน CI ก่อน merge; human approve required +**Rationale**: ADR-031 v2.0 Locked — ทุก change ผ่าน PR ที่ human review เท่านั้น; ป้องกัน accidental direct push to protected branches +**Alternatives considered**: +- Hermes push ตรง develop — ปฏิเสธ: ADR-031 explicit lock; repo gate compliance +- Admin token — ปฏิเสธ: ADR-031 explicit prohibition; least privilege principle + +--- + +## R-009: Resource Limits บน ASUSTOR (non-Swarm Docker) + +**Decision**: กำหนด fallback resource limits ทั้งใน `deploy.resources` (Swarm syntax) และ top-level `cpus`/`mem_limit` (non-Swarm syntax) เพื่อให้ enforce บน ASUSTOR ADM Docker; verify ด้วย `docker inspect` และ `docker stats` +**Rationale**: ADR-031 note — `deploy.resources` อาจถูก ignore ใน non-Swarm Docker บน ASUSTOR; ต้อง verify จาก runtime ไม่ใช่ compose file เท่านั้น +**Alternatives considered**: +- Swarm mode บน ASUSTOR — ไม่จำเป็นสำหรับ single-node DevOps tool; เพิ่ม complexity โดยไม่จำเป็น + +--- + +## R-010: Context Loading Strategy (Selective Context) + +**Decision**: Hermes โหลด context แบบ selective ตาม task type เพื่อลด token ที่ส่งไป Cloud AI: DevOps task → CONTEXT-ADR-031+AGENTS.md; DMS feature coding → +CONTEXT.md; Schema/DB → +schema SQL (read-only); Bug fix → +Dev Qdrant search results +**Rationale**: ADR-031 v2.0 — ลด cost ของ Cloud AI; ป้องกันส่ง production DB query results เข้า Cloud AI context (Data Classification Policy) +**Alternatives considered**: +- โหลด CONTEXT.md ทุก request — เพิ่ม token cost; ไม่จำเป็นสำหรับ pure DevOps queries diff --git a/specs/200-fullstacks/231-hermes-agent/spec.md b/specs/200-fullstacks/231-hermes-agent/spec.md new file mode 100644 index 00000000..787d6ac9 --- /dev/null +++ b/specs/200-fullstacks/231-hermes-agent/spec.md @@ -0,0 +1,220 @@ +// File: specs/200-fullstacks/231-hermes-agent/spec.md +// Change Log: +// - 2026-05-29: Initial specification derived from ADR-031 v2.0 + +# Feature Specification: Hermes Agent — Autonomous Dev Orchestrator & Telegram DevOps Bridge + +**Feature Branch**: `231-hermes-agent` +**Created**: 2026-05-29 +**Status**: Draft +**Category**: 200-fullstacks +**Input**: ADR-031 v2.0 (specs/06-Decision-Records/ADR-031-hermes-agent-telegram-devops-bridge.md) + +## Overview + +Hermes Agent เป็น Autonomous Development Loop Orchestrator และ Telegram DevOps Bridge ที่รันบน ASUSTOR NAS แบบ always-on โดยทำหน้าที่ 2 roles หลัก: + +1. **Autonomous Dev Orchestrator** (primary) — รับ coding task จาก Developer ผ่าน Telegram/CLI, โหลด context, วางแผน, จ่ายงานให้ sub-agents (Cloud AI), รัน self-correction loop (lint/tsc/test), และสร้าง PR ใน Gitea สำหรับ human review +2. **Telegram DevOps Bridge** (subsystem) — รับ DevOps commands ผ่าน Telegram bot สำหรับ read-only queries (CI status, repo summary) และ write-with-confirmation actions (create branch/issue/PR/trigger CI) + +Hermes **ไม่ใช่** production DMS service, ไม่ใช่ DMS AI inference boundary, และไม่แตะ production DMS schema ทุกกรณี + +--- + +## Clarifications + +### Session 2026-05-29 + +Ambiguity scan ran across all 10 taxonomy categories. All categories scored **Clear** — ADR-031 v2.0 Locked Decisions (grill-with-docs 2026-05-29) pre-resolve every design choice that would otherwise require clarification: + +- Q: Cloud AI scope (which AI services allowed for Hermes?) → A: Claude/GPT-4o for orchestration + Haiku/GPT-4o-mini for sub-agents; DMS document processing remains ADR-023A Ollama-only (Cloud AI Exception, ADR-031 v2.0 Locked) +- Q: Dev Qdrant isolation (shared with DMS Qdrant?) → A: Separate instance on ASUSTOR port 6334, collection `lcbp3_code_chunks` indexed by `repoName`+`moduleName` — never shared with DMS Qdrant port 6333 (ADR-031 v2.0 Locked) +- Q: SOUL.md persistence (repo vs. container?) → A: Container volume only (`/volume1/docker/hermes/SOUL.md`), never synced to repo, rotated every 30 days (ADR-031 v2.0 Locked) +- Q: hermes proxy port (conflict with PaddleOCR?) → A: Port 8766 for hermes proxy; port 8765 is reserved for PaddleOCR sidecar per ADR-023A (ADR-031 v1.1.1 fix) +- Q: hermes_operations_log location (DMS audit_logs?) → A: Hermes-owned store only (SQLite/Postgres volume or structured log), never writes to DMS `audit_logs` (ADR-031 v2.0 Locked) + +**Coverage Summary**: Functional Scope ✅ | Domain & Data Model ✅ | Interaction & UX ✅ | Non-Functional ✅ | Integration ✅ | Edge Cases ✅ | Constraints ✅ | Terminology ✅ | Completion Signals ✅ + +No questions asked. Proceeding directly to `/speckit-plan`. + +--- + +## User Scenarios & Testing _(mandatory)_ + +### User Story 1 — Autonomous Coding Task Orchestration (Priority: P1) + +Developer ส่ง coding task เช่น "scaffold NestJS module for X" ผ่าน Telegram หรือ CLI แล้ว Hermes โหลด project context, วางแผน, แตกงาน, delegate ไปยัง sub-agents, รัน lint/tsc/test self-correction loop, และสร้าง PR ใน Gitea branch `hermes/feat-*` สำหรับ Developer review/approve + +**Why this priority**: เป็น core value ของ Hermes — ช่วยให้ Developer สั่งงาน coding จากที่ไหนก็ได้โดยไม่ต้องเปิด IDE และได้รับ PR ที่พร้อม review ภายในเวลาอันสั้น + +**Independent Test**: Developer ส่ง Telegram message "scaffold NestJS module for repository diagnostics" → Hermes ส่งกลับ PR link ใน Gitea branch `hermes/feat-*` ที่ผ่าน lint/tsc + +**Acceptance Scenarios**: + +1. **Given** Developer อยู่ใน Telegram allowlist, **When** ส่ง coding task, **Then** Hermes โหลด context ที่เหมาะกับ task type (selective loading), วางแผน, delegate sub-agent, รัน lint/tsc/test +2. **Given** sub-agent ส่งโค้ดที่ lint ล้มเหลว, **When** Hermes รัน self-correction, **Then** ส่งกลับไปให้ sub-agent แก้ไขสูงสุด 3 iterations ก่อนหยุดและแจ้ง Developer +3. **Given** โค้ดผ่าน lint/tsc/test ทุก check, **When** Hermes push, **Then** commit ลง `hermes/feat-{task-id}` branch โดย `hermes-bot` service account แล้วสร้าง PR พร้อม assign to Developer +4. **Given** Hermes ต้องการ code patterns จาก codebase, **When** ค้นหา, **Then** ใช้ Dev Qdrant (ASUSTOR) ที่แยกจาก DMS Qdrant เท่านั้น +5. **Given** task เสร็จสิ้น, **When** Hermes บันทึก session, **Then** เขียนลง SOUL.md ภายใน container เท่านั้น (ไม่ sync ลง repo) + +--- + +### User Story 2 — Telegram Read-only DevOps Commands (Priority: P2) + +DevOps engineer/Developer ส่ง read-only commands ผ่าน Telegram เช่น `/ci_status`, `/repo_summary`, `/status`, `/audit_summary` และรับผลลัพธ์กลับมาทันทีโดยไม่มีผลข้างเคียงต่อระบบ + +**Why this priority**: ช่วยให้ทีมตรวจสอบสถานะ CI/repo จากมือถือโดยไม่ต้องเปิด Gitea UI — ลด context switching และเพิ่ม DevOps visibility + +**Independent Test**: ส่ง `/ci_status` ใน Telegram → รับสถานะ CI ล่าสุดจาก Gitea กลับมาภายใน 10 วินาที พร้อม reference transactionId + +**Acceptance Scenarios**: + +1. **Given** Telegram user อยู่ใน allowlist, **When** ส่ง `/ci_status`, **Then** Hermes ดึงสถานะ CI ล่าสุดจาก Gitea แล้วตอบกลับพร้อม `[Ref: {transactionId}]` +2. **Given** Telegram user ไม่อยู่ใน allowlist, **When** ส่ง command ใดก็ตาม, **Then** Hermes ปฏิเสธ request และไม่ดำเนินการใดๆ +3. **Given** Telegram webhook request เข้ามา, **When** ตรวจสอบ `X-Telegram-Bot-Api-Secret-Token` ไม่ตรง, **Then** reject request ทันที +4. **Given** Telegram user ส่ง request เกิน rate limit (>10 ต่อนาที), **When** Hermes ตรวจสอบ Redis counter, **Then** ปฏิเสธ request และแจ้ง user +5. **Given** command ทุกประเภท, **When** รับ/ส่งข้อมูล, **Then** บันทึก inbound/outbound ใน `hermes_operations_log` พร้อม transactionId ทันที + +--- + +### User Story 3 — Telegram Write-with-Confirmation DevOps Actions (Priority: P3) + +DevOps engineer ส่ง action commands ผ่าน Telegram เช่น "เตรียม branch/PR proposal สำหรับ fix/ci-pnpm-cache" — Hermes ขอ explicit confirmation ก่อนดำเนินการ และบันทึก transactionId ทุกขั้นตอน + +**Why this priority**: ช่วยให้ทีมสั่งงาน DevOps actions จากมือถือได้อย่างปลอดภัยด้วย human confirmation gate ป้องกัน accidental changes + +**Independent Test**: ส่ง "สร้าง branch proposal สำหรับ fix/ci-cache" → Hermes แสดง summary + ขอ confirmation → ยืนยัน → Hermes สร้าง branch ใน Gitea + บันทึก hermes_operations_log + แจ้ง PR created + +**Acceptance Scenarios**: + +1. **Given** Developer ส่ง write action command, **When** Hermes รับ, **Then** แสดง action summary และขอ explicit confirmation ก่อนดำเนินการ +2. **Given** Developer ยืนยัน action, **When** Hermes ดำเนิน, **Then** ใช้ Gitea write token ที่แยกและมี scope แคบ (ไม่ใช่ admin token) สำหรับ create branch/issue/PR/trigger CI เท่านั้น +3. **Given** action สำเร็จหรือล้มเหลว, **When** สิ้นสุด, **Then** บันทึก `transactionId`, token identity, target repo/branch, และผลลัพธ์ใน `hermes_operations_log` +4. **Given** command ที่เป็น forbidden action (push main/develop, production deploy, schema migration, destructive ops, direct DB write), **When** รับ command ดังกล่าว, **Then** Hermes ปฏิเสธทุกกรณี ไม่ว่าจะผ่าน confirmation หรือไม่ +5. **Given** Developer ยืนยัน create branch, **When** สร้างสำเร็จ, **Then** branch pattern ต้องเป็น `hermes/feat-*`, `hermes/fix-*`, หรือ `hermes/refactor-*` เท่านั้น + +--- + +### User Story 4 — Developer AI Proxy (hermes proxy) (Priority: P4) + +Developer บน laptop ใช้ Codex CLI หรือ agy โดยชี้ `OPENAI_BASE_URL` ไปยัง `hermes proxy` (port 8766 บน ASUSTOR) เพื่อใช้ Hermes เป็น Developer AI Proxy สำหรับ coding/devops assistance เท่านั้น + +**Why this priority**: ช่วยให้ CLI tools บน laptop (Codex, agy via MCP) เชื่อมกับ Hermes context บน ASUSTOR ได้ โดยใช้ infrastructure ที่มีอยู่แล้ว + +**Independent Test**: บน Windows PowerShell ตั้ง `$env:OPENAI_BASE_URL = "http://:8766/v1"` → รัน `codex "scaffold NestJS module"` → ได้รับ response ที่มี DMS context + +**Acceptance Scenarios**: + +1. **Given** Developer ตั้ง OPENAI_BASE_URL ชี้ไป hermes proxy, **When** ส่ง coding/devops request, **Then** hermes proxy รับและ forward ไป Cloud AI พร้อม DMS context +2. **Given** proxy รับ payload ที่คล้าย production document content, secret, token, password, หรือ storage path, **When** ตรวจพบ, **Then** ถือเป็น security incident, redact log ทันที, และ reject request +3. **Given** hermes proxy ใช้ port 8766, **When** deploy, **Then** ต้องไม่ conflict กับ PaddleOCR sidecar (port 8765) ตาม ADR-023A +4. **Given** hermes proxy รับ request ใดก็ตาม, **When** ประมวลผล, **Then** expose เฉพาะ LAN/VPN เท่านั้น ห้ามเปิด public internet +5. **Given** Developer ใช้ agy กับ Hermes MCP, **When** เรียก `mcp_hermes-memory_recall`, **Then** Hermes ส่ง DMS context กลับมาโดยไม่มี production document payload หรือ DB query results + +--- + +### User Story 5 — Staged Rollout & Health Monitoring (Priority: P5) + +Admin deploy Hermes ผ่าน staged rollout (Stage 0-5) โดยแต่ละ stage มี acceptance gate ที่ต้องผ่านก่อนขึ้น stage ถัดไป และมี monitoring ที่แยก Hermes health ออกจาก DMS production health + +**Why this priority**: รับประกันว่า Hermes ถูก deploy อย่างปลอดภัยแบบ incremental และการล่มของ Hermes ไม่ส่งผลกระทบต่อ DMS production ทุกกรณี + +**Independent Test**: ปิด Hermes container แล้วตรวจสอบว่า DMS frontend/backend/Workflow Engine/AI pipeline ยังทำงานปกติ 100% + +**Acceptance Scenarios**: + +1. **Given** Admin ต้องการ deploy Hermes, **When** เริ่ม Stage 1, **Then** Hermes container รันแบบ LAN/VPN-only ด้วย Redis/log store แยกจาก DMS production Redis +2. **Given** Stage acceptance gate ยังไม่ผ่าน, **When** Admin พยายาม deploy Stage ถัดไป, **Then** ระบบหรือ process บล็อกไว้จน gate ผ่าน +3. **Given** Hermes container ล่ม, **When** ตรวจสอบ DMS production, **Then** DMS frontend/backend/Workflow Engine/AI pipeline ทำงานตามปกติ 100% (failure isolation) +4. **Given** Hermes down หรือ Telegram Bridge down, **When** Monitoring แจ้งเตือน, **Then** alert เป็น DevOps warning ไม่ใช่ production DMS outage alert +5. **Given** resource limits กำหนดไว้ใน Docker Compose (CPU 2.0, RAM 4GB limit / 2GB reservation), **When** deploy บน ASUSTOR, **Then** verified ด้วย `docker inspect` และ `docker stats` ว่า runtime enforce จริง + +--- + +### Edge Cases + +- Hermes sub-agent ล้มเหลวหลัง 3 iterations — หยุดงานและแจ้ง Developer ผ่าน Telegram พร้อม error detail; ไม่สร้าง PR ที่มีโค้ดผิด +- SOUL.md ขนาดใหญ่เกินไปหลัง 30 วัน — Rotate/clear ตาม schedule; Hermes resume context จาก SOUL.md ต้น session +- hermes-bot ถูก revoke token — ทุก write action ล้มเหลว gracefully พร้อมแจ้ง Developer; read-only commands ยังใช้ token แยกได้ +- ASUSTOR restart — Hermes Redis (AOF persistence) recover queue jobs; SOUL.md อยู่ใน container volume ปลอดภัย +- Telegram API ล่ม — BullMQ retry 3 ครั้งด้วย exponential backoff ก่อน dead-letter +- Developer ส่ง secret/token จริงผ่าน Telegram command — Hermes redact ออกจาก log ทันที ไม่ forward ไป Cloud AI +- Dev Qdrant (ASUSTOR) ล่ม — Hermes fallback ไป context-only mode (ไม่มี semantic search) โดย DMS Qdrant ไม่ถูกแตะ +- hermes proxy รับ production document payload — Security incident: redact, reject, alert +- inter-VLAN routing ยังไม่เปิด (ASUSTOR → QNAP) — Stage 2+ ไม่สามารถ deploy ได้; Hermes แสดง error ชัดเจนว่า network path blocked +- hermes-bot พยายาม push ตรง main/develop — Git server-side branch protection block ทุกกรณี + +--- + +## Requirements _(mandatory)_ + +### Functional Requirements + +- **FR-001**: Hermes MUST run as an isolated Docker container on ASUSTOR NAS (CPU ≤ 2 cores, RAM ≤ 4GB) within LAN/VPN boundary เท่านั้น +- **FR-002**: Hermes MUST implement Autonomous Dev Orchestration loop: load selective context → plan → delegate to Cloud sub-agents → self-correction (lint/tsc/test, max 3 iterations) → commit via hermes-bot → create PR +- **FR-003**: Hermes MUST use Cloud AI (Claude/GPT-4o for orchestration, Claude Haiku/GPT-4o-mini for sub-agents) เฉพาะ dev orchestration layer — ไม่ใช่ DMS document processing +- **FR-004**: Data Classification Policy MUST be enforced: Code/Config/ADR/Stack trace ส่ง Cloud AI ได้ — Production runtime data (document content, user info, project business data จาก DB) ห้ามส่งออกทุกกรณี +- **FR-005**: Hermes MUST maintain a separate Dev Qdrant instance on ASUSTOR (collection: `lcbp3_code_chunks`, indexed by `repoName`+`moduleName`) ห้ามใช้ DMS Qdrant instance +- **FR-006**: Hermes MUST maintain SOUL.md working journal ภายใน container volume เท่านั้น (ไม่ sync ลง repo, rotate ทุก 30 วัน) +- **FR-007**: Hermes MUST load selective context ตาม task type: DevOps → CONTEXT-ADR-031+AGENTS.md; DMS feature → +CONTEXT.md; Schema/DB → +schema SQL; Bug fix → +Dev Qdrant +- **FR-008**: Hermes MUST enforce Git Identity rules: ใช้ `hermes-bot` service account, push เฉพาะ `hermes/*` branches, ห้าม push main/develop/release ทุกกรณี, ทุก change ต้องผ่าน PR ที่ human approve +- **FR-009**: Hermes Telegram MUST verify `X-Telegram-Bot-Api-Secret-Token` ทุก webhook request +- **FR-010**: Hermes Telegram MUST enforce allowlist (`HERMES_TELEGRAM_ALLOWED_USER_IDS`) สำหรับ DevOps commands ทุกระดับ +- **FR-011**: Hermes Telegram MUST apply Redis-based rate limiting (default: 10 requests/minute/user) +- **FR-012**: Hermes MUST queue all outbound Telegram notifications ผ่าน BullMQ queue `hermes-notification-queue` พร้อม retry 3 ครั้ง exponential backoff +- **FR-013**: Hermes MUST record every inbound/outbound operation ใน `hermes_operations_log` ด้วย transactionId (UUIDv7), operator identity, command type, target system, status, timestamps — ห้ามเขียนลง DMS `audit_logs` +- **FR-014**: Hermes operations log MUST redact command payload ที่อาจมี secret, token, sensitive file path, หรือ production document content +- **FR-015**: Hermes MUST implement 6-stage gated rollout (Stage 0–5) โดยห้ามข้ามไปยัง stage ที่สูงกว่าโดยยังไม่ผ่าน acceptance gate +- **FR-016**: Hermes failure MUST NOT affect DMS production: frontend, backend, Workflow Engine, AI pipeline, and user-facing app ต้องทำงานตามปกติเมื่อ Hermes ล่ม +- **FR-017**: Hermes MUST NOT add or modify any DMS production schema (no SQL delta, no migration, no `user_telegram_mapping` creation) +- **FR-018**: `hermes proxy` MUST expose OpenAI-compatible API (port 8766) สำหรับ Developer AI Proxy เท่านั้น (ห้ามใช้ port 8765 ที่ PaddleOCR sidecar ใช้อยู่) +- **FR-019**: Hermes MUST use separate Redis instance/volume จาก DMS production Redis; queue names ต้องขึ้นต้นด้วย `hermes-` +- **FR-020**: All secrets (Telegram bot token, webhook secret, Gitea token, DB credential, proxy API key) MUST be stored ภายนอก repo ใน ASUSTOR secret store พร้อม rotation plan + +### Key Entities + +- **HermesAgent**: Docker container orchestrator รันบน ASUSTOR ควบคุม Development Loop ทั้งหมด +- **HermesTelegramGateway**: รับ inbound Telegram webhook, ตรวจสอบ allowlist + webhook secret + rate limit, forward ไปยัง DevOps Command Router +- **HermesTelegramDispatcher**: BullMQ Worker ดึงงานจาก `hermes-notification-queue` เพื่อส่ง outbound Telegram message พร้อม transactionId reference +- **HermesDevOpsCommandRouter**: Route และ execute DevOps commands ตาม permission tier (read-only / write-with-confirmation / forbidden) +- **HermesOperationsLog**: Hermes-owned log store (SQLite หรือ structured log) บันทึก inbound/outbound DevOps operations พร้อม transactionId และ redacted payload +- **HermesSubAgent**: Cloud AI delegate (Claude Haiku / GPT-4o-mini) รับ code generation task จาก Orchestrator และส่ง code diff กลับ +- **SOUL.md**: Container-local working journal บันทึก per-session task context, delegated sub-agents, iterations, PR results +- **DevQdrant**: Qdrant instance บน ASUSTOR (port 6334) สำหรับ codebase embeddings เท่านั้น — collection `lcbp3_code_chunks` +- **HermesProxy**: OpenAI-compatible API proxy (port 8766) สำหรับ Codex CLI / agy MCP integration + +--- + +## Success Criteria _(mandatory)_ + +### Measurable Outcomes + +- **SC-001**: Developer สามารถรับ PR link จาก Hermes ภายใน 30 นาที สำหรับ typical feature scaffolding task (เมื่อ sub-agent ผ่าน lint/tsc ใน iteration แรก) +- **SC-002**: Self-correction loop แก้ lint/tsc/test failures ได้ภายใน 3 iterations ≥ 80% ของกรณีก่อนที่จะ escalate ไป Developer +- **SC-003**: Telegram read-only commands (`/ci_status`, `/repo_summary`, `/status`) ตอบกลับภายใน 10 วินาที ≥ 95% ของ requests +- **SC-004**: DMS production availability (frontend/backend/Workflow Engine) ไม่ได้รับผลกระทบเมื่อ Hermes container ล่ม (0% downtime attributable to Hermes) +- **SC-005**: 100% ของ Telegram requests จาก non-allowlisted users ถูก reject โดยไม่มีการดำเนินการใดๆ +- **SC-006**: 100% ของ DevOps write actions มี transactionId บันทึกใน `hermes_operations_log` ก่อนดำเนิน action +- **SC-007**: All 6 rollout stage acceptance gates ผ่าน verification ก่อน advance ไปยัง stage ถัดไป ไม่มีกรณี skip gate +- **SC-008**: ไม่พบ production document content, DB query results, secrets, หรือ storage paths ใน Cloud AI request payloads (verified จาก proxy request logs) +- **SC-009**: hermes-bot ไม่มี push access ไปยัง `main`, `develop`, หรือ `release/*` branches (verified โดย Gitea branch protection + token scope test) +- **SC-010**: `hermes_operations_log` redacts ทุก payload ที่ตรวจพบ secret/token/sensitive-path ก่อนบันทึก (verified โดย secret scan ของ log output) + +--- + +## Assumptions + +- ADR-031 v2.0 Locked Decisions ทั้งหมดใช้บังคับและไม่อยู่ในขอบเขตที่เปลี่ยนได้โดย spec นี้ +- Cloud AI exception (Claude/GPT-4o) สำหรับ Hermes dev orchestration layer ได้รับการอนุมัติแล้วใน ADR-031 v2.0 +- ASUSTOR NAS มี Docker รองรับ resource limits (cpus/mem_limit); verified ด้วย `docker inspect`/`docker stats` ตาม ADR note +- Gitea `hermes-bot` service account และ Telegram bot ต้องถูกสร้างแยกต่างหากก่อน Stage 1/3 +- inter-VLAN routing จาก ASUSTOR ไปยัง QNAP (MariaDB :3306, Gitea :3000) ต้องเปิดก่อน Stage 2 +- DMS production Qdrant (ADR-023A, port 6333) และ Dev Qdrant (Hermes, port 6334) เป็นคนละ instance + +## Out of Scope + +- Production DMS Telegram commands (query/mutate documents, Workflow Engine actions) — ต้องเป็น ADR/spec แยก +- `user_telegram_mapping` table สำหรับ DMS — ห้ามสร้างใน ADR-031 rollout +- DMS production schema changes ทุกกรณี +- Direct integration ระหว่าง Hermes และ DMS BullMQ/Redis/Qdrant/Ollama +- Hermes เป็น DMS AI runtime path (ใช้ DMS Ollama pipeline ตาม ADR-023/023A) diff --git a/specs/200-fullstacks/231-hermes-agent/tasks.md b/specs/200-fullstacks/231-hermes-agent/tasks.md new file mode 100644 index 00000000..5e1cc24c --- /dev/null +++ b/specs/200-fullstacks/231-hermes-agent/tasks.md @@ -0,0 +1,274 @@ +// File: specs/200-fullstacks/231-hermes-agent/tasks.md +// Change Log: +// - 2026-05-29: Initial task list for Hermes Agent (ADR-031 v2.0) + +# Tasks: Hermes Agent — Autonomous Dev Orchestrator & Telegram DevOps Bridge + +**Input**: Design documents from `specs/200-fullstacks/231-hermes-agent/` +**Prerequisites**: plan.md ✅ | spec.md ✅ | research.md ✅ | data-model.md ✅ | contracts/ ✅ | quickstart.md ✅ + +**Organization**: Tasks grouped by user story (US1–US5) for independent implementation and testing +**Staged Rollout**: US5 tasks map to Stage gates — do not skip stages + +--- + +## Format: `[ID] [P?] [Story] Description` + +- **[P]**: Can run in parallel (different files, no dependencies on incomplete tasks) +- **[Story]**: Which user story this task belongs to (US1–US5) +- Paths below are relative to `hermes/` monorepo package root (standalone NestJS project) + +--- + +## Phase 1: Setup (Hermes Project Initialization) + +**Purpose**: Bootstrap `hermes/` project structure and Docker infrastructure + +- [ ] T001 Create `hermes/` NestJS project: `package.json`, `tsconfig.json`, `nest-cli.json`, `.env.example` with TypeScript strict mode and all dependencies from plan.md +- [ ] T002 [P] Create `hermes/Dockerfile` — multi-stage Node.js 22 Alpine build for ASUSTOR deployment +- [ ] T003 [P] Create `specs/04-Infrastructure-OPS/04-00-docker-compose/ASUSTOR/hermes/docker-compose.hermes.yml` — hermes-agent container with CPU 2.0 / mem 4096M limits (fallback + deploy.resources per ADR-031 note) +- [ ] T004 [P] Create `specs/04-Infrastructure-OPS/04-00-docker-compose/ASUSTOR/hermes/docker-compose.hermes-redis.yml` — hermes-redis container with `hermes.redis.conf` (AOF persistence, maxmemory 512mb, isolated from DMS Redis) +- [ ] T005 [P] Create `specs/04-Infrastructure-OPS/04-00-docker-compose/ASUSTOR/hermes/docker-compose.hermes-qdrant.yml` — hermes-qdrant container on port 6334 (separated from DMS Qdrant port 6333) +- [ ] T006 Create `hermes/src/config/hermes.config.ts` — typed env vars (all secrets via env; no hardcoded values; ห้าม commit secret จริง) +- [ ] T007 Create `hermes/src/app.module.ts` — root module wiring all feature modules + +**Checkpoint**: `docker compose -f docker-compose.hermes.yml up -d` รัน hermes container ได้; `docker inspect` แสดง resource limits ถูกต้อง + +--- + +## Phase 2: Foundational (Core Infrastructure — Blocks All User Stories) + +**Purpose**: Cross-cutting concerns ทุก user story ต้องอาศัย + +**⚠️ CRITICAL**: No user story work can begin until this phase is complete + +- [ ] T008 Create `hermes/src/common/utils/uuid.util.ts` — UUIDv7 generation ตาม ADR-019 (`generateTransactionId()` returns UUIDv7 string) +- [ ] T009 [P] Create `hermes/src/common/utils/secret-redactor.util.ts` — scan command payload สำหรับ secret/token/password/storage-path patterns แล้ว redact ก่อน log (FR-014) +- [ ] T010 [P] Create `hermes/src/common/guards/api-key.guard.ts` — validate `X-API-Key` header ต่อทุก non-webhook endpoint; return 401 ถ้าไม่ถูกต้อง +- [ ] T011 [P] Create `hermes/src/common/interceptors/transaction.interceptor.ts` — auto-generate UUIDv7 transactionId ต่อทุก request และ attach ลง response headers + request context +- [ ] T012 Create `hermes/src/operations/operations-log.service.ts` — SQLite CRUD สำหรับ `hermes_operations_log` (create entry, update status, find by transactionId); ใช้ `better-sqlite3` +- [ ] T013 [P] Create `hermes/src/operations/operations.module.ts` และ `hermes/src/operations/operations.controller.ts` — GET `/operations/logs` + GET `/operations/logs/:transactionId` (ตาม contracts/hermes-api.yaml) +- [ ] T014 Create `hermes/src/health/health.controller.ts` — GET `/health` returns `HermesStatus` with queue counts; no auth required (security: []) +- [ ] T015 [P] Write unit tests `hermes/test/unit/secret-redactor.spec.ts` — test cases: token patterns, password= patterns, storage paths, ไม่ redact code snippets / ADR content + +- [ ] T054 [P] Write unit tests `hermes/test/unit/operations-log.spec.ts` — test cases: create entry, update status, findByTransactionId, redaction enforcement, retention boundary + +**Checkpoint**: API Key guard ทำงาน; Operations log บันทึก/query ได้; Secret redactor pass tests; Health endpoint ตอบกลับ + +--- + +## Phase 3: User Story 1 — Autonomous Dev Orchestrator (Priority: P1) 🎯 MVP + +**Goal**: Developer ส่ง coding task → Hermes orchestrate sub-agents → self-correction loop → PR created + +**Independent Test**: POST `/orchestration/tasks` ด้วย `{description: "scaffold NestJS health module", taskType: "DMS_FEATURE", telegramChatId: "test"}` → GET `/orchestration/tasks/:id` แสดง `status: PR_CREATED` + `prUrl` populated ภายใน expected timeout + +### Implementation for User Story 1 + +- [ ] T016 [P] [US1] Create `hermes/src/qdrant/dev-qdrant.service.ts` — Qdrant JS client สำหรับ Dev Qdrant (ASUSTOR port 6334); collection `lcbp3_code_chunks`; search by `repoName`+`moduleName` (ไม่ใช้ `projectPublicId` filter) +- [ ] T017 [P] [US1] Create `hermes/src/orchestrator/context-loader.service.ts` — selective context loading ตาม task type (DEVOPS/DMS_FEATURE/SCHEMA_DB/BUG_FIX); โหลด CONTEXT-ADR-031.md + AGENTS.md เสมอ; เพิ่ม CONTEXT.md สำหรับ DMS_FEATURE; ห้าม load production DB query results +- [ ] T018 [P] [US1] Create `hermes/src/orchestrator/sub-agent.service.ts` — Cloud AI delegation: Claude Haiku/GPT-4o-mini สำหรับ code generation; Data Classification enforcement (ห้าม production data ใน prompt payload) +- [ ] T019 [US1] Create `hermes/src/orchestrator/self-correction.service.ts` — รัน lint/tsc/test ผ่าน MCP hermes-tools; วนซ้ำสูงสุด 3 iterations; ถ้า > 3 → escalate notification ผ่าน BullMQ (depends on T018) +- [ ] T020 [US1] Create `hermes/src/orchestrator/soul.service.ts` — read/append/rotate SOUL.md ที่ `/volume1/docker/hermes/SOUL.md`; rotate ทุก 30 วัน; ไม่ sync ลง repo +- [ ] T021 [US1] Create `hermes/src/orchestrator/orchestrator.service.ts` — main dev loop: context load → plan → sub-agent delegate → self-correction → commit via hermes-bot → create PR → record SOUL.md + operations log (depends on T016–T020) +- [ ] T022 [US1] Create `hermes/src/orchestrator/orchestrator.controller.ts` — POST `/orchestration/tasks`, GET `/orchestration/tasks/:id` ตาม OpenAPI contract; ใช้ hermes-orchestration-queue (BullMQ) +- [ ] T023 [US1] Create `hermes/src/orchestrator/orchestrator.module.ts` — wire all orchestrator providers +- [ ] T024 [P] [US1] Write unit tests `hermes/test/unit/orchestrator.spec.ts` — test context loader (correct files per task type), sub-agent delegation call, self-correction loop iteration count enforcement + +**Checkpoint**: POST orchestration task ได้รับ taskId; GET task แสดง status transitions; SOUL.md มี session entry; Dev Qdrant query ไม่แตะ DMS Qdrant + +--- + +## Phase 4: User Story 2 — Telegram Read-only DevOps Commands (Priority: P2) + +**Goal**: DevOps engineer ส่ง `/ci_status`, `/repo_summary`, `/status` ผ่าน Telegram และรับผลลัพธ์กลับ ≤ 10 วินาที + +**Independent Test**: ส่ง webhook payload `/ci_status` พร้อม valid secret token + allowlisted user → ตรวจสอบ operations log entry + Telegram outbound message queued + BullMQ job created + +### Implementation for User Story 2 + +- [ ] T025 [P] [US2] Create `hermes/src/integrations/gitea/gitea.service.ts` — read-only Gitea API methods: getLatestCI(), getRepoSummary(), getIssues(), getPRs(); ใช้ read-only token; ห้าม write operations ใน phase นี้ +- [ ] T026 [P] [US2] Create `hermes/src/integrations/telegram/telegram-rate-limiter.service.ts` — Redis-based rate limit: `hermes:telegram:{userId}` key, incr + expire 60s, threshold 10 req/min (FR-011) +- [ ] T027 [US2] Create `hermes/src/integrations/telegram/hermes-telegram-gateway.ts` — inbound webhook handler: verify `X-Telegram-Bot-Api-Secret-Token` → check allowlist → check rate limit → record inbound to operations log → dispatch to command router (depends on T025, T026) +- [ ] T028 [US2] Create `hermes/src/integrations/telegram/hermes-devops-command-router.ts` — route read-only commands (/status, /ci_status, /repo_summary, /audit_summary, /help); queue outbound response via BullMQ hermes-notification-queue (depends on T027) +- [ ] T029 [US2] Create `hermes/src/integrations/telegram/hermes-telegram-dispatcher.ts` — BullMQ Worker @Processor('hermes-notification-queue'): @Process('telegram-devops-outbound') — send via Telegram Bot API; record outbound to operations log; retry 3x exponential backoff (ADR-007, FR-012) +- [ ] T030 [US2] Create `hermes/src/integrations/telegram/telegram.module.ts` — wire all telegram providers + BullMQ queue registration +- [ ] T031 [P] [US2] Write unit tests `hermes/test/unit/telegram-gateway.spec.ts` — webhook secret verification, allowlist rejection, rate limit enforcement, operations log inbound record (depends on T027) +- [ ] T032 [P] [US2] Write unit tests `hermes/test/unit/command-router.spec.ts` — command routing (/ prefix parsing), forbidden command detection, outbound job queuing (depends on T028) + +**Checkpoint**: POST `/telegram/webhook` ด้วย wrong secret → 401; non-allowlisted user → rejected; valid read-only command → operations log entry + BullMQ job created + +--- + +## Phase 5: User Story 3 — Telegram Write-with-Confirmation (Priority: P3) + +**Goal**: DevOps engineer สั่ง write action → Hermes ขอ confirmation → ดำเนิน action → บันทึก operations log + +**Independent Test**: ส่ง "สร้าง branch proposal สำหรับ fix/test" → รับ confirmation prompt → ยืนยัน → Gitea branch `hermes/fix-test` ถูกสร้าง + operations log มี git write entry + forbidden action blocklist ทำงาน + +### Implementation for User Story 3 + +- [ ] T033 [P] [US3] Extend `hermes/src/integrations/gitea/gitea.service.ts` — เพิ่ม write methods: createBranch(), createIssue(), createPR(), triggerCI() ใช้ write token แยก (least privilege, ไม่ใช่ admin token); branch pattern validation (hermes/*) +- [ ] T034 [US3] Extend `hermes/src/integrations/telegram/hermes-devops-command-router.ts` — เพิ่ม write-with-confirmation flow: (1) parse write intent → (2) show action summary → (3) wait for explicit confirmation → (4) execute → (5) record operations log; forbidden action blocklist (push main/develop, production deploy, schema migration, direct DB write, storage delete) → reject immediately +- [ ] T035 [US3] Integrate `hermes-bot` Git identity ใน `hermes/src/orchestrator/orchestrator.service.ts` — `simple-git` config: user.name "Hermes Bot", user.email "hermes-bot@np-dms.work"; push เฉพาะ `hermes/*` branches; commit message format: `"feat(hermes): {task description}\n\nOrchestrated by Hermes ADR-031 v2.0"` +- [ ] T036 [P] [US3] Write operations log record ใน `hermes/src/operations/operations-log.service.ts` สำหรับ Git write actions — บันทึก `gitea_token_identity`, `target_repo`, `target_branch`, status ก่อนและหลัง action (depends on T033) + +**Checkpoint**: Write command ต้องการ confirmation; hermes-bot branch creation ใช้ pattern `hermes/fix-*`; forbidden actions ถูก blocked; operations log มี token identity record + +--- + +## Phase 6: User Story 4 — Developer AI Proxy (Priority: P4) + +**Goal**: Developer ใช้ Codex CLI / agy โดยชี้ `OPENAI_BASE_URL` → `hermes proxy` port 8766 รับ request สำหรับ coding/devops assistance เท่านั้น + +**Independent Test**: ตั้ง OPENAI_BASE_URL → hermes proxy → ส่ง coding request → รับ response พร้อม DMS context; ส่ง payload ที่มี password/token → ถูก reject + redact log + +### Implementation for User Story 4 + +- [ ] T037 [US4] Create `hermes/src/proxy/proxy.service.ts` — OpenAI-compatible API (port 8766); forward coding/devops requests ไป Cloud AI พร้อม DMS context injection; validate payload ไม่มี production data (ใช้ secret-redactor.util.ts); ห้าม forward ถ้าตรวจพบ production data +- [ ] T038 [US4] Create `hermes/src/proxy/proxy.module.ts` + controller — bind ที่ port 8766 แยกจาก main API port 8080; API Key auth; LAN/VPN-only note ใน config +- [ ] T039 [P] [US4] Create `hermes/src/integrations/mcp/mcp-server.service.ts` — expose `/mcp` endpoint สำหรับ agy + Windsurf integration; implement `hermes-memory` tool (recall DMS context); implement `hermes-tools` tool (bash/git execution on ASUSTOR) +- [ ] T040 [P] [US4] Create `hermes/src/integrations/mcp/mcp.module.ts` — wire MCP server providers +- [ ] T041 [P] [US4] Verify port isolation: proxy port 8766 ≠ PaddleOCR sidecar port 8765 (ADR-023A) — add port validation assertion ใน `hermes/src/config/hermes.config.ts` ที่ startup + +**Checkpoint**: `curl http://:8766/v1/models` returns models list; payload ที่มี "password:" ถูก reject; `/mcp` endpoint accessible; port 8765 ไม่ถูก bind โดย Hermes + +--- + +## Phase 7: User Story 5 — Staged Rollout & Health Monitoring (Priority: P5) + +**Goal**: Admin deploy Hermes ผ่าน 6-stage gated rollout พร้อม monitoring ที่แยก Hermes health จาก DMS + +**Independent Test**: ปิด hermes container → ตรวจสอบ DMS frontend/backend/workflow-engine response 200; Hermes down alert ≠ DMS production outage alert + +### Implementation for User Story 5 + +- [ ] T042 [P] [US5] Create `specs/04-Infrastructure-OPS/04-00-docker-compose/ASUSTOR/hermes/stage-gates/` — checklist files per stage (stage-0.md → stage-5.md) ตาม quickstart.md acceptance gates; แต่ละ gate มี verification commands และ pass/fail criteria +- [ ] T043 [US5] Extend `hermes/src/health/health.controller.ts` (extends T014) — เพิ่ม subsystem health: Redis status, Dev Qdrant status, Operations log status, hermes proxy status, BullMQ queue depths; return `HermesStatus` object ครบถ้วนตาม contracts/hermes-api.yaml +- [ ] T044 [P] [US5] Create monitoring alert configuration: Hermes down / Telegram Bridge down / MCP unavailable / hermes proxy down = DevOps warning (ไม่ใช่ DMS production outage); repeated auth failure / rate limit spike = security alert; document ใน `specs/04-Infrastructure-OPS/04-00-docker-compose/ASUSTOR/hermes/monitoring-alerts.md` +- [ ] T045 [P] [US5] Write failure isolation verification script `specs/04-Infrastructure-OPS/04-00-docker-compose/ASUSTOR/hermes/verify-isolation.sh` — `docker stop hermes_agent_lcbp3` แล้ว check DMS endpoints return 200; ใช้ใน Stage 1 acceptance gate +- [ ] T046 [P] [US5] Create SOUL.md rotation cron job: เพิ่ม cron schedule ใน `hermes/src/orchestrator/soul.service.ts` สำหรับ rotate ทุก 30 วัน (archive + clear SOUL.md) + +**Checkpoint**: Health endpoint แสดง subsystem status ครบถ้วน; Stage gate checklists ครบ 6 stages; Failure isolation test pass (DMS ยังทำงานเมื่อ Hermes ล่ม) + +--- + +## Phase 8: Polish & Cross-Cutting Concerns + +**Purpose**: Quality, security, và documentation finalization + +- [ ] T047 [P] Verify all TypeScript files have `// File:` header and `// Change Log:` comments ตาม AGENTS.md; JSDoc สำหรับ public classes (Thai comments) +- [ ] T048 [P] Replace all `console.log` ด้วย NestJS Logger (`this.logger.log/warn/error`) ทั่วทั้ง `hermes/src/` +- [ ] T049 Secret scan validation: ตรวจสอบว่าไม่มี secret จริงใน `hermes/` source tree, compose files, `.env.example`, หรือ spec files; เพิ่ม pre-commit hook (mandatory — FR-020) +- [ ] T050 [P] Resource limit verification: สร้าง `specs/04-Infrastructure-OPS/04-00-docker-compose/ASUSTOR/hermes/verify-resources.sh` — `docker inspect` + `docker stats` แล้วเปรียบเทียบกับ expected limits (CPU 2.0 / RAM 4096MB) +- [ ] T051 [P] Data Classification audit: review hermes proxy + sub-agent service code ว่าไม่มี production DB query results หรือ document content ใน Cloud AI request payloads +- [ ] T052 Run `quickstart.md` staged verification (Stage 0 → Stage 5) และ update checklist results; document final rollout status +- [ ] T053 [P] Create `specs/04-Infrastructure-OPS/04-00-docker-compose/ASUSTOR/hermes/secret-rotation.md` — Secret rotation runbook สำหรับ `HERMES_PROXY_API_KEY`, Telegram bot token, Gitea read-only + write tokens, read-only DB credential; include rotation schedule, revocation steps, และ operator offboarding procedure (FR-020) + +--- + +## Dependencies & Execution Order + +### Phase Dependencies + +- **Phase 1 (Setup)**: ไม่มี dependency — เริ่มทันที +- **Phase 2 (Foundational)**: ต้องการ Phase 1 — **BLOCKS ทุก user story** +- **Phase 3 (US1)**: ต้องการ Phase 2 เสร็จ — เป็น MVP +- **Phase 4 (US2)**: ต้องการ Phase 2 เสร็จ — สามารถขนาน Phase 3 ได้ +- **Phase 5 (US3)**: ต้องการ Phase 4 เสร็จ (extends Telegram dispatcher) + Phase 3 บางส่วน (hermes-bot git) +- **Phase 6 (US4)**: ต้องการ Phase 2 เสร็จ — สามารถขนาน Phase 3/4 ได้ +- **Phase 7 (US5)**: ต้องการ Phase 3+4 เสร็จเพื่อ health checks ครบถ้วน +- **Phase 8 (Polish)**: ต้องการทุก user story phase เสร็จ + +### User Story Dependencies + +- **US1 (P1)**: Phase 2 เสร็จ; ไม่ขึ้นกับ US2/US3/US4/US5 +- **US2 (P2)**: Phase 2 เสร็จ; ไม่ขึ้นกับ US1/US3/US4/US5 +- **US3 (P3)**: US2 (Phase 4) เสร็จ + US1 hermes-bot integration บางส่วน +- **US4 (P4)**: Phase 2 เสร็จ; ไม่ขึ้นกับ US1/US2/US3 +- **US5 (P5)**: US1+US2 เสร็จสำหรับ health checks; สามารถเริ่ม stage-gate docs ขนานได้ตั้งแต่ Phase 1 + +### Within Each User Story + +- Utilities/Guards (T008-T015) ก่อน feature implementation +- Service → Controller → Module ordering +- Unit tests [P] สามารถเขียนขนานกับ implementation ที่ไม่มี circular dependency + +--- + +## Parallel Execution Examples + +### Phase 2 (Foundational — parallel within phase): + +```bash +# รันพร้อมกัน: +T008: uuid.util.ts +T009: secret-redactor.util.ts +T010: api-key.guard.ts +T011: transaction.interceptor.ts +T014: health.controller.ts +T015: secret-redactor.spec.ts +``` + +### Phase 3 US1 (parallel foundations before orchestrator): + +```bash +# รันพร้อมกัน: +T016: dev-qdrant.service.ts +T017: context-loader.service.ts +T018: sub-agent.service.ts +# รอ T016-T018 เสร็จ → T019, T020 +# รอ T019-T020 เสร็จ → T021, T022 +``` + +### Phase 4+6 (US2 และ US4 ขนานกับ US1): + +```bash +# ขณะที่ทีม A ทำ US1 (Phase 3): +# ทีม B ทำ US2 (Phase 4): T025, T026 ก่อน → T027 → T028, T029 +# ทีม C ทำ US4 (Phase 6): T037, T038, T039 ขนานกัน +``` + +--- + +## Implementation Strategy + +### MVP First (US1 Only — Autonomous Dev Orchestrator) + +1. Complete Phase 1: Setup +2. Complete Phase 2: Foundational (CRITICAL) +3. Complete Phase 3: US1 — Autonomous Dev Orchestrator +4. **STOP + VALIDATE**: ส่ง coding task → ตรวจสอบ PR created in Gitea +5. Demo to developer team + +### Incremental Delivery + +1. Setup + Foundational → Foundation ready (Stage 1 acceptance gate ✅) +2. Add US1 → Autonomous coding loop (MVP) → demo +3. Add US2 → Telegram read-only DevOps (Stage 3 acceptance gate ✅) +4. Add US3 → Write-with-confirmation (Stage 4 acceptance gate ✅) +5. Add US4 → Developer AI Proxy (Stage 5 acceptance gate ✅) +6. Add US5 → Full monitoring + staged rollout docs complete + +### Staged Rollout Alignment + +| Deployment Stage | Prerequisite Tasks | +|------------------|--------------------| +| Stage 0 (Docs) | T001–T007 (Setup) | +| Stage 1 (LAN container) | T008–T015 (Foundational) + T042, T045 | +| Stage 2 (Read-only DB/Gitea) | T025 (Gitea read-only) | +| Stage 3 (Telegram read-only) | T026–T032 (US2 complete) | +| Stage 4 (Write-with-confirmation) | T033–T036 (US3 complete) | +| Stage 5 (Proxy) | T037–T041 (US4 complete) | + +--- + +## Notes + +- [P] tasks = different files, no dependency conflicts — safe to parallelize +- hermes-bot Gitea token ต้องสร้างก่อน T033/T035 +- Telegram bot token ต้องสร้างก่อน T027 +- ห้าม commit secret จริงใน `.env.example` หรือ compose files — placeholder only +- ทุก TypeScript file ต้องขึ้นต้นด้วย `// File: hermes/src/...` ตาม AGENTS.md +- ห้ามใช้ DMS production Redis, DMS Qdrant, DMS `audit_logs` ทุกกรณี +- ADR-031 Stage gate ต้องผ่านก่อน deploy stage ถัดไป — ห้าม skip