본문으로 건너뛰기
cccskills
무료GitHub에 공개

pdf

Convert markdown/HTML/BPMN to PDF (pandoc/md-to-pdf/wkhtmltopdf/bpmn-to-image), destination-prompted; graceful-degrades.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

me2resh/apexyard스타 538(GitHub 538 + cccskills 0)

실행 점수 미검증

설치 방법 보기

포함된 파일(4)

  • SKILL.md11.8 KB
  • convert.sh11.9 KB
  • tests/smoke.sh11.3 KB
  • tests/test_md_to_pdf_fallback.sh6.6 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

Writing: read docs/skills/shared/writing-rule.md before you write a durable artifact.

/pdf — Export Any Doc to PDF

Convert a framework-generated document (markdown, HTML, BPMN) to PDF for sharing with non-technical stakeholders, board members, customers, or auditors.

Sits alongside /c4 (Mermaid markdown), /dfd (Mermaid markdown), /tech-vision (markdown), /write-spec (PRD markdown), /journey (self-contained HTML), /process (BPMN XML), and the audit family (/threat-model, /launch-check, etc., all of which write dated markdown audits). Those skills emit a single source-of-truth artefact in its native format; /pdf is the dedicated bridge to PDF for the moments when prose isn't enough.

The destination question

A PDF can land in one of two places, and the answer depends on whether the doc should travel with the code if the project spun out tomorrow. This mirrors the existing rule in docs/multi-project.md:

