bullswarm 0.28.3 → 0.28.5

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/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # bullswarm changelog
2
2
 
3
+ ## 0.28.5 — narrow-terminal detail panes use the whole screen
4
+
5
+ - tui: on a narrow terminal (under 100 columns, e.g. a phone over SSH) the
6
+ agent detail, workflow technical details and planner overview panes wrapped
7
+ their text to the width they would have beside the 34-column sidebar, so a
8
+ 60-column screen showed 22-character lines inside a 58-character panel. The
9
+ text now wraps to the pane it occupies: full width when narrow, the right
10
+ column otherwise. Regression test at 60 columns.
11
+
12
+ ## 0.28.4 — the skill says how, the schema file says what
13
+
14
+ - skill: the method and the schema are now separate files. `skill/SKILL.md`
15
+ (1,345 → 914 words) keeps only what the kernel cannot check: choosing the
16
+ shape, decomposing into territories, dependencies as inputs rather than
17
+ phases, the integrator, evidence, the effort rule (writers are `implement`;
18
+ high belongs to `integration`, `architecture`, `adversarial-acceptance`;
19
+ never `defaults.effort: high`), and an explicit validate → read `advisories`
20
+ → adjust → launch sequence. The new `skill/references/program.md` holds the
21
+ program format: fields, kinds, requirement-ID derivation, enforced rules and
22
+ one example that validates with no advisories. `plan contract` is no longer a
23
+ step in the default flow; operations.md documents it as the live fallback
24
+ and the dispatched planner's brief. Reasoning depth, digest details and the
25
+ watch flags live in operations.md only.
26
+
3
27
  ## 0.28.3 — connector upgrades learn new packaged profiles
4
28
 
5
29
  - command-code: a profile entry for `deepseek/deepseek-v4.1-flash` that
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bullswarm",
3
- "version": "0.28.3",
3
+ "version": "0.28.5",
4
4
  "description": "Route work across coding-agent CLI subscriptions — paced by live quota meters, verified by content, never trusting exit codes.",
5
5
  "type": "module",
