Skip to main content
A finding is a problem an agent hit in the factory while working on an item, such as a flaky test or a wrong instruction. Agents record problems they hit in the factory so you can fix the cause before the next agent hits it. A problem in the agent’s own change is fixed, not recorded.

Read them on the item page

The work item page lists its findings on the Findings tab, one row per problem, with the most time lost first. Findings that name no time come last. When several agents in one build record the same problem, the tab shows one row. Its title and account come from the report that lost the most time. Its time lost is the sum of all the reports. A line under the title says how many times it was reported. Expand the row to read each report.
A work item page on its Findings tab, with findings sorted by time lost and columns for kind, items seen on, time lost and status

The Findings tab shows each finding's problem, how many items reported it, and the time it cost.

Each row has these columns:
  • Finding: the one-sentence title, and the file and line it is about. For a context finding it names the instruction’s path and line.
  • Kind: the finding’s category. A context finding also shows whether the instruction is wrong, broken or missing.
  • Seen on: how many items reported the finding’s problem, such as 3 items. Select it to open the problem drawer.
  • Time lost: the approximate minutes between the two events the agent marked, such as ~12 min. A row of several reports shows their minutes added. A finding with no marked events shows a dash.
  • Status: every problem is Open today.
A finding that reports two problems shows the first in its row. The expanded row names both.

Expand a row

Select the arrow at the start of a row to read the longer account:
  • What happened, Cause and What would help, as the agent recorded them.
  • Rule: for a context finding, the instruction’s path and the quoted sentence.
  • A fix goes to: the repository to change. For a context finding this is the control-plane repository and its commit when one was recorded. Otherwise it is the repository of the item’s first pull request.
  • What the agent was doing, as it recorded it, such as “build session”.
  • Problem: each problem the finding reports, and how the finding joined it: by matching an earlier report, by the agent’s link and its reason, or as the first report.
  • Open the session: a link to the agent’s session at the turn it recorded.

The problem drawer

Select a row’s Seen on count to open a drawer for that problem. It shows the problem’s title, kind, status, item count and the total time lost. Under that it lists every report, newest first:
  • the item it was reported on, linked to the item
  • the date and the time it lost
  • the finding’s title
  • how it joined the problem: “matched an earlier report”, the agent’s reason, or “first report”
  • Open the session, a link to the session at the window the agent marked
  • for a report that also reports another problem, a link that opens that problem’s drawer
The drawer and the tab are read-only. Nothing on them merges, splits, relinks or dismisses a finding. Viewing findings needs the evidence.read permission. Without it the tab shows no findings. An item with no findings shows No findings. Findings do not affect whether the work passes. No check, policy or merge gate reads them.

Read them across the factory

The Findings page in the sidebar lists every problem your work items reported, with the most time lost first. It sits between Work and Metrics. It needs the evidence.read permission, and a member without it sees no entry. A row is a problem, not a finding. A problem reported on ten items is one row. Each row has these columns:
  • Problem: the problem’s title. Select the row to open the problem drawer described above.
  • Kind: the category of the problem’s newest finding.
  • Items: how many work items reported the problem.
  • Reports: how many findings joined the problem.
  • Time lost: the approximate minutes the reports lost, added together. A problem with no measured time shows a dash.
  • Last seen: when the problem was last reported.
Sort the list by Most time lost (the default), Most reports or Last seen. A tie goes to the problem reported most recently. Narrow the list with these filters:
  • Kind: one of the six categories in the table above. A problem matches when its newest finding has that category.
  • Period: the last 7 days, the last 30 days (the default), the last 90 days or all time.
  • Search: type in the search box. A problem matches when its title contains every word you type, ignoring case.
A period counts only the reports inside it. A problem with no report in the period is left out. For a problem reported 40 days ago and again 3 days ago, the last 30 days show one report and only its time lost. The page address holds the sort and the filters, so a link to the page shows the same view to another member. The page loads 100 problems at a time. Select Load more for the next 100. A factory with no findings shows No findings are recorded yet. The API below reads the same figures as the page.

Read them over the API or MCP

Four read-only routes rank a factory’s problems and read findings back. Each is also an MCP tool, and each needs the evidence.read permission, which the Reader preset holds.
  • GET /v1/problems (tool list_problems) ranks the factory’s problems by reports (work items affected, the default) or minutesLost. Each row has its strict keys, reports, findings, minutesLost and avgMinutesLost.
  • GET /v1/problems/{problemId} (tool get_problem) returns one problem’s figures and its findings, newest first, at most 100.
  • GET /v1/findings/summary (tool get_findings_summary) returns time lost per category. A finding counts once even when it reports two problems.
  • GET /v1/work-items/{workItemId}/findings (tool get_work_item_findings) returns one work item’s findings, newest first and at most the newest 500 (pagination.truncated is true when there are more), with the problems each reports. A key scoped to one work item can read its own item’s findings and no other’s.
