- Add /model command to switch models per-session (persisted in metadata)
- Support aliases: sonnet, opus, haiku → full model IDs
- Add load_persona_for_session() helper that applies model override
- Increase asyncio subprocess stdout buffer to 10MB (fixes crash on
large stream-json lines from image tool results)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix typing indicator not showing: clean up stale typing tasks between
messages and use dynamic event lookup in callbacks instead of capturing
a specific event at creation time
- Fix stream-json input format: use nested message object for stdin NDJSON
- Switch --system-prompt to --append-system-prompt so Claude Code's
default system prompt (with model identity) is preserved
- Add --dangerously-skip-permissions for full tool access in subprocess
- Use full model ID (claude-sonnet-4-5-20250929) in default persona
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create MessageBatcher class for debounce-based message batching
- Update make_callbacks() to include on_tool_use with progress notifications
- Add typing indicator support with stop_event control
- Implement smart message splitting with MarkdownV2 escaping
- Update handle_message() to use typing and batching
- Update handle_photo() and handle_document() to save to session directories
- Add auto-analysis for photos and file upload notifications
- Update session switching and archiving to handle typing and batchers
- Replace fresh-process-per-turn with persistent subprocess model
- Accept NDJSON messages on stdin via --input-format stream-json
- Emit stream-json events on stdout including tool_use events
- Add on_tool_use callback for progress notifications
- Persistent stdout/stderr readers run for process lifetime
- Result events mark not busy but don't exit reader loop
- stdin.write + drain pattern prevents pipe buffer deadlock
- Auto-start process if not running when send_message called
- Crash recovery restarts persistent process with --continue
Instruments the full message pipeline with [TIMING] log entries:
- Message age (Telegram delivery delay)
- Subprocess state (cold-start vs reused)
- Process spawn, first stdout, first assistant text
- Telegram send latency, total wall time
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Persona JSON nests model and max_turns under "settings" but the
subprocess was looking for them at the top level, so --model and
--max-turns were never passed to claude CLI.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Archives session directory with tar+pigz to sessions_archive/,
terminates any running subprocess first, clears active session if needed.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Only auto-restart on positive exit codes (genuine crashes), not negative
return codes (signals like SIGTERM from our own process management)
- Add iscoroutinefunction check for on_error in crash handler max-retry path
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The telegram/ directory's __init__.py shadowed the python-telegram-bot pip
package. Remove __init__.py and use direct sibling imports instead.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add /new and /session commands to create and switch sessions
- Route plain text messages to active session's Claude subprocess
- Auto-spawn subprocess when switching to session with no process
- Update help text with session commands
- Handle async callbacks in ClaudeSubprocess (inspect.iscoroutinefunction)
- Preserve all existing bot commands (/status, /pbs, etc.)
- Use block=False for non-blocking message handling
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Spawns Claude Code CLI with stream-json output in session directories
- Reads stdout/stderr concurrently via asyncio.gather (no pipe deadlock)
- Handles process lifecycle with clean termination (no zombies)
- Queues messages during processing using asyncio.Queue
- Auto-restarts on crash with --continue flag (max 3 retries)
- Parses stream-json events (assistant, result, system) to callbacks
- Supports persona configuration (system_prompt, model, max_turns)
- Uses terminate() + wait_for() + kill() fallback pattern
Based on research: .planning/phases/01-session-process-foundation/01-RESEARCH.md
- Four persona templates: default, brainstorm, planner, research
- JSON schema: name, description, system_prompt, settings
- Each persona has distinct system_prompt for different modes
- Settings include model and max_turns configuration
- Fix SessionManager paths to use homelab directory
- SessionManager class with session lifecycle management
- Session CRUD: create, list, switch, get, update
- Session validation: alphanumeric, hyphens, underscores only
- Persona inheritance from library on session creation
- Session status tracking: idle, active, suspended
- Metadata persistence with JSON on disk
- Active session tracking and switching logic
- Telegram bot (@georgsen_homelab_bot) for two-way communication
- Commands: /status, /pbs, /backups, /beszel, /kuma, /ping
- Photos and files saved to inbox for Claude to read
- Runs as systemd user service
- Shared storage via ZFS bind mounts
- rpool/shared/mikkel on PVE host
- Mounted to ~/stuff in mgmt, dev, general containers
- SMB access via \\mgmt\stuff (Tailscale MagicDNS)
- Updated helper scripts list in CLAUDE.md
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>