ChicagoDave/sharpee

Parser-Based Interactive Fiction Platform developed in Typescript with a Custom Modeling Language

TypeScript

16

2,503 commits

updated Sep 28, 2026

See the code

See what people are saying

SourceMessageScoreDate

There is more to code review than (automatable) detection

I was just at the Explore DDD conference in Denver and a portion of Friday was sitting at the cafe tables informally discussing the impact of GenAI on software engineering with notable people. Most of these people were deeply concerned that if we lean into using GenAI for “everything” that our…

0

Sep 28, 2026

README

Sharpee

npm

A parser-based Interactive Fiction authoring platform built in TypeScript.

Quick Start

The sharpee CLI ships in @sharpee/devkit — install it globally:

npm install -g @sharpee/devkit

Scaffold a project, then build and play:

sharpee init my-adventure
cd my-adventure
npm install
sharpee build
open dist/web/index.html
CommandWhat it does
sharpee init <name>Create a new story project
sharpee init-browserAdd browser client to existing project
sharpee buildBuild .sharpee bundle + browser client
sharpee build-browserBuild browser client only
sharpee ifidGenerate or validate an IFID

What's Included

@sharpee/sharpee is the umbrella package — it re-exports the story runtime baseline (ADR-178), the imports a story author needs. It deliberately does not re-export every symbol; for advanced use, import a sub-package directly. All 28 packages below are published individually on npm under the @sharpee scope.

PackageDescription
@sharpee/sharpeeUmbrella package — re-exports the story runtime baseline (ADR-178)
@sharpee/coreEvent system, types, utilities
@sharpee/engineGame engine, turn cycle, command execution
@sharpee/event-processorApplies semantic events to the world model
@sharpee/world-modelEntity system with traits and behaviors
@sharpee/if-domainCore domain model and contracts
@sharpee/if-servicesRuntime service interfaces (perception)
@sharpee/stdlib51 standard IF actions (take, drop, open, lock, etc.)
@sharpee/lang-en-usEnglish language output
@sharpee/parser-en-usEnglish natural language parser
@sharpee/helpersFluent entity builders (createHelpers(world))
@sharpee/queriesLINQ-style fluent entity query API
@sharpee/characterNPC behavior chain: character model, conversation, goals, influence, propagation
@sharpee/pluginsPlugin contracts for engine turn-cycle extensibility
@sharpee/plugin-schedulerDaemons and fuses (timed events)
@sharpee/plugin-state-machineDeclarative puzzle and narrative orchestration
@sharpee/mediaAudio event types, AudioRegistry, and capability negotiation
@sharpee/text-blocksStructured text output interfaces (ITextBlock, IDecoration)
@sharpee/channel-serviceUniversal channel-I/O wire producer (ADR-163)
@sharpee/platform-browserFramework-free browser client infrastructure
@sharpee/ext-basic-combatGeneric skill-based combat extension
@sharpee/ext-testingDebug and testing tools (/debug, /trace, $teleport)
@sharpee/bootstrapStory loader — assembles a .sharpee story into a runnable game
@sharpee/devkitThe sharpee CLI — build/test/verify/scaffold orchestration (ADR-180)
@sharpee/story-runtime-baselineManifest of the canonical baseline packages a bundle may import (ADR-178)
@sharpee/ide-protocolWire types for the IDE project-introspection manifest (ADR-184)
@sharpee/transcript-testerTranscript-based testing framework

Features

  • Event-Driven Architecture — Immutable semantic events for all state changes
  • Natural Language Parser — Complex player commands with slot constraints
  • Rich World Model — Entities with traits, behaviors, and relationships
  • 51 Standard Actions — take, drop, open, close, lock, unlock, wear, eat, drink, attack, and more
  • Four-Phase Action Pattern — Consistent validate/execute/report/blocked flow
  • Capability Dispatch — Entity-specific handling for generic verbs
  • Entity Helpers — Fluent builder API for rooms, objects, containers, doors, actors
  • NPC Behavior Chain — Character model with psychology, constraint-based conversation, goal pursuit, information propagation, and NPC-to-NPC influence
  • Direction Vocabularies — Location-relative directions (compass, naval, minimal, or custom)
  • Audio System — Typed audio events, AudioRegistry, procedural sound, atmosphere builder
  • Daemons & Fuses — Timed events and background processes
  • Perception System — Darkness, blindness, and sensory restrictions
  • Language Layer Separation — All text output goes through localizable message IDs
  • Channel-Based UI — Story→UI signals flow over channels (ADR-163); the same story runs in the CLI and in a framework-free browser client
  • Full TypeScript — Strict typing throughout

Creating a Story

import { Story, StoryConfig } from '@sharpee/engine';
import { WorldModel, IFEntity, Direction } from '@sharpee/world-model';
import { createHelpers } from '@sharpee/helpers';

export const config: StoryConfig = {
  id: 'my-adventure',
  title: 'My Adventure',
  author: 'Your Name',
  version: '1.0.0',
};

export class MyStory implements Story {
  config = config;

  initializeWorld(world: WorldModel): void {
    const { room, object } = createHelpers(world);

    const start = room('Starting Room')
      .description('A simple room with a lamp on the floor.')
      .build();

    object('brass lamp')
      .description('A well-polished brass lamp.')
      .in(start)
      .build();

    const player = world.getPlayer();
    world.moveEntity(player!.id, start.id);
  }

  createPlayer(world: WorldModel): IFEntity {
    const { actor } = createHelpers(world);

    return actor('yourself')
      .description('As good-looking as ever.')
      .aliases('self', 'me')
      .properName()
      .inventory({ maxItems: 10 })
      .build();
  }
}

export const story = new MyStory();
export default story;

See the Getting Started guide for a complete walkthrough.

Entity Helpers

createHelpers(world) returns fluent builders for common entity types:

import { createHelpers } from '@sharpee/helpers';

const { room, object, container, actor, door } = createHelpers(world);

// Rooms
const cave = room('Dark Cave').description('A damp cave.').dark().build();

// Objects with custom traits
const note = object('crumpled note')
  .description('A crumpled piece of paper.')
  .addTrait(new ReadableTrait({ text: 'The code is 4-7-2.' }))
  .in(cave)
  .build();

// Containers
const chest = container('wooden chest')
  .openable({ isOpen: false })
  .lockable({ isLocked: true, keyId: key.id })
  .in(cave)
  .build();

// Items in closed containers (bypasses validation)
object('gold coin').skipValidation().in(chest).build();

// Doors between rooms
door('iron door')
  .between(cave, hallway, Direction.NORTH)
  .openable({ isOpen: false })
  .build();

Architecture

+-----------------------------------------------+
|              Your Story                       |
+--------------------+--------------------------+
| stdlib (actions)   | lang-en-us (messages)    |
| plugins (npc,      | parser-en-us (grammar)   |
|  scheduler, state) |                          |
+--------------------+--------------------------+
| engine | world-model | helpers | channels     |
+-----------------------------------------------+
| if-domain | if-services | event-processor     |
+-----------------------------------------------+
| core (events, types) | media (audio types)   |
+-----------------------------------------------+

Rendering is the engine's prose pipeline producing ITextBlock[], carried to the UI by channels (ADR-163/174) — there is no separate text service.

Key Principles

  1. Actions emit semantic events, not text — The language layer converts message IDs to prose
  2. Behaviors own mutations — Actions coordinate, behaviors perform state changes
  3. Traits compose entity capabilities — Add container, lockable, wearable, etc.
  4. Parser scope is permissive — Actions decide if visibility is truly required

Standard Actions

