humanish 0.0.1 → 0.15.1
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 +437 -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 +363 -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 +357 -0
- package/dist/codex-app-server-ui.js.map +1 -0
- package/dist/codex-app-server.d.ts +144 -0
- package/dist/codex-app-server.js +754 -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 +1094 -0
- package/dist/concurrent-shared-world-lab.js.map +1 -0
- package/dist/core/git-state.d.ts +33 -0
- package/dist/core/git-state.js +277 -0
- package/dist/core/git-state.js.map +1 -0
- package/dist/core/git-workspace.d.ts +31 -0
- package/dist/core/git-workspace.js +447 -0
- package/dist/core/git-workspace.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 +621 -0
- package/dist/cua-actor-lab.js +2845 -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 +1532 -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 +351 -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 +429 -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 +583 -0
- package/dist/lab-config.js +1789 -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 +382 -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 +306 -0
- package/dist/observer-static.js.map +1 -0
- package/dist/observer.d.ts +46 -0
- package/dist/observer.js +550 -0
- package/dist/observer.js.map +1 -0
- package/dist/openai-responses-cu.d.ts +113 -0
- package/dist/openai-responses-cu.js +545 -0
- package/dist/openai-responses-cu.js.map +1 -0
- package/dist/oss-lab.d.ts +52 -0
- package/dist/oss-lab.js +344 -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 +277 -0
- package/dist/oss-meta-lab.js +4529 -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 +2349 -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-paths.d.ts +56 -0
- package/dist/run-paths.js +340 -0
- package/dist/run-paths.js.map +1 -0
- package/dist/run.d.ts +794 -0
- package/dist/run.js +4844 -0
- package/dist/run.js.map +1 -0
- package/dist/scripted-browser-actor.d.ts +297 -0
- package/dist/scripted-browser-actor.js +1399 -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 +788 -0
- package/dist/scripted-browser-lab.js.map +1 -0
- package/dist/selected-output-paths.d.ts +49 -0
- package/dist/selected-output-paths.js +354 -0
- package/dist/selected-output-paths.js.map +1 -0
- package/dist/shared-world-lab.d.ts +208 -0
- package/dist/shared-world-lab.js +1049 -0
- package/dist/shared-world-lab.js.map +1 -0
- package/dist/source-archive.d.ts +82 -0
- package/dist/source-archive.js +408 -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 +250 -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 +311 -0
- package/docs/contracts/run-bundle.md +358 -0
- package/docs/contracts/schemas.md +984 -0
- package/docs/goals/current.md +428 -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 +237 -0
- package/docs/ramp/README.md +207 -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,250 @@
|
|
|
1
|
+
# Maintainer OSS Meta-Lab
|
|
2
|
+
|
|
3
|
+
Date: 2026-06-01
|
|
4
|
+
|
|
5
|
+
Status: implemented as an experimental repo-owned lab manifest plus
|
|
6
|
+
compatibility aliases.
|
|
7
|
+
|
|
8
|
+
Safety amendment (2026-07-14): beginning with `0.15.1`, the bundled `oss`
|
|
9
|
+
manifest is a contract-only dry-run. A direct live OSS meta-lab request fails
|
|
10
|
+
with `HUMANISH_OSS_META_LIVE_ISOLATION_REQUIRED` before callbacks, filesystem
|
|
11
|
+
or network side effects, credential forwarding, or provider launch. The
|
|
12
|
+
historical design and evidence description below is preserved as a record; it
|
|
13
|
+
is not current execution guidance. The separate `oss-smoke` clone/discard lane
|
|
14
|
+
remains available for public repositories.
|
|
15
|
+
|
|
16
|
+
## Decision
|
|
17
|
+
|
|
18
|
+
`humanish/labs/oss.yaml` is this repo's authorized-repo meta-simulation
|
|
19
|
+
dogfood loop. It is intentionally a lab manifest, not the canonical consumer
|
|
20
|
+
shape. Consumer projects should author their own `humanish/labs/*.yaml` files
|
|
21
|
+
and run them with `humanish watch <lab>` or `humanish lab run <lab>`.
|
|
22
|
+
|
|
23
|
+
The lab should feel like `humanish watch`: it opens the Observer and, for human
|
|
24
|
+
output, keeps the shell attached. Its top-level Observer is an
|
|
25
|
+
Observer-of-Observers: each lane represents a headed E2B desktop assigned to a
|
|
26
|
+
GitHub `owner/repo` slug. Inside each desktop, the bootstrap clones the repo,
|
|
27
|
+
gets it into local dev mode where feasible, installs and initializes Humanish,
|
|
28
|
+
runs nested Humanish proof commands, starts the target app when a runnable
|
|
29
|
+
script is present, opens desktop/mobile app windows plus the nested Observer in
|
|
30
|
+
the E2B browser, and starts a nonblocking Codex actor attempt.
|
|
31
|
+
|
|
32
|
+
The previous clone/discard proof loop remains useful, but it is now explicitly
|
|
33
|
+
named `humanish/labs/oss-smoke.yaml`.
|
|
34
|
+
|
|
35
|
+
## Commands
|
|
36
|
+
|
|
37
|
+
Main operator path:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
humanish watch oss
|
|
41
|
+
humanish lab run oss
|
|
42
|
+
humanish lab run oss --repos CorentinTh/it-tools,drawdb-io/drawdb,maciekt07/TodoApp,lissy93/dashy
|
|
43
|
+
humanish lab run oss --repo CorentinTh/it-tools --repo drawdb-io/drawdb --count 4
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Agent/CI contract path:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
humanish lab run oss --dry-run --json --no-open
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Disposable clone smoke path:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
humanish lab run oss-smoke
|
|
56
|
+
humanish lab run oss-smoke --limit 1 --keep
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Local dogfood shortcuts:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
pnpm humanish:lab:oss
|
|
63
|
+
pnpm humanish:lab:oss:ci
|
|
64
|
+
pnpm humanish:lab:oss:smoke
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Repo Selection
|
|
68
|
+
|
|
69
|
+
The default public targets are product-like, locally runnable apps/tools:
|
|
70
|
+
|
|
71
|
+
- `CorentinTh/it-tools`
|
|
72
|
+
- `drawdb-io/drawdb`
|
|
73
|
+
- `maciekt07/TodoApp`
|
|
74
|
+
- `lissy93/dashy`
|
|
75
|
+
|
|
76
|
+
Target selection should minimize distance from a real user-facing journey.
|
|
77
|
+
Good defaults expose an app, CLI, or agent-facing tool that can be tried out of
|
|
78
|
+
the box, preferably with a local dev script and no account setup. Libraries,
|
|
79
|
+
frameworks, starters, and infrastructure packages belong only in scenarios that
|
|
80
|
+
explicitly test developer experience. They are poor defaults for proving
|
|
81
|
+
Humanish as a user-simulation harness because they add another abstract setup
|
|
82
|
+
layer before any product behavior is visible.
|
|
83
|
+
|
|
84
|
+
`--repos` accepts a comma-separated list. Repeated `--repo` is also supported.
|
|
85
|
+
If `--count` is larger than the repo list, assignments cycle through the repo
|
|
86
|
+
pool. Inputs must be GitHub `owner/repo` slugs. Arbitrary URLs, local paths,
|
|
87
|
+
tokens, and SSH remotes are rejected. Private repos are maintainer-only and
|
|
88
|
+
require an authorized `GH_TOKEN` or `GITHUB_TOKEN` at runtime; no token value is
|
|
89
|
+
written to committed source or public issue text.
|
|
90
|
+
|
|
91
|
+
## Private Product Labs
|
|
92
|
+
|
|
93
|
+
Private products can be used for local maintainer dogfood, but they must stay
|
|
94
|
+
out of the public package surface. Do not commit private repo names as defaults,
|
|
95
|
+
fixtures, screenshots, README examples, npm assets, skill examples, or issue
|
|
96
|
+
draft text.
|
|
97
|
+
|
|
98
|
+
The safe local shape is:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
humanish watch .humanish/labs/private-app.yaml --env-file .humanish/local/provider.env
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
with an authorized runtime GitHub token and default repo redaction enabled.
|
|
105
|
+
Do not pass `--no-redact-repos` for a private target. Public receipts for
|
|
106
|
+
those runs should say `authorized private app target` and point only to ignored
|
|
107
|
+
local artifact paths, redacted statuses, and verifier results. Never publish
|
|
108
|
+
private screenshots, logs, app URLs, source snippets, branch names, issue
|
|
109
|
+
names, stream URLs, or operational details.
|
|
110
|
+
|
|
111
|
+
## Runtime Shape
|
|
112
|
+
|
|
113
|
+
The meta-lab writes ignored local Observer evidence:
|
|
114
|
+
|
|
115
|
+
```text
|
|
116
|
+
.humanish/
|
|
117
|
+
runs/<oss-meta-run-id>/
|
|
118
|
+
run.json
|
|
119
|
+
review.json
|
|
120
|
+
review.md
|
|
121
|
+
events.ndjson
|
|
122
|
+
observer/
|
|
123
|
+
index.html
|
|
124
|
+
observer-data.json
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Each stream lane records:
|
|
128
|
+
|
|
129
|
+
- assigned repo slug for public runs, or a redacted lane label for token-backed
|
|
130
|
+
maintainer/private runs;
|
|
131
|
+
- whether a live E2B desktop stream exists; auth-bearing stream URLs are
|
|
132
|
+
runtime-only for the attached Observer server and are not persisted;
|
|
133
|
+
- target app URL/status when a runnable script becomes HTTP-ready inside the
|
|
134
|
+
sandbox;
|
|
135
|
+
- nested Observer presence and nested verification status;
|
|
136
|
+
- headed desktop visual-window status and browser window count;
|
|
137
|
+
- Codex actor status, optionally moved before deterministic setup with
|
|
138
|
+
`HUMANISH_OSS_META_ACTOR_FIRST=1` and required through
|
|
139
|
+
`HUMANISH_OSS_META_REQUIRE_ACTOR=1`;
|
|
140
|
+
- setup-quality filesystem evidence: shallow tree, Humanish setup checks,
|
|
141
|
+
package scripts, study-quality rating, and allowlisted previews for public
|
|
142
|
+
runs;
|
|
143
|
+
- public-safe remote bootstrap log tail;
|
|
144
|
+
- public-safe gaps and events.
|
|
145
|
+
|
|
146
|
+
The current implementation launches live E2B desktop streams when
|
|
147
|
+
`E2B_API_KEY` and `OPENAI_API_KEY` are present, overlays those stream URLs only
|
|
148
|
+
in the attached Observer server, and marks missing key or launch failures
|
|
149
|
+
in-lane. It also packs the local Humanish package, uploads it into each sandbox,
|
|
150
|
+
raises a visible bootstrap terminal, clones the assigned repo, runs nested
|
|
151
|
+
Humanish setup and proof commands, starts the target app, opens desktop/mobile
|
|
152
|
+
app windows, opens the nested Observer in the sandbox browser, arranges visible
|
|
153
|
+
browser windows for screenshot proof, and starts the Codex actor attempt. By
|
|
154
|
+
default the actor remains nonblocking and runs after deterministic readback; with
|
|
155
|
+
`HUMANISH_OSS_META_ACTOR_FIRST=1`, the actor attempts setup/use before
|
|
156
|
+
deterministic validation; with `HUMANISH_OSS_META_REQUIRE_ACTOR=1`, the bootstrap
|
|
157
|
+
waits up to `HUMANISH_OSS_META_ACTOR_TIMEOUT_MS` for terminal actor readback and
|
|
158
|
+
will not mark the lane passed unless the actor exits cleanly.
|
|
159
|
+
|
|
160
|
+
When the remote bootstrap completes, the host persists a local
|
|
161
|
+
`setup-quality/<stream>-setup-quality.json` artifact. The Observer Files tab can
|
|
162
|
+
render it inline from the served Observer. Static `file://` observers keep the
|
|
163
|
+
artifact link openable but do not hydrate it inline. Token-backed/private runs
|
|
164
|
+
suppress raw file previews by default while preserving the setup checks and
|
|
165
|
+
tree shape. They also preserve `studyQuality` structural signals so an actor
|
|
166
|
+
that merely installs Humanish receives a `ceremonial` rating instead of being
|
|
167
|
+
treated as successful user-study leverage.
|
|
168
|
+
|
|
169
|
+
The live desktop substrate is an optional peer dependency. Install it in the
|
|
170
|
+
project that runs live labs:
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
npm i -D @e2b/desktop
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Remaining substrate work: upgrade the nested `--app-url` browser proof into
|
|
177
|
+
provider-backed personas that actually drive multi-step target-app journeys,
|
|
178
|
+
and live-prove actor-first setup/use, not only deterministic bootstrap readback.
|
|
179
|
+
|
|
180
|
+
## Smoke Harness Runtime
|
|
181
|
+
|
|
182
|
+
`humanish lab run oss-smoke` shallow clones lightweight public GitHub repos into
|
|
183
|
+
ignored runtime state, applies Humanish setup inside each throwaway clone, runs
|
|
184
|
+
the synthetic four-lane proof path, verifies the generated bundle, records
|
|
185
|
+
git-status evidence, writes an ignored report, and removes cloned repos by
|
|
186
|
+
default.
|
|
187
|
+
|
|
188
|
+
```text
|
|
189
|
+
.humanish/
|
|
190
|
+
lab/oss/<run-id>/
|
|
191
|
+
report.json
|
|
192
|
+
report.md
|
|
193
|
+
tmp/oss-lab/<run-id>/
|
|
194
|
+
repos... # removed by default
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Each cloned repo receives disposable uncommitted changes:
|
|
198
|
+
|
|
199
|
+
- `humanish/` source starter files;
|
|
200
|
+
- `.humanish/` runtime state;
|
|
201
|
+
- `.gitignore` updates;
|
|
202
|
+
- `package.json` script updates;
|
|
203
|
+
- synthetic run/Observer evidence under the clone's ignored `.humanish/`.
|
|
204
|
+
|
|
205
|
+
The clone is removed unless `--keep` is passed. The host report remains under
|
|
206
|
+
ignored `.humanish/lab/oss/<run-id>/`.
|
|
207
|
+
|
|
208
|
+
## Safety Rules
|
|
209
|
+
|
|
210
|
+
- GitHub `owner/repo` slugs only.
|
|
211
|
+
- Private repos require an authorized runtime token. Token-backed runs redact
|
|
212
|
+
repo labels in durable artifacts by default and must not appear in committed
|
|
213
|
+
fixtures, docs examples, public issue text, or published media.
|
|
214
|
+
- pnpm dependency build scripts may be allowed only inside the disposable E2B
|
|
215
|
+
lab so target app surfaces can start. Never use this as a host install
|
|
216
|
+
default.
|
|
217
|
+
- No credential prompts; smoke clone calls set `GIT_TERMINAL_PROMPT=0`.
|
|
218
|
+
- No commits, pushes, branches, tags, GitHub API mutation, deploys, or issue
|
|
219
|
+
filing.
|
|
220
|
+
- Do not write key values into committed `humanish/` source.
|
|
221
|
+
- Do not emit PII, PHI, raw private transcripts, private screenshots, secrets,
|
|
222
|
+
keys, or private upstream artifacts.
|
|
223
|
+
|
|
224
|
+
## What This Proves
|
|
225
|
+
|
|
226
|
+
The meta-lab proves the operator control surface and artifact contract for
|
|
227
|
+
watching multiple Codex/E2B setup attempts at once. The live path now detects
|
|
228
|
+
E2B desktop fanout, visible bootstrap terminals, local-package upload,
|
|
229
|
+
disposable authorized-repo setup, target app HTTP readiness when a runnable
|
|
230
|
+
script is present, headed browser-window layout, nested live `--app-url`
|
|
231
|
+
desktop/mobile browser proof when the target app runs, nested Observer opening,
|
|
232
|
+
and top-level lane completion from remote evidence. It does not yet prove a
|
|
233
|
+
general provider-backed multi-step target-app persona runtime.
|
|
234
|
+
|
|
235
|
+
The smoke harness proves first-run Humanish package compatibility against
|
|
236
|
+
arbitrary public JavaScript repositories:
|
|
237
|
+
|
|
238
|
+
- setup can patch real package.json files without committing;
|
|
239
|
+
- generated `humanish/` source can coexist with external repo layout;
|
|
240
|
+
- ignored `.humanish/` runtime proof can be generated;
|
|
241
|
+
- the Observer can render from those disposable proofs;
|
|
242
|
+
- verification passes before the clone is discarded.
|
|
243
|
+
|
|
244
|
+
Neither path may claim private product behavior proof without live, redacted,
|
|
245
|
+
public-safe evidence.
|
|
246
|
+
|
|
247
|
+
Feedback candidates are derived from this evidence when a lane records concrete
|
|
248
|
+
setup-quality gaps, ceremonial/absent study quality, or actor-reported Humanish
|
|
249
|
+
CLI blockers. `humanish feedback` uses those candidates before falling back to
|
|
250
|
+
generic dry-run follow-up drafts.
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# Project Layout Contract
|
|
2
|
+
|
|
3
|
+
Date: 2026-06-01
|
|
4
|
+
|
|
5
|
+
Status: target layout for apps that install `humanish`.
|
|
6
|
+
|
|
7
|
+
## Decision
|
|
8
|
+
|
|
9
|
+
Use two roots:
|
|
10
|
+
|
|
11
|
+
```text
|
|
12
|
+
humanish/ # committed source of simulation intent
|
|
13
|
+
.humanish/ # ignored runtime state, evidence, local overlays, and secrets
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Do not gitignore all Humanish state. Labs, personas, scenarios, policies,
|
|
17
|
+
adapters, coverage maps, and review vocabulary are the harness. They must be
|
|
18
|
+
versioned, reviewed, and reproducible from a clean clone.
|
|
19
|
+
|
|
20
|
+
Do not commit run bundles, raw screenshots, browser traces, transcripts,
|
|
21
|
+
draft issue bodies before verification, local auth, local overrides, or secrets.
|
|
22
|
+
|
|
23
|
+
## Committed Source Plane
|
|
24
|
+
|
|
25
|
+
`humanish/` is the project-owned simulation contract:
|
|
26
|
+
|
|
27
|
+
```text
|
|
28
|
+
humanish/
|
|
29
|
+
README.md
|
|
30
|
+
config.ts
|
|
31
|
+
personas/
|
|
32
|
+
synthetic-new-user.yaml
|
|
33
|
+
skeptical-power-user.yaml
|
|
34
|
+
scenarios/
|
|
35
|
+
first-run-smoke.yaml
|
|
36
|
+
onboarding-regression.yaml
|
|
37
|
+
labs/
|
|
38
|
+
first-run.yaml
|
|
39
|
+
policies/
|
|
40
|
+
redaction.yaml
|
|
41
|
+
network.yaml
|
|
42
|
+
credentials.example.yaml
|
|
43
|
+
adapters/
|
|
44
|
+
app.ts
|
|
45
|
+
review/
|
|
46
|
+
vocabulary.yaml
|
|
47
|
+
milestones.yaml
|
|
48
|
+
coverage-map.md
|
|
49
|
+
coverage-matrix.md
|
|
50
|
+
fixtures/
|
|
51
|
+
synthetic-login-state.json
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Humanish Format Stack
|
|
55
|
+
|
|
56
|
+
Use formats based on who edits the file and how it is consumed:
|
|
57
|
+
|
|
58
|
+
- `.yaml` for human-authored Humanish source: personas, scenarios, policies,
|
|
59
|
+
labs, review vocabulary, and review milestones. Prefer `.yaml` over `.yml`
|
|
60
|
+
for Humanish-owned source files.
|
|
61
|
+
- `.ts` for executable project integration: `humanish/config.ts`, adapters,
|
|
62
|
+
route catalogs, app launch plans, and logic that benefits from imports or
|
|
63
|
+
type checking.
|
|
64
|
+
- `.json` for generated machine artifacts and synthetic fixtures: run bundles,
|
|
65
|
+
observer data, review JSON, latest/history pointers, and fixture records.
|
|
66
|
+
- `.ndjson` for appendable event or transcript streams.
|
|
67
|
+
- `.yml` is acceptable for ecosystem files that conventionally use it, such as
|
|
68
|
+
`.github/workflows/*.yml`; do not use `.yml` for Humanish-owned authored
|
|
69
|
+
source.
|
|
70
|
+
|
|
71
|
+
Do not convert personas or scenarios to JSON because parser implementation is
|
|
72
|
+
easier. Keep authored simulation intent readable, then validate it through
|
|
73
|
+
schemas and CLI checks. TOML is not part of the current Humanish stack; add it
|
|
74
|
+
only if a concrete scalar global-config need appears that is better served by
|
|
75
|
+
TOML than YAML, TypeScript, or JSON.
|
|
76
|
+
|
|
77
|
+
Committed files must be public-safe:
|
|
78
|
+
|
|
79
|
+
- synthetic personas only;
|
|
80
|
+
- synthetic or redacted fixtures only;
|
|
81
|
+
- env var names only, never values;
|
|
82
|
+
- no PHI, PII, keys, tokens, raw private transcripts, real screenshots, real
|
|
83
|
+
customer data, or real patient data.
|
|
84
|
+
|
|
85
|
+
Changing a scenario or persona is equivalent to changing a test. It should be
|
|
86
|
+
visible in PR review.
|
|
87
|
+
|
|
88
|
+
## Ignored Runtime Plane
|
|
89
|
+
|
|
90
|
+
`.humanish/` is local/generated state:
|
|
91
|
+
|
|
92
|
+
```text
|
|
93
|
+
.humanish/
|
|
94
|
+
runs/
|
|
95
|
+
<run-id>/
|
|
96
|
+
run.json
|
|
97
|
+
review.md
|
|
98
|
+
review.json
|
|
99
|
+
observer/
|
|
100
|
+
screenshots/
|
|
101
|
+
traces/
|
|
102
|
+
terminal/
|
|
103
|
+
feedback/
|
|
104
|
+
cache/
|
|
105
|
+
tmp/
|
|
106
|
+
logs/
|
|
107
|
+
labs/
|
|
108
|
+
local/
|
|
109
|
+
labs/
|
|
110
|
+
personas/
|
|
111
|
+
policies/
|
|
112
|
+
secrets/
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Default `.gitignore` entry:
|
|
116
|
+
|
|
117
|
+
```gitignore
|
|
118
|
+
.humanish/
|
|
119
|
+
.env*
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
If a target repo already uses `.env.example`, preserve its existing exception.
|
|
123
|
+
|
|
124
|
+
## Local Overrides
|
|
125
|
+
|
|
126
|
+
When a team needs private local personas or credentials, use ignored overlays:
|
|
127
|
+
|
|
128
|
+
```text
|
|
129
|
+
.humanish/local/personas/*.yaml
|
|
130
|
+
.humanish/local/policies/*.yaml
|
|
131
|
+
.humanish/local/labs/*.yaml
|
|
132
|
+
.humanish/labs/*.yaml
|
|
133
|
+
.humanish/secrets/*
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Committed `humanish/labs/*.yaml` should be useful to anyone with a clean clone.
|
|
137
|
+
Ignored `.humanish/labs/*.yaml` and `.humanish/local/labs/*.yaml` are for
|
|
138
|
+
machine-specific or private dogfood labs. The CLI should warn that local
|
|
139
|
+
overlays cannot be used for reproducible CI or public issue drafts unless
|
|
140
|
+
redacted into committed synthetic equivalents.
|
|
141
|
+
|
|
142
|
+
## CI And Reproducibility
|
|
143
|
+
|
|
144
|
+
CI should reproduce proof from committed inputs:
|
|
145
|
+
|
|
146
|
+
- app commit;
|
|
147
|
+
- `humanish` version;
|
|
148
|
+
- `humanish/config.ts`;
|
|
149
|
+
- scenario and persona catalog;
|
|
150
|
+
- lab manifest;
|
|
151
|
+
- policy files;
|
|
152
|
+
- synthetic fixtures;
|
|
153
|
+
- declared env var names.
|
|
154
|
+
|
|
155
|
+
CI should store generated run bundles as artifacts, not commit them.
|
|
156
|
+
|
|
157
|
+
## Why Not `.humanish/` For Everything?
|
|
158
|
+
|
|
159
|
+
A fully ignored `.humanish/` makes setup feel tidy, but it hides the product
|
|
160
|
+
contract. Future agents and contributors cannot see what the harness is meant
|
|
161
|
+
to prove, CI cannot validate it from a clean clone, and PR review cannot catch
|
|
162
|
+
weakened personas or dropped hard paths.
|
|
163
|
+
|
|
164
|
+
A partially tracked dotdir is possible but worse UX. Dotdirs read as local,
|
|
165
|
+
editors hide them, and negated gitignore rules are easy to break. A visible
|
|
166
|
+
`humanish/` source root plus ignored `.humanish/` runtime root is clearer.
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# State-driven executor (the `CuaExecutor` port)
|
|
2
|
+
|
|
3
|
+
Date: 2026-06-15
|
|
4
|
+
|
|
5
|
+
Status: shipped (PR1 of issue #148). The library path (a custom executor + a
|
|
6
|
+
non-vision provider, driven through the lab with NO E2B and NO vision) is
|
|
7
|
+
implemented and proven. A config-only deterministic lane and a
|
|
8
|
+
`subject.contract.ref` JS-module loader are deferred (see "Deferred", below).
|
|
9
|
+
|
|
10
|
+
## What this is
|
|
11
|
+
|
|
12
|
+
The computer-use (CUA) loop in [`src/computer-use.ts`](../../src/computer-use.ts)
|
|
13
|
+
is provider- and substrate-agnostic by design: the model lives behind a
|
|
14
|
+
`CuaProvider` port and the thing being driven lives behind a `CuaExecutor` port.
|
|
15
|
+
You do not have to drive a screen with a vision model. You can point the loop at
|
|
16
|
+
**an already-running local app** and drive it through that app's **in-process
|
|
17
|
+
JavaScript automation contract** (e.g. `window.app.getState()`,
|
|
18
|
+
`sendChat(text)`, `dispatch(action)`, `navigate(target)`), using `getState()` as
|
|
19
|
+
the progress signal instead of a quantized screenshot — keeping humanish's
|
|
20
|
+
composition (personas, the Observer, the normalized `ActorTrace` evidence
|
|
21
|
+
bundle, redaction, and the friction / no-progress loop).
|
|
22
|
+
|
|
23
|
+
This is the "plural harnesses / transport-agnostic" intent of
|
|
24
|
+
[`actor-contract.md`](./actor-contract.md), made into a supported seam.
|
|
25
|
+
|
|
26
|
+
## The port
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
interface CuaExecutor {
|
|
30
|
+
observe(): Promise<CuaObservation>; // capture current state
|
|
31
|
+
execute(action: CuaAction): Promise<void>; // perform one action
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface CuaObservation {
|
|
35
|
+
screenshot?: Buffer; // OPTIONAL — a state executor omits it
|
|
36
|
+
stateSignature: string; // REQUIRED — the fallback progress key
|
|
37
|
+
appState?: Record<string, unknown>; // structured state; preferred for progress
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
- **`screenshot` is optional.** A non-vision (state) executor omits it. The loop
|
|
42
|
+
persists no screenshot that turn; `counts.screenshots` stays 0, so the trace's
|
|
43
|
+
`redaction.screenshots` resolves to `"n/a"`. No fabricated `Buffer.alloc(0)`
|
|
44
|
+
ever reaches disk. (A vision executor still returns a frame, exactly as before.)
|
|
45
|
+
- **`stateSignature` is still required.** Derive it from your own state — e.g.
|
|
46
|
+
`JSON.stringify({ route, turn, modal })`. It is the canonical fallback progress
|
|
47
|
+
key when `appState` is absent. It is never written to the trace as text.
|
|
48
|
+
- **`appState` is the preferred progress input.** When present, the loop's
|
|
49
|
+
friction / no-progress detection keys off a deterministic, sorted-key,
|
|
50
|
+
depth/length-capped projection of it (`stableProgressKey`) rather than the
|
|
51
|
+
signature. So a route change drives "progress" even when a quantized signature
|
|
52
|
+
would not, and key insertion order can never fabricate a delta.
|
|
53
|
+
|
|
54
|
+
### `stateSignature` vs `appState`
|
|
55
|
+
|
|
56
|
+
Either is enough on its own. `appState` is preferred because `getState()` is a
|
|
57
|
+
far more reliable progress signal than a quantized screenshot signature on a
|
|
58
|
+
graphically dense (pixel-art) UI. `stableProgressKey(appState)`:
|
|
59
|
+
|
|
60
|
+
- sorts object keys (order-independent — shuffled keys ARE NOT progress);
|
|
61
|
+
- caps depth, key count, array length, string length, and total output;
|
|
62
|
+
- never throws on a cyclic or huge `appState` — it degrades to a bounded value
|
|
63
|
+
(cycles become `"[Circular]"`, over-cap nodes become markers). This is
|
|
64
|
+
correctness-load-bearing: a hostile or merely large state blob cannot crash the
|
|
65
|
+
loop.
|
|
66
|
+
|
|
67
|
+
## You need a NON-vision provider too
|
|
68
|
+
|
|
69
|
+
Swapping the executor is not enough. The default OpenAI computer-use provider is
|
|
70
|
+
**vision-based**: it sends the screenshot as the `computer_call_output`, so a
|
|
71
|
+
screenshot-less observation would crash it. A genuinely non-vision flow swaps
|
|
72
|
+
**both** the executor (the state contract) **and** the provider (a brain that
|
|
73
|
+
reasons over app state).
|
|
74
|
+
|
|
75
|
+
**Provider-authoring contract:**
|
|
76
|
+
|
|
77
|
+
- A **vision** provider MUST set `requiresFrame: true` (the OpenAI provider does).
|
|
78
|
+
When a `requiresFrame: true` provider is handed a screenshot-less observation,
|
|
79
|
+
the loop fails closed with a structured `harness_error` per turn — not a silent
|
|
80
|
+
crash, not a false pass.
|
|
81
|
+
- A **state-reasoning** provider omits `requiresFrame` (defaults falsey) and reads
|
|
82
|
+
`req.observation.appState`.
|
|
83
|
+
|
|
84
|
+
`requiresFrame` defaulting to falsey is a known third-party-author footgun (a
|
|
85
|
+
vision provider that forgets to set it would get a blank-frame crash instead of a
|
|
86
|
+
clean verdict). This slice accepts it because only one vision provider exists
|
|
87
|
+
today, and records it here.
|
|
88
|
+
|
|
89
|
+
## `appState` is RUNTIME-ONLY (not evidence, in this slice)
|
|
90
|
+
|
|
91
|
+
`appState` is an in-memory progress-comparison input, exactly like
|
|
92
|
+
`stateSignature` (which is itself never written as text). It is **never** copied
|
|
93
|
+
into any `ActorTraceItem`, reason, id, or count, and is **never** persisted to the
|
|
94
|
+
trace. Only the derived progress key is computed in-memory and discarded.
|
|
95
|
+
|
|
96
|
+
Why: the published-evidence scan catches only secret-*shaped* patterns. A
|
|
97
|
+
structured app blob (ids, free-form state, possibly user chat or shapeless
|
|
98
|
+
tokens) is exactly the "value has no shape" gap that pattern redaction cannot
|
|
99
|
+
close. So this slice does not treat `appState` as an evidence surface at all.
|
|
100
|
+
|
|
101
|
+
The bundle is self-describing about it (invariant 6): when a state executor
|
|
102
|
+
surfaces `appState`, the trace's `redaction.notes` declares that app state was
|
|
103
|
+
observed each turn to drive progress detection and was NOT written to the trace.
|
|
104
|
+
|
|
105
|
+
A future "appState in evidence" slice MUST route a stringified projection through
|
|
106
|
+
`redaction.redactText` (and the lab's `scrubText`) AND cap / whitelist fields
|
|
107
|
+
before persisting — pattern + literal redaction alone cannot sanitize an
|
|
108
|
+
arbitrary blob.
|
|
109
|
+
|
|
110
|
+
## Provenance is honestly UNPINNED (invariant 5)
|
|
111
|
+
|
|
112
|
+
An already-running local dev server cannot be commit-pinned. The bundle does not
|
|
113
|
+
silently omit a subject block — it DECLARES the absence: `subject.source:
|
|
114
|
+
app-url` with `state.provenance: "undeclared"` (the app-url "absence declared"
|
|
115
|
+
marker), and a `cua-lab.subject.declared` event that states the entry is a local
|
|
116
|
+
dev server driven in-process, caller-provisioned and UNPINNED, with no E2B
|
|
117
|
+
desktop created.
|
|
118
|
+
|
|
119
|
+
## Two entry points
|
|
120
|
+
|
|
121
|
+
### 1. Bare `runComputerUseLoop` (lowest level)
|
|
122
|
+
|
|
123
|
+
Implement `CuaExecutor.observe()/execute()`, derive `stateSignature`/`appState`
|
|
124
|
+
from your own state, pair it with a non-vision `CuaProvider`, and call
|
|
125
|
+
`runComputerUseLoop`. You own the bundle/redaction wiring.
|
|
126
|
+
|
|
127
|
+
### 2. `runLab` + `buildExecutor` / `buildProvider` (keeps the composition)
|
|
128
|
+
|
|
129
|
+
The supported library path. It keeps personas, the Observer, the evidence
|
|
130
|
+
bundle, redaction, and the friction loop, while skipping E2B entirely:
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
import { runLab, parseLabConfig, type CuaExecutor, type CuaProvider } from "humanish";
|
|
134
|
+
|
|
135
|
+
// local-app YAML (shareable; fails closed without hooks):
|
|
136
|
+
// schema: humanish.lab.v2
|
|
137
|
+
// id: pixel-bae-state
|
|
138
|
+
// subject: { source: local-app, appUrl: http://localhost:5173 }
|
|
139
|
+
// actors: [{ type: openai-computer-use, persona: pixel-pat, mission: "…" }]
|
|
140
|
+
// scenario: { mode: live }
|
|
141
|
+
const parsed = parseLabConfig(yaml);
|
|
142
|
+
if (!parsed.ok) throw new Error(parsed.error.message);
|
|
143
|
+
|
|
144
|
+
const outcome = await runLab(parsed.config, {
|
|
145
|
+
cwd: process.cwd(),
|
|
146
|
+
dryRun: false,
|
|
147
|
+
cuaHooks: {
|
|
148
|
+
buildExecutor: async ({ appUrl }) => createAppContractExecutor(bridge, appUrl),
|
|
149
|
+
buildProvider: async () => createStateBrain(),
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
// outcome.backend === "cua"; outcome.result.sandbox === undefined (NO E2B); the
|
|
153
|
+
// trace's provider id is the injected brain's id.
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
When `cuaHooks.buildExecutor` is set, `runCuaActorLab` takes a branch that NEVER
|
|
157
|
+
loads the E2B module, creates a sandbox, runs `prepareDesktop`, provisions a
|
|
158
|
+
clone, opens a browser, or starts a stream. `sandboxId`/`streamUrl` stay
|
|
159
|
+
undefined, so `result.sandbox` is omitted — the verifiable "no E2B SDK call"
|
|
160
|
+
proof.
|
|
161
|
+
|
|
162
|
+
Two boot-time fail-closed guards (both BEFORE any key check, so a CLI invocation
|
|
163
|
+
never sees a misleading `KEYS_MISSING` first):
|
|
164
|
+
|
|
165
|
+
- `HUMANISH_CUA_LAB_EXECUTOR_NO_PROVIDER` — `buildExecutor` without `buildProvider`
|
|
166
|
+
(a state executor MUST be paired with a non-vision provider). `buildProvider`
|
|
167
|
+
ALONE is allowed — that is just a model swap on the normal E2B route.
|
|
168
|
+
- `HUMANISH_CUA_LAB_LOCAL_APP_NO_EXECUTOR` — a `subject.source: local-app` config
|
|
169
|
+
run with no `buildExecutor` hook (there is no built-in in-process driver yet).
|
|
170
|
+
A structured error, never a desktop attempt.
|
|
171
|
+
|
|
172
|
+
Key gating is route-aware: the in-process route uses the caller's OWN model and
|
|
173
|
+
executor, so no `OPENAI_API_KEY`/`E2B_API_KEY` is required.
|
|
174
|
+
|
|
175
|
+
## A note on `appState` typing
|
|
176
|
+
|
|
177
|
+
`CuaObservation.appState` is `Record<string, unknown> | undefined` under the
|
|
178
|
+
repo's strict flags (`exactOptionalPropertyTypes`, `noUncheckedIndexedAccess`).
|
|
179
|
+
A value typed as an `interface` does NOT satisfy `Record<string, unknown>`
|
|
180
|
+
(interfaces have no implicit index signature), and a direct `as Record<...>` cast
|
|
181
|
+
on an interface-typed value is rejected. Use one of:
|
|
182
|
+
|
|
183
|
+
- a `type` alias for your state shape (type aliases get the index signature);
|
|
184
|
+
- a spread into a fresh object literal (`{ ...state }`); or
|
|
185
|
+
- `as unknown as Record<string, unknown>`.
|
|
186
|
+
|
|
187
|
+
Read every optional field defensively, and spread-omit optional fields
|
|
188
|
+
(`...(x === undefined ? {} : { x })`) rather than assigning `undefined`.
|
|
189
|
+
|
|
190
|
+
## Deferred (tracked, not shipped here)
|
|
191
|
+
|
|
192
|
+
- **PR2 — a config-only deterministic `state-contract` lane.** A registered,
|
|
193
|
+
model-free lane driving a built-in `window.app.*` bridge over the existing
|
|
194
|
+
`ScriptedPageLike.evaluate` primitive + a YAML step program, `scenario.mode:
|
|
195
|
+
live` gating actuation. It would be deterministic step replay, NOT
|
|
196
|
+
`runComputerUseLoop`, and must not overclaim friction-loop reuse.
|
|
197
|
+
- **PR3 — a `subject.contract.ref` JS-module loader.** A config-referenced module
|
|
198
|
+
loaded and run in-process with full harness privileges is a genuinely NEW trust
|
|
199
|
+
surface with no precedent in this repo (the scripted lane loads only declarative
|
|
200
|
+
YAML; serve commands run isolated inside the disposable E2B sandbox). It earns
|
|
201
|
+
its place only behind its own clamping / trust / digest-pinning design.
|
|
202
|
+
pixel-bae does not need it: a library caller builds the bridge in their own
|
|
203
|
+
trusted code (entry point 2 above).
|