6
6
  "bin": {
package/skill/SKILL.md CHANGED
@@ -5,167 +5,120 @@ description: Delegate bounded work through Bullswarm to one quota-routed coding
5
5
 
6
6
  # Bullswarm
7
7
 
8
- You supply the task or dependency graph. Bullswarm routes workers by quota and
9
- capability, runs them, and saves their outputs. For workflows, **you are the
10
- planner by default**: write the graph once; the kernel executes it to the end.
8
+ You write the task. Bullswarm picks a worker by quota and capability, runs it,
9
+ and saves the output. For a workflow you are the planner: write the program
10
+ once and the kernel runs it to the end.
11
11
 
12
12
  Keep the user's scope and working directory. Delegate only authorized work;
13
13
  permission to delegate does not authorize messages, releases, or other external
14
- writes. If `BULLSWARM_DEPTH` is set, do the assigned work directly unless the
15
- task explicitly requires nested delegation.
14
+ writes. If `BULLSWARM_DEPTH` is set you are already a worker: do the assigned
15
+ work directly unless it explicitly requires nested delegation.
16
16
 
17
- ## 1. Choose the shape yourself
17
+ ## 1. Choose the shape
18
18
 
19
- Use one agent for a bounded outcome such as a review or localized fix. Use a
20
- workflow for parallel territories, integration, or implementation followed by
21
- independent acceptance. There is no preview or classifier step — decide from
22
- the request itself and go directly to the matching mode below.
19
+ One agent for one bounded outcome: a review, a localized fix, a study with one
20
+ deliverable. A workflow when the work splits into parallel territories, needs
21
+ integration, or needs independent acceptance. Decide from the request itself;
22
+ there is no classifier command.
23
23
 
24
24
  ## 2a. One agent
25
25
 
26
- Dispatch it directly:
27
-
28
26
  ```bash
29
27
  bullswarm run --lane=analyze --add-dir=<abs-dir> --prompt='<task>' --json
30
28
  ```
31
29
 
32
- An unrecognized `--flag` on any command prints `unknown flag --name` plus
33
- that command's synopsis and exits 2, before routing or spawning anything.
34
-
35
- Choose `build` for edits, `chore` for mechanical edits, or `analyze` for
36
- read-only work. Use `--task-file` instead of `--prompt` for long text or
37
- awkward quoting. The result's top-level fields include `ok`, `keepOnClaude`,
38
- `pick` (the chosen `{pool, model, command}`), `outFile`, and `why`:
39
-
40
- - `keepOnClaude: true`: do the work yourself, even if `ok` is true.
41
- - Otherwise, when `ok: true`, read `outFile` and check its content before using it.
42
- - `ok: false`: inspect and report the failure; a successful CLI exit is not
43
- proof that the work succeeded.
44
-
45
- Do not run `doctor` unless dispatch reports a readiness problem.
30
+ Lanes: `build` edits, `chore` mechanical edits, `analyze` read-only. Use
31
+ `--task-file` for long text. Read the result: `keepOnClaude: true` means do it
32
+ yourself; `ok: true` means read `outFile` and check its content before using
33
+ it; `ok: false` means inspect and report the failure. A clean exit code is not
34
+ proof of success. Do not run `doctor` unless dispatch reports a readiness
35
+ problem.
46
36
 
47
37
  ## 2b. A workflow
48
38
 
49
- Get the planning contract:
39
+ The program format lives in [program.md](references/program.md): fields, kinds,
40
+ requirement IDs, enforced rules, and one example. This section is how to
41
+ author the graph.
42
+
43
+ - **Decompose.** One action per bounded outcome a single worker can finish
44
+ alone. Every writer gets an `ownedFiles` territory. All workers share one
45
+ tree, so tell each to preserve others' edits and to report any file it needs
46
+ outside its territory instead of editing it.
47
+ - **Dependencies are inputs, not phases.** `dependsOn` lists the actions whose
48
+ outputs this action reads. Everything with no unmet dependency runs at once.
49
+ A phase is simply the set of actions that become ready together; never add a
50
+ dependency to fake one.
51
+ - **Integrate after parallel writers.** One `integration` action that depends
52
+ on all of them, directly or through a digest, with `ownedFiles: []`, which
53
+ on a build-lane action means no territory limit. It reads their outputs,
54
+ resolves shared-file requests, and runs the repository's acceptance checks.
55
+ It runs alone.
56
+ - **Check independently when acceptance matters.** One `adversarial-acceptance`
57
+ action with empty `affects` and `ownedFiles`, `evidenceFor` set to the
58
+ requirement IDs it judges, depending on every writer that affects them.
59
+ Describe what to inspect; the kernel supplies the evidence format. A
60
+ requirement may be covered by evidence alone: a "verification" deliverable
61
+ is the evidence report in the run result, not a file.
62
+ - **Digest when outputs pile up.** A `digest` action when three or more outputs
63
+ feed one reader, or a reader's inputs exceed about 20 KB. The reader depends
64
+ on the digest instead of the raw writers and gets `digestOf` links to them;
65
+ the digest keeps every shared-file request. Evidence never depends on a
66
+ digest.
67
+ - **Effort.** Writers are `implement`. High belongs to exactly three kinds:
68
+ `integration` (the sole writer after parallel work), `architecture` (a
69
+ read-only judgment whose report a later action consumes), and
70
+ `adversarial-acceptance` (independent evidence). A study that reads code and
71
+ writes markdown is `implement`. When a judgment must land in a file, keep it
72
+ `implement`, or split it into an `architecture` action plus a writer that
73
+ records its report. Never set `defaults.effort` to `high`, and do not
74
+ restate `lane` or `effort` on an action that has a `kind`.
75
+ - **Prompts are self-contained.** Each names the absolute workspace path
76
+ (nothing is substituted), the outcome, the relevant files, the dependency
77
+ outputs to read, and the concrete checks to run.
78
+
79
+ ### Validate, read, adjust, then launch
80
+
81
+ Keep the goal in a file and pass it as `"$(cat goal.txt)"` to both commands,
82
+ so validate and launch get identical text, apostrophes and line breaks
83
+ included.
50
84
 
51
85
  ```bash
52
- bullswarm workflow plan contract '<goal>' --cwd=<abs-dir> --json
86
+ bullswarm workflow plan validate "$(cat goal.txt)" --cwd=<abs-dir> --program=<abs-dir>/plan.json --json
53
87
  ```
54
88
 
55
- Use exactly the same goal when validating and launching. Keep `--cwd` fixed to
56
- the absolute target directory even when generating the plan elsewhere. Preserve
57
- the requested outcomes; numbered deliverables produce separate requirement IDs. The contract
58
- contains the current schema, IDs, rules, and a worked program example.
59
-
60
- Write `plan.json` from the contract's worked example. The bare program has
61
- `schemaVersion: "bullswarm.workflow.program.v2"` and a populated `actions` array.
62
- Each action needs `id`, `purpose`, `dependsOn`, `affects`, `ownedFiles`,
63
- `prompt`, and `evidenceFor`, plus either `kind` or an explicit `lane`. Copy
64
- requirement IDs from the contract. Optional `inputs`/`produces` describe actual
65
- artifacts; ordinary dependencies do not need them. Never put provider/model
66
- fields into the program.
67
-
68
- Set `kind` on every action and it fills `lane` and `effort`: `mechanical`
69
- (chore/low), `io-read` (analyze/low), `digest` (analyze/low), `check`
70
- (analyze/medium), `implement` (build/medium), `integration` (build/high),
71
- `architecture` (analyze/high),
72
- `adversarial-acceptance` (analyze/high). An explicit `lane` or `effort` still
73
- wins, then the kind table, then an optional program-level `defaults` object
74
- (`effort` and `reasoning` only), then the per-lane default. A kind outside that
75
- list is rejected before anything runs. `plan validate` and `workflow goal` also
76
- print non-blocking `advisory:` lines — `all-writers-high` and `docs-at-high` —
77
- which never change acceptance or the exit code.
78
-
79
- Author the graph around these rules:
80
-
81
- - **Shared tree:** give each writer an intended `ownedFiles` territory. New
82
- files survive; territories guide scheduling, not file rejection. Tell workers
83
- others share the tree, preserve their edits, and report shared-file requests.
84
- - **Real dependencies:** independent actions run concurrently. After parallel
85
- writers, add a sole integrator depending on all of them, with `lane: "build"`
86
- and `ownedFiles: []`. It reads their outputs, handles shared-file requests,
87
- and runs repository acceptance checks. This unrestricted integrator runs alone.
88
- - **Optional digest:** `kind: "digest"` condenses its dependencies' outputs into
89
- one artifact so an expensive consumer reads a digest instead of many raw
90
- files. It is extractive — the kernel writes the task and it quotes verbatim,
91
- never judges. Add one when three or more writers feed a single integrator, or
92
- when any consumer's dependency outputs exceed roughly 20 KB. It needs at least
93
- one `dependsOn`, empty `evidenceFor` and empty `ownedFiles`; `affects` may be
94
- empty. Never let an evidence action depend on a digest — evidence reads the
95
- real artifacts, and the validator exits 2 if it does. Consumers still get a
96
- `digestOf` list naming each digested source, so they can drill down.
97
- - **Self-contained work:** each prompt names the exact workspace, outcome,
98
- relevant files, and concrete checks. Use `medium` effort for ordinary build
99
- or analysis, `low` for mechanical chores, and `high` for difficult judgment.
100
- - **Optional evidence:** an independent check uses `lane: "analyze"`, empty
101
- `affects`/`ownedFiles`, and `evidenceFor` requirement IDs. Depend on every
102
- writer affecting those requirements. Describe the checks; the kernel adds
103
- the evidence JSON instructions. Evidence is optional for graph completion.
104
- - **Optional reasoning depth:** `effort` picks the model tier; the optional
105
- `reasoning` field picks how hard that model thinks. Values are
106
- `low|medium|high|xhigh|max`, or `default` to pass nothing and let the worker
107
- CLI's own setting decide. It applies to that one action and outranks every
108
- configured level for it — so a `low`-effort integrator can still get `xhigh`
109
- thinking. Omit it and the configured level applies; it never changes the
110
- pool, model, or effort tier, and a connector that does not accept the exact
111
- level gets the nearest level it supports. Set it only when an action needs
112
- deeper thinking than its tier implies (a tricky shared-file integrator,
113
- ambiguous acceptance judgment) or cheaper thinking for mechanical work.
114
- For the whole run instead of one action, pass
115
- `--worker-reasoning <level>` (and `--planner-reasoning <level>` with
116
- `--orchestrator`) to `workflow goal`; the contract's `reasoning` block
117
- echoes what a launch will apply.
118
-
119
- Validate, then launch:
89
+ Exit 2 means the program is invalid: the JSON lists `issues`; fix them and
90
+ validate again. Exit 0 always carries an `advisories` array. Each entry names
91
+ an action whose effort is above what its work warrants (`all-writers-high`,
92
+ `docs-at-high`): lower that action's kind and validate again, or write the
93
+ reason it needs high into its `purpose`. An empty array means launch now, with
94
+ the same goal, `--cwd` and absolute `--program` (validate's `next.launch` line
95
+ is this command):
120
96
 
121
97
  ```bash
122
- bullswarm workflow plan validate '<goal>' --cwd=<abs-dir> --program=plan.json --json
123
- bullswarm workflow goal '<goal>' --cwd=<abs-dir> --program=plan.json --json
98
+ bullswarm workflow goal "$(cat goal.txt)" --cwd=<abs-dir> --program=<abs-dir>/plan.json --json
124
99
  ```
125
100
 
126
- An invalid program exits 2 and launches nothing. Fix the reported issues and
127
- validate again. A valid launch detaches and returns `shortId`; report it.
101
+ The launch detaches and returns `shortId`; report it.
128
102
 
129
- ## 3. Observe and judge the result
103
+ ## 3. Observe and judge
130
104
 
131
105
  ```bash
132
106
  bullswarm workflow watch <shortId> --next
133
- bullswarm workflow watch <shortId> --next --after <sequence> --since <iso-timestamp>
134
107
  bullswarm workflow runs result <shortId> --json --summary
135
108
  ```
136
109
 
137
- Use the compact summary in the status loop. Read the full envelope with `--json` alone when the run is failed or partial, or before judging evidence.
138
-
139
- When the user asked you to complete the work, follow the run through its result.
140
- Launch `bullswarm workflow watch <shortId> --next` in a background terminal, act
141
- on the printed event when it exits, and relaunch until the outcome line reports
142
- a pause or a terminal status. Each exit that leaves the run going ends with
143
- `next: bullswarm workflow watch <shortId> --next --after <sequence> --since <iso>`:
144
- relaunch with exactly those two values, so events committed while you were
145
- acting are printed instead of skipped and a stall you already saw does not
146
- report twice. In `--jsonl` mode there is no such line take `--after` from the
147
- `sequence` field of the last object. V2 watch prints one line per notable event
148
- and stays silent while work is merely in progress; `--heartbeat` is opt-in and
149
- `--stall-after` (default 300s) reports a silent running agent. A usage-limit
150
- failure always prints `⚠ ... usage limit on <pool> · paused until <deadline>
151
- · retrying on another pool`, then `↺ ... now on <pool> · <model>` once the
152
- mechanical retry lands — even without `--verbose`. Pass `--classic` for the
153
- older heartbeat-based watcher instead (V2 only; it cannot combine with
154
- `--next`). A legacy authored-graph run cannot be watched: the watcher prints
155
- the legacy line and exits 2.
156
- `watch` also exits at a durable planning pause; that is not completion.
157
-
158
- Read action outputs and actual artifacts, and probe important edge cases yourself.
159
- `completed` means the graph succeeded; `verified` means the evidence agents
160
- returned passing verdicts, which can still miss bugs. A `partial` result
161
- exposes failed or skipped branches. Negative evidence remains negative and does
162
- not trigger automatic gap-planning rounds. Author follow-up work explicitly
163
- when the requested outcome still needs repairs.
164
-
165
- Shared files remain after failure or cancellation. Saved older runs keep their
166
- original execution behavior. Exit 0 can mean launched, paused, or completed;
167
- always inspect the returned status.
168
-
169
- Read [operations.md](references/operations.md) only when you need **steering,
170
- cancellation, resume, scouting, a dispatched planner, explicit isolation,
171
- routing diagnosis**. Ordinary work needs only the flow above.
110
+ Run `watch --next` in a background terminal. When it exits, act on the printed
111
+ event and relaunch with the exact `next: bullswarm workflow watch <shortId>
112
+ --next --after <sequence> --since <iso>` line it printed, until the outcome
113
+ line reports a pause or a terminal status. A pause is not completion.
114
+
115
+ Then read the real outputs and artifacts and probe the important edge cases
116
+ yourself. `completed` means the graph ran. `verified` means evidence passed,
117
+ which can still miss bugs. `partial` exposes failed or skipped branches; author
118
+ follow-up work explicitly when the outcome still needs repair. Shared files
119
+ remain after failure or cancellation. Exit 0 can mean launched, paused, or
120
+ completed, so always inspect the returned status.
121
+
122
+ [operations.md](references/operations.md) covers steering, cancellation,
123
+ resume, scouting, a dispatched planner, isolation, watch flags, reasoning
124
+ depth, digest details, the live planning contract, and routing diagnosis.
@@ -91,6 +91,20 @@ commands fail closed with their short ID and retained run directory.
91
91
 
92
92
  ## Program actions: `kind`, `defaults`, and advisories
93
93
 
94
+ The program format itself — fields, kinds, requirement IDs, enforced rules
95
+ and an example — is in [program.md](program.md). The same rules are also served
96
+ live by the running kernel:
97
+
98
+ ```bash
99
+ bullswarm workflow plan contract '<goal>' --cwd=<abs-dir> --json
100
+ ```
101
+
102
+ That contract carries the goal's derived requirement IDs, the exact validate
103
+ and launch commands with goal and `--cwd` filled in, and any run-wide
104
+ `reasoning` override. It is the brief a dispatched planner receives, and the
105
+ fallback for a caller whose `plan validate` rejects field names or kinds after
106
+ an upgrade.
107
+
94
108
  An action's `kind` names what the work IS and derives its `lane` and `effort`,
95
109
  so a program states the nature once instead of re-deciding two routing fields:
96
110
 
@@ -0,0 +1,134 @@
1
+ # Workflow program format
2
+
3
+ `plan.json` is the program that `bullswarm workflow goal` executes. Before
4
+ launch, `bullswarm workflow plan validate` checks it against the running
5
+ kernel. Exit 2 returns `issues` and a `next` block; fix the issues yourself.
6
+ Exit 0 returns the resolved program and an `advisories` array. This file
7
+ ships with the kernel it describes; fetch the live contract only when an issue
8
+ names an unknown field, kind, or `schemaVersion`, which can only happen after
9
+ an upgrade this file has not followed:
10
+
11
+ ```bash
12
+ bullswarm workflow plan contract '<goal>' --cwd=<abs-dir> --json
13
+ ```
14
+
15
+ ## Program
16
+
17
+ | field | required | value |
18
+ |---|---|---|
19
+ | `schemaVersion` | yes | exactly `bullswarm.workflow.program.v2` |
20
+ | `actions` | yes | non-empty array of actions |
21
+ | `defaults` | no | object with only `effort` (`high`, `medium`, `low`) and `reasoning` (`low`, `medium`, `high`, `xhigh`, `max`, `default`); applies where neither the action nor its kind sets the field |
22
+
23
+ No other top-level field is accepted.
24
+
25
+ ## Action
26
+
27
+ | field | required | value |
28
+ |---|---|---|
29
+ | `id` | yes | kebab-case, unique in the program |
30
+ | `purpose` | yes | one line: what this action delivers |
31
+ | `dependsOn` | yes | ids of the actions whose outputs this one reads; `[]` if none |
32
+ | `affects` | yes | requirement IDs this action's work contributes to; an action with `ownedFiles` must list at least one |
33
+ | `ownedFiles` | yes | repo-relative paths this action may edit; `[]` on a build-lane action means no territory limit (the integrator); analyze-lane actions edit nothing |
34
+ | `prompt` | yes | the self-contained task text with the absolute workspace path written in (nothing is substituted; `<cwd>` in the example is a placeholder); for a `digest`, one line of focus appended to the kernel-written task |
35
+ | `evidenceFor` | yes | requirement IDs this action judges; `[]` unless it is evidence |
36
+ | `kind` | kind or lane | one of the kinds below |
37
+ | `lane` | kind or lane | `analyze` (read-only), `build` (edits), `chore` (mechanical edits); only when there is no kind |
38
+ | `effort` | no | `high`, `medium`, `low`; overrides the kind's effort |
39
+ | `reasoning` | no | `low`, `medium`, `high`, `xhigh`, `max`, `default`; how hard the picked model thinks, outranks every configured level |
40
+ | `inputs`, `produces` | no | artifact IDs, kebab-case: the producer lists an ID in `produces`, its consumer in `inputs`; omit for ordinary dependencies |
41
+
42
+ Any other field is rejected. Resolution per field: the action's own `lane` or
43
+ `effort`, then the kind table, then `defaults`, then the lane's default.
44
+
45
+ ## Kinds
46
+
47
+ | kind | lane | effort | use for |
48
+ |---|---|---|---|
49
+ | `mechanical` | chore | low | renames, formatting, generated edits |
50
+ | `io-read` | analyze | low | fetch or read something and report it |
51
+ | `digest` | analyze | low | condense dependency outputs verbatim; the kernel writes its task |
52
+ | `check` | analyze | medium | a read-only inspection with a report |
53
+ | `implement` | build | medium | ordinary edits and writing, including docs written from code study |
54
+ | `integration` | build | high | the sole writer after parallel writers; `ownedFiles: []` |
55
+ | `architecture` | analyze | high | a read-only cross-cutting judgment; its report feeds a later action |
56
+ | `adversarial-acceptance` | analyze | high | independent evidence; empty `affects` and `ownedFiles`, `evidenceFor` set |
57
+
58
+ An analyze-lane action edits nothing; its deliverable is the report a
59
+ dependent reads.
60
+
61
+ ## Requirement IDs
62
+
63
+ The kernel derives requirements from the goal text. Each numbered item, `1.`
64
+ or `1)` at the start of a line or inline in one line counting from 1, becomes
65
+ `requirement-N` in order. A goal with no numbered items is one
66
+ `requirement-1`. Number distinct deliverables in the goal to get one verdict
67
+ each, and use exactly the same goal text for validate and launch.
68
+
69
+ ## Enforced rules
70
+
71
+ - A goal that starts with `read-only`, or says repository files must not be
72
+ modified, forbids mutation: every `ownedFiles` must be `[]`.
73
+ - A `digest` needs at least one `dependsOn`, empty `evidenceFor`, empty
74
+ `ownedFiles`, and no evidence action may list it in `dependsOn`. Only the
75
+ direct dependency is checked; evidence may depend on an action that itself
76
+ read a digest.
77
+ - A requirement needs no writer: coverage by `evidenceFor` alone is accepted,
78
+ and evidence itself is optional.
79
+ - An evidence action's prompt describes what to inspect only. A directive such
80
+ as "return only JSON" is rejected; the kernel owns the evidence format.
81
+ - A kind outside the table, a lane outside `analyze|build|chore`, or an effort
82
+ outside `high|medium|low` exits 2 before anything runs.
83
+
84
+ ## Example
85
+
86
+ Goal: `1. Add --since to runs list. 2. Document it in README.`
87
+
88
+ ```json
89
+ {
90
+ "schemaVersion": "bullswarm.workflow.program.v2",
91
+ "actions": [
92
+ {
93
+ "id": "since-flag",
94
+ "kind": "implement",
95
+ "purpose": "Add --since to runs list with a unit test",
96
+ "dependsOn": [],
97
+ "affects": ["requirement-1"],
98
+ "ownedFiles": ["src/workflow/runs-cli.js", "tests/runs-list.test.js"],
99
+ "evidenceFor": [],
100
+ "prompt": "In <cwd>, add a --since <time> flag to `bullswarm workflow runs list` in src/workflow/runs-cli.js with a unit test in tests/runs-list.test.js. Others share this tree: preserve their edits and report any file you need outside your territory. Run `npm test` and quote the summary line."
101
+ },
102
+ {
103
+ "id": "readme",
104
+ "kind": "implement",
105
+ "purpose": "Document --since in README",
106
+ "dependsOn": [],
107
+ "affects": ["requirement-2"],
108
+ "ownedFiles": ["README.md"],
109
+ "evidenceFor": [],
110
+ "prompt": "In <cwd>, document the --since <time> flag of `bullswarm workflow runs list` in the runs section of README.md, matching the style of the neighbouring flags. Edit README.md only."
111
+ },
112
+ {
113
+ "id": "integrate",
114
+ "kind": "integration",
115
+ "purpose": "Reconcile both edits and run the full suite",
116
+ "dependsOn": ["since-flag", "readme"],
117
+ "affects": ["requirement-1", "requirement-2"],
118
+ "ownedFiles": [],
119
+ "evidenceFor": [],
120
+ "prompt": "In <cwd>, read both dependency outputs, resolve any shared-file requests they raised, make the README wording match the flag as implemented, run `npm test`, and quote the summary line."
121
+ },
122
+ {
123
+ "id": "verify",
124
+ "kind": "adversarial-acceptance",
125
+ "purpose": "Independently confirm the flag works and is documented",
126
+ "dependsOn": ["since-flag", "readme", "integrate"],
127
+ "affects": [],
128
+ "ownedFiles": [],
129
+ "evidenceFor": ["requirement-1", "requirement-2"],
130
+ "prompt": "In <cwd>, exercise `bullswarm workflow runs list --since <time> --json` against a fixture home with runs on both sides of the bound, and check that README.md describes the flag and its accepted time forms. Inspect only; try to break it."
131
+ }
132
+ ]
133
+ }
134
+ ```
@@ -572,16 +572,15 @@ export function renderWorkflowTui(row, {
572
572
  // readable and explicit back navigation preserves the same hierarchy.
573
573
  const leftWidth = Math.min(SIDEBAR_WIDTH, Math.max(1, width - 3));
574
574
  const rightWidth = Math.max(1, width - leftWidth);
575
- const orchestrationLines = orchestratorDetailLines(
576
- model,
577
- Math.max(20, (orchestratorDetail ? width : rightWidth) - 4),
578
- spinnerFrame,
579
- { verbose: orchestratorVerbose },
580
- );
581
- const detail = orchestratorDetail
582
- ? orchestrationLines
583
- : agentDetailLines(model, Math.max(20, rightWidth - 4), spinnerFrame);
584
- const technical = workflowTechnicalLines(model, Math.max(20, rightWidth - 4));
575
+ // The detail text is wrapped once, before the layout below picks a body, so
576
+ // it must wrap to the pane it will actually occupy: the full width on a
577
+ // narrow terminal (one pane at a time), the right column beside the sidebar
578
+ // otherwise. Wrapping to the right column on a 60-column phone left every
579
+ // line at 22 characters inside a 58-character panel.
580
+ const paneWidth = Math.max(20, (narrow ? width : rightWidth) - 4);
581
+ const orchestrationLines = orchestratorDetailLines(model, paneWidth, spinnerFrame, { verbose: orchestratorVerbose });
582
+ const detail = orchestratorDetail ? orchestrationLines : agentDetailLines(model, paneWidth, spinnerFrame);
583
+ const technical = workflowTechnicalLines(model, paneWidth);
585
584
  const contentHeight = bodyHeight - 2;
586
585
  const scrollSource = workflowVerbose ? technical : detail;
587
586
  const maxScroll = Math.max(0, scrollSource.length - contentHeight);