approved-tasks.json, dashboard/status.json, anaf-monitor/monitor.log
are auto-modified by background processes (heartbeat, cron jobs, ANAF
monitor). Untracking them stops the noisy "auto-commit from dashboard"
churn. Files stay on disk; readers (router._load_approved_tasks etc.)
already handle missing files by returning empty defaults.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
State files updated by dashboard/heartbeat/cron jobs, plus new KB
captures (samsung firmware todo, scout song reel, weekly youtube notes).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three fixes that together restore the planning UX:
- Dashboard reopen showed only a 500-char truncated excerpt of the last
assistant message. Backend now reads the Claude session JSONL directly
and returns full per-turn history; frontend iterates and renders all
bubbles, falling back to last_text_excerpt when the JSONL is missing.
- Phases never advanced because the agent ran /plan-* skills inline as
tool calls and the marker protocol was loose. Tightened the planning
prompt (mandatory PHASE_STATUS marker on the last line of every turn,
ban on inline phase invocation), and the frontend now auto-calls
/plan/advance when phase_ready=true.
- The phase strip never showed visual state because data-phase values
("office-hours") didn't match orchestrator phase names ("/office-hours").
Added normalizePhase + cleanup of PHASE_STATUS markers from rendered
bubbles.
Also bumps eco.py session-content truncation from 2k to 20k so /eco
session views aren't cut mid-response either.
Bumps last_text_excerpt fallback in planning_session.py from 500 to
50_000 so even when the JSONL is unavailable, the bubble isn't sliced
mid-word.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Hash fragments never reach the server so they're lost during login
redirects. ?file= survives the ?next= flow; #hash still works for
direct access when already logged in.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The reverse proxy strips /echo/ before Python, so next=/workspace.html.
Both the JS redirect and the server-side already-logged-in path now
prepend /echo to produce a valid public URL.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Pass current path as ?next= when bouncing unauthenticated requests
to /echo/login; after successful auth, JS reads and validates the
param (must start with /echo/, not /echo/login) before redirecting.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fonturile inter-*.woff2 și tokens.css nu mai sunt referențiate —
Inter se încarcă din Google Fonts, tokens.css a fost înlocuit
de professional-theme.css în romfast-website (fișier greșit în repo).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Systemd user units get a minimal PATH that omits ~/.local/bin where
the claude binary lives, causing plan/respond to 500 on every call.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
_resolve_planning_key searches all active sessions by slug regardless of
adapter, so respond/finalize/cancel/advance work even when planning was
initiated from Discord or Telegram.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Tailscale Serve mapează /echo/* → 127.0.0.1:8088 (dashboard) și / →
:18789 (alt backend). Browser-ul calling /api/ralph/status (relative cu
absolute path la root domain) ajungea la 18789 care nu are endpoint Ralph
→ 502 Bad Gateway.
Fix: toate cele 6 URL-uri (5x fetch + 1x EventSource) folosesc acum prefix
/echo/api/ralph/* pentru a respecta routing-ul tailscale. Pattern consistent
cu workspace.html și index.html (verificat manual).
Endpoints atinse: /status, /<slug>/log, /<slug>/prd, /<slug>/stop,
/<slug>/rollback, /stream (SSE).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
approved-tasks.json mutat de start_planning_session cu status='planning'.
Sesiune activă: 14d2d96d-d4eb-4472-9b07-4a869909c564.
Confirmare empirică că flow-ul Discord/Telegram → modal/ForceReply →
PlanningOrchestrator funcționează end-to-end pe production.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dashboard/api.py: adaug link "Ralph" (lucide bot icon) în NAV_HTML între
Workspace și KB. Pagina ralph.html se injectează corect cu nav-ul (verificat
live via curl pe :8088/ralph.html).
tests/test_e2e_planning_walkthrough.py (nou): 4 teste integration care
simulează scripted exact ce face un user pe Discord:
- click Planifică pe game-library cu UI scope → 4 faze (incl design-review)
- /office-hours → ceo → eng → design → final-plan.md stub scris pe disk
- "Dau drumul" → status approved + final_plan_path în approved-tasks.json
- description fără UI keywords → 3 faze (skip design)
- /cancel mid-planning → status revert pending, state cleared
- mesaj fără planning state → cade pe Claude main chat (NU orchestrator)
Subprocess `claude -p` mock-uit; testează tot wire-up-ul router → orchestrator
→ session și schema approved-tasks.json. Nu consumă credite.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces 5s polling on /echo/ralph.html with EventSource streaming and adds
a rollback control for the running Ralph cards.
Server (dashboard/handlers/ralph.py):
- /api/ralph/stream — Server-Sent Events. Emits `event: status` whenever a
signature over the projects' state changes (poll filesystem at 2s); emits
`event: heartbeat` every 30s to keep proxies happy. Disables proxy
buffering via X-Accel-Buffering:no.
- /api/ralph/<slug>/rollback (POST) — runs `git revert --no-edit HEAD` in
the project; falls back to `git reset --hard HEAD~1` only if revert
reports conflict. After rolling back the commit, decrements `passes` on
the last user story marked complete in prd.json (atomic temp+rename
write, same pattern as ralph_dag.py). Returns
`{success, message, reverted_commit, story_reverted, method}`.
- _ralph_validate_slug tightened to a strict regex (alphanum + dash +
underscore, ≤64 chars) plus explicit ../, /, \ rejection. All previously
accepted slugs still pass; URL-encoded traversal and shell metachars
now blocked before the filesystem is touched.
- _ralph_collect_status / _ralph_signature factored out of
handle_ralph_status so the SSE loop can reuse them and detect changes
cheaply.
Server (dashboard/api.py):
- HTTPServer → ThreadingHTTPServer with daemon_threads=True. SSE is a
long-lived response; without threading a single client would block all
other dashboard endpoints.
- /api/ralph/stream (GET) and /api/ralph/<slug>/rollback (POST) wired
into the dispatch.
Client (dashboard/ralph.html):
- EventSource('/api/ralph/stream') with permanent fallback to 5s polling
when readyState=CLOSED (no server, CORS blocked, browser without SSE).
- Indicator badge: 🟢 Live (SSE), ⏱ Polling (fallback), Offline.
- Rollback button (undo-2 icon) on running cards; native confirm() with
message: "Asta va da git revert HEAD pe <slug> și va decrementa ultima
story trecută. Continui?"
Tests (tests/test_dashboard_ralph_endpoint.py, +20 cases):
- Strict slug validator: underscore allowed, >64 rejected, special chars
/ backslash / URL-encoded traversal rejected.
- _ralph_collect_status + _ralph_signature: stable when nothing changes,
flips when project added or `passes` toggles.
- Rollback: invalid slug → 400, non-git project → 400, real two-commit
repo revert succeeds and decrements last passing story (US-002 goes
passes:false while US-001 stays passes:true), no-passing-stories case
succeeds with story_reverted=None, response shape contract, atomic
helper leaves no .tmp file behind.
- API routing smoke: confirms ThreadingHTTPServer + stream + rollback
references present in dashboard/api.py.
39/39 tests pass on tests/test_dashboard_ralph_endpoint.py. Pre-existing
failures in test_dashboard_constants.py::test_base_dir_is_echo_core (the
worktree dir is `echo-core-realtime`, not `echo-core`) and
test_dashboard_unified_index.py::test_index_has_all_panels are unrelated
to this change and reproduced on master.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Înainte: click pe 🧠 Planifică (Discord/Telegram) sau /plan <slug> fără descriere
pe un proiect din workspace fără entry în approved-tasks.json → mesaj eroare
"Adaugă mai întâi cu /p <slug> <descriere>" și user-ul trebuia să facă două
operații.
Acum:
- Discord button "Planifică" cu descriere goală → deschide RalphPlanModal cu
TextInput pentru descriere; on_submit pornește direct start_planning_session
- Discord /plan <slug> fără description param și fără entry → același modal
(response.send_modal ÎNAINTE de defer — Discord constraint)
- Telegram callback "Planifică" cu descriere goală → set state
STEP_INPUT_DESCRIPTION_THEN_PLAN + ForceReply; handle_message detectează
step și pornește planning cu textul user-ului
- ralph_flow.py: nou STEP_INPUT_DESCRIPTION_THEN_PLAN (alături de cel existent
pentru propose-only)
start_planning_session deja auto-creează entry în approved-tasks.json dacă
proiectul lipsește, deci flow-ul e end-to-end: workspace → click → descriere
→ planning agent activ.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Echo Core devine planning agent: poartă o conversație multi-fază cu Marius
folosind skill-urile gstack (/office-hours → /plan-ceo-review →
/plan-eng-review → /plan-design-review opt) și produce final-plan.md în
~/workspace/<slug>/scripts/ralph/, gata să fie consumat de Ralph PRD
generator (W3) noaptea.
Decizii arhitecturale (din eng review + spike findings):
- PlanningSession ca clasă SEPARATĂ de chat-ul main (NU mode=string param)
— separation explicit. claude_session.py rămâne strict pentru chat;
planning trăiește în src/planning_session.py + src/planning_orchestrator.py.
Inheritance literală nu se aplică (claude_session.py expune funcții
module-level, nu o clasă) — separation e satisfacută prin module distinct.
- Fresh subprocess PER skill phase, NU single resumed session — phase-urile
coordinează via disk artifacts (gstack convention în
~/.gstack/projects/<slug>/). Avoids context window growth.
- --max-turns 20 default + retry pe error_max_turns la --max-turns 30.
Spike a arătat că prompt-uri complexe pot exploda turn budget-ul.
- approved-tasks.json schema extins cu planning_session_id + final_plan_path
(Status flow: pending → planning → approved → running → complete).
- State separat în sessions/planning.json (NU active.json), keyed pe
(adapter, channel_id) pentru re-resume la restart echo-core.
Trigger-e:
- Discord: slash command /plan <slug> [descriere] cu autocomplete pe pending,
buton "🧠 Planifică" în RalphProjectView, și /cancel slash command.
- Telegram: /plan + /cancel commands, plus buton "🧠 Planifică" în
ralph project keyboard.
- Router: state-aware routing — dacă chat-ul e în planning, mesajele plain
trec la PlanningOrchestrator.respond() prin --resume; /cancel revine la
status pending; /advance / "Continuă faza" advance fază nouă (fresh
subprocess); /finalize sau "Dau drumul" promote la status approved.
Discord defer pattern: toate butoanele noi (PlanningActiveView,
PlanningFinalView, "🧠 Planifică") apelează await
interaction.response.defer(ephemeral=True) ÎNAINTE de orice IO — evită
"Interaction failed" pe IO >3s.
UX strings warm + colaborativ (per design review): "🧠 Pornesc planning
pentru ...", "Răspunde aici", "Continuă faza", "Dau drumul tonight",
"Anulează" — niciun "Submit/Approve/Cancel" generic.
Tests: 23 noi (test_planning_session, test_planning_orchestrator,
test_router_planning) — toate pass. Mock pe _run_claude pentru a evita
subprocess Claude real în CI.
Files new:
prompts/planning_agent.md
src/planning_session.py
src/planning_orchestrator.py
tests/test_planning_session.py
tests/test_planning_orchestrator.py
tests/test_router_planning.py
Files modified:
src/claude_session.py — _run_claude(cwd=...) optional + surface subtype/is_error
src/router.py — state-aware routing, start_planning_session, planning_advance/approve/cancel, _ralph_propose schema cu planning_session_id + final_plan_path
src/adapters/discord_bot.py — /plan + /cancel slash commands; planning views imported
src/adapters/discord_views.py — PlanningActiveView, PlanningFinalView, "Planifică" button în RalphProjectView, _split_chunks helper
src/adapters/telegram_bot.py — /plan + /cancel handlers, callback_ralph extins cu plan/planadvance/plancancel/planapprove, planning keyboards
Status testelor pe modulele atinse: 75 passed, 0 failed
(test_claude_session security_section preexistent — neatins).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Restructurare Ralph QC loop pe smart gate dispatcher tag-driven (în loc de
5 faze fixe), DAG dependsOn cu propagare blocked, retry guard 3-strike, rate
limit detection, plus dashboard live cu polling 5s.
Changes:
- tools/ralph_prd_generator.py: parametru optional final_plan_path; când e
furnizat, invocă Claude Opus pe final-plan.md pentru extragere user stories
cu schema extinsă (tags, dependsOn, acceptanceCriteria 3-5). Backward compat
păstrat — fără final_plan_path, fallback la heuristic-ul vechi.
- tools/ralph/prd-template.json: schema W3 (tags[], dependsOn[], retries,
failed, blocked, failureReason, requiresDesignReview).
- tools/ralph/prompt.md: 4 faze (impl, base quality, smart gates, commit) +
dispatcher pe story.tags. Tags vide → run-all-gates fallback (safe default).
- tools/ralph_dag.py (nou): tag validation heuristic anti-silent-regression
(force ui dacă diff atinge .vue/.tsx/.html/.css/.scss; force db pentru
migrations sau .sql; force vercel dacă există vercel.json) + topological
sort cu blocked propagation + atomic prd.json updates.
- tools/ralph/ralph.sh: --max-turns 30, DAG-aware story selection, retry
counter cu auto-fail la 3, rate limit detection (sleep 30min + 1 retry),
CLI subcommands prin tools/ralph_dag.py helper.
- dashboard/handlers/ralph.py (nou): /api/ralph/status + /<slug>/log + /prd
+ /stop. Defensive vs corrupt prd.json. Sandbox-ed PID kill.
- dashboard/ralph.html (nou): live cards 3/2/1 col responsive, polling 5s,
drawer pentru log/PRD viewer, status colors (--status-running/blocked/
failed/complete declarate inline), Lucide icons cu aria-labels.
- dashboard/api.py: mount /api/ralph/* (GET status/log/prd, POST stop).
- tests/: 72 teste noi (smart gates, DAG, retry, dashboard endpoint).
Note arhitecturale:
- Polling 5s ales peste SSE/WebSocket (suficient pentru iter Ralph 8-15min)
- Tag validation rulează POST-iter pe diff git pentru anti-silent-regression
- Rate limit retry: 1 dată per rulare, apoi mark failed=rate_limited
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Restructurează comenzile Ralph într-un dispatcher unificat (_try_ralph_dispatch)
care suportă atât comenzile noi scurte (/p /a /l /k) cât și aliasurile legacy
(!propose !approve !status !stop). Pe Discord adaugă slash commands native cu
autocomplete dinamic pentru pending (/a) și running (/k). Pe Telegram apar în
meniul /. WhatsApp le parsează ca text plain.
Activează cron jobs morning-report (08:30) și evening-report (21:00) și adaugă
night-execute (23:00) pentru execuția autonomă a proiectelor aprobate.
Foundation pentru W1 din planul "Echo Core conversational planning agent".
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add full Ralph section to CLAUDE.md: flow diagram, !approve/!status/!stop
commands, file paths, status lifecycle, workspace projects list, and
safety rules (no core files, echo-core self-improve only on dedicated branch).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Use GITEA_TOKEN from dashboard/.env for git clone in night-execute
- Fix remote URLs on existing workspace repos to include token
- Clone all 8 romfast projects to ~/workspace/: roa2web, btgo-playwright,
space-booking, romfast-website, game-library, wol (+ gomag-vending, vending_data_intelligence_report)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Clone romfastsql repo local pe /home/moltbot/workspace/romfastsql/
- Fix: LXC 171 e pe pvemini, nu pveelite
- Adaug secțiuni lipsă: HA groups, corosync token tuning (post-incident 2026-04-20)
- Diagnostic tools: rasdaemon, netconsole, kdump-tools
- OOM alerting, mail notifications, swap pveelite
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Uncommitted files alone are not an actionable heartbeat alert.
Only send a message if there are other findings besides git status.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
LXC 171 mutat pe pveelite (nu pvemini), RAM 4GB (nu 16GB).
LXC 110 disk 8GB (nu 30GB), SSH user moltbot@.
Adăugat VM 302 (oracle-test, 10.0.20.130).
VM 201 extins cu detalii IIS, domenii, Win-ACME, ZFS replication.
VM 109 extins cu Oracle 19c, schedule backup RMAN.
Proxmox VE 8.4.14, storage cluster documentat.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Referințele vechi ~/clawd și gitea.romfast.ro/romfast/clawd rămase
din migrarea OpenClaw au fost corectate în index.html și files.html.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
memory/* was fully ignored; now only memory/kb/ is tracked
so notes, coaching sessions, insights, and project docs are
versioned while embeddings and sqlite databases stay untracked.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>