humanish 0.80.0 → 0.81.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.
Files changed (45) hide show
  1. package/README.md +9 -3
  2. package/dist/actor-contract.d.ts +16 -0
  3. package/dist/actor-contract.js.map +1 -1
  4. package/dist/chrome-cdp-probe.js +13 -0
  5. package/dist/chrome-cdp-probe.js.map +1 -1
  6. package/dist/computer-use.d.ts +7 -1
  7. package/dist/computer-use.js +156 -13
  8. package/dist/computer-use.js.map +1 -1
  9. package/dist/cua-actor-lab.d.ts +7 -6
  10. package/dist/cua-actor-lab.js +95 -21
  11. package/dist/cua-actor-lab.js.map +1 -1
  12. package/dist/e2b-desktop-launch.d.ts +28 -1
  13. package/dist/e2b-desktop-launch.js +88 -1
  14. package/dist/e2b-desktop-launch.js.map +1 -1
  15. package/dist/e2b-desktop-screenshot-cleanup.d.ts +15 -0
  16. package/dist/e2b-desktop-screenshot-cleanup.js +67 -0
  17. package/dist/e2b-desktop-screenshot-cleanup.js.map +1 -0
  18. package/dist/e2b-terminal-lab.d.ts +3 -2
  19. package/dist/e2b-terminal-lab.js +176 -85
  20. package/dist/e2b-terminal-lab.js.map +1 -1
  21. package/dist/first-run-path.js +2 -2
  22. package/dist/first-run-path.js.map +1 -1
  23. package/dist/index.d.ts +1 -1
  24. package/dist/index.js.map +1 -1
  25. package/dist/lab-config.d.ts +11 -14
  26. package/dist/lab-config.js +2 -2
  27. package/dist/lab-config.js.map +1 -1
  28. package/dist/openai-responses-cu.js +76 -49
  29. package/dist/openai-responses-cu.js.map +1 -1
  30. package/dist/program.js +16 -7
  31. package/dist/program.js.map +1 -1
  32. package/dist/run.d.ts +1 -1
  33. package/dist/terminal-node-bootstrap.d.ts +4 -0
  34. package/dist/terminal-node-bootstrap.js +58 -0
  35. package/dist/terminal-node-bootstrap.js.map +1 -0
  36. package/dist/terminal-runtime-auth.d.ts +13 -0
  37. package/dist/terminal-runtime-auth.js +24 -0
  38. package/dist/terminal-runtime-auth.js.map +1 -0
  39. package/docs/architecture/actor-contract.md +22 -0
  40. package/docs/architecture/terminal-product-lane.md +108 -7
  41. package/docs/contracts/feedback.md +14 -0
  42. package/docs/contracts/schemas.md +1 -1
  43. package/docs/goals/current.md +45 -13
  44. package/docs/ramp/README.md +1 -1
  45. package/package.json +4 -2
