Skip to content

Repository files navigation

HypAware

HypAware records the sessions, logs, and telemetry from your AI agents into one queryable history.

It captures conversations and traffic from local AI clients (Claude Code, Codex), raw Anthropic / OpenAI API traffic, and OpenTelemetry logs / traces / metrics. Recordings land in a local query cache and can stay on your machine or sync to a central server.

There are two ways to run it:

  • Shared. Each machine signs into your organization on the central server with one command, hyp remote login, and forwards its recordings there. One history follows you across machines and harnesses, and usage, spend, and activity can be queried and reported across the whole team.
  • Solo, fully local. No central server, no account. Everything stays in a local query cache on your machine. Start with npx hypaware.

Part of HypStack, an open-source stack for AI observability.

Contents: Requirements · Quickstart · Team setup · Files · Querying · Activity graph · Clients · Privacy controls · Daemon · Troubleshooting · Uninstalling · Project documents

Requirements

  • Node.js >= 22.12
  • macOS (launchd) or Linux (systemd --user) for the persistent daemon

Quickstart (solo, fully local)

npx hypaware

When run through npx, the walkthrough also installs a durable global copy of the CLI (npm install -g hypaware) so the daemon and the hyp command outlive the npx cache. Every command below is available as both hyp and hypaware.

On a TTY this launches the interactive walkthrough:

  1. Pick the sources to capture. Any subset of:

    • Claude Code conversations (claude)
    • Codex conversations, CLI and Desktop (codex)
    • OTEL logs / traces / metrics (otel)

    The raw proxy sources (raw-anthropic, raw-openai) are not offered in the menu. They open a gateway upstream but configure no client and carry no projector of their own, so on their own they proxy traffic and record nothing. They remain real sources: hyp setup --source raw-anthropic still composes one, and a config that already collects one keeps it through a reconfigure (LLP 0202).

  2. Pick an export strategy: keep the local query cache only, write Parquet files under <HYP_HOME>/exports, or configure later.

  3. The retention window is not asked: the pathway sets it, 90 days on a team install and 120 on a local-only one. hyp setup --retention-days <N> overrides it, and query.cache.retention in the written config remains the post-install knob.

  4. HypAware composes a minimal config with only the bundled plugins it needs, writes it to <HYP_HOME>/hypaware-config.json, installs the persistent daemon (launchd on macOS, systemd --user on Linux), attaches the selected clients, and starts capturing.

  5. The walkthrough finishes by printing the config path, daemon status, per-client attach results, and a first look at what was captured: token volume per model, activity per day, which repos the sessions ran in, and which tools got called. Reprint it any time with hyp query overview.

  6. Last, it offers a few questions worth asking of that data and starts your AI client on the one you pick, opening straight into the answer. Pick it up again any time with hyp ask, or skip the menu with hyp ask "which sessions touched the auth module".

For unattended installs (CI, scripted bootstraps, dotfiles) use the non-interactive flags:

hyp setup --yes \
  --source claude --source otel \
  --client claude \
  --export local-parquet \
  --retention-days 90

Other init flags:

Flag Meaning
--yes / -y Accept defaults; do not prompt
--no-daemon Skip daemon install and restart
--dry-run Render the config + planned actions, write nothing
--client claude|codex Attach a client (repeatable)
--source <id> Add a capture source (repeatable)
--export <choice> keep-local, local-parquet, or configure-later
--retention-days <N> Override the default 90-day retention window
--from-file <config.json> Skip the picker and load a known-good config
--bin <path> Override the binary path the daemon installer uses

Set up for your team (hyp remote login)

If your organization is set up on the central server, enrolling a machine is one command:

npx hypaware remote login

This opens a browser sign-in. Your organization is resolved from your work email domain, and the machine enrolls itself: it provisions the forwarding sink, stores a per-machine credential (mode 0600, never in shell history), installs the persistent daemon, and starts capturing and forwarding. No bootstrap token, no URL to copy, no hand-edited config.

The same sign-in also unlocks remote queries, so you can ask questions across the whole team's recordings, not just this machine's:

hyp query sql "select count(*) from ai_gateway_messages" --remote

Privacy review before anything ships. Nothing is forwarded immediately. The first sync (which includes backfilled history) waits until 11:59pm local time on the day you enroll, and the login prints the exact deadline. Before then, open Claude or Codex and run the hypaware-privacy skill to review what will ship, mark directories ignore / local-only / sync, and purge anything sensitive. Done reviewing, or want to see data on the server sooner? hyp sync shows what would leave and sends it once you confirm.

