livt - Living Text
Collaborate on board. Make it living in text.
Outcome
Collaborative outcomes evolve alongside the product as living text.
Opportunities
- Stale Discovery: Discovery-phase artifacts are not persisted after synchronous collaboration sessions
- Discovery-Development Gap: Persisted discovery artifacts are not leveraged in the development process
Solutions
- Provide a CLI tool that captures collaborative outcomes as text files (YAML, Markdown)
- Track consistency across artifacts via ID-based references with automated checks
- Treat Formulation artifacts (Gherkin scenarios) as generated output, not the source of truth — the master lives in Discovery artifacts
Live Demo
livt dogfoods itself: its own discovery artifacts — stories, story maps, example mappings, and ubiquitous language — are published with livt build as a live demo. It shows exactly what the guides below describe.
Installation
livt ships as a single static binary. Every release is built by the release workflow on GitHub Actions, and every artifact is:
- listed in
checksums.txt(SHA-256) - signed with a GitHub artifact attestation (Sigstore build provenance) tying it to the exact source commit and workflow run
- built from the module as served by the Go module proxy and verified against the Go checksum database, so the binaries can be reproduced from the public source
Pick the method that matches how much of that verification you want automated.
mise (recommended)
The mise github backend
downloads the release binary and verifies its build provenance attestation by
default — a tampered or foreign-built asset fails to install.
mise use "github:boykush/livt@<version>"
Or in mise.toml:
[settings]
lockfile = true # pin checksum + provenance in mise.lock
[tools]
"github:boykush/livt" = "<version>"
With lockfile = true, the
asset checksum and attestation provenance are recorded in mise.lock, so
later installs — on CI or a teammate’s machine — must match bit-for-bit.
Manual download
Download the archive for your platform and checksums.txt from
GitHub Releases, then verify
before running:
# Provenance: proves the artifact was built by this repository's release
# workflow on GitHub Actions (requires the GitHub CLI)
gh attestation verify livt_<version>_<os>_<arch>.tar.gz --repo boykush/livt
# Integrity: check the SHA-256 checksum (macOS: shasum -a 256 -c)
sha256sum --check --ignore-missing checksums.txt
tar -xzf livt_<version>_<os>_<arch>.tar.gz
install livt ~/.local/bin/ # or anywhere on your PATH
Build from source
Source installs are verified by the Go checksum database: everyone gets
byte-identical source for a given version, and a silently re-pushed tag is
rejected. Pin a release version rather than latest so installs stay
reproducible.
go install github.com/boykush/livt@<version>
Or with the mise go backend
(requires Go on your PATH):
mise use "go:github.com/boykush/livt@<version>"
Getting Started
Installation
Install with mise, which verifies the release binary’s build provenance attestation by default:
mise use "github:boykush/livt@<version>"
See Installation for all methods and how release artifacts are verified.
Quick Start
- Create the required directories:
mkdir -p stories discoveries/usm discoveries/example-mappings ubiquitous
- Create your first story in
stories/my-first-story.md:
---
name: My first story
---
As a user
I want to do something
So that I get value
- Build and serve:
livt serve
- Open http://localhost:3000 in your browser. Every page has a sidebar to switch between Example Mappings, Story Maps, Stories, and Ubiquitous Language. Open Stories to find the story you just created:

Stories
Stories are Markdown files with YAML frontmatter, stored in the stories/ directory.
The stories/ directory is the committed story registry: once a story candidate is committed for detailed discovery, its key is owned by stories/{story-key}.md.
Format
---
name: Story display name
---
Story body in Markdown.
The name field in frontmatter is required. The story key is derived from the filename (without .md).
Story keys must be kebab-case, using lowercase letters, numbers, and hyphens.
Key uniqueness is enforced by the filesystem: two committed stories cannot use the same stories/{story-key}.md path.
Example
stories/confirm-story-map.md:
---
name: Confirm story map
---
As a team member
I want to view the story map as a board
So that I can visually confirm the discovery outcomes maintained in text
This story has key confirm-story-map, which is used to reference it from story maps and example mappings.
Commit from a story map
Committing a story candidate from a story map into the registry is handled by the
/story-commit skill (from the discovery-facilitator plugin), rather than a CLI command.
Given the story map and the candidate, it creates stories/{story-key}.md first and then writes
the same key back to the matching candidate in the story map.

