Getting it into your agent
One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.
npx agentmods add rules/danielvm-git/bigpowers/generate-allure-reportgit clone --depth 1 https://github.com/danielvm-git/bigpowersWrote this? Show the measurements
A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.
[](https://agentmods.dev/rules/danielvm-git/bigpowers/generate-allure-report)<a href="https://agentmods.dev/rules/danielvm-git/bigpowers/generate-allure-report"><img src="https://agentmods.dev/badge/rules/danielvm-git/bigpowers/generate-allure-report.svg" alt="Measured on agentmods" height="20"></a>What it costs to keep this loaded
Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.
| Model | Per session | Once invoked |
|---|---|---|
| Fable 5 | $0.00068 | $0.02503 |
| Opus 5 | $0.00034 | $0.01252 |
| Sonnet 5 | $0.00014 | $0.00501 |
| Haiku 4.5 | $0.00007 | $0.00250 |
Grade A, and why
generate-allure-report scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured today.
A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.
Nothing flagged
None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.
How it starts
The opening of the file, as written. The whole thing — 285 lines — stays where its author put it; the contents beside it link to each section on GitHub.
Generate Allure Report
Generate Allure TestOps-compatible reports from bigpowers project metadata. Produces JUnit XML for story-level test results, custom categories for filtering, and executor metadata — all in the allure-results/ directory.
Quick Start
bash scripts/generate-allure-report.sh
What It Produces
Three files in allure-results/:
| File | Description |
|---|---|
junit-results.xml |
One <testcase> per story with <properties> for risk, security, WSJF, tier, wave, and status. Incomplete stories get a <failure> element. |
categories.json |
Custom Allure categories for filtering by epic, risk level (P0), and security reviews. |
executor.json |
Build metadata — name, type, version from release-plan.yaml, build order. |
Data Sources
See REFERENCE.md
Verify
test -f allure-results/junit-results.xml && test -f allure-results/categories.json && test -f allure-results/executor.json
Handoff
- next_skill: null (terminal skill — no downstream workflow step)
generate-allure-report — Reference
Data Sources
The script reads five YAML sources from the project:
| Source | Path | Fields Used |
|---|---|---|
| Execution status | specs/execution-status.yaml |
epics, stories, development_status |
| Release plan | specs/release-plan.yaml |
release.version, release.status, bugs summary |
| Epic capsules | specs/epics/**/epic.yaml + -tasks.yaml |
Epic metadata, task pass/fail counts |
| Cycle times | specs/metrics/cycle-times.yaml |
Story-level cycle_minutes, bcp_per_hour, source |
| Bug registry | specs/bugs/registry.yaml |
Bug counts by status and severity |
Script Body
scripts/generate-allure-report.sh:
#!/usr/bin/env bash
set -euo pipefail
source "$(dirname "${BASH_SOURCE[0]}")/lib/python-env.sh"
ROOT="$(git rev-parse --show-toplevel 2>/dev/null)" || ROOT="$(dirname "${BASH_SOURCE[0]}")/.."
mkdir -p "$ROOT/allure-results"
$PYTHON - "$ROOT" <<'PY'
import json
import sys
import xml.etree.ElementTree as ET
from pathlib import Path
root = Path(sys.argv[1])
out = root / "allure-results"
# 1. Read execution-status.yaml
exec_status_file = root / "specs" / "execution-status.yaml"
release_plan_file = root / "specs" / "release-plan.yaml"
cycle_times_file = root / "specs" / "metrics" / "cycle-times.yaml"
bugs_registry_file = root / "specs" / "bugs" / "registry.yaml"
sys.path.insert(0, str(root / "scripts" / "lib"))
from simple_yaml import parse_simple_yaml
exec_status = parse_simple_yaml(exec_status_file.read_text()) if exec_status_file.exists() else {}
release_plan = parse_simple_yaml(release_plan_file.read_text()) if release_plan_file.exists() else {}
cycle_times = parse_simple_yaml(cycle_times_file.read_text()) if cycle_times_file.exists() else {"stories": []}
bugs_registry = parse_simple_yaml(bugs_registry_file.read_text()) if bugs_registry_file.exists() else {"bugs": []}
# Build cycle-times lookup
ct_lookup = {}
for ct in cycle_times.get("stories", []):
if isinstance(ct, dict):
ct_lookup[ct.get("id", "")] = ct
# 2. Build JUnit XML
stories = exec_status.get("stories", {})
# Counts for testsuite attributes
total_stories = len(stories)
incomplete = sum(1 for s in stories.values() if isinstance(s, dict) and s.get("status") != "done")
testsuite = ET.Element("testsuite", {
"name": "bigpowers-epic-progress",
"tests": str(total_stories),
"failures": str(incomplete),
"errors": "0",
"skipped": "0",
})
for story_id in sorted(stories.keys()):
story = stories[story_id]
if not isinstance(story, dict):
continue
epic_id = story.get("epic", "unknown")
title = story.get("title", story_id)
bcps = story.get("bcps", 0)
status = story.get("status", "backlog")
risk_max = story.get("risk_max", "none")
security_max = story.get("security_max", "none")
# Enrich with cycle-times data
ct_data = ct_lookup.get(story_id, {})
cycle_minutes = ct_data.get("cycle_minutes", 0)
bcp_per_hour = ct_data.get("bcp_per_hour", 0)
# Time: cycle_minutes * 60 for seconds in Allure display
time_seconds = cycle_minutes * 60.0 if cycle_minutes else 0.0
testcase = ET.SubElement(testsuite, "testcase", {
"classname": epic_id,
"name": f"{story_id}: {title}",
"time": str(round(time_seconds, 3)),
})
props = ET.SubElement(testcase, "properties")
ET.SubElement(props, "property", {"name": "risk", "value": risk_max})
ET.SubElement(props, "property", {"name": "security", "value": security_max})
ET.SubElement(props, "property", {"name": "bcps", "value": str(bcps)})
ET.SubElement(props, "property", {"name": "status", "value": status})
ET.SubElement(props, "property", {"name": "bcp_per_hour", "value": str(bcp_per_hour)})
ET.SubElement(props, "property", {"name": "lead_time_minutes", "value": str(cycle_minutes)})
if status != "done":
ET.SubElement(testcase, "failure", {
"message": f"Story {story_id} is {status} [risk={risk_max}, security={security_max}]",
"type": "StoryIncomplete"
})
tree = ET.ElementTree(testsuite)
ET.indent(tree, space=" ")
tree.write(str(out / "junit-results.xml"), encoding="utf-8", xml_declaration=True)
# 3. Build categories.json
epics = exec_status.get("epics", {})
categories = []
for epic_id in sorted(epics.keys()):
epic = epics[epic_id]
if isinstance(epic, dict) and epic.get("status") != "done":
categories.append({
"name": f"Epic: {epic.get('title', epic_id)}",
"matchedStatuses": ["failed"],
"messageRegex": f".*{epic_id}:.*"
})
categories.append({
"name": "P0 Risk",
"matchedStatuses": ["failed"],
"messageRegex": ".*risk.*P0.*"
})
categories.append({
"name": "Security Review",
"matchedStatuses": ["failed"],
"messageRegex": ".*security.*(?:medium|high).*"
})
# Add bug-based categories
bug_list = bugs_registry.get("bugs", [])
bug_count = len(bug_list) if isinstance(bug_list, list) else 0
open_bugs = sum(1 for b in bug_list if isinstance(b, dict) and b.get("status") not in ("fixed", "closed", None))
if open_bugs > 0:
categories.append({
"name": "Open Bugs",
"matchedStatuses": ["failed"],
"messageRegex": ".*Bug.*"
})
(out / "categories.json").write_text(json.dumps(categories, indent=2))
# 4. Build executor.json
rl = release_plan.get("release", {}) if isinstance(release_plan.get("release"), dict) else {}
executor = {
"name": "bigpowers",
"type": "bigpowers",
"buildName": rl.get("version", "unknown") if isinstance(rl, dict) else "unknown",
"buildOrder": len(exec_status.get("development_status", {})),
}
(out / "executor.json").write_text(json.dumps(executor, indent=2))
# Summary
epic_count = len([e for e in epics.values() if isinstance(e, dict) and e.get("status") == "done"])
total_epics = len(epics)
print(f"generate-allure-report: {total_stories} stories, {epic_count}/{total_epics} epics done, {bug_count} bugs")
print(f" -> {out}/junit-results.xml")
print(f" -> {out}/categories.json")
print(f" -> {out}/executor.json")
PY
What this file has done since we first saw it
Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.
- today First seen · 285 lines · 68 tokens per session scan A 9d2334a97608
generate-allure-report is a cursor rule published in the GitHub repository danielvm-git/bigpowers (162 stars, last pushed 2d ago), licensed MIT. It adds 68 tokens to every session and 2,503 once invoked, about $0.0003 per session on Opus 5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-09-03.
Other cursor rules, from other repositories
ponytail
Ponytail, lazy senior dev mode. Always pick the simplest solution that works.
app-router-patterns
Next.js 14+ App Router patterns — Server Components, Client Components, Route Handlers, Server Actions, and metadata API.
context-os
ContextOS rules for context-os.
database
Database architecture, schema design, Prisma, Drizzle ORM, indexing strategies, migrations, and N+1 query resolution.
vue
Rules for Vue (2 and 3) single-file components.
nextjs
ContextOS rules for nextjs.