Skip to content

Add UAPI.18: CLI introspection - #223

Draft
behrmann wants to merge 22 commits into
uapi-group:mainfrom
behrmann:cli-introspection
Draft

Add UAPI.18: CLI introspection#223
behrmann wants to merge 22 commits into
uapi-group:mainfrom
behrmann:cli-introspection

Conversation

@behrmann

Copy link
Copy Markdown
Member

This is a draft that @keszybz based his work in systemd/systemd#43152 on (with a few typos) fixed. A few commits have been put on top addressing a few things that where found during the review of that PR already and that were commented on behrmann@e7911dc#comments. It also adds what's currently pending in systemd/systemd#43430.

The idea is to have a JSON schema that describes the full output (or a superset of that) that one would get from a binary via --help in a structured way. The idea is that this would allow to automatically generate command line completion from this, which we have already done in mkosi, but would also allow other things, like checking for features of a command line program without resorting to brittle parsing of help output.

This is still very much work in progress.

Comment thread specs/cli_introspection.md Outdated
Comment thread specs/cli_introspection.md Outdated
"version": "myversion",
"features": ["feature1", "feature2", …]
"abstract": ["paragraph1", "paragraph2", …],
"postscript": ["paragraph1", "paragraph2", …],

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

i think we should find a better name for "footer", as that indicates location where to print that, not the category of the text it contains.

Changed it to postscript, but I'm open to other things.

-`required_argument`, or
-`optional_argument`.

`help` is a string that defines the help text of the option.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

hmm, you call this "help" here, and "abstract for the verbs. we should figure this out, and stick to the same concept

I've still got adding help stashed, because the command objects describe both the top-level program and verbs (so this can cover subcommands in git's style, something systemd doesn't really do). In this case a short help string for a verb makes sense and abstract and postscript don't.

Comment thread specs/cli_introspection.md Outdated
Comment thread specs/cli_introspection.md Outdated
Comment on lines +102 to +103
`documentation` is an array of string values describing URIs referencing
documentation for this command, see `man:uri(7)`for a description of valid URIs.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

As mentioned in systemd/systemd#43152 I really like the style man:foo.sec used there, but this currently clashes with the definitions in man:uri(7). I think this works because man reads the dot as the file suffix. Changing this might be difficult, since it would need an IETF RFC?

@keszybz keszybz left a comment

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.

What about using semantic breaks? I think it'd also make making review comment easier.

There should be a complete example, or maybe even more than one.

Comment thread specs/cli_introspection.md Outdated
Comment thread specs/cli_introspection.md
Comment thread specs/cli_introspection.md Outdated
Comment thread specs/cli_introspection.md Outdated
Comment thread specs/cli_introspection.md Outdated
Comment thread specs/cli_introspection.md Outdated
Comment thread specs/cli_introspection.md Outdated
Comment thread specs/cli_introspection.md Outdated
Comment thread specs/cli_introspection.md Outdated
Comment thread specs/cli_introspection.md Outdated
Comment thread specs/cli_introspection.md Outdated
Comment thread specs/cli_introspection.md Outdated
Comment thread specs/cli_introspection.md Outdated
Comment thread specs/cli_introspection.md Outdated
aliases, e.g. for backwards-compatibility.

`argspec` is an array of argspec objects describing the arguments to the command
after the name of the command, i.e. `argv` excluding the element with index 0.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

in the brief version above you suggest the array contains strings, here you write "objects". what is it?

Comment thread specs/cli_introspection.md Outdated
that should not be larger than 16.

`documentation` is an array of string values describing URIs referencing
documentation for this command, see `man:uri(7)`for a description of valid URIs.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

i think we really shoudl recommend man: and https:// urls, and discourage everything else.

man: urls might not be standard, but rlevant terminals all support them.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The worked example has got both, I'll leave this open to add the encouragement for man:

Comment thread specs/cli_introspection.md Outdated
command. If it is empty, it defaults to the value of `name`.

`type` is a string describing what the argument is. It is either of
- `argument`, a direct argument to the command,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

