forkcell 0.1.0a0__tar.gz
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.
- forkcell-0.1.0a0/LICENSE +51 -0
- forkcell-0.1.0a0/NOTICE +12 -0
- forkcell-0.1.0a0/PKG-INFO +216 -0
- forkcell-0.1.0a0/README.md +199 -0
- forkcell-0.1.0a0/forkcell/__init__.py +7 -0
- forkcell-0.1.0a0/forkcell/api.py +191 -0
- forkcell-0.1.0a0/forkcell/checkpoint.py +148 -0
- forkcell-0.1.0a0/forkcell/cli.py +3676 -0
- forkcell-0.1.0a0/forkcell/native.py +618 -0
- forkcell-0.1.0a0/forkcell/overlay.py +363 -0
- forkcell-0.1.0a0/forkcell/volume.py +567 -0
- forkcell-0.1.0a0/forkcell.egg-info/PKG-INFO +216 -0
- forkcell-0.1.0a0/forkcell.egg-info/SOURCES.txt +16 -0
- forkcell-0.1.0a0/forkcell.egg-info/dependency_links.txt +1 -0
- forkcell-0.1.0a0/forkcell.egg-info/entry_points.txt +2 -0
- forkcell-0.1.0a0/forkcell.egg-info/top_level.txt +1 -0
- forkcell-0.1.0a0/pyproject.toml +25 -0
- forkcell-0.1.0a0/setup.cfg +4 -0
forkcell-0.1.0a0/LICENSE
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
|
|
10
|
+
|
|
11
|
+
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
|
|
12
|
+
|
|
13
|
+
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
|
|
14
|
+
|
|
15
|
+
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
|
|
16
|
+
|
|
17
|
+
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
|
|
18
|
+
|
|
19
|
+
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
|
|
20
|
+
|
|
21
|
+
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work.
|
|
22
|
+
|
|
23
|
+
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on or derived from the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link or bind by name to the interfaces of, the Work and Derivative Works thereof.
|
|
24
|
+
|
|
25
|
+
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner.
|
|
26
|
+
|
|
27
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
|
|
28
|
+
|
|
29
|
+
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
|
|
30
|
+
|
|
31
|
+
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work.
|
|
32
|
+
|
|
33
|
+
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, provided that You meet the following conditions:
|
|
34
|
+
|
|
35
|
+
(a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
|
|
36
|
+
|
|
37
|
+
(b) You must cause any modified files to carry prominent notices stating that You changed the files; and
|
|
38
|
+
|
|
39
|
+
(c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
|
|
40
|
+
|
|
41
|
+
(d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file.
|
|
42
|
+
|
|
43
|
+
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work shall be under the terms and conditions of this License.
|
|
44
|
+
|
|
45
|
+
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work.
|
|
46
|
+
|
|
47
|
+
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
48
|
+
|
|
49
|
+
8. Limitation of Liability. In no event and under no legal theory shall any Contributor be liable to You for damages arising as a result of this License or out of the use or inability to use the Work.
|
|
50
|
+
|
|
51
|
+
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer support, warranty, indemnity, or other liability obligations on Your own behalf only.
|
forkcell-0.1.0a0/NOTICE
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
ForkCell
|
|
2
|
+
Copyright 2026 BeforeWire.
|
|
3
|
+
|
|
4
|
+
ForkCell is distributed under the Apache License, Version 2.0.
|
|
5
|
+
|
|
6
|
+
ForkCell depends on OpenShell as its governed runtime. The preview branch pins a runtime fork at:
|
|
7
|
+
|
|
8
|
+
https://github.com/beforewire/openshell
|
|
9
|
+
|
|
10
|
+
That runtime fork is derived from NVIDIA OpenShell and retains the upstream OpenShell copyright, license, and notices in the submodule repository.
|
|
11
|
+
|
|
12
|
+
The OpenShell workspace-substrate patch used by ForkCell is applied in the pinned runtime fork. A patch artifact is retained under `patches/` for review and upstreaming provenance.
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: forkcell
|
|
3
|
+
Version: 0.1.0a0
|
|
4
|
+
Summary: Governed execution cells for AI agents, with rollback and receipts
|
|
5
|
+
Author: BeforeWire
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Keywords: ai-agents,sandbox,checkpoint,openshell,policy,receipts
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Requires-Python: >=3.11
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
License-File: NOTICE
|
|
16
|
+
Dynamic: license-file
|
|
17
|
+
|
|
18
|
+
# ForkCell
|
|
19
|
+
|
|
20
|
+
[中文](README.zh-CN.md) | English
|
|
21
|
+
|
|
22
|
+
ForkCell is a governed execution-cell layer for AI agents: it adds fast workspace rollback, policy-bound runs, and reviewable receipts to local agent execution.
|
|
23
|
+
|
|
24
|
+
> Checkpoint -> governed run -> receipt -> accept, restore, or fork.
|
|
25
|
+
|
|
26
|
+
ForkCell is currently the `v0.1.0-preview` source preview (`0.1.0a0` Python package version). The public-preview branch is intentionally small: it contains the ForkCell control plane, a pinned governed-runtime submodule, a review patch artifact, and the minimum scripts/docs needed to understand and run the preview.
|
|
27
|
+
|
|
28
|
+
## Why ForkCell Exists
|
|
29
|
+
|
|
30
|
+
AI agents increasingly edit repositories, install packages, call APIs, and touch credentials. A plain sandbox can isolate a process, and a plain snapshot can roll files back, but teams also need to answer:
|
|
31
|
+
|
|
32
|
+
- What checkpoint did the agent start from?
|
|
33
|
+
- What runtime policy governed the run?
|
|
34
|
+
- Which egress or L7 policy events occurred?
|
|
35
|
+
- Was the failed run restored, accepted, or forked?
|
|
36
|
+
- Can a reviewer inspect a durable receipt instead of raw logs?
|
|
37
|
+
|
|
38
|
+
ForkCell turns a risky agent command into an auditable transaction.
|
|
39
|
+
|
|
40
|
+
## What ForkCell Does
|
|
41
|
+
|
|
42
|
+
ForkCell owns the transaction/control plane:
|
|
43
|
+
|
|
44
|
+
- creates filesystem checkpoints for a cell workspace;
|
|
45
|
+
- runs commands through a governed runtime integration;
|
|
46
|
+
- binds policy revision, checkpoint identity, workspace config, and command result into receipts;
|
|
47
|
+
- records accept/restore decisions as first-class artifacts;
|
|
48
|
+
- restores quickly through metadata generation switching on the native overlay backend;
|
|
49
|
+
- keeps fallback/degraded backend decisions explicit.
|
|
50
|
+
|
|
51
|
+
Runtime enforcement is handled by the configured governed runtime; see
|
|
52
|
+
`Runtime Integration` for the current preview substrate.
|
|
53
|
+
|
|
54
|
+
ForkCell does **not** implement business-semantic policy such as refund limits or claim eligibility in core. Business policy should live in an external application/PDP/tool gateway. ForkCell focuses on runtime capability policy and transaction receipts.
|
|
55
|
+
|
|
56
|
+
## Repository Layout
|
|
57
|
+
|
|
58
|
+
```text
|
|
59
|
+
forkcell/
|
|
60
|
+
forkcell/ # Python CLI/API and checkpoint providers
|
|
61
|
+
scripts/ # preview build, gateway, and smoke scripts
|
|
62
|
+
patches/ # runtime patch review/provenance artifacts
|
|
63
|
+
docs/ # architecture and preview docs
|
|
64
|
+
upstream/openshell # submodule: current pinned runtime fork
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The OpenShell patch is already applied in the pinned `beforewire/openshell` submodule. The patch file under `patches/` is kept as a review/upstreaming artifact, not as a normal build-time step.
|
|
68
|
+
|
|
69
|
+
## Runtime Integration
|
|
70
|
+
|
|
71
|
+
ForkCell's preview runtime integration uses a pinned OpenShell fork:
|
|
72
|
+
|
|
73
|
+
```text
|
|
74
|
+
repo: https://github.com/beforewire/openshell
|
|
75
|
+
branch: forkcell-workspace-substrate
|
|
76
|
+
tag: forkcell-runtime-v0.1.3-preview
|
|
77
|
+
commit: 393c25a86d9128ff5e38ecf537809efe58470266
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The runtime fork carries a narrow workspace-substrate change:
|
|
81
|
+
|
|
82
|
+
- Docker driver accepts a typed `docker.workspace` / `forkcell_overlay` contract;
|
|
83
|
+
- the workspace backing volume is mounted at a private path;
|
|
84
|
+
- the supervisor prepares/chowns overlay runtime directories before privilege drop and hardening;
|
|
85
|
+
- runtime policy, egress, credential, and OCSF paths stay unchanged.
|
|
86
|
+
|
|
87
|
+
In this preview, OpenShell provides the runtime enforcement layer:
|
|
88
|
+
|
|
89
|
+
- sandbox lifecycle;
|
|
90
|
+
- process and filesystem policy;
|
|
91
|
+
- egress/L7 policy;
|
|
92
|
+
- credential/provider path;
|
|
93
|
+
- OCSF/log events.
|
|
94
|
+
|
|
95
|
+
See `patches/openshell.lock` and `docs/openshell-native-fast-substrate.md`.
|
|
96
|
+
|
|
97
|
+
## Quickstart
|
|
98
|
+
|
|
99
|
+
Prerequisites:
|
|
100
|
+
|
|
101
|
+
- macOS or Linux host with Docker available;
|
|
102
|
+
- Python 3.11+;
|
|
103
|
+
- Rust/Cargo for building OpenShell CLI/gateway;
|
|
104
|
+
- access to the `beforewire/openshell` submodule.
|
|
105
|
+
|
|
106
|
+
Clone with submodules:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
git clone --recurse-submodules https://github.com/beforewire/forkcell.git
|
|
110
|
+
cd forkcell
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Or initialize submodules after cloning:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
git submodule update --init --recursive
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Install ForkCell locally:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
python3 -m venv .venv
|
|
123
|
+
source .venv/bin/activate
|
|
124
|
+
pip install -e .
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Run the lightweight preview smoke:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
./scripts/validate_public_smoke.sh
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Build the pinned governed runtime:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
./scripts/build_patched_openshell_runtime.sh
|
|
137
|
+
python3 -m forkcell.cli runtime install --from upstream/openshell
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Start the local patched runtime gateway:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
./scripts/start_patched_openshell_gateway.sh
|
|
144
|
+
export FORKCELL_OPENSHELL_BIN="$PWD/.forkcell/runtime/native-overlay/bin/openshell"
|
|
145
|
+
export OPENSHELL_GATEWAY_ENDPOINT="http://127.0.0.1:17671"
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Create a native cell and run a restore-on-fail command:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
mkdir -p /tmp/forkcell-demo
|
|
152
|
+
printf 'hello\n' >/tmp/forkcell-demo/hello.txt
|
|
153
|
+
|
|
154
|
+
python3 -m forkcell.cli native init demo --from /tmp/forkcell-demo
|
|
155
|
+
python3 -m forkcell.cli native run --checkpoint-before --restore-on-fail demo -- \
|
|
156
|
+
sh -lc 'echo changed > hello.txt; exit 7'
|
|
157
|
+
python3 -m forkcell.cli receipt show --cell demo --latest --format md
|
|
158
|
+
cat /tmp/forkcell-demo/hello.txt
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
The command intentionally exits with status `7` inside the sandbox. Success means
|
|
162
|
+
ForkCell records `Decision: restored` in the receipt and the final `cat` prints
|
|
163
|
+
`hello`.
|
|
164
|
+
|
|
165
|
+
Stop the gateway when done:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
./scripts/stop_patched_openshell_gateway.sh
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Current Preview Metrics
|
|
172
|
+
|
|
173
|
+
Latest validation for this preview line:
|
|
174
|
+
|
|
175
|
+
- native overlay `restore_sync_ms`: `0ms` on small, medium, and pruned workspaces, meaning the synchronous generation switch is sub-ms/rounded to zero;
|
|
176
|
+
- native overlay correctness matrix: `7/7` cases passed;
|
|
177
|
+
- native policy smoke: deny host, allow GET, and L7 deny passed;
|
|
178
|
+
- runtime packaging and CI-style gate passed;
|
|
179
|
+
- runtime sandbox lifecycle is still roughly hundreds of milliseconds, so only the synchronous restore substrate should be described as sub-ms/`0ms`.
|
|
180
|
+
|
|
181
|
+
Fresh README-path validation on macOS + Docker also produced a tiny-workspace receipt with `checkpoint duration: 0ms`, `restore duration: 0ms`, `restore_sync_ms: 0ms`, and `total_restore_path_ms: 726ms`. The latter includes runtime sandbox delete/lifecycle and log collection, not just ForkCell's restore substrate.
|
|
182
|
+
|
|
183
|
+
A sanitized evidence summary is in `docs/evidence-summary.md`.
|
|
184
|
+
|
|
185
|
+
## Backends
|
|
186
|
+
|
|
187
|
+
- `native-overlay`: production fast path when the patched governed runtime is configured.
|
|
188
|
+
- `layer-clone`: compatible fallback; restore is metadata-only but run-layer preparation copies the checkpoint tree.
|
|
189
|
+
- `volume-delta`: governed Docker volume workspace with CAS/delta restore.
|
|
190
|
+
- `local-overlay`: local degraded-policy filesystem fallback for development.
|
|
191
|
+
|
|
192
|
+
In this preview, `native-overlay`, `layer-clone`, and `volume-delta` are backed by OpenShell. The backend names describe ForkCell restore strategies; the runtime integration describes the sandbox/policy engine underneath.
|
|
193
|
+
|
|
194
|
+
## Non-goals For This Preview
|
|
195
|
+
|
|
196
|
+
- no memory/process checkpoint;
|
|
197
|
+
- no VM/MicroVM/KVM isolation layer;
|
|
198
|
+
- no business-semantic policy evaluator in ForkCell core;
|
|
199
|
+
- no replacement for OpenShell policy/egress enforcement;
|
|
200
|
+
- no claim of pure macOS/Windows native isolation;
|
|
201
|
+
- no claim that full sandbox lifecycle is `0ms`.
|
|
202
|
+
|
|
203
|
+
## Documentation
|
|
204
|
+
|
|
205
|
+
- `docs/architecture.md` - product boundary and control-plane architecture.
|
|
206
|
+
- `docs/openshell-native-fast-substrate.md` - OpenShell workspace substrate design.
|
|
207
|
+
- `docs/testing-plan.md` - preview smoke and integration validation plan.
|
|
208
|
+
- `docs/evidence-summary.md` - sanitized validation summary.
|
|
209
|
+
|
|
210
|
+
## About BeforeWire
|
|
211
|
+
|
|
212
|
+
ForkCell is part of BeforeWire's agent-trust infrastructure work: make agent execution reviewable, reversible, and policy-bound without pretending that local development needs a full cloud MicroVM product on day one.
|
|
213
|
+
|
|
214
|
+
## Status
|
|
215
|
+
|
|
216
|
+
`v0.1.0-preview` / `0.1.0a0` is experimental. The preview is intended to show the product boundary and the working checkpoint/restore/receipt path before the project is promoted to a broader public release.
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# ForkCell
|
|
2
|
+
|
|
3
|
+
[中文](README.zh-CN.md) | English
|
|
4
|
+
|
|
5
|
+
ForkCell is a governed execution-cell layer for AI agents: it adds fast workspace rollback, policy-bound runs, and reviewable receipts to local agent execution.
|
|
6
|
+
|
|
7
|
+
> Checkpoint -> governed run -> receipt -> accept, restore, or fork.
|
|
8
|
+
|
|
9
|
+
ForkCell is currently the `v0.1.0-preview` source preview (`0.1.0a0` Python package version). The public-preview branch is intentionally small: it contains the ForkCell control plane, a pinned governed-runtime submodule, a review patch artifact, and the minimum scripts/docs needed to understand and run the preview.
|
|
10
|
+
|
|
11
|
+
## Why ForkCell Exists
|
|
12
|
+
|
|
13
|
+
AI agents increasingly edit repositories, install packages, call APIs, and touch credentials. A plain sandbox can isolate a process, and a plain snapshot can roll files back, but teams also need to answer:
|
|
14
|
+
|
|
15
|
+
- What checkpoint did the agent start from?
|
|
16
|
+
- What runtime policy governed the run?
|
|
17
|
+
- Which egress or L7 policy events occurred?
|
|
18
|
+
- Was the failed run restored, accepted, or forked?
|
|
19
|
+
- Can a reviewer inspect a durable receipt instead of raw logs?
|
|
20
|
+
|
|
21
|
+
ForkCell turns a risky agent command into an auditable transaction.
|
|
22
|
+
|
|
23
|
+
## What ForkCell Does
|
|
24
|
+
|
|
25
|
+
ForkCell owns the transaction/control plane:
|
|
26
|
+
|
|
27
|
+
- creates filesystem checkpoints for a cell workspace;
|
|
28
|
+
- runs commands through a governed runtime integration;
|
|
29
|
+
- binds policy revision, checkpoint identity, workspace config, and command result into receipts;
|
|
30
|
+
- records accept/restore decisions as first-class artifacts;
|
|
31
|
+
- restores quickly through metadata generation switching on the native overlay backend;
|
|
32
|
+
- keeps fallback/degraded backend decisions explicit.
|
|
33
|
+
|
|
34
|
+
Runtime enforcement is handled by the configured governed runtime; see
|
|
35
|
+
`Runtime Integration` for the current preview substrate.
|
|
36
|
+
|
|
37
|
+
ForkCell does **not** implement business-semantic policy such as refund limits or claim eligibility in core. Business policy should live in an external application/PDP/tool gateway. ForkCell focuses on runtime capability policy and transaction receipts.
|
|
38
|
+
|
|
39
|
+
## Repository Layout
|
|
40
|
+
|
|
41
|
+
```text
|
|
42
|
+
forkcell/
|
|
43
|
+
forkcell/ # Python CLI/API and checkpoint providers
|
|
44
|
+
scripts/ # preview build, gateway, and smoke scripts
|
|
45
|
+
patches/ # runtime patch review/provenance artifacts
|
|
46
|
+
docs/ # architecture and preview docs
|
|
47
|
+
upstream/openshell # submodule: current pinned runtime fork
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The OpenShell patch is already applied in the pinned `beforewire/openshell` submodule. The patch file under `patches/` is kept as a review/upstreaming artifact, not as a normal build-time step.
|
|
51
|
+
|
|
52
|
+
## Runtime Integration
|
|
53
|
+
|
|
54
|
+
ForkCell's preview runtime integration uses a pinned OpenShell fork:
|
|
55
|
+
|
|
56
|
+
```text
|
|
57
|
+
repo: https://github.com/beforewire/openshell
|
|
58
|
+
branch: forkcell-workspace-substrate
|
|
59
|
+
tag: forkcell-runtime-v0.1.3-preview
|
|
60
|
+
commit: 393c25a86d9128ff5e38ecf537809efe58470266
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The runtime fork carries a narrow workspace-substrate change:
|
|
64
|
+
|
|
65
|
+
- Docker driver accepts a typed `docker.workspace` / `forkcell_overlay` contract;
|
|
66
|
+
- the workspace backing volume is mounted at a private path;
|
|
67
|
+
- the supervisor prepares/chowns overlay runtime directories before privilege drop and hardening;
|
|
68
|
+
- runtime policy, egress, credential, and OCSF paths stay unchanged.
|
|
69
|
+
|
|
70
|
+
In this preview, OpenShell provides the runtime enforcement layer:
|
|
71
|
+
|
|
72
|
+
- sandbox lifecycle;
|
|
73
|
+
- process and filesystem policy;
|
|
74
|
+
- egress/L7 policy;
|
|
75
|
+
- credential/provider path;
|
|
76
|
+
- OCSF/log events.
|
|
77
|
+
|
|
78
|
+
See `patches/openshell.lock` and `docs/openshell-native-fast-substrate.md`.
|
|
79
|
+
|
|
80
|
+
## Quickstart
|
|
81
|
+
|
|
82
|
+
Prerequisites:
|
|
83
|
+
|
|
84
|
+
- macOS or Linux host with Docker available;
|
|
85
|
+
- Python 3.11+;
|
|
86
|
+
- Rust/Cargo for building OpenShell CLI/gateway;
|
|
87
|
+
- access to the `beforewire/openshell` submodule.
|
|
88
|
+
|
|
89
|
+
Clone with submodules:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
git clone --recurse-submodules https://github.com/beforewire/forkcell.git
|
|
93
|
+
cd forkcell
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Or initialize submodules after cloning:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
git submodule update --init --recursive
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Install ForkCell locally:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
python3 -m venv .venv
|
|
106
|
+
source .venv/bin/activate
|
|
107
|
+
pip install -e .
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Run the lightweight preview smoke:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
./scripts/validate_public_smoke.sh
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Build the pinned governed runtime:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
./scripts/build_patched_openshell_runtime.sh
|
|
120
|
+
python3 -m forkcell.cli runtime install --from upstream/openshell
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Start the local patched runtime gateway:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
./scripts/start_patched_openshell_gateway.sh
|
|
127
|
+
export FORKCELL_OPENSHELL_BIN="$PWD/.forkcell/runtime/native-overlay/bin/openshell"
|
|
128
|
+
export OPENSHELL_GATEWAY_ENDPOINT="http://127.0.0.1:17671"
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Create a native cell and run a restore-on-fail command:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
mkdir -p /tmp/forkcell-demo
|
|
135
|
+
printf 'hello\n' >/tmp/forkcell-demo/hello.txt
|
|
136
|
+
|
|
137
|
+
python3 -m forkcell.cli native init demo --from /tmp/forkcell-demo
|
|
138
|
+
python3 -m forkcell.cli native run --checkpoint-before --restore-on-fail demo -- \
|
|
139
|
+
sh -lc 'echo changed > hello.txt; exit 7'
|
|
140
|
+
python3 -m forkcell.cli receipt show --cell demo --latest --format md
|
|
141
|
+
cat /tmp/forkcell-demo/hello.txt
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
The command intentionally exits with status `7` inside the sandbox. Success means
|
|
145
|
+
ForkCell records `Decision: restored` in the receipt and the final `cat` prints
|
|
146
|
+
`hello`.
|
|
147
|
+
|
|
148
|
+
Stop the gateway when done:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
./scripts/stop_patched_openshell_gateway.sh
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Current Preview Metrics
|
|
155
|
+
|
|
156
|
+
Latest validation for this preview line:
|
|
157
|
+
|
|
158
|
+
- native overlay `restore_sync_ms`: `0ms` on small, medium, and pruned workspaces, meaning the synchronous generation switch is sub-ms/rounded to zero;
|
|
159
|
+
- native overlay correctness matrix: `7/7` cases passed;
|
|
160
|
+
- native policy smoke: deny host, allow GET, and L7 deny passed;
|
|
161
|
+
- runtime packaging and CI-style gate passed;
|
|
162
|
+
- runtime sandbox lifecycle is still roughly hundreds of milliseconds, so only the synchronous restore substrate should be described as sub-ms/`0ms`.
|
|
163
|
+
|
|
164
|
+
Fresh README-path validation on macOS + Docker also produced a tiny-workspace receipt with `checkpoint duration: 0ms`, `restore duration: 0ms`, `restore_sync_ms: 0ms`, and `total_restore_path_ms: 726ms`. The latter includes runtime sandbox delete/lifecycle and log collection, not just ForkCell's restore substrate.
|
|
165
|
+
|
|
166
|
+
A sanitized evidence summary is in `docs/evidence-summary.md`.
|
|
167
|
+
|
|
168
|
+
## Backends
|
|
169
|
+
|
|
170
|
+
- `native-overlay`: production fast path when the patched governed runtime is configured.
|
|
171
|
+
- `layer-clone`: compatible fallback; restore is metadata-only but run-layer preparation copies the checkpoint tree.
|
|
172
|
+
- `volume-delta`: governed Docker volume workspace with CAS/delta restore.
|
|
173
|
+
- `local-overlay`: local degraded-policy filesystem fallback for development.
|
|
174
|
+
|
|
175
|
+
In this preview, `native-overlay`, `layer-clone`, and `volume-delta` are backed by OpenShell. The backend names describe ForkCell restore strategies; the runtime integration describes the sandbox/policy engine underneath.
|
|
176
|
+
|
|
177
|
+
## Non-goals For This Preview
|
|
178
|
+
|
|
179
|
+
- no memory/process checkpoint;
|
|
180
|
+
- no VM/MicroVM/KVM isolation layer;
|
|
181
|
+
- no business-semantic policy evaluator in ForkCell core;
|
|
182
|
+
- no replacement for OpenShell policy/egress enforcement;
|
|
183
|
+
- no claim of pure macOS/Windows native isolation;
|
|
184
|
+
- no claim that full sandbox lifecycle is `0ms`.
|
|
185
|
+
|
|
186
|
+
## Documentation
|
|
187
|
+
|
|
188
|
+
- `docs/architecture.md` - product boundary and control-plane architecture.
|
|
189
|
+
- `docs/openshell-native-fast-substrate.md` - OpenShell workspace substrate design.
|
|
190
|
+
- `docs/testing-plan.md` - preview smoke and integration validation plan.
|
|
191
|
+
- `docs/evidence-summary.md` - sanitized validation summary.
|
|
192
|
+
|
|
193
|
+
## About BeforeWire
|
|
194
|
+
|
|
195
|
+
ForkCell is part of BeforeWire's agent-trust infrastructure work: make agent execution reviewable, reversible, and policy-bound without pretending that local development needs a full cloud MicroVM product on day one.
|
|
196
|
+
|
|
197
|
+
## Status
|
|
198
|
+
|
|
199
|
+
`v0.1.0-preview` / `0.1.0a0` is experimental. The preview is intended to show the product boundary and the working checkpoint/restore/receipt path before the project is promoted to a broader public release.
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
import subprocess
|
|
6
|
+
import sys
|
|
7
|
+
import uuid
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Any, Iterable, Mapping
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ForkCellCommandError(RuntimeError):
|
|
14
|
+
def __init__(self, args: list[str], returncode: int, stdout: str, stderr: str) -> None:
|
|
15
|
+
self.args_list = args
|
|
16
|
+
self.returncode = returncode
|
|
17
|
+
self.stdout = stdout
|
|
18
|
+
self.stderr = stderr
|
|
19
|
+
super().__init__(
|
|
20
|
+
f"forkcell command failed ({returncode}): {' '.join(args)}\nstdout:\n{stdout}\nstderr:\n{stderr}"
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass(frozen=True)
|
|
25
|
+
class CommandResult:
|
|
26
|
+
args: list[str]
|
|
27
|
+
returncode: int
|
|
28
|
+
stdout: str
|
|
29
|
+
stderr: str
|
|
30
|
+
json: dict[str, Any]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _extract_json_object(text: str) -> dict[str, Any]:
|
|
34
|
+
decoder = json.JSONDecoder()
|
|
35
|
+
for index, char in enumerate(text):
|
|
36
|
+
if char != "{":
|
|
37
|
+
continue
|
|
38
|
+
try:
|
|
39
|
+
value, end = decoder.raw_decode(text[index:])
|
|
40
|
+
except json.JSONDecodeError:
|
|
41
|
+
continue
|
|
42
|
+
if isinstance(value, dict) and not text[index + end :].strip():
|
|
43
|
+
return value
|
|
44
|
+
raise ValueError("missing JSON object in command output")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _normalize_command(command: str | Iterable[str]) -> list[str]:
|
|
48
|
+
if isinstance(command, str):
|
|
49
|
+
return ["sh", "-lc", command]
|
|
50
|
+
return [str(part) for part in command]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
LEGACY_BACKEND_ALIASES = {
|
|
54
|
+
"openshell-native-overlay": "native-overlay",
|
|
55
|
+
"openshell-layer-clone": "layer-clone",
|
|
56
|
+
"openshell-volume": "volume-delta",
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _normalize_backend(backend: str) -> str:
|
|
61
|
+
return LEGACY_BACKEND_ALIASES.get(backend, backend)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class ForkCellClient:
|
|
65
|
+
"""Small Python facade for agent-style ForkCell workflows.
|
|
66
|
+
|
|
67
|
+
The facade intentionally shells out to `python -m forkcell.cli` so the API
|
|
68
|
+
and CLI share the same state, receipts, and review artifacts during the
|
|
69
|
+
current governed-runtime integration.
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
def __init__(
|
|
73
|
+
self,
|
|
74
|
+
*,
|
|
75
|
+
root: str | Path | None = None,
|
|
76
|
+
python: str | None = None,
|
|
77
|
+
env: Mapping[str, str] | None = None,
|
|
78
|
+
) -> None:
|
|
79
|
+
self.root = Path(root or Path.cwd()).resolve()
|
|
80
|
+
self.python = python or sys.executable
|
|
81
|
+
self.env = dict(os.environ)
|
|
82
|
+
if env:
|
|
83
|
+
self.env.update(env)
|
|
84
|
+
|
|
85
|
+
def cli(self, args: list[str], *, check: bool = True) -> CommandResult:
|
|
86
|
+
full_args = [self.python, "-m", "forkcell.cli", *args]
|
|
87
|
+
proc = subprocess.run(full_args, cwd=self.root, env=self.env, text=True, capture_output=True)
|
|
88
|
+
parsed: dict[str, Any] = {}
|
|
89
|
+
output = proc.stdout.strip()
|
|
90
|
+
if output:
|
|
91
|
+
try:
|
|
92
|
+
parsed = _extract_json_object(output)
|
|
93
|
+
except ValueError:
|
|
94
|
+
parsed = {}
|
|
95
|
+
if check and proc.returncode != 0:
|
|
96
|
+
raise ForkCellCommandError(full_args, proc.returncode, proc.stdout, proc.stderr)
|
|
97
|
+
return CommandResult(
|
|
98
|
+
args=full_args,
|
|
99
|
+
returncode=proc.returncode,
|
|
100
|
+
stdout=proc.stdout,
|
|
101
|
+
stderr=proc.stderr,
|
|
102
|
+
json=parsed,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
def create_native_cell(
|
|
106
|
+
self,
|
|
107
|
+
*,
|
|
108
|
+
source: str | Path,
|
|
109
|
+
name: str | None = None,
|
|
110
|
+
backend: str = "native-overlay",
|
|
111
|
+
) -> "ForkCellSandbox":
|
|
112
|
+
cell = name or f"fc-api-{uuid.uuid4().hex[:8]}"
|
|
113
|
+
self.cli(["native", "init", cell, "--from", str(Path(source).resolve())])
|
|
114
|
+
return ForkCellSandbox(client=self, name=cell, backend=_normalize_backend(backend))
|
|
115
|
+
|
|
116
|
+
def native_cell(self, name: str, *, backend: str = "native-overlay") -> "ForkCellSandbox":
|
|
117
|
+
return ForkCellSandbox(client=self, name=name, backend=_normalize_backend(backend))
|
|
118
|
+
|
|
119
|
+
def review_status(self) -> dict[str, Any]:
|
|
120
|
+
return self.cli(["review", "status", "--format", "json"]).json
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
@dataclass
|
|
124
|
+
class ForkCellSandbox:
|
|
125
|
+
client: ForkCellClient
|
|
126
|
+
name: str
|
|
127
|
+
backend: str = "native-overlay"
|
|
128
|
+
auto_delete: bool = True
|
|
129
|
+
|
|
130
|
+
def __post_init__(self) -> None:
|
|
131
|
+
self.backend = _normalize_backend(self.backend)
|
|
132
|
+
|
|
133
|
+
def __enter__(self) -> "ForkCellSandbox":
|
|
134
|
+
return self
|
|
135
|
+
|
|
136
|
+
def __exit__(self, exc_type: object, exc: object, tb: object) -> None:
|
|
137
|
+
if self.auto_delete:
|
|
138
|
+
self.delete(check=False)
|
|
139
|
+
|
|
140
|
+
def status(self) -> dict[str, Any]:
|
|
141
|
+
return self.client.cli(["native", "status", self.name]).json
|
|
142
|
+
|
|
143
|
+
def checkpoint(self, *, name: str | None = None) -> dict[str, Any]:
|
|
144
|
+
args = ["native", "checkpoint", self.name]
|
|
145
|
+
if name:
|
|
146
|
+
args.extend(["--name", name])
|
|
147
|
+
return self.client.cli(args).json
|
|
148
|
+
|
|
149
|
+
def restore(self, checkpoint: str | None = None) -> dict[str, Any]:
|
|
150
|
+
args = ["native", "restore", self.name]
|
|
151
|
+
if checkpoint:
|
|
152
|
+
args.append(checkpoint)
|
|
153
|
+
return self.client.cli(args).json
|
|
154
|
+
|
|
155
|
+
def run(
|
|
156
|
+
self,
|
|
157
|
+
command: str | Iterable[str],
|
|
158
|
+
*,
|
|
159
|
+
checkpoint_before: bool = False,
|
|
160
|
+
checkpoint_name: str | None = None,
|
|
161
|
+
restore_on_fail: bool = False,
|
|
162
|
+
policy: str | Path | None = None,
|
|
163
|
+
logs_since: str = "5m",
|
|
164
|
+
) -> dict[str, Any]:
|
|
165
|
+
if self.backend == "native-overlay":
|
|
166
|
+
args = ["native", "run"]
|
|
167
|
+
elif self.backend == "layer-clone":
|
|
168
|
+
args = ["native", "run-layer"]
|
|
169
|
+
else:
|
|
170
|
+
args = ["run", self.name, "--backend", self.backend]
|
|
171
|
+
if checkpoint_before:
|
|
172
|
+
args.append("--checkpoint-before")
|
|
173
|
+
if checkpoint_name:
|
|
174
|
+
args.extend(["--checkpoint-name", checkpoint_name])
|
|
175
|
+
if restore_on_fail:
|
|
176
|
+
args.append("--restore-on-fail")
|
|
177
|
+
if policy:
|
|
178
|
+
args.extend(["--policy", str(policy)])
|
|
179
|
+
if logs_since:
|
|
180
|
+
args.extend(["--logs-since", logs_since])
|
|
181
|
+
if self.backend in {"native-overlay", "layer-clone"}:
|
|
182
|
+
args.append(self.name)
|
|
183
|
+
args.extend(["--", *_normalize_command(command)])
|
|
184
|
+
run = self.client.cli(args).json
|
|
185
|
+
receipt = Path(run.get("receipt", ""))
|
|
186
|
+
if receipt.exists():
|
|
187
|
+
return json.loads(receipt.read_text())
|
|
188
|
+
return run
|
|
189
|
+
|
|
190
|
+
def delete(self, *, check: bool = True) -> dict[str, Any]:
|
|
191
|
+
return self.client.cli(["native", "delete", self.name], check=check).json
|