What you configure
These are opt-in annotations. They add agent-useful metadata to your commands and flags without changing handler logic. Call them once per command, outside your handlers.
Metadata annotations
Attach a Metadata struct to a command. The fields appear in --schema and describe output so agents can understand the command without running it.
murliCobra.Annotate(queryCmd, murli.Metadata{
AgentDescription: "Search the document index for semantically similar content.",
WhenToUse: "When the user wants to find documents by meaning rather than keyword.",
Idempotent: true,
Returns: &murli.ReturnSchema{
Type: "json",
Description: "Ranked list of search results",
Shape: map[string]any{"path": "string", "score": "float32"},
},
Examples: []murli.Example{
{Command: "mytool query woodworking", Description: "Find documents about woodworking", ExpectedExitCode: 0},
},
})
murli.annotate(query_cmd, murli.Metadata(
agent_description="Search the document index for semantically similar content.",
when_to_use="When the user wants to find documents by meaning rather than keyword.",
idempotent=True,
returns=murli.ReturnSchema(
type="json",
description="Ranked list of search results",
properties={"path": "string", "score": "float"},
),
examples=[
murli.Example(command="mytool query woodworking", description="Find documents about woodworking"),
],
))
Metadata fields
| Go field | Python field | Type | Purpose |
|---|---|---|---|
| AgentDescription | agent_description | string | Description optimised for agent consumption |
| WhenToUse | when_to_use | string | Guidance on when to choose this command over alternatives |
| Idempotent | idempotent | bool | Surfaced as safety.idempotent in schema |
| Mutating | mutating | bool | Activates the non-interactive confirmation guard |
| DryRunnable | dry_runnable | bool | Surfaced as safety.dry_run_supported |
| Destructive | destructive | bool | Surfaced as safety.destructive |
| Returns | returns | *ReturnSchema | Shape and description of the JSON payload |
| Arguments | arguments | []ArgumentMetadata | Positional argument descriptions |
| Examples | examples | []Example | Worked examples with command string and expected exit code |
| FlagAnnotations | flag_annotations | map/dict | Per-flag metadata. Key is the flag name. |
Flag annotations
Per-flag metadata marks sensitive values, declares valid enumerations, and enables profile support.
murliCobra.Annotate(queryCmd, murli.Metadata{
FlagAnnotations: map[string]murli.FlagAnnotation{
"top": {Enum: []string{"5", "10", "20", "50"}},
"token": {Sensitive: true},
"format": {Profileable: true},
},
})
murli.annotate(query_cmd, murli.Metadata(
flag_annotations={
"top": murli.FlagAnnotation(enum=["5", "10", "20", "50"]),
"token": murli.FlagAnnotation(sensitive=True),
"format": murli.FlagAnnotation(profileable=True),
},
))
FlagAnnotation fields
| Go field | Python field | Type | Effect |
|---|---|---|---|
| Sensitive | sensitive | bool | Value redacted in schema output and logs |
| Profileable | profileable | bool | Flag can be saved and recalled via named profiles |
| Persistent | persistent | bool | Flag applies to all subcommands |
| Enum | enum | []string / list[str] | Valid values. Surfaced in schema and error envelopes. |
| MutuallyExclusiveWith | mutually_exclusive_with | []string / list[str] | Flag names that cannot be set simultaneously |
| Pattern | pattern | string | Regex the value must match (informational) |
| Env | env | string | Environment variable that sets this flag when present |
Profiles
Profiles let users save named sets of flag values and recall them with --profile <name>. The profile subcommand is auto-mounted. Mark any flag as profileable to include it in profile operations.
# Save current flags as a named profile $ mytool profile set dev --top 10 --format table # Use the profile in a subsequent call $ mytool query woodworking --profile dev # equivalent to: mytool query woodworking --top 10 --format table # List available profiles $ mytool profile list
Profile data is stored in ~/.config/<toolname>/profiles.json. See the Go reference for the full ProfileStore API.
# Save flags as a named profile $ mytool profile set dev --top 10 --format table # Use the profile in a subsequent call $ mytool query woodworking --profile dev # Set a default profile $ mytool profile set-default dev # List available profiles $ mytool profile list
Profile subcommands: list, set, delete, set-default, show. Profiles are stored in platformdirs.user_config_dir(tool_name) / "profiles.json". See the Python reference for details.
Conventions linter
murli.CheckConventions checks command and flag names against the conventional vocabulary and writes advisory warnings. Go only; requires -tags murlidev.
func TestConventions(t *testing.T) {
issues := murli.CheckConventions(
[]string{"get", "list", "delete", "fetch"}, // "fetch" will warn
[]string{"json", "force", "format"}, // "format" will warn
os.Stderr,
)
if issues > 0 {
t.Errorf("found %d convention issues", issues)
}
}