Skip to content

DEMO: Onboarding DEMO for New Users #1692

Description

@BryanHarrisScripts

Goal

Create a first-run DEMO experience that lets a new Human understand and try PlotPickle before creating or unlocking a private local profile.

This should reduce onboarding friction without weakening the existing profile, Guest, storage, canon or agent-authority boundaries.

Why

PlotPickle is easier to understand by experiencing it than by reading a feature list. A new user should be able to launch the app, choose DEMO, interact with a small synthetic story world, see how decisions propagate, and then decide whether to create a real local profile.

The experience should borrow the useful idea behind HumanLayer's show-me skill: explain the current thing visually with the smallest useful view. For PlotPickle, this becomes a bounded Sage capability rather than a dependency on HumanLayer.

Refs #1675 and the existing profile/auth work in #1143.

First-run shape

On a fresh installation, present two clear choices:

  1. DEMO � See PlotPickle work

    • no account, password, GitHub, BUZZ identity, provider key or cloud setup required;
    • opens a synthetic, disposable PlotPickle world;
    • safe to reset at any time.
  2. ENTER PLOTPICKLE � Create or unlock your private profile

    • uses the existing local-profile/authentication architecture unchanged.

For returning users with an existing local profile, normal startup may continue to favor the profile chooser while keeping DEMO available as a secondary action.

Architectural boundary

DEMO must be a separate bounded runtime. It must NOT silently expand the current Guest surface.

Existing Guest behavior remains unchanged: ephemeral notes only, no mounting of the private PlotPickle application, and deletion on exit.

DEMO may mount a curated application experience only against synthetic/demo-owned data. It must have no read/write access to:

  • private Human profiles;
  • private projects or libraries;
  • Human Wyrmwood state;
  • BUZZ private identity/context;
  • provider credentials;
  • GitHub/Google connections;
  • real PPF canon;
  • local filesystem paths outside the demo-owned sandbox.

Demo content

Start with one small prepared STORY scenario, ideally 5–10 minutes.

The demo should visibly demonstrate a few uniquely PlotPickle behaviors rather than expose every workspace:

  • a character makes or receives a consequential decision;
  • STORY deterministically recalculates the result;
  • character/private knowledge remains hidden from the wrong participant;
  • a Story Piece or structured consequence is visible;
  • PPF/canon authority is explained without allowing DEMO to mutate real canon;
  • Wyrmwood presents a playable/story consequence where useful;
  • Sage explains what changed and why.

Sage "Show Me" capability

Add a narrow explanatory mode for Sage that selects the smallest useful visual representation for the current concept.

Possible views:

  • before/after state change;
  • character knowledge partition;
  • decision → consequence flow;
  • scene/character/object relationship map;
  • STORY vs PPF vs Wyrmwood vs BUZZ authority diagram;
  • agent permission/authority boundary.

This is an explanatory projection only. It must not gain new write authority or bypass existing trust/canon checks.

Conversion into the real product

At natural points, DEMO may offer Make This Mine / Start My Story.

That action must:

  1. leave the disposable DEMO authority boundary;
  2. create or unlock a real local Human profile through the existing profile flow;
  3. create a fresh real project;
  4. copy only explicitly approved demo-derived starter content;
  5. never copy demo credentials, hidden system state, runtime authority or synthetic identity artifacts.

A user must also be able to exit DEMO with no profile creation and no retained private state.

Suggested phases

Phase 0 � Contract and boundary

  • define DEMO runtime authority and data ownership;
  • explicitly preserve Guest and auth behavior;
  • define reset/delete semantics;
  • define allowed handoff payload into a new real profile.

Phase 1 � Deterministic demo world

  • bundle one small synthetic STORY scenario;
  • add resettable disposable state;
  • prove no private profile/canon/provider access;
  • support replay from a known seed/state.

Phase 2 � First-run UI

  • add DEMO and ENTER PLOTPICKLE choices;
  • preserve returning-user profile behavior;
  • provide clear exit/reset controls;
  • avoid setup/provider prompts inside DEMO.

Phase 3 � Sage Show Me

  • add concise visual explanation projections;
  • use existing STORY/PPF/agent data contracts rather than inventing a second graph or authority model;
  • keep explanatory output read-only.

Phase 4 � Make This Mine

  • explicit transition into profile creation/unlock;
  • copy only approved starter content into a fresh project;
  • verify DEMO state cannot become privileged state.

Phase 5 � UAT and packaging

  • fresh-install UAT from installer → DEMO → interaction → reset → exit;
  • DEMO → Make This Mine → real profile/project UAT;
  • verify private profile isolation with an existing profile present;
  • update README/onboarding docs;
  • compile and smoke-test PlotPickleSetup.exe before release readiness.

