Agent skill

New Plugin

by apache in apache/skywalking-python

Scaffold a new SkyWalking Python instrumentation plugin with all required files (plugin code, tests, docker-compose, expected data, services)

Apache-2.0Auto-check passedDevOps & Cloud

Install New Plugin

skills CLI
$ npx skills add apache/skywalking-python --skill new-plugin -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install apache/skywalking-python new-plugin --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/apache/skywalking-python.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/new-plugin .claude/skills/new-plugin && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
new-plugin
GitHub stars
219
Token cost
~3.3k tokens
SKILL.md length
524 words
Files
1
Skills in repo
2
Repo updated
First seen
Licence
Apache-2.0

At a glance

Scaffold a new SkyWalking Python instrumentation plugin with all required files (plugin code, tests, docker-compose, expected data, services)

  • Works in 6 steps: Plugin Module: skywalking/plugins/sw_.py → Component Enum: skywalking/init.py → Test Directory:… → …
  • Tasks that involve Containers
  • SKILL.md covers Files to Generate and Post-Generation Reminders
  • Calls make, poetry and pip

What it does

New Plugin is an agent skill from apache/skywalking-python. Scaffold a new SkyWalking Python instrumentation plugin with all required files (plugin code, tests, docker-compose, expected data, services)

Its SKILL.md is about 3.3k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in DevOps & Cloud, covering Containers and Observability. It works with Python, Docker and Apache Kafka. The repository describes itself as: The Python agent for Apache SkyWalking. The licence is Apache-2.0.

When your agent uses it

  • Tasks that involve Containers
  • Tasks that involve Observability

Example prompts

  • “/new-plugin”

Requirements

  • Python 3
  • Docker

Workflow steps

6 steps, taken from the step headings in SKILL.md.

  1. Plugin Module: skywalking/plugins/sw_.py
  2. Component Enum: skywalking/init.py
  3. Test Directory: tests/plugin/{data|http|web}/sw_/
  4. Update pyproject.toml
  5. Regenerate Docs
  6. Lint Check

What it can do on your machine

Read from SKILL.md and the folder at commit 5666826. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • make
    • poetry
    • pip

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    Links to these hosts (documentation or services it may open):

    • github.com

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

New Plugin loads about 3.3k tokens when it runs. Until then it costs about 38 tokens; SKILL.md has 524 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~38
When it runs · the whole SKILL.md, loaded when a task matches
~3.3k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from apache/skywalking-python at commit 5666826, republished under its Apache-2.0 licence (© apache). 524 words, ~3,319 tokens.

