issues-fs.sgit.ai / start

Five minutes with the CLI

Install, initialise, create two nodes, link them, read them back — as a human and as an agent. Every command below exists in issues-fs-cli 0.3.0, checked against its source rather than against a README, and each step says what it writes to disk.

If you have no Python, stop here and go to /lite/five-minutes.html instead. Issues-FS-lite needs no install at all — three folders and four mv operations. This page is the full mode, which buys you typed relationships and costs you a dependency.

1 · Install

pip install issues-fs-cli

That gives you the issues-fs console script. Python 3.12 or newer. The package pulls in issues-fs, the core library, as a dependency — you do not install both.

2 · Initialise a graph

$ cd your-project
$ issues-fs init

Creates a .issues/ directory in the current folder. Use --path (or -p) to put it somewhere else. From then on, every command works from anywhere inside the tree: CLI__Context.discover_issues_root() walks up from the working directory looking for a .issues/, the same way git finds a .git/.

3 · Load the type system

$ issues-fs types init

Writes the default type registry into .issues/config/: 12 node types and 10 link types. This is the step that makes the rest a graph rather than a folder of files — an edge type is not a free string, it is a verb with a declared inverse and a declared set of node types it may join.

$ issues-fs types list
git-repo · bug · task · feature · person · project · phase
research · spike · security-review · threat-model · question

$ issues-fs link-types list
blocks/blocked-by · has-task/task-of · assigned-to/assignee-of
depends-on/dependency-of · contains/contained-by · has-project/project-of
has-phase/phase-of · has-feature/feature-of · asks/asked-by · (and one more)

The tenth pair is relates-to/relates-to — a self-inverse the wider corpus explicitly forbids, shipped in the default config anyway. That tension, narrated rather than hidden.

4 · Create two nodes

$ issues-fs create task "Write the /shipped page" --priority high --tags site,docs
Task-1

$ issues-fs create bug "PyPI badge 404s in the Docs README"
Bug-1

Two things happened per node. A JSON file was written under .issues/, keyed by a 10-character GUID that you will never type. And a human label was generated — Task-1, Bug-1 — from the node's type and a per-type counter, which is what every other command takes as an argument. Two identities per node, and why.

⚠️ -p is overloaded. On init it is --path. On create and update it is --priority. It is a real wart and it is documented here rather than hidden, because the failure mode is silent: issues-fs create task "…" -p . sets the priority to . rather than doing anything with a path.

$ issues-fs link Task-1 blocks Bug-1

That one command wrote to two files. Edges in Issues-FS are stored on both endpoints — blocks on Task-1, and its declared inverse blocked-by on Bug-1. There is no separate edge store to consult and no join to perform: whichever node you load, its relationships are already in your hand. It is also why counting link entries in a live graph gives you roughly twice the number of logical relationships. The edge schema.

6 · Read it back

$ issues-fs list --output table
$ issues-fs list --type bug --status open
$ issues-fs show Task-1 --depth 1        # the node and everything one hop away
$ issues-fs links Task-1                 # just the relationships

Three output formats: table (the default), json and markdown, selected with --output/-o.

7 · The same thing, for an agent

$ issues-fs list --for-agent
$ issues-fs show Task-1 --depth 2 --for-agent

--for-agent is available on every one of the 14 commands and forces JSON regardless of the configured output format. It is not a mode you enter — it is a flag you add to whatever you were already doing, which means an agent and a human can run the same command and each gets a form they can use. All 14 commands, with their real flags.

8 · Commit it

$ git add .issues
$ git commit -m "track the site build in the site's own repo"

This is the point of the whole design. The tracker is inside the repository it tracks, so it branches with it, merges with it, and travels with a clone. A pull request that changes code and closes an issue is one diff. Nothing needs to be running for any of that to be true.

The whole thing

pip install issues-fs-cli
issues-fs init
issues-fs types init
issues-fs create task "Write the /shipped page" --priority high --tags site,docs
issues-fs create bug  "PyPI badge 404s in the Docs README"
issues-fs link Task-1 blocks Bug-1
issues-fs list --output table
issues-fs show Task-1 --depth 1
issues-fs list --for-agent
git add .issues && git commit -m "..."

Where to go next

The 14 commands →

Every command with its positional arguments and real flags, the three output formats, and the two warts worth knowing.

The data model →

What a node is, what an edge is, how labels are generated, and the five regex-validated primitives underneath.

A real graph →

The live 71-node graph from SGraph Send, with the node-type and link-type configs as downloads.

The .issues DSL →

A third way to author nodes — a line-oriented text format, parsed into the same graph. Built, tested and undocumented until this site.

For an agent

pip install issues-fs-cli gives you the issues-fs command. issues-fs init then issues-fs types init. Create with issues-fs create <node_type> "<title>" — it prints the label (Task-1) that every other command takes. Link with issues-fs link <source> <verb> <target>; the inverse is written automatically on the other endpoint. Add --for-agent to any command to force JSON. Commands work from anywhere inside the tree — the CLI walks up to find .issues/. Watch -p: it means --path on init and --priority on create and update; prefer the long forms.