@outerlayer/cli 0.20.0 → 0.22.1

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.
Files changed (147) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +15 -5
  3. package/dist/{agent-setup-AM42SA2D.js → agent-setup-LTSLXPS3.js} +13 -12
  4. package/dist/build-6WRNZPVR.js +12 -0
  5. package/dist/build-command-ND2ENDBS.js +50 -0
  6. package/dist/build-info.json +1 -1
  7. package/dist/{builder-C4QNTYMS.js → builder-G3MLDMTI.js} +7 -5
  8. package/dist/{check-BR5D27CX.js → check-UYKEMQNR.js} +48 -50
  9. package/dist/{chunk-AMFWYESY.js → chunk-276D7BJ7.js} +1 -1
  10. package/dist/{chunk-X5H2WYMB.js → chunk-2Q3PZ42G.js} +1 -1
  11. package/dist/{chunk-3CWUOFV6.js → chunk-3AZYLAJC.js} +13 -8
  12. package/dist/{chunk-LRG3ZMZD.js → chunk-3V5C64Y5.js} +4 -4
  13. package/dist/{chunk-QOZKPLVJ.js → chunk-3W333NFO.js} +40 -1
  14. package/dist/{chunk-7YP7T6GV.js → chunk-4AVDD7VX.js} +2 -2
  15. package/dist/{chunk-KYS3TQAG.js → chunk-56X5TOJY.js} +4 -4
  16. package/dist/{chunk-3ZR7Y23Y.js → chunk-5NJIWKD4.js} +650 -70
  17. package/dist/{chunk-NNLA7LLQ.js → chunk-5OCIHFGE.js} +29 -5
  18. package/dist/{chunk-EAEELQVQ.js → chunk-6YBLN4TR.js} +5 -5
  19. package/dist/{chunk-AD3EYI7P.js → chunk-7FEY33MY.js} +259 -56
  20. package/dist/{chunk-QNLX477Q.js → chunk-AEKSX4EY.js} +165 -72
  21. package/dist/{chunk-FBTGMSQF.js → chunk-BET347JZ.js} +16 -9
  22. package/dist/{chunk-JHGEBPLE.js → chunk-BOMRFYTZ.js} +3 -3
  23. package/dist/{chunk-MTP2QEVO.js → chunk-CQAEV3Z5.js} +1 -1
  24. package/dist/{chunk-XZ4H4X5F.js → chunk-CUFFDEF3.js} +15 -8
  25. package/dist/{chunk-BM63HB2M.js → chunk-EAQSOE62.js} +2 -2
  26. package/dist/{chunk-VYAL7PUE.js → chunk-EFB3FGLC.js} +1 -1
  27. package/dist/{chunk-GEMQLBMW.js → chunk-ENTHEUKT.js} +6 -6
  28. package/dist/{chunk-B6SCN5NY.js → chunk-FOCML5FI.js} +175 -44
  29. package/dist/{chunk-LW7G5TJB.js → chunk-FRNYCJ4W.js} +2 -2
  30. package/dist/chunk-GISNHSYL.js +41 -0
  31. package/dist/{chunk-G2YNJIGF.js → chunk-HCVLP7XA.js} +10 -1
  32. package/dist/{chunk-N2PXGQRL.js → chunk-IHNQWF6F.js} +1 -1
  33. package/dist/{chunk-CG36IONK.js → chunk-JRCSET55.js} +2 -2
  34. package/dist/{chunk-MLAAT4S6.js → chunk-JV4YGAAW.js} +3 -3
  35. package/dist/{chunk-XNGMQ27R.js → chunk-JZGFDTNC.js} +2 -2
  36. package/dist/{chunk-GGOMT6KF.js → chunk-NYTZ7HVN.js} +1 -1
  37. package/dist/{chunk-CGGPS7SI.js → chunk-O6RJ3QMU.js} +5 -5
  38. package/dist/{chunk-QEFKA2QD.js → chunk-OBCFK4QD.js} +2 -2
  39. package/dist/{chunk-HOKXGFDR.js → chunk-ORNJJ7XN.js} +22 -16
  40. package/dist/{chunk-M2ZWWTWZ.js → chunk-OW52QLK3.js} +1 -1
  41. package/dist/{chunk-PSN33ERW.js → chunk-QC72I5GQ.js} +3 -3
  42. package/dist/{chunk-FVMYKL6L.js → chunk-QF7WZUU6.js} +1 -1
  43. package/dist/{chunk-IF2OSI5T.js → chunk-QOALB6ZD.js} +2 -2
  44. package/dist/{chunk-ZX4I2MEK.js → chunk-TPKYTORP.js} +1 -1
  45. package/dist/{chunk-S5PCA3SN.js → chunk-UF5L4BAI.js} +1 -1
  46. package/dist/{chunk-R22NZSGA.js → chunk-URAKVDSI.js} +9 -9
  47. package/dist/{chunk-BQXFBI7T.js → chunk-URWYRAIC.js} +32 -7
  48. package/dist/{chunk-7UWVLZXD.js → chunk-USWVXQIH.js} +1 -1
  49. package/dist/{chunk-P53VEAOF.js → chunk-V5CG75NX.js} +1 -1
  50. package/dist/{chunk-6X4SQ5MY.js → chunk-V7SAQ645.js} +1 -1
  51. package/dist/{chunk-TWF3RICI.js → chunk-VSUXCMMH.js} +110 -11
  52. package/dist/{chunk-Z7K3L4FC.js → chunk-W3SWJ2TD.js} +2 -2
  53. package/dist/{chunk-ECODQ7II.js → chunk-XACXXKQ5.js} +1 -1
  54. package/dist/{chunk-5VML45HH.js → chunk-XCRZTXRL.js} +2 -2
  55. package/dist/chunk-XR56WEA5.js +718 -0
  56. package/dist/chunk-ZNPE7FW5.js +137 -0
  57. package/dist/{chunk-PIZRPNKR.js → chunk-ZPSLJFGL.js} +5 -5
  58. package/dist/claude-launcher-TBWV3YL3.js +267 -0
  59. package/dist/{cli-MKF7TU7X.js → cli-U253V422.js} +161 -120
  60. package/dist/{command-ZQNEPDS6.js → command-IQTPFSXY.js} +32 -34
  61. package/dist/{config-CLSGABD5.js → config-H4QS332G.js} +3 -2
  62. package/dist/{connect-cmd-UNYKGDAL.js → connect-cmd-ZFOK6HEL.js} +5 -5
  63. package/dist/{context-cleanup-CHEWNYU6.js → context-cleanup-DSA3HGQU.js} +1 -1
  64. package/dist/{control-plane-launch-34LNRJWR.js → control-plane-launch-OWSNH6YA.js} +62 -28
  65. package/dist/{dist-WO7NOJNG.js → dist-7IH56ELA.js} +1 -1
  66. package/dist/{docker-BFU3AQGY.js → docker-JU422JL7.js} +7 -7
  67. package/dist/{doctor-DHUM5DBB.js → doctor-FZTS57ZO.js} +35 -36
  68. package/dist/{emit-artifact-cmd-XBHM647X.js → emit-artifact-cmd-YLZ5WLSF.js} +19 -18
  69. package/dist/{emit-cmd-W55AEBCA.js → emit-cmd-3W5IO5ET.js} +3 -3
  70. package/dist/{emit-criteria-cmd-UNMWHOUY.js → emit-criteria-cmd-MF6TVE7C.js} +13 -12
  71. package/dist/{emit-finding-cmd-7JHVRYOP.js → emit-finding-cmd-S3YMFTZT.js} +13 -12
  72. package/dist/{emit-result-cmd-5NZMLCJK.js → emit-result-cmd-JHEUFTPX.js} +19 -18
  73. package/dist/{emit-step-cmd-347XNGPQ.js → emit-step-cmd-TUI2T3DS.js} +14 -13
  74. package/dist/{exec-client-7UMESIE2.js → exec-client-ATPF2DDB.js} +4 -3
  75. package/dist/{governing-source-HAA4OW57.js → governing-source-XSEIRSBE.js} +19 -18
  76. package/dist/{guest-init-KPBQOFE5.js → guest-init-DF7V5D2R.js} +4 -3
  77. package/dist/{hook-fast-RL5E5OXE.js → hook-fast-O3UUN6SO.js} +2 -2
  78. package/dist/host-key-ATB23GI3.js +9 -0
  79. package/dist/{import-capture-cmd-TK4XY7RD.js → import-capture-cmd-Q56DDZVO.js} +1 -1
  80. package/dist/index.js +5 -5
  81. package/dist/init-VZE72CR4.js +52 -0
  82. package/dist/{init-V6FOMD2V.js → init-ZZZPYGUH.js} +32 -33
  83. package/dist/{init-cmd-Z4O4PPLZ.js → init-cmd-W5VV62ZN.js} +25 -23
  84. package/dist/{init-update-7DVAKWW3.js → init-update-YFPIQS5G.js} +69 -24
  85. package/dist/{install-4SEFIIW2.js → install-SFACZU7E.js} +5 -4
  86. package/dist/{install-cmd-QDOTR4OM.js → install-cmd-6HTP7I43.js} +6 -5
  87. package/dist/{login-browser-DX35MARZ.js → login-browser-BN5UKPHS.js} +3 -3
  88. package/dist/{logout-cmd-5V5MMBSY.js → logout-cmd-RZFWTNYD.js} +2 -2
  89. package/dist/{logs-AMLKC3VP.js → logs-N3ZX7HFV.js} +3 -2
  90. package/dist/loop-6WENRS5S.js +75 -0
  91. package/dist/machine-M4MQBV5A.js +47 -0
  92. package/dist/{mcp-install-cmd-GGWB3JJ2.js → mcp-install-cmd-GD4QUP7Z.js} +2 -2
  93. package/dist/{mcp-serve-cmd-N3UTY6EE.js → mcp-serve-cmd-SBW7HYKD.js} +6 -5
  94. package/dist/{paths-7XP63OAX.js → paths-AKX2OOLF.js} +3 -2
  95. package/dist/pending-7SGWZCEH.js +9 -0
  96. package/dist/{pidfile-3DM4OBKO.js → pidfile-G2J5WBQS.js} +4 -3
  97. package/dist/receive-files-T2BIUBQL.js +254 -0
  98. package/dist/{record-3WP6V2K5.js → record-Q4IEYIVV.js} +4 -3
  99. package/dist/relay-PSZ4LGMW.js +210 -0
  100. package/dist/relay-protocol-K7KP2SPI.js +6 -0
  101. package/dist/{runner-env-FRZFFHDF.js → runner-env-GZHXM27A.js} +6 -5
  102. package/dist/runner-identity-FTHZFMGY.js +14 -0
  103. package/dist/{runner-key-5FOWCW7J.js → runner-key-QT7GKGEE.js} +32 -33
  104. package/dist/{session-sender-U2BBUWNO.js → session-sender-BK6TGNVO.js} +20 -19
  105. package/dist/{spec-cmd-FVLJOFGC.js → spec-cmd-ZNJ3GXWC.js} +13 -12
  106. package/dist/{starter-pack-6LQVLBIA.js → starter-pack-5EQYGSJF.js} +2 -2
  107. package/dist/{status-BINH7MBG.js → status-JOO7MGIC.js} +36 -38
  108. package/dist/{statusline-fast-KN3BX67H.js → statusline-fast-2OK3DVAA.js} +2 -2
  109. package/dist/{sync-cmd-VXOUFS4I.js → sync-cmd-W2FPY3T5.js} +19 -18
  110. package/dist/{watch-OH645CV2.js → watch-WLH5ZUZU.js} +19 -18
  111. package/dist/{work-claim-cmd-DRQCHCOK.js → work-claim-cmd-4PLDTEZR.js} +17 -16
  112. package/dist/{work-cmd-5I3J2XQQ.js → work-cmd-KWHAYUYB.js} +13 -12
  113. package/dist/{work-comment-cmd-UCCPWUSR.js → work-comment-cmd-4CUI7ZDE.js} +13 -12
  114. package/dist/{work-logs-cmd-7352CJPG.js → work-logs-cmd-AF253WLM.js} +13 -12
  115. package/dist/{work-open-pr-cmd-LSH4VHJM.js → work-open-pr-cmd-JETE6HRL.js} +15 -14
  116. package/dist/{work-pr-cmd-H4OQR26N.js → work-pr-cmd-V5G4CPMG.js} +14 -13
  117. package/dist/{work-stop-cmd-CRDHXQVW.js → work-stop-cmd-FIEKUDGE.js} +13 -12
  118. package/package.json +2 -2
  119. package/skill-pack/maintained/outerlayer-amend/SKILL.md +17 -6
  120. package/skill-pack/maintained/outerlayer-build/SKILL.md +347 -0
  121. package/skill-pack/{template/build → maintained/outerlayer-build}/references/evidence.md +2 -2
  122. package/skill-pack/{template/build → maintained/outerlayer-build}/references/release.md +4 -4
  123. package/skill-pack/{template/build → maintained/outerlayer-build}/references/review-loop.md +3 -1
  124. package/skill-pack/shipped.json +2 -0
  125. package/skill-pack/template/build/SKILL.md +4 -253
  126. package/skill-pack/validators/acceptance-criteria.yaml +1 -1
  127. package/dist/build-TQ6X5PYN.js +0 -12
  128. package/dist/chunk-3UZTIRLF.js +0 -320
  129. package/dist/chunk-CX22S5BA.js +0 -45
  130. package/dist/chunk-LLM3I5YU.js +0 -89
  131. package/dist/chunk-SADUQSO4.js +0 -50
  132. package/dist/chunk-VMJPFQNE.js +0 -261
  133. package/dist/claude-launcher-J5M44PFS.js +0 -115
  134. package/dist/host-key-U4B5QETR.js +0 -8
  135. package/dist/init-XG47KCI4.js +0 -53
  136. package/dist/loop-EAZQMAE2.js +0 -77
  137. package/dist/machine-TRHBT5NE.js +0 -48
  138. package/dist/pending-532ABZYC.js +0 -8
  139. package/dist/relay-L76HDX72.js +0 -46
  140. package/dist/{chunk-YVZJ6GKF.js → chunk-DIB2WLBL.js} +1 -1
  141. package/dist/{chunk-GOSFARMS.js → chunk-F35VMF5M.js} +1 -1
  142. package/dist/{chunk-DSF2FWAZ.js → chunk-IZSVXRDR.js} +1 -1
  143. /package/skill-pack/{template/build → maintained/outerlayer-build}/references/agent-briefs.md +0 -0
  144. /package/skill-pack/{template/build → maintained/outerlayer-build}/references/criteria-judge.md +0 -0
  145. /package/skill-pack/{template/build → maintained/outerlayer-build}/references/review-briefs.md +0 -0
  146. /package/skill-pack/{template/build → maintained/outerlayer-build}/scripts/criterion-citations.mjs +0 -0
  147. /package/skill-pack/{template/build → maintained/outerlayer-build}/scripts/record-criteria.mjs +0 -0
