Skip to content
internal/strictclisupport
On this page

First-class support for strictcli projects: reading the schema document the CLI dumps, and rendering its commands, flags, arguments and groups as pages.

#internal/strictclisupport

#internal/strictclisupport

Package strictclisupport is first-class support for strictcli-based projects.

It reads .strictcli/schema.json -- the document <app> --dump-schema writes -- for the CLI's structure (the app, its commands, flags, arguments and groups) and renders that structure as Markdown documentation pages.

#Version 2 only

The reader accepts schema_version 2 and nothing else. v2 is not a superset of v1: it deletes the type, repeatable and arg-level required keys the v1 reader read, and adds constructs (selectors, constraints, update declarations) v1 had no encoding for. A schema of any other version is a hard error naming the regeneration command, because the alternative -- reading a v1 document with v2 rules -- is a page that silently labels every flag str and every positional argument required. That page shipped once already, which is why there is no fallback here.

#KindIndex

Go go
const KindIndex PageKind = "index"

KindIndex is the CLI reference index page.

#KindCommand

Go go
const KindCommand PageKind = "command"

KindCommand is a top-level command's page.

#KindGroup

Go go
const KindGroup PageKind = "group"

KindGroup is a command group's page.

#SupportedSchemaVersion

Go go
const SupportedSchemaVersion = 2

SupportedSchemaVersion is the one dumped-schema format this reader understands. There is no v1 path and no negotiated fallback.

#PageKind

Go go
type PageKind string

PageKind is which CLI page a description belongs to. Every default description and every recognition of one is decided per kind.

#FlagHelp

Go go
type FlagHelp struct

FlagHelp is one declaration a reader sees, as IterFlagHelp reports it.

#SchemaError

Go go
type SchemaError struct

SchemaError is returned when a schema document is present but cannot be read on v2's terms: a wrong or absent schema_version, an absent project_id, or a project_id naming a different project.

It is the counterpart of the Python surface's ValueError, and a distinct type so the command layer renders it as the refusal it is rather than as an unexpected internal failure.

#SchemaDiscoveryError

Go go
type SchemaDiscoveryError struct

SchemaDiscoveryError is returned when .strictcli/schema.json discovery finds nothing or finds more than one candidate.

It is a hard error: a page that asked for a CLI table cannot be rendered from a schema nobody named, and picking one of several silently would document a different app than the author meant.

#Structure

Go go
type Structure struct

Structure is a CLI's structure as the renderers read it: the app's own facts, its behavioral-completeness declarations, and its commands and groups in declaration order.

The per-command and per-group entries stay decoded objects rather than becoming typed records, for two reasons the Python model had as well: every key a schema carries reaches the renderers untouched, whether this version of selfdoc knows it or not, and the staleness measurement hashes a command's whole entry, so anything dropped here would silently change what a hash covers.

#NoSchemaError

Go go
type NoSchemaError struct

NoSchemaError is returned by ExtractCLIStructure when the project has no dumped schema at all -- the one condition ReadSchemaJSON answers in band instead.

#Object

Go go
type Object = extractors.JSONObject

Object is one decoded JSON object of a dumped schema, remembering the order its keys appeared in.

The order is not a nicety: the index page lists commands and groups in the order the schema declares them, so a model that lost the order would reshuffle every generated page from one run to the next.

#ComputeDefaultCLIDescription

Go go
func ComputeDefaultCLIDescription(kind PageKind, name, appName, helpText string) (string, error)

ComputeDefaultCLIDescription returns the machine-default description for a CLI page.

When the page's help text is at least minHelpForFirstSentence characters long the default is the first sentence of that help; otherwise it is a long-form template naming the app and the command. The index default is always the fixed long-form template.

An unrecognized kind is an error: the caller knows which page it is writing, and inventing a description for a page whose kind is unknown would publish one.

#IsDefaultCLIDescription

Go go
func IsDefaultCLIDescription(value string, kind PageKind, name, appName, helpText string) (bool, error)

IsDefaultCLIDescription reports whether value is a machine-generated default CLI description.

Every historical machine form is recognized, so machine residue is reseeded rather than frozen as if a person had written it:

