Skip to content

Instantly share code, notes, and snippets.

@perigrin
Last active March 15, 2026 02:54
Show Gist options
  • Select an option

  • Save perigrin/efbb494dcd4a5456d52c85bf277be2ae to your computer and use it in GitHub Desktop.

Select an option

Save perigrin/efbb494dcd4a5456d52c85bf277be2ae to your computer and use it in GitHub Desktop.
git-chain PRD: local-first git-native Critical Chain project management CLI
title tags description
git-chain PRD
projects
ideas
Product requirements document for git-chain, a local-first git-native Critical Chain project management CLI

git-chain: Product Requirements Document

Overview

git-chain is a git subcommand for Critical Chain project management that stores all state locally in the git repository using special refs (refs/chain/state). It requires no external services, works offline, and syncs automatically via standard git push/pull. Invoked as git chain (git finds the git-chain binary on $PATH). The workflow is inspired by Critical Chain project management and the No Estimates philosophy.

This is a standalone Go binary — no runtime dependencies, no GitHub dependency, no API tokens required.

Philosophy

Core Principles

  1. Local-first, git-native. All state lives in the git repository itself. No external databases, no API dependencies. Works offline. Syncs when you push/pull.
  2. Target dates are constraints, scope is variable. Projects commit to a date. What ships by that date flexes based on reality.
  3. Thin vertical slices. Every issue represents an independently shippable unit of value. You can stop anywhere and have delivered something useful.
  4. One session per issue. Issues should be completable in a single focused work session. For a human, that's roughly one work day. For an LLM, that's one context window before ~60% utilization. If an issue takes multiple sessions, the buffer absorbs the cost — if this happens often, slice thinner or increase default session size.
  5. Urgency = cut order. All issues are expected to ship. Urgency only matters if buffer consumption forces a scope decision — then low drops first, moderate second, high last.
  6. No sprints. Time-boxing happens at the project level (milestones with optional due dates), not as a separate recurring container.
  7. Work in progress is limited. Finish issues before starting new ones.
  8. Agent-friendly. Every operation is available via CLI, JSON export, or direct git ref access. No interactive prompts required.

What is Critical Chain Project Management?

Critical Chain Project Management (CCPM) comes from Eli Goldratt's Critical Chain (1997), which applies Theory of Constraints thinking to project management. The core insight: traditional project management fails because people pad every individual task with safety time, then waste that safety through procrastination (Student Syndrome) and Parkinson's Law (work expands to fill the time available). The result is projects that are always late despite every task having generous estimates.

CCPM's fix is structural:

  1. Strip safety from individual tasks. Give each task an aggressive-but-possible estimate (roughly the median duration, not the "safe" 90th percentile).
  2. Pool the safety into a shared buffer at the end. Instead of hiding safety in each task, aggregate it into a project buffer that protects the delivery date.
  3. Focus on the critical chain — the longest sequence of dependent tasks, accounting for both task dependencies and resource dependencies. This is the constraint that determines your minimum project duration.
  4. Monitor buffer consumption, not task completion dates. The fever chart compares "% of work done" against "% of buffer consumed." If buffer is burning faster than work is completing, you have a real problem. If not, individual tasks running "late" is fine — that's what the buffer is for.

The result is faster, more predictable project delivery. You finish sooner because you aren't wasting safety time, and you finish more predictably because the buffer absorbs normal variation without triggering panic.

How git-chain Applies CCPM

git-chain translates CCPM into a developer workflow with some opinionated adaptations:

The chain is a DAG of issues with explicit dependencies. By marking which issues block others, git chain list --critical calculates the longest sequential path — the critical chain. Work not on the critical chain can happen in parallel or be cut without affecting the target date.

Sessions replace time estimates. Rather than estimating hours or days, every issue targets one session of focused work (configurable, default 2 hours). This is the aggressive-but-possible estimate. If an issue takes more than one session, the extra sessions consume buffer. No one estimates how long anything takes — you just work in sessions and let the data tell you how you're doing.

