@outerlayer/cli 0.1.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 +7 -0
- package/LICENSE +202 -0
- package/README.md +320 -0
- package/dist/build-info.json +1 -0
- package/dist/chunk-4H56Y7O6.js +589 -0
- package/dist/chunk-A3WLZX2F.js +120 -0
- package/dist/chunk-A6NNKRJU.js +650 -0
- package/dist/chunk-D77LS3UI.js +42 -0
- package/dist/chunk-DEDV5V4U.js +87324 -0
- package/dist/chunk-ECSYRPCC.js +334 -0
- package/dist/chunk-IWIUYLDR.js +472 -0
- package/dist/chunk-JJP7YLMN.js +25 -0
- package/dist/chunk-KFYJV2ZG.js +7978 -0
- package/dist/chunk-OZ7C3XUE.js +34 -0
- package/dist/chunk-RCQXYLMO.js +96 -0
- package/dist/chunk-TFUIDMOB.js +34 -0
- package/dist/chunk-VNVZDWO3.js +10 -0
- package/dist/chunk-VU34RWDU.js +339 -0
- package/dist/chunk-WQ6VGRGZ.js +150 -0
- package/dist/chunk-XN2XZFTK.js +165 -0
- package/dist/chunk-YMTXR7PJ.js +200 -0
- package/dist/chunk-YRYMNBGQ.js +54 -0
- package/dist/chunk-Z5GEFMRW.js +45 -0
- package/dist/chunk-ZJSNLVCE.js +58 -0
- package/dist/cli-3JYGL2OB.js +5311 -0
- package/dist/config-POF7DEQW.js +7 -0
- package/dist/context-materialize-J6CRQ7O7.js +589 -0
- package/dist/emit-artifact-cmd-23F4YKQ3.js +339 -0
- package/dist/emit-cmd-TWSYYEZI.js +208 -0
- package/dist/emit-commit-credit-cmd-2GX5M2BR.js +121 -0
- package/dist/emit-finding-cmd-6K7ERPKG.js +235 -0
- package/dist/emit-result-cmd-NDFHMJX7.js +225 -0
- package/dist/hook-fast-CBW4ZETX.js +8 -0
- package/dist/hook-wrap-fast-36WGE6EX.js +8 -0
- package/dist/import-capture-cmd-EUMBGIV3.js +176 -0
- package/dist/import-ruler-cmd-7LH2QOMG.js +173 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +25 -0
- package/dist/init-PTBITAUO.js +103 -0
- package/dist/login-cmd-IRX6LZT7.js +62 -0
- package/dist/logs-TRNPQM42.js +63 -0
- package/dist/loop-NFSOBUUJ.js +646 -0
- package/dist/mcp-install-cmd-FDQH6SEN.js +75 -0
- package/dist/mcp-serve-cmd-57EZZOTL.js +123 -0
- package/dist/paths-D2VGWWFI.js +6 -0
- package/dist/pidfile-PTW76F56.js +8 -0
- package/dist/status-WGOJTXZF.js +94 -0
- package/dist/statusline-fast-Z5U5CEC6.js +8 -0
- package/dist/sync-cmd-C5UGI4SF.js +15 -0
- package/dist/watch-V3K4PESQ.js +70 -0
- package/dist/work-claim-cmd-FQDWQVT2.js +98 -0
- package/dist/work-cmd-CW26EZZO.js +16 -0
- package/dist/work-launch-YNNCKIH3.js +6 -0
- package/dist/work-pr-cmd-W2QNMWXP.js +115 -0
- package/package.json +58 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# @outerlayer/cli
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- e27bd86: First release under the `@outerlayer/cli` name. The published package carries no dependencies: everything the CLI needs is bundled into its `dist`, so `npx @outerlayer/cli` installs the single tarball and nothing else.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
|
|
2
|
+
Apache License
|
|
3
|
+
Version 2.0, January 2004
|
|
4
|
+
http://www.apache.org/licenses/
|
|
5
|
+
|
|
6
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
7
|
+
|
|
8
|
+
1. Definitions.
|
|
9
|
+
|
|
10
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
11
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
12
|
+
|
|
13
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
14
|
+
the copyright owner that is granting the License.
|
|
15
|
+
|
|
16
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
17
|
+
other entities that control, are controlled by, or are under common
|
|
18
|
+
control with that entity. For the purposes of this definition,
|
|
19
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
20
|
+
direction or management of such entity, whether by contract or
|
|
21
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
22
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
23
|
+
|
|
24
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
25
|
+
exercising permissions granted by this License.
|
|
26
|
+
|
|
27
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
28
|
+
including but not limited to software source code, documentation
|
|
29
|
+
source, and configuration files.
|
|
30
|
+
|
|
31
|
+
"Object" form shall mean any form resulting from mechanical
|
|
32
|
+
transformation or translation of a Source form, including but
|
|
33
|
+
not limited to compiled object code, generated documentation,
|
|
34
|
+
and conversions to other media types.
|
|
35
|
+
|
|
36
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
37
|
+
Object form, made available under the License, as indicated by a
|
|
38
|
+
copyright notice that is included in or attached to the work
|
|
39
|
+
(an example is provided in the Appendix below).
|
|
40
|
+
|
|
41
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
42
|
+
form, that is based on (or derived from) the Work and for which the
|
|
43
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
44
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
45
|
+
of this License, Derivative Works shall not include works that remain
|
|
46
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
47
|
+
the Work and Derivative Works thereof.
|
|
48
|
+
|
|
49
|
+
"Contribution" shall mean any work of authorship, including
|
|
50
|
+
the original version of the Work and any modifications or additions
|
|
51
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
52
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
53
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
54
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
55
|
+
means any form of electronic, verbal, or written communication sent
|
|
56
|
+
to the Licensor or its representatives, including but not limited to
|
|
57
|
+
communication on electronic mailing lists, source code control systems,
|
|
58
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
59
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
60
|
+
excluding communication that is conspicuously marked or otherwise
|
|
61
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
62
|
+
|
|
63
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
64
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
65
|
+
subsequently incorporated within the Work.
|
|
66
|
+
|
|
67
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
68
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
69
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
70
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
71
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
72
|
+
Work and such Derivative Works in Source or Object form.
|
|
73
|
+
|
|
74
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
75
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
76
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
77
|
+
(except as stated in this section) patent license to make, have made,
|
|
78
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
79
|
+
where such license applies only to those patent claims licensable
|
|
80
|
+
by such Contributor that are necessarily infringed by their
|
|
81
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
82
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
83
|
+
institute patent litigation against any entity (including a
|
|
84
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
85
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
86
|
+
or contributory patent infringement, then any patent licenses
|
|
87
|
+
granted to You under this License for that Work shall terminate
|
|
88
|
+
as of the date such litigation is filed.
|
|
89
|
+
|
|
90
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
91
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
92
|
+
modifications, and in Source or Object form, provided that You
|
|
93
|
+
meet the following conditions:
|
|
94
|
+
|
|
95
|
+
(a) You must give any other recipients of the Work or
|
|
96
|
+
Derivative Works a copy of this License; and
|
|
97
|
+
|
|
98
|
+
(b) You must cause any modified files to carry prominent notices
|
|
99
|
+
stating that You changed the files; and
|
|
100
|
+
|
|
101
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
102
|
+
that You distribute, all copyright, patent, trademark, and
|
|
103
|
+
attribution notices from the Source form of the Work,
|
|
104
|
+
excluding those notices that do not pertain to any part of
|
|
105
|
+
the Derivative Works; and
|
|
106
|
+
|
|
107
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
108
|
+
distribution, then any Derivative Works that You distribute must
|
|
109
|
+
include a readable copy of the attribution notices contained
|
|
110
|
+
within such NOTICE file, excluding those notices that do not
|
|
111
|
+
pertain to any part of the Derivative Works, in at least one
|
|
112
|
+
of the following places: within a NOTICE text file distributed
|
|
113
|
+
as part of the Derivative Works; within the Source form or
|
|
114
|
+
documentation, if provided along with the Derivative Works; or,
|
|
115
|
+
within a display generated by the Derivative Works, if and
|
|
116
|
+
wherever such third-party notices normally appear. The contents
|
|
117
|
+
of the NOTICE file are for informational purposes only and
|
|
118
|
+
do not modify the License. You may add Your own attribution
|
|
119
|
+
notices within Derivative Works that You distribute, alongside
|
|
120
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
121
|
+
that such additional attribution notices cannot be construed
|
|
122
|
+
as modifying the License.
|
|
123
|
+
|
|
124
|
+
You may add Your own copyright statement to Your modifications and
|
|
125
|
+
may provide additional or different license terms and conditions
|
|
126
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
127
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
128
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
129
|
+
the conditions stated in this License.
|
|
130
|
+
|
|
131
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
132
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
133
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
134
|
+
this License, without any additional terms or conditions.
|
|
135
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
136
|
+
the terms of any separate license agreement you may have executed
|
|
137
|
+
with Licensor regarding such Contributions.
|
|
138
|
+
|
|
139
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
140
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
141
|
+
except as required for reasonable and customary use in describing the
|
|
142
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
143
|
+
|
|
144
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
145
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
146
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
147
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
148
|
+
implied, including, without limitation, any warranties or conditions
|
|
149
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
150
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
151
|
+
appropriateness of using or redistributing the Work and assume any
|
|
152
|
+
risks associated with Your exercise of permissions under this License.
|
|
153
|
+
|
|
154
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
155
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
156
|
+
unless required by applicable law (such as deliberate and grossly
|
|
157
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
158
|
+
liable to You for damages, including any direct, indirect, special,
|
|
159
|
+
incidental, or consequential damages of any character arising as a
|
|
160
|
+
result of this License or out of the use or inability to use the
|
|
161
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
162
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
163
|
+
other commercial damages or losses), even if such Contributor
|
|
164
|
+
has been advised of the possibility of such damages.
|
|
165
|
+
|
|
166
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
167
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
168
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
169
|
+
or other liability obligations and/or rights consistent with this
|
|
170
|
+
License. However, in accepting such obligations, You may act only
|
|
171
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
172
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
173
|
+
defend, and hold each Contributor harmless for any liability
|
|
174
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
175
|
+
of your accepting any such warranty or additional liability.
|
|
176
|
+
|
|
177
|
+
END OF TERMS AND CONDITIONS
|
|
178
|
+
|
|
179
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
180
|
+
|
|
181
|
+
To apply the Apache License to your work, attach the following
|
|
182
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
183
|
+
replaced with your own identifying information. (Don't include
|
|
184
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
185
|
+
comment syntax for the file format. We also recommend that a
|
|
186
|
+
file or class name and description of purpose be included on the
|
|
187
|
+
same "printed page" as the copyright notice for easier
|
|
188
|
+
identification within third-party archives.
|
|
189
|
+
|
|
190
|
+
Copyright 2026 Magu Studios, Inc.
|
|
191
|
+
|
|
192
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
193
|
+
you may not use this file except in compliance with the License.
|
|
194
|
+
You may obtain a copy of the License at
|
|
195
|
+
|
|
196
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
197
|
+
|
|
198
|
+
Unless required by applicable law or agreed to in writing, software
|
|
199
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
200
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
201
|
+
See the License for the specific language governing permissions and
|
|
202
|
+
limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
# outerlayer
|
|
2
|
+
|
|
3
|
+
Capture what your coding agents actually did, and sync it to your OuterLayer
|
|
4
|
+
cloud workspace.
|
|
5
|
+
|
|
6
|
+
OuterLayer captures the sessions your coding agents already write to disk
|
|
7
|
+
(Claude Code, Codex CLI, Cursor) and syncs them to your OuterLayer cloud
|
|
8
|
+
workspace, where you and your team can see what your agents did across every
|
|
9
|
+
repo. Capture itself is local: it reads the session files your agents already
|
|
10
|
+
write to disk. Uploading is a separate, launch-gated step — what reaches the
|
|
11
|
+
network, and when, is below.
|
|
12
|
+
|
|
13
|
+
Launch a session naming the work it's for, then sync:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
npx @outerlayer/cli init # install the capture hooks
|
|
17
|
+
npx @outerlayer/cli work add --issue 42 # create the work item; prints its number
|
|
18
|
+
OUTERLAYER_WORK=7 claude # launch a session naming that number
|
|
19
|
+
npx @outerlayer/cli sync --dry-run # see exactly what would leave your machine
|
|
20
|
+
npx @outerlayer/cli sync # upload sessions launched that way
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Privacy, stated plainly
|
|
24
|
+
|
|
25
|
+
**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 add`,
|
|
27
|
+
which prints its factory-scoped number, then set that number before
|
|
28
|
+
starting your agent — `OUTERLAYER_WORK=7 claude`. The session-start hook
|
|
29
|
+
then records the launch and the session uploads whole, from its first turn,
|
|
30
|
+
until it ends. A session launched without the variable never leaves the machine,
|
|
31
|
+
in any tool, however `sync` is invoked. There is no way to turn upload on
|
|
32
|
+
mid-session — the decision is made once, at launch.
|
|
33
|
+
|
|
34
|
+
Only Claude Code has a session-start hook today, so only Claude Code sessions
|
|
35
|
+
can be launched as work. Codex CLI and Cursor sessions are captured locally
|
|
36
|
+
and never upload.
|
|
37
|
+
|
|
38
|
+
**`outerlayer sync` is the complete upload, and it sends only launched
|
|
39
|
+
sessions.** It runs when you run it. The hooks also fire `outerlayer sync
|
|
40
|
+
--quiet` in the background after each agent turn and when a session ends, at
|
|
41
|
+
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
|
+
only once it is over. Set `"autoSync": false` in `~/.outerlayer/config.json`
|
|
44
|
+
to leave every automatic upload — the background sync and the daemon's
|
|
45
|
+
streaming below — to your own command.
|
|
46
|
+
|
|
47
|
+
**`outerlayer daemon` uploads a launched session as it grows, turn by turn,
|
|
48
|
+
while it runs, and nothing else.** The same launch gate as `sync` applies: a
|
|
49
|
+
session started without `OUTERLAYER_WORK` is never streamed, in whole or in
|
|
50
|
+
part, and neither is a session the repo filter excludes. It sends only the
|
|
51
|
+
turns since the last one it already sent, and it stops sending the moment
|
|
52
|
+
the session ends. `"autoSync": false` stops it too, and it is read on every
|
|
53
|
+
send, so turning it off takes effect without restarting the daemon.
|
|
54
|
+
`outerlayer sync` still runs on top of this and remains the complete,
|
|
55
|
+
authoritative upload — the daemon exists so a session's page can follow
|
|
56
|
+
along before that sync ever runs.
|
|
57
|
+
|
|
58
|
+
These commands also talk to your workspace. None of them sends session
|
|
59
|
+
content:
|
|
60
|
+
|
|
61
|
+
- **`outerlayer work add`, `remove`, `status`, `list`, `link-session`, `pr`,
|
|
62
|
+
`claim`, `renew`, `release`** read and write your Floor. The session-start
|
|
63
|
+
hook spawns `outerlayer work link-session` when you launch a session with
|
|
64
|
+
`OUTERLAYER_WORK`, naming the item and the session id — the item itself
|
|
65
|
+
must already exist, created ahead of time with `outerlayer work add`.
|
|
66
|
+
`outerlayer work pr` sends the session id and the pull request number and
|
|
67
|
+
repository — never the session's own content. `outerlayer work claim`
|
|
68
|
+
records a lease for this host before it starts working on an item, so two
|
|
69
|
+
hosts never build the same piece of work at once; `renew` extends it and
|
|
70
|
+
`release` marks it done. A runner key needs `git_connection.read` to list
|
|
71
|
+
and read items, `work_item_claim.insert` to claim, and
|
|
72
|
+
`work_item_claim.update` to renew or release — the two claim permissions
|
|
73
|
+
are not granted to a dashboard role by default, since a claim is a host's
|
|
74
|
+
lease, not a person's.
|
|
75
|
+
- **`outerlayer runner start`** lists, claims, renews and releases work
|
|
76
|
+
items the same way `work claim`/`renew`/`release` do, on the schedule its
|
|
77
|
+
config sets — it sends nothing about the job it runs beyond that; the
|
|
78
|
+
agent it starts is a separate process with its own credentials, from the
|
|
79
|
+
`runner` block, never the copy-out daemon's. `runner check` makes one
|
|
80
|
+
list call to confirm the key works and sends nothing else; `runner init`,
|
|
81
|
+
`runner status` and `runner logs` make no network call at all.
|
|
82
|
+
- **`outerlayer emit artifact`** uploads the file you name — a screenshot, a
|
|
83
|
+
recording, a report, a log — along with its caption. With no recorded
|
|
84
|
+
session to attach it to, it uploads immediately, anchored to a pull request
|
|
85
|
+
or to the git checkout.
|
|
86
|
+
- **`outerlayer emit <name>`** and **`outerlayer emit commit-credit`** send
|
|
87
|
+
one check's outcome, and one commit's attribution, for a work item. Run
|
|
88
|
+
from inside a session, they send only when that session carries a launch
|
|
89
|
+
record — the session's own content may not leave by a second route. Run
|
|
90
|
+
from CI or a plain shell, where there is no session, they send as they
|
|
91
|
+
always have.
|
|
92
|
+
- **`outerlayer emit finding`** and **`outerlayer emit findings <file>`** send
|
|
93
|
+
one finding, or a whole batch of them, for a work item — the same
|
|
94
|
+
anchoring as `emit <name>` (`--item`, or the recorded session's own item),
|
|
95
|
+
except a session may record findings on the item it was launched for.
|
|
96
|
+
- **`outerlayer mcp serve`** is the stdio MCP server your editor spawns. It
|
|
97
|
+
forwards every JSON-RPC message the editor sends to the gateway and returns
|
|
98
|
+
the reply.
|
|
99
|
+
|
|
100
|
+
The session-start hook reaches the network in two more cases:
|
|
101
|
+
|
|
102
|
+
- **In a repository your factory governs**, it asks the control plane which
|
|
103
|
+
context repository and ref this checkout is pinned to (`GET
|
|
104
|
+
/v1/context/source`, with your API key), then `git fetch`es that ref. It
|
|
105
|
+
sends the repository name; it degrades to the last known commit when the
|
|
106
|
+
control plane cannot be reached.
|
|
107
|
+
- **When your repository's git hooks are missing**, it runs that
|
|
108
|
+
repository's own `prepare` script (`yarn prepare` / `npm run prepare`).
|
|
109
|
+
What that script does is your repository's business; installers commonly
|
|
110
|
+
download packages.
|
|
111
|
+
|
|
112
|
+
The daemon's one-shot sweep (`outerlayer daemon --once`) makes no network
|
|
113
|
+
calls — the copy-out mirror it performs is the same one the long-running
|
|
114
|
+
daemon runs continuously, and neither the sweep nor an ineligible session
|
|
115
|
+
in the long-running daemon opens a connection. The session-start hook makes
|
|
116
|
+
none either, in a repository your factory does not govern. All three are
|
|
117
|
+
checked rather than promised: a test runs each of them with `fetch` and
|
|
118
|
+
`net.Socket.prototype.connect` replaced by stubs that throw, and asserts
|
|
119
|
+
nothing tried to connect. Those two stubs cover every outbound path this
|
|
120
|
+
process opens itself — anything built on `node:http`, `node:https` or
|
|
121
|
+
`node:tls` opens its socket through `connect`, and `fetch` opens its own
|
|
122
|
+
below that method. A child process opens its sockets in its own address
|
|
123
|
+
space, past both stubs, so the same test records every program each run
|
|
124
|
+
starts and asserts none of them fetches over the network.
|
|
125
|
+
|
|
126
|
+
Failures the hook cannot show you — a refused `OUTERLAYER_WORK` value, a
|
|
127
|
+
`work add` that could not reach the Floor — are appended to
|
|
128
|
+
`~/.outerlayer/spool/hook-errors.log`, and the next session start says so.
|
|
129
|
+
The addition retries a gateway it cannot reach a few times, with backoff,
|
|
130
|
+
before it gives up.
|
|
131
|
+
|
|
132
|
+
- **The tier is applied before anything leaves.** The default tier is
|
|
133
|
+
`full`: message text, thinking, images, and tool input/output all ship.
|
|
134
|
+
`--tier redacted` strips that content client-side, keeping only structure
|
|
135
|
+
(repos, branches, file paths, tool names, error signatures) and metrics;
|
|
136
|
+
`--tier metrics` strips identifiers too (the server additionally clamps to
|
|
137
|
+
your org's configured ceiling — sending more than it allows stores less).
|
|
138
|
+
- **`--dry-run` shows exactly what would leave** — per-session rows, image
|
|
139
|
+
bytes, and the precise field classes stripped at the chosen tier. Add
|
|
140
|
+
`--json` to inspect the literal request payloads. Zero network calls.
|
|
141
|
+
|
|
142
|
+
## Commands
|
|
143
|
+
|
|
144
|
+
| Command | What it does |
|
|
145
|
+
|---|---|
|
|
146
|
+
| `outerlayer sync` | Upload sessions launched with `OUTERLAYER_WORK` to your OuterLayer cloud workspace (incremental — only what's new since the last sync). Tier-gated client-side (`--tier metrics\|redacted\|full`, default `full`); `--dry-run` prints exactly what would leave the machine; `--all` re-sends everything (idempotent server-side). Credentials come from `outerlayer login`, `OUTERLAYER_*` env vars, or `--url/--app-id`. |
|
|
147
|
+
| `outerlayer login [--url] [--app-id]` | Save the cloud URL, app id, and API key to `~/.outerlayer/config.json` once. The key is read from stdin (`echo "$KEY" \| outerlayer login …`) or a prompt with echo off; it is never a flag. `--no-input` refuses to prompt. |
|
|
148
|
+
| `outerlayer init` | Install the capture hooks and the status-line segment. `--json` for scripts. Claude Code deletes transcripts after ~30 days; run `outerlayer daemon` separately to mirror them first — `init` does not start it for you. |
|
|
149
|
+
| `outerlayer daemon` | Run the copy-out daemon in the foreground (`--once` for a single sweep, which uploads nothing). Once cloud credentials exist, it also streams a launched session's new turns as they land — see Privacy, above. `outerlayer watch` is the former name and still works, with a warning. |
|
|
150
|
+
| `outerlayer doctor` | Check the installation: hooks, status-line freshness, and sync health. `--json` prints the checks and a summary for scripts. |
|
|
151
|
+
| `outerlayer context emit [--check]` | Compile `.outerlayer/` into each configured target tool's native files (targets come from `.outerlayer/config.json`). `--check` computes outputs and diffs against disk without writing (CI mode). Bare `outerlayer emit` with no name still compiles, with a deprecation warning. |
|
|
152
|
+
| `outerlayer import ruler` | Port a `.ruler/` tree ([Ruler](https://github.com/intellectronica/ruler)) into the equivalent `.outerlayer/` tree — mostly a rename; never overwrites an existing `.outerlayer/`. |
|
|
153
|
+
| `outerlayer hooks wrap` / `outerlayer hooks unwrap` | Auto-wrap (or undo wrapping) `PreToolUse`/`PostToolUse` hooks for execution evidence — one spawn per firing. |
|
|
154
|
+
| `outerlayer emit artifact <file> --caption <text> [--for <criterion-id>] [--pr <n>]` | Upload a proof artifact — screenshot, recording, report, or log — with its caption. Inside a recorded session it spools locally and ships on the next `sync`; otherwise it uploads immediately, anchored to a pull request or the current checkout. `--replaces` retires artifacts an earlier run uploaded. |
|
|
155
|
+
| `outerlayer emit <name> --result <pass\|fail> [--link <url>] [--body <text>\|--body-file <path>] --item <number>` | Record one named check's outcome on a work item. A check that ran carries the run URL as its proof (`--link`); a judgment you are making yourself carries one sentence (`--body`, or `--body-file` to read it from a file — `-` reads standard input). A `fail` needs at least one of the two; a `pass` needs neither. `--item` names the work item by the number printed when the item was created — always required, in or out of a recorded session; from inside a session it can only name an item that session was NOT launched for (a session cannot record a check on its own item). Prints the recorded check's id. Who recorded it comes from your API key, never from what you send. |
|
|
156
|
+
| `outerlayer emit artifact-review --result <pass\|fail> --artifact <id> [--body <text>\|--body-file <path>]` | Record a person's own pass or fail on one artifact — evidence already emitted, bound to a criterion. `--artifact` names it and replaces `--item`; the gateway resolves the work item from the artifact's own pull request. `--link` is refused. A `fail` reads its sentence from `--body`/`--body-file`, or from standard input when neither is given. Refused from inside a recorded session — an artifact verdict is a person's act, the same rule the gateway enforces. Prints the recorded verdict's id. |
|
|
157
|
+
| `outerlayer emit commit-credit --pr <n> …` | Send one commit's attribution for a pull request. |
|
|
158
|
+
| `outerlayer emit finding --id <id> --subject <change\|context> --title <text> --file <path> --kind <behavior\|hygiene\|proof> --verdict <confirmed\|refuted\|unverified> --source <implementer\|reviewer\|refuter\|gate> --where <label> [--item <number>] …` | Record one finding — what was found wrong about the change (`--subject change`) or about a rule it ran on (`--subject context`, which then needs `--rule-path`, `--rule-quote` and `--rule-relation` together — all three are required, not just `--rule-path`). Validated against the same contract the gateway checks before anything is sent. `--item` names the work item; without it, inside a recorded session, the item that session was launched for is used automatically — unlike `emit <name>`, a session may record findings on its own item. Re-emitting the same `--id` on the item replaces that finding. |
|
|
159
|
+
| `outerlayer emit findings <file> [--item <number>]` | Record a whole batch at once, read from a `FindingBatch` JSON file (`-` for standard input) — the same shape and validation as `emit finding`, one record per subject/title/file/kind/verdict/source/where. Anchored the same way: `--item`, else a recorded session's own item. |
|
|
160
|
+
| `outerlayer mcp install [--transport stdio\|http] [--url] [--name] [--command]` | Write (or update) an `mcpServers` entry in `.mcp.json` for the OuterLayer gateway. Default `stdio`: the client spawns `outerlayer mcp serve`, which reads the API key from `~/.outerlayer/config.json` (or `OUTERLAYER_API_KEY`) each time it connects, so a reconnect picks up a newly saved or rotated key. `--transport http` writes a direct `POST /v1/mcp` entry referencing `${OUTERLAYER_API_KEY}`, resolved by the client from the environment it was launched with. Never writes an API key. Pass `--url`/`--app-id` for self-host. |
|
|
161
|
+
| `outerlayer mcp serve [--url] [--app-id]` | Stdio MCP server bridging stdin/stdout JSON-RPC to the gateway's `POST /v1/mcp`. What the stdio `.mcp.json` entry runs; exits 1 with a clear message when no API key is configured. |
|
|
162
|
+
| `outerlayer work add --issue <n>\|--pr <n> [--repo] [--note]` | Records that a source — a recorded session, a CI run, or the API key's bound member — is working on an issue or pull request. The only way an item becomes visible on the Floor. |
|
|
163
|
+
| `outerlayer work remove --issue <n>\|--pr <n> --reason <text> [--repo]` | Withdraws the caller's own addition, recording the reason. Never deletes anything; the item leaves the Floor only once no live addition remains on it. Removing again is a no-op that still succeeds. |
|
|
164
|
+
| `outerlayer work status --issue <n>\|--pr <n> [--repo]` | Shows one item's stage, section, gate ledger, linked pull requests and sessions, and its additions. |
|
|
165
|
+
| `outerlayer work list [--stage] [--section] [--repo] [--unclaimed] [--startable] [--needs amend]` | Lists live work items for the current factory, filterable by stage, section, claim state and whether an open fail is waiting for an answer. |
|
|
166
|
+
| `outerlayer work pr <n> [--repo] [--session-id]` | Run inside a session on a work item: declares that pull request `<n>` in the checkout's repository belongs to that item. Idempotent — declaring the same pull request twice is a no-op. Refuses when the session is on no item, or the repository is not connected. |
|
|
167
|
+
| `outerlayer work 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. A live lease already held by a different host is refused; claiming again under the same host extends it. Lease length defaults to 900 seconds, the server's own cap. |
|
|
168
|
+
| `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 host holds it. |
|
|
169
|
+
| `outerlayer work release --item <n>\|--issue <n> [--repo] [--host] [--outcome]` | Marks this host's lease released, optionally recording how the attempt ended. Releasing an already-released lease is a no-op that returns the recorded release time and outcome. |
|
|
170
|
+
| `outerlayer runner init [--config <path>]` | Writes a `runner` block with defaults and three example hooks, keeping every key the config already had. Refuses rather than overwriting an existing block. |
|
|
171
|
+
| `outerlayer runner check [--config <path>]` | Validates the config, the hooks and the key, prints the settings the runner would use, and exits non-zero on a problem. Takes no work and writes no pid file. |
|
|
172
|
+
| `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. |
|
|
173
|
+
| `outerlayer runner stop [--config <path>] [--now]` | Takes no more work and waits for running jobs to finish, naming each every five seconds. `--now` ends them immediately with outcome `stopped`. Ctrl-C on a foreground runner drains; a second one stops now. |
|
|
174
|
+
| `outerlayer runner status [--config <path>] [--recent] [--json]` | A header naming the runner's own state, then a row per running job — item, queue, stage, elapsed, started, lease, job directory. `--recent` adds finished jobs, newest first, capped at 20, with their outcomes. |
|
|
175
|
+
| `outerlayer runner logs <item> [--config <path>] [-f]` | Prints the newest attempt's log for one item, following it with `-f`. |
|
|
176
|
+
|
|
177
|
+
The `work` commands need an API key that carries `Ingest traces`
|
|
178
|
+
(`trace.write`) to add, remove, and declare a pull request (`pr`), and `Read
|
|
179
|
+
the Work page` (`git_connection.read`) to look an item up — which `remove` and
|
|
180
|
+
`status` both do before they act. Tick both when you mint the key, in
|
|
181
|
+
Settings → API keys. Claiming a lease needs `Claim work items`
|
|
182
|
+
(`work_item_claim.insert`); renewing or releasing one needs `Renew or
|
|
183
|
+
release work item claims` (`work_item_claim.update`). Withdrawing an
|
|
184
|
+
addition somebody else made additionally needs `Withdraw others' work from
|
|
185
|
+
the Work page` (`git_connection.update`).
|
|
186
|
+
|
|
187
|
+
### Recording your own pass or fail on a check
|
|
188
|
+
|
|
189
|
+
`outerlayer emit` also records a judgment you make yourself, under a check
|
|
190
|
+
name a validator declares, on the work item — not any one pull request, so
|
|
191
|
+
it holds across every pull request the item has. Say what is wrong, in one
|
|
192
|
+
sentence:
|
|
193
|
+
|
|
194
|
+
```
|
|
195
|
+
outerlayer emit code-review --result fail --item 412 \
|
|
196
|
+
--body "The button should be the destructive red, not grey."
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
The sentence can come from a file, or from standard input with `-`:
|
|
200
|
+
|
|
201
|
+
```
|
|
202
|
+
echo "The button should be the destructive red, not grey." \
|
|
203
|
+
| outerlayer emit code-review --result fail --item 412 --body-file -
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Record a pass once the work is right:
|
|
207
|
+
|
|
208
|
+
```
|
|
209
|
+
outerlayer emit code-review --result pass --item 412
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
`--item` is always required, in or out of a recorded session. A session
|
|
213
|
+
records a check only on an item it was NOT launched for, by naming it with
|
|
214
|
+
`--item`; a check on the item the session itself was launched for needs a
|
|
215
|
+
machine key (an API key run outside the recorded session) or CI.
|
|
216
|
+
|
|
217
|
+
Three things to know. Who recorded a check is decided by the API key you
|
|
218
|
+
used, never by anything in the request. A key bound to a membership records
|
|
219
|
+
the check against that person, and once a fail is recorded, only a person's
|
|
220
|
+
key can record over it. A failing check needs a run link or a sentence,
|
|
221
|
+
because a fail with neither is something nobody can act on. And a check only
|
|
222
|
+
holds a gate once a validator in `.outerlayer/validators/` declares its emit
|
|
223
|
+
name; without one the check is recorded and read back, and blocks nothing.
|
|
224
|
+
|
|
225
|
+
A review of the work itself is different: it is recorded from the Review
|
|
226
|
+
tab on the work item page, not the CLI, and holds every pull request of the
|
|
227
|
+
item until a person records a pass — no validator declaration needed.
|
|
228
|
+
`outerlayer emit` refuses `work-review` outright; recording it anywhere but
|
|
229
|
+
the work item page is not supported. The gateway refuses a review, and an
|
|
230
|
+
artifact verdict, on an item that is closed or shipped, has no evaluation
|
|
231
|
+
yet, or whose evaluation is still waiting on a session link, with the code
|
|
232
|
+
`item_not_reviewable`. A recorded pass carries the head commit of every
|
|
233
|
+
pull request the item had at the time; once one of them moves, that pass
|
|
234
|
+
stops counting and a fresh review is needed. A repository can require a
|
|
235
|
+
current pass before the evidence check completes by setting the base
|
|
236
|
+
branch's `review` policy key to `required` (default `optional`, alongside
|
|
237
|
+
`merge_gate`) — the check then stays in progress, not failed, until a
|
|
238
|
+
current pass exists.
|
|
239
|
+
|
|
240
|
+
`outerlayer emit artifact-review` sits between the two: a person's own pass
|
|
241
|
+
or fail, like a review, but on one piece of evidence rather than the whole
|
|
242
|
+
item. A fail here holds the item the same way a review's fail does, and
|
|
243
|
+
counts the work as bad on Quality once, however many artifacts carry one —
|
|
244
|
+
it also lists the item on a queue the API exposes, naming the artifact and
|
|
245
|
+
why it failed, so a host with a session linked to the item can answer it
|
|
246
|
+
with a replacement, or the fail's own recorder can pass over it directly.
|
|
247
|
+
The item's own pass stays available only once every required artifact has
|
|
248
|
+
a pass and no fail is still open.
|
|
249
|
+
|
|
250
|
+
Every command accepts `--no-color`, and color is off on its own when stdout is not a terminal, when `NO_COLOR` is set, or when `TERM` is `dumb`. `FORCE_COLOR=1` turns it on for a pipe. Commands that print anything accept `--json`.
|
|
251
|
+
|
|
252
|
+
## Status line
|
|
253
|
+
|
|
254
|
+
`init` also adds an ambient Claude Code status-line segment showing what your
|
|
255
|
+
session and your agents are costing today:
|
|
256
|
+
|
|
257
|
+
```
|
|
258
|
+
⬢ OL $0.87 session · $23.40 today across 3 agents · 12 unsynced
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
The session figure comes straight from Claude Code's own cost field, so it
|
|
262
|
+
always matches what Claude Code itself would show. The cross-agent total and
|
|
263
|
+
unsynced count come from `~/.outerlayer/statusline.json`, a small file the
|
|
264
|
+
`watch` daemon keeps fresh — the status line itself never parses transcripts,
|
|
265
|
+
so it stays well under Claude Code's refresh budget. On a day with only one
|
|
266
|
+
active agent, the scope adapts: `across N agents` becomes `across N sessions`
|
|
267
|
+
if you ran several sessions with it, or drops entirely to a bare `$X today`
|
|
268
|
+
for a single session — "across 1 agent" never appears.
|
|
269
|
+
|
|
270
|
+
If a `statusLine` command is already configured, `init` **wraps it rather
|
|
271
|
+
than replacing it**: your existing command's output is printed first, the
|
|
272
|
+
OuterLayer segment appends after. A hang or failure in the wrapped command
|
|
273
|
+
never blanks the line — it times out and OuterLayer's segment prints alone.
|
|
274
|
+
`outerlayer init --remove` restores the original command exactly.
|
|
275
|
+
|
|
276
|
+
Without `outerlayer watch` running, the line degrades gracefully to the
|
|
277
|
+
session figure alone plus a dim `outerlayer doctor` hint — run `outerlayer
|
|
278
|
+
doctor` to see why (usually: the daemon isn't running, or hasn't refreshed
|
|
279
|
+
recently).
|
|
280
|
+
|
|
281
|
+
Opt out of the segment with `outerlayer init --no-statusline`.
|
|
282
|
+
|
|
283
|
+
## Supported agents
|
|
284
|
+
|
|
285
|
+
| Agent | Source | Status |
|
|
286
|
+
|---|---|---|
|
|
287
|
+
| Claude Code | `~/.claude/projects` (+ raw mirror) | full: turns, tool I/O, thinking, images, subagents, cost |
|
|
288
|
+
| Codex CLI | `~/.codex/sessions` | captured locally only — turns, tool I/O, edits (apply_patch), errors, usage |
|
|
289
|
+
| Cursor | `~/.cursor/chats` | captured locally only — turns, thinking, tool I/O, edits, errors, no cost (Cursor stores no token usage) |
|
|
290
|
+
|
|
291
|
+
Upload needs a session-start hook to record the launch, and only Claude Code
|
|
292
|
+
has one, so only Claude Code sessions can be launched as work today.
|
|
293
|
+
|
|
294
|
+
Sessions from every agent land in one canonical schema
|
|
295
|
+
(`@outerlayer/session-schema`), so sync and everything downstream treat them
|
|
296
|
+
identically. Adding an agent is one source adapter.
|
|
297
|
+
|
|
298
|
+
## How capture works
|
|
299
|
+
|
|
300
|
+
Your agents already write complete transcripts to disk — OuterLayer treats
|
|
301
|
+
those as the source of truth rather than wrapping or proxying the agent:
|
|
302
|
+
|
|
303
|
+
- **`init`** adds a <50ms hook that notes each session event and installs
|
|
304
|
+
the status-line segment.
|
|
305
|
+
- **`outerlayer daemon`** mirrors transcripts before the agent deletes them
|
|
306
|
+
— so history survives even for agents with retention windows. It's a
|
|
307
|
+
separate, long-running process you start yourself; `init` doesn't start
|
|
308
|
+
it for you.
|
|
309
|
+
- **`sync`** parses whatever is on disk and ships the sessions you launched
|
|
310
|
+
with `OUTERLAYER_WORK`, incrementally, only what's new since the last run.
|
|
311
|
+
|
|
312
|
+
No API keys, no model calls, no interception. If you uninstall OuterLayer,
|
|
313
|
+
your agents never notice.
|
|
314
|
+
|
|
315
|
+
## Requirements
|
|
316
|
+
|
|
317
|
+
Node 22+. macOS and Linux; Windows untested (issues welcome). Capturing
|
|
318
|
+
**Cursor** sessions additionally needs Node 22.5+ (it reads Cursor's SQLite
|
|
319
|
+
chat store via the `node:sqlite` builtin); on older Node, Cursor is not
|
|
320
|
+
captured at all.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"id":"2026-09-23T16:41:05.295Z+7ad24522","root":"/Users/carbonteq/manage-ai/control-plane/cli-release","pkg":"outerlayer"}
|