Bugs
A bug is what your team hit on the way to delivering the work. Nine statuses, eight typed relations, and an initiative parent that is always required. The agent can suggest triage and surface potential duplicates as you file.
A bug is what your team hit on the way to delivering the work. A customer reported it, a verification plan caught it, a test run failed, or a developer noticed it in a sandbox; whatever the path, the bug ends up as a record that the team can triage, schedule, and verify a fix for.
A bug always rolls up to an initiative so it has somewhere in the work model to belong. It can also be scoped to the plan under which it was found, if the team can point to the specific piece of work that surfaced it. The plan parent is optional; the initiative parent is not. This is the difference between we found this while shipping the CSV server endpoint (plan + initiative) and we found this somewhere in the export feature (initiative only).
If you are coming from Jira, a bug is a Bug-type issue, but with a stronger requirement that it belongs to a Feature (the initiative). If you are coming from Linear, a bug is an Issue typed as a bug, with a clearer split between severity (how bad the impact is) and priority (how soon we plan to fix it).
How a bug sits in the work model
The initiative is the required parent. A plan can be the optional parent the bug was found under. Eight typed relations connect a bug to other bugs, test cases, steps, and pull requests. A sprint can pick it up for a time-box without owning it.
How it looks in practice
Continuing the worked example.
While Priya was finishing the CSV server endpoint implementation plan, a verification run caught a regression: exports that span more than two months of data time out. Sarah files it as a bug.
| Field | Value |
|---|---|
| Title | Export timeout on large date ranges |
| Initiative | CSV Export on the Reporting Page |
| Plan | CSV server endpoint |
| Reporter | Sarah Chen |
| Severity | High |
| Priority | High |
| Status | In progress |
| Assignee | Priya Patel |
| Component | reports.export-service |
| Environment | staging |
| Source | test-execution |
| Estimate | 2 hours |
| Sprint | Sprint 24, position 5 |
The distinctive parts are populated like this.
Relations (3, on the sidebar).
| Type | Target |
|---|---|
| found-by | Test case: Export 6 months of data, 50k rows (failed in staging run) |
| affects-step | Plan step: Stream CSV writer to response on CSV server endpoint |
| related | Bug: Reporting page slow render on big result sets (separately tracked) |
AI triage suggestions (when Sarah filed it, the action launcher offered).
| Field | Suggested | Reason |
|---|---|---|
| Severity | High | "Customer-visible workflow blocked above 2-month range; downgrades export to unusable." |
| Component | reports.export-service | "Body mentions streamCsv and references /api/reports/export; both live in this service." |
| Labels | regression, performance | "Behavior worked at smaller ranges; failure mode is timeout, not error." |
Now look at how the bug connects.
Upward. The bug rolls up to the CSV Export on the Reporting Page initiative. On the initiative's Bugs tab Sarah sees it sitting alongside the rollup chip on the Spec tab showing 1 bug open, 1 total. The bug also points at the CSV server endpoint plan as its optional parent; on the plan detail page the Bugs tab lists it.
Sideways. The bug sits in Sprint 24 (the same sprint as the three plans), at position 5 on the team's mixed-entity backlog. On the sprint board it appears in the In progress column with a coral accent that distinguishes it visually from the plan cards. The team is working it alongside Priya's other plan in the same sprint.
Through the relation graph. The bug carries three typed relations: a found-by link to the failing test case run, an affects-step link to the implementation step that wrote the streaming response, and a related link to a separately tracked bug about reporting-page performance. Each relation is a typed pointer rather than a free-form note, so the graph can be queried (show me every bug found by this test case; show me every bug that affects this step) instead of read by eye.
Rollups at a glance. On the initiative the bug counts as 1 in Bugs open count. Once Priya marks it Fixed and Sarah verifies it, the bug drops out of Bugs open count but stays in Bugs count (which is total non-cancelled). On the sprint board it sits in the In progress column with the plans.
Statuses
Nine. Backed by a real workflow, enforced server-side.
| Status | What it means |
|---|---|
| Triage | Just filed; needs severity, priority, and assignment. |
| Backlog | Triaged and accepted; not yet scheduled for work. |
| Todo | Scheduled; will be picked up this cycle. |
| In progress | Developer is actively working on a fix. |
| In review | Fix submitted; a pull request is under code review. |
| Fixed | Fix merged; awaiting verification by the reporter or QA. |
| Verified | Verified that the fix resolves the issue. |
| Closed | Done; no further action needed. |
| Canceled | Will not fix; the resolution field captures why. |
Open vs closed for rollups
For the initiative's Bugs open count rollup, five statuses count as open: triage, backlog, todo, in-progress, in-review. The other four are out of the count: fixed, verified, closed, and canceled. The split mirrors how teams actually use the rollup. Open is we still owe this work; the moment a fix is merged, the bug stops weighing against the team's open count even though it is still pending verification.
Canceled bugs are excluded from total counts as well; a bug that gets canceled was effectively never a real bug.
Resolution and root cause
When you close or cancel a bug, the platform asks for two pieces of metadata that turn the closed record into something useful later.
The resolution picker captures why the bug is no longer worked: fixed, duplicate, won't-fix, cannot-reproduce, by-design, or obsolete. The Cancel transition refuses to save without a resolution selected, so a canceled bug always carries a recorded reason. The decline dialog that surfaces when you pick Cancel from the status dropdown narrows the choices to four: won't-fix, by-design, cannot-reproduce, and obsolete. The other two (fixed and duplicate) are not cancel reasons; they are status moves of their own (Verified / Closed-as-duplicate), so the dialog deliberately leaves them out. The full six-value picker is available on the Classification card if you ever need to re-record a different resolution after the fact.
The root cause picker captures what kind of thing this bug was. Nine values are available: code-defect, design-flaw, missing-requirement, configuration, environment, third-party, regression, data-issue, performance. Filling this in is optional but the analytics pay off over time; teams that fill it in religiously can ask how much of our work last quarter went to regressions? and get a real answer.
Reopens
The workflow allows reopens. From Closed you can transition back to In progress; from Canceled you can transition back to Triage. The reopen creates a new audit-log entry with the change source recorded, so a reader can tell when and why a bug came back. The full set of bug statuses and transitions, and what your admin can change, is covered in Customizing workflows.
Severity and priority
Two fields that look similar and get confused, kept separate on purpose.
Severity measures the impact of the bug on a user. Four values: critical (the product is unusable for affected users), high (a major workflow is broken), medium (an annoying defect with a workaround), low (a polish issue). Severity is descriptive; it is meant to be set by whoever files the bug, based on the experience.
Priority measures how soon the team plans to fix it. Four values: urgent, high, medium, low. Priority is the team's commitment; it is set during triage based on capacity, the release timeline, and the rest of the backlog.
Keeping them separate matters because a high severity bug can be low priority (yes, this is a real defect; no, we are not going to fix it this quarter; the user can use the workaround). A low severity bug can be high priority (the impact is minor but the fix is one line, and we want it shipped before the customer call). Folding the two into one field forces the team to pretend these are the same conversation, which they are not.
The matrix above is illustrative, not prescriptive. A team will define its own cells based on its product, its customers, and its current commitments. The right answer for a medium / urgent bug at a B2B SaaS startup mid-launch is not the same as the right answer at a regulated enterprise platform in maintenance mode. The matrix is a vocabulary for the triage conversation; the team picks the policy.
When you create one
The flow is short.
- Open the place the bug belongs. Most of the time that is an initiative's Bugs tab or a plan's Bugs tab; the platform pre-fills the initiative and the plan based on where you are.
- Click New bug. The form opens. Title and severity are required; everything else is optional at create.
- Save. The bug lands at status Triage and the agent runs an inline suggest-triage pass for severity, priority, component, and labels. You can accept or override each suggestion before moving the bug into Backlog or Todo.
A bug can also be filed from outside the planning surface. The four source kinds are tracked on the record so a reader can tell where the bug came from later.
- Manual is the default; a person filed it.
- Chat is set when the agent files a bug from a conversation (you mentioned a bug in chat, let me file it for you).
- Test-execution is set when a verification run records a failure; the bug is created with the failing test case as a
found-byrelation, and the same test case ID is also stamped onto the bug'ssourceTestCaseIdas a first-class field. The relation makes the bug queryable through the graph; the source field makes the origin unambiguous even if the relation is later edited. - Automated is set when an integration or a background flow files the bug (for example, a flaky-test detector).
Filing a bug from chat
The fastest way to file a bug is to tell the agent what you saw. An engineer in a chat about a plan says I am hitting a timeout when I export more than two months of data; the agent recognizes the report shape, drafts a bug title, body, severity, and component grounded in the conversation context and the plan's repo, and offers to file it. You accept or edit the draft, and the bug lands as a real record with source: chat and a link back to the chat session.
This is the moment that a sloppy verbal bug report ("hey the export is broken") usually evaporates by the end of the day. The agent's draft pre-populates the parent initiative from the chat's scope, attaches the relevant log lines, picks a sensible severity from the wording (timeout and blocked suggest high; flicker and off-by-one suggest medium or low), and proposes a component based on which files the chat had been editing. The reviewer can tighten any of these in one click, but the floor is much higher than a one-line file this note.
The distinctive parts
AI suggest-triage
A bug filed in Triage status can be triaged by the agent. The General card in the sidebar carries an inline AI Suggest button. Clicking it runs the agent across the bug's title, body, and component context and returns a structured suggestion for severity, priority, component, and labels.
Each suggested field carries a one-sentence reason. The reasons matter; they are the difference between the agent thinks this is High severity (opaque) and the agent thinks this is High severity because the body mentions a customer-blocking timeout (auditable). You apply each suggestion individually with an Accept button, so you can take the severity and reject the labels if the reasons do not hold up.
The agent is allowed to omit fields it cannot confidently propose. A short, low-context bug body ("dashboard slow on Tuesday") might come back with only a severity suggestion and nothing else, because the rest of the context is missing. The agent also omits any field whose suggested value would match what is already on the record, so it does not redundantly re-affirm decisions that have already been made. Honest omissions matter more than impressive-looking guesses.
Suggest triage is most useful at the moment a non-engineer files a bug. A product manager, a customer-success engineer, or a support engineer reporting what a customer just told them is operating without the right vocabulary for the severity field; medium and high and urgent are not their daily words. The agent's draft gives them a starting set with explicit reasons, which they can adjust if they disagree. It is least useful on a bug the engineering team filed for itself out of a verification run, since the structured fields are usually obvious in that context.
Suggest triage is non-blocking and best-effort. If no AI runtime is reachable from the workspace, the action returns an empty result rather than failing; the area renders an empty state and the bug stays in Triage. The same AI-runtime cascade that governs every other agent run applies here, so the cost path is the workspace's normal one.
Potential-duplicate detection
When you file a new bug, the platform runs a token-overlap check against every open bug already filed under the same initiative and surfaces up to three candidates that look similar. The check is non-blocking and the result is returned inline on the create response; the new bug saves regardless, and the candidates render in a dialog the moment the save completes. Closed and canceled bugs are excluded from the scan, so a resolved older bug does not keep getting suggested as the same issue forever.
The duplicate signal is a ranked hint, not a labelled diagnosis. The platform returns the candidate bugs themselves (title, status, the rest of the record) sorted by similarity; the score that ranked them stays server-side. If one of the candidates is in fact the same bug, link it as duplicate-of with one click and the dialog moves the new bug onto a closed-as-duplicate path. If none of them are right, dismiss the dialog and the new bug stays open. The signal is most useful in workspaces with a lot of customer-reported bugs, where the same issue tends to land twice or three times before someone notices.
The relation graph
A bug carries up to eight kinds of typed relation, captured in the sidebar.
| Relation | What it points at |
|---|---|
| duplicate-of | The canonical bug this one duplicates. Closing as duplicate is a separate workflow move on the status side; the relation is the structural pair. |
| related | A loosely associated bug or test case. |
| blocks | Another bug this bug is blocking. |
| blocked-by | Another bug blocking this bug's fix. |
| regressed-from | A previously fixed bug that this bug regressed. |
| found-by | The test case or step that surfaced this bug. |
| fixed-by | The pull request that fixed this bug. |
| affects-step | The specific step (on a plan or a flow) the bug breaks. |
Each relation is a typed pointer with a target type (one of bug, test-case, step, commit, or pull request) and a target ID. The sidebar's Relations card lets you add and remove relations; each relation renders with the target's title and a click-through to it.
The graph is free-form: nothing checks for cycles or contradictions, and a bug can carry as many relations of as many types as the team finds useful. The whole graph is queryable through the workspace-wide grid: show me every bug found by this test case is a column filter, not a special view.
This is what turns a bug record from prose into data. A team that never types its relations has a list of bugs that read like a forum thread; a team that types its relations every time has a graph it can ask questions of. Which test case finds the most regressions? is a found-by filter combined with a regressed-from filter; which engineer's PRs are linked to the most fixed-by relations? is a join across the graph. None of this needs a dashboard project; the grid is the dashboard. Six months of disciplined relation-typing turns into a real engineering analytics surface for free.
How a regression gets caught
The regressed-from relation is the most under-rated of the eight. When a previously-fixed bug comes back, the engineer files a new bug and links regressed-from to the old one. The platform now has a graph edge that says this part of the product has broken twice; the next time someone asks what surface area regresses most in our product?, the answer is one filter away.
This matters because the answer informs where to spend the next quarter's test budget. A bug filed five times against the same plan over twelve months is a structural test-coverage gap; the team can read it directly off the graph, without anyone running a quarterly review. The fixed-by relation closes the loop: linking the PR that fixed the regression turns the graph edge into a complete causal chain (here is the bug, here is the PR, here is the test case that should have caught it but did not). Six months of that history is a credible answer to why do we keep breaking this?
Customer-reported vs internally-found bugs
The source field is a quiet workhorse. Combined with reporter (who filed) and rootCause (what kind of issue this is), it lets a team triangulate where its bug volume actually comes from.
The query a leader asks every quarter is some flavor of how many customer-facing regressions did we ship? The combination is source: manual (a person filed it) plus reporter outside the engineering team (a PM, CSE, or customer-success engineer) plus rootCause: regression. The same three fields can answer what fraction of our bugs are internal dogfooding? (source: manual + reporter on the team), what is our verification catching? (source: test-execution), and what is the flaky-test detector noticing before anyone else? (source: automated).
The point is not the specific queries; it is that the structured fields make queries like these answerable from the grid rather than from a separate analytics surface. A team that fills these in religiously is depositing into an analytical surplus they can spend later. A team that does not fills out a dashboard project six months later instead, and the dashboard never has the historical depth the grid would have had.
Sprint membership
A bug can sit in at most one sprint at a time. The sprint picker on the sidebar writes the sprint ID and the bug's position within that sprint's backlog. Clearing the picker unassigns the bug, which sends it back to the unscheduled list on the workspace-wide grid.
On the sprint's mixed-entity backlog the bug renders as a coral card alongside the plan cards, mapped onto four unified columns: Todo (bug triage / backlog / todo), In progress (bug in-progress / in-review), Done (bug fixed / verified / closed). The bug's nine statuses are kept on the bug; the sprint board only uses them to decide which column to render in. A bug in Blocked-equivalent status does not exist; the workflow does not include one for bugs, so the bug column maps from the bug's own status independently of the plan's status mapping.
Estimation
Like plans, bugs can carry an estimate in hours, in points, or in both. The team's primary estimate unit (set on the team's settings page) decides which one renders by default on the grid and on the sprint backlog. Sprint capacity rolls up the estimates from both plans and bugs in the sprint, so a bug counts against the team's capacity the same way a plan does.
The detail page
A bug has a deliberately tight detail page. Two tabs at the top:
- Spec is the body of the bug, a markdown document that captures repro steps, expected vs actual, environment notes, and any logs or stack traces.
- Documents lists files attached to the bug (logs, screenshots, customer emails).
Most of what shapes a bug is metadata, not body, so the detail page leans heavily on the sidebar. The sidebar cards, top to bottom:
- General carries the heaviest load: status, severity, priority, assignee, estimate (hours and points), sprint picker, AI triage suggestions when they are available, reporter, source, and the created and updated timestamps.
- Parent context (conditional) renders the parent plan and the required parent initiative as click-through chips. It appears when at least one parent is set.
- Classification holds labels, component, environment, root cause, and the resolution chip when the bug is closed or canceled.
- Version info records the found-in-version and fixed-in-version build references.
- Relations is the typed-relation graph from above (the eight kinds, with the add and remove controls).
- Integration links (conditional) lists work-item references in linked systems like Azure DevOps; the card hides itself if there are no links.
- History lists recent activity on the bug.
The page header carries the status dropdown (with allowed transitions only), the action launcher for the bug's AI actions, and the kebab for edit, delete, and the rest. Continue in Chat is deliberately not on the bug detail page; clicking the bug's primary chat action redirects to the parent plan's chat panel with the bug pre-attached to the conversation. The broader work-context (the plan's body, the linked repo, the verification results) lives on the plan, so the chat about what to do about this bug opens where that context is. The bug stays linked into the session; the agent's edits to the bug record from chat are tagged AI-authored on the History card.
The list
The Bugs page is the workspace-wide view. It runs on the shared data grid, with the standard column filters, the filter panel, inline editing, bulk edit, and shareable URL views.
The default columns are title, severity badge, priority badge, status badge, assignee avatar, component, environment, labels, and the updated timestamp. The filter panel adds source, plan, initiative, and the per-relation filters.
Triage mode
A toggle in the toolbar switches the grid into Triage mode: the status filter is replaced with Triage only, and the sort flips to severity first (critical first, low last) then created-at (newest first), so the most impactful unrecorded bugs surface at the top. The intent is to let a triage owner work through the inbox in one sitting without leaving the grid.
Triage mode is meant to be the first thing a triage owner does in the morning. The view is shareable as a URL, so a team that rotates triage can hand off the inbox by sending a link.
History, soft-delete, restore
Bugs are not snapshot-versioned the way initiatives and plans are; the field set is small enough that the per-event audit trail covers what changed. The sidebar's History card surfaces the recent activity for the bug pulled from the audit log: status moves, severity and priority edits, sprint assignments, relation changes, and AI suggestions applied. Each entry carries the actor, the timestamp, and a marker for whether the edit came from a person or the agent.
Soft-delete and hard-delete live on different surfaces, which is worth being explicit about.
From the list, soft-delete
The Bugs page lets you soft-delete a bug from its row menu. The bug drops out of the default list and lands in the Trash. From the trash view, Restore brings the bug back at its previous status with relations and sprint membership intact; Delete permanently is the hard-delete path for unrecoverable cleanup.
From the detail page, hard-delete
The bug detail page's kebab carries a single Delete action that is hard-delete. A confirm dialog with explicit "this cannot be undone" copy stops you from doing it by accident. The detail page is the I know what I am doing surface; the list page is the I am triaging through fifty rows surface, and the soft path lives there.
The audit log captures the actor and timestamp on either path, so deletes are recoverable as a fact even when the record itself is not.