Skip to content

Commit 96f519f

Browse files
authored
Add guarded Agent Machine and Office execution
Adds explicit --execute --policy-ok guarded local execution for Agent Machine directory materialization and Office text generation/conversion evidence flows.
1 parent 43828e3 commit 96f519f

6 files changed

Lines changed: 655 additions & 66 deletions

File tree

README.md

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ It should contain:
1919
- guardrail/eval/evidence helpers;
2020
- agent sandbox/run helpers;
2121
- Agent Machine local mount and secure host-interface helpers;
22-
- Office Plane dry-run, inspection, and evidence helpers;
22+
- Office Plane dry-run, guarded execution, inspection, and evidence helpers;
2323
- fingerprint and proof bundle tools;
2424
- local-to-mesh registration helpers;
2525
- release/operator install scripts.
@@ -38,7 +38,7 @@ It should not contain:
3838

3939
## sourceosctl CLI
4040

41-
`sourceosctl` is the read-only/dry-run CLI surface for SourceOS developer and AI operator workflows.
41+
`sourceosctl` is the guarded CLI surface for SourceOS developer and AI operator workflows. Commands are read-only or dry-run by default. Narrow local mutations require explicit `--execute --policy-ok` and emit evidence.
4242

4343
### Usage
4444

@@ -62,12 +62,15 @@ sourceosctl [--version] <command> [<subcommand>] [options]
6262
| `sourceosctl agents sandbox plan --dry-run` | Print agent sandbox plan (dry-run only) |
6363
| `sourceosctl agent-machine mounts plan` | Render Agent Machine local mount plan for dev/docs/downloads roots (dry-run) |
6464
| `sourceosctl agent-machine mounts init --dry-run` | Render mount initialization plan; no directories or mounts are created |
65+
| `sourceosctl agent-machine mounts init --execute --policy-ok` | Create only scoped local output/download directories and emit AgentMachineMountEvidence |
6566
| `sourceosctl agent-machine mounts inspect [--include-downloads]` | Inspect default/local Agent Machine mount posture |
6667
| `sourceosctl agent-machine mounts evidence inspect <path>` | Inspect Agent Machine mount evidence JSON (read-only) |
6768
| `sourceosctl office doctor` | Inspect local Office Plane backend availability, including LibreOffice detection |
6869
| `sourceosctl office plan` | Render an OfficeArtifact-compatible workroom artifact plan |
6970
| `sourceosctl office generate --dry-run` | Render an Office generation plan without writing files |
71+
| `sourceosctl office generate --execute --policy-ok --format md|txt|json` | Write a guarded text/Markdown/JSON artifact and emit OfficeArtifactEvidence |
7072
| `sourceosctl office convert <path> --to <format> --dry-run` | Render a LibreOffice-style conversion plan without writing files |
73+
| `sourceosctl office convert <path> --to <format> --execute --policy-ok` | Run guarded local LibreOffice conversion and emit OfficeArtifactEvidence |
7174
| `sourceosctl office inspect <path>` | Inspect a local office artifact file and hash it |
7275
| `sourceosctl office evidence inspect <path>` | Inspect Office Plane evidence JSON (read-only) |
7376

