@codefilabs/tq 0.0.2 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +100 -3
- package/package.json +4 -1
- package/scripts/tq +126 -17
- package/scripts/tq-converse +726 -0
- package/scripts/tq-cron-sync +92 -0
- package/scripts/tq-install.sh +75 -11
- package/scripts/tq-message +96 -27
- package/scripts/tq-setup +1 -1
- package/scripts/tq-telegram-poll +216 -34
- package/skills/tq/SKILL.md +42 -6
- package/skills/tq/references/session-naming.md +16 -0
package/scripts/tq-telegram-poll
CHANGED
|
@@ -5,14 +5,23 @@ export PATH="/opt/homebrew/bin:/usr/local/bin:$PATH"
|
|
|
5
5
|
|
|
6
6
|
CONFIG_FILE="$HOME/.tq/config/message.yaml"
|
|
7
7
|
OFFSET_FILE="$HOME/.tq/telegram-poll-offset"
|
|
8
|
+
ORCHESTRATOR_SESSION="tq-orchestrator"
|
|
9
|
+
DAEMON_MODE=0
|
|
10
|
+
POLL_TIMEOUT=0
|
|
11
|
+
|
|
12
|
+
if [[ "${1:-}" == "--daemon" ]]; then
|
|
13
|
+
DAEMON_MODE=1
|
|
14
|
+
POLL_TIMEOUT=30
|
|
15
|
+
fi
|
|
8
16
|
|
|
9
17
|
# --- Read config ---
|
|
10
18
|
if [[ ! -f "$CONFIG_FILE" ]]; then
|
|
11
19
|
exit 0
|
|
12
20
|
fi
|
|
13
21
|
|
|
14
|
-
CONFIG_SCRIPT=$(mktemp /tmp/tq-poll-config-XXXXXX
|
|
15
|
-
|
|
22
|
+
CONFIG_SCRIPT=$(mktemp /tmp/tq-poll-config-XXXXXX)
|
|
23
|
+
PROCESS_SCRIPT=$(mktemp /tmp/tq-poll-process-XXXXXX)
|
|
24
|
+
trap 'rm -f "$CONFIG_SCRIPT" "$PROCESS_SCRIPT"' EXIT
|
|
16
25
|
|
|
17
26
|
cat > "$CONFIG_SCRIPT" <<'PYEOF'
|
|
18
27
|
import sys, os, re, json
|
|
@@ -51,27 +60,6 @@ print(json.dumps({
|
|
|
51
60
|
}))
|
|
52
61
|
PYEOF
|
|
53
62
|
|
|
54
|
-
CONFIG_JSON="$(python3 "$CONFIG_SCRIPT" "$CONFIG_FILE")"
|
|
55
|
-
BOT_TOKEN="$(python3 -c "import sys,json; print(json.loads(sys.argv[1]).get('bot_token',''))" "$CONFIG_JSON")"
|
|
56
|
-
USER_ID="$(python3 -c "import sys,json; print(json.loads(sys.argv[1]).get('user_id',''))" "$CONFIG_JSON")"
|
|
57
|
-
|
|
58
|
-
if [[ -z "$BOT_TOKEN" || -z "$USER_ID" ]]; then
|
|
59
|
-
exit 0
|
|
60
|
-
fi
|
|
61
|
-
|
|
62
|
-
# --- Read offset ---
|
|
63
|
-
OFFSET=0
|
|
64
|
-
if [[ -f "$OFFSET_FILE" ]]; then
|
|
65
|
-
OFFSET="$(cat "$OFFSET_FILE")"
|
|
66
|
-
fi
|
|
67
|
-
|
|
68
|
-
# --- Fetch updates ---
|
|
69
|
-
UPDATES="$(curl -s "https://api.telegram.org/bot${BOT_TOKEN}/getUpdates?offset=${OFFSET}&limit=10&timeout=0" 2>&1)"
|
|
70
|
-
|
|
71
|
-
# --- Process updates ---
|
|
72
|
-
PROCESS_SCRIPT=$(mktemp /tmp/tq-poll-process-XXXXXX.py)
|
|
73
|
-
trap 'rm -f "$CONFIG_SCRIPT" "$PROCESS_SCRIPT"' EXIT
|
|
74
|
-
|
|
75
63
|
cat > "$PROCESS_SCRIPT" <<'PYEOF'
|
|
76
64
|
import sys, json
|
|
77
65
|
|
|
@@ -100,8 +88,11 @@ for update in results:
|
|
|
100
88
|
if text:
|
|
101
89
|
chat_id = msg['chat']['id']
|
|
102
90
|
message_id = msg['message_id']
|
|
103
|
-
#
|
|
104
|
-
|
|
91
|
+
# Extract reply_to_message_id if present
|
|
92
|
+
reply_to = msg.get('reply_to_message', {}).get('message_id', '')
|
|
93
|
+
# Output: chat_id<TAB>message_id<TAB>reply_to<TAB>text
|
|
94
|
+
# Use '-' placeholder for empty reply_to (bash read collapses consecutive tabs)
|
|
95
|
+
messages.append(f"{chat_id}\t{message_id}\t{reply_to or '-'}\t{text}")
|
|
105
96
|
|
|
106
97
|
if new_offset is not None:
|
|
107
98
|
with open(offset_file, 'w') as f:
|
|
@@ -111,19 +102,210 @@ for m in messages:
|
|
|
111
102
|
print(m)
|
|
112
103
|
PYEOF
|
|
113
104
|
|
|
114
|
-
|
|
105
|
+
CONFIG_JSON="$(python3 "$CONFIG_SCRIPT" "$CONFIG_FILE")"
|
|
106
|
+
BOT_TOKEN="$(python3 -c "import sys,json; print(json.loads(sys.argv[1]).get('bot_token',''))" "$CONFIG_JSON")"
|
|
107
|
+
USER_ID="$(python3 -c "import sys,json; print(json.loads(sys.argv[1]).get('user_id',''))" "$CONFIG_JSON")"
|
|
108
|
+
|
|
109
|
+
if [[ -z "$BOT_TOKEN" || -z "$USER_ID" ]]; then
|
|
110
|
+
exit 0
|
|
111
|
+
fi
|
|
112
|
+
|
|
113
|
+
# --- Read offset ---
|
|
114
|
+
OFFSET=0
|
|
115
|
+
if [[ -f "$OFFSET_FILE" ]]; then
|
|
116
|
+
OFFSET="$(cat "$OFFSET_FILE")"
|
|
117
|
+
fi
|
|
118
|
+
|
|
119
|
+
# --- Handle Telegram commands ---
|
|
120
|
+
handle_command() {
|
|
121
|
+
local cmd="$1"
|
|
122
|
+
local chat_id="$2"
|
|
123
|
+
|
|
124
|
+
case "$cmd" in
|
|
125
|
+
/converse|/converse\ *)
|
|
126
|
+
if [[ "$ORCHESTRATOR_ACTIVE" == "1" ]]; then
|
|
127
|
+
curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
|
|
128
|
+
-d "chat_id=${chat_id}" \
|
|
129
|
+
--data-urlencode "text=Orchestrator already running. Just send messages — they'll be routed automatically." \
|
|
130
|
+
> /dev/null 2>&1 || true
|
|
131
|
+
else
|
|
132
|
+
if command -v tq-converse &>/dev/null; then
|
|
133
|
+
tq-converse start 2>&1 || true
|
|
134
|
+
ORCHESTRATOR_ACTIVE=1
|
|
135
|
+
curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
|
|
136
|
+
-d "chat_id=${chat_id}" \
|
|
137
|
+
--data-urlencode "text=Orchestrator started. Send messages and they'll be routed to the right conversation." \
|
|
138
|
+
> /dev/null 2>&1 || true
|
|
139
|
+
fi
|
|
140
|
+
fi
|
|
141
|
+
return 0
|
|
142
|
+
;;
|
|
143
|
+
/stop)
|
|
144
|
+
if command -v tq-converse &>/dev/null; then
|
|
145
|
+
tq-converse stop 2>&1 || true
|
|
146
|
+
ORCHESTRATOR_ACTIVE=0
|
|
147
|
+
curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
|
|
148
|
+
-d "chat_id=${chat_id}" \
|
|
149
|
+
--data-urlencode "text=Orchestrator stopped." \
|
|
150
|
+
> /dev/null 2>&1 || true
|
|
151
|
+
fi
|
|
152
|
+
return 0
|
|
153
|
+
;;
|
|
154
|
+
/stop\ *)
|
|
155
|
+
local SLUG="${cmd#/stop }"
|
|
156
|
+
if command -v tq-converse &>/dev/null; then
|
|
157
|
+
tq-converse stop "$SLUG" 2>&1 || true
|
|
158
|
+
curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
|
|
159
|
+
-d "chat_id=${chat_id}" \
|
|
160
|
+
--data-urlencode "text=Session '$SLUG' stopped." \
|
|
161
|
+
> /dev/null 2>&1 || true
|
|
162
|
+
fi
|
|
163
|
+
return 0
|
|
164
|
+
;;
|
|
165
|
+
/status)
|
|
166
|
+
if command -v tq-converse &>/dev/null; then
|
|
167
|
+
local STATUS_TEXT
|
|
168
|
+
STATUS_TEXT="$(tq-converse status 2>&1 || true)"
|
|
169
|
+
curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
|
|
170
|
+
-d "chat_id=${chat_id}" \
|
|
171
|
+
--data-urlencode "text=${STATUS_TEXT}" \
|
|
172
|
+
> /dev/null 2>&1 || true
|
|
173
|
+
fi
|
|
174
|
+
return 0
|
|
175
|
+
;;
|
|
176
|
+
/list)
|
|
177
|
+
if command -v tq-converse &>/dev/null; then
|
|
178
|
+
local LIST_TEXT
|
|
179
|
+
LIST_TEXT="$(tq-converse list 2>&1 || true)"
|
|
180
|
+
curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
|
|
181
|
+
-d "chat_id=${chat_id}" \
|
|
182
|
+
--data-urlencode "text=${LIST_TEXT}" \
|
|
183
|
+
> /dev/null 2>&1 || true
|
|
184
|
+
fi
|
|
185
|
+
return 0
|
|
186
|
+
;;
|
|
187
|
+
esac
|
|
188
|
+
return 1
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
# --- poll_once: fetch and process a single batch of updates ---
|
|
192
|
+
poll_once() {
|
|
193
|
+
local UPDATES MESSAGES
|
|
194
|
+
|
|
195
|
+
UPDATES="$(curl -s --max-time $((POLL_TIMEOUT + 10)) "https://api.telegram.org/bot${BOT_TOKEN}/getUpdates?offset=${OFFSET}&limit=10&timeout=${POLL_TIMEOUT}" 2>&1)"
|
|
196
|
+
|
|
197
|
+
MESSAGES="$(python3 "$PROCESS_SCRIPT" "$UPDATES" "$USER_ID" "$OFFSET_FILE")"
|
|
198
|
+
|
|
199
|
+
# Re-read offset (python may have updated it)
|
|
200
|
+
if [[ -f "$OFFSET_FILE" ]]; then
|
|
201
|
+
OFFSET="$(cat "$OFFSET_FILE")"
|
|
202
|
+
fi
|
|
203
|
+
|
|
204
|
+
if [[ -z "$MESSAGES" ]]; then
|
|
205
|
+
return 0
|
|
206
|
+
fi
|
|
207
|
+
|
|
208
|
+
# Check if orchestrator is running
|
|
209
|
+
ORCHESTRATOR_ACTIVE=0
|
|
210
|
+
if tmux has-session -t "$ORCHESTRATOR_SESSION" 2>/dev/null; then
|
|
211
|
+
ORCHESTRATOR_ACTIVE=1
|
|
212
|
+
fi
|
|
213
|
+
|
|
214
|
+
mkdir -p "$HOME/.tq/workspace"
|
|
115
215
|
|
|
116
|
-
|
|
117
|
-
|
|
216
|
+
while IFS=$'\t' read -r CHAT_ID MSG_ID REPLY_TO MSG; do
|
|
217
|
+
if [[ -z "$MSG" ]]; then
|
|
218
|
+
continue
|
|
219
|
+
fi
|
|
220
|
+
|
|
221
|
+
echo "[tq-telegram-poll] message: ${MSG:0:60}"
|
|
118
222
|
|
|
119
|
-
while IFS=$'\t' read -r CHAT_ID MSG_ID MSG; do
|
|
120
|
-
if [[ -n "$MSG" ]]; then
|
|
121
|
-
echo "[tq-telegram-poll] prompt: ${MSG:0:60}"
|
|
122
223
|
# React with 👀 to acknowledge receipt
|
|
123
224
|
curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/setMessageReaction" \
|
|
124
225
|
-H "Content-Type: application/json" \
|
|
125
226
|
--data-raw "{\"chat_id\":${CHAT_ID},\"message_id\":${MSG_ID},\"reaction\":[{\"type\":\"emoji\",\"emoji\":\"👀\"}]}" \
|
|
126
227
|
> /dev/null 2>&1 || true
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
228
|
+
|
|
229
|
+
# Check for Telegram commands first
|
|
230
|
+
if [[ "$MSG" == /* ]]; then
|
|
231
|
+
if handle_command "$MSG" "$CHAT_ID"; then
|
|
232
|
+
continue
|
|
233
|
+
fi
|
|
234
|
+
fi
|
|
235
|
+
|
|
236
|
+
# --- Routing logic (3-tier) ---
|
|
237
|
+
|
|
238
|
+
# Store the latest message ID for reply threading
|
|
239
|
+
echo "$MSG_ID" > "$HOME/.tq/conversations/latest-msg-id" 2>/dev/null || true
|
|
240
|
+
echo "$CHAT_ID" > "$HOME/.tq/conversations/latest-chat-id" 2>/dev/null || true
|
|
241
|
+
|
|
242
|
+
ROUTED=0
|
|
243
|
+
|
|
244
|
+
# Normalize placeholder
|
|
245
|
+
[[ "$REPLY_TO" == "-" ]] && REPLY_TO=""
|
|
246
|
+
|
|
247
|
+
# Tier 1: Telegram reply → deterministic routing via registry
|
|
248
|
+
if [[ -n "$REPLY_TO" && "$ORCHESTRATOR_ACTIVE" == "1" ]]; then
|
|
249
|
+
SLUG="$(tq-converse lookup-msg "$REPLY_TO" 2>/dev/null || true)"
|
|
250
|
+
if [[ -n "$SLUG" ]]; then
|
|
251
|
+
CHILD_SESSION="tq-conv-${SLUG}"
|
|
252
|
+
if tmux has-session -t "$CHILD_SESSION" 2>/dev/null; then
|
|
253
|
+
echo "[tq-telegram-poll] reply-routing to: $SLUG (via msg $REPLY_TO)"
|
|
254
|
+
tq-converse track-msg "$SLUG" "$MSG_ID"
|
|
255
|
+
# Store msg_id for this session's reply threading
|
|
256
|
+
echo "$MSG_ID" > "$HOME/.tq/conversations/sessions/$SLUG/reply-to-msg-id" 2>/dev/null || true
|
|
257
|
+
tq-converse route "$SLUG" "$MSG"
|
|
258
|
+
ROUTED=1
|
|
259
|
+
fi
|
|
260
|
+
fi
|
|
261
|
+
fi
|
|
262
|
+
|
|
263
|
+
# Tier 2: Explicit #slug prefix → deterministic routing
|
|
264
|
+
if [[ "$ROUTED" == "0" && "$MSG" == \#* && "$ORCHESTRATOR_ACTIVE" == "1" ]]; then
|
|
265
|
+
# Extract slug from #slug-name prefix
|
|
266
|
+
SLUG="$(echo "$MSG" | sed 's/^#\([a-z0-9-]*\).*/\1/')"
|
|
267
|
+
ACTUAL_MSG="$(echo "$MSG" | sed 's/^#[a-z0-9-]* *//')"
|
|
268
|
+
if [[ -n "$SLUG" && -n "$ACTUAL_MSG" ]]; then
|
|
269
|
+
CHILD_SESSION="tq-conv-${SLUG}"
|
|
270
|
+
if tmux has-session -t "$CHILD_SESSION" 2>/dev/null; then
|
|
271
|
+
echo "[tq-telegram-poll] explicit routing to: $SLUG"
|
|
272
|
+
tq-converse track-msg "$SLUG" "$MSG_ID"
|
|
273
|
+
echo "$MSG_ID" > "$HOME/.tq/conversations/sessions/$SLUG/reply-to-msg-id" 2>/dev/null || true
|
|
274
|
+
tq-converse route "$SLUG" "$ACTUAL_MSG"
|
|
275
|
+
ROUTED=1
|
|
276
|
+
fi
|
|
277
|
+
fi
|
|
278
|
+
fi
|
|
279
|
+
|
|
280
|
+
# Tier 3: Orchestrator routing (smart, Claude-powered)
|
|
281
|
+
if [[ "$ROUTED" == "0" && "$ORCHESTRATOR_ACTIVE" == "1" ]]; then
|
|
282
|
+
echo "[tq-telegram-poll] routing via orchestrator"
|
|
283
|
+
# Format message with metadata for the orchestrator
|
|
284
|
+
FORMATTED_MSG="[tq-msg msg_id=${MSG_ID} chat_id=${CHAT_ID}"
|
|
285
|
+
if [[ -n "$REPLY_TO" ]]; then
|
|
286
|
+
FORMATTED_MSG="${FORMATTED_MSG} reply_to=${REPLY_TO}"
|
|
287
|
+
fi
|
|
288
|
+
FORMATTED_MSG="${FORMATTED_MSG}]
|
|
289
|
+
${MSG}"
|
|
290
|
+
tq-converse send "$FORMATTED_MSG"
|
|
291
|
+
ROUTED=1
|
|
292
|
+
fi
|
|
293
|
+
|
|
294
|
+
# Fallback: no orchestrator — spawn one-off task (legacy behavior)
|
|
295
|
+
if [[ "$ROUTED" == "0" ]]; then
|
|
296
|
+
echo "[tq-telegram-poll] no orchestrator — spawning one-off task"
|
|
297
|
+
tq --no-chrome --prompt "$MSG"
|
|
298
|
+
fi
|
|
299
|
+
|
|
300
|
+
done <<< "$MESSAGES" || true
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
# --- Main: single run or daemon loop ---
|
|
304
|
+
if [[ "$DAEMON_MODE" == "1" ]]; then
|
|
305
|
+
echo "[tq-telegram-poll] daemon started (long-poll timeout=${POLL_TIMEOUT}s)"
|
|
306
|
+
while true; do
|
|
307
|
+
poll_once || true
|
|
308
|
+
done
|
|
309
|
+
else
|
|
310
|
+
poll_once
|
|
311
|
+
fi
|
package/skills/tq/SKILL.md
CHANGED
|
@@ -3,10 +3,11 @@ name: tq
|
|
|
3
3
|
description: >
|
|
4
4
|
This skill should be used when the user asks to "add to queue", "run queue", "queue these tasks",
|
|
5
5
|
"schedule with tq", "tq status", "check task queue", "create a tq queue", "set up cron for tq",
|
|
6
|
-
"run claude in background", "batch prompts in tmux",
|
|
7
|
-
|
|
8
|
-
"tmux queue", "scheduled claude tasks"
|
|
9
|
-
|
|
6
|
+
"run claude in background", "batch prompts in tmux", "start a conversation", "converse via telegram",
|
|
7
|
+
"telegram conversation mode", or wants to manage Claude prompts running in tmux sessions via the
|
|
8
|
+
tq CLI tool. Triggers on phrases like "queue", "tq", "task queue", "tmux queue", "scheduled claude tasks",
|
|
9
|
+
"conversation mode", "telegram chat", "converse".
|
|
10
|
+
version: 1.1.0
|
|
10
11
|
---
|
|
11
12
|
|
|
12
13
|
# tq — Claude Task Queue Runner
|
|
@@ -17,8 +18,9 @@ Installed to PATH via `/install`: `/opt/homebrew/bin/tq`
|
|
|
17
18
|
|
|
18
19
|
## Overview
|
|
19
20
|
|
|
20
|
-
tq
|
|
21
|
-
|
|
21
|
+
tq manages Claude Code sessions via tmux in two modes:
|
|
22
|
+
1. **Queue mode** — batches prompts into YAML queue files, spawns each as an independent tmux session. Idempotent — running `tq` again skips `done` and live `running` tasks.
|
|
23
|
+
2. **Conversation mode** — persistent interactive Claude Code sessions orchestrated via Telegram. An orchestrator routes messages to the right conversation, creating new sessions or resuming existing ones.
|
|
22
24
|
|
|
23
25
|
## Queue File Format
|
|
24
26
|
|
|
@@ -59,6 +61,9 @@ Statuses: `pending` → `running` → `done`
|
|
|
59
61
|
| `/jobs [filter]` | List all scheduled tq cron jobs |
|
|
60
62
|
| `/health [queue]` | System-wide diagnostics |
|
|
61
63
|
| `/install` | Symlink tq binaries to PATH |
|
|
64
|
+
| `/converse [start\|stop\|status]` | Manage Telegram conversation sessions |
|
|
65
|
+
| `/tq-reply` | Send response back to Telegram (conversation mode) |
|
|
66
|
+
| `/setup-telegram` | Configure Telegram bot token and notifications |
|
|
62
67
|
|
|
63
68
|
## CLI Usage
|
|
64
69
|
|
|
@@ -102,6 +107,37 @@ The Claude extension stores the browser name as `bridgeDisplayName` in the exten
|
|
|
102
107
|
- Right-click the Claude extension icon in the Chrome toolbar → **Options**
|
|
103
108
|
- Or open the sidepanel and look for a settings/gear icon with a name field
|
|
104
109
|
|
|
110
|
+
## Conversation Mode
|
|
111
|
+
|
|
112
|
+
Start an orchestrator: `tq-converse start` or send `/converse` from Telegram.
|
|
113
|
+
|
|
114
|
+
The orchestrator routes incoming Telegram messages to the appropriate conversation session:
|
|
115
|
+
- Telegram reply to a known message → routes to that session automatically
|
|
116
|
+
- `#slug message` → routes to the named session
|
|
117
|
+
- New topic → orchestrator spawns a new session with a descriptive slug
|
|
118
|
+
|
|
119
|
+
Each conversation is a persistent Claude Code interactive session in its own tmux window.
|
|
120
|
+
Child sessions use `/tq-reply` to send responses back to Telegram as threaded replies.
|
|
121
|
+
|
|
122
|
+
### Conversation CLI
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
tq-converse start # start orchestrator
|
|
126
|
+
tq-converse spawn <slug> --cwd <dir> # new conversation session
|
|
127
|
+
tq-converse route <slug> <message> # send to a session
|
|
128
|
+
tq-converse list # list active sessions
|
|
129
|
+
tq-converse stop [<slug>] # stop session or orchestrator
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Telegram Commands
|
|
133
|
+
|
|
134
|
+
| Command | Purpose |
|
|
135
|
+
|---------|---------|
|
|
136
|
+
| `/converse` | Start the orchestrator |
|
|
137
|
+
| `/stop [slug]` | Stop orchestrator or a specific session |
|
|
138
|
+
| `/status` | Show all sessions |
|
|
139
|
+
| `/list` | List active conversations |
|
|
140
|
+
|
|
105
141
|
## Additional Resources
|
|
106
142
|
|
|
107
143
|
- **`references/session-naming.md`** — Session/window name generation algorithm and examples
|
|
@@ -48,3 +48,19 @@ WINDOW="$(echo "$PROMPT" | awk '{print $1" "$2}' \
|
|
|
48
48
|
- Epoch suffix prevents collision when the same prompt is re-queued after a reset
|
|
49
49
|
- tmux session names must not contain `.` or `:` — the character replacement handles this
|
|
50
50
|
- The `-` separator between base and epoch is always present; if the base ends with `-`, it gets stripped first to avoid `--`
|
|
51
|
+
|
|
52
|
+
## Conversation Mode Session Names
|
|
53
|
+
|
|
54
|
+
Conversation sessions use a different naming scheme — slug-based, no epoch suffix:
|
|
55
|
+
|
|
56
|
+
| Type | Pattern | Example |
|
|
57
|
+
|------|---------|---------|
|
|
58
|
+
| Orchestrator | `tq-orchestrator` (fixed) | `tq-orchestrator` |
|
|
59
|
+
| Child session | `tq-conv-<slug>` | `tq-conv-fix-auth` |
|
|
60
|
+
| Child window | `<slug>` | `fix-auth` |
|
|
61
|
+
|
|
62
|
+
Slugs are short kebab-case names (2-4 words) chosen by the orchestrator Claude when a
|
|
63
|
+
new conversation is created. Examples: `fix-auth-bug`, `refactor-api`, `update-docs`.
|
|
64
|
+
|
|
65
|
+
Since there is no epoch suffix, conversation session names are unique by slug. Starting
|
|
66
|
+
a session with an already-active slug will reuse the existing session.
|