is this supposed to be what gnu getopt() docs call "positional arguments"?

Comment thread specs/cli_introspection.md Outdated

`type` is a string describing what the argument is. It is either of
- `argument`, a direct argument to the command,
- `option`, which is an option from the `options` array of a command, or

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

these are switches, right?

Comment thread specs/cli_introspection.md Outdated

`optional` is a boolean describing whether an argspec object of type `argument`
or `verb` must be passed or not. `optional` is ignored for argspec objects of
type `option`.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

very confusing that option and optional both exist, and do unrelated things?

maybe rename "option" to "switch"?

Comment thread specs/cli_introspection.md Outdated
Comment thread specs/cli_introspection.md Outdated
this option may not be called together with.

`values` is an array of *value objects* describing the values this option may
take. Value objects are described in a section below.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

maybe make clear that absence or null of this means that the syntax/dictionary of the values is left open

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I added a formulation regarding this. PTAL whether the intent "this is some arbitrary blob we don't say anything about" comes across.

@poettering

Copy link
Copy Markdown
Collaborator

verb objects are not defined yet, but i guess you know that

@poettering poettering changed the title CLI introspection Add UAPI.18: CLI introspection Aug 25, 2026
Comment thread specs/cli_introspection.md Outdated
Comment on lines +98 to +100
`verbs` are command objects that describe a program's verbs, also called
subcommands. Verbs may recursively define further verbs up to a maximum depth
that should not be larger than 16.

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.

Should verbs have their own features and version and project fields? Maybe say that those are not allowed except at the top level?

@keszybz

keszybz commented Aug 26, 2026

Copy link
Copy Markdown
Member

verb objects are not defined yet, but i guess you know that

They are defined as recursive commands.

@poettering

Copy link
Copy Markdown
Collaborator

They are defined as recursive commands.

ah, i see that now. not sure that's ideal though, because some of the props of commands don't really apply to verbs, do they?

dunno, i am a bit unsure about thsi.

@keszybz

keszybz commented Aug 26, 2026

Copy link
Copy Markdown
Member

During implementation I realized that there should be a way to mark both verbs and options as deprecated. Maybe even commands.

EDIT: I'm now using optional 'isDeprecated: true'.

@keszybz

keszybz commented Aug 27, 2026

Copy link
Copy Markdown
Member

Another RFE: indicate that some part of the description is missing. For example, if options are not described, or helps are excluded to save space, etc. And in the future, if we include a description of how to generate values for an option, that is missing for an option. For example, because the completions should be generated dynamically.

- add nomenclature preamble
- make version array-valued, to capture downstream versions, e.g.

  $ systemctl --version
  systemd 261 (261.2-1-arch)

- merge options and verbs arrays into arguments array and drop argspec array

  The argspec array was necessary because options and verbs were treated
  separately and therefore no order between options, positional arguments and
  verbs was established. The split was awkward, because of the need to consult
  multiple arrays in the object referencing each other. Combining all arguments
  into a single array established a natural ordering.

  This at least the objects in the arguments array to carry a type, so for
  consistency everything gets one.

- drop group and section for sections
- add example
- indent JSON to 2 spaces
@behrmann

Copy link
Copy Markdown
Member Author

I pushed some changes addressing the above remarks, but after implementing them I mostly rewrote this to get rid of the argspec array.

The argspec array was necessary because options and verbs were treated separately and therefore no order between options, positional arguments and verbs was established. The split was awkward, because of the need to consult multiple arrays in the object referencing each other. Combining all arguments into a single array established a natural ordering and makes the information more local. This also gets red of some of the option/optional confusions. Unfortunately it meant that the type from the argspec objections needed to be pushed down, because now objects of different shapes live in the same array. For consistency everything got a type field.

I also added a nomenclature section and added a worked example.

The latest commit address @keszybz most recent RFE.

@poettering

Copy link
Copy Markdown
Collaborator

given that we are going to release systemd v262 soon, where this is supported, is it time to undraft and stabilize this?

@behrmann

Copy link
Copy Markdown
Member Author

