K6 logo

K6

Organization
grafana
k6

Generate, validate, and review k6 test scripts — load, stress, spike, soak, smoke, breakpoint, functional, and protocol. Covers HTTP, WebSocket, gRPC, browser, all executors, thresholds, checks, custom metrics, the k6-testing library, k6 Cloud execution, and the xk6 extension ecosystem; uses the xk6-docs CLI (with grafana.com web fallback) for docs lookup and validates every script by running it. Use when writing, generating, validating, or debugging any k6 or load-test script (including plain-language asks like "load test this API" or "stress test my service"), choosing executors/scenarios, or setting thresholds. For end-to-end website performance suites use k6-perf-test-website; for documenting k6 itself use k6-docs; for a browser/UI test authored from a plain-language user journey (selectors discovered by exploring the live site) use k6-browser-test.

Overview

Publishergrafana
Repositoryskills
Skill namek6
Stars
289
Forks
27
Bundled files
21
LicenseApache-2.0
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • 21 bundled files

    Scripts, templates, and references the model can read while it works. Files are read-only and never executed.

  • Open source

    Published by grafana on GitHub. Read the source before you install it.

Installation

Install the K6 AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
    https://github.com/grafana/skills/tree/main/skills/grafana-k6/k6
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/grafana/skills.git /tmp/skills
mkdir -p .claude/skills
cp -r /tmp/skills/skills/grafana-k6/k6 .claude/skills/k6
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable K6 in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads K6 on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so K6 is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

k6 Script Generation

Efficiency note: This is a short linear recipe (read example → adapt → save → validate → review). A todo list would just mirror the headings without adding value, so skip the planning overhead and execute the steps directly.

Agent-agnostic: The steps below describe capabilities, not specific tools. Where a step says "fetch a URL" or "write a file", use whatever your agent provides for that capability (e.g. a web-fetch tool, a file-write tool, or shell curl/tee).


Step 1: Pick the right example file

Read only the file that matches the user's request. Examples provide structural scaffolding — the correct scaffold, option shapes, and import patterns.

User needsRead this file
HTTP REST, auth flow, batch requestsexamples/http.js
HTML parsing with parseHTML, SharedArrayexamples/html.js
WebSocketexamples/websocket.js
gRPCexamples/grpc.js
Browser automationexamples/browser.js
Browser + functional test / expect() / k6-testingexamples/functional.js (browser scenario)
Functional/integration tests, expect(), k6-testingexamples/functional.js
Custom metrics, execution module, handleSummary, per-vu-iterationsexamples/metrics.js
Load patterns, all executors (ramping, arrival rate, per-VU, etc.)examples/executors.js
Cloud run, --local-execution, cloud optionsexamples/cloud.js
Crypto (HMAC, MD5, SHA256) or encoding (base64)examples/crypto-encoding.js
xk6-fakerexamples/ext-faker.js
xk6-redisexamples/ext-redis.js
xk6-sql / sqlite3 / postgresexamples/ext-sql.js
xk6-execexamples/ext-exec.js
xk6-dnsexamples/ext-dns.js
xk6-tlsexamples/ext-tls.js
xk6-tcpexamples/ext-tcp.js
xk6-crawlerexamples/ext-crawler.js

Example files live in the examples/ directory alongside this SKILL.md.

When the request matches multiple rows (e.g. "browser" + "functional test"), prefer the row whose assertion style fits the intent. If the user says "functional test", "assert", "verify", or "expect", use functional.js even if the test involves a browser — it demonstrates expect() with auto-retrying browser matchers. Use browser.js for browser load/performance tests that don't emphasize correctness assertions.

Browser test from a plain-language journey? If the user describes a browser flow in prose and the selectors aren't known yet — i.e. they must be discovered by driving the live site — defer to the k6-browser-test skill, which explores the live page to resolve real getBy* locators before writing the test. Use the browser rows above when the page structure and selectors are already known.


Step 2: Adapt the example

Use the loaded example as the starting point. Adapt it to the user's exact requirements:

  • Change endpoints, VU counts, durations, thresholds
  • Add or remove scenario steps
  • Rename functions and variables to match the domain
  • Every expression must be complete and runnable — no { ... }, // TODO, or stubs
  • Match the request — don't over-build. Implement exactly what was asked. Don't add custom request tags, extra sleep() calls, additional endpoints, or options the user didn't request. Unrequested complexity lowers quality and reduces adherence to the spec.