- the current first-sentence form (help at least minHelpForFirstSentence characters), or - the long-form default template (a shorter help, or the index), or - the historical help[:155] truncation, with or without a trailing ellipsis, or - any prefix of the raw help at least 100 characters long (a truncated default from any prior cut point).

An empty value counts as a machine default: it is a blank machine placeholder the caller should reseed. CLI machine text is derivable from the schema, so this is a live recompute -- no static set can cover the truncated prefix family.

name is accepted for symmetry with ComputeDefaultCLIDescription and is not read: which template a value is compared against is decided by the kind and the help text alone.

#ExpectedCLIPageFilenames

Go go
func ExpectedCLIPageFilenames(structure *Structure) []string

ExpectedCLIPageFilenames returns the filenames GenerateCLIPages would write for structure.

The stale-file cleanup pass reads it to know which CLI page names are current, so the pages a prior run generated are not deleted as stale before the new ones have been written.

#GenerateCLIPages

Go go
func GenerateCLIPages(structure *Structure, docsDir string, handle *effects.Handle) ([]string, error)

GenerateCLIPages generates the Markdown documentation pages for structure into docsDir: an index page, one page per top-level command and one page per command group.

Every page carries generated = true frontmatter and is written read-only through handle, atomically. A page whose description frontmatter has been hand-edited keeps that description; one still carrying a machine default has it recomputed and is marked seeded = true.

It returns the generated filenames, relative to docsDir.

#IterFlagTokens

Go go
func IterFlagTokens(flags []any) []string

IterFlagTokens returns every --token an invocation can actually type, in declaration order, recursing through selector scopes.

A member-spelled selector's own name is not among them -- it is never typed -- while each of its choices is, and a scoped flag is a token like any other. This is what a completeness check must compare a page against; comparing against flag NAMES would demand that a page document a token no user can write.

#IterFlagHelp

Go go
func IterFlagHelp(flags []any) []FlagHelp

IterFlagHelp returns the label and help of every declaration a reader sees, in declaration order.

It recurses through selector scopes, so a scoped flag's help is measured like any other. A selector's own label is its bare name, and each choice is labelled by the token that elects it.

#UsesStrictcli

Go go
func UsesStrictcli(sourcePaths []string, baseDir string) bool

UsesStrictcli reports whether the project at baseDir has a .strictcli/schema.json file.

sourcePaths is accepted for call-site symmetry and is not read: detection is the presence of the schema document and nothing else.

#DiscoverSchemaDirs

Go go
func DiscoverSchemaDirs(baseDir string) []string

DiscoverSchemaDirs discovers the directories under baseDir that hold a .strictcli/schema.json.

It walks baseDir, pruning vendored and build directories and every hidden directory, and records each visited directory that holds a schema as a path relative to baseDir -- the project root being ".". That relative path is the value a schema-dir attribute takes.

The result is sorted. A walk error is not reported: an unreadable directory holds no schema anyone can name, which is the same answer as a directory that holds none.

#ReadSchemaJSON

Go go
func ReadSchemaJSON(baseDir string) (*Structure, error)

ReadSchemaJSON reads baseDir's .strictcli/schema.json and translates it into the structure the renderers read.

It returns a nil structure and a nil error when the document does not exist -- "this project has no dumped schema" is an answer, not a failure. Every per-entry field the renderers read (value_schema, presence, default, choices, elect_by, nullable, negatable, unique, prefixed, variadic, hidden, deprecated, passthrough, flag_sets, constraints, update_of, write_mode) and every effects-regime per-command field (effect, consequential, grants, dry_run_supported, dry_run_unsupported_reason) is carried through untouched.

strictcli omits the app-level global_flags, infra and deprecated keys when they are empty and some emitters write an explicit null; both normalize to empty containers, so a renderer can truth-test them.

A document declaring a schema_version other than SupportedSchemaVersion, carrying no project_id, or naming a different project than the manifest, is a SchemaError.

#CommandName

Go go
func CommandName(entry *Object) string { return getString(entry, "name") }

CommandName is the name a command or group entry declares.

The entries of a Structure are decoded objects rather than typed records -- see the type's own documentation for why -- so these accessors are how a consumer reads the fields every consumer reads, without each one restating how a missing or wrongly-typed field degrades.

