Modular logs and telemetry collector. Plugin-kernel architecture.
HypAware captures conversations and traffic from local AI clients (Claude
Code, Codex), raw Anthropic / OpenAI API traffic, and OpenTelemetry
logs / traces / metrics into a local query cache and optional Parquet
exports. It runs fully local by default, no central server required, and a
host can optionally join a fleet (hyp join) to forward its recordings to a
central server.
Part of HypStack, an open-source stack for AI observability.
npx hypawareOn a TTY this launches the interactive walkthrough:
- Pick the sources to capture. Any subset of:
- Claude Code conversations (
claude) - Codex conversations (
codex) - Raw Anthropic API traffic (
raw-anthropic) - Raw OpenAI API traffic (
raw-openai) - OTEL logs / traces / metrics (
otel)
- Claude Code conversations (
- Pick an export strategy: keep the local query cache only, write
Parquet files under
<HYP_HOME>/exports, or configure later. - Pick a retention window (default
30days). - 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--useron Linux), attaches the selected clients, and starts capturing. - The walkthrough finishes by printing the config path, daemon status,
per-client attach results, and a first
hyp querycommand to run.
For unattended installs (CI, scripted bootstraps, dotfiles) use the non-interactive flags:
hyp init --yes \
--source claude --source otel \
--client claude \
--export local-parquet \
--retention-days 30Other 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 30-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 |
hyp join enrolls a host in a fleet so its recordings are forwarded to a
central sink:
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 installIt 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.
| Path | Contents |
|---|---|
<HYP_HOME>/hypaware-config.json |
Active config (rewritten by hyp init) |
<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.
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 query status to inspect cache freshness per dataset.
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 graph neighbors <node> --depth 2 # walk out from a seed nodehyp 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.
Claude Code and Codex additionally get a hypaware-graph skill (and a
graph_neighbors tool) so an assistant can project and walk the graph on your
behalf.
Attach a single client (idempotent — running twice is a no-op):
hyp attach claude
hyp attach codex
# Equivalent flag form:
hyp attach --client claude
hyp attach --client codexDetach (removes only HypAware-managed settings):
hyp detach claude
hyp detach codex
# Equivalent aliases:
hyp detach --client claude
hyp detach --client codex
hyp unattach claude
hyp unattach codexBoth commands support --dry-run and --json for inspection and
scripting. Claude writes only HypAware-related keys to
~/.claude/settings.json; Codex writes a hypaware provider entry to
~/.codex/config.toml. Unrelated keys in either file are preserved.
A .hypignore file declares a data-usage policy for a directory subtree. It
currently carries exactly one class, ignore: AI gateway exchanges (Claude /
Codex) whose working directory is at or under a directory containing a
.hypignore are never written to the local cache. The live LLM call is
untouched; only persistence is suppressed.
Resolution is gitignore-style: from an exchange's cwd, HypAware walks up the
directory tree, and any .hypignore found on the way governs. Dropping one
file at a repo root covers the whole repo, but the file works anywhere in the
ancestor chain, including outside a git repo.
Manage it with the CLI (idempotent; hand-authoring the dotfile is optional):
hyp ignore # write a .hypignore at the repo root (or cwd if not in a repo)
hyp ignore <path> # ignore a specific directory subtree
hyp ignore --check # report whether cwd is ignored, which file governs, and
# how many already-cached rows from the scope remain
hyp unignore # remove the governing .hypignore, re-enabling recordinghyp ignore writes a self-documenting file (a comment header plus the ignore
token); an empty or comment-only .hypignore also means ignore. Pass
--json to hyp ignore for a machine-readable result.
Two things to know:
- Prospective only. A
.hypignoregates future recording and backfills. Rows already captured before the file existed are left in place;hyp ignore --checksurfaces that residual count. - Folder matching needs a
cwd. Only the Claude and Codex pathways supply one, so.hypignoreis a no-op for theraw-anthropic/raw-openaiproxy and OTEL sources.
To pause recording for just the current Claude session (in-memory, reversible,
not committed) use the /hypaware-ignore and /hypaware-unignore skills
instead.
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 file (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 init will install.
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 --jsonWhen 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 init or hyp init --from-file <config.json> |
config_invalid |
the loaded config failed schema / cross-plugin validation | hyp init --from-file <config.json> |
client_without_gateway |
a client plugin (Claude / Codex) is enabled but @hypaware/ai-gateway is not |
re-run hyp init, then hyp attach --client <name> |
gateway_missing_anthropic_upstream |
@hypaware/claude enabled but no Anthropic upstream is registered on the gateway |
re-run hyp init and pick the Anthropic upstream |
gateway_missing_openai_upstream |
@hypaware/codex enabled but no OpenAI upstream is registered |
re-run hyp init and pick the OpenAI upstream |
sink_missing_encoder |
a local-fs sink is configured but no encoder plugin is enabled | re-run hyp init and pick "local Parquet export" |
client_attach_missing |
a client plugin is enabled but its settings file shows no HypAware marker | hyp attach --client claude or hyp 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 daemonhyp daemon install— re-install the launchd / systemd unithyp attach --client claude/hyp attach --client codex— wire a selected client into the local gatewayhyp init --from-file <path>— rebuild the config from a known-good file without re-running the interactive picker
Run before tagging a new HypAware release:
npm test # if a test script is present
npm run typecheck # if a typecheck script is present
npm pack --dry-run # verify the published file setRe-run the smoke battery and confirm every one is green:
hyp smoke package_bin_boot
hyp smoke cli_bundled_plugins_activated
hyp smoke daemon_foreground_start_stop
hyp smoke daemon_install_render
hyp smoke walkthrough_picker_to_first_query
hyp smoke client_attach_idempotent
hyp smoke gateway_claude_capture
hyp smoke gateway_codex_capture
hyp smoke hypignore_capture_drop
hyp smoke local_only_export_withhold
hyp smoke otel_loopback_capture
hyp smoke local_parquet_export
hyp smoke status_diagnosticsFinally, exercise the manual gate end-to-end on at least one macOS host and one Linux host:
npm pack
npx ./hypaware-*.tgz
hypaware status
hypaware daemon restart
hypaware query sql "select count(*) from ai_gateway_messages"
hypaware query sql "select count(*) from traces"
hypaware query sql "select count(*) from logs"
hypaware daemon uninstallsrc/
core/ # the kernel
observability/ # tracer, logger, meter, attrs, span helpers
manifest.js
dep_graph.js
registry/ # capabilities, commands, datasets, sources, sinks
runtime/ # paths, activation, loader, daemon runtime
cache/ # intrinsic Iceberg-backed cache
cli/ # dispatch, walkthrough, core_commands
config/ # v2 schema, validator
daemon/ # platform installers (launchd / systemd) + lifecycle
plugin_install/ # resolver, fetch, lock, update_check
sinks/ # cron driver + encoder utility
hypaware-core/
smoke/ # `hyp smoke <name>` flows
plugins-workspace/
ai-gateway/ # @hypaware/ai-gateway
otel/ # @hypaware/otel
local-fs/ # @hypaware/local-fs
format-parquet/ # @hypaware/format-parquet
format-jsonl/ # @hypaware/format-jsonl
claude/ # @hypaware/claude
codex/ # @hypaware/codex
central/ # @hypaware/central (bundled, opt-in via `hyp join`)
gascity/ # @hypaware/gascity (bundled, opt-in)
bin/
hypaware.js # CLI entrypoint (bound to both `hypaware` and `hyp`)
Design rationale lives in numbered LLP documents under llp/
(Linked Literate Programming). Start here:
llp/0000-hypaware.explainer.md— root overview and subsystem mapllp/0002-v1-scope.decision.md— what actually shipped in V1llp/0001-adopting-llp.plan.md— how this docs system was set up
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/.
docs/PLUGIN_AUTHORING.md— how to write a plugin (hyp plugin new/hyp plugin doctor)hypaware-plugin-kernel-types.d.ts— public plugin interfaces