For multi-scenario scripts (browser + HTTP, cloud): use named scenarios with exec pointing to separate exported functions.


Step 3: Fill gaps with docs (only if needed)

The example covers common patterns. Adapt from it directly. Skip this step entirely if the example provides everything you need.

Only reach for docs if:

  • The user asks for an API or option not demonstrated in the example, or
  • You are not confident about the exact signature, option name, or return type

When a gap exists, first establish the docs command (one-time per session).

The k6 x docs CLI renders content only when it detects a TTY. Since agents run non-interactively, wrap every call with script to allocate a pseudo-TTY and pipe the ANSI-stripped content to stdout:

bash
# Detect OS once (macOS vs Linux have different `script` flags):
if [[ "$(uname -s)" == "Darwin" ]]; then
  DOCS_CMD="script -q /dev/null k6 x docs"
else
  DOCS_CMD="script -qc 'k6 x docs' /dev/null"
fi

# Verify it works — should print a topic list, NOT a "browse files" guide:
$DOCS_CMD 2>/dev/null | head -5

If the output still shows "k6 documentation is a directory of markdown files", the TTY wrapper isn't working. Fall back to web docs under https://grafana.com/docs/k6/latest/ — fetch pages with whatever web-fetch capability your agent has (a built-in fetch tool, or curl in a shell).

If k6 x docs fails outright (command not found, provisioning or 404 errors), read SETUP.md — it covers auto-provisioning on k6 v1.7.0+ and the manual xk6 build for older versions.

Then look up what you need:

bash
$DOCS_CMD <path>              # e.g. javascript-api k6-http
$DOCS_CMD <path> --depth 2
$DOCS_CMD search <term>

Common CLI paths and the 2-call strategy are in docs-guidance.md.

Do not use unpkg, @types/k6, or any npm type definition URLs.


Step 4: Save