#CommandHelp

Go go
func CommandHelp(entry *Object) string { return getString(entry, "help") }

CommandHelp is the help text a command or group entry declares, "" when it declares none.

#CommandFlags

Go go
func CommandFlags(entry *Object) []any { return getList(entry, "flags") }

CommandFlags are a command's flag declarations, in declaration order. Each element is a decoded object, which is what IterFlagTokens and IterFlagHelp read.

#CommandArgs

Go go
func CommandArgs(entry *Object) []any { return getList(entry, "args") }

CommandArgs are a command's positional-argument declarations, in declaration order.

#GroupCommands

Go go
func GroupCommands(group *Object) []*Object

GroupCommands are a group's subcommands, in declaration order.

#Field

Go go
func Field(entry *Object, key string) string { return getString(entry, key) }

Field is the string value of one declared field of any schema entry -- a flag's env var, an argument's help -- and "" when the entry omits it or declares it as something other than a string.

#ExtractCLIStructure

Go go
func ExtractCLIStructure(sourcePaths []string, baseDir string) (*Structure, error)

ExtractCLIStructure reads the CLI structure from baseDir's dumped schema.

It is ReadSchemaJSON with the absent document turned into a NoSchemaError, for the call sites that have already established the project uses strictcli. sourcePaths is accepted for call-site symmetry and is not read.

#PlainValue

Go go
func PlainValue(v any) any

PlainValue converts a decoded schema value into the plain Go value model -- map[string]any, []any and scalars.

It is what the schema-hash input needs: the hash is canonical JSON with sorted keys, so the ordered model this package reads a schema with carries nothing the hash uses, and a reflect-based encoder cannot walk it.

#SchemaError.Error

Go go
func (e *SchemaError) Error() string { return e.Message }

Error returns the diagnostic.

#SchemaDiscoveryError.Error

Go go
func (e *SchemaDiscoveryError) Error() string { return e.Message }

Error returns the diagnostic.

#NoSchemaError.Error

Go go
func (e *NoSchemaError) Error() string

Error names the directory and the command that writes the missing document.

More tools from this site

  • claudestream Drive Claude Code from Python: run it as a subprocess and read its output as typed events, with async and sync sessions, sandbox policies, and tools you define in Python
  • claudewheel A TUI Claude Code Launcher that lets you have more than one profile, manage sessions lifecycle, pick the exact CC version, model to use (even older unlisted ones), pick which GitHub account to use, etc.
  • dirstat Fast, single-binary directory statistics CLI: every file under a tree grouped by format, with counts, sizes, and lines of code, as a colored terminal table or as JSON
  • fastware A batteries-included ASGI framework: msgspec JSON, a managed Granian server, dependency injection, SSE, WebSockets, auth, and a test client
  • go-toml-edit Zero-dep TOML editing library for Go with comment preservation
  • howmuchleft The fastest Claude Code statusline: context window, 5-hour, and weekly limit usage as three customizable gradient bars, rendering in about 6 ms
  • orxtra
  • pgdesign
  • predraw Declarative rendering pipeline: describe a scene in JSON and get SVG, PNG and WebP out, with light and dark style tokens, reusable components and text converted to path outlines
  • reposummary Turn a git repository's history into a Markdown journal: pick a time window or revision range and get a readable digest of what changed, optionally narrated by an LLM
  • rlsbl Release orchestration and project scaffolding CLI that bumps versions, validates a structured JSONL changelog, tags only the commit CI verified, and publishes to npm, PyPI, Go and more
  • safegit git wrapper CLI that gives each commit its own temporary index and retries ref updates on conflict, so concurrent agents share one repository
  • saferm Command-line replacement for rm that archives every deletion with a mandatory reason and the context it ran in, so deleted files can be listed, inspected and restored
  • strictcli
  • stricttest An always-on test-isolation floor: a pytest plugin and a Go env-hygiene module that make a test suite structurally unable to reach real credentials, the real HOME, the network, or the development repository.
  • wesktop A Python framework that turns an ASGI web app into a desktop application, serving it from a local Granian server and displaying it in a native OS window via pywebview
Search