From ca1dc858ecde1c93feb027598cbdfccf49480636 Mon Sep 17 00:00:00 2001
From: ajspig <46900795+ajspig@users.noreply.github.com>
Date: Mon, 20 Apr 2026 23:25:12 -0400
Subject: [PATCH] cli docs (#589)
* docs: adding cli doc
* docs: adding generated script and content and github workflow
* chore: removing workflow
* fix: (docs) re-format and add details to cli-reference docs
---------
Co-authored-by: Vineeth Voruganti <13438633+VVoruganti@users.noreply.github.com>
---
docs/docs.json | 3 +-
docs/snippets/cli-commands.mdx | 547 ++++++++++++++++++++++++
docs/v3/documentation/reference/cli.mdx | 220 ++++++++++
honcho-cli/scripts/generate_cli_docs.py | 261 +++++++++++
4 files changed, 1030 insertions(+), 1 deletion(-)
create mode 100644 docs/snippets/cli-commands.mdx
create mode 100644 docs/v3/documentation/reference/cli.mdx
create mode 100644 honcho-cli/scripts/generate_cli_docs.py
diff --git a/docs/docs.json b/docs/docs.json
index 0b357367..54262e3f 100644
--- a/docs/docs.json
+++ b/docs/docs.json
@@ -84,7 +84,8 @@
"group": "Reference",
"pages": [
"v3/documentation/reference/platform",
- "v3/documentation/reference/sdk"
+ "v3/documentation/reference/sdk",
+ "v3/documentation/reference/cli"
]
}
]
diff --git a/docs/snippets/cli-commands.mdx b/docs/snippets/cli-commands.mdx
new file mode 100644
index 00000000..4eb9d2d3
--- /dev/null
+++ b/docs/snippets/cli-commands.mdx
@@ -0,0 +1,547 @@
+{/*
+ GENERATED by honcho-cli/scripts/generate_cli_docs.py — do not edit.
+ Re-generate with: uv run --package honcho-cli python honcho-cli/scripts/generate_cli_docs.py
+ Source of truth: honcho-cli/src/honcho_cli/commands/
+*/}
+
+## honcho conclusion
+
+List, search, create, and delete peer conclusions (Honcho's memory atoms).
+
+
+
+Create a conclusion.
+
+```bash
+honcho conclusion create
+```
+
+
+
+ Observer peer ID.
+
+
+ Observed peer ID.
+
+
+ Session context. Short alias: `-s`.
+
+
+
+Delete a conclusion.
+
+```bash
+honcho conclusion delete
+```
+
+
+
+ Observer peer ID.
+
+
+ Observed peer ID.
+
+
+ Skip confirmation. Short alias: `-y`.
+
+
+
+List conclusions.
+
+```bash
+honcho conclusion list
+```
+
+
+ Observer peer ID.
+
+
+ Observed peer ID.
+
+
+ Max results.
+
+
+
+Semantic search over conclusions.
+
+```bash
+honcho conclusion search
+```
+
+
+
+ Observer peer ID.
+
+
+ Observed peer ID.
+
+
+ Max results.
+
+
+
+
+## honcho config
+
+Inspect CLI configuration.
+
+```bash
+honcho config
+```
+
+
+## honcho doctor
+
+Verify config and connectivity. Scope with -w / -p to check workspace, peer, and queue health.
+
+```bash
+honcho doctor
+```
+
+
+## honcho help
+
+Show help message.
+
+```bash
+honcho help
+```
+
+
+## honcho init
+
+Set API key and server URL in ~/.honcho/config.json.
+
+Press Enter to keep the current value or type a replacement.
+Workspace / peer / session scoping is per-command via -w / -p / -s
+or HONCHO_* env vars — never persisted.
+
+```bash
+honcho init
+```
+
+
+ API key (admin JWT).
+
+
+ Honcho API URL (e.g. https://api.honcho.dev, http://localhost:8000).
+
+
+## honcho message
+
+List, create, and get messages within a session.
+
+
+
+Create a message in a session.
+
+```bash
+honcho message create
+```
+
+
+
+ Peer ID of the message sender. Short alias: `-p`.
+
+
+ JSON metadata to associate with the message.
+
+
+ Session ID. Short alias: `-s`.
+
+
+
+Get a single message by ID.
+
+```bash
+honcho message get
+```
+
+
+
+ Session ID. Short alias: `-s`.
+
+
+
+List messages in a session. Scoped to a peer with -p.
+
+```bash
+honcho message list []
+```
+
+
+
+ Number of recent messages.
+
+
+ Show oldest first (default is newest first).
+
+
+ Show only IDs, peer, token count, and created_at (no content).
+
+
+ Filter by peer ID. Short alias: `-p`.
+
+
+
+
+## honcho peer
+
+List, create, chat with, search, and manage peers and their representations.
+
+
+
+Get raw peer card content.
+
+```bash
+honcho peer card []
+```
+
+
+
+ Target peer for relationship card.
+
+
+
+Query the dialectic about a peer.
+
+```bash
+honcho peer chat
+```
+
+
+
+ Target peer for perspective.
+
+
+ Reasoning level: minimal, low, medium, high, max. Short alias: `-r`.
+
+
+
+Create or get a peer.
+
+```bash
+honcho peer create
+```
+
+
+
+ Whether Honcho will form a representation of this peer. Negate with `--no-observe-me`.
+
+
+ JSON metadata to associate with the peer.
+
+
+
+Get metadata for a peer.
+
+```bash
+honcho peer get-metadata []
+```
+
+
+
+
+Inspect a peer: card, session count, recent conclusions.
+
+```bash
+honcho peer inspect []
+```
+
+
+
+
+List all peers in the workspace.
+
+```bash
+honcho peer list
+```
+
+
+
+Get the formatted representation for a peer.
+
+```bash
+honcho peer representation []
+```
+
+
+
+ Target peer to get representation about.
+
+
+ Semantic search query to filter conclusions.
+
+
+ Maximum number of conclusions to include.
+
+
+
+Search a peer's messages.
+
+```bash
+honcho peer search
+```
+
+
+
+ Max results.
+
+
+
+Set metadata for a peer.
+
+```bash
+honcho peer set-metadata
+```
+
+
+
+ Peer ID (uses default if omitted). Short alias: `-p`.
+
+
+
+
+## honcho session
+
+List, inspect, create, delete, and manage conversation sessions and their peers.
+
+
+
+Add peers to a session.
+
+```bash
+honcho session add-peers
+```
+
+
+
+
+
+Get session context (what an agent would see).
+
+```bash
+honcho session context []
+```
+
+
+
+ Token budget.
+
+
+ Include summary. Negate with `--no-summary`.
+
+
+
+Create or get a session.
+
+```bash
+honcho session create
+```
+
+
+
+ Comma-separated peer IDs to add to the session.
+
+
+ JSON metadata to associate with the session.
+
+
+
+Delete a session and all its data. Destructive — requires --yes or interactive confirm.
+
+```bash
+honcho session delete []
+```
+
+
+
+ Skip confirmation. Short alias: `-y`.
+
+
+
+Get metadata for a session.
+
+```bash
+honcho session get-metadata []
+```
+
+
+
+
+Inspect a session: peers, message count, summaries, config.
+
+```bash
+honcho session inspect []
+```
+
+
+
+
+List sessions in the workspace.
+
+```bash
+honcho session list
+```
+
+
+ Filter by peer. Short alias: `-p`.
+
+
+
+List peers in a session.
+
+```bash
+honcho session peers []
+```
+
+
+
+
+Remove peers from a session.
+
+```bash
+honcho session remove-peers
+```
+
+
+
+
+
+Get the representation of a peer within a session.
+
+```bash
+honcho session representation []
+```
+
+
+
+
+ Target peer (what peer_id knows about target).
+
+
+ Semantic search query to filter conclusions.
+
+
+ Maximum number of conclusions to include.
+
+
+
+Search messages in a session.
+
+```bash
+honcho session search []
+```
+
+
+
+
+ Max results.
+
+
+
+Set metadata for a session.
+
+```bash
+honcho session set-metadata []
+```
+
+
+
+ JSON metadata to set (e.g. '\{"key": "value"\}'). Short alias: `-d`.
+
+
+
+Get session summaries (short + long).
+
+```bash
+honcho session summaries []
+```
+
+
+
+
+
+## honcho workspace
+
+List, create, inspect, delete, and search workspaces.
+
+
+
+Create or get a workspace.
+
+```bash
+honcho workspace create
+```
+
+
+
+ JSON metadata to associate with the workspace.
+
+
+
+Delete a workspace. Use --dry-run first to see what will be deleted.
+
+Requires --yes to skip confirmation, or will prompt interactively.
+If sessions exist, requires --cascade to delete them first.
+
+```bash
+honcho workspace delete
+```
+
+
+
+ Skip confirmation prompt (for scripted/agent use). Short alias: `-y`.
+
+
+ Delete all sessions before deleting the workspace.
+
+
+ Show what would be deleted without deleting.
+
+
+
+Inspect a workspace: peers, sessions, config.
+
+```bash
+honcho workspace inspect []
+```
+
+
+
+
+List all accessible workspaces.
+
+```bash
+honcho workspace list
+```
+
+
+
+Get queue processing status.
+
+```bash
+honcho workspace queue-status
+```
+
+
+ Filter by observer peer.
+
+
+ Filter by sender peer.
+
+
+
+Search messages across workspace.
+
+```bash
+honcho workspace search
+```
+
+
+
+ Max results.
+
+
+
diff --git a/docs/v3/documentation/reference/cli.mdx b/docs/v3/documentation/reference/cli.mdx
new file mode 100644
index 00000000..7b89bfeb
--- /dev/null
+++ b/docs/v3/documentation/reference/cli.mdx
@@ -0,0 +1,220 @@
+---
+title: 'CLI Reference'
+description: 'Command-line interface for Honcho — inspect workspaces, peers, sessions, and memory from your terminal'
+icon: 'terminal'
+---
+
+import CliCommands from "/snippets/cli-commands.mdx";
+
+## Install
+
+
+```bash uv (recommended)
+uv tool install honcho-cli
+```
+
+```bash uvx (ephemeral)
+uvx honcho-cli
+```
+
+
+## Quick Start
+
+```bash
+honcho init # confirm/set apiKey + Honcho URL in ~/.honcho/config.json
+honcho doctor # verify your config + connectivity
+honcho # show banner + command list
+```
+
+## Configuration
+
+The CLI resolves config in this order: **flag → env var → config file → default**.
+
+| Value | File key | Env var | Flag | Persisted? |
+|-------------|-------------------|------------------------|------------------------|------------|
+| API key | `apiKey` | `HONCHO_API_KEY` | — | Yes |
+| API URL | `environmentUrl` | `HONCHO_BASE_URL` | — | Yes |
+| Workspace | — | `HONCHO_WORKSPACE_ID` | `-w` / `--workspace` | No |
+| Peer | — | `HONCHO_PEER_ID` | `-p` / `--peer` | No |
+| Session | — | `HONCHO_SESSION_ID` | `-s` / `--session` | No |
+| JSON output | — | `HONCHO_JSON` | `--json` | No |
+
+### Persisted config
+
+The CLI shares `~/.honcho/config.json` with sibling Honcho tools. It owns only
+`apiKey` and `environmentUrl` at the top level — everything else (`hosts`,
+`sessions`, etc.) is written by other tools and left untouched on save.
+
+```json
+{
+ "apiKey": "hch-v3-...",
+ "environmentUrl": "https://api.honcho.dev",
+ "hosts": { "claude_code": { "...": "..." } }
+}
+```
+
+Per-command scoping (workspace / peer / session) is handled via `-w` / `-p` / `-s`
+flags or `HONCHO_*` env vars. **Not** persisted as CLI defaults. This is
+deliberate: every invocation is explicit about what it operates on.
+
+
+### Runtime overrides
+
+Workspace, peer, and session scoping are **per-command only** — pass flags or
+`HONCHO_*` env vars on every invocation.
+
+```bash
+# Per-command flags
+honcho peer card -w prod -p user
+
+# Or export once per shell
+export HONCHO_WORKSPACE_ID=prod
+export HONCHO_PEER_ID=user
+honcho peer card
+
+# One-off against a different server
+HONCHO_BASE_URL=http://localhost:8000 honcho workspace list
+
+# CI/CD — env vars only, no config file needed
+export HONCHO_API_KEY=hch-v3-xxx
+export HONCHO_BASE_URL=https://api.honcho.dev
+honcho workspace list
+```
+
+## Output & exit codes
+
+Every command adapts its output to the context:
+
+- **TTY** — human-readable tables via Rich.
+- **Piped or redirected** — JSON automatically (detected via `isatty`).
+- **`--json` flag / `HONCHO_JSON=1`** — force JSON regardless of terminal.
+
+Collection commands emit JSON arrays; single-resource commands emit JSON objects. Errors are always structured:
+
+```json
+{
+ "error": {
+ "code": "PEER_NOT_FOUND",
+ "message": "Peer 'abc' not found in workspace 'my-ws'",
+ "details": {"workspace_id": "my-ws", "peer_id": "abc"}
+ }
+}
+```
+
+| Exit code | Meaning |
+|-----------|---------|
+| `0` | Success |
+| `1` | Client error (bad input, resource not found) |
+| `2` | Server error |
+| `3` | Auth error (missing or invalid API key) |
+
+CI pipelines and agent runtimes can branch on these without parsing stderr.
+
+## Command reference
+
+
+
+## Workflows
+
+### Inspect an unfamiliar workspace
+
+When you pick up a workspace and need to orient — start broad, narrow to the peer and session you care about.
+
+
+
+ ```bash
+ honcho workspace inspect --json
+ honcho peer list --json
+ ```
+
+
+ ```bash
+ honcho peer inspect --json
+ honcho peer card --json
+ ```
+
+
+ ```bash
+ honcho conclusion list --observer --json
+ honcho conclusion search "topic" --observer --json
+ ```
+
+
+ ```bash
+ honcho session inspect --json
+ honcho message list --last 20 --json
+ honcho session context --json
+ honcho session summaries --json
+ ```
+
+
+
+
+ `honcho session context` shows exactly what an agent would receive at inference time — check it before `honcho peer chat` if a response surprises you.
+
+
+### A peer isn't learning
+
+If new messages aren't producing new conclusions, work down the diagnostic ladder.
+
+```bash
+# Is observation enabled for this peer?
+honcho peer inspect --json | jq '.configuration'
+
+# Is the deriver actually processing?
+honcho workspace queue-status --json
+
+# Do any conclusions exist at all? Any for the expected topic?
+honcho conclusion list --observer --json
+honcho conclusion search "expected topic" --observer --json
+```
+
+### Session context looks wrong
+
+When an agent's responses don't reflect what you expect it to know.
+
+```bash
+honcho session context --json
+honcho session summaries --json
+honcho message list --last 50 --json
+```
+
+### Dialectic returns bad answers
+
+When `honcho peer chat` or the dialectic API is hallucinating or missing context.
+
+```bash
+# What does the peer card actually say?
+honcho peer card --json
+
+# Any conclusions for this topic?
+honcho conclusion search "topic" --observer --json
+
+# Reproduce the query against the CLI
+honcho peer chat "what do you know about X?" --json
+```
+
+## Scripting & automation
+
+Pipe commands into `jq` for inline transforms, or set `HONCHO_*` env vars for a CI/CD environment with no config file:
+
+```bash
+# Pipe to jq
+honcho peer list --json | jq '.[].id'
+honcho workspace inspect --json | jq '.peers'
+
+# Machine-parseable health check — exit code for CI, details for logs
+honcho doctor --json
+
+# CI/CD — env vars only, no ~/.honcho/config.json
+export HONCHO_API_KEY=hch-v3-xxx
+export HONCHO_BASE_URL=https://api.honcho.dev
+honcho workspace list
+```
+
+Non-interactive onboarding:
+
+```bash
+# Pre-seed via flags / env vars; init still prompts for anything missing
+HONCHO_API_KEY=hch-v3-xxx honcho init --base-url https://api.honcho.dev
+```
diff --git a/honcho-cli/scripts/generate_cli_docs.py b/honcho-cli/scripts/generate_cli_docs.py
new file mode 100644
index 00000000..8fa4e223
--- /dev/null
+++ b/honcho-cli/scripts/generate_cli_docs.py
@@ -0,0 +1,261 @@
+"""Generate ``docs/snippets/cli-commands.mdx`` from the Typer app.
+
+Walks the ``honcho`` Typer app and emits a Mintlify snippet using native
+Mintlify components: ```` / ```` for subcommand
+grouping and ```` for each argument and option. The output is a
+single snippet included by ``docs/v3/documentation/reference/cli.mdx``.
+
+Usage::
+
+ uv run --package honcho-cli python honcho-cli/scripts/generate_cli_docs.py
+
+ # Or as a drift check (non-zero exit if the committed snippet is stale):
+ uv run --package honcho-cli python honcho-cli/scripts/generate_cli_docs.py --check
+"""
+
+from __future__ import annotations
+
+import sys
+from argparse import ArgumentParser
+from pathlib import Path
+
+import click
+import typer.main
+
+from honcho_cli.main import app
+
+REPO_ROOT = Path(__file__).resolve().parents[2]
+OUTPUT = REPO_ROOT / "docs" / "snippets" / "cli-commands.mdx"
+
+HEADER = """{/*
+ GENERATED by honcho-cli/scripts/generate_cli_docs.py — do not edit.
+ Re-generate with: uv run --package honcho-cli python honcho-cli/scripts/generate_cli_docs.py
+ Source of truth: honcho-cli/src/honcho_cli/commands/
+*/}
+
+"""
+
+# Documented once in cli.mdx's Configuration table. Skip at the per-command
+# level so each Accordion only shows options specific to that subcommand.
+GLOBAL_OPTIONS: set[tuple[str, str]] = {
+ ("--workspace", "Override workspace ID"),
+ ("--peer", "Override peer ID"),
+ ("--session", "Override session ID"),
+ ("--json", "Force JSON output"),
+}
+
+
+def _escape_mdx(text: str) -> str:
+ """Escape MDX-sensitive characters in prose so Mintlify's parser doesn't
+ mistake ``{...}`` for a JSX expression or ```` for a JSX tag."""
+ return (
+ text.replace("\\", "\\\\")
+ .replace("{", "\\{")
+ .replace("}", "\\}")
+ .replace("<", "\\<")
+ )
+
+
+def _attr(value: str) -> str:
+ """Escape a string for use inside a JSX double-quoted attribute value."""
+ return value.replace("\\", "\\\\").replace('"', "'")
+
+
+def _long_opt(param: click.Option) -> str | None:
+ return next((o for o in param.opts if o.startswith("--")), None)
+
+
+def _short_opt(param: click.Option) -> str | None:
+ return next(
+ (o for o in param.opts if o.startswith("-") and not o.startswith("--")),
+ None,
+ )
+
+
+def _is_global(param: click.Parameter) -> bool:
+ if not isinstance(param, click.Option) or not param.help:
+ return False
+ return (_long_opt(param), param.help) in GLOBAL_OPTIONS
+
+
+def _param_type(param: click.Parameter) -> str:
+ if isinstance(param, click.Option) and param.is_flag:
+ return "boolean"
+ if isinstance(param.type, click.Choice):
+ return "string"
+ name = getattr(param.type, "name", "")
+ if name in ("integer", "int"):
+ return "number"
+ if name in ("float", "decimal"):
+ return "number"
+ if name == "boolean":
+ return "boolean"
+ return "string"
+
+
+def _param_path(param: click.Parameter) -> str:
+ if isinstance(param, click.Argument):
+ return param.name or ""
+ return _long_opt(param) or (param.opts[0] if param.opts else "")
+
+
+def _param_required(param: click.Parameter) -> bool:
+ if isinstance(param, click.Argument):
+ return param.required
+ if isinstance(param, click.Option):
+ return bool(param.required)
+ return False
+
+
+def _default_attr(param: click.Parameter) -> str | None:
+ default = param.default
+ if default is None or default is False or callable(default):
+ return None
+ if isinstance(default, (list, tuple)) and not default:
+ return None
+ if default is True:
+ return "true"
+ return _attr(str(default))
+
+
+def _ensure_period(text: str) -> str:
+ return text if text.endswith((".", "?", "!", ":")) else text + "."
+
+
+def _param_body(param: click.Parameter) -> str:
+ parts: list[str] = []
+ if isinstance(param, click.Option):
+ if param.help:
+ parts.append(_ensure_period(_escape_mdx(param.help.strip())))
+ short = _short_opt(param)
+ if short:
+ parts.append(f"Short alias: `{short}`.")
+ if param.secondary_opts:
+ neg = " / ".join(f"`{o}`" for o in param.secondary_opts)
+ parts.append(f"Negate with {neg}.")
+ if isinstance(param.type, click.Choice):
+ choices = ", ".join(f"`{c}`" for c in param.type.choices)
+ parts.append(f"One of: {choices}.")
+ return " ".join(parts)
+
+
+def _render_param(param: click.Parameter) -> list[str]:
+ props = [
+ f'path="{_attr(_param_path(param))}"',
+ f'type="{_param_type(param)}"',
+ ]
+ if _param_required(param):
+ props.append("required")
+ default_attr = _default_attr(param)
+ if default_attr is not None:
+ props.append(f'default="{default_attr}"')
+ body = _param_body(param).strip()
+ open_tag = f""
+ if body:
+ return [open_tag, f" {body}", ""]
+ return [open_tag.replace(">", " />")]
+
+
+def _params_of(
+ cmd: click.Command, *, strip_globals: bool
+) -> list[click.Parameter]:
+ args = [p for p in cmd.params if isinstance(p, click.Argument)]
+ opts = [
+ p
+ for p in cmd.params
+ if isinstance(p, click.Option)
+ and not p.hidden
+ and not (strip_globals and _is_global(p))
+ ]
+ return args + opts
+
+
+def _invocation_line(cmd: click.Command, path: list[str]) -> str:
+ args = [p for p in cmd.params if isinstance(p, click.Argument)]
+ parts = [" ".join(path)]
+ for a in args:
+ placeholder = f"<{a.name}>"
+ if not a.required:
+ placeholder = f"[{placeholder}]"
+ parts.append(placeholder)
+ return " ".join(parts)
+
+
+def _render_accordion(cmd: click.Command, path: list[str]) -> list[str]:
+ lines = [f'']
+ if cmd.help:
+ lines.append(_escape_mdx(cmd.help.strip()))
+ lines.append("")
+ lines.append("```bash")
+ lines.append(_invocation_line(cmd, path))
+ lines.append("```")
+ lines.append("")
+ for p in _params_of(cmd, strip_globals=True):
+ lines.extend(_render_param(p))
+ lines.append("")
+ return lines
+
+
+def _render_top(cmd: click.Command, path: list[str]) -> list[str]:
+ lines = [f"## {' '.join(path)}", ""]
+ if cmd.help:
+ lines.append(_escape_mdx(cmd.help.strip()))
+ lines.append("")
+
+ if isinstance(cmd, click.Group) and cmd.commands:
+ lines.append("")
+ for sub_name in sorted(cmd.commands):
+ lines.extend(
+ _render_accordion(cmd.commands[sub_name], path + [sub_name])
+ )
+ lines.append("")
+ lines.append("")
+ return lines
+
+ lines.append("```bash")
+ lines.append(_invocation_line(cmd, path))
+ lines.append("```")
+ lines.append("")
+ for p in _params_of(cmd, strip_globals=True):
+ lines.extend(_render_param(p))
+ lines.append("")
+ return lines
+
+
+def build() -> str:
+ root: click.Command = typer.main.get_command(app)
+ if not isinstance(root, click.Group):
+ raise SystemExit("Expected root command to be a Group")
+
+ body: list[str] = []
+ for name in sorted(root.commands):
+ body.extend(_render_top(root.commands[name], ["honcho", name]))
+ return HEADER + "\n".join(body) + "\n"
+
+
+def main() -> int:
+ parser = ArgumentParser()
+ parser.add_argument(
+ "--check",
+ action="store_true",
+ help="Exit non-zero if the committed snippet differs from generated output.",
+ )
+ ns = parser.parse_args()
+ generated = build()
+ if ns.check:
+ current = OUTPUT.read_text() if OUTPUT.exists() else ""
+ if current != generated:
+ print(
+ f"::error::{OUTPUT} is stale. Re-run without --check to regenerate.",
+ file=sys.stderr,
+ )
+ return 1
+ return 0
+ OUTPUT.parent.mkdir(parents=True, exist_ok=True)
+ OUTPUT.write_text(generated)
+ print(f"Wrote {OUTPUT}")
+ return 0
+
+
+if __name__ == "__main__":
+ raise SystemExit(main())