given that we are going to release systemd v262 soon, where this is supported, is it time to undraft and stabilize this?

I think the current version in systemd is not quite what's in this spec at the moment (@keszybz will know best) and there's one or two more things I've not pushed yet, because $DAYJOB kept me busy these past two weeks and I've not had time to work on this since BtO.

The introspection stuff is has a note

This feature
is experimental and the JSON schema may be subject to change in later
release until a future stabilization announcement.

in the NEWS for 262, so this can still change, but I think releasing the spec is more something for after this stabilizes and becomes useful in systemd.

@julian-klode

Copy link
Copy Markdown
Collaborator

I think this maps reasonably well to my half-design for APT's declarative command-line parser, but it would be useful to be a bit more explicit about help messages.

In my mental model (not fully implemented), I define command help as usage, summary and long description - the pattern we go for being

  • Main help shows the commands and their summary
  • Command-specific help is Usage: apt <command> ... (possibly multiple lines) followed by the long description.

I can map this to the spec to map usage to arguments, help for the short description, and abstract the long one.

One of the things that we likely can't address well here is multi-mode commands, notably we have:

Usage: apt [options] why <package>
       apt [options] why-not <package>

Explain why a package is or is not installed. The why command
shows why an installed package is present; why-not shows why a
package cannot be installed. Takes a single package name.

And similarly say install and remove - it often makes sense to document them together if they have the same flags but inverse behavior. We'd instead need to repeat ourselves.

One thing that could be more strictly defined to be useful is the help field - I'm thinking about fish completions which show a short description next to each item. The field is a bit loosely defined and reads like I could add a second-line, which sometimes is useful for --help, say:

--foo   Do bar. 
            This is not the best thing in the world, consider using --bar instead.  # would not want this in fish

Finally, option groups are often shared for us by up to 10 verbs, having to repeat ourselves is a bit of an overhead but it's likely not the end of the world.

```

where `mediaType` is the fixed string
`application/vnd.uapi-group.cli-introspection-0` and `commands` is a non-empty

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.

Drop "-0" here.

`project` is a string describing what this command belongs to.
This may the package that installed it or the project that produced it.

`isDeprecated` is a boolean describing whether the command has been

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.

… something?

"type": "argument"
"name": "filename",
"value_name": "FILE",
"help": "Show this help",

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.

This should be something like "filename to operate on", since this is an arg.


`sections` is an array of string that defines sections in which this option should
be shown.
This is only for display-purposes.

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.

I think "display purposes" is more usual.

i.e. an option object may not have names both with and without dashes.
Options prefixed with a single dash (`-`) are called short options and options
prefixed with two dashes (`--`) are called long options.
Short options are usually followed by a single character,

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.

"Short options are usually just a single character after the dash"

prefixed with two dashes (`--`) are called long options.
Short options are usually followed by a single character,
whereas long options can be a longer string.
Short options may be followed by multiple characters,

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.

I would rephase this. A single-dash option with a long name is not a short option, but a long option with just one dash ;(

Comment on lines +369 to +405
"+AUDIT",
"-SELINUX",
"+APPARMOR",
"-IMA",
"+IPE",
"+SMACK",
"+SECCOMP",
"+GCRYPT",
"+GNUTLS",
"+OPENSSL",
"+ACL",
"+BLKID",
"+CURL",
"+ELFUTILS",
"+FIDO2",
"+IDN2",
"+KMOD",
"+LIBCRYPTSETUP",
"+LIBCRYPTSETUP",
"PLUGINS",
"+LIBFDISK",
"+PCRE2",
"+PWQUALITY",
"+P11KIT",
"+QRENCODE",
"+TPM2",
"+BZIP2",
"+LZ4",
"+XZ",
"+ZLIB",
"+ZSTD",
"+BPF",
"FRAMEWORK",
"+BTF",
"+XKBCOMMON",
"+UTMP",
"+LIBARCHIVE"

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.

In the spec we could trim this to maybe 5 lines. We don't need all the systemd internals here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Development

Successfully merging this pull request may close these issues.

4 participants