Useful login flags: --no-forward signs in for remote queries only (no enrollment), --no-browser prints the sign-in URL instead of opening one, --token-file <path> / stdin supply a static token, and --host <label> overrides the host label the server shows for this machine.

Want this for your team? We host organizations on the central server. Get in touch and we will set one up for your email domain; after that, everyone on the team onboards with the single hyp remote login above.

For the full rollout story (fleet tokens, managed config, Claude Desktop capture, verifying machines) see the team setup guide; for what enrollment means for each person's data, see what HypAware records and how to control it.

Unattended enrollment (hyp join)

For scripted rollouts (MDM, dotfiles, CI images) where no browser is available, hyp join enrolls a host with a fleet policy token instead of an interactive sign-in:

hyp join <url> [token]
hyp join <url> --token-file <path>     # read the token from a file (recommended for MDM)
echo "<token>" | hyp join <url>        # or from stdin
hyp join <url> <token> --no-daemon     # write the seed only, skip daemon install

It writes a central-enrollment config (mode 0600) to a dedicated layer under config-control/, never to your local hypaware-config.json, so joining augments an existing install rather than replacing it, then installs and starts the daemon (unless --no-daemon is passed).

The policy token is a multi-use fleet-wide credential. Prefer --token-file or stdin over a positional argument, which would otherwise land in shell history and process listings. Other flags: --bin <path> overrides the binary the daemon installer records, and --no-daemon writes the seed without installing or restarting the daemon.

Files and directories

Path Contents
<HYP_HOME>/hypaware-config.json Active config (rewritten by hyp setup)
<HYP_HOME>/hypaware/ Kernel state root
<HYP_HOME>/hypaware/plugins/<name>/ Per-plugin state
<HYP_HOME>/hypaware/cache/ Local query cache (Iceberg-backed)
<HYP_HOME>/hypaware/sinks/<name>/outbox/ Failed export rows awaiting retry
<HYP_HOME>/hypaware/dev-telemetry/ Daemon self-telemetry (logs, traces, metrics)
<HYP_HOME>/hypaware/logs/daemon.{out,err}.log Daemon stdout / stderr (launchd / systemd)
<HYP_HOME>/exports/ Local Parquet exports (when the local-fs sink is enabled)

HYP_HOME defaults to ~/.hyp. Override it by exporting HYP_HOME=... before invoking the CLI or the daemon.

Querying captured data

Start with the overview: input, cached and output tokens per provider and model, the same per day, which repos the sessions ran in, and which tools get called - the same block hyp setup ends on.

hyp query overview            # --json to script it, --sql to print the queries
hyp query overview --days 90  # widen the window past what fits by default

The block states the period it covers. It picks a window it can summarize quickly, so a large cache narrows the period rather than hanging - and the line under the title always says which days the numbers describe.

Input is prompt sent fresh and cached is prompt served from (or written to) the cache, so input + cached is the whole prompt; output is what the model generated.

Then query anything directly:

hyp query sql "select count(*) from ai_gateway_messages"
hyp query sql "select count(*) from traces"
hyp query sql "select count(*) from logs"

Use hyp query schema <dataset> to see the columns available on each dataset, and hyp cache status to inspect cache freshness per dataset.

Building and querying the activity graph

Alongside the row datasets, HypAware can project captured activity into a node/edge activity graph: which sessions ran in which app, against which model, using which tools, touching which files. The projection is deterministic (exact-key matching, no models), and the context-graph plugins are active by default.

Projection is a manual, cheap-to-rerun step. Build or refresh the graph from what has been captured, then walk it from a seed node:

hyp graph project                       # project captured data into the node/edge graph
hyp graph compact                       # merge duplicate rows (optional housekeeping)
hyp query graph neighbors <node> --depth 2    # walk out from a seed node

hyp query graph neighbors takes a node_id, natural key, or label as the seed, plus --depth, --direction out|in|both, --type <node_type>, --edge-type <type> (repeatable), and --limit. The graph is also plain data: the node and edge datasets are queryable through hyp query sql like any other dataset.

This plugin ships a graph_neighbors tool and the hyp graph help that explains the traversal, and the hypaware-query skill covers when to ask the graph rather than the messages, so an assistant can project and walk the graph on your behalf.

Attaching and detaching AI clients