since and until limit every figure to findings recorded in that window. A problem with none in the window is left out. command matches problems with a finding whose command contains the text, ignoring case. file matches a path prefix on a finding’s file or rule path. A finding that reports several problems counts in full toward each, so the list does not add up to a total. Use the category summary for totals.

Reduce check failures

To find and fix the check that costs the most:
  1. Call list_problems with command=pre-push and sort=minutesLost. The first row is the costliest pre-push problem.
  2. Call get_problem with its id. The findings give the cause, a suggestion, the error line and the strict keys. A strict key is the exact text that joins a finding to the problem, so search your scripts and logs for it.
  3. Fix the check, the test or the rule, and open a pull request.
  4. After it merges, call list_problems again with since set to the merge time. If the problem is gone from the list, or its reports stopped growing, it stopped recurring.
These reads see only what agents recorded. A failed push by a person, or a CI failure no agent noticed, is not counted.

How findings group into problems

The same problem gets recorded again and again, on different items and in different words. Every finding therefore links to one or more problems: one thing in the factory that keeps costing time, reported by every finding that hits it. A problem belongs to your factory and lists every work item that reported it. Nobody merges or confirms anything. The agent that records the finding decides, using three rules. The three rules for what counts as the same problem:
  1. Same problem means one fix resolves both. The same error or symptom is not enough.
  2. A gap in the instructions is its own problem, separate from the thing it fails to mention. They are fixed in different places.
  3. A finding can report more than one problem. Link each one, or record one finding per problem.
A finding joins a problem in this order:
  1. A key matches. The finding’s own fields make keys. For example, a wrong instruction is keyed by the file that holds it, the quoted sentence and how it fails. A tooling finding is keyed by the command and its first error line, with numbers, hashes, paths, versions and durations ignored. A flaky test is keyed by test file and test name. A command alone never joins: two different problems can fail the same command. When a key belongs to a problem, the finding joins it, whatever the agent says.
  2. The agent names the problem. --problem <id> --link-reason <text> links the finding to that problem. Repeat --problem for each problem the finding reports.
  3. The agent asks for a new problem. --new creates one, titled with the finding’s title.
  4. Otherwise the agent chooses. The server searches every problem in the factory, whatever its category or repository, and returns the three closest. Nothing is stored. If nothing is close, a new problem is created.

Choose among candidates

When the search finds close problems, outerlayer emit finding prints each one. It shows the problem’s id, title, how many reports it has, and the title and cause of its reports. It then prints the three rules and exits with exit code 3. Exit code 3 is not a failure: it means the finding was not stored and needs your choice. The last lines say how to continue, so 2>&1 | tail -3 still shows them.
Run the same command again with one of these:
  • --problem <id> --link-reason <text> when the finding reports an existing problem. Repeat --problem for each one.
  • --new when none of the candidates is the same problem.
Each decision is stored once. The record holds the method (key, agent link, new, or no candidates) and the matched key or the agent’s reason. It also holds the candidates shown, the recording session and the time. The candidates shown are those the search offered for an agent link or new. A key join shows none, and so does a search that found none. Running the command again with an id already recorded on the item replaces that finding and keeps its problems. outerlayer emit findings <file> stores the findings that match a key, lists the ones that need a choice, and exits with code 3. Add problems with linkReason, or new: true, to those entries and run it again.

Mark when the problem started and ended

Every finding records how long the problem took. The CLI reads two events from the session’s transcript on your machine, and from the transcripts of the subagents it ran:
  • Start: the event named by --started-at. Without it, the start is the first tool output that contains the finding’s --error text.
  • End: the event named by --ended-at. Without it, the end is the newest event, the moment the finding is recorded.
When the session has events and no start is found, nothing is stored. The command prints the recent events, each with an id and its time, and exits with code 1:
Run it again with --started-at e118. An id with a prefix, such as a5c9fb78:e42, is an event of the subagent that prefix names. --find <text> lists every event that contains the text, older ones included, and records nothing. --untimed records a finding with no time, for a problem that cost none in this session. The server stores both events and the minutes between their times. A finding recorded where the CLI finds no transcript records no time, and still counts toward how often the problem occurs. Only Claude Code sessions have a transcript the CLI can read today.

Record one

An agent records one finding with outerlayer emit finding, or a batch from a JSON file with outerlayer emit findings. Each finding needs an id, a category, a title, a file and where it was recorded. It can also carry the cause, detail and suggestion, and the command, error line, test name or symbol that let the factory recognise the problem next time. The maintained outerlayer-findings skill tells agents when a problem is worth recording. outerlayer init installs it when you run init in a git repository.