Skip to content

Workspaces

Everything a person reads or edits lives at the top level of the workspace; machine state lives under .triage/, which init adds to .gitignore.

triage.toml        project definition: repo, checkout, env, categories, fields, rules, skills, models, sandbox
settings.json      agent defaults saved from the app's Settings page (overrides [agents])
AGENTS.md          the procedure agents follow
NOTES.md           reusable techniques agents add as they learn them
issues/<N>.md      one writeup per issue, the source of truth
repros/<N>*.py     reproducers, their logs and screenshots
INDEX.md           generated overview of all writeups
prs/policy.md      the contribution policy PR review checks against
skills/            agent skills (directories with a SKILL.md)
prompts/           role prompts for triage and review
templates/         the writeup template
triage.py          entry point: ./triage.py <command>
.triage/           issue list, caches, claims, jobs, transcripts, label and PR review results

Writeups

A writeup is markdown with YAML frontmatter:

---
issue: 386
title: "MultiSelect marks first item in options when values match"
category: confirmed
confidence: high
reproduced: yes
repro: repros/386_app.py
recommendation: keep
summary: "Selecting a later option with a duplicate label still marks the first one"
verified: no
---

## Diagnosis
...

## Proposed GitHub comment
...

./triage.py validate checks writeups against the categories, fields and rules in triage.toml. ./triage.py finish <N> stamps the tested-on versions, validates the file, releases the claim and regenerates INDEX.md. When you edit a writeup in the app it is validated before saving, and the editor warns you if the file changed on disk in the meantime.

Categories and fields

[[categories]] lists the outcomes agents can choose from, in decision order; the order is part of the procedure in AGENTS.md. [fields] adds project-specific frontmatter fields, each with a type (str, bool, enum, list), optional values, default and required, and a column title to show it in INDEX.md.

[fields]
classic_ui = { type = "bool", default = false, required = true, column = "Classic" }
pmui_reproduces = { type = "enum", values = ["yes", "no", "untested", "n/a"], default = "n/a" }

Rules

Rules encode project knowledge that would otherwise live in a prompt. There are three stages:

  • validate rules (the default stage) check finished writeups. when matches frontmatter values, and require lists fields that must then be filled, or expect lists the values they may have.
  • scaffold rules set fields when a writeup is created, based on what the issue mentions.
  • context rules add hints next to components detected in the issue text, shown in ./triage.py context.

Scaffold and context rules can test attributes of detected components with "component.<attr>" = true. The component map comes from [components], typically generated by a script in the project.

# Panel: classic widgets with a panel-material-ui counterpart
[[rules]]
stage = "scaffold"
when = { "component.modern" = true }
set = { classic_ui = true }

[[rules]]
stage = "context"
when = { "component.modern" = true }
hint = "modern counterpart: `{modern}`; test it too"

[[rules]]
when = { category = "classic-ui" }
expect = { pmui_reproduces = ["no", "untested"] }
message = "classic-ui requires `pmui_reproduces: no` or `untested`"

Skills

Skills are directories with a SKILL.md (name, description and instructions). [skills] paths lists where to look; each entry can be a skill or a directory of skills. The built-in agent sees every enabled skill's name and description and loads the full instructions only when it needs them. Disable skills with [skills] disabled or from the Settings page, and list them with ./triage.py skills.

Syncing

./triage.py sync fetches the open issue list (title, labels, issue type, update time). --details also refreshes the cached body, comments and timeline of every issue, and --stale only those that changed since they were triaged. ./triage.py stale lists writeups whose issue has new activity. The Sync page in the app shows the same information with a history of past syncs.