Attach a single client (idempotent: running twice is a no-op):

hyp client attach <client>             # claude, codex, openclaw, ...
# Equivalent flag form:
hyp client attach --client <client>
# Pre-rollover spelling, still accepted:
hyp attach <client>

Detach (removes only HypAware-managed settings):

hyp client detach <client>
# Equivalent aliases:
hyp client detach --client <client>
hyp detach <client>
hyp unattach <client>

Both commands support --dry-run and --json for inspection and scripting. Each adapter writes only HypAware-managed settings to its client's own config file (for example ~/.claude/settings.json for Claude, a hypaware provider entry in ~/.codex/config.toml for Codex); unrelated keys in every file are preserved.

Claude Code attaches by telemetry, not by proxy

hyp client attach claude writes one reversible env block into ~/.claude/settings.json that turns on Claude Code's own OpenTelemetry export and points it at a loopback listener the daemon runs. It leaves ANTHROPIC_BASE_URL alone, sets no proxy, and installs no certificate authority, so Claude Code still talks straight to api.anthropic.com, Remote Control keeps working, and a daemon that is down or wedged costs you capture rather than your session. Nothing has to be quit and reopened: Claude Code reads the env block at launch, on every launch path.

Two things ride along with the conversation rows:

  • Raw request and response bodies land in ~/.hyp/spool/claude-bodies (owner-only) until the listener projects them and deletes them. They carry what the events do not: the system prompt, the tool list, and untruncated tool arguments. The directory is capped (512 MB by default, oldest evicted first), and both hyp privacy purge and hyp client detach claude empty it.
  • Behavioral signals the wire never showed land in their own claude_telemetry_events table: tool accept and reject decisions, permission mode changes, per-request cost, hook and MCP health.

Claude Code 2.1.193 or newer is required (2.1.214 for the full tool-decision detail). Below the floor, attach refuses the switch, leaves any existing attach exactly as it is, and prints claude update, rather than silently capturing less.

hyp client detach claude removes exactly those keys, restores anything they displaced, and sweeps the spool.

If this machine was attached by proxy before, hyp client attach claude is also the migration: it releases the proxy keys, unwinds the launchd environment, and tells you how to end the CA trust that it will not end for you (hyp client detach claude --purge).

Proxy mode (TLS interception for the clients that still proxy)

Claude Code no longer uses this path. It remains how the gateway captures a client that cannot simply be pointed at a different base URL. Turn it on in the ai-gateway section of ~/.hyp/hypaware-config.json and restart the daemon:

{ "name": "@hypaware/ai-gateway", "config": { "proxy_mode": true } }
hyp daemon restart

Such a client is then pointed at the gateway with HTTPS_PROXY and NODE_EXTRA_CA_CERTS rather than a base URL. What that changes:

  • A machine-local certificate authority is generated under ~/.hyp/hypaware/tls, readable only by you, and name-constrained so it cannot vouch for any host outside the provider set HypAware intercepts. Trust stays file-scoped to the proxied client's own settings: nothing installs it into any OS trust store, including your login keychain, and anything wider is your own decision. Earlier releases attached Claude Code by proxy and did add the CA to the macOS login keychain as a user-domain trusted root, for a transport that trusts only the keychain; macOS raised its own password dialog for that, it never needed admin rights, and the machine-wide system keychain was never touched. If you ran one of those releases, that trust setting is still on your account until you remove it. hyp status shows the fingerprint, every host the CA is permitted to vouch for, and whether the login keychain still trusts it. hyp client detach <client> leaves the CA and any trust an earlier release was granted in place, because a detach is not a statement about the certificate and no attach re-creates the grant; hyp client detach <client> --purge and hyp daemon uninstall remove both.
  • On macOS, an earlier proxy attach also left a login-session variable behind. Bun picks its trust store before any settings file is read, so a keychain root only counts if NODE_USE_SYSTEM_CA=1 is already in the process environment. The attach that trusted the CA therefore ran launchctl setenv NODE_USE_SYSTEM_CA 1 and installed a small LaunchAgent, ~/Library/LaunchAgents/com.hyperparam.hypaware.node-system-ca.plist, whose only job is to re-run that command at each login. No attach writes either one today; on a machine that ran one of those releases the agent stays a login item until it is removed, and the variable stays session-wide for other Node programs to read too. launchctl setenv reaches processes launched after it, so a terminal app that was already running must be fully quit and reopened. hyp client detach <client> --purge and hyp daemon uninstall clear both unconditionally, and hyp client attach claude unwinds them when it migrates a previously proxied machine. A plain hyp client detach <client> only clears them while that client's attach marker still records a proxy attach, so on a machine already migrated to another attach mode it is not the command that removes the leftover. hyp status shows whether the variable is currently live.
  • Only the hosts a registered upstream names are decrypted. Every other host the client talks to is tunnelled through without being decrypted.
  • What gets recorded does not change. Only the recorded API paths are stored; the other paths a client calls on the same host are passed through without being stored.

