[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M7315XG4BJHM3H7YR8AVCSCT":3,"skill-same:01M7315XG4BJHM3H7YR8AVCSCT":48},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":19,"linkOnly":20,"markdownContent":21,"markdownBody":22,"frontMatter":23,"refName":25,"commitSha":26,"skillDirectory":27,"forksCount":28,"repositoryHtmlUrl":29,"repositoryHomepageUrl":6,"ownerHtmlUrl":30,"ownerBlogUrl":31,"ownerDescription":32,"updatedAt":33,"install":34,"resources":47},"01M7315XG4BJHM3H7YR8AVCSCT","netmiko-ssh-automation",null,"Safe Python Netmiko patterns for read-only collection, bounded batch SSH, TextFSM parsing, guarded config changes, timeouts, and network automation error handling.","SriramGandhiS\u002FSkills","SriramGandhiS","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F211849986?v=4","01M72WQCW12BYX71C6WN584TTA","Sriram S","01M72WQCWTJ2RD0ET1X31AF1RC",1,"MIT","https:\u002F\u002Fgithub.com\u002FSriramGandhiS\u002FSkills\u002Fblob\u002Fmaster\u002Fskills\u002Fnetmiko-ssh-automation\u002FSKILL.md",[],[],"2026-11-11 15:11:14",false,"---\nname: netmiko-ssh-automation\ndescription: Safe Python Netmiko patterns for read-only collection, bounded batch SSH, TextFSM parsing, guarded config changes, timeouts, and network automation error handling.\norigin: community\n---\n\n# Netmiko SSH Automation\n\nUse this skill when writing or reviewing Python automation that connects to\nnetwork devices with Netmiko. Keep the default path read-only; config changes\nneed a separate change window, peer review, and rollback plan.\n\n## When to Use\n\n- Collecting `show` command output across routers, switches, or firewalls.\n- Building a small audit script for interface, routing, or config evidence.\n- Adding timeouts and exception handling to network SSH scripts.\n- Parsing command output with TextFSM when a template exists.\n- Reviewing automation before it touches production devices.\n\n## Safety Defaults\n\n- Start with read-only `send_command()` collection.\n- Keep inventory small and explicit; do not sweep whole address ranges.\n- Use environment variables, a vault, or `getpass`; never hardcode credentials.\n- Set connection and read timeouts.\n- Limit concurrency so older devices are not overloaded.\n- Require an explicit operator flag before `send_config_set()`.\n- Do not call `save_config()` until the change has been verified and approved.\n\n## Read-Only Connection Pattern\n\n```python\nimport os\nfrom getpass import getpass\nfrom netmiko import ConnectHandler\nfrom netmiko.exceptions import (\n    NetmikoAuthenticationException,\n    NetmikoTimeoutException,\n    ReadTimeout,\n)\n\ndevice = {\n    \"device_type\": \"cisco_ios\",\n    \"host\": \"192.0.2.10\",\n    \"username\": os.environ.get(\"NETMIKO_USERNAME\") or input(\"Username: \"),\n    \"password\": os.environ.get(\"NETMIKO_PASSWORD\") or getpass(\"Password: \"),\n    \"secret\": os.environ.get(\"NETMIKO_ENABLE_SECRET\"),\n    \"conn_timeout\": 10,\n    \"auth_timeout\": 20,\n    \"banner_timeout\": 15,\n    \"read_timeout_override\": 30,\n}\n\ntry:\n    with ConnectHandler(**device) as conn:\n        if device.get(\"secret\") and not conn.check_enable_mode():\n            conn.enable()\n        output = conn.send_command(\"show ip interface brief\", read_timeout=30)\n        print(output)\nexcept NetmikoAuthenticationException:\n    print(\"Authentication failed\")\nexcept NetmikoTimeoutException:\n    print(\"SSH connection timed out\")\nexcept ReadTimeout:\n    print(\"Command read timed out\")\n```\n\nUse placeholder addresses from documentation ranges in examples. Keep real\ninventory in an ignored local file or a secrets-managed system.\n\n## Batch Collection\n\n```python\nfrom concurrent.futures import ThreadPoolExecutor, as_completed\nfrom typing import Any\n\ndef collect_show(device: dict[str, Any], command: str) -> dict[str, Any]:\n    host = device[\"host\"]\n    try:\n        with ConnectHandler(**device) as conn:\n            output = conn.send_command(command, read_timeout=45)\n        return {\"host\": host, \"ok\": True, \"output\": output}\n    except (NetmikoAuthenticationException, NetmikoTimeoutException, ReadTimeout) as exc:\n        return {\"host\": host, \"ok\": False, \"error\": type(exc).__name__}\n\nresults = []\nwith ThreadPoolExecutor(max_workers=8) as pool:\n    futures = [pool.submit(collect_show, device, \"show version\") for device in devices]\n    for future in as_completed(futures):\n        results.append(future.result())\n```\n\nKeep `max_workers` low unless the device estate and AAA systems are known to\nhandle higher connection volume.\n\n## Structured Parsing\n\nNetmiko can ask TextFSM, TTP, or Genie to parse supported command output. Treat\nparser output as an optimization, not the only evidence path.\n\n```python\nwith ConnectHandler(**device) as conn:\n    parsed = conn.send_command(\n        \"show ip interface brief\",\n        use_textfsm=True,\n        raise_parsing_error=False,\n        read_timeout=30,\n    )\n\nif isinstance(parsed, str):\n    print(\"No parser template matched; store raw output for review\")\nelse:\n    for row in parsed:\n        print(row)\n```\n\nIf parsing drives a blocking decision, keep the raw command output alongside\nthe parsed result so an operator can inspect mismatches.\n\n## Guarded Config Pattern\n\n```python\nimport os\n\ncommands = [\n    \"interface GigabitEthernet0\u002F1\",\n    \"description CHANGE-1234 UPLINK-TO-CORE\",\n]\n\napply_changes = os.environ.get(\"APPLY_NETWORK_CHANGES\") == \"1\"\n\nif not apply_changes:\n    print(\"Dry run only. Candidate commands:\")\n    print(\"\\n\".join(commands))\nelse:\n    with ConnectHandler(**device) as conn:\n        conn.enable()\n        before = conn.send_command(\"show running-config interface GigabitEthernet0\u002F1\")\n        output = conn.send_config_set(commands)\n        after = conn.send_command(\"show running-config interface GigabitEthernet0\u002F1\")\n        print(before)\n        print(output)\n        print(after)\n        print(\"Verify behavior before saving startup config.\")\n```\n\nSaving the config is a separate approval step. In production, include a rollback\nsnippet and capture before\u002Fafter evidence in the change record.\n\n## Review Checklist\n\n- Does the script identify an explicit inventory source?\n- Are credentials absent from source, logs, and exception messages?\n- Are `conn_timeout`, `auth_timeout`, and command `read_timeout` set?\n- Are failures reported per device without stopping the whole batch?\n- Does the script avoid broad scans and unbounded concurrency?\n- Are config changes behind a dry-run or explicit operator flag?\n- Is `save_config()` separate from the initial push and tied to verification?\n\n## Anti-Patterns\n\n- Hardcoding passwords, enable secrets, or private keys in source.\n- Sending config commands as the default code path.\n- Running automation against a CIDR range instead of a reviewed inventory.\n- Logging full running configs to shared systems without sanitization.\n- Treating parser success as proof that the device state is correct.\n\n## See Also\n\n- Skill: `cisco-ios-patterns`\n- Skill: `network-config-validation`\n- Skill: `network-interface-health`\n","# Netmiko SSH Automation\n\nUse this skill when writing or reviewing Python automation that connects to\nnetwork devices with Netmiko. Keep the default path read-only; config changes\nneed a separate change window, peer review, and rollback plan.\n\n## When to Use\n\n- Collecting `show` command output across routers, switches, or firewalls.\n- Building a small audit script for interface, routing, or config evidence.\n- Adding timeouts and exception handling to network SSH scripts.\n- Parsing command output with TextFSM when a template exists.\n- Reviewing automation before it touches production devices.\n\n## Safety Defaults\n\n- Start with read-only `send_command()` collection.\n- Keep inventory small and explicit; do not sweep whole address ranges.\n- Use environment variables, a vault, or `getpass`; never hardcode credentials.\n- Set connection and read timeouts.\n- Limit concurrency so older devices are not overloaded.\n- Require an explicit operator flag before `send_config_set()`.\n- Do not call `save_config()` until the change has been verified and approved.\n\n## Read-Only Connection Pattern\n\n```python\nimport os\nfrom getpass import getpass\nfrom netmiko import ConnectHandler\nfrom netmiko.exceptions import (\n    NetmikoAuthenticationException,\n    NetmikoTimeoutException,\n    ReadTimeout,\n)\n\ndevice = {\n    \"device_type\": \"cisco_ios\",\n    \"host\": \"192.0.2.10\",\n    \"username\": os.environ.get(\"NETMIKO_USERNAME\") or input(\"Username: \"),\n    \"password\": os.environ.get(\"NETMIKO_PASSWORD\") or getpass(\"Password: \"),\n    \"secret\": os.environ.get(\"NETMIKO_ENABLE_SECRET\"),\n    \"conn_timeout\": 10,\n    \"auth_timeout\": 20,\n    \"banner_timeout\": 15,\n    \"read_timeout_override\": 30,\n}\n\ntry:\n    with ConnectHandler(**device) as conn:\n        if device.get(\"secret\") and not conn.check_enable_mode():\n            conn.enable()\n        output = conn.send_command(\"show ip interface brief\", read_timeout=30)\n        print(output)\nexcept NetmikoAuthenticationException:\n    print(\"Authentication failed\")\nexcept NetmikoTimeoutException:\n    print(\"SSH connection timed out\")\nexcept ReadTimeout:\n    print(\"Command read timed out\")\n```\n\nUse placeholder addresses from documentation ranges in examples. Keep real\ninventory in an ignored local file or a secrets-managed system.\n\n## Batch Collection\n\n```python\nfrom concurrent.futures import ThreadPoolExecutor, as_completed\nfrom typing import Any\n\ndef collect_show(device: dict[str, Any], command: str) -> dict[str, Any]:\n    host = device[\"host\"]\n    try:\n        with ConnectHandler(**device) as conn:\n            output = conn.send_command(command, read_timeout=45)\n        return {\"host\": host, \"ok\": True, \"output\": output}\n    except (NetmikoAuthenticationException, NetmikoTimeoutException, ReadTimeout) as exc:\n        return {\"host\": host, \"ok\": False, \"error\": type(exc).__name__}\n\nresults = []\nwith ThreadPoolExecutor(max_workers=8) as pool:\n    futures = [pool.submit(collect_show, device, \"show version\") for device in devices]\n    for future in as_completed(futures):\n        results.append(future.result())\n```\n\nKeep `max_workers` low unless the device estate and AAA systems are known to\nhandle higher connection volume.\n\n## Structured Parsing\n\nNetmiko can ask TextFSM, TTP, or Genie to parse supported command output. Treat\nparser output as an optimization, not the only evidence path.\n\n```python\nwith ConnectHandler(**device) as conn:\n    parsed = conn.send_command(\n        \"show ip interface brief\",\n        use_textfsm=True,\n        raise_parsing_error=False,\n        read_timeout=30,\n    )\n\nif isinstance(parsed, str):\n    print(\"No parser template matched; store raw output for review\")\nelse:\n    for row in parsed:\n        print(row)\n```\n\nIf parsing drives a blocking decision, keep the raw command output alongside\nthe parsed result so an operator can inspect mismatches.\n\n## Guarded Config Pattern\n\n```python\nimport os\n\ncommands = [\n    \"interface GigabitEthernet0\u002F1\",\n    \"description CHANGE-1234 UPLINK-TO-CORE\",\n]\n\napply_changes = os.environ.get(\"APPLY_NETWORK_CHANGES\") == \"1\"\n\nif not apply_changes:\n    print(\"Dry run only. Candidate commands:\")\n    print(\"\\n\".join(commands))\nelse:\n    with ConnectHandler(**device) as conn:\n        conn.enable()\n        before = conn.send_command(\"show running-config interface GigabitEthernet0\u002F1\")\n        output = conn.send_config_set(commands)\n        after = conn.send_command(\"show running-config interface GigabitEthernet0\u002F1\")\n        print(before)\n        print(output)\n        print(after)\n        print(\"Verify behavior before saving startup config.\")\n```\n\nSaving the config is a separate approval step. In production, include a rollback\nsnippet and capture before\u002Fafter evidence in the change record.\n\n## Review Checklist\n\n- Does the script identify an explicit inventory source?\n- Are credentials absent from source, logs, and exception messages?\n- Are `conn_timeout`, `auth_timeout`, and command `read_timeout` set?\n- Are failures reported per device without stopping the whole batch?\n- Does the script avoid broad scans and unbounded concurrency?\n- Are config changes behind a dry-run or explicit operator flag?\n- Is `save_config()` separate from the initial push and tied to verification?\n\n## Anti-Patterns\n\n- Hardcoding passwords, enable secrets, or private keys in source.\n- Sending config commands as the default code path.\n- Running automation against a CIDR range instead of a reviewed inventory.\n- Logging full running configs to shared systems without sanitization.\n- Treating parser success as proof that the device state is correct.\n\n## See Also\n\n- Skill: `cisco-ios-patterns`\n- Skill: `network-config-validation`\n- Skill: `network-interface-health`\n",{"name":5,"origin":24,"description":7},"community","master","d6ca01da0f24a3b0e26e4a8b7b66cbd25d429f5d","skills\u002Fnetmiko-ssh-automation",0,"https:\u002F\u002Fgithub.com\u002FSriramGandhiS\u002FSkills","https:\u002F\u002Fgithub.com\u002FSriramGandhiS","https:\u002F\u002Fsriram.website\u002F","Curious guy who keeps tinkering until something works","2026-05-20 16:21:34",{"source":8,"skillName":5,"commands":35,"prompt":45,"zipAvailable":46},[36,39,42],{"tool":37,"command":38},"npx","npx skills add SriramGandhiS\u002FSkills --skill netmiko-ssh-automation",{"tool":40,"command":41},"bunx","bunx skills add SriramGandhiS\u002FSkills --skill netmiko-ssh-automation",{"tool":43,"command":44},"pnpm","pnpm dlx skills add SriramGandhiS\u002FSkills --skill netmiko-ssh-automation","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FSriramGandhiS\u002FSkills\u002Fblob\u002Fmaster\u002Fskills\u002Fnetmiko-ssh-automation\u002FSKILL.md",true,[],[49,56,61,67,74,81],{"skillNo":50,"name":51,"nameZh":6,"description":52,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":53,"categories":54,"keywords":55,"publishedAt":19},"01M732609EPJWV13PVTX3GT4TM","webgpu-threejs-tsl","Comprehensive guide for developing WebGPU-enabled Three.js applications using TSL (Three.js Shading Language). Covers WebGPU renderer setup, TSL syntax and node materials, compute shaders, post-processing effects, and WGSL integration. Use this skill when working with Three.js WebGPU, TSL shaders, node materials, or GPU compute in Three.js.","https:\u002F\u002Fgithub.com\u002FSriramGandhiS\u002FSkills\u002Fblob\u002Fmaster\u002Fwebgpu-threejs-tsl\u002Fskills\u002Fwebgpu-threejs-tsl\u002FSKILL.md",[],[],{"skillNo":57,"name":51,"nameZh":6,"description":52,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":58,"categories":59,"keywords":60,"publishedAt":19},"01M7325XM47AGWB6K6C4VXKE6B","https:\u002F\u002Fgithub.com\u002FSriramGandhiS\u002FSkills\u002Fblob\u002Fmaster\u002Fwebgpu-threejs-tsl\u002FSKILL.md",[],[],{"skillNo":62,"name":63,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":64,"categories":65,"keywords":66,"publishedAt":19},"01M7325WP6DES69JKC840VMFEP","verification-loop","https:\u002F\u002Fgithub.com\u002FSriramGandhiS\u002FSkills\u002Fblob\u002Fmaster\u002Fweb-assets\u002Fdocs\u002Fzh-TW\u002Fskills\u002Fverification-loop\u002FSKILL.md",[],[],{"skillNo":68,"name":69,"nameZh":6,"description":70,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":71,"categories":72,"keywords":73,"publishedAt":19},"01M7325TFQF1DZTQ6J3WGQQ1VR","tdd-workflow","Use this skill when writing new features, fixing bugs, or refactoring code. Enforces test-driven development with 80%+ coverage including unit, integration, and E2E tests.","https:\u002F\u002Fgithub.com\u002FSriramGandhiS\u002FSkills\u002Fblob\u002Fmaster\u002Fweb-assets\u002Fdocs\u002Fzh-TW\u002Fskills\u002Ftdd-workflow\u002FSKILL.md",[],[],{"skillNo":75,"name":76,"nameZh":6,"description":77,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":78,"categories":79,"keywords":80,"publishedAt":19},"01M7325RGV9AY9PK92D2V8KKPW","strategic-compact","Suggests manual context compaction at logical intervals to preserve context through task phases rather than arbitrary auto-compaction.","https:\u002F\u002Fgithub.com\u002FSriramGandhiS\u002FSkills\u002Fblob\u002Fmaster\u002Fweb-assets\u002Fdocs\u002Fzh-TW\u002Fskills\u002Fstrategic-compact\u002FSKILL.md",[],[],{"skillNo":82,"name":83,"nameZh":6,"description":84,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":85,"categories":86,"keywords":87,"publishedAt":19},"01M7325MZC28SE86E7NMCNEFS4","security-review","Use this skill when adding authentication, handling user input, working with secrets, creating API endpoints, or implementing payment\u002Fsensitive features. Provides comprehensive security checklist and patterns.","https:\u002F\u002Fgithub.com\u002FSriramGandhiS\u002FSkills\u002Fblob\u002Fmaster\u002Fweb-assets\u002Fdocs\u002Fzh-TW\u002Fskills\u002Fsecurity-review\u002FSKILL.md",[],[]]