What Otis records
Surfaces
What a surface is, how your app names one, and how Otis uses surfaces to keep the parts of your product apart.
A surface is a named part of your product that users work in, such as one copilot, one MCP server or one command-line tool. Your app chooses the names. Otis stores the surface on each span and uses it to keep activity in different parts of your product apart.
This page explains how a surface is set and where it changes what Otis does. A service name says which codebase produced a span. A surface says which part of the product the user was in, and one service often hosts several.
Purpose of surfaces
Many products have more than one place where users work with AI. A chat assistant and an inline editor may live in the same app and share a session, and they succeed or fail for different reasons. Without a surface, their activity runs together. With one, Otis can find tasks in each part separately and report errors against the part where they happened.
Surface assignment
Surface describes the SDK options. In summary:
- For a whole app. Set
surfacewhen you initialize the SDK, and every span from that app carries it. - For one flow. Set
surfacein the context for a flow. This overrides the app's default for the spans in that flow. - For an MCP server. Set
surfacein the server's options. If you leave it out, the app's default applies. - For a command-line tool. The surface defaults to the tool's name.
Otis stores the surface exactly as you send it. A span with no surface has an empty one. Choose a small set of stable names, because each distinct name is treated as a separate part of your product.
Effects of a surface
Task detection
Otis finds tasks within each surface separately. How strictly it does so depends on the kind of task:
- Activity tasks are found per surface. Otis measures idle time within one surface, so activity elsewhere doesn't keep a burst open.
- Conversation tasks are grouped by chat ID first. A chat stays together even if its messages carry different surfaces. The surface separates only the messages that have no chat ID.
- Tool tasks are grouped by chat ID and surface together. Calls to two surfaces are separate tasks even inside one chat.
Each task records every surface that its spans carried.
Error reporting
Otis counts failures for each operation on each surface. An insight about a failing operation names the surface, so the same operation in two parts of your product is reported as two findings.
Session descriptions
When Otis writes a narrative for a session, it records the surface of each step and the points where the user moved from one surface to another.
Answers in chat
When you ask Otis to compare parts of your product in chat, it compares by surface.
Reading surfaces
- Label all of a flow, or none of it. If only some spans in a flow carry a surface, Otis treats the labeled and unlabeled spans as two different surfaces. In a session that mixes conversation and product actions, unlabeled actions then form tasks of their own.
- An empty surface is a surface. Spans with no surface are grouped together, apart from every named surface.
- Names are compared exactly. Otis doesn't change the case of a surface or trim it, so
Copilotandcopilotare different surfaces.
Surfaces in Otis
In the data browser, the span list and the task list each have a Surface column and a filter. Opening a span or a task shows its surface.