@forgezero/agent 0.1.39 → 0.1.41
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/README.md +357 -348
- package/dist/agent-heartbeat.js +16 -14
- package/dist/agent-update-helper.js +15 -13
- package/dist/agent-update.js +15 -13
- package/dist/bootstrap.d.ts +13 -0
- package/dist/bootstrap.js +244 -832
- package/dist/cli/index.d.ts +0 -2
- package/dist/cloudflare-bootstrap.d.ts +21 -128
- package/dist/cloudflare-bootstrap.js +146 -788
- package/dist/cloudflare-edge.d.ts +3 -151
- package/dist/cloudflare-edge.js +28 -248
- package/dist/credential-schema.d.ts +60 -0
- package/dist/credential-schema.js +335 -0
- package/dist/definition.js +2 -2
- package/dist/deploy-file.js +2 -2
- package/dist/fz-agent.js +1787 -3387
- package/dist/fz.js +1938 -4712
- package/dist/index.d.ts +33 -0
- package/dist/metal-bootstrap.js +1 -1
- package/dist/platform-bootstrap-runtime.d.ts +5 -0
- package/dist/platform-bootstrap-runtime.js +25 -6
- package/dist/project-context.js +1 -1
- package/dist/provision.js +18 -16
- package/dist/software-helper.js +2 -2
- package/dist/software.js +2 -2
- package/dist/version.d.ts +1 -1
- package/package.json +9 -5
- package/dist/cli/custody.d.ts +0 -35
package/README.md
CHANGED
|
@@ -1,399 +1,408 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
GENERATED FILE — do not edit.
|
|
3
|
+
|
|
4
|
+
Change scripts/generate-guides.ts or its typed sources, run `bun run guides`,
|
|
5
|
+
and commit the generator and rendered files together.
|
|
6
|
+
-->
|
|
7
|
+
|
|
1
8
|
# @forgezero/agent
|
|
2
9
|
|
|
3
|
-
|
|
10
|
+
The node agent deploys on a compute; tenant mode also holds one complete project across environments in RAM and serves it over a group-scoped unix socket, while platform mode never duplicates the API vault.
|
|
4
11
|
|
|
5
|
-
|
|
6
|
-
unix socket. `@forgezero/vault` prefers that socket over an API key whenever it
|
|
7
|
-
exists, so an application on a machine running the agent reads its secrets
|
|
8
|
-
because of *where it is*, not because it holds something that could be stolen
|
|
9
|
-
from it.
|
|
12
|
+
## Global package root and supported runtimes
|
|
10
13
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
Every managed compute. It owns node identity, attestation and repository pipelines. Tenant mode additionally holds one whole project across its environments in RAM and answers over a unix socket; platform mode never replicates the API vault beside the process that already holds every unlocked realm seed. Supported runtimes: bun, node. The global base/root import is @forgezero/agent. Every public import or command is listed below; the documentation inventory is checked in both directions against package.json exports.
|
|
15
|
+
|
|
16
|
+
```text
|
|
17
|
+
import * as root from '@forgezero/agent';
|
|
14
18
|
```
|
|
15
19
|
|
|
16
|
-
|
|
17
|
-
in one version prevents a newly installed `fz` from provisioning a different
|
|
18
|
-
agent protocol. Both executable artifacts bundle their ForgeZero runtime
|
|
19
|
-
dependencies, so the constrained SSH bootstrap can transfer the reviewed pair
|
|
20
|
-
to a new host without relying on a checkout, `node_modules`, or a second remote
|
|
21
|
-
package-resolution step. Library subpath exports remain modular packages.
|
|
20
|
+
## Commands
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
both recovery phrases never enter the terminal:
|
|
22
|
+
bun add -g @forgezero/agent — Install the version-matched fz operator CLI and fz-agent daemon.
|
|
23
|
+
fz bootstrap platform --help — Inspect attended platform bootstrap inputs before applying them.
|
|
24
|
+
fz bootstrap tenant --help — Inspect tenant enrolment/bootstrap inputs.
|
|
25
|
+
fz status — Read installed service and bootstrap evidence.
|
|
28
26
|
|
|
29
|
-
```
|
|
30
|
-
|
|
27
|
+
```text
|
|
28
|
+
bun add -g @forgezero/agent
|
|
29
|
+
fz bootstrap platform --help
|
|
30
|
+
fz bootstrap tenant --help
|
|
31
31
|
fz status
|
|
32
|
-
|
|
33
|
-
fz unlock --phrase-file /secure/offline-phrase.txt # run once per participating custodian
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
Install the service explicitly:
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
fz agent install --apply # writes a hardened systemd unit
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
## Host bootstrap
|
|
43
|
-
|
|
44
|
-
The package is also the host installer. There is no separate shell setup
|
|
45
|
-
script and no second implementation for tenant or platform machines:
|
|
46
|
-
|
|
47
|
-
```bash
|
|
48
|
-
fz bootstrap platform # interactive plan, no mutation
|
|
49
|
-
sudo fz bootstrap platform prepare --bootstrap-config ./platform.json --apply
|
|
50
|
-
# Register the printed read-only deploy key. For genesis, run --apply on all
|
|
51
|
-
# three Agency members concurrently; later agency:none joiners run alone.
|
|
52
|
-
sudo fz bootstrap platform --bootstrap-config ./platform.json --apply
|
|
53
|
-
sudo fz bootstrap tenant --bootstrap-config ./tenant.json --apply
|
|
54
|
-
sudo fz bootstrap metal --bootstrap-config ./metal.json --apply
|
|
55
|
-
sudo fz bootstrap status
|
|
56
|
-
sudo fz bootstrap repair --bootstrap-config ./original.json --apply
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
Platform database participation is explicit in the private JSON configuration.
|
|
60
|
-
The three genesis nodes use `database.agency: "member"`; later DB+API joiners
|
|
61
|
-
normally use `database.agency: "none"`, which starts a Coordinator and DBServer
|
|
62
|
-
without adding a fourth Agency member. Enrolment is likewise explicit:
|
|
63
|
-
`enrolment.source: "genesis-derived"` only for the offline genesis fleet, or
|
|
64
|
-
`"api-token"` with `tokenFile` for every API-authorized later node. No behavior
|
|
65
|
-
is inferred from a hostname or numeric suffix.
|
|
66
|
-
|
|
67
|
-
Repair is not a second installation path: the CLI detects the installed
|
|
68
|
-
platform/tenant or metal state and dispatches to that profile's validator. It
|
|
69
|
-
fails closed if both state formats are present or neither is present. A private
|
|
70
|
-
intent journal binds an interrupted first apply, and later repair refuses a
|
|
71
|
-
config whose immutable host identity differs from the installed profile. Status checks the persisted
|
|
72
|
-
identity record, both Agent sockets, profile-owned systemd units and, for a
|
|
73
|
-
platform host, the active API health endpoint, nginx configuration and live
|
|
74
|
-
Coordinator-mode evidence.
|
|
75
|
-
|
|
76
|
-
Platform bootstrap supports an elastic Community ArangoDB 3.11.14 fleet. The
|
|
77
|
-
first three database-capable computes establish the writable cluster; later
|
|
78
|
-
database joiners and API-only computes use the same command with their typed
|
|
79
|
-
profile and an API-issued one-time enrolment file. Nothing treats three as a
|
|
80
|
-
maximum.
|
|
81
|
-
|
|
82
|
-
After genesis, a tenant can designate an enrolled compute as a bootstrap
|
|
83
|
-
runner. The API creates a project-bound, expiring job containing only public
|
|
84
|
-
SSH coordinates and a pinned Ed25519 host-key fingerprint. The runner claims it
|
|
85
|
-
with its hybrid node identity, reads its SSH key only from a local systemd
|
|
86
|
-
credential, pins one vetted DNS answer, transfers this packaged CLI, and runs
|
|
87
|
-
the same `fz bootstrap tenant` flow on the target. Claim renewal, completion,
|
|
88
|
-
retry and cancellation are fenced in the compute aggregate; the API never
|
|
89
|
-
stores the SSH private key or a plaintext enrolment token.
|
|
90
|
-
|
|
91
|
-
The attended Cloudflare resource phase is part of the same published command,
|
|
92
|
-
but remains separate from the root host install so its management token never
|
|
93
|
-
enters the API or Agent service environment:
|
|
94
|
-
|
|
95
|
-
```bash
|
|
96
|
-
chmod 600 cloudflare-bootstrap.json cloudflare-management.token
|
|
97
|
-
fz bootstrap platform cloudflare --bootstrap-config ./cloudflare-bootstrap.json
|
|
98
|
-
fz bootstrap platform cloudflare --bootstrap-config ./cloudflare-bootstrap.json --apply
|
|
99
|
-
# After every host is bootstrapped and publishing healthy KV state:
|
|
100
|
-
fz bootstrap platform cloudflare verify --bootstrap-config ./cloudflare-handoff.json
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
The reviewed JSON has `format: 1`, kind
|
|
104
|
-
`forgezero-cloudflare-bootstrap-request`, a `checkpointPath`, the typed
|
|
105
|
-
`coordinates`, and `tokenFiles` containing file paths only. `coordinates.nodes`
|
|
106
|
-
explicitly lists each node name, origin hostname, loopback service, Tunnel name
|
|
107
|
-
and Access application name. Relative token, checkpoint and Worker project
|
|
108
|
-
paths resolve beside the config file. Plan is offline. Apply creates/reuses one
|
|
109
|
-
shared KV namespace, Worker and Access service token plus one Tunnel, Access
|
|
110
|
-
application, ingress rule and DNS record per node. The command prints only
|
|
111
|
-
resource IDs and per-node handoff paths. The complete owner-only checkpoint
|
|
112
|
-
stays on the operator laptop; `<checkpoint>.hosts/<node>.json` contains only
|
|
113
|
-
that node's connector and required runtime capabilities and is the file copied
|
|
114
|
-
to the host for `fz bootstrap platform`. Management tokens are never persisted.
|
|
115
|
-
Each host pins cloudflared diagnostics to loopback and bootstrap/status requires
|
|
116
|
-
the expected Tunnel UUID, a connector UUID, and all four documented edge
|
|
117
|
-
connections—not merely an active process. The final `verify` is read-only: it
|
|
118
|
-
uses the checkpoint's Access service credential only on the operator laptop to
|
|
119
|
-
probe every origin, then probes every stable Worker domain without privileged
|
|
120
|
-
headers. Its printed evidence contains hostnames and HTTP status codes only.
|
|
32
|
+
```
|
|
121
33
|
|
|
122
|
-
##
|
|
34
|
+
## fz
|
|
123
35
|
|
|
124
|
-
|
|
36
|
+
The operator command: keys, status, genesis, unlock, run, and agent install. This entry requires a Bun/Node host runtime.
|
|
125
37
|
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
const fz = new ForgeZero({ project: 'altpilot', environment: 'production' });
|
|
129
|
-
await fz.get('STRIPE_KEY');
|
|
38
|
+
```text
|
|
39
|
+
fz --help
|
|
130
40
|
```
|
|
131
41
|
|
|
132
|
-
|
|
133
|
-
agent, it does not — and the key that would have been in the environment does
|
|
134
|
-
not exist on the box.
|
|
42
|
+
## fz run
|
|
135
43
|
|
|
136
|
-
|
|
44
|
+
The fallback for software that cannot read the local socket: start a process with scoped vault values in its environment. This entry requires a Bun/Node host runtime.
|
|
137
45
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
cache only has what you fetched, so a secret you have never read is exactly the
|
|
142
|
-
one you cannot get when the platform is unreachable.
|
|
46
|
+
```text
|
|
47
|
+
fz run --help
|
|
48
|
+
```
|
|
143
49
|
|
|
144
|
-
|
|
145
|
-
scope rather than only what was read. It is bounded by the scope the compute is
|
|
146
|
-
assigned to, and by SEV-SNP keeping the host out of guest memory.
|
|
50
|
+
## fz agent install
|
|
147
51
|
|
|
148
|
-
|
|
149
|
-
every secret this guest has ever held — the exact artefact the design exists to
|
|
150
|
-
remove. A restart re-fetches.
|
|
52
|
+
Provision the same hardened agent service locally that the platform provisions remotely. This entry requires a Bun/Node host runtime.
|
|
151
53
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
54
|
+
```text
|
|
55
|
+
fz agent install --help
|
|
56
|
+
```
|
|
155
57
|
|
|
156
|
-
|
|
157
|
-
staleness bound, `get` fails rather than returning a value it can no longer
|
|
158
|
-
vouch for. An application that receives a revoked credential and succeeds with
|
|
159
|
-
it is worse off than one that receives an error — the error is visible.
|
|
58
|
+
## fz-agent
|
|
160
59
|
|
|
161
|
-
|
|
60
|
+
The service entry point. Identity and private Git material arrive only as systemd credentials. A platform bootstrap may use a statically configured local control socket; an enrolled tenant guest instead builds each deployment manager from the signed server claim and reads all commands from the checked-out .fz definition. Tenant cache scope and live attestation still need to be constructed from enrolment. This entry requires a Bun/Node host runtime.
|
|
61
|
+
|
|
62
|
+
```text
|
|
63
|
+
fz-agent --help
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## fz-agent (socket)
|
|
67
|
+
|
|
68
|
+
identity, sign, attest, get, sync and held — the whole interface an application sees. This entry requires a Bun/Node host runtime.
|
|
69
|
+
|
|
70
|
+
```text
|
|
71
|
+
fz-agent (socket) --help
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## @forgezero/agent/migration-pull
|
|
75
|
+
|
|
76
|
+
PQ-authenticated outbound lifecycle claims with fenced renewal, awaited async execution, idempotent acknowledgement and bounded shutdown drain. The executor reports local facts only.
|
|
77
|
+
|
|
78
|
+
```text
|
|
79
|
+
import * as api from '@forgezero/agent/migration-pull';
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## @forgezero/agent/lifecycle-helper
|
|
83
|
+
|
|
84
|
+
The root-owned fixed-operation boundary for migration work. Signed controller claims can request only private reachability probes, local health checks, or stops of units named in a root-owned profile; they cannot carry commands.
|
|
85
|
+
|
|
86
|
+
```text
|
|
87
|
+
import * as api from '@forgezero/agent/lifecycle-helper';
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## @forgezero/agent/provision
|
|
91
|
+
|
|
92
|
+
The install plan as data, with no transport — so `fz` running locally and the platform running over SSH provision an identical machine.
|
|
93
|
+
|
|
94
|
+
```text
|
|
95
|
+
import * as api from '@forgezero/agent/provision';
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## @forgezero/agent/subscribe
|
|
99
|
+
|
|
100
|
+
Realtime scope sync over a WebSocket, with the poll kept underneath it: the poll is what establishes freshness, and a change it finds that the socket never sent is proof the socket is lying.
|
|
101
|
+
|
|
102
|
+
```text
|
|
103
|
+
import * as api from '@forgezero/agent/subscribe';
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## @forgezero/agent/ssh-listen
|
|
107
|
+
|
|
108
|
+
The socket SSH_AUTH_SOCK points at. The protocol handler had nowhere to speak — an agent protocol with no socket is a parser. The containing directory is 0700 before anything binds, because the socket’s own mode is only corrected after it already exists.
|
|
109
|
+
|
|
110
|
+
```text
|
|
111
|
+
import * as api from '@forgezero/agent/ssh-listen';
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## @forgezero/agent/ssh-server
|
|
162
115
|
|
|
163
|
-
|
|
164
|
-
|---|---|
|
|
165
|
-
| `attested` | SEV-SNP guest. The credential is a hardware report, and the platform can refuse a node whose measurement is wrong. |
|
|
166
|
-
| `enrolled` | No SNP. The credential is the enrolment token plus a hybrid Ed25519 + ML-DSA-65 signature. |
|
|
116
|
+
Serve the SSH agent protocol so SSH_AUTH_SOCK points at the vault — two operations implemented, and ADD_IDENTITY refused so no process can inject a key ssh would offer to every host.
|
|
167
117
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
118
|
+
```text
|
|
119
|
+
import * as api from '@forgezero/agent/ssh-server';
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## @forgezero/agent/pipeline
|
|
123
|
+
|
|
124
|
+
CI/CD on the compute: secrets reach the step that named them and nothing else, attestation gates the run, and a required attestation that fails is a refusal rather than a downgrade.
|
|
125
|
+
|
|
126
|
+
```text
|
|
127
|
+
import * as api from '@forgezero/agent/pipeline';
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## @forgezero/agent/agent-heartbeat
|
|
131
|
+
|
|
132
|
+
Signed node health publication with bounded renewal and shutdown withdrawal.
|
|
133
|
+
|
|
134
|
+
```text
|
|
135
|
+
import * as api from '@forgezero/agent/agent-heartbeat';
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## @forgezero/agent/agent-update
|
|
139
|
+
|
|
140
|
+
Verified Agent update planning against the platform release coordinate.
|
|
141
|
+
|
|
142
|
+
```text
|
|
143
|
+
import * as api from '@forgezero/agent/agent-update';
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## @forgezero/agent/agent-update-helper
|
|
147
|
+
|
|
148
|
+
Root-owned fixed update operations with registry origin and integrity validation.
|
|
149
|
+
|
|
150
|
+
```text
|
|
151
|
+
import * as api from '@forgezero/agent/agent-update-helper';
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## @forgezero/agent/bootstrap
|
|
155
|
+
|
|
156
|
+
Typed platform and tenant bootstrap planning, application and status contracts.
|
|
157
|
+
|
|
158
|
+
```text
|
|
159
|
+
import * as api from '@forgezero/agent/bootstrap';
|
|
160
|
+
```
|
|
173
161
|
|
|
174
|
-
|
|
175
|
-
evidence: report acquisition and AMD-rooted measurement verification still have
|
|
176
|
-
to cross the production fleet. Until then the node is honestly `enrolled`; the
|
|
177
|
-
Agent never manufactures an attestation-shaped fallback.
|
|
162
|
+
## @forgezero/agent/capacity-calibration
|
|
178
163
|
|
|
179
|
-
|
|
180
|
-
and signs its one-use hybrid ML-KEM-768 + X25519 response key. Vault replication,
|
|
181
|
-
deployment claims, attestation and metal provisioning responses are AES-256-GCM
|
|
182
|
-
sealed to that request before crossing the edge; there is no Ed25519-only or
|
|
183
|
-
successful plaintext-response downgrade.
|
|
164
|
+
One-time target-local safe-concurrency calibration with private evidence.
|
|
184
165
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
166
|
+
```text
|
|
167
|
+
import * as api from '@forgezero/agent/capacity-calibration';
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## @forgezero/agent/cloudflare-bootstrap
|
|
189
171
|
|
|
190
|
-
|
|
172
|
+
Attended Cloudflare Tunnel, KV and runtime-token bootstrap with private resumable handoff.
|
|
191
173
|
|
|
174
|
+
```text
|
|
175
|
+
import * as api from '@forgezero/agent/cloudflare-bootstrap';
|
|
192
176
|
```
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
177
|
+
|
|
178
|
+
## @forgezero/agent/cloudflare-edge
|
|
179
|
+
|
|
180
|
+
Strict Cloudflare REST operations used by the attended bootstrap controller.
|
|
181
|
+
|
|
182
|
+
```text
|
|
183
|
+
import * as api from '@forgezero/agent/cloudflare-edge';
|
|
196
184
|
```
|
|
197
185
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
node signature over a deployment or whole-project sync request and impersonate
|
|
202
|
-
the Agent without ever extracting its key. Deployment enters through the
|
|
203
|
-
root-only control socket or signed outbound claim path, then the deployment
|
|
204
|
-
manager validates the checked-in definition and submits it to the common keyed
|
|
205
|
-
queue.
|
|
186
|
+
## @forgezero/agent/compute
|
|
187
|
+
|
|
188
|
+
Compute claim, renewal, execution and completion client contracts.
|
|
206
189
|
|
|
207
|
-
|
|
190
|
+
```text
|
|
191
|
+
import * as api from '@forgezero/agent/compute';
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## @forgezero/agent/credential-schema
|
|
195
|
+
|
|
196
|
+
Canonical systemd credential names and validation shared by bootstrap and services.
|
|
197
|
+
|
|
198
|
+
```text
|
|
199
|
+
import * as api from '@forgezero/agent/credential-schema';
|
|
200
|
+
```
|
|
208
201
|
|
|
209
|
-
|
|
210
|
-
Git-owned context and generate the small files each AI product discovers:
|
|
202
|
+
## @forgezero/agent/definition
|
|
211
203
|
|
|
212
|
-
|
|
204
|
+
Validated project deployment definition and workload profiles.
|
|
205
|
+
|
|
206
|
+
```text
|
|
207
|
+
import * as api from '@forgezero/agent/definition';
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## @forgezero/agent/deploy-file
|
|
211
|
+
|
|
212
|
+
Read and validate a checked-out .fz deployment file without executing project input.
|
|
213
|
+
|
|
214
|
+
```text
|
|
215
|
+
import * as api from '@forgezero/agent/deploy-file';
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## @forgezero/agent/metal-bootstrap
|
|
219
|
+
|
|
220
|
+
Physical-metal bootstrap planning, application and status evidence.
|
|
221
|
+
|
|
222
|
+
```text
|
|
223
|
+
import * as api from '@forgezero/agent/metal-bootstrap';
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## @forgezero/agent/metal-provision
|
|
227
|
+
|
|
228
|
+
Validated confidential guest provisioning profiles and cloud-init rendering.
|
|
229
|
+
|
|
230
|
+
```text
|
|
231
|
+
import * as api from '@forgezero/agent/metal-provision';
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## @forgezero/agent/platform-bootstrap-runtime
|
|
235
|
+
|
|
236
|
+
Pure platform bootstrap validation, render and resumable phase-state contracts.
|
|
237
|
+
|
|
238
|
+
```text
|
|
239
|
+
import * as api from '@forgezero/agent/platform-bootstrap-runtime';
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## @forgezero/agent/project-context
|
|
243
|
+
|
|
244
|
+
Project identity and repository context validation for operator and managed runs.
|
|
245
|
+
|
|
246
|
+
```text
|
|
247
|
+
import * as api from '@forgezero/agent/project-context';
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## @forgezero/agent/provisioning-pull
|
|
251
|
+
|
|
252
|
+
Signed provisioning work claim, renewal, execution and acknowledgement.
|
|
253
|
+
|
|
254
|
+
```text
|
|
255
|
+
import * as api from '@forgezero/agent/provisioning-pull';
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## @forgezero/agent/schema/deploy-v2.json
|
|
259
|
+
|
|
260
|
+
Published JSON Schema for deployment definition version 2.
|
|
261
|
+
|
|
262
|
+
```text
|
|
263
|
+
import * as api from '@forgezero/agent/schema/deploy-v2.json';
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## @forgezero/agent/software
|
|
267
|
+
|
|
268
|
+
Exact managed-software inventory, requirement and evidence contracts.
|
|
269
|
+
|
|
270
|
+
```text
|
|
271
|
+
import * as api from '@forgezero/agent/software';
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## @forgezero/agent/software-helper
|
|
275
|
+
|
|
276
|
+
Root-owned fixed installation/update boundary for declared software.
|
|
277
|
+
|
|
278
|
+
```text
|
|
279
|
+
import * as api from '@forgezero/agent/software-helper';
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## @forgezero/agent/ubuntu
|
|
283
|
+
|
|
284
|
+
Ubuntu host validation and deterministic systemd/unit rendering helpers.
|
|
285
|
+
|
|
286
|
+
```text
|
|
287
|
+
import * as api from '@forgezero/agent/ubuntu';
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## fz-agent (replica)
|
|
291
|
+
|
|
292
|
+
The project-scoped vault replica: resident in RAM, never on disk, invalidated by cursor rather than by timer, and refusing a read it can no longer vouch for.
|
|
293
|
+
|
|
294
|
+
```text
|
|
295
|
+
fz-agent (replica) --help
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
## Outbound control boundary
|
|
299
|
+
|
|
300
|
+
The Metal Agent initiates outbound signed HTTPS for orchestration. Applications use the project-scoped local Unix socket; the platform never opens an inbound shell control plane.
|
|
301
|
+
|
|
302
|
+
```text
|
|
303
|
+
metal/compute Agent -> outbound signed HTTPS -> platform API
|
|
304
|
+
application -> local Unix socket -> project-scoped Vault replica
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
## Keep project truth synchronized
|
|
308
|
+
|
|
309
|
+
One versioned ForgeZero manifest generates thin AI-tool adapters and CI rejects drift.
|
|
310
|
+
|
|
311
|
+
```text
|
|
213
312
|
fz project init
|
|
214
|
-
# edit .forgezero/project.json and create its named truth sources
|
|
215
313
|
fz project sync
|
|
216
314
|
fz project check
|
|
217
315
|
```
|
|
218
316
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
`fz
|
|
222
|
-
|
|
223
|
-
|
|
317
|
+
## Install both machine commands
|
|
318
|
+
|
|
319
|
+
One public package installs `fz` and `fz-agent` at the same version. `fz` breaks the bootstrap circle from an operator machine; `fz-agent` runs managed work. Keeping them together prevents a new bootstrap command from provisioning an old daemon protocol.
|
|
320
|
+
|
|
321
|
+
```text
|
|
322
|
+
bun add -g @forgezero/agent
|
|
323
|
+
fz --help
|
|
324
|
+
fz-agent --help
|
|
325
|
+
```
|
|
224
326
|
|
|
225
|
-
##
|
|
327
|
+
## One project memory for every AI tool
|
|
226
328
|
|
|
227
|
-
|
|
228
|
-
code and the browser approves it in the selected tenant realm:
|
|
329
|
+
Conversation memory and dated audits are observations, not architecture. `fz project init` creates one strict, vendor-neutral manifest in Git; `sync` renders only the thin discovery files Claude, Codex, Gemini, Copilot and Cursor expect, and `check` fails if a named truth source disappeared or an adapter was edited independently. Teams can switch tools without restating the project and without maintaining five competing plans.
|
|
229
330
|
|
|
230
|
-
```
|
|
231
|
-
fz
|
|
232
|
-
|
|
233
|
-
fz
|
|
331
|
+
```text
|
|
332
|
+
fz project init # creates .forgezero/project.json
|
|
333
|
+
# edit the manifest and its named truth sources
|
|
334
|
+
fz project sync # generate vendor adapters
|
|
335
|
+
fz project check # CI/handoff drift gate
|
|
234
336
|
```
|
|
235
337
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
338
|
+
## Genesis is browser-first; recovery can remain headless
|
|
339
|
+
|
|
340
|
+
The CLI starts device authorization before the founder exists and opens the one-use invitation created by `fz bootstrap platform`. The browser creates the account, registers and freshly proves its passkey, confirms the account recovery phrase, then explicitly approves the displayed terminal code and continues to custody. The CLI receives only a bounded session. Custody phrases and passkey PRF output remain in the browser. After restart, each participating custodian opens only their own phrase envelope using an owner-only phrase file or stdin and contributes the share from their own authenticated, freshly proved session. No CLI process collects several custodians’ phrases. SSH remains transport and Git interoperability only; it is not a ForgeZero authentication or custody factor. Neither path creates a privileged server bypass.
|
|
341
|
+
|
|
342
|
+
```text
|
|
343
|
+
fz genesis --mode 2-of-3 --api https://api.example --app https://console.example
|
|
344
|
+
fz status
|
|
345
|
+
fz unlock --phrase-file /secure/offline-phrase.txt
|
|
346
|
+
```
|
|
240
347
|
|
|
241
|
-
|
|
242
|
-
the same API and access matrix:
|
|
348
|
+
## Use website operations from a project or an AI agent
|
|
243
349
|
|
|
244
|
-
|
|
350
|
+
Every UI operation is an API operation. `fz ui routes --json` discovers the exact actions allowed by the signed-in account’s current realm, lifecycle stage and grants from the API’s enforced matrix, so the CLI and AI agents carry no copied route list. `fz api` (also `fz ui`) executes authenticated JSON GET, POST, PUT, PATCH and DELETE without requiring a browser visit for ordinary work. Paths are forced onto the signed-in origin, query values are repeatable, bodies can be inline, stdin or a file, and server grants plus fresh-proof rules remain authoritative. `fz project init|sync|check` separately gives AI tools one Git-persisted project memory.
|
|
351
|
+
|
|
352
|
+
```text
|
|
353
|
+
fz ui routes --json
|
|
245
354
|
fz ui routes pipeline
|
|
246
355
|
fz ui get /workspace/pipelines --query projectKey=my-project
|
|
247
|
-
fz api post /workspace/pipelines/status
|
|
248
|
-
--data '{"pipelineKey":"pl_…","enabled":false}'
|
|
356
|
+
fz api post /workspace/pipelines/status --data '{"pipelineKey":"pl_…","enabled":false}'
|
|
249
357
|
generate-request | fz api post /workspace/action --data -
|
|
250
358
|
```
|
|
251
359
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
##
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
```
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
`https://www.forgezero.net/schemas/deploy-v2.json`.
|
|
302
|
-
|
|
303
|
-
Git is the only local-to-live synchronization mechanism. `sync` validates and
|
|
304
|
-
prints that rule; it does not create a second mutable command copy in the API.
|
|
305
|
-
The verified webhook identifies one exact commit, and a successful Agent result
|
|
306
|
-
persists the definition digest so the Applications screen can prove which local
|
|
307
|
-
contract became live.
|
|
308
|
-
|
|
309
|
-
Catalog status is an admission boundary, not a suggestion. `testing` coordinates
|
|
310
|
-
are visible in the development catalog for ForgeZero qualification but cannot be
|
|
311
|
-
selected by any deploy file. A repository cannot promote software by calling
|
|
312
|
-
itself development; only a reviewed catalog change to `active` unlocks it.
|
|
313
|
-
|
|
314
|
-
The daemon owns source checkout and command execution. Bootstrap explicitly
|
|
315
|
-
awaits release one because the API does not exist yet, then the Agent consumes a
|
|
316
|
-
one-use platform enrolment capability. There is no branch watcher. Every normal
|
|
317
|
-
platform or tenant release is one durable API delivery atomically expanded to
|
|
318
|
-
one row for every independently attached compute target. Release-scoped steps
|
|
319
|
-
run on one target elected by stable target ordering, never on a user-declared
|
|
320
|
-
coordinator:
|
|
321
|
-
`pending` is written before dispatch, `running` and a fenced lease before project
|
|
322
|
-
code, and only an awaited successful pipeline writes `deployed`. An expired
|
|
323
|
-
claim can be recovered; its stale token cannot renew or finish.
|
|
324
|
-
|
|
325
|
-
Compute replacement uses the same outbound pattern through
|
|
326
|
-
`@forgezero/agent/migration-pull`: claim one action for this exact compute,
|
|
327
|
-
renew its fencing lease while the awaited function runs, and acknowledge the
|
|
328
|
-
result before accepting more work. The public function accepts the executor as
|
|
329
|
-
an async callback so an embedding Agent can keep privilege and OS policy outside
|
|
330
|
-
the transport. Node evidence is deliberately local-only; it cannot claim
|
|
331
|
-
Agency quorum, replication completion, seed residency, edge exclusion or
|
|
332
|
-
Cloudflare route existence on behalf of the controller.
|
|
333
|
-
|
|
334
|
-
The managed daemon uses `@forgezero/agent/lifecycle-helper` as that executor.
|
|
335
|
-
It is a separate root service behind a group-scoped Unix socket and accepts only
|
|
336
|
-
fixed lifecycle operations. Unit names and loopback health endpoints come from
|
|
337
|
-
a root-owned profile; a signed claim cannot supply a command or path. For a
|
|
338
|
-
cross-network database member, the common installer enrolls the headless WARP
|
|
339
|
-
client from systemd credentials materialized only in `/run`. Readiness requires
|
|
340
|
-
WARP to be connected and the controller-selected private peer IP and database
|
|
341
|
-
port to be reachable. Database traffic is never exposed through a public IP,
|
|
342
|
-
public hostname, or inbound firewall rule.
|
|
343
|
-
|
|
344
|
-
The same package also runs the identity-only Metal Agent. It initiates outbound
|
|
345
|
-
hybrid-signed HTTPS and requires request-bound PQ-sealed responses while pulling
|
|
346
|
-
only claims assigned to its enrolled hostname, then passes
|
|
347
|
-
the fixed claim over a local Unix socket to a narrowly privileged root helper.
|
|
348
|
-
The helper can materialize the audited QEMU profile; it cannot clone a project,
|
|
349
|
-
read Vault data, accept arbitrary commands, or retain tenant credentials. Root
|
|
350
|
-
SSH is an operator-only platform recovery path, not the normal tenant
|
|
351
|
-
dispatch mechanism.
|
|
352
|
-
|
|
353
|
-
New guests also call this same public `fz agent install --apply --enrol` path
|
|
354
|
-
from cloud-init. Metal provisioning does not carry a second handwritten Agent
|
|
355
|
-
unit or deployment runner, so platform and tenant guests cannot drift at that
|
|
356
|
-
foundation boundary.
|
|
357
|
-
|
|
358
|
-
Shutdown has one process-wide deadline. New deployment claims and background
|
|
359
|
-
sync stop first, claimed work drains under its lease fence, and only then do the
|
|
360
|
-
queues and application socket close. Vault/attestation calls or a stale local
|
|
361
|
-
socket cannot consume systemd's longer stop timeout: exceeding the Agent deadline
|
|
362
|
-
is reported and exits non-zero instead of being silently killed midway by PID 1.
|
|
363
|
-
|
|
364
|
-
Repository read authorization is explicit per pipeline: public HTTPS, the
|
|
365
|
-
compute's systemd-sealed SSH deploy key, or a fine-grained HTTPS token selected
|
|
366
|
-
by a project-vault secret name. A signed claim contains the mode and secret name
|
|
367
|
-
only. The agent resolves the value from its scoped memory cache, limits the Git
|
|
368
|
-
header to the repository origin, never writes the token into a command, and
|
|
369
|
-
never exposes it to tenant pipeline steps. These provider-neutral modes are the
|
|
370
|
-
complete contract; a GitHub App is not a missing dependency and would be added
|
|
371
|
-
later only as an explicit provider-specific mode with expiry and revocation tests.
|
|
372
|
-
|
|
373
|
-
An operator may also force a deployment and await the complete result over the
|
|
374
|
-
private control socket:
|
|
375
|
-
|
|
376
|
-
```bash
|
|
377
|
-
fz-agent deploy --revision=<full-40-character-commit> --release-executor
|
|
378
|
-
fz-agent status
|
|
379
|
-
fz-agent pause
|
|
380
|
-
fz-agent pause-key --key=project:production
|
|
381
|
-
fz-agent stop-key --key=project:production # running finishes; pending work is removed
|
|
382
|
-
fz-agent start-key --key=project:production
|
|
383
|
-
fz-agent cancel --id=q_42
|
|
384
|
-
```
|
|
385
|
-
|
|
386
|
-
The node seed and read-only Git private key are loaded with
|
|
387
|
-
`LoadCredentialEncrypted=`. Their encrypted, host-bound blobs persist under
|
|
388
|
-
`/etc/forgezero/creds`; decrypted values exist only in the service's private
|
|
389
|
-
`$CREDENTIALS_DIRECTORY`. Platform bootstrap has no second clone/build path.
|
|
390
|
-
Bootstrap records the forge's SSH host key during the attended access check;
|
|
391
|
-
the daemon uses `StrictHostKeyChecking=yes` and never accepts a new host key by
|
|
392
|
-
itself.
|
|
393
|
-
|
|
394
|
-
Full documentation: **https://www.forgezero.net/docs/agent**
|
|
395
|
-
|
|
396
|
-
## Licence
|
|
397
|
-
|
|
398
|
-
MIT. Part of [ForgeZero](https://www.forgezero.net) — secrets, attested compute and
|
|
399
|
-
deploys.
|
|
360
|
+
## What changes for an application
|
|
361
|
+
|
|
362
|
+
Nothing. With no agent, this needs FORGEZERO_API_KEY in the environment. With the agent, it does not — and the key that would have been on the box does not exist. `@forgezero/vault` prefers the socket automatically.
|
|
363
|
+
|
|
364
|
+
```text
|
|
365
|
+
import { ForgeZero } from '@forgezero/vault';
|
|
366
|
+
|
|
367
|
+
const fz = new ForgeZero({ project: 'altpilot', environment: 'production' });
|
|
368
|
+
await fz.get('STRIPE_KEY');
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
## A local copy, not a cache
|
|
372
|
+
|
|
373
|
+
The agent holds the whole assigned project across all of its environments, not just what has already been read. Each application still supplies its environment and cannot cross the enrolled project boundary. That is the difference between surviving an outage and not: a read-through cache lacks the never-before-read value precisely when the platform is unreachable. The cost is that a compromised guest exposes everything in the enrolled project rather than only what was read — bounded by the project and by SEV-SNP keeping the host out of guest memory.
|
|
374
|
+
|
|
375
|
+
## Local access is explicit Unix membership
|
|
376
|
+
|
|
377
|
+
The socket is mode 0660 in the dedicated forgezero-vault group. A service account must be deliberately added to that group before it can read the project replica; unrelated local users and the credential-free deployment runner cannot connect. Mode 0600 would make the advertised app integration unusable, while a world-readable socket would hand the vault to every process on the guest.
|
|
378
|
+
|
|
379
|
+
## Never on disk
|
|
380
|
+
|
|
381
|
+
A cache file would hand an attacker with filesystem access every secret this guest has ever held, which is precisely the artefact this design exists to remove. A restart re-fetches. There is no version of "just persist it, it is encrypted" that survives the key also being on the box.
|
|
382
|
+
|
|
383
|
+
## Invalidated by cursor, and refused when stale
|
|
384
|
+
|
|
385
|
+
A TTL alone means a rotated secret keeps working for the length of the TTL — the window rotation exists to close. The agent polls a change cursor and drops what moved, so a rotation propagates regardless of TTL. And if sync has not succeeded within the staleness bound, a read is refused rather than served: an application that receives a revoked credential and succeeds with it is worse off than one that receives an error, because the error is visible.
|
|
386
|
+
|
|
387
|
+
## Two postures, decided by the hardware
|
|
388
|
+
|
|
389
|
+
An SNP guest can produce an attestation report and the platform can refuse a node whose measurement is wrong. Anything else authenticates with its enrolment token and a hybrid Ed25519 + ML-DSA-65 signature. Both are real: enrolled is still strictly better than an API key in the application, because the key never leaves the agent, rotation reaches every process, and the socket is filesystem-scoped.
|
|
390
|
+
|
|
391
|
+
```text
|
|
392
|
+
attested /dev/sev-guest present -> hardware report
|
|
393
|
+
enrolled no SNP device -> enrolment token + hybrid signature
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
## The app socket cannot impersonate the node
|
|
397
|
+
|
|
398
|
+
The group-scoped application socket exposes only replica get, held and sync operations. Node identity, hybrid signing and attestation stay inside the Agent's outbound clients. Every Agent call requires HTTPS outside loopback, signs a one-use hybrid ML-KEM-768 + X25519 recipient and refuses a successful response that is not sealed back to that request. A process allowed to read one environment therefore cannot ask the Agent to sign a deployment, heartbeat or whole-project replication request and act as the node.
|
|
399
|
+
|
|
400
|
+
```text
|
|
401
|
+
get one secret in the selected environment
|
|
402
|
+
sync invalidate rotated values
|
|
403
|
+
held names held in the selected environment
|
|
404
|
+
|
|
405
|
+
identity/sign/attest refused on the application socket
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
Full rendered documentation: https://www.forgezero.net/docs/agent
|