# What HypAware records, and how to control it

Canonical: https://hypaware.ai/docs/privacy

HypAware records AI activity on your host. This page explains what is
captured, where it goes, and how to control it. If your team is rolling
HypAware out, read this page before you enroll.

## What gets recorded

Each capture source you enable during `hyp setup` records into the local
query cache under `~/.hyp` (`HYP_HOME`):

| Source | What lands in the cache |
| --- | --- |
| `claude` | Claude Code prompts, responses, tool calls and results, system prompts, tool definitions, and working directory where available |
| `claude-desktop` | Claude Desktop conversations imported from local transcripts on macOS |
| `codex` | Codex CLI and Desktop conversations imported from their shared local session files |
| `codex-cloud` | Codex Cloud coding chats read from OpenAI's service with the ChatGPT login Codex keeps on your host (HypAware keeps no copy of it): user and assistant text, command calls and their outputs, and MCP calls and results; no reasoning content |
| `chatgpt-work` | ChatGPT Work web and mobile conversations, read the same way as `codex-cloud`; they can include everyday conversations that are not about coding. Off unless you choose it |
| `cursor` | Cursor editor and CLI conversations, including file contents and command output seen by its tools; explicitly connected Cloud VMs also record API text and supplied tool/edit observations |
| `opencode` | OpenCode CLI and Desktop conversations from its managed plugin and history exports |
| `pi` | Pi conversations from its managed extension and local session files |
| `droid` | Factory Droid local CLI transcripts, including prompts, responses, tool arguments and results, and working directory; no billed token usage or cost |
| `grok` | Grok Build local sessions, including prompts, responses, reasoning summaries, tool arguments and results, and working directory |
| `openclaw` | OpenClaw conversations from gateway traffic and local transcripts |
| `hermes` | Hermes Agent conversations read from its local state database |
| `goose` | Goose CLI and Desktop conversations read from its local session database, including tool calls and results, token usage, and working directory |
| `crush` | Crush conversations read from each project's local database, including tool calls and results and the project directory; no token usage. The `files` table, which holds copies of file contents, is never read |
| `mastracode` | Mastra Code conversations read from its local `mastra.db`, including tool calls and results and the project directory; no per-turn token usage or cost. Only the threads and messages tables are read; `settings.json`, `auth.json`, `mastra-vectors.db` and the observability store are never read |
| `antigravity`, `antigravity-desktop` | Antigravity CLI and Desktop conversations read from their local summary databases and transcripts, including model thinking, tool calls and results, and working directory |
| `copilot` | VS Code Copilot completed spans from its local databases, for sessions with a verified local working directory |
| `nanoclaw` | NanoClaw Claude transcripts read from an explicitly configured local installation |
| `langgraph` | LangGraph model, tool, and graph callbacks from your application, with its working directory and Git context |
| `ollama` | Ollama CLI and SDK chat and generate requests sent through the local capture route: system, user, and assistant text and the new response's token usage. Image bytes are omitted, and an exchange with thinking or tool calls is not saved |
| `raw-anthropic`, `raw-openai` | API requests and responses routed through the local gateway |
| `otel` | OpenTelemetry logs, traces, and metrics sent to the local OTLP listener |
| `github` | Structural repository activity such as issue, pull request, commit, file, review, and comment metadata; content remains on GitHub |
| `linear` | Structural issue metadata for configured teams (identifier, team, state, and Linear ids of the creator and assignee) and GitHub pull request links attached to those issues; titles, descriptions, and comments remain in Linear |

