21 KiB
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/.
- Plan First — task-uri cu checkboxes în plan mode
- Verify Plan — check-in cu Marius înainte de implementare la schimbări mari
- Track Progress — marchează task-urile complete pe măsură ce le faci
- Explain Changes — high-level summary la fiecare pas
- Document Results — la final, secțiune review în PR sau în
tasks/<task>.md - 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
# 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 lahttp://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:
- Navigare (întâi, pentru lookup pe subiect/parafrază): citește
memory/kb/index.md(router cu folderele), alege folderul relevant, apoimemory/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 detools/update_notes_index.py(regenerat din heartbeat). - 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 cudegraded: 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-reviewdacă 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):
/ldeschideRalphRootView(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)însessions/ralph_flow.jsonșisessions/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.pysau alte fișiere core din echo-core. - Self-improvement echo-core NUMAI pe branch
ralph/echo-improve, niciodată pe master. - Clone-urile folosesc
GITEA_TOKENdindashboard/.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ștebranch(default:main).
Cum le setezi:
- CLI/chat:
/p <slug> --repo <name> --branch <feature> [--base-branch <name>] <descriere>(parser în_ralph_proposelasrc/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.