Acceptance criteria

  • A fresh user can experience useful PlotPickle behavior without creating a profile.
  • DEMO works without Internet, BUZZ, GitHub, Google or external AI credentials where deterministic local demo behavior is sufficient.
  • DEMO cannot read or write any existing Human-private state.
  • Guest remains its existing restricted ephemeral-notes boundary.
  • Reset returns the demo to a known clean state.
  • Sage can visually explain key PlotPickle concepts without receiving extra authority.
  • "Make This Mine" crosses into the existing real profile boundary explicitly and copies only approved content.
  • Returning-user startup remains understandable and does not force DEMO.
  • README reflects the shipped behavior.
  • Windows installer compiles and passes packaged interaction plus install/uninstall smoke tests.

Non-goals

  • no replacement of the local profile/auth system;
  • no anonymous public cloud account;
  • no weakening of PPF canon authority;
  • no second STORY engine;
  • no second knowledge graph;
  • no arbitrary external browsing or provider setup inside DEMO;
  • no turning Guest into a general unauthenticated application session.

Primary risk

Risk: DEMO gradually becomes a second, partially privileged PlotPickle runtime and duplicates product logic.

Mitigation: DEMO must use the same production STORY/PPF projections and UI components through a synthetic data adapter, while keeping a distinct disposable storage/authority boundary. If a feature requires a duplicate engine or special privileged path, it does not belong in DEMO.

Current developer brief

Developer Workbench review: 2026-09-07T20:53:58.1565609+00:00
Reviewed exact PR head: 805437548b92b01d804fceac118644f35090b046

{
  "file": {
    "name": "scripts/windows-installer/demo-onboarding-smoke.mjs",
    "diff": {
      "from": "index 00cfb5a61..15281d26a 100644\n--- a/scripts/windows-installer/demo-onboarding-smoke.mjs\n+++ b/scripts/windows-installer/demo-onboarding-smoke.mjs\n@@ -13,7 +13,7 @@ const root = path.resolve(process.argv[2] ?? \".\");\n const reportDirectory = path.resolve(process.argv[3] ?? path.join(root, \"reports\", \"windows-demo-onboarding\"));\n const totalTimeoutMs = Math.min(Number(process.env.PLOTPICKLE_DEMO_SMOKE_TIMEOUT_MS || 6 * 60_000), 6 * 60_000);\n const actionTimeoutMs = 20_000;\n-const routeTimeoutMs = 45_000;\n+const routeTimeoutMs = 90_000;\n const coldDemoTimeoutMs = 90_000;\n const coldProfileTimeoutMs = 120_000;\n const deadline = Date.now() + totalTimeoutMs;",
      "to": "index 2a3760bd9..2a3760bd9 100644\n--- a/scripts/windows-installer/demo-onboarding-smoke.mjs\n+++ b/scripts/windows-installer/demo-onboarding-smoke.mjs\n@@ -13,7 +13,8 @@ const root = path.resolve(process.argv[2] ?? \".\");\n const reportDirectory = path.resolve(process.argv[3] ?? path.join(root, \"reports\", \"windows-demo-onboarding\"));\n const totalTimeoutMs = Math.min(Number(process.env.PLOTPICKLE_DEMO_SMOKE_TIMEOUT_MS || 6 * 60_000), 6 * 60_000);\n const actionTimeoutMs = 20_000;\n-const routeTimeoutMs = 90_000;\n+const routeTimeoutMs = 45_000;\n+const navigationCommandTimeoutMs = 10_000;\n const coldDemoTimeoutMs = 90_000;\n const coldProfileTimeoutMs = 120_000;\n const deadline = Date.now() + totalTimeoutMs;\n@@ -263,8 +264,18 @@ async function browserState(client) {\n }\n \n async function navigate(client, url) {\n-  await client.send(\"Page.navigate\", { url }, routeTimeoutMs);\n-  await waitFor(client, `document.readyState !== \"loading\" && Boolean(document.body)`, `Navigation to ${url}`);\n+  try {\n+    await client.send(\"Page.navigate\", { url }, navigationCommandTimeoutMs);\n+  } catch (error) {\n+    const message = error instanceof Error ? error.message : String(error);\n+    if (!/^Page\\.navigate exceeded \\d+ ms\\.$/u.test(message)) throw error;\n+  }\n+  await waitFor(\n+    client,\n+    `location.href.startsWith(${JSON.stringify(url)}) && document.readyState !== \"loading\" && Boolean(document.body)`,\n+    `Navigation to ${url}`,\n+    routeTimeoutMs,\n+  );\n }\n \n async function installSessionCookie(client, baseUrl, cookieHeader) {"
    }
  }
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions