- TypeScript 91%
- JavaScript 7.6%
- Nix 1.4%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .forgejo/workflows | ||
| src | ||
| test | ||
| .envrc | ||
| .gitignore | ||
| flake.lock | ||
| flake.nix | ||
| GOAL.md | ||
| LICENSE | ||
| package.json | ||
| pnpm-lock.yaml | ||
| pnpm-workspace.yaml | ||
| README.md | ||
| TODO.md | ||
| tsconfig.build.json | ||
| tsconfig.json | ||
| vitest.config.ts | ||
World Feast
World Feast is an interactive, Pi-backed CLI for continuing stories and keeping a Markdown world project consistent. Production workflows use Pi's public InteractiveMode, including native streaming, thinking display, tool cards, and scrollback. The simple line terminal remains available when tests inject input/output/sessionFactory.
Requirements and installation
Use Node.js 26 or later. From a source checkout:
corepack enable
pnpm install --frozen-lockfile
pnpm run build
# Use the current directory as the world project.
node dist/cli.js
# Or name a readable world-project directory.
node dist/cli.js /path/to/world
Nix users can build the pinned flake package instead:
nix build
./result/bin/world-feast /path/to/world
For development, the default flake shell provides Node.js and the pinned pnpm version. With direnv and nix-direnv installed, allow the checked-in .envrc once:
direnv allow
pnpm install --frozen-lockfile
The built command accepts zero or one world-project path. -h or --help prints usage without starting an interactive session. To make the built executable available as world-feast, run pnpm setup once to configure pnpm's global binary directory, start a new shell, then run from the source checkout:
pnpm link --global
world-feast /path/to/world
Model authentication
World Feast does not provide login, provider, or model command-line flags. It uses the installed Pi coding-agent SDK, with World Feast's config root set to ~/.config/world-feast by default or $XDG_CONFIG_HOME/world-feast when XDG_CONFIG_HOME is an absolute path. Configure the provider and model in that same root before starting World Feast:
PI_CODING_AGENT_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/world-feast" pnpm exec pi
In Pi, use /login to authenticate and /model to select a model. World Feast reads auth.json, models.json, and settings.json from this root. Provider environment keys supported by Pi can supply authentication instead. User Pi extensions for World Feast belong in ~/.config/world-feast/extensions/ or $XDG_CONFIG_HOME/world-feast/extensions/; project-local Pi extensions remain under <world-project>/.pi/extensions/.
World projects
World Feast discovers Markdown files recursively inside every top-level directory of the project. characters, groups, and stories are built-in groupings; any other top-level directory is a custom grouping, and custom groupings can contain arbitrary nested directories.
my-world/
├── characters/
│ └── mira.md
├── groups/
│ └── harbor-watch.md
├── stories/
│ ├── opening.md
│ └── arcs/
│ └── arrival.md
└── places/ # custom grouping
└── coast/
└── breakwater.MD
Only regular Markdown files (.md, case-insensitive) within those directories are discovered. Files at the project root and symbolic links are ignored during discovery.
Story chronology
A story can begin with a YAML-style frontmatter block containing before and/or after lists. Both inline arrays and block lists are accepted:
---
before: [stories/opening.md]
after:
- "../arrival.md"
---
The tide was already turning.
before and after express the story's chronology relative to the listed stories. A reference beginning with stories/ is a project-root story path. Every other reference is resolved relative to the directory of the story that declares it. Thus, from stories/arcs/arrival.md, stories/opening.md names <project>/stories/opening.md, while ../arrival.md names <project>/stories/arrival.md. References must resolve to discovered paths beneath stories/; missing and self-references are invalid.
Before any mode starts, World Feast validates every discovered story. Malformed frontmatter and missing, outside-story, or self-references abort startup with affected paths and details; fix them before continuing.
Interactive workflows
Start the CLI, choose a workflow from the menu, and type chat requests. Story and single-file workflows then prompt for a project-relative target path. Consequences mode has no target prompt.
$ node dist/cli.js ./my-world
Welcome to World Feast.
Project: ./my-world
Your world files stay behind the selected workflow's safety boundary.
Type /switch to choose another workflow or /exit to leave.
┌─ World Feast ─────────────────────────────────────────────┐
│ Choose a workflow │
│ 1 Story Draft and review an addition to a story │
│ 2 Single-file Update one Markdown world file │
│ 3 Consequences Update non-story world records │
│ 4 Switch Return to the mode menu │
│ 5 Exit Leave World Feast │
└───────────────────────────────────────────────────────────┘
Mode: 1
Starting Story mode (every proposal requires approval)…
Target Markdown file (or /switch, /exit): stories/arcs/arrival.md
Connecting to Pi…
Pi is ready.
Message (/switch to change mode, /exit to quit): Write the first exchange at the harbor gate.
You › Write the first exchange at the harbor gate.
Pi › The harbor gate was already crowded when the bell rang.
Select workflows with their number or name (story, single-file, or consequences). A target must be a project-relative Markdown file beneath a world grouping; story mode further requires a path beneath stories/.
| Workflow | Permission guarantee |
|---|---|
| Story | The assistant has read-only research access and cannot mutate files directly. World Feast appends only prose that you accept (or edit and accept) to the selected story; this creates the selected story when it does not exist and never replaces existing bytes. |
| Single-file | The assistant can create or update only the selected Markdown target; it cannot mutate any other path. |
| Consequences | The assistant can create or update Markdown files canonically outside stories/, including genuinely distinct custom groupings; mutations through path or filesystem-identity aliases to stories are denied. |
All modes enforce world-root-relative paths: absolute paths, traversal, and symbolic-link paths are rejected.
Secure capability file operations require Linux with an accessible /proc/self/fd; elsewhere, World Feast fails closed with an actionable error rather than using race-prone pathname operations. Descriptor-anchored final operations resist concurrent replacement of ancestor paths.
Reviewing stories and changing modes
For every story response, World Feast displays a proposal and asks for a review:
┌─ Proposed story addition ─────────────────────────────────┐
The harbor gate was already crowded when the bell rang.
└───────────────────────────────────────────────────────────┘
Nothing is written until you approve it.
Review the displayed proposal: [a]ccept, [r]eject, [e]dit, /switch, or /exit: a
a/accept appends the proposal to the target story. r/reject discards it. e/edit asks for replacement prose and appends that instead.
At a target prompt, /switch (or /leave) ends the active workflow and returns to the mode menu. Inside native Pi, use /switch, /leave, or /exit; these are World Feast extension commands and shut down the current Pi screen cleanly. In story mode, Pi presents a native confirmation/input dialog after each assistant turn. The story is read-only to Pi and is appended only after accept or non-empty edit; reject/blank edit writes nothing. This review happens before the next native Pi turn, so the assistant transcript stays Pi-native without pretending the review is a chat message.