Reference

gohealthcli describe-schema

Emit the archive's schema in one of two modes.

--sql dumps live DDL straight from sqlite_master, excluding internal sqlite_* objects. Use this when you want the actual truth of what tables and views exist right now.

The JSON catalog is the success-mode default: it emits a curated document combining the Normalized Views Registry's per-view metadata (name, migration version, declared columns), the live table+column shape from pragma_table_info, the merged hand-curated narrative file, and a stable wire-shape version field. Downstream tools (a Claude skill, an MCP server, a dashboard) read the JSON catalog as the contract. The Common Flag Set --json flag is accepted for the uniform-flag contract but does not change behaviour — the catalog is emitted unless --sql overrides.

--plain is accepted as a no-op — the schema catalog has no key/value plain shape, so describe-schema --plain emits the JSON catalog and surfaces a // note: --plain is a no-op … comment line on stderr; stdout stays valid JSON so users redirecting it to a file are unaffected. --plain --json together fails with the documented mutual-exclusion error.

--db <path> is honoured on its own — passing a Health Archive path without --config opens that archive directly, matching the other read commands (PRD #144 slice 1). When --config is left at its default and only --db is explicit, --db wins without an agreement check; when both --config and --db are explicit and disagree, the error names --db and --config rather than the internal archive_path field.

A drift test in CI fails when a public view exists in sqlite_master without a matching catalog entry — the JSON shape and the live schema cannot diverge silently.

#Normalized View column types

SQLite views don't carry declared column types. pragma_table_info reports the type of each view column from the underlying expression's affinity, which for any non-trivial JSON projection comes back as either an empty string or the literal BLOB. The JSON catalog is read as a contract by LLM consumers, so a column like daily_steps.step_count (an INTEGER projection over data_points) being reported as BLOB actively poisons agent reasoning.

The catalog rewrites those misleading values to the literal "unknown". Every entry in views[*].columns_detailed[*].type is therefore either a real SQL type (TEXT, INTEGER, REAL, NUMERIC, …) or the literal "unknown" — never BLOB, never empty. Treat "unknown" as "the runtime type is opaque from the catalog alone — inspect a row or consult the view DDL".

Table columns (in tables[*].columns) are unaffected: real BLOB columns on real tables still report BLOB. The fallback is view-only.

#Flags

FlagTypeDefaultDescription
--configstringconfig file path
--dbstringSQLite Health Archive path
--jsonboolfalseaccepted for uniformity; the JSON catalog is the success-mode default
--plainboolfalseno-op (schema catalog has no plain shape); emits JSON catalog + stderr note
--no-inputboolfalseaccepted for uniformity; describe-schema does no prompting
--sqlboolfalsedump live DDL from sqlitemaster (excludes internal sqlite* objects)