Documentation

how it works.

This page covers installation, the core model, the terminal UI and the browser GUI, synchronization, and agent integration.

Installation

Epiq ships as a single binary (with an npm package alternative). The binary installs to ~/.local/bin by default.

Quick install (binary)

curl -fsSL https://raw.githubusercontent.com/ljtn/epiq/main/install.sh | sh

Override the location with EPIQ_INSTALL_DIR (or XDG_BIN_HOME), and pin a version with EPIQ_VERSION=v1.0.0.

Via npm

npm install --global epiq

Verify

epiq --version

Getting started in two steps

Epiq lives inside a Git repository — your issues can live where your code lives.

  1. Make sure you are inside a Git repository. For collaboration, use a repo with a remote (e.g. cloned from GitHub).
    # if needed
    git init
  2. Run Epiq:
    epiq

On first run this opens an interactive setup wizard that gets you going in about 30 seconds. Once your project is set up, you can also launch the browser GUI:

epiq gui
What gets created. The setup wizard writes user config to ~/.epiq-global/config.json. Initialization adds a project definition at ./.epiq/project.json, authoritative Git state at ~/.epiq-global/worktrees/<id>, and updates your .gitignore to ignore local-only .epiq/log/.

Two front ends, one board

epiq opens the terminal UI, epiq gui the browser app. They are two views of the same event log in the same repository — switch whenever you like, or keep both open; whatever one writes, the other shows. The rest of this page is split the same way: the terminal, then the browser.

Core concepts

The hierarchy

State is a tree of nodes. From the top down: workspace → board → swimlane → issue. Issues hold a description, tags, assignees, comments, and a full history log. Commands are context-aware — for instance :close only exists for issues.

Event-sourced state

Every change is stored as an append-only event in a user-scoped log, rather than mutating a shared file. The current state is materialized in memory by replaying a merge of all user logs in a deterministic order (time-sortable ULIDs plus a reference to the last known event). This makes concurrent edits converge to the same state and keeps Git merges trivial.

Local-first

All operations apply instantly on your machine. Synchronization happens explicitly with :sync or automatically. When histories diverge, merging the event logs and replaying them leads to a consistent state.

Command reference

Type : to enter command-line mode, then a command. Commands accept a modifier (in violet) and a free-text argument. Autocompletion suggests valid modifiers as you type, and the set of available commands depends on what is selected.

Create & edit

Command Description
:new issue|swimlane|board <name> Create a new board, swimlane, or issue
:edit title <text> Rename the selected node inline
:edit description Open the description of the selected issue in your preferred external editor (no inline text — also bound to e)
:edit comment <text> Edit the currently selected comment inline (only your own comments)
:comment <text> Add a comment to the selected issue
:delete Delete the currently selected node
:move Move a node — usually triggered with m, then navigate and confirm

Issue workflow

Command Description
:tag <name> Add or create a tag on the selected issue
:untag <name> Remove a tag from the selected issue
:assign <name> Assign a user to the selected issue
:unassign <name> Remove an assignee from the selected issue
:yank ref|title|description|tags|assignees Copy the selected item's ref, title, description, tags, or assignees to the system clipboard (also bound to y). Description, tags, and assignees are offered when the issue has them
:close Move the selected issue to the Closed swimlane
:reopen Move a closed issue back to its previous swimlane

View & history

Command Description
:filter tag|assignee|description|title|clear <value> Filter the board; combine filters by running several in succession
:peek <offset>|<date>|now|prev|next View the board's state at another point in time. Offset is <n>h, d, w, mo, or y (e.g. 3d); or an absolute YYYY-MM-DD date
:replay <offset>|<date> [duration] Replay board history forward from a point in time as an animation, with an optional playback duration (e.g. 30s)
:export Export the current board layout to markdown

System & sync

Command Description
:sync Pull, commit, and push Epiq state via Git
:config editor|username|view|autoSync|syncDebounceMs|logLevel <value> Update editor, username, view, auto-sync, sync debounce, or log level
:init Initialize Epiq in the current Git repository
:help Open the help screen
:exit Exit the application
:coffee 1|3|5|20|custom Sponsor the development of Epiq ☕

