> ## Documentation Index
> Fetch the complete documentation index at: https://docs.basset.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Instrument metadata

> The fields that describe how an instrument reports, not what it reports

Every instrument in `basset menu`, and on its own page in this section, carries
the same handful of fields below its **Reveals** list. **Reveals** says what a
reading contains. The fields below say how it arrives — which is what decides
whether you read one reading or a hundred, and whether it shows up the moment
you ask or only when something happens.

## Delivery

The mechanical shape a reading is produced by.

| Value | Means |
| - | - |
| `reading` | Pulled once, on demand, when the instrument activates — a status read |
| `stream` | An ongoing hook that emits readings on its own, as things happen |
| `fault` | Never runs on its own — fires only when a different instrument raises a fault |

`fault` instruments are triggered by one of three kinds: `hang`, `termination`,
or `memoryPressure`. Today only
[`runtime.threadSnapshot`](/instruments/runtime/thread-snapshot)
is fault-delivered — it fires when
[`concurrency.mainThreadHang`](/instruments/concurrency/main-thread-hang)
crosses its threshold or
[`memory.pressure`](/instruments/memory/pressure) crosses into critical, and
shares a `faultId` with the reading that triggered it.

## Cadence

The rhythm within that delivery shape.

| Value | Means |
| - | - |
| `once` | A single reading, taken at activation |
| `onChange` | A reading each time the watched state changes — no fixed schedule |
| `interval` | A reading on a fixed timer, aggregated into that window |

Every `interval` instrument shares one construct on the device — a timer
that fires on a fixed period and hands the window's own instrument a chance
to report. Whether that instrument then always reports (even an empty
window) or only when there's something to say is a choice each instrument
makes internally, not a distinction this catalog tracks — both read as
`interval` here, since the wire shape and the timing are identical either
way.

Delivery and cadence are independent. `stream` instruments are usually
`onChange` or `interval` — but
[`camera.device.inventory`](/instruments/camera/device-inventory) is `stream`,
`once`: it observes for changes the same way the rest of the camera domain
does, and simply never sees one during an ordinary run, since the hardware a
phone exposes doesn't change while the app is open.

`basset menu` and each instrument's own page print delivery and cadence
together, as one field: `stream, interval`.

## Mechanism

What the instrument hooks to produce a reading.

| Value | Means |
| - | - |
| `statusRead` | Reads a value the OS already tracks — no hook installed |
| `notification` | Subscribes to a `NotificationCenter` post |
| `osWatcher` | An Apple watcher object basset creates and owns (`NWPathMonitor`, `CADisplayLink`) — a live callback, but on nothing the app itself created or exposed |
| `kvo` | Key-Value Observing on an object the OS vends |
| `swizzle` | Intercepts a method at load time, ahead of the app's own implementation |
| `delegateProxy` | Inserts a forwarding delegate ahead of the app's own |
| `runLoopObserver` | Watches the main run loop directly |
| `machCall` | A low-level system call |
| `osLogStore` | Reads the unified log |
| `reflection` | Reads a framework's own internals by name |
| `none` | No live hook — the value is computed on demand or supplied by another instrument |

This names what triggers a reading, not just how its values are fetched once
triggered. [`network.session.configuration`](/instruments/network/session-configuration)
reads a `URLSessionConfiguration`'s properties directly, but it only learns a
session exists by riding the same swizzled factory
[`network.urlSession.taskMetrics`](/instruments/network/url-session-task-metrics)
installs — so it's `swizzle`, not `statusRead`. `statusRead` is reserved for
an instrument with nothing watching at all: `once` delivery, or a `stream`
instrument like [`camera.device.inventory`](/instruments/camera/device-inventory)
whose only "watching" is the dispatch shape itself, never an installed hook.

## Overhead

A coarse cost rating, from negligible to high. Instruments in this catalog
today run `negligible`, `low`, or `medium` — nothing currently ships at
`high`.

## Requires

The floor an instrument needs to run: a minimum iOS version, whether it needs
real hardware, and the earliest basset SDK release that shipped it. An
instrument that reads camera or Bluetooth state, for example, reports nothing
useful in a simulator and says so here. Most of the catalog has shipped since
`0.1.1`, the first tagged release — an instrument added later carries the
version it arrived in, so integrating against an older pinned SDK tells you up
front which instruments aren't there yet, rather than a request that silently
activates nothing.

## Config

Most instruments take no configuration — activating one by name is enough.
The few that expose a tuning knob list it here, as a key, a type, and a
default. Set one on activation with `name:key=value,...`:

```bash theme={"dark"}
basset request create -i concurrency.mainThreadHang:thresholdMs=300
```

An instrument with no config fields listed accepts no `:key=value` at all —
sending one is refused rather than silently ignored.

## Related

Other instruments that answer an adjacent question — read together when one
alone doesn't explain what happened.

## Describes

Almost every instrument describes the run that's capturing it right now. A
few describe a run that already ended — this field says which, so a reading
about a crash three launches ago isn't mistaken for one about the current
session.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.