If YES (travels with the code)If NO (ApexYard's view)
Project's own repo: workspace/<name>/docs/Ops fork: projects/<name>/pdfs/
Examples: API spec, deployment runbook, internal sequenceExamples: handover assessment, stakeholder update, launch-check verdict

The skill asks, doesn't guess. The 4-option prompt below covers every common case.

Usage

/pdf projects/sample-app/architecture/vision.md
/pdf workspace/sample-app/docs/architecture/context.md
/pdf projects/sample-app/audits/security/2026-05-19.md
/pdf projects/sample-app/journeys/checkout-v2.html
/pdf projects/sample-app/processes/onboarding.bpmn
/pdf <input> --no-prompt                  # use default_destination from config
/pdf <input> --converter=pandoc           # force a specific converter
/pdf <input> --destination=workspace      # skip the prompt, write to workspace/<name>/docs/
/pdf <input> --destination=projects       # skip the prompt, write to projects/<name>/pdfs/
/pdf <input> --destination=keep           # skip the prompt, keep next to source
/pdf <input> --destination=/absolute/path/out.pdf  # explicit path
/pdf <input> --project=sample-app         # override auto-detected project name

Path resolution

Read workspace_dir and projects_dir from .claude/hooks/_lib-portfolio-paths.sh so split-portfolio adopters resolve to the sibling private repo transparently:

source "$(git rev-parse --show-toplevel)/.claude/hooks/_lib-read-config.sh"
source "$(git rev-parse --show-toplevel)/.claude/hooks/_lib-portfolio-paths.sh"
projects_dir=$(portfolio_projects_dir)
workspace_dir=$(portfolio_workspace_dir)

Defaults to single-fork (./projects, ./workspace). Don't hardcode literal projects/ or workspace/ paths in the bash blocks below — let the helper resolve whichever mode the adopter is in.

Process

Use AskUserQuestion for every operator option menu in this skill. Follow .claude/rules/reporting-style.md § Operator choices. Preserve multiple selections where the menu permits them. Split menus with more than four options into sequential wizard questions. Keep single yes/no and ticket confirmation prompts as written. The prose menus below are fallbacks only when the harness lacks AskUserQuestion.

1. Resolve the input file

INPUT="$1"
if [ ! -f "$INPUT" ]; then
  echo "/pdf: input file not found: $INPUT" >&2
  exit 2
fi
# Absolute path for downstream resolution
ABS_INPUT=$(cd "$(dirname "$INPUT")" && pwd)/$(basename "$INPUT")

2. Sniff the input format

By extension:

ExtensionFormat
.md, .markdownMarkdown
.html, .htmHTML
.bpmn, .bpmn20.xmlBPMN

Anything else → exit 2 with a clear "unsupported input format" message + the supported list.

3. Auto-detect <name> from the input path

The destination prompt needs a project name to fill in. Inference order:

  1. If --project=<name> was passed → use it.
  2. If ABS_INPUT is under <projects_dir>/<name>/... → name is the path segment after projects_dir.
  3. If ABS_INPUT is under <workspace_dir>/<name>/... → name is the path segment after workspace_dir.
  4. If neither matched (e.g. cwd is ops-fork root and input is docs/foo.md) → name is unresolved. The prompt will show "(no project — supply via --project)" in slots 1 + 2, and slots 3 + 4 remain valid.

4. Show the destination prompt

Use AskUserQuestion for the destination unless --no-prompt or --destination=... was passed. Recommend the path that fits the document's readers. Use the prompt below only when the harness lacks the tool.

Where should the PDF land?

  (1) workspace/<name>/docs/<stem>.pdf  ← travels with the code
  (2) projects/<name>/pdfs/<stem>.pdf   ← ApexYard's view
  (3) <custom path>                     ← anywhere
  (k) keep next to source               ← <input-dir>/<stem>.pdf

  Hint: pick (1) if a downstream reader of the project repo would want
  this PDF (API spec, deployment runbook). Pick (2) if it's framework
  context (handover, stakeholder update, audit). Pick (k) when in doubt.

> 

When <name> couldn't be resolved, slots (1) and (2) print as (no project — supply via --project) and accepting them prompts for a name.

5. Compute the output path

STEM=$(basename "$INPUT")
STEM="${STEM%.*}"   # strip the extension

Filename rule:

  • Default → <stem>.pdf
  • Audit-class outputs: if ABS_INPUT matches <projects_dir>/<name>/audits/<dim>/<YYYY-MM-DD>.md (the dated-subdir convention from AgDR-0019), keep the date in the filename — the stem already contains it, so <stem>.pdf is correct as-is. No special case needed.

By destination:

DestinationOutput path
1 / workspace<workspace_dir>/<name>/docs/<stem>.pdf
2 / projects<projects_dir>/<name>/pdfs/<stem>.pdf
3 / <path>the operator-supplied path (relative to cwd, or absolute)
k / keep<dir-of-input>/<stem>.pdf

If the parent dir doesn't exist, mkdir -p it.

If the output file already exists, ask the operator: overwrite (o), pick a new path (n), or quit (q). No silent overwrite.

6. Run the converter

Delegate to convert.sh (the skill's converter-dispatch helper). It takes --from, --to, optional --converter=<name>, optional --pdf-engine=<eng>, and outputs to --out.

SKILL_DIR="$(dirname "$(realpath "$0")")"
"$SKILL_DIR/convert.sh" \
  --from="$ABS_INPUT" \
  --to="$OUT" \
  ${CONVERTER:+--converter="$CONVERTER"} \
  ${PDF_ENGINE:+--pdf-engine="$PDF_ENGINE"}
RC=$?

convert.sh exit codes:

  • 0 — converted cleanly
  • 1 — conversion failed (offending converter output streamed to stderr)
  • 2 — bad input / unsupported format
  • 3 — no converter available; advisory printed to stderr naming each install option. The skill propagates this exit code.

7. Report

On success:

✓ PDF written: <OUT>
  Source:     <ABS_INPUT>
  Format:     <markdown|html|bpmn> → PDF
  Converter:  <pandoc|md-to-pdf|wkhtmltopdf|bpmn-to-image+pandoc>
  Size:       <size>

On exit 3:

✗ No PDF converter is installed.

Markdown inputs can use:
  • pandoc           — brew install pandoc (or apt-get install pandoc)
                       For best output also install xelatex (mactex / texlive-xetex)
  • md-to-pdf (npm)  — npm install -g md-to-pdf  (or run via npx, no install)

HTML inputs can use:
  • wkhtmltopdf      — brew install --cask wkhtmltopdf
  • pandoc           — same as above (uses its HTML reader)

BPMN inputs need a two-step pipeline:
  • bpmn-to-image (npm) → SVG → pandoc → PDF

Install at least one of the above and re-run /pdf.

The skill does not silently fall back to leaving you without a PDF — it explicitly exits 3 so the operator knows the gap and can fix it.

Config

.claude/project-config.defaults.json ships a pdf block:

"pdf": {
  "preferred_converter": "pandoc",
  "pdf_engine": "xelatex",
  "default_destination": "ask"
}
  • preferred_converter — when both pandoc and a fallback are installed, prefer this one. null means "first one found in the dispatch order".
  • pdf_engine — passed to pandoc as --pdf-engine=<engine>. Common values: xelatex (best Unicode), pdflatex (smaller install), wkhtmltopdf (no LaTeX needed but degraded typography).
  • default_destination — used when --no-prompt is passed. Must be one of workspace, projects, keep, or ask. ask with --no-prompt is an error (the skill exits 2 — operator must change config or drop --no-prompt).

Adopters override in .claude/project-config.json:

{
  "pdf": {
    "preferred_converter": "md-to-pdf",
    "default_destination": "keep"
  }
}

Rules

  1. Always ask about destination unless --no-prompt or --destination=... was passed. The "would it follow the code?" question is genuinely contextual; guessing wrong creates landed-in-the-wrong-repo cleanup work.
  2. Never silently overwrite an existing PDF. Always prompt or require --destination=<explicit-path> which the operator owns.
  3. Graceful degrade only on missing dep, not on conversion failure. Missing converter → exit 3 + advisory. Converter installed but threw an error → exit 1 + propagate the converter's stderr. The two are different failure modes with different fixes.
  4. Source format detection by extension only. We don't sniff content (would add complexity for marginal value — operators know what they're converting).
  5. No special-case templates. v1 uses the converter's defaults. Custom LaTeX templates, branded header/footer, etc. are out of scope (separate ticket).
  6. No batch mode. One input → one PDF. If the operator needs ten, they loop in shell. Keeps the skill's destination-prompt logic single-purpose.

When to use this

TriggerUse /pdf?
Board needs a one-pager PDF of a PRDYes
Sharing an audit verdict with a customerYes
Customer-facing API documentationYes (write to workspace/<name>/docs/)
Internal stakeholder updateYes (write to projects/<name>/pdfs/)
Quick-share a diagram from /c4 for a meetingYes (use keep to drop next to the source)
Replace the source markdown with the PDFNo — the source stays canonical; PDF is a render
Batch-converting 50 audit reportsNo — loop /pdf in shell, the skill stays single-input

Out of scope (v1)

  • --pdf flag on each doc-emitting skill that converts at write-time. Cleaner one-command UX but couples every doc skill to the converter dep. Standalone /pdf is v1; per-skill integration can land in v1.5 if operator usage demands it.
  • Custom LaTeX templates / branding / headers / footers. Use system pandoc defaults for v1.
  • Batch export across multiple inputs. Loop in shell.
  • Auto-watch + regenerate on source change. Out of scope.
  • PDF accessibility audit (tagged structure, alt-text propagation). The accessibility-audit skill covers the source markdown; PDF accessibility is a downstream concern.

See also

  • AgDR-0034 — converter dispatch + destination prompt rationale + standalone-skill vs flag-on-each-skill decision
  • docs/multi-project.md § "Architecture diagrams" — the "would it follow the code?" rule extended to PDF outputs
  • .claude/skills/process/lint.sh — graceful-degrade-on-missing-dep pattern that this skill mirrors for converter detection
  • .claude/skills/_lib-mermaid-lint.sh — same pattern, npx-fallback case

Part of ApexYard — multi-project SDLC framework for Claude Code · MIT.

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

WCAG 2.1 AA audit — perceivable, operable, understandable, robust criteria. Deep-dive for /launch-check accessibility.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

me2resh/apexyard5382026년 10월 26일 업데이트

WCAG 2.2 AA audit — perceivable, operable, understandable, robust criteria. Deep-dive for /launch-check accessibility.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

me2resh/apexyard5382026년 10월 26일 업데이트

agdr

무료

Browse / search / show / stats AgDRs across the portfolio — recalls "have we decided this before?".

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

me2resh/apexyard5382026년 10월 26일 업데이트

Analytics audit — SDK config, event naming, funnel completeness, dashboards. Deep-dive for /launch-check analytics.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

me2resh/apexyard5382026년 10월 26일 업데이트

Record per-PR architecture-review approval for design-artifact PRs (required by the architecture gate). ONLY on an explicit per-PR architect "approved".

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

me2resh/apexyard5382026년 10월 26일 업데이트

Record per-PR design-review approval (UI merge gate). ONLY on an explicit per-PR designer "approved".

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

me2resh/apexyard5382026년 10월 26일 업데이트

me2resh의 스킬 모두 보기

이 스킬의 문제 신고