@spoolway/win32-x64 0.1.0 → 0.3.0
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 +167 -92
- package/bin/spoolway.exe +0 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,7 +5,13 @@
|
|
|
5
5
|
</picture>
|
|
6
6
|
</p>
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
<p align="center">
|
|
9
|
+
<a href="LICENSE"><img alt="license" src="https://img.shields.io/github/license/marvingygas/spoolway?style=flat-square&label=license&labelColor=3f3f46&color=18181b"></a>
|
|
10
|
+
<a href="https://github.com/marvingygas/spoolway/actions/workflows/ci.yml"><img alt="ci" src="https://img.shields.io/github/actions/workflow/status/marvingygas/spoolway/ci.yml?branch=main&style=flat-square&label=ci&labelColor=3f3f46"></a>
|
|
11
|
+
<a href="https://github.com/marvingygas/spoolway/releases/latest"><img alt="release" src="https://img.shields.io/github/v/release/marvingygas/spoolway?style=flat-square&label=release&labelColor=3f3f46&color=18181b"></a>
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
Minimalistic command line state machine for turning coding agents into a pipeline you can actually reason about. No dependencies, terminal native. Runs headless or in a supported multiplexer. Manages worktrees and opens GitHub stacked pull requests.
|
|
9
15
|
|
|
10
16
|
Supported providers:
|
|
11
17
|
|
|
@@ -20,34 +26,33 @@ Supported multiplexers:
|
|
|
20
26
|
|
|
21
27
|
## Why
|
|
22
28
|
|
|
23
|
-
Running one coding agent is easy. Running five is
|
|
24
|
-
|
|
25
|
-
in your head, and it stops the moment you look away.
|
|
29
|
+
Running one coding agent is easy. Running five is hard: which one is done, which one is
|
|
30
|
+
stuck, and which one is rewriting a file another one needs. The order lives in your head.
|
|
26
31
|
|
|
27
|
-
|
|
28
|
-
|
|
32
|
+
spoolway replaces the orchestrating agent that keeps everything together. It has no model
|
|
33
|
+
inside, so it never surprises you with a bill or an opinion.
|
|
29
34
|
|
|
30
35
|
## Features
|
|
31
36
|
|
|
32
|
-
- **A dispatcher with no model in it.** Every scheduling decision is
|
|
33
|
-
|
|
34
|
-
and is safe to interrupt at any point.
|
|
37
|
+
- **A dispatcher with no model in it.** Every scheduling decision is a counter, a
|
|
38
|
+
timestamp, or a position in the pipeline file. It costs nothing and is safe to interrupt.
|
|
35
39
|
- **Any mix of agents.** Each step names its own agent and model: a local model for
|
|
36
|
-
implementation, a cloud model for review, a shell command for the
|
|
37
|
-
- **A worktree per task.** Every task
|
|
38
|
-
|
|
40
|
+
implementation, a cloud model for review, a shell command for the tests.
|
|
41
|
+
- **A worktree per task.** Every task works on its own branch in its own checkout.
|
|
42
|
+
Parallel tasks never touch each other's files.
|
|
39
43
|
- **Stacked pull requests.** A dependent task's branch is cut from its dependency's
|
|
40
|
-
branch
|
|
41
|
-
|
|
42
|
-
- **Session reuse.** A step can resume its prompt's earlier conversation
|
|
43
|
-
|
|
44
|
-
- **Unattended runs.** Overnight,
|
|
45
|
-
|
|
46
|
-
- **Trials.** Fork
|
|
47
|
-
arms
|
|
48
|
-
- **Routines.** Keep the tasks you run
|
|
49
|
-
- **
|
|
50
|
-
|
|
44
|
+
branch. A chain of tasks arrives as one ordered stack of PRs. You land the stack.
|
|
45
|
+
Optional, driven by **`spoolway stack`**.
|
|
46
|
+
- **Session reuse.** A step can resume its prompt's earlier conversation. It stops
|
|
47
|
+
reusing when the model's window is too full.
|
|
48
|
+
- **Unattended runs.** Overnight, an unblocker prompt resumes blocked work. A token or
|
|
49
|
+
dollar ceiling stops the run.
|
|
50
|
+
- **Trials.** Fork a group into one arm per task, each on its own pipeline, and compare
|
|
51
|
+
the arms in eval.
|
|
52
|
+
- **Routines.** Keep the tasks you run more than once in `.spoolway/routines/`.
|
|
53
|
+
- **Jobs.** Run a routine on a cron schedule. A running dispatcher fires it.
|
|
54
|
+
- **Eval built in.** Every lane's spend and outcome go into a ledger. You see what your
|
|
55
|
+
last pipeline edit did to pass rate and price.
|
|
51
56
|
|
|
52
57
|
## Install
|
|
53
58
|
|
|
@@ -55,8 +60,9 @@ sometimes does. spoolway won't surprise you with a bill or an opinion.
|
|
|
55
60
|
npm install -g spoolway
|
|
56
61
|
```
|
|
57
62
|
|
|
58
|
-
|
|
59
|
-
|
|
63
|
+
The package is a small wrapper around a prebuilt binary. It runs on Linux (x64, arm64,
|
|
64
|
+
musl), macOS (Apple Silicon, Intel) and Windows (x64, experimental). `spoolway update` shows
|
|
65
|
+
what changed, and `spoolway whats-new` prints the release notes offline.
|
|
60
66
|
|
|
61
67
|
From source instead, in a clone of this repository:
|
|
62
68
|
|
|
@@ -74,24 +80,20 @@ Platform notes and requirements in full: **[Installation and setup](docs/install
|
|
|
74
80
|
spoolway init
|
|
75
81
|
```
|
|
76
82
|
|
|
77
|
-
`spoolway doctor` checks that everything the configured pipeline needs is
|
|
78
|
-
present, any time you want to confirm the project would run.
|
|
83
|
+
`spoolway doctor` checks that everything the configured pipeline needs is present.
|
|
79
84
|
|
|
80
85
|
### 2. Plan, or create queueable spoolway tasks directly
|
|
81
86
|
|
|
82
|
-
Tell the `/spoolway-plan` skill what you want built. It
|
|
83
|
-
|
|
84
|
-
cuts the plan into tasks.
|
|
87
|
+
Tell the `/spoolway-plan` skill what you want built. It talks the shape through with you
|
|
88
|
+
and writes one plan page. Approve the page and it cuts the plan into tasks.
|
|
85
89
|
|
|
86
90
|
<img src="docs/screenshots/plan.png" alt="a plan page written by /spoolway-plan">
|
|
87
91
|
|
|
88
|
-
|
|
89
|
-
documents straight away.
|
|
92
|
+
If you already know the shape, `/spoolway-tasks` cuts the task documents straight away.
|
|
90
93
|
|
|
91
|
-
**Both skills are optional.** A task is
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
the frontmatter a task document must carry:
|
|
94
|
+
**Both skills are optional.** A task is a Markdown file in `~/.spoolway/<project>/pending/`.
|
|
95
|
+
An issue exporter, a script, or any model can write one. This command prints the
|
|
96
|
+
frontmatter a task document must carry:
|
|
95
97
|
|
|
96
98
|
```
|
|
97
99
|
spoolway task contract
|
|
@@ -105,10 +107,10 @@ spoolway queue
|
|
|
105
107
|
|
|
106
108
|
<img src="docs/screenshots/queue.png" alt="the queue screen">
|
|
107
109
|
|
|
108
|
-
*The queue screen lists
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
110
|
+
*The queue screen lists groups on the left and the selected group's tasks on the right.
|
|
111
|
+
Each task names its own pipeline. `enter` queues what is checked and offers to start
|
|
112
|
+
dispatching. `g` gates a task, `p` forks a group into a trial, `s` saves a group as a
|
|
113
|
+
routine, and `r` opens the routines in `.spoolway/routines/`.*
|
|
112
114
|
|
|
113
115
|
### 4. Dispatch
|
|
114
116
|
|
|
@@ -118,32 +120,30 @@ spoolway dispatch # watch the board, and step in only where you are needed
|
|
|
118
120
|
|
|
119
121
|
<img src="docs/screenshots/dispatch.png" alt="the dispatcher board">
|
|
120
122
|
|
|
121
|
-
*One row per task, grouped by `group:`. The board
|
|
122
|
-
|
|
123
|
-
|
|
123
|
+
*One row per task, grouped by `group:`. The board shows what each lane is spending, what
|
|
124
|
+
every queued task waits on, and which tasks are paused for you. NEXT tells a lane holding a
|
|
125
|
+
question apart from a task waiting at a gate. The bottom line shows the slots in use and
|
|
126
|
+
every scheduled job with its next firing.*
|
|
124
127
|
|
|
125
128
|
Every task on the board is in one of a few states:
|
|
126
129
|
|
|
127
130
|
| State | Meaning |
|
|
128
131
|
|---|---|
|
|
129
132
|
| `queued` | Waiting for its dependencies and a free slot. |
|
|
130
|
-
| `running` | An agent is working the task's current step
|
|
131
|
-
| `
|
|
132
|
-
| `
|
|
133
|
-
| `blocked` | Something needs a person. |
|
|
133
|
+
| `running` | An agent is working the task's current step, or it has just moved there and a lane is starting. |
|
|
134
|
+
| `paused` | Waiting for you on purpose: a gate, a question in its pane, or a park. `r` on the board resumes it. |
|
|
135
|
+
| `blocked` | A step reported a block, or ran out of loops. Read the task's `## Blocker`, then `spoolway resume`. An unattended run hands it to the unblocker prompt instead. |
|
|
134
136
|
| `unreachable` | A task it depends on is blocked, so it cannot start until you clear that one. |
|
|
135
137
|
| `done` | Finished: the branch is handed over, the worktree removed, the task archived. |
|
|
136
138
|
|
|
137
139
|
### 5. Calibrate
|
|
138
140
|
|
|
139
|
-
The `/spoolway-calibrate` skill reads your archived tasks
|
|
140
|
-
|
|
141
|
-
|
|
141
|
+
The `/spoolway-calibrate` skill reads your archived tasks, their step-level evaluation results
|
|
142
|
+
and the spend ledger. It compares them with the prompts, pipelines and settings that produced
|
|
143
|
+
them. The comparison explains review failures, blocked sessions and wasted loops.
|
|
142
144
|
|
|
143
|
-
It walks each finding with you, with the
|
|
144
|
-
|
|
145
|
-
everything else. This is how a pipeline that blocks constantly turns into one that runs
|
|
146
|
-
unattended.
|
|
145
|
+
It walks each finding with you, with the numbers behind it. It applies the prompt and pipeline
|
|
146
|
+
changes you pick.
|
|
147
147
|
|
|
148
148
|
## A task is what travels the line, and you define it
|
|
149
149
|
|
|
@@ -164,8 +164,8 @@ depends_on:
|
|
|
164
164
|
## References
|
|
165
165
|
```
|
|
166
166
|
|
|
167
|
-
**The frontmatter is spoolway's, the body is yours.** spoolway never reads the body
|
|
168
|
-
|
|
167
|
+
**The frontmatter is spoolway's, the body is yours.** spoolway never reads the body. The
|
|
168
|
+
agent works from it, and you own the skeleton it is written from.
|
|
169
169
|
|
|
170
170
|
## The pipeline is a file
|
|
171
171
|
|
|
@@ -181,7 +181,7 @@ steps:
|
|
|
181
181
|
description: Write the code to satisfy the task's acceptance criteria.
|
|
182
182
|
agent: pi
|
|
183
183
|
prompt: implementer
|
|
184
|
-
model:
|
|
184
|
+
model: Ornith-1.5-35B-A3B
|
|
185
185
|
session: true
|
|
186
186
|
on_pass: review
|
|
187
187
|
on_fail: blocked
|
|
@@ -202,7 +202,7 @@ steps:
|
|
|
202
202
|
description: Bring the domain documents in line with what this task changed.
|
|
203
203
|
agent: pi
|
|
204
204
|
prompt: archivist
|
|
205
|
-
model:
|
|
205
|
+
model: Ornith-1.5-35B-A3B
|
|
206
206
|
on_pass: handover
|
|
207
207
|
on_fail: blocked
|
|
208
208
|
|
|
@@ -221,75 +221,150 @@ steps:
|
|
|
221
221
|
on_fail: blocked
|
|
222
222
|
```
|
|
223
223
|
|
|
224
|
-
**You do not have to write one by hand.** The `/spoolway-
|
|
225
|
-
for you
|
|
224
|
+
**You do not have to write one by hand.** The `/spoolway-config` skill writes and edits
|
|
225
|
+
pipelines for you.
|
|
226
226
|
|
|
227
|
-
##
|
|
227
|
+
## Jobs
|
|
228
|
+
|
|
229
|
+
A job runs a routine on a schedule. It has three parts: a cron expression, a pipeline, and a
|
|
230
|
+
routine saved under `.spoolway/routines/`.
|
|
231
|
+
|
|
232
|
+
The dispatcher fires a due job at the start of its pass. While any job is enabled, the
|
|
233
|
+
dispatcher stays up on an empty queue. A `spoolway dispatch` left running overnight is all a
|
|
234
|
+
job needs.
|
|
235
|
+
|
|
236
|
+
```
|
|
237
|
+
spoolway jobs # the screen: write, edit, pause, delete, or fire a job
|
|
238
|
+
spoolway jobs list # every job, its schedule, and when it fires next
|
|
239
|
+
spoolway jobs run <name> # fire one now, ignoring its schedule
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
<img src="docs/screenshots/jobs.png" alt="the jobs screen">
|
|
228
243
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
244
|
+
*The jobs screen. `n` asks for three things: the routine, the cron expression, and the
|
|
245
|
+
pipeline. A job fires once per matching minute. It skips a window while its previous run is
|
|
246
|
+
still in the queue. A window that passes while no dispatcher runs is not caught up later.*
|
|
247
|
+
|
|
248
|
+
A job is a few lines of TOML in `~/.spoolway/<project>/jobs.toml`. Put one in
|
|
249
|
+
`.spoolway/jobs.toml` inside the checkout to share it with the team.
|
|
232
250
|
|
|
233
251
|
```toml
|
|
234
|
-
|
|
252
|
+
[jobs.nightly-audit]
|
|
253
|
+
schedule = "0 3 * * 1-5" # weekdays at 03:00, local time
|
|
254
|
+
pipeline = "impl_fast"
|
|
255
|
+
routine = "nightly" # a folder or a single .md under .spoolway/routines/
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Routines
|
|
259
|
+
|
|
260
|
+
A routine is work you run more than once. It lives in `.spoolway/routines/`, tracked in git.
|
|
261
|
+
Press `s` on a group in the queue screen to save it there, and `r` to browse and queue what is
|
|
262
|
+
saved. Every queued copy gets a fresh id, so a routine can run again. The saved files are
|
|
263
|
+
never changed.
|
|
264
|
+
|
|
265
|
+
### Trials
|
|
266
|
+
|
|
267
|
+
A trial answers one question: which pipeline does this task best? Press `p` on a group in the
|
|
268
|
+
queue screen, pick a pipeline per task, and tick any steps to skip. Every task becomes one arm
|
|
269
|
+
under its chosen pipeline, and all arms share one trial id. Compare them with
|
|
270
|
+
`spoolway eval --runs --trial <id>`. An arm never pushes a branch or opens a pull request. When
|
|
271
|
+
the last arm finishes, every arm's copy is removed. The source group and the ledger rows stay.
|
|
272
|
+
|
|
273
|
+
## Issue tracker
|
|
274
|
+
|
|
275
|
+
Event hooks sync tasks with an issue tracker. Sample scripts for GitHub and Jira ship with `spoolway init`.
|
|
276
|
+
|
|
277
|
+
| Event | When it fires |
|
|
278
|
+
|---|---|
|
|
279
|
+
| `fetch` | `spoolway issue show <ref>` reads one issue out of the tracker |
|
|
280
|
+
| `open` | `spoolway queue add` opens a ticket per document |
|
|
281
|
+
| `queued` | A task arrives in the queue |
|
|
282
|
+
| `blocked` | A task comes to rest on `blocked` |
|
|
283
|
+
| `paused` | A task arrives on the persisted `paused` stage; a live-step row whose public state is `paused` does not fire it |
|
|
284
|
+
| `done` | A task finishes |
|
|
235
285
|
|
|
286
|
+
**The two shipped scripts are samples.** `spoolway init` writes `github.sh` and `jira.sh` into
|
|
287
|
+
`.spoolway/hooks/`. A native Windows install gets the `.ps1` pair.
|
|
288
|
+
|
|
289
|
+
See **[Issue Tracking](docs/configuration.md#issue_tracking--a-hook-fired-on-four-task-events)**.
|
|
290
|
+
|
|
291
|
+
## Configurable per project
|
|
292
|
+
|
|
293
|
+
- Unattended mode hands **`blocked`** tasks to a prompt you define, so the pipeline keeps
|
|
294
|
+
running while nobody is watching.
|
|
295
|
+
- Set a model for generating pipelines.
|
|
296
|
+
|
|
297
|
+
```toml
|
|
236
298
|
[dispatch]
|
|
237
299
|
backend = "herdr" # herdr, tmux, or headless
|
|
238
300
|
herdr_mode = "split" # "split": a workspace per task; "grouped": one shared tab, a pane per task
|
|
239
|
-
|
|
301
|
+
tmux_mode = "grouped" # "grouped": one session for the run; "split": a session per task
|
|
302
|
+
worktree_root = "" # where a task's worktree is cut; blank is ~/.spoolway/<project>/worktrees
|
|
303
|
+
interval = "10s" # how long the dispatcher waits between passes
|
|
240
304
|
lane_quiet = "15m" # silence before a lane is reminded to report
|
|
241
305
|
default_pipeline = "default" # which pipeline a task runs when it names none
|
|
242
|
-
auto_commit = true
|
|
306
|
+
auto_commit = true # commit a lane's leftover work when its step settles
|
|
243
307
|
|
|
244
308
|
[unattended]
|
|
245
309
|
enabled = true # the overnight switch
|
|
246
|
-
max_output_tokens = 0 #
|
|
310
|
+
max_output_tokens = 0 # output-token ceiling for a run with nobody watching; 0 is none
|
|
311
|
+
max_cost_usd = 0.0 # dollar ceiling for the same run; 0 is none
|
|
247
312
|
skip_blocked_lane = true # a cleared block carries the task past the step it blocked on
|
|
248
313
|
blocked_agent = "claude" # who staffs `blocked` when nobody is at the keyboard
|
|
249
314
|
blocked_model = "claude-opus-5"
|
|
250
315
|
blocked_effort = "medium"
|
|
316
|
+
blocked_session = true # the unblocker carries its own earlier session forward
|
|
251
317
|
blocked_prompt = "unblocker"
|
|
252
318
|
|
|
253
319
|
[pipeline_gen]
|
|
254
320
|
pipeline_agent = "claude" # who `spoolway pipeline gen` opens its session as
|
|
255
321
|
pipeline_model = "claude-opus-5"
|
|
256
322
|
pipeline_effort = "medium"
|
|
257
|
-
pipeline_auto = false # false asks before writing the pipeline
|
|
258
|
-
pipeline_local_models = false
|
|
259
323
|
|
|
260
|
-
[
|
|
261
|
-
|
|
324
|
+
[housekeeping]
|
|
325
|
+
update_check = true # tell a person at a keyboard that a newer release is out
|
|
326
|
+
calibrate_window = "14d" # how far back `/spoolway-calibrate` reads
|
|
327
|
+
retention_days = 30 # how long run records and archived tasks are kept; 0 keeps everything
|
|
328
|
+
price_max_age_days = 30 # how old the price table may be before `spoolway doctor` says so
|
|
262
329
|
|
|
263
|
-
[
|
|
264
|
-
|
|
330
|
+
[agents.claude]
|
|
331
|
+
kind = "claude"
|
|
332
|
+
concurrency = 3 # most lanes of this profile at once
|
|
333
|
+
session_reuse_ctx = 50 # % of the window before a carried session restarts fresh
|
|
334
|
+
session_blocked_ctx = 0 # % of the window at which a running lane is stopped and blocked; 0 is off
|
|
335
|
+
permission_mode = "auto"
|
|
265
336
|
|
|
266
|
-
[
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
337
|
+
[agents.codex]
|
|
338
|
+
kind = "codex"
|
|
339
|
+
concurrency = 3
|
|
340
|
+
session_reuse_ctx = 50
|
|
341
|
+
session_blocked_ctx = 0
|
|
342
|
+
permission_mode = "never"
|
|
270
343
|
|
|
271
344
|
[agents.pi]
|
|
272
345
|
kind = "pi"
|
|
273
|
-
session_reuse_ctx = 50 # % of the window before a carried session restarts fresh
|
|
274
|
-
|
|
275
|
-
[agents.claude]
|
|
276
|
-
kind = "claude"
|
|
277
|
-
concurrency = 3
|
|
278
346
|
session_reuse_ctx = 50
|
|
279
|
-
|
|
347
|
+
session_blocked_ctx = 0
|
|
280
348
|
|
|
281
|
-
[models."
|
|
349
|
+
[models."Ornith-1.5-35B-A3B"] # a local model, served by llama.cpp
|
|
282
350
|
context_window = 100096
|
|
283
|
-
slots =
|
|
351
|
+
slots = 2 # parallel lanes the local server can actually hold
|
|
284
352
|
exclusive = true # never alongside another exclusive model
|
|
353
|
+
local = true # runs on hardware you own
|
|
354
|
+
|
|
355
|
+
[issue_tracking]
|
|
356
|
+
hook = "" # a script in .spoolway/hooks/, e.g. "github.sh"; blank runs none
|
|
357
|
+
project_key = "" # handed to the hook verbatim, e.g. owner/repo
|
|
358
|
+
on_fail = "ignore" # what a failing hook does: ignore it, or pause the task
|
|
359
|
+
key_in_names = false # prefix branch and worktree names with the tracker's slug
|
|
285
360
|
```
|
|
286
361
|
|
|
287
362
|
See **[Configuration](docs/configuration.md)**.
|
|
288
363
|
|
|
289
364
|
## Eval every run
|
|
290
365
|
|
|
291
|
-
|
|
292
|
-
time, and what the lane reported. Every edit to your pipelines, prompts or config
|
|
366
|
+
When a lane finishes, its transcript is read and written to a ledger: tokens, cost, wall
|
|
367
|
+
time, and what the lane reported. Every edit to your pipelines, prompts or config creates a
|
|
293
368
|
new version, so you can see what your last change did to pass rate and price.
|
|
294
369
|
|
|
295
370
|
```
|
|
@@ -298,13 +373,13 @@ spoolway eval
|
|
|
298
373
|
|
|
299
374
|
<img src="docs/screenshots/eval.png" alt="the eval screen">
|
|
300
375
|
|
|
301
|
-
*The eval screen on its runs view, one row per attempt at a task
|
|
302
|
-
|
|
303
|
-
|
|
376
|
+
*The eval screen on its runs view, one row per attempt at a task. `tab` cycles the views: per
|
|
377
|
+
pipeline, per step, runs, per watched directory, and per session outside the lanes. `f` filters,
|
|
378
|
+
`e` exports CSV.*
|
|
304
379
|
|
|
305
380
|
## Documentation
|
|
306
381
|
|
|
307
|
-
See **[Documentation index](DOCS.md)**.
|
|
382
|
+
See **[Documentation index](DOCS.md)**.
|
|
308
383
|
|
|
309
384
|
## License
|
|
310
385
|
|
package/bin/spoolway.exe
CHANGED
|
Binary file
|