@worldbreakstudios/cc-eye-watcher
v0.0.1
Published
Transcript watcher for Claude Code Observer (cc-eye)
Maintainers
Readme
Transcript Watcher
The transcript watcher monitors Claude Code session transcript files and automatically uploads new messages to the Convex database via the observer API.
Installation
NPM (Recommended)
npm install -g @worldbreakstudios/cc-eye-watcherNPX (No Installation)
npx @worldbreakstudios/cc-eye-watcher --transcript-path /path/to/transcript.jsonl --session-id abc123Local Development
cd hook-watcher
chmod +x index.js
./index.js --transcript-path /path/to/transcript.jsonl --session-id abc123Setup
1. Set Environment Variables
export OBSERVER_AUTH_TOKEN="your-auth-token-here"
export OBSERVER_API_URL="http://localhost:3000/api/events" # optional, defaults to localhostYou can generate an auth token in the main app:
cd app
npm run generate-token2. Configure Claude Code Hook
The transcript watcher needs to know:
- transcript_path: Path to the Claude session transcript file
- session_id: The Claude session ID
These are typically provided by Claude Code hooks when a session starts.
Usage
Running Manually
cc-eye-watcher \
--transcript-path /path/to/transcript.jsonl \
--session-id abc123-session-idRunning as a Background Service
You can run the watcher in the background for each active Claude session:
# Start watcher in background
nohup cc-eye-watcher \
--transcript-path ~/.claude/sessions/abc123/transcript.jsonl \
--session-id abc123 \
> /tmp/transcript-watcher-abc123.log 2>&1 &
# Save the process ID
echo $! > /tmp/transcript-watcher-abc123.pidStopping the Watcher
# If you saved the PID
kill $(cat /tmp/transcript-watcher-abc123.pid)
# Or find and kill manually
ps aux | grep cc-eye-watcher
kill <PID>How It Works
- File Watching: The script polls the transcript file every second (configurable)
- Incremental Reading: Only reads new content since the last check (tracks file position)
- Message Parsing: Parses JSONL format messages with
roleandcontent - API Upload: Sends each message to Convex via the
/api/eventsendpoint as aTranscriptMessageevent
Transcript Format
The watcher expects transcript files in JSONL format (one JSON object per line):
{"role":"user","content":"Hello, can you help me?","timestamp":1234567890}
{"role":"assistant","content":"Of course! What do you need?","timestamp":1234567891}Event Data
Each transcript message is uploaded as a TranscriptMessage event with:
{
session_id: string,
hook_event_name: "TranscriptMessage",
cwd: string,
transcript_path: string,
timestamp: number,
message_role: "user" | "assistant",
message_content: string
}Integration with Claude Code
To automatically start the transcript watcher for each Claude session, you can create a hook that:
- Captures the
SessionStartevent - Extracts
transcript_pathandsession_id - Starts the transcript watcher as a background process
- Stops the watcher on
SessionEnd
Example hook script:
#!/bin/bash
# ~/.claude/hooks/session_start.sh
EVENT_DATA=$(cat)
SESSION_ID=$(echo "$EVENT_DATA" | jq -r '.session_id')
TRANSCRIPT_PATH=$(echo "$EVENT_DATA" | jq -r '.transcript_path')
if [ -n "$TRANSCRIPT_PATH" ] && [ -n "$SESSION_ID" ]; then
nohup cc-eye-watcher \
--transcript-path "$TRANSCRIPT_PATH" \
--session-id "$SESSION_ID" \
> "/tmp/transcript-watcher-$SESSION_ID.log" 2>&1 &
echo $! > "/tmp/transcript-watcher-$SESSION_ID.pid"
fiTroubleshooting
Messages Not Appearing
- Check the watcher is running:
ps aux | grep cc-eye-watcher - Check the log file for errors
- Verify environment variables are set
- Test the API manually:
curl -X POST http://localhost:3000/api/events \ -H "Authorization: your-token" \ -H "Content-Type: application/json" \ -d '{"session_id":"test","hook_event_name":"TranscriptMessage","cwd":"/tmp","message_role":"user","message_content":"test"}'
High CPU Usage
The default poll interval is 1 second. You can modify the code to increase it:
const watcher = new TranscriptWatcher({
transcriptPath,
sessionId,
pollInterval: 5000, // Poll every 5 seconds
});Development
Testing
# Create a test transcript file
echo '{"role":"user","content":"test message"}' > /tmp/test-transcript.jsonl
# Run the watcher
cc-eye-watcher --transcript-path /tmp/test-transcript.jsonl --session-id test
# In another terminal, append a new message
echo '{"role":"assistant","content":"response message"}' >> /tmp/test-transcript.jsonlLicense
MIT
