@iamu-dev/iamu 0.2.0-beta.4 → 0.2.0-beta.5

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 CHANGED
@@ -17001,6 +17001,35 @@ function printStep(opts, record, projectRoot) {
17001
17001
  }
17002
17002
  }
17003
17003
  async function browseStep(args, opts, driver) {
17004
+ if (opts.stepFile) {
17005
+ try {
17006
+ let raw;
17007
+ if (opts.stepFile === "-") {
17008
+ raw = readFileSync6(0, "utf8");
17009
+ } else {
17010
+ raw = readFileSync6(opts.stepFile, "utf8");
17011
+ }
17012
+ const data = JSON.parse(raw);
17013
+ if (data.run && typeof data.run === "string") opts.run = data.run;
17014
+ if (data.action && typeof data.action === "string")
17015
+ opts.action = data.action;
17016
+ if (data.note && typeof data.note === "string") opts.note = data.note;
17017
+ if (data.surface && typeof data.surface === "string")
17018
+ opts.surface = data.surface;
17019
+ if (args.length === 0 && data.cmd) {
17020
+ if (Array.isArray(data.cmd)) {
17021
+ args = data.cmd.map(String);
17022
+ } else if (typeof data.cmd === "string") {
17023
+ args = data.cmd.trim().split(/\s+/);
17024
+ }
17025
+ }
17026
+ } catch (err) {
17027
+ return fail(
17028
+ `Failed to read step payload from ${opts.stepFile}: ${err.message}`,
17029
+ opts
17030
+ );
17031
+ }
17032
+ }
17004
17033
  if (!opts.run)
17005
17034
  return fail("--run <run-id> is required for browse step.", opts);
17006
17035
  if (!opts.action) {
@@ -19457,8 +19486,21 @@ async function evaluate(runId, opts) {
19457
19486
  )
19458
19487
  };
19459
19488
  const prompt = composeJudgePrompt(input);
19489
+ const promptFilePath = opts?.promptFile ?? path25.join(runDirPath, "judge_prompt.md");
19490
+ await fs25.writeFile(promptFilePath, prompt, "utf8");
19460
19491
  if (opts?.json) {
19461
- console.log(JSON.stringify({ ...input, judge_prompt: prompt }, null, 2));
19492
+ console.log(
19493
+ JSON.stringify(
19494
+ {
19495
+ ...input,
19496
+ prompt_file: path25.relative(projectRoot, promptFilePath),
19497
+ prompt_file_abs: path25.resolve(promptFilePath),
19498
+ judge_prompt: prompt
19499
+ },
19500
+ null,
19501
+ 2
19502
+ )
19503
+ );
19462
19504
  return;
19463
19505
  }
19464
19506
  console.log(prompt);
@@ -19550,7 +19592,7 @@ ${formatIssues(fileResult.error)}`,
19550
19592
  runId,
19551
19593
  validatedVerdicts
19552
19594
  );
19553
- const cloudInfo = await pushRunToCloud(projectRoot, runId);
19595
+ const cloudInfo = opts?.push === false ? void 0 : await pushRunToCloud(projectRoot, runId);
19554
19596
  if (opts?.json) {
19555
19597
  console.log(
19556
19598
  JSON.stringify(
@@ -19794,7 +19836,7 @@ async function collectCompletionExtras(run, opts) {
19794
19836
  parseRunViewport(manifest.viewport)
19795
19837
  );
19796
19838
  const codeWarning = opts?.force ? null : codeChangedWarning(manifest.build, detectWorktreeState(projectRoot));
19797
- const cloudInfo = await pushRunToCloud(projectRoot, runId);
19839
+ const cloudInfo = opts?.push === false ? void 0 : await pushRunToCloud(projectRoot, runId);
19798
19840
  return { revisit, viewportWarning, codeWarning, cloudInfo };
19799
19841
  }
19800
19842
  function completeJsonPayload(canonical, extras) {
@@ -20247,9 +20289,28 @@ async function match(runId, opts) {
20247
20289
  );
20248
20290
  const needed = input.current.length > 0 && (input.prior.length > 0 || (input.guidance ?? []).length > 0);
20249
20291
  const prompt = needed ? composeMatchPrompt(input) : null;
20292
+ const promptFilePath = opts?.promptFile ?? path27.join(runDirPath, "match_prompt.md");
20293
+ if (prompt) {
20294
+ await fs27.writeFile(promptFilePath, prompt, "utf8");
20295
+ } else {
20296
+ try {
20297
+ await fs27.unlink(promptFilePath);
20298
+ } catch {
20299
+ }
20300
+ }
20250
20301
  if (opts?.json) {
20251
20302
  console.log(
20252
- JSON.stringify({ ...input, needed, match_prompt: prompt }, null, 2)
20303
+ JSON.stringify(
20304
+ {
20305
+ ...input,
20306
+ needed,
20307
+ prompt_file: prompt ? path27.relative(ctx.projectRoot, promptFilePath) : null,
20308
+ prompt_file_abs: prompt ? path27.resolve(promptFilePath) : null,
20309
+ match_prompt: prompt
20310
+ },
20311
+ null,
20312
+ 2
20313
+ )
20253
20314
  );
20254
20315
  return;
20255
20316
  }
@@ -20723,7 +20784,10 @@ function registerWalkthroughCommands(program2) {
20723
20784
  ).option(
20724
20785
  "--run <run-id>",
20725
20786
  "Run ID to size browser (start) or record step into (step)"
20726
- ).option("--action <text>", "Action description (step only)").option("--note <text>", "Persona inner monologue / reasoning (step only)").option("--surface <name>", "Screen or surface name (step only)").option("--width <px>", "Window width (start)").option("--height <px>", "Window height (start)").option("--headless", "Run without a window (start)").option(
20787
+ ).option("--action <text>", "Action description (step only)").option("--note <text>", "Persona inner monologue / reasoning (step only)").option("--surface <name>", "Screen or surface name (step only)").option(
20788
+ "--step-file <path>",
20789
+ "Read step payload (action, note, cmd) from a JSON file or '-' for stdin (step only)"
20790
+ ).option("--width <px>", "Window width (start)").option("--height <px>", "Window height (start)").option("--headless", "Run without a window (start)").option(
20727
20791
  "--port <port>",
20728
20792
  "CDP port (start), default 9333",
20729
20793
  (value) => parsePortOption(value)
@@ -20799,9 +20863,9 @@ function registerWalkthroughCommands(program2) {
20799
20863
  ).option("-y, --yes", "Skip interactive prompts").option("--no-prompt", "Skip interactive prompt to view results").option("--view", "Open results in browser immediately without prompt").option(
20800
20864
  "--strict-provenance",
20801
20865
  "Fail if steps show synthetic or programmatic timing anomalies"
20802
- ).addHelpText(
20866
+ ).option("--no-push", "Skip pushing the run to Iamu Cloud").addHelpText(
20803
20867
  "after",
20804
- "\nExamples:\n $ iamu complete <run-id>\n $ iamu complete <run-id> --view\n $ iamu complete <run-id> --no-prompt\n $ iamu complete <run-id> --json\n $ iamu complete <run-id> --strict-provenance"
20868
+ "\nExamples:\n $ iamu complete <run-id>\n $ iamu complete <run-id> --view\n $ iamu complete <run-id> --no-prompt\n $ iamu complete <run-id> --no-push\n $ iamu complete <run-id> --json\n $ iamu complete <run-id> --strict-provenance"
20805
20869
  ).action(
20806
20870
  async (runId, opts) => {
20807
20871
  const { complete: complete2 } = await Promise.resolve().then(() => (init_complete(), complete_exports));
@@ -20810,23 +20874,27 @@ function registerWalkthroughCommands(program2) {
20810
20874
  );
20811
20875
  program2.command("match <run-id>").helpGroup("Walkthrough:").description(
20812
20876
  "Compose the prompt that links this run's findings to earlier ones"
20813
- ).option("--json", "Output the match input bundle as JSON").action(async (runId, opts) => {
20814
- const { match: match2 } = await Promise.resolve().then(() => (init_match(), match_exports));
20815
- await match2(runId, opts);
20816
- });
20877
+ ).option("--json", "Output the match input bundle as JSON").option("--prompt-file <path>", "Write the generated prompt to a file").action(
20878
+ async (runId, opts) => {
20879
+ const { match: match2 } = await Promise.resolve().then(() => (init_match(), match_exports));
20880
+ await match2(runId, opts);
20881
+ }
20882
+ );
20817
20883
  program2.command("match-record <run-id>").helpGroup("Walkthrough:").description(
20818
20884
  "Record finding matches and re-derive the run's since-last-run delta"
20819
20885
  ).requiredOption("--file <path>", "Path to matches JSON file").option("--json", "Output match results as JSON").action(async (runId, opts) => {
20820
20886
  const { matchRecord: matchRecord2 } = await Promise.resolve().then(() => (init_match(), match_exports));
20821
20887
  await matchRecord2(runId, opts);
20822
20888
  });
20823
- program2.command("evaluate <run-id>").helpGroup("Walkthrough:").description("Compose evaluation prompt for human-test questions").option("--json", "Output evaluation input bundle as JSON").action(async (runId, opts) => {
20824
- const { evaluate: evaluate2 } = await Promise.resolve().then(() => (init_evaluate(), evaluate_exports));
20825
- await evaluate2(runId, opts);
20826
- });
20827
- program2.command("evaluate-record <run-id>").helpGroup("Walkthrough:").description("Record evaluation verdicts into the run's verdicts.json").requiredOption("--file <path>", "Path to verdicts JSON file").option("--json", "Output summary as JSON").option("-y, --yes", "Skip interactive prompts").option("--no-prompt", "Skip interactive prompt to view results").option("--view", "Open results in browser immediately without prompt").addHelpText(
20889
+ program2.command("evaluate <run-id>").helpGroup("Walkthrough:").description("Compose evaluation prompt for human-test questions").option("--json", "Output evaluation input bundle as JSON").option("--prompt-file <path>", "Write the generated prompt to a file").action(
20890
+ async (runId, opts) => {
20891
+ const { evaluate: evaluate2 } = await Promise.resolve().then(() => (init_evaluate(), evaluate_exports));
20892
+ await evaluate2(runId, opts);
20893
+ }
20894
+ );
20895
+ program2.command("evaluate-record <run-id>").helpGroup("Walkthrough:").description("Record evaluation verdicts into the run's verdicts.json").requiredOption("--file <path>", "Path to verdicts JSON file").option("--json", "Output summary as JSON").option("-y, --yes", "Skip interactive prompts").option("--no-prompt", "Skip interactive prompt to view results").option("--no-push", "Skip pushing the updated run to Iamu Cloud").option("--view", "Open results in browser immediately without prompt").addHelpText(
20828
20896
  "after",
20829
- "\nExamples:\n $ iamu evaluate-record <run-id> --file verdicts.json\n $ iamu evaluate-record <run-id> --file verdicts.json --no-prompt\n $ iamu evaluate-record <run-id> --file verdicts.json --json"
20897
+ "\nExamples:\n $ iamu evaluate-record <run-id> --file verdicts.json\n $ iamu evaluate-record <run-id> --file verdicts.json --no-prompt\n $ iamu evaluate-record <run-id> --file verdicts.json --no-push\n $ iamu evaluate-record <run-id> --file verdicts.json --json"
20830
20898
  ).action(
20831
20899
  async (runId, opts) => {
20832
20900
  const { evaluateRecord: evaluateRecord2 } = await Promise.resolve().then(() => (init_evaluate(), evaluate_exports));
package/dist/index.js CHANGED
@@ -16980,6 +16980,35 @@ function printStep(opts, record, projectRoot) {
16980
16980
  }
16981
16981
  }
16982
16982
  async function browseStep(args, opts, driver) {
16983
+ if (opts.stepFile) {
16984
+ try {
16985
+ let raw;
16986
+ if (opts.stepFile === "-") {
16987
+ raw = readFileSync6(0, "utf8");
16988
+ } else {
16989
+ raw = readFileSync6(opts.stepFile, "utf8");
16990
+ }
16991
+ const data = JSON.parse(raw);
16992
+ if (data.run && typeof data.run === "string") opts.run = data.run;
16993
+ if (data.action && typeof data.action === "string")
16994
+ opts.action = data.action;
16995
+ if (data.note && typeof data.note === "string") opts.note = data.note;
16996
+ if (data.surface && typeof data.surface === "string")
16997
+ opts.surface = data.surface;
16998
+ if (args.length === 0 && data.cmd) {
16999
+ if (Array.isArray(data.cmd)) {
17000
+ args = data.cmd.map(String);
17001
+ } else if (typeof data.cmd === "string") {
17002
+ args = data.cmd.trim().split(/\s+/);
17003
+ }
17004
+ }
17005
+ } catch (err) {
17006
+ return fail(
17007
+ `Failed to read step payload from ${opts.stepFile}: ${err.message}`,
17008
+ opts
17009
+ );
17010
+ }
17011
+ }
16983
17012
  if (!opts.run)
16984
17013
  return fail("--run <run-id> is required for browse step.", opts);
16985
17014
  if (!opts.action) {
@@ -19436,8 +19465,21 @@ async function evaluate(runId, opts) {
19436
19465
  )
19437
19466
  };
19438
19467
  const prompt = composeJudgePrompt(input);
19468
+ const promptFilePath = opts?.promptFile ?? path25.join(runDirPath, "judge_prompt.md");
19469
+ await fs25.writeFile(promptFilePath, prompt, "utf8");
19439
19470
  if (opts?.json) {
19440
- console.log(JSON.stringify({ ...input, judge_prompt: prompt }, null, 2));
19471
+ console.log(
19472
+ JSON.stringify(
19473
+ {
19474
+ ...input,
19475
+ prompt_file: path25.relative(projectRoot, promptFilePath),
19476
+ prompt_file_abs: path25.resolve(promptFilePath),
19477
+ judge_prompt: prompt
19478
+ },
19479
+ null,
19480
+ 2
19481
+ )
19482
+ );
19441
19483
  return;
19442
19484
  }
19443
19485
  console.log(prompt);
@@ -19529,7 +19571,7 @@ ${formatIssues(fileResult.error)}`,
19529
19571
  runId,
19530
19572
  validatedVerdicts
19531
19573
  );