@@ -1,260 +1,11 @@
1
1
  ---
2
2
  name: build
3
- description: >
4
- Build one approved issue end to end: implement it, review it with a sized panel
5
- of agents, run the repository's own checks, open the pull request, and attach
6
- the review and criteria reports as evidence. Use when a work item exists for an
7
- issue and you want it built. Invoke with OUTERLAYER_WORK=<number> claude "/build".
3
+ description: Build one approved issue end to end. Invoke with OUTERLAYER_WORK=<n> claude "/build".
8
4
  disable-model-invocation: true
9
5
  ---
10
6
 
11
- Run the CLI as `outerlayer`. If that command is not on PATH, run `npx -y @outerlayer/cli` with the same arguments. Every `outerlayer ...` command below follows this rule.
7
+ Read ../outerlayer-build/SKILL.md, relative to this skill's folder, and follow it from start to finish. Apply the changes below for this repository.
12
8
 
13
- Build one issue into an evidenced pull request. `/spec` writes and gets
14
- approval for the issue. This skill builds it. It never writes the spec.
9
+ ## Changes for this repository
15
10
 
16
- This file holds the phase order and the rules that bind every phase. Each
17
- phase reads its own reference on entry, never before:
18
-
19
- - [references/review-loop.md](references/review-loop.md): the review phase.
20
- - [references/review-briefs.md](references/review-briefs.md): the reviewer, refuter and mutation briefs.
21
- - [references/agent-briefs.md](references/agent-briefs.md): the briefs for every other agent.
22
- - [references/release.md](references/release.md): sync, pull request, CI.
23
- - [references/criteria-judge.md](references/criteria-judge.md): the brief that judges each criterion.
24
- - [references/evidence.md](references/evidence.md): manual test and evidence.
25
-
26
- Paste a brief verbatim into the agent that runs it. Add only the run's own
27
- values, such as paths, the branch and the item number.
28
-
29
- Every text a person will read follows the writing rule in the repository's
30
- instructions file, if it has one. Otherwise write for a reader who was not in
31
- the session: short sentences, the outcome first, and plain words. Paste that
32
- rule into every agent that writes prose.
33
-
34
- ## Arguments
35
-
36
- `/build` takes no issue number. It builds the work item named by
37
- `OUTERLAYER_WORK`, the item's number. The launch is:
38
-
39
- OUTERLAYER_WORK=<number> claude "/build"
40
-
41
- The item exists because someone ran `outerlayer work build --issue <reference>`.
42
- Given a request instead of a work item, stop and say:
43
-
44
- Spec it first: /spec <the request as given>
45
-
46
- Optional flag: `--unattended` means no person is present and nothing wakes
47
- the session after a turn ends. Spawn every agent in the foreground and wait
48
- for it in the same turn. Run the gate in the foreground with the maximum
49
- timeout. End the turn only at the final report.
50
-
51
- ## State rules
52
-
53
- These bind the orchestrator in every phase. Rule 5 also binds every spawned agent.
54
-
55
- 1. **Never end a turn waiting on nothing.** End a turn while work is in
56
- flight only when something live will wake the session: a spawned agent or
57
- a background command. Before saying "waiting on X", confirm X is live.
58
- Work that is not live did not happen: redo it once.
59
- 2. **One redo per piece of work.** A second failure of the same work means
60
- the orchestrator takes it over. It reads what the agent left, finishes the
61
- brief itself in the foreground, and names the takeover in its status line.
62
- If the gate still cannot go green, escalate.
63
- 3. **The gate runs in the foreground, one heavy command at a time.** The gate
64
- is the repository's own pre-push checks and tests, as its instructions
65
- file names them. Never run it in the background. Never start a suite while
66
- an agent runs one. Never bypass a hook: no `--no-verify`, no skipped hook,
67
- even when a hook fails. Fix what the hook reports.
68
- 4. **Checkpoint and re-orient.** Before phase 1, write a state file at
69
- `"$(git rev-parse --absolute-git-dir)/build-state.json"`, replacing any
70
- earlier one. Record the phase, the review round, the spawned agents, the
71
- agent count, the issue reference, the pull request number, the branch, and
72
- from phase 4 the tier verdict. Overwrite it at every phase change. On
73
- entering a phase, after any wake, and after any compaction, read the state
74
- file, `git status`, the branch, the live agent list, and the issue or pull
75
- request when the phase uses them. Live sources win over the file. Treat the
76
- file as absent when its branch does not match the current branch.
77
- When you overwrite the file, keep its `criteria` entry: phase 2 writes it
78
- and the judge reads it.
79
- Beside it, create `"$(git rev-parse --absolute-git-dir)/build-reports/"`,
80
- emptied of any earlier run's files. Every spawned agent writes its full
81
- report there and returns a summary of at most ten lines. Give each agent
82
- the absolute path. Reports never land in the working tree, so review never
83
- reads them as product code. Read summaries and pass file paths, never
84
- report bodies. Delete both at the end of phase 6.
85
- Once a pull request exists, read `outerlayer work threads --item
86
- "$OUTERLAYER_WORK" --json`. Each thread with `waitingOn` of `agent` holds a
87
- person's comment. Answer each before the run ends, as the `outerlayer-amend` skill does.
88
- 5. **A session never records a pass or fail on an artifact.** It emits
89
- artifacts. A person decides pass or fail. A build records one result, the
90
- verdict of its own review, on the `code-review` check. The
91
- `acceptance-criteria` check is judged and recorded by the factory host. When
92
- the item holds no criteria, no judge runs and the host records a fail
93
- saying so.
94
- 6. **Observed status only.** Every status claim in the final report (a gate
95
- result, a CI conclusion, mergeability) quotes command output observed
96
- after the last change it describes. No quoted output means unknown, never
97
- green. Quoted output goes in the report to the user. Pull request bodies
98
- carry curated links, never raw output.
99
- 7. **Files no issue.** The build files no issue anywhere, and no agent does.
100
- A defect outside the change, or a follow-up the fix pass deferred, becomes a
101
- candidate issue in a report: a title, a body and a target repository. The
102
- final report lists every candidate for the user to file with `/spec`.
103
- 8. **Reader pass.** No text reaches the git host as the session wrote it.
104
- The pull request title and body, and every comment, go through one cold
105
- rewrite agent. Its only inputs are the draft and the writing rule. It
106
- returns the rewrite and the terms it cut or explained. Check that every
107
- path, identifier, number, criterion id and link survived, and restore any
108
- that did not.
109
- 9. **Run budget.** Spawn at most sixty agents in a run. Keep the count in the
110
- state file. Past three quarters, say where the count stands in the status
111
- line. A run that would exceed the budget stops and lists what is left
112
- unverified. The review phase also holds a limit on agents in flight.
113
- 10. **Factory problems are findings.** Every agent records the problems it
114
- hit outside the change with the `outerlayer-findings` skill, as its brief
115
- says. The orchestrator records only the ones it hit itself. The final
116
- report lists every finding by id.
117
-
118
- ## Phases
119
-
120
- Run them in order.
121
-
122
- 1. **Intake.** Read `OUTERLAYER_WORK`. If it is missing or does not parse,
123
- stop and hand back:
124
-
125
- outerlayer work build --issue <reference> # once; prints the item number
126
- OUTERLAYER_WORK=<number> claude "/build"
127
-
128
- Run `outerlayer work status --item "$OUTERLAYER_WORK" --json` and read the
129
- item's tracker key. It is a GitHub `#n`, or a Linear or Jira key. Read the
130
- issue from the same JSON: `title`, and `issue`, which holds the issue as
131
- OuterLayer last copied it from the tracker. `issue.body` is the
132
- description in Markdown, and `url`, `state` and `labels` come with it. This
133
- copy works for every tracker. A build often holds no Linear or Jira
134
- credential, so do not depend on a tracker tool. Use one only to add what
135
- the copy lacks, such as the issue's comments. When `issue.syncStatus` is
136
- `unreadable`, the copy is from an earlier read: say so in the intake
137
- summary. When it is `not_found`, or `issue.syncedAt` is null and no tracker
138
- tool can read the issue, stop: there is no issue to build from.
139
- Write the issue's title, URL and body to
140
- `"$(git rev-parse --absolute-git-dir)/build-reports/issue.md"`. The issue
141
- is the source of truth for the whole run. Every later agent is given that
142
- file's path, so no agent needs a tracker tool to read it.
143
- Restate the task in one or two sentences and confirm the issue is still
144
- open (`issue.state`) and unclaimed. If the item shows a live claim by
145
- another runner that has not expired, stop and name it.
146
- Phase 2 finds the issue's criteria. If it finds some, they are the
147
- definition of done, and each declares a proof form or a test. If it finds
148
- none, the build drafts them from the issue's description, and the drafted
149
- criteria are the definition of done in the same way. An issue is never
150
- sent back for lacking criteria.
151
- Ask nothing from here until the final report. An agent that needs a ruling
152
- states its assumption in its report and continues. The final report lists
153
- every assumption.
154
- 2. **Read the criteria.** Record the issue's criteria on the item, so the
155
- Criteria tab, the item's status and the judge hold the pull request to one
156
- list. Read the whole issue and find its acceptance criteria in whatever
157
- form they are written: under a heading of any wording, as a checklist or
158
- numbered items, as "done when" prose, with ids or without. There is no
159
- fixed shape. Keep each criterion's text exactly as the author wrote it.
160
- Never reword one. A criterion you think is wrong becomes a note in the
161
- final report, never an edit.
162
-
163
- Write them, in the order the issue lists them, to a file:
164
-
165
- { "criteria": [ { "id": "<the id, if the issue gives one>", "text": "<verbatim>", "proof": null } ] }
166
-
167
- Give `proof` an artifact kind (`video`, `screenshot`, `report`, `log`,
168
- `test` or `file`) only when the issue states that proof explicitly, as in
169
- `(proof: screenshot)`. Never infer a proof kind from the words. Then run:
170
-
171
- node .outerlayer/skills/build/scripts/record-criteria.mjs --item "$OUTERLAYER_WORK" --criteria-file <file>
172
-
173
- The script keeps the issue's ids only when every criterion carries one
174
- that fits the id grammar. Otherwise, a partly numbered list included, it
175
- numbers every criterion `AC-<item number>-NN` in order, and the state file
176
- says why. The final report says the criteria were numbered and from what.
177
- A file the script cannot use exits 2 with the reason. Fix the file and
178
- run it again.
179
-
180
- When the issue has no criteria anywhere, draft them from the issue's
181
- description. Each is one observable behavior the description asks for, in
182
- its words, adding no scope it does not state. Write them to the same kind
183
- of file without ids, set `proof` only when the description asks for that
184
- proof, and run the script with `--drafted` added. It numbers the draft
185
- `AC-<item number>-NN` and records it with `drafted: true`, so the Criteria
186
- tab says the build drafted the list.
187
-
188
- The script writes the list to
189
- `"$(git rev-parse --absolute-git-dir)/build-reports/criteria.json"` and runs
190
- `outerlayer emit criteria` on it. The gateway decides whether a list may be
191
- recorded. A 409 means the item already has a recorded list. That list
192
- stands, and nothing is recorded. No command returns the item's list, so the
193
- build cannot read it: it holds the work to its own reading of the criteria
194
- and says so in the final report. Any other refusal is written to the state
195
- file with its message, and the build continues. The script writes the
196
- outcome under `criteria` in the state file: `source` (`issue`, `drafted`,
197
- `item`, or `none` when even a draft holds no criterion), `recorded`,
198
- `count`, `list` and `numbered`. On a 409, `list` is empty, and the build's
199
- reading of the criteria goes under `issueReading`.
200
-
201
- Drafted criteria are tiered, proven and judged like any others. A drafted
202
- list stands like any recorded list. A later build's record
203
- answers 409 until a person replaces the list with
204
- `outerlayer emit criteria`, even after criteria are added to the issue. The
205
- final report says the criteria were drafted and how to replace them.
206
-
207
- Change nothing in the issue. The intake summary names how many criteria
208
- were recorded, whether they kept the issue's ids or were numbered, and
209
- whether they were drafted.
210
- 3. **Implement.** When `OUTERLAYER_BRANCH` is set, as it is in a host's
211
- build, work on that branch, checking it out if it is not current, and
212
- push only to it: the host refuses a push to any other branch. Otherwise
213
- branch `feat/<slug>` from the default branch. Spawn the implementer with the Implementer brief from
214
- [references/agent-briefs.md](references/agent-briefs.md), the issue, the
215
- drafted criteria with their ids when the build drafted them, the branch
216
- and the instructions-file pointer. The phase ends when the
217
- repository's own pre-push checks and tests pass on the branch. Review
218
- never opens on a red branch. A branch that cannot go green escalates.
219
- 4. **Review.** Read [references/review-loop.md](references/review-loop.md) on
220
- entry and run it. It sizes the panel to the finished diff: one generalist
221
- for a small diff, the generalist and one focused reviewer for a medium
222
- one, the generalist and up to three for a large or risky one. Findings are
223
- merged into classes, checked by a refuter, fixed, and rechecked once. Then
224
- write the review report as an HTML file and emit it:
225
-
226
- outerlayer emit artifact <report>.html --caption "Review of the change and what it found"
227
-
228
- Its verdict is recorded on the `code-review` check once the pull request
229
- is open, as release.md says.
230
-
231
- 5. **Sync and pull request.** Read [references/release.md](references/release.md)
232
- on entry and run it. A release agent rebases, gates and pushes. Open the
233
- pull request as release.md says: a runner build with `outerlayer work open-pr`,
234
- which links it, and a local session with `gh pr create` and then
235
- `outerlayer work pr <number>`. When the build recorded criteria, from the issue or drafted, a fresh agent judges them with
236
- [references/criteria-judge.md](references/criteria-judge.md), and the
237
- judge's HTML report is linked to its tests and emitted:
238
-
239
- node .outerlayer/skills/build/scripts/criterion-citations.mjs --report <judge-report>.html
240
- outerlayer emit artifact <judge-report>.html --for acceptance-criteria --caption "Each criterion judged against its test"
241
-
242
- The build does not record that verdict: the factory host judges the
243
- criteria itself and records the `acceptance-criteria` check, as release.md
244
- says. When the state file holds no criteria, no judge runs.
245
- Watch CI until every check has concluded.
246
- 6. **Manual test and evidence.** Read [references/evidence.md](references/evidence.md)
247
- when the pull request opens, and run it. Capture the proof each criterion
248
- declares, emit it. Then release the lease.
249
- 7. **Release the lease.** Run this last, after the pull request is open and
250
- the evidence is emitted, and run no other tool call after it:
251
-
252
- outerlayer work release --item "$OUTERLAYER_WORK"
253
-
254
- A session that names a work item holds a lease on it, and review stays
255
- closed until the lease is released. In a session this command releases the
256
- session's own lease and no one else's. A later tool call takes the lease
257
- again, so write the final report as plain text once this has run. Skip this
258
- step in a runner build, whose host releases its own lease. Then end the run
259
- with the final report. The report lists every candidate issue and every
260
- assumption.
11
+ None yet. Add a change under the name of the phase it applies to: Intake, Criteria, Implement, Review, Pull request, Evidence.
@@ -32,4 +32,4 @@ run:
32
32
  where: host
