Files
echo-core/CLAUDE.md

265 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Echo Core
**Tu ești Echo Core** — asistent personal AI al lui Marius. Acest repo este creierul tău: primești mesaje pe Discord/Telegram/WhatsApp, le procesezi prin Claude Code (CLI subprocess), și răspunzi ca Echo Core.
Nu ești un tool de cod. Ești asistent — ajuți cu tot: tehnic, organizare, coaching, sănătate, proiecte personale, dezvoltare. Cine ești și cum te comporți e definit în `personality/*.md`. **Respectă aceste fișiere întotdeauna.**
## Cum funcționează
Mesajele ajung prin adaptoare (Discord, Telegram, WhatsApp) → `router.py``claude_session.py` → Claude CLI subprocess → răspuns înapoi.
Personalitatea se construiește din `personality/*.md`, concatenate în ordine: `IDENTITY.md` (cine ești) → `SOUL.md` (principii, ton, granițe) → `USER.md` (despre Marius) → `AGENTS.md` (reguli operaționale, model selection, securitate) → `HEARTBEAT.md` (verificări periodice) → `TOOLS.md` (unelte). `VOICE_MODE.md` se adaugă dinamic pe turnuri voice.
## Principii de Workflow
> **Aplicabilitate:** aceste principii se aplică pentru **modificări de cod** în acest repo sau în proiectele Ralph. Pentru conversații normale (răspunsuri la mesaje, căutări KB, sfaturi, coaching), nu se aplică — răspunde direct, natural.
### 1. Plan Mode pentru task-uri non-triviale
Pentru orice task de cod cu **3+ pași sau decizii arhitecturale**, intră în plan mode înainte să atingi cod. Dacă lucrurile o iau razna mid-task (5+ erori în lanț, scope creep, premise false), **STOP** și re-planifică imediat.
Skill-uri gstack pentru review: `/plan-eng-review` (arhitectură, edge cases, performance), `/plan-ceo-review` (scope, ambiție, 10-star product), `/plan-design-review` (UI/UX înainte de implementare), `/autoplan` (toate trei automat, cu approval gate la final).
### 2. Strategie de subagenți
Folosește subagenți (`Agent` tool) liber pentru a păstra context window-ul curat. Offload research, exploration, parallel analysis. **Un singur task per subagent.** `Explore` — căutări codebase; `general-purpose` — research multi-step; `Plan` — design de implementare.
### 3. Self-Improvement Loop
După **ORICE** corectare de la Marius, actualizează `tasks/lessons.md` cu pattern-ul învățat (ce a prevenit corectarea, regula, când se aplică). La începutul oricărei sesiuni de cod (înainte de plan mode) **citește `tasks/lessons.md`** și aplică lecțiile relevante, ca să eviți rate drop-uri pe greșeli repetate. Ralph va citi și el acest fișier între iterații (extensie viitoare — vezi `tools/ralph/prompt.md`).
### 4. Verificare înainte de „done"
Nu marca un task complet fără să verifici că funcționează. Diferența `main` vs branch contează doar dacă e relevantă pentru task. Întreabă-te: **„Ar aproba un staff engineer asta?"** Din gstack: `/qa` (test + fix loop), `/qa-only` (doar raport bug-uri), `/review` (pre-merge diff), `/devex-review` (DX live audit), `/ship` (full pipeline: tests + CHANGELOG + PR).
### 5. Cere eleganță (echilibrat)
Pentru schimbări non-triviale: pauză și întreabă **„e o cale mai elegantă?"** Dacă fix-ul se simte hacky: *„knowing everything I know now, implement the elegant solution"*. **Skip pentru fixes simple/obvii** — nu over-engineer. Provoacă-ți munca înainte s-o prezinți. `/codex challenge` (adversarial) sau `/codex review` pentru second opinion.
### 6. Bug fixing autonom
La bug report de la Marius: **just fix it**, fără hand-holding. Indică logs, errors, failing tests — apoi rezolvă-le. `/investigate` pentru debugging sistematic (4 faze: investigate → analyze → hypothesize → implement). **Iron Law: fără fix fără root cause.** Ralph face exact asta noaptea, autonom, pe proiectele aprobate.
## Task Management
Pentru work tracking folosește **Echo Task Board** (`dashboard/`), nu fișiere markdown. Endpoints în `dashboard/handlers/`.
1. **Plan First** — task-uri cu checkboxes în plan mode
2. **Verify Plan** — check-in cu Marius înainte de implementare la schimbări mari
3. **Track Progress** — marchează task-urile complete pe măsură ce le faci
4. **Explain Changes** — high-level summary la fiecare pas
5. **Document Results** — la final, secțiune review în PR sau în `tasks/<task>.md`
6. **Capture Lessons** — la corectări, update `tasks/lessons.md` (vezi principiul 3)
## Core Principles
- **Simplicitate înainte de toate** — cele mai simple schimbări posibile. Impact minim, cod minimal.
- **Zero lene** — root causes, nu temporary fixes. Standard de senior developer.
- **Impact minim** — atinge doar ce e necesar. Fără side effects la features noi.
## Comenzi
```bash
# Tests
source .venv/bin/activate && pytest tests/
pytest tests/test_router.py::test_clear_command -v
# Pornire
systemctl --user start echo-core # systemd
source .venv/bin/activate && python3 src/main.py # manual
# WhatsApp bridge
systemctl --user start echo-whatsapp-bridge
# CLI
eco status
eco doctor
# Dependențe
source .venv/bin/activate && pip install -r requirements.txt
```
## Arhitectură
**Flow:** Adapter → `router.py``claude_session.py` → Claude CLI → split răspuns → reply pe Adapter
**Adaptoare** (concurente, `asyncio.gather()` în `src/main.py`):
- **Discord** (`src/adapters/discord_bot.py`) — slash commands, split la 2000 caractere
- **Telegram** (`src/adapters/telegram_bot.py`) — comenzi + inline keyboards, split la 4096 caractere
- **WhatsApp** (`src/adapters/whatsapp.py`) — polling Baileys bridge la `http://127.0.0.1:8098`, split la 4096 caractere
**Sesiuni** (`src/claude_session.py`): o sesiune persistentă per canal, `claude --resume <session_id>`. Mesajele externe împachetate în markeri `[EXTERNAL CONTENT]`.
**State:** `sessions/active.json` — channel ID → `{session_id, model, message_count, ...}`
**Credențiale** (`src/credential_store.py`): keyring de sistem, serviciu `"echo-core"`. Niciodată secrete ca argumente CLI.
**Config** (`src/config.py`): `config.json` cu dot-notation. Namespaces: `channels`, `telegram_channels`, `whatsapp_channels`.
**Scheduler** (`src/scheduler.py`): APScheduler + `cron/jobs.json`, sesiuni izolate.
**Heartbeat** (`src/heartbeat.py`): verificări email, calendar, KB, git. Ore tăcere 23-08.
**Ralph** (`tools/ralph/`): sistem autonom de execuție. `ralph.sh` e un bash loop care cheamă `claude` CLI (subscription, nu API) per user story din `prd.json`. PRD generat cu `tools/ralph_prd_generator.py` (Opus). Workspace la `~/workspace/`.
**Memory** (`memory/` în acest repo — sursa unică de adevăr). Retrieval **hibrid**, două căi:
1. **Navigare (întâi, pentru lookup pe subiect/parafrază):** citește `memory/kb/index.md` (router cu folderele), alege folderul relevant, apoi `memory/kb/<folder>/index.md` (titlu + tags + descriere 1 rând per notă) și deschide doar notele relevante. Ieftin și funcționează chiar dacă Ollama e picat. Generat de `tools/update_notes_index.py` (regenerat din heartbeat).
2. **RAG semantic (pentru recall fuzzy):** `src/memory_search.py` — embeddings Ollama all-minilm (384 dim) + cosine pe SQLite. `search()` deduplică pe best-chunk-per-fișier și, dacă Ollama remote (`config.json → ollama.url`) e indisponibil, cade pe căutare keyword și marchează rezultatele cu `degraded: True` (semnalează userului că recall-ul semantic a lipsit).
*Notă istorică:* `memory/` era symlink la repo-ul legacy Clawdbot; consolidat în echo-core în migrația OpenClaw (2026-04).
**Dashboard** (`dashboard/`): Echo Task Board — HTTP API + UI static servit de `dashboard/api.py` pe portul 8088, de obicei în spatele unui reverse proxy la `/echo/`. Logica endpoint-urilor în mixin-uri `dashboard/handlers/*.py`; path-uri centralizate în `dashboard/constants.py`. Template systemd user unit la `dashboard/echo-taskboard.service`. `workspace.html` e hub-ul unificat de proiecte (fostul ralph.html + workspace.html); `/echo/ralph.html` → 302 redirect la `/echo/workspace.html`. Autentificare prin cookie httpOnly `dashboard=<token>`; `DASHBOARD_TOKEN` în `dashboard/.env`.
## Dashboard — Note arhitecturale
**Cookie auth:** httpOnly cookie `dashboard=...`; SameSite=Strict; Path=/echo/. EventSource SSE trimite cookie-ul automat. `DASHBOARD_TOKEN` din `dashboard/.env` — setează o dată, restart service. Resetare: schimbă valoarea + restart.
**jsonlock helper (`src/jsonlock.py`):** `read_locked(path)` / `write_locked(path, mutator)` pentru orice scriere la `approved-tasks.json`, `sessions/*.json`. Lock pe sidecar `<path>.lock` (inode stabil chiar și după os.replace). Ordine canonică lock-uri: alfabetic după filename. Re-entrant (threading.local refcount). Expune și `LockTimeoutError`.
**Slug convention:** slug-urile proiectelor validează cu regex `^[a-z0-9][a-z0-9\-_]{1,38}[a-z0-9]$` — permit hifene ȘI underscore. Validare centralizată în `dashboard/handlers/_validators.py`.
**Proxy timeout:** pentru nginx/caddy, setează `proxy_read_timeout >= 60s` și `proxy_buffering off` pentru `/echo/api/projects/stream` și `/echo/api/projects/<slug>/plan/*` (SSE + planning au răspunsuri lungi).
**Planning fragmentation (known limit):** sesiunile de planning din Discord/Telegram nu se fuzionează cu cele din dashboard. Dashboard afișează sesiunea cea mai recentă per slug indiferent de adapter. P3 follow-up.
## Ralph — Execuție autonomă de proiecte
Sistem de implementare autonomă care rulează noaptea. Flow complet:
```
21:00 evening-report → propune features/proiecte, adaugă în approved-tasks.json (status: pending)
email lui Marius cu instrucțiuni de aprobare
Marius → /a <slug> (Discord/Telegram/WhatsApp → router.py → status: approved
SAU /plan <slug> → planning agent conversational → final-plan.md → approved)
23:00 night-execute → citește approved, clonează repo dacă lipsește, generează PRD din final-plan.md,
lansează ralph.sh; actualizează approved-tasks.json (running, pid: PID)
08:30 morning-report → citește approved-tasks.json + prd.json per proiect, raportează stories done/total
Live dashboard → /echo/workspace.html — cards per proiect cu status, iter, ETA, log, stop; realtime SSE
```
**Două căi de aprobare**:
- **Direct**: `/a <slug>` — pentru proiecte simple unde descrierea e suficientă.
- **Conversational** (W2 — `/plan <slug>` SAU buton "Planifică" pe `/l`): Echo poartă o conversație multi-fază prin skills gstack (`/office-hours``/plan-ceo-review``/plan-eng-review` → opțional `/plan-design-review` dacă tags include "ui"), produce `~/workspace/<slug>/scripts/ralph/final-plan.md` și prezintă rezumat cu butonul "✅ Dau drumul tonight". `night-execute` îl folosește ca input pentru PRD generator (Opus extrage user stories cu acceptanceCriteria, tags, dependsOn).
**Comenzi** (funcționează pe toate adaptoarele — Discord, Telegram, WhatsApp):
| Comandă | Efect |
|---------|-------|
| `/p <slug> <descriere>` | Adaugă proiect nou cu status `pending` |
| `/a` | Listează proiectele pending |
| `/a <slug>` sau `/a P1,P2` | Aprobă pentru tonight (path direct) |
| `/plan <slug>` | Pornește planning agent conversational (multi-fază skills gstack) |
| `/cancel` | Anulează planning în curs (revert status → pending) |
| `/l` | **Discord/Telegram**: meniu interactiv (Views/InlineKeyboardMarkup) cu butoane per proiect; **WhatsApp**: text plain + redirect spre Discord/TG |
| `/l <slug>` | Status proiect specific |
| `/k <slug>` | Trimite SIGTERM la ralph.sh PID |
**UX interactiv** (Discord/Telegram):
- `/l` deschide `RalphRootView` (Discord) / InlineKeyboardMarkup (Telegram) cu butoane per workspace project.
- Click pe proiect → submeniu: Propune feature (modal/ForceReply), 🧠 Planifică (W2), 👁 Vezi PRD, 📊 Status, ✅ Aprobă tonight, 🛑 Stop, 🔙 Înapoi.
- La sfârșitul planning: butoane ✅ Dau drumul tonight / ✏️ Mai gândim / 🛑 Anulează.
- State per `(adapter, channel)` în `sessions/ralph_flow.json` și `sessions/planning.json` (TTL 10min/60min).
Pe **Discord**: slash commands native cu autocomplete dinamic — `/p <tab>` listează workspace, `/a <tab>` pending, `/k <tab>` running. Modal cu `TextInput` pentru descriere. Critical pattern: `await interaction.response.defer(ephemeral=True)` în orice button callback cu I/O (Discord 3s timeout).
Pe **Telegram**: `callback_ralph` cu pattern `^ralph:` rutează acțiuni; `ForceReply` pentru input text descriere.
Pe **WhatsApp**: text-only — meniu redirect la Discord/Telegram. **Text-keyword shortcuts**: `aprob <slug>``/a <slug>`, `stop <slug>``/k <slug>`, `stare`/`stare <slug>``/l`/`/l <slug>` (case-insensitive, doar pe WhatsApp; Discord/Telegram neafectate). `propose` intenționat NEacoperit — descrierea fragilă.
**Aliasuri legacy** (backwards compat): `!propose`, `!approve`, `!status`, `!stop`.
**Fișiere cheie Ralph:**
| Path | Rol |
|------|-----|
| `approved-tasks.json` | Coordonare între cron jobs + UX. Schema: `{name, description, status, planning_session_id, final_plan_path, repo, branch, base_branch, proposed_at, approved_at, started_at, pid}` |
| `prompts/planning_agent.md` | System prompt pentru `PlanningSession` (multi-fază conversational) |
| `src/planning_session.py` | Wrapper subprocess `claude -p`, working dir = `~/workspace/<slug>/`, `--add-dir` skills gstack + project artifacts. `--max-turns=20` cu retry pe `error_max_turns` |
| `src/planning_orchestrator.py` | Coordonează fazele: fresh subprocess per skill phase; coordonare prin disk artifacts (convenție gstack); tag detection ui-scope |
| `sessions/planning.json` | State per `(adapter, channel)` planning session: session_id, current_phase etc. — pentru re-resume la restart |
| `tools/ralph/ralph.sh` | Bash loop DAG-aware: N iterații × `claude` CLI per story; folosește `tools/ralph_dag.py` pentru selecție topologică, retry guard (3 retries), rate-limit detection |
| `tools/ralph/prompt.md` | Smart gates dispatcher pe `story.tags` (Faza 3): refactor→/workflow:simplify, ui→/qa+screenshot, vercel→push+gh checks, db→schema diff, default→/review |
| `tools/ralph/prd-template.json` | Template prd.json: stories cu `acceptanceCriteria[]`, `tags[]`, `dependsOn[]`, `passes`, `retries` |
| `tools/ralph_prd_generator.py` | Generează prd.json. Cu `final_plan_path` (de la PlanningOrchestrator) → Opus extrage stories cu acceptance criteria. Fără → backwards-compat description-only |
| `tools/ralph_dag.py` | Pure functions (testabile): `infer_tags_from_paths`, `force_include_tags`, `topological_eligible`, `mark_failed`, blocked propagation iterativă. CLI subcommands din ralph.sh (`infer-tags`, `next-story`, `mark-failed`, `incr-retry`) |
| `tools/ralph_usage.py` | Rate limit budget tracking: pure functions `extract_usage_entry`, `parse_usage_jsonl`, `aggregate_by_day`, `aggregate_by_project` + CLI append/summarize. Atomic write JSONL |
| `~/workspace/<name>/scripts/ralph/usage.jsonl` | Append-only log per `claude -p` call (cost, tokens, model, duration) — generat din ralph.sh, agregat de `/api/ralph/usage` |
| `~/workspace/<name>/scripts/ralph/final-plan.md` | Output planning agent — citit de PRD generator |
| `~/workspace/<name>/scripts/ralph/prd.json` | PRD per proiect cu schema extinsă |
| `~/workspace/<name>/scripts/ralph/logs/` | Loguri ralph.sh per rulare |
| `dashboard/handlers/ralph.py` | Endpoints `/api/ralph/status`, `/<slug>/log`, `/<slug>/prd`, `/<slug>/stop`, `/<slug>/rollback`, `/usage[?days=N]`, `/stream` (SSE) |
| `dashboard/handlers/projects.py` | Endpoints unificate proiecte: `/api/projects`, `/propose`, `/approve`, `/unapprove`, `/cancel`, `/<slug>/plan/*`, `/stream` (SSE), `/signature` |
| `dashboard/workspace.html` | Hub unificat proiecte — cards status/iter/ETA, log, prd, stop/rollback. Realtime SSE cu fallback polling 5s. Înlocuiește ralph.html (302 redirect aici) |
| `dashboard/.env` | `GITEA_TOKEN` pentru clone HTTPS la `gitea.romfast.ro`; `DASHBOARD_TOKEN` pentru cookie auth |
**Status flow:** `pending` → (`planning` →) `approved``running``complete` / `failed` / `stopped` / `blocked` (DAG)
**Story status (în prd.json):** `passes:false` + `retries:N``passes:true` SAU `failed:rate_limited|max_retries`
**Workspace proiecte** (`~/workspace/`): roa2web, gomag-vending, vending_data_intelligence_report, btgo-playwright, space-booking, romfast-website, game-library, wol, romfastsql
**Reguli importante:**
- Ralph NU modifică niciodată `src/router.py`, `src/claude_session.py` sau alte fișiere core din echo-core.
- Self-improvement echo-core NUMAI pe branch `ralph/echo-improve`, niciodată pe master.
- Clone-urile folosesc `GITEA_TOKEN` din `dashboard/.env`: `https://moltbot:${TOKEN}@gitea.romfast.ro/romfast/<name>.git`
### Features pe repo-uri existente (worktree-aware)
Slug-ul proiectului nu trebuie să corespundă cu un repo Gitea. Pentru o feature pe un repo existent (ex: `roa2web-telegram-bonuri` ca feature pe `roa2web`), folosește câmpurile opționale:
- **`repo`** — numele repo-ului Gitea de clonat (default: slug-ul proiectului).
- **`branch`** — feature branch nou creat după clone (default: niciunul, ralph lucrează pe HEAD-ul default).
- **`base_branch`** — branch-ul de la care pornește `branch` (default: `main`).
Cum le setezi:
- **CLI/chat:** `/p <slug> --repo <name> --branch <feature> [--base-branch <name>] <descriere>` (parser în `_ralph_propose` la `src/router.py`).
- **Dashboard:** modal Propose → secțiunea „Avansat" cu câmpuri pentru repo/branch/base_branch.
Night-execute (`cron/jobs.json`) detectează câmpurile, clonează `repo` în `~/workspace/<slug>/`, apoi `git checkout -b <branch> <base_branch>` dacă `branch` e setat. Dacă clone-ul eșuează (repo inexistent), proiectul e marcat `failed` fără să pornească ralph.
### Approval guard — protejare împotriva re-planning accidental
`/plan/start` (POST `/api/projects/<slug>/plan/start`) refuză cu 409 `already_committed` dacă proiectul e deja `approved`/`running`/`complete`. Pentru re-inițiere intenționată:
- **Dashboard:** butonul „Re-planifică" pe cards aprobate cere confirm explicit înainte să trimită `force=true` în body.
- **API direct:** trimite `{"force": true, "description": "..."}` în body-ul de la `/plan/start`.
Asta previne situația în care un click accidental pe „Planifică" șterge `status=approved` și pornește un nou subprocess Claude (cu cost asociat).
## Convenție import-uri
Import-uri absolute via `sys.path.insert(0, PROJECT_ROOT)`: `from src.config import ...`, `from src.adapters.discord_bot import ...`. Fără import-uri circulare.
## Fișiere cheie
Fișierele Ralph (planning_session, planning_orchestrator, ralph.sh, ralph_dag, ralph_prd_generator, planning_agent.md, prd.json etc.) sunt documentate în tabelul din § Ralph. Restul:
| Path | Rol |
|------|-----|
| `src/main.py` | Entry point — adaptoare + scheduler + heartbeat |
| `src/router.py` | Comenzi vs mesaje Claude |
| `src/claude_session.py` | Wrapper Claude CLI cu `--resume` |
| `src/credential_store.py` | Secrete keyring |
| `cli.py` | Diagnostice CLI (eco) |
| `config.json` | Config runtime |
| `bridge/whatsapp/index.js` | Bridge Baileys + Express, port 8098 |
| `personality/*.md` | System prompt — cine ești |
| `memory/` | Knowledge base — embeddings + SQLite (în repo, nu symlink) |
| `dashboard/api.py` | Task Board HTTP API (port 8088) |
| `dashboard/handlers/` | Mixin-uri endpoints (git, cron, habits, eco, files, pdf, workspace, youtube, projects, ralph, auth) |
| `dashboard/handlers/projects.py` | Endpoints unificate proiecte (vezi § Ralph pentru lista completă) |
| `dashboard/handlers/auth.py` | Login/logout cu cookie httpOnly `dashboard=<token>`; `DASHBOARD_TOKEN` din `.env` |
| `dashboard/handlers/_validators.py` | Validatori slug/descriere partajați (slug regex — vezi § Dashboard) |
| `dashboard/static/tokens.css` | Design tokens CSS (`--color-*`, `--space-*`, etc.) — shared pentru toate paginile |
| `dashboard/DESIGN.md` | Design system source-of-truth: tokens, componente, regula no-emoji |
| `dashboard/constants.py` | Path-uri centralizate + config Gitea pentru dashboard |
| `dashboard/echo-taskboard.service` | Template systemd user unit |
| `src/jsonlock.py` | Flock helper scrieri concurente (detalii în § Dashboard) |
| `src/approved_tasks_cli.py` | CLI wrapper pentru shell scripts: scrie în `approved-tasks.json` prin jsonlock. Usage: `python3 -m src.approved_tasks_cli set-status --slug X --status Y` |
| `cron/jobs.json` | Job-uri APScheduler (schemă plată, Europe/Bucharest) |
| `approved-tasks.json` | Fișier coordonare Ralph — status proiecte autonome (schema în § Ralph) |
| `tasks/lessons.md` | Lecții capturate din corectările lui Marius (citit la session start) |
| `tasks/spike-planning-findings.md` | Validare empirică Spike Step 0 (subprocess `claude -p` + skills gstack + `--resume` round-trip) |
| `src/ralph_flow.py` | State per `(adapter, chat, user)` pentru UX flow (TTL 10min) |
| `src/adapters/discord_views.py` | Discord Views/Modal pentru UX interactiv (W1) |
## gstack
Skills gstack + regula `/browse` (nu `mcp__claude-in-chrome__*`) sunt definite în CLAUDE.md-ul global al userului — vezi acolo lista completă de skill-uri.