@codefilabs/tq 0.0.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 +296 -0
- package/package.json +41 -0
- package/scripts/tq +419 -0
- package/scripts/tq-install.sh +78 -0
- package/scripts/tq-message +318 -0
- package/scripts/tq-setup +147 -0
- package/scripts/tq-telegram-poll +129 -0
- package/scripts/tq-telegram-watchdog +23 -0
- package/skills/tq/SKILL.md +108 -0
- package/skills/tq/references/cron-expressions.md +67 -0
- package/skills/tq/references/session-naming.md +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
# tq — Task Queue for Claude
|
|
2
|
+
|
|
3
|
+
A lightweight task queue runner that spawns Claude AI tasks as independent tmux sessions.
|
|
4
|
+
|
|
5
|
+
## What It Does
|
|
6
|
+
|
|
7
|
+
`tq` lets you define a list of Claude prompts in a YAML file and run them all as independent background jobs. Each prompt gets its own named tmux session running the `claude` CLI — you can attach to any session to watch progress, and detach without interrupting the work.
|
|
8
|
+
|
|
9
|
+
Tasks are idempotent: running `tq queue.yaml` again skips tasks that are already `done` or have a live `running` session. Task identity is derived from a SHA-256 hash of the prompt content, so changing a prompt text treats it as a new task while re-running unchanged prompts is always a no-op.
|
|
10
|
+
|
|
11
|
+
The tool is designed for macOS with cron scheduling in mind: drop a queue YAML in `~/.tq/queues/`, add a crontab line, and tasks run automatically every morning (or on whatever schedule you choose). Run `tq --status` to reap dead sessions and print a status table.
|
|
12
|
+
|
|
13
|
+
## Requirements
|
|
14
|
+
|
|
15
|
+
- macOS (uses `security` CLI for keychain access to Claude OAuth tokens)
|
|
16
|
+
- tmux (`brew install tmux`)
|
|
17
|
+
- `claude` CLI — [Claude Code](https://claude.ai/code) (`npm install -g @anthropic-ai/claude-code` or similar)
|
|
18
|
+
- python3 (macOS system Python is sufficient — stdlib only, no pip installs needed)
|
|
19
|
+
- Google Chrome with Claude Code extension installed
|
|
20
|
+
- `reattach-to-user-namespace` (optional, `brew install reattach-to-user-namespace` — fixes keychain access in tmux)
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
Run this in your terminal:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
curl -fsSL https://raw.githubusercontent.com/kevnk/tq/main/scripts/tq-install.sh | bash
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Here's exactly what that command does:
|
|
31
|
+
|
|
32
|
+
1. **Downloads the install script** from this repo over HTTPS (`-fsSL` = fail on error, silent, follow redirects) and pipes it directly to `bash` — nothing is saved to disk.
|
|
33
|
+
|
|
34
|
+
2. **Registers the tq marketplace** with Claude Code by running `claude plugin marketplace add kevnk/tq`. This clones the tq repo into `~/.claude/plugins/marketplaces/tq/` so Claude knows where to find it.
|
|
35
|
+
|
|
36
|
+
3. **Installs the tq plugin** by running `claude plugin install tq@tq`. This caches the plugin files into `~/.claude/plugins/cache/tq/tq/<version>/` and registers the plugin's skills and slash commands with Claude Code. After this, Claude will recognize commands like `/todo`, `/schedule`, `/jobs`, and `/health`.
|
|
37
|
+
|
|
38
|
+
4. **Symlinks `tq`** into `/opt/homebrew/bin` (Apple Silicon) or `/usr/local/bin` (Intel Mac) so the command is available in your shell and in cron jobs.
|
|
39
|
+
|
|
40
|
+
5. **Creates `~/.tq/queues/` and `~/.tq/logs/`** — the default directories for queue files and log output.
|
|
41
|
+
|
|
42
|
+
If `claude` is not on your PATH, steps 2–3 are skipped with a warning and only the CLI tools are installed.
|
|
43
|
+
|
|
44
|
+
To install the CLI tools to a custom location instead:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
curl -fsSL https://raw.githubusercontent.com/kevnk/tq/main/scripts/tq-install.sh | TQ_INSTALL_DIR=/usr/local/bin bash
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Quick Start
|
|
51
|
+
|
|
52
|
+
Create a queue file:
|
|
53
|
+
|
|
54
|
+
```yaml
|
|
55
|
+
# ~/.tq/queues/morning.yaml
|
|
56
|
+
cwd: /Users/yourname/projects/myapp
|
|
57
|
+
|
|
58
|
+
tasks:
|
|
59
|
+
- prompt: fix the login bug in the auth service
|
|
60
|
+
- prompt: write unit tests for the payment module
|
|
61
|
+
- prompt: |
|
|
62
|
+
Review the README and update it to reflect
|
|
63
|
+
the current API endpoints and authentication flow
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Run it:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
tq ~/.tq/queues/morning.yaml
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Output:
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
[spawned] tq-fix-the-login-451234 -- fix the login bug in the auth service
|
|
76
|
+
[spawned] tq-write-unit-test-451235 -- write unit tests for the payment module
|
|
77
|
+
[spawned] tq-review-the-readme-451236 -- Review the README and update it to reflect
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Check status:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
tq --status ~/.tq/queues/morning.yaml
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Output:
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
STATUS SESSION STARTED PROMPT
|
|
90
|
+
---------- ------------------------- ---------------------- ------
|
|
91
|
+
done tq-fix-the-login-451234 2026-03-06T09:01:02 fix the login bug in the auth service
|
|
92
|
+
running tq-write-unit-test-451235 2026-03-06T09:01:03 write unit tests for the payment module
|
|
93
|
+
running tq-review-the-readme-451236 2026-03-06T09:01:04 Review the README and update it to reflect
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Queue File Format
|
|
97
|
+
|
|
98
|
+
Queue files are standard YAML:
|
|
99
|
+
|
|
100
|
+
```yaml
|
|
101
|
+
cwd: /path/to/working/directory # sets working directory for each claude task
|
|
102
|
+
|
|
103
|
+
tasks:
|
|
104
|
+
# Inline prompt (single line)
|
|
105
|
+
- prompt: fix the login bug in auth service
|
|
106
|
+
|
|
107
|
+
# Named task — human-readable label for tmux session naming
|
|
108
|
+
- name: write-tests
|
|
109
|
+
prompt: write unit tests for the payment module
|
|
110
|
+
|
|
111
|
+
# Block literal (|) — preserves line breaks exactly
|
|
112
|
+
- prompt: |
|
|
113
|
+
Write comprehensive unit tests for the payment module.
|
|
114
|
+
Cover happy path and all error cases.
|
|
115
|
+
Use jest and mock the Stripe API.
|
|
116
|
+
|
|
117
|
+
# Block folded (>) — newlines become spaces (like a paragraph)
|
|
118
|
+
- prompt: >
|
|
119
|
+
Refactor the authentication service to use JWT tokens
|
|
120
|
+
instead of session cookies, updating all dependent endpoints.
|
|
121
|
+
|
|
122
|
+
# Quoted inline
|
|
123
|
+
- prompt: "update the README's installation section"
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Queue files are **never modified** by `tq` — they are read-only inputs.
|
|
127
|
+
|
|
128
|
+
### Notifications (optional)
|
|
129
|
+
|
|
130
|
+
Add a `message:` block to receive a notification when each task completes:
|
|
131
|
+
|
|
132
|
+
```yaml
|
|
133
|
+
cwd: /Users/yourname/projects/myapp
|
|
134
|
+
message:
|
|
135
|
+
service: telegram # telegram | slack
|
|
136
|
+
content: summary # summary | status | details | log
|
|
137
|
+
tasks:
|
|
138
|
+
- prompt: refactor the auth module
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Content types:**
|
|
142
|
+
- `summary` — Claude writes a 2–3 sentence digest of what it accomplished
|
|
143
|
+
- `status` — task name, done/failed, duration (no live Claude session needed)
|
|
144
|
+
- `details` — prompt first line, status, duration, hash
|
|
145
|
+
- `log` — last 200 lines of tmux pane scrollback
|
|
146
|
+
|
|
147
|
+
The `message:` block overrides the global config for that queue. Global credentials (bot tokens etc.) live in `~/.tq/config/message.yaml` — never in queue files. Run `/setup-telegram` to configure Telegram notifications interactively.
|
|
148
|
+
|
|
149
|
+
## Commands
|
|
150
|
+
|
|
151
|
+
### `tq <queue.yaml>`
|
|
152
|
+
|
|
153
|
+
Parses the queue file and spawns a new tmux session for each pending task.
|
|
154
|
+
|
|
155
|
+
- Skips tasks with `status=done`
|
|
156
|
+
- Skips tasks with `status=running` that have a live tmux session
|
|
157
|
+
- Flips tasks with `status=running` but a dead tmux session to `done`, then skips them
|
|
158
|
+
- Spawns all remaining (pending) tasks as new tmux sessions
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
tq ~/.tq/queues/morning.yaml
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### `tq --status <queue.yaml>`
|
|
165
|
+
|
|
166
|
+
Prints a formatted status table for all tasks in the queue. Also reaps any dead tmux sessions by flipping their state from `running` to `done`.
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
tq --status ~/.tq/queues/morning.yaml
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Run this via cron every 30 minutes to keep state accurate even if sessions die unexpectedly.
|
|
173
|
+
|
|
174
|
+
### `tq --prompt <text>`
|
|
175
|
+
|
|
176
|
+
Run a single ad-hoc prompt without a queue file. Useful for one-off tasks.
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
tq --prompt "fix the login bug in auth service" --cwd ~/projects/myapp --name fix-login
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Options:
|
|
183
|
+
- `--prompt <text>` — the prompt to run (required for this mode)
|
|
184
|
+
- `--cwd <dir>` — working directory (defaults to `~/.tq/workspace`)
|
|
185
|
+
- `--name <name>` — label for tmux session naming (defaults to `adhoc`)
|
|
186
|
+
- `--notify <type>` — completion notification: `macos`, `bell`, or a path to a shell script
|
|
187
|
+
|
|
188
|
+
## How It Works
|
|
189
|
+
|
|
190
|
+
**Step 1 — Parse**: `tq` runs an embedded Python script (written to a temp file) that reads the queue YAML and generates three files per task, all named by an 8-character SHA-256 hash of the prompt:
|
|
191
|
+
|
|
192
|
+
- `<hash>.prompt` — the raw prompt text
|
|
193
|
+
- `<hash>.launch.py` — a small Python launcher that `execvp`s into `claude` (replacing itself with the claude process so the tmux window ends up running claude directly)
|
|
194
|
+
- `~/.tq/sessions/<hash>/settings.json` — Claude settings registering a Stop hook
|
|
195
|
+
|
|
196
|
+
**Step 2 — Auth capture**: The Python parser reads the Claude OAuth token from the macOS keychain (`security find-generic-password -s 'Claude Code-credentials'`) and bakes it into the launcher script. This means each task has its credentials embedded and can run unattended even in a cron context.
|
|
197
|
+
|
|
198
|
+
**Step 3 — Spawn**: For each pending task, `tq` creates a named tmux session (`tq-<slug>-<epoch>`) and sends `python3 <hash>.launch.py` to it via `tmux send-keys`. The launcher runs inside the tmux window, then `execvp`s into `claude --dangerously-skip-permissions --chrome <prompt>`, replacing itself so the window ends up running a live `claude` session.
|
|
199
|
+
|
|
200
|
+
**Step 4 — Completion**: When `claude` finishes, the Stop hook (`on-stop.sh`) fires automatically and updates the task's state file: `status=running` → `status=done`. The next `tq` run will skip this task.
|
|
201
|
+
|
|
202
|
+
## Claude Code Plugin
|
|
203
|
+
|
|
204
|
+
`tq` ships with a Claude skill definition at `skills/tq/SKILL.md`. Install it into Claude by copying or symlinking the `skills/tq/` directory into `~/.claude/skills/tq/`.
|
|
205
|
+
|
|
206
|
+
Once installed, Claude can manage your task queues via slash commands:
|
|
207
|
+
|
|
208
|
+
| Command | Purpose |
|
|
209
|
+
|---------|---------|
|
|
210
|
+
| `/init [dirs...]` | Scan workspace directories and build a project catalog for `cwd:` lookup |
|
|
211
|
+
| `/todo <natural language>` | Create or update a queue and optionally schedule it |
|
|
212
|
+
| `/schedule <natural language>` | Add or update a cron schedule for a queue |
|
|
213
|
+
| `/pause <queue>` | Remove the run cron line (keep status-check) |
|
|
214
|
+
| `/unschedule <queue>` | Remove all cron lines for a queue |
|
|
215
|
+
| `/jobs` | List all scheduled tq cron jobs |
|
|
216
|
+
| `/health` | System-wide diagnostics |
|
|
217
|
+
| `/setup-telegram` | Interactive wizard to configure Telegram notifications |
|
|
218
|
+
| `/install` | Symlink tq binaries to PATH |
|
|
219
|
+
|
|
220
|
+
Claude will infer the queue name from context: "every morning" → `morning.yaml`, "daily" → `daily.yaml`, or the current directory's basename if no schedule keyword is present.
|
|
221
|
+
|
|
222
|
+
### `/init` — Workspace setup
|
|
223
|
+
|
|
224
|
+
Run `/init` once per machine to tell tq where your projects live:
|
|
225
|
+
|
|
226
|
+
```
|
|
227
|
+
/init ~/Sites ~/Projects
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
This scans the given directories for git repositories, writes `~/.tq/config/workspaces.yaml` (which directories to scan), and generates `~/.tq/workspace-map.md` (a catalog of every discovered project with its path and type). Re-run `/init` anytime to refresh after cloning new repos.
|
|
231
|
+
|
|
232
|
+
Once initialized, `/todo` uses the workspace map to resolve project names in natural language — e.g. "fix the login bug in myapp" will automatically set `cwd:` to myapp's full path.
|
|
233
|
+
|
|
234
|
+
## State Files
|
|
235
|
+
|
|
236
|
+
State is stored in `.tq/` directories adjacent to the queue YAML file:
|
|
237
|
+
|
|
238
|
+
```
|
|
239
|
+
~/.tq/queues/
|
|
240
|
+
├── morning.yaml ← your queue file
|
|
241
|
+
└── .tq/
|
|
242
|
+
└── morning/
|
|
243
|
+
├── a1b2c3d4 ← task state file (key=value)
|
|
244
|
+
├── a1b2c3d4.prompt ← raw prompt text
|
|
245
|
+
├── a1b2c3d4.launch.py ← generated launcher (contains OAuth token)
|
|
246
|
+
└── ...
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Each state file looks like:
|
|
250
|
+
|
|
251
|
+
```
|
|
252
|
+
status=done
|
|
253
|
+
session=tq-fix-the-login-451234
|
|
254
|
+
window=fix-the
|
|
255
|
+
prompt=fix the login bug in auth service
|
|
256
|
+
started=2026-03-06T09:01:02
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
**Resetting tasks:**
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
# Reset one task (tq will re-run it next time)
|
|
263
|
+
rm ~/.tq/queues/.tq/morning/a1b2c3d4
|
|
264
|
+
|
|
265
|
+
# Reset entire queue
|
|
266
|
+
rm -rf ~/.tq/queues/.tq/morning/
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## Security Notes
|
|
270
|
+
|
|
271
|
+
The `.tq/` directories contain live OAuth tokens written in plaintext into `*.launch.py` launcher files at runtime. These files are ephemeral and local-only, but:
|
|
272
|
+
|
|
273
|
+
- **Never commit `.tq/` directories to git** — they contain your Claude auth tokens
|
|
274
|
+
- Add `.tq/` to your `.gitignore` if your queue files are inside a git repository
|
|
275
|
+
|
|
276
|
+
The `--dangerously-skip-permissions` flag is passed to every Claude session. This is required for unattended automation — without it, Claude would prompt for permission confirmations that no human is present to answer.
|
|
277
|
+
|
|
278
|
+
## Scheduling
|
|
279
|
+
|
|
280
|
+
Add cron entries to run your queues automatically:
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
crontab -e
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
```cron
|
|
287
|
+
# Run morning queue at 9am daily
|
|
288
|
+
0 9 * * * /opt/homebrew/bin/tq ~/.tq/queues/morning.yaml >> ~/.tq/logs/tq.log 2>&1
|
|
289
|
+
|
|
290
|
+
# Sweep dead sessions every 30 minutes (keeps status accurate)
|
|
291
|
+
*/30 * * * * /opt/homebrew/bin/tq --status ~/.tq/queues/morning.yaml >> ~/.tq/logs/tq.log 2>&1
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
Logs accumulate in `~/.tq/logs/tq.log`.
|
|
295
|
+
|
|
296
|
+
See `skills/tq/references/cron-expressions.md` for a natural language → cron expression reference.
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@codefilabs/tq",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "A lightweight task queue runner that spawns Claude AI tasks as independent tmux sessions",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"claude",
|
|
7
|
+
"ai",
|
|
8
|
+
"tmux",
|
|
9
|
+
"queue",
|
|
10
|
+
"automation",
|
|
11
|
+
"task-runner",
|
|
12
|
+
"cron"
|
|
13
|
+
],
|
|
14
|
+
"homepage": "https://github.com/CodefiLabs/tq#readme",
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/CodefiLabs/tq/issues"
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/CodefiLabs/tq.git"
|
|
21
|
+
},
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"bin": {
|
|
24
|
+
"tq": "./scripts/tq",
|
|
25
|
+
"tq-message": "./scripts/tq-message",
|
|
26
|
+
"tq-setup": "./scripts/tq-setup",
|
|
27
|
+
"tq-telegram-poll": "./scripts/tq-telegram-poll",
|
|
28
|
+
"tq-telegram-watchdog": "./scripts/tq-telegram-watchdog"
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"scripts/",
|
|
32
|
+
"skills/",
|
|
33
|
+
"README.md"
|
|
34
|
+
],
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=18"
|
|
37
|
+
},
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
}
|
|
41
|
+
}
|