@aarwitz/tapp 0.15.1 → 0.16.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 CHANGED
@@ -18,7 +18,7 @@ npx -y @aarwitz/tapp shot # screenshot the booted sim → file path (
18
18
  npx -y @aarwitz/tapp apps # what's installed on the simulator, with bundle ids
19
19
  npx -y @aarwitz/tapp build [dir] # build the app in an Xcode repo + install it (≈ tapp_build)
20
20
  npx -y @aarwitz/tapp qa app.apk --platform android --app-id com.acme.app
21
- npx -y @aarwitz/tapp flow run .autotap/flows/smoke.yml # committed, keyless E2E replay
21
+ npx -y @aarwitz/tapp flow run .tapp/flows/smoke.yml # committed, keyless E2E replay
22
22
  ```
23
23
 
24
24
  **Seeing the screen, per client:** if you can read image files into your context (Claude
@@ -92,13 +92,13 @@ Returns `{verdict, confidence, headline, screensExplored, actionsPerformed, find
92
92
 
93
93
  ## Flows (deterministic E2E tests)
94
94
 
95
- Flow YAML is repository-native test code. Commit it under `.autotap/flows/`; CI can replay it
95
+ Flow YAML is repository-native test code. Commit it under `.tapp/flows/`; CI can replay it
96
96
  without a coding agent, model, subscription, or API key. AI generation and `assert_ai` are optional.
97
97
 
98
98
  - **Record:** every successful `session_act` is recorded. After driving a flow, call
99
- `tapp_flow_save { name: "checkout" }` → writes `.autotap/flows/checkout.yml` with waits and
99
+ `tapp_flow_save { name: "checkout" }` → writes `.tapp/flows/checkout.yml` with waits and
100
100
  a final screen assertion auto-inserted; typed credentials are templated to `$TEST_EMAIL`/`$TEST_PASSWORD`.
101
- - **Replay:** `tapp_flow_run { flowPath: ".autotap/flows/checkout.yml" }` — exact steps,
101
+ - **Replay:** `tapp_flow_run { flowPath: ".tapp/flows/checkout.yml" }` — exact steps,
102
102
  deterministic assertions, same result every time. A failed assertion is a finding.
103
103
  - **Generate:** `tapp_flow_generate { goal: "log in and add the first item to cart" }` —
104
104
  grounded in the app's actually-explored screens, so it can't invent steps.
package/README.md CHANGED
@@ -90,9 +90,9 @@ npx -y @aarwitz/tapp ci install .
90
90
  ```
91
91
 
92
92
  The baseline command writes only after autonomous QA and every selected deterministic suite pass
93
- conclusively. It stores `.autotap/baselines/<platform>/<target-id>.json`; the generated workflow
93
+ conclusively. It stores `.tapp/baselines/<platform>/<target-id>.json`; the generated workflow
94
94
  uses that exact target identity so two apps on the same platform never share a baseline. `ci
95
- install` writes `.github/workflows/tapp.yml` plus `.autotap/ci.json`, refuses unresolved build
95
+ install` writes `.github/workflows/tapp.yml` plus `.tapp/ci.json`, refuses unresolved build
96
96
  configuration and existing-file collisions, and never commits, pushes, enables branch protection,
97
97
  or creates GitHub resources. Review and pin the generated Tapp release reference to its immutable
98
98
  commit SHA before production.
@@ -182,8 +182,8 @@ Then ask your agent:
182
182
 
183
183
  Full agent playbook: [AGENTS.md](./AGENTS.md) — ships inside the package so agents can read it too.
184
184
  Application-model and import contract: [`docs/application-model.md`](docs/application-model.md).
185
- The desktop Coverage view reads the same `.autotap/application-model.json`,
186
- `.autotap/release-plan.json`, and `.autotap/ui-map.json`, including explicit proposal review; it
185
+ The desktop Coverage view reads the same `.tapp/application-model.json`,
186
+ `.tapp/release-plan.json`, and `.tapp/ui-map.json`, including explicit proposal review; it
187
187
  does not maintain a separate product model. Map nodes identify both the real launch entry and the
188
188
  deterministic per-platform navigation root used for bounded changed-surface replay.
189
189
 
@@ -271,8 +271,8 @@ The first successful, conclusive run on `main` seeds a repository-scoped Actions
271
271
  90-day baseline artifact. Both are keyed by platform and stable application-model target id. Pull requests automatically restore it and fail only on **new**
272
272
  high/critical findings or broken Flows—not pre-existing debt. No baseline commit or PAT is required.
273
273
  If you prefer a reviewed, durable baseline, run `tapp baseline create` and commit the generated
274
- `.autotap/baselines/<platform>/<target-id>.json`; `tapp ci install` wires its explicit path into the
275
- corresponding job. The legacy `.autotap/baseline.json` is still recognized. Automatic baseline restore and the PR comment need `actions: read` and
274
+ `.tapp/baselines/<platform>/<target-id>.json`; `tapp ci install` wires its explicit path into the
275
+ corresponding job. The legacy `.tapp/baseline.json` is still recognized. Automatic baseline restore and the PR comment need `actions: read` and
276
276
  `pull-requests: write` as shown above. Secrets are unavailable to workflows from forks, so
277
277
  auth-gated apps should either use a non-secret UI-testing launch argument or skip the gate for
278
278
  untrusted forks.
@@ -305,14 +305,14 @@ or accept a prebuilt one:
305
305
  android-app-id: com.acme.app
306
306
  android-project: android
307
307
  android-task: :app:assembleDebug
308
- flows: android/.autotap/flows/*.yml
308
+ flows: android/.tapp/flows/*.yml
309
309
  ```
310
310
 
311
311
  For web, pass `platform: web` plus `web-target:` and Tapp uses the application model to run its
312
312
  lockfile-backed install/build, start a detected package script or read-only static server, wait for
313
313
  readiness, gate it, and stop it even on failure. Pass `url:` instead for an already-running owned
314
314
  environment. Add
315
- `scenarios: .autotap/scenarios/*.yml` to gate isolated cross-account journeys; see
315
+ `scenarios: .tapp/scenarios/*.yml` to gate isolated cross-account journeys; see
316
316
  [`docs/scenarios.md`](docs/scenarios.md). Automatic
317
317
  baselines are isolated by platform and target, so two same-platform apps are never compared.
318
318
 
@@ -351,8 +351,11 @@ verdict calculation run entirely locally — no telemetry, nothing phones home.
351
351
  features are explicit: finding enrichment requires `TAPP_ENABLE_REMOTE_AI=1` (an ambient
352
352
  API key alone never changes data handling), and AI flow generation / `assert_ai` only run
353
353
  when you invoke them; these send selected metadata (screen names, finding titles) to your
354
- configured model provider. Runtime configuration uses `TAPP_*` environment variables; deprecated
355
- aliases remain readable for compatibility.
354
+ configured model provider. Runtime configuration uses `TAPP_*` environment variables. Repository
355
+ artifacts live under `.tapp/`, and desktop run configuration uses `.tapp.yml`. Existing
356
+ `.autotap/`, `.autotap.yml`, and `AUTOTAP_*` inputs remain readable as migration fallbacks; when
357
+ both names exist, Tapp uses the canonical one. Rename the old directory/config in your next
358
+ reviewed repository change—no secrets or evidence formats need to be rewritten.
356
359
 
357
360
  Committed Flow replay, recording a driven session, autonomous exploration, exact assertions,
358
361
  regression comparison, and CI gating require **no API key and no coding agent at runtime**. AI is
package/bin/tapp.js CHANGED
@@ -22,16 +22,16 @@ import fs from "node:fs";
22
22
  import os from "node:os";
23
23
  import path from "node:path";
24
24
  import { fileURLToPath } from "node:url";
25
+ import { existingProjectArtifactPath, isProjectArtifactDirectory } from "../mcp-server/src/project-paths.js";
25
26
 
26
27
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
27
28
  const packageRoot = path.resolve(__dirname, "..");
28
29
  const pkg = JSON.parse(fs.readFileSync(path.join(packageRoot, "package.json"), "utf8"));
29
30
 
30
31
  // Redirect all writable output away from the (possibly read-only) package dir.
31
- // The old environment alias remains populated only for older helper integrations.
32
+ // The old environment alias remains a read-only fallback for older integrations.
32
33
  const tappHome = (process.env.TAPP_HOME || process.env.AUTOTAP_HOME || path.join(os.homedir(), ".tapp")).trim();
33
34
  process.env.TAPP_HOME = tappHome;
34
- if (!process.env.AUTOTAP_HOME) process.env.AUTOTAP_HOME = tappHome;
35
35
  fs.mkdirSync(tappHome, { recursive: true });
36
36
 
37
37
  const [, , command = "help", ...rest] = process.argv;
@@ -221,7 +221,7 @@ switch (command) {
221
221
  console.error("❌ --explore writes grounded UI Map evidence and cannot be combined with --dry-run");
222
222
  process.exit(2);
223
223
  }
224
- const outDir = typeof flags["out-dir"] === "string" ? flags["out-dir"] : ".autotap";
224
+ const outDir = typeof flags["out-dir"] === "string" ? flags["out-dir"] : ".tapp";
225
225
  const artifactDir = path.resolve(projectDir, outDir);
226
226
  if (!artifactDir.startsWith(projectDir + path.sep) && artifactDir !== projectDir) {
227
227
  console.error("❌ --out-dir must remain inside the repository");
@@ -292,7 +292,7 @@ switch (command) {
292
292
  case "plan": {
293
293
  const { flags, positionals } = parseVerbArgs(rest);
294
294
  const verb = positionals[0] || "show";
295
- const planPath = path.resolve(positionals[1] || ".autotap/release-plan.json");
295
+ const planPath = positionals[1] ? path.resolve(positionals[1]) : existingProjectArtifactPath(process.cwd(), "release-plan.json");
296
296
  if (!fs.existsSync(planPath)) {
297
297
  console.error(`❌ Release plan not found: ${planPath}`);
298
298
  process.exit(2);
@@ -366,7 +366,7 @@ switch (command) {
366
366
  break;
367
367
  }
368
368
  if (verb !== "review") {
369
- console.error("usage: tapp plan show [.autotap/release-plan.json]\n tapp plan review [.autotap/release-plan.json] --approve name[,name] --reject name[,name] --defer name[,name]\n tapp plan generate [.autotap/release-plan.json] [--project-dir DIR]\n tapp plan validate [.autotap/release-plan.json] --project-dir DIR --platform web [--url URL] [--target NAME|PATH]\n tapp plan promote [.autotap/release-plan.json] --project-dir DIR [--item name[,name]]");
369
+ console.error("usage: tapp plan show [.tapp/release-plan.json]\n tapp plan review [.tapp/release-plan.json] --approve name[,name] --reject name[,name] --defer name[,name]\n tapp plan generate [.tapp/release-plan.json] [--project-dir DIR]\n tapp plan validate [.tapp/release-plan.json] --project-dir DIR --platform web [--url URL] [--target NAME|PATH]\n tapp plan promote [.tapp/release-plan.json] --project-dir DIR [--item name[,name]]");
370
370
  process.exit(2);
371
371
  }
372
372
  const list = (value) => typeof value === "string" ? value.split(",").map((item) => item.trim()).filter(Boolean) : [];
@@ -377,7 +377,7 @@ switch (command) {
377
377
  }
378
378
  const { reviewProductPlan } = await import(path.join(packageRoot, "mcp-server", "src", "product-operations.js"));
379
379
  const reviewProjectDir = typeof flags["project-dir"] === "string" ? path.resolve(flags["project-dir"])
380
- : path.basename(path.dirname(planPath)) === ".autotap" ? path.dirname(path.dirname(planPath)) : path.dirname(planPath);
380
+ : isProjectArtifactDirectory(path.basename(path.dirname(planPath))) ? path.dirname(path.dirname(planPath)) : path.dirname(planPath);
381
381
  try { plan = reviewProductPlan({ projectDir: reviewProjectDir, planPath, ...decisions }).plan; }
382
382
  catch (error) { console.error(`❌ Could not review release plan: ${error.message || String(error)}`); process.exit(2); }
383
383
  console.log(`✅ Release plan updated — ${plan.items.filter((item) => ["approved", "accepted"].includes(item.decision)).length} accepted/approved · ${plan.items.filter((item) => item.decision === "rejected").length} rejected · ${plan.items.filter((item) => item.decision === "pending").length} pending`);
@@ -608,7 +608,7 @@ switch (command) {
608
608
  const verb = positionals[0] || "validate";
609
609
  const taskPath = positionals[1] ? path.resolve(positionals[1]) : "";
610
610
  if (!["validate", "compile", "run"].includes(verb) || !taskPath) {
611
- console.error("usage: tapp task validate <task.yml> [--platform ios|android|web] [--map .autotap/ui-map.json]\n tapp task compile <task.yml> --platform PLATFORM [--inputs '{\"name\":\"value\"}'] [--out compiled.json]\n tapp task run <task.yml> --platform PLATFORM [--url URL|--bundle-id ID|--app-id ID] [--inputs JSON]");
611
+ console.error("usage: tapp task validate <task.yml> [--platform ios|android|web] [--map .tapp/ui-map.json]\n tapp task compile <task.yml> --platform PLATFORM [--inputs '{\"name\":\"value\"}'] [--out compiled.json]\n tapp task run <task.yml> --platform PLATFORM [--url URL|--bundle-id ID|--app-id ID] [--inputs JSON]");
612
612
  process.exit(2);
613
613
  }
614
614
  if (!fs.existsSync(taskPath)) { console.error(`❌ Task not found: ${taskPath}`); process.exit(2); }
@@ -741,7 +741,7 @@ switch (command) {
741
741
  const verb = positionals[0] || "validate";
742
742
  const contractPath = positionals[1] ? path.resolve(positionals[1]) : "";
743
743
  if (!["validate", "compile", "run"].includes(verb) || !contractPath) {
744
- console.error("usage: tapp contract validate <name.contract.ts> [--platform ios|android|web] [--map .autotap/ui-map.json]\n tapp contract compile <name.contract.ts> --platform PLATFORM [--out compiled.json]\n tapp contract run <name.contract.ts> --platform PLATFORM [--url URL|--bundle-id ID|--app-id ID]");
744
+ console.error("usage: tapp contract validate <name.contract.ts> [--platform ios|android|web] [--map .tapp/ui-map.json]\n tapp contract compile <name.contract.ts> --platform PLATFORM [--out compiled.json]\n tapp contract run <name.contract.ts> --platform PLATFORM [--url URL|--bundle-id ID|--app-id ID]");
745
745
  process.exit(2);
746
746
  }
747
747
  const {
@@ -918,7 +918,7 @@ switch (command) {
918
918
  console.error("❌ --platform must be ios|android|web");
919
919
  process.exit(2);
920
920
  }
921
- const out = path.resolve(typeof flags.out === "string" ? flags.out : path.join(".autotap", "ui-map.json"));
921
+ const out = path.resolve(typeof flags.out === "string" ? flags.out : path.join(".tapp", "ui-map.json"));
922
922
  const observed = buildUiMapFromMarkers({
923
923
  markersPath,
924
924
  platform,
@@ -936,7 +936,7 @@ switch (command) {
936
936
  break;
937
937
  }
938
938
  if (verb === "inspect") {
939
- const mapPath = path.resolve(positionals[1] || path.join(".autotap", "ui-map.json"));
939
+ const mapPath = positionals[1] ? path.resolve(positionals[1]) : existingProjectArtifactPath(process.cwd(), "ui-map.json");
940
940
  if (!fs.existsSync(mapPath)) { console.error(`❌ UI Map not found: ${mapPath}`); process.exit(2); }
941
941
  const map = JSON.parse(fs.readFileSync(mapPath, "utf8"));
942
942
  const errors = validateUiMap(map);
@@ -959,7 +959,7 @@ switch (command) {
959
959
  if (!diff.comparableFullSweep && (diff.notObservedNodes.length || diff.notObservedEdges.length)) console.log("ℹ️ Absence is not labeled a regression because the runs were not declared comparable full sweeps.");
960
960
  process.exit(diff.lostReachability.length || diff.lostTransitions.length ? 1 : 0);
961
961
  }
962
- console.error("usage: tapp map build <ocqa-markers.txt> [--platform ios|android|web] [--out .autotap/ui-map.json]\n tapp map inspect [ui-map.json]\n tapp map diff <before.json> <after.json> [--comparable]");
962
+ console.error("usage: tapp map build <ocqa-markers.txt> [--platform ios|android|web] [--out .tapp/ui-map.json]\n tapp map inspect [ui-map.json]\n tapp map diff <before.json> <after.json> [--comparable]");
963
963
  process.exit(2);
964
964
  }
965
965
 
@@ -1096,7 +1096,7 @@ switch (command) {
1096
1096
  process.exit(2);
1097
1097
  }
1098
1098
  const projectDir = fs.realpathSync(path.resolve(positionals[1] || (typeof flags["project-dir"] === "string" ? flags["project-dir"] : process.cwd())));
1099
- const modelPath = path.resolve(projectDir, typeof flags.model === "string" ? flags.model : path.join(".autotap", "application-model.json"));
1099
+ const modelPath = typeof flags.model === "string" ? path.resolve(projectDir, flags.model) : existingProjectArtifactPath(projectDir, "application-model.json");
1100
1100
  if (!modelPath.startsWith(projectDir + path.sep) || !fs.existsSync(modelPath)) {
1101
1101
  console.error(`❌ Application model not found inside the repository: ${modelPath}\n Run tapp init --explore, review/generate/validate/promote the plan, then create the baseline.`);
1102
1102
  process.exit(2);
@@ -1203,7 +1203,7 @@ switch (command) {
1203
1203
  let projectDir;
1204
1204
  try { projectDir = fs.realpathSync(path.resolve(positionals[0] || (typeof flags["project-dir"] === "string" ? flags["project-dir"] : process.cwd()))); }
1205
1205
  catch { console.error(`❌ Repository directory not found: ${positionals[0] || flags["project-dir"] || process.cwd()}`); process.exit(2); }
1206
- const modelPath = path.resolve(projectDir, typeof flags.model === "string" ? flags.model : path.join(".autotap", "application-model.json"));
1206
+ const modelPath = typeof flags.model === "string" ? path.resolve(projectDir, flags.model) : existingProjectArtifactPath(projectDir, "application-model.json");
1207
1207
  if (!modelPath.startsWith(projectDir + path.sep) || !fs.existsSync(modelPath)) {
1208
1208
  console.error(`❌ Application model not found inside the repository: ${modelPath}\n Run tapp init --explore first.`);
1209
1209
  process.exit(2);
@@ -1242,7 +1242,7 @@ switch (command) {
1242
1242
  actionRef,
1243
1243
  defaultBranch: typeof flags["default-branch"] === "string" ? flags["default-branch"] : "main",
1244
1244
  workflowPath: typeof flags.out === "string" ? flags.out : ".github/workflows/tapp.yml",
1245
- manifestPath: typeof flags.manifest === "string" ? flags.manifest : ".autotap/ci.json",
1245
+ manifestPath: typeof flags.manifest === "string" ? flags.manifest : ".tapp/ci.json",
1246
1246
  replace: flags.replace === true,
1247
1247
  allowUnresolved: flags["allow-unresolved"] === true,
1248
1248
  });
package/browser/app.js CHANGED
@@ -471,7 +471,7 @@ async function entriesFromDrop(event) {
471
471
  }
472
472
 
473
473
  // The webkitdirectory input (and some drop implementations) silently exclude hidden
474
- // entries, which destroys committed .autotap/ config. The File System Access picker
474
+ // entries, which destroys committed .tapp/ config. The File System Access picker
475
475
  // enumerates hidden files, so it is preferred wherever it exists.
476
476
  async function entriesFromDirectoryHandle(handle, prefix = "") {
477
477
  const entries = [];
@@ -526,7 +526,7 @@ async function uploadRepository(name, entries, { hiddenComplete = false } = {})
526
526
  $("#operation-progress-bar").style.width = "100%";
527
527
  const hasHiddenEntries = entries.some((entry) => entry.path.split("/").some((part) => part.startsWith(".")));
528
528
  if (!hiddenComplete && !hasHiddenEntries) {
529
- toast("Imported, but no hidden files (like .autotap/) came through — this browser's folder picker skips them. Committed Tapp config was not uploaded.", true);
529
+ toast("Imported, but no hidden files (like .tapp/) came through — this browser's folder picker skips them. Committed Tapp config was not uploaded.", true);
530
530
  } else {
531
531
  toast("Repository imported into an isolated Tapp workspace");
532
532
  }
@@ -41,7 +41,7 @@
41
41
  <div class="source-icon">↥</div>
42
42
  <p class="eyebrow">CLOUD COPY</p>
43
43
  <h2>Upload a project folder</h2>
44
- <p>Upload an isolated working copy from this computer. Committed hidden config (like <code>.autotap/</code>) is included; dependency and build output folders are skipped.</p>
44
+ <p>Upload an isolated working copy from this computer. Committed hidden config (like <code>.tapp/</code>) is included; dependency and build output folders are skipped.</p>
45
45
  <button class="primary" id="browse-folder">Browse folder</button>
46
46
  <input id="folder-input" type="file" webkitdirectory multiple hidden>
47
47
  <small>For direct edits to an existing checkout, start with <code>tapp app /path/to/repo</code>.</small>
@@ -39,7 +39,7 @@ in the local process/filesystem. This is a local trust boundary, not hosted mult
39
39
  11. **Install CI** by previewing and writing a reviewable repository patch. Tapp does not commit,
40
40
  push, create GitHub secrets, or enable branch protection.
41
41
 
42
- Successful semantic actions can be saved in `.autotap/flows/`; credential values are templated to
42
+ Successful semantic actions can be saved in `.tapp/flows/`; credential values are templated to
43
43
  environment references. Long-lived repository artifacts store binding names, not resolved secret
44
44
  values.
45
45
 
@@ -51,7 +51,7 @@ Current convergence:
51
51
  installation call the same operations;
52
52
  - the GitHub Action and `runProductGate` call the same portable gate and evidence protocol;
53
53
  - VS Code remains a thin MCP client;
54
- - desktop reads the same `.autotap` artifacts but still has legacy import/build orchestration. It is
54
+ - desktop reads the same `.tapp` artifacts but still has legacy import/build orchestration. It is
55
55
  retained, not the launch UX, until that orchestration is removed;
56
56
  - `cloud/runner` is retained prototype evidence for exact checkout, versioned operation envelopes,
57
57
  leases, and cleanup. It is not the production hosted adapter or an adequate arbitrary-customer
@@ -60,10 +60,10 @@ Current convergence:
60
60
 
61
61
  ## Canonical repository protocol
62
62
 
63
- New product behavior writes only `.autotap/`:
63
+ New product behavior writes only `.tapp/`:
64
64
 
65
65
  ```text
66
- .autotap/
66
+ .tapp/
67
67
  project.json # actors, env binding names, controlled lifecycle; never secret values
68
68
  application-model.json # detected/observed/declared product facts
69
69
  ui-map.json # grounded screen/action/transition graph
@@ -74,9 +74,10 @@ New product behavior writes only `.autotap/`:
74
74
  ci.json # generated CI installation manifest
75
75
  ```
76
76
 
77
- `.autotap.yml` and `.tapp.yml` are legacy compatibility inputs, not parallel sources of product
78
- truth. Do not add a fourth configuration format. Migration readers may normalize old input into the
79
- canonical model; only an explicit reviewed operation may write new repository artifacts.
77
+ `.tapp.yml` is the canonical run configuration. Existing `.autotap.yml`, `.autotap/`, and
78
+ `AUTOTAP_*` inputs remain readable during migration, but new examples and output use the Tapp names.
79
+ Do not add another configuration format. Migration readers may normalize old input into the canonical
80
+ model; only an explicit reviewed operation may write new repository artifacts.
80
81
 
81
82
  ## Anti-duplication rules
82
83
 
@@ -3,9 +3,9 @@
3
3
  `tapp init` is the deterministic import, exploration, and planning entrypoint of Tapp's customer
4
4
  journey. It turns a repository into three platform-neutral, repository-native artifacts:
5
5
 
6
- - `.autotap/ui-map.json` — observed UI states, controls, and transitions from real exploration;
7
- - `.autotap/application-model.json` — what Tapp can support with evidence;
8
- - `.autotap/release-plan.json` — the compact set of committed and proposed business guarantees a
6
+ - `.tapp/ui-map.json` — observed UI states, controls, and transitions from real exploration;
7
+ - `.tapp/application-model.json` — what Tapp can support with evidence;
8
+ - `.tapp/release-plan.json` — the compact set of committed and proposed business guarantees a
9
9
  customer must review before generation.
10
10
 
11
11
  Plain `tapp init` performs source/artifact inspection only. `tapp init --explore` additionally uses
@@ -73,7 +73,7 @@ tapp actor list .
73
73
  tapp init . --refresh
74
74
  ```
75
75
 
76
- This writes `.autotap/project.json`. The file contains roles, `default`/`isolated` session policy,
76
+ This writes `.tapp/project.json`. The file contains roles, `default`/`isolated` session policy,
77
77
  provisioning mode, same-origin lifecycle declarations, and environment-variable *names*. The CLI
78
78
  and MCP `tapp_actor_config` reject credential values and refuse to replace an actor without an
79
79
  explicit `--replace`/`replace: true`. Contracts refer to `$ALICE_EMAIL`-style placeholders. Tapp
@@ -144,24 +144,24 @@ and the real-surface validation required before it can be trusted.
144
144
  ## Explicit review
145
145
 
146
146
  ```bash
147
- tapp plan show .autotap/release-plan.json
148
- tapp plan review .autotap/release-plan.json \
147
+ tapp plan show .tapp/release-plan.json
148
+ tapp plan review .tapp/release-plan.json \
149
149
  --approve signInWorks,checkoutWorks \
150
150
  --reject marketingPageReachable \
151
151
  --defer adminAuditWorks
152
152
 
153
- # Only after review: generate grounded Task + contract drafts under .autotap/proposals/.
154
- tapp plan generate .autotap/release-plan.json --project-dir .
153
+ # Only after review: generate grounded Task + contract drafts under .tapp/proposals/.
154
+ tapp plan generate .tapp/release-plan.json --project-dir .
155
155
 
156
156
  # Replay the draft on the real target and attach evidence to the plan.
157
157
  # Omit --url to build/start/stop the detected managed browser target.
158
- tapp plan validate .autotap/release-plan.json --project-dir . --platform web
158
+ tapp plan validate .tapp/release-plan.json --project-dir . --platform web
159
159
  # Or connect to an already-running owned environment.
160
- tapp plan validate .autotap/release-plan.json --project-dir . \
160
+ tapp plan validate .tapp/release-plan.json --project-dir . \
161
161
  --platform web --url http://127.0.0.1:3000
162
162
 
163
163
  # Explicitly accept only fully validated drafts into canonical reviewed locations.
164
- tapp plan promote .autotap/release-plan.json --project-dir . \
164
+ tapp plan promote .tapp/release-plan.json --project-dir . \
165
165
  --item checkoutWorks
166
166
  ```
167
167
 
@@ -181,7 +181,7 @@ The macOS desktop Coverage experience reads these same files. Its **Application*
181
181
  detected targets, actors, capabilities, journeys, Tasks, contracts, and exact remediation. Its
182
182
  **Release Plan** tab writes explicit approve/reject/defer decisions atomically into the canonical
183
183
  plan while preserving fields from newer engine versions; committed contract intent is not editable
184
- through these proposal controls. Flow Map merges the repository `.autotap/ui-map.json` with current
184
+ through these proposal controls. Flow Map merges the repository `.tapp/ui-map.json` with current
185
185
  run evidence instead of building a separate desktop-only graph.
186
186
 
187
187
  Schema compatibility is exercised by the repository's protocol tests and retained desktop reader.
@@ -191,8 +191,8 @@ actor-attributed Task calls, captured output variables, bounded eventual asserti
191
191
  reviewed project lifecycle, then compile through the isolated Scenario executor. Existing
192
192
  Task-backed proposals compose those reviewed Tasks. For UI-Map-only proposals, it finds an observed path from each platform's
193
193
  recorded entry state, deduplicates shared semantic transitions into compositional Task drafts under
194
- `.autotap/proposals/tasks/`, grounds every Task in exact node/edge ids, and writes the contract draft
195
- under `.autotap/proposals/contracts/`. Proposal Tasks are visible only to proposal contracts; an
194
+ `.tapp/proposals/tasks/`, grounds every Task in exact node/edge ids, and writes the contract draft
195
+ under `.tapp/proposals/contracts/`. Proposal Tasks are visible only to proposal contracts; an
196
196
  ordinary committed contract or CI glob cannot silently consume one.
197
197
 
198
198
  Generation blocks when entry-state evidence is missing, the target is unreachable, an observed
@@ -200,7 +200,7 @@ action cannot be represented deterministically, or platform paths require incomp
200
200
  composition. It never overwrites a draft, statically compiles each declared platform, and marks all
201
201
  outputs untrusted. Missing non-secret Task inputs stay blocked until the plan has explicit bindings;
202
202
  standard email/password secrets remain placeholders. Successful grounding and compilation are not
203
- real-surface evidence and never promote drafts into `.autotap/tasks` or `.autotap/contracts`.
203
+ real-surface evidence and never promote drafts into `.tapp/tasks` or `.tapp/contracts`.
204
204
 
205
205
  `plan validate` invokes the ordinary deterministic contract executor and records pass/fail evidence
206
206
  per declared platform. A multi-platform draft remains only partially validated until every declared
@@ -209,8 +209,8 @@ substitution or automatic assertion update.
209
209
 
210
210
  `plan promote` is the explicit acceptance boundary. It refuses any contract or generated Task that
211
211
  has not passed every declared platform, preflights every destination, never overwrites a reviewed
212
- artifact, moves accepted files from `.autotap/proposals/{tasks,contracts}` into
213
- `.autotap/{tasks,contracts}`, and applies their exact node/edge coverage to the canonical UI Map.
212
+ artifact, moves accepted files from `.tapp/proposals/{tasks,contracts}` into
213
+ `.tapp/{tasks,contracts}`, and applies their exact node/edge coverage to the canonical UI Map.
214
214
  Shared Task paths in still-unpromoted proposals are rewritten to the canonical file. Promotion does
215
215
  not commit, push, or install CI; the resulting repository patch remains reviewable by the customer.
216
216
 
@@ -232,7 +232,7 @@ tapp ci install . --action-ref aarwitz/tapp@v0.13.1
232
232
 
233
233
  Baseline creation rejects non-gate JSON, missing or mismatched target identity, platform mismatch,
234
234
  failed Flows/Scenarios/contracts, `blocked`, and `inconclusive`. It writes atomically to
235
- `.autotap/baselines/<platform>/<target-id>.json` and requires `--replace` to supersede reviewed
235
+ `.tapp/baselines/<platform>/<target-id>.json` and requires `--replace` to supersede reviewed
236
236
  evidence. Capture-local paths are replaced with portable `tapp-capture:` references before the
237
237
  repository artifact is written. The gate also checks baseline platform and target identity before
238
238
  comparing findings. On iOS, the same validated launch arguments and string-valued launch
@@ -240,7 +240,7 @@ environment are passed to autonomous exploration and deterministic Flow/contract
240
240
  JSON or unsupported value types fail before execution rather than silently testing different app
241
241
  configurations.
242
242
 
243
- CI installation writes `.github/workflows/tapp.yml` and `.autotap/ci.json`, never overwrites by
243
+ CI installation writes `.github/workflows/tapp.yml` and `.tapp/ci.json`, never overwrites by
244
244
  default, and refuses unresolved iOS schemes, Android ids, browser lockfiles, or runtimes. The
245
245
  workflow uses exact contract paths, maps each actor environment binding to a same-named GitHub
246
246
  Secret, uses the first/default actor for autonomous-login inputs, preserves the remaining bindings
package/docs/scenarios.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Multi-actor Scenarios
2
2
 
3
- A Scenario is Tapp's low-level deterministic multi-actor execution format in `.autotap/scenarios/*.yml`. It uses the same semantic actions, polling assertions, timeouts, evidence markers, and merge policy as a Flow, but adds isolated named actors, shared variables, and explicit lifecycle steps. The customer-facing business authoring layer is a TypeScript [release contract](release-contracts.md), which composes reusable Tasks and compiles to this runtime instead of duplicating UI steps.
3
+ A Scenario is Tapp's low-level deterministic multi-actor execution format in `.tapp/scenarios/*.yml`. It uses the same semantic actions, polling assertions, timeouts, evidence markers, and merge policy as a Flow, but adds isolated named actors, shared variables, and explicit lifecycle steps. The customer-facing business authoring layer is a TypeScript [release contract](release-contracts.md), which composes reusable Tasks and compiles to this runtime instead of duplicating UI steps.
4
4
 
5
5
  Ordinary replay is keyless. AI may propose a Scenario during authoring, but no model, API key, or coding agent participates when CI executes it.
6
6
 
@@ -61,13 +61,13 @@ teardown:
61
61
  ## Run it
62
62
 
63
63
  ```bash
64
- tapp scenario validate .autotap/scenarios/social-system.yml
64
+ tapp scenario validate .tapp/scenarios/social-system.yml
65
65
  ALICE_EMAIL=alice@example.test ALICE_PASSWORD=demo \
66
66
  BOB_EMAIL=bob@example.test BOB_PASSWORD=demo \
67
- tapp scenario run .autotap/scenarios/social-system.yml
67
+ tapp scenario run .tapp/scenarios/social-system.yml
68
68
 
69
69
  tapp ci --platform web --url http://127.0.0.1:4180 \
70
- --scenarios '.autotap/scenarios/*.yml' \
70
+ --scenarios '.tapp/scenarios/*.yml' \
71
71
  --json-out tapp-report.json --md-out tapp-report.md
72
72
  ```
73
73
 
@@ -78,16 +78,16 @@ GitHub Action:
78
78
  with:
79
79
  platform: web
80
80
  url: http://127.0.0.1:4180
81
- scenarios: .autotap/scenarios/*.yml
81
+ scenarios: .tapp/scenarios/*.yml
82
82
  ```
83
83
 
84
84
  MCP clients call `tapp_scenario_run` with `scenarioPath`, or an inline reviewed Scenario. The structured result identifies `kind: scenario`, actual executed/total steps, and actor-tagged steps.
85
85
 
86
86
  ## Verified fixture and boundaries
87
87
 
88
- `SocialDemo/.autotap/contracts/social-system.contract.ts` is the reference system guarantee; the Scenario remains its low-level execution proof and backwards-compatible escape hatch. On 2026-08-04 the contract passed 41/41 compiled steps using two isolated contexts against one delayed shared backend. With `SOCIAL_DEMO_FAULT=hide-cross-actor-posts`, the unchanged contract failed for Bob at 19/41 and the portable merge gate exited non-zero specifically because one release contract failed.
88
+ `SocialDemo/.tapp/contracts/social-system.contract.ts` is the reference system guarantee; the Scenario remains its low-level execution proof and backwards-compatible escape hatch. On 2026-08-04 the contract passed 41/41 compiled steps using two isolated contexts against one delayed shared backend. With `SOCIAL_DEMO_FAULT=hide-cross-actor-posts`, the unchanged contract failed for Bob at 19/41 and the portable merge gate exited non-zero specifically because one release contract failed.
89
89
 
90
- The fixture's `.autotap/project.json` is the central actor contract. It records Alice and Bob's
90
+ The fixture's `.tapp/project.json` is the central actor contract. It records Alice and Bob's
91
91
  roles, isolated sessions, seeded provisioning, reset lifecycle, and four environment-variable
92
92
  names. The release contract and Scenario consume those names; neither stores the public fixture
93
93
  values. Customer values belong in the local environment or CI secret store.