cml — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited cml (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.
Build and operate CML labs through the CML MCP tools. The guidance below covers the conventions and pitfalls an agent will not infer correctly on its own. General networking knowledge (e.g., what OSPF is, how a switch works) is assumed and not repeated here.
IDs are opaque — copy them, never reconstruct them. When a tool returns an identifier (lab, node, interface, or link UUID), pass that exact value to later calls. Never retype an ID from memory or rebuild one from context; a single altered character makes the call fail, and the corrupted value can still look well-formed, so you cannot catch the error by inspecting it. If you are not certain you have the exact value, re-fetch it with the relevant listing tool (get_nodes_for_cml_lab, get_interfaces_for_node, get_all_links_for_lab) rather than guessing. One exception: send_cli_command identifies its node by label, not UUID — see Configuration.
Build a lab by composing small, verifiable steps. Do not try to hand-assemble a complete topology object and import it in one call unless the user has explicitly provided a finished model.
Default sequence:
create_empty_lab (title, optional description/notes) → capture the returned lab_id.get_cml_node_definitions once, to learn valid node_definition values for this server. Do not guess names like csr1000v/iosv — servers differ in what's installed. If get_cml_node_definitions returns an error or an empty list, stop immediately and tell the user: the server returned no node definitions and you cannot proceed without them. Do not guess any node_definition value. If the device type the user asked for isn't in the returned list, stop and tell them — name the closest available definitions and let them choose. Never silently substitute a different device type. If `get_cml_node_definitions` returns 2 or more definitions whose names or descriptions could reasonably satisfy the user's request (i.e., they are the same device family or serve the same functional role — e.g. "a Cisco router" matching iol-xe, iosv, csr1000v, cat8000v), list every matching definition by its exact name and ask the user to pick one before proceeding. Do not silently choose the first match.add_node_to_cml_lab per device. Set label, node_definition, and x/y (see Layout). Each add auto-creates that definition's default interfaces.start_cml_lab(lab_id). To start nodes in a specific order (e.g., core infrastructure before edge devices), call start_cml_node(lab_id, node_id) sequentially, using wait_for_convergence=true on each node before starting the next when a later node depends on an earlier one being reachable. See references/operations.md for full lifecycle details.Why incremental beats `create_full_lab_topology`: the full-import tool requires a complete, schema-valid Topology object — exact version, every node id, every interface id, and links referencing those interface IDs by hand. A single mismatch fails the whole import with little to localize the error. The incremental tools validate and return real UUIDs at each step, so failures are isolated and self-correcting.
Escape hatch: use create_full_lab_topology only when (a) the user provides a complete, schema-valid topology object (e.g. an exported/serialized model, or the equivalent complete lab/nodes/links object) or (b) the user explicitly demands a single atomic import. In both cases, load references/topology-schema.md before constructing or validating the topology object. A detailed request _described in prose_ ("three routers in a triangle, each running OSPF") is not a reason to one-shot it; build those incrementally too.
If the user references an existing lab by name or description, call get_cml_labs (or get_cml_lab_by_title) to retrieve its lab_id before any modification. Never create a new lab when the user intends to extend an existing one. Once you have the lab_id, resume at whatever step of the default sequence is appropriate (e.g., step 3 to add nodes, step 4 to connect them).
connect_two_nodes takes interface UUIDs, not node UUIDs. You cannot connect two nodes from their node IDs alone.
For each link:
get_interfaces_for_node(lab_id, node_id) for both endpoints.Loopback0) and any management-only interface; pick a physical data interface (e.g. Ethernet0/0, GigabitEthernet0/1).connect_two_nodes(lab_id, src_int=<iface UUID>, dst_int=<iface UUID>).add_interface_to_node first, then re-fetch.If connect_two_nodes fails, re-fetch interfaces on both nodes (the one you picked may have just been linked), choose genuinely free ones, and retry once. If it fails again, stop and report to the user: state which two nodes you were trying to connect, the interface UUIDs you selected, the exact error returned by the tool, and the current interface availability on both nodes (from the re-fetched list). Do not attempt further retries.
After connecting, optionally get_all_links_for_lab to confirm the topology matches intent before configuring or starting.
Unless the user specifies coordinates, place nodes so a person opening the lab in the CML UI sees a readable diagram they can manipulate — not an overlapping pile. Set x/y on every node at creation time (range −15000..15000; keeping things near the origin is fine).
The goal, not rigid rules: legible, conventional, minimal crossings. In practice that means:
y) and keep the layout roughly symmetric.For labs with distinct functional zones (Core, DMZ, Branch, etc.), group them visually with annotations so the human can read structure at a glance. smart_annotations (tag-based, auto-enclosing) are the lightest way to box and label a group; plain rectangle + text annotations work when you need manual placement. See references/annotations-and-layout.md for coordinate recipes and annotation arguments.
Pick the tool by scenario; each row is independent:
| Scenario | Tool | Node state required | Node identity arg | config_command flag |
|---|---|---|---|---|
| Initial/startup config | configure_cml_node | CREATED | UUID (node_id) | N/A |
| Live incremental config | send_cli_command | BOOTED | label | true |
| Live exec/show commands | send_cli_command | BOOTED | label | false (default) |
Notes: configure_cml_node's config arg is a plain string of CLI lines. With send_cli_command and config_command=true, send config lines _without_ configure terminal/end — the tool handles mode entry.
When the user just wants a working baseline, prefer seeding startup configs on CREATED nodes, then start the lab — rather than booting everything and configuring live.
Changing config after a node has booted: configure_cml_node won't work on a running node — it needs CREATED state. Two options: for incremental changes to a live device, use send_cli_command (this is the usual path — don't wipe just to tweak config). To replace the _startup_ config wholesale, the node must return to CREATED, which means wiping it — a destructive step: confirm with the user, then stop_cml_node → wipe_cml_node → configure_cml_node → start_cml_node.
get_nodes_for_cml_lab / get_all_links_for_lab to confirm structure and read node state.get_console_log(lab_id, node_id) to watch boot progress; pass console=1 for the second serial port on multi-console nodes (some container nodes).start_cml_node(..., wait_for_convergence=true) when a later step depends on the node being stable.wipe_cml_node, wipe_cml_lab, delete_cml_node, and delete_cml_lab are irreversible. Always state exactly what will be destroyed and get an explicit "yes" before calling. Never wipe/delete as an implicit cleanup step.
connect_two_nodes wants interface UUIDs, not node UUIDs. Always get_interfaces_for_node first.configure_cml_node needs CREATED, send_cli_command needs BOOTED) and node identity (send_cli_command takes the label; nearly everything else takes the UUID). See Configuration for the full rules.node_definition values are server-specific. Call get_cml_node_definitions (and get_node_definition_detail for interface counts/defaults) instead of assuming a device exists.add_node_to_cml_lab auto-creates default interfaces; only add_interface_to_node when you've exhausted them.references/topology-schema.md — the full create_full_lab_topology object shape. Read this only when calling create_full_lab_topology — either because the user supplied an already-structured topology object, or because the user explicitly demanded a single atomic import.references/annotations-and-layout.md — coordinate recipes for common layouts (hub-spoke, spine-leaf, linear) and the argument shapes for text/shape/smart annotations and link conditioning. Read when laying out a non-trivial topology or adding visual grouping.references/operations.md — lifecycle (start/stop lab), packet capture on links, link conditioning (latency/loss/jitter), and user/group/permission admin. Read when the task goes beyond building and configuring.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.