Configuration
One YAML file. Every command reads asz.yaml from the working directory when no -config flag is
given, and -config FILE names another one. The file at the repository root is the default
configuration with every value written out, and a test holds it to the compiled defaults, so
reading that file is reading the defaults.
storage:
root: ./data
adapters:
- name: claude-code-local
enabled: true
source_root: ""
include: []
exclude:
- /private/tmp/**
collector:
mode: watch
interval: 5s
max_delta_bytes: 2097152
storage
| Key | Default | Meaning |
|---|---|---|
root |
./data |
The storage root: where collected data lands and where conversations are assembled. A relative path is resolved from the working directory. |
The default is ignored by git, so running the collector inside a checkout never stages private transcripts.
adapters
A list. claude-code-local reads Claude Code’s files from this machine. claude-code-changes
reads the change records the asz Claude Code plugin writes beside them. See
the changes adapter. claude-code-otlp receives the runtime’s own
exporter. See the receiver adapter. Every command runs once per enabled
adapter.
| Key | Default | Meaning |
|---|---|---|
name |
claude-code-local, claude-code-changes or claude-code-otlp |
|
enabled |
true for local and changes; false for the receiver |
A disabled adapter is skipped by every command. |
source_root |
empty | Where Claude Code keeps its files. Empty resolves it the way Claude Code does: CLAUDE_CONFIG_DIR, then XDG_CONFIG_HOME/claude, then ~/.claude, each followed by projects. Set it only to collect from a copy or a mounted directory. |
include |
empty | Session filters, see below. Empty means every session is a candidate. |
exclude |
/private/tmp/** |
Session filters, see below. |
metrics |
false |
Derive the runtime’s own metric family from the landed files, claude_code.token.usage in phase one, name for name with the runtime’s exporter. See Metrics. |
listen |
none | On claude-code-otlp only: the address the runtime’s exporter is pointed at, such as 127.0.0.1:4317, serving gRPC and HTTP with protobuf on the one port. |
metrics_lookback |
24h |
How far back the first derivation over a root reaches. A duration such as 24h, or a number of days such as 7d. 0 or none derives everything. Later passes derive every new file whole. |
Each named adapter inherits its own defaults for omitted fields. An explicit enabled: false
disables it, and exclude: [] clears the default exclusions. Naming only some adapters replaces
the default adapter list; it does not add the other adapters back.
Session filters
A session is judged by the working directory its main transcript was recorded under. An entry that
starts with / is a working directory, and ** after it matches everything beneath. Anything else
is a glob matched against the source directory name as Claude Code wrote it, which is the working
directory with every separator replaced by -.
A session’s child agents can run in other directories, so the filter looks at the main transcript only. A session that merely used a scratch directory for a child agent is still collected. When the main transcript has been pruned, the session is judged on all of its directories together and is excluded only when every one of them matches, so an orphaned child stream from a real project is still collected.
Claude Code runs its own helper agents in scratch directories under /private/tmp. Those sessions
are the tool’s, not yours, which is why they are excluded by default.
collector
| Key | Default | Meaning |
|---|---|---|
mode |
watch |
watch polls the source continuously. once makes a single pass, which is the backfill path over history that already exists. asz collect then exits, and asz server goes on serving what that pass produced. -once on the command line overrides the file. |
interval |
5s |
How long the pipeline sleeps between passes in watch mode. It is the whole period: asz collect and asz server land, parse and send once per interval. |
max_delta_bytes |
2097152 |
How much of a growing source the collector lands in one .sd file, 2 MiB. A large catch-up is split into several files. When the next source line is longer than the budget, the collector reads to the end of the source instead. That file then holds the long line and every complete line after it. A file travels whole as one log record, so the largest record a receiver has to accept is the largest file, not the budget. A change applies to new files only. asz repack brings an existing root under a new budget. |
Several local adapters
collector is set on each adapter, but asz collect and asz server run one pipeline for all
the enabled local adapters, claude-code-local and claude-code-changes. One pass reads them
all. See collect. One pipeline has one mode and one period, so the
settings combine:
- It watches when any of them has
mode: watch. It makes a single pass only when every one of them hasmode: once, or with-once. - It runs at the shortest
intervalamong them. A source that asks for 2 seconds is still read every 2 seconds when another asks for a minute. max_delta_bytesdoes not combine. Each adapter cuts its own files at its own budget.
A disabled adapter does not count. The receiver, claude-code-otlp, takes no collector block,
so it does not count either. When it is the only adapter enabled, asz collect sends what it
lands to export.otlp.endpoint every 5 seconds, the compiled default.
Both commands print the result when they start, on their source line: (every 5s) when the
pipeline watches, (once) when it does not. asz view collects nothing, but it checks the root
for new rounds at the same shortest interval.
parse
parse:
max_round_bytes: 2097152
| Key | Default | Meaning |
|---|---|---|
max_round_bytes |
2097152 |
The largest .sf round file the parser writes, 2 MiB, the same budget as a landed file. A round travels whole as one log record. The parser narrows a round’s input window until the round fits and leaves the rest of the evidence to the next round, so one parse pass may write several rounds. A round covering a single landed file is published whole even when larger. |
export
export:
otlp:
protocol: grpc
endpoint: ""
tls: false
service_name: ""
instance_id: ""
layer: AI_AGENT
batch_bytes: 8388608
max_bytes_per_minute: 0
logs: true
metrics: true
| Key | Default | Meaning |
|---|---|---|
protocol |
grpc |
The transport: grpc, or http with a protobuf body. The SkyWalking OAP accepts both. |
endpoint |
empty | Where the receiver listens. For grpc, host:port: the OAP’s gRPC port, 127.0.0.1:11800 by default. For http, the receiver’s base URL, to which /v1/logs is appended: the OAP’s REST port, http://127.0.0.1:12800. Empty means asz push refuses to run. |
tls |
false |
For grpc, connect with TLS, verified against the system’s roots. For http, the scheme of the endpoint decides. |
service_name |
empty | The service every record is attributed to. Empty means the runtime that produced each session, read off its landed header: Claude Code for claude-code-local, Mock Agent for mock. One service per kind of agent. |
instance_id |
empty | Sent as service.instance.id: who is pushing, in words the people reading the receiver recognise, for example a mailbox such as wusheng@tetrate.io, a name, or a machine. Empty means user@host of the machine running asz push, which is stable across restarts. |
layer |
AI_AGENT |
Sent as service.layer, the layer the receiver places the service in. The OAP selects its rules by layer, and a layer name is upper case with underscores. |
headers |
none | Sent with every request, as gRPC metadata or as HTTP headers, for example Authorization. |
batch_bytes |
8388608 |
How many file bytes one request carries at most, 8 MiB, which keeps a request under the 10 MiB the OAP’s HTTP server accepts and well under the 50 MB its gRPC server accepts. A file larger than this is sent alone, in a request of its own. |
max_bytes_per_minute |
0 |
At most this many bytes on the wire per minute: a pass waits before a request until a minute’s budget covers it. Zero is no limit. See Rate. |
logs |
true |
Send the landed files and rounds, as OTLP logs. |
metrics |
true |
Send the metrics spool, as OTLP metrics. One of the two must be on. |
See Export over OpenTelemetry for what is sent.
The changes adapter
adapters:
- name: claude-code-changes
enabled: true
source_root: ""
include: []
exclude:
- /private/tmp/**
collector:
mode: watch
interval: 5s
max_delta_bytes: 2097152
claude-code-changes lands the records the asz Claude Code plugin
writes: which files each shell command changed, and each edit made inside a subagent, as
git-style hunks. Empty source_root resolves plugins/data under the same directory
claude-code-local resolves, and reads every plugin directory named asz-changes-* under it.
Set source_root to collect from a copy. The session filters are the ones above, judged by the
workspace each session’s records name. It is on by default because it costs nothing when the
plugin is not installed: there is nothing to discover. It takes no metrics.
The receiver adapter
adapters:
- name: claude-code-otlp
enabled: true
listen: 127.0.0.1:4317
metrics: true
claude-code-otlp receives what Claude Code’s own OpenTelemetry exporter sends, with the
runtime configured as its documentation says: CLAUDE_CODE_ENABLE_TELEMETRY=1,
OTEL_METRICS_EXPORTER=otlp, OTEL_EXPORTER_OTLP_ENDPOINT at listen, over gRPC or
http/protobuf. Phase one lands its metrics in the storage root’s spool for asz push. Logs and
traces are accepted and dropped. It runs while asz collect or asz server runs, beside the
local adapter, and not with -once. metrics may be on here or on claude-code-local, never
on both: the configuration refuses to load, since the two would count the same tokens twice.
Precedence
-config FILEon the command line../asz.yamlin the working directory.- The compiled defaults, which are the values shown above.
A file may leave keys out. Anything unset takes its default, except that a file which lists
adapters replaces the whole list.