@sjawhar/claude-envoy 1.8.0 → 1.8.2
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/.claude-plugin/plugin.json +1 -1
- package/.omp-plugin/plugin.json +1 -1
- package/README.md +8 -5
- package/dist/envoy-channel.js +1 -1
- package/legion/agents/thermonuclear-code-quality.md +1 -1
- package/legion/agents/thermonuclear-deep-review.md +1 -1
- package/legion/skills/legion-architect/SKILL.md +8 -3
- package/legion/skills/legion-architect/references/wake-routing.md +5 -0
- package/legion/skills/legion-controller/SKILL.md +2 -2
- package/legion/skills/legion-oracle/SKILL.md +5 -7
- package/legion/skills/legion-worker/SKILL.md +4 -4
- package/legion/skills/legion-worker/references/pr-body.md +2 -2
- package/legion/skills/{ce-simplify-code → simplify-settled-diff}/SKILL.md +6 -5
- package/package.json +1 -1
- package/scripts/build.ts +20 -4
- package/skills/asd-ste100/SKILL.md +2 -19
- package/skills/dispatch-first/SKILL.md +7 -1
- package/skills/dispatch-writing-specs/SKILL.md +6 -4
- package/skills/envoy/SKILL.md +1 -1
- package/skills/outside-message/SKILL.md +7 -26
- package/skills/plain-words/SKILL.md +41 -42
- package/skills/plain-words/references/mechanics.md +49 -0
- package/{legion/skills → skills}/thermonuclear-code-quality/SKILL.md +10 -0
- package/{legion/skills → skills}/thermonuclear-deep-review/SKILL.md +13 -7
- /package/legion/skills/{ce-simplify-code → simplify-settled-diff}/LICENSE +0 -0
- /package/legion/skills/{ce-simplify-code → simplify-settled-diff}/references/personas/code-quality-reviewer.md +0 -0
- /package/legion/skills/{ce-simplify-code → simplify-settled-diff}/references/personas/code-reuse-reviewer.md +0 -0
- /package/legion/skills/{ce-simplify-code → simplify-settled-diff}/references/personas/efficiency-reviewer.md +0 -0
- /package/{legion/skills → skills}/thermonuclear-code-quality/LICENSE +0 -0
- /package/{legion/skills → skills}/thermonuclear-deep-review/LICENSE +0 -0
package/.omp-plugin/plugin.json
CHANGED
package/README.md
CHANGED
|
@@ -261,9 +261,11 @@ human approval surface.
|
|
|
261
261
|
|
|
262
262
|
## Skills
|
|
263
263
|
|
|
264
|
-
The plugin ships
|
|
264
|
+
The plugin ships ten skills, `claude-envoy:envoy`, `claude-envoy:dispatch`,
|
|
265
265
|
`claude-envoy:dispatch-first`, `claude-envoy:dispatch-writing-specs`, `claude-envoy:asd-ste100`,
|
|
266
|
-
`claude-envoy:outside-message`, `claude-envoy:plain-words
|
|
266
|
+
`claude-envoy:outside-message`, `claude-envoy:plain-words`, `claude-envoy:agent-secrets` and the
|
|
267
|
+
reviewer's pair, `claude-envoy:thermonuclear-code-quality` and
|
|
268
|
+
`claude-envoy:thermonuclear-deep-review`.
|
|
267
269
|
The first four teach the Envoy tools, the `dispatch` command and how to write a spec; `asd-ste100` gives the
|
|
268
270
|
ASD-STE100 rules for text a person reads; `outside-message` holds the steps and the approval before text
|
|
269
271
|
reaches a person outside the company; `plain-words` the empty verb phrases to delete from any text a
|
|
@@ -277,10 +279,11 @@ on every `SessionStart` (startup, resume, clear, compact, fork) and `SubagentSta
|
|
|
277
279
|
`hooks/hooks.json` bullet above describes; it sends a spec, or an ask, comment or message a person
|
|
278
280
|
reads, to `dispatch-writing-specs`, which the session loads by name.
|
|
279
281
|
|
|
280
|
-
`envoy`, `dispatch`, `dispatch-first`, `dispatch-writing-specs`, `asd-ste100`, `outside-message`, `plain-words` and `agent-secrets` are the eight a standalone Claude Code session uses
|
|
282
|
+
`envoy`, `dispatch`, `dispatch-first`, `dispatch-writing-specs`, `asd-ste100`, `outside-message`, `plain-words` and `agent-secrets` are the eight a standalone Claude Code session uses, and the
|
|
283
|
+
reviewer's pair, `thermonuclear-code-quality` and `thermonuclear-deep-review`, ships here too, so
|
|
284
|
+
one copy of each rubric reaches both harnesses. The other root skills
|
|
281
285
|
stay out of this plugin: they belong to Legion's roles (the architect, controller, oracle and retro
|
|
282
|
-
skills, and the phase workers' `legion-worker` and `
|
|
283
|
-
`thermonuclear-*` pair (`skills/AGENTS.md`). A phase worker on Claude Code gets them from the
|
|
286
|
+
skills, and the phase workers' `legion-worker` and `simplify-settled-diff`) (`skills/AGENTS.md`). A phase worker on Claude Code gets them from the
|
|
284
287
|
generated `legion/` plugin (below). Link another root skill here only when a standalone Claude
|
|
285
288
|
Code session needs it.
|
|
286
289
|
|
package/dist/envoy-channel.js
CHANGED
|
@@ -55090,7 +55090,7 @@ var import_nats2 = __toESM(require_mod4(), 1);
|
|
|
55090
55090
|
|
|
55091
55091
|
// package.json
|
|
55092
55092
|
var name = "@sjawhar/claude-envoy";
|
|
55093
|
-
var version2 = "1.8.
|
|
55093
|
+
var version2 = "1.8.2";
|
|
55094
55094
|
var legion = {
|
|
55095
55095
|
daemonApiVersion: 53
|
|
55096
55096
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: thermonuclear-code-quality
|
|
3
3
|
description: Diff-scoped maintainability audit for structure, abstraction, file growth, branching complexity, and type boundaries.
|
|
4
|
-
skills: [
|
|
4
|
+
skills: [claude-envoy:thermonuclear-code-quality]
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Thermonuclear Code Quality
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: thermonuclear-deep-review
|
|
3
3
|
description: Diff-scoped security and correctness audit for bugs, breakages, developer-experience regressions, and feature-gate leaks.
|
|
4
|
-
skills: [
|
|
4
|
+
skills: [claude-envoy:thermonuclear-deep-review]
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Thermonuclear Deep Review
|
|
@@ -40,8 +40,6 @@ You own one issue tree from its first decision to the merge that closes it. The
|
|
|
40
40
|
- On each `child-closed`, read the child's handoff. Edit the spec of each open child the result changes, and take out each child it makes unneeded with `park_child` and say why with `dispatch comment`.
|
|
41
41
|
- Before you park a child for good (one made unneeded, or parked so its tree can finish), set the `--blocked-by` list of each sibling that waits on it again without it (one call with the rest of its list, or `--clear-blocked-by` when it was the only one), or park that sibling too: a parked child is stopped, not done, and its dependents stay held with no notice. A park followed by `rerun_child` keeps its dependents' links: they wait through the rerun and start when the rerun's merge closes the child.
|
|
42
42
|
- A released child holds an admission slot of its own while a worker of it has work, and waits in the admission line for one, so a tree of four working issues holds four of the cap's issues. It never becomes a root while your tree is live.
|
|
43
|
-
- A root that waited in the admission queue, never ran and never left another tree joins your tree once a person makes it your child, if it is `todo`, and otherwise at your release of it (the `child-status` row of [wake routing](skill://legion-architect/references/wake-routing.md)); once in, it is held for its blockers like any child you release. A root that left another tree, handed over by its finished tree or admitted as an orphan, stays its own tree and never joins yours, even one that was your root's child before your root was admitted again. A labelled `todo` issue under a child you have not released, unless it ran as a tree of its own or left another tree, is held under that unreleased child (not a blocked-by hold): it waits for no slot until your release of it or of that child brings it in, with any `todo` child of its own.
|
|
44
|
-
- A release that cannot take a child in is refused 409 and writes nothing, its message naming the child and why: release the rest of the wave again without it. `CHILD_NOT_ADOPTABLE` is an issue that runs or ran as a tree of its own, carries a run handed over to it, or was handed over (or admitted as an orphan) as a root of its own: leave it there, or ask the controller. `CHILD_IN_OTHER_TREE` is another tree's child. When the tree it names is a root held under an unreleased child of yours (a root that queued and never ran, so it has no architect of its own), release that root, or the unreleased child it sits under, instead: its children come with it. Otherwise re-parent the child back in Dispatch, or ask that tree's architect or the controller.
|
|
45
43
|
|
|
46
44
|
## 3. Children complete
|
|
47
45
|
|
|
@@ -65,7 +63,14 @@ The reviewer's `phase-finished` with an `APPROVED` review puts the issue in `acc
|
|
|
65
63
|
- the reviewer's approval of that head by SHA (`gh api --paginate repos/<o>/<r>/pulls/<n>/reviews`);
|
|
66
64
|
- each claim the reviewer's prose commits to, checked against the code at that head and command output, never against the finding it ruled on or its own verdict: no other agent has read that prose.
|
|
67
65
|
|
|
68
|
-
Accept only when every `before_merge` check of the issue's own Verification document has a passing result that is current at the approved head, every requirement the spec marks has a check (`dispatch read --issue <issue>` names each one that has none), and no criterion left the tree
|
|
66
|
+
Accept only when every `before_merge` check of the issue's own Verification document has a passing result that is current at the approved head, every requirement the spec marks has a check (`dispatch read --issue <issue>` names each one that has none), and no criterion left the tree. On a parent, that head is section 4's last round.
|
|
67
|
+
|
|
68
|
+
- The issue's own checks at the issue's own head are the whole gate: a child's result against one of your checks proves nothing for you, because a child's pull request never makes a root check's result current.
|
|
69
|
+
- A child that carries part of a root requirement proves it with a check on the child's own Verification document whose `serves` names that requirement, which clears the root's coverage flag for it.
|
|
70
|
+
- An issue with no Verification document, or with no `before_merge` check, is a gap the tester and the reviewer name and neither refuses, so your acceptance is the only gate on it: name that gap in your acceptance comment and decide there, accepting the issue or sending it back with the checks you write yourself. That decision closes no design gate, on the condition `skill://legion-worker/references/merge-gate.md` states.
|
|
71
|
+
- A finding ask on the issue holds the acceptance until it is resolved or carries the controller's reply (`skill://legion-architect/references/acceptance.md`).
|
|
72
|
+
|
|
73
|
+
Post that evidence as a `dispatch comment`, naming each check with its result, then `legion({ op: "sign_off", issue: "<KEY>" })`.
|
|
69
74
|
|
|
70
75
|
- `sign_off` works only in `accepting` (`SIGNOFF_OUTSIDE_ACCEPTING`), and the daemon refuses it while an issue beneath it is still in the workflow (`SIGNOFF_CHILD_IN_WORKFLOW`, naming each one), so a parent is accepted after its children, on the head of its last round (section 4).
|
|
71
76
|
- When a check has no current passing result, or its result contradicts what you read: `request_backward_move` with `issue`, `to` (`implementing` or `testing`) and a `reason` naming the check by its block id. It counts a review round.
|
|
@@ -40,3 +40,8 @@ and 7 (a conflict, the hand-over, the close) is in
|
|
|
40
40
|
| `worker-died` | Its `role` and `phase`. That role's claim failed: its launches or prompts ran out. For a phase worker the daemon holds the issue (phase `held`) and starts nothing more on it. Reassess the work, then decide with `retry_or_escalate`: `retry` when the failure looks agent-specific or transient, `escalate` to hand the held issue to the controller when it looks environmental. |
|
|
41
41
|
| `held` | Its `role` and `phase` (the phase the issue left), or `phase` with `reason: "escalated"`. Without `reason`, that phase's worker ran out of launches or prompts: the issue is held (phase `held`), the `worker-died` that comes with it is yours to answer with `retry_or_escalate` as that row says, and the controller hears of the hold too. With `reason: "escalated"`, it records your own `escalate`: the controller has the issue now, and you start nothing for it. |
|
|
42
42
|
| `ready-refused` | Its `version` and `reason`. The merger's READY was refused, and its packet is kept with the completion so no second READY is ever needed. With `version` greater than 0, `reason` reads `READY refused: approve design version <N> before requesting READY.`: the root's spec is already registered at that version, so get it approved (`skill://legion-architect/references/design-gate.md`), and the daemon advances the merge and posts the kept packet the moment it is. With `version` 0, `reason` reads `READY refused: no design version is approved; register and approve the tree's spec before requesting READY.`: the root has no spec registered yet, so register it and get it approved (`skill://legion-architect/references/design-gate.md`) exactly as above; the daemon releases the kept packet the same way — at registration itself when that opens the gate (`gates.design: off`, or Dispatch already shows the version approved), otherwise the moment a human approves the version you registered. Either way, nothing else is needed once the gate opens. On a root whose catch-up said `carried`, the gate is a copy on the old root's spec document: run nothing of `skill://legion-architect/references/design-gate.md`; tell the controller the READY waits on a human's approval of that document, and `carried-gate-opened` follows the approval. A `reason` starting `READY_PACKET_MISSING` names a READY refused before the daemon kept packets: that READY is void and the issue stays in merging, so start it over (`park_child` then `rerun_child`, for a child) or end it. |
|
|
43
|
+
|
|
44
|
+
## A root that joins your tree, and a refused release
|
|
45
|
+
|
|
46
|
+
- A root that waited in the admission queue, never ran and never left another tree joins your tree once a person makes it your child, if it is `todo`, and otherwise at your release of it (the `child-status` row of [wake routing](skill://legion-architect/references/wake-routing.md)); once in, it is held for its blockers like any child you release. A root that left another tree, handed over by its finished tree or admitted as an orphan, stays its own tree and never joins yours, even one that was your root's child before your root was admitted again. A labelled `todo` issue under a child you have not released, unless it ran as a tree of its own or left another tree, is held under that unreleased child (not a blocked-by hold): it waits for no slot until your release of it or of that child brings it in, with any `todo` child of its own.
|
|
47
|
+
- A release that cannot take a child in is refused 409 and writes nothing, its message naming the child and why: release the rest of the wave again without it. `CHILD_NOT_ADOPTABLE` is an issue that runs or ran as a tree of its own, carries a run handed over to it, or was handed over (or admitted as an orphan) as a root of its own: leave it there, or ask the controller. `CHILD_IN_OTHER_TREE` is another tree's child. When the tree it names is a root held under an unreleased child of yours (a root that queued and never ran, so it has no architect of its own), release that root, or the unreleased child it sits under, instead: its children come with it. Otherwise re-parent the child back in Dispatch, or ask that tree's architect or the controller.
|
|
@@ -17,13 +17,13 @@ except a clear defect a role reports ([Issues handed to Legion](#issues-handed-t
|
|
|
17
17
|
- A direct Dispatch message that decides scope, priority or an owner is a ruling: after you answer it, run the weekly-plan reconciliation (`skill://legion-controller/references/backlog-stewardship.md`), because the plan must record the rule.
|
|
18
18
|
- Handle one wake per turn, then end the turn. Never poll or wait for an event, because the daemon wakes you again (`tick` at least every `controller_wake_interval_seconds`).
|
|
19
19
|
- Before any side effect, read `read_state` and the Dispatch issue, because a wake can be stale or sent twice.
|
|
20
|
-
- Read a session's state from the Envoy registry, never from its absence from a list
|
|
20
|
+
- Read a session's state from the Envoy registry, never from its absence from a list (`skill://envoy`). Start no replacement for an `unresponsive` session, take nothing from it, and never report it as gone, because it is working and keeps its claims.
|
|
21
21
|
- Keep no notes between turns, because a restarted session has only `read_state` and Dispatch.
|
|
22
22
|
- Reach the daemon only through the `legion` tool: `read_state`, and `set_status` to `todo`, `backlog` or `icebox`. Run no `legion` from bash, because the tool holds the controller grant.
|
|
23
23
|
- Never edit a repository, push a commit or call `handoff_complete`, and never forward a raw event to an architect, because the daemon runs the phases and raw events only fill the architect's context.
|
|
24
24
|
- Never open a design gate, because only a person's approval of the root's spec in Dispatch opens it.
|
|
25
25
|
- When a `dispatch` command fails, or a `curl` read of Dispatch fails or prints no JSON array, act on nothing it would decide and name its first line in your summary (the turn's last message), because an empty read is no evidence. A Slack read answers a JSON object, and `skill://legion-controller/references/slack-mentions.md` holds its own success test.
|
|
26
|
-
- Before you say that a service or an API is out of reach, run the call through the secrets broker's client
|
|
26
|
+
- Before you say that a service or an API is out of reach, run the call through the secrets broker's client (`skill://agent-secrets`), and report it unreachable only with the command you ran and its output.
|
|
27
27
|
- Write every Dispatch comment, message and ask as `skill://dispatch-writing-specs`'s "Rules for the text" say.
|
|
28
28
|
- A message that must reach more than 4 role topics is yours to send and nobody else's (`skill://envoy`). Send it to no more than 4 topics a minute, and send none while a daemon restart or a pod roll is under way, because each publish wakes a session that reads its whole context again, which the provider charges as uncached input: a mean of 576,083 tokens a wake, a median of 493,636 and a ninetieth percentile of 1,327,888. Spread the rest over later turns, and name in your summary the topics you have not sent to yet.
|
|
29
29
|
|
|
@@ -7,10 +7,9 @@ description: Use when you are about to ask a human a question about a pattern, c
|
|
|
7
7
|
|
|
8
8
|
If this skill disagrees with the code, a command's output or its `--help`, follow those and say which line of this skill is wrong.
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
- Ask the human directly when the answer is a choice between options that each work (a preference, requirement, scope decision or judgment call), because no file can choose. Quote any earlier decision a file records (`file:line`), so the human can confirm it in one word.
|
|
10
|
+
Which questions to research and which to put to a person, and what your answer must say about
|
|
11
|
+
what you searched: `skill://dispatch-first`, "Research before you ask". The steps below are how
|
|
12
|
+
you research in a Legion repository.
|
|
14
13
|
|
|
15
14
|
## Research steps
|
|
16
15
|
|
|
@@ -43,6 +42,5 @@ Before you rely on a step 1 hit, `grep` `docs/solutions/` for its path. If anoth
|
|
|
43
42
|
|
|
44
43
|
## Output
|
|
45
44
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
- Not found: "Checked docs/solutions/ (queries: ...) and codebase (scout query: ...) - no file answers this", so the reader knows what was searched. Then ask the human the part no step answered.
|
|
45
|
+
Report as `skill://dispatch-first` says, and name `docs/solutions/` and the codebase queries you
|
|
46
|
+
ran, so the reader knows what was searched.
|
|
@@ -19,11 +19,11 @@ You work one phase of one issue in a jj workspace every role of the issue shares
|
|
|
19
19
|
|
|
20
20
|
## Stop rules
|
|
21
21
|
|
|
22
|
-
- **A refused completion is information, not a retry loop.** Quote the answer verbatim to the architect, so "my work is lost" and "my work belongs to an ended run" read differently. `HANDOFF_STALE_GENERATION` (the issue is on a newer run
|
|
22
|
+
- **A refused completion is information, not a retry loop.** Quote the answer verbatim to the architect, so "my work is lost" and "my work belongs to an ended run" read differently. `HANDOFF_STALE_GENERATION` (the issue is on a newer run) or `HANDOFF_NO_RUN` (your claim holds no task): push nothing further, end the turn without completing, and tell the architect; if the task then arrives and its work and handoff are already done, call `handoff_complete` again in that task's turn, and never redo the work or write a second handoff. `HANDOFF_STALE_ASSIGNMENT` (the issue left your phase and came back while your turn ran, so your work belongs to the assignment before the one the phase hands you now): end the turn without completing and tell the architect, and report that work and that verdict no further. The phase was entered again, so the task it hands you now is work of its own — a testing assignment after a red is for the head the fix pushed, which your verdict on the head before it does not answer for: do that work at the head the task names, write a handoff of its own for it, and complete in its turn. `HANDOFF_NOT_CURRENT_PHASE`: the issue left your phase; report, never complete again. `HANDOFF_NO_PULL_REQUEST` (the implementer's completion found no open pull request on `legion/<KEY>`, and none recorded merged): open it and complete again at the same commit; when the answer names a closed pull request, the architect decides the phase: tell it, and open or reopen nothing until it answers. `HANDOFF_ALREADY_RECORDED`: the first answer stands; if you did not see it, tell the architect. `HANDOFF_SESSION_MISMATCH` names a record another session wrote: read it, record it again from your session with `dispatch handoff-write`, and complete. A reminder is not a task: after an accepted completion, a second call is refused.
|
|
23
23
|
- **A turn that ends with your phase open is reminded**, at the end of every turn for as long as the phase stays open. Answer by completing, or with a WAITING line naming what you wait on, which buys a quiet wait; a turn that ends while background work of your own is still running buys the same quiet with no line at all, since that work wakes you when it finishes. A run of reminders that change nothing tells your architect. Under `runtime: kubernetes` that quiet wait also lets the daemon release your issue's pod, while background work of yours keeps the pod, because your session reports that work to the daemon.
|
|
24
|
-
- **A released pod is not a stop.** Under `runtime: kubernetes` the daemon releases your issue's pod once no role of it has a turn in progress or a turn due for ten minutes.
|
|
24
|
+
- **A released pod is not a stop.** Under `runtime: kubernetes` the daemon releases your issue's pod once no role of it has a turn in progress or a turn due for ten minutes. Your session, your phase, your place in it and the task you hold are all kept, and your unpushed commits and working-copy change are restored into the next pod, so a release costs a pod start and nothing else. A wait that raises no event of its own wakes you at the backstop alone, 60 minutes after the release, so name the wait in your WAITING line and expect that hour. A release keeps nothing else of the disk — `$TMPDIR`, every ignored file, each role's home, a test database and the CodeGraph index all go with the pod — so put work you must keep on the branch, in a tracked file or in Dispatch. The backstop runs only while your phase is open.
|
|
25
25
|
- **The workspace is read-only for you from the moment your phase ends**, whether you ended it by completing or a CI red took it back while your turn ran: no commit, no `jj new`, no edit to a tracked file, in the turn still running when the message reaches you and in every turn after it, until a new task names your phase. Nothing stops that turn for you, so stopping is yours to do: drop the work in hand and leave whatever you have uncommitted. The active phase owns the workspace, and your session is kept, until your issue leaves the workflow, to answer questions and to take your next assignment.
|
|
26
|
-
- **An update task comes before your own work.** The daemon sends one when it must replace the pod your issue's roles run in, and your role prompt carries the steps: push every commit you want kept to the issue branch, call the `legion` tool's `ready_for_update` with the round id that task names, and end the turn. The daemon takes your answer for that round alone and refuses one that names another, so read the id from the task you answer. If your `legion` tool has no `ready_for_update` operation, push, then end your last message with a line that starts with WAITING and names the round, then end the turn: the daemon reads that turn's end as your answer. It completes no phase and ends none. After you answer you wait:
|
|
26
|
+
- **An update task comes before your own work.** The daemon sends one when it must replace the pod your issue's roles run in, and your role prompt carries the steps: push every commit you want kept to the issue branch, call the `legion` tool's `ready_for_update` with the round id that task names, and end the turn. The daemon takes your answer for that round alone and refuses one that names another, so read the id from the task you answer. If your `legion` tool has no `ready_for_update` operation, push, then end your last message with a line that starts with WAITING and names the round, then end the turn: the daemon reads that turn's end as your answer. It completes no phase and ends none. After you answer, you wait: start no further work on the issue until the daemon's next task reaches you.
|
|
27
27
|
- **Never start another Legion role**: the daemon starts every phase worker.
|
|
28
28
|
- **Never end your turn blocked on a decision someone else owns.** Send a product, scope, design, lifecycle or cross-phase decision to the owning architect as your role prompt says, with the issue, phase, verified observation, what you tried and the decision needed; a human-only to-do is a `dispatch ask`. Otherwise proceed: a phase that stops silently holds its issue until someone notices. Three waits stand rather than proceed, each with a WAITING line naming what it waits on: a planner on a decision the plan itself needs, because a plan completed around an open decision carries that gap into every later phase; a reviewer on a half of the round that has no review, which it neither approves nor reads in the agent's place (`skill://legion-worker/references/merge-gate.md`); and any pushing role whose second push still has not carried the pull request onto its commit, which waits rather than hand the next role a commit the pull request does not name (*Every role pushes its own commits*, below).
|
|
29
29
|
- **No surface reaches the changed path** is a report to the architect, never a reason to complete (`skill://legion-worker/references/pr-body.md#when-no-surface-reaches-the-changed-path`).
|
|
@@ -50,7 +50,7 @@ Read each by its `skill://` link: a read by path stops at 300 lines.
|
|
|
50
50
|
|
|
51
51
|
- Before a push, run the identity check (`skill://legion-worker/references/default-branch-check.md`) and then, with the `$default` it set, read your branch's own commit messages: `jj -R "$LEGION_WORKSPACE" log -r "${default}@origin..@" -T 'description ++ "\n"'` — earlier phases' commits in it are expected; never `ancestors(@, 5)`, which stops at five where one measurement found branches of 12 and 28 commits, and never `description.first_line()`, which shows no trailer. Invent no trailer of your own: the pane's jj appends `Omp-Session:` to every commit the pane's shell makes, in any jj repository, and, for a repository the deployment names, the issue line `Dispatch: <KEY>` beside it, that one scoped to the pane's own workspace. A jj repository you clone or create under that workspace is stamped like the workspace, so a commit you make in one carries this deployment's issue key: clone a repository you will push elsewhere outside `$LEGION_WORKSPACE`, and push no commit made under it to a repository that takes no issue key. Three commits carry neither — one `git` made in the colocated workspace, one another process made outside the pane's shell, and, on the Claude harness, one a subagent's bash made, which may not carry the session's environment file (anthropics/claude-code#46696, which `packages/claude-envoy/hooks/session-hook.ts` records and ships a `dispatch` fallback for, though one measurement on the pinned release found those exports present there). A commit of yours that shows a line short is cured by describing it again, since the trailer is appended when a description is set. A re-describe appends the issue line only where the shell it runs in has the pane's jj config overlay, so it adds nothing in a shell that carries none — a subagent's bash, or a pane whose overlay the writer could not make. Where it adds nothing, write the line yourself: put `Dispatch: $LEGION_ISSUE_TRAILER` into the description as a trailer line of its own, and only when `LEGION_ISSUE_TRAILER` is set, since that variable is the deployment's own name for the key this repository takes, and an unset one means the repository takes no key and the line belongs in no commit of it. Look because a base branch can require the issue line in the commit that lands: a squash builds that message from the branch's commit messages, and it leaves a merge commit's message out, so the line belongs in an ordinary commit.
|
|
52
52
|
- Only work is pushed: code, red tests, a forward merge, a rewrite, and the empty commit that carries the pull request onto the commit you pushed (the bullet below). No commit message carries a line or bracket keyword that stops GitHub's workflows (`[skip ci]` and its kin), since every head needs its own checks and a base that requires a check will not merge a head whose checks never ran. Retro pushes nothing: it records what the work taught with `dispatch comment` on the issue.
|
|
53
|
-
- **After a push, read the pull request's head and check that it is your commit.** A branch and a pull request are two objects on GitHub: the push moves the branch, and GitHub then moves the pull request onto the new commit, which is what starts its checks
|
|
53
|
+
- **After a push, read the pull request's head and check that it is your commit.** A branch and a pull request are two objects on GitHub: the push moves the branch, and GitHub then moves the pull request onto the new commit, which is what starts its checks, and a push GitHub does not follow leaves the newer commit with no checks while Legion reads and tests the older one. The step applies once the branch has an open pull request, whose number your task's `Pull request:` line names (`gh pr list --repo <the issue's repository> --head legion/<KEY> --state open --json number --jq '.[0].number'` when it names none): run `gh pr view <n> --repo <the issue's repository> --json headRefOid --jq .headRefOid` about ten seconds after your push, again about ten seconds later, and a last time about thirty seconds after that, with a read that gives the pushed commit ending the step there and only the last read deciding a mismatch, and compare each answer with the commit you pushed, which `jj -R "$LEGION_WORKSPACE" log -r legion/<KEY>@origin --no-graph -T commit_id` prints in the 40 characters `headRefOid` answers in. This read is of the pull request's own head and of no check, so the wait it makes is not a wait on CI (`skill://legion-worker/references/pr-body.md#never-waiting-on-ci`). When the last read still is not your commit, carry the pull request with a commit of its own, an empty one when your work is complete and an empty one just as much when `@` holds work of yours, since a push of a commit the branch already holds moves no ref; the push section of your role prompt gives the one `jj` recipe, which leaves `@` and everything in it where it is. A new head makes every result recorded at the old head older, so record each `before_merge` check again at the new head. When that second push does not carry the pull request either, tell your architect the commit you pushed, the head each read gave and the time of each, and end the turn with a WAITING line naming that answer rather than completing: a phase completed here hands the next role a commit the pull request does not name. The push you make to answer an update task is the exception: that task has you answer the daemon and end the turn at once, so make this read in your next turn, before your phase completes. The merger pushes nothing, so this step never falls to it; it reports a mismatch it sees to the architect.
|
|
54
54
|
- A planner whose issue moved back from implementing starts on the remote tip, `jj -R "$LEGION_WORKSPACE" new legion/<KEY>@origin`, so a commit it makes never sits on the implementer's unpushed commits.
|
|
55
55
|
|
|
56
56
|
## PR body, review, and the merge gate
|
|
@@ -30,7 +30,7 @@ later phase keeps it current rather than replacing it:
|
|
|
30
30
|
- Thread <node id>: accepted by the reviewer — <its reason, one line>; resolved at <head-sha>.
|
|
31
31
|
- Thread <node id>: still open — <what remains>; unresolved at <head-sha>.
|
|
32
32
|
|
|
33
|
-
**Thermo:** `
|
|
33
|
+
**Thermo:** `simplify-settled-diff` once at <head-sha>: <0 applied | applied → new head <sha>>; defects reported: <none | <n>, fixed in <sha>>; thermonuclear pair at the reviewed head <sha>:
|
|
34
34
|
<verdict>. (on a docs-only PR the simplify half and the defects are recorded as on any other diff, and the pair half reads `thermonuclear pair: not run (docs-only)`)
|
|
35
35
|
|
|
36
36
|
**Checks:** one line per `check` block of the issue's Verification document, in the document's
|
|
@@ -181,7 +181,7 @@ gap and decides there, which is the only gate on such an issue.
|
|
|
181
181
|
real-surface verification is not repeated, except in a parent's last round, which the architect
|
|
182
182
|
or the implementer's forward-merge comment names to you: then run a full test round. Different:
|
|
183
183
|
a full test round.
|
|
184
|
-
- **The implementer runs `skill://
|
|
184
|
+
- **The implementer runs `skill://simplify-settled-diff` once per pull request, in its first
|
|
185
185
|
implementing round, after its own results and before it completes that round,
|
|
186
186
|
whatever the diff touches, a docs-only diff included.** The daemon starts no implementing round
|
|
187
187
|
between a clean review and the approval, so this is the one slot before the tester and the
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
2
|
+
name: simplify-settled-diff
|
|
3
3
|
description: "Simplify settled, recently changed code for clarity, reuse, quality, and efficiency while preserving behavior. Use after implementation and before review."
|
|
4
4
|
argument-hint: "[blank to simplify current branch changes, or describe what to simplify]"
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
Simplify recently changed code for clarity, reuse, quality, and efficiency while preserving exact behavior. Prioritize readable, explicit code over compact code — fewer lines is not the goal.
|
|
8
8
|
|
|
9
|
+
Legion's fork of the MIT-licensed Compound Engineering `ce-simplify-code` skill (LICENSE beside this file), renamed so a session that also installs the upstream pool loads one of the two by name.
|
|
9
10
|
|
|
10
11
|
## Step 1: Identify scope
|
|
11
12
|
|
|
@@ -15,11 +16,11 @@ Resolve the simplification scope in this order:
|
|
|
15
16
|
2. **Otherwise, in git**, use the current branch versus its base. Without a usable base, use staged and unstaged changes (`git diff HEAD`).
|
|
16
17
|
3. **Outside git or without a diff**, use files the user named or that were edited earlier in the conversation.
|
|
17
18
|
|
|
18
|
-
If none of the above produces a non-empty scope, stop and ask the user what to simplify rather than guessing
|
|
19
|
+
If none of the above produces a non-empty scope, stop and ask the user what to simplify rather than guessing, with the host's blocking question tool, matched by capability and not by another host's name. A tool in the current list exists; never call a question tool to ask whether it exists. Where the list names one that is not loaded, load it with the host's tool-discovery primitive. Fall back to numbered options on the user-visible chat surface only where the host lists no such tool or a real call to it errors. Never silently skip the question.
|
|
19
20
|
|
|
20
21
|
**Preflight.** Every file of the scope is in the pass: documentation, workflow and configuration files as much as code, and a scope that holds no code at all still runs. A pass that drops the documentation drops the files a wrong procedure lives in, which is the failure this rule exists to stop. Read generated, vendored and lockfile content for what it shows and edit none of it. This is never a size gate: explicit small scopes still run, and callers own any size or cost threshold.
|
|
21
22
|
|
|
22
|
-
|
|
23
|
+
Report the review, apply and verification outcomes together; do not open one task per reviewer.
|
|
23
24
|
|
|
24
25
|
## Step 2: Launch 3 review agents in parallel
|
|
25
26
|
|
|
@@ -31,7 +32,7 @@ Dispatch three generic subagents — code-reuse, code-quality, and efficiency re
|
|
|
31
32
|
|
|
32
33
|
Do not paraphrase these rubrics from memory — read each file and pass it verbatim, or the reviewer loses the gating rules that keep the pass behavior-preserving.
|
|
33
34
|
|
|
34
|
-
**Bounded dispatch.**
|
|
35
|
+
**Bounded dispatch.** Launch only as many reviewers as the harness accepts at once, and read a concurrency or active-agent-limit error as backpressure: leave the reviewer queued and retry when a slot frees, rather than record it as a reviewer failure. Where a dispatch fails for a reason that survives correcting the call, run that reviewer's pass inline with the same prompt asset and say so in one line.
|
|
35
36
|
|
|
36
37
|
**Agent.** In Oh My Pi, dispatch each persona as the bundled reviewer, `task(agent="reviewer")`. Each runs as a job of its own, so `wait` for its result and read the findings from what it returns. Which model that agent runs on is the operator's configuration.
|
|
37
38
|
|
|
@@ -51,7 +52,7 @@ An interface or data shape that existed only in an earlier iteration of the curr
|
|
|
51
52
|
|
|
52
53
|
**Never simplify away a safety check.** Preserve trust-boundary validation, data-loss protection, security checks, and accessibility affordances. Skip any finding that would thin or remove one.
|
|
53
54
|
|
|
54
|
-
**Honor caller
|
|
55
|
+
**Honor a plan the caller passed as context.** A plan the brief names as context is not scope: preserve each decision it marks `session-settled:`, including a duplication or a separation it made on purpose.
|
|
55
56
|
|
|
56
57
|
## Step 4: Verify behavior is preserved
|
|
57
58
|
|
package/package.json
CHANGED
package/scripts/build.ts
CHANGED
|
@@ -59,11 +59,14 @@ export const CLAUDE_TOOL_NAMES: Readonly<Record<string, string | null>> = {
|
|
|
59
59
|
|
|
60
60
|
/** One pi-legion agent file in Claude Code's agent format. The frontmatter keeps `name`,
|
|
61
61
|
* `description` and `color`; `tools` is mapped through `CLAUDE_TOOL_NAMES`; `autoloadSkills`
|
|
62
|
-
* becomes `skills`, each the plugin
|
|
62
|
+
* becomes `skills`, each namespaced by the plugin that ships it — `legion:<skill>` for one the
|
|
63
|
+
* generated plugin stages, `claude-envoy:<skill>` for one this package ships, since a phase
|
|
64
|
+
* worker installs both and Claude Code resolves a namespaced name in its own plugin alone;
|
|
65
|
+
* `model` (an Oh My Pi model
|
|
63
66
|
* role, which Claude Code does not read, so the agent runs on the pane's model) and every
|
|
64
67
|
* comment are dropped. The body is kept as it is. No shipped agent declares `blocking`
|
|
65
68
|
* (`packages/pi-legion/src/shipped-agents.test.ts`), so nothing here reads it. */
|
|
66
|
-
export function claudeAgent(file: string, source: string): string {
|
|
69
|
+
export function claudeAgent(file: string, source: string, legionSkills?: Set<string>): string {
|
|
67
70
|
const match = /^---\n([\s\S]*?)\n---\n/.exec(source)
|
|
68
71
|
if (match === null) throw new Error(`${file} has no frontmatter`)
|
|
69
72
|
const lines: string[] = []
|
|
@@ -93,7 +96,12 @@ export function claudeAgent(file: string, source: string): string {
|
|
|
93
96
|
} else if (key === "autoloadSkills") {
|
|
94
97
|
const skills = /^\[(.*)\]$/.exec(value)?.[1]
|
|
95
98
|
if (skills === undefined) throw new Error(`${file}'s autoloadSkills is not a flow list`)
|
|
96
|
-
const names = skills.split(",").map((skill) =>
|
|
99
|
+
const names = skills.split(",").map((skill) => {
|
|
100
|
+
const name = skill.trim()
|
|
101
|
+
const plugin =
|
|
102
|
+
legionSkills === undefined || legionSkills.has(name) ? "legion" : "claude-envoy"
|
|
103
|
+
return `${plugin}:${name}`
|
|
104
|
+
})
|
|
97
105
|
lines.push(`skills: [${names.join(", ")}]`)
|
|
98
106
|
} else {
|
|
99
107
|
lines.push(line)
|
|
@@ -207,11 +215,19 @@ export async function buildLegionPlugin(outdir: string): Promise<string[]> {
|
|
|
207
215
|
}
|
|
208
216
|
reads.push(source)
|
|
209
217
|
}
|
|
218
|
+
// The skills this generated plugin stages, so an agent's `autoloadSkills` entry that is not one
|
|
219
|
+
// of them is namespaced to the package that does ship it (this one), which a phase worker
|
|
220
|
+
// installs beside this plugin.
|
|
221
|
+
const legionSkills = new Set(
|
|
222
|
+
(await readdir(stagedSkills, { withFileTypes: true }))
|
|
223
|
+
.filter((entry) => entry.isDirectory())
|
|
224
|
+
.map((entry) => entry.name),
|
|
225
|
+
)
|
|
210
226
|
const agents = join(repoRoot, "packages", "pi-legion", "agents")
|
|
211
227
|
await mkdir(join(outdir, "agents"))
|
|
212
228
|
for (const name of (await readdir(agents)).filter((file) => file.endsWith(".md")).sort()) {
|
|
213
229
|
const source = await readFile(join(agents, name), "utf8")
|
|
214
|
-
await writeFile(join(outdir, "agents", name), claudeAgent(name, source))
|
|
230
|
+
await writeFile(join(outdir, "agents", name), claudeAgent(name, source, legionSkills))
|
|
215
231
|
reads.push(join(agents, name))
|
|
216
232
|
}
|
|
217
233
|
await mkdir(join(outdir, "hooks"))
|
|
@@ -8,19 +8,6 @@ Copied from danyuchn/asd-ste100-skill at 32511c69 under its MIT licence (LICENSE
|
|
|
8
8
|
|
|
9
9
|
# Simplified Technical English (ASD-STE100)
|
|
10
10
|
|
|
11
|
-
ASD-STE100 is a controlled-language standard built by the aerospace and defense industry (ASD, the AeroSpace and Defense Industries Association of Europe) to stop maintenance technicians from misreading English instructions. The standard removes the two biggest sources of misreading: words with more than one meaning, and sentences with more than one possible structure.
|
|
12
|
-
|
|
13
|
-
This skill borrows that same discipline for a different reader: an **AI agent or a downstream system** that has to parse an English string — an error message, a tool description, an inter-agent instruction, a status report — without a human in the loop to resolve ambiguity. If a maintenance technician can misread "close the valve" as an adjective ("the valve that is near") instead of a command, so can a language model.
|
|
14
|
-
|
|
15
|
-
## When to Use This Skill
|
|
16
|
-
|
|
17
|
-
- An agent's output (explanation, instruction, log message, tool description) reads as dense, jargon-heavy, or ambiguous.
|
|
18
|
-
- Text will be consumed by another agent, a translation pipeline, or a non-native English reader, and misparsing has a real cost.
|
|
19
|
-
- You are writing a prompt, system message, or tool description and want to remove ambiguity before a model ever sees it.
|
|
20
|
-
- You want a **before/after** comparison showing exactly which rule was violated and how the rewrite fixes it. Ask for it — the default output is the rewritten text alone (see Output Format).
|
|
21
|
-
|
|
22
|
-
This skill is not for creative or marketing copy — STE is deliberately flat and literal. Do not apply it to text where voice, nuance, or persuasion is the point.
|
|
23
|
-
|
|
24
11
|
## Two Modes
|
|
25
12
|
|
|
26
13
|
Pick a mode before rewriting. If the user does not say which, infer it from the text type. Keep the choice internal unless the user asks for the rule table (see Output Format).
|
|
@@ -33,11 +20,11 @@ The two modes and the structural/lexical split are the same distinction seen fro
|
|
|
33
20
|
|
|
34
21
|
## Source and Scope
|
|
35
22
|
|
|
36
|
-
|
|
23
|
+
The rule summary, its citations and worked examples are in `references/writing-rules.md` and `examples/before-after.md`.
|
|
37
24
|
|
|
38
25
|
It does **not** reproduce ASD's ~900-word approved dictionary verbatim. ASD-STE100 is free to obtain, but it is not free to redistribute: Issue 9, page 2 states that "no reproduction or publication of it, in whole or in part, shall be made without the written authority of an officer of ASD," and grants free reproduction rights only to eight listed categories (ASD/AIA/AIAC member associations and their member companies and customers, member-state defence ministries, A4A, airworthiness authorities, and universities and research institutes for educational purposes). This project is in none of them, so the dictionary stays out of this repo.
|
|
39
26
|
|
|
40
|
-
Instead, this skill applies the *underlying principle* (pick the plainest, most common word available and use it the same way every time) rather than checking against a fixed word list. When exact ASD-approved wording matters
|
|
27
|
+
Instead, this skill applies the *underlying principle* (pick the plainest, most common word available and use it the same way every time) rather than checking against a fixed word list. When exact ASD-approved wording matters, get the standard and check word-by-word against the real dictionary.
|
|
41
28
|
|
|
42
29
|
## Core Rewrite Rules
|
|
43
30
|
|
|
@@ -134,7 +121,3 @@ Follow the table with a one-line note on anything you deliberately did **not** s
|
|
|
134
121
|
- Make weak content true or useful. STE fixes the *form* of a text, not its substance. A hollow paragraph rewritten under these rules becomes a clean, short, well-punctuated hollow paragraph. If the text has nothing to say, no rewrite fixes that — say so instead of polishing it.
|
|
135
122
|
- Shorten past the point of clarity. Cutting words is not the goal. Removing ambiguity is the goal. Past a certain point compression starts costing the reader time rather than saving it, so stop when the sentence is unambiguous, not when it is shortest.
|
|
136
123
|
|
|
137
|
-
## Additional Resources
|
|
138
|
-
|
|
139
|
-
- **`references/writing-rules.md`** — fuller summary of the 9 rule sections and dictionary structure, with citations to the official standard and secondary sources.
|
|
140
|
-
- **`examples/before-after.md`** — worked examples, including official STE examples and agent-output examples built for this skill.
|
|
@@ -18,7 +18,7 @@ dispatch search --query 'reviewer threads OR review comments'
|
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
- No hits: remove a word before you add one. Try two or three wordings before you decide nothing exists.
|
|
21
|
-
- Open each hit that can be yours with `dispatch read --issue KEY`, then its parent (`child_of` under `Links:`, or a document's `Issue:`).
|
|
21
|
+
- Open each hit that can be yours with `dispatch read --issue KEY`, then its parent (`child_of` under `Links:`, or a document's `Issue:`), with its status and recent events.
|
|
22
22
|
|
|
23
23
|
## What to do with what you find
|
|
24
24
|
|
|
@@ -28,6 +28,12 @@ dispatch search --query 'reviewer threads OR review comments'
|
|
|
28
28
|
- **Question already decided:** the answered ask is the record. Cite it (`dispatch://KEY/ask/<id>`). Do not ask again.
|
|
29
29
|
- **Duplicate found:** keep the issue with the spec, copy to it what only the duplicate has, and close the duplicate (`--status done --reason 'Duplicate of dispatch://KEY.'`). When it has the `legion` label or another holder's claim, comment the kept issue's name on it instead.
|
|
30
30
|
|
|
31
|
+
## Research before you ask
|
|
32
|
+
|
|
33
|
+
- Research when a file, command or document can show the answer (a pattern, a convention, a solved problem, a technical approach), because a person must not answer twice what the repository already records.
|
|
34
|
+
- Ask a person only for what their authority, taste or risk appetite settles, because no file holds that. Where a file already records the decision, cite it (`file:line`) and follow it; ask again only when the facts it rested on changed.
|
|
35
|
+
- Say what you searched: each part you found with its source, and each part you did not, with the queries you ran. Ask only the part no search answered.
|
|
36
|
+
|
|
31
37
|
## Reach a person only through Dispatch
|
|
32
38
|
|
|
33
39
|
Reach a person through an ask, an ask block or an approval request.
|
|
@@ -39,16 +39,18 @@ For each spec, ask, comment and message:
|
|
|
39
39
|
- Link each source where the person wrote it, each id whole. With no link, state the design.
|
|
40
40
|
- In a spec, cite code by file and symbol, never a line number: it goes stale at the next edit.
|
|
41
41
|
- A sentence that cites a gate passing (test, review, check) also says what the pass does not show: "Tests pass: a wrong verdict, not a missing one."
|
|
42
|
-
- Keep only text
|
|
43
|
-
- Explain each name a new reader may not know, and what each issue you name does for them.
|
|
42
|
+
- Keep only text a reader needs to understand, decide, build or check, and say what each issue you name does for them (`skill://plain-words`).
|
|
44
43
|
- In an ask, ask block, comment or message, name a requirement or check by what it is, never its number.
|
|
45
44
|
|
|
46
45
|
## Questions
|
|
47
46
|
|
|
48
47
|
- Name the concrete case and its numbers, then the choice in those terms, never "Which option?".
|
|
49
|
-
- A choice inside what the person asked for,
|
|
48
|
+
- A choice inside what the person asked for, one their messages favour, routine cleanup, sequencing, naming, a choice between equivalent options, and a fix you can make are yours.
|
|
50
49
|
- Ask only for the person's authority, taste or risk appetite, when options differ on what they care about.
|
|
51
|
-
- Ask with an [ask block](skill://dispatch/SKILL.md#asks-and-ask-blocks): 2 to 4 options, answerable on a phone.
|
|
50
|
+
- Ask with an [ask block](skill://dispatch/SKILL.md#asks-and-ask-blocks): 2 to 4 options, answerable on a phone, and name nothing the reader cannot see from it ("the message above").
|
|
51
|
+
- For each technical term you coined in this session, count the files that hold it, in the repositories the work touches and in Dispatch, by exact match; a single-digit count means expand the term or drop it, because a term you coined reads as familiar to you. A count misses a coinage made of common words, so read the draft for those too.
|
|
52
|
+
- Measure each claim the ask rests on, its premise and each option's precondition. Where you cannot, mark the claim unverified and name the measurement that is missing; call an option unavailable only where a precondition is shown to fail. A premise can go stale within the hour, and no unmeasured number goes in one.
|
|
53
|
+
- Before you pass a question on as one only an attended or privileged act answers, name the source that answers it and try that source, then the other records that hold it, because a 403 or an unfamiliar surface does not make a fact unknowable. Keep a privileged read for what only the live system knows.
|
|
52
54
|
|
|
53
55
|
## Each version
|
|
54
56
|
|
package/skills/envoy/SKILL.md
CHANGED
|
@@ -70,7 +70,7 @@ Every topic starts with `notifications.`.
|
|
|
70
70
|
- One `pr.<n>.checks` event arrives per commit whose checks settle, the head or not. Compare its `sha` with the head you wait on, because an earlier commit's settlement can arrive first. A commit whose message carries one of GitHub's skip keywords (`[skip ci]` and its kin) starts no workflow, so no settlement of it may ever arrive.
|
|
71
71
|
- Settlement waits until the commit has had no check event for 5 seconds (`ENVOY_CI_DEBOUNCE`) and every reported check run and check suite of it has finished. No event arrives before that. Envoy does not read GitHub's required-checks list, so a green settlement does not mean GitHub will merge the PR.
|
|
72
72
|
- A `pr.<n>` event with `closed` and `merged: true` means the PR merged; it carries `merge_commit_sha`, `merged_by` and `head_sha`.
|
|
73
|
-
-
|
|
73
|
+
- Code that orders settlements of one commit follows `skill://envoy/references/check-settlement.md`.
|
|
74
74
|
- A Legion implementer waits this way only on a re-run of a red check its task names. Otherwise it pushes and completes its phase, and the daemon reads CI for it (`skill://legion-worker`).
|
|
75
75
|
|
|
76
76
|
## Roles and team topics
|
|
@@ -50,14 +50,13 @@ report, a disclosure, and a reply to a maintainer who wrote first.
|
|
|
50
50
|
do: a reader of the same model as the writer is the weaker check, though no measurement here
|
|
51
51
|
separates the two.
|
|
52
52
|
|
|
53
|
-
**Step 4 ends with a list of what it removed, and that list goes in the ask.**
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
sentence "the reviewer removed nothing", which is itself an answer.
|
|
53
|
+
**Step 4 ends with a list of what it removed, and that list goes in the ask.** An instruction alone
|
|
54
|
+
does not make the cut happen, so the list is what proves it did: three lines naming what came out,
|
|
55
|
+
or the sentence "the reviewer removed nothing", which is itself an answer.
|
|
56
|
+
|
|
57
|
+
**The text the operator approves is the text the reviewer cut, byte for byte.** Any edit after the
|
|
58
|
+
cut, even one line of fact, sends the text back through step 1 and a new fresh review, because a
|
|
59
|
+
sentence added after the cut reaches the operator unreviewed.
|
|
61
60
|
|
|
62
61
|
The form of the text is not in this skill. Where the stream that owns the relationship keeps its own
|
|
63
62
|
rules for writing to maintainers — in its project's `AGENTS.md`, in its skills, or in its brief —
|
|
@@ -85,24 +84,6 @@ An ask for an outside message has, in this order:
|
|
|
85
84
|
Link the research, not the message. An ask with no removal line has not had step 4, whatever it
|
|
86
85
|
says.
|
|
87
86
|
|
|
88
|
-
## Never write these
|
|
89
|
-
|
|
90
|
-
Delete the empty verb phrases and say the literal thing instead. These shapes:
|
|
91
|
-
|
|
92
|
-
| Never | Write instead |
|
|
93
|
-
|---|---|
|
|
94
|
-
| "to name the problem" | say the problem |
|
|
95
|
-
| "land the change" | merge it, release it, deploy it — whichever it is |
|
|
96
|
-
| "carry the finding to X" | tell X, send X, put it on the issue |
|
|
97
|
-
| "this shows the gap" | the gap is … |
|
|
98
|
-
| "that pays for itself" | it costs $X and returns $Y |
|
|
99
|
-
|
|
100
|
-
The test: delete the verb phrase and ask what literally happens. If you cannot say what happens, you
|
|
101
|
-
did not know, and the phrase hid that from both of you. Write what happens.
|
|
102
|
-
|
|
103
|
-
The same rule runs over asks, specs, messages, commit bodies and pull-request descriptions, not only
|
|
104
|
-
outside messages. `skill://plain-words` has the full list and the rewrites.
|
|
105
|
-
|
|
106
87
|
## What this skill does not cover
|
|
107
88
|
|
|
108
89
|
- Text written in a person's own name, which that person signs off.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: plain-words
|
|
3
|
-
description: "Use before you send or publish any text a person reads: an ask, a spec, a Dispatch comment, a message to a colleague, a pull-request body, a commit message, a report, a status update. It removes empty verb phrases and replaces each with the literal thing.
|
|
3
|
+
description: "Use before you send or publish any text a person reads: an ask, a spec, a Dispatch comment, a message to a colleague, a pull-request body, a commit message, a report, a status update. Also use before you answer a question a person asked, and before a draft goes to a reviewer. It removes empty verb phrases and replaces each with the literal thing."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Say the literal thing
|
|
@@ -10,59 +10,51 @@ thing instead.
|
|
|
10
10
|
|
|
11
11
|
Run this over your text before you send it. It takes a minute and it is not optional.
|
|
12
12
|
|
|
13
|
-
##
|
|
14
|
-
|
|
15
|
-
Take the verb phrase out and ask: **what literally happens?** Write that. If you cannot say what
|
|
16
|
-
happens, you did not know, and the phrase hid it from you as well as from the reader.
|
|
17
|
-
|
|
18
|
-
## The phrases, in the order agents actually use them
|
|
13
|
+
## Answering a question
|
|
19
14
|
|
|
20
|
-
|
|
15
|
+
1. Answer the exact question, only it, in the order it was asked, because anything else reads as
|
|
16
|
+
evasion and the question comes again.
|
|
17
|
+
2. Start from what happens, not from a setting, a flag or a name: the reader can reach the setting
|
|
18
|
+
from the behaviour, not the reverse.
|
|
19
|
+
3. Define each term where you first use it, in literal words. No analogy: the reader cannot tell
|
|
20
|
+
which part of one is true.
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|---|---:|---|
|
|
24
|
-
| land the change, land the PR | **1,053** | merge it, release it, deploy it, apply it — whichever one it is |
|
|
25
|
-
| unblock the work | 151 | X can start once Y merges |
|
|
26
|
-
| name the problem, name the owner, name a date | 23 | say the problem; who owns it is X; it is due on 11-02 |
|
|
27
|
-
| it pays for itself, that pays | 13 | it costs $16,306 and returns $60,379 a month |
|
|
28
|
-
| carry it to X, carry the finding | 11 | tell X; send it to X; put it on the issue |
|
|
29
|
-
| this shows the gap, the number shows | 5 | the gap is 12 of 30; the number is 1.17 |
|
|
22
|
+
## Before you send
|
|
30
23
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
24
|
+
A fresh session that has only what the reader has removes what the reader does not need, and lists
|
|
25
|
+
every term it cannot define. Fix each listed term. A reviewer that reads only to approve has not
|
|
26
|
+
done this step, and an instruction alone did not make it happen, so the two lists are what show it
|
|
27
|
+
ran. The check runs on the text going to the reader, never on the instructions you give that
|
|
28
|
+
session or on what it sends back, which would never end.
|
|
34
29
|
|
|
35
|
-
|
|
36
|
-
skill and without it (11 drafts against 10, over 72). Use the test rather than the row: if deleting
|
|
37
|
-
"name" leaves a sentence that says what happens, delete it; if it does not, you were about to write
|
|
38
|
-
a verb for an action you had not decided on.
|
|
30
|
+
## The test
|
|
39
31
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
costs a reader attention and buys nothing.
|
|
32
|
+
Take the verb phrase out and ask: **what literally happens?** Write that. If you cannot say what
|
|
33
|
+
happens, you did not know, and the phrase hid it from you as well as from the reader.
|
|
43
34
|
|
|
44
|
-
##
|
|
35
|
+
## The phrases, commonest first
|
|
45
36
|
|
|
46
|
-
|
|
47
|
-
|
|
37
|
+
| Never | What to write |
|
|
38
|
+
|---|---|
|
|
39
|
+
| land the change, land the PR | merge it, release it, deploy it, apply it — whichever one it is |
|
|
40
|
+
| unblock the work | X can start once Y merges |
|
|
41
|
+
| name the problem, name the owner, name a date | say the problem; who owns it is X; it is due on <date> |
|
|
42
|
+
| it pays for itself, that pays | it costs $16,306 and returns $60,379 a month |
|
|
43
|
+
| carry it to X, carry the finding | tell X; send it to X; put it on the issue |
|
|
44
|
+
| this shows the gap, the number shows | the gap is 12 of 30; the number is 1.17 |
|
|
48
45
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
Either recommend it or do not raise it.
|
|
46
|
+
The rows are in the order agents write them, so look for the first row first: you reach for "land"
|
|
47
|
+
when you cannot say whether the thing merged, released or deployed. If you can say which, say it.
|
|
48
|
+
If you cannot, that is the sentence — "it is approved and not merged" — and it is more useful than
|
|
49
|
+
any verb.
|
|
54
50
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
phrases live.
|
|
51
|
+
On the "name the X" row an instruction alone does not work, so use the test: delete "name". If the
|
|
52
|
+
sentence then says what happens, keep it that way; if it says nothing, you had not decided the
|
|
53
|
+
action, so decide it and write it.
|
|
59
54
|
|
|
60
55
|
## Do not shout
|
|
61
56
|
|
|
62
|
-
|
|
63
|
-
obnoxious format with all caps headers and stuff?
|
|
64
|
-
|
|
65
|
-
No capitalised headers. No capitalised phrases for emphasis. Bold only where a number, a name or a
|
|
57
|
+
No ALL-CAPS headings. No ALL-CAPS phrases for emphasis. Bold only where a number, a name or a
|
|
66
58
|
choice needs to be found again.
|
|
67
59
|
|
|
68
60
|
The reason it appears: an agent writes a long passage, cannot find its point, and puts a handle on
|
|
@@ -86,3 +78,10 @@ collector collects, a sweep sweeps.
|
|
|
86
78
|
English. This skill removes verb phrases that carry no fact. Neither removes AI writing tells, so
|
|
87
79
|
where your session has a pass for those it is a third one. Run them all on an outside message
|
|
88
80
|
(`skill://outside-message`); run this one on everything.
|
|
81
|
+
|
|
82
|
+
The two passes themselves — the structural one and the one that removes the writing that marks
|
|
83
|
+
text as an agent's — are `skill://plain-words/references/mechanics.md`.
|
|
84
|
+
|
|
85
|
+
One kind of text may also have a form skill of its own — a comment to another project's
|
|
86
|
+
maintainers, a document a buyer reads — where the operator ships one; your stream's brief names
|
|
87
|
+
it. This skill holds for all text either way.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# The two passes over a draft
|
|
2
|
+
|
|
3
|
+
Read this when you have a draft and want the passes themselves, not the rule. The structural pass
|
|
4
|
+
makes a sentence hard to misread; the tells pass removes the writing that marks text as an agent's.
|
|
5
|
+
`skill://plain-words` holds the rule each pass serves: every verb names something that happened.
|
|
6
|
+
|
|
7
|
+
Run the structural pass first: a tell often disappears with the sentence that carried it.
|
|
8
|
+
|
|
9
|
+
## The structural pass
|
|
10
|
+
|
|
11
|
+
1. One instruction per sentence. A sentence that holds two actions hides the second from a reader
|
|
12
|
+
who stops at the first.
|
|
13
|
+
2. Active voice, with the actor named. "The job is retried" leaves the reader to guess who retries
|
|
14
|
+
it; "the daemon retries the job" does not.
|
|
15
|
+
3. Simple tenses. A compound tense carries a time relation the reader has to reconstruct, so keep
|
|
16
|
+
one only where that relation is the fact.
|
|
17
|
+
4. Write the thing, not its noun form: "the build failed", not "a build failure occurred". A noun
|
|
18
|
+
made from a verb drops the actor and the time.
|
|
19
|
+
5. Cut a noun stack to three words. Four or more leave the reader guessing which word modifies
|
|
20
|
+
which.
|
|
21
|
+
6. One idea per paragraph, and a list wherever you write three or more of anything. A reader
|
|
22
|
+
counts a list and cannot count a sentence.
|
|
23
|
+
7. Keep every qualifier, exception, number and hedge. Where keeping one makes the sentence long,
|
|
24
|
+
keep it long and say why: dropping "may" turns a possibility into a claim.
|
|
25
|
+
8. Use one word for one thing, through the whole text. A synonym reads as a second thing.
|
|
26
|
+
|
|
27
|
+
## The tells pass
|
|
28
|
+
|
|
29
|
+
1. Delete a sentence that says what you are about to say, or what you have just said. A reader who
|
|
30
|
+
has the point does not need it announced.
|
|
31
|
+
2. Delete praise of the work and of the reader: "great question", "a robust solution".
|
|
32
|
+
3. Delete the symmetry an agent reaches for: "not only X but also Y", "it is not just A, it is B".
|
|
33
|
+
Write the half that is true.
|
|
34
|
+
4. Delete a hedge that costs a second read: "it may be worth considering whether". Recommend it or
|
|
35
|
+
leave it out.
|
|
36
|
+
5. Delete a closing offer to do more. Where something remains, name it as the next step with its
|
|
37
|
+
owner.
|
|
38
|
+
6. Cut an em dash and a semicolon into two sentences, unless the aside is the fact.
|
|
39
|
+
7. Replace a word that rates the thing ("comprehensive", "significant", "seamless") with the
|
|
40
|
+
measurement that made you reach for it.
|
|
41
|
+
8. Read the first and last sentence of each paragraph alone. Where they say the same thing, delete
|
|
42
|
+
one.
|
|
43
|
+
|
|
44
|
+
## Where a fuller pass exists
|
|
45
|
+
|
|
46
|
+
`skill://asd-ste100` is the full controlled-language standard behind the structural pass: run it
|
|
47
|
+
where a reader must not misread one sentence. Neither pass here replaces `skill://plain-words`,
|
|
48
|
+
which is the rule both serve. Where your session installs a fuller pass of its own over AI writing
|
|
49
|
+
tells, run that one after the tells pass above; this file is what you run when it does not.
|
|
@@ -58,3 +58,13 @@ Then one entry per finding: `path:line`, the smell, the cost it adds, and the re
|
|
|
58
58
|
- A structural regression, a hacky or magic abstraction, a boundary leak, or a missed obvious decomposition blocks whatever the PR says, because no evidence makes the code easier to change.
|
|
59
59
|
- Every other finding blocks, and the verdict is CHANGES, unless the PR gives evidence that the simpler form fails: a caller it breaks, a measured cost, or a constraint outside the diff that the PR names with `path:line` or a link. "It works" and "tests pass" are no such evidence, because this review judges structure, not behavior.
|
|
60
60
|
- State a blocking finding as blocking, directly and without rudeness. A "maybe" or "consider" finding reads as optional and gets skipped.
|
|
61
|
+
|
|
62
|
+
## A reviewer rates, a lead decides
|
|
63
|
+
|
|
64
|
+
- Rate each finding; the lead disposes of it. Put on the must-fix list only a finding that has to
|
|
65
|
+
be fixed before this change ships, because a list that mixes those with the rest gets filtered
|
|
66
|
+
by nobody.
|
|
67
|
+
- The four dispositions the lead gives a finding are act on, consider, noted and dismissed. Write
|
|
68
|
+
each finding so the lead can place it: the evidence, the cost, and what it depends on.
|
|
69
|
+
- Do not review a diff you wrote. A reviewer that grades its own work reports no finding against
|
|
70
|
+
it, so hand the diff to a session that did not write it.
|
|
@@ -8,22 +8,18 @@ disable-model-invocation: true
|
|
|
8
8
|
|
|
9
9
|
If this skill disagrees with the code, a command's output or its `--help`, follow those and say which line of this skill is wrong.
|
|
10
10
|
|
|
11
|
-
Make your own scratch
|
|
12
|
-
|
|
13
|
-
`$TMPDIR` on the issue's volume, so a sweep like `rm -rf "$TMPDIR"/tmp.*` deletes directories
|
|
14
|
-
another role has open.
|
|
11
|
+
Make your own scratch as `skill://thermonuclear-code-quality` says, and delete only the paths
|
|
12
|
+
you made: every role of this issue writes into one shared `$TMPDIR`.
|
|
15
13
|
|
|
16
14
|
## Verdict
|
|
17
15
|
|
|
18
|
-
The first line of the report is the verdict, in exactly this form, because a PR gate reads only that line:
|
|
16
|
+
The first line of the report is the verdict, in exactly this form, because a PR gate reads only that line. `<sha>` is the short sha of the head you reviewed, or the sha your brief names when you have no shell:
|
|
19
17
|
|
|
20
18
|
- `Verdict: CHANGES at <sha>` when the report has a Medium or High finding.
|
|
21
19
|
- `Verdict: APPROVE at <sha>` when it has none. Minor findings do not block.
|
|
22
20
|
|
|
23
21
|
Priority: trace each finding end to end first. Minor changes no behavior, hides no error and breaks no gate; any other finding is Medium, or High when the report holds its trace, because developers who get false High findings stop listening.
|
|
24
22
|
|
|
25
|
-
`<sha>`: `git rev-parse --short=8 HEAD` at the head you reviewed, or the sha your brief names when you have no shell.
|
|
26
|
-
|
|
27
23
|
## Scope
|
|
28
24
|
|
|
29
25
|
Audit the checked-out branch. Report issues in code its diff adds or modifies, in the unchanged consumers check 2 finds, and in the PR body's claims (check 6), because the author fixes only this diff and the diff never shows them.
|
|
@@ -78,3 +74,13 @@ Only after your own audit, so others' findings do not steer it, and only with a
|
|
|
78
74
|
1. Read the PR/MR's comments and review comments, bots' included, with `gh` or `glab`.
|
|
79
75
|
2. Check their findings in the code: a comment is not evidence. Include the valid ones you missed; for one you share, add their evidence if yours lacks it.
|
|
80
76
|
3. Mark each finding that came from that discussion, so readers can tell it from yours.
|
|
77
|
+
|
|
78
|
+
## A reviewer rates, a lead decides
|
|
79
|
+
|
|
80
|
+
- Rate each finding; the lead disposes of it. Put on the must-fix list only a finding that has to
|
|
81
|
+
be fixed before this change ships, because a list that mixes those with the rest gets filtered
|
|
82
|
+
by nobody.
|
|
83
|
+
- The four dispositions the lead gives a finding are act on, consider, noted and dismissed. Write
|
|
84
|
+
each finding so the lead can place it: the trace, the consumer it breaks, and what it depends on.
|
|
85
|
+
- Do not review a diff you wrote. A reviewer that grades its own work reports no finding against
|
|
86
|
+
it, so hand the diff to a session that did not write it.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|