skills/gen-pdf/SKILL.md
Converts a Markdown file to a styled PDF with DevExpert branding (logo in bottom-right corner). Use when asked to generate a PDF from a Markdown document, or when any DevExpert proposal/document needs to be exported as PDF.
npx skillsauth add antoniolg/agent-kit gen-pdfInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Convierte cualquier fichero Markdown a PDF con un acabado visual cercano al export de Obsidian (tipografía y jerarquía neutras) y mantiene el logo de DevExpert en la esquina inferior derecha.
.mdpip install markdown-it-py[plugins] weasyprint reportlab PyPDF2
assets/devexpert-logo.png (logo horizontal completo, relativo a la carpeta de la skill)~/Documents/aipal/40-archive/Usa el siguiente script Python. Acepta input_md y output_pdf como variables:
import os
import tempfile
from pathlib import Path
from markdown_it import MarkdownIt
from PyPDF2 import PdfReader, PdfWriter
from reportlab.lib.pagesizes import A4
from reportlab.pdfgen import canvas
from weasyprint import CSS, HTML
md = MarkdownIt("commonmark", {"breaks": True, "html": True}).enable("table")
CSS_STYLES = """
@page {
size: A4;
margin: 30mm 24mm 26mm 24mm;
}
html, body {
margin: 0;
padding: 0;
color: #111111;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Helvetica, Arial, sans-serif;
font-size: 12pt;
line-height: 1.46;
}
p {
margin: 0 0 0.82em 0;
}
h1, h2, h3, h4 {
color: #111111;
font-weight: 800;
line-height: 1.12;
margin: 0;
}
h1 {
font-size: 24pt;
margin-bottom: 0.9em;
}
h2 {
font-size: 20pt;
margin-top: 1.1em;
margin-bottom: 0.74em;
}
h3 {
font-size: 16pt;
margin-top: 0.95em;
margin-bottom: 0.58em;
}
h4 {
font-size: 13pt;
margin-top: 0.8em;
margin-bottom: 0.4em;
}
strong {
color: #111111;
font-weight: 800;
}
ul, ol {
margin: 0.35em 0 0.9em 1.28em;
padding: 0;
}
li {
margin-bottom: 0.24em;
}
li::marker {
color: #a0a0a0;
}
table {
width: 100%;
border-collapse: collapse;
margin: 0.9em 0 1.1em 0;
font-size: 10.5pt;
}
th, td {
border: 1px solid #d4d4d4;
padding: 7px 10px;
text-align: left;
vertical-align: top;
}
th {
background: #f3f3f3;
color: #111111;
font-weight: 700;
}
tr:nth-child(even) td {
background: #fafafa;
}
blockquote {
border-left: 3px solid #d0d0d0;
padding-left: 12px;
color: #303030;
margin: 0.8em 0;
}
code {
font-family: "SF Mono", "SFMono-Regular", Menlo, Consolas, "Liberation Mono", monospace;
font-size: 0.9em;
background: #f5f5f5;
padding: 0.08em 0.28em;
border-radius: 4px;
}
pre code {
display: block;
white-space: pre-wrap;
padding: 0.8em;
}
a {
color: #111111;
text-decoration: underline;
text-decoration-color: #c1c1c1;
}
hr {
border: 0;
height: 0;
margin: 0;
padding: 0;
background: transparent;
page-break-after: always;
break-after: page;
}
"""
def resolve_logo_path(explicit_logo_path=None):
if explicit_logo_path:
explicit_path = Path(explicit_logo_path).expanduser()
if explicit_path.exists():
return explicit_path
candidates = []
env_logo = os.getenv("GEN_PDF_LOGO_PATH")
if env_logo:
candidates.append(Path(env_logo).expanduser())
skill_dir = os.getenv("GEN_PDF_SKILL_DIR")
if skill_dir:
candidates.append(Path(skill_dir).expanduser() / "assets" / "devexpert-logo.png")
candidates.extend(
[
Path.cwd() / "assets" / "devexpert-logo.png",
Path.home() / ".claude" / "skills" / "gen-pdf" / "assets" / "devexpert-logo.png",
]
)
for candidate in candidates:
if candidate.exists():
return candidate
return None
def gen_pdf(input_md, output_pdf, add_logo=True, logo_path=None):
input_md_path = Path(input_md).expanduser()
output_pdf_path = Path(output_pdf).expanduser()
output_pdf_path.parent.mkdir(parents=True, exist_ok=True)
content = input_md_path.read_text(encoding="utf-8")
html_content = md.render(content)
full_html = f"""<!doctype html>
<html>
<head><meta charset="utf-8" /></head>
<body>{html_content}</body>
</html>"""
HTML(string=full_html, base_url=str(input_md_path.parent)).write_pdf(
str(output_pdf_path), stylesheets=[CSS(string=CSS_STYLES)]
)
if not add_logo:
return
resolved_logo = resolve_logo_path(logo_path)
if not resolved_logo:
return
reader = PdfReader(str(output_pdf_path))
writer = PdfWriter()
with tempfile.NamedTemporaryFile(suffix=".pdf", delete=False) as temp_file:
temp_logo_pdf = temp_file.name
page_width, _ = A4
canvas_obj = canvas.Canvas(temp_logo_pdf, pagesize=A4)
canvas_obj.drawImage(
str(resolved_logo),
page_width - 128,
14,
width=110,
height=27,
mask="auto",
preserveAspectRatio=True,
)
canvas_obj.showPage()
canvas_obj.save()
logo_overlay_page = PdfReader(temp_logo_pdf).pages[0]
for page in reader.pages:
page.merge_page(logo_overlay_page)
writer.add_page(page)
with output_pdf_path.open("wb") as output_file:
writer.write(output_file)
os.unlink(temp_logo_pdf)
gen_pdf en un script temporal en /tmp/input_md = ruta al fichero Markdown y output_pdf = ruta de salidaadd_logo=True para documentos DevExpertGEN_PDF_SKILL_DIR o GEN_PDF_LOGO_PATH$TMPDIR/aipal/documents/) y responde con [[document:/ruta]]--- en el Markdown fuerzan salto de página en el PDFbreaks=True)base_url del fichero de entradaassets/devexpert-logo.png, no el icono cuadrado.tools
Use the private LearnWorlds CLI to inspect DevExpert Academy users, find students by email, list their enrolled courses/products, look up products, and perform safe enrollment workflows. Trigger when Antonio asks what courses a student has in LearnWorlds or academia.devexpert.io, whether someone belongs to the current or next AI Expert edition, or to use the LearnWorlds/academy CLI.
tools
Orchestrates Android development tasks including project creation, deployment, SDK management, and environment diagnostics using the `android` command-line tool.
development
Elite website image-to-code skill for Codex. For visually important web tasks, it must first generate the design image(s) itself, deeply analyze them, then implement the website to match them as closely as possible. In Codex, it must prefer large, readable, section-specific images instead of tiny compressed boards, generate fresh standalone images for sections or detail views instead of cropping old ones, avoid lazy under-generation, avoid cards-inside-cards-inside-cards UI, and keep the hero clean, spacious, readable, and visible on a small laptop.
development
Create, repair, validate, preview, and package Codex-compatible animated pet spritesheets from character art, screenshots, generated images, or visual references. Use when a user wants to hatch a Codex pet, create a custom animated pet, or build a built-in pet asset with an 8x9 atlas, transparent unused cells, row-by-row animation prompts, QA contact sheets, preview videos, and pet.json packaging. This skill composes the installed $imagegen system skill for visual generation and uses bundled scripts for deterministic spritesheet assembly.