humanish 0.0.1 → 0.15.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/AGENTS.md +77 -0
- package/CONTRIBUTING.md +39 -0
- package/LICENSE +21 -0
- package/README.md +435 -8
- package/SECURITY.md +34 -0
- package/dist/actor-contract.d.ts +107 -0
- package/dist/actor-contract.js +286 -0
- package/dist/actor-contract.js.map +1 -0
- package/dist/actor-registry.d.ts +73 -0
- package/dist/actor-registry.js +93 -0
- package/dist/actor-registry.js.map +1 -0
- package/dist/adapter-extension.d.ts +54 -0
- package/dist/adapter-extension.js +214 -0
- package/dist/adapter-extension.js.map +1 -0
- package/dist/argv.d.ts +1 -0
- package/dist/argv.js +8 -0
- package/dist/argv.js.map +1 -0
- package/dist/artifact-reference.d.ts +22 -0
- package/dist/artifact-reference.js +47 -0
- package/dist/artifact-reference.js.map +1 -0
- package/dist/browser-evidence-hygiene.d.ts +7 -0
- package/dist/browser-evidence-hygiene.js +40 -0
- package/dist/browser-evidence-hygiene.js.map +1 -0
- package/dist/claude-agent-sdk.d.ts +94 -0
- package/dist/claude-agent-sdk.js +356 -0
- package/dist/claude-agent-sdk.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +5 -0
- package/dist/cli.js.map +1 -0
- package/dist/codex-app-server-ui.d.ts +39 -0
- package/dist/codex-app-server-ui.js +327 -0
- package/dist/codex-app-server-ui.js.map +1 -0
- package/dist/codex-app-server.d.ts +141 -0
- package/dist/codex-app-server.js +747 -0
- package/dist/codex-app-server.js.map +1 -0
- package/dist/command-failure.d.ts +29 -0
- package/dist/command-failure.js +54 -0
- package/dist/command-failure.js.map +1 -0
- package/dist/computer-use-actor.d.ts +52 -0
- package/dist/computer-use-actor.js +48 -0
- package/dist/computer-use-actor.js.map +1 -0
- package/dist/computer-use.d.ts +232 -0
- package/dist/computer-use.js +615 -0
- package/dist/computer-use.js.map +1 -0
- package/dist/concurrency.d.ts +1 -0
- package/dist/concurrency.js +27 -0
- package/dist/concurrency.js.map +1 -0
- package/dist/concurrent-shared-world-lab.d.ts +115 -0
- package/dist/concurrent-shared-world-lab.js +1092 -0
- package/dist/concurrent-shared-world-lab.js.map +1 -0
- package/dist/core/git-state.d.ts +31 -0
- package/dist/core/git-state.js +142 -0
- package/dist/core/git-state.js.map +1 -0
- package/dist/core/index.d.ts +4 -0
- package/dist/core/index.js +3 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/run-primitives.d.ts +66 -0
- package/dist/core/run-primitives.js +120 -0
- package/dist/core/run-primitives.js.map +1 -0
- package/dist/cua-actor-lab.d.ts +620 -0
- package/dist/cua-actor-lab.js +2834 -0
- package/dist/cua-actor-lab.js.map +1 -0
- package/dist/device-presets.d.ts +67 -0
- package/dist/device-presets.js +50 -0
- package/dist/device-presets.js.map +1 -0
- package/dist/e2b-desktop-executor.d.ts +101 -0
- package/dist/e2b-desktop-executor.js +309 -0
- package/dist/e2b-desktop-executor.js.map +1 -0
- package/dist/e2b-desktop-launch.d.ts +144 -0
- package/dist/e2b-desktop-launch.js +59 -0
- package/dist/e2b-desktop-launch.js.map +1 -0
- package/dist/e2b-detached.d.ts +53 -0
- package/dist/e2b-detached.js +130 -0
- package/dist/e2b-detached.js.map +1 -0
- package/dist/e2b-terminal-lab.d.ts +345 -0
- package/dist/e2b-terminal-lab.js +1467 -0
- package/dist/e2b-terminal-lab.js.map +1 -0
- package/dist/env-file.d.ts +14 -0
- package/dist/env-file.js +108 -0
- package/dist/env-file.js.map +1 -0
- package/dist/feedback.d.ts +51 -0
- package/dist/feedback.js +313 -0
- package/dist/feedback.js.map +1 -0
- package/dist/image-evidence.d.ts +2 -0
- package/dist/image-evidence.js +33 -0
- package/dist/image-evidence.js.map +1 -0
- package/dist/index.d.ts +63 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/init-templates.d.ts +12 -0
- package/dist/init-templates.js +369 -0
- package/dist/init-templates.js.map +1 -0
- package/dist/init.d.ts +26 -0
- package/dist/init.js +343 -0
- package/dist/init.js.map +1 -0
- package/dist/lab-app-runner.d.ts +78 -0
- package/dist/lab-app-runner.js +403 -0
- package/dist/lab-app-runner.js.map +1 -0
- package/dist/lab-config.d.ts +578 -0
- package/dist/lab-config.js +1751 -0
- package/dist/lab-config.js.map +1 -0
- package/dist/lab-engine.d.ts +77 -0
- package/dist/lab-engine.js +216 -0
- package/dist/lab-engine.js.map +1 -0
- package/dist/lab-preflight.d.ts +67 -0
- package/dist/lab-preflight.js +385 -0
- package/dist/lab-preflight.js.map +1 -0
- package/dist/labs.d.ts +53 -0
- package/dist/labs.js +176 -0
- package/dist/labs.js.map +1 -0
- package/dist/observer-assets.d.ts +2 -0
- package/dist/observer-assets.js +2630 -0
- package/dist/observer-assets.js.map +1 -0
- package/dist/observer-data.d.ts +63 -0
- package/dist/observer-data.js +145 -0
- package/dist/observer-data.js.map +1 -0
- package/dist/observer-static.d.ts +39 -0
- package/dist/observer-static.js +192 -0
- package/dist/observer-static.js.map +1 -0
- package/dist/observer.d.ts +46 -0
- package/dist/observer.js +353 -0
- package/dist/observer.js.map +1 -0
- package/dist/openai-responses-cu.d.ts +113 -0
- package/dist/openai-responses-cu.js +531 -0
- package/dist/openai-responses-cu.js.map +1 -0
- package/dist/oss-lab.d.ts +52 -0
- package/dist/oss-lab.js +299 -0
- package/dist/oss-lab.js.map +1 -0
- package/dist/oss-meta-lab-scoring.d.ts +15 -0
- package/dist/oss-meta-lab-scoring.js +145 -0
- package/dist/oss-meta-lab-scoring.js.map +1 -0
- package/dist/oss-meta-lab.d.ts +279 -0
- package/dist/oss-meta-lab.js +4889 -0
- package/dist/oss-meta-lab.js.map +1 -0
- package/dist/oss-remote-telemetry.d.ts +77 -0
- package/dist/oss-remote-telemetry.js +403 -0
- package/dist/oss-remote-telemetry.js.map +1 -0
- package/dist/persona.d.ts +35 -0
- package/dist/persona.js +133 -0
- package/dist/persona.js.map +1 -0
- package/dist/pi-agent-core.d.ts +77 -0
- package/dist/pi-agent-core.js +203 -0
- package/dist/pi-agent-core.js.map +1 -0
- package/dist/program.d.ts +54 -0
- package/dist/program.js +2347 -0
- package/dist/program.js.map +1 -0
- package/dist/redaction.d.ts +90 -0
- package/dist/redaction.js +292 -0
- package/dist/redaction.js.map +1 -0
- package/dist/run.d.ts +784 -0
- package/dist/run.js +4555 -0
- package/dist/run.js.map +1 -0
- package/dist/scripted-browser-actor.d.ts +294 -0
- package/dist/scripted-browser-actor.js +1286 -0
- package/dist/scripted-browser-actor.js.map +1 -0
- package/dist/scripted-browser-lab.d.ts +107 -0
- package/dist/scripted-browser-lab.js +738 -0
- package/dist/scripted-browser-lab.js.map +1 -0
- package/dist/shared-world-lab.d.ts +208 -0
- package/dist/shared-world-lab.js +1048 -0
- package/dist/shared-world-lab.js.map +1 -0
- package/dist/source-archive.d.ts +82 -0
- package/dist/source-archive.js +365 -0
- package/dist/source-archive.js.map +1 -0
- package/dist/stop-conditions.d.ts +26 -0
- package/dist/stop-conditions.js +66 -0
- package/dist/stop-conditions.js.map +1 -0
- package/dist/terminal-agent-actor.d.ts +36 -0
- package/dist/terminal-agent-actor.js +23 -0
- package/dist/terminal-agent-actor.js.map +1 -0
- package/docs/architecture/actor-contract.md +431 -0
- package/docs/architecture/github-feedback-loop.md +189 -0
- package/docs/architecture/local-codex-tui-actor.md +213 -0
- package/docs/architecture/observer.md +118 -0
- package/docs/architecture/oss-lab-poc.md +242 -0
- package/docs/architecture/project-layout.md +166 -0
- package/docs/architecture/state-driven-executor.md +203 -0
- package/docs/architecture/terminal-product-lane.md +148 -0
- package/docs/contracts/adapter-fixtures.md +80 -0
- package/docs/contracts/core.md +71 -0
- package/docs/contracts/feedback.md +145 -0
- package/docs/contracts/policy.md +305 -0
- package/docs/contracts/run-bundle.md +358 -0
- package/docs/contracts/schemas.md +984 -0
- package/docs/goals/current.md +409 -0
- package/docs/principles/invariants-and-defaults.md +135 -0
- package/docs/principles/self-driving-harness.md +129 -0
- package/docs/product/open-source-install-experience.md +229 -0
- package/docs/ramp/README.md +200 -0
- package/docs/release/open-source-readiness.md +208 -0
- package/docs/release/public-readiness-standard.md +205 -0
- package/docs/roadmap/world-class-open-source-v0.md +311 -0
- package/package.json +102 -8
- package/skills/humanish/SKILL.md +244 -0
- package/skills/humanish/agents/openai.yaml +7 -0
- package/index.js +0 -1
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
# Current Goals
|
|
2
|
+
|
|
3
|
+
Status date: 2026-07-08 (rev 13)
|
|
4
|
+
|
|
5
|
+
This page is the current public-safe operating goal for `humanish`. Keep it
|
|
6
|
+
short enough to reread before a coding session and concrete enough that future
|
|
7
|
+
agents can choose useful work without private context.
|
|
8
|
+
|
|
9
|
+
## North Star
|
|
10
|
+
|
|
11
|
+
Humanish should be the open-source CLI that lets a maintainer ask:
|
|
12
|
+
|
|
13
|
+
> What happens when realistic synthetic personas try to use this app, CLI, or
|
|
14
|
+
> agent-facing workflow?
|
|
15
|
+
|
|
16
|
+
The answer should be observable, verifiable, public-safe, and easy to turn into
|
|
17
|
+
actionable feedback.
|
|
18
|
+
|
|
19
|
+
## Definition Of Awesome
|
|
20
|
+
|
|
21
|
+
A world-class Humanish run should eventually provide:
|
|
22
|
+
|
|
23
|
+
- one human-friendly command that starts simulations and opens Observer;
|
|
24
|
+
- multiple synthetic personas with different goals, patience, and skill levels;
|
|
25
|
+
- UI, CLI, TUI, and code-agent lanes in one mission-control Observer;
|
|
26
|
+
- real evidence: screenshots, terminal transcripts, lifecycle events, traces,
|
|
27
|
+
filesystem setup-quality snapshots, artifacts, and verifier output;
|
|
28
|
+
- clear pass, fail, blocked, and gap states;
|
|
29
|
+
- public-safe feedback issue drafts that do not mutate GitHub by default;
|
|
30
|
+
- first-class `.yaml` lab manifests for reusable simulation runs;
|
|
31
|
+
- adapter contracts that let projects customize behavior without forking core;
|
|
32
|
+
- release gates that prevent PII, PHI, secrets, private artifacts, and stale
|
|
33
|
+
internal residue from reaching the public repo or package.
|
|
34
|
+
|
|
35
|
+
## Current Objective
|
|
36
|
+
|
|
37
|
+
Make the public package and repo credible enough that an external maintainer can:
|
|
38
|
+
|
|
39
|
+
1. install the skill;
|
|
40
|
+
2. install `humanish`;
|
|
41
|
+
3. run `humanish init`;
|
|
42
|
+
4. run `humanish watch`;
|
|
43
|
+
5. run `humanish watch first-run` or another lab manifest;
|
|
44
|
+
6. inspect Observer evidence;
|
|
45
|
+
7. verify the bundle;
|
|
46
|
+
8. produce a public-safe feedback draft;
|
|
47
|
+
9. understand the next live-adapter path without reading chat history.
|
|
48
|
+
|
|
49
|
+
## Near-Term Goals
|
|
50
|
+
|
|
51
|
+
### 1. Public Readiness
|
|
52
|
+
|
|
53
|
+
Keep the repository clean and public-safe.
|
|
54
|
+
|
|
55
|
+
Acceptance:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pnpm release:check
|
|
59
|
+
git diff --check
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Fresh clone release checks should pass before public visibility changes.
|
|
63
|
+
|
|
64
|
+
### 2. Future-Agent Ramp
|
|
65
|
+
|
|
66
|
+
Maintain a durable ramp that tells future contributors and coding agents where
|
|
67
|
+
to start, what exists, what remains, and what proof is required.
|
|
68
|
+
|
|
69
|
+
Acceptance:
|
|
70
|
+
|
|
71
|
+
- [`docs/ramp/README.md`](../ramp/README.md) stays current;
|
|
72
|
+
- this page stays current;
|
|
73
|
+
- README links both;
|
|
74
|
+
- release package includes both docs directories.
|
|
75
|
+
|
|
76
|
+
### 3. Fresh-Agent Install Proof
|
|
77
|
+
|
|
78
|
+
Prove the skill and package setup flow from a disposable target app with no chat
|
|
79
|
+
context.
|
|
80
|
+
|
|
81
|
+
Target proof:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
npm i -D humanish
|
|
85
|
+
npx humanish init --yes
|
|
86
|
+
npx humanish watch --json --no-open
|
|
87
|
+
npx humanish verify --run latest --json
|
|
88
|
+
npx humanish feedback issue --run latest --repo owner/repo --format markdown
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
The proof target must use synthetic personas and no real user data.
|
|
92
|
+
|
|
93
|
+
### 4. Live Browser Adapter
|
|
94
|
+
|
|
95
|
+
Graduate from synthetic UI lanes to a real browser journey against a local app.
|
|
96
|
+
|
|
97
|
+
Minimum acceptance:
|
|
98
|
+
|
|
99
|
+
- local app target detection;
|
|
100
|
+
- browser launch;
|
|
101
|
+
- route/state capture;
|
|
102
|
+
- screenshot artifact;
|
|
103
|
+
- run bundle references screenshot evidence;
|
|
104
|
+
- Observer renders the screenshot;
|
|
105
|
+
- `verify` fails closed if required evidence is missing;
|
|
106
|
+
- bounded desktop/mobile two-step browser persona proof with per-step traces and
|
|
107
|
+
screenshots. `done`
|
|
108
|
+
- LLM-driven browser lane: the registered `openai-computer-use` actor dispatches
|
|
109
|
+
from a lab config (`subject.source: app-url`, loopback entry only) into a hosted
|
|
110
|
+
E2B desktop, fills the provider-neutral `stream.actor` trace seam, and persists
|
|
111
|
+
a verified redacted bundle (0.3.0 registered the actor; 0.4.0 made
|
|
112
|
+
`actors[].type` a real dispatch key). `done`
|
|
113
|
+
- Clone subject provider: `subject.source: clone` + `serve` clones a repo INTO the
|
|
114
|
+
sandbox, installs/builds/starts it from config, probes readiness, and records
|
|
115
|
+
provenance (repo, commit, env names) in the bundle — config-only computer-use
|
|
116
|
+
labs against real apps (0.5.0; see `docs/goals/proof-roadmap/goal.md` —
|
|
117
|
+
repo-only, not shipped in the npm package — and
|
|
118
|
+
`docs/principles/invariants-and-defaults.md`, which ships in the package).
|
|
119
|
+
`done`
|
|
120
|
+
- De-paranoia (0.6.0): the redaction redesign + demoted defaults. Screenshots are
|
|
121
|
+
full-fidelity by default (redaction binds the publish boundary, not capture —
|
|
122
|
+
`policies.redactScreenshots` opts back in); `policies.allowPublicTargets` lets an
|
|
123
|
+
owner drive a declared deployment/preview; `subject.clone.keep` is honored on
|
|
124
|
+
failure for debugging; `serve.installTimeoutMs`/`buildTimeoutMs` are configurable
|
|
125
|
+
for monorepo-scale builds. Doctrine updated with the capture-vs-publish rule. This
|
|
126
|
+
re-sequences the proof roadmap: a redaction redesign and an overridable
|
|
127
|
+
public-target policy are prerequisites for any decision-grade depth evidence, so
|
|
128
|
+
they land BEFORE the consumer-web-app / agent-skill depth phases. `done`
|
|
129
|
+
- Device presets (0.6.1): viewport/device is a real dimension, with LITERAL values copied
|
|
130
|
+
from the in-house sims (mobile 414×896 … wide 1920×1080; default `desktop` 1440×950) —
|
|
131
|
+
not guessed. `execution.desktop.device` picks the per-run viewport; the guessed 1280×800
|
|
132
|
+
is gone. Honest fidelity: on the E2B route only width/height render (real mobile *layout*)
|
|
133
|
+
+ the model is told its device, matching the sims' organic lanes; true touch/DPR/UA needs
|
|
134
|
+
the CDP actor. Per-*persona* device (N×devices) rides fan-out. `done`
|
|
135
|
+
|
|
136
|
+
### 5. Live Terminal And Codex Lanes
|
|
137
|
+
|
|
138
|
+
Make local PTY and Codex-style lanes reliable enough that Observer can show
|
|
139
|
+
running, passed, failed, blocked, and timed-out states without human inference.
|
|
140
|
+
|
|
141
|
+
Minimum acceptance:
|
|
142
|
+
|
|
143
|
+
- sanitized transcript persistence;
|
|
144
|
+
- explicit completion reason;
|
|
145
|
+
- verifier checks redaction status;
|
|
146
|
+
- Observer polling reflects lane completion;
|
|
147
|
+
- no raw private transcript or credential values.
|
|
148
|
+
|
|
149
|
+
Terminal-product real-agent lane (0.8.0; depth-axis layer 6, so an adopter can delete a
|
|
150
|
+
bespoke real-agent sim for humanish + a thin adapter — see
|
|
151
|
+
`docs/goals/terminal-product-lane/goal.md`):
|
|
152
|
+
|
|
153
|
+
- `subject.source: terminal-product` + `execution.target: e2b-terminal` + the registered
|
|
154
|
+
`codex-exec` terminal actor route a config to a real Codex agent studying a product from
|
|
155
|
+
public surfaces inside an E2B shell. `done`
|
|
156
|
+
- The credential-placement inversion is enforced by construction AND by verifier: the runtime
|
|
157
|
+
key is injected ONLY command-scoped into the `codex` invocation, never sandbox-global; a
|
|
158
|
+
deny-by-default allowlist excludes GitHub/payment/deploy/db creds; metadata is a positive
|
|
159
|
+
allowlist; stdin is disabled with an always-present interventions ledger; cleanup is proven
|
|
160
|
+
or the run fails closed. `done`
|
|
161
|
+
- Cost/no-spend ledger with the null-vs-known-zero-vs-absent discipline (unknowns are `null`,
|
|
162
|
+
never guessed); the no-spend proof is DERIVED from the ledger, never asserted; `maxUsd`/
|
|
163
|
+
`maxJobs`/`maxMinutes` caps enforced fail-closed. `done`
|
|
164
|
+
- Product-adapter extension seam: exported contract types + a scorer/feedback DI hook +
|
|
165
|
+
adapter-namespaced product nouns, so an adopter attaches scoring/feedback as a thin
|
|
166
|
+
in-repo extension without forking core. `done`
|
|
167
|
+
- Cleanup is proven BY EXACT CREATED ID: `Sandbox.kill(id)`, confirmed further by
|
|
168
|
+
`Sandbox.getInfo(id)` where the SDK exposes it, and humanish never calls `Sandbox.list`. A live
|
|
169
|
+
rung never needs a dedicated or isolated E2B key; the SAME shared operator key used everywhere
|
|
170
|
+
else in this repo is safe, because humanish only ever reaches a sandbox it created (see
|
|
171
|
+
"The placement rule" corollary in `docs/principles/invariants-and-defaults.md`).
|
|
172
|
+
- LIVE-PROVEN (2026-07-09): a real Codex agent, bootstrapped in a stock E2B shell (Node
|
|
173
|
+
installed in-sandbox, run via `npx -y @openai/codex@latest exec`), studied a public
|
|
174
|
+
agent-CLI product from its declared public surfaces and ran the product's free zero-spend
|
|
175
|
+
guide within `$0` no-spend caps; verdict nonce-verified, cleanup proven BY EXACT ID
|
|
176
|
+
(`getInfo(id)` SandboxNotFoundError, never `Sandbox.list`), verify 15/15, share_ready
|
|
177
|
+
(`docs/goals/terminal-product-lane/receipts/terminal-live-rung-2026-07-09.md`). This closes
|
|
178
|
+
the #159 live-receipt gap. Optional follow-up: a custom image with the agent runtime baked in
|
|
179
|
+
to drop the per-run npx bootstrap. Duplex-PTY/xterm replay is a deferred SLICE 5.
|
|
180
|
+
|
|
181
|
+
Multi-lane fan-out for the computer-use lab (0.9.0; proof-roadmap layer 2, the prerequisite
|
|
182
|
+
for multi-actor shared-state work — #163, see `docs/goals/multi-lane-fanout/goal.md`):
|
|
183
|
+
|
|
184
|
+
- `actors[0].lanes[]` (differentiated roster: per-lane persona/device/starting-surface) XOR
|
|
185
|
+
`actors[0].count` (homogeneous) fan out N independent E2B desktops in ONE run bundle;
|
|
186
|
+
`per-lane worlds` is the only topology this slice (shared-world is #164). `done`
|
|
187
|
+
- `execution.concurrency` bounds in-flight paid desktops (default min(N,3); env may only
|
|
188
|
+
lower it); a pre-flight spend/lane plan prints before any sandbox/provider call and at $0
|
|
189
|
+
in dry-run; per-lane teardown reclaims ONLY each lane's own sandbox by id (never
|
|
190
|
+
account-wide). `done`
|
|
191
|
+
- Proven deterministically (fake substrate: bounded concurrency, by-id teardown, fail-fast,
|
|
192
|
+
hollow-lane caught) AND with a kept live rung (2 lanes, two distinct desktops, both
|
|
193
|
+
reclaimed by id, bundle verifies — `docs/goals/multi-lane-fanout/receipts/`). `done`
|
|
194
|
+
- Deferred: seed-fork provisioning (PR-2), in-process-route fan-out, shared-world topology
|
|
195
|
+
(#164).
|
|
196
|
+
|
|
197
|
+
Shared-world topology — multi-actor against ONE shared mutable service (0.10.0; proof-roadmap
|
|
198
|
+
layer 7; #164; `docs/goals/shared-world-topology/`). The north-star sim leverage: MANY personas,
|
|
199
|
+
ONE shared world.
|
|
200
|
+
|
|
201
|
+
- Sequential (`topology: shared-world`, concurrency 1): one sandbox, N role seats take turns
|
|
202
|
+
against the shared DB; a checkpoint timeline proves role B acted on a world already containing
|
|
203
|
+
role A's mutation. `done`
|
|
204
|
+
- **Concurrent (`topology: shared-world` + `concurrency > 1`): one subject sandbox served +
|
|
205
|
+
`getHost`-exposed, N actor desktop sandboxes drive that one URL SIMULTANEOUSLY** (reuses fan-out
|
|
206
|
+
orchestration; all N+1 reclaimed by id). Honest attribution under concurrency: per-persona
|
|
207
|
+
outcomes + harness-clocked `laneWindows` proving real overlap + a `stateSeries` of the shared
|
|
208
|
+
world under load; causation is structurally inexpressible (independent series, no
|
|
209
|
+
per-delta→actor field). `done`
|
|
210
|
+
- A new `attributionClass: isolated | shared-world` honesty axis + verify FAIL-CLOSED on the
|
|
211
|
+
required/forbidden `attributionLimits` sets + a concurrency-on-pass gate (a passed concurrent
|
|
212
|
+
run must show real overlap AND a state delta coincident with it). `getHost` URLs are
|
|
213
|
+
internet-reachable → the route is gated (verify) to synthetic+seeded subjects; the raw URL is
|
|
214
|
+
digest-only in evidence. `done`
|
|
215
|
+
- **LIVE-PROVEN (0.10.1):** a kept live receipt ran 3 personas concurrently against ONE
|
|
216
|
+
getHost-exposed synthetic plane — all 3 passed, all 3 lane-windows overlapped on the real clock,
|
|
217
|
+
the shared stateSeries evolved under load, N+1=4 sandboxes reclaimed by id, verify ok
|
|
218
|
+
(`docs/goals/shared-world-topology/receipts/concurrent-live-rung-2026-06-17.md`). One trial =
|
|
219
|
+
phase-change proof, not scale. The next step is the real downstream sim migration (a
|
|
220
|
+
synthetic-seeded multi-role app in the adopter's domain). Per-action causation,
|
|
221
|
+
cross-sandbox concurrency beyond getHost, and #108 PII/PHI remain out of scope.
|
|
222
|
+
- shared-world (sequential AND concurrent) now also accepts `subject.source: local-tree` alongside
|
|
223
|
+
`clone`: the ONE subject sandbox packs the operator's own working tree instead of cloning,
|
|
224
|
+
reusing `provisionLocalTreeSubject` from the local-tree keystone (0.14.0). Provenance carries
|
|
225
|
+
`archiveSha256` (the pin - one archive per run, so no per-lane unanimity math applies) plus
|
|
226
|
+
host-side commit/dirty when the packed root is a git work tree; local-tree has no repo/publicRepo
|
|
227
|
+
field. The N actor desktops on the concurrent route still drive the harness-minted getHost URL
|
|
228
|
+
exactly as before; only the subject's provisioning + provenance source changed. The multi-origin
|
|
229
|
+
design (`docs/goals/multi-origin-shared-world/design.md`) remains a separate, still-held
|
|
230
|
+
downstream slice. `next patch`
|
|
231
|
+
|
|
232
|
+
Adopter-driven engine features (0.11.0; surfaced by real bespoke-sim migrations):
|
|
233
|
+
|
|
234
|
+
- `execution.desktop.template` — run a lab on a CUSTOM E2B desktop image (name/ID) instead of the
|
|
235
|
+
stock `desktop` template, threaded to `Sandbox.create(template, opts)` via one
|
|
236
|
+
`createDesktopSandbox` seam across every desktop route (cua single+fan-out, sequential +
|
|
237
|
+
concurrent shared-world subject+actors). Absent == the byte-stable stock-template call; recorded
|
|
238
|
+
as `RunBundle.desktopTemplate`. Lets a Node/bun/DB-bearing adopter image run without
|
|
239
|
+
installing the runtime per lane. `done`
|
|
240
|
+
- `humanish observe --run <id>` — serves a run's Observer over `http://127.0.0.1:<port>` (loopback
|
|
241
|
+
only, path-traversal-guarded to the run dir, `/`->`/observer/index.html`) instead of `file://`,
|
|
242
|
+
so browsers/automation can open it and artifact links resolve. `done`
|
|
243
|
+
|
|
244
|
+
Patch hardening (0.11.1):
|
|
245
|
+
|
|
246
|
+
- concurrent shared-world review now fails closed when any actor lane records a failed terminal
|
|
247
|
+
trace; a lane can remain evidence without making the aggregate review green. `done`
|
|
248
|
+
- scripted-browser labs can provision a single cloned synthetic subject, expose it through a
|
|
249
|
+
tokenless sandbox host, and drive deterministic scripted steps while persisting only public-safe
|
|
250
|
+
provenance and host digests. `done`
|
|
251
|
+
|
|
252
|
+
Adopter-driven roster/readback ergonomics (0.12.0):
|
|
253
|
+
|
|
254
|
+
- Lane grouping metadata (`actorType`, `surface`, `caseGroup`) is adapter-owned and projected into
|
|
255
|
+
Observer `laneGroups[]` plus stream labels, so downstream projects can group simulated users
|
|
256
|
+
without teaching Humanish private role names. `done`
|
|
257
|
+
- `actors[0].roster[]` is compact authoring sugar for repeated lane groups. The parser expands it
|
|
258
|
+
into deterministic `lanes[]` (`<group.id>-01`, `<group.id>-02`, ...) before the engine runs, so
|
|
259
|
+
the runtime and run bundle keep one normalized lane shape. `done`
|
|
260
|
+
|
|
261
|
+
Provenance hardening (0.12.1):
|
|
262
|
+
|
|
263
|
+
- Clone-subject provenance now refreshes after successful provisioning phases, so `subject.commit`
|
|
264
|
+
records the served subject HEAD rather than only the initial clone HEAD. This preserves truthful
|
|
265
|
+
run-bundle provenance when an adopter's install/provisioning step checks out the exact revision to
|
|
266
|
+
test. `done`
|
|
267
|
+
|
|
268
|
+
Adapter artifact evidence (0.12.15):
|
|
269
|
+
|
|
270
|
+
- Browser/shared-world adapter hooks may now write product/state proof files under the ignored run
|
|
271
|
+
directory and return namespaced `humanish.adapter-artifact.v1` references. Core validates only the
|
|
272
|
+
generic reference shape and local-path safety, Observer links the artifacts, and `verify` fails
|
|
273
|
+
closed if a referenced file disappears. The payload schema and product nouns stay in the adapter's
|
|
274
|
+
namespace. `done`
|
|
275
|
+
|
|
276
|
+
Evidence hygiene and readback polish (0.12.16):
|
|
277
|
+
|
|
278
|
+
- Browser-backed lanes launch Chromium with shared evidence-hygiene defaults (first-run/update
|
|
279
|
+
background surfaces suppressed, extensions/sync/component update disabled, password/autofill
|
|
280
|
+
profile prompts disabled) so screenshots prefer product pixels over browser chrome. `done`
|
|
281
|
+
- Run-bundle producers now use percent-scale simulation progress consistently: terminal states
|
|
282
|
+
serialize as `100`, and only true in-progress shared-world snapshots serialize partial progress.
|
|
283
|
+
This keeps Observer status pills from rendering completed runs as low-percentage complete states.
|
|
284
|
+
`done`
|
|
285
|
+
- Verify results now separate valid local evidence from public-promotable evidence with
|
|
286
|
+
`shareSafety.status`. Raw full-fidelity screenshot runs remain valid local proof
|
|
287
|
+
(`local_only`), while feedback draft/issue commands require `share_ready` and fail
|
|
288
|
+
closed with structured reasons. `done`
|
|
289
|
+
|
|
290
|
+
Attached CUA live Observer (next patch):
|
|
291
|
+
|
|
292
|
+
- Plain computer-use labs now honor the same attached `onObserverReady` lifecycle as shared-world
|
|
293
|
+
labs: a live CUA run writes an in-progress bundle before actor sessions complete, loopback
|
|
294
|
+
`serveObserver` can hydrate desktop stream iframes while actors are still running, and stream auth
|
|
295
|
+
URLs remain runtime-only through the Observer WeakMap rather than persisted into `run.json` or
|
|
296
|
+
`observer-data.json`. `done`
|
|
297
|
+
|
|
298
|
+
Local working-tree subject + operator observability (0.14.0):
|
|
299
|
+
|
|
300
|
+
- `subject.source: local-tree` packs the lab resolution cwd on the host (git-aware
|
|
301
|
+
enumeration honoring `.gitignore` and including uncommitted work, an always-on
|
|
302
|
+
non-overridable secrets denylist, symlinks stored never dereferenced, one
|
|
303
|
+
enumeration driving both the tar file list and the digest), uploads the
|
|
304
|
+
once-per-run archive into each lane's desktop sandbox, extracts into the subject
|
|
305
|
+
dir, and reuses the clone route's install/build/state/start/probe pipeline
|
|
306
|
+
unchanged. Provenance pins the tree by `archiveSha256` (a dirty tree cannot be
|
|
307
|
+
commit-pinned) plus host-side commit/dirty; `verify` fails closed on a live
|
|
308
|
+
local-tree bundle without a well-formed pin. Live-proven twice with kept
|
|
309
|
+
receipts: a dirty synthetic fixture and this repo packing itself
|
|
310
|
+
(`docs/goals/local-tree-subject/receipts/`). `done`
|
|
311
|
+
- Subject provisioning phase events: started/completed boundaries for
|
|
312
|
+
clone/upload/extract/install/build/serve/readiness/seed-step phases stream to
|
|
313
|
+
stderr by default (injectable via `CuaActorLabHooks.onPhase` /
|
|
314
|
+
`SharedWorldLabHooks.onPhase`) and the completed trail persists into
|
|
315
|
+
`bundle.events`; a single-lane provisioned boot is never silent again. `done`
|
|
316
|
+
- Truthful CLI envelopes at the command boundary: any uncaught action error emits
|
|
317
|
+
one structured `humanish.cli-response.v1` envelope (never a raw stack trace under
|
|
318
|
+
`--json`, never a second stdout document after a flushed envelope), `humanish runs`
|
|
319
|
+
gained a real failure branch, and `doctor` failure now exits 2 like every other
|
|
320
|
+
structured command (behavioral change). `done`
|
|
321
|
+
|
|
322
|
+
### 6. Lab Manifest Shape
|
|
323
|
+
|
|
324
|
+
Make reusable simulations feel like source artifacts, not hardcoded command
|
|
325
|
+
branches.
|
|
326
|
+
|
|
327
|
+
Minimum acceptance:
|
|
328
|
+
|
|
329
|
+
- `humanish/labs/*.yaml` is the committed lab source convention;
|
|
330
|
+
- `.humanish/labs/*.yaml` and `.humanish/local/labs/*.yaml` are ignored local
|
|
331
|
+
overlays;
|
|
332
|
+
- `humanish watch [lab]`, `humanish lab list`, `humanish lab inspect <lab>`, and
|
|
333
|
+
`humanish lab run <lab>` are supported;
|
|
334
|
+
- `--env-file <path>` loads local values for the current command without
|
|
335
|
+
persisting values into artifacts;
|
|
336
|
+
- maintainer dogfood labs such as `oss` are examples, not the canonical
|
|
337
|
+
consumer taxonomy.
|
|
338
|
+
|
|
339
|
+
### 7. OSS Lab Health Readback
|
|
340
|
+
|
|
341
|
+
Make the maintainer `oss` lab report nested lane health back into the
|
|
342
|
+
top-level Observer instead of relying on a human watching the desktops.
|
|
343
|
+
|
|
344
|
+
Minimum acceptance:
|
|
345
|
+
|
|
346
|
+
- each lane records setup status; `done`
|
|
347
|
+
- each lane records target app status/URL or blocker; `done`
|
|
348
|
+
- each lane records nested Observer presence; `done`
|
|
349
|
+
- each lane records nested verification status or blocker; `done`
|
|
350
|
+
- each lane records setup-quality filesystem evidence and Observer can inspect
|
|
351
|
+
it; `done`
|
|
352
|
+
- top-level Observer updates lane verdicts from evidence; `done`
|
|
353
|
+
- feedback candidates are derived from setup-quality/actor evidence; `done`
|
|
354
|
+
- Codex app-server actor telemetry is persisted as redacted trace, event, and
|
|
355
|
+
transcript artifacts; `done`
|
|
356
|
+
- each lane receives a meaningful-use score over setup, filesystem, nested
|
|
357
|
+
Humanish proof, actor activity, product surface, and feedback; `done`
|
|
358
|
+
- provider-backed nested app-url proof now drives a bounded two-step
|
|
359
|
+
desktop/mobile browser persona journey in a headed E2B lane; `done`
|
|
360
|
+
- app-specific executable browser steps can now be authored under
|
|
361
|
+
`humanish/scenarios/*.yaml` and are summarized into top-level nested proof
|
|
362
|
+
evidence; `done`
|
|
363
|
+
- repeated public app/tool headed proofs with app-specific manifests have passed
|
|
364
|
+
against two public targets; `done`
|
|
365
|
+
- next gap: richer multi-step product journeys and broader multi-persona
|
|
366
|
+
matrices.
|
|
367
|
+
|
|
368
|
+
## Non-Goals
|
|
369
|
+
|
|
370
|
+
Do not make these default behavior:
|
|
371
|
+
|
|
372
|
+
- live provider spend;
|
|
373
|
+
- GitHub API mutation;
|
|
374
|
+
- hosted queues, databases, or webhooks;
|
|
375
|
+
- production deploys;
|
|
376
|
+
- real customer/user/patient data;
|
|
377
|
+
- private screenshots or raw transcripts;
|
|
378
|
+
- private upstream artifacts.
|
|
379
|
+
|
|
380
|
+
Maintainer-only tooling can exist later, but it must be opt-in, token-explicit,
|
|
381
|
+
and dry-run-first.
|
|
382
|
+
|
|
383
|
+
## Drift Alarms
|
|
384
|
+
|
|
385
|
+
Stop and correct course if:
|
|
386
|
+
|
|
387
|
+
- docs start depending on chat memory;
|
|
388
|
+
- Observer gets prettier without stronger evidence;
|
|
389
|
+
- feedback drafts imply product proof from synthetic contract proof;
|
|
390
|
+
- tests pass while generated artifacts are not inspectable;
|
|
391
|
+
- actor setup/use trials produce findings that never become feedback candidates;
|
|
392
|
+
- live labs require private infrastructure to look impressive;
|
|
393
|
+
- package docs link to files that are not shipped;
|
|
394
|
+
- public-safety gates become optional.
|
|
395
|
+
|
|
396
|
+
## Best Next Work
|
|
397
|
+
|
|
398
|
+
The next most useful engineering slice is repeated agent dogfood against real
|
|
399
|
+
apps and tools, while preserving the public-safety boundary:
|
|
400
|
+
|
|
401
|
+
- public/open-source fixture proof for publishable examples;
|
|
402
|
+
- private maintainer dogfood through the repo-only public-safe packet, which is
|
|
403
|
+
intentionally not part of the npm payload, at
|
|
404
|
+
[`docs/goals/private-repo-agent-dogfood/goal.md`](https://github.com/danielgwilson/humanish/blob/main/docs/goals/private-repo-agent-dogfood/goal.md);
|
|
405
|
+
- then richer provider-backed app-specific browser persona manifests.
|
|
406
|
+
|
|
407
|
+
That sequence keeps the package honest: first prove a new maintainer or agent
|
|
408
|
+
can start, then prove Humanish can observe real product behavior, then use the
|
|
409
|
+
failures to improve the harness.
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# Invariants and Defaults
|
|
2
|
+
|
|
3
|
+
Humanish's safety and honesty rules come in exactly two strengths. Confusing them is how
|
|
4
|
+
harnesses rot: a route-scoped default gets written down as if it were doctrine, then the next
|
|
5
|
+
legitimate use case looks like a violation and either gets blocked (capability loss) or
|
|
6
|
+
waved through ad hoc (safety loss). This page is the boundary.
|
|
7
|
+
|
|
8
|
+
## Invariants
|
|
9
|
+
|
|
10
|
+
True on every route, enforced in code, never overridable by config. A feature that cannot
|
|
11
|
+
satisfy these does not ship; a third-party extension that cannot satisfy these does not
|
|
12
|
+
certify (see the conformance suite).
|
|
13
|
+
|
|
14
|
+
1. **Secret values never reach PUBLISHED evidence.** No key, token, credential value, or
|
|
15
|
+
session-secret may appear in any artifact that leaves the operator's machine — a committed
|
|
16
|
+
file, a shared bundle, a feedback issue. Names of provisioned environment variables are
|
|
17
|
+
evidence; their values never are. Harness-level errors pass through redaction before
|
|
18
|
+
persisting, because SDK error strings can echo secrets. The enforcement point is the
|
|
19
|
+
PUBLISH/VERIFY boundary, not capture: a local run's text artifacts are scrubbed of
|
|
20
|
+
secret-shaped values unconditionally, and raw screenshots (which may render on-screen
|
|
21
|
+
content) are retained locally under gitignored `.humanish/` and never emitted by a publish
|
|
22
|
+
command (feedback/review carry path strings, not pixels). In this repo the CI binary-asset
|
|
23
|
+
scan additionally blocks them from commit; downstream projects do not get that scan — their
|
|
24
|
+
protection is the init-scaffolded `.gitignore` plus their own review. To share a bundle
|
|
25
|
+
as-is, set `policies.redactScreenshots: true` (blurs
|
|
26
|
+
at capture); a redact-on-export step for already-captured raw bundles is planned, not yet
|
|
27
|
+
shipped. (See "the capture-vs-publish rule" below — blurring frames at *capture* was a
|
|
28
|
+
default mistaken for this invariant.)
|
|
29
|
+
- Scope note: the literal scrub of KNOWN provisioned values runs on harness log-tails,
|
|
30
|
+
errors, AND model-authored narration (reasoning/message) before it persists; secret-SHAPED
|
|
31
|
+
values are caught everywhere by pattern redaction. The text artifacts are local
|
|
32
|
+
(gitignored) regardless.
|
|
33
|
+
2. **Actors only drive harness-minted URLs.** A model with input control (mouse, keyboard,
|
|
34
|
+
terminal) is only ever pointed at a URL the harness itself issued or validated under a
|
|
35
|
+
declared policy (loopback entry, provisioned subject, declared external target). Never an
|
|
36
|
+
arbitrary URL from unvalidated input.
|
|
37
|
+
3. **Live spend is explicit.** No configuration default, omission, or fallback may cause
|
|
38
|
+
provider or sandbox spend. Spend requires an affirmative declaration (`scenario.mode:
|
|
39
|
+
live`, an env opt-in gate for spend-bearing tests).
|
|
40
|
+
4. **Evidence verifies fail-closed.** A run bundle that cannot pass verification (schema,
|
|
41
|
+
redaction status, artifact presence, public-safety scan) is a failed run, even when the
|
|
42
|
+
session "worked." The gate applies to the harness's own error reports.
|
|
43
|
+
5. **Provenance is recorded or its absence is declared.** Every bundle states what the
|
|
44
|
+
subject was (commit, image, fixture, or an explicit "unpinned" marker). Evidence that
|
|
45
|
+
cannot say what it measured cannot support a decision.
|
|
46
|
+
6. **Claims match mechanism.** A config field that is parsed but not consumed warns; a
|
|
47
|
+
document that overstates behavior is a defect; an evidence artifact never claims a
|
|
48
|
+
stronger evidence class than its actor and scenario can support.
|
|
49
|
+
7. **Reclamation is by exact created id, never account-wide enumeration.** A route that
|
|
50
|
+
creates a provider resource (an E2B sandbox, for example) tracks the exact id it created and
|
|
51
|
+
reclaims and PROVES cleanup against that id alone (a returned found-and-killed boolean, a
|
|
52
|
+
getInfo-by-id NotFound check). No route ever calls a provider's list-everything endpoint to
|
|
53
|
+
discover or verify its own cleanup, because that endpoint enumerates the whole account/team,
|
|
54
|
+
not just what humanish created. This is what makes a single shared operator key safe: humanish
|
|
55
|
+
only ever reaches a resource it created, never anything else the key's owner is running.
|
|
56
|
+
The one narrow exception is an explicit, maintainer-run orphan sweep (never a default, never
|
|
57
|
+
reachable by a normal lab run) that is itself opt-in gated (an explicit flag or env var) and
|
|
58
|
+
documented as such at its call site.
|
|
59
|
+
|
|
60
|
+
## Defaults
|
|
61
|
+
|
|
62
|
+
Right most of the time, overridable with declared friction (an explicit config field, an
|
|
63
|
+
env gate, a warning in the run output). Overriding a default is a supported use case;
|
|
64
|
+
silently drifting from one is not.
|
|
65
|
+
|
|
66
|
+
| Default | Why it is the default | Legitimate override |
|
|
67
|
+
|---|---|---|
|
|
68
|
+
| Dry-run | Spend safety (invariant 3 sets the floor; dry-run keeps the floor far away) | `scenario.mode: live` |
|
|
69
|
+
| Per-lane worlds | Isolation, attribution, reproducibility | `subject.topology: shared-world` — N seats against ONE provisioned, mutable plane for scenarios that ARE about interaction between roles (#164). `execution.concurrency: 1` (default) = SEQUENTIAL turns (one sandbox); `> 1` = CONCURRENT (one getHost-exposed subject sandbox + N actor sandboxes driving it at once, synthetic-subject only). The bundle declares the weaker `attributionClass: shared-world` + a verify-enforced `attributionLimits` ceiling (the concurrent set drops `sequential-only` and adds `best-effort-causal-attribution` etc.), so the looser per-role attribution is honest, not hidden. |
|
|
70
|
+
| External key placement | Smallest blast radius: when the keyed process (e.g. a computer-use provider loop) runs outside the sandbox, its key never enters | In-sandbox placement when the keyed process runs inside (an agent harness under test); declared per actor type, with a spend budget |
|
|
71
|
+
| Loopback entry URLs | Public-safety: never drive third-party sites unbidden | `policies.allowPublicTargets` for an owner-declared deployment/preview (a Vercel preview of your own app). Multi-lane public/preview fan-out needs explicit `actors[0].lanes[].target` for every lane, so the adapter-owned topology is declared rather than inferred. Provisioned clone subjects always serve in-sandbox on loopback |
|
|
72
|
+
| Full-fidelity screenshots, local | The common case is watching a sim of your OWN app locally; blur destroys the deliverable. Raw frames live in gitignored `.humanish/` (this repo's CI adds a binary-asset commit scan; downstream projects rely on the scaffolded `.gitignore` and their own review) | `policies.redactScreenshots: true` blurs at capture for share-as-is bundles (a redact-on-export step for raw bundles is planned) |
|
|
73
|
+
| Synthetic, seeded state | Pinned provenance; no real user data in evidence paths | Declared external state, recorded as UNPINNED in provenance |
|
|
74
|
+
| Single lane | Cost + evidence simplicity | Declared fan-out where the backend supports it — `actors[0].count: N` (homogeneous), explicit `actors[0].lanes[]` (differentiated persona/device/instruction), or compact `actors[0].roster[]` groups that normalize into lanes on the computer-use E2B route (per-lane worlds, cap 16; `execution.concurrency` bounds concurrent paid lanes) |
|
|
75
|
+
| Stock `desktop` template | The stock E2B desktop image is right for most subjects; absent `execution.desktop.template` keeps `Sandbox.create(opts)` byte-stable | `execution.desktop.template` names a custom E2B desktop image (any name/id, no allowlist) for a subject needing baked-in runtimes the stock image lacks (e.g. node/bun/a local Postgres) — threaded to `Sandbox.create(template, opts)` on every desktop-creating route and recorded in the bundle as `desktopTemplate` (public-safe) |
|
|
76
|
+
| Desktop default URL opener | Preserve the route/image's historical browser/default opener behavior when unset | `execution.desktop.browser: chrome | chromium | firefox` makes hosted CUA/shared-world browser choice explicit, fail-closed, and recorded as `desktopBrowser` in the run bundle |
|
|
77
|
+
|
|
78
|
+
## The placement rule (worked example)
|
|
79
|
+
|
|
80
|
+
"No environment variables enter the sandbox" was once stated as a rule. It is not one — it
|
|
81
|
+
is the external-placement *default* as instantiated on the computer-use route, where the
|
|
82
|
+
model's brain runs outside the sandbox. The underlying invariant-level principle is:
|
|
83
|
+
|
|
84
|
+
> **Keys live where the keyed process runs — and nowhere else. Names go in evidence; values
|
|
85
|
+
> never. Blast radius is bounded by key scoping and budgets, not by hoping.**
|
|
86
|
+
|
|
87
|
+
Consequences:
|
|
88
|
+
|
|
89
|
+
- A computer-use provider loop runs outside → forwarding env into its sandbox is rejected.
|
|
90
|
+
- A subject app (a real web app under test) runs inside → its declared env names are
|
|
91
|
+
provisioned in, values never persisted.
|
|
92
|
+
- An agent harness under test runs inside with real keys → that is the point of the lab;
|
|
93
|
+
the keys are presumed exfiltratable by the agent (sandboxing does not protect them — key
|
|
94
|
+
scoping and spend budgets do), and the lane carries a budget/ledger.
|
|
95
|
+
|
|
96
|
+
Placement is registry metadata per actor type, enforced by the engine — not a vibe.
|
|
97
|
+
|
|
98
|
+
Two corollaries:
|
|
99
|
+
|
|
100
|
+
- **Serve commands are author-trusted.** A lab's `serve` steps execute inside the disposable
|
|
101
|
+
sandbox with the declared subject env present — the same trust class as the repo's own
|
|
102
|
+
package.json scripts. Run only lab configs you trust; declare only the env names the
|
|
103
|
+
subject genuinely needs.
|
|
104
|
+
- **Pattern redaction is not enough for provisioned values.** A provisioned value (a database
|
|
105
|
+
password, an arbitrary token) has no detectable "shape," so the harness scrubs every value
|
|
106
|
+
it provisioned by LITERAL match before any log tail or error can persist — pattern-based
|
|
107
|
+
redaction is the second pass, not the only one.
|
|
108
|
+
|
|
109
|
+
## The capture-vs-publish rule (worked example)
|
|
110
|
+
|
|
111
|
+
"Every screenshot is blurred to a 128px thumbnail" was once enforced at *capture* — the
|
|
112
|
+
loop never retained a usable frame. That destroyed the core deliverable for the common case
|
|
113
|
+
(a developer watching a sim of their OWN app locally) to defend against a leak that can only
|
|
114
|
+
happen at *publish*. The proof it was a default, not an invariant: the same product already
|
|
115
|
+
shipped raw full-resolution frames on the meta route with only a "do not publish" warning +
|
|
116
|
+
the `.humanish/` gitignore + the binary-asset scan. Two routes, opposite policies, identical
|
|
117
|
+
threat. The corrected principle:
|
|
118
|
+
|
|
119
|
+
> **A default's enforcement point belongs at the PUBLISH/VERIFY boundary, never at
|
|
120
|
+
> CAPTURE/RUNTIME — unless capture-time is the only physically possible point.**
|
|
121
|
+
|
|
122
|
+
Consequences:
|
|
123
|
+
|
|
124
|
+
- Screenshots are retained **raw and full-fidelity** by default, in gitignored `.humanish/`.
|
|
125
|
+
`policies.redactScreenshots: true` blurs at capture for a share-as-is bundle; a
|
|
126
|
+
redact-on-export step for already-captured raw bundles is planned (not yet shipped). The
|
|
127
|
+
frame sent to the provider is always raw regardless — the model must see the screen to act.
|
|
128
|
+
- The loopback wall and the synthetic-data stance were the same error: enforcing at
|
|
129
|
+
capture/runtime (rejecting a public target outright; banning realistic local input) what
|
|
130
|
+
belongs at publish (an owner-declared `allowPublicTargets`; redaction at the publish step). A genuine
|
|
131
|
+
capture-time invariant — shell-injection shape checks, id-shape validation — passes the test
|
|
132
|
+
because capture *is* the only point it can hold.
|
|
133
|
+
|
|
134
|
+
Litmus: for any constraint, ask "is this true everywhere, or true by default? — and if a
|
|
135
|
+
default, is it enforced at the boundary where the risk is actually realized?"
|