[Cursor Cloud](https://hypaware.ai/docs/integrations/cursor/index.md#cursor-cloud-agents-beta) is separately
opted in with `hyp cursor-cloud connect` inside the VM. Its local grant binds
one agent and repository, and holds no API key. The runtime key is sent only to
Cursor's fixed API origin for conversation reads; captured rows follow the
existing recording and export policy. Disconnect revokes new capture and
preserves previously captured data.

Conversation capture includes message content, not just metadata. Depending on
what the client exposes, records can also include system prompts, tool arguments
and results, working directories, and Git metadata. The available fields differ
by client and capture method.

Rows age out according to [local retention settings](https://hypaware.ai/docs/configuration/index.md#set-local-retention).
Retention does not delete original client transcripts or copies already exported.

### The raw-body spool

With Claude Code attached, Claude Code writes each raw request and response
body into `~/.hyp/spool/claude-bodies`, a directory HypAware creates
owner-only (`0700`). It is a transit area, not storage: HypAware reads a file
only for the few fields its event stream leaves out (the system prompt, the
tool list, message ordering, untruncated tool arguments) and deletes the file
as soon as it has them. The same content is already in Claude Code's own
transcripts under `~/.claude/projects`.

Spool cleanup works as follows:

- A session you ignored, by `.hypignore`, by a host-local marking, or with
  `hyp session ignore`, has its bodies **deleted unread**, not skipped.
- The default cap is 512 MB, configured as `telemetry.spool_max_bytes` in
  the `@hypaware/claude` plugin's config. The listener and Claude hooks enforce
  it by deleting the oldest files first. It is periodic cleanup, not a filesystem
  quota: files can accumulate between checks, and cleanup requires one of those
  processes to run. Deleted bodies cannot supply missing capture detail.
- `hyp privacy purge` empties it, whatever else you asked that purge to delete, and
  `hyp detach claude` empties it on the way out.

### Proxy mode and certificate cleanup

Claude Code uses OTEL capture by default. An explicitly configured proxy routes
HTTPS through the local gateway. The gateway decrypts AI provider hosts named
by the configured capture adapters; other hosts are tunneled without decryption.
Only supported provider API requests are recorded.

The proxy's local certificate authority (CA) is stored under
`~/.hyp/hypaware/tls`. It is restricted to supported provider hosts and excludes
IP addresses. Current attach operations use client-scoped trust. An installation
that previously used Claude proxy capture may still have a CA trusted in the
macOS login keychain, a `NODE_USE_SYSTEM_CA` launchd environment variable, and
`~/Library/LaunchAgents/com.hyperparam.hypaware.node-system-ca.plist`. Those
settings affect other programs using that account's trust or environment.

Inspect these artifacts with `hyp status --verbose`. `hyp detach claude --purge`
and `hyp daemon uninstall` remove the CA, its keychain trust, the launchd
variable, and the login agent. Plain `hyp detach claude` leaves the CA and
keychain trust; it clears the variable and agent only when the attach marker
still identifies a proxy attach.

## Where it goes

- **Local only**: recordings stay in the local cache, plus any local exports
  you configured.
- **HypAware Cloud** (after choosing Sync to the cloud in setup,
  `hyp remote login`, or `hyp join`): recorded rows are synced to
  HypAware Cloud, including conversation content. The controls below
  decide which rows that covers.

> **Note:** Local recording does not mean HypAware makes no network requests. Supervised
> global installations check npm for [automatic updates](https://hypaware.ai/docs/cli/index.md#update-hypaware)
> by default; those checks do not send recordings. The [GitHub](https://hypaware.ai/docs/integrations/github/index.md)
> and [Linear](https://hypaware.ai/docs/integrations/linear/index.md) plugins, once signed in or given a token,
> call the GitHub and Linear APIs with your own credentials to collect their
> data; they send no recordings. Separately configured remote destinations and diagnostic
> exporters can also send data.

HypAware Cloud operators can read synced data across every org, and each
such read is recorded in that org's audit trail. For support, they can also
view a member's dashboard as that member sees it, read-only and for at most
an hour at a time. Each such session is recorded in that org's audit trail
under the operator's name, with the reason they gave.

Enrollment also enables [product telemetry](#product-telemetry) for the
organization unless you saved a preference. It is separate from session recordings.

## The three usage classes

Every directory subtree resolves to one class. Starting at the session's
working directory, HypAware uses the nearest ancestor `.hypignore` file and
the most-specific matching host-local marking. It then takes the most
restrictive result across those sources: `ignore`, then `local-only`, then
`sync`. This is not a merge of every ancestor file.

| Class        | Recorded locally | Synced to HypAware Cloud    |
|--------------|------------------|------------------------------|
| `sync`       | yes              | yes (the default)            |
| `local-only` | yes              | never                        |
| `ignore`     | never            | never                        |

`local-only` rows stay fully queryable on your own host; they are
withheld at the export seam, so no sink or remote query can see them.

## Marking directories

There are two authoring surfaces for the same classes:

- **A committable `.hypignore` dotfile** marks a subtree `ignore` and
  travels with the repo, so it covers every clone:

  ```sh
  hyp privacy ignore              # write a .hypignore at the repo root (or cwd)
  hyp privacy ignore <path>       # ignore a specific subtree
  hyp privacy unignore            # remove it, re-enabling recording
  ```

  An empty or comment-only `.hypignore` also means `ignore`.

- **A host-local store** (`hyp privacy`) records the class privately on
  this host, never as a file in the repo. Use it when the marking itself
  is sensitive (a dotfile in a hidden directory is a breadcrumb pointing at
  exactly the thing you are hiding), or when the path is not a repo:

  ```sh
  hyp privacy set <path> ignore        # never recorded, no dotfile
  hyp privacy set <path> local-only    # recorded, never synced
  hyp privacy set <path> sync          # explicitly synced (not asked again)
  hyp privacy show [path]              # which class governs, and why
  hyp privacy list                     # every host-local entry
  hyp privacy unset <path> [class]     # back to the implicit default
  ```

On a host connected to HypAware Cloud, folders you have not marked sync
without asking. You can instead be asked, once per new folder, how to
handle it, at the moment you open a session there:

```sh
hyp privacy folders ask    # ask once per new folder
hyp privacy folders sync   # back to syncing without asking (the default)
hyp privacy folders        # report which is in force
```

This gates the question only. In either setting, folders you already
marked keep their class, `.hypignore` files are unaffected, and nothing
already local-only or ignored starts syncing. The setting is host-local
and reversible, `hyp setup` asks for it in its own step (unattended:
`hyp setup --new-folders ask|sync`), and `hyp status` names it on an enrolled
host.

Three caveats apply to both surfaces:

> **Caution:** **Prospective only.** A marking gates future recording and syncing.
> Rows captured before it existed stay in the cache; deleting them is the
> separate, explicit `hyp privacy purge` step below.

**Class resolution needs a working directory.** The client sources
(Claude Code, Claude Desktop, Codex, Cursor, OpenCode, Pi, Droid, OpenClaw,
Goose, Crush, Mastra Code, Copilot, LangGraph) supply one. NanoClaw uses the host `groups/<folder>`
workspace. Antigravity takes it from the conversation's workspace; a
conversation with no workspace has no scope to match and is recorded
unconditionally. Hermes supplies the real one for an interactive session it
recorded a cwd for, and scopes a messaging-channel session (Telegram, Discord, Slack,
WhatsApp, Signal, email) under a derived `~/.hermes/channels/<source>` path
instead; an interactive Hermes session with no recorded cwd has no scope to
match and is recorded unconditionally. The `raw-anthropic` / `raw-openai`
proxy, OTEL, and Ollama sources never supply one, so directory markings are a no-op
for them. Codex Cloud and ChatGPT Work chats carry a path on OpenAI's machine,
not yours, so local markings and `.hypignore` never classify them either;
`hyp session ignore` and export settings still apply.

> **Caution:** **A session is classed by its own directory, not by what it reads.**
> Local SQL and search normally hide local-only rows from a caller that can
> sync. If you explicitly include them with `--include-local-only` or copy
> private content into another session, that session follows its own directory's
> class. A report-generating conversation in a `sync` folder can therefore sync
> the private excerpts it quotes. `hyp report generate` uses the directory you
> type it in and does not change its class. Choose that directory deliberately,
> or run `hyp session ignore` inside the supported session it starts.

## Control a whole client's sharing

Keep a locally configured client's recordings on this host:

```sh
hyp privacy client codex local-only
hyp privacy client codex sync
```

Unattended setup takes the same choice as `--local-only-client codex` or
`--sync-client codex`, each repeatable; omitted, the current choice stays.
Organization-managed clients cannot be changed with this local control. Use
[directory markings](#marking-directories) for project-level exclusions.
Returning a client to `sync` affects future exports; previously withheld history
requires a separate, confirmed `hyp sync --history codex`. Completing team setup
can clear client-level local-only choices; review the [setup prompts](https://hypaware.ai/docs/team-setup/index.md#follow-the-prompts).

## Pausing a single session

Run `hyp session ignore` inside a Claude Code or Codex session to resolve its
ID automatically. If it cannot establish the ID, the command refuses to guess.
For another supported recorder, pass an explicitly verified session ID as
shown in the [session reference](https://hypaware.ai/docs/cli-reference/index.md#control-the-current-session).

The command sends the exclusion to local recorder control routes for the
gateway, Claude telemetry, OpenCode, Pi, Droid, Grok Build, and Cursor when they
are running. Goose, Crush, and Mastra Code have no control route; they read the
saved exclusion on their next poll. A Crush session is ignored by its HypAware
session ID, `crush-` followed by the Crush session ID, and a Mastra Code thread
by `mastracode-` followed by its thread ID. On an install that records only
Goose, Crush, or Mastra Code the command saves nothing, so mark the session's
working directory with `hyp privacy ignore <dir>` instead. The Claude listener
deletes ignored sessions' spooled bodies unread. Use `hyp session unignore` to
resume and `hyp session status` to check the result.

Gateway, Claude, OpenCode, Pi, Droid, Grok Build, Goose, Crush, and Mastra Code
exclusions are saved under `<HYP_HOME>/hypaware/session-ignores/` and survive
restarts. **Cursor exclusions are currently in memory only and must be
reapplied after a recorder restart.** OpenClaw and Hermes do not support this
session control; use directory markings or disable their capture integrations.

Claude (including Desktop transcripts), Codex, OpenCode, Pi, Droid, Grok Build,
Goose, Crush, and Mastra Code backfill honor saved exclusions, including manual
imports in a separate process. Saving must succeed before a persistent recorder
reports success. If its exclusion store is unreadable or corrupt, capture and
transcript imports pause while AI requests still forward. Commands and source
status report the error. Repair the saved state and restart HypAware before
relying on capture again.

A resumed session keeps its ID. A fork creates a new ID and needs its own
exclusion, except on Grok Build, where a fork or subagent inherits its parent's.
For attached Claude Desktop Code sessions, the managed SessionStart hook
supplies the ID to later Bash commands. Hosts without hooks or `CLAUDE_ENV_FILE`
require an explicitly verified ID; a matching directory or recent transcript is
insufficient.

Ignoring does not delete earlier records, original client transcripts, or
exported copies. Unignoring makes the entire transcript eligible for import,
including turns written while ignored. Use `hyp privacy purge --session <id>`
to delete previously captured rows.

## Deleting what was already recorded

`hyp privacy purge` permanently deletes rows from this host's local cache:

```sh
hyp privacy purge <path>          # rows whose cwd is at or under the path
hyp privacy purge --session <id>  # one session's rows, here and on your servers
hyp privacy purge --ignored       # every row whose directory now resolves to ignore
hyp privacy purge --all           # everything, wholesale
```

It prompts on a TTY; pass `--yes` for non-interactive use.

> **Caution:** A session purge is the only form that reaches beyond this host. It also
> deletes that session's rows from every configured or signed-in remote and
> every enrolled server, and keeps the session from being recorded again. The
> confirmation prompt names the servers it will contact:

```sh
hyp privacy purge --session <id> --remote <target>  # this host and one server
hyp privacy purge --session <id> --local-only       # this host only
```

Deleting on a server uses your login, and needs you to be the session's owner
or an organization admin. If a server cannot be reached or refuses, the
command exits nonzero; run it again to finish. Copies quoted into a published
report are not removed, and the underlying files are reclaimed by later
maintenance, not at the moment of the purge.

The path, `--ignored`, and `--all` forms are local only: they never contact a
sink or a server, and never delete copies already exported or synced.

Every form of it also empties the raw-body spool described above, including
the targeted ones: a spooled body has not been read yet, so nothing about it
says which directory or session it belongs to, and leaving it would let the
next batch write back rows you just deleted.

## Local file permissions

HypAware creates its local storage readable only by your user: directories
0700 and recorded content (the cache spool, cached data, local exports, the
daemon log) 0600, whatever your umask. On an existing install, each start tightens
`HYP_HOME`, its `hypaware` directory, and a cache root kept elsewhere to 0700,
which keeps other users out of the older files below them without rewriting
any of them.

It only tightens a directory it can tell is its own. A custom `HYP_HOME` or
cache location that holds other files, or that another user owns, is left as
it is, and HypAware logs a `storage.root_not_secured` warning and keeps
running; files written there before this release keep their old modes. Parent directories are never changed.

On Windows, where POSIX modes do not apply, each start sets the same roots
to an access list naming only your account, SYSTEM, and Administrators, and
everything HypAware creates under them inherits it. Permissions a root picked
up from its parent folder are removed, but a permission someone granted by
hand on the root itself is kept, so a folder shared on purpose stays shared:
HypAware sets the grants for those three accounts and leaves other explicit
grants alone. The same care applies:
a shared or foreign directory is left as found with the warning above.
Files that already existed under a custom location outside your user
profile keep their old access until they are rewritten; the default
location under your profile was already covered by the profile's own
access rules.

## Redaction when content is recorded

The built-in rules below also run before a row is written to the local cache,
so recognized credentials and sensitive file-tool contents are masked in the
cache itself and in every local query, not only in exports. This is on by
default and has no switch to turn it off. It covers every capture source that
writes the cache, live capture and transcript backfill alike, including Claude
Code telemetry events and OpenTelemetry logs, traces and metrics. It runs again
on content a capture adds while settling a row, including when compaction
settles a row again.

> **Caution:** A credential masked when it is recorded cannot be recovered from
> HypAware. If the heuristic below masks something that was not a secret, only
> the client's own transcript still holds it. This is why the heuristic's
> thresholds stay conservative.

Some differences from export redaction:

- [Custom patterns](https://hypaware.ai/docs/configuration/index.md#redact-exported-content) apply to exports
  only. The local cache masks the built-ins alone.
- A file read is masked when its call names a sensitive file, including a call
  recorded in an earlier batch. A read whose call HypAware never saw is kept
  locally; exports still mask it.
- A row too large for the traversal budget below is still recorded instead
  of failing. Each column is checked on its own. A column still too large gets
  only the text patterns: file paths and credential key names inside it are
  not recognized, and a nested value that is not text is dropped.
- Rows recorded before this change keep their content, and so do rows still
  waiting to be written when you upgrade. To remove them, use
  `hyp privacy purge`.
- The raw-body spool and the LangGraph outbox are written by other programs,
  so their files are not masked. HypAware masks what it records from them.

## Automatic export redaction

Cloud forwarding and file exports mask recognizable credentials and known
sensitive file-tool contents, whether or not the content was masked when it
was recorded. Existing directory and session withholding applies first.
Configure [additional regex patterns](https://hypaware.ai/docs/configuration/index.md#redact-exported-content)
for your organization's secret formats.

Built-ins recognize common AI and GitHub keys, AWS access-key IDs, Slack tokens,
Google API keys (`AIza...`), Stripe live secret keys (`sk_live_...`), JWTs with
or without a `Bearer` prefix, bearer tokens, credential-bearing database URLs,
private keys, named credential fields, and plaintext password/API-key
assignments. They also mask file-tool
payloads for `.env` variants, private-key files, common credential stores and
shell configuration/history. Template files such as `.env.example` do not
trigger full-file masking, though credential patterns still apply.

A heuristic also masks unknown random tokens: a standalone run of 32 to 128
letters, digits, `-` and `_` that mixes uppercase, lowercase and digits and is
as varied as a randomly generated key. It leaves commit SHAs, UUIDs and other
hex alone, along with ordinary code identifiers, paths and URLs, provider IDs
such as `chatcmpl-...` or `toolu_...`, standard base64 that is padded with
`=`, touches a `+` or `/`, or sits inside a PEM block, and digests or keys labelled
`h1:`, `SHA256:`, `sha-256=` or `ssh-ed25519`. It has limits both ways.
Random-looking public values can be masked: long identifiers packed with
acronyms and digits, document or video IDs, base58 addresses, nonces, and
lines of wrapped base64 outside a PEM block. It misses secrets shorter than 32
or longer than 128 characters, hex-only or single-case secrets, secrets
embedded in a path or URL, most secrets in standard base64 (they usually
contain `+` or `/`), and about 3% of random 32-character tokens. It is on by
default, like the other built-ins, with no switch to turn it off.

File masking uses recorded tool arguments and call/result links. A named file
read whose path cannot be established within the current export scan has its
output masked conservatively. This can remove ordinary read output, especially
when its call was exported on an earlier tick. Arbitrary shell commands are
not parsed to infer which files they read.

Masking also scans nested attributes and raw-frame string values. It preserves
top-level row identities, directory attribution, timestamps, and numeric usage.
Object keys and binary values are not scanned; encoded data and image content
are not decoded. Uncommon secret formats may remain unless a custom pattern covers them. Automatic
masking does not replace directory exclusions or privacy review.

Custom patterns run in an isolated worker with one row at a time and a
one-second matching deadline. Exceeding that deadline or the per-row traversal
budget fails export instead of sending an unscanned row. The budget is depth
64, 100000 visited values and 16 MiB of UTF-16 string bytes per row.
Adding a rule affects subsequent exports; it does not recall earlier copies.

## Review before the first Cloud sync

Before sharing recordings, review captured directories with the
`hypaware-privacy` skill in Claude Code or Codex. It checks this host's local
cache, samples recordings, and proposes directory markings and deletions for
your confirmation. A review cannot guarantee it will find every secret.
Redaction covers recognized patterns; other local content stays as recorded.
You can run the review at any time, even without Cloud enrollment.

<!-- agent: Run the hypaware-privacy skill: review what this host has recorded, sample it, and propose which folders to mark local-only or ignore before anything syncs. Do not delete anything without asking me. -->
```sh
hyp privacy show
hyp privacy list
```

For the enrollment hold, deadline, and unattended behavior, see
[the first-sync review](https://hypaware.ai/docs/team-setup/index.md#review-before-the-first-upload).

For disconnecting a host while retaining its local recordings, see
[Cloud and teams](https://hypaware.ai/docs/team-setup/index.md#disconnect-a-host).

## The daemon's own telemetry

HypAware's operational diagnostics are separate from product telemetry:

- With `HYP_DEV_TELEMETRY=1`, logs, spans, and metrics are written locally under
  `~/.hyp/hypaware/dev-telemetry/`.
- Without that setting, an inherited `OTEL_EXPORTER_OTLP_ENDPOINT` sends those
  diagnostics to the configured endpoint.
- With neither setting, those diagnostic providers do not record or export data.

These diagnostics use component, operation, and status attributes. They are
designed to exclude credentials and raw prompt content. Service output logs are
separate; see [data paths](https://hypaware.ai/docs/configuration/index.md#know-where-data-lives).

## Product telemetry

Product telemetry reports how HypAware itself is running. It is enabled for an
enrolled organization unless you saved an `off` or `local` preference. An
already-enrolled host starts reporting on its next CLI run or daemon start
after an upgrade, without a new prompt. Standalone installations default to off.
Check the effective state and destination:

<!-- agent: Use HypAware to tell me whether product telemetry is on, where it goes, and show me the next batch it would send. -->
```sh
hyp telemetry status
```

Organization telemetry goes to the HypAware server this host is enrolled
with, using its existing enrollment. The CLI does not send telemetry anywhere
else. The server also copies the HypAware version, OS family, and configured
client names to PostHog for product analytics, where they are kept until
Hyperparam deletes them.

### Control and preview

```sh
hyp telemetry off
hyp telemetry enable local
hyp telemetry preview
hyp telemetry enable organization
```

`off` saves your preference, including across re-enrollment, and removes queued
batches. It cannot recall batches the server already accepted. If saving fails,
the command exits nonzero and reports that telemetry remains enabled.

`local` keeps a preview queue without sending it. `organization` enables sending
and requires exactly one eligible enrolled central sink with an HTTPS
destination. Changing the mode clears older pending batches. `preview` prints
the exact next batch, or `null` if none is queued.

Restart a running daemon after enabling collection. It notices disabling and
enrollment changes within 30 seconds. `hyp status` also reports telemetry state.

### What is collected

| Data | Examples |
| --- | --- |
| Command outcomes | A command name from a fixed list, success or failure, duration, and selected setup steps; custom commands appear as `other` |
| Installation and process details | HypAware version, OS, architecture, Node major version, configured integrations, and generated installation/process identifiers |
| Daemon health | Lifecycle events, memory and CPU summaries, and counts of rows captured, written, and exported |
| Setup milestones | That this installation captured its first row, and that it ran its first successful query. Each is sent once; changing the telemetry mode or re-enrolling can send it again |
| Query usage | For a `hyp query` command or an MCP query tool: up to four dataset names from a fixed list (others appear as `other`), whether the query ran locally or on a remote, the row count as a range (`0`, `1-10`, `11-100`, `101-1000`, or more than 1000), and whether it came from a terminal, an MCP client, or an agent's shell |
| MCP tool calls | A tool name from a fixed list (others appear as `other`), success or failure, an error code from a fixed list, and duration |

Query usage and MCP tool calls are sent only to a server that reports it
accepts them; an older server receives the other rows without them. An
agent's shell is recognized by the presence of environment variables that
known agents set; their values are not read or sent.

Conversations, prompts, responses, argument values, SQL, file paths, credentials,
and free-text error messages are excluded. Coverage is partial: a killed process
may never report a completion, and missing measurements do not mean zero activity.

### Storage and delivery

The queue holds at most 160 batches of 32 KiB each, up to 5 MiB. It lives under
`~/.hyp/hypaware/product-telemetry/`. New records are dropped when it is full.
Batches expire after seven days when a collector or sender runs; an inactive
installation cannot clean up on a timer. A sudden power loss may lose queued data.

The daemon attempts one batch every 30 seconds. Without a daemon, a CLI command
may send an earlier batch while it runs. Command exit does not wait for delivery,
so a final batch may remain queued until HypAware runs again.

Network failures retry with backoff. A 401 first triggers a credential refresh;
continued 401 or a 403 pauses delivery for an hour. A server without compatible
telemetry support also pauses delivery. Permanent payload rejections
(400, 409, 413, 415, or 422) discard the rejected batch. The receiving server must
have product reporting enabled.
