- Auth: move from state.json to SQLite authed_chats table, with memory cache
- Remove Persistent/state.json, all state now in noc.db
- HTTP API: POST /api/chat (end-to-end LLM), GET /api/logs (failed API requests)
- API logging: store raw request/response for 400 errors in api_log table
- Agent completion: spawn_agent sends LifeEvent::AgentDone via channel,
life loop picks up with full conversation context and responds
- Config structs: derive Clone for HTTP server
- System prompt: instruct LLM not to add timestamps
- Makefile: rsync without --delete to preserve VPS-only tools
- Configurable backend: claude (CLI) or openai (API), selected in config.yaml
- OpenAI streaming via SSE with conversation history in memory
- Session isolation: config name included in session UUID
- Markdown to Telegram HTML conversion (pulldown-cmark) for final messages
- Fix sendMessageDraft: skip cursor to preserve monotonic text growth,
skip empty content chunks from SSE stream
- Simplify Makefile: single deploy target
- Streaming: use claude --output-format stream-json, edit TG message
every 5s with progress, show tool use status during execution,
◎ cursor indicator while processing
- File transfer: download user uploads to ~/incoming/, scan
~/outgoing/{sid}/ for new files after claude completes
- Error handling: wrap post-auth logic in handle_inner, all errors
reply to user instead of silently failing
- Remote deploy: make deploy-hera via SSH, generate service from
template with dynamic PATH/REPO
- Service: binary installed to ~/bin/noc, WorkingDirectory=%h
- Invoke claude directly instead of ms wrapper
- Session state persisted to disk across restarts
Async Rust bot (teloxide + tokio) that:
- Authenticates users per chat with a passphrase (resets daily at 5am)
- Generates deterministic UUID v5 session IDs from chat_id + date
- Pipes messages to `claude -p --session-id/--resume <uuid>`
- Persists auth and session state to disk across restarts
- Deploys as systemd --user service via `make deploy`