Story Maps
Story maps are YAML files stored in discoveries/usm/. They define the structure of a User Story Map with activities, steps, stories, and release slices.
Format
name: Map Name
activities:
- key: activity-key
name: Activity Name
steps:
- key: step-key
name: Step Name
stories:
- key: story-key
name: Story Card Name
release: release-id
- name: Lightweight Story Card
releases:
- id: release-id
name: Release Name
ubiquitous:
- term-key
Ubiquitous Language
ubiquitousis optional: each entry is a ubiquitous language term key- Referenced terms render as pink stickies below the board, linking to
ubiquitous.html#{term-key} - A key with no matching term file renders as a plain pink card
Releases
- Each release defines a horizontal divider on the board
- Each release has an
idthat story cards reference withrelease - Stories with a
releaseappear above that release’s divider - A release without
namedefaults to “Release N” based on position - Stories not in any release appear below all dividers
- Story cards without
keyappear as plain cards and can still belong to a release - A story can reference only one release
Example
discoveries/usm/collaborative-discovery.yaml:
name: Collaborative Discovery
activities:
- key: story-mapping
name: Story Mapping
steps:
- key: discover-stories
name: Discover stories
stories:
- key: confirm-story-context
name: Confirm story context
release: walking-skeleton
- key: confirm-story-map
name: Confirm story map
release: walking-skeleton
- name: Draft session outcomes
- key: slice-releases
name: Slice into releases
stories:
- key: split-release-scope
name: Split release scope
release: release-2
- key: discovery
name: Discovery
steps:
- key: discover-rules
name: Discover rules
stories:
- key: confirm-discovery-outcomes
name: Confirm discovery outcomes
release: walking-skeleton
releases:
- id: walking-skeleton
name: Walking Skeleton
- id: release-2

Example Mappings
Example mappings are YAML files stored in discoveries/example-mappings/. They capture the rules, examples, and questions discovered during an Example Mapping session for a story.
Format
story: story-key
rules:
- id: R-01
name: Rule description
examples:
- id: EX-01
name: Example description
issues:
- https://github.com/owner/repo/issues/1
automated: true
questions:
- id: Q-01
text: Question text
ubiquitous:
- term-key
storyis optional (links to the corresponding story detail page)- IDs must be unique within their rule or question list
ubiquitousis optional: each entry is a ubiquitous language term key, rendered as a pink sticky linking toubiquitous.html#{term-key}. A key with no matching term file renders as a plain pink card.issuesis optional: the rule’s automation Issue URLs on implementation repos (Issue URLs only). The master records the links; their state lives at the URL target. A rule withoutissuesis unlinked.automatedis optional: records the judgment that the rule is actually automated by tests, which is independent of Issues being filed or closed. Absent means not automated. Set it when the rule’s automation lands; unset it when the rule changes.
Visual Layout
The board renders cards in the Example Mapping format:
- Yellow card: Story (top)
- Blue cards: Rules (row below story)
- Green cards: Examples (stacked under their rule)
- Red cards: Questions (separate column)
- Pink cards: Ubiquitous language terms (referenced via
ubiquitous, below the board)
Example
discoveries/example-mappings/confirm-discovery-outcomes.yaml:
rules:
- id: R-01
name: An example mapping can be rendered as a sticky view with only a story reference
examples:
- id: EX-01
name: A YAML with only a story reference displays a single yellow Story card
- id: R-02
name: Cards are laid out following the Example Mapping format
examples:
- id: EX-01
name: Rules are displayed as blue cards in a row below the Story card
- id: EX-02
name: Examples are displayed as green cards stacked under their Rule
- id: EX-03
name: Questions are displayed as red cards in a separate column
questions: []