Download SKILL.mdSave it as .claude/skills/new-plugin/SKILL.md (or your agent's skills folder).
name
new-plugin
description
Scaffold a new SkyWalking Python instrumentation plugin with all required files (plugin code, tests, docker-compose, expected data, services)
user-invocable
true

New SkyWalking Python Plugin

Generate a complete instrumentation plugin for the SkyWalking Python agent. Ask the user for:

  1. Library name (e.g., httpx, pymemcache, clickhouse-driver)
  2. Plugin type: web framework (Entry spans), HTTP client (Exit spans), database (Exit spans), cache (Exit spans), message queue (Entry+Exit spans), RPC (Entry+Exit spans)
  3. Library versions to test (e.g., ['1.0', '2.0'])
  4. Minimum Python version (default >=3.7)
  5. External service needed for tests? (e.g., Redis, MySQL, Kafka — or none for HTTP client plugins)

If the user provides a library name without details, research the library to determine the appropriate type and instrumentation points.

Files to Generate

1. Plugin Module: skywalking/plugins/sw_<name>.py

Use the Apache 2.0 license header (copy from any existing plugin file).

Follow these patterns based on plugin type:

For HTTP Exit plugins (like sw_requests.py):

python
from skywalking import Layer, Component, config
from skywalking.trace.context import get_context, NoopContext
from skywalking.trace.span import NoopSpan
from skywalking.trace.tags import TagHttpMethod, TagHttpURL, TagHttpStatusCode

link_vector = ['<documentation URL>']
support_matrix = {
    '<pip-package-name>': {
        '>=3.13': ['<major>.*'],  # use .* wildcard for latest patch (e.g., '4.*')
        '>=3.10': ['<older_minor>.*', '<major>.*'],
    }
}
note = """"""

def install():
    from <library> import <Class>
    _original = <Class>.<method>

    def _sw_method(this, *args, **kwargs):
        # Parse URL/peer from args
        span = NoopSpan(NoopContext()) if config.ignore_http_method_check(method) \
            else get_context().new_exit_span(op=path, peer=netloc, component=Component.<Name>)

        with span:
            carrier = span.inject()
            span.layer = Layer.Http
            # Inject carrier into outgoing headers
            for item in carrier:
                headers[item.key] = item.val
            span.tag(TagHttpMethod(method))
            span.tag(TagHttpURL(url))
            res = _original(this, *args, **kwargs)
            span.tag(TagHttpStatusCode(res.status_code))
            if res.status_code >= 400:
                span.error_occurred = True
            return res

    <Class>.<method> = _sw_method

For Web Entry plugins (like sw_flask.py):

python
from skywalking import Layer, Component, config
from skywalking.trace.carrier import Carrier
from skywalking.trace.context import get_context, NoopContext
from skywalking.trace.span import NoopSpan
from skywalking.trace.tags import TagHttpMethod, TagHttpURL, TagHttpStatusCode

def install():
    from <framework> import <App>
    _original = <App>.<handler_method>

    def _sw_handler(this, *args, **kwargs):
        req = <get_request>
        carrier = Carrier()
        for item in carrier:
            if item.key.capitalize() in req.headers:
                item.val = req.headers[item.key.capitalize()]

        span = NoopSpan(NoopContext()) if config.ignore_http_method_check(req.method) \
            else get_context().new_entry_span(op=req.path, carrier=carrier, inherit=Component.General)

        with span:
            span.layer = Layer.Http
            span.component = Component.<Name>
            span.peer = f"{remote_addr}:{remote_port}"
            span.tag(TagHttpMethod(req.method))
            span.tag(TagHttpURL(req.url))
            resp = _original(this, *args, **kwargs)
            span.tag(TagHttpStatusCode(resp.status_code))
            if resp.status_code >= 400:
                span.error_occurred = True
            return resp

    <App>.<handler_method> = _sw_handler

For Database/Cache Exit plugins (like sw_redis.py):

python
from skywalking import Layer, Component
from skywalking.trace.context import get_context
from skywalking.trace.tags import TagDbType, TagDbInstance, TagDbStatement  # or TagCacheType, TagCacheOp, etc.

def install():
    from <library> import <Connection>
    _original = <Connection>.<method>

    def _sw_method(this, *args, **kwargs):
        peer = f'{this.host}:{this.port}'
        with get_context().new_exit_span(op='<DB>/<operation>', peer=peer, component=Component.<Name>) as span:
            span.layer = Layer.Database  # or Layer.Cache
            span.tag(TagDbType('<DB type>'))
            span.tag(TagDbStatement(query))
            res = _original(this, *args, **kwargs)
            return res

    <Connection>.<method> = _sw_method

For MQ plugins (producer Exit + consumer Entry):

  • Producer: new_exit_span, inject carrier into message headers, Layer.MQ
  • Consumer: new_entry_span, extract carrier from message headers, Layer.MQ

For async plugins: Use async def wrappers, await the original call.

For C extension libraries: Use wrapt.ObjectProxy pattern (see sw_psycopg2.py).

2. Component Enum: skywalking/__init__.py

Add a new entry to the Component enum. Check the last Python-specific ID (7000+) and increment. Example:

python
NewLib = 7020  # Next available ID

If the component already exists in the SkyWalking ecosystem (check existing enum), reuse that ID.

3. Test Directory: tests/plugin/{data|http|web}/sw_<name>/

Choose the subdirectory:

  • web/ for web frameworks
  • http/ for HTTP clients
  • data/ for databases, caches, message queues

Create these files:

__init__.py

Empty file with license header.

test_<name>.py
python
from typing import Callable
import pytest
import requests
from skywalking.plugins.sw_<name> import support_matrix
from tests.orchestrator import get_test_vector
from tests.plugin.base import TestPluginBase

@pytest.fixture
def prepare():
    return lambda *_: requests.get('http://0.0.0.0:9090/<endpoint>', timeout=5)

class TestPlugin(TestPluginBase):
    @pytest.mark.parametrize('version', get_test_vector(lib_name='<name>', support_matrix=support_matrix))
    def test_plugin(self, docker_compose, version):
        self.validate()
docker-compose.yml
yaml
version: '2.1'

services:
  collector:
    extends:
      service: collector
      file: ../../docker-compose.base.yml

  # Add external service if needed (database, cache, MQ broker)
  # <service_name>:
  #   image: <image>
  #   ports: [<port>:<port>]
  #   healthcheck: ...
  #   networks: [beyond]

  provider:
    extends:
      service: agent
      file: ../../docker-compose.base.yml
    ports:
      - 9091:9091
    volumes:
      - .:/app
    command: ['bash', '-c', 'pip install flask && pip install -r /app/requirements.txt && sw-python run python3 /app/services/provider.py']
    depends_on:
      collector:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/9091"]
      interval: 5s
      timeout: 60s
      retries: 120
    environment:
      SW_AGENT_NAME: provider
      SW_AGENT_LOGGING_LEVEL: DEBUG

  consumer:
    extends:
      service: agent
      file: ../../docker-compose.base.yml
    ports:
      - 9090:9090
    volumes:
      - .:/app
    command: ['bash', '-c', 'pip install flask && pip install -r /app/requirements.txt && sw-python run python3 /app/services/consumer.py']
    depends_on:
      collector:
        condition: service_healthy
      provider:
        condition: service_healthy
    environment:
      SW_AGENT_NAME: consumer
      SW_AGENT_LOGGING_LEVEL: DEBUG

networks:
  beyond:

Key points:

  • Consumer listens on port 9090, provider on 9091
  • Consumer calls provider to create cross-process trace
  • Use sw-python run python3 to start with agent instrumentation
  • The consumer uses Flask to expose an HTTP endpoint for the test's prepare() fixture to hit
  • The provider uses the target library (e.g., makes a Redis call, DB query)
  • Both install the target library via pip install -r /app/requirements.txt
Show full SKILL.md (205 more words)Show less
services/provider.py

Flask app on port 9091 that uses the target library. Example for a data plugin:

python
if __name__ == '__main__':
    from flask import Flask, jsonify
    app = Flask(__name__)

    @app.route('/endpoint', methods=['POST', 'GET'])
    def handler():
        import <target_library>
        # Make a call using the target library
        # e.g., client = redis.StrictRedis(host='redis'); client.get('key')
        return jsonify({'status': 'ok'})

    app.run(host='0.0.0.0', port=9091)
services/consumer.py

Flask app on port 9090 that calls the provider:

python
import requests

if __name__ == '__main__':
    from flask import Flask, jsonify
    app = Flask(__name__)

    @app.route('/endpoint', methods=['POST', 'GET'])
    def handler():
        res = requests.post('http://provider:9091/endpoint', timeout=5)
        return jsonify(res.json())

    app.run(host='0.0.0.0', port=9090)
services/__init__.py

Empty file with license header.

expected.data.yml

Define expected spans. Structure depends on plugin type:

For a data/cache Exit plugin (consumer -> provider -> external service):

yaml
segmentItems:
  - serviceName: provider
    segmentSize: 1
    segments:
      - segmentId: not null
        spans:
          - operationName: <DB>/<operation>
            parentSpanId: 0
            spanId: 1
            spanLayer: Database  # or Cache
            startTime: gt 0
            endTime: gt 0
            componentId: <ID>
            spanType: Exit
            peer: <service>:<port>
            skipAnalysis: false
            tags:
              - key: db.type
                value: <type>
              - key: db.statement
                value: <query>
          - operationName: /endpoint
            parentSpanId: -1
            spanId: 0
            spanLayer: Http
            startTime: gt 0
            endTime: gt 0
            componentId: 7001
            spanType: Entry
            peer: not null
            skipAnalysis: false
            tags:
              - key: http.method
                value: POST
              - key: http.url
                value: http://provider:9091/endpoint
              - key: http.status_code
                value: '200'
            refs:
              - parentEndpoint: /endpoint
                networkAddress: 'provider:9091'
                refType: CrossProcess
                parentSpanId: 1
                parentTraceSegmentId: not null
                parentServiceInstance: not null
                parentService: consumer
                traceId: not null
  - serviceName: consumer
    segmentSize: 1
    segments:
      - segmentId: not null
        spans:
          - operationName: /endpoint
            parentSpanId: 0
            spanId: 1
            spanLayer: Http
            startTime: gt 0
            endTime: gt 0
            componentId: 7002
            spanType: Exit
            peer: provider:9091
            skipAnalysis: false
            tags:
              - key: http.method
                value: POST
              - key: http.url
                value: http://provider:9091/endpoint
              - key: http.status_code
                value: '200'
          - operationName: /endpoint
            parentSpanId: -1
            spanId: 0
            spanLayer: Http
            startTime: gt 0
            endTime: gt 0
            componentId: 7001
            spanType: Entry
            peer: not null
            skipAnalysis: false
            tags:
              - key: http.method
                value: GET
              - key: http.url
                value: http://0.0.0.0:9090/endpoint
              - key: http.status_code
                value: '200'

Important notes for expected data:

  • Spans within a segment are ordered child-first (highest spanId first)
  • Entry spans have parentSpanId: -1
  • Exit spans reference the entry span as parent
  • Cross-process refs link consumer exit span to provider entry span
  • componentId must match the Component enum value exactly
  • Consumer's exit span uses Requests component (7002) since it calls via requests.post()
  • Consumer's entry span uses Flask component (7001) since it receives via Flask
4. Update pyproject.toml

Add the library to [tool.poetry.group.plugins.dependencies]:

bash
poetry add <library> --group plugins
5. Regenerate Docs
bash
make doc-gen
6. Lint Check
bash
make lint

Post-Generation Reminders

After generating all files, remind the user:

  1. A new component ID may need to be registered in the main SkyWalking repo's component-libraries.yml and a logo added to the UI repo
  2. Run make doc-gen to regenerate Plugins.md
  3. Run make lint to verify code style
  4. Test locally: build the Docker image and run poetry run pytest -v tests/plugin/<category>/sw_<name>/
  5. All files need the Apache 2.0 license header

© apache, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in .claude/skills/new-plugin of apache/skywalking-python.

Open the folder on GitHubat commit 5666826

Compare with similar skills

New Plugin next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

New Plugin compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
New Plugin this skillapache/skywalking-python219—~3.3kAutomated safety check: PassApache-2.0
Minimegasandia-minimega/minimega160—~3.2kAutomated safety check: PassGPL-3.0-only
Unraiddinglebear-ai/unraid135—~5.4kAutomated safety check: NotesMIT
Cosmos3 Env TroubleshootNVIDIA/cosmos-framework556—~1.3kAutomated safety check: NotesCustom licence
Generate Nemo Gym Envadithya-s-k/FineEnvs421—~2.1kAutomated safety check: PassApache-2.0
Liveblog Devliveblog/liveblog118—~1.9kAutomated safety check: PassAGPL-3.0

Similar skills

  • Minimega

    sandia-minimega/minimega

    This skill should be used when the user asks how to configure, run, automate, integrate, or troubleshoot minimega (VMs, namespaces, VLANs, clusters, miniccc, miniweb, command socket or Python API…

    160 GitHub stars~3.2k tokensUpdated yesterday
    DevOps & CloudAuto-check passed
  • Unraid

    dinglebear-ai/unraid

    This skill should be used when the user mentions Unraid, asks to check server health, monitor array or disk status, list or restart Docker containers, start or stop VMs, read system logs, check…

    135 GitHub stars~5.4k tokensUpdated 4 days ago
    DevOps & CloudAuto-check: notes
  • Cosmos3 Env Troubleshoot

    NVIDIA/cosmos-framework

    Official

    Diagnose and fix Cosmos3 environment, installation, and runtime errors.

    556 GitHub stars~1.3k tokensUpdated 11 days ago
    DevOps & CloudAuto-check: notes
  • Generate Nemo Gym Env

    adithya-s-k/FineEnvs

    Builds a NeMo Gym (NVIDIA) variant of an RL environment. An agent skill from adithya-s-k/FineEnvs.

    421 GitHub stars~2.1k tokensUpdated yesterday
    DevOps & CloudAuto-check passed
  • Liveblog Dev

    liveblog/liveblog

    Run a local Liveblog development environment. An agent skill from liveblog/liveblog.

    118 GitHub stars~1.9k tokensUpdated yesterday
    DevOps & CloudAuto-check passed
  • Maintains the DDNS project's GitHub Actions, Docker and Nuitka builds, packaging and release preparation without touching publishing credentials.

    4.7k GitHub stars~444 tokensUpdated yesterday
    DevOps & CloudAuto-check passed

More from apache/skywalking-python

  • Plugin Test

    apache/skywalking-python

    Build Docker test images and run SkyWalking Python plugin/unit/e2e tests locally, mirroring the CI pipeline

    219 GitHub stars~2.3k tokensUpdated 15 days ago
    Auto-check passed

Categories

Questions about New Plugin

What does New Plugin do?

Scaffold a new SkyWalking Python instrumentation plugin with all required files (plugin code, tests, docker-compose, expected data, services). New Plugin is an agent skill from apache/skywalking-python.

When should I use New Plugin?

New Plugin fits situations like: tasks that involve Containers; tasks that involve Observability.

How do I install New Plugin in Claude Code?

Run `npx skills add apache/skywalking-python --skill new-plugin -a claude-code`. Or copy the skill folder (.claude/skills/new-plugin in apache/skywalking-python) into .claude/skills/new-plugin in your project. Claude Code loads it when a task matches its description.

How do I install New Plugin in Codex?

Run `npx skills add apache/skywalking-python --skill new-plugin -a codex`. Or copy the skill folder (.claude/skills/new-plugin in apache/skywalking-python) into .agents/skills/new-plugin in your project. Codex loads it when a task matches its description.

Can I use New Plugin in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add apache/skywalking-python --skill new-plugin -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/new-plugin, .gemini/skills/new-plugin, .github/skills/new-plugin and .opencode/skills/new-plugin in your project.

What does New Plugin need to run?

Going by SKILL.md and its folder, New Plugin needs the command-line tools its instructions call (make, poetry and pip). Our summary lists: Python 3; Docker.

Does New Plugin access the network?

SKILL.md names 1 domain. As links in the text: github.com. This is read from the text; nothing was executed.

Is New Plugin safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does New Plugin use?

New Plugin is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does New Plugin use?

About 3.3k tokens (SKILL.md is roughly 13k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to New Plugin?

Skills that share tags, products or a category with New Plugin: Minimega (sandia-minimega/minimega, 160 stars), Unraid (dinglebear-ai/unraid, 135 stars), Cosmos3 Env Troubleshoot (NVIDIA/cosmos-framework, 556 stars) and Generate Nemo Gym Env (adithya-s-k/FineEnvs, 421 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains New Plugin?

apache (a GitHub organization) maintains it in apache/skywalking-python, which has 219 GitHub stars. The repository holds 2 skills in this directory. The repository was last updated on September 22, 2026.

Source: apache/skywalking-python on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.