gns3-lab-automation
GNS3 network lab operations including topology management, device configuration via console, and troubleshooting workflows for routers and switches
Best use case
gns3-lab-automation is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
GNS3 network lab operations including topology management, device configuration via console, and troubleshooting workflows for routers and switches
Teams using gns3-lab-automation should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/skill/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How gns3-lab-automation Compares
| Feature / Agent | gns3-lab-automation | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
GNS3 network lab operations including topology management, device configuration via console, and troubleshooting workflows for routers and switches
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# GNS3 Lab Automation Skill
## Overview
GNS3 (Graphical Network Simulator-3) is a network emulation platform for building complex network topologies. This skill provides knowledge for automating GNS3 lab operations through the MCP server.
## Key Features (Must Know!)
### 🗒️ Project Notes/Memory System
**Problem**: Lab configurations consume conversation context (IPs, credentials, architecture notes)
**Solution**: Store persistent notes in per-project README
**When to use:**
- ✅ Always read notes when starting work on a project
- ✅ Update notes after configuring new devices
- ✅ Document IP schemes, credentials, topology changes
- ✅ Record troubleshooting findings and solutions
**Tools:**
- `get_project_readme()` - Retrieve project documentation
- `update_project_readme(content)` - Save/update documentation (markdown format)
**Resource:** `projects://{id}/readme` (read-only browsing)
**Example Workflow:**
```python
# 1. Always start by reading existing notes
notes = get_project_readme()
# 2. Do your work (configure router, add nodes, etc.)
# ...
# 3. Update notes with new information
update_project_readme("""
# Lab Configuration
## Network Topology
- Router1: 10.1.0.1/24 (GigabitEthernet0/0)
- Router2: 10.1.0.2/24 (GigabitEthernet0/0)
## Credentials
- Username: admin
- Password: cisco123
## Last Updated
2025-10-26: Added Router2, configured OSPF
""")
```
### 📋 Template Usage Notes
**Problem**: Forgetting default credentials, boot times, device-specific setup steps
**Solution**: Templates include built-in usage notes with device info
**What's included:**
- Default credentials (username/password)
- Boot timing estimates ("First boot takes 60 seconds...")
- Persistent storage locations ("/root directory persists")
- Console availability and device-specific quirks
**How to access:**
- **For specific node:** `projects://{id}/nodes/{node_id}/template`
- **For template:** `gns3://templates/{template_id}`
**Example:**
```python
# Get usage notes for a MikroTik node you just created
usage = read_resource("projects://{id}/nodes/{node_id}/template")
# Returns: "The login is admin, with no password by default.
# On first boot, RouterOS is actually being installed..."
```
**Pro Tip:** Check template usage before configuring new devices to avoid common mistakes!
## Core Concepts
### MCP Resources (v0.13.0 - NEW)
**MCP resources provide browsable state** via standardized URIs, replacing query tools for better IDE integration.
**Resource Benefits:**
- Browsable in MCP-aware tools (inspectors, IDEs)
- Automatic discovery and autocomplete
- Consistent URI scheme (`gns3://` protocol)
- Better performance with resource subscriptions
**Available Resources (v0.29.0 - URI Standardization):**
**Project-Centric Resources:**
- `projects://` - List all GNS3 projects
- `projects://{project_id}` - Get project details by ID
- `projects://{project_id}/readme` - Get project README/notes (v0.23.0)
- `projects://{project_id}/sessions/console/` - Console sessions in project (v0.29.1)
- `projects://{project_id}/sessions/ssh/` - SSH sessions in project (v0.29.1)
**Object-Centric Resources:**
- `nodes://{project_id}/` - List nodes in project (NodeSummary, table mode v0.30.0)
- `nodes://{project_id}/{node_id}` - Get node details (full NodeInfo)
- `nodes://{project_id}/{node_id}/template` - Get template usage notes for node (v0.23.0)
- `links://{project_id}/` - List network links in project (table mode v0.30.0)
- `drawings://{project_id}/` - List drawing objects (table mode v0.30.0)
**Diagram Resources (v0.33.0):**
- `diagrams://{project_id}/topology` - Get topology diagram as SVG (visualize lab layout)
**Template Resources (Static, Not Project-Scoped):**
- `templates://` - List all available templates (table mode v0.30.0)
- `templates://{template_id}` - Get template details with usage notes (v0.23.0)
**Session Resources (Dual Access Patterns v0.29.1):**
*Path-based (project-scoped):*
- `projects://{project_id}/sessions/console/` - Console sessions in project
- `projects://{project_id}/sessions/ssh/` - SSH sessions in project
*Query-parameter-based (filtered):*
- `sessions://console/?project_id={id}` - Console sessions filtered by project
- `sessions://ssh/?project_id={id}` - SSH sessions filtered by project
*Unfiltered (all sessions):*
- `sessions://console/` - All console sessions across all projects (table mode v0.30.0)
- `sessions://console/{node_name}` - Console session for specific node
- `sessions://ssh/` - All SSH sessions across all projects (table mode v0.30.0)
- `sessions://ssh/{node_name}` - SSH session status for node
- `sessions://ssh/{node_name}/history` - SSH command history (table mode v0.30.0)
- `sessions://ssh/{node_name}/buffer` - SSH continuous buffer
**Proxy Resources:**
- `proxies:///status` - Main proxy status (THREE slashes)
- `proxies://` - Proxy registry (host + lab proxies, table mode v0.30.0)
- `proxies://sessions` - All proxy sessions (table mode v0.30.0)
- `proxies://project/{project_id}` - Proxies for specific project
- `proxies://{proxy_id}` - Specific proxy details
**Resource vs Tool Usage:**
- **Resources**: Query state (read-only) - use for browsing, monitoring
- **Tools**: Modify state (actions) - use for changes, commands, configuration
**Example Resource Workflow:**
```
# Browse resources (read-only)
1. List all projects: projects://
2. Pick project ID from list
3. View nodes: nodes://{project_id}/
4. Check topology diagram: diagrams://{project_id}/topology
5. Check SSH sessions: sessions://ssh/?project_id={project_id}
6. Check SSH session for specific node: sessions://ssh/R1
# Use tools to modify (actions)
7. Call ssh_configure() to create SSH session
8. Call ssh_command() to execute commands
9. Call set_node() to change node state
10. Call export_topology_diagram() to save diagram as PNG/SVG
```
**Removed in v0.14.0 (use MCP resources instead):**
- `list_projects()` → Use resource `projects://`
- `list_nodes()` → Use resource `nodes://{project_id}/`
- `get_node_details()` → Use resource `nodes://{project_id}/{node_id}`
- `get_links()` → Use resource `links://{project_id}/`
- `list_templates()` → Use resource `templates://`
- `list_drawings()` → Use resource `drawings://{project_id}/`
- `get_console_status()` → Use resource `sessions://console/{node_name}`
- `ssh_get_status()` → Use resource `sessions://ssh/{node_name}`
- `ssh_get_history()` → Use resource `sessions://ssh/{node_name}/history`
- `ssh_get_command_output()` → Use resource with filtering
- `ssh_read_buffer()` → Use resource `sessions://ssh/{node_name}/buffer`
**Final Architecture (v0.34.0):**
- **27 Action Tools**: Modify state (create, delete, configure, execute commands)
- **21 MCP Resources**: Browse state (projects, nodes, sessions, diagrams, proxies) with table mode
- **5 MCP Prompts**: Guided workflows (ssh_setup, topology_discovery, troubleshooting, lab_setup, node_setup)
- **Clear separation**: Tools change things, Resources view things, Prompts guide workflows
- **Table Mode (v0.30.0)**: All list resources use simple table format for readability
### Projects
- **Projects** are isolated network topologies with their own nodes, links, and configuration
- Projects have status: `opened` or `closed`
- Always ensure a project is opened before working with nodes
- Use `open_project()` to activate a project
### Nodes
- **Nodes** represent network devices (routers, switches, servers, etc.)
- Node types: `qemu` (VMs), `docker` (containers), `ethernet_switch`, `nat`, etc.
- Node status: `started` or `stopped`
- Each node has a unique `node_id` and human-readable `name`
**Node Deletion & Cleanup (v0.34.0):**
- `delete_node(node_name)` removes node from project
- **Automatic SSH session cleanup**: When a node is deleted, all SSH sessions are automatically cleaned up:
- Disconnects SSH sessions on ALL registered proxies (host proxy + lab proxies)
- Cleans up internal session mappings
- Best-effort cleanup - won't block deletion if cleanup fails
- **Why**: Prevents orphaned SSH sessions consuming resources
- **Example**:
```python
delete_node("Router1")
# Automatically:
# 1. Deletes node from GNS3
# 2. Disconnects SSH session if active
# 3. Cleans up proxy mappings
# No manual cleanup needed!
```
### Choosing Between SSH and Console Tools
**IMPORTANT: Always prefer SSH tools when available!**
**Use SSH Tools For:**
- Production automation workflows
- Configuration management
- Command execution on network devices
- Better reliability with automatic prompt detection
- Structured output and error handling
- Available SSH tools: `ssh_send_command()`, `ssh_send_config_set()`, `ssh_read_buffer()`, `ssh_get_history()`
**Use Console Tools Only For:**
- **Initial device configuration** (enabling SSH, creating users, generating keys)
- **Troubleshooting** when SSH is unavailable or broken
- **Devices without SSH support** (VPCS, simple switches)
- Interactive TUI navigation (vim, menu systems)
**Typical Workflow:**
1. Start with console tools to configure SSH access
2. Establish SSH session with `configure_ssh()`
3. Switch to SSH tools for all automation
4. Return to console only if SSH fails
### Local Execution on SSH Proxy Container (v0.28.0)
**Use node_name="@" to execute commands directly on the SSH proxy container.**
**Why Use Local Execution:**
- Test connectivity before accessing devices (ping, traceroute)
- Run ansible playbooks from /opt/gns3-ssh-proxy mount
- Execute diagnostic tools not available on network devices
- Orchestrate multi-device operations with custom scripts
**Available Tools:**
- **Network diagnostics**: ping, traceroute, ip, ss, netstat
- **DNS queries**: dig, nslookup
- **HTTP client**: curl
- **Automation**: ansible-core, python3, bash
- **Working directory**: /opt/gns3-ssh-proxy (shared with host)
**Key Advantages:**
- No ssh_configure() needed
- Direct access to diagnostic tools
- Ansible playbooks can orchestrate multiple devices
- Mix local and remote commands in ssh_batch()
**Examples:**
```python
# Test connectivity before device access
ssh_command("@", "ping -c 3 10.10.10.1")
# Run ansible playbook (mounted from host)
ssh_command("@", "ansible-playbook /opt/gns3-ssh-proxy/backup.yml -i inventory")
# DNS lookup for lab devices
ssh_command("@", "dig router1.lab.local")
# Bash script (list of commands)
ssh_command("@", [
"cd /opt/gns3-ssh-proxy",
"python3 backup_configs.py",
"ls -la backups/"
])
# Batch operations - test connectivity then configure devices
ssh_batch([
{"type": "send_command", "node_name": "@", "command": "ping -c 2 10.1.1.1"},
{"type": "send_command", "node_name": "@", "command": "ping -c 2 10.1.1.2"},
{"type": "send_command", "node_name": "R1", "command": "show ip int brief"},
{"type": "send_command", "node_name": "R2", "command": "show ip int brief"}
])
```
**File Sharing with Host:**
1. Place files in `/opt/gns3-ssh-proxy/` on GNS3 host
2. Access same path in container
3. Useful for: ansible playbooks, Python scripts, configuration templates
**Note:** Local execution returns `{success, output, exit_code}` instead of SSH job format.
### Error Responses
**All tools return standardized error responses** (v0.20.0) with machine-readable error codes and actionable guidance.
**Error Response Structure:**
```json
{
"error": "Human-readable error message",
"error_code": "MACHINE_READABLE_CODE",
"details": "Additional error details",
"suggested_action": "How to fix the error",
"context": {
"parameter": "value",
"debugging_info": "..."
},
"server_version": "0.20.0",
"timestamp": "2025-10-25T14:30:00.000Z"
}
```
**Error Code Categories:**
**Resource Not Found (404-style):**
- `PROJECT_NOT_FOUND` - No project open or project doesn't exist
- `NODE_NOT_FOUND` - Node name not found in project
- `LINK_NOT_FOUND` - Link ID doesn't exist
- `TEMPLATE_NOT_FOUND` - Template name not available
- `DRAWING_NOT_FOUND` - Drawing ID not found
- `SNAPSHOT_NOT_FOUND` - Snapshot name doesn't exist
**Validation Errors (400-style):**
- `INVALID_PARAMETER` - Invalid parameter value
- `MISSING_PARAMETER` - Required parameter not provided
- `PORT_IN_USE` - Port already connected to another node
- `NODE_RUNNING` - Operation requires node to be stopped
- `NODE_STOPPED` - Operation requires node to be running
- `INVALID_ADAPTER` - Adapter name/number not valid for node
- `INVALID_PORT` - Port number exceeds adapter capacity
**Connection Errors (503-style):**
- `GNS3_UNREACHABLE` - Cannot connect to GNS3 server
- `GNS3_API_ERROR` - GNS3 server API error
- `CONSOLE_DISCONNECTED` - Console session lost
- `CONSOLE_CONNECTION_FAILED` - Failed to connect to console
- `SSH_CONNECTION_FAILED` - Failed to establish SSH session
- `SSH_DISCONNECTED` - SSH session lost
**Authentication Errors (401-style):**
- `AUTH_FAILED` - Authentication failed
- `TOKEN_EXPIRED` - JWT token expired
- `INVALID_CREDENTIALS` - Wrong username/password
**Internal Errors (500-style):**
- `INTERNAL_ERROR` - Server internal error
- `TIMEOUT` - Operation timed out
- `OPERATION_FAILED` - Generic operation failure
**Example Error Handling:**
```python
# Attempt to start a node
result = set_node("Router1", action="start")
# Check for errors
if "error" in result:
error = json.loads(result)
if error["error_code"] == "NODE_NOT_FOUND":
# Use suggested_action to fix
print(error["suggested_action"]) # "Use list_nodes() to see all available nodes"
# Check available nodes from context
print(error["context"]["available_nodes"]) # ["Router2", "Router3", "Switch1"]
elif error["error_code"] == "GNS3_UNREACHABLE":
# Server connection issue
print(f"Cannot reach GNS3 at {error['context']['host']}:{error['context']['port']}")
```
**Common Error Scenarios:**
1. **No project open**: Most tools require an open project
- Error: `PROJECT_NOT_FOUND`
- Fix: `open_project("ProjectName")`
2. **Node not found**: Typo in node name (case-sensitive)
- Error: `NODE_NOT_FOUND`
- Fix: Check available_nodes in error context or use resource `projects://{id}/nodes/`
3. **Port already in use**: Trying to connect already-connected port
- Error: `PORT_IN_USE`
- Fix: Disconnect existing link first with `set_connection([{"action": "disconnect", "link_id": "..."}])`
4. **Node must be stopped**: Trying to modify running node properties
- Error: `NODE_RUNNING`
- Fix: `set_node("NodeName", action="stop")` then retry
### Tool Annotations (v0.19.0)
**MCP tool annotations** provide metadata to IDE/MCP clients for better UX and safety.
**destructive** (3 tools):
- `delete_node`, `restore_snapshot`, `delete_drawing`
- IDE may show warnings or require confirmation
- These operations delete data or make irreversible changes
- **Always create backups before using destructive tools**
**idempotent** (9 tools):
- `open_project`, `create_project`, `close_project`, `set_node`
- `console_disconnect`, `ssh_configure`, `ssh_disconnect`
- `update_drawing`, `export_topology_diagram`
- Safe to retry - same operation produces same result
- Example: Opening already-opened project is safe
**read_only** (1 tool):
- `console_read`
- Tool only reads data, makes no state changes
- May be cached by MCP clients
**creates_resource** (5 tools):
- `create_project`, `create_node`, `create_snapshot`
- `export_topology_diagram`, `create_drawing`
- Tool creates new resources (in GNS3 or filesystem)
**modifies_topology** (3 tools):
- `set_connection`, `create_node`, `delete_node`
- Tool changes network topology structure
- May require project reload in GNS3 GUI
### Console Access
- Nodes have **console** ports for CLI access
- Console types:
- `telnet`: CLI access (most routers/switches) - currently supported
- `vnc`: Graphical access (desktops/servers) - not yet supported
- `spice+agent`: Enhanced graphical - not yet supported
- `none`: No console
- **Auto-connect workflow** (v0.2.0):
1. Just use `console_send(node_name, command)` - automatically connects if needed
2. Read output with `console_read(node_name)` - returns new output since last read (diff mode, default since v0.9.0)
3. Or use `console_read(node_name, mode="last_page")` for last ~25 lines
4. Or use `console_read(node_name, mode="all")` for full buffer
5. Disconnect with `console_disconnect(node_name)` when done
- Sessions are managed automatically by node name
- Session timeout: 30 minutes of inactivity
**Console State Tracking (v0.34.0):**
- **IMPORTANT**: Must read console BEFORE sending commands
- **Why**: Ensures you understand current terminal state (prompt, login screen, etc.)
- **Enforced**: All send operations (`console_send`, `console_send_and_wait`, `console_keystroke`) check access state
- **Workflow**:
1. First: `console_read("R1")` - Check terminal state (are you at login? prompt? password?)
2. Then: `console_send("R1", "command\n")` - Send appropriate command
3. Read again: `console_read("R1")` - Verify command executed
- **Error**: If you try to send without reading first, you'll get:
```
"Cannot send to console - terminal not accessed yet.
Use console_read() to check current terminal state first."
```
- **Best Practice**: Always read → send → read pattern for reliable automation
### Interactive Console Automation (v0.21.1)
For workflows that need to **wait for specific prompts** before proceeding:
**Tool**: `console_send_and_wait(node_name, command, wait_pattern, timeout, raw)`
**Best Practice Workflow:**
1. **Check the prompt first** - See what you're waiting for:
```
console_send("R1", "\n") # Wake console
output = console_read("R1") # Check output: "Router#"
```
2. **Use that pattern** in console_send_and_wait:
```
result = console_send_and_wait(
"R1",
"show ip interface brief\n",
wait_pattern="Router#", # Wait for this exact prompt
timeout=10
)
```
3. **Check the result**:
```json
{
"output": "Interface IP-Address ...\nGi0/0 192.168.1.1 ...\nRouter#",
"pattern_found": true,
"timeout_occurred": false,
"wait_time": 0.8
}
```
**Use Cases:**
- **Interactive logins**: Wait for "Login:" prompt
- **Command completion**: Wait for prompt to return before next command
- **Configuration mode**: Wait for "(config)#" before sending configs
- **Reboots**: Wait for boot messages to complete
**Examples:**
```
# Wait for login prompt
console_send_and_wait("R1", "\n", wait_pattern="Login:", timeout=30)
# Wait for enable prompt
console_send_and_wait("R1", "enable\n", wait_pattern="#", timeout=5)
# Configuration mode
console_send_and_wait("R1", "configure terminal\n", wait_pattern="(config)#", timeout=5)
# No pattern - just wait 2 seconds and return output
console_send_and_wait("R1", "save config\n")
```
**Pattern Matching:**
- Supports regex patterns: `"Router[>#]"` matches "Router>" OR "Router#"
- Pattern search is case-sensitive by default
- If `wait_pattern=None`, waits 2 seconds and returns output
- Polls console every 0.5 seconds until pattern found or timeout
**Error Handling:**
- Invalid regex: Returns error with `error_code="INVALID_PARAMETER"`
- Console disconnected: Returns error with `error_code="CONSOLE_DISCONNECTED"`
- Timeout without pattern: Sets `timeout_occurred=true`, still returns accumulated output
**When to Use:**
- ✅ Interactive console workflows (logins, menus, confirmations)
- ✅ Ensuring command completion before next step
- ✅ Boot sequences with specific prompts
- ❌ Simple command execution - use `console_send()` + `console_read()` instead
- ❌ SSH-capable devices - use `ssh_command()` for better reliability
### Batch Console Operations (v0.22.0)
For workflows that need to **execute multiple console operations** efficiently:
**Tool**: `console_batch(operations)` - Execute multiple console operations with two-phase validation
**Two-Phase Execution:**
1. **VALIDATE ALL** operations (check nodes exist, required params present)
2. **EXECUTE ALL** operations (only if all valid, sequential execution)
**Supported Operation Types:**
Each operation in the batch can be any of these types with **full parameter support**:
1. **"send"** - Send data to console
```json
{
"type": "send",
"node_name": "R1",
"data": "show version\n",
"raw": false // optional
}
```
2. **"send_and_wait"** - Send command and wait for pattern
```json
{
"type": "send_and_wait",
"node_name": "R1",
"command": "show ip interface brief\n",
"wait_pattern": "Router#", // optional
"timeout": 30, // optional
"raw": false // optional
}
```
3. **"read"** - Read console output
```json
{
"type": "read",
"node_name": "R1",
"mode": "diff", // optional: diff/last_page/num_pages/all
"pattern": "error", // optional grep pattern
"case_insensitive": true // optional
}
```
4. **"keystroke"** - Send special keystroke
```json
{
"type": "keystroke",
"node_name": "R1",
"key": "enter" // up/down/enter/ctrl_c/etc
}
```
**Use Case 1: Multiple Commands on One Node**
```json
console_batch([
{"type": "send_and_wait", "node_name": "R1", "command": "show version\n", "wait_pattern": "Router#"},
{"type": "send_and_wait", "node_name": "R1", "command": "show ip route\n", "wait_pattern": "Router#"},
{"type": "send_and_wait", "node_name": "R1", "command": "show running-config\n", "wait_pattern": "Router#"}
])
```
**Use Case 2: Same Command on Multiple Nodes** (Parallel Analysis)
```json
console_batch([
{"type": "send_and_wait", "node_name": "R1", "command": "show ip int brief\n", "wait_pattern": "#"},
{"type": "send_and_wait", "node_name": "R2", "command": "show ip int brief\n", "wait_pattern": "#"},
{"type": "send_and_wait", "node_name": "R3", "command": "show ip int brief\n", "wait_pattern": "#"}
])
```
**Use Case 3: Mixed Operations** (Interactive Workflow)
```json
console_batch([
{"type": "send", "node_name": "R1", "data": "\n"}, // Wake console
{"type": "read", "node_name": "R1", "mode": "last_page"}, // Check prompt
{"type": "send_and_wait", "node_name": "R1", "command": "show version\n", "wait_pattern": "#"},
{"type": "keystroke", "node_name": "R1", "key": "ctrl_c"} // Cancel if needed
])
```
**Return Format:**
```json
{
"completed": [0, 1, 2], // Indices of successful operations
"failed": [3], // Indices of failed operations
"results": [
{
"operation_index": 0,
"success": true,
"operation_type": "send_and_wait",
"node_name": "R1",
"result": {
"output": "...",
"pattern_found": true,
"timeout_occurred": false,
"wait_time": 1.2
}
},
{
"operation_index": 3,
"success": false,
"operation_type": "send_and_wait",
"node_name": "R4",
"error": {
"error": "Node not found: R4",
"error_code": "NODE_NOT_FOUND",
"suggested_action": "..."
}
}
],
"total_operations": 4,
"execution_time": 5.3
}
```
**When to Use:**
- ✅ Running same diagnostic command on multiple routers
- ✅ Executing multi-step workflows on one device
- ✅ Gathering data from multiple nodes for comparison/analysis
- ✅ Interactive sequences with validation checks between steps
- ❌ Single operations - use individual tools for simplicity
- ❌ SSH-capable devices - consider SSH batch operations for better reliability
**Advantages:**
- **Validation**: All operations validated before execution (prevents partial failures)
- **Structured Results**: Clear success/failure status per operation
- **Timing**: Execution time tracking for performance analysis
- **Flexibility**: Mix different operation types in one batch
- **Error Isolation**: Failed operations don't stop the batch, all results returned
### Coordinate System and Topology Layout
GNS3 uses a specific coordinate system for positioning elements:
**Node Positioning:**
- Node coordinates (x, y) represent the **top-left corner** of the node icon
- Icon sizes:
- **PNG images**: 78×78 pixels (custom device icons)
- **SVG/internal icons**: 58×58 pixels (built-in icons)
- Node center is at `(x + icon_size/2, y + icon_size/2)`
- Example: Node at (100, 100) with PNG icon has center at (139, 139)
**Label Positioning:**
- Node labels are stored as **offsets from node top-left to label box top-left**
- GNS3 API returns: `label: {x: -10, y: -25, text: "Router1", rotation: 0, style: "..."}`
- The offset (x, y) represents: node_top_left → label_box_top_left
- Label box contains text that is **right-aligned and vertically centered** within the box
- Text alignment: `text-anchor: end; dominant-baseline: central`
**Link Connections:**
- Links connect to the **center** of nodes, not the top-left corner
- Connection point: `(node_x + icon_size/2, node_y + icon_size/2)`
- When using `set_connection()`, specify which adapter and port on each node
**Drawing Objects (v0.8.0 - Unified create_drawing):**
- Create drawings with `create_drawing(drawing_type, x, y, ...)` where type is "rectangle", "ellipse", "line", or "text"
- All drawing coordinates (x, y) represent the **top-left corner** of bounding box
- **Rectangle**: `create_drawing("rectangle", x, y, width=W, height=H, fill_color="#fff", border_color="#000")`
- **Ellipse**: `create_drawing("ellipse", x, y, rx=50, ry=30, fill_color="#fff", border_color="#000")`
- **Line**: `create_drawing("line", x, y, x2=100, y2=50, border_color="#000", border_width=2)` - ends at (x+x2, y+y2)
- **Text**: `create_drawing("text", x, y, text="Label", font_size=10, color="#000", font_weight="normal")`
- Z-order: 0 = behind nodes (backgrounds), 1 = in front of nodes (labels)
**Topology Export:**
- Use `export_topology_diagram()` to create SVG/PNG screenshots
- Renders nodes with actual icons, links, drawings, and labels
- All positioning respects the coordinate system above
- Output includes:
- Visual status indicators on nodes (started=green, stopped=red)
- Port status indicators on links (active=green circles, shutdown=red circles)
- Preserved fonts and styling from GNS3
**Layout Best Practices:**
- **Minimum spacing** to avoid overlaps:
- Horizontal: 150-200px between node icons
- Vertical: 100-150px between node icons
- Site rectangles: 250-350px wide, 200-300px tall
- Padding around elements: 50px minimum
- **Site organization**:
- Place background rectangles at z=0 (behind nodes)
- Place site labels at z=1 (in front of rectangles)
- Position site labels 30px above rectangle top edge
- Center nodes within site rectangles for clean layout
- **Node positioning**:
- PNG icons (78×78): Need more spacing than SVG icons (58×58)
- Account for label width when positioning adjacent nodes
- Estimated label width: `text_length * font_size * 0.6`
- **Connection planning**:
- Consider link paths when positioning nodes
- Avoid crossing links where possible for clarity
- Star topologies: Central node with radial connections
- Mesh topologies: Triangular or grid layouts work best
## Common Workflows
### Starting a Lab Environment
```
1. List projects to find your lab
2. Open the target project
3. List nodes to see topology
4. Start nodes in order (usually: core switches → routers → endpoints)
5. Wait ~30-60s for devices to boot
6. Verify status with list_nodes
```
### Configuring a Router via Console
```
1. Ensure node is started (use set_node if needed)
2. Send initial newline to wake console: send_console("Router1", "\n")
3. Read output to see prompt: read_console("Router1")
4. Send configuration commands one at a time
5. Always read output after each command to verify
6. Default behavior (v0.8.0): returns only new output since last read
7. Disconnect when done: disconnect_console("Router1")
```
**Example:**
```
send_console("R1", "\n")
read_console("R1") # See prompt (diff mode default since v0.9.0)
send_console("R1", "show ip interface brief\n")
read_console("R1") # See command output (only new lines)
disconnect_console("R1") # Clean up when done
```
### Using send_and_wait_console for Automation
For automated workflows, `send_and_wait_console()` simplifies command execution by waiting for specific prompts:
```
Workflow:
1. First, identify the prompt pattern
- Send \n and read output to see what prompt looks like
- Note the exact prompt: "Router#", "[admin@MikroTik] >", "switch>", etc.
2. Use the prompt pattern in automated commands
- send_and_wait_console(node, command, wait_pattern=<prompt>)
- Tool waits until prompt appears, then returns all output
3. No need to manually wait or read - tool handles timing
```
**Example - Automated configuration:**
```
# Step 1: Identify the prompt
send_console("R1", "\n")
output = read_console("R1") # Output shows "Router#"
# Step 2: Use prompt pattern for automation
result = send_and_wait_console("R1",
"show ip interface brief\n",
wait_pattern="Router#",
timeout=10)
# Returns when "Router#" appears - command is complete
# Step 3: Continue with more commands
result = send_and_wait_console("R1",
"configure terminal\n",
wait_pattern="Router\\(config\\)#", # Prompt changes in config mode
timeout=10)
```
**When to use send_and_wait_console:**
- Automated scripts where you know the expected prompts
- Long-running commands that need completion confirmation
- Interactive menus where you need to wait for specific text
**When to use send_console + read_console:**
- Interactive troubleshooting where prompts may vary
- Exploring unknown device states
- When you need fine-grained control over timing
### Console Best Practices
- **Always** read console output after sending commands
- **Wait** 1-2 seconds between commands for device processing
- **Send** `\n` (newline) first to wake up console
- **Look for** prompts (>, #) in output to confirm device is ready
- **Default behavior** (v0.9.0): `read_console()` returns only new output since last read (diff mode)
- **Last page mode**: Use `read_console(node, mode="last_page")` for last ~25 lines
- **Full buffer**: Use `read_console(node, mode="all")` for entire console history
- **Before using send_and_wait_console()**: First check what the prompt looks like with `read_console()`
- Different devices have different prompts: `Router#`, `[admin@MikroTik] >`, `switch>`, etc.
- Use the exact prompt pattern in `wait_pattern` parameter to ensure command completion
- Example: Send `\n`, read output to see `Router#`, then use `wait_pattern="Router#"` for commands
- This prevents missing output or waiting for wrong prompt
- **No need** to manually connect - auto-connects on first send/read
- **Disconnect** when done to free resources (30min timeout otherwise)
- For RouterOS (MikroTik): default user `admin`, empty password
- For Arista vEOS: default user `admin`, no password
### Troubleshooting Connectivity
```
1. Check node status (all started?)
2. Verify console access (can you connect?)
3. Check interfaces: send "show ip interface brief" or equivalent
4. Check routing: send "show ip route"
5. Test ping: send "ping <target_ip>"
6. Read output after each command
```
### Topology Visualization (v0.33.0)
**Viewing Diagrams:**
Use the diagram resource to quickly visualize lab topology:
```
# Get topology as SVG
diagram = read_resource("diagrams://{project_id}/topology")
```
**Exporting Diagrams:**
Use `export_topology_diagram()` tool to save diagrams as files:
```
# Export as both SVG and PNG
export_topology_diagram(
output_path="/path/to/topology",
format="both" # or "svg", "png"
)
# Export with crop region
export_topology_diagram(
output_path="/path/to/cropped",
format="png",
crop_x=100, crop_y=100,
crop_width=800, crop_height=600
)
```
**Diagram Features:**
- Node positions, status indicators (color-coded by status)
- Network links with connection information
- Drawing objects (labels, shapes, annotations)
- Automatic layout based on node coordinates
- SVG format: scalable, text-based, ideal for AI analysis
- PNG format: rasterized for sharing/presentation
**Use Cases:**
- Document lab topology
- Visual topology review before making changes
- Share lab configuration with team
- Analyze network layout and connectivity patterns
## MCP Prompts - Guided Workflows (v0.17.0)
**MCP prompts** provide step-by-step guidance for complex multi-step operations.
### Available Prompts
**ssh_setup** - Device-Specific SSH Configuration
- Covers 6 device types: Cisco IOS, NX-OS, MikroTik, Juniper, Arista, Linux
- Step-by-step instructions from console configuration to SSH session establishment
- Device-specific commands with parameter placeholders
- Troubleshooting guidance for common SSH issues
Usage:
```
Call the ssh_setup prompt with device_type parameter
Example: ssh_setup(device_type="cisco_ios", node_name="R1")
```
**topology_discovery** - Network Topology Discovery and Visualization
- Guides through using MCP resources to browse projects/nodes/links
- Instructions for `export_topology_diagram` tool usage
- Topology pattern analysis (hub-and-spoke, mesh, tiered, etc.)
- Common topology questions to answer during discovery
Usage:
```
Call the topology_discovery prompt to start guided discovery
The prompt walks through resource browsing and diagram export
```
**troubleshooting** - OSI Model-Based Systematic Troubleshooting
- Layer 1-7 troubleshooting methodology
- Common issues and resolutions for each layer
- Console and SSH troubleshooting workflows
- Performance analysis and log collection
Usage:
```
Call the troubleshooting prompt for systematic diagnosis
Example: troubleshooting(node_name="R1", issue="connectivity")
```
**lab_setup** - Automated Topology Creation (v0.18.0)
- Creates complete topologies with single command
- 6 topology types: star, mesh, linear, ring, OSPF, BGP
- Automatic node positioning using layout algorithms
- IP addressing schemes
Topology types:
- **star**: Hub-and-spoke (parameter: spoke_count)
- **mesh**: Full mesh (parameter: router_count)
- **linear**: Chain topology (parameter: router_count)
- **ring**: Circular topology (parameter: router_count)
- **ospf**: Multi-area OSPF (parameter: area_count, 3 routers per area)
- **bgp**: Multiple AS (parameter: AS_count, 2 routers per AS)
Usage:
```
Call the lab_setup prompt with topology_type and device_count
Example: lab_setup(topology_type="ospf", device_count=3)
```
**node_setup** - Complete Node Setup Workflow (v0.23.0)
- End-to-end workflow for adding new node to lab
- Covers: create, boot, configure IP, document, establish SSH
- Device-specific configuration commands (Cisco IOS, Linux, MikroTik)
- Automatic project README documentation updates
- SSH session verification
Workflow steps:
1. Create node from template at specified coordinates
2. Start node and wait for boot completion (device-specific timing)
3. Configure IP address via console (device-specific commands)
4. Document IP/credentials in project README
5. Establish and verify SSH session for automation
Usage:
```
Call the node_setup prompt to get guided workflow
Example: node_setup(template_name="Cisco IOSv", node_name="R1",
x=100, y=100, ip_address="10.1.1.1/24")
```
## SSH Automation (v0.12.0)
SSH automation via Netmiko for advanced device management. Requires SSH proxy container deployed to GNS3 host.
### Prerequisites
SSH must be enabled on device first using console tools:
**Cisco IOS:**
```
send_console('R1', 'configure terminal\n')
send_console('R1', 'username admin privilege 15 secret cisco123\n')
send_console('R1', 'crypto key generate rsa modulus 2048\n')
send_console('R1', 'ip ssh version 2\n')
send_console('R1', 'line vty 0 4\n')
send_console('R1', 'login local\n')
send_console('R1', 'transport input ssh\n')
send_console('R1', 'end\n')
```
**MikroTik RouterOS:**
```
send_console('MT1', '/user add name=admin password=admin123 group=full\n')
send_console('MT1', '/ip service enable ssh\n')
```
### Basic SSH Workflow
**1. Configure SSH Session:**
```
configure_ssh('R1', {
'device_type': 'cisco_ios',
'host': '10.10.10.1',
'username': 'admin',
'password': 'cisco123'
})
```
**2. Execute Commands:**
```
# Show commands
ssh_send_command('R1', 'show ip interface brief')
ssh_send_command('R1', 'show running-config')
# Configuration commands
ssh_send_config_set('R1', [
'interface GigabitEthernet0/0',
'ip address 192.168.1.1 255.255.255.0',
'no shutdown'
])
```
**3. Review History:**
```
# List recent commands
ssh_get_history('R1', limit=10)
# Search history
ssh_get_history('R1', search='interface')
# Get specific command output
ssh_get_command_output('R1', job_id='...')
```
### Session Management (v0.1.6)
SSH sessions are automatically managed with the following features:
**30-Minute Session TTL:**
- Sessions automatically expire after 30 minutes of inactivity
- Activity timestamp updated on every operation:
- SSH command execution (`ssh_send_command`, `ssh_send_config_set`)
- Buffer reads (via resources)
- Session configuration (reuse of existing session)
- Expired sessions are automatically detected and recreated
- No manual intervention required
**Session Health Checks:**
- Before reusing existing sessions, health checks verify connection is still alive
- Health check methods:
1. Netmiko `is_alive()` if available (Netmiko 4.0+)
2. Lightweight empty command test (fallback)
- Stale/closed connections automatically recreated
- Ensures reliable session reuse
**Auto-Recovery from Stale Sessions (THE KEY FEATURE):**
When commands fail with "Socket is closed":
1. Stale session **automatically removed** from session manager
2. Error response includes `error_code="SSH_DISCONNECTED"` and `suggested_action`
3. **Just retry configure_ssh() with same parameters - no force needed!**
4. Fresh session will be created automatically
5. Retry your ssh_command() - it will work
**Recovery Workflow:**
```
# 1. Command fails with "Socket is closed"
result = ssh_send_command('R1', 'show version')
# Returns: error_code="SSH_DISCONNECTED",
# suggested_action="Session was stale and has been removed. Reconnect..."
# 2. Simply retry configure_ssh() - NO force parameter needed
# Stale session already cleaned up, new session will be created
configure_ssh('R1', device_dict)
# 3. Retry command - works now
result = ssh_send_command('R1', 'show version') # ✅ Works
```
**Force Recreation Parameter (rarely needed):**
- Use `force=True` ONLY for: credential changes, manual troubleshooting
- NOT needed for stale session recovery (auto-cleanup handles it)
- Example:
```
# Force recreation to change credentials (uncommon use case)
configure_ssh('R1', device_dict, force=True)
```
**Error Codes (v0.1.6):**
- `SSH_DISCONNECTED` - Session closed (stale connection) → Just retry configure_ssh()
- `TIMEOUT` - Command timed out → Increase read_timeout parameter
- `COMMAND_FAILED` - Generic command failure → Check command syntax
### Adaptive Async for Long Commands
For long-running operations (firmware upgrades, backups):
```
# Start command, return job_id immediately
result = ssh_send_command('R1', 'copy running-config tftp:', wait_timeout=0)
job_id = result['job_id']
# Poll for completion
status = ssh_get_job_status(job_id)
# Returns: {completed, output, execution_time}
# For 15+ minute commands:
ssh_send_command('R1', 'upgrade firmware', read_timeout=900, wait_timeout=0)
```
### Supported Device Types
200+ device types via Netmiko:
- **cisco_ios** - Cisco IOS/IOS-XE
- **cisco_nxos** - Cisco Nexus
- **juniper** - Juniper JunOS
- **arista_eos** - Arista EOS
- **mikrotik_routeros** - MikroTik RouterOS
- **linux** - Linux/Alpine
- See Netmiko documentation for complete list
### SSH Best Practices
- **Enable SSH first** using console tools
- **Use job history** for audit trails and debugging
- **Set wait_timeout=0** for long commands to avoid blocking
- **Poll with ssh_get_job_status()** for async operations
- **Review ssh_get_history()** to verify command execution
- **Clean sessions** with ssh_cleanup_sessions() when changing lab topology
- **Check status** with ssh_get_status() to verify connection before commands
## Device-Specific Commands
### MikroTik RouterOS
- Login prompt: `Login:` → send `admin\n`
- Password: just press enter (empty)
- Prompt: `[admin@MikroTik] >`
- Show interfaces: `/interface print`
- Show IP addresses: `/ip address print`
- Show routes: `/ip route print`
### Arista vEOS
- Login: `admin` (no password)
- Prompt: `switch>`
- Enable mode: `enable` → `switch#`
- Show interfaces: `show interfaces status`
- Show IP: `show ip interface brief`
- Config mode: `configure terminal`
### Cisco IOS (CSR1000v, IOSv)
- Prompt: `Router>` (user mode), `Router#` (privileged)
- Enable: `enable`
- Show interfaces: `show ip interface brief`
- Show routes: `show ip route`
- Config: `configure terminal`
## Error Handling
### Node Won't Start
- Check node details for errors
- Verify compute resources available
- Some nodes (Windows) take 5+ minutes to boot
### Console Not Responding
- Check node is actually started
- Try sending `\n` or `\r\n` to wake console
- Some consoles have startup delay (30-60s after node start)
### Session Timeout
- Console sessions expire after 30 minutes of inactivity
- Always disconnect when done to free resources
- Sessions managed by node_name (no manual tracking needed)
## Multi-Node Operations
When working with multiple nodes:
1. Start nodes using `set_node(node_name, action='start')` or batch operations
2. Console sessions identified by node_name (no manual tracking needed)
3. Configure one device at a time, verify before moving on
4. Read output to get only new lines (diff mode default since v0.8.0) - avoids confusion between devices
5. Disconnect sessions when done: `disconnect_console(node_name)`
**Example - Configure multiple routers:**
```
# Start all routers
set_node("R1", action="start")
set_node("R2", action="start")
# Configure R1
send_console("R1", "\n")
read_console("R1") # Diff mode default - only new output
send_console("R1", "configure terminal\n")
read_console("R1") # Only new output since last read
# ... more commands ...
disconnect_console("R1")
# Configure R2 (same pattern)
send_console("R2", "\n")
# ... configure R2 ...
disconnect_console("R2")
```
## Managing Network Connections
### Link Management with set_connection
Use `set_connection(connections)` for batch link operations. Operations execute sequentially (top-to-bottom) with predictable state on failure.
**Connection Format:**
```python
connections = [
# Disconnect a link
{"action": "disconnect", "link_id": "abc123"},
# Connect two nodes (using adapter names - recommended)
{"action": "connect",
"node_a": "R1", "adapter_a": "eth0", "port_a": 0,
"node_b": "R2", "adapter_b": "GigabitEthernet0/0", "port_b": 1},
# Or using adapter numbers (legacy)
{"action": "connect",
"node_a": "R1", "adapter_a": 0, "port_a": 0,
"node_b": "R2", "adapter_b": 0, "port_b": 1}
]
```
**Adapter Names vs Numbers:**
- **Adapter names** (recommended): Use port names like "eth0", "GigabitEthernet0/0", "Ethernet0"
- **Adapter numbers** (legacy): Use numeric adapter index (0, 1, 2, ...)
- Response always shows **both**: `"adapter_a": 0, "port_a_name": "eth0"`
**Returns:**
```json
{
"completed": [
{"index": 0, "action": "disconnect", "link_id": "abc123"},
{"index": 1, "action": "connect", "link_id": "new-id",
"node_a": "R1", "node_b": "R2",
"adapter_a": 0, "port_a": 0, "port_a_name": "eth0",
"adapter_b": 0, "port_b": 1, "port_b_name": "GigabitEthernet0/0"}
],
"failed": null
}
```
**Best Practices:**
- **Always** call `get_links()` first to check current topology and see port names
- Use **adapter names** for readability (e.g., "eth0" instead of 0)
- Get link IDs from output (in brackets) for disconnection
- Disconnect existing links before connecting to occupied ports
- Operations stop at first failure for predictable state
**Example - Rewire topology:**
```python
# 1. Check current topology
get_links()
# Output shows port names: eth0, GigabitEthernet0/0, etc.
# 2. Disconnect old link and create new one (using port names)
set_connection([
{"action": "disconnect", "link_id": "abc-123"},
{"action": "connect",
"node_a": "R1", "adapter_a": "eth0", "port_a": 0,
"node_b": "Switch1", "adapter_b": "Ethernet3", "port_b": 3}
])
```
## Node Positioning & Configuration
### Unified Node Control with set_node
Use `set_node(node_name, ...)` for both control and configuration:
**Control Actions:**
- `action="start"` - Start the node
- `action="stop"` - Stop the node
- `action="suspend"` - Suspend node (VM only)
- `action="reload"` - Reload node
- `action="restart"` - Stop, wait (3 retries × 5s), then start
**Configuration Properties:**
- `x`, `y` - Position on canvas
- `z` - Z-order (layer) for overlapping nodes
- `locked` - Lock position (True/False)
- `ports` - Number of ports (ethernet switches only)
**Examples:**
```python
# Start a node
set_node("R1", action="start")
# Restart with retry logic
set_node("R1", action="restart") # Waits for clean stop
# Move and lock position
set_node("R1", x=100, y=200, locked=True)
# Configure switch ports
set_node("Switch1", ports=16)
# Combined operation
set_node("R1", action="start", x=150, y=300)
```
**Restart Behavior:**
- Stops node and polls status (3 attempts × 5 seconds)
- Waits for confirmed stop before starting
- Returns all retry attempts in result
- Use for nodes that need clean restart
## Snapshot Management (v0.18.0)
Snapshots capture complete project state for version control and rollback.
### Creating Snapshots
Before major changes, create a snapshot for safe rollback:
**Workflow:**
1. Stop all running nodes (optional but recommended for consistency)
2. Create snapshot with descriptive name
3. Make your changes
4. If issues occur, restore to snapshot
**Example:**
```
create_snapshot("Before OSPF Configuration",
"Working baseline before adding OSPF")
```
**Best Practices:**
- Use descriptive names with dates: "2025-10-26 Working OSPF Config"
- Stop nodes before snapshot for consistent state
- Document what each snapshot represents
- Create snapshots at major milestones
### Restoring Snapshots
Rollback to previous state (⚠️ **DESTRUCTIVE** - all changes since snapshot are lost):
**Restore Process:**
1. Call `restore_snapshot("snapshot_name")`
2. Tool automatically:
- Stops all running nodes
- Disconnects all console sessions
- Restores project to snapshot state
3. All changes since snapshot are permanently lost
**Example:**
```
restore_snapshot("Before OSPF Configuration")
```
**Warning:** Destructive operation - creates backup before testing restore procedure.
### Browsing Snapshots
List available snapshots via resource:
```
projects://{project_id}/snapshots/
```
View snapshot details:
```
projects://{project_id}/snapshots/{snapshot_id}
```
## Project Notes/Memory (v0.23.0)
**Store project-specific context** to avoid consuming conversation context. Agent can maintain persistent notes about IPs, credentials, and architecture.
### Features
- **Per-Project Storage**: Each lab has separate README.txt file
- **Zero Context Cost**: Notes loaded only on explicit tool call
- **Markdown Format**: Human-readable, supports formatting
- **Native GNS3 Storage**: Uses built-in README.txt via API
- **Persistent**: Saved with project, portable
### Tools
**get_project_readme(project_id?)**
- Retrieve project documentation
- Returns markdown content
- Uses current project if ID not specified
**update_project_readme(content, project_id?)**
- Save project documentation
- Markdown format
- Creates README.txt if doesn't exist
### MCP Resource
```
projects://{project_id}/readme
```
Browsable resource for read-only access to project notes.
### Common Use Cases
**IP Addressing Documentation:**
```markdown
# Network Lab
## IP Addressing
- Router1: 10.1.0.1/24 (GigabitEthernet0/0)
- Router2: 10.1.0.2/24 (GigabitEthernet0/0)
- Management VLAN: 192.168.100.0/24
## VLANs
- VLAN 10: Users (10.10.0.0/24)
- VLAN 20: Servers (10.20.0.0/24)
- VLAN 100: Management (192.168.100.0/24)
```
**Credentials & Access:**
```markdown
## Device Credentials
- Router1: admin / vault:router1-pass
- Router2: admin / vault:router2-pass
- Switches: admin / vault:switch-default
## SSH Access
- Router1: ssh://10.1.0.1:22
- Router2: ssh://10.1.0.2:22
```
**Architecture Notes:**
```markdown
## Lab Architecture
### Topology
Router1 ← → Router2 (OSPF backbone)
| |
Switch1 Switch2
| |
Clients Servers
### Protocols
- OSPF Area 0: Backbone between routers
- HSRP: VIP 10.1.0.254 (priority R1=110, R2=100)
- STP: Root bridge is Switch1
```
**Configuration Snippets:**
```markdown
## Standard Configs
### OSPF Template
```
router ospf 1
network 10.0.0.0 0.255.255.255 area 0
passive-interface default
no passive-interface GigabitEthernet0/0
```
### HSRP Template
```
interface GigabitEthernet0/1
standby 1 ip 10.1.0.254
standby 1 priority 110
standby 1 preempt
```
```
**Troubleshooting Notes:**
```markdown
## Known Issues
### Router1 High CPU
- **Symptom**: CPU >80% after OSPF config
- **Cause**: Debug logging enabled
- **Fix**: `no debug all`
### Switch1 Port Flapping
- **Symptom**: Port Gi0/1 up/down
- **Cause**: Bad cable in lab
- **Fix**: Use port Gi0/2 instead
```
### Workflow Example
```python
# Agent discovers lab setup
# Get current notes
notes = get_project_readme()
# Agent configures new router, updates notes
update_project_readme("""
# Lab Update 2025-10-26
## New Router Added
- Router3: 10.1.0.3/24
- SSH: admin / vault:router3-pass
- Role: Border router for internet access
## OSPF Updated
- Added Router3 to Area 0
- Redistributing default route from Router3
## Next Steps
- Configure NAT on Router3
- Test internet connectivity from clients
""")
```
## Template Usage Notes (v0.23.0)
**Templates have built-in usage notes** with default credentials, setup instructions, and important information about persistent storage.
### What Template Usage Contains
- **Default Credentials** - Username/password for pre-configured images
- Example: "Username: ubuntu, Password: ubuntu"
- Example: "The login is admin, with no password by default"
- **Setup Instructions** - First-boot procedures and installation details
- Boot timing estimates (e.g., "On first boot, RouterOS is actually being installed...")
- Console availability notes
- **Persistent Storage Info** - Which directories persist across reboots
- Example: "The /root directory is persistent."
- **Configuration Guidance** - Device-specific quirks and recommendations
### Accessing Template Usage (Read-Only)
**For a specific template:**
```
Resource: gns3://templates/{template_id}
Returns: Full template details including usage field
```
**For a specific node (most common):**
```
Resource: projects://{project_id}/nodes/{node_id}/template
Returns: Template usage notes for that node
```
**Lazy Loading Pattern:**
- Template list (`projects://{id}/templates/`) excludes usage to keep lightweight
- Usage loaded separately only when needed to avoid context bloat
- Each node has `template_id` linking to its template
### Usage Examples
**Check default credentials before connecting:**
```
1. Get node details: projects://{id}/nodes/{node_id}
2. Note template_id from node
3. Check template usage: gns3://templates/{template_id}
4. See "Username: admin" in usage field
5. Use those credentials with ssh_configure()
```
**Find persistent storage directories:**
```
1. Browse node's template: projects://{id}/nodes/{node_id}/template
2. Look for "persistent" in usage field
3. Note which directories survive reboots
4. Store important data in those locations
```
**Best Practice:** Always check template usage before initial configuration to find default credentials and understand device-specific setup requirements.
## Lab Setup Automation (v0.18.0)
Use `lab_setup` prompt to create complete topologies automatically.
### Creating a Lab
The lab_setup prompt creates:
- Nodes positioned using layout algorithms
- Network links between nodes
- IP addressing schemes
- Complete topology diagrams
### Topology Types
**Star Topology** (Hub-and-Spoke):
```
lab_setup(topology_type="star", device_count=4)
```
- Creates: 1 hub router + 4 spoke routers
- Links: Hub-to-each-spoke
- IP: 10.0.{spoke}.0/24 per link
**Mesh Topology** (Full Mesh):
```
lab_setup(topology_type="mesh", device_count=4)
```
- Creates: 4 routers, all interconnected
- Links: N*(N-1)/2 point-to-point links
- IP: 10.0.{subnet}.0/30 per link
**Linear Topology** (Chain):
```
lab_setup(topology_type="linear", device_count=4)
```
- Creates: 4 routers in series (R1-R2-R3-R4)
- Links: Sequential connections
- IP: 10.0.{link}.0/30
**Ring Topology** (Circular):
```
lab_setup(topology_type="ring", device_count=4)
```
- Creates: 4 routers in a ring
- Links: Each router connects to two neighbors
- Closes the loop for redundancy
**OSPF Topology** (Multi-Area):
```
lab_setup(topology_type="ospf", device_count=3)
```
- Creates: 3 areas with Area 0 backbone
- Nodes: 3 routers per area + ABRs
- IP: 10.{area}.0.{router}/32 loopbacks
**BGP Topology** (Multiple AS):
```
lab_setup(topology_type="bgp", device_count=3)
```
- Creates: 3 autonomous systems
- Nodes: 2 routers per AS (iBGP peering)
- Links: eBGP between adjacent AS
- IP: 10.{AS}.1.0/30 (iBGP), 172.16.{link}.0/30 (eBGP)
### Customizing Labs
**Parameters:**
- `topology_type`: Required topology type (star/mesh/linear/ring/ospf/bgp)
- `device_count`: Number of devices/areas/AS (topology-specific)
- `template_name`: Device template (default: "Alpine Linux")
- `project_name`: Target project (uses current if not specified)
**Example:**
```
lab_setup("ospf", device_count=2,
template_name="Cisco IOSv",
project_name="OSPF Lab")
```
## Drawing Tools (v0.19.0 - Hybrid Architecture)
Create visual annotations on topology diagrams using drawing tools.
**Hybrid Pattern:**
- **READ**: Browse drawings via resource `projects://{id}/drawings/`
- **WRITE**: Modify drawings via tools (create_drawing, update_drawing, delete_drawing)
### Available Drawing Types
**Rectangle** - For site boundaries, network segments
```
create_drawing("rectangle", x=100, y=100, width=300, height=200,
fill_color="#f0f0f0", border_color="#000000", z=0)
```
**Ellipse** - For cloud/WAN representations, circles
```
create_drawing("ellipse", x=200, y=200, rx=50, ry=50,
fill_color="#ffffff", border_color="#0000ff", z=0)
```
**Line** - For connections, arrows, dividers
```
create_drawing("line", x=100, y=100, x2=200, y2=150,
color="#ff0000", border_width=3, z=1)
```
**Text** - For labels, site names, annotations
```
create_drawing("text", x=150, y=50, text="Data Center A",
font_size=14, font_weight="bold", color="#000000", z=1)
```
### Updating Drawings
Modify drawing properties:
```
update_drawing(drawing_id="abc123", x=120, y=80, rotation=45)
```
### Deleting Drawings
Remove drawing (⚠️ **DESTRUCTIVE**):
```
delete_drawing(drawing_id="abc123")
```
### Z-order Layers
- `z=0`: Background shapes (behind nodes)
- `z=1`: Foreground labels and annotations
- Higher z values appear in front
## Automation Tips
- **Always check status** before operations (is node started? is project open?)
- **Read before write** to console (check current state first)
- **Verify each step** before proceeding (don't assume success)
- **Handle errors gracefully** (node might not start immediately)
- **Clean up** console sessions when done
- **Use set_node** for node lifecycle operations (replaces start/stop)
- **Use set_connection** for topology changes (batch operations)
## Example Workflows
See `examples/` folder for:
- `ospf_lab.md` - Setting up OSPF routing between routers
- `bgp_lab.md` - Configuring BGP peering
- Common troubleshooting proceduresRelated Skills
performing-ioc-enrichment-automation
通过编排 VirusTotal、AbuseIPDB、Shodan、MISP 和其他情报源的查询, 自动化入侵指标(IOC)丰富化,提供上下文评分和处置建议。 适用于 SOC 分析师在告警分诊或事件调查期间需要对 IP、域名、URL 和文件哈希 进行快速多源丰富化时。
implementing-soar-automation-with-phantom
使用 Splunk SOAR(原 Phantom)实施安全编排、自动化和响应(SOAR)工作流, 自动化告警分诊、IOC 富化、遏制动作和事件响应剧本。 适用于 SOC 团队需要减少分析师手工工作、标准化响应流程, 或将多种安全工具集成到自动化工作流中时。
detecting-aws-guardduty-findings-automation
使用 EventBridge 和 Lambda 自动化处理 AWS GuardDuty 威胁检测发现,实现实时事件响应、自动隔离受损资源和安全通知工作流。
salesforce-cli-automation
Use this skill when automating Salesforce work with the unified Salesforce CLI (`sf`, v2): shell scripts, Make/npm tasks, cron jobs, and CI steps that need stable flags, `--json` output, org aliases, bulk/data commands, plugins, and non-interactive auth patterns. Trigger keywords: sf CLI automation, sfdx migration, JSON output CI, sf project deploy script, sf data bulk, CLI plugins, target-org alias, machine-readable CLI. NOT for choosing or wiring a specific CI platform (GitHub Actions, GitLab, Jenkins, Bitbucket, Azure DevOps—use those devops skills), VS Code Salesforce extensions, or Copado/Gearset release management UIs.
release-notes-automation
Use when generating customer- or stakeholder-facing release notes from git history, Jira/ADO ticket links, and Salesforce metadata diffs at deploy time. Triggers: 'auto-generate release notes', 'changelog from commits', 'release notes from PR titles', 'what changed in this deployment'. NOT for managed-package version creation, push upgrades, or org assessment.
cumulusci-automation
Use this skill when configuring CumulusCI (cci) for Salesforce project automation: authoring cumulusci.yml tasks and flows, customizing or composing standard flows, integrating Robot Framework acceptance tests, and running cci flows in CI pipelines with JWT-based authentication. Covers task class_path/options wiring, flow step ordering, org and source declarations, cross-project reuse via sources, and the standard flow library (dev_org, qa_org, ci_feature, install_beta). NOT for raw SFDX/sf CLI workflows without CumulusCI, scratch org pool management (use scratch-org-pools), unlocked or managed package versioning (use unlocked-package-development or second-generation-managed-packages), or Salesforce-native DevOps Center pipelines (use devops-center-pipeline).
deployment-automation-architecture
Deployment automation architecture on Salesforce: pipeline orchestration, branch strategy, environment topology, quality gates, release trains. Selecting between Copado, Gearset, Flosum, and native SFDX + GitHub Actions. NOT for cloud-specific deploy mechanics (use cloud-specific-deployment-architecture). NOT for CI/CD tool tutorials.
cpq-test-automation
Use when writing, reviewing, or debugging test classes for Salesforce CPQ (Steelbrick) functionality — including quote creation, price rules, contracting, ordering, and CPQ API integration. Trigger keywords: CPQ test class, SBQQ test, quote calculation test, price rule test, CPQ Apex test, ServiceRouter test, QuoteCalculator test. NOT for standard Apex testing patterns unrelated to CPQ, nor for UI/Selenium test authoring outside the CPQ context.
cpq-api-and-automation
Use when programmatically driving Salesforce CPQ operations from Apex or REST — creating quotes, adding products, calculating pricing, saving quotes, amending contracts, or renewing contracts through the SBQQ.ServiceRouter API. Trigger keywords: CPQ API, SBQQ.ServiceRouter, QuoteCalculator, QuoteReader, QuoteSaver, QuoteProductAdder, ProductLoader, ContractAmender, ContractRenewer, programmatic quote, calculate callback, CPQ REST API. NOT for standard REST API or Salesforce Connect. NOT for declarative CPQ configuration such as price rules, discount schedules, or product rules. NOT for CPQ plugin interfaces (QuoteCalculatorPlugin, OrderPlugin).
sandbox-post-refresh-automation
Automating the post-sandbox-refresh cleanup via the `SandboxPostCopy` interface — the Apex class that runs ONCE after a sandbox refresh / clone completes, before users can log in. Used to mask emails, deactivate users, scrub integration endpoints, disable scheduled jobs, repopulate sample data, and reapply any per-environment configuration that the metadata copy doesn't carry. Covers the interface contract (`runApexClass` setting, `SandboxContext` parameter, single-execution semantics), the email-masking pattern that prevents production emails firing from sandbox tests, and the runbook checklist of what every refresh should reset. NOT for the sandbox refresh-strategy decision (use devops/sandbox-strategy-designer), NOT for general bulk Apex (use apex/scheduled-apex).
process-automation-selection
Use when deciding which Salesforce automation tool should own a requirement, including before-save and after-save Flow, screen Flow, scheduled Flow, invocable Apex, Apex triggers, and migration off Workflow Rules or Process Builder. Triggers: 'Flow or Apex trigger', 'which automation tool should I use', 'Process Builder migration', 'Workflow Rule retirement', 'same-record update or trigger'. NOT for detailed implementation of a Flow or trigger after the automation boundary has already been chosen.
marketing-automation-requirements
Use this skill when gathering, documenting, or validating requirements for a Salesforce marketing automation program — covering MCAE (Account Engagement / Pardot) lifecycle stages, MQL/SQL threshold definitions, scoring model specifications (sources, weights, decay, ceiling), handoff notification design, CRM field updates on status change, and sales SLA. Trigger keywords: MQL criteria, marketing-to-sales handoff, lead lifecycle, scoring requirements, automation program requirements, Marketing Cloud Automation Studio scope. NOT for implementation of MCAE automation rules, MCAE scoring configuration, MC Automation Studio SQL activity authoring, or Einstein Lead Scoring setup — those are covered by dedicated implementation skills.