AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified Apache-2.0 Self-run

Netbox Custom Scripts

skill-netboxlabs-skills-netbox-custom-scripts · by netboxlabs

>

No reviews yet
0 installs
21 views
0.0% view→install

Install

$ agentstack add skill-netboxlabs-skills-netbox-custom-scripts

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access Used
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-netboxlabs-skills-netbox-custom-scripts)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
1mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Netbox Custom Scripts? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

NetBox Custom Scripts

> Your knowledge of NetBox custom scripts may be outdated. The Script class API, variable types, and job framework evolve between NetBox releases. Prefer retrieval over pre-trained knowledge.

Retrieval Sources

| Source | URL / Method | Use for | |--------|-------------|---------| | Custom scripts docs | https://netboxlabs.com/docs/netbox/customization/custom-scripts/ | Script class, variables, scheduling | | NetBox repo | https://github.com/netbox-community/netbox | Script framework source code | | NetBox MCP server | If configured — verify object state before/after script execution | Testing script output |

FIRST: Verify Environment

Custom scripts run inside NetBox. Confirm your NetBox instance is running and you can access the scripts endpoint:

curl -s -H "Authorization: Bearer $NETBOX_TOKEN" "$NETBOX_URL/api/extras/scripts/" | python -m json.tool

You should see a list of installed scripts. Scripts are loaded from SCRIPTS_ROOT (default: /opt/netbox/netbox/scripts/).


Use this skill when writing or debugging custom scripts that run inside NetBox. For plugin development (new models, views, APIs), see [netbox-plugin-development](../netbox-plugin-development/SKILL.md).

Quick Reference

Minimal Script

from extras.scripts import Script, StringVar, ObjectVar
from dcim.models import Site

class HelloWorld(Script):
    class Meta:
        name = "Hello World"
        description = "A minimal example script"
        commit_default = False

    site = ObjectVar(model=Site)

    def run(self, data, commit):
        self.log_success(f"Selected site: {data['site']}", data['site'])
        return "Done"

Log Methods

| Method | Level | Side Effect | |--------|-------|-------------| | self.log_debug(msg, obj) | DEBUG | — | | self.log_info(msg, obj) | INFO | — | | self.log_success(msg, obj) | SUCCESS | — | | self.log_warning(msg, obj) | WARNING | — | | self.log_failure(msg, obj) | FAILURE | Sets self.failed = True |

Both msg and obj are optional. Markdown is supported in messages. If obj has get_absolute_url(), it becomes a clickable link in the UI.

Common Imports

from extras.scripts import Script, AbortScript
from extras.scripts import (
    StringVar, TextVar, IntegerVar, BooleanVar, ChoiceVar,
    MultiChoiceVar, ObjectVar, MultiObjectVar, FileVar,
    IPAddressVar, IPAddressWithMaskVar, IPNetworkVar,
    DateVar, DateTimeVar, DecimalVar,
)
from dcim.models import Device, Site, Interface, Rack, Region
from ipam.models import IPAddress, Prefix, VLAN, VRF
from tenancy.models import Tenant
from circuits.models import Circuit

Script Structure

Meta Attributes

| Attribute | Default | Purpose | |-----------|---------|---------| | name | Class name | Display name in UI | | description | '' | Description shown in UI | | commit_default | True | Default state of commit checkbox | | scheduling_enabled | True | Allow scheduled/recurring execution | | job_timeout | RQ_DEFAULT_TIMEOUT | Max runtime in seconds | | field_order | Declaration order | Tuple of field names | | fieldsets | None | Grouped field layout (overrides field_order) |

Fieldsets

Group related fields in the UI:

class Meta:
    fieldsets = (
        ('Source', ('region', 'site')),
        ('Configuration', ('vlan_id', 'description')),
    )

Module-Level Ordering

Control display order when a file has multiple scripts:

script_order = (ScriptA, ScriptB, ScriptC)

Form Variables

All variables support: label, description, default, required (default True), widget.

| Variable | Key Options | Notes | |----------|-------------|-------| | StringVar | min_length, max_length, regex | Single-line text | | TextVar | — | Multi-line textarea | | IntegerVar | min_value, max_value | | | BooleanVar | — | Always optional internally | | ChoiceVar | choices (list of (value, label)) | Blank choice auto-added | | MultiChoiceVar | choices | Multiple selection | | ObjectVar | model, query_params, null_option, selector, quick_add | Dynamic API-backed dropdown. selector (4.5+) shows an advanced object-picker; quick_add (4.6.2+) adds an inline "create new" button | | MultiObjectVar | Same as ObjectVar | Multiple objects | | FileVar | — | File upload (only available during execution) | | IPAddressVar | — | IPv4/IPv6 without mask | | IPAddressWithMaskVar | — | IP with prefix (e.g., 192.168.1.1/24) | | IPNetworkVar | min_prefix_length, max_prefix_length | Network prefix | | DateVar / DateTimeVar | — | Date/time pickers | | DecimalVar | min_value, max_value, max_digits, decimal_places | |

