Commit graph

22 commits

Author SHA1 Message Date
06c52466f2 feat(03-02): add /timeout and /sessions commands
- Added timeout_cmd() to set per-session idle timeout (1-120 min range)
  - Shows current timeout when called without args
  - Updates session metadata and existing idle timer
- Added sessions_cmd() to list all sessions with status
  - Shows LIVE (subprocess running) or IDLE (suspended) status
  - Displays persona and relative last-active time (e.g., '2m ago')
  - Marks current active session with arrow
- Registered both commands in main()
- Commands already added to help text in Task 1

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 23:37:30 +00:00
6ebdb4a555 feat(03-02): wire suspend/resume lifecycle with race locks, startup cleanup, and graceful shutdown
- Added suspend_session() callback for idle timer (terminates subprocess, updates metadata to suspended, silent)
- Added get_subprocess_lock() helper to prevent race between timeout and user message
- Updated handle_message/handle_photo/handle_document with resume logic (detects suspended, shows 'Resuming session...', spawns with --continue)
- Added idle timer reset in on_complete callback (timer only starts after Claude finishes)
- Added idle timer reset on user activity (message/photo/document)
- Updated new_session() to initialize idle timer after subprocess creation
- Updated switch_session_cmd() to initialize idle timer when auto-spawning subprocess
- Updated archive_session_cmd() to cancel idle timer and remove subprocess lock
- Updated model_cmd() to cancel idle timer when terminating subprocess
- Added cleanup_orphaned_subprocesses() to kill orphaned PIDs verified via /proc/cmdline at startup
- Added post_init() callback for startup cleanup
- Added post_shutdown() callback for graceful shutdown (terminates all subprocesses, cancels all timers)
- Updated help text with new commands

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 23:36:43 +00:00
74f12a13fc feat(03-01): extend session metadata and PID tracking
- Add idle_timeout field (default 600s) to session metadata
- Add get_session_timeout() helper to SessionManager
- Add pid property to ClaudeSubprocess for PID tracking
- Enables lifecycle management to query timeout values and track process PIDs
2026-02-04 23:28:40 +00:00
488d94ebcf feat(03-01): create SessionIdleTimer module
- Asyncio-based per-session idle timeout detection
- reset() method updates timestamp and creates new timer task
- cancel() method stops timer on shutdown/archive
- Properties for seconds_since_activity and last_activity
- Automatic callback firing after configurable timeout
2026-02-04 23:28:04 +00:00
ce76f18485 docs: add /model and session commands to help text and CLAUDE.md
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 22:43:49 +00:00
0bca340920 feat(02-02): add /model command and fix stdout buffer overflow
- 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>
2026-02-04 22:42:23 +00:00
2d0d4da992 fix(02-02): typing indicator lifecycle, model identity, tool permissions
- 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>
2026-02-04 22:10:02 +00:00
f246d18fa0 feat(02-02): integrate typing indicators, batching, and file handling
- 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
2026-02-04 19:24:09 +00:00
6b624d7f80 feat(02-01): create telegram_utils with message formatting
- Add split_message_smart: code-block-aware message splitting at 4000 chars
- Add escape_markdown_v2: escape 17 special chars outside code blocks
- Add typing_indicator_loop: re-send typing every 4s with asyncio.Event
- Smart splitting respects triple-backtick and single-backtick boundaries
- Never splits inside code blocks (preserves syntax)
- Regex pattern identifies code regions for selective escaping
2026-02-04 19:17:20 +00:00
6a115a4947 refactor(02-01): persistent subprocess with stream-json I/O
- 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
2026-02-04 19:15:46 +00:00
d878931e79 feat(01-03): add timing profiler for response latency debugging
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>
2026-02-04 18:30:05 +00:00
2302b75e14 fix(01-02): read model/max_turns from persona settings object
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>
2026-02-04 18:18:38 +00:00
faab47afbd feat(01-01): restructure personas with pipeline workflow
- default: generic helpful assistant
- homelab: infrastructure management (was default)
- brainstorm: creative ideation → produces BRAINSTORM.md with
  vision, MVP, v1.0, v2.0 feature sets
- planner: takes BRAINSTORM.md → produces PRD, BRD, SoW
- research: unchanged

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 18:13:21 +00:00
3fec4ed848 fix(01-01): update persona models to claude-sonnet-4-5-20250929
Plans hardcoded an outdated model. Updated all 4 personas to Sonnet 4.5.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 18:06:08 +00:00
a27ac010ec feat(01-03): add /archive command to compress and remove sessions
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>
2026-02-04 18:01:14 +00:00
3cc97adcd0 fix(01-03): don't treat SIGTERM as crash, fix async callbacks in crash handler
- 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>
2026-02-04 17:58:27 +00:00
d08f3527cd fix(01-03): fix import collision between local telegram/ and pip package
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>
2026-02-04 17:57:22 +00:00
3a62e01f6f feat(01-03): wire session manager and Claude subprocess into Telegram bot
- 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>
2026-02-04 17:40:43 +00:00
8fce10c5ba feat(01-02): create ClaudeSubprocess module for process management
- 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
2026-02-04 17:33:49 +00:00
ba8acf00b3 feat(01-01): create persona library with default templates
- 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
2026-02-04 17:33:16 +00:00
447855ceec feat(01-01): create SessionManager module
- 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
2026-02-04 17:32:16 +00:00
c50c348004 Add Telegram bot and shared storage documentation
- 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>
2026-01-16 14:21:51 +00:00