You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/commands.md
+115Lines changed: 115 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -58,6 +58,121 @@ app.Map(
58
58
59
59
Root help now includes a dedicated `Global Options:` section with built-ins plus custom options registered through `options.Parsing.AddGlobalOption<T>(...)`.
60
60
61
+
### Hiding individual options
62
+
63
+
Use `.WithOption(<targetName>, option => option.Hidden())` to hide one command option without hiding its command. The target is the CLR handler parameter or options-group property name, not the rendered `--option-name` token:
The callback shape is deliberate. `CommandBuilder` and `OptionBuilder` both expose `Hidden` and `AutomationHidden`, so an API returning the option builder would let `.Option("x").Hidden()` sit in a chain reading exactly like the command-level `.Hidden()` while meaning something quite different, with nothing to signal that the subject had changed. `WithOption` keeps the subject explicit and the chain on the command.
73
+
74
+
For declarative registration, set `Hidden = true` on `ReplOptionAttribute`. This works on direct parameters, options-group properties, and typed global-options properties:
75
+
76
+
```csharp
77
+
publicsealedclassDeploymentOptions
78
+
{
79
+
[ReplOption(Hidden=true)]
80
+
publicstring? InternalToken { get; set; }
81
+
}
82
+
```
83
+
84
+
Manually registered global options can be selected after registration:
Do not hide the whole option when only an old spelling is deprecated. Declare the legacy token in `HiddenAliases`; it remains accepted by CLI and REPL parsing while the canonical token stays visible:
`HiddenAliases` registers those tokens itself; they do not also need to appear in `Aliases`. If the same exact token appears in both arrays, hidden visibility wins. Tokens remain case-sensitive when the option is case-sensitive, so `--account` can be hidden without hiding a distinct `--ACCOUNT` alias.
105
+
106
+
The fluent form operates on an alias already declared in `Aliases`:
A hidden alias is omitted from command/root help, typo suggestions, interactive and shell completion (including value completion after manually typing it), aggregate and exact-path documentation, and MCP schemas. MCP callers use the visible canonical argument name; the hidden alias is only a backwards-compatible CLI/REPL fallback. Like every hidden surface, this is discoverability metadata rather than authorization.
132
+
133
+
Hidden options are omitted from help, interactive and shell completion (including value providers), documentation export, and generated MCP schemas. They remain valid parser inputs on the command line and in the REPL, and bind normally when supplied explicitly.
134
+
135
+
Over MCP the omission is stricter. The advertised tool schema and the list of accepted arguments are built from the same option list, so a `tools/call` that supplies a hidden option is **rejected** — exactly like a call to a hidden command. A hidden option is therefore reachable from a human-driven CLI or REPL session, but not from an agent.
136
+
137
+
A hidden option must be omittable for the provider that builds a discovery surface, because that client otherwise has no valid invocation path. Repl checks the same fallbacks and precedence as the handler binder: a CLR default or nullable shape, synthetic `IProgress<double>`/`IProgress<ReplProgressEvent>` from an available `IReplInteractionChannel`, then direct `IServiceProvider.GetService` before explicit `ExactlyOne`/`OneOrMore` lower bounds are enforced. Direct handler parameters are validated when aggregate documentation or MCP discovery is built, not by `Map` or `.Hidden()`, because `Run` and MCP may receive an external provider only after mapping. If the active provider cannot supply the value, discovery fails with the required-hidden diagnostic rather than advertising an impossible command. Required options-group properties still fail immediately during mapping because that binding path never consults DI.
138
+
139
+
A fluent `.Hidden(isHidden: false)` overrides `ReplOptionAttribute.Hidden`. For direct handler parameters this can restore visibility before provider-aware discovery. A required hidden options-group property is rejected while the command is mapped, before a fluent override can run, so fix that attribute instead.
140
+
141
+
> **Hiding is not access control.** A hidden option stays a fully invocable part of the command line for anyone who knows its name — nothing about it is authenticated, authorized, or secret. Use it for deprecated switches, diagnostic escape hatches and migration aliases. Gate privileged behavior with real authorization, never with obscurity.
142
+
143
+
### Hiding an option from agents only
144
+
145
+
`.AutomationHidden()` is the option-level counterpart of `CommandBuilder.AutomationHidden()`: it withholds the option from programmatic surfaces while leaving it fully visible to people.
The declarative form is `[ReplOption(AutomationHidden = true)]`. It is **not** supported on typed global-options properties and fails fast there, because global options never reach a programmatic surface at all — the flag would have nothing to act on. `GlobalOptionBuilder` has no `AutomationHidden` for the same reason, enforced by its type rather than by a runtime check.
153
+
154
+
The two axes are independent:
155
+
156
+
| Surface |`.Hidden()`|`.AutomationHidden()`|
157
+
|---|---|---|
158
+
| Command help | omitted |**listed**|
159
+
| Interactive and shell completion | omitted |**offered**|
| CLI and REPL parsing and binding | unaffected | unaffected |
165
+
166
+
Both are discovery filters, and neither is an access-control boundary.
167
+
168
+
### Troubleshooting an option that will not bind
169
+
170
+
Almost always a target-name mistake. `WithOption` takes the **CLR** handler parameter or options-group property name, not the rendered `--option-name` token — `WithOption("internalMode", …)`, never `WithOption("internal-mode", …)`. An unknown target throws at configuration time and the message lists the targets that do exist, so read it rather than guessing.
171
+
172
+
If the option is genuinely hidden and you want to confirm what the app thinks, export the command explicitly: `doc export <command path> --json` includes hidden options with `"isHidden": true`. The aggregate export omits them, so target the command.
173
+
174
+
Note there is no built-in signal for *use* of a hidden option. If the point is retiring a deprecated switch, record that in the handler yourself — otherwise nothing will tell you when it has become safe to remove.
175
+
61
176
### Accessing global options outside handlers
62
177
63
178
Parsed global option values are available via `IGlobalOptionsAccessor`, registered in DI automatically. This enables access from middleware, DI service factories, and handlers:
-`Hidden` to suppress discovery without changing parsing or binding
29
30
- optional per-parameter `CaseSensitivity`
30
31
- optional `Arity`
31
32
-`ReplArgumentAttribute`
@@ -41,6 +42,8 @@ Supporting enums:
41
42
-`ReplParameterMode`
42
43
-`ReplArity`
43
44
45
+
Option visibility can also be configured fluently with `CommandBuilder.WithOption(targetName, option => option.Hidden())` and `ParsingOptions.GlobalOption(name).Hidden()`. Fluent visibility overrides the attribute value, including `.Hidden(isHidden: false)`. Unknown targets fail during configuration instead of being ignored. Hidden options must be omittable, but inferred `ExactlyOne` alone does not make an omittable nullable/defaulted CLR parameter invalid. Required options-group properties fail immediately during mapping because their binder never consults DI. Required direct handler parameters are validated later, when aggregate documentation or MCP discovery knows the active provider; discovery accepts them when the binder can synthesize progress from `IReplInteractionChannel` or resolve the parameter from DI, and otherwise emits the required-hidden diagnostic.
46
+
44
47
### Options groups
45
48
46
49
-`ReplOptionsGroupAttribute` (on a class) marks it as a reusable parameter group
@@ -107,6 +110,9 @@ This same schema drives:
107
110
- command help option sections
108
111
- shell option completion candidates
109
112
- exported documentation option metadata
113
+
- generated MCP tool and prompt schemas
114
+
115
+
Hidden options are filtered from those discovery surfaces, while the same schema continues to accept and bind their tokens during direct execution.
0 commit comments