Voice utterances and text messages on the same Discord channel now share
one Claude session, and Echo's voice replies are mirrored back into the
text channel. Replaces the old voice:<id> session-key split.
Changes:
- src/adapters/_text_chunks.py: new leaf module for split_message
(used by both discord_bot and voice pipeline)
- src/router.py: drop voice: prefix from session_key; add [voice] marker;
strip leading [speaker:/[voice] tokens from user input (anti-jailbreak);
remove dead double-clear of voice: key
- src/claude_session.py: include personality/VOICE_MODE.md unconditionally
(rules become per-turn-aware via [speaker:] prefix instead of session flag)
- src/voice/pipeline.py: VoiceSession splits text_channel_id +
voice_channel_id; resolve text channel per-send (no stale refs); mirror
Echo's reply text into the text channel after route_message returns
- src/adapters/discord_voice.py: /voice join passes both channel ids
- src/adapters/discord_bot.py: import split_message from leaf module
- personality/VOICE_MODE.md: rewrite as per-turn dynamic rules;
add synthesis instructions for text turns after voice turns
Tests:
- tests/test_router.py: 4 new cases (plain channel_id, anti-jailbreak,
text-adapter regression, no-double-clear)
- tests/test_pipeline_mirror.py: new — Echo reply mirror chunking,
empty guard, mirror_enabled=False, send-raises resilience
- tests/test_voice_session_channel_ids.py: new — split-attr contract
+ metrics payload schema
- tests/test_voice_session_cleanup.py: update for new kwargs
Plan: /home/moltbot/.claude/plans/vreau-ca-tot-textul-greedy-rivest.md
Co-Authored-By: Claude Opus 4.7 <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>
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>
Digest summarizes unread emails via Claude CLI; forward sends raw
content (split to 4096 chars). Wired as /email digest and
/email forward slash commands, plus instant per-guild sync on ready.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Replace all ~/clawd and ~/.clawdbot paths with ~/echo-core equivalents
in tools (git_commit, ralph_prd_generator, backup_config, lead-gen)
- Update personality files: TOOLS.md repo/paths, AGENTS.md security audit cmd
- Migrate HANDOFF.md architectural decisions to docs/architecture.md
- Tighten credentials/ dir to 700, add to .gitignore
- Add .claude/ and *.pid to .gitignore
- Various adapter, router, and session improvements from prior work
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Prompt injection protection: external messages wrapped in [EXTERNAL CONTENT]
markers, system prompt instructs Claude to never follow external instructions
- Invocation logging: all Claude CLI calls logged with channel, model, duration,
token counts to echo-core.invoke logger
- Security logging: separate echo-core.security logger for unauthorized access
attempts (DMs from non-admins, unauthorized admin/owner commands)
- Security log routed to logs/security.log in addition to main log
- Extended echo doctor: Claude CLI functional check, config.json secret scan,
.gitignore completeness, file permissions, Ollama reachability, bot process
- Subprocess env stripping logged at debug level
373 tests pass (10 new security tests).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Semantic search over memory/*.md files using all-minilm embeddings.
Adds /search Discord command and `echo memory search/reindex` CLI.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
/model (show/change), /restart (owner), /logs, set_session_model API, model reset on /clear. 20 new tests (161 total).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>