Movement: going, entering, exiting, climbing Manipulation: taking, dropping, putting, inserting, removing, giving, throwing Containers/Doors: opening, closing, locking, unlocking Examination: looking, examining, searching, reading Interaction: talking, showing, attacking Devices: switching on/off, pushing, pulling, raising, lowering Wearables: wearing, taking off Consumables: eating, drinking Senses: touching, smelling, listening Meta: inventory, score, help, save, restore, restart, quit, undo, again, wait, about, version, sleep

Repository Development

Prerequisites — Node, pnpm at the exact declared version, and the platform-specific extras — are listed with their checks in docs/core-concepts/prerequisites.md. Worth two minutes before the first build on a new machine.

git clone https://github.com/ChicagoDave/sharpee.git
cd sharpee
corepack enable        # pins pnpm to the version package.json declares
pnpm install

# FRESH CLONE ONLY (needed once): tsf compiles the platform packages, then
# repokit itself is built — tsf does not build it, so ./repokit won't exist yet.
npx tsf build
pnpm --filter @sharpee/repokit build

# Build everything (repokit; ADR-187)
./repokit build dungeo

# Run tests
pnpm test

# Run specific package tests
pnpm --filter '@sharpee/stdlib' test

# Run story transcript tests
node dist/cli/sharpee.js --test stories/dungeo/tests/transcripts/*.transcript

Example Stories

StoryLocationDescription
dungeostories/dungeoMainframe Zork implementation (~191 rooms, 650 points + 100 endgame)
familyzootutorials/familyzoo/v1.5.0, tutorials/familyzoo/v2.0.0The book's Family Zoo — chapter-by-chapter tutorial snapshots, built against the published npm packages. Split into two editions: v1.5.0 (the frozen 1.x line, pins ^1.5) and v2.0.0 (the Phrase Algebra line, pins ^2.0)
entropystories/entropyOriginal sci-fi story with audio system (in progress)

Roadmap

Sharpee is actively developed. These are the open Architecture Decision Records representing planned future work.

Recently Implemented

  • NPC Behavior Chain (ADR-141, 142, 144, 145, 146) — Character psychology, conversation, goal pursuit, information propagation, NPC influence
  • Direction Vocabularies (ADR-143) — Location-relative directions (compass, naval, minimal, custom)
  • Audio System (ADR-138) — SFX, music, ambient, procedural audio, AudioRegistry
  • Entity Helpers (ADR-140) — Fluent builder API for story setup
  • Action Interceptors (ADR-118) — Story-level hooks on standard actions

Accepted (Implementation Planned)

  • Screen Reader Accessibility (ADR-100) — ARIA support for the browser client
  • Speech Accessibility (ADR-139) — TTS/STT for blind and motor-impaired players
  • Equivalent Objects (ADR-147) — Identical object groups, numeric commands, trade/sell/barter

Proposed

AreaADRDescription
Story ParadigmsADR-083Spirit PC — Non-physical player character support
Story ParadigmsADR-102Dialogue Extension — NPC conversation systems (ASK/TELL, menus)
Story ParadigmsADR-103Choice-Based Stories — CYOA-style with parser hybrid
World ModelADR-020Clothing and Pockets — Container hierarchy for wearable items
ClientsADR-098Terminal Client — CLI-based game client
ClientsADR-099GLK Client — Standard IF interpreter protocol
ClientsADR-122Rich Media and Story Styling — Embedded media in output
Zifmia (retired)ADR-125Panel and Windowing System — Multi-panel desktop client
Zifmia (retired)ADR-128Walkthrough Panel — In-client walkthrough display
Zifmia (retired)ADR-130Story Installers — Split runner from author packaging tool
Author ToolsADR-115Map Export CLI — Export story maps from code
Author ToolsADR-116Prompt-to-Playable — AI-assisted story development
Author ToolsADR-131Automated World Explorer — Regression test generator
EngineADR-127Location-Scoped Interceptors — Room-tied action interceptors

See the full ADR index for the complete set of architecture decisions.

License

MIT License — Copyright 2025-2026 David Cornelson

ChicagoDave/sharpee

Parser-Based Interactive Fiction Platform developed in Typescript with a Custom Modeling Language

TypeScript

16

2,503 commits

updated Sep 28, 2026

See the code

See what people are saying

SourceMessageScoreDate

There is more to code review than (automatable) detection

I was just at the Explore DDD conference in Denver and a portion of Friday was sitting at the cafe tables informally discussing the impact of GenAI on software engineering with notable people. Most of these people were deeply concerned that if we lean into using GenAI for “everything” that our…

0

Sep 28, 2026

README

Sharpee

npm

A parser-based Interactive Fiction authoring platform built in TypeScript.

Quick Start

The sharpee CLI ships in @sharpee/devkit — install it globally:

npm install -g @sharpee/devkit

Scaffold a project, then build and play:

sharpee init my-adventure
cd my-adventure
npm install
sharpee build
open dist/web/index.html
CommandWhat it does
sharpee init <name>Create a new story project
sharpee init-browserAdd browser client to existing project
sharpee buildBuild .sharpee bundle + browser client
sharpee build-browserBuild browser client only
sharpee ifidGenerate or validate an IFID

What's Included

@sharpee/sharpee is the umbrella package — it re-exports the story runtime baseline (ADR-178), the imports a story author needs. It deliberately does not re-export every symbol; for advanced use, import a sub-package directly. All 28 packages below are published individually on npm under the @sharpee scope.

PackageDescription
@sharpee/sharpeeUmbrella package — re-exports the story runtime baseline (ADR-178)
@sharpee/coreEvent system, types, utilities
@sharpee/engineGame engine, turn cycle, command execution
@sharpee/event-processorApplies semantic events to the world model
@sharpee/world-modelEntity system with traits and behaviors
@sharpee/if-domainCore domain model and contracts
@sharpee/if-servicesRuntime service interfaces (perception)
@sharpee/stdlib51 standard IF actions (take, drop, open, lock, etc.)
@sharpee/lang-en-usEnglish language output
@sharpee/parser-en-usEnglish natural language parser
@sharpee/helpersFluent entity builders (createHelpers(world))
@sharpee/queriesLINQ-style fluent entity query API
@sharpee/characterNPC behavior chain: character model, conversation, goals, influence, propagation
@sharpee/pluginsPlugin contracts for engine turn-cycle extensibility
@sharpee/plugin-schedulerDaemons and fuses (timed events)
@sharpee/plugin-state-machineDeclarative puzzle and narrative orchestration
@sharpee/mediaAudio event types, AudioRegistry, and capability negotiation
@sharpee/text-blocksStructured text output interfaces (ITextBlock, IDecoration)
@sharpee/channel-serviceUniversal channel-I/O wire producer (ADR-163)
@sharpee/platform-browserFramework-free browser client infrastructure
@sharpee/ext-basic-combatGeneric skill-based combat extension
@sharpee/ext-testingDebug and testing tools (/debug, /trace, $teleport)
@sharpee/bootstrapStory loader — assembles a .sharpee story into a runnable game
@sharpee/devkitThe sharpee CLI — build/test/verify/scaffold orchestration (ADR-180)
@sharpee/story-runtime-baselineManifest of the canonical baseline packages a bundle may import (ADR-178)
@sharpee/ide-protocolWire types for the IDE project-introspection manifest (ADR-184)
@sharpee/transcript-testerTranscript-based testing framework

Features

  • Event-Driven Architecture — Immutable semantic events for all state changes
  • Natural Language Parser — Complex player commands with slot constraints
  • Rich World Model — Entities with traits, behaviors, and relationships
  • 51 Standard Actions — take, drop, open, close, lock, unlock, wear, eat, drink, attack, and more
  • Four-Phase Action Pattern — Consistent validate/execute/report/blocked flow
  • Capability Dispatch — Entity-specific handling for generic verbs
  • Entity Helpers — Fluent builder API for rooms, objects, containers, doors, actors
  • NPC Behavior Chain — Character model with psychology, constraint-based conversation, goal pursuit, information propagation, and NPC-to-NPC influence
  • Direction Vocabularies — Location-relative directions (compass, naval, minimal, or custom)
  • Audio System — Typed audio events, AudioRegistry, procedural sound, atmosphere builder
  • Daemons & Fuses — Timed events and background processes
  • Perception System — Darkness, blindness, and sensory restrictions
  • Language Layer Separation — All text output goes through localizable message IDs
  • Channel-Based UI — Story→UI signals flow over channels (ADR-163); the same story runs in the CLI and in a framework-free browser client
  • Full TypeScript — Strict typing throughout

Creating a Story

import { Story, StoryConfig } from '@sharpee/engine';
import { WorldModel, IFEntity, Direction } from '@sharpee/world-model';
import { createHelpers } from '@sharpee/helpers';

export const config: StoryConfig = {
  id: 'my-adventure',
  title: 'My Adventure',
  author: 'Your Name',
  version: '1.0.0',
};

export class MyStory implements Story {
  config = config;

  initializeWorld(world: WorldModel): void {
    const { room, object } = createHelpers(world);

    const start = room('Starting Room')
      .description('A simple room with a lamp on the floor.')
      .build();

    object('brass lamp')
      .description('A well-polished brass lamp.')
      .in(start)
      .build();

    const player = world.getPlayer();
    world.moveEntity(player!.id, start.id);
  }

  createPlayer(world: WorldModel): IFEntity {
    const { actor } = createHelpers(world);

    return actor('yourself')
      .description('As good-looking as ever.')
      .aliases('self', 'me')
      .properName()
      .inventory({ maxItems: 10 })
      .build();
  }
}

export const story = new MyStory();
export default story;

See the Getting Started guide for a complete walkthrough.

Entity Helpers

createHelpers(world) returns fluent builders for common entity types:

import { createHelpers } from '@sharpee/helpers';

const { room, object, container, actor, door } = createHelpers(world);

// Rooms
const cave = room('Dark Cave').description('A damp cave.').dark().build();

// Objects with custom traits
const note = object('crumpled note')
  .description('A crumpled piece of paper.')
  .addTrait(new ReadableTrait({ text: 'The code is 4-7-2.' }))
  .in(cave)
  .build();

// Containers
const chest = container('wooden chest')
  .openable({ isOpen: false })
  .lockable({ isLocked: true, keyId: key.id })
  .in(cave)
  .build();

// Items in closed containers (bypasses validation)
object('gold coin').skipValidation().in(chest).build();

// Doors between rooms
door('iron door')
  .between(cave, hallway, Direction.NORTH)
  .openable({ isOpen: false })
  .build();

Architecture

+-----------------------------------------------+
|              Your Story                       |
+--------------------+--------------------------+
| stdlib (actions)   | lang-en-us (messages)    |
| plugins (npc,      | parser-en-us (grammar)   |
|  scheduler, state) |                          |
+--------------------+--------------------------+
| engine | world-model | helpers | channels     |
+-----------------------------------------------+
| if-domain | if-services | event-processor     |
+-----------------------------------------------+
| core (events, types) | media (audio types)   |
+-----------------------------------------------+

Rendering is the engine's prose pipeline producing ITextBlock[], carried to the UI by channels (ADR-163/174) — there is no separate text service.

Key Principles

  1. Actions emit semantic events, not text — The language layer converts message IDs to prose
  2. Behaviors own mutations — Actions coordinate, behaviors perform state changes
  3. Traits compose entity capabilities — Add container, lockable, wearable, etc.
  4. Parser scope is permissive — Actions decide if visibility is truly required

Standard Actions

Movement: going, entering, exiting, climbing Manipulation: taking, dropping, putting, inserting, removing, giving, throwing Containers/Doors: opening, closing, locking, unlocking Examination: looking, examining, searching, reading Interaction: talking, showing, attacking Devices: switching on/off, pushing, pulling, raising, lowering Wearables: wearing, taking off Consumables: eating, drinking Senses: touching, smelling, listening Meta: inventory, score, help, save, restore, restart, quit, undo, again, wait, about, version, sleep

Repository Development

Prerequisites — Node, pnpm at the exact declared version, and the platform-specific extras — are listed with their checks in docs/core-concepts/prerequisites.md. Worth two minutes before the first build on a new machine.

git clone https://github.com/ChicagoDave/sharpee.git
cd sharpee
corepack enable        # pins pnpm to the version package.json declares
pnpm install

# FRESH CLONE ONLY (needed once): tsf compiles the platform packages, then
# repokit itself is built — tsf does not build it, so ./repokit won't exist yet.
npx tsf build
pnpm --filter @sharpee/repokit build

# Build everything (repokit; ADR-187)
./repokit build dungeo

# Run tests
pnpm test

# Run specific package tests
pnpm --filter '@sharpee/stdlib' test

# Run story transcript tests
node dist/cli/sharpee.js --test stories/dungeo/tests/transcripts/*.transcript

Example Stories

StoryLocationDescription
dungeostories/dungeoMainframe Zork implementation (~191 rooms, 650 points + 100 endgame)
familyzootutorials/familyzoo/v1.5.0, tutorials/familyzoo/v2.0.0The book's Family Zoo — chapter-by-chapter tutorial snapshots, built against the published npm packages. Split into two editions: v1.5.0 (the frozen 1.x line, pins ^1.5) and v2.0.0 (the Phrase Algebra line, pins ^2.0)
entropystories/entropyOriginal sci-fi story with audio system (in progress)

Roadmap

Sharpee is actively developed. These are the open Architecture Decision Records representing planned future work.

Recently Implemented

  • NPC Behavior Chain (ADR-141, 142, 144, 145, 146) — Character psychology, conversation, goal pursuit, information propagation, NPC influence
  • Direction Vocabularies (ADR-143) — Location-relative directions (compass, naval, minimal, custom)
  • Audio System (ADR-138) — SFX, music, ambient, procedural audio, AudioRegistry
  • Entity Helpers (ADR-140) — Fluent builder API for story setup
  • Action Interceptors (ADR-118) — Story-level hooks on standard actions

Accepted (Implementation Planned)

  • Screen Reader Accessibility (ADR-100) — ARIA support for the browser client
  • Speech Accessibility (ADR-139) — TTS/STT for blind and motor-impaired players
  • Equivalent Objects (ADR-147) — Identical object groups, numeric commands, trade/sell/barter

Proposed

AreaADRDescription
Story ParadigmsADR-083Spirit PC — Non-physical player character support
Story ParadigmsADR-102Dialogue Extension — NPC conversation systems (ASK/TELL, menus)
Story ParadigmsADR-103Choice-Based Stories — CYOA-style with parser hybrid
World ModelADR-020Clothing and Pockets — Container hierarchy for wearable items
ClientsADR-098Terminal Client — CLI-based game client
ClientsADR-099GLK Client — Standard IF interpreter protocol
ClientsADR-122Rich Media and Story Styling — Embedded media in output
Zifmia (retired)ADR-125Panel and Windowing System — Multi-panel desktop client
Zifmia (retired)ADR-128Walkthrough Panel — In-client walkthrough display
Zifmia (retired)ADR-130Story Installers — Split runner from author packaging tool
Author ToolsADR-115Map Export CLI — Export story maps from code
Author ToolsADR-116Prompt-to-Playable — AI-assisted story development
Author ToolsADR-131Automated World Explorer — Regression test generator
EngineADR-127Location-Scoped Interceptors — Room-tied action interceptors

See the full ADR index for the complete set of architecture decisions.

License

MIT License — Copyright 2025-2026 David Cornelson

Languages

TypeScript

80.5%

Swift

6.3%

HTML

3.1%

MDX

2.3%

JavaScript

2.3%

C#

1.6%

CSS

1.5%

Shell

1.4%