Line 1 of every script must be a generated-by comment. Get the current UTC timestamp first (the file content depends on it, so this can't be parallelized with the write):

bash
date -u +%Y-%m-%dT%H:%M:%SZ

Then include it as line 1:

javascript
// Generated by grafana-k6 on 2026-03-25T22:02:20.203Z

Save to k6/scripts/<descriptive-name>.js. Use lowercase kebab-case filenames. If your file-write capability doesn't create parent directories automatically, mkdir -p k6/scripts first.

The script file on disk is the deliverable — always write it. Never end the task with the script shown only in chat: Steps 5–7 (validate, review, present) all require the file to exist at k6/scripts/<name>.js. If a write fails, retry it before continuing.


Step 5: Validate

Match top-down — the first matching row wins:

Script typeCommand
Imports k6/browserk6 run k6/scripts/<name>.js
Any ramping-vus or *-arrival-rate scenariok6 inspect k6/scripts/<name>.js — a full run would execute the entire load profile against the target
Other named executor: blocks (short scenarios)k6 run k6/scripts/<name>.js
Everything else (HTTP, WS, gRPC)k6 run --vus 1 --iterations 1 k6/scripts/<name>.js

What counts as passing: for functional and browser scripts, validation passes only when the exit code is 0 and the summary shows no failed checks or expect() errors — a script that completes with failing assertions is not validated. k6's error output names the exact locator or assertion that failed (and what it waited for); use it to fix the selector or logic. For load tests, exit code 0 is a pass, and a pure threshold breach under load (exit code 99) is acceptable.

If validation fails: read stderr, fix the root cause, retry up to 3 attempts. After 3 failures, present the error and ask the user how to proceed (or, when running unattended, deliver the best attempt and clearly report the unresolved error).


Step 6: Best-practices review

General checks (all scripts)

Review the script against the rules below. The checklist is authoritative — only look up docs ($DOCS_CMD best-practices or https://grafana.com/docs/k6/latest/using-k6/) if you're uncertain about a specific rule.

  • export const options with realistic VUs/duration. Default VUs/durations make the test meaningful out of the box.
  • Define thresholds for every load test. Without thresholds the run can't fail in CI even when performance regresses, which defeats the point of running a load test. At minimum include http_req_duration and http_req_failed (or the protocol equivalent). Pure functional tests — single-iteration expect()-only scripts — can skip this.
  • Include sleep() in closed-model (VU-based) load tests. sleep() represents user think time; without it, VUs hammer endpoints faster than any real user would, inflating throughput and crowding out the system under test. This applies to VU-based HTTP, WebSocket, gRPC, crypto, and extension scripts. Open-model executors (constant-arrival-rate, ramping-arrival-rate) already pace iterations to a target rate, so sleep() there is usually unnecessary — it only ties up VUs without changing the offered load. Browser scripts use page.waitForTimeout() instead; single-iteration functional tests and one-shot connectivity/demo scripts can skip it. In event-driven WebSocket scripts, put the sleep() inside the close handler (see examples/websocket.js) — sleeping in the main function body blocks the event loop before any messages arrive.
  • Assert every response. Browser scripts: use expect() from k6-testing — it auto-retries against locators and replaces waitFor() + isVisible() + check() chains. If you need a metric-tracked check() inside an async browser function, the standard check from k6 works fine as long as the predicate is synchronous — await the value first, then check it. Only reach for the k6-utils wrapper (https://jslib.k6.io/k6-utils/1.5.0/index.js) when the predicate itself must await something: a bare async predicate returns a Promise, which is always truthy, so the check silently passes. HTTP/gRPC/WS scripts: use check() for metric-tracked assertions, or expect() for functional tests. Silent failures are worse than loud ones.
  • Browser scripts: wrap interactions in try/finally with page.close() in finally, so pages clean up even when assertions throw.
  • gRPC scripts: wrap the iteration's calls in try/finally and call client.close() in the finally block, so the connection is released even when a check throws mid-iteration.
  • WebSocket scripts: wrap JSON.parse of incoming messages in try/catch — servers can send non-JSON frames, and one bad frame shouldn't kill the VU.
  • No let/var at top level — use const, since module-scope state is shared across VUs and mutability there is almost always a bug.
  • No deprecated imports — use k6/websockets for WebSockets; both k6/ws and k6/experimental/websockets are deprecated.

Load & breakpoint tests

  • Breakpoint tests: ramp offered load, not VUs. Use an open-model executor (ramping-arrival-rate) so the request rate is independent of how slow the system gets; a closed model (ramping-vus) throttles itself as latency rises and masks the breaking point. Pair thresholds with abortOnFail: true and a short delayAbortEval so the run stops (and reports) once an SLO is crossed.
  • Track SLO-relevant custom metrics for reporting: per-endpoint latency (Trend), an error Rate, and any domain counters — plus a handleSummary that surfaces p95/p99, throughput (req/s), and error rate. See examples/executors.js and examples/metrics.js.
  • Hybrid protocol + browser load tests: wrap the browser flow in try/catch and record failures to a custom error metric instead of letting an expect() throw — a single flaky browser iteration must not abort a long protocol load run.

Browser scripts — recommended practices

If the script imports k6/browser, read browser-best-practices.md and apply all checks. Fix issues and re-validate.


Step 7: Present results

  1. Full script with file path
  2. Validation output
  3. Best-practices notes (issues found, or "all checks passed")
  4. Suggested run command
bash
k6 run --vus 10 --duration 30s k6/scripts/api-load-test.js
k6 run k6/scripts/browser-test.js
k6 cloud run k6/scripts/cloud-test.js
k6 cloud run --local-execution k6/scripts/hybrid-test.js
./k6-with-faker run k6/scripts/faker-test.js
K6_BROWSER_HEADLESS=true k6 run k6/scripts/browser-test.js

Step 8: Execute

If the user confirms, run the command.

Bundled files

The model reads these on demand while the skill is loaded. They are exposed as readable files and are never executed.

Frequently asked questions

What does the K6 AI skill do?

Generate, validate, and review k6 test scripts — load, stress, spike, soak, smoke, breakpoint, functional, and protocol. Covers HTTP, WebSocket, gRPC, browser, all executors, thresholds, checks, custom metrics, the k6-testing library, k6 Cloud execution, and the xk6 extension ecosystem; uses the xk6-docs CLI (with grafana.com web fallback) for docs lookup and validates every script by running it. Use when writing, generating, validating, or debugging any k6 or load-test script (including plain-language asks like "load test this API" or "stress test my service"), choosing executors/scenarios...

Why use K6 on TypingMind?

Because you install it once and use it with any model. K6 is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install K6 in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/grafana/skills/tree/main/skills/grafana-k6/k6. TypingMind reads its SKILL.md and bundles its files and installs it as a skill you can enable per chat.

Which AI models can use K6?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with K6?

As many as you like. As long as a model supports skills, you can use K6 with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the K6 AI skill free?

Yes. It is published on GitHub by grafana under the Apache-2.0 license. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