Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 21 additions & 9 deletions catalog.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1258,12 +1258,14 @@ community:
domain: Home Assistant
description: "Read and update the entity, area, and device registries that only the WebSocket API exposes, call services with a capability pre-check and an explained refusal, and summarise sensor history, logbook, and recorder statistics with their data-quality caveats - `HASS_AXI_READ_ONLY` refuses every write on both transports."
admission:
status: exception
reviewed_revision: 5555f1323d8b27c5aa1dd36ebbf6b7b6f2e8222c
status: admitted
reviewed_revision: 1e457472581925cea35a790e1663c3ba39efa8b3
reviewed_components:
- pyproject.toml
- src/hass_axi/__init__.py
- src/hass_axi/entry.py
- src/hass_axi/cli.py
- src/hass_axi/argspec.py
- src/hass_axi/errors.py
- src/hass_axi/output.py
- src/hass_axi/toon.py
Expand All @@ -1272,6 +1274,12 @@ community:
- src/hass_axi/ws.py
- src/hass_axi/config.py
- src/hass_axi/hooks.py
- src/hass_axi/sessionlog.py
- src/hass_axi/skill.py
- src/hass_axi/toolkit/__init__.py
- src/hass_axi/toolkit/names.py
- src/hass_axi/toolkit/shapes.py
- src/hass_axi/toolkit/recorder.py
- src/hass_axi/commands/_common.py
- src/hass_axi/commands/home.py
- src/hass_axi/commands/context.py
Expand All @@ -1289,14 +1297,18 @@ community:
- src/hass_axi/commands/wscmd.py
- skills/hass-axi/SKILL.md
source_observations:
- "Tag v0.8.0 is 5555f1323d8b27c5aa1dd36ebbf6b7b6f2e8222c. pyproject.toml declares the `hass-axi` console script (hass_axi.cli:main) with dependencies axi-toolkit>=0.3.0 and websockets>=13.0, and src/hass_axi/__init__.py carries version 0.8.0. The tool was published as `ha-axi` up to 0.7.1 and renamed; it is unrelated to the batamire/ha-axi entry above."
- "src/hass_axi/cli.py is the single error boundary: an AxiError renders as a structured `error`/`code`/`class`/`help` document on stdout with the error's exit code, and any other exception renders as INTERNAL_ERROR instead of a raw traceback. src/hass_axi/errors.py maps usage errors to exit 2 and every other failure to exit 1. An unknown flag is refused by name with the valid flags for that subcommand (UNKNOWN_FLAG, exit 2), an unknown command and a missing subcommand list the valid ones, and `-v`/`--version` print the tool name and version."
- "src/hass_axi/toon.py is an in-tree TOON encoder and src/hass_axi/output.py is the one output boundary: TOON by default with `--json` and `--human` modes, registered secrets redacted before anything reaches stdout or stderr, and `truncate` appending the original length. src/hass_axi/commands/state.py, service.py, and template.py truncate long attribute, description, and rendered-template text with a `--full` hint. List commands print shown, matched, and total counts with a larger-`--limit` suggestion; `entity list`, `device list`, and `state list` default to three fields and `statistics list` to four, with `--fields` selecting from the wider set."
- "src/hass_axi/readonly.py classifies every subcommand and declared WebSocket command as read, write, or dynamic, treats anything unclassified as a write, and refuses writes with READ_ONLY (exit 2) when HASS_AXI_READ_ONLY is non-empty; src/hass_axi/rest.py and src/hass_axi/ws.py enforce the same gate on their own transports. src/hass_axi/commands/api.py treats only GET, HEAD, and OPTIONS as reads, and src/hass_axi/ws.py classifies a `ws --raw` type no declaration names as a write. src/hass_axi/config.py takes the URL and token from the environment only (no token flag or credential file), and src/hass_axi/rest.py refuses a redirect that changes scheme or host instead of forwarding the Authorization header."
- "Tag v0.10.0 is 1e457472581925cea35a790e1663c3ba39efa8b3. pyproject.toml declares the `hass-axi` console script (hass_axi.entry:main) with dependencies axi-toolkit>=0.3.0 and websockets>=13.0, and src/hass_axi/__init__.py carries version 0.10.0 and imports nothing. The tool was published as `ha-axi` up to 0.7.1 and renamed; it is unrelated to the batamire/ha-axi entry above."
- "src/hass_axi/entry.py answers a bare `-v`, `-V`, or `--version` before anything else is loaded: it imports only `sys` and the package `__init__`, prints the bare version (0.10.0), and exits 0, and it imports src/hass_axi/cli.py only for any other invocation. cli.py prints the same bare line for a version flag in any other position and in every output mode, and loads each command module, the configuration loader, and the transports on first use."
- "src/hass_axi/cli.py is the single error boundary: an AxiError renders as a structured `error`/`code`/`class`/`help` document on stdout with the error's exit code, and any other exception renders as INTERNAL_ERROR instead of a raw traceback. src/hass_axi/errors.py maps usage errors to exit 2 and every other failure to exit 1. src/hass_axi/argspec.py declares each subcommand's flags: an unknown flag is refused by name with the valid flags for that subcommand (UNKNOWN_FLAG, exit 2), and cli.py answers an unknown command or a missing subcommand with the valid ones. `<command> --help` prints that command's reference: its subcommands, each one's flags with defaults, notes, and examples."
- "src/hass_axi/toon.py is an in-tree TOON encoder and src/hass_axi/output.py is the one output boundary: TOON by default with `--json` and `--human` modes, registered secrets redacted before anything reaches stdout or stderr, and `truncate` appending the original length. src/hass_axi/commands/state.py, service.py, and template.py truncate long attribute, description, and rendered-template text with a `--full` hint. List commands print shown, matched, and total counts with a larger-`--limit` suggestion; `entity list`, `device list`, `state list`, and `service list --domain` default to three fields and `statistics list`, `sensor list` (src/hass_axi/commands/sensor.py), `logbook get` (src/hass_axi/commands/logbook.py), and `area list` (src/hass_axi/commands/area.py) to four, with `--fields` selecting from the wider set and an unknown field name refused (UNKNOWN_FIELD, exit 2) before any request."
- "`shorten` in src/hass_axi/commands/_common.py bounds the raw output of src/hass_axi/commands/api.py and src/hass_axi/commands/wscmd.py: every list keeps its first 25 items, every object its first 25 keys, and every string its first 1200 characters, and a result still over 20,000 characters has its nested containers replaced by counts. A `truncated` line says what was cut and the total size in characters, the `--full` hint is printed only when something was cut, and `--full` prints the whole response."
- "src/hass_axi/readonly.py classifies every subcommand and declared WebSocket command as read, write, or dynamic, treats anything unclassified as a write, and refuses writes with READ_ONLY (exit 2) when HASS_AXI_READ_ONLY is non-empty; src/hass_axi/rest.py and src/hass_axi/ws.py enforce the same gate on their own transports, and src/hass_axi/ws.py classifies a `ws --raw` type no declaration names as a write. src/hass_axi/config.py takes the URL and token from the environment only (no token flag or credential file), and src/hass_axi/rest.py refuses a redirect that changes scheme or host instead of forwarding the Authorization header."
- "One `--write` flag, declared in src/hass_axi/commands/_common.py, gates every command that changes Home Assistant: `service call` (service.py), an `api` request with any method but GET or HEAD (api.py), a `ws` command whose type is not a declared read (wscmd.py), and `entity update`, `area create`, `area update`, and `device update` (entity.py, area.py, device.py). Without it each prints `preview: nothing was sent to Home Assistant` with the request or the `would_change` from/to rows and exits 0; the `service call` preview reads the published service model and the registries and raises the errors the call itself would. A preview is classified as a read, so a read-only session can still see it. `setup hooks` and `setup skill` write local files and take no `--write`."
- "src/hass_axi/commands/service.py pre-checks the capability a service publishes for area and device targets (UNSUPPORTED_CAPABILITY, with `--no-check` to send anyway), exits 1 with NO_ENTITIES_TARGETED when a target reached nothing, and explains a refused call from the service model (for example UNKNOWN_SERVICE_FIELD listing the accepted fields). src/hass_axi/commands/entity.py, area.py, and device.py report `already matches the requested values, no change made` for an update that already holds, and `area create` reports an existing area of the same name instead of failing."
- "src/hass_axi/commands/home.py is the no-argument live view (entity counts by domain, unavailable count, next-step help). src/hass_axi/hooks.py installs a SessionStart hook for Claude Code and Codex and a managed OpenCode plugin only when `hass-axi setup hooks` runs (src/hass_axi/commands/setup.py); the hook runs `hass-axi context`, which src/hass_axi/commands/context.py writes to need no connection or credential and to exit 0. The skill is produced by `hass-axi setup skill`, which generates skills/hass-axi/SKILL.md from the command table and has a `--check` mode for staleness; the committed copy is current at the pin."
- "Gaps observed at the pin: src/hass_axi/commands/sensor.py defaults list rows to six fields and src/hass_axi/commands/logbook.py to five. src/hass_axi/commands/api.py and src/hass_axi/commands/wscmd.py print the whole response with no size truncation. `service call`, write-method `api` requests, and write `ws` commands are sent without a confirmation or preview flag; the capability pre-check and HASS_AXI_READ_ONLY are the only gates. `setup hooks` has no status or removal subcommand and installs no session-end hook. The bare home view prints the description and setup help but exits 1 when HA_URL/HA_TOKEN are unset or Home Assistant is unreachable."
exception: "Principle 2 is partial: `sensor list` defaults to six fields and `logbook get` to five. Principle 3 is partial: `api` and `ws` output is not size-truncated. Principle 6 is partial: `service call` and the raw `api`/`ws` write paths mutate without a confirmation or preview step, relying on the capability pre-check and the opt-in `HASS_AXI_READ_ONLY` switch. Principle 7 lacks hook status/removal and session-end capture. Principle 8 home view exits 1 without configuration or a reachable server. Observations apply to the pinned wrapper source, not independently verified Home Assistant behavior."
- "src/hass_axi/commands/home.py is the no-argument live view: executable path, description, entity counts by domain, unavailable and unknown counts, capped not-reporting, low-battery, and stale-sensor lists, and next-step help. With HA_URL/HA_TOKEN unset or Home Assistant unreachable it returns the same document with `live_state: not available - ...`, a `code` and `class`, the command names, and setup help, and src/hass_axi/cli.py exits 0 for it."
- "src/hass_axi/hooks.py installs SessionStart and SessionEnd hooks for Claude Code and Codex (setting Codex's `[features] hooks`) and a managed OpenCode plugin only when `hass-axi setup hooks` runs (src/hass_axi/commands/setup.py), recording the bare binary name only when PATH resolves it to this executable; a repeat install reports each target current and a moved path is repaired. `setup hooks status` reports each target as installed, stale, or missing and writes nothing; `setup hooks remove` takes out only the entries this tool wrote, leaves Codex's features flag, and reports absent on a second run. The start hook runs `hass-axi context`, which src/hass_axi/commands/context.py writes to need no connection or credential and to exit 0."
- "The session-end hook runs `hass-axi context end`. src/hass_axi/sessionlog.py reads the transcript the hook payload names (or, from the OpenCode plugin, which fires on session idle or deletion, the commands it passes), and records one entry per session: directory, date, a count per command name, and how many invocations carried `--write` - never an argument. `hass-axi context` prints the latest entry for the current directory as `last_session`. The skill is produced by `hass-axi setup skill` (src/hass_axi/skill.py), which generates skills/hass-axi/SKILL.md from the command table and has a `--check` mode for staleness; the committed copy is current at the pin."
- "src/hass_axi/toolkit/ is an importable library surface the CLI is built on: names.py (case- and accent-folded matching, resolution that reports ties and near misses), shapes.py (entity-id and response-shape checks), and recorder.py (statistics summaries and their caveats). The three modules import only the standard library."
- name: plex-axi
url: https://github.com/dmealing/plex-axi
author: dmealing
Expand Down
Loading