Writing Livekit Scenarios
livekit-examples/agent-starter-python
Creates and maintains the scenarios a LiveKit agent simulation runs, and wires the agent to consume them.
Performance and load testing skill using k6, covering load test scripts, thresholds, scenarios, checks, custom metrics, and results analysis.
$ npx skills add PramodDutta/qaskills --skill k6-performance -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install PramodDutta/qaskills k6-performance --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/PramodDutta/qaskills.git skills-src && mkdir -p .claude/skills && cp -r skills-src/packs/qa-essentials/skills/k6-performance .claude/skills/k6-performance && rm -rf skills-srcUse ~/.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/
Install the "k6-performance" agent skill from https://github.com/PramodDutta/qaskills/tree/main/packs/qa-essentials/skills/k6-performance into .claude/skills/k6-performance/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "k6-performance", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/PramodDutta/qaskills/tree/main/packs/qa-essentials/skills/k6-performanceType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add PramodDutta/qaskills --skill k6-performance -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install PramodDutta/qaskills k6-performance --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/PramodDutta/qaskills.git skills-src && mkdir -p .agents/skills && cp -r skills-src/packs/qa-essentials/skills/k6-performance .agents/skills/k6-performance && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "k6-performance" agent skill from https://github.com/PramodDutta/qaskills/tree/main/packs/qa-essentials/skills/k6-performance into .agents/skills/k6-performance/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "k6-performance", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add PramodDutta/qaskills --skill k6-performance -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install PramodDutta/qaskills k6-performance --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/PramodDutta/qaskills.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/packs/qa-essentials/skills/k6-performance .cursor/skills/k6-performance && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "k6-performance" agent skill from https://github.com/PramodDutta/qaskills/tree/main/packs/qa-essentials/skills/k6-performance into .cursor/skills/k6-performance/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "k6-performance", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/PramodDutta/qaskills.git --path packs/qa-essentials/skills/k6-performance--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add PramodDutta/qaskills --skill k6-performance -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install PramodDutta/qaskills k6-performance --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/PramodDutta/qaskills.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/packs/qa-essentials/skills/k6-performance .gemini/skills/k6-performance && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "k6-performance" agent skill from https://github.com/PramodDutta/qaskills/tree/main/packs/qa-essentials/skills/k6-performance into .gemini/skills/k6-performance/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "k6-performance", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install PramodDutta/qaskills k6-performanceInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add PramodDutta/qaskills --skill k6-performance -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/PramodDutta/qaskills.git skills-src && mkdir -p .github/skills && cp -r skills-src/packs/qa-essentials/skills/k6-performance .github/skills/k6-performance && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "k6-performance" agent skill from https://github.com/PramodDutta/qaskills/tree/main/packs/qa-essentials/skills/k6-performance into .github/skills/k6-performance/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "k6-performance", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add PramodDutta/qaskills --skill k6-performance -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install PramodDutta/qaskills k6-performance --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/PramodDutta/qaskills.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/packs/qa-essentials/skills/k6-performance .opencode/skills/k6-performance && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "k6-performance" agent skill from https://github.com/PramodDutta/qaskills/tree/main/packs/qa-essentials/skills/k6-performance into .opencode/skills/k6-performance/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "k6-performance", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
k6-performancePerformance and load testing skill using k6, covering load test scripts, thresholds, scenarios, checks, custom metrics, and results analysis.
K6 Performance is an agent skill from PramodDutta/qaskills. Performance and load testing skill using k6, covering load test scripts, thresholds, scenarios, checks, custom metrics, and results analysis.
Its SKILL.md is about 3.2k 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 Testing & QA, covering Load testing. The repository describes itself as: QA Skills Directory QA Skills is a curated directory of testing-specific skills for AI coding agents (Claude Code, Cursor, Copilot, etc.). The licence is MIT.
5 steps, taken from the first numbered list in SKILL.md.
Read from SKILL.md and the folder at commit 1d2a092. It shows what the files ask for, not the result of running them.
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.
No scripts in the folder and no shell commands in SKILL.md (its code samples are javascript and bash).
From the folder's file list and the shell code blocks in SKILL.md.
Hosts in commands or code, which the agent is likely to contact:
jslib.k6.ioFrom URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
K6 Performance loads about 3.2k tokens when it runs. Until then it costs about 39 tokens; SKILL.md has 458 words of instructions outside code blocks.
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.
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.
The full file from PramodDutta/qaskills at commit 1d2a092, republished under its MIT licence (© PramodDutta). 458 words, ~3,246 tokens.
.claude/skills/k6-performance/SKILL.md (or your agent's skills folder).You are an expert performance engineer specializing in k6 load testing. When the user asks you to write, review, or debug k6 performance tests, follow these detailed instructions.
k6/
scripts/
smoke-test.js
load-test.js
stress-test.js
spike-test.js
soak-test.js
scenarios/
api-scenarios.js
user-flows.js
utils/
helpers.js
auth.js
data-generators.js
data/
users.csv
payloads.json
thresholds/
default-thresholds.js
config/
environments.js
results/
.gitkeepimport http from 'k6/http';
import { check, sleep, group } from 'k6';
import { Rate, Trend, Counter } from 'k6/metrics';
// Custom metrics
const errorRate = new Rate('errors');
const loginDuration = new Trend('login_duration');
const requestCount = new Counter('total_requests');
export const options = {
stages: [
{ duration: '2m', target: 10 }, // Ramp up to 10 users
{ duration: '5m', target: 10 }, // Stay at 10 users
{ duration: '2m', target: 50 }, // Ramp up to 50 users
{ duration: '5m', target: 50 }, // Stay at 50 users
{ duration: '2m', target: 0 }, // Ramp down
],
thresholds: {
http_req_duration: ['p(95)<500', 'p(99)<1000'], // 95th percentile < 500ms
http_req_failed: ['rate<0.01'], // Error rate < 1%
errors: ['rate<0.05'], // Custom error rate < 5%
login_duration: ['p(95)<800'], // Login 95th < 800ms
},
};
const BASE_URL = __ENV.BASE_URL || 'http://localhost:3000';
export default function () {
group('Homepage', () => {
const response = http.get(`${BASE_URL}/`);
check(response, {
'homepage status is 200': (r) => r.status === 200,
'homepage loads in < 2s': (r) => r.timings.duration < 2000,
'homepage has correct title': (r) => r.body.includes('<title>'),
});
errorRate.add(response.status !== 200);
requestCount.add(1);
});
sleep(1);
group('Login', () => {
const startTime = Date.now();
const loginResponse = http.post(`${BASE_URL}/api/auth/login`, JSON.stringify({
email: 'user@example.com',
password: 'SecurePass123!',
}), {
headers: { 'Content-Type': 'application/json' },
});
loginDuration.add(Date.now() - startTime);
check(loginResponse, {
'login status is 200': (r) => r.status === 200,
'login returns token': (r) => JSON.parse(r.body).token !== undefined,
});
errorRate.add(loginResponse.status !== 200);
requestCount.add(1);
});
sleep(Math.random() * 3 + 1); // Random think time between 1-4 seconds
}export const options = {
vus: 1,
duration: '1m',
thresholds: {
http_req_duration: ['p(99)<1500'],
http_req_failed: ['rate<0.01'],
},
};
// Quick validation that the system works under minimal load
export default function () {
const response = http.get(`${BASE_URL}/api/health`);
check(response, {
'status is 200': (r) => r.status === 200,
});
sleep(1);
}export const options = {
stages: [
{ duration: '5m', target: 100 }, // Ramp up
{ duration: '10m', target: 100 }, // Steady state
{ duration: '5m', target: 0 }, // Ramp down
],
thresholds: {
http_req_duration: ['p(95)<500'],
http_req_failed: ['rate<0.01'],
},
};export const options = {
stages: [
{ duration: '2m', target: 100 },
{ duration: '5m', target: 100 },
{ duration: '2m', target: 200 },
{ duration: '5m', target: 200 },
{ duration: '2m', target: 300 },
{ duration: '5m', target: 300 },
{ duration: '2m', target: 400 },
{ duration: '5m', target: 400 },
{ duration: '10m', target: 0 },
],
thresholds: {
http_req_duration: ['p(95)<1000'],
http_req_failed: ['rate<0.05'],
},
};export const options = {
stages: [
{ duration: '1m', target: 10 }, // Normal load
{ duration: '10s', target: 500 }, // Spike!
{ duration: '3m', target: 500 }, // Stay at spike
{ duration: '10s', target: 10 }, // Recovery
{ duration: '3m', target: 10 }, // Observe recovery
{ duration: '1m', target: 0 }, // Ramp down
],
};export const options = {
stages: [
{ duration: '5m', target: 50 }, // Ramp up
{ duration: '4h', target: 50 }, // Sustained load for 4 hours
{ duration: '5m', target: 0 }, // Ramp down
],
thresholds: {
http_req_duration: ['p(95)<500'],
http_req_failed: ['rate<0.01'],
},
};export const options = {
scenarios: {
browse_products: {
executor: 'ramping-vus',
startVUs: 0,
stages: [
{ duration: '2m', target: 50 },
{ duration: '5m', target: 50 },
{ duration: '2m', target: 0 },
],
gracefulRampDown: '30s',
exec: 'browseProducts',
},
checkout_flow: {
executor: 'constant-arrival-rate',
rate: 10, // 10 iterations per timeUnit
timeUnit: '1s',
duration: '5m',
preAllocatedVUs: 20,
maxVUs: 50,
exec: 'checkoutFlow',
},
api_health_check: {
executor: 'constant-vus',
vus: 5,
duration: '10m',
exec: 'healthCheck',
},
},
thresholds: {
'http_req_duration{scenario:browse_products}': ['p(95)<300'],
'http_req_duration{scenario:checkout_flow}': ['p(95)<800'],
'http_req_duration{scenario:api_health_check}': ['p(95)<100'],
},
};
export function browseProducts() {
http.get(`${BASE_URL}/api/products`);
sleep(2);
}
export function checkoutFlow() {
// Full checkout flow
const cart = http.post(`${BASE_URL}/api/cart`, JSON.stringify({
productId: 'prod-001',
quantity: 1,
}), { headers: { 'Content-Type': 'application/json' } });
check(cart, { 'cart created': (r) => r.status === 201 });
const checkout = http.post(`${BASE_URL}/api/checkout`, JSON.stringify({
cartId: JSON.parse(cart.body).id,
}), { headers: { 'Content-Type': 'application/json' } });
check(checkout, { 'checkout success': (r) => r.status === 200 });
sleep(1);
}
export function healthCheck() {
http.get(`${BASE_URL}/api/health`);
sleep(1);
}import http from 'k6/http';
import { check } from 'k6';
// Setup function runs once before the test
export function setup() {
const loginResponse = http.post(`${BASE_URL}/api/auth/login`, JSON.stringify({
email: 'load-test@example.com',
password: 'SecurePass123!',
}), {
headers: { 'Content-Type': 'application/json' },
});
const body = JSON.parse(loginResponse.body);
return { token: body.token };
}
export default function (data) {
const params = {
headers: {
Authorization: `Bearer ${data.token}`,
'Content-Type': 'application/json',
},
};
const response = http.get(`${BASE_URL}/api/users/me`, params);
check(response, {
'authenticated request succeeds': (r) => r.status === 200,
});
}import { SharedArray } from 'k6/data';
import papaparse from 'https://jslib.k6.io/papaparse/5.1.1/index.js';
import { open } from 'k6';
const csvData = new SharedArray('users', function () {
return papaparse.parse(open('./data/users.csv'), { header: true }).data;
});
export default function () {
const user = csvData[Math.floor(Math.random() * csvData.length)];
const response = http.post(`${BASE_URL}/api/auth/login`, JSON.stringify({
email: user.email,
password: user.password,
}), {
headers: { 'Content-Type': 'application/json' },
});
check(response, {
'login successful': (r) => r.status === 200,
});
}import { SharedArray } from 'k6/data';
import { open } from 'k6';
const products = new SharedArray('products', function () {
return JSON.parse(open('./data/payloads.json'));
});
export default function () {
const product = products[__VU % products.length];
const response = http.post(`${BASE_URL}/api/products`, JSON.stringify(product), {
headers: { 'Content-Type': 'application/json' },
});
check(response, {
'product created': (r) => r.status === 201,
});
}import { Trend, Rate, Counter, Gauge } from 'k6/metrics';
// Trend -- tracks min, max, avg, percentiles
const apiCallDuration = new Trend('api_call_duration');
// Rate -- tracks percentage of non-zero values
const failureRate = new Rate('failure_rate');
// Counter -- tracks cumulative count
const totalRequests = new Counter('total_requests');
// Gauge -- tracks last value
const activeUsers = new Gauge('active_users');
export default function () {
const start = Date.now();
const response = http.get(`${BASE_URL}/api/products`);
const duration = Date.now() - start;
apiCallDuration.add(duration);
failureRate.add(response.status !== 200);
totalRequests.add(1);
activeUsers.add(__VU);
}sleep() between requests to model real users.group() for logical sections -- Groups appear in results and help analysis.check() extensively -- Checks validate correctness under load.SharedArray for large datasets -- It reduces memory usage across VUs.--out json=results.json for post-analysis.sleep() creates unrealistic load patterns.setup()/teardown() -- Use lifecycle hooks for test data management.open() outside the default function.# Basic run
k6 run scripts/load-test.js
# With environment variables
k6 run -e BASE_URL=https://staging.example.com scripts/load-test.js
# With output to JSON
k6 run --out json=results/output.json scripts/load-test.js
# With cloud output (k6 Cloud)
k6 cloud scripts/load-test.js
# With InfluxDB output
k6 run --out influxdb=http://localhost:8086/k6 scripts/load-test.js
# Override VUs and duration
k6 run --vus 50 --duration 5m scripts/smoke-test.jsAfter a test run, analyze these key metrics:
Look for these patterns:
© PramodDutta, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in packs/qa-essentials/skills/k6-performance of PramodDutta/qaskills.
Open the folder on GitHubat commit 1d2a092
K6 Performance 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.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| K6 Performance this skillPramodDutta/qaskills | 232 | — | ~3.2k | Automated safety check: Pass | MIT | |
| Writing Livekit Scenarioslivekit-examples/agent-starter-python | 264 | 1 repos | ~2.5k | Automated safety check: Pass | MIT | |
| Go Testingcxuu/golang-skills | 170 | 1 repos | ~1.3k | Automated safety check: Pass | Apache-2.0 | |
| Goalcraftgrp06/goalcraft | 102 | — | ~3.8k | Automated safety check: Pass | MIT | |
| Thinking Partnermattnowdev/thinking-partner | 206 | — | ~4.4k | Automated safety check: Pass | MIT | |
| Visionkunchenguid/vision | 329 | — | ~2.9k | Automated safety check: Pass | MIT |
livekit-examples/agent-starter-python
Creates and maintains the scenarios a LiveKit agent simulation runs, and wires the agent to consume them.
cxuu/golang-skills
A skill your agent uses when writing, reviewing, or improving Go test code — including table-driven tests, subtests, parallel tests, test helpers, test doubles, and assertions with cmp.Diff.
grp06/goalcraft
Turn a rough draft, vague ambition, or messy task brief into a powerful Codex /goal objective for persistent, evidence-checked work.
mattnowdev/thinking-partner
A deterministic thinking partner that challenges assumptions and applies mental models to sharpen decisions, solve problems, and think more clearly.
kunchenguid/vision
Draft and stress-test a VISION.md for a repository, then iterate with the author on an interactive review board until approved.
owenHochwald/volt
Safely exercise and evaluate HTTP APIs with the Volt CLI, including authenticated requests, JSON bodies, staged load, machine-readable results, performance baselines, and before/after comparisons.
PramodDutta/qaskills
A skill your agent uses when adding or editing QA skills in seed-skills/ or getting them onto the live qaskills.sh catalog, e.g.
PramodDutta/qaskills
A skill your agent uses when publishing SEO blog articles to qaskills.sh, e.g.
PramodDutta/qaskills
A skill your agent uses when deploying qaskills.sh to production, verifying whether a deploy landed, or when a push to main did not show up on the live site, e.g.
PramodDutta/qaskills
Comprehensive RESTful API testing patterns covering HTTP methods, status codes, request/response validation, authentication, error handling, and contract testing.
PramodDutta/qaskills
The complete QA skill for Claude Code — turn Claude into an expert QA engineer that picks the right test type, writes reliable Playwright, Cypress, and pytest tests, eliminates flaky tests, enforces…
PramodDutta/qaskills
End-to-end testing skill using Cypress for web applications, covering custom commands, network intercepts, fixtures, cy.session, and component testing patterns.
Categories
Performance and load testing skill using k6, covering load test scripts, thresholds, scenarios, checks, custom metrics, and results analysis. K6 Performance is an agent skill from PramodDutta/qaskills. Performance and load testing skill using k6, covering load test scripts, thresholds, scenarios, checks, custom metrics, and results analysis.
K6 Performance fits situations like: tasks that involve Load testing.
Run `npx skills add PramodDutta/qaskills --skill k6-performance -a claude-code`. Or copy the skill folder (packs/qa-essentials/skills/k6-performance in PramodDutta/qaskills) into .claude/skills/k6-performance in your project. Claude Code loads it when a task matches its description.
Run `npx skills add PramodDutta/qaskills --skill k6-performance -a codex`. Or copy the skill folder (packs/qa-essentials/skills/k6-performance in PramodDutta/qaskills) into .agents/skills/k6-performance in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add PramodDutta/qaskills --skill k6-performance -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/k6-performance, .gemini/skills/k6-performance, .github/skills/k6-performance and .opencode/skills/k6-performance in your project.
SKILL.md names no scripts, command-line tools or credentials: K6 Performance is instructions for the agent only.
SKILL.md names 1 domain. In commands or code: jslib.k6.io; the agent is likely to contact it when it follows the instructions. This is read from the text; nothing was executed.
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.
K6 Performance is published under the MIT licence (declared in SKILL.md). It allows redistribution, so the full SKILL.md is shown on this page.
About 3.2k 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.
Skills that share tags, products or a category with K6 Performance: Writing Livekit Scenarios (livekit-examples/agent-starter-python, 264 stars), Go Testing (cxuu/golang-skills, 170 stars), Goalcraft (grp06/goalcraft, 102 stars) and Thinking Partner (mattnowdev/thinking-partner, 206 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
PramodDutta (a GitHub user) maintains it in PramodDutta/qaskills, which has 232 GitHub stars. The repository holds 11 skills in this directory. The repository was last updated on October 4, 2026.
Source: PramodDutta/qaskills on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.