packages/hone-client/README.md
Rama main · réplica de lectura del repositorio original.
# hone-client
The **send side** of [Hone](https://github.com/artisan-build/hone). Install it in a Laravel
app you want to monitor. It redirects that app's own
[`laravel/nightwatch`](https://github.com/laravel/nightwatch) telemetry to your self-hosted
Hone server.
See the [default integration guide](docs/integrate/default.md) for agent-driven setup and verification.
> **Read-only mirror.** This repository is a read-only split of the
> [`artisan-build/hone`](https://github.com/artisan-build/hone) monorepo. Issues and pull
> requests are disabled here — please open them on the monorepo.
## What it does
`hone-client` is thin by design — its only job is to redirect Nightwatch's output to your
Hone app.
- **Rebinds the Nightwatch ingest transport** through a service provider. Nightwatch exposes
its ingest as a swappable object on the container-bound `Core`; `hone-client` replaces it
with one that batches records and POSTs them over HTTPS to your Hone server. No fork of
`laravel/nightwatch`, no daemon, no on-disk buffer.
- **Batches and POSTs** a versioned envelope to the ingest endpoint, authenticating with
`HONE_TOKEN`. `HONE_URL` remains the fallback endpoint.
- **Fails open.** If the endpoint is unreachable, records are dropped and counted without
failing the host app. Web requests keep network work in request termination; long-running
console processes also send full or aged buffers while they run.
- **Octane-safe** — no per-request static state leakage.
It does **not** do sampling (that lives in your Nightwatch config) and it adds **no
redaction layer** (see [Privacy](#privacy)).
## Activation — by presence of config, no boolean
The rebind fires **only when both `HONE_URL` and `HONE_TOKEN` are present and non-empty.**
| `HONE_URL` | `HONE_TOKEN` | Behavior |
| --- | --- | --- |
| set | set | **Active** — telemetry ships to Hone. |
| unset | unset | Inert (the normal state for an app that isn't monitored). |
| only one set | | Inert, but **logs a warning** (half-configured). |
The kill switch is removing or commenting the `HONE_*` values.
## Installation
```bash
composer require artisan-build/hone-client
php artisan hone:install
```
`hone:install` wires the app for tracking: it sets `HONE_URL` / `HONE_TOKEN`, pins
`hone-client` at a caret constraint (`^X`), and confirms your Nightwatch setup will activate.
It is idempotent and asks for consent before touching any file.
### Setting up with a coding agent (skill)
This package ships a **`configuring-hone-client`** skill so a skill-aware coding agent (Claude
Code, etc.) can do the whole setup for you. After `composer require`, it lives at:
```
vendor/artisan-build/hone-client/skills/configuring-hone-client/SKILL.md
```
Point your agent at that file (or copy the `configuring-hone-client/` directory into your
project's `.claude/skills/`) and ask it to *"configure the Hone client."* The skill walks
through the prerequisites, `hone:install`, **verifying the Nightwatch transport rebind is
active** (the step that actually proves it's working), setting the `NIGHTWATCH_DEPLOY` deploy
dimension, confirming receipt on the Hone server over MCP, and the common
"telemetry isn't arriving" failure modes.
### Source-app environment
```dotenv
NIGHTWATCH_ENABLED=true # Nightwatch collects when enabled (the default)
HONE_URL=https://hone.<client>.example/ingest
HONE_TOKEN=<issued by your Hone app's registry>
NIGHTWATCH_DEPLOY=<commit sha, set at deploy; Cloud, Forge and Vapor are read automatically>
# HONE_DISCOVER_INGEST=false # Optional: always use HONE_URL
# Optional tuning: console buffers flush every 60 seconds with 2s connect / 5s total timeouts.
# HONE_FLUSH_INTERVAL=60
# HONE_CONSOLE_CONNECT_TIMEOUT=2
# HONE_CONSOLE_TIMEOUT=5
```
You do **not** need a `NIGHTWATCH_TOKEN`. Nightwatch's collection is gated by
`NIGHTWATCH_ENABLED` (default `true`), not the token — and Hone never talks to Nightwatch's
cloud, so no real Nightwatch credential is required.
When discovery is enabled, `hone-client` schedules `hone:refresh-ingest` hourly. The command
reads `/capabilities` and caches its `ingest.url` for one hour. Telemetry delivery never makes
that discovery request: it uses a fresh cached URL when one exists and otherwise immediately
falls back to `HONE_URL`. A base `HONE_URL` is normalized to its `/ingest` endpoint. If the
scheduler is unavailable, the cache expires, or the cache cannot be read, delivery continues
to use the fallback. Set `HONE_DISCOVER_INGEST=false` to skip scheduling and always use the
fallback.
If a separately managed local agent holds the token instead of the app, duplicate `NIGHTWATCH_TOKEN` into the app environment so `hone-client` leaves Nightwatch enabled.
> **On Laravel Cloud:** do **not** enable the built-in Nightwatch toggle — it runs Cloud's
> managed agent and ships to Nightwatch's cloud, which conflicts with the rebind. Install
> `laravel/nightwatch` + `hone-client` and let the rebind own the transport. Set
> `NIGHTWATCH_*_SAMPLE_RATE` explicitly and high — storage is your only cost.
## Keeping in sync — `hone:update`
After any major update, run:
```bash
php artisan hone:update
```
It calls `{HONE_URL}/capabilities`, compares the `hone-contracts` major you have installed
against the majors your Hone server supports, and either gives the all-clear or tells you to
**update your Hone app first.** The canonical upgrade order is always: **update Hone, then
update your apps.**
`hone-client` also emits a one-line local nudge when the installed `hone-contracts` **major**
changes, reminding you to run `hone:update`. It's zero-network — just a reminder.
## Client identity
`hone-client` carries [`artisan-build/bfc-client`](https://github.com/artisan-build/bfc-client),
which gives this installation a **stable, opaque identity** so the Hone server can attribute an
ingest token to a specific install.
- Every telemetry POST to `HONE_URL` carries the identity in an **`X-BfC-Client-Id`** header,
alongside the `HONE_TOKEN` bearer auth. The identity is a **label, never a credential** — it
grants nothing on its own. It is only ever sent to your Hone server.
- If the identity cannot be resolved, telemetry still ships — **without** the header. Attribution
is never worth dropping telemetry for.
- The identity defaults to a UUID generated once and persisted to
`storage_path('app/bfc-client/identity')`. **On an ephemeral filesystem set
`BFC_CLIENT_IDENTITY` explicitly**, or the identity churns on every deploy.
- `bfc-client` also registers an unauthenticated, throttled `GET /bfc-client` proof-of-life route
that returns the package name and this identity. Move it with `BFC_CLIENT_PROOF_OF_LIFE_PATH`
or disable it with `BFC_CLIENT_PROOF_OF_LIFE=false`.
## Privacy
Hone adds **no** redaction layer; redaction belongs in your Nightwatch config, before
transmission, and `hone-client` ships its recommended defaults **off**:
- **Query bindings are never captured** — SQL arrives parameterized; bound values never enter
the pipeline.
- **Request-body capture stays off** (the Nightwatch default).
- For apps using raw SQL literals or PII-bearing exception messages, configure Nightwatch's
`redactQueries` / exception-message hooks.
Because stored telemetry is parameterized and pre-redacted upstream, it is safe to feed to
an LLM. That is the point.
## License
MIT. See [LICENSE](LICENSE).