# Generate and manage reports

Canonical: https://hypaware.ai/docs/cli-reference/generate-and-manage-reports

```text
hyp report <subcommand> [args...]
```

Use `hyp report --help` to list report operations:

```sh
hyp report --help
```

`generate` and `save` are local. The other report commands use a remote
target and resolve the default remote if `--remote` is omitted. `publish`,
`recommend`, `mark`, and `delete` require a write-capable credential.

## `hyp report generate`

```sh
hyp report generate
hyp report generate "Cover last week and focus on repeated debugging work"
```

Launches a recorded AI client with its installed `hypaware-report` skill in
the caller's current working directory. Recorded means what it does for
`hyp ask`: attached, or configured with no attach marker to write (Codex in
its transcript mode). Its CLI must also be on `PATH`, and the
`hypaware-report` skill must already be installed for it. Optional quoted
instructions set the period or focus; otherwise the skill uses the previous
calendar month. If more than one such client could be started, it asks which;
a run that cannot prompt (input or output is not a terminal, or `HYP_NO_TUI=1`)
takes the first client of the offered set rather than failing. The set is in
the order `hyp ask` uses: ascending client id. That pick is
also time-bounded on a terminal: unanswered for 10 seconds, it takes that same
first client and says so on stdout (`No answer at the client prompt - starting
the first one.`), and the first keypress lifts the deadline. The client keeps
its normal permissions, and the session is recorded under the current
directory's own usage class: this is not session isolation, so excerpts it
reads out of `local-only` history are quoted into a transcript that syncs if
the directory you typed the command in does
([PRIVACY.md](https://hypaware.ai/docs/privacy/index.md#marking-directories)). No remote login is required,
and nothing is published unless requested.

The skill drafts `./hypaware-report-<from>-to-<to>/report.md` and linked
pages, using `-2`, `-3`, etc. if the folder already exists, unless you request
another destination, and once the report is reviewed runs
`hyp report save` on that folder, which moves it into `$HYP_HOME/reports`.
A declined pick starts nothing and succeeds; no recorded client carrying the
skill, or a process-start failure, returns `1`. The exit status covers the
launch only, never whether report generation completed. `hyp report list`
shows the saved report; `hyp report publish <name> ...` shares it.

## `hyp report save`

```text
hyp report save <dir> [--keep]
```

Moves a finished report folder into the store, `$HYP_HOME/reports/<name>/`
(`~/.hyp/reports` unless `HYP_HOME` is set), where `hyp report list` finds it
and `hyp report publish <name>` takes it by name. The skill ends with this
step so an agent never writes under your home directory itself.

The folder is held to the publish allow-list before anything moves: it must
hold `report.md` and otherwise only `usage.md`, `work.md`, `health.md`, and
`recommendation-<slug>.md` as regular files. A stray file (a working ledger,
`.DS_Store`) is named and the command exits `2` with nothing created. The
folder keeps its name, which must be a plain directory name with no hidden
prefix; a taken name gets `-2`, `-3`, etc. rather than overwriting. By default
the source folder is removed once its pages are copied: only those pages are
unlinked and the folder removed with a plain `rmdir`, so a file that appeared
since is left where it is and named. `--keep` copies and leaves the draft.

```sh
hyp report save ./hypaware-report-2026-08-01-to-2026-08-31
```

```text
saved hypaware-report-2026-08-01-to-2026-08-31 to /Users/me/.hyp/reports/hypaware-report-2026-08-01-to-2026-08-31
  list: hyp report list --local
  publish: hyp report publish hypaware-report-2026-08-01-to-2026-08-31 --kind usage-review --period 2026-08-01-to-2026-08-31
```

The period on the publish line is read off the folder name the generator
chose; a name in another shape leaves a `<period>` placeholder to fill in.

## `hyp report publish`

```text
hyp report publish <file-or-dir> --kind <kind> --period <period> [--title <title>] [--org <org>] [--remote <target>]
```

Uploads Markdown for the remote to render. The source is a path, or the name
of a saved report (`hyp report list --local`), which resolves to
`$HYP_HOME/reports/<name>` when no such path exists here. A single file must
be `.md` or `.markdown`, sent as `text/markdown`. A folder must contain `report.md` at
its root and may otherwise contain only `usage.md`, `work.md`, `health.md`,
and `recommendation-<slug>.md` (slug: lowercase `[a-z0-9][a-z0-9-]*`).
The legacy `change-<slug>.md` spelling is also accepted. HTML,
images, client assets, subdirectories, and symlinks are rejected before any
upload. The remote renders the HTML; there is no local render step in the
publish path. The remote identifies repeat uploads by content hash. `--org`
applies only to an operator credential that can name an organization.

```sh
hyp report publish hypaware-report-2026-08-01-to-2026-08-31 --kind usage-review --period 2026-08
```

## `hyp report recommend`

```text
hyp report recommend <file.md> [--title <title>] [--org <org>] [--remote <target>]
```

Publishes one recommendation page on its own, with no report around it, for
an analysis that yields a single recommendation. The file must be `.md` or
`.markdown` and is written like a `recommendation-<slug>.md` page inside a
report: the first `# ` heading is the title (`--title` overrides it) and the
bold paragraph under it is the thesis. A page with no heading and no `--title`
is refused before upload. The remote wraps the page in a report of kind
`recommendation` whose period is the publish date (UTC `YYYY-MM-DD`), mints
the `hyprec-` id, and renders it; the report appears in `hyp report list` like
any other and `hyp report get recommendation <period> <id>` serves the page.
Repeat uploads of the same content answer with the existing id (`already
published`). A remote that predates the standalone route returns `1` and says
so. Requires the publisher role, like `publish`.

```sh
hyp report recommend ./recommendation-no-python3.md
```

```text
published hyprec-0123456789abcdef (recommendation/2026-10-03/REPORT_ID)
  view: hyp report get hyprec-0123456789abcdef
```

## `hyp report list`

```text
hyp report list [--local] [--kind <kind>] [--period <period>] [--limit <n>] [--before <publishedAt>] [--recommendations] [--status <state,...>] [--org <org>] [--json] [--remote <target>]
```

Lists the newest reports visible to the selected organization, then this
host's saved reports (`$HYP_HOME/reports`, as `hyp report save` leaves
them) in their own section, newest first by `report.md` mtime, at most 100
with the rest counted. A host with nothing saved prints no section.
`--local` prints the saved section alone, with no remote read, and takes none
of the remote's selectors or filters. When nothing selects or filters the
remote and it cannot be read, the saved reports are still listed under a
one-line warning and the command exits `0`; `--remote`, any filter, or
`--json` keeps the failure and its exit code. `--json` prints the remote's
records alone, so `--limit` bounds the array and the last row's `publishedAt`
is the next `--before`; `--local --json` prints the saved reports, one row
each as `{ "source": "local", "name", "path", "modifiedAt" }`.

```text
saved reports (/Users/me/.hyp/reports):
  2026-09-02T10:00:00.000Z	local	hypaware-report-2026-08-01-to-2026-08-31
  publish one: hyp report publish <name> --kind <kind> --period <period>
```

An empty remote list
succeeds. A report the server recorded as incomplete ends its line with a
notice: `incomplete:` and then `N of M slices analyzed` when the survey
analyzed fewer slices than it found, `N days not inventoried` for days it
could not list, and `generation cut short` when generation stopped early,
joined by `;`. A complete report, or one the server recorded nothing about,
has no notice. Each report's recommendations follow its line, one per line, as the
minted id, its state in brackets, the `recommendation-<slug>` page the id
names, and the page's title, with its thesis on the line below. The state is
the one the remote supplies, such as `open`, `in_progress`, `applied`, or
`dismissed` as last recorded with `hyp report mark`. The label appears only
when the remote supplies a nonempty state, and an explicit `open` shows
`[open]`. A missing, empty, or malformed status, as from a remote that records
none, shows no label: a missing status does not say the recommendation is
open. The page is the artifact path
`hyp report get` takes. A remote that does not read the page's opening at
publish, or a report published before it did, lists the id and page alone.
`--json` prints the records whole, `recommendations` included.

```text
  2026-08-24T09:00:00.000Z	usage-review/2026-W34	REPORT_ID	48213 bytes	Usage review	incomplete: 3 of 5 slices analyzed
      hyprec-0123456789abcdef	[applied]	recommendation-batch-the-retries	Batch the retries
          Every retry is its own call, 506 times a month. One queue fixes it.
      hyprec-fedcba9876543210	recommendation-tenant-check
```

`--recommendations` lists the recommendations themselves, flat across
reports and newest report first, from the remote's recommendation index: id,
state in brackets (under the same rule, so a row without a supplied state has
no label), the parent report's publish time, the parent report as
`kind/period/id` (or `standalone` for one published with `hyp report
recommend`), and the title, with the thesis below. It has no coverage
notice, because the recommendation index does not carry the report's
coverage; the report listing shows it. `--status <state,...>`
filters by state and implies `--recommendations`; an unknown state is refused
before any request, and an empty value (an unset shell variable) still selects
the flat form rather than falling back to the report listing. A remote that
predates the recommendation index returns `1` and says so. `--kind`,
`--period`, `--limit`, and `--before` filter on the parent report in either
form. With `--json`, the flat form prints the remote's recommendation rows
whole.

```text
  hyprec-0123456789abcdef	[in_progress]	2026-08-24T09:00:00.000Z	usage-review/2026-W34/REPORT_ID	Batch the retries
      Every retry is its own call, 506 times a month. One queue fixes it.
  hyprec-fedcba9876543210	[open]	2026-10-03T09:00:00.000Z	standalone	No python3 on the runner
```

```sh
hyp report list --kind usage-review --limit 10 --json
hyp report list --local --json
hyp report list --status open,in_progress
```

## `hyp report get`

```text
hyp report get <kind> <period> <id> [path] [--output <file>] [--org <org>] [--remote <target>]
hyp report get <rec-id> [--output <file>] [--org <org>] [--remote <target>]
```

Fetches a report's entry document or one artifact. Without `--output`, it
writes the exact bytes to standard output, including binary artifact bytes.
A `path` with no extension of its own is tried as given and then as
`.md` and `.html`, so the `recommendation-<slug>` stem `hyp report list`
prints fetches that page without spelling out how it was published.

```sh
hyp report get usage-review 2026-W34 REPORT_ID --output ./usage-review.html
```

Replace `REPORT_ID` with the ID from `hyp report list`.

Given a recommendation id instead (`hyprec-` and sixteen hex characters, the id
`hyp report list` prints under each report), it resolves the id to its report
and page and prints that page (Markdown, or HTML when the report was published
without it) with a `Citations from the report record` tail: the turns the page
cites as `evidence:N`, numbered to match, and the queries the report ran to
reach the recommendation, verbatim in `sql` blocks, and then a `Status`
section: the current state with its reason, links, who recorded it and when,
followed by the history one line per event, oldest first. A recommendation
nobody has marked reads `State: open (never marked)`. This is the read to make
from inside an AI client session when asked to fix a recommendation by id.

```sh
hyp report get hyprec-0123456789abcdef
```

```text
## Status

State: applied
Reason: Landed in hyparam/hypaware#912
Link: https://github.com/hyparam/hypaware/pull/912
By: email:dev@example.com (via cli)
At: 2026-10-03T18:21:07.000Z

History, oldest first:

- 2026-10-01T09:00:00.000Z  in_progress  by email:dev@example.com  via dashboard
- 2026-10-03T18:21:07.000Z  applied  by email:dev@example.com  via cli: Landed in hyparam/hypaware#912 https://github.com/hyparam/hypaware/pull/912
```

## `hyp report fix`

```text
hyp report fix [id] [--kind <kind>] [--period <period>] [--limit <n>] [--org <org>] [--remote <target>]
```

Starts a recorded AI client on one recommendation, in the current directory.
The id is the one `hyp report list` prints under each report. HypAware
resolves it to its report, checks the recommendation page still exists, and
starts the client with instructions to read it through
`hyp report get <rec-id>` and make the change in the current repository.
Nothing is written to disk. The client takes over the terminal and nothing is
pre-authorized: the client asks before running the read. The instructions end
by telling the client to record the outcome: `hyp report mark <rec-id> applied
--reason "<one line>" --link <PR url>` once the change is landed, or
`hyp report mark <rec-id> dismissed --reason "<why>"` if the recommendation
should not be done, with the run's `--org` and `--remote` carried along.

With no id on a terminal, it asks in two steps: first which report, newest
first, each with its publish date and how many recommendations it carries
(a report with none is not offered); then which of that report's
recommendations, labeled by the page's title and described by its thesis
when the remote lists them, else by the page name. Escape on the second
list
returns to the first. `--kind`, `--period` and `--limit` narrow which reports
are offered. Without a terminal, or with `HYP_NO_TUI=1`, the id is required
and omitting it there returns `2`. The client offer set is the recorded one
`hyp report generate` draws on, without the skill requirement: attached, or
configured with no attach marker to write, and with its CLI on `PATH`. If
more than one such client could be started, it asks which; a run given an id
that cannot prompt takes the first of that set, in the order `hyp ask` uses:
ascending client id. That pick is also time-bounded
on a terminal: unanswered for 10 seconds, it takes the first of that set and
says so on stdout (`No answer at the client prompt - starting the first
one.`), and the first keypress lifts the deadline. The report and
recommendation listings above each have their own 10-second deadline, which
starts when that list is shown and is lifted by the first keypress on it;
going back to the first list starts a fresh one. A listing left unanswered
picks nothing and starts nothing: it prints `hyp report fix: no answer at the
picker - nothing started.` with the usage line to stderr and returns `2`. A
declined pick succeeds, as does a listing that carries no
recommendations. A malformed id returns `2`. An unknown id, a recommendation
page the report no longer carries, no launchable client, or a process-start
failure returns `1`.

```sh
hyp report fix hyprec-0123456789abcdef
hyp report fix --kind usage-review
```

## `hyp report mark`

```text
hyp report mark <id> <open|in_progress|applied|dismissed> [--reason <text>] [--link <url>]... [--org <org>] [--remote <target>]
```

Records what became of a recommendation. The id is the one `hyp report list`
prints (the legacy `rec-` spelling is accepted). The state is the remote's
vocabulary: `open`, `in_progress`, `applied`, or `dismissed`; any state may
follow any other, so reopening is the same verb. `--reason` (one line, up to
2000 characters) is required for `dismissed` and optional otherwise; a
dismissal without one is refused with exit `2` before any request. `--link`
is repeatable and takes absolute `http(s)` URLs, the pull request that landed
the change most of all (up to 8; a value with a literal comma is split on it,
so percent-encode one). An empty `--link` is refused with exit `2` rather than
recorded as no link. The event is appended on the remote with `via: cli`;
nothing is kept locally. The receipt is the new state line with the reason
and links as recorded. An unknown id, or a remote that predates the status
route, returns `1` and names both readings. Requires the publisher role, like
`publish`.

```sh
hyp report mark hyprec-0123456789abcdef applied --reason "Landed in hyparam/hypaware#912" --link https://github.com/hyparam/hypaware/pull/912
hyp report mark hyprec-0123456789abcdef dismissed --reason "The retry loop was removed in 1.39"
```

```text
marked hyprec-0123456789abcdef [applied]	Batch the retries
  reason: Landed in hyparam/hypaware#912
  link: https://github.com/hyparam/hypaware/pull/912
```

## `hyp report delete`

```text
hyp report delete <kind> <period> <id> [--yes] [--org <org>] [--remote <target>]
```

**Warning:** This operation permanently deletes the report and its artifacts
for every member of the organization. It prompts on a terminal. A
non-interactive call without `--yes` refuses with exit code `2`.

```sh
hyp report delete usage-review 2026-W34 REPORT_ID
```

Replace `REPORT_ID` with the reviewed report ID. Avoid `--yes` during manual
work so you can confirm the target.

