climax-config-generator — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited climax-config-generator (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Generate YAML configuration files for CLImax — a tool that exposes any CLI as MCP (Model Context Protocol) tools via a simple YAML mapping.
CLImax reads a YAML file that describes a CLI's commands and arguments, then runs as an MCP server that exposes those commands as tools. An LLM client (Claude Desktop, Cursor, etc.) can then discover and invoke those CLI commands directly.
The YAML config is the only thing you need to write. CLImax handles the MCP protocol, subprocess execution, argument assembly, timeouts, and error handling.
You need the CLI's help output to generate a good config. Ask the user to provide it, or if you have shell access, capture it directly:
# Top-level help
<cli> --help
# Subcommand help (repeat for each important subcommand)
<cli> <subcommand> --helpIf the user provides only top-level help, that's fine for a first pass. You can note which subcommands would benefit from deeper --help inspection and offer to expand later.
Not every subcommand should be a tool. Apply this filter:
Include:
Exclude:
Flag destructive commands clearly in the description if you do include them: "⚠️ DESTRUCTIVE: Permanently deletes..." — and set risk: destructive, which triggers an approval dialog at runtime. See Approval Dialogs.
Follow the schema and rules below precisely.
# --- Top-level (CLImaxConfig) ---
name: "<cli>-tools" # Short identifier, conventionally <cli>-tools
description: "MCP tools for <X>" # What this collection of tools does
command: "<cli>" # Base command (must be on PATH or absolute path)
env: # Optional: extra env vars for all commands
KEY: "value"
working_dir: "/some/path" # Optional: working directory for all commands
# --- Tools list (ToolDef) ---
tools:
- name: <cli>_<action> # snake_case, MUST be prefixed with CLI name
description: "<what and why>" # Explain WHEN and WHY to use this, not just what
command: "<subcommand>" # Appended to base command (can be multi-word)
timeout: 30 # Optional: seconds before killing (default 30)
risk: read # Optional: read (default) | write | destructive
# write/destructive PROMPT the user by default
confirm_message: "Delete {path}?" # Optional: approval dialog template (uses arg names)
resolve: # Optional: resolve opaque IDs for confirm_message
_friendly_name: # Variable name available in confirm_message
command: "describe-thing" # Subcommand (inherits base command)
args: # Arg templates using {arg_name} from tool args
id: "{thing_id}"
timeout: 10 # Short timeout (default 10s)
# --- Arguments (ToolArg) ---
args: # Optional — omit entirely for no-arg commands
- name: <arg_name> # snake_case
type: string # string | integer | number | boolean
description: "<what>" # Clear, concise
required: false # true if command fails without it
flag: "--flag-name" # CLI flag (omit for positional args)
positional: false # true = no flag, placed directly on command line
default: <value> # Optional default value
enum: [val1, val2] # Optional: restrict to specific values
cwd: false # true = value sets working directory, not passed to CLI
stdin: false # true = value piped via stdin, not passed to CLIgit_status, docker_ps, jj_logmax_count, output_format, no_graphname field must be unique across all tools (this matters when multiple configs are merged)flag: "--something" — value follows the flag: --format jsontype: boolean — the flag is present when true, absent when false: --verbosepositional: true and NO flag — value placed directly: git clone <url>flag nor positional is set, CLImax generates --<arg-name> from the arg name (underscores → hyphens)flag: "-n" worksToolDef, not ToolArg) — per-tool timeout in seconds, overriding the default 30s. Set higher for write operations or commands that talk to slow APIs.command field supports multi-word subcommands: command: "bookmark list" produces jj bookmark listjj_bookmark_list with command: "bookmark list", not a separate bookmark tool"Run git log" — Good: "Show recent commit history with optional filtering by author or count""The format flag" — Good: "Output format — use 'json' for structured data, 'table' for human reading"required: true only for args the command genuinely fails withoutdefault for sensible defaults that save the LLM from always specifying them (e.g. default: 10 for log limits)--exec, --command)risk: write for tools that modify state; risk: destructive for irreversible operationsconfirm_message to destructive tools with a clear description of what will happenresolve blocks when tool arguments contain opaque IDs that need human-readable context in the approval dialogSince 0.5.0, the risk field controls real runtime behavior. By default, every tool marked `risk: write` or `risk: destructive` shows a native confirmation dialog before it runs, and the call does not proceed until the user approves it.
This makes risk the highest-stakes field in the config. Getting it wrong fails in both directions:
write) — the user gets a popup on every routine call. A git_log or aws_s3_ls that prompts is worse than useless; people disable approvals entirely, losing protection on the tools that needed it.read) — it executes silently with no confirmation. This is the dangerous direction.The default policy is approval.global: write. Levels, from a policy file:
approval.global | Prompts for |
|---|---|
none | nothing |
destructive | risk: destructive only |
write (default) | risk: write and risk: destructive |
all | every tool call, including reads |
Per-tool overrides win over the global level — approval.tools.<tool_name>: false in a policy file, or require_approval on a tool policy entry.
The dividing line for destructive is "could the user get this back if they clicked Approve by mistake?" — not how alarming the verb sounds.
confirm_messageWithout one, the user sees the raw assembled command. That's fine for simple tools and poor for anything with opaque arguments. Name the specific thing being affected:
- name: gh_pr_close
description: "Close a pull request without merging it"
command: pr close
risk: write
confirm_message: "Close PR #{number} in {repo}?"When the argument is an ID the user won't recognize, use a resolve block to look up something human-readable first. The resolve command runs before the dialog, and its output becomes a template variable:
- name: aws_ec2_terminate
description: "⚠️ DESTRUCTIVE: Permanently terminate an EC2 instance"
command: ec2 terminate-instances
risk: destructive
resolve:
_instance_name:
command: "ec2 describe-instances"
args:
instance-ids: "{instance_id}"
query: "Reservations[0].Instances[0].Tags[?Key=='Name']|[0].Value"
timeout: 10
confirm_message: "Terminate instance {_instance_name} ({instance_id})? This cannot be undone."Terminate instance web-prod-01 (i-0abc123)? is a decision the user can actually make. Terminate instance i-0abc123? is not.
Template variables come from the tool's own arg names plus any resolve keys. A name that doesn't resolve degrades to a generic message rather than failing the call, so verify every {placeholder} matches a real arg or resolve key.
If no GUI and no TTY is available, the default approval.headless: deny refuses the call rather than running it unprompted. Anything marked write or destructive will fail closed when CLImax runs unattended — CI, a container, a remote MCP client with no display.
That is the correct default, but it means risk annotations decide whether a config works at all in automation. If a config is meant for unattended use, say so, and point at --headless-approve or approval.global: none rather than downgrading honest risk levels to make prompts go away.
Users can verify dialogs display on their system with climax test-dialog.
- name: jj_status
description: "Show the working copy status and repo state"
command: status args:
- name: verbose
type: boolean
description: "Show detailed output"
flag: "--verbose"Produces: <cmd> --verbose when true, nothing when false.
- name: git_add
description: "Stage files for the next commit"
command: add
args:
- name: path
type: string
description: "File or directory to stage (use '.' for all)"
required: true
positional: truePositional args are placed before flag args in the assembled command.
- name: docker_compose_ps
description: "List containers managed by Docker Compose"
command: compose psProduces: docker compose ps
- name: format
type: string
description: "Output format"
flag: "--format"
enum: ["json", "table", "csv"] - name: obsidian_create
description: "Create a new note in the vault"
command: create
timeout: 120
args:
- name: path
type: string
flag: "path="
- name: content
type: string
description: "Note content"
stdin: trueThe content value is piped via stdin; only path= appears on the command line.
- name: git_status
description: "Show working tree status for a specific repo"
command: status
args:
- name: directory
type: string
description: "Repository path to run in"
cwd: trueThe directory value sets the subprocess working directory — it never appears on the command line.
After generating a config, mentally verify:
command at top level is just the base command (e.g. git, not git status)command is the subcommand only (e.g. status, not git status)type: boolean (not string "true"/"false")positional: true and no flagflag or a name that auto-converts cleanly (underscores → hyphens)risk: destructive and a confirm_messagerisk: writewrite — they would prompt on every call{placeholder} in a confirm_message matches a real arg name or resolve keyconfirm_message names the specific thing affected, not just the actionresolve blocks reference valid argument names in their templatesSave the generated config as <cli>.yaml. If the user has an existing CLImax project, save to the configs/ directory. The file should be immediately usable:
climax <cli>.yaml --log-level INFOAfter the first pass, offer to:
--help subcommand outputclimax <cli>.yaml --log-level DEBUG and checking the tool list~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.