Two things to know before turning it on:

  • If the daemon is not running, a proxied client's HTTPS all fails, not just its model calls. Attach refuses to write the settings unless proxy mode is actually running, and hyp client detach <client> is the escape hatch.
  • If you already use a corporate proxy, set upstream_proxy to it so traffic still chains through it. Attach warns and backs up your existing HTTPS_PROXY (restored on detach) rather than silently replacing it:
{ "name": "@hypaware/ai-gateway",
  "config": { "proxy_mode": true, "upstream_proxy": "http://proxy.corp:8080" } }

Codex is unaffected and keeps using the base-URL mechanism.

Desktop apps

Codex Desktop needs no separate setup. hyp client attach codex covers the Codex CLI and Codex Desktop together, because the two share the file it writes (~/.codex/config.toml, or $CODEX_HOME/config.toml) and the history it backfills (~/.codex/sessions/**). Rows from either surface land in ai_gateway_messages; the entrypoint column carries Codex's originator, which is what tells a Desktop session from a terminal one.

Claude Desktop does need its own setup (hyp client claude-desktop install), and hyp init will not offer it: Claude Desktop is the one client whose setup takes a browser sign-in and a sudo prompt to place a root-owned managed-preferences plist, which is not something a first-run checklist should ask for (LLP 0297). It is opt-in, macOS-only, and always explicit: enable the plugins in ~/.hyp/hypaware-config.json, then run the install. See the CLI reference for the exact plugins[] entries.

hyp client claude-desktop install
hyp client claude-desktop verify

The vendor difference is why the shape is different, not a gap in Codex support: Claude Desktop exposes no user-writable settings file to amend, so HypAware configures it through that plist, and it delegates inference to its embedded CLI (rows arrive as client_name = 'claude' with entrypoint = 'claude-desktop-3p').

What HypAware does not do for Codex Desktop: it never parses the app's own container at ~/Library/Application Support/Codex. That store is opaque and undocumented, so hyp client history import codex flags it as an unsupported_location and moves on. It is not the only copy of those conversations, so nothing is lost: live traffic is captured through the gateway, and past sessions come back from ~/.codex/sessions. The same applies to the ChatGPT desktop app and browser storage, which HypAware does not capture at all.

See LLP 0141 for the reasoning, and docs/ACCEPTANCE.md for the manual check that Desktop traffic is actually landing.

Controlling what is recorded and forwarded

Every directory subtree resolves to a usage class, evaluated gitignore-style from an exchange's working directory: sync (recorded, forwarded to the team server if enrolled; the default), local-only (recorded, never forwarded), or ignore (never recorded; the live LLM call is untouched, only persistence is suppressed). When multiple markings apply, the most restrictive wins.

There are two ways to mark a subtree:

hyp privacy ignore [path]                     # write a committable .hypignore dotfile (travels with the repo)
hyp privacy unignore [path]                   # remove it, re-enabling recording

hyp privacy set <path> ignore          # same effect, stored machine-local (no dotfile in the repo)
hyp privacy set <path> local-only      # recorded but never forwarded
hyp privacy set <path> sync            # explicitly synced, not asked again
hyp privacy show [path]                # which class governs, and from which source
hyp privacy list                       # every machine-local entry
hyp privacy unset <path> [class]       # back to the implicit default

On a machine connected to a server, folders you have not marked sync without asking. If you would rather be asked once per new folder, a session opened somewhere new can prompt you to classify it instead:

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

This gates the question only: folders you already marked keep their class, and .hypignore files are unaffected either way. hyp setup asks for this in its own step, and hyp status names it on an enrolled machine.

Markings are prospective only: rows captured before a marking existed stay in the cache. Delete those with the separate destructive step:

hyp privacy purge <path> | --session <id> | --ignored | --all   # delete already-cached rows (prompts; --yes to skip)

To pause recording for just the current Claude or Codex session (in-memory, reversible) run hyp session ignore from inside it; hyp session unignore resumes and hyp session status reports the current answer.

The full model, including what enrollment forwards and the first-sync privacy review, is in what HypAware records and how to control it. One caveat worth repeating: directory markings need a working directory, which only the Claude and Codex pathways supply, so they are a no-op for the raw-anthropic / raw-openai proxy and OTEL sources.

Daemon lifecycle

hyp daemon install      # launchd LaunchAgent (macOS) or systemd --user unit (Linux)
hyp daemon start        # ensure the service is started
hyp daemon status       # health snapshot
hyp daemon restart      # bounce after a config change
hyp daemon stop         # signal the running daemon to shut down
hyp daemon uninstall    # remove the service and detach clients (config + recordings are kept)

hyp daemon install --dry-run --json prints the rendered plist or unit content and target paths without touching the filesystem, useful for verifying what hyp setup will install.

Troubleshooting

hyp status is the entry point for any "is HypAware working?" question. It prints the active config path, daemon install/run state, active plugins, source and sink rows, per-client attach state, retention window, cache size, and a recent-error count. Pass --json for the stable machine-readable shape that smokes and support tools rely on:

hyp status
hyp status --json

When something is wrong, hyp status surfaces a diagnostics: section with one row per finding. Each row carries a kind (a stable machine-readable identifier) and one or more repair: lines you can run directly. The common Phase 8 conditions:

kind meaning repair
config_missing no ~/.hyp/hypaware-config.json was found hyp setup or hyp setup --from-file <config.json>
config_invalid the loaded config failed schema / cross-plugin validation hyp setup --from-file <config.json>
client_without_gateway a client plugin (Claude / Codex) is enabled but @hypaware/ai-gateway is not re-run hyp setup, then hyp client attach --client <name>
gateway_missing_anthropic_upstream a gateway-routed Anthropic client (OpenClaw) is enabled but no Anthropic upstream is registered re-run hyp setup and pick the Anthropic upstream
gateway_missing_openai_upstream @hypaware/codex enabled but no OpenAI upstream is registered re-run hyp setup and pick the OpenAI upstream
sink_missing_encoder a local-fs sink is configured but no encoder plugin is enabled re-run hyp setup and pick "local Parquet export"
client_attach_missing a client plugin is enabled but its settings file shows no HypAware marker hyp client attach --client claude or hyp client attach --client codex
daemon_binary_missing the daemon installer references a binary that no longer exists on disk hyp daemon install
daemon_loaded_no_pid the daemon service file is installed but launchd / systemd is not loading it hyp daemon restart
recent_errors the local telemetry directory has recent error log entries inspect ~/.hyp/hypaware/dev-telemetry, then hyp daemon restart

Useful follow-on commands when a diagnostic fires:

  • hyp daemon restart: bounce the persistent daemon
  • hyp daemon install: re-install the launchd / systemd unit
  • hyp client attach --client claude / hyp client attach --client codex: wire a selected client into HypAware capture
  • hyp setup --from-file <path>: rebuild the config from a known-good file without re-running the interactive picker

Uninstalling

To remove HypAware from a machine completely:

hyp leave                     # only if enrolled with a team server: stop forwarding, drop the credential
hyp daemon uninstall          # remove the launchd / systemd service and detach every attached client
npm uninstall -g hypaware     # remove the CLI
rm -rf ~/.hyp                 # delete all local recordings, config, and state

hyp daemon uninstall restores each attached client's own settings on its way out, so no client is left pointing at a gateway that no longer exists; to detach a single client without uninstalling, use hyp client detach <client>.

The first three steps are non-destructive and reversible; deleting ~/.hyp permanently removes every local recording. Note that copies already forwarded to a team server or exported to Parquet are not affected; see docs/PRIVACY.md.

Project documents

User-facing guides live under docs/:

Contributor material (repository layout, release checklist, test model) lives in AGENTS.md.

Design rationale lives in numbered LLP documents under llp/ (Linked Literate Programming). Start here:

The former monolithic docs (hypaware-design.md, finish-v1.md, hypaware-implementation-plan.md) were decomposed into the LLP corpus and are preserved under llp/tombstones/. Public plugin interfaces are declared in hypaware-plugin-kernel-types.d.ts.

About

Records sessions, logs, and telemetry from your AI agents into one queryable history

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages