Skip to content
Back to skills

Demo

ASecurity

Generate a believable, lived-in ALIVE world from a free-text persona description (custom path) or a deterministic sandbox preset. Routes the create/list/activate/deactivate/delete/status surface and orchestrates the 5-stage subagent generation pipeline.

  • 130 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added May 27, 2026
toolspythongoshellbashtestinggitapi

Works with

  • claude code
  • cli
  • api

Security analysis

A100/100

Pro scans all 19 files and shows the line behind each finding

Scanned May 27, 2026

npx -y skills add alivecontext/alive --skill demo --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Demo?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Demo
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/alivecontext-demo/badge)](https://www.skillsdirectory.com/skills/alivecontext-demo)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: alive:demo
description: "Generate a believable, lived-in ALIVE world from a free-text persona description (custom path) or a deterministic sandbox preset. Routes the create/list/activate/deactivate/delete/status surface and orchestrates the 5-stage subagent generation pipeline."
user-invocable: true
---

# alive:demo -- generative demo-world skill

This is the router. Route on `$ARGUMENTS[0]` to a sibling `.md` file (when present) or to the interactive `create` flow. Six subcommands + an interactive default:

| `$ARGUMENTS[0]` | Routes to | Status |
| --- | --- | --- |
| _empty_ / `create` | Interactive: preset vs. custom; `create.md` for the custom path | wired |
| `list` | `list.md` | wired |
| `activate <ref>` | `activate.md` | wired |
| `deactivate` | `deactivate.md` | wired |
| `delete <ref>` | `delete.md` | wired |
| `status` | `status.md` | wired |
| `reset` | rebuilds demo-state.json (recovery from schema mismatch) | wired |
| `spike-test` | retired (fn-2-2zz.1 spike) | removed below |

All five non-create sibling `.md` files (`list.md`, `activate.md`, `deactivate.md`, `delete.md`, `status.md`) invoke their CLI subcommand under `$ALIVE_PLUGIN_ROOT/bin/alive demo <name>` and print the CLI's `rendered_block` field verbatim. `create.md` is the custom-path orchestrator: it walks Stage 0 -> Stage 1 hand-off -> Stage 2/3/4/5 driver chain end-to-end. The interactive default below routes the human into either the preset path or `create.md` based on their pick.

The router emits bordered blocks INLINE as markdown — matches the convention in `plugins/alive/skills/world/SKILL.md` and `plugins/alive/skills/save/SKILL.md`. There is no Python `render_block` bridge: the LLM emits its own markdown; only the CLI uses `lib.format_block` (per the codex review which rejected forcing LLM formatting from Python).

User choices use `AskUserQuestion`, never inline `1. / 2. / 3.` answer text. Numbered options inside a bordered block are advisory; the actual decision flows through the question tool.

---

## State + paths (canonical)

| Concern | Path | Override? |
| --- | --- | --- |
| Demo state file | `~/.config/alive/demo-state.json` | NO. Tests set `HOME` to `tmp_path`. |
| Demo state lock | `~/.config/alive/.demo-state.lock` | NO. |
| World-root pointer | `~/.config/alive/world-root` | NO — owned by `_world_root_io.write_world_root_file` (#64). |
| Demo worlds + partials | `~/.alive-demos/` | YES via `$ALIVE_DEMO_BASE_DIR`. |

`$ALIVE_DEMO_BASE_DIR` is the only env override the demo skill reads. It controls where promoted worlds (`<base>/wld_<ulid>/`) and in-flight partials (`<base>/wld_<ulid>.partial/`) live. The state file and the world-root pointer stay canonical so the existing system-wide readers (`_common.py`, `alive-common.sh`, `world/SKILL.md`) keep working unchanged.

---

## Router — interactive default (`/alive:demo` with no args)

When invoked with no subcommand, render this block inline and dispatch via `AskUserQuestion`:

```
╭─ 🐿️ /alive:demo
│
│   No demo subcommand given. Two paths:
│
│    1. preset       (sandbox-testing, deterministic, ~10s)
│    2. custom       (persona-driven, LLM-backed, ~1-2 min)
│
│   What would you like to do?
╰─
```

Then:

- `AskUserQuestion` with options `Preset (sandbox-testing)`, `Custom (persona-driven)`, `Cancel`.
- On `Preset` -> the "Preset path (sandbox testing)" section below; the squirrel calls `alive demo preset run --preset realistic-seeded` after the activation pre-check confirmation.
- On `Custom` -> jump into `create.md` (sibling of this file). `create.md` owns the persona intake, partial-dir mint, Stage 0 driver loop, Stage 1 hand-off to `anchor_confirm.md`, and the Stage 2/3/4/5 driver chain end-to-end.
- On `Cancel` -> render the cancellation block and stop:

```
╭─ 🐿️ cancelled
│
│   No demo world created. Run /alive:demo again any time.
╰─
```

When routing to `create.md`, render this one-line cue inline before jumping in so the human sees the routing decision:

```
> routing to create.md (custom persona path)
```

---

## Subcommand routing

The CLI is the only path that touches `demo-state.json` and the world-root pointer. Each subcommand below shells out to `$ALIVE_PLUGIN_ROOT/bin/alive demo <name>` and prints the CLI's `rendered_block` field verbatim. Sibling `.md` files carry the per-subcommand UX detail; SKILL.md keeps the per-subcommand entry points short.

### `list`

Routes to `list.md`. Prints a 6-column bordered-block table of every promoted demo world plus partial generations. Active world is flagged with `*active` in the STATUS column.

```bash
$ALIVE_PLUGIN_ROOT/bin/alive demo list
```

See `list.md` for envelope shape and error handling.

### `activate <ref>`

Routes to `activate.md`. Resolves `<ref>` via 3-step fallback (exact label, ULID prefix, ambiguous-match envelope), runs the activation pre-check, and (with `--confirm`) runs the tail of the Stage 5 transaction (build-log refresh + step 10 demo-state staging + step 11 world-root commit) against the existing world.

```bash
$ALIVE_PLUGIN_ROOT/bin/alive demo activate <ref>
$ALIVE_PLUGIN_ROOT/bin/alive demo activate <ref> --confirm
```

`<ref>` is the lowercase derived label (e.g. `alex-boring-angel-investor`) OR a ULID prefix of at least 3 characters (e.g. `01j5hk7y` or `wld_01j5hk7y`).

The squirrel drives the picker on `error.code == "ambiguous_ref"`: render the picker block from the envelope, dispatch `AskUserQuestion`, re-run with the picked ULID.

The squirrel drives confirmation on `error.code == "needs_confirmation"`: render the warning block, dispatch `AskUserQuestion` (`Activate anyway`, `Cancel`), re-run with `--confirm`.

See `activate.md` for full flow and resolution rules.

### `deactivate`

Routes to `deactivate.md`. Restores the world-root pointer to the cached `previous_world_root` value, then clears `active_world` and `previous_world_root` in demo-state.json.

```bash
$ALIVE_PLUGIN_ROOT/bin/alive demo deactivate
```

Three result branches: `ok` (pointer flipped, restart Claude Code), `no_demo_active` (nothing to do), and `no_previous_world` (cold demo; user must create another or set the pointer manually).

See `deactivate.md` for the cold-demo case and atomicity contract.

### `delete <ref>`

Routes to `delete.md`. Resolves `<ref>` (same rules as activate), refuses on the currently-active world, and (with `--confirm`) calls `shutil.rmtree`. Without `--confirm`, the CLI returns `error.code == "needs_confirmation"` carrying an irreversibility surface so the squirrel dispatches `AskUserQuestion` before the destructive call.

```bash
$ALIVE_PLUGIN_ROOT/bin/alive demo delete <ref>          # dry run; surfaces irreversibility block
$ALIVE_PLUGIN_ROOT/bin/alive demo delete <ref> --confirm  # actually delete
```

Active worlds raise `error.code == "refused_active"`; the user must `/alive:demo deactivate` first.

See `delete.md` for the irreversibility contract.

### `status`

Routes to `status.md`. Prints a 5-7 line bordered block summarising the active demo world, the cached previous world-root, and the next-step hint.

```bash
$ALIVE_PLUGIN_ROOT/bin/alive demo status
```

The CLI runs `state.load_state()` which executes the world-root self-heal -- demo-state converges to whatever `~/.config/alive/world-root` actually points at. The `status` envelope is the canonical "what does the system think is active?" surface.

See `status.md` for output shapes and the self-heal contract.

### `reset`

This subcommand is router-owned, not a CLI handler. When the human runs `/alive:demo reset`:

1. Read `~/.config/alive/world-root` via `_world_root_io.read_world_root_file()` to learn the live pointer (if any).
2. Atomically write a fresh `demo-state.json` matching `state.default_state()`. If the pointer names a directory previously promoted by the demo skill (recognizable by `<world>/.alive/_demo-build-log.md`), populate `active_world` from the build log. Otherwise leave it null.
3. Render this block:

```
╭─ 🐿️ demo state reset
│
│   demo-state.json rebuilt from world-root pointer.
│   Schema version: 0.1
│
│   active_world: <ulid|none>
╰─
```

Reset is the documented escape hatch when `alive demo status` raises `schema_version_mismatch` — the CLI's hint points here.

---

## Schema-version mismatch UX

When `alive demo status` (or any other CLI handler) returns:

```json
{"success": false, "error": {"code": "schema_version_mismatch", ...}}
```

surface this exactly:

```
╭─ 🐿️ demo state — version mismatch
│
│   demo-state.json was written by an older release.
│   Found: <found-version>
│   Expected: 0.1
│
│   Fix: run /alive:demo reset
╰─
```

Then `AskUserQuestion` with `Run reset now`, `Show file path`, `Cancel`. On `Run reset now` → invoke the `reset` flow above. On `Show file path` → render the canonical state path inline.

---

## Dispatch primitives (consumed by fn-2-2zz.4 → .9)

The following primitives lived in this file's fn-2-2zz.1 stub and survive into the full router. fn-2-2zz.4–.9 stage bodies reference them by name; do not rename without bumping every consumer.

Both primitives use the runtime's subagent dispatch tool (named **Task** in the runtime tool surface, "the Agent tool" in skill prose throughout this codebase — `plugins/alive/skills/session-history/heavy-revive.md:9`, `plugins/alive/skills/system-cleanup/SKILL.md:63`, etc.). The parameter that selects subagent class is `subagent_type`:

- `"general-purpose"` — write-capable; used for stages 0, 2, 3, 4 (every stage that emits JSON to disk).
- `"Explore"` — read-only; not used by demo stages but documented for future audits.

### Prompt-rendering wrapper (mandatory)

Per `plugins/alive/rules/squirrels.md:335-340`, brief injection is manual and the wrapper is non-negotiable. Before every dispatch:

1. **Read** `plugins/alive/templates/subagent-brief.md` once per session and cache the content as `brief_content`.
2. **Substitute** `{WORLD_ROOT}` (active world root, or partial dir if no live world) and `{PLUGIN_ROOT}` (resolved plugin root via `_common.resolve_plugin_root`).
3. **Wrap** every per-stage prompt body as the literal string:

```
CONTEXT:
{brief_content}

TASK:
{actual_task}
```

This exact `CONTEXT:` / `TASK:` wrapper is what every dispatched subagent receives. Do not improvise: subagents that don't see the brief in this shape will not know walnut/bundle/tasks.py conventions and will make mistakes.

### Primitive A — single-subagent dispatch (stages 0, 3, 4)

Render a single Task tool call with:

- `subagent_type: "general-purpose"`
- `description`: one-line label, e.g. `"alive-demo stage 0 spine"`
- `prompt`: the wrapper above, where `{actual_task}` is the stage-specific body. Stage 0's body lives at `plugins/alive/templates/demo/stage_0_spine.v1.md` (created by fn-2-2zz.4). All bodies use `{PARTIAL_DIR}` for the partial directory (`<$ALIVE_DEMO_BASE_DIR>/wld_<ulid>.partial/`) and substitute it before dispatch.

The dispatching squirrel reads the on-disk file the subagent writes; the one-line return is acknowledgement only, never the artifact.

Slug rules (enforced by stage emissions and re-validated by `validate.py` in fn-2-2zz.10): `^[a-z0-9]+(-[a-z0-9]+)*$`. No leading hyphen, no double hyphens, no unicode, no path separators.

### Primitive B — parallel-subagent dispatch (stage 2)

In a single assistant turn, emit one Task tool call per Stage 2 descriptor returned by `stages/stage2.py:prepare_dispatches`. The descriptor list spans every spine entity: `walnut_roster[*]` walnuts, `people_roster[*]` persons, AND `bundle_distribution[*]` bundles (bundles use a compound `<walnut_slug>__<bundle_slug>` directory key so the same bundle name under two walnuts never collides). Each call:

- `subagent_type: "general-purpose"`
- `description`: the descriptor's `description` field, e.g. `"alive-demo stage 2 walnut marcos-clothings"`, `"alive-demo stage 2 person john-park"`, or `"alive-demo stage 2 bundle marcos-clothings__seed-round"`.
- `prompt`: the descriptor's `prompt` field — the per-entity body wrapped in the canonical `CONTEXT:` / `TASK:` envelope. The body has `{{entity_type}}`, `{{entity_data}}`, `{{anchor_moment_refs}}`, and `{{output_dir}}` already substituted; the parent does not modify the prompt.

The output for each subagent is a **directory** at:

```
{PARTIAL_DIR}/_stage_outputs/entities/<slug>/
```

containing multiple files per the `entity_type`:

- **person / walnut** — `key.md`, `log.md`, `insights.md` (3 files).
- **bundle** — `context.manifest.yaml`, `tasks.json` (2 files).

The full per-file contract is in `plugins/alive/templates/demo/schema/entity.schema.md` and the in-prompt summary at `plugins/alive/templates/demo/stage_prompts/stage_2_entity.v1.md`. Per-slug paths are non-overlapping by construction (one subagent owns one directory). Batch by `DEFAULT_BATCH_SIZE = 6` (Anthropic's ~7 concurrent guidance with one headroom slot for the parent itself); fire one batch per assistant turn and wait for all acknowledgements before starting the next. The on-disk handoff is the source of truth; subagents return a one-line acknowledgement only.

Within each subagent, individual file writes use the atomic-write helpers (`_common.atomic_write_text` / `_common.atomic_write_json`, temp + `os.replace`).

### Validation hook (fn-2-2zz.10)

After Stage 0 / 2 / 3 / 4 each, run `validate.py` (lives at `plugins/alive/skills/demo/validate.py`, lands in fn-2-2zz.10) on the partial dir. On failure:

1. **Auto-retry once.** Re-fire the SAME stage's primitive with a truncated `previous_output` + `validation_errors` list as feedback context appended to `{actual_task}`.
2. **On second failure**, surface this block:

```
╭─ 🐿️ stage <N> validation failed twice
│
│   Errors:
│    • <error 1>
│    • <error 2>
│
│   What now?
╰─
```

Then `AskUserQuestion` with `Accept partial (continue)`, `Retry full from stage <N>`, `Cancel`. On `Cancel`, the partial dir stays on disk as a resumable handle (the user can run `alive demo delete <ref>` later to destroy it explicitly); the failure marker is preserved so `alive demo resume` can re-offer the retry.

Stage 1 is in-session UX — no LLM, no validator. Stage 5 is deterministic Python — own integrity checks at the activation transaction level (fn-2-2zz.9).

---

## Preset path (sandbox testing) — fn-2-2zz.11

When the human picks "preset (sandbox-testing)" from the create-flow branch (or invokes `alive demo preset run` directly), the skill skips Stages 0..4 entirely. The preset content is hand-authored at `plugins/alive/skills/demo/preset/realistic-seeded/`; the activation transaction copies that tree to `<base>/wld_<ULID>/` and runs the Stage 5 transactional sequence (steps 3, 7, 8, 10, 11) verbatim. Steps 5 and 6 are skipped (preset ships pre-baked `completed.json` and a fully-canonical walnut tree from copytree); steps 4 and 9 are preset-specific.

Three CLI entry points:

```bash
# 1. Validate + emit plan (no writes).
alive demo preset prepare --preset realistic-seeded

# 2. Execute the activation transaction. Pass --confirm if step 1 reports
#    pre-check findings on the live world.
alive demo preset run --preset realistic-seeded [--confirm]

# 3. Post-activation Read-Before-Speaking + pointer/state verification.
alive demo preset verify --world <path>
```

Use the same restart-Claude-Code block (documented later in this file) after `run` succeeds so the new world index is picked up.

If the preset directory or its `_world_meta.json` is missing, the CLI returns `error.code = "preset_not_found"` with a `hint` pointing the user at the custom path. Surface this inline:

```
╭─ 🐿️ preset path unavailable
│
│   The realistic-seeded preset is not present in this build.
│   Use the custom (persona-driven) path instead:
│
│   ▸ /alive:demo create  (then choose Custom)
╰─
```

## Stage 2 — entity prose subagents (parallel)

Once Stage 1's anchor envelope is frozen, fan out one Agent tool call per
entity (person walnut, venture/experiment/life-area walnut, bundle) so the
prose generation runs concurrently. The deterministic per-slug paths are
documented in `plugins/alive/templates/demo/schema/entity.schema.md` and
the prompt in `plugins/alive/templates/demo/stage_prompts/stage_2_entity.v1.md`.

Driver loop the parent squirrel runs:

1. Call `alive demo stage2 prepare --partial <partial>` (CLI subcommand
   below) — emits a JSON list of dispatch descriptors built from the
   spine + anchor envelope. Bundle slugs are compounded as
   `<walnut>__<bundle>` so two `seed-round` bundles under different
   walnuts never collide on disk.
2. Render this status block inline before firing:

   ```
   ╭─ 🐿️ stage 2 dispatch
   │
   │   <N> entities to generate (P persons, W walnuts, B bundles)
   │   batched <M> calls per assistant turn
   │
   │   Output: _stage_outputs/entities/<slug>/
   ╰─
   ```

3. **Fire all Agent tool calls in a single message in parallel** for the
   first batch. Each call uses `subagent_type: "general-purpose"`,
   `description` and `prompt` from the descriptor. Wait for all
   acknowledgements; never read the disk before the runtime returns.
   Repeat per batch (default 6 per Anthropic concurrent guidance).
4. Call `alive demo stage2 collect-validate --partial <partial>` —
   walks the per-slug directories, validates each via the hand-rolled
   stdlib validator (no `pyyaml`, no `jsonschema`), and emits a
   findings list keyed on slug.
5. **On clean validation:** call `alive demo stage2 freeze --partial <partial>`
   to write `_stage_outputs/stage2_done.json`. Surface the success
   block:

   ```
   ╭─ 🐿️ stage 2 frozen
   │
   │   <N> entity directories validated
   │   _stage_outputs/stage2_done.json written
   │
   │   Next: stage 3 timeline materialisation (fn-2-2zz.7)
   ╰─
   ```

6. **On findings (one auto-retry per slug, per epic):** call
   `alive demo stage2 retry-dispatch --partial <partial>` to receive
   retry descriptors with the per-slug findings appended as feedback,
   fire those Agent calls in a single message in parallel, then
   re-collect-validate. Second failure surfaces the 3-option
   `AskUserQuestion` (accept partial / retry full / cancel) per the
   pattern documented earlier under "Validation hook (fn-2-2zz.10)".

The `prepare` / `collect-validate` / `retry-dispatch` / `freeze` JSON
envelopes are the only path the skill uses to read or write the partial
directory; never Read or Edit `entities/<slug>/` files from the parent
session. The CLI envelope shape is:

```json
{
  "success": true,
  "stage": "2",
  "partial_dir": "<abs path>",
  "dispatches": [<descriptor>, ...]   // for prepare
  "coverage": {<slug>: {...}, ...}     // for collect-validate
  "findings": [<finding>, ...]         // for collect-validate
  "marker": {<frozen marker>}          // for freeze
}
```

Voice / style enforcement: the prompt template carries the
`no-em-dashes` rule, the synthetic-surname allowlist, the
`no-real-public-figure-surnames` guard, second-person voice in body
sections, and ALIVE narrative tone (vivid, specific, no closure). The
validator rejects em / en / horizontal-bar dashes in body prose; the
synthetic-surname rule is enforced by the prompt itself (the validator
cannot tell a real surname from an invented one).

## Stage 3: timeline materialisation (single subagent)

Once Stage 2's entity envelope is frozen (`stage2_done.json` on disk),
fan in to ONE Agent tool call that writes the full log timeline. Stage 3
is the longest single pass; one head holds the whole world in context
so cross-references stay coherent. Outputs land at
`<partial>/_stage_outputs/log.md` (world-level), and per-slug under
`<partial>/_stage_outputs/people-logs/<slug>.md` and
`<partial>/_stage_outputs/walnut-logs/<slug>.md`. Bundle activity is
recorded inside the parent walnut's log (matches v3 layout).

Driver loop the parent squirrel runs:

1. Call `alive demo stage3 prepare --partial <partial>` (CLI subcommand
   below). The CLI reads spine + anchors + stage2_done.json, gates on
   `frozen=true`, and emits a single dispatch descriptor (one prompt,
   one subagent_type, one description, plus the expected output paths).
2. Render this status block inline before firing:

   ```
   ╭─ 🐿️ stage 3 dispatch
   │
   │   single subagent (sequential, full-timeline coherence)
   │
   │   Output: _stage_outputs/log.md
   │           _stage_outputs/people-logs/<slug>.md
   │           _stage_outputs/walnut-logs/<slug>.md
   ╰─
   ```

3. **Fire ONE Agent tool call** with `subagent_type: "general-purpose"`,
   `description` and `prompt` from the descriptor. Wait for the
   one-line acknowledgement (`wrote N world entries, M people logs,
   K walnut logs`); never read disk before the runtime returns.
4. Call `alive demo stage3 collect-validate --partial <partial>`. This
   walks the world log + per-slug log files and emits a findings list.
5. **On clean validation:** call `alive demo stage3 freeze --partial <partial>`
   to write `_stage_outputs/stage3_done.json`. Surface the success
   block:

   ```
   ╭─ 🐿️ stage 3 frozen
   │
   │   <N> entries across world + <P> person + <W> walnut logs
   │   _stage_outputs/stage3_done.json written
   │
   │   Next: stage 4 insights synthesis (fn-2-2zz.8)
   ╰─
   ```

6. **On findings (one auto-retry per epic locked decision):** call
   `alive demo stage3 retry-dispatch --partial <partial>` to receive a
   single retry descriptor with the validator findings appended as
   feedback, fire that Agent call, then re-collect-validate. Second
   failure surfaces the 3-option `AskUserQuestion` (accept partial /
   retry full / cancel) per the pattern documented earlier under
   "Validation hook (fn-2-2zz.10)".

The `prepare` / `collect-validate` / `retry-dispatch` / `freeze` JSON
envelopes are the only path the skill uses to read or write the partial
directory; never Read or Edit `log.md` / `people-logs/` / `walnut-logs/`
files from the parent session.

Voice / style enforcement: the prompt template carries the no-em-dashes
rule, the synthetic-surname continuation, the deterministic
squirrel-ID hashing function (SHA-256 over `date + entity_hash`), the
Decision-WHY rule, the anchor coverage rule (every anchor moment yields
>=3 entries that reference its title or hook entities), the cross-walnut
rule (regular entries cite at most one walnut), and the entity-ref
resolution rule (every `[[slug]]` resolves to a real walnut/person; bundle
compound slugs are not permitted as wikilink targets; one-off proper
nouns appear as plain text matching the documented color allowlist
regex). The validator at `stages/stage3.py:validate_timeline` enforces
all of the above.

Stage 3 OVERWRITES the placeholder log.md frontmatter that Stage 2 leaves
in `entities/<slug>/log.md`? NO. Stage 3 writes a NEW set of log files
under `_stage_outputs/log.md`, `_stage_outputs/people-logs/`, and
`_stage_outputs/walnut-logs/`. The Stage 2 placeholder log.md files in
`entities/<slug>/` stay where Stage 2 wrote them; the activation
transaction (Stage 5) is responsible for resolving the two into the
world's final per-walnut log layout.

## Stage 4: insights synthesis (single subagent)

Once Stage 3's timeline is frozen (`stage3_done.json` on disk), fan in
to ONE Agent tool call that writes the standing insights. Stage 4 is
shorter than Stage 3 but still load-bearing: every insight must cite
at least one log entry by `(YYYY-MM-DD, squirrel:<8-hex>)` so the demo
proof point holds (the agent answers context-reliant questions by
citing entries). Outputs land at
`<partial>/_stage_outputs/insights.md` (world-level) and per-walnut
under `<partial>/_stage_outputs/walnut-insights/<slug>.md`. Per-walnut
files are CONDITIONAL: produce one only where the timeline supports a
real recurring pattern.

Driver loop the parent squirrel runs:

1. Call `alive demo stage4 prepare --partial <partial>` (CLI subcommand
   below). The CLI reads spine + anchors + stage3_done.json, gates on
   `frozen=true`, and emits a single dispatch descriptor (one prompt,
   one subagent_type, one description, plus the expected output paths).
2. Render this status block inline before firing:

   ```
   ╭─ 🐿️ stage 4 dispatch
   │
   │   single subagent (cross-walnut + per-walnut insights)
   │
   │   Output: _stage_outputs/insights.md
   │           _stage_outputs/walnut-insights/<slug>.md  (conditional)
   ╰─
   ```

3. **Fire ONE Agent tool call** with `subagent_type: "general-purpose"`,
   `description` and `prompt` from the descriptor. Wait for the
   one-line acknowledgement (`wrote insights.md (N insights), K
   walnut-insights files`); never read disk before the runtime returns.
4. Call `alive demo stage4 collect-validate --partial <partial>`. This
   walks the world insights file + walnut-insights/ dir and emits a
   findings list.
5. **On clean validation:** call `alive demo stage4 freeze --partial <partial>`
   to write `_stage_outputs/stage4_done.json`. Surface the success
   block:

   ```
   ╭─ 🐿️ stage 4 frozen
   │
   │   <N> insights across world + <K> walnut-insights files
   │   _stage_outputs/stage4_done.json written
   │
   │   Next: stage 5 deterministic activation (fn-2-2zz.9)
   ╰─
   ```

6. **On findings (one auto-retry per epic locked decision):** call
   `alive demo stage4 retry-dispatch --partial <partial>` to receive a
   single retry descriptor with the validator findings appended as
   feedback, fire that Agent call, then re-collect-validate. Second
   failure surfaces the 3-option `AskUserQuestion` (accept partial /
   retry full / cancel) per the pattern documented earlier under
   "Validation hook (fn-2-2zz.10)".

The `prepare` / `collect-validate` / `retry-dispatch` / `freeze` JSON
envelopes are the only path the skill uses to read or write the
partial directory; never Read or Edit `insights.md` /
`walnut-insights/` files from the parent session.

Voice / style enforcement: the prompt template carries the
no-em-dashes rule, the citation format
`(YYYY-MM-DD, squirrel:<8-hex>)`, the section vocabulary from
`templates/walnut/insights.md` (Strategy / Process / Technical /
People / Patterns / Tensions / Open Questions / Other), the coherence
rule (every bullet has a citation; either an anchor session or a
recurring pattern across two or more entries), and the restraint rule
(per-walnut insights only where the timeline supports a real recurring
pattern). The validator at `stages/stage4.py:validate_insights` enforces
citation FORMAT and presence; full citation RESOLUTION (does the cited
entry actually exist?) is the fn-2-2zz.10 validator's job.

## Stage 5: deterministic activation transaction

Stage 5 is **deterministic Python**, no LLM. It takes the fully-baked Stage 0-4 partial directory and activates it as the live ALIVE world via an 11-step transaction with **exactly one commit point at step 11**. Failure at any step 1-10 leaves `~/.config/alive/world-root` unchanged.

The 11 steps are documented at `plugins/alive/skills/demo/scaffold.py`. Briefly:

1. `activation_pre_check` — flag findings on the current live world (`saves: 0` + transcript >4KB; log.md mtime > now.json mtime; `saves: 0` + non-null `recovery_state`).
2. `os.rename(<partial>, <base>/wld_<ULID>/)` — atomic same-FS promotion.
3. Generate `<world>/.alive/preferences.yaml`.
4. Generate `<world>/.alive/_squirrels/*.yaml` per session in the world log.
5. Synthesize `<walnut>/_kernel/completed.json` (80 % of tasks, backdated).
6. `step_6_install_entities` — move Stage 0-4 outputs from `_stage_outputs/` into the canonical walnut layout (per-walnut `_kernel/{key,log,insights}.md`, per-person `02_Life/people/<slug>/_kernel/...`, per-bundle `<walnut>/<bundle>/{context.manifest.yaml,tasks.json}`, world-level `.alive/{log,insights}.md`); `os.replace` per-file + final `rmtree` of the entities dir; idempotent via SHA-256 equality checks.
7. Shell out `project.py --walnut <abs>` per walnut → `_kernel/now.json`.
8. Shell out `generate-index.py <world-root>` → `.alive/_index.{yaml,json}`.
9. Write `<world>/.alive/_demo-build-log.md` (provenance frontmatter for `state.py` self-heal).
10. Atomically update `~/.config/alive/demo-state.json` (flock + atomic-write): cache previous pointer, mark `partial_generations[N].status = "promoted"`, populate `active_world`. **Pre-commit metadata staging.**
11. **`_world_root_io.write_world_root_file(<world>)`** — THE single commit point.

### Calling Stage 5 from this skill

The router calls Stage 5 via the CLI (never via direct Python imports — the skill prose layer never reaches into modules):

```bash
# Step 1: dry-run plan + pre-check.
alive demo stage5 prepare --partial <abs-path>
```

If the response carries `plan.needs_confirmation == true`, surface this bordered block AND fire `AskUserQuestion`:

```
╭─ 🐿️ activation — uncommitted work on current world
│
│   The current live world has unsaved work the demo activation will
│   replace:
│
│   <findings as one bullet per finding>
│
│   Activate anyway? Your unsaved work stays on disk; the agent will
│   see the demo world after restart.
│
│   ▸  1. Yes, activate    2. Cancel
╰─
```

Use `AskUserQuestion` with options `Activate anyway`, `Cancel`. On cancel, render a cancellation block and stop. On confirm, proceed:

```bash
# Step 2: run the 11-step transaction.
alive demo stage5 run --partial <abs-path> --confirm
```

(Drop `--confirm` when the pre-check returned no findings.)

### Post-activation block (mandatory)

After step 11 commits successfully, render the restart-Claude-Code block (documented later in this skill). The agent in the current session continues to read the OLD `WORLD_INDEX` injection until restart.

### Failure surfaces

The CLI emits `success: false` envelopes on:

* `stage5_not_ready` — stage{0..4}_done markers missing or not frozen. Hint: run Stages 0-4 first.
* `needs_confirmation` — pre-check found unsaved work; re-run with `--confirm`.
* `stage5_error` — any error in steps 2-11 (rename failure, project.py crash, write-permission denied, ...). On these, the world-root pointer is GUARANTEED unchanged (the only writer is step 11, which is the last step). The partial dir's state on disk depends on which step failed; the user can re-run `alive demo stage5 run` to retry from scratch (the rename in step 2 is idempotent only if the partial still exists — failures at step 2 leave the partial untouched, failures after step 2 leave the freshly-renamed world directory at `<base>/wld_<ULID>/` for inspection / cleanup).

## What this router does NOT do (deferred to siblings)

- **Custom-path orchestration** -- `create.md` (sibling of this file) drives Stage 0 through Stage 5 end-to-end for the persona-driven path. The router only emits the no-args picker and routes the human into `create.md` on `Custom`.
- **Stage bodies** -- Stage 0, Stage 1, Stage 2, Stage 3, Stage 4, Stage 5 all shipped.
- **Validator** -- `validate.py` (stdlib-only).
- **Sandbox preset** -- shipped (see § "Preset path (sandbox testing)" above; lean Nova Station preset under `preset/realistic-seeded/`).
- **list / activate / deactivate / delete / status bodies** -- shipped (sibling `.md` files + `cli_register.py` handlers + `lib.py` helpers + `stages/{activate_existing,deactivate,delete_existing}.py`).
- **Failure-mode hardening + fixture regen** -- shipped.

## Restart-Claude-Code instruction (post-activation)

After Stage 5 commits the new world-root pointer (fn-2-2zz.9), the active session's existing `WORLD_INDEX` injection is stale. The skill MUST surface this block before any further action:

```
╭─ 🐿️ activated — restart Claude Code
│
│   Demo world activated:
│     <ulid>  ·  <label>
│     <path>
│
│   The session-start hook injects WORLD_INDEX once per session. To pick
│   up the new world index, restart Claude Code (Cmd+Q + relaunch).
│
│   Or: run /alive:world to re-render against the new pointer.
╰─
```

(The skill cannot magic-relaunch Claude Code in v3.2 — that's deferred to v4 per spec § "Out of scope".)

---

## Coherence retry contract (fn-2-2zz.10)

Every LLM-driven stage (0, 2, 3, 4) is gated by `validate.py:validate_stage(<stage_id>, <partial_dir>)` immediately after the subagent writes its outputs. Stage 1 is UX-only and has no coherence check.

The validator returns a `ValidationResult` envelope with one of three statuses:

- `ok` -- proceed to the next stage.
- `retryable` -- one auto-retry. The dispatcher has two compatible options:
  - **Direct**: append `validate.format_retry_feedback(result)` (a preformatted markdown block) to the original stage prompt and re-dispatch the subagent. This is the path for callers that hold the original prompt string in hand.
  - **Stage-native**: pass the per-stage findings list directly into the stage's existing `retry_dispatch()` helper (e.g. `stage3.retry_dispatch(descriptor, stage3_findings)`). The stage helpers consume their own native finding shape; convert by reading the per-stage findings off `validate_stage`'s underlying call (or by re-calling the stage's own validator). This is the path that re-uses the `retry_dispatch()` API verbatim.

  Either path: re-run the subagent, re-run `validate_stage`. If the second run is also `retryable` or `fatal`, the squirrel surfaces the second-failure user prompt below.
- `fatal` -- structural / schema-version failure that re-dispatch will not fix. Surface the second-failure user prompt immediately.

### Second-failure user surface

When validation fails twice (or returns `fatal` on the first run), the squirrel emits this block inline and fires `AskUserQuestion`:

```
╭─ 🐿️ stage <N> validation: second failure
│
│   <count> error(s) remain after one retry.
│
│   First three:
│   - [<code>] <where>: <evidence>
│   ...
│
│   ▸ Three options:
│   1. Accept partial   (proceed with current outputs)
│   2. Retry full       (re-dispatch the whole stage from scratch)
│   3. Cancel           (abandon this demo world)
╰─
```

Render via `validate.three_option_surface_block(result)`. The squirrel calls `AskUserQuestion` with the three options exactly as rendered. **Workers cannot fire AskUserQuestion themselves** -- the parent skill at the squirrel level does, after the worker's stage dispatcher returns the failure result up.

### Cross-stage citation resolution (Stage 4 -> Stage 3)

`validate.py:_validate_stage_4` adds a check the per-stage `stage4.validate_insights` intentionally defers: every insight bullet's `(YYYY-MM-DD, squirrel:<8-hex>)` citation must resolve to a real Stage 3 log entry. The 8-hex prefix is matched against the 16-hex squirrel-ids in `world log + people-logs/*.md + walnut-logs/*.md`. Format-only checks live in Stage 4; resolution lives here.

The validator also enforces the **anchor-or-pattern** rule (per-bullet): every insight bullet either cites an anchor-moment date OR cites >=3 distinct resolved log entries (by `(sid_8, date)` pair) on its own. Distinct sessions on the same day count as distinct refs; the same `(sid, date)` pair cited twice counts once. A one-off bullet that rides on the section's other bullets does not earn its insight slot.

### CLI entry point

`alive demo validate <stage_id> --partial <path>` emits the `ValidationResult` JSON for the parent squirrel. Stage IDs: `0`, `2`, `3`, `4`. Stage 1 returns a `usage` error (UX-only stage).

---

## Failure recovery (fn-2-2zz.13)

Three failure modes (15a / 15b / 15c per the epic spec) surface a bordered block plus a state mutation so a later `alive demo resume` can offer a retry. Each mode is rendered via `lib.py`'s failure handlers. Print the `rendered_block` field verbatim; do not re-wrap it.

### 15a. Validation fails twice (any LLM stage)

Stages 0 / 2 / 3 / 4 each ship one auto-retry. On second failure the orchestrator calls the per-stage `surface_double_failure(...)` (or `run_stage0(..., surface_failure_blocks=True)` returns the envelope inline). The bordered block carries:

- `\U0001f6d1` glyph in the title (renders as a stop-sign octagon).
- The first 5 errors with truncated evidence; total error count.
- The raw output path (the failing subagent file on disk).
- The partial directory path so the user can inspect intermediate stage outputs.
- Instructions: inspect, run `alive demo resume`, file a bug at `https://github.com/alivecontext/alive/issues/new`.

`demo-state.json` is updated transactionally: the partial's entry gets `failed_at_stage = "<stage>_<label>"`, `failed_reason = "validation_double_failure"`, and `failed_at = <iso ts>`. The entry's `status` stays `in_progress` so `find_resumable_partials` lists it.

### 15b. Stage 5 projection step crashes

Steps 7 (`project.py --walnut <walnut>`) and 8 (`generate-index.py <world>`) shell out to deterministic scripts. Either failing means the activation transaction cannot reach the step-11 commit point. Call `scaffold.activate(..., surface_failure_blocks=True)`; on subprocess crash or nonzero exit the function returns an envelope with `status: "failed"` and `failure_mode: "projection_failure"`. The pointer is GUARANTEED untouched (step 11 has not fired). The partial generation is marked `failed_at_stage = "5_promote"`, `failed_reason = "projection_failure"`.

### 15c. Atomic write fails (disk full / read-only / permission denied)

Step 10 (`step_10_stage_demo_state`) is the only step in the activation transaction that mutates demo-state.json under flock. Wrapped in try/except OSError; the failure handler renders a block but does NOT mutate state (because the mutation is what failed). Demo-state.json is preserved by the atomic-rename contract: either the new content lands fully or the previous content stays intact.

The block calls out the specific errno + cause, lists common errno triages (28 / 30 / 13), and points at `df -h` + permission inspection.

### `alive demo resume` subcommand

```
alive demo resume                # list resumable partials
alive demo resume <partial-id>   # show retry plan for one
```

- Zero resumable: friendly "nothing to resume" block.
- One resumable: returns `{partial_id, failed_at_stage, failed_reason, suggested_action, rendered_block}`. The squirrel's prose drives the actual retry by calling the right stage entry point (the CLI cannot re-fire LLM dispatches autonomously).
- Multiple resumable + no `partial_id`: ambiguous-list block listing each by `<label>  -  <ulid>  (failed at <stage>, reason: <reason>)`.

See `resume.md` (sibling of this file) for the prose walkthrough.

---

## What this stub deliberately does NOT do (carried over from fn-2-2zz.1)

The fn-2-2zz.1 stub had a `spike-test` subcommand that is now retired — its job (validating the dispatch primitives empirically) was discharged by the live gate (see `_spike.md` § "Gate result"). If a human invokes `/alive:demo spike-test`, route to:

```
╭─ 🐿️ spike-test — retired
│
│   The fn-2-2zz.1 spike gate already PASSED (2026-04-29). Dispatch
│   primitives are now codified in this router under § "Dispatch
│   primitives". Use /alive:demo (no args) for the create flow.
╰─
```

`_spike.md` itself stays in this directory until fn-2-2zz.14 / merge prep, then is deleted.

---

## References

- `plugins/alive/skills/demo/state.py` — demo-state.json IO + self-heal.
- `plugins/alive/skills/demo/lib.py` — `format_block`, `format_table`, `new_world_ulid`, `derive_label`.
- `plugins/alive/skills/demo/cli_register.py` — `alive demo` argparse wiring.
- `plugins/alive/templates/demo/prefix_table.md` — v4 ULID prefix namespace.
- `plugins/alive/scripts/_common.py` — `atomic_write_json`, `flock_file`, `resolve_plugin_root`, `iso_now`.
- `plugins/alive/scripts/_world_root_io.py` — `read_world_root_file`, `write_world_root_file` (Stage 5 commit).
- `plugins/alive/_vendor/ulid/` — vendored python-ulid 3.1.0.
- `plugins/alive/templates/subagent-brief.md` — substitution template for the dispatch wrapper.
- `.flow/specs/fn-2-2zz.md` — the epic plan; § "Approach" is canonical for the activation transaction.
- `.flow/tasks/fn-2-2zz.3.md` — this task's spec.

Files in this skill

  • README.md11 KB
  • SKILL.md39.5 KB
  • activate.md6.8 KB
  • anchor_confirm.md10.9 KB
  • create.md17 KB
  • deactivate.md2.7 KB
  • delete.md3.5 KB
  • lib.py59.5 KB
  • list.md3.5 KB
  • preset/realistic-seeded/02_Life/people/jax-stellara/_kernel/insights.md308 B
  • preset/realistic-seeded/02_Life/people/jax-stellara/_kernel/key.md900 B
  • preset/realistic-seeded/02_Life/people/jax-stellara/_kernel/log.md845 B
  • preset/realistic-seeded/02_Life/people/ryn-okata/_kernel/insights.md627 B
  • preset/realistic-seeded/02_Life/people/ryn-okata/_kernel/key.md968 B
  • preset/realistic-seeded/02_Life/people/ryn-okata/_kernel/log.md1.2 KB
  • preset/realistic-seeded/04_Ventures/nova-station/_kernel/completed.json1.3 KB
  • preset/realistic-seeded/04_Ventures/nova-station/_kernel/insights.md1.7 KB
  • preset/realistic-seeded/04_Ventures/nova-station/_kernel/key.md1.5 KB
  • preset/realistic-seeded/04_Ventures/nova-station/_kernel/log.md4.2 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.