Skip to content

chore(cli): spike command facts for the command contract - #7557

Draft
mdonnalley wants to merge 4 commits into
developfrom
mikedonnalley/command-facts-poc
Draft

mdonnalley wants to merge 4 commits into
developfrom
mikedonnalley/command-facts-poc

Conversation

@mdonnalley

@mdonnalley mdonnalley commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

Proof of concept for a command contract built from Effect CLI's existing slots and per-fact annotations. Not intended to merge as is; it will be split into separate PRs.

Each fact a command declares lives where Effect already has a slot (input in Command.make, descriptions and examples in Command.with*) or as one Context key on Command.annotations, written by a combinator that also installs the fact's check. A registry pairs each fact with a Schema and its check kinds (compiler, render, runtime or none), and commandCatalog walks the command tree and returns every command's facts as data.

What it adds:

  • Fact registry and catalog (command-internal/command-facts/): registerFact, COMMAND_FACTS, a test that fails on unregistered annotations, and commandCatalog. Permissions, target policy, output, global flags and stage are registered.
  • Global flags read (withGlobalFlagsRead): a two-way check against the leaf's requirement type, so an undeclared read or an unused declaration fails to compile. Help lists only the global flags a command declares. Adopted on branches delete.
  • Typed output (CommandOutput.withHandler): the handler returns the output schema's type, and a wrapper encodes and writes it. Adopted on branches delete.
  • Release stage (withStage): declares experimental status and installs the gate before the handler and its layers. The docs spec reads it. Adopted on network-bans get and remove.
  • Example parsing (parseExample, checkDocsExamples): pnpm docs:spec parses every published example against the command tree without running handlers.

Known gaps: global flag reads through Effect.serviceOption bypass the check; the catalog omits positional arguments and flag value types.

Comment on lines +21 to +22
readonly readonly: boolean;
readonly destructive: boolean;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

quickly skimming this PR and this caught my eye — is it possible for a command to be both readonly and destructive? should CatalogTraits be a string enum instead (e.g., 'readonly' | 'destructive' | 'other')?

This branch has not been deployed

No deployments
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