package/dist/run.d.ts CHANGED
@@ -831,7 +831,7 @@ export interface RunCostLine {
831
831
  modelId?: string;
832
832
  /** null = NOT MEASURED / no rate; never coerced to 0. */
833
833
  estimatedCostUsd: number | null;
834
- reason?: "no_rate_for_model" | "no_rate_for_desktop" | "no_token_usage" | "no_duration";
834
+ reason?: "no_rate_for_model" | "no_rate_for_desktop" | "no_token_usage" | "no_duration" | "closing_usage_unreported";
835
835
  /** Pricing provenance date; non-null iff estimatedCostUsd is non-null. */
836
836
  ratesAsOf: string | null;
837
837
  source?: string;
@@ -0,0 +1,4 @@
1
+ export declare const TERMINAL_NODE_VERSION = "22.23.2";
2
+ export declare const TERMINAL_NODE_NPM_PREFIX_SCRIPT: string;
3
+ /** Unkeyed runtime prerequisite for stock Linux desktops. No apt repository refresh (#674). */
4
+ export declare const TERMINAL_NODE_BOOTSTRAP_COMMAND: string;
@@ -0,0 +1,58 @@
1
+ // Node 22 remains a supported LTS line. Pin the official release and trusted archive hashes:
2
+ // https://nodejs.org/en/about/previous-releases
3
+ // https://nodejs.org/dist/v22.23.2/SHASUMS256.txt (checked 2026-09-05)
4
+ // A checksum fetched alongside the archive at runtime would not pin what we trust.
5
+ export const TERMINAL_NODE_VERSION = "22.23.2";
6
+ // npm normally derives its global prefix from the real Node executable. This distribution
7
+ // lives under /opt, while its public executables use /usr/local/bin. Set only a missing
8
+ // built-in default; npm's environment, CLI, user and global config still take precedence.
9
+ export const TERMINAL_NODE_NPM_PREFIX_SCRIPT = [
10
+ 'const fs = require("node:fs");',
11
+ 'const file = process.argv[1];',
12
+ 'let existing = "";',
13
+ 'try { existing = fs.readFileSync(file, "utf8"); } catch (error) { if (error.code !== "ENOENT") throw error; }',
14
+ 'if (!/^[\\t ]*prefix[\\t ]*=/m.test(existing)) fs.appendFileSync(file, "\\nprefix=/usr/local\\n");'
15
+ ].join(" ");
16
+ /** Unkeyed runtime prerequisite for stock Linux desktops. No apt repository refresh (#674). */
17
+ export const TERMINAL_NODE_BOOTSTRAP_COMMAND = [
18
+ "set -eu",
19
+ "# humanish terminal-node-bootstrap",
20
+ "node_major=0",
21
+ `if command -v node >/dev/null 2>&1; then node_major=$(node -e 'console.log(Number(process.versions.node.split(".")[0]))' 2>/dev/null || echo 0); fi`,
22
+ `if command -v node >/dev/null 2>&1 && command -v npm >/dev/null 2>&1 && [ "$node_major" -ge 20 ] && npm --version >/dev/null 2>&1; then`,
23
+ // An explicit exit under set -e runs the stock login shell's failing clear_console logout hook
24
+ // and turns this successful fast path into exit 1. Finish the compound command naturally.
25
+ " :",
26
+ "else",
27
+ `case "$(uname -s):$(uname -m)" in`,
28
+ ` Linux:x86_64) node_arch=x64; node_sha=b294a556e639d64338823920e5866c21c02741742d2e1529ee1a225c1ec9252a ;;`,
29
+ ` Linux:aarch64|Linux:arm64) node_arch=arm64; node_sha=013b59cfd2819703a6f4a14ab891fc46fc2a4e3f5bcd92de3fb4929b43e35b30 ;;`,
30
+ ` *) echo 'humanish: terminal runtime requires a supported Linux x64/arm64 desktop or working Node >=20 and npm' >&2; exit 1 ;;`,
31
+ "esac",
32
+ "for prerequisite in curl sha256sum tar gzip mktemp sudo; do",
33
+ ` command -v "$prerequisite" >/dev/null 2>&1 || { echo "humanish: terminal runtime bootstrap requires $prerequisite" >&2; exit 1; }`,
34
+ "done",
35
+ `node_archive="node-v${TERMINAL_NODE_VERSION}-linux-$node_arch.tar.gz"`,
36
+ `node_target="/opt/humanish/node-v${TERMINAL_NODE_VERSION}-linux-$node_arch"`,
37
+ `node_temp=$(mktemp -d /tmp/humanish-node.XXXXXX)`,
38
+ `trap 'rm -rf "$node_temp"' EXIT`,
39
+ `curl --fail --silent --show-error --location --proto '=https' --proto-redir '=https' --connect-timeout 10 --max-time 90 --retry 1 --retry-max-time 120 --output "$node_temp/$node_archive" "https://nodejs.org/dist/v${TERMINAL_NODE_VERSION}/$node_archive"`,
40
+ `(cd "$node_temp" && printf '%s %s\\n' "$node_sha" "$node_archive" | sha256sum --check --status) || { echo 'humanish: terminal Node archive checksum did not match the trusted release' >&2; exit 1; }`,
41
+ // Only a verified official archive reaches privileged extraction. The versioned install is
42
+ // root-owned; subsequent ordinary and sudo shells find it through standard /usr/local/bin.
43
+ "sudo -n mkdir -p /opt/humanish /usr/local/bin",
44
+ `sudo -n tar --extract --gzip --file "$node_temp/$node_archive" --directory /opt/humanish --no-same-owner`,
45
+ "for executable in node npm npx; do",
46
+ ` sudo -n ln -sfn "$node_target/bin/$executable" "/usr/local/bin/$executable"`,
47
+ "done",
48
+ // Keep global product executables on the existing ordinary/sudo PATH (#679). The new
49
+ // versioned distribution is the only config we modify; no user/global npmrc or profile.
50
+ `sudo -n "$node_target/bin/node" -e '${TERMINAL_NODE_NPM_PREFIX_SCRIPT}' "$node_target/lib/node_modules/npm/npmrc"`,
51
+ "hash -r",
52
+ `node -e 'process.exit(Number(process.versions.node.split(".")[0]) >= 20 ? 0 : 1)' && npm --version >/dev/null`,
53
+ // Product installation already uses sudo; detect a template whose sudo PATH cannot see Node
54
+ // rather than changing global PATH or permissions to make it look supported.
55
+ `sudo -n node -e 'process.exit(Number(process.versions.node.split(".")[0]) >= 20 ? 0 : 1)' && sudo -n npm --version >/dev/null`,
56
+ "fi"
57
+ ].join("\n");
58
+ //# sourceMappingURL=terminal-node-bootstrap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal-node-bootstrap.js","sourceRoot":"","sources":["../src/terminal-node-bootstrap.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,gDAAgD;AAChD,uEAAuE;AACvE,mFAAmF;AACnF,MAAM,CAAC,MAAM,qBAAqB,GAAG,SAAS,CAAC;AAE/C,0FAA0F;AAC1F,wFAAwF;AACxF,0FAA0F;AAC1F,MAAM,CAAC,MAAM,+BAA+B,GAAG;IAC7C,gCAAgC;IAChC,+BAA+B;IAC/B,oBAAoB;IACpB,+GAA+G;IAC/G,oGAAoG;CACrG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAEZ,+FAA+F;AAC/F,MAAM,CAAC,MAAM,+BAA+B,GAAG;IAC7C,SAAS;IACT,oCAAoC;IACpC,cAAc;IACd,qJAAqJ;IACrJ,yIAAyI;IACzI,+FAA+F;IAC/F,0FAA0F;IAC1F,KAAK;IACL,MAAM;IACN,mCAAmC;IACnC,6GAA6G;IAC7G,4HAA4H;IAC5H,iIAAiI;IACjI,MAAM;IACN,6DAA6D;IAC7D,qIAAqI;IACrI,MAAM;IACN,uBAAuB,qBAAqB,2BAA2B;IACvE,oCAAoC,qBAAqB,oBAAoB;IAC7E,kDAAkD;IAClD,iCAAiC;IACjC,wNAAwN,qBAAqB,iBAAiB;IAC9P,wMAAwM;IACxM,2FAA2F;IAC3F,2FAA2F;IAC3F,+CAA+C;IAC/C,0GAA0G;IAC1G,oCAAoC;IACpC,+EAA+E;IAC/E,MAAM;IACN,qFAAqF;IACrF,wFAAwF;IACxF,uCAAuC,+BAA+B,6CAA6C;IACnH,SAAS;IACT,+GAA+G;IAC/G,4FAA4F;IAC5F,6EAA6E;IAC7E,+HAA+H;IAC/H,IAAI;CACL,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { E2BNetworkOptions } from "./e2b-desktop-launch.js";
2
+ export declare const OPENAI_EGRESS_HOST = "api.openai.com";
3
+ /** E2B envd installs the sandbox-specific proxy CA into this system bundle before routing. */
4
+ export declare const E2B_SYSTEM_CA_BUNDLE = "/etc/ssl/certs/ca-certificates.crt";
5
+ /** An inert nonsecret value satisfies Codex exec's auth prerequisite. E2B replaces the header. */
6
+ export declare const OPENAI_EGRESS_PLACEHOLDER = "humanish-egress-auth-placeholder";
7
+ /**
8
+ * Keep the runtime key in the host-side E2B request, outside sandbox env/files. The installed
9
+ * E2B SDK declares that transform headers override existing request headers. This adds no routing
10
+ * restrictions: every sandbox process can still spend via the provider proxy. Never log the
11
+ * returned options. An adopter's existing exact-host rule must not be silently overwritten.
12
+ */
13
+ export declare function buildOpenAiEgressNetwork(keyValue: string, existing?: E2BNetworkOptions): E2BNetworkOptions;
@@ -0,0 +1,24 @@
1
+ export const OPENAI_EGRESS_HOST = "api.openai.com";
2
+ /** E2B envd installs the sandbox-specific proxy CA into this system bundle before routing. */
3
+ export const E2B_SYSTEM_CA_BUNDLE = "/etc/ssl/certs/ca-certificates.crt";
4
+ /** An inert nonsecret value satisfies Codex exec's auth prerequisite. E2B replaces the header. */
5
+ export const OPENAI_EGRESS_PLACEHOLDER = "humanish-egress-auth-placeholder";
6
+ /**
7
+ * Keep the runtime key in the host-side E2B request, outside sandbox env/files. The installed
8
+ * E2B SDK declares that transform headers override existing request headers. This adds no routing
9
+ * restrictions: every sandbox process can still spend via the provider proxy. Never log the
10
+ * returned options. An adopter's existing exact-host rule must not be silently overwritten.
11
+ */
12
+ export function buildOpenAiEgressNetwork(keyValue, existing) {
13
+ if (Object.keys(existing?.rules ?? {}).some((host) => host.toLowerCase().replace(/\.$/, "") === OPENAI_EGRESS_HOST)) {
14
+ throw new Error("openai-egress conflicts with an existing api.openai.com network rule; refusing to overwrite it.");
15
+ }
16
+ return {
17
+ ...existing,
18
+ rules: {
19
+ ...existing?.rules,
20
+ [OPENAI_EGRESS_HOST]: [{ transform: { headers: { Authorization: `Bearer ${keyValue}` } } }]
21
+ }
22
+ };
23
+ }
24
+ //# sourceMappingURL=terminal-runtime-auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal-runtime-auth.js","sourceRoot":"","sources":["../src/terminal-runtime-auth.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,kBAAkB,GAAG,gBAAgB,CAAC;AACnD,8FAA8F;AAC9F,MAAM,CAAC,MAAM,oBAAoB,GAAG,oCAAoC,CAAC;AACzE,kGAAkG;AAClG,MAAM,CAAC,MAAM,yBAAyB,GAAG,kCAAkC,CAAC;AAE5E;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CACtC,QAAgB,EAChB,QAA4B;IAE5B,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,kBAAkB,CAAC,EAAE,CAAC;QACpH,MAAM,IAAI,KAAK,CAAC,iGAAiG,CAAC,CAAC;IACrH,CAAC;IACD,OAAO;QACL,GAAG,QAAQ;QACX,KAAK,EAAE;YACL,GAAG,QAAQ,EAAE,KAAK;YAClB,CAAC,kBAAkB,CAAC,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,QAAQ,EAAE,EAAE,EAAE,EAAE,CAAC;SAC5F;KACF,CAAC;AACJ,CAAC"}
@@ -293,6 +293,28 @@ not cost — a live scripted run drives a real browser against a real running ap
293
293
  declaration as spend. "Live" on this route must never silently come to mean "costs money";
294
294
  this paragraph is the record of that decision.
295
295
 
296
+ ## Optional closing report
297
+
298
+ `CuaProvider.debrief` is an optional read-only request after a structured
299
+ `stopWhen` or dwell stop. It returns a `CuaTurn` with `closingReport` containing
300
+ `summary` and `frictionReports`; an empty friction list is valid. The loop rejects
301
+ actions, pending safety checks, and invalid report shapes. It redacts accepted
302
+ reports, records them in `ActorTrace.debrief`, and projects one readable message
303
+ without invoking action or communication callbacks.
304
+
305
+ This request uses the final observation and retained provider history. It does
306
+ not expose the hidden stop criterion or change the original task outcome. It is
307
+ skipped before any participant turn, after natural completion, without provider
308
+ support, or without remaining time and known budget. An attempted request's
309
+ unreported usage remains an unknown cost line. `counts.debriefCalls` is separate
310
+ from interaction turns, and reported usage contributes to aggregate cost.
311
+
312
+ The OpenAI implementation makes one request with tools disabled and structured
313
+ output; no HTTP or policy retries. Stateless/ZDR mode does not offer retrospective
314
+ reporting because it does not retain the required session history. The
315
+ [paired live receipt](../goals/computer-use-actor/receipts/structured-closing-report-2026-09-05.md)
316
+ records both report recovery and control failures in the separate legacy parser.
317
+
296
318
  ## The state-driven executor seam (shipped — the transport-agnostic intent, made real)
297
319
 
298
320
  The `CuaExecutor` / `CuaProvider` ports are the concrete realization of the "plural harnesses /
@@ -1,6 +1,6 @@
1
1
  # Terminal-product real-agent lane (issue #154)
2
2
 
3
- Date: 2026-06-16 (current-state note updated 2026-07-14)
3
+ Date: 2026-06-16 (runtime-auth contract updated 2026-09-05)
4
4
 
5
5
  Status: live terminal-product route shipped in `0.8.0`. The in-sandbox backend,
6
6
  command-scoped credential placement, exact-id cleanup proof, an interventions ledger,
@@ -16,8 +16,8 @@ for the full slice plan and the safety contract.
16
16
 
17
17
  A lab lane for **terminal-product real-agent studies**: a real autonomous coding
18
18
  agent (Codex) discovering and using a CLI/product from its **public surfaces
19
- only**, running **inside an E2B shell** with command-scoped runtime auth, capped
20
- at no-spend, emitting durable terminal/substrate/cost/no-spend/cleanup/
19
+ only**, running **inside an E2B shell** with declared runtime-auth placement and
20
+ spend/time caps, emitting durable terminal/substrate/cost/no-spend/cleanup/
21
21
  intervention proof that verifies fail-closed. This is distinct from the browser
22
22
  lanes: it is not testing whether a browser can click a local web app — it tests
23
23
  whether an autonomous agent can discover and use a CLI/product surface from
@@ -36,7 +36,7 @@ fail-closed cross-validation, and forward-declared warnings.
36
36
  | `subject.product` | `{ name, publicSurfaces[] }` — the only world the agent sees |
37
37
  | `execution.target` | `e2b-terminal` (or absent → implied) |
38
38
  | `execution.terminal` | `{ transport: exec-stream, stdin: disabled }` |
39
- | `execution.runtimeAuth` | `openai-env` (names-only durable evidence) |
39
+ | `execution.runtimeAuth` | `openai-env` (default) or opt-in `openai-egress`; names-only durable evidence |
40
40
  | `scenario.caps` | `{ maxUsd, maxJobs, maxMinutes }` — the blast-radius budget |
41
41
  | `policies` | `allowPrivateRepoAccess` / `allowProviderCredentials` / `allowPaymentCredentials` / `allowGitHubMutation`, all DEFAULT FALSE |
42
42
  | `actors[0].type` | `codex-exec` — a registered terminal actor (`keyPlacement: in-sandbox-command-scoped`) |
@@ -46,9 +46,110 @@ Routing is `routesToTerminalProduct(config)` — the single source of truth that
46
46
  both `selectLabBackend` and the forward-declared-warning logic consume, mirroring
47
47
  `routesToComputerUse` / `routesToScriptedBrowser`.
48
48
 
49
- ## The safety contract (the lane's reason to exist)
50
-
51
- This lane **inverts** the credential-placement default of every other E2B route.
49
+ ## Runtime auth: raw-key placement and remaining provider access
50
+
51
+ `execution.runtimeAuth: openai-env` remains the compatible default. It supplies
52
+ `CODEX_API_KEY` command-scoped to Codex, with `OPENAI_API_KEY` also supplied when
53
+ that was the host source. Child processes can read and use the raw key.
54
+
55
+ Opt in to keeping the raw key outside the sandbox:
56
+
57
+ ```yaml
58
+ execution:
59
+ target: e2b-terminal
60
+ runtimeAuth: openai-egress
61
+ terminal:
62
+ transport: exec-stream
63
+ stdin: disabled
64
+ ```
65
+
66
+ `openai-egress` resolves the same host key (`CODEX_API_KEY` first, otherwise
67
+ `OPENAI_API_KEY`) and supplies it only to E2B's host-side network rule for
68
+ `api.openai.com`. The rule sets the HTTPS `Authorization` header. The sandbox's
69
+ Codex command receives the nonsecret value `humanish-egress-auth-placeholder`
70
+ under `CODEX_API_KEY`, plus `CODEX_CA_CERTIFICATE` pointing at E2B's existing
71
+ system CA bundle (`/etc/ssl/certs/ca-certificates.crt`) so TLS verification trusts
72
+ the platform's proxy CA. Humanish does not disable TLS verification or download
73
+ an unauthenticated CA. The sandbox receives no raw runtime key in command env, sandbox env,
74
+ files, metadata, or captured evidence. The host still scrubs the actual key from
75
+ output and errors, including errors during sandbox creation.
76
+
77
+ This mode supports the default OpenAI endpoint only. Humanish explicitly sets
78
+ Codex's built-in `openai` provider and `openai_base_url` to
79
+ `https://api.openai.com/v1` for that invocation. It does not support a custom
80
+ provider, proxy base URL, or regional endpoint under this mode. `openai-env`
81
+ retains its existing command behavior. E2B header rules are a public-beta
82
+ capability; the local contract is checked against the installed Desktop SDK
83
+ (`@e2b/desktop` 2.3.3, resolving `e2b` 2.46.1).
84
+
85
+ **The sandbox still has a spendable OpenAI proxy capability.** Every process can
86
+ make authenticated requests to that host from sandbox creation until teardown,
87
+ including bootstrap/setup commands and commands launched outside Codex. Calls
88
+ made outside Codex may be absent from its usage ledger. This mode does not impose
89
+ a provider-side spending limit, restrict models/API paths, or make
90
+ `scenario.caps.maxUsd` a preventive provider budget. A hard provider budget needs
91
+ a separately enforced control; do not infer zero spend from an unmeasured ledger
92
+ line.
93
+
94
+ Public internet discovery stays unrestricted unless the lab already declares
95
+ `execution.egressAllow`. The mode preserves that allowlist and its deny-all
96
+ fallback without adding hosts. If an allowlist omits `api.openai.com`, provider
97
+ requests can fail. E2B domain allowlists are routing controls rather than strict
98
+ destination isolation on shared infrastructure. An existing exact OpenAI host
99
+ rule is rejected instead of silently overwritten.
100
+
101
+ Evidence records the selected auth mode and the residual proxy capability.
102
+ Resolved live actor traces use `keyPlacement: external` in `openai-egress`; the
103
+ actor registry continues to describe the default `in-sandbox-command-scoped`
104
+ placement. Dry runs record declarations and prove no live proxy behavior.
105
+
106
+ The upstream contracts are documented in [E2B internet access and network
107
+ rules](https://docs.e2b.dev/network/internet-access) and [Codex advanced
108
+ configuration](https://developers.openai.com/codex/config-advanced),
109
+ [Codex custom CA bundles](https://developers.openai.com/codex/auth#custom-ca-bundles),
110
+ and [E2B's CA installer](https://github.com/e2b-dev/infra/blob/main/packages/envd/internal/host/cacerts.go).
111
+ E2B's installed
112
+ SDK documents that transformed headers override request headers. Deterministic
113
+ request/redaction tests do not establish live wire behavior. The [2026-09-05
114
+ transport receipt](../goals/terminal-product-lane/receipts/2026-09-05-runtime-egress-auth.md)
115
+ records the controlled live header/auth checks and their scope.
116
+
117
+ ## Runtime prerequisite
118
+
119
+ The terminal route reuses a working Node >=20 and npm from the calling shell.
120
+ Otherwise it installs the pinned official Node 22.23.2 Linux x64 or arm64 archive,
121
+ downloaded over verified HTTPS and checked against an architecture-specific
122
+ SHA256 committed in the bootstrap. It does not refresh apt repositories or fetch
123
+ an unpinned checksum beside the archive. Node 22 is a supported LTS line on the
124
+ [official release schedule](https://nodejs.org/en/about/previous-releases); the
125
+ trusted hashes come from its [release manifest](https://nodejs.org/dist/v22.23.2/SHASUMS256.txt).
126
+
127
+ Installation requires `curl`, `sha256sum`, `tar`, `gzip`, `mktemp`, and passwordless
128
+ `sudo`. Only a verified archive is extracted into a root-owned versioned directory
129
+ under `/opt/humanish`; `/usr/local/bin` links make Node/npm/npx available to later
130
+ shells. In that new distribution only, a missing built-in npm `prefix` defaults
131
+ to `/usr/local`, so global product executables use the existing PATH. Existing
132
+ distribution settings and higher-priority npm overrides are preserved; an adopter
133
+ override can still choose a bin directory outside PATH. The installer changes no
134
+ user/global npm configuration, global permissions, or shell startup files. It
135
+ checks Node/npm in both ordinary and sudo shells after installation. The existing
136
+ runtime fast path preserves user-specific installations; a later sudo product
137
+ install can still fail if that installation is absent from sudo's PATH.
138
+
139
+ The [global executable receipt](../goals/terminal-product-lane/receipts/2026-09-05-global-npm-prefix.md)
140
+ records the regression found after the initial runtime-only proof and its stock
141
+ desktop checks. npm documents [global executable locations](https://docs.npmjs.com/cli/v10/configuring-npm/folders#executables)
142
+ and the [distribution built-in configuration](https://docs.npmjs.com/cli/v10/configuring-npm/npmrc#built-in-config-file).
143
+
144
+ An egress allowlist must permit `nodejs.org` if the runtime needs installation,
145
+ as well as the registries and product surfaces the study uses. Missing tools,
146
+ unsupported architectures, a failed download or checksum, and a failed runtime
147
+ check stop the lane before Codex. Downloads have finite connection, transfer, and
148
+ retry bounds within the existing five-minute bootstrap deadline.
149
+
150
+ ## The original command-scoped safety contract
151
+
152
+ The default mode **inverts** the credential-placement default of every other E2B route.
52
153
  On the computer-use route the model's key stays *outside* the sandbox; here the
53
154
  agent-under-test runs *inside* with a real `OPENAI_API_KEY`/`CODEX_API_KEY` and
54
155
  is **presumed exfiltratable**. The doctrine (invariants-and-defaults.md, the
@@ -52,6 +52,20 @@ setup-quality gap, ceremonial/absent study quality, target-app blocker, or
52
52
  Humanish CLI blocker. The OSS
53
53
  meta-lab is one maintainer dogfood example, not the only candidate source.
54
54
 
55
+ For completed computer-use sessions, participant-reported friction comes from
56
+ the redacted closing report and observed-report clauses in earlier messages.
57
+ Matching `stopWhen` or ending a dwell window does not discard an earlier
58
+ report or change the successful completion verdict. Exact repeated reports
59
+ appear once in the lane's candidate. Harness notices, reasoning, and observed
60
+ page content do not become participant findings; quoted app copy and negated
61
+ reports retain the existing exclusions. Code excerpts are treated as quoted
62
+ material. Interim matching requires an observation-shaped clause and filters
63
+ common plans, questions, and hypotheticals; a report followed by a retry plan
64
+ can still qualify. This text
65
+ heuristic does not establish that a reported defect is real or independently
66
+ confirmed. A custom session's closing `reason` remains eligible even when it
67
+ was not repeated in the message trace.
68
+
55
69
  ### `draft`
56
70
 
57
71
  Builds structured feedback from the strongest run candidate first. If no
@@ -3,7 +3,7 @@
3
3
  Date: 2026-06-02 (current-state note updated 2026-07-14)
4
4
 
5
5
  Status: reference map for the major contracts shipped through source version
6
- `0.80.0`; it is not an exhaustive inventory of command/result envelopes. Exported types,
6
+ `0.81.0`; it is not an exhaustive inventory of command/result envelopes. Exported types,
7
7
  schema constants, parsers, and validators in `src/` are authoritative. Rows
8
8
  marked "reserved" name layering intent only — no code emits or validates them
9
9
  yet. Do not emit a reserved schema.
@@ -29,11 +29,19 @@ study completed, reproduced, and produced a real accessibility finding via a
29
29
  keyboard-first participant
30
30
  ([docs/goals/email-gated-signup/receipts/](email-gated-signup/receipts/)).
31
31
 
32
- ## Current Program Truth (source `0.80.0`)
32
+ ## Current Program Truth (source `0.81.0`)
33
33
 
34
34
  The package source and repository implementation in this tree agree on these
35
35
  points:
36
36
 
37
+ **Mobile input correction, 2026-09-05 (#676).** The historical 4/4 TodoMVC phone-lane rename
38
+ failures describe the shipped desktop pointer-to-touch conversion path. In two new hosted
39
+ conformance probes, SDK double click emitted two single clicks; direct touch opened the same
40
+ original editor in both. A separate local native-X control reproduced the difference by toggling
41
+ conversion. Mobile viewport and touch flags do not certify gesture equivalence or establish a
42
+ physical-device app defect. Mobile lanes using touch conversion now carry that advisory in run
43
+ warnings. [Method, traces summary and limits](computer-use-actor/receipts/mobile-input-conformance-2026-09-05.md).
44
+
37
45
  The immutable 2026-06-10 proof-roadmap packet is paired with a
38
46
  [current implementation checkpoint](https://github.com/danielgwilson/humanish/blob/main/docs/goals/proof-roadmap/README.md).
39
47
 
@@ -463,6 +471,23 @@ Stop and correct course if:
463
471
 
464
472
  ## Best Next Work
465
473
 
474
+ **2026-09-05 (0.81.0).** First use now distinguishes the free evidence preview
475
+ from a live participant study, with concise successful setup output and complete JSON details
476
+ (#660). The website has runnable docs and a generated CLI reference (#661, #668). Retained participant
477
+ reports survive automatic stops. Supported providers with retained history can add one closing
478
+ report when time and known budget remain; clean reports such as “no confusion or hesitation”
479
+ stay clean (#658, #670, #671). Desktop startup cleanup retains acquired handles and records
480
+ confirmed or unknown reclamation. The SDK's detached screenshot-file cleanup rejection is
481
+ handled (#665, #666).
482
+ Terminal output reconciles SDK callbacks with returned aggregates, preserving legitimate
483
+ repeated lines and usage turns while avoiding doubled capture (#672). Opt-in `openai-egress`
484
+ auth keeps the raw OpenAI runtime key outside the sandbox; every sandbox process can still
485
+ spend through the proxy, so this is not a provider spending limit (#663). Stock terminal
486
+ startup installs a checksum-verified Node archive without refreshing unrelated package mirrors
487
+ and gives newly installed npm a default global prefix on the standard PATH (#677, #680). Mobile studies warn that desktop pointer-to-touch conversion can change repeated-tap
488
+ behavior; gesture failures require direct or native touch confirmation before app attribution
489
+ (#678).
490
+
466
491
  **2026-09-04, night (0.80.0).** The observation window reaches every desktop route: the
467
492
  sequential and concurrent shared-world seats forward `dwell` the way they forward `stopWhen`
468
493
  (#645), with a plumbing test per route and two live receipts, three participants holding together
@@ -490,8 +515,9 @@ gives a hosted Chrome lane a capture device (ffmpeg's test pattern generated in
490
515
  `desktopBrowser.media`; a microphone is refused without an image that has an audio stack, before
491
516
  any spend. Live, Chrome raised its real dialog with a preview of the feed, the participant chose
492
517
  "Allow this time" and read back 640x480 (`receipts/participant-camera-2026-09-04.md`). Under
493
- mobile emulation the TodoMVC rename now blocks 3 of 3 phone participants; Excalidraw stays clean
494
- at 12 of 12.
518
+ the then-shipped mobile-emulation input path, TodoMVC rename had stopped 3 of 3 phone
519
+ participants at this checkpoint; Excalidraw read 12 of 12. The 2026-09-05 input-conformance
520
+ correction above qualifies attribution of those mobile failures.
495
521
 
496
522
  **2026-09-04, later (0.78.0).** `@e2b/desktop` moved from 2.2.3 to 2.3.3 (#638): its 2.3.1
497
523
  changelog names the socket #581 found today, a background command's event stream the SDK kept
@@ -526,10 +552,10 @@ mobile-emulated browser: `execution.desktop.fidelity.mobileEmulation: true` appl
526
552
  CSS viewport, the preset's device pixel ratio, touch events and a mobile user agent before the
527
553
  participant's first observation, and the bundle records what the page then reported about itself
528
554
  under `desktopGeometry.fidelity` (#221, `docs/goals/computer-use-actor/receipts/mobile-emulation-2026-09-03.md`).
529
- On the published 0.76.0, with touch emulated, neither phone participant on TodoMVC could rename at
530
- all (a double-tap selects text; the double-click editor never opens), where the 500 px runs without
531
- touch had finished and only called the rename touch-hostile: the responsive-viewport study reported
532
- an opinion, the mobile-emulated study reported a blocker.
555
+ On the published 0.76.0, neither phone participant could rename through the emulated input path,
556
+ where the 500 px runs without touch had finished. Those are historical instrument observations:
557
+ the 2026-09-05 conformance check found SDK double click and direct touch differ on the original
558
+ editor, so the earlier outcome does not establish a touch-device app defect.
533
559
  The persona axis was replicated the same evening on drawDB and TodoMVC and given a third app,
534
560
  Excalidraw, as the clean control (`persona-axis-phone-2026-09-03.md`); a multi-lane study's
535
561
  second and third findings reach `feedback draft` through `--candidate` (#609); a negated report
@@ -566,16 +592,22 @@ and a Claude participant with no memory across turns (#520). `humanish stats` (#
566
592
 
567
593
  The standing queue, in rough order:
568
594
 
569
- 1. #581, the remaining half: a `Sandbox.create` that fails after the API allocated the sandbox
595
+ 1. #509, the microphone tier: a custom desktop image with an audio stack
596
+ (`execution.desktop.template`), then `media.microphone` threaded into the launch the way the
597
+ camera is; the parse-time refusal stands until then;
598
+ 2. #581, the remaining half: a `Sandbox.create` that fails after the API allocated the sandbox
570
599
  (the desktop SDK's own startup) leaves a sandbox this run never learned the id of, reclaimed only
571
600
  by the provider's timeout; the linger itself is the SDK's held command stream, closed by the
572
- 2.3.3 bump (0.78.0), and `doctor` names an older SDK;
573
- 2. #513: there is still nowhere to read the docs on humanish.dev (site copy is locked; a docs
601
+ 2.3.3 bump (0.78.0), and `doctor` names an older SDK; the upstream ask is drafted for the
602
+ operator;
603
+ 3. #221's later tier, a real device or simulator behind the emulated lane, and #623's
604
+ scripted-browser route, which has no model loop and so no dwell or later-tab applier;
605
+ 4. #513: there is still nowhere to read the docs on humanish.dev (site copy is locked; a docs
574
606
  route needs the operator's sign-off);
575
- 3. the TUI views over `stats` and `export` (#455's metrics screen and `s` key), design-gated;
576
- 4. the launch post: a draft with every number and its receipt path sits outside the public repo,
607
+ 5. the TUI views over `stats` and `export` (#455's metrics screen and `s` key), design-gated;
608
+ 6. the launch post: a draft with every number and its receipt path sits outside the public repo,
577
609
  awaiting the operator; nothing has been announced;
578
- 5. registry promotions (#431) and the shared-world honesty half (#365, #446), unchanged.
610
+ 7. registry promotions (#431) and the shared-world honesty half (#365, #446), unchanged.
579
611
 
580
612
  Earlier state, kept for the record:
581
613
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  Status: public-safe contributor and agent ramp.
4
4
 
5
- Package/source version in this tree: `0.80.0` (2026-09-04). The Observer is phone-usable as a stated requirement (observer/AGENTS.md); interactive primitives start from Base UI. The Observer renderer is the observer/ workspace artifact only; the legacy string-concat renderer was deleted at cutover (#426), and rollback is a version pin to 0.42.0. The containment boundary introduced in
5
+ Package/source version in this tree: `0.81.0` (2026-09-05). The Observer is phone-usable as a stated requirement (observer/AGENTS.md); interactive primitives start from Base UI. The Observer renderer is the observer/ workspace artifact only; the legacy string-concat renderer was deleted at cutover (#426), and rollback is a version pin to 0.42.0. The containment boundary introduced in
6
6
  `0.15.1` remains in force: managed run and output paths bind to validated
7
7
  physical filesystem identities, and stored provider IDs are evidence, not
8
8
  cleanup authority. The bundled OSS meta-lab is dry-run only until
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "humanish",
3
- "version": "0.80.0",
3
+ "version": "0.81.0",
4
4
  "description": "Open-source-safe CLI for persona simulation, observer review, and public-safe feedback drafts.",
5
5
  "author": "Daniel G Wilson <daniel@danielgwilson.com>",
6
6
  "keywords": [
@@ -73,7 +73,9 @@
73
73
  "tui:typecheck": "pnpm --filter humanish-tui typecheck",
74
74
  "tui:smoke": "node scripts/tui-smoke.mjs",
75
75
  "tui:test": "pnpm --filter humanish-tui test",
76
- "release:dogfood": "node scripts/release-dogfood.mjs"
76
+ "release:dogfood": "node scripts/release-dogfood.mjs",
77
+ "docs:generate": "tsx scripts/generate-cli-docs.ts",
78
+ "docs:check": "tsx scripts/generate-cli-docs.ts --check"
77
79
  },
78
80
  "repository": {
79
81
  "type": "git",