@@ -87,16 +90,19 @@ python3 bin/sourceosctl ai labs list
8790
python3 bin/sourceosctl agents sandbox plan --dry-run
8891
python3 bin/sourceosctl agent-machine mounts plan
8992
python3 bin/sourceosctl agent-machine mounts init --dry-run
93+
python3 bin/sourceosctl agent-machine mounts init --execute --policy-ok --evidence-out ./mount-evidence.json
9094
python3 bin/sourceosctl agent-machine mounts inspect --include-downloads
9195
python3 bin/sourceosctl office doctor
9296
python3 bin/sourceosctl office plan --artifact-type slide-deck --format pptx --title "Demo Deck"
9397
python3 bin/sourceosctl office generate --dry-run --artifact-type document --format docx --title "Demo Report"
98+
python3 bin/sourceosctl office generate --execute --policy-ok --artifact-type document --format md --title "Demo Report" --evidence-out ./office-evidence.json
9499
python3 bin/sourceosctl office convert ./example.docx --to pdf --dry-run
100+
python3 bin/sourceosctl office convert ./example.docx --to pdf --execute --policy-ok --evidence-out ./office-convert-evidence.json
95101
```
96102

97103
### Agent Machine local mount defaults
98104

99-
The first Agent Machine mount slice is contract-first and dry-run only. It aligns with the SourceOS contracts in `SourceOS-Linux/sourceos-spec`:
105+
The first Agent Machine mount slice aligns with the SourceOS contracts in `SourceOS-Linux/sourceos-spec`:
100106

101107
- `AgentMachineLocalDataPlane`
102108
- `AgentMachineMountPolicy`
@@ -107,16 +113,18 @@ Default host roots:
107113
| Purpose | Host path | Agent path | Posture |
108114
| --- | --- | --- | --- |
109115
| Code / repositories | `~/dev` | `/workspace/dev` | read/write; explicit workspace root |
110-
| Generated documents / reports | `~/Documents/SourceOS/agent-output` | `/workspace/output` | read/write; created only by future explicit mutation |
116+
| Generated documents / reports | `~/Documents/SourceOS/agent-output` | `/workspace/output` | read/write; created only by explicit guarded materialization |
111117
| Browser downloads | `~/Downloads/SourceOS/agent-downloads` | `/workspace/downloads` | browser read/write; agent read-only |
112118

113119
The CLI does **not** mount `$HOME` wholesale and does **not** expose `.ssh`, `.gnupg`, browser profiles, keychains, cloud credential directories, token stores, or password stores by default.
114120

121+
Guarded materialization creates only the declared `createIfMissing` folders. It does not create Podman machines, Podman bind mounts, containers, or background services.
122+
115123
TopoLVM is treated as a Linux cluster-local backend profile for the same logical mount contract. It is not used for macOS/APFS local mode and it is not represented as cross-node shared storage.
116124

117125
### Office Plane local defaults
118126

119-
The first Office Plane slice is dry-run/read-only. It aligns with `SocioProphet/prophet-workspace`:
127+
The Office Plane aligns with `SocioProphet/prophet-workspace`:
120128

121129
- `ProfessionalWorkroom`
122130
- `OfficeArtifact`
@@ -137,11 +145,17 @@ Backends are modeled as an abstraction:
137145
- Microsoft Graph / Office 365 and Google Workspace: compatibility adapters, not core authority.
138146
- SourceOS-native: future native document surfaces.
139147

140-
The CLI does not create, convert, or modify files yet. It renders plans and inspects artifacts/evidence. Email sending and external publishing remain policy-gated side effects and are not enabled here.
148+
Guarded Office execution is intentionally narrow:
149+
150+
- `office generate --execute --policy-ok` currently writes only `txt`, `md`, or `json` artifacts.
151+
- Office binary generation (`docx`, `xlsx`, `pptx`, `odt`, `ods`, `odp`) remains disabled until template/render backends are hardened.
152+
- `office convert --execute --policy-ok` uses local LibreOffice/`soffice` when available.
153+
- All guarded Office execution emits or writes `OfficeArtifactEvidence`.
154+
- Email sending, external publishing, and calendar modification remain policy-gated side effects and are not enabled here.
141155

142156
### Design constraints
143157

144-
All commands in the current surface are **read-only or dry-run**. No mutating command is implemented. Commands that would mutate host state are explicitly rejected at runtime.
158+
All mutating commands require `--execute --policy-ok`. Commands that would mutate host state without both flags are rejected at runtime.
145159

146160
## First milestone
147161

sourceosctl/cli.py

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,9 @@ def add_mount_common(p):
163163
add_mount_common(mounts_plan_p)
164164
mounts_plan_p.set_defaults(func=agent_machine.mounts_plan)
165165

166-
mounts_init_p = mounts_sub.add_parser("init", help="Render mount initialization plan (dry-run only)")
166+
mounts_init_p = mounts_sub.add_parser(
167+
"init", help="Render or execute guarded local directory materialization"
168+
)
167169
add_mount_common(mounts_init_p)
168170
mounts_init_p.add_argument(
169171
"--dry-run",
@@ -172,6 +174,23 @@ def add_mount_common(p):
172174
dest="dry_run",
173175
help="Print plan without creating directories or mounts (default: True)",
174176
)
177+
mounts_init_p.add_argument(
178+
"--execute",
179+
action="store_true",
180+
default=False,
181+
help="Create only explicitly-scoped output/download directories; does not create Podman mounts",
182+
)
183+
mounts_init_p.add_argument(
184+
"--policy-ok",
185+
action="store_true",
186+
default=False,
187+
help="Confirm Policy Fabric/operator approval for guarded local materialization",
188+
)
189+
mounts_init_p.add_argument(
190+
"--evidence-out",
191+
default=None,
192+
help="Optional path to write AgentMachineMountEvidence JSON",
193+
)
175194
mounts_init_p.set_defaults(func=agent_machine.mounts_init)
176195

177196
mounts_inspect_p = mounts_sub.add_parser("inspect", help="Inspect default/local mount posture")
@@ -236,7 +255,9 @@ def add_office_common(p):
236255
add_office_common(office_plan_p)
237256
office_plan_p.set_defaults(func=office.plan)
238257

239-
office_generate_p = office_sub.add_parser("generate", help="Render Office generation plan (dry-run only)")
258+
office_generate_p = office_sub.add_parser(
259+
"generate", help="Render or execute guarded Office text/Markdown/JSON generation"
260+
)
240261
add_office_common(office_generate_p)
241262
office_generate_p.add_argument("--template", default=None, help="Optional template reference")
242263
office_generate_p.add_argument("--prompt-ref", default=None, help="Optional prompt/context reference")
@@ -248,9 +269,28 @@ def add_office_common(p):
248269
dest="dry_run",
249270
help="Print generation plan without writing files (default: True)",
250271
)
272+
office_generate_p.add_argument(
273+
"--execute",
274+
action="store_true",
275+
default=False,
276+
help="Write txt/md/json artifacts only; Office binary generation remains disabled",
277+
)
278+
office_generate_p.add_argument(
279+
"--policy-ok",
280+
action="store_true",
281+
default=False,
282+
help="Confirm Policy Fabric/operator approval for guarded Office generation",
283+
)
284+
office_generate_p.add_argument(
285+
"--evidence-out",
286+
default=None,
287+
help="Optional path to write OfficeArtifactEvidence JSON",
288+
)
251289
office_generate_p.set_defaults(func=office.generate)
252290

253-
office_convert_p = office_sub.add_parser("convert", help="Render Office conversion plan (dry-run only)")
291+
office_convert_p = office_sub.add_parser(
292+
"convert", help="Render or execute guarded LibreOffice conversion"
293+
)
254294
office_convert_p.add_argument("input", help="Input Office artifact path")
255295
office_convert_p.add_argument("--to", required=True, help="Target format, e.g. pdf, docx, pptx")
256296
add_office_common(office_convert_p)
@@ -261,6 +301,23 @@ def add_office_common(p):
261301
dest="dry_run",
262302
help="Print conversion plan without writing files (default: True)",
263303
)
304+
office_convert_p.add_argument(
305+
"--execute",
306+
action="store_true",
307+
default=False,
308+
help="Run LibreOffice conversion under guarded local execution",
309+
)
310+
office_convert_p.add_argument(
311+
"--policy-ok",
312+
action="store_true",
313+
default=False,
314+
help="Confirm Policy Fabric/operator approval for guarded Office conversion",
315+
)
316+
office_convert_p.add_argument(
317+
"--evidence-out",
318+
default=None,
319+
help="Optional path to write OfficeArtifactEvidence JSON",
320+
)
264321
office_convert_p.set_defaults(func=office.convert)
265322

266323
office_inspect_p = office_sub.add_parser("inspect", help="Inspect an Office artifact file")

0 commit comments

Comments
 (0)