Ubiquitous Language
Ubiquitous language terms are Markdown files with YAML frontmatter, stored in the
ubiquitous/ directory. Each file is a single term, and livt renders them as a
table you can browse like a database.
Format
---
name: Term display name
---
Definition in Markdown.
The name field in frontmatter is the display term. The term key is derived
from the filename (without .md) and must be kebab-case, using lowercase
letters, numbers, and hyphens. The body is the term’s definition.
Example
ubiquitous/story-map.md:
---
name: Story Map
---
A board to overview activities, steps, and stories alongside release slices.
Visual Layout
livt build renders every term as a row on a single page at ubiquitous.html,
with Term, Key, and Definition columns. Each row carries an
id={term-key} anchor, so a term is linkable as ubiquitous.html#{term-key}.
Referencing terms from boards
Story maps and example mappings can declare the terms they use with a top-level
ubiquitous list of term keys:
ubiquitous:
- story-map
- story
Referenced terms render as pink stickies below the board, each linking to its
glossary row (ubiquitous.html#{term-key}). A key with no matching
ubiquitous/{term-key}.md file renders as a plain pink card, so references
degrade gracefully. See Story Maps and
Example Mappings.
Commands
livt serve
Build artifacts and start a local server.
While the server is running, livt watches the input directories
(discoveries/example-mappings, stories, discoveries/usm, and ubiquitous).
When a file changes, livt rebuilds and reloads the page in the browser
automatically, so you can preview refinements while editing.
livt serve [flags]
| Flag | Short | Default | Description |
|---|---|---|---|
--port | -p | 3000 | Port to listen on |
--out | -o | dist | Output directory |
livt build
Build static HTML from artifacts without starting a server.
livt build [flags]
| Flag | Short | Default | Description |
|---|---|---|---|
--out | -o | dist | Output directory |
livt mcp
Run an MCP (Model Context Protocol) server that exposes the discovery master (story maps, stories, example mappings, and the ubiquitous language). An implementation repo’s coding agent can then fetch the spec for a story or rule without reading livt’s source.
The master usually lives in a separate checkout from the consumer, so point at
it with --root or the LIVT_ROOT environment variable. The flag takes
precedence; both default to the current directory.
livt mcp [flags]
| Flag | Default | Description |
|---|---|---|
--root | $LIVT_ROOT, then . | Path to the livt project root holding the discovery master |
--http | (off; stdio) | Serve over Streamable HTTP at this address (e.g. localhost:5488) instead of stdio; the MCP endpoint is <addr>/mcp |
Transports
By default the server runs over stdio, spawned per consumer — the client
launches livt mcp as a subprocess. This suits a single repo with the master
checked out alongside it.
Pass --http to instead serve over Streamable HTTP from one long-running
process, so several repos on the same machine can share a single server without
each holding a checkout of the master:
livt mcp --http localhost:5488
Each consumer points its MCP client at http://localhost:5488/mcp. The server
is stateless and read-only, so one process backs many clients; keep git pull
current on its checkout and the served spec (and spec_version) updates live.
For distributing this client configuration to implementation repos, see the
livt-mcp plugin.
This mode assumes local use with no authentication — the server is meant to bind
to localhost, not a public network.
Tools
| Tool | Arguments | Returns |
|---|---|---|
list_stories | — | Every story with its key and name. Each entry links to its story resource (uri); stories that have an example mapping also include example_mapping_uri. |
list_story_maps | — | Every story map with its name and its story map resource URI (uri). |
Resources
The spec itself is exposed as resources, addressable by URI (story map → story → mapping → rule, with ubiquitous terms linked from mappings and story maps):
| URI | Returns |
|---|---|
livt://story-map/{map_name} | A story map: activities, steps, story cards, and releases. Committed story cards link to their story resource. {map_name} is the map’s display name (percent-encoded) — the same identifier the build output uses for story-map/{name}.html. |
livt://story/{story_key} | The story’s name, body, and frontmatter meta (e.g. issue), plus example_mapping_uri when a mapping exists. |
livt://mapping/{story_key} | The story’s example mapping (rules, examples, questions, ubiquitous terms). Each rule carries its own uri, and ubiquitous_terms resolves each referenced term to its resource URI. |
livt://mapping/{story_key}/rule/{rule_id} | A single rule and its examples, plus its recorded automation: issues (automation Issue URLs) and automated (whether the rule is automated by tests). Rules inside livt://mapping/{story_key} carry the same fields. |
livt://ubiquitous/{term_key} | A ubiquitous language term’s name and definition. |
Read them with resources/read; all appear in resources/templates/list. The
server advertises templates only — there is no concrete resource list and no
change notification (subscribe); every read is served fresh from disk.
Every tool and resource payload also includes a spec_version field – the
short git revision of the master – so consumers can tell which version of the
spec they are reading and detect drift.
livt version
Print the version of livt.
livt version
File Structure
Input
project-root/
stories/
{story-key}.md # Story files
discoveries/
usm/
{map-name}.yaml # Story map files
example-mappings/
{story-key}.yaml # Example mapping files
ubiquitous/
{term-key}.md # Ubiquitous language term files
- Story keys are derived from filenames (without extension)
- Story keys must be kebab-case: lowercase letters, numbers, and hyphens
- The
stories/directory is the committed story registry, andstories/{story-key}.mdprovides story key uniqueness - Example mapping filenames must match story keys to link them
- Term keys are derived from
ubiquitous/{term-key}.mdfilenames and used asubiquitous.html#{term-key}link anchors
Output
livt build generates the following structure:
dist/
index.html # Example mappings overview (home)
story-maps.html # Story maps overview
stories.html # Story list
ubiquitous.html # Ubiquitous language table
story/
{story-key}.html # Story detail pages
mapping/
{story-key}.html # Example mapping boards
story-map/
{map-name}.html # Story map boards
Every page shares a left sidebar that links the four resource types (Example Mappings, Story Maps, Stories, Ubiquitous Language). The overview pages render each example mapping and story map as a preview card.