See [references/script-variables.md](references/script-variables.md) for full details.

Dynamic Filtering with ObjectVar

Reference other form fields using $ prefix in query_params:

region = ObjectVar(model=Region)
site = ObjectVar(model=Site, query_params={'region_id': '$region'})
rack = ObjectVar(model=Rack, query_params={'site_id': '$site'})

The UI dynamically filters each dropdown based on the parent selection.

ORM Access & Change Logging

Scripts have full Django ORM access. Three critical rules:

1. Always call full_clean() before save()

device = Device(name='new-device', site=site, role=role, device_type=dtype)
device.full_clean()   # Validates model constraints — skipping risks data corruption
device.save()

2. Call snapshot() before modifying existing objects

device = Device.objects.get(name='existing')
device.snapshot()     # Required for change log to show a diff
device.status = 'active'
device.full_clean()
device.save()

3. Use _changelog_message for context (optional)

device._changelog_message = 'Bulk status update via maintenance script'
device.save()

See [references/orm-patterns.md](references/orm-patterns.md) for query optimization and bulk patterns.

Transaction Handling

All script execution is wrapped in transaction.atomic(). This means:

  • commit=True: Changes persist if the script completes without error
  • commit=False: All DB changes are rolled back after run() completes (dry-run mode)
  • Any exception: All changes are rolled back regardless of commit setting
  • Scripts cannot partially commit — it's all or nothing

Clean Abort

from utilities.exceptions import AbortScript

if critical_error:
    raise AbortScript("Clear error message")

AbortScript logs the message as a failure and rolls back all changes — no stack trace in the output.

log_failure Does NOT Abort

Calling self.log_failure() sets self.failed = True (shows warning in UI) but does not stop execution. Use AbortScript to actually halt.

Execution Model

Scripts run as background jobs via Django-RQ:

  • UI/API submission → job queued to Redis → RQ worker executes
  • CLI: python manage.py runscript --commit --user admin module.ClassName
  • Scheduling: Set schedule_at for future execution, interval for recurrence
  • Timeout: Controlled by Meta.job_timeout or global RQ_DEFAULT_TIMEOUT

> NetBox 4.6 background-job changes: completion notifications are disabled for scripts running in the background (4.6) — don't rely on a UI notification to signal a scheduled run finished; check job status instead. NetBox 4.6.2 also prevents duplicate scheduled background jobs (re-submitting an already-queued recurring job no longer stacks duplicates).

See [references/execution-model.md](references/execution-model.md) for job lifecycle details.

Job States

PENDINGRUNNINGCOMPLETED | ERRORED | FAILED

Or SCHEDULEDPENDING → ...

Validation Reports (Test Methods)

Methods named test_* are auto-detected and run as validation checks:

class CablingAudit(Script):
    class Meta:
        name = "Cabling Audit"

    def test_console_connections(self):
        for device in Device.objects.filter(status='active'):
            ports = ConsolePort.objects.filter(device=device)
            for port in ports:
                if port.connected_endpoints:
                    self.log_success(None, port)  # Count success without message
                else:
                    self.log_failure(f"No console connection: {port}", device)

If run() is not overridden, NetBox executes pre_run() → all test_* methods → post_run().

> NetBox 4.0+: Reports were merged into scripts. Legacy report log signature (obj, message) still works but is deprecated — use (message, obj).

Anti-Patterns

| Mistake | Consequence | Fix | |---------|------------|-----| | Skip full_clean() | Data integrity violations | Always validate before save | | Skip snapshot() | Change log shows no diff | Call before modifying existing objects | | Expect log_failure to stop | Script continues running | Use AbortScript to halt | | Long-running script | Killed by timeout | Set Meta.job_timeout | | Import from netbox.dcim.models | ImportError | Use from dcim.models import ... | | Assume FileVar persists | File only available during execution | Process/copy file in run() | | Rely on self.request.user in CLI | Gets NetBoxFakeRequest | Handle gracefully | | Module name conflicts | Import collisions | Avoid naming scripts like installed packages |

Script File Management

  • Scripts are Python files in SCRIPTS_ROOT (default: $INSTALL/netbox/scripts/)
  • Upload via UI (Admin > Custom Scripts) or place files directly
  • Each file becomes a ScriptModule; classes auto-discovered
  • Removing a class from a file soft-deletes its DB record if job history exists (is_executable=False)
  • Storage backend configurable via Django STORAGES (supports S3)
  • Scripts can also be synced from a remote DataSource (git/S3); on NetBox 4.6.2+ remote-source scripts are validated on sync, so a malformed script is caught at sync time rather than first execution

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.