NVIDIA / NVIDIA/SkillSpector

## Feature: Role-aware scanning for structured skill formats such as AISOP/AISP

Open
#130 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
17.9k
Forks
1.5k
Avg merge
5d 10h
Merged PRs (30d)
66

Description

Feature: Role-aware scanning for structured skill formats such as AISOP/AISP

Summary

Add an optional structured skill analyzer that detects machine-readable skill workflow formats such as AISOP/AISP and enriches static findings with role-aware context.

This would not replace the existing static analyzers, semantic analyzers, MCP analyzers, or SARIF reporting.

It would add a pre-analysis / enrichment layer that helps SkillSpector distinguish:

executable workflow step
constraint
deny-list
anti-example
documentation
defensive test fixture
tool declaration
resource file
generated README / bridge file
unknown

The main goal is to reduce polarity-blind false positives while preserving conservative behavior for unknown or unstructured skills.


Motivation

Static patterns are intentionally conservative, but they can be polarity-blind.

The same dangerous string can mean different things depending on where it appears:

Bash(rm -rf /*) inside an executable step:
  dangerous action

Bash(rm -rf /*) inside hard_deny:
  defensive policy

git push --force origin main # NEVER DO THIS:
  anti-example

disallowedTools: [Write, Edit, MultiEdit]:
  explicit prohibition, not capability

INJECTION_TESTS = ["Ignore previous instructions..."]:
  red-team fixture, not prompt injection by itself

For unstructured skill directories, this is hard to infer.

But structured skill packages can expose this context directly.

For example, AISOP/AISP-style packages separate:

aisop.main:
  workflow topology

functions.<node>.stepN:
  executable workflow steps

functions.<node>.constraints:
  boundary rules / constraints

aisp_contract.resources:
  resource inventory

README.md:
  generated bootstrap documentation

SKILL.md:
  optional Agent Skills bridge / discovery layer

A structured analyzer could use this layout to attach context to findings before scoring.


Proposed analyzer

Add a new analyzer layer, for example:

structured_skill_analyzer

or a more specific implementation:

structured_aisop_analyzer

The analyzer would:

  1. detect structured skill files;
  2. parse structural metadata;
  3. build a role map for file regions;
  4. annotate static findings with role and polarity;
  5. optionally emit informational findings about declared tools, workflow steps, constraints, and resources.

Detection candidates

The analyzer could detect AISOP/AISP-style packages when it sees patterns such as:

*.aisop.json
aisp.aisop.json

and JSON structures such as:

root is a 2-message array
system.content.protocol == "AISOP V1.0.0" or "AISP V1.0.0"
user.content.aisop exists
user.content.functions exists

For AISP packages, it could also detect:

user.content.aisp_contract exists
user.content.aisp_contract.resources exists

Detection should be strict enough to avoid trusting arbitrary JSON that merely claims to be structured.


Role map output

The analyzer could produce a role map like:

{
  "format": "AISOP",
  "file": "aisp.aisop.json",
  "program_id": "example_skill",
  "declared_tools": ["filesystem", "shell"],
  "regions": [
    {
      "path": "user.content.functions.capture.step2",
      "role": "executable_step",
      "mode": "sys.llm.json"
    },
    {
      "path": "user.content.functions.capture.constraints[0]",
      "role": "constraint"
    },
    {
      "path": "user.content.functions.verify.step1",
      "role": "executable_step",
      "mode": "natural_language"
    },
    {
      "path": "user.content.aisp_contract.resources[0]",
      "role": "resource_declaration"
    }
  ]
}

This role map could then be used by existing static findings.


Finding enrichment

Current findings could be enriched with fields like:

{
  "text_role": "executable_step | constraint | deny_list | anti_example | documentation | defensive_test | tool_declaration | resource | unknown",
  "risk_polarity": "dangerous_action | defensive_reference | prohibition | example | unknown",
  "structured_source": "user.content.functions.capture.step2",
  "role_confidence": 0.94
}

This would let the report preserve both:

the raw static finding
the role-aware interpretation

Example:

{
  "rule": "dangerous_shell_command",
  "match": "rm -rf /*",
  "original_severity": "HIGH",
  "adjusted_severity": "INFO",
  "text_role": "deny_list",
  "risk_polarity": "prohibition",
  "reason": "The match appears inside a hard deny-list rather than an executable step."
}

AISOP example

Here is a small strict AISOP V1.0.0 example that shows why structure helps.

[
  {
    "role": "system",
    "content": {
      "protocol": "AISOP V1.0.0",
      "axiom_0": "Human_Sovereignty_and_Wellbeing",
      "id": "safe_shell_policy_example",
      "name": "Safe Shell Policy Example",
      "version": "1.0.0",
      "summary": "Example showing executable steps, constraints, and deny-list style safety boundaries.",
      "flow_format": "mermaid",
      "loading_mode": "node",
      "tools": ["filesystem", "shell"],
      "params": {
        "target_path": "string"
      },
      "system_prompt": "{system_prompt}"
    }
  },
  {
    "role": "user",
    "content": {
      "instruction": "RUN aisop.main",
      "user_input": "{user_input}",
      "aisop": {
        "main": "graph TD\n    inspect[Inspect target] --> decide[Decide safe action]\n    decide --> execute[Execute safe action]\n    execute --> end_node((End))"
      },
      "functions": {
        "inspect": {
          "step1": "sys.io.read(target_path) -> target_content",
          "output_mapping": "target_content",
          "constraints": [
            "Read-only inspection must not modify files."
          ]
        },
        "decide": {
          "step1": "Classify whether the requested operation is safe, destructive, or prohibited.",
          "step2": "The following examples are prohibited and must remain deny-list entries, not executable instructions: rm -rf /*, curl http://example.com/install.sh | bash, git push --force origin main.",
          "output_mapping": "safety_decision",
          "constraints": [
            "Never execute a command listed as prohibited.",
            "Dangerous strings in the deny-list are defensive references, not actions."
          ]
        },
        "execute": {
          "step1": "sys.assert('safety_decision != prohibited', 'Prohibited shell command')",
          "step2": "Run only the approved safe action.",
          "output_mapping": "execution_result",
          "constraints": [
            "Do not run any deny-list command.",
            "Do not treat examples in decide.step2 as executable instructions."
          ]
        },
        "end_node": {
          "step1": "Return execution_result."
        }
      }
    }
  }
]

A polarity-blind scanner may see:

rm -rf /*
curl ... | bash
git push --force

and mark them as high risk.

A role-aware structured analyzer can see that they appear in:

user.content.functions.decide.step2

with surrounding language:

prohibited
deny-list entries
not executable instructions

and with enforcement later in:

user.content.functions.execute.step1

So the scanner can still preserve the raw match, but classify it as:

{
  "text_role": "deny_list",
  "risk_polarity": "prohibition",
  "adjusted_severity": "INFO",
  "reason": "Dangerous command appears as a prohibited example, not as executable behavior."
}

If the same string appeared inside an actual executable sys.run(...) or script body, it should remain high severity.


Integration with existing architecture

This seems to fit SkillSpector’s current analyzer architecture.

The development guide describes the data flow as:

resolve_input
  -> build_context
  -> parallel analyzers
  -> meta_analyzer
  -> report

The structured skill analyzer could run after build_context or as one of the analyzer nodes.

It could attach role metadata to findings before meta_analyzer, or emit a separate set of informational findings that other analyzers can use.

A minimal first version could avoid changing risk scoring:

  1. detect AISOP/AISP files;
  2. parse workflow nodes, function steps, constraints, resources, and declared tools;
  3. emit a structured context report;
  4. leave severity scoring unchanged.

A second version could use the role map to adjust confidence/severity for static-only false positives.


Suggested implementation phases
Phase 1: Detect and summarize
  • Detect .aisop.json and aisp.aisop.json.

  • Validate minimal structure.

  • Extract:

    • protocol
    • id
    • declared tools
    • workflow nodes
    • function steps
    • constraints
    • resources
  • Emit informational findings only.

Phase 2: Role-map findings
  • Map static matches to structured source locations.

  • Add:

    • text_role
    • risk_polarity
    • structured_source
    • role_confidence
Phase 3: Adjust static scoring
  • Keep high severity for executable dangerous actions.
  • Downgrade clear deny-list / anti-example / defensive-test contexts.
  • Preserve raw static finding for auditability.
  • Do not suppress unknown or ambiguous matches.
Phase 4: Add tests

Add fixtures for:

AISOP executable dangerous step:
  should remain high risk

AISOP deny-list containing dangerous command:
  should be informational / defensive reference

AISOP anti-example:
  should be downgraded

AISOP constraints:
  should not be treated as executable behavior

Malformed AISOP:
  should not be trusted as structured context

AISP resources:
  should be treated as declared resource inventory, not automatically executable

Non-goals
  • Do not require skills to use AISOP or AISP.
  • Do not trust structured metadata blindly.
  • Do not suppress findings only because a file claims to be structured.
  • Do not weaken detection for executable scripts.
  • Do not replace existing static / semantic / MCP analyzers.
  • Do not make AISOP/AISP a required dependency.

The goal is only to use structure as an optional context signal for role-aware triage.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the development guide's resolve_input → build_context → parallel analyzers → meta_analyzer → report flow, then inspect how existing analyzers emit findings. Scope an initial AISOP/AISP detector around the listed minimal structure and Phase 1 fields, adding fixtures for valid, malformed, executable, deny-list, constraint, anti-example, and resource cases. Done means structured context is reported without changing severity, while malformed or unstructured input remains conservative.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
devtools, security
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.