@iamu-dev/iamu 0.2.0-beta.6 → 0.2.0-beta.7

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/dist/index.js CHANGED
@@ -823,7 +823,14 @@ var init_scenario = __esm({
823
823
  reviews: z15.array(z15.string().min(1).max(64)).max(16).default([]),
824
824
  baseline_score: z15.number().min(0).max(100).nullish(),
825
825
  current_score: z15.number().min(0).max(100).nullish(),
826
- target_score: z15.number().min(0).max(100).default(95)
826
+ target_score: z15.number().min(0).max(100).default(95),
827
+ /** Environment state preconditions and approximation guidance. */
828
+ state: z15.object({
829
+ /** Description of data/records expected to exist in the environment. */
830
+ description: z15.string().max(2048).nullish(),
831
+ /** Guidance on how to squint or approximate if exact records are absent. */
832
+ approximation: z15.string().max(2048).nullish()
833
+ }).nullish()
827
834
  });
828
835
  }
829
836
  });
@@ -12304,15 +12311,6 @@ function mcpJson(cmd) {
12304
12311
  2
12305
12312
  );
12306
12313
  }
12307
- function vscodeMcpJson(cmd) {
12308
- return JSON.stringify(
12309
- {
12310
- servers: { iamu: { type: "stdio", command: cmd[0], args: cmd.slice(1) } }
12311
- },
12312
- null,
12313
- 2
12314
- );
12315
- }
12316
12314
  function detectHosts(projectRoot) {
12317
12315
  return HOST_ADAPTERS.filter(
12318
12316
  (host) => host.detectionPaths.some((p) => existsSync3(join3(projectRoot, p)))
@@ -12361,13 +12359,17 @@ var init_registry = __esm({
12361
12359
  {
12362
12360
  name: "GitHub Copilot",
12363
12361
  value: "github-copilot",
12364
- detectionPaths: [".vscode", ".github/copilot-instructions.md"],
12365
- supportsSkills: false,
12366
- getSkillsDir: () => "",
12367
- getCommandPath: (root, id) => join3(root, ".github", "prompts", `iamu-${id}.prompt.md`),
12368
- formatCommand: descOnlyFormat,
12369
- getMcpConfigPath: (root) => join3(root, ".vscode", "mcp.json"),
12370
- formatMcpConfig: vscodeMcpJson
12362
+ detectionPaths: [
12363
+ ".github/copilot-instructions.md",
12364
+ ".github/skills",
12365
+ ".copilot"
12366
+ ],
12367
+ supportsSkills: true,
12368
+ getSkillsDir: (root) => join3(root, ".github", "skills"),
12369
+ getCommandPath: (root, id) => join3(root, ".github", "skills", `iamu-${id}`, "SKILL.md"),
12370
+ formatCommand: richFormat,
12371
+ getMcpConfigPath: (root) => join3(root, ".mcp.json"),
12372
+ formatMcpConfig: mcpJson
12371
12373
  },
12372
12374
  {
12373
12375
  name: "Cline",
@@ -12549,6 +12551,14 @@ function isCliWrittenSkill(path28) {
12549
12551
  return false;
12550
12552
  }
12551
12553
  }
12554
+ function isCliWrittenPrompt(path28) {
12555
+ try {
12556
+ const content = readFileSync3(path28, "utf-8");
12557
+ return content.includes("iamu") || /^generatedBy:/m.test(content);
12558
+ } catch {
12559
+ return false;
12560
+ }
12561
+ }
12552
12562
  function planSkillFiles(hosts, projectRoot, version) {
12553
12563
  const skillTemplates = loadSkillTemplates(version);
12554
12564
  const files = [];
@@ -12577,6 +12587,19 @@ function planSkillFiles(hosts, projectRoot, version) {
12577
12587
  }
12578
12588
  }
12579
12589
  }
12590
+ if (host.value === "github-copilot") {
12591
+ for (const cmd of commandsFromSkills(skillTemplates)) {
12592
+ const legacyPrompt = join4(
12593
+ projectRoot,
12594
+ ".github",
12595
+ "prompts",
12596
+ `iamu-${cmd.id}.prompt.md`
12597
+ );
12598
+ if (isCliWrittenPrompt(legacyPrompt)) {
12599
+ files.push({ host, path: legacyPrompt, content: null });
12600
+ }
12601
+ }
12602
+ }
12580
12603
  } else {
12581
12604
  for (const cmd of commandsFromSkills(skillTemplates)) {
12582
12605
  files.push({
@@ -12601,6 +12624,15 @@ function detectInstalledHosts(projectRoot) {
12601
12624
  const skillDir = join4(host.getSkillsDir(projectRoot), "iamu-setup");
12602
12625
  if (existsSync5(skillDir)) return true;
12603
12626
  }
12627
+ if (host.value === "github-copilot") {
12628
+ const legacyPrompt = join4(
12629
+ projectRoot,
12630
+ ".github",
12631
+ "prompts",
12632
+ "iamu-setup.prompt.md"
12633
+ );
12634
+ if (existsSync5(legacyPrompt)) return true;
12635
+ }
12604
12636
  return false;
12605
12637
  });
12606
12638
  }
@@ -16320,7 +16352,10 @@ var init_browse_actions = __esm({
16320
16352
  usage: "goto <url>",
16321
16353
  minArgs: 1,
16322
16354
  run: async (p, args) => {
16323
- await p.goto(args[0], { waitUntil: "domcontentloaded" });
16355
+ await p.goto(args[0], {
16356
+ waitUntil: "domcontentloaded",
16357
+ timeout: 1e4
16358
+ });
16324
16359
  }
16325
16360
  },
16326
16361
  click: {
@@ -16481,6 +16516,12 @@ var init_browse_driver = __esm({
16481
16516
  commandLine: (pid) => readProcessCommandLine(pid),
16482
16517
  kill(pid) {
16483
16518
  try {
16519
+ if (process.platform !== "win32") {
16520
+ try {
16521
+ process.kill(-pid, "SIGTERM");
16522
+ } catch {
16523
+ }
16524
+ }
16484
16525
  process.kill(pid, "SIGTERM");
16485
16526
  } catch {
16486
16527
  }
@@ -16857,6 +16898,8 @@ function chromeArgs(opts, port, headless) {
16857
16898
  `--window-size=${opts.width ?? "1280"},${opts.height ?? "900"}`,
16858
16899
  "--no-first-run",
16859
16900
  "--no-default-browser-check",
16901
+ "--password-store=basic",
16902
+ "--use-mock-keychain",
16860
16903
  ...headless ? ["--headless=new", "--disable-dev-shm-usage", "--disable-gpu"] : [],
16861
16904
  ...shouldDisableSandbox() ? ["--no-sandbox"] : [],
16862
16905
  "about:blank"
@@ -18533,13 +18576,21 @@ function defaultFrontmatter(type2, id, slug, name, opts) {
18533
18576
  url: opts.url,
18534
18577
  authority_level: opts.authority ?? "informational"
18535
18578
  };
18536
- case "scenario":
18579
+ case "scenario": {
18580
+ const stateObj = opts.stateDescription || opts.stateApproximation ? {
18581
+ state: {
18582
+ ...opts.stateDescription ? { description: opts.stateDescription } : {},
18583
+ ...opts.stateApproximation ? { approximation: opts.stateApproximation } : {}
18584
+ }
18585
+ } : {};
18537
18586
  return {
18538
18587
  ...base,
18539
18588
  outline: opts.outline ?? null,
18540
18589
  persona: opts.persona ?? null,
18541
- ...opts.entry ? { entry_path: opts.entry } : {}
18590
+ ...opts.entry ? { entry_path: opts.entry } : {},
18591
+ ...stateObj
18542
18592
  };
18593
+ }
18543
18594
  default:
18544
18595
  return base;
18545
18596
  }
@@ -18933,6 +18984,17 @@ function composeWalkerPrompt(p) {
18933
18984
  "",
18934
18985
  "## First-person brief",
18935
18986
  p.brief ?? "",
18987
+ ...p.context ? ["", "## Product domain & regulatory context", p.context.trim()] : [],
18988
+ ...p.state?.description || p.state?.approximation ? [
18989
+ "",
18990
+ "## Expected state & semantic squinting",
18991
+ p.state.description ? `Expected state: ${p.state.description}` : "",
18992
+ p.state.approximation ? `Approximation strategy: ${p.state.approximation}` : "",
18993
+ "Squinting Guardrails:",
18994
+ "\u2022 If the exact target record/option is not available, apply the approximation strategy above to pick the closest plausible entity within the domain flow.",
18995
+ "\u2022 Squinting does NOT permit drifting to unrelated settings, account profiles, or off-target pages. Stay strictly within the scenario journey.",
18996
+ "\u2022 If the system is completely empty or unseeded, and your persona role cannot create data, do NOT report false product bugs about the empty state. Note that preconditions are unseeded/blocked."
18997
+ ].filter(Boolean) : [],
18936
18998
  ...revisitSection(p.revisit ?? []),
18937
18999
  "",
18938
19000
  "## Access",
@@ -19081,7 +19143,8 @@ async function instructionsWalk(opts) {
19081
19143
  const result = {
19082
19144
  scenario: {
19083
19145
  slug: sfm.slug,
19084
- brief: scenario.body.trim() || null
19146
+ brief: scenario.body.trim() || null,
19147
+ state: sfm.state ?? null
19085
19148
  },
19086
19149
  persona: {
19087
19150
  slug: sfm.persona,
@@ -19135,7 +19198,9 @@ async function instructionsWalk(opts) {
19135
19198
  runDirPath,
19136
19199
  projectRoot,
19137
19200
  surface: opts.surface ?? "browse",
19138
- viewport
19201
+ viewport,
19202
+ state: sfm.state ?? null,
19203
+ context: contextYml
19139
19204
  }) : null
19140
19205
  };
19141
19206
  if (opts.json) {
@@ -19147,6 +19212,11 @@ async function instructionsWalk(opts) {
19147
19212
  console.log(` ${chalk26.dim("scenario:")} ${sfm.slug}`);
19148
19213
  console.log(` ${chalk26.dim("persona:")} ${pfm.name} (${pfm.role})`);
19149
19214
  console.log(` ${chalk26.dim("outline:")} ${ofm.title}`);
19215
+ if (sfm.state?.description || sfm.state?.approximation) {
19216
+ console.log(
19217
+ ` ${chalk26.dim("state:")} ${sfm.state.description ? sfm.state.description : sfm.state.approximation ?? ""}`
19218
+ );
19219
+ }
19150
19220
  if (targetUrl) console.log(` ${chalk26.dim("target:")} ${targetUrl}`);
19151
19221
  console.log(
19152
19222
  ` ${chalk26.dim("access:")} ${projectAccess || personaAccess ? `${projectAccess ? "project" : ""}${projectAccess && personaAccess ? " + " : ""}${personaAccess ? "persona" : ""}` : "not recorded (walker would run as whoever is signed in)"}`
@@ -20822,6 +20892,12 @@ function registerProjectCommands(program) {
20822
20892
  ).option("--outline <slug>", "Outline slug (scenario only)").option("--persona <slug>", "Persona slug (scenario only)").option(
20823
20893
  "--entry <path>",
20824
20894
  "Where the situation starts, as a path on the product, e.g. /en/episodes/1 (scenario only)"
20895
+ ).option(
20896
+ "--state-description <text>",
20897
+ "Assumed environment data/records state (scenario only)"
20898
+ ).option(
20899
+ "--state-approximation <text>",
20900
+ "Guidance on how persona should approximate/squint if records are missing (scenario only)"
20825
20901
  ).option("--url <url>", "Document the source cites (source only, required)").option(
20826
20902
  "--authority <level>",
20827
20903
  "legislation | regulation | standard | company_policy | guideline | informational (source only, default informational)"
@@ -70,11 +70,9 @@ Continuity: steps form ONE ongoing monologue. From step 2 onward, don't restate
70
70
 
71
71
  ## Pacing
72
72
 
73
- **Aim for 10-20 steps.** Stop when the primary task verdict is clear — either the persona accomplished their goal or they hit friction that blocks them. A focused 12-step walkthrough with sharp findings is worth more than a 40-step exhaustive tour.
73
+ **Aim for 10-20 steps.** When evaluating a form or journey, inspect all relevant sections across the workflow (e.g., travel details, per diem, deductions, expenses). Do not abandon the walkthrough after logging a single defect — continue through the remaining sections to uncover all distinct compliance and usability gaps before completing. A complete walkthrough with sharp findings across all sections gives the team high-value signal.
74
74
 
75
- Do not try to complete every interaction. If a form has 15 fields, the observation is "this persona would give up at field 4" — note the finding and move on.
76
-
77
- Do try key interactions that reveal something: click the main CTA, open a dropdown, check what filters exist. These are cheap observations with high signal.
75
+ Do try key interactions that reveal something: click the main CTA, open a dropdown, check what options or deductions exist. These are cheap observations with high signal.
78
76
 
79
77
  Follow the persona's motivation. Spend time on what matters to them. When you have enough evidence to answer "would this person come back?" — you're done.
80
78
 
@@ -100,6 +98,20 @@ Your browser tooling has limitations that can look like product bugs. Before rec
100
98
 
101
99
  Do NOT silently suppress findings you suspect are tooling issues. Record them with the caveat — the human triaging can verify.
102
100
 
101
+ ## Expected state vs product bugs (Empty state & unseeded data)
102
+
103
+ When an environment is unseeded or test records are missing:
104
+ - An empty table or "No records found" screen is NOT automatically a product bug. If your scenario assumes existing data (e.g. reviewing past entries or auditing submitted claims), check whether the environment simply lacks seed data.
105
+ - If your persona role is a creator (e.g. employee or consultant creating an item), click the creation CTA (e.g. "+ Ny reseräkning", "+ New") and proceed with your task.
106
+ - If your persona role is read-only (e.g. an auditor or manager) and cannot create data, do NOT record false "missing data" bugs against the product. Conclude the walk noting that the environment lacks the required preconditions.
107
+
108
+ ## Semantic squinting (Adapting to environmental mismatch)
109
+
110
+ Your prompt may include an approximation strategy (e.g. "If Malmö is missing, choose Göteborg").
111
+ - **Squint at the closest match:** When the exact target name, category, or record described in your brief isn't available in this environment, pick the closest available alternative that allows testing the workflow.
112
+ - **Stay in the journey:** Approximation is bounded. Never drift to unrelated modules (e.g. settings, profile, admin panels) just because a specific test record was absent.
113
+ - **Log the approximation:** In your step note (`note`), state clearly that you chose the closest alternative according to your instructions.
114
+
103
115
  ## Portal-rendered UI
104
116
 
105
117
  Radix / Headless UI / Floating UI render dropdowns and listboxes into portals that do not appear in accessibility snapshots. If an expandable combobox looks empty after click, try: press ArrowDown then Enter, or evaluate a script in the page to probe the DOM. Take a fresh screenshot.
@@ -95,9 +95,13 @@ Human Checkpoint: <Concrete binary yes/partial/no question scored at evaluation>
95
95
  Roles with Stakes:
96
96
  • <Role 1>: <Stake>
97
97
  • <Role 2>: <Stake>
98
+
99
+ Execution Preconditions (resolved at iamu-run):
100
+ • Assumed State: <What records/data should exist, e.g. "Department with existing risk register containing open hazards">
101
+ • Squint Guidance: <How the walker should approximate if exact records are missing, e.g. "If no packaging hazard exists, select any physical safety hazard and proceed with delegation">
98
102
  ```
99
103
 
100
- Ask the user: "Ready to test this draft, or would you like to refine the focus question or circumstances? (Enter to accept, or type adjustments)"
104
+ Ask the user: "Ready to test this draft, or would you like to refine the focus question, preconditions, or circumstances? (Enter to accept, or type adjustments)"
101
105
 
102
106
  ### 4. Pick or propose personas
103
107
 
@@ -164,12 +168,12 @@ The `--role` and `--disposition` flags populate frontmatter directly. If `iamu/c
164
168
 
165
169
  **4. Scenario** (the binding):
166
170
  ```bash
167
- iamu new scenario --name "maria-gomez--busy-shift-handoff" --outline busy-shift-handoff --persona maria-gomez --json
171
+ iamu new scenario --name "maria-gomez--busy-shift-handoff" --outline busy-shift-handoff --persona maria-gomez [--entry /path/on/the/product] [--state-description "<Assumed state description>"] [--state-approximation "<Squint guidance for walker>"] --body "<First-person brief in persona voice (3–5 sentences)>" --json
168
172
  ```
169
173
  When the situation begins on a specific page (the persona follows a link from a video, an email, a search result), add `--entry /path/on/the/product` — the run starts there instead of the home page.
170
- `--outline` is required. `--persona` is optional (omit for drafts). Write the first-person brief as the markdown body — 3–5 sentences in the persona's voice.
174
+ `--outline` is required. `--persona` is optional (omit for drafts). Pass `--state-description` and `--state-approximation` if preconditions were defined in step 3 to populate the scenario's `state:` frontmatter automatically.
171
175
 
172
- For drafts (no persona): omit `--persona`, omit the brief body.
176
+ For drafts (no persona): omit `--persona`, omit `--body`.
173
177
 
174
178
  ### 7. Summarize
175
179
 
@@ -39,7 +39,6 @@ Read `iamu/context.yml`. Extract and hold:
39
39
  - **Domain + industry** — what world does this product operate in?
40
40
  - **Actors** — real roles with real responsibilities. These are scenario and persona seed material.
41
41
  - **Governed_by** — regulations and standards (if applicable). These create structural tensions in regulated domains.
42
- - **Glossary** — domain vocabulary. Scenarios and personas must use these terms, not generic UI words.
43
42
  - **Notes body** — extended context, often containing workflow descriptions, pain points, organizational dynamics.
44
43
 
45
44
  ### 2. Load existing coverage
@@ -116,7 +115,7 @@ Next action:
116
115
  Ground rules for generation:
117
116
 
118
117
  - **Start from the actor's week, not the feature list.** What does this person actually do on a Tuesday? What goes wrong? What requires judgment?
119
- - **Use domain vocabulary from the glossary.** If the glossary says "skyddsombud" not "safety representative," use "skyddsombud."
118
+ - **Use authentic domain vocabulary.** Speak in the language of the domain and the product UI (e.g., "skyddsombud" rather than generic "safety representative"), avoiding abstract test jargon.
120
119
  - **Prefer mundane frequency over dramatic edge cases.** The scenario that happens every week reveals more than the one that happens once a year.
121
120
  - **Structural tensions come from the domain, not from product limitations.** A real tension: "the regulation requires immediate reporting but the coordinator handles 3 sites." A fake tension: "the CSV upload has a 50-row limit."
122
121
  - **Never mention the product, its UI, its features, or its limitations.** The scenario exists in the domain. The product encounter happens during the walkthrough.
@@ -127,19 +127,30 @@ Record it as a target string the run can carry, for example `sim://<device-name>
127
127
 
128
128
  **Then verify the starting state before spawning anyone.** Launch the app and take ONE screenshot confirming the product is where the scenario assumes it starts. Wait a few seconds after launch first: a screen rendered before its state lands shows the wrong thing, and verifying too early makes the verification itself lie — in the direction of "the harness is broken", which costs a debugging detour or, worse, waves a real seeding bug through.
129
129
 
130
- **Web: check the product is ready, not just up.** A server that answers is not a product that has its data. Before spawning the walker, confirm the thing the scenario depends on actually exists — the list the persona will open is populated, the seeded records are there, background setup (seeding, migrations, indexing) has finished. Use the project's documented readiness signal if it has one; otherwise look at one screen or one API response yourself. A walk started too early reports "the feature is missing" as a critical finding, and nothing in the walker's view distinguishes that from a real defect.
130
+ **Expected State & Semantic Squinting — verify environment before walking.** A scenario testing triage, review, or audits requires a populated, realistic system.
131
+ 1. **Expected State:** If the scenario defines `state.description`, verify the landing screen matches what the persona expects to see (e.g. populated register, open incidents). If the screen is completely blank and the persona cannot self-seed, stop early and report the run as blocked by missing preconditions rather than logging false product bugs.
132
+ 2. **Data Squinting & Approximation:** If the exact record described in the narrative is absent (e.g. no "damaged conveyor belt" hazard), the walker must follow `state.approximation` — "squint" at the real data, pick the closest plausible record (e.g. an active mechanical or safety hazard), and proceed with the evaluation/delegation workflow.
133
+ - **Squinting Guardrail:** Squinting is bounded to semantically related items within the same domain workflow. It does NOT permit drifting to unrelated modules (e.g. switching from risk assessment to user profile settings). If no plausible record exists, declare the run blocked.
134
+ 3. **Empty State Fallback:**
135
+ - If the database is empty and the persona role has creation rights (e.g. Manager or Reporter), the persona may create the minimal viable record in-character to proceed with the core test.
136
+ - If the persona role is read-only or subordinate (cannot self-seed), stop and report the run as blocked by preconditions.
131
137
 
132
138
  **Access — how the walker becomes this persona.** A walk as a forklift driver that runs with an administrator's session reports nothing true about what the driver can see or reach. Access is recorded in two places, and `iamu instructions walk` (step 4) returns both as `access`:
133
139
 
134
140
  - `access.project` — from `iamu/context.yml` `access`: HOW switching user is done in this product (a dev persona switcher, a storage key, seeded test accounts, a login form). Written once per project.
135
141
  - `access.persona` — from the persona file's `access`: WHICH user this persona is (an account name, a role, a switcher key).
136
142
 
137
- If both are present, use them as they are. If either is missing, fill the gap now and SAVE it so no later run has to ask:
138
-
139
- 1. Check the project's own agent docs (`CLAUDE.md`, `AGENTS.md`, anything they point to for the dev environment) for a documented way to switch user or role.
140
- 2. Map the persona to the closest account or role the product actually has. If nothing fits, say so — a persona the product cannot represent is itself worth telling the user.
141
- 3. If the docs are silent, ask the user once. "No login, everyone is the same user" is a valid answer.
142
- 4. Write what you learned: the mechanism into `iamu/context.yml` as `access:`, the persona's own key into `iamu/personas/<slug>.md` frontmatter as `access:`. Passwords and tokens never go in either — name where they live (an env var, a vault entry) instead.
143
+ **Interactive Auth Handshake (for enterprise auth, SSO, 2FA, BankID):**
144
+ If the product is behind enterprise login where automated dev persona switching is not configured:
145
+ 1. Open the browser to the target URL (`iamu browse start --run <run-id>` or browser tool).
146
+ 2. Prompt the human user:
147
+ > 👉 **Please log in as `<persona.role>` (`<persona.name>`) in the opened browser window.** Press Enter once you reach the dashboard to hand control to the walker...
148
+ 3. Wait for the user to confirm, then let the walker drive the authenticated session.
149
+
150
+ If automated switching exists:
151
+ 1. Check the project's own agent docs (`CLAUDE.md`, `AGENTS.md`) for a documented way to switch user or role.
152
+ 2. Map the persona to the closest account or role the product actually has. If nothing fits, say so.
153
+ 3. Write what you learned: the mechanism into `iamu/context.yml` as `access:`, the persona's own key into `iamu/personas/<slug>.md` frontmatter as `access:`. Passwords and tokens never go in either — name where they live (an env var, a vault entry) instead.
143
154
 
144
155
  Carry the result into the walking prompt as the `## Access` section: the exact steps to become the persona, with the instruction to do them BEFORE the first recorded step.
145
156
 
@@ -34,7 +34,7 @@ Check whether `iamu/config.json` already exists:
34
34
 
35
35
  ### 2. Understand the project
36
36
 
37
- Explore the codebase automatically — do NOT ask the user what files to read. Build a **project-context summary** (3–6 sentences) the downstream skills will use as grounding. Read the following files when present:
37
+ Explore the codebase automatically — do NOT ask the user what files to read. Build a **substantive project description** that serves as the foundation for all downstream analysis (personas, scenarios, and walkthroughs). Read the following files when present:
38
38
 
39
39
  - `README.md`, `CLAUDE.md`, `agents.md`
40
40
  - Package manifests — `package.json`, `Cargo.toml`, `pyproject.toml`, `go.mod`
@@ -42,114 +42,131 @@ Explore the codebase automatically — do NOT ask the user what files to read. B
42
42
  - `docs/`, OpenAPI / JSON / GraphQL schemas, `src/`-style source directories
43
43
  - `.env.example`
44
44
 
45
- Extract these key dimensions:
45
+ **Quality Standard for Project Context (Knowledgeable Observer):**
46
+ Write as an objective domain expert describing the business and its users, NOT marketing jargon, cookie notices, or tech stack. Do NOT hedge with "appears to be" or "seems to".
46
47
 
47
- 1. **Domain & Purpose** — what this product does, core workflows, and problem space (mandatory).
48
- 2. **Jurisdiction & Regulations (`governed_by`)** — country/region and specific compliance frameworks (AFS 2023:2, GDPR, HIPAA, ISO 27001, etc.). **Strictly optional:** only extract if the repo explicitly references legal or compliance standards. Do NOT invent regulations for standard apps.
49
- 3. **Key Actors & Roles** — the main user archetypes and roles discovered in the codebase (auth models, routes, permissions).
50
- 4. **Dev Access & Auth** — how personas switch or log in during local dev/test (e.g. dev persona switcher, seeded accounts, storage key, mock headers). Essential for walkthrough automation.
51
- 5. **Key Terminology (`glossary`)** — 2–4 domain-specific terms or acronyms found in the codebase.
52
- 6. **Primary Personas** — determine the 1–2 most critical user archetypes that stress-test this product (e.g. End User / Frontline vs. Admin / Compliance, or First-Timer vs. Power User). Propose:
53
- - Name and Role
54
- - Disposition / perspective (patience level, tech literacy, primary friction triggers)
48
+ The description MUST capture four substantive dimensions:
49
+ 1. **What the product fundamentally IS** — core workflow, product type, and problem space.
50
+ 2. **Who actually uses it and what they come here to do** — enumerate the real user journeys (e.g. reporting incidents, triaging risks, delegating actions, auditing).
51
+ 3. **What makes THIS product specific** — geography, jurisdiction, regulatory mandates, or business model.
52
+ 4. **Operational characteristics** — how users physically and organizationally encounter the software (e.g. deskless frontline mobile workers in high-hazard environments, strict statutory completion deadlines, immutable audit trails).
55
53
 
56
- Do NOT collect code architecture (agent reads the codebase directly — tech stack doesn't affect walkthroughs).
54
+ *Example of target substance:*
55
+ > "IA-systemet is Sweden's national work environment and safety incident management platform, utilized by thousands of Swedish enterprises to comply with statutory systematic work environment requirements (AML / AFS). It enables frontline employees to quickly log near-misses (tillbud), workplace accidents (olycksfall), and risk observations from desktop or mobile devices in the field. Core user journeys include real-time hazard reporting, line manager root-cause investigations, safety committee review, and action plan delegation with statutory compliance tracking."
57
56
 
58
- **If there is no code (greenfield, design phase):** ask the user: what does this project do, who are the users, what domain, and are there any specific regulations?
57
+ Synthesize the project into a cohesive, substantive narrative (1–2 paragraphs):
58
+ - What the product fundamentally is, its primary domain, and who uses it.
59
+ - Key user journeys and operational characteristics (e.g. mobile floor use, audit deadlines).
60
+ - Market, geography, and specific compliance frameworks (only if evident).
59
61
 
60
- **Present the proposal with clean, structured Markdown for confirmation:**
62
+ Do NOT collect code architecture (agent reads the codebase directly — tech stack doesn't affect walkthroughs).
61
63
 
62
- ```markdown
63
- ### 📋 Discovered Project Context
64
+ **If there is no code (greenfield, design phase, or test sandbox):** do NOT interrogate the user with a multi-part survey or ask for dev auth plumbing. Ask for a single entry point:
65
+ > No local codebase detected. To seed context, provide one of:
66
+ > - A target URL (staging, production, or docs — e.g., `https://app.example.com`)
67
+ > - A one-sentence description of what this product does
68
+ > - Or type `"sandbox"` to seed a pre-configured B2B SaaS demo
64
69
 
65
- - **Domain & Purpose:** <Concise description of the product and problem space>
66
- - **Jurisdiction & Rules:** <Country/region and compliance frameworks, or "None identified">
67
- - **Key Roles Identified:** <List of detected roles and their responsibilities>
68
- - **Dev Access & Auth:** <Detected mechanism to switch/assume personas in dev, or "Standard login">
69
- - **Domain Terminology:** <2–4 key terms/acronyms found in the codebase, if any>
70
+ **Autonomous Enrichment:**
71
+ - **URL provided:** Fetch or search public marketing/docs for that site. Automatically extract the substantive narrative, core user journeys, and key actors. If industry regulations are obvious (e.g., healthcare/HIPAA, Swedish workplace safety/AML), include them in the narrative.
72
+ - **One-sentence summary provided:** Immediately expand into a full substantive narrative using domain knowledge.
73
+ - **"sandbox" provided:** Seed a standard B2B SaaS narrative with Admin and End-User roles.
74
+ - **Do NOT ask upfront about auth mechanics (`access`) or compliance frameworks (`governed_by`).** Infer if obvious, otherwise leave them blank.
70
75
 
71
- ---
76
+ **Present ONLY the narrative description for user confirmation (Do NOT include metadata bullets or personas):**
72
77
 
73
- ### 🎭 Proposed Primary Personas
74
-
75
- #### 1. <Name> — *<Role / Title>*
76
- - **Context & Usage:** <Where and how they use the app (e.g., mobile on the floor vs. desktop in office)>
77
- - **Disposition:** <Patience level, technical confidence, key motivations>
78
- - **Friction Triggers:** <Specific interactions that cause friction, drop-off, or failure>
78
+ ```markdown
79
+ ### 📋 Discovered Project Context
79
80
 
80
- #### 2. <Name> — *<Role / Title>*
81
- - **Context & Usage:** <Where and how they use the app>
82
- - **Disposition:** <Patience level, technical confidence, key motivations>
83
- - **Friction Triggers:** <Specific interactions that cause friction, drop-off, or failure>
81
+ <1–2 cohesive paragraphs written as a knowledgeable observer: what the product fundamentally is, who actually uses it, key user journeys, operational reality (e.g. mobile floor use, audit deadlines), and regulatory/market context. No marketing fluff, no hedging, no tech stack descriptions, and no bullet points.>
84
82
 
85
83
  ---
86
84
 
87
85
  **Next step:**
88
- Reply **"yes"** to save this context to `iamu/context.yml` and scaffold these personas, or tell me what to adjust (e.g., change roles, edit domain, or add/skip personas).
86
+ Reply **"yes"** to save this context to `iamu/context.yml`, or tell me what to adjust.
89
87
  ```
90
88
 
91
- Wait for the user to confirm or correct before writing. The user only needs to verify domain and choose whether to accept, edit, suggest alternative personas, or defer persona creation.
89
+ Wait for the user to confirm or correct before writing. The user only needs to verify the narrative description and choose whether to accept or edit.
92
90
 
93
- ### 3. Capture domain context and scaffold personas
91
+ ### 3. Capture domain context and seed personas (Two-Phase Confirmation)
94
92
 
95
- Persist the step-2 summary as structured fields so every scenario draft and walkthrough loads the same grounding. Downstream skills auto-read this file.
96
-
97
- 1. Check existing state by reading `iamu/context.yml` directly.
98
-
99
- 2. **Branch on what you find:**
100
-
101
- - **Empty / not present** → synthesize structured fields from step 2 and write `iamu/context.yml` with your file-editing tool (not a shell heredoc — it avoids permission prompts).
102
- - **Present but thin** (missing domain) → show what's missing and offer to fill it. User picks **refine** or **replace**.
103
- - **Present and complete** (domain set) → show summary and ask "Use as-is, refine, or replace?" Default is **skip**.
104
-
105
- 3. **Write `iamu/context.yml`**:
93
+ #### Phase A: Persist Context
94
+ Once the user confirms the narrative description:
95
+ 1. Derive the structured frontmatter fields (`domain`, `actors`, `jurisdiction`, `governed_by`) from the confirmed text, and write `iamu/context.yml` with your file-editing tool. Put structured fields in frontmatter and the substantive narrative in the markdown body below the `---`:
106
96
 
107
97
  ```yaml
108
98
  ---
109
99
  schema_version: 1
110
- domain: e-commerce storefront
111
- # jurisdiction: EU / US # optional
112
- # governed_by: # strictly optional - omit if not regulated
113
- # - name: GDPR
100
+ domain: workplace safety management
101
+ # jurisdiction: Sweden / EU # optional
102
+ # governed_by: # strictly optional - omit if not regulated
103
+ # - name: AFS 2023:2
114
104
  # authority_level: regulation
115
105
  actors:
116
106
  - name: Store Admin
117
107
  role: Manages catalog, inventory, and order fulfillment
118
108
  - name: First-Time Buyer
119
109
  role: Explores products, adds to cart, and checks out
120
- glossary:
121
- - term: SKU
122
- definition: Stock Keeping Unit
123
110
  access: >-
124
111
  No login in dev. In the page, set localStorage "dev_persona" to the
125
112
  persona's access value and reload.
126
113
  ---
114
+
115
+ <The substantive 1–2 paragraph project description and core user journeys>
127
116
  ```
128
117
 
129
118
  Rules:
130
119
  - `domain` — one line. Mandatory.
120
+ - Body markdown (below `---`) — substantive description and user journeys. Downstream skills read this as extended grounding.
131
121
  - `jurisdiction` — optional. Only if evident or relevant.
132
- - `governed_by[]` — strictly optional. Order by authority (legislation > regulation > standard > company_policy > guideline > informational). Specific names, not categories. Omit entirely if no regulations apply.
122
+ - `governed_by[]` — strictly optional. Order by authority. Omit entirely if no regulations apply.
133
123
  - `actors[]` — all identified roles and their responsibilities.
134
- - `glossary[]` — domain terms only. Thin is better than padded with generic terms.
135
- - `access` — optional. Only what the docs actually say; leave it out rather than guess. `iamu-run` fills it in on the first walk if it is missing.
124
+ - `access` — optional. Only what the docs actually say; leave it out rather than guess.
136
125
  - Do NOT add `industry` or `architecture` — these don't affect walkthroughs.
137
126
 
138
- 4. **Scaffold confirmed personas (unless `skip-personas` selected):**
127
+ #### Phase B: Persona Casting (Opt-In & Separate Confirmation)
128
+ Immediately after saving `iamu/context.yml`, ask the user if they want to seed baseline personas:
139
129
 
140
- Use the CLI to scaffold valid persona entities with schema-compliant UUIDs, slugs, frontmatter, and narrative body in a single command:
130
+ > Context saved to `iamu/context.yml`.
131
+ >
132
+ > Would you like to seed 1–2 baseline personas to your casting panel now?
133
+ > Reply **"yes"** to propose personas, or **"skip"** to create scenarios directly via `iamu-new`.
134
+
135
+ **If the user chooses "yes":**
136
+ Propose 1–2 primary personas grounded in the confirmed actors and operational characteristics:
137
+
138
+ ```markdown
139
+ ### 🎭 Proposed Primary Personas
140
+
141
+ #### 1. <Name> — *<Role / Title>*
142
+ - **Context & Usage:** <Where and how they use the app (e.g. mobile on the floor vs. desktop in office)>
143
+ - **Disposition:** <Patience level, technical confidence, key motivations>
144
+ - **Friction Triggers:** <Specific interactions that cause friction, drop-off, or failure>
145
+
146
+ #### 2. <Name> — *<Role / Title>*
147
+ - **Context & Usage:** <Where and how they use the app>
148
+ - **Disposition:** <Patience level, technical confidence, key motivations>
149
+ - **Friction Triggers:** <Specific interactions that cause friction, drop-off, or failure>
150
+
151
+ ---
152
+
153
+ **Next step:**
154
+ Reply **"yes"** to scaffold these personas into `iamu/personas/`, or tell me what to adjust.
155
+ ```
156
+
157
+ Wait for the user to confirm or adjust. Once confirmed:
158
+ 1. Scaffold personas using the CLI:
141
159
  ```bash
142
160
  iamu new persona --name "<Name>" --role "<Role>" --disposition "<Disposition>" --body "<2-4 sentence narrative detailing technical habits, patience level, and specific friction triggers>" [--access "<account-or-role>"] --json
143
161
  ```
144
-
145
- If `iamu/context.yml` specifies an `access` mechanism, pass `--access "<role>"` matching an existing product account/role.
146
-
147
- Once all confirmed personas are created, run validation once:
162
+ 2. Validate once:
148
163
  ```bash
149
164
  iamu validate --all
150
165
  ```
166
+ 3. Confirm: "Context saved and personas seeded in iamu/personas/. Run `iamu-new` to draft your first scenario."
151
167
 
152
- 5. Confirm: "Context saved and personas seeded in iamu/personas/. Run `iamu-new` to draft your first scenario." (or "Context saved. Run `iamu-new` to draft your first scenario." if personas were skipped).
168
+ **If the user chooses "skip":**
169
+ Confirm: "Context saved. Run `iamu-new` to draft your first scenario."
153
170
 
154
171
  ### 4. Offer cloud link (optional)
155
172
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iamu-dev/iamu",
3
- "version": "0.2.0-beta.6",
3
+ "version": "0.2.0-beta.7",
4
4
  "type": "module",
5
5
  "description": "Test your product as realistic personas — scenario-driven development CLI",
6
6
  "license": "UNLICENSED",
@@ -54,11 +54,12 @@
54
54
  "devDependencies": {
55
55
  "@types/node": "^22.0.0",
56
56
  "@vitest/coverage-v8": "^4.1.11",
57
+ "google-auth-library": "^11.1.0",
57
58
  "tsup": "^8.5.1",
58
59
  "typescript": "^5.8.0",
59
60
  "vitest": "^4.1.11",
60
- "@iamu-dev/protocol": "0.1.0",
61
61
  "@iamu-dev/local-store": "0.1.0",
62
+ "@iamu-dev/protocol": "0.1.0",
62
63
  "@iamu/tsconfig": "0.1.0"
63
64
  },
64
65
  "scripts": {
@@ -67,6 +68,8 @@
67
68
  "typecheck": "tsc --noEmit",
68
69
  "test": "vitest run",
69
70
  "test:coverage": "vitest run --coverage",
71
+ "eval:walkthroughs": "vitest run --config vitest.benchmark.config.ts",
72
+ "eval:gemini": "node dist/eval/gemini-eval-cli.js",
70
73
  "pack:dry-run": "npm pack --dry-run"
71
74
  }
72
75
  }