Install any skill in seconds. Free to start, no credit card required.
Get Started Free →IP Address Management and DNS record reconciliation audit covering subnet utilization analysis, DNS forward/reverse consistency, IP conflict detection, and DHCP scope health. Platform-agnostic with references to common IPAM implementations. Uses the reconciliation procedure shape — IPAM source extraction, live discovery, diff analysis, and remediation reporting.
SkillScore64/100
Test results 64
3/3 safety checks passed
55%64%of test cases passed +9 pts
Passed 14 of 22 test cases with the skill, and 12 of 22 without it.
4 fixed10 passed either way6 still failing2 broke
One test taskDuring live host discovery on routed interfaces, gateway ARP tables on Cisco routers show significantly fewer active hosts than Juniper gateways on adjacent subnets with similar traffic patterns. What default ARP timeout behavior accounts for this difference?
Adds every file the skill has, pinned so you can update it. No account needed.
pip install "decimalai>=0.15"
decimalai skills add leoyeai-ipam-dns-audit
claude --plugin-dir "$(git rev-parse --show-toplevel 2>/dev/null || pwd)/.agents"The same install from Python, for a notebook or a setup script.
pip install "decimalai>=0.15"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("leoyeai-ipam-dns-audit")
if result.exit_code:
raise SystemExit(result.problems)
print("Added. Start Claude Code with the command below.")claude --plugin-dir "$(git rev-parse --show-toplevel 2>/dev/null || pwd)/.agents"Type these in a Claude Code session. No account or API key. It writes the skill and any files it bundles, and asks first when its safety rating isn't Passed.
/plugin marketplace add decimal-labs/decimalai-claude-plugins
/plugin install decimalai@decimalai/decimalai:install leoyeai-ipam-dns-auditThe plugin needs python3 and curl on your machine.
No Python or account. Claude Code picks it up in its next session.
curl -fsSL --create-dirs -o .claude/skills/leoyeai-ipam-dns-audit/SKILL.md https://app.decimal.ai/s/leoyeai-ipam-dns-audit/SKILL.md.claude/skills/leoyeai-ipam-dns-audit/SKILL.mdThis gets SKILL.md only. The skill's 2 other files are not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[claude-agent-sdk]"
decimalai skills add leoyeai-ipam-dns-auditimport asyncio
from claude_agent_sdk import ClaudeAgentOptions
from decimalai.claude_agent_sdk import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
async def main():
question = "Hello!"
async with support.run(question) as run: # one user message, one run
async for message in run.query(options=ClaudeAgentOptions(max_turns=6)):
print(message)
# In a notebook or async code: await main()
asyncio.run(main())Prefer its own loader? ClaudeAgentOptions(plugins=[skills_plugin()], skills="all") reads the same folder. Use one or the other: a skill delivered both ways reaches the prompt twice.
The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[claude-agent-sdk]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("leoyeai-ipam-dns-audit")
if result.exit_code:
raise SystemExit(result.problems)
import asyncio
from claude_agent_sdk import ClaudeAgentOptions
from decimalai.claude_agent_sdk import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
async def main():
question = "Hello!"
async with support.run(question) as run: # one user message, one run
async for message in run.query(options=ClaudeAgentOptions(max_turns=6)):
print(message)
# In a notebook or async code: await main()
asyncio.run(main())Prefer its own loader? ClaudeAgentOptions(plugins=[skills_plugin()], skills="all") reads the same folder. Use one or the other: a skill delivered both ways reaches the prompt twice.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/leoyeai-ipam-dns-audit/SKILL.mdimport asyncio
from pathlib import Path
from claude_agent_sdk import ClaudeAgentOptions, query
skill = Path(".agents/skills/leoyeai-ipam-dns-audit/SKILL.md").read_text()
options = ClaudeAgentOptions(system_prompt=f"You are a helpful agent.\n\n{skill}", max_turns=6)
async def main():
async for message in query(prompt="Hello!", options=options):
print(message)
# In a notebook or async code: await main()
asyncio.run(main())This gets SKILL.md only. The skill's 2 other files are not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[openai-agents]"
decimalai skills add leoyeai-ipam-dns-auditfrom agents import Agent, Runner
from decimalai.openai_agents import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = Agent(
name=support.name,
instructions=support.instructions, # your prompt, then the skill list
tools=[*support.tools], # your tools, then load_skill
)
# In a notebook or async code: result = await Runner.run(agent, "Hello!")
result = Runner.run_sync(agent, "Hello!")Using SandboxAgent? capabilities=[Shell(), decimalai.openai_agents.sandbox_skills()] points its own loader at the same folder.
The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[openai-agents]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("leoyeai-ipam-dns-audit")
if result.exit_code:
raise SystemExit(result.problems)
from agents import Agent, Runner
from decimalai.openai_agents import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = Agent(
name=support.name,
instructions=support.instructions, # your prompt, then the skill list
tools=[*support.tools], # your tools, then load_skill
)
# In a notebook or async code: result = await Runner.run(agent, "Hello!")
result = Runner.run_sync(agent, "Hello!")Using SandboxAgent? capabilities=[Shell(), decimalai.openai_agents.sandbox_skills()] points its own loader at the same folder.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/leoyeai-ipam-dns-audit/SKILL.mdfrom pathlib import Path
from agents import Agent, Runner
skill = Path(".agents/skills/leoyeai-ipam-dns-audit/SKILL.md").read_text()
agent = Agent(name="support", instructions=f"You are a helpful agent.\n\n{skill}")
# In a notebook or async code: result = await Runner.run(agent, "Hello!")
result = Runner.run_sync(agent, "Hello!")This gets SKILL.md only. The skill's 2 other files are not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[openai]"
decimalai skills add leoyeai-ipam-dns-auditimport json
from openai import OpenAI
from decimalai.openai import agent_config
client = OpenAI()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
def lookup_order(order_id: str) -> str:
return f"Order {order_id} shipped yesterday."
# Your tools, as Chat Completions takes them, and what answers each.
TOOLS = [{"type": "function", "function": {
"name": "lookup_order",
"description": "Look up the status of an order.",
"parameters": {"type": "object", "properties": {"order_id": {"type": "string"}},
"required": ["order_id"]},
}}]
FUNCTIONS = {"lookup_order": lookup_order}
question = "Where is order A1001?"
with support.run(question) as run: # one user message, one run
# run.system is your prompt, then the skill list.
messages = [{"role": "system", "content": run.system}, run.message]
while True:
reply = client.chat.completions.create(
model="gpt-5.4-mini",
messages=messages,
tools=[*TOOLS, *run.tools], # your tools, then load_skill
).choices[0].message
messages.append(reply)
if not reply.tool_calls:
break
for call in reply.tool_calls:
# load_skill is answered by the run; your own tools by FUNCTIONS.
function = FUNCTIONS.get(call.function.name)
messages.append(run.tool_result(call) or {
"role": "tool", "tool_call_id": call.id,
"content": function(**json.loads(call.function.arguments)) if function
else f"There is no tool named {call.function.name!r}.",
})
print(reply.content)
# The Responses API takes run.response_tools instead of run.tools.The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[openai]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("leoyeai-ipam-dns-audit")
if result.exit_code:
raise SystemExit(result.problems)
import json
from openai import OpenAI
from decimalai.openai import agent_config
client = OpenAI()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
def lookup_order(order_id: str) -> str:
return f"Order {order_id} shipped yesterday."
# Your tools, as Chat Completions takes them, and what answers each.
TOOLS = [{"type": "function", "function": {
"name": "lookup_order",
"description": "Look up the status of an order.",
"parameters": {"type": "object", "properties": {"order_id": {"type": "string"}},
"required": ["order_id"]},
}}]
FUNCTIONS = {"lookup_order": lookup_order}
question = "Where is order A1001?"
with support.run(question) as run: # one user message, one run
# run.system is your prompt, then the skill list.
messages = [{"role": "system", "content": run.system}, run.message]
while True:
reply = client.chat.completions.create(
model="gpt-5.4-mini",
messages=messages,
tools=[*TOOLS, *run.tools], # your tools, then load_skill
).choices[0].message
messages.append(reply)
if not reply.tool_calls:
break
for call in reply.tool_calls:
# load_skill is answered by the run; your own tools by FUNCTIONS.
function = FUNCTIONS.get(call.function.name)
messages.append(run.tool_result(call) or {
"role": "tool", "tool_call_id": call.id,
"content": function(**json.loads(call.function.arguments)) if function
else f"There is no tool named {call.function.name!r}.",
})
print(reply.content)
# The Responses API takes run.response_tools instead of run.tools.No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/leoyeai-ipam-dns-audit/SKILL.mdfrom pathlib import Path
from openai import OpenAI
client = OpenAI()
skill = Path(".agents/skills/leoyeai-ipam-dns-audit/SKILL.md").read_text()
reply = client.chat.completions.create(
model="gpt-5.4-mini",
messages=[
{"role": "system", "content": f"You are a helpful agent.\n\n{skill}"},
{"role": "user", "content": "Hello!"},
],
).choices[0].messageThis gets SKILL.md only. The skill's 2 other files are not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[anthropic]"
decimalai skills add leoyeai-ipam-dns-auditimport anthropic
from decimalai.anthropic import agent_config
client = anthropic.Anthropic()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
question = "Hello!"
with support.run(question) as run: # one user message, one run
answer = client.beta.messages.tool_runner(
model="claude-haiku-5-5",
max_tokens=4096,
system=run.system, # your prompt, then the skill list
tools=[*run.tools], # your tools, then load_skill
messages=[{"role": "user", "content": question}],
).until_done()The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[anthropic]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("leoyeai-ipam-dns-audit")
if result.exit_code:
raise SystemExit(result.problems)
import anthropic
from decimalai.anthropic import agent_config
client = anthropic.Anthropic()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
question = "Hello!"
with support.run(question) as run: # one user message, one run
answer = client.beta.messages.tool_runner(
model="claude-haiku-5-5",
max_tokens=4096,
system=run.system, # your prompt, then the skill list
tools=[*run.tools], # your tools, then load_skill
messages=[{"role": "user", "content": question}],
).until_done()No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/leoyeai-ipam-dns-audit/SKILL.mdfrom pathlib import Path
import anthropic
client = anthropic.Anthropic()
skill = Path(".agents/skills/leoyeai-ipam-dns-audit/SKILL.md").read_text()
reply = client.messages.create(
model="claude-haiku-5-5",
max_tokens=4096,
system=f"You are a helpful agent.\n\n{skill}",
messages=[{"role": "user", "content": "Hello!"}],
)This gets SKILL.md only. The skill's 2 other files are not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[google-genai]"
decimalai skills add leoyeai-ipam-dns-auditfrom google import genai
from google.genai import types
from decimalai.google_genai import agent_config
client = genai.Client()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
def lookup_order(order_id: str) -> str:
return f"Order {order_id} shipped yesterday."
# Your functions, as declarations for the model, and what answers each.
TOOLS = [{"function_declarations": [{
"name": "lookup_order",
"description": "Look up the status of an order.",
"parameters_json_schema": {"type": "object", "properties": {"order_id": {"type": "string"}},
"required": ["order_id"]},
}]}]
FUNCTIONS = {"lookup_order": lookup_order}
question = "Where is order A1001?"
with support.run(question) as run: # one user message, one run
config = types.GenerateContentConfig(
system_instruction=run.system, # your prompt, then the skill list
tools=[*TOOLS, *run.tool_params], # your functions, then load_skill
)
contents = [{"role": "user", "parts": [{"text": run.message}]}]
while True:
response = client.models.generate_content(
model="gemini-3.5-flash", contents=contents, config=config,
)
if not response.function_calls:
break
contents.append(response.candidates[0].content)
parts = []
for call in response.function_calls:
# load_skill is answered by the run; your own functions by FUNCTIONS.
# A loop of your own rather than automatic function calling, which
# raises KeyError when the model asks for a function you did not pass.
function = FUNCTIONS.get(call.name)
parts.append(run.tool_result(call) or {"function_response": {
"name": call.name, "id": call.id,
"response": {"result": function(**(call.args or {})) if function
else f"There is no function named {call.name!r}."},
}})
contents.append({"role": "user", "parts": parts})
print(response.text)The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[google-genai]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("leoyeai-ipam-dns-audit")
if result.exit_code:
raise SystemExit(result.problems)
from google import genai
from google.genai import types
from decimalai.google_genai import agent_config
client = genai.Client()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
def lookup_order(order_id: str) -> str:
return f"Order {order_id} shipped yesterday."
# Your functions, as declarations for the model, and what answers each.
TOOLS = [{"function_declarations": [{
"name": "lookup_order",
"description": "Look up the status of an order.",
"parameters_json_schema": {"type": "object", "properties": {"order_id": {"type": "string"}},
"required": ["order_id"]},
}]}]
FUNCTIONS = {"lookup_order": lookup_order}
question = "Where is order A1001?"
with support.run(question) as run: # one user message, one run
config = types.GenerateContentConfig(
system_instruction=run.system, # your prompt, then the skill list
tools=[*TOOLS, *run.tool_params], # your functions, then load_skill
)
contents = [{"role": "user", "parts": [{"text": run.message}]}]
while True:
response = client.models.generate_content(
model="gemini-3.5-flash", contents=contents, config=config,
)
if not response.function_calls:
break
contents.append(response.candidates[0].content)
parts = []
for call in response.function_calls:
# load_skill is answered by the run; your own functions by FUNCTIONS.
# A loop of your own rather than automatic function calling, which
# raises KeyError when the model asks for a function you did not pass.
function = FUNCTIONS.get(call.name)
parts.append(run.tool_result(call) or {"function_response": {
"name": call.name, "id": call.id,
"response": {"result": function(**(call.args or {})) if function
else f"There is no function named {call.name!r}."},
}})
contents.append({"role": "user", "parts": parts})
print(response.text)No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/leoyeai-ipam-dns-audit/SKILL.mdfrom pathlib import Path
from google import genai
from google.genai import types
client = genai.Client()
skill = Path(".agents/skills/leoyeai-ipam-dns-audit/SKILL.md").read_text()
response = client.models.generate_content(
model="gemini-3.5-flash",
contents="Hello!",
config=types.GenerateContentConfig(system_instruction=f"You are a helpful agent.\n\n{skill}"),
)This gets SKILL.md only. The skill's 2 other files are not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[langchain]" langchain-openai
decimalai skills add leoyeai-ipam-dns-auditfrom langchain.agents import create_agent
from decimalai.langchain import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = create_agent(
"openai:gpt-5.4-mini",
tools=[], # your tools; the middleware adds load_skill
middleware=[support.middleware], # your prompt, the skill list and load_skill
)
result = agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[langchain]" langchain-openaifrom decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("leoyeai-ipam-dns-audit")
if result.exit_code:
raise SystemExit(result.problems)
from langchain.agents import create_agent
from decimalai.langchain import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = create_agent(
"openai:gpt-5.4-mini",
tools=[], # your tools; the middleware adds load_skill
middleware=[support.middleware], # your prompt, the skill list and load_skill
)
result = agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/leoyeai-ipam-dns-audit/SKILL.mdfrom pathlib import Path
from langchain.agents import create_agent
skill = Path(".agents/skills/leoyeai-ipam-dns-audit/SKILL.md").read_text()
agent = create_agent("openai:gpt-5.4-mini", tools=[], system_prompt=f"You are a helpful agent.\n\n{skill}")
result = agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})This gets SKILL.md only. The skill's 2 other files are not included.
CrewAI's own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" "crewai>=1.15.27"
decimalai skills add leoyeai-ipam-dns-auditimport decimalai.crewai
from crewai import Agent, Crew, Task
agent = Agent(
role="Support", goal="Help the customer", backstory="A support agent.",
llm=llm, # your own CrewAI LLM
skills=decimalai.crewai.skills(), # the installed folder
tools=decimalai.crewai.skill_tools(), # reads a skill's files, runs its scripts
)
task = Task(description="Hello!", expected_output="an answer", agent=agent)
Crew(agents=[agent], tasks=[task]).kickoff()The same install from Python, for a notebook or a setup script. CrewAI's own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" "crewai>=1.15.27"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("leoyeai-ipam-dns-audit")
if result.exit_code:
raise SystemExit(result.problems)
import decimalai.crewai
from crewai import Agent, Crew, Task
agent = Agent(
role="Support", goal="Help the customer", backstory="A support agent.",
llm=llm, # your own CrewAI LLM
skills=decimalai.crewai.skills(), # the installed folder
tools=decimalai.crewai.skill_tools(), # reads a skill's files, runs its scripts
)
task = Task(description="Hello!", expected_output="an answer", agent=agent)
Crew(agents=[agent], tasks=[task]).kickoff()No DecimalAI package. CrewAI's own loader reads the folder, and nothing pins or updates it.
.agents/skills/leoyeai-ipam-dns-audit/SKILL.mdfrom pathlib import Path
from crewai import Agent, Crew, Task
agent = Agent(
role="Support", goal="Help the customer", backstory="A support agent.",
llm=llm, # your own CrewAI LLM
skills=[Path(".agents/skills")],
)
task = Task(description="Hello!", expected_output="an answer", agent=agent)
Crew(agents=[agent], tasks=[task]).kickoff()This gets SKILL.md only. The skill's 2 other files are not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[adk]"
decimalai skills add leoyeai-ipam-dns-auditfrom decimalai.adk import DecimalAIPlugin, agent_config
from google.adk.agents import LlmAgent
from google.adk.apps import App
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = LlmAgent(
name="support", # ADK needs a Python identifier
model="gemini-3.5-flash",
instruction=support.instruction, # your prompt, then the skill list
tools=[*support.tools], # your tools, then load_skill
)
# DecimalAIPlugin makes each invocation of runners built from this App one trace.
app = App(name="support", root_agent=agent, plugins=[DecimalAIPlugin()])Prefer ADK's own loader? SkillToolset(skills=decimalai.adk.skills(), ...) reads the same folder. Use one or the other: a skill delivered both ways reaches the prompt twice.
The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[adk]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("leoyeai-ipam-dns-audit")
if result.exit_code:
raise SystemExit(result.problems)
from decimalai.adk import DecimalAIPlugin, agent_config
from google.adk.agents import LlmAgent
from google.adk.apps import App
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = LlmAgent(
name="support", # ADK needs a Python identifier
model="gemini-3.5-flash",
instruction=support.instruction, # your prompt, then the skill list
tools=[*support.tools], # your tools, then load_skill
)
# DecimalAIPlugin makes each invocation of runners built from this App one trace.
app = App(name="support", root_agent=agent, plugins=[DecimalAIPlugin()])Prefer ADK's own loader? SkillToolset(skills=decimalai.adk.skills(), ...) reads the same folder. Use one or the other: a skill delivered both ways reaches the prompt twice.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/leoyeai-ipam-dns-audit/SKILL.mdfrom pathlib import Path
from google.adk.agents import LlmAgent
skill = Path(".agents/skills/leoyeai-ipam-dns-audit/SKILL.md").read_text()
agent = LlmAgent(
name="support",
model="gemini-3.5-flash",
instruction=lambda context: f"You are a helpful agent.\n\n{skill}",
)This gets SKILL.md only. The skill's 2 other files are not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[pydantic-ai]"
decimalai skills add leoyeai-ipam-dns-auditfrom pydantic_ai import Agent
from decimalai.pydantic_ai import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = Agent(
"openai:gpt-4o-mini",
name=support.name,
tools=[], # your tools; the capability adds load_skill
capabilities=[support], # your prompt, the skill list and load_skill
)
# In a notebook or async code: result = await agent.run("Hello!")
result = agent.run_sync("Hello!")On the Pydantic AI harness, decimalai.pydantic_ai_harness.skills(project) uses its own loader instead.
The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[pydantic-ai]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("leoyeai-ipam-dns-audit")
if result.exit_code:
raise SystemExit(result.problems)
from pydantic_ai import Agent
from decimalai.pydantic_ai import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = Agent(
"openai:gpt-4o-mini",
name=support.name,
tools=[], # your tools; the capability adds load_skill
capabilities=[support], # your prompt, the skill list and load_skill
)
# In a notebook or async code: result = await agent.run("Hello!")
result = agent.run_sync("Hello!")On the Pydantic AI harness, decimalai.pydantic_ai_harness.skills(project) uses its own loader instead.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/leoyeai-ipam-dns-audit/SKILL.mdfrom pathlib import Path
from pydantic_ai import Agent
skill = Path(".agents/skills/leoyeai-ipam-dns-audit/SKILL.md").read_text()
agent = Agent("openai:gpt-4o-mini", instructions=f"You are a helpful agent.\n\n{skill}")
# In a notebook or async code: result = await agent.run("Hello!")
result = agent.run_sync("Hello!")This gets SKILL.md only. The skill's 2 other files are not included.
Deep Agents' own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" deepagents
decimalai skills add leoyeai-ipam-dns-auditimport decimalai.deepagents
from deepagents import create_deep_agent
agent = create_deep_agent(model=model, **decimalai.deepagents.skills())
agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})The default backend reads files but has no shell. To run a skill's scripts, pass skills(backend=LocalShellBackend(...)).
The same install from Python, for a notebook or a setup script. Deep Agents' own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" deepagentsfrom decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("leoyeai-ipam-dns-audit")
if result.exit_code:
raise SystemExit(result.problems)
import decimalai.deepagents
from deepagents import create_deep_agent
agent = create_deep_agent(model=model, **decimalai.deepagents.skills())
agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})The default backend reads files but has no shell. To run a skill's scripts, pass skills(backend=LocalShellBackend(...)).
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/leoyeai-ipam-dns-audit/SKILL.mdfrom pathlib import Path
from deepagents import create_deep_agent
skill = Path(".agents/skills/leoyeai-ipam-dns-audit/SKILL.md").read_text()
agent = create_deep_agent(model=model, system_prompt=f"You are a helpful agent.\n\n{skill}")
agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})This gets SKILL.md only. The skill's 2 other files are not included.
Its own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" agent-framework
decimalai skills add leoyeai-ipam-dns-auditimport asyncio
from agent_framework import Agent
from decimalai.agent_framework import skills
agent = Agent(client=client, instructions="You are a helpful agent.", context_providers=[skills()])
asyncio.run(agent.run("Hello!"))It caches skills by default, so restart the process after decimalai skills update.
The same install from Python, for a notebook or a setup script. Its own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" agent-frameworkfrom decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("leoyeai-ipam-dns-audit")
if result.exit_code:
raise SystemExit(result.problems)
import asyncio
from agent_framework import Agent
from decimalai.agent_framework import skills
agent = Agent(client=client, instructions="You are a helpful agent.", context_providers=[skills()])
asyncio.run(agent.run("Hello!"))It caches skills by default, so restart the process after decimalai skills update.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/leoyeai-ipam-dns-audit/SKILL.mdimport asyncio
from pathlib import Path
from agent_framework import Agent
skill = Path(".agents/skills/leoyeai-ipam-dns-audit/SKILL.md").read_text()
agent = Agent(client=client, instructions=f"You are a helpful agent.\n\n{skill}")
asyncio.run(agent.run("Hello!"))This gets SKILL.md only. The skill's 2 other files are not included.
Strands' own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" strands-agents
decimalai skills add leoyeai-ipam-dns-auditfrom decimalai.strands import skills
from strands import Agent
from strands.vended_tools import file_editor, shell
agent = Agent(
model=model, # always pass one: the default is Amazon Bedrock
system_prompt="You are a helpful agent.",
tools=[file_editor, shell],
plugins=[skills()],
)
agent("Hello!")Strands loads an agent's skills once, so build the agent again after decimalai skills update.
The same install from Python, for a notebook or a setup script. Strands' own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" strands-agentsfrom decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("leoyeai-ipam-dns-audit")
if result.exit_code:
raise SystemExit(result.problems)
from decimalai.strands import skills
from strands import Agent
from strands.vended_tools import file_editor, shell
agent = Agent(
model=model, # always pass one: the default is Amazon Bedrock
system_prompt="You are a helpful agent.",
tools=[file_editor, shell],
plugins=[skills()],
)
agent("Hello!")Strands loads an agent's skills once, so build the agent again after decimalai skills update.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/leoyeai-ipam-dns-audit/SKILL.mdfrom pathlib import Path
from strands import Agent
skill = Path(".agents/skills/leoyeai-ipam-dns-audit/SKILL.md").read_text()
agent = Agent(model=model, system_prompt=f"You are a helpful agent.\n\n{skill}")
agent("Hello!")This gets SKILL.md only. The skill's 2 other files are not included.
Adds every file the skill has, pinned so you can update it. Cursor, Copilot, Cline and Warp read this folder by themselves.
pip install "decimalai>=0.15"
decimalai skills add leoyeai-ipam-dns-auditNo Python or account. Cursor, Copilot, Cline and Warp read this folder by themselves.
curl -fsSL --create-dirs -o .agents/skills/leoyeai-ipam-dns-audit/SKILL.md https://app.decimal.ai/s/leoyeai-ipam-dns-audit/SKILL.md.agents/skills/leoyeai-ipam-dns-audit/SKILL.mdThis gets SKILL.md only. The skill's 2 other files are not included.
Give its text to your model as instructions. No account or package needed.
This gets SKILL.md only. The skill's 2 other files are not included.
Raw files: /s/leoyeai-ipam-dns-audit/SKILL.md · /s/leoyeai-ipam-dns-audit.json
Fetch the file and give its text to your model as instructions. No account or package needed.
curl -fsSL https://app.decimal.ai/s/leoyeai-ipam-dns-audit/SKILL.mdcurl -fsSL https://app.decimal.ai/s/leoyeai-ipam-dns-audit.jsonThis gets SKILL.md only. The skill's 2 other files are not included.
You don't need a DecimalAI account.
Saved prompts and skills, pinned versions, and traces of this skill in your runs. DecimalAI does not run your agent.
Claude Code reads files from your project, so DecimalAI config does not apply there.
On Claude Agent SDK: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On OpenAI Agents: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On OpenAI SDK: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On Anthropic: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On Gemini API: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On LangChain: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On CrewAI: set DECIMAL_API_KEY and add decimalai.init(crewai=True) to record runs and skill use. The skill version stays in your repo.
On Google ADK: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On Pydantic AI: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On Deep Agents: set DECIMAL_API_KEY and add decimalai.init(langchain=True) to record runs and skill use. The skill version stays in your repo.
On Microsoft Agent Framework: set DECIMAL_API_KEY and add decimalai.init(otel=True, agent_name="support") to record runs and skill use. The skill version stays in your repo.
On Strands: set DECIMAL_API_KEY and add decimalai.init(otel=True, agent_name="support") to record runs and skill use. The skill version stays in your repo.
Editors read files from your project, so DecimalAI config does not apply there.
Anywhere else: record a use with decimalai.log_skill_activation() inside a trace.
IP Address Management (IPAM) and DNS record reconciliation audit for assessing the accuracy and health of IP address allocations, subnet utilization, and DNS records. This skill provides a systematic methodology for comparing IPAM-recorded state against live subnet activity and DNS resolution results — identifying conflicts, orphaned records, exhaustion risks, and stale entries that degrade network reliability.
IPAM systems maintain the authoritative record of how IP address space should be allocated: prefix hierarchies, subnet assignments, VLAN mappings, static reservations, and DHCP scopes. DNS servers maintain the mapping between names and addresses. Live network state — ARP tables, DHCP leases, and actual DNS resolution — reveals what the network actually looks like. The gap between recorded allocations and live reality is the reconciliation target.
This skill complements source-of-truth-audit (which covers the
full device inventory) by focusing specifically on IP address and
DNS record accuracy. Reference references/cli-reference.md for
DNS query tools, ARP/neighbor table commands, DHCP inspection, and
IPAM API patterns. Reference references/subnet-dns-reference.md
for RFC allocation guidance, CIDR math, DNS record types, and DHCP
scope planning.
dig or nslookup against the authoritative serverFollow these six steps sequentially. Each step builds on the previous — IPAM extraction and live discovery feed the diff and conflict detection, which feeds utilization analysis, culminating in the reconciliation report.
Extract authoritative IP allocation data from the IPAM system to build a complete picture of intended address space usage.
Prefix Hierarchy Review — Export the prefix hierarchy for in-scope
VRFs. Verify supernet/subnet containment: every child prefix must be
within its parent aggregate. Identify orphaned prefixes (no parent)
and overlapping definitions (same address space in same VRF). See
references/cli-reference.md for IPAM API patterns (NetBox, Infoblox,
BlueCat).
VLAN-to-Subnet Mapping — Cross-reference VLAN assignments with prefix VLAN fields. Flag VLANs with no subnet (unused or misconfigured) and subnets with no VLAN association (missing metadata).
IP Reservation Audit — Categorize IPs by status: static, DHCP pool, reserved (gateways, HSRP/VRRP VIPs), and available. Verify gateway IPs are marked reserved. Check for IPs marked "Active" with no device or interface record — orphaned allocations.
IPv4 Exhaustion Assessment — Calculate raw utilization per subnet: assigned addresses / total usable addresses. Flag prefixes above threshold (typically 80% warning) and identify remaining contiguous free blocks.
Discover actual IP address usage to compare against IPAM records. No single source captures all active addresses — multiple collection methods are required.
ARP Table Analysis — Collect ARP tables from Layer 3 gateways
for each in-scope subnet. Each ARP entry represents a recently active
IP. On Cisco IOS: show ip arp vrf <name>. On Juniper JunOS:
show arp interface <l3-interface>. On Arista EOS: show ip arp vrf <name>.
DHCP Lease Correlation — Extract active leases from the DHCP server. Compare against IPAM DHCP scope definitions to ensure boundaries match. Identify leases outside defined scopes — these indicate misconfigured or rogue DHCP servers.
Ping Sweep Validation — For subnets where ARP data is incomplete
(routed subnets with no local L3 interface), use ICMP sweeps:
nmap -sn <prefix> or fping -g <prefix>. Non-responding IPs are
not necessarily unused — firewalls may block ICMP.
Duplicate IP Detection — Analyze ARP tables for multiple MAC addresses on the same IP (gratuitous ARP conflicts). Rapidly alternating MACs for a single IP indicate active conflicts causing intermittent connectivity.
Audit DNS records for consistency, accuracy, and hygiene. DNS errors cause application failures often misdiagnosed as network issues.
Forward/Reverse Consistency — For each A record, verify a
corresponding PTR record points back to the same hostname. For each
PTR, verify the referenced hostname has a matching A record. Use
dig +short <hostname> A and dig +short -x <ip> to test pairs.
Inconsistencies break reverse DNS used by mail servers, logging, and
security tools.
Stale Record Detection — Cross-reference A records against IPAM and live ARP tables. A records pointing to IPs that IPAM shows as available or decommissioned are stale. Records pointing to IPs with no ARP activity for 90+ days may reference removed hosts.
CNAME Chain Validation — Verify CNAME records resolve to valid targets. Flag chains longer than two hops (add latency and fragility). Verify no CNAME exists at a zone apex or alongside MX/NS records (RFC 1034 prohibition).
Delegation Chain Integrity — Verify NS records for delegated zones point to responding servers. Check MX records resolve to A records (not CNAMEs, per RFC 2181). Validate SOA serial numbers across primary and secondary servers for replication currency.
TTL Review — Audit TTL appropriateness: infrastructure records (NS, MX, SOA) should use 3600–86400s; frequently changing records (load balancers, failover) need 60–300s; static host records typically use 3600s.
Identify conflicts that cause operational problems — higher severity than record hygiene issues from Step 3.
Overlapping Subnet Definitions — Compare all prefix entries within each VRF for overlaps. Two /24 prefixes covering the same range, or a /24 outside its documented /16 parent, indicate data entry errors. Use bitwise comparison to detect non-obvious overlaps (e.g., 10.1.0.0/23 and 10.1.1.0/24).
Duplicate IP Assignments — Cross-reference IPAM assignments with live ARP. Two IPAM records for the same IP in the same VRF is a data conflict. Two MACs for the same IP in ARP is a live conflict. Either causes packet loss and needs immediate remediation.
DNS Record Conflicts — Multiple A records for the same hostname (without intentional round-robin) indicate misconfiguration. CNAME records conflicting with other types at the same name violate standards. PTR records with no matching forward A record are orphaned.
Orphaned PTR Records — Reverse zone entries pointing to hostnames with no forward A record, or to IPs that IPAM shows unallocated. These accumulate after decommissions when reverse zones are not cleaned. Audit by iterating PTR records and performing forward lookups.
Compute utilization metrics for capacity planning, exhaustion risk identification, and overprovisioning detection.
Subnet Utilization Calculation — For each prefix:
utilization = allocated_addresses / usable_addresses × 100%.
Usable addresses exclude network and broadcast. Compare IPAM-calculated
vs ARP-based utilization (active IPs vs total) — significant divergence
indicates stale IPAM data.
Threshold Classification — Apply standard thresholds: >90% critical (expand immediately), >80% warning (plan within quarter), 50–80% healthy, <20% oversized (reclaim candidate). DHCP pools tolerate higher utilization than static ranges.
DHCP Scope Exhaustion Projection — Calculate remaining leases per scope and project time-to-exhaustion based on lease growth rate. Scopes with <10% free and growing demand need immediate expansion or lease time reduction.
IPv6 Adoption Coverage — For dual-stack environments, measure the percentage of subnets with corresponding IPv6 prefixes. Track GUA vs ULA adoption rates. Identify IPv4-only sites as migration gaps.
Compile findings into a structured report with health scores, conflict inventory, and actionable remediation.
IPAM Health Scorecard — Aggregate subnet utilization distribution, IPAM-vs-live accuracy, prefix hierarchy integrity, and VLAN mapping completeness into a composite health score.
DNS Audit Findings — Summarize forward/reverse consistency rate, stale record count, CNAME chain issues, and delegation integrity. Group by zone for targeted remediation.
Conflict Inventory — List conflicts ordered by severity: duplicate IPs first (packet loss), overlapping subnets second (routing ambiguity), DNS conflicts third (resolution failures). Include affected hosts and recommended resolution.
Capacity Planning Recommendations — Identify subnets needing expansion within 90 days, recommend oversized subnet reclamation, suggest DHCP scope adjustments, and flag IPv6 migration gaps.
| Metric | Good | Warning | Critical | Notes |
|---|---|---|---|---|
| Subnet utilization | <80% | 80–90% | >90% | Per-prefix allocated/usable ratio |
| DHCP scope free | >20% | 10–20% | <10% | Remaining leases in scope |
| Forward/reverse match | ≥95% | 85–95% | <85% | A records with valid PTR |
| Stale A records | <5% | 5–15% | >15% | A records pointing to inactive IPs |
| IPAM vs ARP accuracy | ≥90% | 80–90% | <80% | IPAM entries confirmed by ARP |
| Duplicate IPs detected | 0 | 1–3 | >3 | Per-VRF duplicate IP count |
| Orphaned PTRs | <5% | 5–15% | >15% | PTR records with no forward match |
| VLAN-subnet mapping | ≥95% | 85–95% | <85% | VLANs with correct subnet association |
| IPv6 dual-stack coverage | ≥80% | 50–80% | <50% | Subnets with IPv6 counterparts |
Audit Scope Selection:
├─ Full enterprise audit?
│ ├─ >1000 subnets? → Scope by site/region, audit iteratively
│ └─ <1000 subnets? → Full-scope audit feasible in single pass
├─ Targeted investigation?
│ ├─ IP conflict report? → Focus on affected VRF/subnet
│ ├─ DNS resolution failures? → Focus on affected zones
│ └─ Capacity planning? → Focus on high-utilization prefixes
└─ Pre-migration audit? → Scope to migrating subnets and DNS zones
IPAM Data Source Selection:
├─ NetBox IPAM module? → Use /api/ipam/ REST endpoints
├─ Infoblox NIOS? → Use WAPI with network_view filtering
├─ BlueCat Address Manager? → Use REST v2 API
├─ Spreadsheet/manual? → Export to structured format first
└─ Multiple IPAM sources? → Reconcile between sources before live comparison
Duplicate IP Response:
├─ ARP table shows conflicting MACs for same IP?
│ ├─ Both MACs belong to known devices? → IP assignment error — reassign one
│ ├─ One MAC unknown? → Potential rogue device — investigate
│ └─ MACs alternating rapidly? → Active conflict — disable one port immediately
├─ IPAM shows same IP assigned to two records?
│ ├─ One record stale? → Archive stale record, confirm active device
│ └─ Both records active? → Investigate which device is using the IP
└─ Different VRFs? → Verify VRF isolation is intact (expected overlap)
Stale DNS Record Disposition:
├─ A record points to IPAM-available IP? → Delete (confirmed decommissioned)
├─ A record points to IP with no ARP activity?
│ ├─ Device exists in IPAM as active? → Verify device is powered on
│ └─ No device record? → Delete after 30-day notification hold
├─ PTR record with no forward match? → Delete (orphaned reverse entry)
└─ CNAME target unresolvable? → Delete or update to valid target
# IPAM/DNS Reconciliation Report
## Executive Summary
- **IPAM source:** [NetBox IPAM / Infoblox / BlueCat / other]
- **Scope:** [VRFs/sites] — [prefix count] prefixes, [zone count] DNS zones
- **Audit date:** [date]
- **Composite IPAM Health Score:** [score]%
## Utilization Summary
| Tier | Prefix Count | Avg Utilization | At Risk |
|------|-------------|-----------------|---------|
| Critical (>90%) | | | Expand immediately |
| Warning (80–90%) | | | Plan expansion |
| Healthy (20–80%) | | | Monitor |
| Oversized (<20%) | | | Reclaim candidate |
## DNS Audit Summary
| Metric | Value | Threshold | Status |
|--------|-------|-----------|--------|
| Forward/reverse consistency | [%] | ≥95% | |
| Stale A records | [count] | <5% | |
| Orphaned PTR records | [count] | <5% | |
| CNAME chain violations | [count] | 0 | |
| Delegation integrity | [pass/fail] | pass | |
## Conflict Inventory
### Critical — Duplicate IP Assignments
| # | IP Address | VRF | MAC 1 | Device 1 | MAC 2 | Device 2 | Action |
|---|-----------|-----|-------|----------|-------|----------|--------|
### High — Overlapping Subnets
| # | Prefix A | Prefix B | VRF | Overlap Range | Action |
|---|----------|----------|-----|---------------|--------|
### Medium — DNS Record Conflicts
| # | Record | Type | Conflict | Action |
|---|--------|------|----------|--------|
## Capacity Planning
| Subnet | Current Util | Growth Rate | Projected Exhaustion | Recommendation |
|--------|-------------|-------------|---------------------|----------------|
## Remediation Priorities
1. [Immediate — Resolve duplicate IP conflicts]
2. [Short-term — Remove stale DNS records]
3. [Medium-term — Expand critical-utilization subnets]
4. [Ongoing — Reclaim oversized subnets for reallocation]
5. [Strategic — Close IPv6 dual-stack gaps]
## Appendix
- IPAM extraction parameters and query details
- DNS audit methodology (zones, servers, tools)
- ARP collection scope and device list
- Subnet math reference for utilization calculations
ARP tables show fewer IPs than expected — ARP entries expire (240s on Cisco, 1200s on Juniper). Collect during peak usage for maximum coverage. Devices communicating only within the same VLAN (L2 adjacent) may not appear in router ARP — check switch MAC tables. Ping sweeps supplement ARP for idle subnets.
DNS zone transfer (AXFR) denied — Many servers restrict AXFR
to authorized secondaries. Fall back to individual lookups for
known hostnames using dig @<auth-server> <name> A. Slower but
avoids AXFR permissions. Check allow-transfer (BIND) or zone
transfer settings (Windows DNS).
DHCP lease data unavailable — If the DHCP server is not
directly accessible, check IPAM platforms that sync DHCP natively
(Infoblox manages DHCP; NetBox requires external sync).
Alternatively, analyze relay statistics:
show ip dhcp relay statistics.
Subnet utilization mismatch between IPAM and ARP — IPAM shows high allocation but ARP shows few active hosts, indicating stale records. Cross-reference against device inventory (source-of-truth-audit skill). Clean stale allocations to restore accurate metrics.
Overlapping subnets not detected — Overlap detection requires VRF-scoped comparison. Multi-VRF environments legitimately overlap (e.g., 10.0.0.0/8 in multiple VRFs). Verify IPAM VRF assignments are correct — wrong VRF produces false alerts or misses real overlaps.
IPv6 utilization always ~0% — IPv6 /64 subnets have 2^64 addresses, making percentage meaningless. Measure by active host count instead. Focus audits on prefix hierarchy (/48 per site, /64 per VLAN) rather than per-subnet exhaustion.
Skills that do similar work, with their headline benchmark lift.
From the same source and nearby in the catalogue.