Overview
Add real-time streaming to tri-bot so Claude responses appear progressively in Telegram instead of waiting for the full response.
Requirements
Streaming (sendMessageDraft)
- Spawn
claude -p with --output-format stream-json
- Set
.stdout_behavior = .Pipe on std.process.Child
- Read NDJSON lines from stdout:
type: "stream_event", event.delta.type: "text_delta"
- Accumulate text, call
sendMessageDraft every 500ms
- Final
sendMessage when Claude finishes
/stop command
- Track active
std.process.Child in SharedState
/stop sends SIGTERM to the child process
- Send confirmation: "⛔ Claude process stopped"
Two-thread architecture
- Main thread: Telegram polling (getUpdates → dispatch)
- Worker thread: Claude process + streaming
- Shared state via
std.atomic.Value(bool) for is_busy
const SharedState = struct {
active_child: ?*std.process.Child = null,
is_busy: std.atomic.Value(bool) = std.atomic.Value(bool).init(false),
};
Files to modify
| File |
Change |
NEW claude_stream.zig |
Spawn + pipe + NDJSON parse + sendMessageDraft |
MODIFY bot_loop.zig |
std.Thread.spawn() for /ask, SharedState |
MODIFY handlers.zig |
/stop kills active_child |
Acceptance criteria
Depends on: #54
Overview
Add real-time streaming to tri-bot so Claude responses appear progressively in Telegram instead of waiting for the full response.
Requirements
Streaming (
sendMessageDraft)claude -pwith--output-format stream-json.stdout_behavior = .Pipeonstd.process.Childtype: "stream_event",event.delta.type: "text_delta"sendMessageDraftevery 500mssendMessagewhen Claude finishes/stopcommandstd.process.ChildinSharedState/stopsends SIGTERM to the child processTwo-thread architecture
std.atomic.Value(bool)foris_busyFiles to modify
claude_stream.zigbot_loop.zigstd.Thread.spawn()for /ask, SharedStatehandlers.zigAcceptance criteria
/askshows progressive text in Telegram (streaming)/stopkills running Claude processDepends on: #54