Skip to content

feat: add --brief listings for the document hives (sop, note, ai-skill)#321

Merged
maximelb merged 3 commits into
masterfrom
feat/sop-list-brief
Jul 24, 2026
Merged

feat: add --brief listings for the document hives (sop, note, ai-skill)#321
maximelb merged 3 commits into
masterfrom
feat/sop-list-brief

Conversation

@maximelb

@maximelb maximelb commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Problem

SOP-reading agents follow a two-step flow, and the CLI's own explain text describes it: list the org's SOPs, read the names and descriptions, fetch the one or two that apply.

Step one doesn't do what that flow assumes. GET /v1/hive/{name}/{oid} returns whole records, so limacharlie sop list already hands back every procedure body in full — the subsequent sop get re-fetches something the caller was made to pay for.

That cost lands in an LLM's context window, which is where it hurts. And it scales the wrong way: the guidance is to keep many narrowly-scoped SOPs rather than one giant policy document, so the listing grows with the thing we want people to do more of.

The same shape appears in two sibling hives, for the same reason:

  • org_notes is byte-identical to soptext + description, same 1 MB cap.
  • ai_skill is the worst case — a listing carries every SKILL.md body and every bundled supporting file.

Fix

An opt-in --brief flag on list for those three hives, reducing each record's data to the fields that identify it and leaving usr_mtd / sys_mtd intact:

limacharlie sop list --brief          # the index
limacharlie sop get --key <name>      # the ones that apply

Index fields are description for sop and note, and name / description / when_to_use for ai-skill.

Default output is deliberately unchanged — the doc-exporter reads data.text straight off the SOP listing, and that keeps working.

Why not the metadata endpoint

The hive service does expose a metadata-only listing, but it returns no data, and description is the field agents match on. It would drop exactly the thing that makes the index useful, so this filters client-side instead. Making the server return a description-bearing index would be the more thorough fix; it needs a platform change and isn't required for the flow to work.

Why not --fields / --filter

Both already exist globally, so I checked. --fields description returns {} — it doesn't descend into data. --filter 'values(@)[].data.description' does work but drops the record names, and isn't something an agent would reliably produce.

Shape

make_hive_group gained an index_keys argument naming the fields that summarize a record. Hives whose data is structured config with no body/description split don't get the flag at all, so there's no misleading option promising a summary the factory can't produce.

--brief fails closed: a payload that isn't an object has none of the index fields and is emitted as {} rather than passed through whole. A null payload stays null — absent isn't the same as filtered.

Verification

  • tests/unit/test_cli_sop.py — 10 tests: default listing unchanged; --brief drops bodies while keeping metadata; missing description yields {} rather than KeyError or a leaked body; non-object payloads fail closed; filtering holds for yaml as well as json; note and ai-skill each covered, with ai-skill asserting both the SKILL.md body and the bundled files are gone; secret list --brief is rejected; and every --brief-capable hive is asserted to document the flag in --ai-help.
  • Full unit suite: 3761 passed, 5 skipped (all five skips pre-existing — Windows/macOS-only and two docstring checks).
  • Smoke-tested list --help across sop / note / ai-skill / secret against an installed build, and confirmed option ordering works in all three positions (--output json sop list --brief, sop list --brief --output json, sop --output json list --brief).
  • The existing regression test pinning each group's subcommand set still holds; this adds an option, not a command.

Note on the second commit

The first commit covered sop only. Reviewing it turned up that the factory's --brief explain text was dead code — register_explain is last-write-wins and every relevant hive overrides its own list explain — and that the docstring justified excluding note and ai-skill on grounds that don't hold. The second commit removes the dead text, opts both hives in, adds the --ai-help regression guard, and makes the filter fail closed.

Follow-up

The agent prompts that run sop list live in another repo and should move to --brief once this is released — deliberately not done here, since they'd break against any CLI that predates this flag.

🤖 Generated with Claude Code

https://claude.ai/code/session_01JwVp8Ug988F8G7G6tjkMaz

Every SOP-reading agent follows the same flow: list the org's SOPs, read
the names and descriptions, then fetch the one or two that apply to the
task. The listing endpoint returns whole records though, so step one
already hands back every procedure body in full — the later `sop get` is
re-fetching something the caller was made to pay for.

That cost lands in an LLM's context window, which is exactly where it
hurts. Orgs are encouraged to keep many narrowly-scoped SOPs, so the
listing grows with the thing we want people to do more of.

Adds an opt-in `--brief` that reduces each record's `data` to its
`description` and leaves metadata intact, which is enough to decide what
to fetch. Default output is untouched, so existing consumers that read
`data.text` off the listing keep working.

The mechanism is generic — `make_hive_group` takes an `index_keys`
argument naming the fields that summarize a record — but only the sop
hive opts in here, since it is the only one whose payload is a document.
Hives that name no index fields do not get the flag at all.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JwVp8Ug988F8G7G6tjkMaz
lcbill
lcbill previously approved these changes Jul 24, 2026
Self-review of the previous commit turned up three problems.

Dead code: the factory appended a --brief paragraph to explain_list, but
register_explain is last-write-wins and every hive that would use it
(sop, note, ai_skill) registers its own <group>.list text right after
calling the factory. The paragraph was never reachable. Removed it, put
the guidance in each hive's own explain, and added a test asserting that
any hive offering --brief documents it in --ai-help — that is the surface
agents read, so a flag missing from it may as well not exist.

Scope: the docstring justified excluding other hives by saying their
records are small. That is false. org_notes is byte-identical to sop
(text + description, 1 MB cap) and ai_skill is worse — a listing carries
every SKILL.md body plus every bundled supporting file. Both are listed
by agents for the same reason sop is. Opted both in rather than
documenting around them, and corrected the docstring to describe the
real criterion: a body plus a field describing it.

Fail open: a record whose data was not an object passed through
unfiltered, so --brief could hand back the payload it exists to drop.
Not reachable for these hives given the server-side record types, but
silence is the bad part. Now fails closed to {}; a null payload still
stays null, since absent is not the same as filtered.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JwVp8Ug988F8G7G6tjkMaz
lcbill
lcbill previously approved these changes Jul 24, 2026
@maximelb maximelb changed the title feat(sop): add sop list --brief to list SOPs without their bodies feat: add --brief listings for the document hives (sop, note, ai-skill) Jul 24, 2026
doc/cli/hive-data.md lists `note list` and `sop list` but not the new
--brief flag, and had no ai-skill section at all. Adds the flag to both
existing sections, an ai-skill section alongside them, and a short note
on why the flag exists (list returns whole records, so for these three
hives it carries every document body).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JwVp8Ug988F8G7G6tjkMaz
@maximelb
maximelb enabled auto-merge (squash) July 24, 2026 00:45
@maximelb
maximelb merged commit e95d3da into master Jul 24, 2026
6 checks passed
@maximelb
maximelb deleted the feat/sop-list-brief branch July 24, 2026 00:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants