@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/bin.js +98 -22
- package/dist/eval/gemini-eval-cli.js +976 -0
- package/dist/index.js +98 -22
- package/dist/templates/prompts/walk.md +16 -4
- package/dist/templates/skills/iamu-new.md +8 -4
- package/dist/templates/skills/iamu-propose.md +1 -2
- package/dist/templates/skills/iamu-run.md +18 -7
- package/dist/templates/skills/iamu-setup.md +79 -62
- package/package.json +5 -2
- package/dist/commands/start-run.d.ts +0 -52
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: [
|
|
12365
|
-
|
|
12366
|
-
|
|
12367
|
-
|
|
12368
|
-
|
|
12369
|
-
|
|
12370
|
-
|
|
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], {
|
|
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.**
|
|
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
|
|
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).
|
|
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
|
|
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
|
|
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
|
-
**
|
|
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
|
-
|
|
138
|
-
|
|
139
|
-
1.
|
|
140
|
-
2.
|
|
141
|
-
|
|
142
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
62
|
+
Do NOT collect code architecture (agent reads the codebase directly — tech stack doesn't affect walkthroughs).
|
|
61
63
|
|
|
62
|
-
|
|
63
|
-
|
|
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
|
-
|
|
66
|
-
- **
|
|
67
|
-
- **
|
|
68
|
-
- **
|
|
69
|
-
- **
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
91
|
+
### 3. Capture domain context and seed personas (Two-Phase Confirmation)
|
|
94
92
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
1.
|
|
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:
|
|
111
|
-
# jurisdiction:
|
|
112
|
-
# governed_by:
|
|
113
|
-
# - name:
|
|
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
|
|
122
|
+
- `governed_by[]` — strictly optional. Order by authority. Omit entirely if no regulations apply.
|
|
133
123
|
- `actors[]` — all identified roles and their responsibilities.
|
|
134
|
-
- `
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
}
|