19532
- const cloudInfo = await pushRunToCloud(projectRoot, runId);
19574
+ const cloudInfo = opts?.push === false ? void 0 : await pushRunToCloud(projectRoot, runId);
19533
19575
  if (opts?.json) {
19534
19576
  console.log(
19535
19577
  JSON.stringify(
@@ -19773,7 +19815,7 @@ async function collectCompletionExtras(run, opts) {
19773
19815
  parseRunViewport(manifest.viewport)
19774
19816
  );
19775
19817
  const codeWarning = opts?.force ? null : codeChangedWarning(manifest.build, detectWorktreeState(projectRoot));
19776
- const cloudInfo = await pushRunToCloud(projectRoot, runId);
19818
+ const cloudInfo = opts?.push === false ? void 0 : await pushRunToCloud(projectRoot, runId);
19777
19819
  return { revisit, viewportWarning, codeWarning, cloudInfo };
19778
19820
  }
19779
19821
  function completeJsonPayload(canonical, extras) {
@@ -20226,9 +20268,28 @@ async function match(runId, opts) {
20226
20268
  );
20227
20269
  const needed = input.current.length > 0 && (input.prior.length > 0 || (input.guidance ?? []).length > 0);
20228
20270
  const prompt = needed ? composeMatchPrompt(input) : null;
20271
+ const promptFilePath = opts?.promptFile ?? path27.join(runDirPath, "match_prompt.md");
20272
+ if (prompt) {
20273
+ await fs27.writeFile(promptFilePath, prompt, "utf8");
20274
+ } else {
20275
+ try {
20276
+ await fs27.unlink(promptFilePath);
20277
+ } catch {
20278
+ }
20279
+ }
20229
20280
  if (opts?.json) {
20230
20281
  console.log(
20231
- JSON.stringify({ ...input, needed, match_prompt: prompt }, null, 2)
20282
+ JSON.stringify(
20283
+ {
20284
+ ...input,
20285
+ needed,
20286
+ prompt_file: prompt ? path27.relative(ctx.projectRoot, promptFilePath) : null,
20287
+ prompt_file_abs: prompt ? path27.resolve(promptFilePath) : null,
20288
+ match_prompt: prompt
20289
+ },
20290
+ null,
20291
+ 2
20292
+ )
20232
20293
  );
20233
20294
  return;
20234
20295
  }
@@ -20694,7 +20755,10 @@ function registerWalkthroughCommands(program) {
20694
20755
  ).option(
20695
20756
  "--run <run-id>",
20696
20757
  "Run ID to size browser (start) or record step into (step)"
20697
- ).option("--action <text>", "Action description (step only)").option("--note <text>", "Persona inner monologue / reasoning (step only)").option("--surface <name>", "Screen or surface name (step only)").option("--width <px>", "Window width (start)").option("--height <px>", "Window height (start)").option("--headless", "Run without a window (start)").option(
20758
+ ).option("--action <text>", "Action description (step only)").option("--note <text>", "Persona inner monologue / reasoning (step only)").option("--surface <name>", "Screen or surface name (step only)").option(
20759
+ "--step-file <path>",
20760
+ "Read step payload (action, note, cmd) from a JSON file or '-' for stdin (step only)"
20761
+ ).option("--width <px>", "Window width (start)").option("--height <px>", "Window height (start)").option("--headless", "Run without a window (start)").option(
20698
20762
  "--port <port>",
20699
20763
  "CDP port (start), default 9333",
20700
20764
  (value) => parsePortOption(value)
@@ -20770,9 +20834,9 @@ function registerWalkthroughCommands(program) {
20770
20834
  ).option("-y, --yes", "Skip interactive prompts").option("--no-prompt", "Skip interactive prompt to view results").option("--view", "Open results in browser immediately without prompt").option(
20771
20835
  "--strict-provenance",
20772
20836
  "Fail if steps show synthetic or programmatic timing anomalies"
20773
- ).addHelpText(
20837
+ ).option("--no-push", "Skip pushing the run to Iamu Cloud").addHelpText(
20774
20838
  "after",
20775
- "\nExamples:\n $ iamu complete <run-id>\n $ iamu complete <run-id> --view\n $ iamu complete <run-id> --no-prompt\n $ iamu complete <run-id> --json\n $ iamu complete <run-id> --strict-provenance"
20839
+ "\nExamples:\n $ iamu complete <run-id>\n $ iamu complete <run-id> --view\n $ iamu complete <run-id> --no-prompt\n $ iamu complete <run-id> --no-push\n $ iamu complete <run-id> --json\n $ iamu complete <run-id> --strict-provenance"
20776
20840
  ).action(
20777
20841
  async (runId, opts) => {
20778
20842
  const { complete: complete2 } = await Promise.resolve().then(() => (init_complete(), complete_exports));
@@ -20781,23 +20845,27 @@ function registerWalkthroughCommands(program) {
20781
20845
  );
20782
20846
  program.command("match <run-id>").helpGroup("Walkthrough:").description(
20783
20847
  "Compose the prompt that links this run's findings to earlier ones"
20784
- ).option("--json", "Output the match input bundle as JSON").action(async (runId, opts) => {
20785
- const { match: match2 } = await Promise.resolve().then(() => (init_match(), match_exports));
20786
- await match2(runId, opts);
20787
- });
20848
+ ).option("--json", "Output the match input bundle as JSON").option("--prompt-file <path>", "Write the generated prompt to a file").action(
20849
+ async (runId, opts) => {
20850
+ const { match: match2 } = await Promise.resolve().then(() => (init_match(), match_exports));
20851
+ await match2(runId, opts);
20852
+ }
20853
+ );
20788
20854
  program.command("match-record <run-id>").helpGroup("Walkthrough:").description(
20789
20855
  "Record finding matches and re-derive the run's since-last-run delta"
20790
20856
  ).requiredOption("--file <path>", "Path to matches JSON file").option("--json", "Output match results as JSON").action(async (runId, opts) => {
20791
20857
  const { matchRecord: matchRecord2 } = await Promise.resolve().then(() => (init_match(), match_exports));
20792
20858
  await matchRecord2(runId, opts);
20793
20859
  });
20794
- program.command("evaluate <run-id>").helpGroup("Walkthrough:").description("Compose evaluation prompt for human-test questions").option("--json", "Output evaluation input bundle as JSON").action(async (runId, opts) => {
20795
- const { evaluate: evaluate2 } = await Promise.resolve().then(() => (init_evaluate(), evaluate_exports));
20796
- await evaluate2(runId, opts);
20797
- });
20798
- program.command("evaluate-record <run-id>").helpGroup("Walkthrough:").description("Record evaluation verdicts into the run's verdicts.json").requiredOption("--file <path>", "Path to verdicts JSON file").option("--json", "Output summary as JSON").option("-y, --yes", "Skip interactive prompts").option("--no-prompt", "Skip interactive prompt to view results").option("--view", "Open results in browser immediately without prompt").addHelpText(
20860
+ program.command("evaluate <run-id>").helpGroup("Walkthrough:").description("Compose evaluation prompt for human-test questions").option("--json", "Output evaluation input bundle as JSON").option("--prompt-file <path>", "Write the generated prompt to a file").action(
20861
+ async (runId, opts) => {
20862
+ const { evaluate: evaluate2 } = await Promise.resolve().then(() => (init_evaluate(), evaluate_exports));
20863
+ await evaluate2(runId, opts);
20864
+ }
20865
+ );
20866
+ program.command("evaluate-record <run-id>").helpGroup("Walkthrough:").description("Record evaluation verdicts into the run's verdicts.json").requiredOption("--file <path>", "Path to verdicts JSON file").option("--json", "Output summary as JSON").option("-y, --yes", "Skip interactive prompts").option("--no-prompt", "Skip interactive prompt to view results").option("--no-push", "Skip pushing the updated run to Iamu Cloud").option("--view", "Open results in browser immediately without prompt").addHelpText(
20799
20867
  "after",
20800
- "\nExamples:\n $ iamu evaluate-record <run-id> --file verdicts.json\n $ iamu evaluate-record <run-id> --file verdicts.json --no-prompt\n $ iamu evaluate-record <run-id> --file verdicts.json --json"
20868
+ "\nExamples:\n $ iamu evaluate-record <run-id> --file verdicts.json\n $ iamu evaluate-record <run-id> --file verdicts.json --no-prompt\n $ iamu evaluate-record <run-id> --file verdicts.json --no-push\n $ iamu evaluate-record <run-id> --file verdicts.json --json"
20801
20869
  ).action(
20802
20870
  async (runId, opts) => {
20803
20871
  const { evaluateRecord: evaluateRecord2 } = await Promise.resolve().then(() => (init_evaluate(), evaluate_exports));
@@ -67,47 +67,45 @@ Filter to `triage_status: open`.
67
67
 
68
68
  A run that simply did not come across a finding proves nothing — never call a fix verified because it was not seen. After the list, if any fixes await a re-run, say how many and in which scenarios (`iamu status --json` → `rerun`, with `requests.open` for team requests), and offer `iamu-run <scenario>` for the first one.
69
69
 
70
- Group by `scenario` field and render as a severity-sorted table per scenario group (CRITICAL → MAJOR → MINOR → OBS; hinders and missing first, helps last):
70
+ Group by `scenario` field and render with an executive tally header, followed by a severity-sorted list per scenario group (CRITICAL → MAJOR → MINOR → OBS; hinders and missing first, helps last), including persona quotes, evidence, and clickable file links:
71
71
 
72
72
  ```
73
- Open findings (N total)
74
-
75
- ▼ maria-gomez--busy-shift (4 findings)
76
-
77
- | # | Severity | Type | Finding | Slug |
78
- |---|----------|---------|--------------------------------------------------|------------------------------------------------------------|
79
- | 1 | CRITICAL | hinders | Handoff list is cluttered | maria-gomez--busy-shift--handoff-list-cluttered-a1b2c3 |
80
- | 2 | MAJOR | missing | No visible confirmation after shift submit | maria-gomez--busy-shift--no-submit-confirmation-d4e5f6 |
81
- | 3 | MINOR | hinders | Timeout warning fires mid-input | maria-gomez--busy-shift--timeout-mid-input-g7h8i9 |
82
- | 4 | OBS | helps | Gesture hint at top of screen | maria-gomez--busy-shift--gesture-hint-j1k2l3 |
83
-
84
- ▼ dev-patel--checkout-abandon (3 findings)
85
-
86
- | # | Severity | Type | Finding | Slug |
87
- |---|----------|-----------|--------------------------------------------------|------------------------------------------------------------|
88
- | 5 | CRITICAL | incorrect | Cart total recalculates to wrong amount | dev-patel--checkout-abandon--cart-total-wrong-... |
89
- | 6 | MAJOR | missing | No save-for-later affordance | dev-patel--checkout-abandon--no-save-for-later-... |
90
- | 7 | MINOR | hinders | Auto-scroll on form error | dev-patel--checkout-abandon--auto-scroll-error-... |
73
+ Findings Tally: <N> Open (<C> Critical · <M> Major · <m> Minor) across <S> Scenarios
74
+ Awaiting verification: <K> addressed findings pending re-run
75
+
76
+ ▼ [<scenario>](iamu/scenarios/<scenario>.md) (4 findings)
77
+ 1. [CRITICAL · hinders] Handoff list is cluttered ([file](iamu/findings/<slug>.md))
78
+ • Persona: <Persona Name>: "<Persona reaction or consequence quote>"
79
+ • Evidence: Step <N> at <url>
80
+ • Recommendation: Add status filter chips
81
+
82
+ 2. [MAJOR · missing] No visible confirmation after shift submit ([file](iamu/findings/<slug>.md))
83
+ • Persona: <Persona Name>: "<Persona reaction or consequence quote>"
84
+ • Evidence: Step <N> at <url>
85
+ • Recommendation: Show inline success toast
91
86
  ```
92
87
 
93
- Ask the user which finding to triage (by number, slug, or "skip").
88
+ Ask the user how they would like to triage:
94
89
 
90
+ - **"walk through them"** → iterate through all open findings one-by-one in order with full context, code location, and triage choices (`[Fix now] [Skip / Dismiss] [Discuss] [Next]`).
95
91
  - **"all critical"** → iterate through all critical findings in order.
96
92
  - **Scenario group name** (e.g. "group 1") → iterate through that scenario's findings.
97
- - **Single number or slug** → single finding.
93
+ - **Single number or slug** → single finding (skip to step 3).
94
+ - **"fix 1 and 2"** → make code fixes and mark addressed immediately.
95
+ - **"skip 3" / "dismiss 3"** → dismiss with reason (`out_of_scope`, `not_relevant`, `walker_error`, `duplicate`).
98
96
 
99
97
  ### 3. Direct triage: review one finding
100
98
 
101
- Read the finding file at `iamu/findings/<slug>.md`. Parse the YAML frontmatter and markdown body. Render full detail:
99
+ Read the finding file at `iamu/findings/<slug>.md`. Parse the YAML frontmatter and markdown body. Render full detail with clickable links and evidence:
102
100
 
103
101
  ```
104
- Finding: <title>
105
- Slug: <slug>
106
- Scenario: <scenario>
107
- Type: <type> Severity: <severity> Triage: <triage_status>
102
+ Finding: <title> ([file](iamu/findings/<slug>.md))
103
+ Scenario: [<scenario>](iamu/scenarios/<scenario>.md)
104
+ Severity: <severity> · Type: <type> · Status: <triage_status>
108
105
 
109
- UI fact: <ui_fact>
110
- Consequence: <consequence>
106
+ Persona Quote: "<persona_reaction_or_consequence>"
107
+ UI Fact: <ui_fact>
108
+ Evidence: Step <N> at <url> (Screenshot: [view](iamu/.runs/<run>/screenshots/<NNN>.png))
111
109
 
112
110
  Description:
113
111
  <markdown body above ## Recommendation>
@@ -115,7 +113,7 @@ Description:
115
113
  Recommendation:
116
114
  <## Recommendation section, or "none">
117
115
 
118
- Linked run: iamu/.runs/<run>/report.md
116
+ Report: [report.md](iamu/.runs/<run>/report.md)
119
117
  ```
120
118
 
121
119
  If the finding references a run directory, mention the report path for context. If the user wants to see the screenshot, read from `iamu/.runs/<run>/screenshots/`.
@@ -56,53 +56,48 @@ Determine the mode based on `$ARGUMENTS` and user intent:
56
56
 
57
57
  ### 2. Propose scenario seeds
58
58
 
59
- Propose 2–3 scenario seeds in a compact comparison table fitting the terminal viewport. If personas exist in `iamu/personas/`, explicitly indicate which existing persona pairs with each seed concept. Do not write full paragraphs or full scenarios until a direction is picked.
59
+ Propose 2–3 scenario seeds as scannable numbered cards. Do NOT use multi-column markdown tables with full prose sentences (they wrap awkwardly and break borders in terminal viewports). If personas exist in `iamu/personas/`, explicitly indicate which existing cast member pairs with each seed concept.
60
60
 
61
61
  ```
62
- | # | Seed Concept | Persona / Actor | Type | Human Situation & Core Tension | What It Stress-Tests |
63
- |---|--------------|-----------------|------|--------------------------------|----------------------|
64
- | 1 | <Short title> | <existing slug or role> | Routine | <1-2 sentences on who is doing what> | <What this tests> |
65
- | 2 | <Short title> | <existing slug or role> | Edge case | <1-2 sentences on uncommon situation> | <What this tests> |
66
- | 3 | <Short title> | <existing slug or role> | Tension | <1-2 sentences on conflicting needs> | <What this tests> |
62
+ 1. <Title> (<Type> · <existing persona slug or context actor>)
63
+ • Tension: <1 concise sentence on the human or organizational tension>
64
+ • Stress-tests: <What this reveals about the product>
65
+
66
+ 2. <Title> (<Type> · <existing persona slug or context actor>)
67
+ • Tension: <1 concise sentence>
68
+ • Stress-tests: <What this reveals about the product>
69
+
70
+ 3. <Title> (<Type> · <existing persona slug or context actor>)
71
+ • Tension: <1 concise sentence>
72
+ • Stress-tests: <What this reveals about the product>
67
73
  ```
68
74
 
69
75
  Ask the user: "Which seed should we develop (1–3), or suggest another angle?"
70
76
 
71
77
  ### 3. Develop the situation
72
78
 
73
- Once the user picks a direction, draft the full situation:
74
-
75
- - **Narrative** (3–5 sentences) — mundane specifics, not abstract test language. Time pressure, competing priorities, real constraints. Write it as a human story.
76
- - **Tension** (usually null; set only when two legitimate needs genuinely collide — e.g., speed vs. thoroughness, privacy vs. transparency)
77
- - **Situation roles** (2–4 people with stakes) — each person should see the situation differently. Not conflict for drama — realistic tension like: one person wants to move on, another wants to investigate.
78
- - **Complexity level**
79
-
80
- **Before finalizing**, ask the user: "What should this walkthrough focus on?" This is the research question — what they want to learn. Examples: "Can a new admin onboard without training?", "Does the checkout flow work under time pressure?", "Is the reporting workflow accessible to non-technical users?"
81
-
82
- From their answer, derive ONE concrete human test — a specific yes/partial/no checkpoint the evaluation step will score. Suggest it and let the user refine:
79
+ Once the user picks a direction (e.g. "1"), draft the situation concisely.
83
80
 
84
- > Focus: "Can a new admin onboard without training?"
85
- > Human test: "Could the admin complete employee bulk-import without consulting documentation?"
81
+ Do NOT ask an open-ended question like "What should this walkthrough focus on?" and then immediately answer it yourself in the same turn. Instead, propose an opinionated research focus question and one concrete binary (yes/partial/no) human checkpoint directly in the draft for the user to confirm or adjust.
86
82
 
87
- The user's focus frames the overall assessment after the walkthrough. The human test is a concrete checkpoint that feeds into it.
83
+ Do NOT use markdown blockquote syntax (`>`), which renders as stray `|` pipe characters in terminal frontends. Keep the narrative capped at 2–3 punchy sentences (problem-space only, zero UI terms).
88
84
 
89
85
  Present the draft to the user as a structured, scannable block **before creating anything**:
90
86
 
91
87
  ```
92
88
  ### Situation Draft: <Name>
93
89
 
94
- > **Narrative:** <3–5 sentences describing the human situation without mentioning UI>
95
- >
96
- > **Tension:** <legitimate colliding needs or "None">
97
- > **Focus Question:** <user's research question>
98
- > **Human Checkpoint:** <derived checkpoint question>
90
+ Narrative: <2–3 sentences describing the human situation, time pressure, or physical reality without mentioning software UI>
91
+ Tension: <Legitimate colliding needs or "None">
92
+ Focus Question: <Proposed research focus question, e.g. "Can a frontline worker submit an urgent slip hazard report in under 60 seconds without abandoning floor duties?">
93
+ Human Checkpoint: <Concrete binary yes/partial/no question scored at evaluation>
99
94
 
100
- **Roles with Stakes:**
101
- - **<role>**: <stake>
102
- - **<role>**: <stake>
95
+ Roles with Stakes:
96
+ • <Role 1>: <Stake>
97
+ • <Role 2>: <Stake>
103
98
  ```
104
99
 
105
- User approves, refines ("make it more time-pressured"), or rejects.
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)"
106
101
 
107
102
  ### 4. Pick or propose personas
108
103
 
@@ -110,25 +105,25 @@ User approves, refines ("make it more time-pressured"), or rejects.
110
105
  Inspect `iamu/personas/` (`iamu list personas`). If an existing persona in the casting panel is a natural fit for this situation, propose them first to build longitudinal test history:
111
106
  `Reusable from panel: <slug> (<role>) — <why they fit this situation>`
112
107
 
113
- If no existing persona fits, or if testing an uncovered perspective is needed, propose 2–3 persona candidates in a compact table:
114
-
115
- - Different roles (the manager vs. the field worker vs. the auditor)
116
- - Different dispositions (the patient learner vs. the harried pragmatist)
117
- - Different contexts (first time vs. experienced, desktop vs. mobile, fluent vs. second-language)
108
+ If no existing persona fits, or if testing an uncovered perspective is needed, propose 2–3 persona candidates as numbered cards (do NOT use a wide table):
118
109
 
119
110
  ```
120
- | # | Name | Role | Why this persona tests something different |
121
- |---|------|------|-------------------------------------------|
122
- | 1 | ... | ... | ... |
123
- | 2 | ... | ... | ... |
124
- | 3 | ... | ... | ... |
111
+ 1. <Name> (<Role>)
112
+ • Friction & Biases: <Specific friction triggers, skepticism, and bounce risks>
113
+ • Why this tests something different: <Unique perspective or workflow divergence>
114
+
115
+ 2. <Name> (<Role>)
116
+ • Friction & Biases: <Specific friction triggers, skepticism, and bounce risks>
117
+ • Why this tests something different: <Unique perspective or workflow divergence>
125
118
  ```
126
119
 
127
120
  The user picks one (or more — each becomes a separate scenario). "New" to propose different candidates. "Skip" to save as draft without a persona.
128
121
 
129
122
  ### 5. Classify into capabilities
130
123
 
131
- Situations carry ONE primary capability (product area grouping) and optional secondary capabilities (cross-cutting tags). Read existing capabilities from `iamu/capabilities/`.
124
+ Situations carry ONE primary capability (product area grouping) and optional secondary capabilities (cross-cutting tags). Read existing capabilities directly from `iamu/capabilities/` or `iamu/context.yml`.
125
+
126
+ Do NOT execute interactive bash commands (like `iamu list capabilities`) during conversational turns; resolve capabilities silently from workspace files.
132
127
 
133
128
  - **High confidence match** → assign silently, one line: `Capability: <slug> (auto)`
134
129
  - **Low confidence or new** → ask: "Create new capability `<slug>`?"
@@ -178,12 +173,16 @@ For drafts (no persona): omit `--persona`, omit the brief body.
178
173
 
179
174
  ### 7. Summarize
180
175
 
176
+ Present the created entities with clickable file links and exact run commands:
177
+
181
178
  ```
182
- Scenario: <scenario-slug>
183
- Situation: <situation name>
184
- Persona: <persona-name> (or "draft — no persona yet")
179
+ Created Scenario: [<scenario-slug>](iamu/scenarios/<scenario-slug>.md)
180
+ • Situation: [<outline-slug>](iamu/outlines/<outline-slug>.md)
181
+ • Persona: [<persona-slug>](iamu/personas/<persona-slug>.md) (or "draft — no persona bound yet")
182
+ • Capability: <primary_capability>
185
183
 
186
- Run it: iamu-run <scenario-slug>
184
+ Next step:
185
+ iamu-run <scenario-slug> # Run walkthrough as <persona-name>
187
186
  ```
188
187
 
189
188
  Run `iamu validate --all` to verify all entities before reporting done.
@@ -61,40 +61,56 @@ Four entry paths based on `$ARGUMENTS`:
61
61
  - **Open-ended** (e.g. `iamu-propose`, `iamu-propose "what's missing?"`) — analyze coverage gaps across both scenarios and persona diversity. Prioritize uncovered capabilities and actors without personas.
62
62
  - **Specific tension** (e.g. `iamu-propose "what happens when the safety coordinator disagrees with HR?"`) — use as seed but ground in context. Verify the tension is real (do these actors and dynamics exist in the domain?).
63
63
 
64
- ### 4. Present candidates (Comparison Table)
64
+ ### 4. Present candidates (Numbered Cards)
65
65
 
66
- Present candidates in a single, high-contrast **Markdown comparison table** fitting the terminal viewport. Do NOT dump long paragraphs, full narratives, or regulatory citations upfront.
66
+ Present candidates as scannable numbered cards. Do NOT use multi-column markdown tables with full prose sentences (they wrap awkwardly and break borders in terminal viewports). Do NOT dump long paragraphs, full narratives, or regulatory citations upfront.
67
67
 
68
68
  #### A. When proposing Scenarios:
69
69
 
70
- Lead with a one-line summary of existing coverage, then render the table:
70
+ Lead with existing coverage using clickable links, then render the candidates:
71
71
 
72
72
  ```
73
- Existing coverage: <N> scenarios (<list slugs>). Uncovered areas: <gaps>.
73
+ Existing coverage: <N> scenarios ([<slug1>](iamu/scenarios/<slug1>.md), ...). Uncovered areas: <gaps>.
74
74
 
75
- | # | Situation | Role | Core Domain Tension | What It Stress-Tests |
76
- |---|-----------|------|---------------------|----------------------|
77
- | 1 | <Short situation name> | <Actor from context> | <1-line human/domain tension> | <What this reveals about the product> |
78
- | 2 | ... | ... | ... | ... |
79
- | 3 | ... | ... | ... | ... |
75
+ 1. <Short situation name> (<Actor from context>)
76
+ • Tension: <1-line human/domain tension>
77
+ • Stress-tests: <What this reveals about the product>
80
78
 
81
- Pick a number (1–3) to draft via iamu-new, or refine (e.g. "make #2 more time-pressured", "none of these — explore <area>").
79
+ 2. <Short situation name> (<Actor from context>)
80
+ • Tension: <1-line human/domain tension>
81
+ • Stress-tests: <What this reveals about the product>
82
+
83
+ 3. <Short situation name> (<Actor from context>)
84
+ • Tension: <1-line human/domain tension>
85
+ • Stress-tests: <What this reveals about the product>
86
+
87
+ Next action:
88
+ Type 1, 2, or 3 to scaffold via iamu-new
89
+ Or describe adjustments (e.g. "make #2 more time-pressured", "explore <area>")
82
90
  ```
83
91
 
84
92
  #### B. When proposing Personas:
85
93
 
86
- Lead with existing persona coverage and uncovered roles from `context.yml`:
94
+ Lead with existing persona coverage using clickable links and uncovered roles from `context.yml`:
87
95
 
88
96
  ```
89
- Existing personas: <list slugs>. Uncovered roles from context.yml: <roles>.
97
+ Existing personas: [<slug1>](iamu/personas/<slug1>.md), ... Uncovered roles from context.yml: <roles>.
98
+
99
+ 1. <Name> (<Actor role>)
100
+ • Friction & Biases: <Specific friction triggers, skepticism, and bounce risks>
101
+ • Key Expectations & Vocabulary: <Domain terms and spec requirements>
102
+
103
+ 2. <Name> (<Actor role>)
104
+ • Friction & Biases: <Specific friction triggers, skepticism, and bounce risks>
105
+ • Key Expectations & Vocabulary: <Domain terms and spec requirements>
90
106
 
91
- | # | Persona Candidate | Domain Role | Diagnostic Friction & Biases | Key Expectations & Vocabulary |
92
- |---|-------------------|-------------|------------------------------|-------------------------------|
93
- | 1 | <Name> | <Actor role> | <Specific friction triggers, skepticism, and bounce risks> | <Domain terms and spec requirements> |
94
- | 2 | ... | ... | ... | ... |
95
- | 3 | ... | ... | ... | ... |
107
+ 3. <Name> (<Actor role>)
108
+ • Friction & Biases: <Specific friction triggers, skepticism, and bounce risks>
109
+ • Key Expectations & Vocabulary: <Domain terms and spec requirements>
96
110
 
97
- Pick a number (1–3) to draft via iamu-new (as a standalone persona or with a scenario), or refine.
111
+ Next action:
112
+ Type 1, 2, or 3 to scaffold via iamu-new
113
+ Or describe adjustments
98
114
  ```
99
115
 
100
116
  Ground rules for generation:
@@ -215,6 +215,12 @@ Use atomic CLI commands to drive and record in one step — do NOT manually auth
215
215
  iamu browse step --run <run-id> --action "Opened dashboard" --note "First thing I see is the overview panel" goto https://app.example.com/dashboard
216
216
  iamu browse step --run <run-id> --action "Click checkout" --note "Button was hard to find" click button "Checkout"
217
217
  ```
218
+ **Avoid shell quoting friction:** When persona notes or actions contain quotes, apostrophes, or multi-line monologues, use `--step-file <path>` (or `-` for stdin) to avoid shell escaping errors:
219
+ ```bash
220
+ iamu browse step --run <run-id> --step-file <path-to-step.json> click button "Checkout"
221
+ # or pass the entire action payload including cmd via JSON / stdin:
222
+ # { "action": "...", "note": "...", "cmd": ["click", "button", "Checkout"] }
223
+ ```
218
224
  This executes the browser action, waits for the DOM, takes the screenshot into `screenshots/step-N.png`, captures the URL, and writes `steps/NNN.json` atomically.
219
225
 
220
226
  - **When using an external surface (iOS Simulator / custom MCP):**
@@ -249,26 +255,21 @@ Findings never name a human test: the walker does not see them. The judge links
249
255
 
250
256
  After the walker returns, you MUST complete ALL of the following before presenting findings to the user. Do NOT present findings early. Do NOT ask the user anything. Execute steps A→B→C→D→E in order.
251
257
 
252
- **A. Assemble canonical + report.** Use the CLI:
258
+ **A. Assemble canonical + report (local).** Use `--no-push` so post-processing stays fast, local, and synchronous:
253
259
 
254
260
  ```bash
255
- iamu complete <run-id> --no-prompt
261
+ iamu complete <run-id> --no-prompt --no-push --json
256
262
  ```
257
263
 
258
- This reads all steps, findings, and entity files, assembles `canonical.json`, generates `report.md`, computes the delta against prior runs, and flips the manifest to completed. All in one command.
264
+ This reads all steps, findings, and entity files, assembles `canonical.json`, generates `report.md`, and computes the delta against prior runs.
259
265
 
260
- To get the canonical data for presentation, run with `--json`:
261
- ```bash
262
- iamu complete <run-id> --no-prompt --json
263
- ```
264
-
265
- **B. Match findings to earlier runs.** A fresh walker never words a recurring problem the same way twice, so `complete` alone reports recurrences as new and earlier findings as "not seen". Get the matcher bundle:
266
+ **B. Match findings to earlier runs.** Get the matcher bundle:
266
267
 
267
268
  ```bash
268
269
  iamu match <run-id> --json
269
270
  ```
270
271
 
271
- If `needed` is `false` (no earlier findings for this scenario, or none this run), skip to C. Otherwise dispatch a matcher subagent with `match_prompt` as its only context — NOT the walker, which must never see earlier findings. Write its JSON answer to a file and record it:
272
+ If `needed` is `false` (no earlier findings for this scenario, or none this run), skip to C. Otherwise, read the prompt from `iamu/.runs/<run-id>/match_prompt.md` directly and dispatch a matcher subagent with it as its only context. Write its JSON answer to `<matches.json>` and record it:
272
273
 
273
274
  ```bash
274
275
  iamu match-record <run-id> --file <matches.json>
@@ -276,23 +277,23 @@ iamu match-record <run-id> --file <matches.json>
276
277
 
277
278
  This links recurrences to their earlier canonical finding, marks earlier findings the run's steps show fixed (only with cited steps), and re-derives the delta and report. If the matcher's output is rejected, show the error to the matcher once and retry; if it fails again, continue without it — the exact-text delta from A stands.
278
279
 
279
- **C. Evaluate human tests.** Use the CLI to get the evaluation prompt:
280
+ **C. Evaluate human tests.** Get the evaluation prompt:
280
281
 
281
282
  ```bash
282
283
  iamu evaluate <run-id> --json
283
284
  ```
284
285
 
285
- This returns the judge prompt input bundle. Dispatch the evaluator as a subagent with that prompt. After the evaluator returns verdicts, record them:
286
+ Read the evaluation prompt from `iamu/.runs/<run-id>/judge_prompt.md` directly. Dispatch the evaluator as a subagent with that prompt. After the evaluator returns verdicts, record them locally with `--no-push`:
286
287
 
287
288
  ```bash
288
- iamu evaluate-record <run-id> --file <verdicts.json> --no-prompt
289
+ iamu evaluate-record <run-id> --file <verdicts.json> --no-prompt --no-push
289
290
  ```
290
291
 
291
- This also links the findings each verdict cites to that human test (`human_test_id` on the finding file, only where none is set), so `iamu sync` carries the link to the cloud.
292
+ This links findings to human tests (`human_test_id`) and updates the report with judge verdicts.
292
293
 
293
294
  **D. Read the completed canonical.** Read `iamu/.runs/<run-id>/canonical.json` for the final data including verification delta (if a prior run exists). Use this for step 5 presentation.
294
295
 
295
- **E. Publish (linked mode only).** `complete` and `evaluate-record` already pushed the run itself — report, steps, screenshots, verdicts. What they do not push are the finding files the matcher and judge updated (recurrence links, `human_test_id`); those go with sync:
296
+ **E. Publish (linked mode only).** Upload the completed run, screenshots, verdicts, and findings in one atomic sync:
296
297
 
297
298
  ```bash
298
299
  iamu sync --json
@@ -320,15 +321,17 @@ The `walker_prompt` from `iamu instructions walk` is the source of truth and con
320
321
 
321
322
  ### 5. Present assessment — stay in the conversation
322
323
 
323
- Render results **inline** so the user can act without leaving the conversation. Lead with the overall assessment, not a findings dump.
324
-
325
- 1. **Overall assessment** — answer the research question from the outline's human test. Read the outline's `human_tests[0].question` (the focus question the user defined when creating the scenario). Frame the verdict around it:
324
+ Render results **inline** with a high-contrast executive summary banner, followed by findings enriched with persona voice, evidence citations, and clickable file links.
326
325
 
327
- > **Could the admin complete bulk-import without consulting documentation?** No. The import flow requires knowledge of the role hierarchy that isn't documented in-app. 3 issues found, 1 critical.
326
+ 1. **Executive Summary Banner & Focus Checkpoint**
328
327
 
329
- If the evaluation subagent ran, use its verdict. If it failed or wasn't run, synthesize from findings: count hinders/missing by severity, state whether the persona could complete their task.
328
+ Read the outline's `human_tests[0].question` and answer it directly. Use the evaluation verdict if available:
330
329
 
331
- **This is the most important part of the output.** The user defined this question as their focus — answer it directly.
330
+ ```
331
+ Walkthrough: [<scenario-slug>](iamu/scenarios/<scenario-slug>.md) ([<persona>](iamu/personas/<persona>.md))
332
+ Verdict: <FAIL / PARTIAL / PASS> · <N> Blockers (Critical) · <M> Friction points (Major/Minor) · <K> Helpers (Steps: <N>)
333
+ Focus Checkpoint: "<human_tests[0].question>" → <No / Partial / Yes>: <1-2 sentence direct answer explaining why>
334
+ ```
332
335
 
333
336
  2. **Progress since last run** (only when canonical.json contains a `verification` section). Present the delta:
334
337
 
@@ -340,25 +343,25 @@ Render results **inline** so the user can act without leaving the conversation.
340
343
  + 1 new since that run (date picker locale)
341
344
  ```
342
345
 
343
- `resolved` means the matcher saw this run's steps do the thing the finding said failed — say which step. `not_observed` means only that this walk did not record the finding again. Never present it as fixed: the walker may have stopped before that screen or taken another route. Say which ones were not seen and, if the walk plainly never reached the screen they live on, say that too. `iamu complete` reports whether the walk reached the places where fixes await a re-run (`Re-check places: reached N of M`, `revisit_coverage` in `--json`); name the ones not reached — their fixes stay awaiting.
344
-
345
- If no prior run exists, skip this.
346
+ `resolved` means the matcher saw this run's steps do the thing the finding said failed — say which step. `not_observed` means only that this walk did not record the finding again. Never present it as fixed: the walker may have stopped before that screen or taken another route. Say which ones were not seen and, if the walk plainly never reached the screen they live on, say that too.
346
347
 
347
- 3. **Findings** — severity-first (CRITICAL → MAJOR → MINOR), grouped by type (hinders and missing first — the actionable ones — then helps at the bottom):
348
+ 3. **Findings** — severity-first (CRITICAL → MAJOR → MINOR), grouped by type (hinders and missing first, helps at the bottom). For each finding, include the **persona reaction**, **evidence citation**, and **clickable link**:
348
349
 
349
350
  **Hinders / Missing** (act on these):
350
351
 
351
- | # | Severity | Type | Finding | Recommendation |
352
- |---|----------|------|---------|----------------|
353
- | 1 | CRITICAL | hinders | Submit fails opaquely when required field empty | Show validation inline before submit |
354
- | 2 | MAJOR | hinders | Date picker has no "today" shortcut | Add quick-select for common dates |
355
- | 3 | MINOR | missing | Help text uses jargon ("slutdatum") | Use plain language ("end date") |
352
+ 1. [CRITICAL · hinders] Submit fails opaquely when required field empty ([file](iamu/findings/<slug>.md))
353
+ • Persona: <Persona Name>: "<Persona reaction quote or consequence showing real human friction>"
354
+ • Evidence: Step <N> at <url> (Screenshot: [view](iamu/.runs/<run-id>/screenshots/<NNN>.png))
355
+ • Recommendation: <Concrete recommendation from finding>
356
+
357
+ 2. [MAJOR · hinders] Date picker has no "today" shortcut ([file](iamu/findings/<slug>.md))
358
+ • Persona: <Persona Name>: "<Persona reaction quote or consequence>"
359
+ • Evidence: Step <N> at <url>
360
+ • Recommendation: <Concrete recommendation from finding>
356
361
 
357
362
  **Helps** (preserve these):
358
363
 
359
- | # | Type | Finding |
360
- |---|------|---------|
361
- | 4 | helps | Search auto-suggests from recent entries |
364
+ • [helps] Search auto-suggests from recent entries (Step <N>)
362
365
 
363
366
  4. **What worked** — supportive moments worth preserving (brief, from `what_worked` in the canonical JSON).
364
367
 
@@ -369,16 +372,65 @@ Render results **inline** so the user can act without leaving the conversation.
369
372
 
370
373
  6. **Cloud** — one line, by mode:
371
374
  - **Linked, run on the cloud** → `Shareable report: <url>` (screenshots and step replay for anyone on the team).
372
- - **Linked, run not on the cloud** → the reason from step E and its remedy, e.g. `Cloud: queued — retries on the next iamu sync` or `Cloud: not pushed — <reason>`.
373
- - **Linked, no credentials** → `Cloud: not pushed — this machine has no credentials; iamu auth login restores them.`
374
- - **Sync conflicts or pending deletions** (step E) → one line each: name the findings a teammate changed and give the CLI's resolution (`iamu pull --force` to take theirs after copying your edits aside, or `iamu sync --keep-mine` to keep yours — the user runs that one); for deletions, tell the user to review them and run `iamu sync --confirm-deletes` themselves.
375
- - **Local-only** → nothing, with one exception: on the project's first completed run (`iamu status --json` → `runs.count` is 1), add `Want a link to share this report? iamu auth login connects the project to Iamu Cloud — optional, everything keeps working locally.` Never repeat it on later runs unless the user asks how to share a report.
375
+ - **Linked, run not on the cloud** → the reason from step E and its remedy, e.g. `Cloud: queued — retries on the next iamu sync`.
376
+ - **Local-only** → on first completed run: `Want a link to share this report? iamu auth login connects to Iamu Cloud — optional, everything keeps working locally.`
376
377
 
377
- 7. **End with a verb**: "Which ones should I fix? (You can also dismiss any finding — it won't show up in future runs.)"
378
+ 7. **Next actions (Conversational Triage)**:
378
379
 
379
- **Stay conversational.** The user says "fix 1 and 2" → you read the finding details from the canonical JSON (already in your context from the canonical assembly), look at the relevant code, and make the fix. Mark findings addressed by editing their frontmatter (`triage_status: addressed`, `triage_note: "..."`) as you go.
380
+ Conclude your report with clear conversational prompts instead of raw terminal commands:
381
+
382
+ ```
383
+ What would you like to do?
384
+ • "walk through them" → Review findings one by one with persona context & code location
385
+ • "fix 1 and 2" → Have me implement code fixes directly
386
+ • "discuss 2" → Ask why the persona hit this friction or explore trade-offs
387
+ • "skip 3" / "dismiss 3" → Dismiss finding (out of scope, intended, or walker error)
388
+ • "re-run" → Re-run walkthrough to verify fixes
389
+ ```
380
390
 
381
- If the user says "skip 3" or "not relevant" or "dismiss" for a finding, set `triage_status: dismissed` with a `triage_note` explaining why. **Tell the user:** "Dismissed — this won't be reported in any future walkthrough."
391
+ ### 6. Conversational Triage & Guided Review
392
+
393
+ The conversation is the triage surface. Do NOT eject the user to manual CLI commands or dump them at file paths.
394
+
395
+ #### A. Guided One-by-One Review ("walk through them" / "review one by one")
396
+ When the user asks to review findings one by one:
397
+ 1. **Present Finding #N in isolation**:
398
+ - Number, severity, type, and title
399
+ - Persona consequence quote and why the friction occurred
400
+ - Relevant source code location (inspect project files to provide file path + line numbers)
401
+ - Step & screenshot evidence ([view](iamu/.runs/<run-id>/screenshots/<NNN>.png))
402
+ - Actionable recommendation
403
+ - Clear options prompt:
404
+ `Options: [Fix now] [Skip / Dismiss] [Discuss / Why] [Next finding]`
405
+
406
+ 2. **Handle the user's decision**:
407
+ - **Fix now**:
408
+ Make the code edit, verify it loads (or check local tests/types), update the finding's frontmatter (`triage_status: addressed`, `triage_note: "<summary of fix>"`).
409
+ Tell the user the fix is applied and ask: "Ready for finding #<N+1>?".
410
+ - **Skip / Dismiss**:
411
+ If reason is not specified, ask or infer the appropriate category:
412
+ - `out_of_scope`: Not relevant to this project/flow scope.
413
+ - `not_relevant`: By design / intended behavior.
414
+ - `walker_error`: Walker misread the screen or made a navigational error.
415
+ - `duplicate`: Duplicate of another finding.
416
+ Execute: `iamu triage <slug> --status dismissed --reason <reason> --note "<why>"`.
417
+ Tell the user: "Dismissed as `<reason>` — created guidance rule in `iamu/guidance/<slug>.md` so future walkthroughs will not report this."
418
+ Then advance to finding #<N+1>.
419
+ - **Discuss / Why**:
420
+ Analyze why the persona experienced this friction, cite the persona brief and steps/screenshots, evaluate whether competitor tools solve this pattern, and give a direct opinion on whether it's worth fixing.
421
+ - **Next**:
422
+ Leave open (or set `triage_status: deferred` with note) and advance to finding #<N+1>.
423
+
424
+ 3. **Wrap up after all findings are reviewed**:
425
+ - Run `iamu validate --all`.
426
+ - In linked mode, run `iamu sync --json` once so teammates see the triage decisions.
427
+ - Suggest re-running the walkthrough: `iamu-run <scenario-slug>` to verify fixes.
428
+
429
+ #### B. Direct Batch Actions ("fix 1 and 2", "fix all critical")
430
+ Read the finding details from the canonical JSON (already in context), inspect the code, make the edits, and update frontmatter to `triage_status: addressed` with `triage_note`.
431
+
432
+ #### C. Ad-hoc Questions & Challenges ("why did Karl do that?", "is #2 really a bug?")
433
+ Answer directly using persona brief context and step evidence. If the walker got confused or misinterpreted intended behavior, recommend dismissing as `walker_error` or `not_relevant` rather than adding unnecessary code.
382
434
 
383
435
  **Linked mode: publish triage decisions.** When the user is done fixing and dismissing, run `iamu sync --json` once so teammates see the decisions (and any team request for these findings closes). Report it in one line (`Synced 3 findings to Iamu Cloud.`), with conflicts handled as in item 6. Do not sync after every single edit.
384
436
 
@@ -21,24 +21,28 @@ $ARGUMENTS
21
21
 
22
22
  Do NOT use `find`, `grep`, or `cat` to dump raw `.md` files in `iamu/`. The CLI outputs clean, validated data.
23
23
 
24
- ### 2. Format entity responses as compact tables
24
+ ### 2. Format entity responses with an executive tally and clickable links
25
25
 
26
- When the user asks for personas, scenarios, or findings, respond with a scannable Markdown table. Never dump full psychological profiles, vocabulary lists, or raw frontmatter unless the user explicitly asks for deep detail on one entity.
26
+ When the user asks for project status, lead with an executive tally banner, followed by scannable tables with clickable markdown file links:
27
+
28
+ ```
29
+ Project Status: <P> Personas · <S> Scenarios (<R> Tested, <U> Untested) · <F> Open Findings · <C> Capabilities
30
+ ```
27
31
 
28
32
  **Personas:**
29
33
  | Slug | Name | Role | Status |
30
34
  |---|---|---|---|
31
- | `elin-dahl` | Elin Dahl | Architect & first-time house owner in Falun | active |
35
+ | [`elin-dahl`](iamu/personas/elin-dahl.md) | Elin Dahl | Architect & first-time house owner in Falun | active |
32
36
 
33
37
  **Scenarios:**
34
38
  | Slug | Persona | Outline | Status / Target |
35
39
  |---|---|---|---|
36
- | `replacing-windows` | `elin-dahl` | `measure-and-order` | ready |
40
+ | [`replacing-windows`](iamu/scenarios/replacing-windows.md) | [`elin-dahl`](iamu/personas/elin-dahl.md) | [`measure-and-order`](iamu/outlines/measure-and-order.md) | ready |
37
41
 
38
42
  **Findings:**
39
- | # | Severity | Type | Finding | Status |
43
+ | # | Severity | Type | Finding | File |
40
44
  |---|---|---|---|---|
41
- | 1 | CRITICAL | hinders | Submit fails opaquely on empty field | open |
45
+ | 1 | CRITICAL | hinders | Submit fails opaquely on empty field | [`view`](iamu/findings/<slug>.md) |
42
46
 
43
47
  ### 3. Ignore internal templates
44
48
 
@@ -52,13 +56,16 @@ For a project-status question, add one line on the cloud from `iamu status --jso
52
56
  - **Linked, no credentials** → `Cloud: linked, but this machine has no credentials — iamu auth login.`
53
57
  - **Local-only** → `Cloud: local-only.` Nothing more; no upgrade pitch.
54
58
 
55
- ### 5. Provide clear next steps
59
+ ### 5. Provide copy-pasteable next actions
60
+
61
+ Conclude with exact copy-pasteable commands:
56
62
 
57
- Conclude with one concise action prompt:
58
- - To run a scenario: `iamu-run <scenario-slug>`
59
- - To propose new personas or scenarios: `iamu-propose`
60
- - To draft a persona or scenario directly: `iamu-new`
61
- - To review open findings or team requests: `iamu-findings`
62
- - To inspect reports: `iamu report`, or `iamu open` for the cloud dashboard (linked projects)
63
- - To share unpushed work with the team: `iamu sync` (linked projects)
63
+ ```
64
+ Next actions:
65
+ iamu-run <scenario-slug> # Run a walkthrough for this scenario
66
+ iamu-propose # Propose missing personas or scenarios
67
+ iamu-new # Draft a new scenario or persona
68
+ iamu-findings # Triage open findings
69
+ iamu open # Open project in cloud dashboard
70
+ ```
64
71
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iamu-dev/iamu",
3
- "version": "0.2.0-beta.4",
3
+ "version": "0.2.0-beta.5",
4
4
  "type": "module",
5
5
  "description": "Test your product as realistic personas — scenario-driven development CLI",
6
6
  "license": "UNLICENSED",
@@ -58,8 +58,8 @@
58
58
  "typescript": "^5.8.0",
59
59
  "vitest": "^4.1.11",
60
60
  "@iamu-dev/local-store": "0.1.0",
61
- "@iamu-dev/protocol": "0.1.0",
62
- "@iamu/tsconfig": "0.1.0"
61
+ "@iamu/tsconfig": "0.1.0",
62
+ "@iamu-dev/protocol": "0.1.0"
63
63
  },
64
64
  "scripts": {
65
65
  "build": "tsup && tsc -b tsconfig.build.json --emitDeclarationOnly && node scripts/copy-assets.mjs",