Vibecode Shortcut
track this build4 phases, 12 steps, beginner friendly0%The core loop is buildable, but a dependable replacement becomes a real weekend or multi-day project. For Shortcut, manage software stories, epics, iterations, roadmaps, and engineering workflows. The hard boundary is git integrations, reporting, collaboration, and mature agile project semantics, plus collaboration, integrations, and organizational trust.
You are building a lean indie version of Shortcut. Create the following project files first, then implement the application by following them. Keep the files updated as decisions change. Do not collapse this into a single README or prompt. ===== README.md ===== # Shortcut · indie build A software project tracker where the interesting problems are keeping the board fast at ten thousand items, making workflow states mean something specific, and reporting progress in a way that does not quietly become a productivity measurement of individuals. Estimated effort: **multi-day**. Work `BUILD_PLAN.md` top to bottom · every phase ends in a check that has to pass before the next one starts. ## Stack | Part | Choice | Why | | --- | --- | --- | | Runtime | TypeScript with Fastify and PostgreSQL | items, states and history are relational and query heavy | | History | Every state transition recorded, append only | cycle time and flow are derived from transitions, not from a current state | | Hierarchy | Stories, epics and iterations as separate concerns | conflating them produces a hierarchy nobody can query | | Search | Indexed queries with saved views | at ten thousand items, finding things is the product | | Reporting | Flow metrics at the level of work rather than of people | the same data measures a process or a person and the choice matters | ## Before you start Have every one of these ready. The plan assumes them from step one. - [ ] **Node.js 22 or newer** · free - Why: Runs the server and the query layer. - Get it: nodejs.org, or nvm install 22. - Verify: node --version prints v22 or higher - [ ] **PostgreSQL 16 or newer** · free locally - Why: Ten thousand items with fast filtered queries and an append-only transition log. - Get it: Docker or your package manager. - Verify: A filtered query over ten thousand rows returns within your stated time - [ ] **Ten thousand realistic items** · free - Why: Board performance, pagination stability and ordering all behave completely differently at the scale a team reaches within a year. - Get it: Generate or import a realistic dataset with varied states, epics and a long transition history. - Verify: Ten thousand items exist with several transitions each - [ ] **Your states and their definitions** · free, and it takes a team conversation - Why: Each state needs a written meaning before the first metric is computed, since a workflow assembled by accretion produces numbers nobody can interpret. - Get it: Agree the states with the team, write one sentence per state, and mark which mean started and which mean done. - Verify: Every state has a written definition and explicit started and done properties - [ ] **Your position on individual metrics** · free - Why: The build excludes per-person reporting deliberately, and someone will ask for it, so the reasoning needs to exist before the request rather than after. - Get it: Write down why per-person throughput is not offered and what you will point people at instead. - Verify: A written note exists and appears where someone would look for the feature ## Quick start Follow Phase 1 in `BUILD_PLAN.md`; it creates the project. Then copy `.env.example` to `.env` and fill in the values it documents. ## Honest limits This build deliberately does not replace: - Estimation and velocity forecasting. - Portfolio and resource planning. - Deep development tool integrations. - Per-person productivity reporting. - Git integrations, reporting, collaboration, and mature agile project semantics - deep integrations - enterprise permissions - large-scale reporting - battle-tested notifications and mobile apps If one of those is essential to you, that is the reason to keep paying for Shortcut, and the README should say so rather than pretend. ===== BRIEF.md ===== # Build brief · Shortcut The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me issue tracking where the workflow reflects how work actually moves to replace Shortcut. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Stack (fixed, do not substitute) - Runtime: TypeScript with Fastify and PostgreSQL · items, states and history are relational and query heavy - History: Every state transition recorded, append only · cycle time and flow are derived from transitions, not from a current state - Hierarchy: Stories, epics and iterations as separate concerns · conflating them produces a hierarchy nobody can query - Search: Indexed queries with saved views · at ten thousand items, finding things is the product - Reporting: Flow metrics at the level of work rather than of people · the same data measures a process or a person and the choice matters ### Data model (create this before Phase 1) - stories(id, title, description, state_id, epic_id, iteration_id, estimate, created_at, archived_at) - states(id, name, kind, ordinal, is_started, is_done) · kind names what the state means rather than only its position - transitions(id, story_id, from_state_id, to_state_id, actor_id, at) · append only, the basis of every metric - epics(id, name, state_id, target_date, archived_at) and iterations(id, name, starts_on, ends_on) - links(from_story_id, to_story_id, kind) · blocks, relates or duplicates - saved_views(id, owner_id, query_json, shared) · because a query used daily should not be retyped - Metrics derive from the transition log rather than from a story's current state, so moving an item backwards produces correct history rather than a corrupted measurement. ### Phase 1 · States that mean something Build: Configurable states with a kind marking whether work has started and whether it is done. Record every transition append only. Detect a state nothing ever moves out of and a state nothing ever enters. Trap: A workflow with a state called in progress and another called in development, added at different times by different people, produces metrics that are meaningless because half the work skips one. Require each state to have a written definition and report states that are never used, so the workflow gets pruned rather than accumulating. Done when: Every state has a written definition visible where the state is used. Started and done are explicit properties rather than inferred from position. Transitions are append only and a story moved backwards produces two transitions rather than an edit. States never entered or never left are reported. Do not build yet: No board, hierarchy, search or reporting. ### Phase 2 · A board that stays fast Build: A board and list view over indexed queries with pagination that does not lose position. Support saved views. Measure load and filter time at ten thousand items rather than at a hundred. Trap: Loading every story to render a board works beautifully in a demonstration and becomes unusable at the scale a real team reaches within a year, which is exactly when moving away is most expensive. Paginate and index from the start, and test against a generated ten thousand item dataset. Done when: A board with ten thousand items loads and filters within a stated time, measured. Pagination does not lose scroll position or duplicate items when the underlying data changes. Saved views are shareable and reflect the current query. Reordering within a state persists without rewriting every item's position. Do not build yet: No hierarchy, links or reporting yet. ### Phase 3 · Hierarchy without a hierarchy problem Build: Epics grouping stories toward an outcome and iterations grouping them by time, as separate concerns. Derive epic progress from its stories rather than tracking it separately. Handle a story moving between iterations mid-flight. Trap: Tracking an epic's state separately from its stories produces an epic marked done containing three open stories, and nobody trusts either number afterwards. Derive the epic's progress from its children and let its own state express intent rather than completion. Done when: Epic progress derives from its stories rather than being set independently. A story moving between iterations is recorded and its original iteration's history is not rewritten. An epic with no stories is distinguishable from one whose stories are all complete. Iterations do not force a story to belong to exactly one, or the rule is stated. Do not build yet: No reporting or integration yet. ### Phase 4 · Flow metrics, not people metrics Build: Cycle time and throughput derived from the transition log, reported as distributions. Report at the level of work types and states rather than per person. Make per-person breakdowns absent rather than optional. Trap: Any per-person throughput chart becomes a performance measurement within a quarter regardless of how it was introduced, and the immediate effect is that people split tickets to raise their count. Do not build it, and say why in the interface where someone would look for it. Done when: Cycle time and throughput are reported as distributions from the transition log. No per-person productivity breakdown exists anywhere, verified by looking for one. Metrics are correct for a story moved backwards through states. A story reopened after completion is handled by a stated rule rather than distorting the cycle time. Do not build yet: No integration or archiving yet. ### Phase 5 · Connecting to the work itself Build: Link stories to branches and changes through references, updating state on a declared trigger rather than guessing. Archive rather than delete, keeping transitions. Export everything including history. Trap: Automatically moving a story to done when a branch merges is right most of the time and wrong in exactly the cases that matter, such as a merge behind a flag or a partial implementation. Make the transition explicit in the commit or the merge, so closing a story is a decision someone made rather than an inference. Done when: Stories link to code references and state changes require an explicit declaration rather than being inferred from a merge. Archiving preserves transitions and metrics remain correct for archived work. Export contains stories, transitions, epics and iterations and re-imports identically. A deleted branch does not orphan its story link. Do not build yet: Nothing after this. ### Out of scope (and why) - Estimation and velocity forecasting, which is where trackers make claims their data does not support. - Portfolio and resource planning across teams, which is a different product with different politics. - Deep integrations with every development tool, which is the hosted product's actual value. - Per-person productivity reporting, which is excluded deliberately rather than omitted. ### README must contain - That every workflow state has a written definition, since states accumulate and metrics stop meaning anything - That metrics derive from the append-only transition log rather than from current state - That epic progress derives from its stories, so an epic cannot be done with open children - That no per-person productivity view exists, because it becomes a performance measure regardless of intent - That state changes from code require an explicit declaration rather than being inferred from a merge ===== AGENTS.md ===== # Agent instructions · Shortcut indie build - Read `README.md` and `BUILD_PLAN.md` before writing code. The stack is fixed: TypeScript with Fastify and PostgreSQL, Every state transition recorded, append only, Stories, epics and iterations as separate concerns, Indexed queries with saved views, Flow metrics at the level of work rather than of people. Do not substitute. - Work one phase at a time, in order. Do not start a phase until every "Done when" item of the previous one passes. - Prefer the fewest moving parts that satisfy the step. No frameworks, services or dependencies the plan does not name. - Secrets live in `.env`, never in source or logs. Keep `.env.example` current when a variable is introduced. - Do not invent cryptography, security guarantees, APIs or compliance claims. - Add a focused test for every destructive, security-sensitive or data-loss path the plan names. - Run the project checks before declaring a phase complete, and record any deliberate shortcut in the README under "Tradeoffs". ## Known traps - A workflow with a state called in progress and another called in development, added at different times by different people, produces metrics that are meaningless because half the work skips one. Require each state to have a written definition and report states that are never used, so the workflow gets pruned rather than accumulating. - Loading every story to render a board works beautifully in a demonstration and becomes unusable at the scale a real team reaches within a year, which is exactly when moving away is most expensive. Paginate and index from the start, and test against a generated ten thousand item dataset. - Tracking an epic's state separately from its stories produces an epic marked done containing three open stories, and nobody trusts either number afterwards. Derive the epic's progress from its children and let its own state express intent rather than completion. - Any per-person throughput chart becomes a performance measurement within a quarter regardless of how it was introduced, and the immediate effect is that people split tickets to raise their count. Do not build it, and say why in the interface where someone would look for it. ===== BUILD_PLAN.md ===== # Build plan · Shortcut A software project tracker where the interesting problems are keeping the board fast at ten thousand items, making workflow states mean something specific, and reporting progress in a way that does not quietly become a productivity measurement of individuals. Phases are in dependency order. Each ends in a "Done when" list; treat an unticked item as a blocker, not a note. ## Phase 1 · States that mean something Every workflow state has a definition the team agreed on. ### Steps 1. Mark started and done explicitly Inferring from column position breaks the first time someone reorders. Files: `src/states.ts` 2. Record transitions append only Every metric derives from them, so an edit would rewrite history. Files: `src/transitions.ts` 3. Report unused states Workflows accumulate states nobody remembers adding. Files: `src/workflow-health.ts` ### Done when - [ ] Every state has a visible definition - [ ] Started and done are explicit properties - [ ] Backward moves create transitions rather than edits - [ ] Unused states are reported ### Watch out - A workflow with a state called in progress and another called in development, added at different times by different people, produces metrics that are meaningless because half the work skips one. Require each state to have a written definition and report states that are never used, so the workflow gets pruned rather than accumulating. ## Phase 2 · A board that stays fast Ten thousand items load, filter and reorder without waiting. ### Steps 1. Index and paginate from the start The scale a team reaches is the scale a rewrite is most expensive. Files: `src/queries.ts` 2. Keep pagination stable under change Items moving while you page is the normal case on a live board. Files: `src/pagination.ts` 3. Order without rewriting everything A fractional or sparse ordering rather than sequential integers. Files: `src/ordering.ts`, `src/ordering.test.ts` ### Done when - [ ] Ten thousand items load and filter within a stated time - [ ] Pagination is stable under concurrent change - [ ] Saved views are shareable and current - [ ] Reordering does not rewrite every item ### Watch out - Loading every story to render a board works beautifully in a demonstration and becomes unusable at the scale a real team reaches within a year, which is exactly when moving away is most expensive. Paginate and index from the start, and test against a generated ten thousand item dataset. ## Phase 3 · Hierarchy without a hierarchy problem Epics and iterations organise work without becoming a second workflow. ### Steps 1. Derive epic progress from stories An epic marked done with open children destroys trust in both. Files: `src/epics.ts` 2. Keep iteration history intact on a move Moving a story out should not erase that it was in. Files: `src/iterations.ts` 3. Separate time grouping from outcome grouping Conflating them produces a hierarchy nobody can query. Files: `src/hierarchy.ts` ### Done when - [ ] Epic progress derives from its stories - [ ] Moving between iterations preserves history - [ ] Empty and complete epics are distinguishable - [ ] Iteration membership rules are stated ### Watch out - Tracking an epic's state separately from its stories produces an epic marked done containing three open stories, and nobody trusts either number afterwards. Derive the epic's progress from its children and let its own state express intent rather than completion. ## Phase 4 · Flow metrics, not people metrics Reporting describes how work moves rather than how fast individuals are. ### Steps 1. Derive metrics from transitions Current state cannot tell you how long anything took. Files: `src/metrics.ts`, `src/metrics.test.ts` 2. Report distributions by work type The tail is where the process problems are. Files: `src/metrics.ts` 3. Build no per-person productivity view It becomes a performance measure within a quarter regardless of intent. Files: `tests/no-person-metrics.test.ts` ### Done when - [ ] Cycle time and throughput derive from transitions - [ ] No per-person productivity breakdown exists - [ ] Backward moves produce correct metrics - [ ] Reopened stories follow a stated rule ### Watch out - Any per-person throughput chart becomes a performance measurement within a quarter regardless of how it was introduced, and the immediate effect is that people split tickets to raise their count. Do not build it, and say why in the interface where someone would look for it. ## Not in this build - Estimation and velocity forecasting. - Portfolio and resource planning. - Deep development tool integrations. - Per-person productivity reporting. ## After v1, if you want it - Blocked time as a first-class measurement, which is where most cycle time actually goes - A cumulative flow view, which the transition log already supports - Work type classification so cycle times are compared like with like ===== .env.example ===== # Copy to .env and fill in. Never commit .env; this file documents it. # Required · secret. Stories, transitions and team activity. DATABASE_URL=postgres://localhost:5432/tracker # Required. Pagination is required at real scale, not an optimisation. BOARD_PAGE_SIZE=100 # Required. Measured at ten thousand items rather than at a hundred. BOARD_LOAD_TARGET_MS=500 # Required. Present as a constant. It becomes a performance measure regardless of intent. PER_PERSON_METRICS=never # Required. A merge behind a flag is not a completed story. AUTO_TRANSITION_ON_MERGE=never # Required. Transitions are the metric history and outlive the stories. ARCHIVE_RETENTION_YEARS=7
You are building a lean indie version of Shortcut. Create the following project files first, then implement the application by following them. Keep the files updated as decisions change. Do not collapse this into a single README or prompt. ===== README.md ===== # Shortcut · indie build A software project tracker where the interesting problems are keeping the board fast at ten thousand items, making workflow states mean something specific, and reporting progress in a way that does not quietly become a productivity measurement of individuals. Estimated effort: **multi-day**. Work `BUILD_PLAN.md` top to bottom · every phase ends in a check that has to pass before the next one starts. ## Stack | Part | Choice | Why | | --- | --- | --- | | Runtime | TypeScript with Fastify and PostgreSQL | items, states and history are relational and query heavy | | History | Every state transition recorded, append only | cycle time and flow are derived from transitions, not from a current state | | Hierarchy | Stories, epics and iterations as separate concerns | conflating them produces a hierarchy nobody can query | | Search | Indexed queries with saved views | at ten thousand items, finding things is the product | | Reporting | Flow metrics at the level of work rather than of people | the same data measures a process or a person and the choice matters | ## Before you start Have every one of these ready. The plan assumes them from step one. - [ ] **Node.js 22 or newer** · free - Why: Runs the server and the query layer. - Get it: nodejs.org, or nvm install 22. - Verify: node --version prints v22 or higher - [ ] **PostgreSQL 16 or newer** · free locally - Why: Ten thousand items with fast filtered queries and an append-only transition log. - Get it: Docker or your package manager. - Verify: A filtered query over ten thousand rows returns within your stated time - [ ] **Ten thousand realistic items** · free - Why: Board performance, pagination stability and ordering all behave completely differently at the scale a team reaches within a year. - Get it: Generate or import a realistic dataset with varied states, epics and a long transition history. - Verify: Ten thousand items exist with several transitions each - [ ] **Your states and their definitions** · free, and it takes a team conversation - Why: Each state needs a written meaning before the first metric is computed, since a workflow assembled by accretion produces numbers nobody can interpret. - Get it: Agree the states with the team, write one sentence per state, and mark which mean started and which mean done. - Verify: Every state has a written definition and explicit started and done properties - [ ] **Your position on individual metrics** · free - Why: The build excludes per-person reporting deliberately, and someone will ask for it, so the reasoning needs to exist before the request rather than after. - Get it: Write down why per-person throughput is not offered and what you will point people at instead. - Verify: A written note exists and appears where someone would look for the feature ## Quick start Follow Phase 1 in `BUILD_PLAN.md`; it creates the project. Then copy `.env.example` to `.env` and fill in the values it documents. ## Honest limits This build deliberately does not replace: - Estimation and velocity forecasting. - Portfolio and resource planning. - Deep development tool integrations. - Per-person productivity reporting. - Git integrations, reporting, collaboration, and mature agile project semantics - deep integrations - enterprise permissions - large-scale reporting - battle-tested notifications and mobile apps If one of those is essential to you, that is the reason to keep paying for Shortcut, and the README should say so rather than pretend. ===== BRIEF.md ===== # Build brief · Shortcut The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me issue tracking where the workflow reflects how work actually moves to replace Shortcut. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Stack (fixed, do not substitute) - Runtime: TypeScript with Fastify and PostgreSQL · items, states and history are relational and query heavy - History: Every state transition recorded, append only · cycle time and flow are derived from transitions, not from a current state - Hierarchy: Stories, epics and iterations as separate concerns · conflating them produces a hierarchy nobody can query - Search: Indexed queries with saved views · at ten thousand items, finding things is the product - Reporting: Flow metrics at the level of work rather than of people · the same data measures a process or a person and the choice matters ### Data model (create this before Phase 1) - stories(id, title, description, state_id, epic_id, iteration_id, estimate, created_at, archived_at) - states(id, name, kind, ordinal, is_started, is_done) · kind names what the state means rather than only its position - transitions(id, story_id, from_state_id, to_state_id, actor_id, at) · append only, the basis of every metric - epics(id, name, state_id, target_date, archived_at) and iterations(id, name, starts_on, ends_on) - links(from_story_id, to_story_id, kind) · blocks, relates or duplicates - saved_views(id, owner_id, query_json, shared) · because a query used daily should not be retyped - Metrics derive from the transition log rather than from a story's current state, so moving an item backwards produces correct history rather than a corrupted measurement. ### Phase 1 · States that mean something Build: Configurable states with a kind marking whether work has started and whether it is done. Record every transition append only. Detect a state nothing ever moves out of and a state nothing ever enters. Trap: A workflow with a state called in progress and another called in development, added at different times by different people, produces metrics that are meaningless because half the work skips one. Require each state to have a written definition and report states that are never used, so the workflow gets pruned rather than accumulating. Done when: Every state has a written definition visible where the state is used. Started and done are explicit properties rather than inferred from position. Transitions are append only and a story moved backwards produces two transitions rather than an edit. States never entered or never left are reported. Do not build yet: No board, hierarchy, search or reporting. ### Phase 2 · A board that stays fast Build: A board and list view over indexed queries with pagination that does not lose position. Support saved views. Measure load and filter time at ten thousand items rather than at a hundred. Trap: Loading every story to render a board works beautifully in a demonstration and becomes unusable at the scale a real team reaches within a year, which is exactly when moving away is most expensive. Paginate and index from the start, and test against a generated ten thousand item dataset. Done when: A board with ten thousand items loads and filters within a stated time, measured. Pagination does not lose scroll position or duplicate items when the underlying data changes. Saved views are shareable and reflect the current query. Reordering within a state persists without rewriting every item's position. Do not build yet: No hierarchy, links or reporting yet. ### Phase 3 · Hierarchy without a hierarchy problem Build: Epics grouping stories toward an outcome and iterations grouping them by time, as separate concerns. Derive epic progress from its stories rather than tracking it separately. Handle a story moving between iterations mid-flight. Trap: Tracking an epic's state separately from its stories produces an epic marked done containing three open stories, and nobody trusts either number afterwards. Derive the epic's progress from its children and let its own state express intent rather than completion. Done when: Epic progress derives from its stories rather than being set independently. A story moving between iterations is recorded and its original iteration's history is not rewritten. An epic with no stories is distinguishable from one whose stories are all complete. Iterations do not force a story to belong to exactly one, or the rule is stated. Do not build yet: No reporting or integration yet. ### Phase 4 · Flow metrics, not people metrics Build: Cycle time and throughput derived from the transition log, reported as distributions. Report at the level of work types and states rather than per person. Make per-person breakdowns absent rather than optional. Trap: Any per-person throughput chart becomes a performance measurement within a quarter regardless of how it was introduced, and the immediate effect is that people split tickets to raise their count. Do not build it, and say why in the interface where someone would look for it. Done when: Cycle time and throughput are reported as distributions from the transition log. No per-person productivity breakdown exists anywhere, verified by looking for one. Metrics are correct for a story moved backwards through states. A story reopened after completion is handled by a stated rule rather than distorting the cycle time. Do not build yet: No integration or archiving yet. ### Phase 5 · Connecting to the work itself Build: Link stories to branches and changes through references, updating state on a declared trigger rather than guessing. Archive rather than delete, keeping transitions. Export everything including history. Trap: Automatically moving a story to done when a branch merges is right most of the time and wrong in exactly the cases that matter, such as a merge behind a flag or a partial implementation. Make the transition explicit in the commit or the merge, so closing a story is a decision someone made rather than an inference. Done when: Stories link to code references and state changes require an explicit declaration rather than being inferred from a merge. Archiving preserves transitions and metrics remain correct for archived work. Export contains stories, transitions, epics and iterations and re-imports identically. A deleted branch does not orphan its story link. Do not build yet: Nothing after this. ### Out of scope (and why) - Estimation and velocity forecasting, which is where trackers make claims their data does not support. - Portfolio and resource planning across teams, which is a different product with different politics. - Deep integrations with every development tool, which is the hosted product's actual value. - Per-person productivity reporting, which is excluded deliberately rather than omitted. ### README must contain - That every workflow state has a written definition, since states accumulate and metrics stop meaning anything - That metrics derive from the append-only transition log rather than from current state - That epic progress derives from its stories, so an epic cannot be done with open children - That no per-person productivity view exists, because it becomes a performance measure regardless of intent - That state changes from code require an explicit declaration rather than being inferred from a merge ===== AGENTS.md ===== # Agent instructions · Shortcut indie build - Read `README.md` and `BUILD_PLAN.md` before writing code. The stack is fixed: TypeScript with Fastify and PostgreSQL, Every state transition recorded, append only, Stories, epics and iterations as separate concerns, Indexed queries with saved views, Flow metrics at the level of work rather than of people. Do not substitute. - Work one phase at a time, in order. Do not start a phase until every "Done when" item of the previous one passes. - Prefer the fewest moving parts that satisfy the step. No frameworks, services or dependencies the plan does not name. - Secrets live in `.env`, never in source or logs. Keep `.env.example` current when a variable is introduced. - Do not invent cryptography, security guarantees, APIs or compliance claims. - Add a focused test for every destructive, security-sensitive or data-loss path the plan names. - Run the project checks before declaring a phase complete, and record any deliberate shortcut in the README under "Tradeoffs". ## Known traps - A workflow with a state called in progress and another called in development, added at different times by different people, produces metrics that are meaningless because half the work skips one. Require each state to have a written definition and report states that are never used, so the workflow gets pruned rather than accumulating. - Loading every story to render a board works beautifully in a demonstration and becomes unusable at the scale a real team reaches within a year, which is exactly when moving away is most expensive. Paginate and index from the start, and test against a generated ten thousand item dataset. - Tracking an epic's state separately from its stories produces an epic marked done containing three open stories, and nobody trusts either number afterwards. Derive the epic's progress from its children and let its own state express intent rather than completion. - Any per-person throughput chart becomes a performance measurement within a quarter regardless of how it was introduced, and the immediate effect is that people split tickets to raise their count. Do not build it, and say why in the interface where someone would look for it. ===== BUILD_PLAN.md ===== # Build plan · Shortcut A software project tracker where the interesting problems are keeping the board fast at ten thousand items, making workflow states mean something specific, and reporting progress in a way that does not quietly become a productivity measurement of individuals. Phases are in dependency order. Each ends in a "Done when" list; treat an unticked item as a blocker, not a note. ## Phase 1 · States that mean something Every workflow state has a definition the team agreed on. ### Steps 1. Mark started and done explicitly Inferring from column position breaks the first time someone reorders. Files: `src/states.ts` 2. Record transitions append only Every metric derives from them, so an edit would rewrite history. Files: `src/transitions.ts` 3. Report unused states Workflows accumulate states nobody remembers adding. Files: `src/workflow-health.ts` ### Done when - [ ] Every state has a visible definition - [ ] Started and done are explicit properties - [ ] Backward moves create transitions rather than edits - [ ] Unused states are reported ### Watch out - A workflow with a state called in progress and another called in development, added at different times by different people, produces metrics that are meaningless because half the work skips one. Require each state to have a written definition and report states that are never used, so the workflow gets pruned rather than accumulating. ## Phase 2 · A board that stays fast Ten thousand items load, filter and reorder without waiting. ### Steps 1. Index and paginate from the start The scale a team reaches is the scale a rewrite is most expensive. Files: `src/queries.ts` 2. Keep pagination stable under change Items moving while you page is the normal case on a live board. Files: `src/pagination.ts` 3. Order without rewriting everything A fractional or sparse ordering rather than sequential integers. Files: `src/ordering.ts`, `src/ordering.test.ts` ### Done when - [ ] Ten thousand items load and filter within a stated time - [ ] Pagination is stable under concurrent change - [ ] Saved views are shareable and current - [ ] Reordering does not rewrite every item ### Watch out - Loading every story to render a board works beautifully in a demonstration and becomes unusable at the scale a real team reaches within a year, which is exactly when moving away is most expensive. Paginate and index from the start, and test against a generated ten thousand item dataset. ## Phase 3 · Hierarchy without a hierarchy problem Epics and iterations organise work without becoming a second workflow. ### Steps 1. Derive epic progress from stories An epic marked done with open children destroys trust in both. Files: `src/epics.ts` 2. Keep iteration history intact on a move Moving a story out should not erase that it was in. Files: `src/iterations.ts` 3. Separate time grouping from outcome grouping Conflating them produces a hierarchy nobody can query. Files: `src/hierarchy.ts` ### Done when - [ ] Epic progress derives from its stories - [ ] Moving between iterations preserves history - [ ] Empty and complete epics are distinguishable - [ ] Iteration membership rules are stated ### Watch out - Tracking an epic's state separately from its stories produces an epic marked done containing three open stories, and nobody trusts either number afterwards. Derive the epic's progress from its children and let its own state express intent rather than completion. ## Phase 4 · Flow metrics, not people metrics Reporting describes how work moves rather than how fast individuals are. ### Steps 1. Derive metrics from transitions Current state cannot tell you how long anything took. Files: `src/metrics.ts`, `src/metrics.test.ts` 2. Report distributions by work type The tail is where the process problems are. Files: `src/metrics.ts` 3. Build no per-person productivity view It becomes a performance measure within a quarter regardless of intent. Files: `tests/no-person-metrics.test.ts` ### Done when - [ ] Cycle time and throughput derive from transitions - [ ] No per-person productivity breakdown exists - [ ] Backward moves produce correct metrics - [ ] Reopened stories follow a stated rule ### Watch out - Any per-person throughput chart becomes a performance measurement within a quarter regardless of how it was introduced, and the immediate effect is that people split tickets to raise their count. Do not build it, and say why in the interface where someone would look for it. ## Not in this build - Estimation and velocity forecasting. - Portfolio and resource planning. - Deep development tool integrations. - Per-person productivity reporting. ## After v1, if you want it - Blocked time as a first-class measurement, which is where most cycle time actually goes - A cumulative flow view, which the transition log already supports - Work type classification so cycle times are compared like with like ===== .env.example ===== # Copy to .env and fill in. Never commit .env; this file documents it. # Required · secret. Stories, transitions and team activity. DATABASE_URL=postgres://localhost:5432/tracker # Required. Pagination is required at real scale, not an optimisation. BOARD_PAGE_SIZE=100 # Required. Measured at ten thousand items rather than at a hundred. BOARD_LOAD_TARGET_MS=500 # Required. Present as a constant. It becomes a performance measure regardless of intent. PER_PERSON_METRICS=never # Required. A merge behind a flag is not a completed story. AUTO_TRANSITION_ON_MERGE=never # Required. Transitions are the metric history and outlive the stories. ARCHIVE_RETENTION_YEARS=7
You are building a production product version of Shortcut. Create the following project files first, then implement the application by following them. Keep the files updated as decisions change. Do not collapse this into a single README or prompt. ===== PRODUCT.md ===== # Shortcut · product brief ## Problem The core loop is buildable, but a dependable replacement becomes a real weekend or multi-day project. For Shortcut, manage software stories, epics, iterations, roadmaps, and engineering workflows. The hard boundary is git integrations, reporting, collaboration, and mature agile project semantics, plus collaboration, integrations, and organizational trust. ## Product outcome A tracker that stays fast at real scale, whose metrics describe how work moves rather than how fast people are, and where an epic cannot be complete while its stories are open. ## Target user A builder who needs a maintainable product foundation, not a one-off demo. ## Required capabilities - Docker - PostgreSQL - self-hosted server - email credentials for invitations ## Explicit non-goals for v1 - Estimation and velocity forecasting. - Portfolio and resource planning. - Deep development tool integrations. - Per-person productivity reporting. - Git integrations, reporting, collaboration, and mature agile project semantics - deep integrations - enterprise permissions - large-scale reporting - battle-tested notifications and mobile apps ## Success criteria - Every state is confirmed to have a visible definition - Ten thousand items are confirmed to load and filter within target - Epic progress is confirmed derived from its stories - No per-person productivity view is confirmed to exist - Code integration is confirmed to require explicit declaration ===== BRIEF.md ===== # Build brief · Shortcut The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me issue tracking where the workflow reflects how work actually moves to replace Shortcut. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Stack (fixed, do not substitute) - Runtime: TypeScript with Fastify and PostgreSQL · items, states and history are relational and query heavy - History: Every state transition recorded, append only · cycle time and flow are derived from transitions, not from a current state - Hierarchy: Stories, epics and iterations as separate concerns · conflating them produces a hierarchy nobody can query - Search: Indexed queries with saved views · at ten thousand items, finding things is the product - Reporting: Flow metrics at the level of work rather than of people · the same data measures a process or a person and the choice matters ### Data model (create this before Phase 1) - stories(id, title, description, state_id, epic_id, iteration_id, estimate, created_at, archived_at) - states(id, name, kind, ordinal, is_started, is_done) · kind names what the state means rather than only its position - transitions(id, story_id, from_state_id, to_state_id, actor_id, at) · append only, the basis of every metric - epics(id, name, state_id, target_date, archived_at) and iterations(id, name, starts_on, ends_on) - links(from_story_id, to_story_id, kind) · blocks, relates or duplicates - saved_views(id, owner_id, query_json, shared) · because a query used daily should not be retyped - Metrics derive from the transition log rather than from a story's current state, so moving an item backwards produces correct history rather than a corrupted measurement. ### Phase 1 · States that mean something Build: Configurable states with a kind marking whether work has started and whether it is done. Record every transition append only. Detect a state nothing ever moves out of and a state nothing ever enters. Trap: A workflow with a state called in progress and another called in development, added at different times by different people, produces metrics that are meaningless because half the work skips one. Require each state to have a written definition and report states that are never used, so the workflow gets pruned rather than accumulating. Done when: Every state has a written definition visible where the state is used. Started and done are explicit properties rather than inferred from position. Transitions are append only and a story moved backwards produces two transitions rather than an edit. States never entered or never left are reported. Do not build yet: No board, hierarchy, search or reporting. ### Phase 2 · A board that stays fast Build: A board and list view over indexed queries with pagination that does not lose position. Support saved views. Measure load and filter time at ten thousand items rather than at a hundred. Trap: Loading every story to render a board works beautifully in a demonstration and becomes unusable at the scale a real team reaches within a year, which is exactly when moving away is most expensive. Paginate and index from the start, and test against a generated ten thousand item dataset. Done when: A board with ten thousand items loads and filters within a stated time, measured. Pagination does not lose scroll position or duplicate items when the underlying data changes. Saved views are shareable and reflect the current query. Reordering within a state persists without rewriting every item's position. Do not build yet: No hierarchy, links or reporting yet. ### Phase 3 · Hierarchy without a hierarchy problem Build: Epics grouping stories toward an outcome and iterations grouping them by time, as separate concerns. Derive epic progress from its stories rather than tracking it separately. Handle a story moving between iterations mid-flight. Trap: Tracking an epic's state separately from its stories produces an epic marked done containing three open stories, and nobody trusts either number afterwards. Derive the epic's progress from its children and let its own state express intent rather than completion. Done when: Epic progress derives from its stories rather than being set independently. A story moving between iterations is recorded and its original iteration's history is not rewritten. An epic with no stories is distinguishable from one whose stories are all complete. Iterations do not force a story to belong to exactly one, or the rule is stated. Do not build yet: No reporting or integration yet. ### Phase 4 · Flow metrics, not people metrics Build: Cycle time and throughput derived from the transition log, reported as distributions. Report at the level of work types and states rather than per person. Make per-person breakdowns absent rather than optional. Trap: Any per-person throughput chart becomes a performance measurement within a quarter regardless of how it was introduced, and the immediate effect is that people split tickets to raise their count. Do not build it, and say why in the interface where someone would look for it. Done when: Cycle time and throughput are reported as distributions from the transition log. No per-person productivity breakdown exists anywhere, verified by looking for one. Metrics are correct for a story moved backwards through states. A story reopened after completion is handled by a stated rule rather than distorting the cycle time. Do not build yet: No integration or archiving yet. ### Phase 5 · Connecting to the work itself Build: Link stories to branches and changes through references, updating state on a declared trigger rather than guessing. Archive rather than delete, keeping transitions. Export everything including history. Trap: Automatically moving a story to done when a branch merges is right most of the time and wrong in exactly the cases that matter, such as a merge behind a flag or a partial implementation. Make the transition explicit in the commit or the merge, so closing a story is a decision someone made rather than an inference. Done when: Stories link to code references and state changes require an explicit declaration rather than being inferred from a merge. Archiving preserves transitions and metrics remain correct for archived work. Export contains stories, transitions, epics and iterations and re-imports identically. A deleted branch does not orphan its story link. Do not build yet: Nothing after this. ### Out of scope (and why) - Estimation and velocity forecasting, which is where trackers make claims their data does not support. - Portfolio and resource planning across teams, which is a different product with different politics. - Deep integrations with every development tool, which is the hosted product's actual value. - Per-person productivity reporting, which is excluded deliberately rather than omitted. ### README must contain - That every workflow state has a written definition, since states accumulate and metrics stop meaning anything - That metrics derive from the append-only transition log rather than from current state - That epic progress derives from its stories, so an epic cannot be done with open children - That no per-person productivity view exists, because it becomes a performance measure regardless of intent - That state changes from code require an explicit declaration rather than being inferred from a merge ===== ARCHITECTURE.md ===== # Architecture · Shortcut ## Stack | Part | Choice | Why | | --- | --- | --- | | Runtime | TypeScript with Fastify and PostgreSQL | items, states and history are relational and query heavy | | History | Every state transition recorded, append only | cycle time and flow are derived from transitions, not from a current state | | Hierarchy | Stories, epics and iterations as separate concerns | conflating them produces a hierarchy nobody can query | | Search | Indexed queries with saved views | at ten thousand items, finding things is the product | | Reporting | Flow metrics at the level of work rather than of people | the same data measures a process or a person and the choice matters | ## Modules Each module has one owner concern and a documented way to replace it. | Module | Owns | How to replace it | | --- | --- | --- | | States | Defined workflow states with explicit meanings. | Any configuration, provided each state carries a written definition. | | Transitions | The append-only history metrics derive from. | Not swappable for current-state metrics, which cannot measure duration. | | Board | Indexed, paginated, stably ordered views. | Any implementation tested at ten thousand items rather than a hundred. | | Hierarchy | Epics and iterations as separate concerns. | Any model, provided epic progress derives from its children. | | Metrics | Flow distributions without per-person views. | Not swappable for individual productivity reporting. | ## Configuration Every runtime setting is an environment variable documented in `.env.example`, validated at startup, with a safe local default wherever one exists. - `DATABASE_URL` · required, secret · Stories, transitions and team activity. - `BOARD_PAGE_SIZE` · required · Pagination is required at real scale, not an optimisation. - `BOARD_LOAD_TARGET_MS` · required · Measured at ten thousand items rather than at a hundred. - `PER_PERSON_METRICS` · required · Present as a constant. It becomes a performance measure regardless of intent. - `AUTO_TRANSITION_ON_MERGE` · required · A merge behind a flag is not a completed story. - `ARCHIVE_RETENTION_YEARS` · required · Transitions are the metric history and outlive the stories. ## Production baseline - Security: least privilege, input validation at every boundary, secret redaction in logs, rate limits on abuse-prone paths, no invented security primitives. - Data: explicit schema and migrations, transactional writes where integrity matters, backup and restore procedures that have been exercised. - Integrations: adapters around third-party providers, idempotent webhook or job processing, bounded retries, timeouts. - Observability: structured logs with request or operation ids, an error-tracking hook, and health and readiness checks where a server exists. - Quality: unit tests for domain rules, integration tests at module boundaries, one end-to-end test of the critical path. ## Decision records For each dependency in the stack table, keep a short note: why it was chosen, its failure mode, and how it is replaced. Do not add infrastructure until a requirement in `PRODUCT.md` justifies it. ===== AGENTS.md ===== # Agent instructions · Shortcut product build - Read `PRODUCT.md` and `ARCHITECTURE.md` before changing code. The stack is fixed: TypeScript with Fastify and PostgreSQL, Every state transition recorded, append only, Stories, epics and iterations as separate concerns, Indexed queries with saved views, Flow metrics at the level of work rather than of people. - Implement milestone by milestone from `MILESTONES.md`; keep each change reviewable and leave the application runnable at every commit. - Treat authentication, payments, encryption, imports, webhooks and destructive actions as high-risk boundaries when present. - Never invent cryptography or silently weaken a requirement to make a check pass. - Put every external service behind an interface with a deterministic fake for tests. - Add migrations and rollback or recovery notes for every persistent data change. - Log useful operational context without credentials, tokens, passwords or personal data. - Update documentation and run every check before completing a milestone. ## Known traps - A workflow with a state called in progress and another called in development, added at different times by different people, produces metrics that are meaningless because half the work skips one. Require each state to have a written definition and report states that are never used, so the workflow gets pruned rather than accumulating. - Loading every story to render a board works beautifully in a demonstration and becomes unusable at the scale a real team reaches within a year, which is exactly when moving away is most expensive. Paginate and index from the start, and test against a generated ten thousand item dataset. - Tracking an epic's state separately from its stories produces an epic marked done containing three open stories, and nobody trusts either number afterwards. Derive the epic's progress from its children and let its own state express intent rather than completion. - Any per-person throughput chart becomes a performance measurement within a quarter regardless of how it was introduced, and the immediate effect is that people split tickets to raise their count. Do not build it, and say why in the interface where someone would look for it. - Automatically moving a story to done when a branch merges is right most of the time and wrong in exactly the cases that matter, such as a merge behind a flag or a partial implementation. Make the transition explicit in the commit or the merge, so closing a story is a decision someone made rather than an inference. ===== MILESTONES.md ===== # Delivery milestones · Shortcut Estimated effort: **multi-day** for the indie phases; the production-only milestones add the trust and operability layer. ## M1 · States that mean something Every workflow state has a definition the team agreed on. ### Steps 1. Mark started and done explicitly Inferring from column position breaks the first time someone reorders. Files: `src/states.ts` 2. Record transitions append only Every metric derives from them, so an edit would rewrite history. Files: `src/transitions.ts` 3. Report unused states Workflows accumulate states nobody remembers adding. Files: `src/workflow-health.ts` ### Done when - [ ] Every state has a visible definition - [ ] Started and done are explicit properties - [ ] Backward moves create transitions rather than edits - [ ] Unused states are reported ### Watch out - A workflow with a state called in progress and another called in development, added at different times by different people, produces metrics that are meaningless because half the work skips one. Require each state to have a written definition and report states that are never used, so the workflow gets pruned rather than accumulating. ## M2 · A board that stays fast Ten thousand items load, filter and reorder without waiting. ### Steps 1. Index and paginate from the start The scale a team reaches is the scale a rewrite is most expensive. Files: `src/queries.ts` 2. Keep pagination stable under change Items moving while you page is the normal case on a live board. Files: `src/pagination.ts` 3. Order without rewriting everything A fractional or sparse ordering rather than sequential integers. Files: `src/ordering.ts`, `src/ordering.test.ts` ### Done when - [ ] Ten thousand items load and filter within a stated time - [ ] Pagination is stable under concurrent change - [ ] Saved views are shareable and current - [ ] Reordering does not rewrite every item ### Watch out - Loading every story to render a board works beautifully in a demonstration and becomes unusable at the scale a real team reaches within a year, which is exactly when moving away is most expensive. Paginate and index from the start, and test against a generated ten thousand item dataset. ## M3 · Hierarchy without a hierarchy problem Epics and iterations organise work without becoming a second workflow. ### Steps 1. Derive epic progress from stories An epic marked done with open children destroys trust in both. Files: `src/epics.ts` 2. Keep iteration history intact on a move Moving a story out should not erase that it was in. Files: `src/iterations.ts` 3. Separate time grouping from outcome grouping Conflating them produces a hierarchy nobody can query. Files: `src/hierarchy.ts` ### Done when - [ ] Epic progress derives from its stories - [ ] Moving between iterations preserves history - [ ] Empty and complete epics are distinguishable - [ ] Iteration membership rules are stated ### Watch out - Tracking an epic's state separately from its stories produces an epic marked done containing three open stories, and nobody trusts either number afterwards. Derive the epic's progress from its children and let its own state express intent rather than completion. ## M4 · Flow metrics, not people metrics Reporting describes how work moves rather than how fast individuals are. ### Steps 1. Derive metrics from transitions Current state cannot tell you how long anything took. Files: `src/metrics.ts`, `src/metrics.test.ts` 2. Report distributions by work type The tail is where the process problems are. Files: `src/metrics.ts` 3. Build no per-person productivity view It becomes a performance measure within a quarter regardless of intent. Files: `tests/no-person-metrics.test.ts` ### Done when - [ ] Cycle time and throughput derive from transitions - [ ] No per-person productivity breakdown exists - [ ] Backward moves produce correct metrics - [ ] Reopened stories follow a stated rule ### Watch out - Any per-person throughput chart becomes a performance measurement within a quarter regardless of how it was introduced, and the immediate effect is that people split tickets to raise their count. Do not build it, and say why in the interface where someone would look for it. ## M5 · Connecting to the work itself (production only) Stories link to code and archiving does not lose history. ### Steps 1. Require an explicit transition declaration A merge behind a flag is not a completed story. Files: `src/integration.ts` 2. Archive rather than delete Transitions are the metric history and are worth more than the story. Files: `src/archive.ts` 3. Export with full history A tracker you cannot leave is a tracker to avoid. Files: `src/export.ts` ### Done when - [ ] State changes require explicit declaration - [ ] Archiving preserves transitions and metrics - [ ] Export round trips including history - [ ] Deleted branches do not orphan links ### Watch out - Automatically moving a story to done when a branch merges is right most of the time and wrong in exactly the cases that matter, such as a merge behind a flag or a partial implementation. Make the transition explicit in the commit or the merge, so closing a story is a decision someone made rather than an inference. ===== OPERATIONS.md ===== # Operations · Shortcut ## Backup The transition log is larger than the stories and is what every metric depends on. Back it up with the same care, since losing it leaves a board with no history and no way to answer how long anything took. ## Restore Restore and confirm transitions are complete and ordered, since a gap produces cycle times that are silently wrong rather than obviously missing. Do a restore drill before the first real user, and write the date here when it passes. ## Monitoring Board query time at current scale and unused state count. The first degrades gradually as the dataset grows and is the thing that makes a tracker feel bad without ever failing. ## Incident checklist Metrics that stopped making sense usually mean the workflow gained a state without a definition, or a story was edited rather than transitioned. The append-only log distinguishes the two. 1. Contain the issue without destroying evidence or user data. 2. Record the timeline and affected scope. 3. Rotate exposed secrets and revoke compromised sessions or credentials. 4. Restore from a verified backup when needed. 5. Document the root cause, the remediation and the regression test. ## Release gate - [ ] Every state is confirmed to have a visible definition - [ ] Ten thousand items are confirmed to load and filter within target - [ ] Epic progress is confirmed derived from its stories - [ ] No per-person productivity view is confirmed to exist - [ ] Code integration is confirmed to require explicit declaration ## Launch constraint Do not market omitted Shortcut capabilities as implemented. The non-goals in `PRODUCT.md` remain user-visible limitations until they are deliberately delivered. ===== .env.example ===== # Copy to .env and fill in. Never commit .env; this file documents it. # Required · secret. Stories, transitions and team activity. DATABASE_URL=postgres://localhost:5432/tracker # Required. Pagination is required at real scale, not an optimisation. BOARD_PAGE_SIZE=100 # Required. Measured at ten thousand items rather than at a hundred. BOARD_LOAD_TARGET_MS=500 # Required. Present as a constant. It becomes a performance measure regardless of intent. PER_PERSON_METRICS=never # Required. A merge behind a flag is not a completed story. AUTO_TRANSITION_ON_MERGE=never # Required. Transitions are the metric history and outlive the stories. ARCHIVE_RETENTION_YEARS=7
# Shortcut · indie build A software project tracker where the interesting problems are keeping the board fast at ten thousand items, making workflow states mean something specific, and reporting progress in a way that does not quietly become a productivity measurement of individuals. Estimated effort: **multi-day**. Work `BUILD_PLAN.md` top to bottom · every phase ends in a check that has to pass before the next one starts. ## Stack | Part | Choice | Why | | --- | --- | --- | | Runtime | TypeScript with Fastify and PostgreSQL | items, states and history are relational and query heavy | | History | Every state transition recorded, append only | cycle time and flow are derived from transitions, not from a current state | | Hierarchy | Stories, epics and iterations as separate concerns | conflating them produces a hierarchy nobody can query | | Search | Indexed queries with saved views | at ten thousand items, finding things is the product | | Reporting | Flow metrics at the level of work rather than of people | the same data measures a process or a person and the choice matters | ## Before you start Have every one of these ready. The plan assumes them from step one. - [ ] **Node.js 22 or newer** · free - Why: Runs the server and the query layer. - Get it: nodejs.org, or nvm install 22. - Verify: node --version prints v22 or higher - [ ] **PostgreSQL 16 or newer** · free locally - Why: Ten thousand items with fast filtered queries and an append-only transition log. - Get it: Docker or your package manager. - Verify: A filtered query over ten thousand rows returns within your stated time - [ ] **Ten thousand realistic items** · free - Why: Board performance, pagination stability and ordering all behave completely differently at the scale a team reaches within a year. - Get it: Generate or import a realistic dataset with varied states, epics and a long transition history. - Verify: Ten thousand items exist with several transitions each - [ ] **Your states and their definitions** · free, and it takes a team conversation - Why: Each state needs a written meaning before the first metric is computed, since a workflow assembled by accretion produces numbers nobody can interpret. - Get it: Agree the states with the team, write one sentence per state, and mark which mean started and which mean done. - Verify: Every state has a written definition and explicit started and done properties - [ ] **Your position on individual metrics** · free - Why: The build excludes per-person reporting deliberately, and someone will ask for it, so the reasoning needs to exist before the request rather than after. - Get it: Write down why per-person throughput is not offered and what you will point people at instead. - Verify: A written note exists and appears where someone would look for the feature ## Quick start Follow Phase 1 in `BUILD_PLAN.md`; it creates the project. Then copy `.env.example` to `.env` and fill in the values it documents. ## Honest limits This build deliberately does not replace: - Estimation and velocity forecasting. - Portfolio and resource planning. - Deep development tool integrations. - Per-person productivity reporting. - Git integrations, reporting, collaboration, and mature agile project semantics - deep integrations - enterprise permissions - large-scale reporting - battle-tested notifications and mobile apps If one of those is essential to you, that is the reason to keep paying for Shortcut, and the README should say so rather than pretend.
# Build brief · Shortcut The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me issue tracking where the workflow reflects how work actually moves to replace Shortcut. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Stack (fixed, do not substitute) - Runtime: TypeScript with Fastify and PostgreSQL · items, states and history are relational and query heavy - History: Every state transition recorded, append only · cycle time and flow are derived from transitions, not from a current state - Hierarchy: Stories, epics and iterations as separate concerns · conflating them produces a hierarchy nobody can query - Search: Indexed queries with saved views · at ten thousand items, finding things is the product - Reporting: Flow metrics at the level of work rather than of people · the same data measures a process or a person and the choice matters ### Data model (create this before Phase 1) - stories(id, title, description, state_id, epic_id, iteration_id, estimate, created_at, archived_at) - states(id, name, kind, ordinal, is_started, is_done) · kind names what the state means rather than only its position - transitions(id, story_id, from_state_id, to_state_id, actor_id, at) · append only, the basis of every metric - epics(id, name, state_id, target_date, archived_at) and iterations(id, name, starts_on, ends_on) - links(from_story_id, to_story_id, kind) · blocks, relates or duplicates - saved_views(id, owner_id, query_json, shared) · because a query used daily should not be retyped - Metrics derive from the transition log rather than from a story's current state, so moving an item backwards produces correct history rather than a corrupted measurement. ### Phase 1 · States that mean something Build: Configurable states with a kind marking whether work has started and whether it is done. Record every transition append only. Detect a state nothing ever moves out of and a state nothing ever enters. Trap: A workflow with a state called in progress and another called in development, added at different times by different people, produces metrics that are meaningless because half the work skips one. Require each state to have a written definition and report states that are never used, so the workflow gets pruned rather than accumulating. Done when: Every state has a written definition visible where the state is used. Started and done are explicit properties rather than inferred from position. Transitions are append only and a story moved backwards produces two transitions rather than an edit. States never entered or never left are reported. Do not build yet: No board, hierarchy, search or reporting. ### Phase 2 · A board that stays fast Build: A board and list view over indexed queries with pagination that does not lose position. Support saved views. Measure load and filter time at ten thousand items rather than at a hundred. Trap: Loading every story to render a board works beautifully in a demonstration and becomes unusable at the scale a real team reaches within a year, which is exactly when moving away is most expensive. Paginate and index from the start, and test against a generated ten thousand item dataset. Done when: A board with ten thousand items loads and filters within a stated time, measured. Pagination does not lose scroll position or duplicate items when the underlying data changes. Saved views are shareable and reflect the current query. Reordering within a state persists without rewriting every item's position. Do not build yet: No hierarchy, links or reporting yet. ### Phase 3 · Hierarchy without a hierarchy problem Build: Epics grouping stories toward an outcome and iterations grouping them by time, as separate concerns. Derive epic progress from its stories rather than tracking it separately. Handle a story moving between iterations mid-flight. Trap: Tracking an epic's state separately from its stories produces an epic marked done containing three open stories, and nobody trusts either number afterwards. Derive the epic's progress from its children and let its own state express intent rather than completion. Done when: Epic progress derives from its stories rather than being set independently. A story moving between iterations is recorded and its original iteration's history is not rewritten. An epic with no stories is distinguishable from one whose stories are all complete. Iterations do not force a story to belong to exactly one, or the rule is stated. Do not build yet: No reporting or integration yet. ### Phase 4 · Flow metrics, not people metrics Build: Cycle time and throughput derived from the transition log, reported as distributions. Report at the level of work types and states rather than per person. Make per-person breakdowns absent rather than optional. Trap: Any per-person throughput chart becomes a performance measurement within a quarter regardless of how it was introduced, and the immediate effect is that people split tickets to raise their count. Do not build it, and say why in the interface where someone would look for it. Done when: Cycle time and throughput are reported as distributions from the transition log. No per-person productivity breakdown exists anywhere, verified by looking for one. Metrics are correct for a story moved backwards through states. A story reopened after completion is handled by a stated rule rather than distorting the cycle time. Do not build yet: No integration or archiving yet. ### Phase 5 · Connecting to the work itself Build: Link stories to branches and changes through references, updating state on a declared trigger rather than guessing. Archive rather than delete, keeping transitions. Export everything including history. Trap: Automatically moving a story to done when a branch merges is right most of the time and wrong in exactly the cases that matter, such as a merge behind a flag or a partial implementation. Make the transition explicit in the commit or the merge, so closing a story is a decision someone made rather than an inference. Done when: Stories link to code references and state changes require an explicit declaration rather than being inferred from a merge. Archiving preserves transitions and metrics remain correct for archived work. Export contains stories, transitions, epics and iterations and re-imports identically. A deleted branch does not orphan its story link. Do not build yet: Nothing after this. ### Out of scope (and why) - Estimation and velocity forecasting, which is where trackers make claims their data does not support. - Portfolio and resource planning across teams, which is a different product with different politics. - Deep integrations with every development tool, which is the hosted product's actual value. - Per-person productivity reporting, which is excluded deliberately rather than omitted. ### README must contain - That every workflow state has a written definition, since states accumulate and metrics stop meaning anything - That metrics derive from the append-only transition log rather than from current state - That epic progress derives from its stories, so an epic cannot be done with open children - That no per-person productivity view exists, because it becomes a performance measure regardless of intent - That state changes from code require an explicit declaration rather than being inferred from a merge
# Agent instructions · Shortcut indie build - Read `README.md` and `BUILD_PLAN.md` before writing code. The stack is fixed: TypeScript with Fastify and PostgreSQL, Every state transition recorded, append only, Stories, epics and iterations as separate concerns, Indexed queries with saved views, Flow metrics at the level of work rather than of people. Do not substitute. - Work one phase at a time, in order. Do not start a phase until every "Done when" item of the previous one passes. - Prefer the fewest moving parts that satisfy the step. No frameworks, services or dependencies the plan does not name. - Secrets live in `.env`, never in source or logs. Keep `.env.example` current when a variable is introduced. - Do not invent cryptography, security guarantees, APIs or compliance claims. - Add a focused test for every destructive, security-sensitive or data-loss path the plan names. - Run the project checks before declaring a phase complete, and record any deliberate shortcut in the README under "Tradeoffs". ## Known traps - A workflow with a state called in progress and another called in development, added at different times by different people, produces metrics that are meaningless because half the work skips one. Require each state to have a written definition and report states that are never used, so the workflow gets pruned rather than accumulating. - Loading every story to render a board works beautifully in a demonstration and becomes unusable at the scale a real team reaches within a year, which is exactly when moving away is most expensive. Paginate and index from the start, and test against a generated ten thousand item dataset. - Tracking an epic's state separately from its stories produces an epic marked done containing three open stories, and nobody trusts either number afterwards. Derive the epic's progress from its children and let its own state express intent rather than completion. - Any per-person throughput chart becomes a performance measurement within a quarter regardless of how it was introduced, and the immediate effect is that people split tickets to raise their count. Do not build it, and say why in the interface where someone would look for it.
# Build plan · Shortcut A software project tracker where the interesting problems are keeping the board fast at ten thousand items, making workflow states mean something specific, and reporting progress in a way that does not quietly become a productivity measurement of individuals. Phases are in dependency order. Each ends in a "Done when" list; treat an unticked item as a blocker, not a note. ## Phase 1 · States that mean something Every workflow state has a definition the team agreed on. ### Steps 1. Mark started and done explicitly Inferring from column position breaks the first time someone reorders. Files: `src/states.ts` 2. Record transitions append only Every metric derives from them, so an edit would rewrite history. Files: `src/transitions.ts` 3. Report unused states Workflows accumulate states nobody remembers adding. Files: `src/workflow-health.ts` ### Done when - [ ] Every state has a visible definition - [ ] Started and done are explicit properties - [ ] Backward moves create transitions rather than edits - [ ] Unused states are reported ### Watch out - A workflow with a state called in progress and another called in development, added at different times by different people, produces metrics that are meaningless because half the work skips one. Require each state to have a written definition and report states that are never used, so the workflow gets pruned rather than accumulating. ## Phase 2 · A board that stays fast Ten thousand items load, filter and reorder without waiting. ### Steps 1. Index and paginate from the start The scale a team reaches is the scale a rewrite is most expensive. Files: `src/queries.ts` 2. Keep pagination stable under change Items moving while you page is the normal case on a live board. Files: `src/pagination.ts` 3. Order without rewriting everything A fractional or sparse ordering rather than sequential integers. Files: `src/ordering.ts`, `src/ordering.test.ts` ### Done when - [ ] Ten thousand items load and filter within a stated time - [ ] Pagination is stable under concurrent change - [ ] Saved views are shareable and current - [ ] Reordering does not rewrite every item ### Watch out - Loading every story to render a board works beautifully in a demonstration and becomes unusable at the scale a real team reaches within a year, which is exactly when moving away is most expensive. Paginate and index from the start, and test against a generated ten thousand item dataset. ## Phase 3 · Hierarchy without a hierarchy problem Epics and iterations organise work without becoming a second workflow. ### Steps 1. Derive epic progress from stories An epic marked done with open children destroys trust in both. Files: `src/epics.ts` 2. Keep iteration history intact on a move Moving a story out should not erase that it was in. Files: `src/iterations.ts` 3. Separate time grouping from outcome grouping Conflating them produces a hierarchy nobody can query. Files: `src/hierarchy.ts` ### Done when - [ ] Epic progress derives from its stories - [ ] Moving between iterations preserves history - [ ] Empty and complete epics are distinguishable - [ ] Iteration membership rules are stated ### Watch out - Tracking an epic's state separately from its stories produces an epic marked done containing three open stories, and nobody trusts either number afterwards. Derive the epic's progress from its children and let its own state express intent rather than completion. ## Phase 4 · Flow metrics, not people metrics Reporting describes how work moves rather than how fast individuals are. ### Steps 1. Derive metrics from transitions Current state cannot tell you how long anything took. Files: `src/metrics.ts`, `src/metrics.test.ts` 2. Report distributions by work type The tail is where the process problems are. Files: `src/metrics.ts` 3. Build no per-person productivity view It becomes a performance measure within a quarter regardless of intent. Files: `tests/no-person-metrics.test.ts` ### Done when - [ ] Cycle time and throughput derive from transitions - [ ] No per-person productivity breakdown exists - [ ] Backward moves produce correct metrics - [ ] Reopened stories follow a stated rule ### Watch out - Any per-person throughput chart becomes a performance measurement within a quarter regardless of how it was introduced, and the immediate effect is that people split tickets to raise their count. Do not build it, and say why in the interface where someone would look for it. ## Not in this build - Estimation and velocity forecasting. - Portfolio and resource planning. - Deep development tool integrations. - Per-person productivity reporting. ## After v1, if you want it - Blocked time as a first-class measurement, which is where most cycle time actually goes - A cumulative flow view, which the transition log already supports - Work type classification so cycle times are compared like with like
# Copy to .env and fill in. Never commit .env; this file documents it. # Required · secret. Stories, transitions and team activity. DATABASE_URL=postgres://localhost:5432/tracker # Required. Pagination is required at real scale, not an optimisation. BOARD_PAGE_SIZE=100 # Required. Measured at ten thousand items rather than at a hundred. BOARD_LOAD_TARGET_MS=500 # Required. Present as a constant. It becomes a performance measure regardless of intent. PER_PERSON_METRICS=never # Required. A merge behind a flag is not a completed story. AUTO_TRANSITION_ON_MERGE=never # Required. Transitions are the metric history and outlive the stories. ARCHIVE_RETENTION_YEARS=7
# Shortcut · product brief ## Problem The core loop is buildable, but a dependable replacement becomes a real weekend or multi-day project. For Shortcut, manage software stories, epics, iterations, roadmaps, and engineering workflows. The hard boundary is git integrations, reporting, collaboration, and mature agile project semantics, plus collaboration, integrations, and organizational trust. ## Product outcome A tracker that stays fast at real scale, whose metrics describe how work moves rather than how fast people are, and where an epic cannot be complete while its stories are open. ## Target user A builder who needs a maintainable product foundation, not a one-off demo. ## Required capabilities - Docker - PostgreSQL - self-hosted server - email credentials for invitations ## Explicit non-goals for v1 - Estimation and velocity forecasting. - Portfolio and resource planning. - Deep development tool integrations. - Per-person productivity reporting. - Git integrations, reporting, collaboration, and mature agile project semantics - deep integrations - enterprise permissions - large-scale reporting - battle-tested notifications and mobile apps ## Success criteria - Every state is confirmed to have a visible definition - Ten thousand items are confirmed to load and filter within target - Epic progress is confirmed derived from its stories - No per-person productivity view is confirmed to exist - Code integration is confirmed to require explicit declaration
# Build brief · Shortcut The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me issue tracking where the workflow reflects how work actually moves to replace Shortcut. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Stack (fixed, do not substitute) - Runtime: TypeScript with Fastify and PostgreSQL · items, states and history are relational and query heavy - History: Every state transition recorded, append only · cycle time and flow are derived from transitions, not from a current state - Hierarchy: Stories, epics and iterations as separate concerns · conflating them produces a hierarchy nobody can query - Search: Indexed queries with saved views · at ten thousand items, finding things is the product - Reporting: Flow metrics at the level of work rather than of people · the same data measures a process or a person and the choice matters ### Data model (create this before Phase 1) - stories(id, title, description, state_id, epic_id, iteration_id, estimate, created_at, archived_at) - states(id, name, kind, ordinal, is_started, is_done) · kind names what the state means rather than only its position - transitions(id, story_id, from_state_id, to_state_id, actor_id, at) · append only, the basis of every metric - epics(id, name, state_id, target_date, archived_at) and iterations(id, name, starts_on, ends_on) - links(from_story_id, to_story_id, kind) · blocks, relates or duplicates - saved_views(id, owner_id, query_json, shared) · because a query used daily should not be retyped - Metrics derive from the transition log rather than from a story's current state, so moving an item backwards produces correct history rather than a corrupted measurement. ### Phase 1 · States that mean something Build: Configurable states with a kind marking whether work has started and whether it is done. Record every transition append only. Detect a state nothing ever moves out of and a state nothing ever enters. Trap: A workflow with a state called in progress and another called in development, added at different times by different people, produces metrics that are meaningless because half the work skips one. Require each state to have a written definition and report states that are never used, so the workflow gets pruned rather than accumulating. Done when: Every state has a written definition visible where the state is used. Started and done are explicit properties rather than inferred from position. Transitions are append only and a story moved backwards produces two transitions rather than an edit. States never entered or never left are reported. Do not build yet: No board, hierarchy, search or reporting. ### Phase 2 · A board that stays fast Build: A board and list view over indexed queries with pagination that does not lose position. Support saved views. Measure load and filter time at ten thousand items rather than at a hundred. Trap: Loading every story to render a board works beautifully in a demonstration and becomes unusable at the scale a real team reaches within a year, which is exactly when moving away is most expensive. Paginate and index from the start, and test against a generated ten thousand item dataset. Done when: A board with ten thousand items loads and filters within a stated time, measured. Pagination does not lose scroll position or duplicate items when the underlying data changes. Saved views are shareable and reflect the current query. Reordering within a state persists without rewriting every item's position. Do not build yet: No hierarchy, links or reporting yet. ### Phase 3 · Hierarchy without a hierarchy problem Build: Epics grouping stories toward an outcome and iterations grouping them by time, as separate concerns. Derive epic progress from its stories rather than tracking it separately. Handle a story moving between iterations mid-flight. Trap: Tracking an epic's state separately from its stories produces an epic marked done containing three open stories, and nobody trusts either number afterwards. Derive the epic's progress from its children and let its own state express intent rather than completion. Done when: Epic progress derives from its stories rather than being set independently. A story moving between iterations is recorded and its original iteration's history is not rewritten. An epic with no stories is distinguishable from one whose stories are all complete. Iterations do not force a story to belong to exactly one, or the rule is stated. Do not build yet: No reporting or integration yet. ### Phase 4 · Flow metrics, not people metrics Build: Cycle time and throughput derived from the transition log, reported as distributions. Report at the level of work types and states rather than per person. Make per-person breakdowns absent rather than optional. Trap: Any per-person throughput chart becomes a performance measurement within a quarter regardless of how it was introduced, and the immediate effect is that people split tickets to raise their count. Do not build it, and say why in the interface where someone would look for it. Done when: Cycle time and throughput are reported as distributions from the transition log. No per-person productivity breakdown exists anywhere, verified by looking for one. Metrics are correct for a story moved backwards through states. A story reopened after completion is handled by a stated rule rather than distorting the cycle time. Do not build yet: No integration or archiving yet. ### Phase 5 · Connecting to the work itself Build: Link stories to branches and changes through references, updating state on a declared trigger rather than guessing. Archive rather than delete, keeping transitions. Export everything including history. Trap: Automatically moving a story to done when a branch merges is right most of the time and wrong in exactly the cases that matter, such as a merge behind a flag or a partial implementation. Make the transition explicit in the commit or the merge, so closing a story is a decision someone made rather than an inference. Done when: Stories link to code references and state changes require an explicit declaration rather than being inferred from a merge. Archiving preserves transitions and metrics remain correct for archived work. Export contains stories, transitions, epics and iterations and re-imports identically. A deleted branch does not orphan its story link. Do not build yet: Nothing after this. ### Out of scope (and why) - Estimation and velocity forecasting, which is where trackers make claims their data does not support. - Portfolio and resource planning across teams, which is a different product with different politics. - Deep integrations with every development tool, which is the hosted product's actual value. - Per-person productivity reporting, which is excluded deliberately rather than omitted. ### README must contain - That every workflow state has a written definition, since states accumulate and metrics stop meaning anything - That metrics derive from the append-only transition log rather than from current state - That epic progress derives from its stories, so an epic cannot be done with open children - That no per-person productivity view exists, because it becomes a performance measure regardless of intent - That state changes from code require an explicit declaration rather than being inferred from a merge
# Architecture · Shortcut ## Stack | Part | Choice | Why | | --- | --- | --- | | Runtime | TypeScript with Fastify and PostgreSQL | items, states and history are relational and query heavy | | History | Every state transition recorded, append only | cycle time and flow are derived from transitions, not from a current state | | Hierarchy | Stories, epics and iterations as separate concerns | conflating them produces a hierarchy nobody can query | | Search | Indexed queries with saved views | at ten thousand items, finding things is the product | | Reporting | Flow metrics at the level of work rather than of people | the same data measures a process or a person and the choice matters | ## Modules Each module has one owner concern and a documented way to replace it. | Module | Owns | How to replace it | | --- | --- | --- | | States | Defined workflow states with explicit meanings. | Any configuration, provided each state carries a written definition. | | Transitions | The append-only history metrics derive from. | Not swappable for current-state metrics, which cannot measure duration. | | Board | Indexed, paginated, stably ordered views. | Any implementation tested at ten thousand items rather than a hundred. | | Hierarchy | Epics and iterations as separate concerns. | Any model, provided epic progress derives from its children. | | Metrics | Flow distributions without per-person views. | Not swappable for individual productivity reporting. | ## Configuration Every runtime setting is an environment variable documented in `.env.example`, validated at startup, with a safe local default wherever one exists. - `DATABASE_URL` · required, secret · Stories, transitions and team activity. - `BOARD_PAGE_SIZE` · required · Pagination is required at real scale, not an optimisation. - `BOARD_LOAD_TARGET_MS` · required · Measured at ten thousand items rather than at a hundred. - `PER_PERSON_METRICS` · required · Present as a constant. It becomes a performance measure regardless of intent. - `AUTO_TRANSITION_ON_MERGE` · required · A merge behind a flag is not a completed story. - `ARCHIVE_RETENTION_YEARS` · required · Transitions are the metric history and outlive the stories. ## Production baseline - Security: least privilege, input validation at every boundary, secret redaction in logs, rate limits on abuse-prone paths, no invented security primitives. - Data: explicit schema and migrations, transactional writes where integrity matters, backup and restore procedures that have been exercised. - Integrations: adapters around third-party providers, idempotent webhook or job processing, bounded retries, timeouts. - Observability: structured logs with request or operation ids, an error-tracking hook, and health and readiness checks where a server exists. - Quality: unit tests for domain rules, integration tests at module boundaries, one end-to-end test of the critical path. ## Decision records For each dependency in the stack table, keep a short note: why it was chosen, its failure mode, and how it is replaced. Do not add infrastructure until a requirement in `PRODUCT.md` justifies it.
# Agent instructions · Shortcut product build - Read `PRODUCT.md` and `ARCHITECTURE.md` before changing code. The stack is fixed: TypeScript with Fastify and PostgreSQL, Every state transition recorded, append only, Stories, epics and iterations as separate concerns, Indexed queries with saved views, Flow metrics at the level of work rather than of people. - Implement milestone by milestone from `MILESTONES.md`; keep each change reviewable and leave the application runnable at every commit. - Treat authentication, payments, encryption, imports, webhooks and destructive actions as high-risk boundaries when present. - Never invent cryptography or silently weaken a requirement to make a check pass. - Put every external service behind an interface with a deterministic fake for tests. - Add migrations and rollback or recovery notes for every persistent data change. - Log useful operational context without credentials, tokens, passwords or personal data. - Update documentation and run every check before completing a milestone. ## Known traps - A workflow with a state called in progress and another called in development, added at different times by different people, produces metrics that are meaningless because half the work skips one. Require each state to have a written definition and report states that are never used, so the workflow gets pruned rather than accumulating. - Loading every story to render a board works beautifully in a demonstration and becomes unusable at the scale a real team reaches within a year, which is exactly when moving away is most expensive. Paginate and index from the start, and test against a generated ten thousand item dataset. - Tracking an epic's state separately from its stories produces an epic marked done containing three open stories, and nobody trusts either number afterwards. Derive the epic's progress from its children and let its own state express intent rather than completion. - Any per-person throughput chart becomes a performance measurement within a quarter regardless of how it was introduced, and the immediate effect is that people split tickets to raise their count. Do not build it, and say why in the interface where someone would look for it. - Automatically moving a story to done when a branch merges is right most of the time and wrong in exactly the cases that matter, such as a merge behind a flag or a partial implementation. Make the transition explicit in the commit or the merge, so closing a story is a decision someone made rather than an inference.
# Delivery milestones · Shortcut Estimated effort: **multi-day** for the indie phases; the production-only milestones add the trust and operability layer. ## M1 · States that mean something Every workflow state has a definition the team agreed on. ### Steps 1. Mark started and done explicitly Inferring from column position breaks the first time someone reorders. Files: `src/states.ts` 2. Record transitions append only Every metric derives from them, so an edit would rewrite history. Files: `src/transitions.ts` 3. Report unused states Workflows accumulate states nobody remembers adding. Files: `src/workflow-health.ts` ### Done when - [ ] Every state has a visible definition - [ ] Started and done are explicit properties - [ ] Backward moves create transitions rather than edits - [ ] Unused states are reported ### Watch out - A workflow with a state called in progress and another called in development, added at different times by different people, produces metrics that are meaningless because half the work skips one. Require each state to have a written definition and report states that are never used, so the workflow gets pruned rather than accumulating. ## M2 · A board that stays fast Ten thousand items load, filter and reorder without waiting. ### Steps 1. Index and paginate from the start The scale a team reaches is the scale a rewrite is most expensive. Files: `src/queries.ts` 2. Keep pagination stable under change Items moving while you page is the normal case on a live board. Files: `src/pagination.ts` 3. Order without rewriting everything A fractional or sparse ordering rather than sequential integers. Files: `src/ordering.ts`, `src/ordering.test.ts` ### Done when - [ ] Ten thousand items load and filter within a stated time - [ ] Pagination is stable under concurrent change - [ ] Saved views are shareable and current - [ ] Reordering does not rewrite every item ### Watch out - Loading every story to render a board works beautifully in a demonstration and becomes unusable at the scale a real team reaches within a year, which is exactly when moving away is most expensive. Paginate and index from the start, and test against a generated ten thousand item dataset. ## M3 · Hierarchy without a hierarchy problem Epics and iterations organise work without becoming a second workflow. ### Steps 1. Derive epic progress from stories An epic marked done with open children destroys trust in both. Files: `src/epics.ts` 2. Keep iteration history intact on a move Moving a story out should not erase that it was in. Files: `src/iterations.ts` 3. Separate time grouping from outcome grouping Conflating them produces a hierarchy nobody can query. Files: `src/hierarchy.ts` ### Done when - [ ] Epic progress derives from its stories - [ ] Moving between iterations preserves history - [ ] Empty and complete epics are distinguishable - [ ] Iteration membership rules are stated ### Watch out - Tracking an epic's state separately from its stories produces an epic marked done containing three open stories, and nobody trusts either number afterwards. Derive the epic's progress from its children and let its own state express intent rather than completion. ## M4 · Flow metrics, not people metrics Reporting describes how work moves rather than how fast individuals are. ### Steps 1. Derive metrics from transitions Current state cannot tell you how long anything took. Files: `src/metrics.ts`, `src/metrics.test.ts` 2. Report distributions by work type The tail is where the process problems are. Files: `src/metrics.ts` 3. Build no per-person productivity view It becomes a performance measure within a quarter regardless of intent. Files: `tests/no-person-metrics.test.ts` ### Done when - [ ] Cycle time and throughput derive from transitions - [ ] No per-person productivity breakdown exists - [ ] Backward moves produce correct metrics - [ ] Reopened stories follow a stated rule ### Watch out - Any per-person throughput chart becomes a performance measurement within a quarter regardless of how it was introduced, and the immediate effect is that people split tickets to raise their count. Do not build it, and say why in the interface where someone would look for it. ## M5 · Connecting to the work itself (production only) Stories link to code and archiving does not lose history. ### Steps 1. Require an explicit transition declaration A merge behind a flag is not a completed story. Files: `src/integration.ts` 2. Archive rather than delete Transitions are the metric history and are worth more than the story. Files: `src/archive.ts` 3. Export with full history A tracker you cannot leave is a tracker to avoid. Files: `src/export.ts` ### Done when - [ ] State changes require explicit declaration - [ ] Archiving preserves transitions and metrics - [ ] Export round trips including history - [ ] Deleted branches do not orphan links ### Watch out - Automatically moving a story to done when a branch merges is right most of the time and wrong in exactly the cases that matter, such as a merge behind a flag or a partial implementation. Make the transition explicit in the commit or the merge, so closing a story is a decision someone made rather than an inference.
# Operations · Shortcut ## Backup The transition log is larger than the stories and is what every metric depends on. Back it up with the same care, since losing it leaves a board with no history and no way to answer how long anything took. ## Restore Restore and confirm transitions are complete and ordered, since a gap produces cycle times that are silently wrong rather than obviously missing. Do a restore drill before the first real user, and write the date here when it passes. ## Monitoring Board query time at current scale and unused state count. The first degrades gradually as the dataset grows and is the thing that makes a tracker feel bad without ever failing. ## Incident checklist Metrics that stopped making sense usually mean the workflow gained a state without a definition, or a story was edited rather than transitioned. The append-only log distinguishes the two. 1. Contain the issue without destroying evidence or user data. 2. Record the timeline and affected scope. 3. Rotate exposed secrets and revoke compromised sessions or credentials. 4. Restore from a verified backup when needed. 5. Document the root cause, the remediation and the regression test. ## Release gate - [ ] Every state is confirmed to have a visible definition - [ ] Ten thousand items are confirmed to load and filter within target - [ ] Epic progress is confirmed derived from its stories - [ ] No per-person productivity view is confirmed to exist - [ ] Code integration is confirmed to require explicit declaration ## Launch constraint Do not market omitted Shortcut capabilities as implemented. The non-goals in `PRODUCT.md` remain user-visible limitations until they are deliberately delivered.
# Copy to .env and fill in. Never commit .env; this file documents it. # Required · secret. Stories, transitions and team activity. DATABASE_URL=postgres://localhost:5432/tracker # Required. Pagination is required at real scale, not an optimisation. BOARD_PAGE_SIZE=100 # Required. Measured at ten thousand items rather than at a hundred. BOARD_LOAD_TARGET_MS=500 # Required. Present as a constant. It becomes a performance measure regardless of intent. PER_PERSON_METRICS=never # Required. A merge behind a flag is not a completed story. AUTO_TRANSITION_ON_MERGE=never # Required. Transitions are the metric history and outlive the stories. ARCHIVE_RETENTION_YEARS=7
$ choose a build depth, inspect the files, then open the complete pack in your agent
People still pay for Shortcut because teams pay because project state has to remain authoritative through staff changes, outages, and years of accumulated workflow exceptions. The recurring cost buys auth, permissions, notifications, search, migrations, audit history, integrations, backups, and uptime, not just the visible interface.
xGit integrations, reporting, collaboration, and mature agile project semantics
xdeep integrations
xenterprise permissions
xlarge-scale reporting
xbattle-tested notifications and mobile apps
Don't feel like building it? These folks already made it free.
all 5 free alternatives to Shortcut →· no votes, no pay-to-list · just what's real
Shortcut pricing
| plan | monthly | annual (per mo) | what you get |
|---|---|---|---|
| free | $0/user | $0/user | Up to 10 users, 1 team, 1 workspace and 1 workflow |
| team | $10/user | $8.50/user | Unlimited users, up to 5 teams, 1 workspace and up to 5 workflows |
| business | $16/user | $12/user | Unlimited users, teams, workspaces and workflows; advanced roadmaps/security/reporting |
| enterprise | custom | — | Custom enterprise security, onboarding, support and controls |
free tierUp to 10 users, 1 team, 1 workspace and 1 workflow
billingmonthly + annual; 14-day Business trial, no credit card
hidden costsEach paid seat includes up to 5 no-cost Observer seats; users who need editing rights are paid. Enterprise is custom. Qualified nonprofits can receive Shortcut free.
verified 2026-08-14 · source ↗
Vibecode Shortcut
Kinda. The core of Shortcut is buildable in a weekend with the prompt on this page, but there are real gaps: Git integrations, reporting, collaboration, and mature agile project semantics, deep integrations. Read the honest list above before committing.
How much does Shortcut cost?
Shortcut costs about $10/month (Team, checked 2026-07-31), which is $120 per year.
What do I lose by replacing Shortcut?
Honestly: Git integrations, reporting, collaboration, and mature agile project semantics; deep integrations; enterprise permissions; large-scale reporting; battle-tested notifications and mobile apps. If any of those are load-bearing for you, keep paying.
Is there an open-source alternative to Shortcut?
Yes: Plane (Linear-and-Jira-shaped work tracking without the subscription; the stack behind it is not small) OpenProject (The enterprise project suite; free in money, expensive in menus) Redmine (Project tracking, time sheets, Gantt, and wikis from the era when software admitted it needed configuration) All 5 curated free alternatives are at vibecodeit.com/shortcut/alternatives. The prompt is for when you want it exactly your way.