Time travel

Because state is a full event log, you can inspect the board as it was at any point in the past. Use :peek with a time offset, or step through history:

# jump to an offset: h, d, w, mo, y (e.g. 3 days ago)
:peek 3d

# or jump to an absolute date
:peek 2026-01-15

# step backward / forward through history
:peek prev
:peek next

# return to the present
:peek now

Where :peek shows a frozen snapshot, :replay plays history forward from that point as an animation — watch the board evolve event by event. The optional second argument sets the playback duration:

# replay the last month of activity
:replay 1mo

# same, spread over a 30 second animation
:replay 1mo 30s

While peeking or replaying, the board is read-only; viewing, yanking to the clipboard, exporting, and configuration remain available.

Export

Run :export to write the current board layout to a markdown file — handy for sharing a snapshot, generating reports, or feeding context to other tools.

:export

Configuration

Adjust settings with :config <setting> <value>.

Setting Description
editor Preferred external editor for descriptions
username Your display name on events and assignments
view wide|dense Board layout density
autoSync on|off Enable or disable automatic synchronization
syncDebounceMs <ms> Debounce window for auto-sync in milliseconds (e.g. 5000, 15000, 30000)
logLevel debug|info|error Logging verbosity

The board

epiq gui serves the same board in the browser. Add tickets and lanes in place, and narrow a busy board with the filter box — it matches on ref or title.

Tickets & commits

Clicking a ticket opens its panel, docked to the right or along the bottom. Descriptions and comments take markdown, and images can be pasted or dropped straight in.

The Code tab is where the ref convention pays off: every commit whose subject starts with the ticket's ref shows up with its diffstat and per-file diff, and any line can be commented on.

Timeline

Drag the scrubber across the history to check out the board as it was at that moment, as volume per period or as individual events. The header reads Read-only while you are in the past, and Now brings you back.

Sync & Git

Epiq uses Git in the background — no manual Git commands required. Running :sync synchronizes changes between your local state (at ~/.epiq-global/worktrees/<id>/) and the remote. By using Git worktrees, synchronization stays isolated from your regular development workflow.

Changes are append-only events in user-scoped files, so Git merges become trivial combinations of independent files. Later events take precedence when conflicts occur, and idempotent events keep concurrent updates predictable.

Tip. Frequent synchronization reduces divergence and keeps the system predictable. Enable :config autoSync on to sync automatically.

MCP & agents

Epiq ships an MCP (Model Context Protocol) server via the epiq-mcp binary, so AI agents can interact with your local instance.

Claude Code

The reliable way to register the server is with claude mcp add — it writes the correct config for you:

# available everywhere (recommended)
claude mcp add --scope user epiq -- npx -y --package=epiq epiq-mcp

# or only in the current project
claude mcp add epiq -- npx -y --package=epiq epiq-mcp

Verify with claude mcp list (it should report epiq … ✔ Connected). MCP servers load at startup, so restart Claude Code after adding the server.

The Epiq skill

Registering the server tells an agent what it can do; the skill tells it how to work the board — use the MCP tools rather than the CLI, sync on demand, keep tickets small and their status current, and record the outcome as a comment. Epiq's own skill lives at .claude/skills/epiq/SKILL.md. Copy it into your project's .claude/skills/ and trim the rules that are specific to this repository:

mkdir -p .claude/skills/epiq
curl -fsSL https://raw.githubusercontent.com/ljtn/epiq/main/.claude/skills/epiq/SKILL.md \
  -o .claude/skills/epiq/SKILL.md
This is what fills the Commits tab. A commit links to a ticket when its subject starts with that ticket's ref — the seven characters shown on the ticket, and what :yank ref copies: git commit -m "A1B2C3D fix the parser". Follow the convention and the ticket gains a Commits tab with the diffstat, the per-file diff, and a comment box on any line; skip it and the work is done but invisible from the board.

Other MCP clients

For hand-configured clients, add the following to the client's MCP config file:

{
  "mcpServers": {
    "epiq": {
      "command": "npx",
      "args": ["-y", "-p", "epiq", "epiq-mcp"]
    }
  }
}