Planning
Most forges treat project management as an afterthought: issues with labels, and a board bolted on. Teams that want real planning run a second tool alongside and then spend their time keeping the two in sync.
neosource treats planning as a first-class surface with the same weight as the repository. This page describes the model — the two kinds of work item, and how a change links back to the work it belongs to.
Two tracks: tickets and issues
Section titled “Two tracks: tickets and issues”This is the load-bearing difference, and everything else follows from it.
Every work item has a team. A repository is optional, and whether it is set is what separates the two tracks:
| Kind | Repository | Numbered as | Example | What it is |
|---|---|---|---|---|
| Ticket | none | team key | ENG-7 |
the team’s own planning work |
| Issue | set | repo number | api#42 |
intake against one repository |
A ticket is what a team files for itself: the work it has decided to do,
living on the team board, drawn from the team’s own sequence and carrying the
team key, which matches ^[A-Z][A-Z0-9]{1,5}$.
An issue is intake against one repository — a bug report, a request from
outside the team, something automation filed. It draws its number from the same
sequence as that repository’s pull requests, so #42 is unambiguous within a
repo.
The reason tickets exist at all is that real planning work frequently spans several repositories, or none. “Migrate the auth flow” touches four services; “decide the retention policy” touches zero. Neither has a natural home in a repository-scoped tracker, and forcing one is how planning ends up in a second product.
Each kind has one home. A team’s Board is its tickets; a repository’s issue list is its issues. The two are joined rather than merged: a ticket can formally track the issues it subsumes, so a team plans an incoming report by filing the ticket that tracks it and works the ticket.
Status and priority
Section titled “Status and priority”Status is a fixed set, not a per-repo vocabulary, and it is the same set for both kinds:
backlog · todo · in_progress · in_review · done · cancelled ·
duplicate
The last three are terminal — they close the item. done, cancelled and
duplicate are distinguished deliberately: “we shipped it”, “we decided not
to” and “this was already filed” are different outcomes, and collapsing them
into one closed state destroys the only signal that tells you which.
Priority is none · urgent · high · medium · low, defaulting to
none.
Cycles
Section titled “Cycles”A cycle is a team-scoped planning window with a start and an end — a sprint, an iteration, whatever your team calls it. A ticket or issue binds to at most one cycle.
Cycles belong to the team rather than to a repository, which is the same argument as above: a two-week window covers whatever that team is working on, and that is rarely one repo’s worth of work.
Labels
Section titled “Labels”A label is scoped to either a repository or a team, never both. Repo labels sort a repository’s own issues and PRs; team labels sort the team’s tickets and whatever cross-cutting work it has picked up.
Issue links
Section titled “Issue links”Tickets and issues relate to each other through typed links. Every link is stored with its inverse, so the relationship reads correctly from both ends:
| Link | Inverse |
|---|---|
blocks |
blocked_by |
related |
related |
duplicate_of |
duplicates |
tracks |
tracked_by |
blocks is the one with behaviour attached: an item with an unresolved
blocked_by link carries a blocked flag, maintained by the system rather
than by someone remembering to set it. When the blocker closes, the flag is
recomputed.
tracks is the link that joins the two tracks, and it is the one with a
direction the product constrains: a ticket tracks an issue, never the
reverse. A team that decides to take on a repo issue links the ticket to it
rather than copying the text into a second item — so the reporter keeps their
issue and the team keeps its plan, and the two stay one relationship rather
than two lists someone reconciles. tracked_by is only ever the inverse row
the system writes.
Linking a change to the work
Section titled “Linking a change to the work”This is where planning being in the forge stops being a filing convention.
Write a linking verb in a pull request body and the link becomes a fact the system holds:
Fixes #42Closes ENG-7Part of #13Two families of verb, differing in whether they move the item:
| Verbs | Link kind | Effect |
|---|---|---|
fixes, closes, resolves |
fixes |
moves the item (below) |
refs, references, part of |
references |
advisory backlink only |
Verbs are matched case-insensitively and may appear anywhere in the body — at
the start of a line, mid-sentence, in a list. Fixes: #42 and Fixes — #42
both parse.
References take three forms: #42 for an issue in the PR’s own repository,
KEY-7 for a ticket in the PR’s workspace, and acme/api#42, which parses but
currently links only when it names the PR’s own repo. Cross-repo and
cross-workspace linking are not yet supported.
What a fixes link does
Section titled “What a fixes link does”- When the PR is opened or its body is edited — a ticket or issue sitting
in
todoorbacklogmoves toin_progress. One already further along is left alone, so re-parsing a body never drags anything backwards. - When the PR merges — it closes as
done, attributed to the PR’s author, unless it is already in a terminal status. Something someone deliberately markedcancelledorduplicateis not resurrected and re-closed.
A references link never transitions anything. It exists so “this work is
part of that” is recorded without asserting that merging finishes it.
The payoff is that the connection between a change and the work it belongs to is something the system knows, rather than a convention you maintain by pasting URLs between two products.
Where this stops
Section titled “Where this stops”- This is planning for engineering teams. It is not a general-purpose work tracker and is not trying to replace company-wide project management.
- Cross-repo and cross-workspace references are not implemented. The
acme/api#42form parses but resolves only within the PR’s own repository. - Issue links relate items to items; there is no dependency graph across cycles or teams.
If you are importing from GitHub, its issues arrive as issues on the repository they came from, and can be kept in sync — GitHub keeps the conversation, neosource holds the planning overlay on top. Filing them as tickets would be the wrong shape: they are intake against a repo, and a ticket is a team’s own plan. See Migrating from GitHub.
See also
Section titled “See also”- Code review — what happens to the change itself.
- Project status — what is ready today.