@outerlayer/cli 0.2.0 → 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 +124 -0
- package/README.md +226 -59
- 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-U32VSRLO.js → chunk-3YPKXE5L.js} +90 -632
- package/dist/{chunk-Q6CL5THG.js → chunk-5DLBAXY5.js} +208 -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-65WXAANR.js → chunk-DVDEBNQJ.js} +17 -2
- package/dist/{work-pr-cmd-AZQPWH4H.js → chunk-DVYHCMB2.js} +9 -26
- 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-4TNZMO7V.js → chunk-G7FSV7JX.js} +3452 -751
- 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-NXLLURA4.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-I3ETLSNE.js → chunk-XCCLFVXM.js} +120 -11
- package/dist/{context-materialize-6WKT3RBQ.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-G7DILYJY.js → cli-NHUXABYH.js} +590 -876
- 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-UQVT3OKW.js → emit-artifact-cmd-KTYW2TN2.js} +24 -20
- package/dist/emit-cmd-DCERAU27.js +9 -0
- package/dist/emit-criteria-cmd-VAUUSAYD.js +166 -0
- package/dist/{emit-finding-cmd-FDOU2OPD.js → emit-finding-cmd-UR4ID45Z.js} +34 -31
- package/dist/{emit-result-cmd-H2T4C2K3.js → emit-result-cmd-FDTUKGKE.js} +34 -62
- 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-I27IST4L.js → status-2UZKKNB7.js} +30 -13
- 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-3DTPJETH.js → watch-5C4ZBBGO.js} +19 -8
- package/dist/{work-claim-cmd-5AUNCLS2.js → work-claim-cmd-LSO2B2EX.js} +33 -20
- package/dist/work-cmd-UOQO2AD4.js +17 -0
- package/dist/work-comment-cmd-WF3EOLAE.js +106 -0
- package/dist/{work-launch-LT663PB3.js → work-launch-YI4CJDAP.js} +1 -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-DCNOXRMV.js +0 -589
- package/dist/chunk-JJP7YLMN.js +0 -25
- package/dist/chunk-OZ7C3XUE.js +0 -34
- package/dist/chunk-WQ6VGRGZ.js +0 -150
- package/dist/hook-fast-J5LCDHUJ.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-ASZRX3CZ.js +0 -648
- package/dist/sync-cmd-BBAUZ5JD.js +0 -17
- package/dist/work-cmd-2P4BVX47.js +0 -18
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,129 @@
|
|
|
1
1
|
# @outerlayer/cli
|
|
2
2
|
|
|
3
|
+
## 0.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 1cffcc2: `outerlayer connect` now checks that the repository is linked to the factory it chose. When it is not, `connect` saves the connection as before, prints the factory's Work page link where the setup panel links a repository, and exits 2. `init` reports its connect step as done with `linked: false` and repeats the link under "Next", and still exits 0. A factory key skips the check. `connect` also takes `--json`, which writes one document with `linked` and, when it is false, `linkUrl`.
|
|
8
|
+
- ecc937a: Add `outerlayer emit criteria <file> [--item <number>]`, which records a work item's acceptance criteria as one list. The list is validated before anything is sent: an empty list, a repeated id or a reserved id is refused. The newest recorded list is what the item's Criteria tab, its count and its status read, and criteria written in an issue body are no longer read. Once an item has a list, only a person can replace it.
|
|
9
|
+
- 6bde8e9: `outerlayer init` now sets up Claude Code in the repository: it installs the starter skills and a new `outerlayer` skill, writes `.outerlayer/config.json` when there is none, runs `outerlayer context emit`, and adds the OuterLayer MCP server to `.mcp.json`. It asks nothing and changes nothing you wrote. It skips this in a repository whose context comes from a control plane, and `--local` skips it too.
|
|
10
|
+
- 69e695a: Adds `builtin:vm`, a third built-in runner backend. On a Linux x86_64 host where the runner's user can use `/dev/kvm`, each build runs in a Firecracker microVM made from the recipe's image. The microVM has no network device. It reaches the runner's tunnel over vsock, and it has the vCPUs, memory and disk that `runner.build` sets.
|
|
11
|
+
|
|
12
|
+
The guest kernel and helper are not published yet, and the hashes pinned in the CLI are placeholders. Until they are published, `outerlayer runner init` does not name `builtin:vm` on any host, and `outerlayer doctor` fails `builtin:vm` hooks with that reason. After the first publish, `runner init` names `builtin:vm` on a Linux x86_64 host where the user can use `/dev/kvm`. A host without usable KVM keeps `builtin:container` or `builtin:process`, unchanged. `outerlayer doctor` adds a `KVM` check, which names the group to join, and a `MicroVM memory` check, which warns when `runner.concurrency` times `runner.build.memory` is more than the host's memory.
|
|
13
|
+
|
|
14
|
+
The first microVM build downloads Firecracker, a guest kernel and a guest helper from github.com, and checks each against a sha256 pinned in the CLI.
|
|
15
|
+
|
|
16
|
+
- b678856: A runner now keeps itself at the CLI version its gateway names. When it has no build in flight, it installs that version beside its current one, checks the version's tarball and provenance against this repository's release workflow, and switches to it. If the new version fails its own checks, the runner goes back to the previous version. Turn this off with `runner.autoUpdate: false`. Run `outerlayer runner install` once on an existing host to move it onto the install layout.
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- 48352ce: The starter `build` skill now records the item's acceptance criteria at intake with `outerlayer emit criteria`. It reads an `## Acceptance criteria` section with ids, or a bullet list under an `Acceptance:` line and adds `AC-<item number>-NN` ids. A list a person already recorded is never replaced. The criteria judge reads the recorded list from the build's state file.
|
|
21
|
+
- 93695bc: `init` ends by saying to commit and push `.outerlayer/` when its agent setup step left files in the repository. The factory reads the policy from the default branch, so no check runs on the repository's pull requests until it is there. The line is left out with `--local`, outside a repository, and under `--json`.
|
|
22
|
+
- d7d56d3: The microVM build disk's copy step can now be supplied by the host that builds the disk. The runner still copies with GNU `cp --sparse=always` by default, so builds on Linux are unchanged.
|
|
23
|
+
- e1a440f: A `builtin:vm` build runs Docker when its recipe asks for it. A recipe asks by listing the `ghcr.io/devcontainers/features/docker-in-docker` feature, at any tag or digest. The microVM then starts its own Docker daemon, and the agent user can run `docker` before the clone starts. Image pulls go through the runner's tunnel like the rest of the build's traffic. Containers the build starts have no route out. If the daemon does not answer within 60 seconds, provisioning fails and names the daemon. Its reason includes the end of the daemon's log. A recipe that does not list the feature runs no daemon. The build's recorded recipe report says whether Docker was asked for.
|
|
24
|
+
|
|
25
|
+
## 0.3.0
|
|
26
|
+
|
|
27
|
+
### Minor Changes
|
|
28
|
+
|
|
29
|
+
- 9b8ebd0: Adds `outerlayer work open-pr --title <text> --body-file <path>`. A host build sends it to the gateway, which opens or edits the item's pull request as the factory's GitHub App. A person's own session runs `gh` under their login and declares the pull request on the item.
|
|
30
|
+
|
|
31
|
+
The runner now speaks protocol 4. A claim names the branch the build works on, and the runner checks that branch out in the provisioned workdir before the command starts. It also sets `OUTERLAYER_BRANCH` for every hook and the command. A container build gets `OUTERLAYER_BRANCH` but not the checkout, so it checks the branch out itself. The runner skips a claim the gateway refuses, such as a pull request from a fork, and logs the refusal code. A gateway from this release refuses a runner below protocol 4 with `runner_upgrade_required`, so upgrade runners to this version.
|
|
32
|
+
|
|
33
|
+
- e377274: `outerlayer login` signs in to your account through the browser: it opens a page where you approve the CLI, then saves a token for your account. It chooses no organization or factory, so commands that need a factory tell you to run `outerlayer connect`. `outerlayer logout` revokes the token and removes it. A factory key, from a flag, `OUTERLAYER_API_KEY` or the config file, always wins over the login, so CI and runners keep acting as their key. Use `--no-browser` to print the link instead, `--no-input` to skip waiting on a person, and `--check` to finish a login that was still waiting.
|
|
34
|
+
- 39f75bc: Adds `outerlayer connect`, which chooses the factory a repository's work goes to. It picks by itself when only one answer is possible, says what it picked and why, and saves the choice in the repository's git directory, shared by every worktree and never committed. With no terminal it exits 1 and lists the `--factory <org>/<factory>` values to pass.
|
|
35
|
+
|
|
36
|
+
`outerlayer init` now connects the repository, installs the hooks and runs `doctor`. It never signs in: with no login it skips the connect step and says to run `outerlayer login`. `init --local` is the old behavior, with no connect step and no network call. `init --json` prints one document naming the outcome of each step.
|
|
37
|
+
|
|
38
|
+
A login now takes its factory from the repository it runs in, not from `appId` in the config file. `--app-id` and `OUTERLAYER_APP_ID` still win. A factory key is unchanged. Run `outerlayer connect` once in each repository that used a login's saved factory.
|
|
39
|
+
|
|
40
|
+
- 91c2778: A container build of a governed repository now starts with its control plane's context in the checkout: `AGENTS.md`, skills and validators, at the control plane's current head. The runner reads the control plane on the host with the host's own git login, and the build receives files, never a credential. A host whose git login cannot read the control plane fails the build at provision with `context_unavailable`, and `outerlayer doctor` checks this on a container host.
|
|
41
|
+
|
|
42
|
+
The runner now speaks protocol 9, because it asks the gateway which repository governs a build's repository. A gateway from this release still accepts a runner at protocol 8.
|
|
43
|
+
|
|
44
|
+
- 3294997: `outerlayer doctor` now asks the gateway three questions. Does the saved credential work? Can it use the factory chosen for this repository? Is the repository linked to that factory? A login and a factory key are each checked the way a command would use them, and a factory key wins over a login. With no credential, the three checks are skipped and doctor makes no network call. The GitHub App check runs only when the credential check passes. Fix hints no longer name `--api-key`, `--root` or `npx @outerlayer/cli`.
|
|
45
|
+
- 89a20a5: `outerlayer doctor` adds one check per repository connected to your factory, once `outerlayer login` has saved a factory key. It warns when the GitHub App installation has not accepted a permission builds need, naming each one and the installation's settings page, and when the default branch does not require a pull request. It reads `GET /v1/repositories/access` and changes nothing.
|
|
46
|
+
- b0519e1: `outerlayer emit finding` now records a problem you hit in the factory. It takes `--category` (`context`, `flaky-test`, `tooling`, `environment`, `defect` or `other`) and drops `--subject`, `--kind`, `--severity`, `--verdict`, `--fixed` and `--source`; each removed flag is refused by name. A `context` finding names the instruction with `--rule-path` and `--rule-relation` (`wrong`, `broken` or `missing`), and quotes it with `--rule-quote` unless the relation is `missing`.
|
|
47
|
+
|
|
48
|
+
`outerlayer emit findings <file>` takes `"schemaVersion": 2` files. A `schemaVersion: 1` file is refused. The gateway refuses a `schemaVersion: 1` batch with a message to upgrade the CLI.
|
|
49
|
+
|
|
50
|
+
`outerlayer init --template default` and `outerlayer context emit` install a new maintained `reporting-findings` skill that tells agents when to record a finding.
|
|
51
|
+
|
|
52
|
+
- 6bddf79: Uploads now carry the session's token counts so far, split per model, speed and input size, so the gateway can price the whole session itself. Each turn's usage also names its 5-minute cache writes and the request's speed. The gateway stores its own price and keeps the cost the CLI worked out only for a turn it has no price for.
|
|
53
|
+
|
|
54
|
+
The CLI's local cost estimate now prices a turn as unknown when the model has no rate for a token class the turn used, such as cache reads. It used to price that class at zero, so the status line showed a lower cost than the true one.
|
|
55
|
+
|
|
56
|
+
- e3f8d26: The runner sends a heartbeat at the end of every poll — its CLI version, poll interval, slots in use and total, and the result of that poll's own request for work. A key without the new `hosts.ingest` permission still polls and claims normally; the heartbeat is refused, logged once, then every tenth poll while it continues, and the host stays off `GET /v1/hosts` until the key is edited to add it.
|
|
57
|
+
- 9de5518: A build the runner starts now holds an item key, not the runner's own key. The claim response carries the key, and the runner passes it as `OUTERLAYER_API_KEY` to the hooks, the command, the sync step and the cleanup hook. It acts only on the claimed item, and only while the claim is live. The runner keeps its own key for renewing and releasing the claim and for heartbeats, and it runs the final sync under the item key before it releases. The runner protocol is now 2, so a gateway that predates the item key does not return one. The runner then releases the claim without starting the build and says so in its log.
|
|
58
|
+
- ea3130e: `outerlayer runner image --repository <owner/name>` builds the image a repository's builds run in, from the devcontainer file on its default branch. It ignores every setting that reaches the host or widens the container's privileges, and lists each one it ignored. It adds this CLI and a pinned Claude Code to the image, reuses the image until the recipe or the tools change, and keeps the newest three. `outerlayer doctor` on a runner host now checks each fetched repository's recipe, the devcontainer CLI, and whether the pinned Claude Code version is behind. The CLI now depends on `@devcontainers/cli`.
|
|
59
|
+
- 1834f72: A build's commits are now authored by the GitHub App's bot account, and credit the member who asked for the build. The claim response carries `commitAuthor` and, when the requester signed in with GitHub, `coAuthor`. The runner sets `GIT_AUTHOR_NAME`, `GIT_AUTHOR_EMAIL`, `GIT_COMMITTER_NAME` and `GIT_COMMITTER_EMAIL` for every process an attempt starts, so a host's own git identity no longer authors a commit.
|
|
60
|
+
|
|
61
|
+
For a co-author, the runner writes a hooks directory into the build's directory and points git at it through `GIT_CONFIG_COUNT`, after any entries the host already passes. Each hook runs the repository's own hook of the same name with the same arguments, input and exit status. `prepare-commit-msg` then adds one `Co-authored-by` line. A build run through an `exec` gets the bot as author and no co-author line.
|
|
62
|
+
|
|
63
|
+
The release records `environment.commitIdentity`. The runner now speaks protocol 8. A gateway that predates the field refuses a release that names it, and the runner sends the release again without it.
|
|
64
|
+
|
|
65
|
+
- c2032f3: A runner whose provision and cleanup hooks are `builtin:container` now runs each build in its own hardened container: no network but loopback, no Linux capabilities, a read-only root filesystem and one volume. The build reaches public addresses only through a tunnel the runner serves, which refuses private, link-local, shared-address and the host's own addresses and records every host the build reached. The runner config gains a `build` block (`memory`, `cpus`, `pids`, `disk`, `variables`), the image's tools layer gains an unprivileged user, `gh` and `tini`, and every release now carries an `environment` object recording what the attempt ran in. The runner protocol is now 2.
|
|
66
|
+
- ca1cc05: A container build no longer holds a credential that can write to its repository. The runner serves the build a local git remote and holds the repository tokens itself. It asks the gateway for a read token before it provisions anything, and for a push token on the build's first push. It renews each token within ten minutes of expiry and revokes every one when the attempt ends. The build's `gh` holds only the read token.
|
|
67
|
+
|
|
68
|
+
The runner forwards a push only when every ref it updates is the branch the claim names. On a branch outside `outerlayer/`, it forwards only creating the branch or a fast-forward. `GH_TOKEN`, `GITHUB_TOKEN`, `GH_ENTERPRISE_TOKEN` and `GITHUB_ENTERPRISE_TOKEN` in `runner.build.variables` are no longer passed into a build. The runner logs each name it skips.
|
|
69
|
+
|
|
70
|
+
A container build now needs a gateway with a GitHub App configured. Without one, every claim ends as `failed` at provision with the reason `repository_tokens_unavailable`. The release records which kinds of token the build used as `environment.credentials`.
|
|
71
|
+
|
|
72
|
+
The runner now speaks protocol 6, because the release carries `credentials` and the runner calls the token route. A gateway that has not been upgraded refuses a release that names `credentials`, so upgrade the gateway first.
|
|
73
|
+
|
|
74
|
+
- 3a32b01: A build the runner provisions with `builtin:container` or `builtin:process` no longer holds the item key or Claude's credential. The runner serves two built-in destinations, `gateway` and `claude`. The build's `OUTERLAYER_URL` and `ANTHROPIC_BASE_URL` point at local addresses, and its `OUTERLAYER_API_KEY` and Claude credential variable hold placeholders. The runner sets the item key and the host's credential on each request it forwards.
|
|
75
|
+
|
|
76
|
+
The runner reads `CLAUDE_CODE_OAUTH_TOKEN`, or else `ANTHROPIC_API_KEY`, from its own environment. A host that sets neither now ends each attempt as `failed` at `provision` with the reason `agent_credential_missing`, so set one before upgrading. Remove `CLAUDE_CODE_OAUTH_TOKEN` from `runner.build.variables`: a name there now gets a placeholder. A host may list at most 18 destinations, down from 20, and may not name one `gateway` or `claude`.
|
|
77
|
+
|
|
78
|
+
- e07a51f: A host's own hooks can now report how their builds are isolated, and `outerlayer runner init` names the hooks that fit the machine. A provision hook can write `isolation`, `exec`, `broker` and `recipe` to `provision.out`. It receives the build's directory, the repository, the recipe commit and the four limits. The new `builtin:process` hooks run builds as processes on machines that cannot isolate them, through the same tunnel, and record `shared-user`. `runner init` names `builtin:container` on Linux or WSL2 with Docker Engine 26 or later, and `builtin:process` elsewhere, and no longer writes hook scripts. `outerlayer doctor` says what a host's builds get. A host can list credentialed services in `runner.build.destinations`. The runner forwards a build's requests to them over HTTPS with the host's header in place of any credential the build sent, so the secret never enters the build, and the release names the destinations a build called. The runner protocol is 4.
|
|
79
|
+
- ad6979c: `outerlayer runner check` now exits 1, before the host takes work, when an enabled queue's command is still the placeholder `runner init` wrote, when built-in hooks find neither `CLAUDE_CODE_OAUTH_TOKEN` nor `ANTHROPIC_API_KEY` set, and when the key lacks `work.claim`. Each message names the queue, `claude setup-token` or the permission.
|
|
80
|
+
|
|
81
|
+
On a runner host, `outerlayer doctor` lists the laptop checks as skipped with one line that says why, adds a `Claude credential` check that names the variable and never its value, and names a missing permission instead of calling the key revoked or expired. Its GitHub App hint says whether the App's own settings must add a permission or an installation owner must accept it.
|
|
82
|
+
|
|
83
|
+
A container build fetches the image recipe of a private repository with the claim's read token, so the host needs no git login. `outerlayer runner image` exits 1 with one line naming the repository when its fetch fails. `outerlayer work build` warns when the gateway says the request cannot earn repository tokens.
|
|
84
|
+
|
|
85
|
+
- b2a18b7: `outerlayer runner init` no longer chooses builds without isolation for you. On a machine that cannot isolate a build, it refuses and says what isolation needs; pass `--allow-process-builds` to run builds as processes under your user instead. On a Mac with no terminal to ask, it refuses and names `--vm`. A host can now list the public hosts its builds may reach in `runner.build.allowHosts`: the tunnel refuses every other name before resolving it, and records the refusal with the range `not-allowed`.
|
|
86
|
+
- 3019459: A runner key now works only from the host that first used it, and the runner signs every request it makes. The runner makes an Ed25519 host key in `~/.outerlayer/runner/host-key.pem` the first time it starts. Its first claim binds the key's public half to the runner key. After that the gateway refuses any request made with that runner key unless the host key signed it.
|
|
87
|
+
|
|
88
|
+
The runner speaks protocol 7, and a gateway from this release refuses a runner below it with `runner_upgrade_required`, so upgrade every runner. To move a runner key to a new host, a member clears its binding on the factory's API keys page, and the new host's next claim binds its own key.
|
|
89
|
+
|
|
90
|
+
`outerlayer doctor` says whether the runner key is bound to this host, bound to another, or not yet bound. A refused signature is reported with its cause: a stale one names the host's clock. `outerlayer runner init` prints the host key's fingerprint.
|
|
91
|
+
|
|
92
|
+
- 85fa250: On macOS, `outerlayer runner init` now offers to create a Linux VM with Lima and run the runner inside it, so builds run in containers and record `container`. `--vm` answers yes and `--no-vm` answers no; a run with no terminal answers no. The VM holds the runner key and the host key, and starts at login through a launch agent and a systemd service. The Mac's config loses `apiKey` and `runner` and gains a `runnerVm` note.
|
|
93
|
+
|
|
94
|
+
`outerlayer doctor` on a Mac with process hooks now says builds are not isolated and names `outerlayer runner init --vm`. With the runner in a VM, it reports the VM's state and how to start it.
|
|
95
|
+
|
|
96
|
+
- 365dab4: The runner and `outerlayer work claim` now send the runner protocol they were built with, as `runnerProtocol`, on every claim, and the runner sends it on every heartbeat. A gateway that needs a newer protocol refuses the claim with `426 runner_upgrade_required`. The runner then logs the minimum protocol and a link to the upgrade steps, and keeps polling so it takes work again once it is upgraded and restarted.
|
|
97
|
+
- 02f7990: `outerlayer init --template default` installs a starter skill pack into `.outerlayer/skills/`. The templates `spec`, `writing-specs` and `build` are copied once and never overwritten. The maintained skills `emitting-evidence` and `amend` are rewritten from the installed CLI on every `outerlayer context emit`, and each carries the CLI version on its first line. `init --template default` also writes a starter `.outerlayer/policy.yaml` unless one exists.
|
|
98
|
+
|
|
99
|
+
`outerlayer context emit --check` now reports drift, and exits 1, when a maintained skill differs from the installed CLI's copy, for example after a CLI upgrade. `outerlayer import capture` rewrites both maintained skills instead of refusing to overwrite a skill with local edits.
|
|
100
|
+
|
|
101
|
+
- 1177caa: `outerlayer work build` takes a Linear or Jira issue key, not only a GitHub issue number: `outerlayer work build --issue ENG-123 --tracker linear`. `--tracker` names which tracker a keyed issue belongs to, required only when a factory has connected more than one. `--repo` is the only way to attach a repository to a keyed issue. A new `--retry <count>` option sends a build request again, up to 4 more times, after any 5xx or 429 answer, including a 5xx from a proxy in front of the gateway. A retry after such an answer can record the request twice. It never resends after a network error or a 4xx other than 429.
|
|
102
|
+
- 852946a: Add `outerlayer work build`, which asks a host to build a work item. `outerlayer work add` alone no longer queues an item for a host. A session launched with `OUTERLAYER_WORK` now holds a 20-minute lease on its item, renewed by a new `PostToolUse` hook and released when the session ends; run `outerlayer init` to add the hook to an existing install.
|
|
103
|
+
- b52a19e: `outerlayer work build` is the one command that starts work on an item. `work build --issue <n>` asks a host to build it. `work build --issue <n> --local` puts it on Work for you to build, and prints the `OUTERLAYER_WORK=<n> claude` line that starts your session on it. `outerlayer work add` is removed; use `work build --local` where you used it.
|
|
104
|
+
- cfddc47: Adds `outerlayer work comment` and `outerlayer work threads`. A work item's review, and each acceptance criterion's own proof, live on comment threads now: a person's pass or fail, an agent's attach or ready. `outerlayer emit`'s per-artifact verdict option is removed — record it as a comment instead.
|
|
105
|
+
|
|
106
|
+
### Patch Changes
|
|
107
|
+
|
|
108
|
+
- 9787d1c: The runner now sends the step an attempt ended in, its exit code, and a one-line reason from `$OUTERLAYER_JOB_DIR/reason` when it releases a work item claim. The reason comes only from a file the host's own cleanup hook writes, scrubbed and cut to 200 characters before it leaves the machine.
|
|
109
|
+
- 22ce869: The status line now keeps the session cost Claude Code reports, and `sync` and the daemon send it with each Claude Code session as `totals.agentReportedCostUsd`. The daily pricing check compares it with the cost the gateway stored.
|
|
110
|
+
- ac57469: Every command on a runner host signs its requests with the host key when it uses the saved runner key. `outerlayer doctor`, `work status`, `sync`, `emit` and the other commands no longer fail with `runner_key_signature_required` once the runner key is bound to the host.
|
|
111
|
+
- 1ba39dc: A container build now starts on the branch its claim names, by the rule a host build uses, before its lifecycle commands run. The checkout is a partial clone that keeps every commit, so a merged `outerlayer/` branch starts from the default branch's head. The build image also writes Claude Code managed settings that run `outerlayer hook`, so the sessions a build starts are linked to the item and uploaded by its sync. The runner copies the build's hook error log into the job directory before it removes the container.
|
|
112
|
+
- 4677cd6: A container or process build can run `yarn install`. The runner now also sets `YARN_HTTPS_PROXY` and `YARN_HTTP_PROXY`, because Yarn 2 and later ignore `HTTPS_PROXY` and could not reach the registry from a build.
|
|
113
|
+
- 1e2f5e3: `outerlayer doctor` checks that a container host can read the control plane of every repository the runner builds. With no `repos.include`, which is how `runner init` leaves the config, it checks every repository connected to the factory instead of nothing.
|
|
114
|
+
- e4f5e1e: `outerlayer sync` no longer writes `~/.outerlayer/spool/session-repos.json`. Nothing reads that file, so it is safe to delete.
|
|
115
|
+
- 0248261: Hooks written by `outerlayer init` run the CLI through `node`, so they keep working when a copy of the CLI loses its execute bit. Run `outerlayer init` again to rewrite hooks written by an earlier version. `outerlayer doctor` now fails "Hooks installed" when a hook runs the CLI script directly and the script is not executable.
|
|
116
|
+
- f90e444: Help and error text use the product's own words. Every `--app-id` option is described as the factory id, no text calls the Work page "Floor", and a key bound to another factory is refused with "bound to a different factory". The package description names only commands the CLI has.
|
|
117
|
+
- e78d9a9: The cost estimate charges 1-hour cache writes at the model's published 1-hour rate. It also charges a request whose total input exceeds a model's long-request threshold at the higher rates for every token, and charges fast mode at its multiplier for models that have one, such as Opus 5.5.
|
|
118
|
+
- 0db0425: The provision hook written by `outerlayer runner init` clones the repository the work item records (`specRepository` in `outerlayer work status --json`) instead of reading it off the tracker key. A Linear or Jira item, whose key such as `ENG-123` names no repository, now clones the right one. An item that records no repository fails its job with one line saying so, rather than trying to clone a URL that does not exist. `runner init` never overwrites a hook, so delete an existing `provision.sh` written by an earlier version before running it again, or make the same edit by hand.
|
|
119
|
+
- 112813e: No change in behavior. The committed `.outerlayer-pin.json` is still written and read the same way; the server no longer compares sessions against it.
|
|
120
|
+
- 02db30e: The `reporting-findings` skill that `outerlayer init` installs now describes the moments it applies to: writing a "Factory problems" section, a build or review report, or noticing a stale instruction, a flaky test or a misbehaving gate. Its batch shape is spelled out so `outerlayer emit findings` files can be written from the skill alone.
|
|
121
|
+
- 4c5a9ea: `outerlayer emit <name>` from inside a recorded session can now record checks on the work item the session was launched for, stored as the session's own. A session still cannot clear a person's fail. The help text and README say so.
|
|
122
|
+
- 7720377: `outerlayer sync` no longer guesses a price for a model name it doesn't recognize exactly, case-insensitively, or as a listed variant (a provider prefix, a region prefix, a date suffix, a `-vN:M` suffix, or a `[1m]` suffix). A name like `claude-opus-4-9` now shows the existing unknown-model warning and stores an unpriced cost, instead of silently pricing as `claude-opus-4` — a different model, at a different rate.
|
|
123
|
+
- 07c2785: `outerlayer work comment` now says that a person's `fail` on the item's general thread is what hands the item to an agent, and that a plain comment or a criterion `fail` no longer does. The README describes the item page in place of the removed Review tab.
|
|
124
|
+
- d15ccf4: `outerlayer work comment` and `outerlayer work threads` print a failed request as a one-line error and exit 1, as the other `work` commands do, instead of a stack trace.
|
|
125
|
+
- dec3f5b: `outerlayer work list --claimed` lists only the work items a host holds right now. Each claimed row shows which host holds it, as which kind of claim, since when and until when. With `--json`, each row carries its `claim` object.
|
|
126
|
+
|
|
3
127
|
## 0.2.0
|
|
4
128
|
|
|
5
129
|
### Minor Changes
|
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,16 +59,26 @@ 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.
|
|
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
|
|
71
82
|
list and read items, and `work.claim` to claim, renew or release — `work.claim`
|
|
72
83
|
is not granted to a dashboard role by default, since a claim is a host's
|
|
73
84
|
lease, not a person's.
|
|
@@ -75,9 +86,157 @@ content:
|
|
|
75
86
|
items the same way `work claim`/`renew`/`release` do, on the schedule its
|
|
76
87
|
config sets — it sends nothing about the job it runs beyond that; the
|
|
77
88
|
agent it starts is a separate process with its own credentials, from the
|
|
78
|
-
`runner` block, never the copy-out daemon's.
|
|
79
|
-
|
|
80
|
-
|
|
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.
|
|
81
240
|
- **`outerlayer emit artifact`** uploads the file you name — a screenshot, a
|
|
82
241
|
recording, a report, a log — along with its caption. With no recorded
|
|
83
242
|
session to attach it to, it uploads immediately, anchored to a pull request
|
|
@@ -88,9 +247,14 @@ content:
|
|
|
88
247
|
route. Run from CI or a plain shell, where there is no session, it sends
|
|
89
248
|
as it always has.
|
|
90
249
|
- **`outerlayer emit finding`** and **`outerlayer emit findings <file>`** send
|
|
91
|
-
one finding, or a whole batch of them, for a work item —
|
|
92
|
-
anchoring as `emit <name>` (`--item`, or
|
|
93
|
-
|
|
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.
|
|
94
258
|
- **`outerlayer mcp serve`** is the stdio MCP server your editor spawns. It
|
|
95
259
|
forwards every JSON-RPC message the editor sends to the gateway and returns
|
|
96
260
|
the reply.
|
|
@@ -122,9 +286,9 @@ space, past both stubs, so the same test records every program each run
|
|
|
122
286
|
starts and asserts none of them fetches over the network.
|
|
123
287
|
|
|
124
288
|
Failures the hook cannot show you — a refused `OUTERLAYER_WORK` value, a
|
|
125
|
-
`work
|
|
289
|
+
`work link-session` that could not reach the factory — are appended to
|
|
126
290
|
`~/.outerlayer/spool/hook-errors.log`, and the next session start says so.
|
|
127
|
-
The
|
|
291
|
+
The link retries a gateway it cannot reach a few times, with backoff,
|
|
128
292
|
before it gives up.
|
|
129
293
|
|
|
130
294
|
- **The tier is applied before anything leaves.** The default tier is
|
|
@@ -142,37 +306,43 @@ before it gives up.
|
|
|
142
306
|
| Command | What it does |
|
|
143
307
|
|---|---|
|
|
144
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`. |
|
|
145
|
-
| `outerlayer login [--
|
|
146
|
-
| `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. |
|
|
147
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. |
|
|
148
|
-
| `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. |
|
|
149
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. |
|
|
150
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/`. |
|
|
151
317
|
| `outerlayer hooks wrap` / `outerlayer hooks unwrap` | Auto-wrap (or undo wrapping) `PreToolUse`/`PostToolUse` hooks for execution evidence — one spawn per firing. |
|
|
152
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. |
|
|
153
|
-
| `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;
|
|
154
|
-
| `outerlayer
|
|
155
|
-
| `outerlayer
|
|
156
|
-
| `outerlayer emit
|
|
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. |
|
|
157
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. |
|
|
158
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. |
|
|
159
|
-
| `outerlayer work
|
|
160
|
-
| `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. |
|
|
161
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. |
|
|
162
|
-
| `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. |
|
|
163
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. |
|
|
164
|
-
| `outerlayer work
|
|
165
|
-
| `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`). |
|
|
166
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. |
|
|
167
|
-
| `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. |
|
|
168
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. |
|
|
169
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`). |
|
|
170
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. |
|
|
171
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. |
|
|
172
342
|
| `outerlayer runner logs <item> [--config <path>] [-f]` | Prints the newest attempt's log for one item, following it with `-f`. |
|
|
173
343
|
|
|
174
344
|
The `work` commands need an API key that carries `work.insert` to add,
|
|
175
|
-
remove, and declare a pull request (`pr`), and `work.read` to look an item up
|
|
345
|
+
remove, and declare a pull request (`pr`, `open-pr`), and `work.read` to look an item up
|
|
176
346
|
— which `remove` and `status` both do before they act. Tick both when you
|
|
177
347
|
mint the key, in Settings → API keys. Claiming, renewing or releasing a
|
|
178
348
|
lease needs `work.claim`. Withdrawing an addition somebody else made
|
|
@@ -203,10 +373,9 @@ Record a pass once the work is right:
|
|
|
203
373
|
outerlayer emit code-review --result pass --item 412
|
|
204
374
|
```
|
|
205
375
|
|
|
206
|
-
`--item` is always required, in or out of a recorded session.
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
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.
|
|
210
379
|
|
|
211
380
|
Three things to know. Who recorded a check is decided by the API key you
|
|
212
381
|
used, never by anything in the request. A key bound to a membership records
|
|
@@ -216,30 +385,28 @@ because a fail with neither is something nobody can act on. And a check only
|
|
|
216
385
|
holds a gate once a validator in `.outerlayer/validators/` declares its emit
|
|
217
386
|
name; without one the check is recorded and read back, and blocks nothing.
|
|
218
387
|
|
|
219
|
-
A review of the work itself is different:
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
The item's own pass stays available only once every required artifact has
|
|
242
|
-
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.
|
|
243
410
|
|
|
244
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`.
|
|
245
412
|
|