Buffer is measured in sessions. Buffer = 50% of the number of issues in a milestone (Goldratt's 50% rule). A milestone with 10 issues has a 5-session buffer. Buffer is consumed when issues spill past one session. You never "enter" the buffer phase — it's a reserve that absorbs variance.

Gas mileage replaces velocity. The ratio of sessions consumed to issues completed, tracked empirically. If your gas mileage is 1.5, you're averaging 1.5 sessions per issue. This feeds forecasting and tells you whether your issues are sized right. If >50% of issues spill, either increase your default session size or slice issues thinner.

Tank represents capacity. For date-constrained milestones: the number of sessions available in the timeframe given current gas mileage. For undated milestones: sustainable developer capacity. git chain rebalance adjusts milestone boundaries to fit within tank capacity.

Milestones are subchains. Each milestone is a segment of the larger project chain. Issues in milestone 2 may depend on issues from milestone 1. The handoff between milestones requires the full kit principle: don't start work on a milestone until its cross-milestone dependencies are complete. Starting with incomplete prerequisites means you'll block mid-milestone — consuming buffer on waiting, not working.

Feeding buffers protect handoffs. When a milestone depends on work from a previous milestone, that's a feeding chain joining the critical chain. The gap between milestones (any slack before the next due date) acts as a feeding buffer — protection against delays in the predecessor milestone propagating forward.

The fever chart is the primary health indicator. Compare % of issues complete vs % of buffer consumed. Green (buffer burn < progress) means healthy. Yellow (roughly equal) means watch closely. Red (buffer burn significantly exceeds progress) means cut scope or extend the date. The target date is the constraint; scope is what flexes. Urgency on issues determines cut order if it comes to that.

Conceptual Model

Concept What It Is
Chain A DAG of issues. The work itself.
Milestone A segment of the chain + a buffer. A delivery grouping with an optional due date.
Session One unit of work (configurable default size). The fuel.
Buffer Calculated reserve measured in sessions (50% of milestone issue count). Displayed but not a phase you enter — you burn buffer or finish with buffer to spare.
Tank Milestone capacity. Date-constrained: sessions available in timeframe given velocity. Undated: sustainable developer capacity.
Gas mileage Historical sessions-per-issue ratio. Tracked empirically, used for forecasting and rebalancing.

Position in the chain determines milestone membership (no separate scoping step). The DAG is the real structure; chain list shows a linearized view (topological sort) by default.

Data Model

Storage Architecture

All state is stored in refs/chain/state — a git ref that points to a tree of files, similar to git-bug and git-appraise. State never appears in the working tree.

Hybrid model:

  • Snapshot tree on the ref: current state of all issues, milestones, and config. Enables fast reads — a single git show or tree walk gets everything.
  • Commit history on the ref: every mutation is a commit. Provides a complete audit trail — who changed what, when, and why.

Reading state: git show refs/chain/state:issues/<id>.md Writing state: The CLI creates a new commit on the ref with the updated tree.

Tree Structure

refs/chain/state → tree:
  config.yml
  issues/
    <uuidv7>.md
  milestones/
    <name>.yml

Issue Format

Issues are markdown files with YAML frontmatter. The ID is the filename (UUIDv7).

# issues/019444a1-b2c3-7def-8901-234567890abc.md
---
title: "Parse basic sub declarations"
state: pending           # pending | in-progress | done | cancelled
urgency: high            # high | moderate | low | (omitted = unset)
milestone: "v0.1"        # references milestones/<name>.yml
blocked_by:              # UUIDv7 refs (bidirectional with 'blocks')
  - "019444a1-a1b2-7cde-8901-234567890abc"
blocks:
  - "019444a1-c3d4-7ef0-8901-234567890abc"
  - "019444a1-d4e5-7f01-8901-234567890abc"
created: "2026-03-14T10:30:00Z"
updated: "2026-03-14T14:22:00Z"
sessions:                # completed session log
  - started: "2026-03-14T10:30:00Z"
    ended: "2026-03-14T11:45:00Z"
---

Implement parsing for basic subroutine declarations
without signatures. Handle `sub foo { }` form.

## Notes

Any markdown content here serves as the issue body.

Issue IDs: UUIDv7 (timestamp-ordered, collision-free). Displayed truncated in CLI output (first 8 characters by default). Any unique prefix works as a reference.

State transitions:

pending ──────────► in-progress ──────────► done
                        │
                        │
                        └──────────► cancelled

pending ──────────────────────────► cancelled

State is an explicit field, not derived from other properties. There is no "triage" state — issues are always in the chain. There is no "backlog" state — pending issues that aren't being worked on are simply pending.

Milestone Format

Milestones are separate YAML files with optional due dates.

# milestones/v0.1.yml
name: "v0.1"
due: "2026-04-15"        # optional
description: "Initial parser implementation"
created: "2026-03-14T10:00:00Z"

Dependencies

Dependencies are stored bidirectionally in issue frontmatter:

  • blocked_by: list of issue IDs this issue waits on
  • blocks: list of issue IDs that wait on this issue

The CLI maintains bidirectional consistency — adding a blocked_by on issue A automatically adds a blocks on issue B, and vice versa.

Configuration

# config.yml
version: 1
default_session_minutes: 120      # configurable session size
hooks:
  post_commit: true               # scan commit messages for closes/starts
sync:
  auto: true                      # push/pull refs/chain/* with normal git ops

Sync

By default, chain init configures refspecs so refs/chain/* syncs automatically on git push and git pull. This means chain state travels with the repository.

  • Auto mode (default): refspecs added to remote config. Push/pull just work.
  • Explicit mode: disable auto sync in config.yml, use chain sync manually.
  • Conflict resolution: last-writer-wins at the file level (issues are separate files, so conflicts are rare). The commit history on the ref preserves both sides.

Commands

chain init

Set up a repository for use with chain.

Behavior:

  • Creates refs/chain/state with initial config.yml
  • Installs post-commit hook (scans commit messages for closes <ref>, finishes <ref>, starts <ref>)
  • Configures refspecs for automatic sync on push/pull
  • Idempotent (safe to run multiple times)

Output:

Initialized chain in current repository.
  Created refs/chain/state
  Installed post-commit hook
  Configured sync refspecs

Options:

  • --no-hooks — Skip hook installation
  • --no-sync — Don't configure automatic refspec sync

chain add <title>

Create the chain (first use) or add a new milestone.

Behavior:

  • If no chain exists: creates the chain and first milestone with the given title
  • If chain exists: creates a new milestone with the given title
  • Milestones are created with no due date by default

Examples:

First use:

$ git chain add "Chalk Parser"
Created chain with milestone: Chalk Parser

Adding another milestone:

$ git chain add "Self-Hosting"
Created milestone: Self-Hosting

Options:

  • --due <date> — Set due date (YYYY-MM-DD or relative: 2 weeks, friday, end of month)

chain list [--graph] [--parallel=N] [--critical]

Show the full chain, linearized by default.

Behavior:

  • Default: topological sort of all issues, grouped by milestone
  • --graph: ASCII DAG visualization showing dependency structure
  • --parallel=N: Gantt-style view showing N parallel work streams
  • --critical: highlight the critical chain (longest sequential path)
  • Issues show state, urgency, and dependency status

Output (default — linearized):

Chalk Parser [due: Apr 15 — 22 days left]

  019444a1  [high]  Implement lexer                 ● in-progress
  019444a2  [high]  Parse basic sub declarations     ○ pending (blocked by 019444a1)
  019444a3  [mod]   Parse signatures                 ○ pending (blocked by 019444a1)
  019444a4  [low]   Error recovery                   ○ pending
  019444a5  [low]   Full method modifier support     ○ pending

Self-Hosting [no due date]

  019444b1  [high]  Bootstrap compiler               ○ pending (blocked by 019444a2)
  019444b2  [mod]   Test harness                     ○ pending

Output (--graph):

Chalk Parser — Dependency Graph

           ┌─── 019444a3 Parse signatures
           │         [pending]
           │
  019444a1 ┼─── 019444a2 ─── 019444b1
  Lexer    │    Declarations   Bootstrap
  [in-prog]│    [pending]      [pending]
           │
           └─── 019444a4 Error recovery
                     [pending]

Critical chain: 019444a1 → 019444a2 → 019444b1

Output (--critical):

Critical Chain (3 issues)

  019444a1  Implement lexer                    ● in-progress
   ↓
  019444a2  Parse basic sub declarations       ○ pending
   ↓
  019444b1  Bootstrap compiler                 ○ pending

Current constraint: 019444a1
Parallel work available: 019444a3, 019444a4, 019444a5, 019444b2

Options:

  • --all — Include done/cancelled issues
  • --milestone <name> — Filter to a specific milestone

Legend: in-progress, pending, done, cancelled


chain status

Show project health: fever chart, gas mileage, buffer consumption.

Behavior:

  • Shows fever chart (% issues complete vs % buffer consumed)
  • Shows gas mileage (historical sessions per issue)
  • Shows buffer health per milestone
  • Shows tank capacity for date-constrained milestones

Output:

Chalk Parser [due: Apr 15 — 22 days left]

Progress: 2/5 issues done (40%)
Sessions: 3 consumed (gas mileage: 1.5 sessions/issue)
Buffer:   2.5 sessions (50% of 5 issues)
          0.5 sessions consumed (1 issue spilled)
Tank:     11 sessions available at current velocity

Fever chart:
  [====........] 40% progress
  [==..........] 20% buffer consumed
       ^ GREEN — ahead of burn rate

Self-Hosting [no due date]

Progress: 0/2 issues done
Buffer:   1 session (50% of 2 issues)
Tank:     unbounded (no due date)

Buffer status zones:

GREEN:  buffer burn % < progress %       (ahead of schedule)
YELLOW: buffer burn % ≈ progress %       (on track, watch closely)
RED:    buffer burn % > progress % + 20  (behind, consider cutting scope)

If buffer is in the red:

Fever chart:
  [===.........] 30% progress
  [========....] 70% buffer consumed
              ^ RED — burning faster than progress

Cut order (by urgency):
  019444a5 [low]  Full method modifier support
  019444a4 [low]  Error recovery

Recommendation: 60% of issues spill. Consider increasing session size
                or slicing issues thinner.

chain rebalance

Adjust milestone boundaries to fit tank capacity.

Behavior:

  • Examines gas mileage and remaining issues per milestone
  • For date-constrained milestones, checks whether current issues fit within the tank
  • Suggests moving issues to later milestones if over capacity
  • Suggests pulling issues forward if under capacity

Output:

Chalk Parser [due: Apr 15]
  Tank: 11 sessions at 1.5 sessions/issue = ~7 issues
  Current: 5 issues — fits with buffer

Self-Hosting [no due date]
  2 issues — no capacity constraint

No rebalancing needed.

If rebalancing is needed:

Chalk Parser [due: Apr 15]
  Tank: 6 sessions at 2.0 sessions/issue = ~3 issues
  Current: 5 issues — 2 over capacity

Suggested moves:
  019444a5 [low]  Full method modifier support → Self-Hosting
  019444a4 [low]  Error recovery → Self-Hosting

Apply? [y/N]

chain issue new <title> [--before <ref>] [--after <ref>] [--blocked-by <ref>] [--blocks <ref>] [--urgency <level>]

Create a new issue. Always appends to the end of the chain unless positioned with --before or --after.

Behavior:

  • Creates issue with UUIDv7 ID
  • Appends to end of chain by default (last position in last milestone)
  • --before/--after position relative to another issue
  • --blocked-by/--blocks wire up dependency edges
  • Opens $EDITOR for body if stdin is a terminal (skip with --no-edit)

Examples:

Quick capture:

$ git chain issue new "Fix heredoc edge case"
Created 019444c1: Fix heredoc edge case

Positioned with dependencies:

$ git chain issue new "Parse complex signatures" --urgency high --after 019444a2 --blocked-by 019444a2
Created 019444c2: Parse complex signatures
  After: 019444a2 (Parse basic sub declarations)
  Urgency: high
  Blocked by: 019444a2

Options:

  • --before <ref> — Position before another issue
  • --after <ref> — Position after another issue
  • --blocked-by <ref> — Add blocking dependency (repeatable)
  • --blocks <ref> — Add downstream dependency (repeatable)
  • --urgency <level> — Set urgency (high/moderate/low)
  • --milestone <name> — Assign to specific milestone (default: last milestone)
  • --body <text> — Issue body
  • --no-edit — Skip $EDITOR for body

chain issue list

List issues only (without milestone grouping).

Behavior:

  • Lists all open issues sorted by chain position
  • Shows state, urgency, and blocking status

Output:

  019444a1  [high]  Implement lexer                 ● in-progress
  019444a2  [high]  Parse basic sub declarations     ○ pending
  019444a3  [mod]   Parse signatures                 ○ pending
  019444a4  [low]   Error recovery                   ○ pending
  019444a5  [low]   Full method modifier support     ○ pending
  019444b1  [high]  Bootstrap compiler               ○ pending
  019444b2  [mod]   Test harness                     ○ pending

Options:

  • --all — Include done/cancelled issues
  • --milestone <name> — Filter to specific milestone
  • --state <state> — Filter by state (pending/in-progress/done/cancelled)

chain issue view <ref>

Show a single issue with full context.

Behavior:

  • Displays issue details plus dependency context
  • Shows position in critical chain (if applicable)
  • Shows session history

Output:

019444a2: Parse basic sub declarations

  State:      pending
  Milestone:  Chalk Parser (due Apr 15)
  Urgency:    high
  Created:    2026-03-14

  Blocked by:
    ✓ 019444a1  Implement lexer (done)

  Blocks:
    019444b1  Bootstrap compiler (pending)

  Sessions: (none yet)

  Chain position:
    019444a1 → [019444a2] → 019444b1
                ^^^^^^^^
    2nd in critical chain (next up)

  Body:
    Implement parsing for basic subroutine declarations
    without signatures. Handle `sub foo { }` form.

chain issue move <ref> --before/--after <other>

Reposition an issue in the chain.

Behavior:

  • Removes issue from current position (reconnects surrounding dependency edges)
  • Inserts at new position relative to the target issue

Example:

$ git chain issue move 019444a4 --before 019444a3
Moved 019444a4 (Error recovery): now before 019444a3 (Parse signatures)

chain issue block <ref> <blocked-by>

Add a dependency edge.

Behavior:

  • Adds blocked_by on the first issue, blocks on the second
  • Maintains bidirectional consistency

Output:

019444a2 blocked by 019444a1

chain issue unblock <ref> <blocked-by>

Remove a dependency edge.

Behavior:

  • Removes the relationship from both sides

Output:

019444a2 no longer blocked by 019444a1

chain issue split <ref>

Break an issue into two sequential parts.

Behavior:

  • Original issue becomes the first part
  • Creates new issue as second part (blocked by first)
  • Downstream dependencies transfer to second part by default
  • Both issues inherit milestone and urgency
  • Prompts for titles if not provided

Example:

$ git chain issue split 019444a2
Title for first part [Parse basic sub declarations (part 1)]: Parse basic signatures
Title for second part [Parse basic sub declarations (part 2)]: Parse complex signatures

Split 019444a2 into:
  019444a2 Parse basic signatures
   ↓
  019444d1 Parse complex signatures

Dependencies transferred: 019444b1 now blocked by 019444d1

Options:

  • --first-title <text> — Title for first part
  • --second-title <text> — Title for second part
  • --keep-deps — Downstream deps stay on first part

chain issue cancel <ref>

Cancel an issue (preserves history).

Behavior:

  • Sets state to cancelled
  • Removes from dependency chains (reconnects around it)
  • Issue remains in the ref history for audit trail

Output:

Cancelled 019444a5: Full method modifier support
  Reconnected: 019444a4 dependencies updated

chain issue remove <ref>

Delete an issue (only for erroneous data).

Behavior:

  • Physically removes the issue file from the tree
  • Only intended for data entry errors, not for descoping work (use cancel for that)
  • Requires --force flag as a safety check

Output:

$ git chain issue remove 019444a5 --force
Removed 019444a5: Full method modifier support (permanently deleted)

chain milestone list

List all milestones.

Behavior:

  • Shows milestones with issue counts and buffer health
  • Highlights current milestone (first with pending issues and earliest due date)

Output:

  Chalk Parser       due Apr 15    2/5 done    buffer: GREEN    ← current
  Self-Hosting       (no date)     0/2 done    buffer: —

chain milestone move

Reorder milestone boundaries.

Behavior:

  • Moves issues between milestones to redefine scope boundaries
  • Can move individual issues or redefine where one milestone ends and the next begins

Examples:

$ git chain milestone move 019444a5 --to "Self-Hosting"
Moved 019444a5 (Full method modifier support): Chalk Parser → Self-Hosting

chain milestone due <milestone> <date>

Attach or change an optional due date.

Behavior:

  • Sets or updates the due date on a milestone
  • Date format: YYYY-MM-DD or relative (2 weeks, friday, end of month)
  • Use --clear to remove the due date

Output:

Chalk Parser: due date → Apr 15
Self-Hosting: due date → May 30 (was: none)

chain handoff [milestone]

Check cross-milestone dependency readiness.

Behavior:

  • Lists cross-milestone dependencies (issues in this milestone blocked by issues in earlier milestones)
  • Shows which are complete vs still open
  • Warns if starting now would violate full kit principle

Output (ready):

Self-Hosting — Handoff Check

Cross-milestone dependencies:
  ✓ 019444a2  Parse basic sub declarations (Chalk Parser, done)

Full kit: Ready to start

Output (not ready):

Self-Hosting — Handoff Check

Cross-milestone dependencies:
  ✓ 019444a1  Implement lexer (Chalk Parser, done)
  ✗ 019444a2  Parse basic sub declarations (Chalk Parser, in-progress)

Full kit: NOT READY
  Blocked issues in Self-Hosting:
    019444b1 Bootstrap compiler ← waiting on 019444a2

Options:
  - Wait for 019444a2 to complete
  - Remove dependency from 019444b1
  - Work on non-blocked issues: 019444b2

chain session start [ref]

Begin working on an issue.

Behavior:

  • Sets issue state to in-progress
  • Records session start time
  • If no ref provided, starts a session on the next pending issue in the critical chain
  • Full kit check: warns if issue is blocked by pending issues

Output:

Started session on 019444a2: Parse basic sub declarations

If blocked:

⚠ 019444a2 is blocked by pending issues:
  019444a1 (Chalk Parser, in-progress)

Start anyway? [y/N]

chain session done [ref]

Complete an issue.

Behavior:

  • Sets issue state to done
  • Records session end time
  • Calculates whether this issue consumed buffer (>1 session)
  • If no ref provided, completes the current in-progress issue

Output:

Completed 019444a2: Parse basic sub declarations
  Session: 1h 15m
  Buffer impact: none (1 session)

If the issue took multiple sessions:

Completed 019444a3: Parse signatures
  Sessions: 2 (total 3h 40m)
  Buffer impact: 1 session consumed from buffer
  Buffer remaining: 1.5 / 2.5 sessions

chain sync

Explicit push/fetch of refs/chain/*.

Behavior:

  • Pushes local chain state to remote
  • Fetches remote chain state
  • Reports any updates

Output:

Synced refs/chain/state with origin
  Pushed: 3 new commits
  Fetched: 0 new commits

chain export [--format json|markdown]

Dump state for agents without CLI access.

Behavior:

  • Outputs complete chain state in the specified format
  • JSON: structured data suitable for programmatic access
  • Markdown: human-readable summary suitable for pasting into conversations

Output (--format json, abbreviated):

{
  "milestones": [
    {
      "name": "Chalk Parser",
      "due": "2026-04-15",
      "issues": [
        {
          "id": "019444a1-b2c3-7def-8901-234567890abc",
          "title": "Implement lexer",
          "state": "done",
          "urgency": "high",
          "blocked_by": [],
          "blocks": ["019444a2-..."],
          "sessions": [{"started": "...", "ended": "..."}]
        }
      ]
    }
  ],
  "gas_mileage": 1.5,
  "buffer": {"total": 2.5, "consumed": 0.5}
}

chain log [issue-ref]

Show audit trail from ref commit history.

Behavior:

  • Without argument: shows all chain mutations in chronological order
  • With issue ref: shows history of changes to that specific issue

Output:

$ git chain log 019444a2
2026-03-14 10:30  Created: "Parse basic sub declarations" (pending)
2026-03-14 14:00  Added dependency: blocked by 019444a1
2026-03-15 09:00  Session started
2026-03-15 10:15  State changed: pending → in-progress
2026-03-15 11:30  Session completed (1h 15m)
2026-03-15 11:30  State changed: in-progress → done

chain help [command]

Show usage information for humans and agents.

Behavior:

  • Without arguments, shows overview of all commands
  • With command name, shows detailed help for that command
  • Output is structured for both human reading and LLM parsing

Output (no arguments):

git-chain: Critical Chain project management, local to your git repo

SETUP
  chain init                          Set up repo, install hooks, configure sync
  chain add <title>                   Create chain (first time) or add milestone

ISSUE COMMANDS
  chain issue new <title>             Create an issue
  chain issue list                    List issues
  chain issue view <ref>              Show issue with full context
  chain issue move <ref> --before/--after <other>   Reposition in chain
  chain issue block <ref> <by>        Add dependency edge
  chain issue unblock <ref> <by>      Remove dependency edge
  chain issue split <ref>             Break into two sequential issues
  chain issue cancel <ref>            Cancel (preserves history)
  chain issue remove <ref>            Delete (erroneous data only)

SESSION COMMANDS
  chain session start [ref]           Begin working on an issue
  chain session done [ref]            Complete an issue

MILESTONE COMMANDS
  chain milestone list                List milestones
  chain milestone move                Reorder milestone boundaries
  chain milestone due <name> <date>   Attach/change due date
  chain handoff [milestone]           Check cross-milestone readiness

VISUALIZATION
  chain list [--graph] [--critical]   Show full chain
  chain status                        Fever chart, gas mileage, buffer health
  chain rebalance                     Adjust milestones to fit capacity

DATA
  chain sync                          Push/fetch refs/chain/*
  chain export [--format json|md]     Dump state for agents
  chain log [ref]                     Audit trail

Run 'chain help <command>' for detailed usage.

Commit Hook Integration

The post-commit hook installed by chain init scans commit messages for:

  • closes <ref> or finishes <ref> — completes the referenced issue (equivalent to chain session done <ref>)
  • starts <ref> — begins a session on the referenced issue (equivalent to chain session start <ref>)

References can be truncated UUIDv7 prefixes (e.g., closes 019444a2).

Opt-out via config.yml: hooks.post_commit: false

Agent Access

Three layers, from most to least integrated:

  1. CLI commands (preferred). If git-chain is installed, agents use git chain directly. All commands support --no-edit and produce parseable output.
  2. chain export — dump complete state as JSON or markdown for agents without CLI access. Paste into conversation context.
  3. Direct ref access via git show — documented as Claude Code Skills. Read individual issues with git show refs/chain/state:issues/<id>.md. No chain binary needed.

Technical Requirements

Dependencies

  • Go 1.22+ (build-time only)
  • git (runtime — for ref manipulation)
  • No runtime dependencies beyond git itself

Installation

go install github.com/perigrin/git-chain@latest

Or download a prebuilt binary from releases (place git-chain on your $PATH).

Build

git clone https://github.com/perigrin/git-chain
cd git-chain
go build -o git-chain .

Configuration

None required. git chain init creates config.yml in the ref tree with sensible defaults. All configuration is optional and lives inside refs/chain/state, not in the working tree.

Migration from Original Design

The following commands from the original GitHub-backed design have been renamed, merged, or removed:

Original Command New Equivalent Reason
chain triage (removed) No triage state; issues are always in the chain
chain scope <id> chain issue move / chain milestone move Position determines milestone; move to reposition
chain start <id> chain session start [ref] Renamed for clarity; session is the core concept
chain done <id> chain session done [ref] Renamed for consistency with session model
chain new <title> chain issue new <title> Moved under issue subcommand
chain milestone new chain add <title> Simplified; creates chain or adds milestone
chain milestone close (removed) Milestones complete when all issues are done
chain critical chain list --critical Merged into chain list as a flag
chain graph chain list --graph Merged into chain list as a flag
chain insert chain issue new --before/--after Merged into issue creation
chain splice chain issue cancel Cancel reconnects deps; splice was a special case
chain blocks chain issue view View shows full dependency context
chain urgency chain issue new --urgency / edit frontmatter Set at creation or edit directly

Future Considerations

Not in v0.1, but worth noting:

  1. External tracker sync — Bidirectional sync with GitHub Issues, Jira, and GitLab Issues. The local git-chain state remains authoritative; sync pushes/pulls state to external trackers for team visibility. Would support teams where not everyone uses git-chain directly.
  2. Agentic code integration — Claude Code plugin with skills for common workflows (/chain-status, /chain-next), MCP server exposing chain state as tools, and direct ref access documented as Claude Code Skills. Would let agents manage project state without shelling out to the CLI.
  3. Resource contention detection — True critical chain includes resource dependencies. If same person is assigned to parallel tasks, warn they're actually sequential.
  4. Resource buffers — Goldratt's "early warning" system. Alert when you're about to need a specific person/skill for critical chain work, so they can prepare.
  5. HTML export — Generate shareable fever chart and Gantt-style visualization for stakeholder updates.
  6. Multi-repo chains — Cross-repo dependencies using remote refs. One chain spanning multiple repositories.
  7. Fever chart history — Track buffer burn over time using the commit history on the ref. Would enable trend analysis: "buffer burn accelerating."
  8. Interactive rebalance — TUI for drag-and-drop milestone boundary adjustment.

Success Criteria

The tool is successful if:

  1. Time from "I have an idea" to "it's captured as an issue" is under 10 seconds (chain issue new)
  2. Daily workflow (chain list, chain session start, chain session done) requires no browser and no network
  3. Project health is visible at a glance (chain status)
  4. Zero configuration required after chain init
  5. Cross-milestone dependencies and handoff readiness are explicit (chain handoff)
  6. Works completely offline; syncs transparently when connectivity returns
  7. A human or agent can learn the tool from chain help alone
  8. An agent without the CLI can access state via git show or chain export
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment