@outerlayer/cli 0.1.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +134 -0
- package/README.md +238 -77
- package/dist/agent-setup-IFH3FB5X.js +197 -0
- package/dist/build-TZUUTRGH.js +9 -0
- package/dist/build-info.json +1 -1
- package/dist/check-WQP2CZDW.js +94 -0
- package/dist/chunk-2E54Z3P5.js +232 -0
- package/dist/chunk-3TT7RQYB.js +55 -0
- package/dist/chunk-3YPKXE5L.js +1683 -0
- package/dist/{chunk-HNCCD2IX.js → chunk-5DLBAXY5.js} +209 -61
- package/dist/{chunk-R5KBGVII.js → chunk-5QRP3MVS.js} +30 -14
- package/dist/chunk-5Y3QQRUH.js +300 -0
- package/dist/chunk-6Y63SXFO.js +383 -0
- package/dist/chunk-774HEQL6.js +178 -0
- package/dist/chunk-7A6RVXPZ.js +2233 -0
- package/dist/chunk-7YIOOFVJ.js +71 -0
- package/dist/chunk-ABIWDUMS.js +104 -0
- package/dist/chunk-AUFG23AA.js +534 -0
- package/dist/chunk-B2G7JHHB.js +42 -0
- package/dist/chunk-BCJNHMZT.js +34 -0
- package/dist/chunk-BCLJSQCV.js +56 -0
- package/dist/chunk-BFESLKPP.js +61 -0
- package/dist/chunk-BJ3KTMDH.js +63 -0
- package/dist/chunk-BKO6JEZI.js +47 -0
- package/dist/chunk-BOLTI6LR.js +37 -0
- package/dist/chunk-CBPPJSAR.js +89 -0
- package/dist/chunk-CBZB6XY6.js +102 -0
- package/dist/{chunk-RCQXYLMO.js → chunk-DVDEBNQJ.js} +18 -18
- package/dist/{work-pr-cmd-GOYSPEN2.js → chunk-DVYHCMB2.js} +10 -25
- package/dist/{chunk-TFUIDMOB.js → chunk-EABW6AJQ.js} +12 -1
- package/dist/{chunk-KFYJV2ZG.js → chunk-EMY4I27X.js} +1 -1
- package/dist/{chunk-NTTPJV35.js → chunk-F47JBIAW.js} +3 -1
- package/dist/chunk-F6GFZXZ3.js +60 -0
- package/dist/{chunk-YOOSBOKS.js → chunk-F7CU5ABH.js} +1 -1
- package/dist/chunk-FAJSS2WN.js +1357 -0
- package/dist/chunk-FS2VYGZT.js +1764 -0
- package/dist/chunk-FV2CCGXK.js +9 -0
- package/dist/{chunk-BQB3U2VD.js → chunk-G7FSV7JX.js} +5113 -3729
- package/dist/{emit-cmd-TWSYYEZI.js → chunk-H5NCNVDA.js} +68 -17
- package/dist/chunk-HE2D4EY5.js +83 -0
- package/dist/chunk-L2DBRKRA.js +94 -0
- package/dist/chunk-LF6MLJCY.js +38 -0
- package/dist/chunk-M5POMKKW.js +1051 -0
- package/dist/{mcp-install-cmd-FDQH6SEN.js → chunk-MQ3IPHIZ.js} +35 -18
- package/dist/{chunk-D77LS3UI.js → chunk-N5FOE5PS.js} +33 -4
- package/dist/chunk-N6LURUEF.js +64 -0
- package/dist/chunk-NYC54VBD.js +1084 -0
- package/dist/chunk-OGFGZQA3.js +23 -0
- package/dist/chunk-QOZKPLVJ.js +226 -0
- package/dist/chunk-RA3O54FC.js +30 -0
- package/dist/chunk-TBT347UY.js +41 -0
- package/dist/{chunk-3VQ4XXQA.js → chunk-UFFXNXLQ.js} +115 -71
- package/dist/chunk-USO2DKBD.js +421 -0
- package/dist/chunk-W4SQCOZU.js +206 -0
- package/dist/{chunk-A3WLZX2F.js → chunk-WIOZAJ2W.js} +15 -2
- package/dist/chunk-WO2BXCTQ.js +83 -0
- package/dist/chunk-WZBHBH3J.js +20 -0
- package/dist/{chunk-IWIUYLDR.js → chunk-XCCLFVXM.js} +118 -189
- package/dist/{context-materialize-J6CRQ7O7.js → chunk-XDDW4FRS.js} +134 -26
- package/dist/chunk-YYYXRJUW.js +101 -0
- package/dist/chunk-ZM2IMMYN.js +76 -0
- package/dist/chunk-ZMYPLFG3.js +71 -0
- package/dist/chunk-ZNA27WEV.js +470 -0
- package/dist/{cli-EFJIG2VT.js → cli-NHUXABYH.js} +597 -965
- package/dist/{paths-D2VGWWFI.js → cli-build-K56DK4DS.js} +1 -1
- package/dist/config-XVJYZ4IQ.js +9 -0
- package/dist/connect-cmd-OOG4TPU7.js +16 -0
- package/dist/context-adopt-UMA4O5NY.js +105 -0
- package/dist/context-materialize-G2FUFC72.js +19 -0
- package/dist/dist-RW4UPPC2.js +6 -0
- package/dist/docker-NEGDLU6D.js +7 -0
- package/dist/doctor-53F2PYY7.js +43 -0
- package/dist/doctor-UFVL4PZY.js +426 -0
- package/dist/{emit-artifact-cmd-KPPD3YLO.js → emit-artifact-cmd-KTYW2TN2.js} +25 -19
- package/dist/emit-cmd-DCERAU27.js +9 -0
- package/dist/emit-criteria-cmd-VAUUSAYD.js +166 -0
- package/dist/{emit-finding-cmd-VR5VEGXJ.js → emit-finding-cmd-UR4ID45Z.js} +35 -30
- package/dist/{emit-result-cmd-YOA5BJKL.js → emit-result-cmd-FDTUKGKE.js} +35 -61
- package/dist/exec-client-4XGXV3XN.js +8 -0
- package/dist/guest-init-GENRHNP7.js +8 -0
- package/dist/hook-fast-EYENPK6F.js +9 -0
- package/dist/{hook-wrap-fast-KXYNX3AD.js → hook-wrap-fast-NPLHJXFK.js} +2 -2
- package/dist/host-key-KDYZ5ECC.js +7 -0
- package/dist/import-capture-cmd-AVZ4VIVJ.js +68 -0
- package/dist/{import-ruler-cmd-7LH2QOMG.js → import-ruler-cmd-GUHL6IY5.js} +1 -1
- package/dist/index.js +4 -4
- package/dist/init-DXBCOAJK.js +36 -0
- package/dist/init-YEXK35CF.js +221 -0
- package/dist/init-cmd-NHR7PRSQ.js +135 -0
- package/dist/install-cmd-7WXOIFDO.js +55 -0
- package/dist/lima-XN65D7GN.js +55 -0
- package/dist/login-browser-7XGSV7MA.js +10 -0
- package/dist/{config-POF7DEQW.js → logout-cmd-QAUFDJ6J.js} +3 -1
- package/dist/{logs-TRNPQM42.js → logs-7RYUH5A6.js} +1 -1
- package/dist/loop-VZOLL4WQ.js +43 -0
- package/dist/machine-WSG52J75.js +35 -0
- package/dist/mcp-install-cmd-RLK4SO3N.js +9 -0
- package/dist/{mcp-serve-cmd-57EZZOTL.js → mcp-serve-cmd-JPTP5FMS.js} +20 -9
- package/dist/paths-OYKMVYJP.js +6 -0
- package/dist/{pidfile-PTW76F56.js → pidfile-UZRH774M.js} +2 -3
- package/dist/real-deps-SU24ZA2K.js +21 -0
- package/dist/relay-L76HDX72.js +46 -0
- package/dist/settings-J2652U5N.js +7 -0
- package/dist/starter-pack-LIZYMKYQ.js +10 -0
- package/dist/{status-JHVSZYC5.js → status-2UZKKNB7.js} +31 -12
- package/dist/{statusline-fast-3C5OXHDD.js → statusline-fast-SVTMBMD7.js} +3 -2
- package/dist/sync-cmd-VPPYCNNM.js +28 -0
- package/dist/version-BWM6VLDI.js +6 -0
- package/dist/{watch-NRLXJUST.js → watch-5C4ZBBGO.js} +20 -7
- package/dist/{work-claim-cmd-HXB7K27H.js → work-claim-cmd-LSO2B2EX.js} +34 -19
- package/dist/work-cmd-UOQO2AD4.js +17 -0
- package/dist/work-comment-cmd-WF3EOLAE.js +106 -0
- package/dist/{work-launch-YNNCKIH3.js → work-launch-YI4CJDAP.js} +2 -1
- package/dist/work-open-pr-cmd-4SSQZMYG.js +156 -0
- package/dist/work-pr-cmd-6AN6RRQJ.js +16 -0
- package/package.json +13 -3
- package/skill-pack/maintained/amend/SKILL.md +104 -0
- package/skill-pack/maintained/emitting-evidence/SKILL.md +99 -0
- package/skill-pack/maintained/emitting-evidence/references/agents-snippet.md +20 -0
- package/skill-pack/maintained/outerlayer/SKILL.md +55 -0
- package/skill-pack/maintained/reporting-findings/SKILL.md +148 -0
- package/skill-pack/template/build/SKILL.md +193 -0
- package/skill-pack/template/build/references/agent-briefs.md +243 -0
- package/skill-pack/template/build/references/criteria-judge.md +91 -0
- package/skill-pack/template/build/references/evidence.md +42 -0
- package/skill-pack/template/build/references/release.md +74 -0
- package/skill-pack/template/build/references/review-briefs.md +275 -0
- package/skill-pack/template/build/references/review-loop.md +158 -0
- package/skill-pack/template/build/scripts/record-criteria.mjs +235 -0
- package/skill-pack/template/spec/SKILL.md +84 -0
- package/skill-pack/template/writing-specs/SKILL.md +134 -0
- package/dist/chunk-JJP7YLMN.js +0 -25
- package/dist/chunk-KKEU6FFR.js +0 -589
- package/dist/chunk-OZ7C3XUE.js +0 -34
- package/dist/chunk-WQ6VGRGZ.js +0 -150
- package/dist/emit-commit-credit-cmd-656BRAQ4.js +0 -121
- package/dist/hook-fast-I2XTHDE6.js +0 -8
- package/dist/import-capture-cmd-EUMBGIV3.js +0 -176
- package/dist/init-PTBITAUO.js +0 -103
- package/dist/login-cmd-IRX6LZT7.js +0 -62
- package/dist/loop-BWE2BS6J.js +0 -646
- package/dist/sync-cmd-S7Q6DWU3.js +0 -15
- package/dist/work-cmd-ABP6XDBP.js +0 -16
package/README.md
CHANGED
|
@@ -13,8 +13,9 @@ network, and when, is below.
|
|
|
13
13
|
Launch a session naming the work it's for, then sync:
|
|
14
14
|
|
|
15
15
|
```
|
|
16
|
-
npx @outerlayer/cli
|
|
17
|
-
npx @outerlayer/cli
|
|
16
|
+
npx @outerlayer/cli login # sign in, once per machine
|
|
17
|
+
npx @outerlayer/cli init # connect this repository to a factory, install the capture hooks
|
|
18
|
+
npx @outerlayer/cli work build --issue 42 --local # create the work item; prints its number
|
|
18
19
|
OUTERLAYER_WORK=7 claude # launch a session naming that number
|
|
19
20
|
npx @outerlayer/cli sync --dry-run # see exactly what would leave your machine
|
|
20
21
|
npx @outerlayer/cli sync # upload sessions launched that way
|
|
@@ -23,7 +24,7 @@ npx @outerlayer/cli sync # upload sessions launched tha
|
|
|
23
24
|
## Privacy, stated plainly
|
|
24
25
|
|
|
25
26
|
**A session uploads only when you launch it with `OUTERLAYER_WORK` naming
|
|
26
|
-
the work item it's for.** Create the item first with `outerlayer work
|
|
27
|
+
the work item it's for.** Create the item first with `outerlayer work build --local`,
|
|
27
28
|
which prints its factory-scoped number, then set that number before
|
|
28
29
|
starting your agent — `OUTERLAYER_WORK=7 claude`. The session-start hook
|
|
29
30
|
then records the launch and the session uploads whole, from its first turn,
|
|
@@ -39,7 +40,7 @@ and never upload.
|
|
|
39
40
|
sessions.** It runs when you run it. The hooks also fire `outerlayer sync
|
|
40
41
|
--quiet` in the background after each agent turn and when a session ends, at
|
|
41
42
|
most once every five minutes, as soon as `outerlayer login` has saved
|
|
42
|
-
credentials. So a launched session uploads while it is still running, not
|
|
43
|
+
credentials and `outerlayer connect` has chosen the repository's factory. So a launched session uploads while it is still running, not
|
|
43
44
|
only once it is over. Set `"autoSync": false` in `~/.outerlayer/config.json`
|
|
44
45
|
to leave every automatic upload — the background sync and the daemon's
|
|
45
46
|
streaming below — to your own command.
|
|
@@ -58,41 +59,202 @@ along before that sync ever runs.
|
|
|
58
59
|
These commands also talk to your workspace. None of them sends session
|
|
59
60
|
content:
|
|
60
61
|
|
|
61
|
-
- **`outerlayer work
|
|
62
|
-
`claim`, `renew`, `release`** read and write your
|
|
62
|
+
- **`outerlayer work build`, `remove`, `status`, `list`, `link-session`, `pr`,
|
|
63
|
+
`claim`, `renew`, `release`, `comment`, `threads`** read and write your factory's work items. The session-start
|
|
63
64
|
hook spawns `outerlayer work link-session` when you launch a session with
|
|
64
65
|
`OUTERLAYER_WORK`, naming the item and the session id — the item itself
|
|
65
|
-
must already exist, created ahead of time with `outerlayer work
|
|
66
|
+
must already exist, created ahead of time with `outerlayer work build --local`.
|
|
66
67
|
`outerlayer work pr` sends the session id and the pull request number and
|
|
67
|
-
repository — never the session's own content. `outerlayer work
|
|
68
|
+
repository — never the session's own content. `outerlayer work open-pr`
|
|
69
|
+
sends the pull request's title and the text of the body file you name. In a
|
|
70
|
+
host build, which holds an item key, it goes to the gateway, which opens or
|
|
71
|
+
edits the pull request as the factory's GitHub App on the branch the claim
|
|
72
|
+
named, and no `gh` command runs. In your own session it runs `gh pr create`
|
|
73
|
+
or `gh pr edit` under your login, then sends the pull request number and
|
|
74
|
+
repository the way `work pr` does. `outerlayer work claim`
|
|
68
75
|
records a lease for this host before it starts working on an item, so two
|
|
69
76
|
hosts never build the same piece of work at once; `renew` extends it and
|
|
70
|
-
`release` marks it done.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
77
|
+
`release` marks it done. `outerlayer work comment` posts one comment on a
|
|
78
|
+
work item's general thread or a criterion thread — the detected session id
|
|
79
|
+
rides along the same way it does for `emit`, only ever narrowing what the
|
|
80
|
+
comment may do; `outerlayer work threads` reads them back. A runner key
|
|
81
|
+
needs `git.read` and `work.read` to
|
|
82
|
+
list and read items, and `work.claim` to claim, renew or release — `work.claim`
|
|
83
|
+
is not granted to a dashboard role by default, since a claim is a host's
|
|
74
84
|
lease, not a person's.
|
|
75
85
|
- **`outerlayer runner start`** lists, claims, renews and releases work
|
|
76
86
|
items the same way `work claim`/`renew`/`release` do, on the schedule its
|
|
77
87
|
config sets — it sends nothing about the job it runs beyond that; the
|
|
78
88
|
agent it starts is a separate process with its own credentials, from the
|
|
79
|
-
`runner` block, never the copy-out daemon's.
|
|
80
|
-
|
|
81
|
-
|
|
89
|
+
`runner` block, never the copy-out daemon's. It also sends a heartbeat at
|
|
90
|
+
the end of every poll: the host, the CLI version, the poll interval, the
|
|
91
|
+
slots in use and total, and the result of that poll's own request for
|
|
92
|
+
work — success, or the error code and message the platform returned.
|
|
93
|
+
Before a build's command starts, the runner also runs `git ls-remote` and
|
|
94
|
+
`git fetch` in the job's workdir, with the host's own git credentials, to
|
|
95
|
+
put it on the branch the claim named. Nothing about the job leaves the host
|
|
96
|
+
that way.
|
|
97
|
+
When the gateway names a higher CLI version than the one running,
|
|
98
|
+
`outerlayer runner start` also calls the public npm registry
|
|
99
|
+
(`registry.npmjs.org`) for `@outerlayer/cli` only: that version's metadata
|
|
100
|
+
at once, and once no build is in flight, its tarball and its provenance
|
|
101
|
+
attestation, plus an `npm install` and an `npm audit signatures` run
|
|
102
|
+
against that same registry. The calls carry no credentials and nothing
|
|
103
|
+
about the host or the factory. Set `runner.autoUpdate` to `false` to stop
|
|
104
|
+
them.
|
|
105
|
+
`runner check` makes a list call and a host-key lookup to confirm the key
|
|
106
|
+
works and sends nothing else; `runner status` and `runner logs` make no network call at all.
|
|
107
|
+
On a runner host, any command that uses the saved runner key signs each
|
|
108
|
+
request it makes with the host key, the way the runner does. The signature
|
|
109
|
+
covers the request's method, path, query and body, and adds nothing else
|
|
110
|
+
to it.
|
|
111
|
+
- **`outerlayer runner init`** makes no network call, except `runner init --vm`
|
|
112
|
+
on a Mac. That runs `limactl`, and Lima downloads a Linux VM image. Inside
|
|
113
|
+
the VM, `apt` downloads Node and `npm` downloads this CLI. Your runner key goes to the VM on the standard
|
|
114
|
+
input of a `limactl shell` command and is never a file or an argument on the
|
|
115
|
+
Mac.
|
|
116
|
+
- **`outerlayer login`**, with no key on stdin, signs in to your account by
|
|
117
|
+
browser approval. It sends your dashboard a one-time public key and this
|
|
118
|
+
machine's host name, then polls for the answer. The answer is a token for
|
|
119
|
+
your account, encrypted to that public key, so only this process can read
|
|
120
|
+
it. It comes with the gateway address and your email, and no factory
|
|
121
|
+
or organization. The token is saved to `~/.outerlayer/config.json` and
|
|
122
|
+
never printed. If this machine held a token from an earlier login, login
|
|
123
|
+
asks the dashboard to revoke it. A key piped on stdin makes no network
|
|
124
|
+
call.
|
|
125
|
+
- **`outerlayer connect`**, and the first step of `outerlayer init`, send a
|
|
126
|
+
request with your login's token: `GET /v1/me/factories?repository=<host/owner/name>`,
|
|
127
|
+
naming this checkout's remote. The gateway answers with the factories you can
|
|
128
|
+
use, and whether this repository is linked to each. Once a factory is chosen,
|
|
129
|
+
a second request, `GET /v1/apps/<factory id>/git/links`, asks which
|
|
130
|
+
repositories that factory has linked, to say whether this one is among them.
|
|
131
|
+
Nothing else leaves the machine. The choice is saved in the repository's git directory, at
|
|
132
|
+
`outerlayer/connection.json`, which git never tracks. With a factory key it
|
|
133
|
+
makes no network call. `outerlayer init --local` makes none either.
|
|
134
|
+
- **`outerlayer logout`** sends the saved token to your dashboard
|
|
135
|
+
(`POST /api/cli/logout`) so it is revoked, then deletes it from the config
|
|
136
|
+
file. It sends nothing else.
|
|
137
|
+
- **`outerlayer runner image`** runs `git fetch` against the repository's
|
|
138
|
+
remote, `https://github.com/<owner>/<name>.git` unless `--remote` names
|
|
139
|
+
another, with the host's own git credentials. It sends nothing about the
|
|
140
|
+
host. Docker pulls base images, features and Claude Code's npm package
|
|
141
|
+
from registries while the image builds, with the host's own `docker
|
|
142
|
+
login`. The tools layer also downloads the pinned `gh` and `tini` releases
|
|
143
|
+
from GitHub, checking each against a digest. The image build runs outside
|
|
144
|
+
any work item and sends nothing to your factory.
|
|
145
|
+
- **`outerlayer runner start` with `builtin:vm` hooks** runs each build in its
|
|
146
|
+
own Firecracker microVM, which has no network device. The guest kernel and
|
|
147
|
+
helper are not published yet, so no host is offered `builtin:vm` and
|
|
148
|
+
`outerlayer doctor` fails it. Once they are, the first microVM
|
|
149
|
+
build downloads a pinned Firecracker release, a guest kernel and a guest
|
|
150
|
+
helper from github.com, and checks each against a sha256 pinned in the CLI;
|
|
151
|
+
the requests send nothing about the host. The build reaches the network only
|
|
152
|
+
through the same tunnel a container build uses, which the runner serves on
|
|
153
|
+
Unix sockets and the guest reaches over vsock. The guest's exec agent accepts
|
|
154
|
+
connections from the host only, and the runner runs every step of the build
|
|
155
|
+
through it, including the build's command (`outerlayer vm-exec` on the host).
|
|
156
|
+
- **`outerlayer runner start` with `builtin:container` hooks** runs each
|
|
157
|
+
build in its own Docker container, which has no network but loopback. The
|
|
158
|
+
build reaches the network only through a tunnel the runner serves on a
|
|
159
|
+
Unix socket, which the container's own `outerlayer broker-relay` process
|
|
160
|
+
reaches from loopback. The tunnel refuses loopback, private, link-local,
|
|
161
|
+
shared-address, multicast and unique-local addresses and the host's own,
|
|
162
|
+
and it terminates no TLS. The tunnel also serves the build a local git
|
|
163
|
+
remote. Git in the container still shows
|
|
164
|
+
`https://github.com/<owner>/<name>.git` and reaches the runner instead,
|
|
165
|
+
which forwards only git's fetch and push requests and Git LFS batch calls
|
|
166
|
+
to github.com. For the item's repository the runner adds a GitHub App
|
|
167
|
+
token it asked your gateway for (`POST /v1/work-items/{id}/claim/tokens`):
|
|
168
|
+
a read token for a fetch, and a push token for a push, which it forwards
|
|
169
|
+
only when every ref the push updates is the branch the claim names. Any
|
|
170
|
+
other repository is forwarded with no credential. Before it forwards a
|
|
171
|
+
push to a branch outside `outerlayer/`, the runner runs `git fetch` and
|
|
172
|
+
`git receive-pack` in a bare mirror it keeps under its own directory, with
|
|
173
|
+
the read token, to check that the push moves the branch forward. The
|
|
174
|
+
build's `gh` holds the read token in a directory the runner owns and
|
|
175
|
+
nothing else. When the attempt ends, the runner revokes every token it was
|
|
176
|
+
issued with `DELETE https://api.github.com/installation/token`, sent with
|
|
177
|
+
the token it revokes. The release for the attempt then lists the hosts the
|
|
178
|
+
build reached, each address the tunnel refused with its range, the names,
|
|
179
|
+
never the values, of the host variables the runner's config passed in, the
|
|
180
|
+
names of the destinations it called, which kinds of token the build used,
|
|
181
|
+
and whether its commits were authored by the GitHub App's bot account and
|
|
182
|
+
credited the member who asked for the build. The runner sets that author in
|
|
183
|
+
the build's environment and adds the `Co-authored-by` line with git hooks it
|
|
184
|
+
writes into the build's own directory.
|
|
185
|
+
- **`outerlayer runner start` with `builtin:container` hooks** also asks your
|
|
186
|
+
gateway which repository governs the item's repository (`GET
|
|
187
|
+
/v1/context/source`, signed with the host key), after the recipe's
|
|
188
|
+
lifecycle commands. When one does, the runner runs `git fetch` against that
|
|
189
|
+
control plane on the host, with the host's own git credentials, and copies
|
|
190
|
+
its context into the checkout through the build's directory. The build
|
|
191
|
+
receives files and no credential for the control plane. The runner deletes
|
|
192
|
+
the staged copy before the command starts. A host that cannot read the
|
|
193
|
+
control plane fails the build at provision.
|
|
194
|
+
- **`outerlayer runner start` with `builtin:process` hooks** runs each build
|
|
195
|
+
as a process under the runner's own user, with no isolation, and the
|
|
196
|
+
attempt records `shared-user`. The runner clones the item's repository
|
|
197
|
+
from `https://github.com/<owner>/<name>.git` with the host's own git
|
|
198
|
+
credentials. It serves the same tunnel on a loopback port, which the
|
|
199
|
+
build reaches through its proxy settings, and the release lists the same
|
|
200
|
+
hosts and refusals.
|
|
201
|
+
- **`outerlayer runner start` with your own executable hooks** runs
|
|
202
|
+
`git ls-remote` against `https://github.com/<owner>/<name>.git`, with the
|
|
203
|
+
host's own git credentials, before each provision hook, to tell the hook
|
|
204
|
+
the commit the default branch points at. It sends nothing about the host,
|
|
205
|
+
and a host whose git cannot reach the remote loses only that hint.
|
|
206
|
+
- **`outerlayer runner start` with `build.destinations`** serves each
|
|
207
|
+
destination the config lists on a local address, and forwards each request
|
|
208
|
+
a build sends there to the destination's upstream, over HTTPS, with the
|
|
209
|
+
header the config names in place of any credential the build sent. The
|
|
210
|
+
header's secret is read from the runner's own environment.
|
|
211
|
+
It is never in a build's environment or files, and the release names a
|
|
212
|
+
destination and nothing more.
|
|
213
|
+
- **`outerlayer runner start` with `builtin:vm`, `builtin:container` or
|
|
214
|
+
`builtin:process` hooks** also serves two built-in destinations, `gateway` and `claude`, to
|
|
215
|
+
each build. The gateway destination forwards a build's requests to your
|
|
216
|
+
gateway with the attempt's item key, and the `claude` destination forwards
|
|
217
|
+
them to `https://api.anthropic.com` with the host's `CLAUDE_CODE_OAUTH_TOKEN`
|
|
218
|
+
or `ANTHROPIC_API_KEY`, read from the runner's own environment. A build holds a placeholder for each and never the value, and the
|
|
219
|
+
release names the two destinations and nothing more. A build under
|
|
220
|
+
`builtin:process` runs as the runner's user and can still read the runner's
|
|
221
|
+
environment and the attempt's job file.
|
|
222
|
+
- **`outerlayer doctor`**, once a factory key is saved (`echo "$KEY" | outerlayer login`),
|
|
223
|
+
asks your gateway (`GET /v1/repositories/access`, with that key) which
|
|
224
|
+
GitHub App permissions each connected repository's installation has not
|
|
225
|
+
accepted, and whether each default branch requires a pull request. The
|
|
226
|
+
request carries nothing about the host, and the gateway stores nothing.
|
|
227
|
+
- **`outerlayer runner check`** also asks your gateway (`GET /v1/runner/host-key`,
|
|
228
|
+
with the runner key, signed with the host key) whether the key holds
|
|
229
|
+
`work.claim`, so a key that cannot claim is named before the host takes work.
|
|
230
|
+
The request carries nothing about the host beyond the signature the key's
|
|
231
|
+
own requests already carry, and the gateway stores nothing.
|
|
232
|
+
- **`outerlayer doctor`** on a runner host, one with a `runner` block in its
|
|
233
|
+
config, also asks the npm registry for the latest Claude Code version, to
|
|
234
|
+
say whether the version the runner's images pin is behind. The request
|
|
235
|
+
names the package and nothing about the host. On a host with
|
|
236
|
+
`builtin:container` hooks it also asks your gateway which repository governs
|
|
237
|
+
each repository in `repos.include` (`GET /v1/context/source`), then runs
|
|
238
|
+
`git ls-remote` against that control plane with the host's own git
|
|
239
|
+
credentials, to say whether the host can read it.
|
|
82
240
|
- **`outerlayer emit artifact`** uploads the file you name — a screenshot, a
|
|
83
241
|
recording, a report, a log — along with its caption. With no recorded
|
|
84
242
|
session to attach it to, it uploads immediately, anchored to a pull request
|
|
85
243
|
or to the git checkout.
|
|
86
|
-
- **`outerlayer emit <name>`**
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
always have.
|
|
244
|
+
- **`outerlayer emit <name>`** sends one check's outcome for a work item.
|
|
245
|
+
Run from inside a session, it sends only when that session carries a
|
|
246
|
+
launch record — the session's own content may not leave by a second
|
|
247
|
+
route. Run from CI or a plain shell, where there is no session, it sends
|
|
248
|
+
as it always has.
|
|
92
249
|
- **`outerlayer emit finding`** and **`outerlayer emit findings <file>`** send
|
|
93
|
-
one finding, or a whole batch of them, for a work item —
|
|
94
|
-
anchoring as `emit <name>` (`--item`, or
|
|
95
|
-
|
|
250
|
+
one finding, or a whole batch of them, for a work item — a problem an agent
|
|
251
|
+
hit in the factory. The anchoring is the same as `emit <name>` (`--item`, or
|
|
252
|
+
the recorded session's own item).
|
|
253
|
+
- **`outerlayer emit criteria <file>`** sends the acceptance criteria of a work
|
|
254
|
+
item as one list (`POST /v1/criteria`): each criterion's id, text and
|
|
255
|
+
declared proof kind, from the JSON file you name. The anchoring is the same
|
|
256
|
+
as `emit finding`. Nothing but the file's content and the item number is
|
|
257
|
+
sent.
|
|
96
258
|
- **`outerlayer mcp serve`** is the stdio MCP server your editor spawns. It
|
|
97
259
|
forwards every JSON-RPC message the editor sends to the gateway and returns
|
|
98
260
|
the reply.
|
|
@@ -124,9 +286,9 @@ space, past both stubs, so the same test records every program each run
|
|
|
124
286
|
starts and asserts none of them fetches over the network.
|
|
125
287
|
|
|
126
288
|
Failures the hook cannot show you — a refused `OUTERLAYER_WORK` value, a
|
|
127
|
-
`work
|
|
289
|
+
`work link-session` that could not reach the factory — are appended to
|
|
128
290
|
`~/.outerlayer/spool/hook-errors.log`, and the next session start says so.
|
|
129
|
-
The
|
|
291
|
+
The link retries a gateway it cannot reach a few times, with backoff,
|
|
130
292
|
before it gives up.
|
|
131
293
|
|
|
132
294
|
- **The tier is applied before anything leaves.** The default tier is
|
|
@@ -144,45 +306,47 @@ before it gives up.
|
|
|
144
306
|
| Command | What it does |
|
|
145
307
|
|---|---|
|
|
146
308
|
| `outerlayer sync` | Upload sessions launched with `OUTERLAYER_WORK` to your OuterLayer cloud workspace (incremental — only what's new since the last sync). Tier-gated client-side (`--tier metrics\|redacted\|full`, default `full`); `--dry-run` prints exactly what would leave the machine; `--all` re-sends everything (idempotent server-side). Credentials come from `outerlayer login`, `OUTERLAYER_*` env vars, or `--url/--app-id`. |
|
|
147
|
-
| `outerlayer login [--
|
|
148
|
-
| `outerlayer
|
|
309
|
+
| `outerlayer login [--dashboard] [--no-browser] [--check <id>]` | Sign in to your account by browser approval: prints an approve link and a code, a signed-in person approves it, and a token for their account is saved to `~/.outerlayer/config.json` without ever being shown. It chooses no factory; `outerlayer connect` does. Without a terminal it prints one JSON document and exits 75; `--check <id>` finishes it (0 signed in, 75 still waiting, 1 denied or expired). A factory key piped on stdin (`echo "$KEY" \| outerlayer login --url … --app-id …`) is saved as before; it is never a flag, and it always wins over the login. `--no-input` refuses to wait on a person. |
|
|
310
|
+
| `outerlayer logout` | Revoke this machine's login on the dashboard and delete it from the config file. A saved factory key and factory are left alone. If the dashboard cannot be reached it still deletes the local copy, exits 1, and says the token stays valid until revoked on `/profile/security`. |
|
|
311
|
+
| `outerlayer connect [--factory <org>/<factory>] [--json]` | Choose the factory this repository's work goes to, and say what it chose and why. With a login it lists the factories you can use and takes the first rule that leaves one answer: `--factory`, the factory this repository is already connected to, the one factory it is linked to, the one factory you can use; on a terminal it then asks, and with no terminal it exits 1 listing each `--factory` value. The choice is saved in the repository's git directory, shared by every worktree and never committed. A factory key already belongs to one factory, so `connect` changes nothing for it. It never links a repository. Once a factory is chosen it asks that factory whether this repository is linked. If not, it still saves the choice, prints the factory's Work page link to stderr and exits 2. `--json` writes one JSON document to stdout. |
|
|
312
|
+
| `outerlayer init` | Connect this repository (`outerlayer connect`), install the capture hooks and the status-line segment, and run `doctor`. It never signs in: without a login it skips the connect step and says to run `outerlayer login`. `--local` installs the hooks only, with no network call. `--json` prints one document naming each step's outcome. Run through `npx`, it copies the CLI to `~/.outerlayer/cli` and points the hooks at that copy, so they survive npm clearing its cache; `npx @outerlayer/cli@latest init --local` upgrades it. From any other install, the hooks run that install. Claude Code deletes transcripts after ~30 days; run `outerlayer daemon` separately to mirror them first — `init` does not start it for you. |
|
|
149
313
|
| `outerlayer daemon` | Run the copy-out daemon in the foreground (`--once` for a single sweep, which uploads nothing). Once cloud credentials exist, it also streams a launched session's new turns as they land — see Privacy, above. `outerlayer watch` is the former name and still works, with a warning. |
|
|
150
|
-
| `outerlayer doctor` | Check the installation: hooks, status-line freshness, and
|
|
314
|
+
| `outerlayer doctor` | Check the installation: hooks, status-line freshness, sync health and, with a factory key, the GitHub App access builds need. `--json` prints the checks and a summary for scripts. |
|
|
151
315
|
| `outerlayer context emit [--check]` | Compile `.outerlayer/` into each configured target tool's native files (targets come from `.outerlayer/config.json`). `--check` computes outputs and diffs against disk without writing (CI mode). Bare `outerlayer emit` with no name still compiles, with a deprecation warning. |
|
|
152
316
|
| `outerlayer import ruler` | Port a `.ruler/` tree ([Ruler](https://github.com/intellectronica/ruler)) into the equivalent `.outerlayer/` tree — mostly a rename; never overwrites an existing `.outerlayer/`. |
|
|
153
317
|
| `outerlayer hooks wrap` / `outerlayer hooks unwrap` | Auto-wrap (or undo wrapping) `PreToolUse`/`PostToolUse` hooks for execution evidence — one spawn per firing. |
|
|
154
318
|
| `outerlayer emit artifact <file> --caption <text> [--for <criterion-id>] [--pr <n>]` | Upload a proof artifact — screenshot, recording, report, or log — with its caption. Inside a recorded session it spools locally and ships on the next `sync`; otherwise it uploads immediately, anchored to a pull request or the current checkout. `--replaces` retires artifacts an earlier run uploaded. |
|
|
155
|
-
| `outerlayer emit <name> --result <pass\|fail> [--link <url>] [--body <text>\|--body-file <path>] --item <number>` | Record one named check's outcome on a work item. A check that ran carries the run URL as its proof (`--link`); a judgment you are making yourself carries one sentence (`--body`, or `--body-file` to read it from a file — `-` reads standard input). A `fail` needs at least one of the two; a `pass` needs neither. `--item` names the work item by the number printed when the item was created — always required, in or out of a recorded session;
|
|
156
|
-
| `outerlayer
|
|
157
|
-
| `outerlayer
|
|
158
|
-
| `outerlayer emit finding --id <id> --
|
|
159
|
-
| `outerlayer emit findings <file> [--item <number>]` | Record a whole batch at once, read from a
|
|
319
|
+
| `outerlayer emit <name> --result <pass\|fail> [--link <url>] [--body <text>\|--body-file <path>] --item <number>` | Record one named check's outcome on a work item. A check that ran carries the run URL as its proof (`--link`); a judgment you are making yourself carries one sentence (`--body`, or `--body-file` to read it from a file — `-` reads standard input). A `fail` needs at least one of the two; a `pass` needs neither. `--item` names the work item by the number printed when the item was created — always required, in or out of a recorded session; a session records checks on its own item like any other, stored as the session's, but cannot clear a person's fail. Prints the recorded check's id. Who recorded it comes from your API key, never from what you send. |
|
|
320
|
+
| `outerlayer work comment --item <n> [--criterion <id>] --body <text> [--artifact <id>] [--pass\|--fail\|--attach\|--ready]` | Post one comment on a work item's general thread, or on one acceptance criterion's own thread with `--criterion`. `--pass`/`--fail` need a person's own credential and apply to the whole item, so they work on the general thread only and the gateway refuses them with `--criterion`; `--attach` makes the named artifact that criterion's current proof; `--ready` hands a thread back to a person. The detected session id rides along automatically, only ever narrowing what the comment may do. |
|
|
321
|
+
| `outerlayer work threads --item <n>` | Read a work item's threads back — the general thread first, then one per criterion with proof or a comment, each with its `waitingOn`. |
|
|
322
|
+
| `outerlayer emit finding --id <id> --category <context\|flaky-test\|tooling\|environment\|defect\|other> --title <text> --file <path> --where <label> [--line <n>] [--item <number>] …` | Record one problem you hit in the factory. `--category` is one of `context` (an instruction that is wrong, broken or missing), `flaky-test`, `tooling`, `environment`, `defect` (a bug outside your own change) or `other`. A `context` finding also needs `--rule-path` and `--rule-relation` (`wrong`, `broken` or `missing`), and `--rule-quote` unless the relation is `missing`. Findings are informational; nothing reads one to pass or fail the work. `--item` names the work item; without it, inside a recorded session, the item that session was launched for is used automatically. Re-emitting the same `--id` on the item replaces that finding. |
|
|
323
|
+
| `outerlayer emit findings <file> [--item <number>]` | Record a whole batch at once, read from a JSON file (`-` for standard input) with `"schemaVersion": 2` — the same shape and validation as `emit finding`, one record per id, category, title, file, line, rule and where. Anchored the same way: `--item`, else a recorded session's own item. |
|
|
324
|
+
| `outerlayer emit criteria <file> [--item <number>]` | Record a work item's acceptance criteria as one list, read from a JSON file (`-` for standard input): `{"criteria": [{"id": "AC-1", "text": "Given …", "proof": null}]}`. An `id` is 1 to 64 characters of `A-Z a-z 0-9 . _ : -`, the same id `emit artifact --for` binds evidence to. `proof` is `video`, `screenshot`, `report`, `log`, `file` or `null` (any bound artifact proves it). The list holds 1 to 200 criteria, each `text` at most 2,000 characters, with no id twice. It is validated before anything is sent. This list is the only source for the item's Criteria tab. Once an item has a list, only a person can replace it: run the command outside an agent session, with your own login. Anchored the same way as `emit findings`: `--item`, else a recorded session's own item. |
|
|
160
325
|
| `outerlayer mcp install [--transport stdio\|http] [--url] [--name] [--command]` | Write (or update) an `mcpServers` entry in `.mcp.json` for the OuterLayer gateway. Default `stdio`: the client spawns `outerlayer mcp serve`, which reads the API key from `~/.outerlayer/config.json` (or `OUTERLAYER_API_KEY`) each time it connects, so a reconnect picks up a newly saved or rotated key. `--transport http` writes a direct `POST /v1/mcp` entry referencing `${OUTERLAYER_API_KEY}`, resolved by the client from the environment it was launched with. Never writes an API key. Pass `--url`/`--app-id` for self-host. |
|
|
161
326
|
| `outerlayer mcp serve [--url] [--app-id]` | Stdio MCP server bridging stdin/stdout JSON-RPC to the gateway's `POST /v1/mcp`. What the stdio `.mcp.json` entry runs; exits 1 with a clear message when no API key is configured. |
|
|
162
|
-
| `outerlayer work
|
|
163
|
-
| `outerlayer work remove --issue <n>\|--pr <n> --reason <text> [--repo]` | Withdraws the caller's own addition, recording the reason. Never deletes anything; the item leaves the
|
|
327
|
+
| `outerlayer work build --issue <n\|KEY>\|--item <n> [--tracker linear\|jira] [--local] [--repo] [--note] [--retry <count>]` | Starts work on an item and puts it on the Work page. `--issue` takes a GitHub issue number or a Linear or Jira key such as `ENG-123`; the gateway verifies a key against the factory's tracker connection before adding it. `--tracker` is needed only when both Linear and Jira are connected. A key gets a repository only from `--repo`, never from the checkout. Without `--local`, records a build request that a host takes when it has a free slot. With `--local` (issue only), no host takes it: it prints the item's number and the line that starts your own session on it, such as `OUTERLAYER_WORK=7 claude`. `--retry` resends after a 5xx or 429 answer, up to that many more times. |
|
|
328
|
+
| `outerlayer work remove --issue <n>\|--pr <n> --reason <text> [--repo]` | Withdraws the caller's own addition, recording the reason. Never deletes anything; the item leaves the Work page only once no live addition remains on it. Removing again is a no-op that still succeeds. |
|
|
164
329
|
| `outerlayer work status --issue <n>\|--pr <n> [--repo]` | Shows one item's stage, section, gate ledger, linked pull requests and sessions, and its additions. |
|
|
165
|
-
| `outerlayer work list [--stage] [--section] [--repo] [--unclaimed] [--startable] [--needs amend]` | Lists live work items for the current factory, filterable by stage, section, claim state and whether
|
|
330
|
+
| `outerlayer work list [--stage] [--section] [--repo] [--claimed] [--unclaimed] [--startable] [--needs amend]` | Lists live work items for the current factory, filterable by stage, section, claim state, startability and whether a comment thread is waiting on an agent. |
|
|
166
331
|
| `outerlayer work pr <n> [--repo] [--session-id]` | Run inside a session on a work item: declares that pull request `<n>` in the checkout's repository belongs to that item. Idempotent — declaring the same pull request twice is a no-op. Refuses when the session is on no item, or the repository is not connected. |
|
|
167
|
-
| `outerlayer work
|
|
168
|
-
| `outerlayer work
|
|
332
|
+
| `outerlayer work open-pr --title <text> --body-file <path> [--repo] [--session-id] [--json]` | Opens the pull request for the work item this session is on, or edits the one already open on its branch. A host build, which holds an item key, sends it to the gateway, which opens it as the factory's GitHub App from the branch the claim named; no `gh` command runs. Your own session runs `gh pr create` or `gh pr edit` under your login and then declares the pull request on the item. Run it again after changing the title or description. |
|
|
333
|
+
| `outerlayer work claim --item <n>\|--issue <n> --kind implement\|amend [--repo] [--host] [--seconds]` | Records a lease for this host (default: its own hostname), so two hosts never build the same item at once. The lease belongs to the runner key that claimed it: a live lease held by a different key is refused, even under the same host name, and claiming again with the same key extends it. The first claim creates the host key (`host-key.pem` beside the config file) and binds the runner key to it; from then on every request made with that key is signed. Lease length defaults to 900 seconds, the server's own cap. |
|
|
334
|
+
| `outerlayer work renew --item <n>\|--issue <n> [--repo] [--host] [--seconds]` | Extends this host's own live lease. Refused if the lease has expired, or if a different runner key holds it (403 `claim_not_held`). |
|
|
169
335
|
| `outerlayer work release --item <n>\|--issue <n> [--repo] [--host] [--outcome]` | Marks this host's lease released, optionally recording how the attempt ended. Releasing an already-released lease is a no-op that returns the recorded release time and outcome. |
|
|
170
|
-
| `outerlayer runner init [--config <path>]` | Writes a `runner` block with defaults
|
|
336
|
+
| `outerlayer runner init [--vm\|--no-vm] [--config <path>]` | Writes a `runner` block with defaults, keeping every key the config already had. It names `builtin:vm` on a Linux machine where the user can use `/dev/kvm` and Docker Engine can build images once the guest kernel and helper are published (not yet), `builtin:container` on that machine until then, `builtin:container` on any other machine with Docker Engine, and `builtin:process` on one without, and writes no hook script. Refuses rather than overwriting an existing block. On macOS it asks whether to create a Linux VM with Lima, installs Docker Engine and the runner in it, and starts both at login; `--vm` answers yes and `--no-vm` answers no, and a run with no terminal answers no. The runner key and the host key then live only in the VM: the Mac's config loses `apiKey` and `runner` and gains a `runnerVm` note, which `outerlayer doctor` reads. |
|
|
171
337
|
| `outerlayer runner check [--config <path>]` | Validates the config, the hooks and the key, prints the settings the runner would use, and exits non-zero on a problem. Takes no work and writes no pid file. |
|
|
172
338
|
| `outerlayer runner start [--config <path>]` | Runs the loop: claim work, run it, sync, clean up, report, release with an outcome. Repeat. Reads the `runner` block from the config file (default `~/.outerlayer/config.json`). Refuses to start on a bad config, an unrunnable hook, or a refused key. |
|
|
339
|
+
| `outerlayer runner image --repository <owner/name> [--remote <url>] [--config <path>] [--json]` | Builds the image a repository's builds run in. Fetches the head of the default branch into the runner's cache, builds its `.devcontainer/devcontainer.json` with the devcontainer CLI, ignores every setting that reaches the host or widens the container's privileges, and adds this CLI and a pinned Claude Code. Reuses the image until the recipe or the tools change, keeps the newest three, and writes `recipe.json` beside the image record. Refuses a Compose recipe (`recipe_needs_docker`) and a repository with only named configurations (`recipe_ambiguous`). |
|
|
173
340
|
| `outerlayer runner stop [--config <path>] [--now]` | Takes no more work and waits for running jobs to finish, naming each every five seconds. `--now` ends them immediately with outcome `stopped`. Ctrl-C on a foreground runner drains; a second one stops now. |
|
|
174
341
|
| `outerlayer runner status [--config <path>] [--recent] [--json]` | A header naming the runner's own state, then a row per running job — item, queue, stage, elapsed, started, lease, job directory. `--recent` adds finished jobs, newest first, capped at 20, with their outcomes. |
|
|
175
342
|
| `outerlayer runner logs <item> [--config <path>] [-f]` | Prints the newest attempt's log for one item, following it with `-f`. |
|
|
176
343
|
|
|
177
|
-
The `work` commands need an API key that carries `
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
release work item claims` (`work_item_claim.update`). Withdrawing an
|
|
184
|
-
addition somebody else made additionally needs `Withdraw others' work from
|
|
185
|
-
the Work page` (`git_connection.update`).
|
|
344
|
+
The `work` commands need an API key that carries `work.insert` to add,
|
|
345
|
+
remove, and declare a pull request (`pr`, `open-pr`), and `work.read` to look an item up
|
|
346
|
+
— which `remove` and `status` both do before they act. Tick both when you
|
|
347
|
+
mint the key, in Settings → API keys. Claiming, renewing or releasing a
|
|
348
|
+
lease needs `work.claim`. Withdrawing an addition somebody else made
|
|
349
|
+
additionally needs `work.update`.
|
|
186
350
|
|
|
187
351
|
### Recording your own pass or fail on a check
|
|
188
352
|
|
|
@@ -209,10 +373,9 @@ Record a pass once the work is right:
|
|
|
209
373
|
outerlayer emit code-review --result pass --item 412
|
|
210
374
|
```
|
|
211
375
|
|
|
212
|
-
`--item` is always required, in or out of a recorded session.
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
machine key (an API key run outside the recorded session) or CI.
|
|
376
|
+
`--item` is always required, in or out of a recorded session. Inside a
|
|
377
|
+
recorded session, the check is stored as the session's, on the item it was
|
|
378
|
+
launched for or any other. A session cannot record over a person's fail.
|
|
216
379
|
|
|
217
380
|
Three things to know. Who recorded a check is decided by the API key you
|
|
218
381
|
used, never by anything in the request. A key bound to a membership records
|
|
@@ -222,30 +385,28 @@ because a fail with neither is something nobody can act on. And a check only
|
|
|
222
385
|
holds a gate once a validator in `.outerlayer/validators/` declares its emit
|
|
223
386
|
name; without one the check is recorded and read back, and blocks nothing.
|
|
224
387
|
|
|
225
|
-
A review of the work itself is different:
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
The item's own pass stays available only once every required artifact has
|
|
248
|
-
a pass and no fail is still open.
|
|
388
|
+
A review of the work itself is different: a person records it as a `pass`
|
|
389
|
+
or `fail` on a work item's general thread (the item page, or `outerlayer
|
|
390
|
+
work comment` on the general thread), never as a named check — no validator declaration needed. The gateway refuses a
|
|
391
|
+
pass or fail on an item that is closed or shipped, has no evaluation yet,
|
|
392
|
+
or whose evaluation is still waiting on a session link, with the code
|
|
393
|
+
`not_reviewable`. A recorded pass on the general thread carries the head
|
|
394
|
+
commit of every pull request the item had at the time; once one of them
|
|
395
|
+
moves, that pass stops counting and a fresh review is needed. A repository
|
|
396
|
+
can require a current pass before the evidence check completes by setting
|
|
397
|
+
the base branch's `review` policy key to `required` (default `optional`,
|
|
398
|
+
alongside `merge_gate`) — the check then stays in progress, not failed,
|
|
399
|
+
until a current pass exists.
|
|
400
|
+
|
|
401
|
+
A criterion thread is scoped to one acceptance criterion rather than the
|
|
402
|
+
whole item: an agent attaches proof with `outerlayer work comment
|
|
403
|
+
--criterion <id> --artifact <id> --attach`, and a person leaves a note on
|
|
404
|
+
it with a plain comment. A pass or fail is a verdict on the whole item, so
|
|
405
|
+
the gateway refuses one on a criterion thread. A fail on any thread counts
|
|
406
|
+
the work as bad on Quality once, however many threads carry one — a fail on
|
|
407
|
+
the general thread also lists the item on the amend queue `outerlayer
|
|
408
|
+
runner start` reads, naming the thread waiting on an agent, until a
|
|
409
|
+
person's next pass or fail clears it.
|
|
249
410
|
|
|
250
411
|
Every command accepts `--no-color`, and color is off on its own when stdout is not a terminal, when `NO_COLOR` is set, or when `TERM` is `dumb`. `FORCE_COLOR=1` turns it on for a pipe. Commands that print anything accept `--json`.
|
|
251
412
|
|