33
33
  emit: acceptance-criteria
34
34
  judge:
35
- brief: .outerlayer/skills/build/references/criteria-judge.md
35
+ brief: .outerlayer/skills/outerlayer-build/references/criteria-judge.md
@@ -1,12 +0,0 @@
1
- #!/usr/bin/env node
2
- import { createRequire } from 'node:module';
3
- export { buildRepositoryImage } from './chunk-3CWUOFV6.js';
4
- export { RecipeError } from './chunk-QOZKPLVJ.js';
5
- import './chunk-CX22S5BA.js';
6
- import './chunk-ECODQ7II.js';
7
- import './chunk-JBJTC3UU.js';
8
- import './chunk-N2PXGQRL.js';
9
- import './chunk-BQXFBI7T.js';
10
- import './chunk-Z5GEFMRW.js';
11
-
12
- createRequire(import.meta.url);
@@ -1,320 +0,0 @@
1
- #!/usr/bin/env node
2
- import { createRequire } from 'node:module';
3
- import { parseSize } from './chunk-7RQ73DLO.js';
4
- import { BUILDKIT_IMAGE } from './chunk-CX22S5BA.js';
5
- import { compareVersions } from './chunk-QNLX477Q.js';
6
- import { runnerDir } from './chunk-N2PXGQRL.js';
7
- import { CLAUDE_PORT, JOB_MOUNT, GATEWAY_PORT, GATEWAY_SOCKET, CLAUDE_SOCKET, RELAY_PORT, DESTINATION_BASE_PORT } from './chunk-BQXFBI7T.js';
8
- import { createHash } from 'crypto';
9
- import { realpathSync } from 'fs';
10
- import { join, dirname, resolve } from 'path';
11
-
12
- createRequire(import.meta.url);
13
-
14
- // src/runner/judge-command.ts
15
- var JUDGE_DIR = "/outerlayer/judge";
16
- var JUDGE_HOME = `${JUDGE_DIR}/home`;
17
- var JUDGE_TREE = `${JUDGE_DIR}/tree`;
18
- var JUDGE_REPORT = `${JUDGE_DIR}/report.html`;
19
- var JUDGE_PROGRAM = "/opt/outerlayer/claude/bin/claude";
20
- var MAX_REPORT_BYTES = 5 * 1024 * 1024;
21
- var JUDGE_MAX_TURNS = 60;
22
- var JUDGE_PATH = "/opt/outerlayer/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
23
- var JUDGE_TOOLS = "Read,Grep,Glob,Write";
24
- function judgeCommand(input) {
25
- const env = {
26
- HOME: JUDGE_HOME,
27
- TMPDIR: `${JUDGE_HOME}/tmp`,
28
- PATH: JUDGE_PATH,
29
- ANTHROPIC_BASE_URL: `http://127.0.0.1:${CLAUDE_PORT}`,
30
- CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: "1",
31
- DISABLE_AUTOUPDATER: "1",
32
- ...input.credential === void 0 ? {} : { [input.credential.variable]: input.credential.placeholder }
33
- };
34
- const argv = [
35
- JUDGE_PROGRAM,
36
- "-p",
37
- "--output-format",
38
- "json",
39
- "--setting-sources",
40
- "user",
41
- "--strict-mcp-config",
42
- "--disable-slash-commands",
43
- "--no-session-persistence",
44
- "--tools",
45
- JUDGE_TOOLS,
46
- "--allowedTools",
47
- // A path that starts with two slashes is absolute in a permission rule.
48
- `Read(/${JUDGE_DIR}/**),Edit(/${JUDGE_REPORT})`,
49
- "--add-dir",
50
- JUDGE_TREE,
51
- "--permission-mode",
52
- "dontAsk",
53
- "--max-turns",
54
- String(JUDGE_MAX_TURNS),
55
- // After the separator, so a brief that starts with a dash is not read as an option.
56
- "--",
57
- input.brief
58
- ];
59
- return { argv, env, cwd: JUDGE_DIR };
60
- }
61
- var HASH_SCRIPT = 'const fs=require("fs"),c=require("crypto");const p=fs.realpathSync(process.argv[1]);process.stdout.write(c.createHash("sha256").update(fs.readFileSync(p)).digest("hex")+" "+p+"\\n")';
62
- var HASH_ARGV = ["/opt/outerlayer/bin/node", "-e", HASH_SCRIPT, JUDGE_PROGRAM];
63
- function parseProgramHash(stdout) {
64
- return /^([0-9a-f]{64}) /.exec(stdout.trim())?.[1];
65
- }
66
-
67
- // src/runner/container/run-args.ts
68
- var BUILD_LABEL = "ai.outerlayer.build";
69
- var RUNNER_LABEL = "ai.outerlayer.runner";
70
- function resolvedRunnerDir(configPath) {
71
- try {
72
- return realpathSync(runnerDir(configPath));
73
- } catch {
74
- try {
75
- return join(realpathSync(dirname(resolve(configPath))), "runner");
76
- } catch {
77
- return resolve(runnerDir(configPath));
78
- }
79
- }
80
- }
81
- function runnerLabelValue(configPath) {
82
- return createHash("sha256").update(resolvedRunnerDir(configPath)).digest("hex").slice(0, 12);
83
- }
84
- function hardened(input) {
85
- const { memory, cpus, pids, cpuset } = input.limits;
86
- return [
87
- "--label",
88
- `${BUILD_LABEL}=${input.buildId}`,
89
- "--label",
90
- `${RUNNER_LABEL}=${input.runnerId}`,
91
- "--network",
92
- "none",
93
- "--cap-drop",
94
- "ALL",
95
- "--security-opt",
96
- "no-new-privileges",
97
- "--read-only",
98
- "--user",
99
- input.user,
100
- // The same figure for swap as for memory leaves the container none.
101
- "--memory",
102
- memory,
103
- "--memory-swap",
104
- memory,
105
- "--cpus",
106
- String(cpus),
107
- ...cpuset === void 0 ? [] : ["--cpuset-cpus", cpuset],
108
- "--pids-limit",
109
- String(pids)
110
- ];
111
- }
112
- function mountPath(path) {
113
- if (/[",]/.test(path)) throw new Error(`${path} holds a comma or a quote, which a Docker mount cannot carry; move the runner's config file`);
114
- return path;
115
- }
116
- function containerRunArgs(input) {
117
- return [
118
- "--detach",
119
- "--name",
120
- input.container,
121
- ...hardened(input),
122
- "--mount",
123
- `type=volume,src=${input.volume},dst=/build`,
124
- // `/tmp` is a directory of the same volume, so it is measured and limited with the rest of the build.
125
- "--mount",
126
- `type=volume,src=${input.volume},dst=/tmp,volume-subpath=tmp`,
127
- "--mount",
128
- `type=bind,src=${mountPath(input.buildDir)},dst=${JOB_MOUNT},readonly`,
129
- ...input.judgeDir === void 0 ? [] : ["--mount", `type=bind,src=${mountPath(input.judgeDir)},dst=${JUDGE_DIR}`],
130
- "--entrypoint",
131
- "/opt/outerlayer/bin/tini",
132
- input.image,
133
- "--",
134
- "/opt/outerlayer/bin/node",
135
- "/opt/outerlayer/cli/dist/index.js",
136
- "broker-relay",
137
- "--port",
138
- String(RELAY_PORT),
139
- "--socket",
140
- `${JOB_MOUNT}/tunnel.sock`,
141
- ...Array.from({ length: input.destinations ?? 0 }, (_unused, index) => [
142
- "--forward",
143
- `${DESTINATION_BASE_PORT + index}=${JOB_MOUNT}/dest-${index}.sock`
144
- ]).flat(),
145
- ...input.builtIns === true ? [
146
- "--forward",
147
- `${GATEWAY_PORT}=${JOB_MOUNT}/${GATEWAY_SOCKET}`,
148
- "--forward",
149
- `${CLAUDE_PORT}=${JOB_MOUNT}/${CLAUDE_SOCKET}`
150
- ] : []
151
- ];
152
- }
153
- function prepareRunArgs(input) {
154
- return [
155
- "--rm",
156
- ...hardened(input),
157
- "--mount",
158
- `type=volume,src=${input.volume},dst=/build`,
159
- "--entrypoint",
160
- "mkdir",
161
- input.image,
162
- "-p",
163
- "-m",
164
- "1777",
165
- "/build/tmp",
166
- "/build/home",
167
- "/build/work"
168
- ];
169
- }
170
- function containerExecArgs(input) {
171
- const literals = Object.keys(input.env.literals).sort().flatMap((name) => ["-e", `${name}=${input.env.literals[name]}`]);
172
- const passed = Object.keys(input.env.passed).filter((name) => input.env.passed[name] !== void 0).sort().flatMap((name) => ["-e", name]);
173
- return [
174
- "-u",
175
- input.user,
176
- ...input.workdir === void 0 ? [] : ["-w", input.workdir],
177
- ...literals,
178
- ...passed,
179
- input.container,
180
- ...input.argv
181
- ];
182
- }
183
-
184
- // src/runner/image/builder.ts
185
- var MIN_BUILDX_VERSION = "0.18.0";
186
- var INSTALL_HINT = "install Docker's Buildx plugin (docker-buildx-plugin on Debian and Ubuntu with Docker's apt repository, docker-buildx on Ubuntu's own packages)";
187
- function builderName(configPath) {
188
- return `outerlayer-${runnerLabelValue(configPath)}`;
189
- }
190
- function proxyEnvironment(env) {
191
- const found = {};
192
- for (const name of ["HTTP_PROXY", "HTTPS_PROXY", "NO_PROXY", "http_proxy", "https_proxy", "no_proxy"]) {
193
- const value = env[name];
194
- if (value !== void 0 && value !== "") found[name] = value;
195
- }
196
- return found;
197
- }
198
- function builderSpec(configPath, memory, env) {
199
- return { name: builderName(configPath), memory, env: proxyEnvironment(env) };
200
- }
201
- function driverOpt(pair) {
202
- return /[",]/.test(pair) ? `"${pair.replace(/"/g, '""')}"` : pair;
203
- }
204
- async function buildxState(run) {
205
- const result = await run("docker", ["buildx", "version"]);
206
- if (result.status !== 0) {
207
- const said = (result.stderr.trim() || result.stdout.trim()).split("\n")[0] ?? "";
208
- return { problem: `docker buildx is not available${said === "" ? "" : ` (${said})`}, so image builds cannot be limited; ${INSTALL_HINT}` };
209
- }
210
- const version = /\bv?(\d+\.\d+\.\d+)/.exec(result.stdout)?.[1];
211
- if (version !== void 0 && compareVersions(version, MIN_BUILDX_VERSION) < 0) {
212
- return { problem: `docker buildx ${version} is too old: the runner's image builder needs Buildx ${MIN_BUILDX_VERSION} or later; update ${INSTALL_HINT}` };
213
- }
214
- return "usable";
215
- }
216
- function isOutOfMemory(output) {
217
- if (/cannot allocate memory/i.test(output)) return true;
218
- if (/did not complete successfully: (exit code: 137|signal: killed)/i.test(output)) return true;
219
- return /ResourceExhausted/i.test(output) && !/larger than max|message size|too large/i.test(output);
220
- }
221
- var running = 0;
222
- async function trackImageBuild(work) {
223
- running++;
224
- try {
225
- return await work();
226
- } finally {
227
- running--;
228
- }
229
- }
230
- var queue = Promise.resolve();
231
- function serialized(work) {
232
- const next = queue.then(work, work);
233
- queue = next.catch(() => void 0);
234
- return next;
235
- }
236
- function readExisting(inspectOutput) {
237
- const options = /^Driver Options:\s*(.*)$/m.exec(inspectOutput)?.[1] ?? "";
238
- const option = (key) => new RegExp(`(?:^|\\s)${key}="([^"]*)"`).exec(options)?.[1];
239
- return { driver: /^Driver:\s*(\S+)/m.exec(inspectOutput)?.[1], memory: option("memory"), image: option("image") };
240
- }
241
- function sameMemory(found, wanted) {
242
- return (parseSize(found) ?? found) === (parseSize(wanted) ?? wanted);
243
- }
244
- var IDLE_POLL_MS = 1e3;
245
- var failures = 0;
246
- function ensureFailureCount() {
247
- return failures;
248
- }
249
- function ensureBuilder(rawRun, spec, options = {}) {
250
- const run = (command, args, opts) => rawRun(command, args, { ...opts, timeoutMs: args.includes("--bootstrap") ? 15 * 6e4 : 2 * 6e4 });
251
- const result = serialized(async () => {
252
- const state = await buildxState(run);
253
- if (state !== "usable") return { ok: false, problem: state.problem };
254
- const sleep = options.sleep ?? ((ms) => new Promise((resolve2) => setTimeout(resolve2, ms)));
255
- const inspected = await run("docker", ["buildx", "inspect", spec.name]);
256
- let create = inspected.status !== 0;
257
- if (!create) {
258
- const found = readExisting(inspected.stdout);
259
- const current = found.driver === "docker-container" && sameMemory(found.memory ?? "", spec.memory) && found.image === BUILDKIT_IMAGE;
260
- if (!current && options.replaceStale === false) {
261
- return {
262
- ok: false,
263
- problem: `the image builder ${spec.name} was made with other settings than runner.build.memory (${spec.memory}) and the pinned BuildKit image; the runner service replaces it when no build is running, or remove it with docker buildx rm ${spec.name}`
264
- };
265
- }
266
- if (!current) {
267
- if (options.waitForIdle === true) while (running > 0) await sleep(IDLE_POLL_MS);
268
- if (running === 0) {
269
- const removed = await run("docker", ["buildx", "rm", spec.name]);
270
- if (removed.status !== 0) return { ok: false, problem: `could not replace the image builder ${spec.name}: ${removed.stderr.trim() || `docker exited ${removed.status}`}` };
271
- create = true;
272
- }
273
- }
274
- }
275
- if (create) {
276
- const opts = [
277
- `memory=${spec.memory}`,
278
- `memory-swap=${spec.memory}`,
279
- `image=${BUILDKIT_IMAGE}`,
280
- ...Object.entries(spec.env ?? {}).map(([name, value]) => `env.${name}=${value}`),
281
- ...spec.driverOpts ?? []
282
- ];
283
- const created = await run("docker", [
284
- "buildx",
285
- "create",
286
- "--name",
287
- spec.name,
288
- "--driver",
289
- "docker-container",
290
- ...opts.flatMap((opt) => ["--driver-opt", driverOpt(opt)])
291
- ]);
292
- if (created.status !== 0) {
293
- const said = created.stderr.trim() || `docker exited ${created.status}`;
294
- if (/failed to find driver/i.test(said)) {
295
- return { ok: false, problem: `this Docker's Buildx has no docker-container driver, so image builds cannot be limited; ${INSTALL_HINT}` };
296
- }
297
- return { ok: false, problem: `could not create the image builder ${spec.name}: ${said}` };
298
- }
299
- }
300
- if (options.bootstrap === true) {
301
- const started = await run("docker", ["buildx", "inspect", "--bootstrap", spec.name]);
302
- if (started.status !== 0) {
303
- return { ok: false, problem: `the image builder ${spec.name} did not start: ${started.stderr.trim() || `docker exited ${started.status}`}` };
304
- }
305
- }
306
- return { ok: true, changed: create };
307
- });
308
- return result.then(
309
- (outcome) => {
310
- if (!outcome.ok) failures++;
311
- return outcome;
312
- },
313
- (err) => {
314
- failures++;
315
- throw err;
316
- }
317
- );
318
- }
319
-
320
- export { BUILD_LABEL, HASH_ARGV, JUDGE_DIR, JUDGE_MAX_TURNS, JUDGE_PROGRAM, MAX_REPORT_BYTES, MIN_BUILDX_VERSION, RUNNER_LABEL, builderName, builderSpec, buildxState, containerExecArgs, containerRunArgs, ensureBuilder, ensureFailureCount, isOutOfMemory, judgeCommand, parseProgramHash, prepareRunArgs, proxyEnvironment, runnerLabelValue, trackImageBuild };
@@ -1,45 +0,0 @@
1
- #!/usr/bin/env node
2
- import { createRequire } from 'node:module';
3
-
4
- createRequire(import.meta.url);
5
-
6
- // src/runner/image/pins.ts
7
- var CLAUDE_CODE_VERSION = "2.1.284";
8
- var DEFAULT_BASE_IMAGE = "ubuntu:24.04@sha256:008173c23f95b170204355c12626cb5a965d779a7e1283b09e9cffbb1bf33ca3";
9
- var NODE_IMAGE = "node:22-bookworm-slim@sha256:43ac6c60b8f89723f746e8a92ce91abd5017e627ce1ddfe4238355d3a30b772c";
10
- var BUILDKIT_IMAGE = "moby/buildkit:v0.33.1@sha256:cec9f139f45e93c5c69c60f8b07cfad9f43f4ef6b6a6cd917527fea5ff2e3dea";
11
- var GH_VERSION = "2.101.0";
12
- var GH_SHA256 = {
13
- amd64: "9bca2d1c16825f109907a23307628a2f0698fbf99662b73a5cf0b020293072b8",
14
- arm64: "b57e8063f18862647c9d22727c32e9da1b963f8bf9db648fe123a6975695640f"
15
- };
16
- var TINI_VERSION = "0.19.0";
17
- var TINI_SHA256 = {
18
- amd64: "c5b0666b4cb676901f90dfcb37106783c5fe2077b04590973b885950611b30ee",
19
- arm64: "eae1d3aa50c48fb23b8cbdf4e369d0910dfc538566bfd09df89a774aa84a48b9"
20
- };
21
- var MICROVM_ARCHES = ["x86_64"];
22
- function firecrackerArch(nodeArch) {
23
- return nodeArch === "x64" ? "x86_64" : nodeArch === "arm64" ? "aarch64" : nodeArch;
24
- }
25
- var FIRECRACKER_VERSION = "1.13.1";
26
- var FIRECRACKER_SHA256 = {
27
- x86_64: "59450b9171ff2ebdf2f9a25be3a248a7ba79fb6371aec51a9d6d8eefca7b4faf"
28
- };
29
- var FIRECRACKER_BINARY_SHA256 = {
30
- x86_64: "7d3924e0c8761edafbf85cb2a94c268ffad249644a40fd02d4e15cde4c206f6e"
31
- };
32
- var GUEST_ASSETS_VERSION = "1";
33
- var GUEST_ASSETS_BASE_URL = `https://github.com/outerlayerai/guest-assets/releases/download/guest-${GUEST_ASSETS_VERSION}`;
34
- var GUEST_KERNEL_SHA256 = {
35
- x86_64: "5a2d716d301615c69fefc2f9574954e838269f14d5e8b0d1bad88b680cd372ee"
36
- };
37
- var GUEST_HELPER_SHA256 = {
38
- x86_64: "4175e89ae8cb633113b5f69ef8b6e206093954411fe53edf86357bc1b7e822f9"
39
- };
40
- function guestAssetsPinned(arch) {
41
- const zero = "0".repeat(64);
42
- return GUEST_KERNEL_SHA256[arch] !== zero && GUEST_HELPER_SHA256[arch] !== zero;
43
- }
44
-
45
- export { BUILDKIT_IMAGE, CLAUDE_CODE_VERSION, DEFAULT_BASE_IMAGE, FIRECRACKER_BINARY_SHA256, FIRECRACKER_SHA256, FIRECRACKER_VERSION, GH_SHA256, GH_VERSION, GUEST_ASSETS_BASE_URL, GUEST_ASSETS_VERSION, GUEST_HELPER_SHA256, GUEST_KERNEL_SHA256, MICROVM_ARCHES, NODE_IMAGE, TINI_SHA256, TINI_VERSION, firecrackerArch, guestAssetsPinned };