Skip to content

feat(#284): /pdf — export any doc with destination prompt#287

Merged
atlas-apex merged 1 commit into
devfrom
feature/GH-284-pdf-skill
May 19, 2026
Merged

feat(#284): /pdf — export any doc with destination prompt#287
atlas-apex merged 1 commit into
devfrom
feature/GH-284-pdf-skill

Conversation

@atlas-apex

Copy link
Copy Markdown
Collaborator

Summary

Adds the /pdf skill — convert any framework-generated doc (markdown, HTML, BPMN) to PDF for sharing with non-technical stakeholders, board members, customers, or auditors.

At export time the operator picks where the PDF lands via a 4-option prompt that mirrors the existing "would it follow the code if the project spun out?" rule from docs/multi-project.md:

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

Converter dispatch picks the right backend for the input format:

  • Markdown → pandoc → md-to-pdf (npm)
  • HTML → wkhtmltopdf → pandoc → md-to-pdf
  • BPMN → bpmn-to-image → SVG → pandoc → PDF

When no converter is installed, exit 3 with an advisory naming each install option — same shape as /process (bpmnlint) and /c4 (Mermaid lint). Adopters who never need PDFs pay zero install cost.

Changes

  • .claude/skills/pdf/SKILL.md — full process + rules + when-to-use table
  • .claude/skills/pdf/convert.sh — converter dispatch helper
  • .claude/skills/pdf/tests/smoke.sh — covers format sniffing, missing-flag handling, missing-converter graceful degrade (mocked PATH), --check-only mode, optional pandoc + wkhtmltopdf paths (skip cleanly when absent), and destination resolution for each of the 4 prompt options
  • .claude/project-config.defaults.json — new pdf block (preferred_converter, pdf_engine, default_destination)
  • docs/multi-project.md § "Architecture diagrams" — extended with a "PDF exports follow the same rule" subsection
  • docs/agdr/AgDR-0034-pdf-export-and-converter-dispatch.md — covers the three load-bearing decisions: standalone-skill vs --pdf flag on every doc skill, dispatch vs hardcoded pandoc, prompt-always vs auto-pick by path
  • CLAUDE.md — skill row added; skill count bumped 48 → 49

Testing

bash .claude/skills/pdf/tests/smoke.sh
# Total: 16   Passed: 14   Failed: 0   Skipped: 2
# (Skipped slots are the optional pandoc / wkhtmltopdf install paths)

Smoke also covered manually (in this worktree pandoc isn't installed, so the missing-converter advisory branch + --check-only reporting both verified end-to-end).

Out of scope (deferred to v1.5, per the ticket)

  • --pdf flag on each doc-emitting skill (cleaner one-command UX but couples every doc skill to the converter dep). The AgDR explains why standalone /pdf is the v1 path.
  • Custom LaTeX templates / branded headers/footers — system pandoc defaults for v1.
  • Batch-export across multiple inputs — loop /pdf in shell.

Closes #284

Glossary

Term Definition
Destination prompt The interactive question /pdf asks at export time about where to write the PDF (the 4-option list above)
"Travels with the code" The test from docs/multi-project.md — if a project spun out tomorrow, would this doc need to come with it? If YES, the doc lives in the project repo (workspace/<name>/docs/); if NO, it lives in ApexYard's projects/<name>/
Converter dispatch The runtime detection in convert.sh that picks the best PDF backend for the input format from what's actually installed on the operator's machine
Graceful degrade The framework convention (from /process and /c4's lint) where missing optional deps produce an exit-3 advisory rather than blocking the skill
Audit-class output A framework-generated artefact that follows the dated-subdir convention (AgDR-0019) — projects/<name>/audits/<dim>/<YYYY-MM-DD>.md. PDFs of these inherit the date in their stem automatically
Single-fork mode / split-portfolio mode The two ApexYard setup modes — see docs/multi-project.md. /pdf reads projects_dir and workspace_dir via the portfolio-paths helper so it works in both transparently

🤖 Generated with Claude Code

…stination prompt

Adds /pdf skill that converts framework-generated docs (markdown, HTML,
BPMN) to PDF via dispatch across pandoc → md-to-pdf → wkhtmltopdf →
bpmn-to-image. At export time the operator picks where the PDF lands
via a 4-option prompt that mirrors the "would it follow the code if the
project spun out?" rule from docs/multi-project.md:

  (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

Graceful-degrades when no converter is installed (exit 3 + advisory
naming each install option) — same shape as /process (bpmnlint) and /c4
(Mermaid lint), so adopters who never want PDFs pay zero install cost.

Includes:

- .claude/skills/pdf/SKILL.md (full process + rules)
- .claude/skills/pdf/convert.sh (converter dispatch)
- .claude/skills/pdf/tests/smoke.sh (format sniffing, missing-converter
  degrade, --check-only, destination resolution for each prompt slot)
- pdf config block in .claude/project-config.defaults.json
  (preferred_converter, pdf_engine, default_destination)
- docs/multi-project.md § "Architecture diagrams" extended with the
  "PDF exports follow the same rule" subsection
- docs/agdr/AgDR-0034 covering the three load-bearing decisions:
  standalone-skill vs --pdf flag on every doc skill, dispatch vs
  hardcoded pandoc, prompt-always vs auto-pick by path
- CLAUDE.md skill table + count bumped 48 → 49

Closes #284

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@atlas-apex atlas-apex left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review: PR #287

Commit: 10b95a4da3edafe681892cf2a3fc6e6088e343f8

Summary

Adds the /pdf skill — converts framework-generated docs (markdown / HTML / BPMN) to PDF with a 4-option destination prompt that mirrors the existing "would it follow the code if the project spun out?" rule from docs/multi-project.md. Shells out to a converter-dispatch helper (convert.sh) that picks the best available backend from pandoc / md-to-pdf / wkhtmltopdf / bpmn-to-image and graceful-degrades (exit 3 + advisory) when no converter is installed. Same shape as /process (bpmnlint) and /c4 (Mermaid lint), so adopters who never need PDFs pay zero install cost.

Checklist Results

  • Architecture & Design: Pass
  • Code Quality: Pass
  • Testing: Pass
  • Security: Pass (no auth/secrets touched)
  • Performance: Pass (synchronous shell, single conversion per invocation, no hot paths)
  • PR Description & Glossary: Pass (6 well-explained terms)
  • Technical Decisions (AgDR): Pass — AgDR-0034 covers all three load-bearing axes (standalone vs per-skill flag, single converter vs dispatch, prompt vs auto-pick)
  • Adopter Handbooks: Pass — no architecture/migration/language-handbook triggers fire; commit-message-quality passes cleanly

Verification Done

  • Exit-code taxonomy (0/1/2/3) matches sibling shapes in _lib-mermaid-lint.sh and process/lint.sh
  • set -uo pipefail (no -e) matches _lib-mermaid-lint.sh (intentional — explicit exit 1 after each converter invocation) ✓
  • Portfolio path resolution: SKILL.md sources _lib-read-config.sh + _lib-portfolio-paths.sh and calls portfolio_projects_dir / portfolio_workspace_dir — no hardcoded literals ✓
  • Test PATH-stripping technique correctly forces the "no converter" branch regardless of host environment; falls back to skip if a symlink leaks ✓
  • BPMN multi-step pipeline (bpmn-to-image → SVG → pandoc → PDF) clearly described in SKILL.md § 6, AgDR-0034, and the convert.sh header comment ✓
  • 4-option destination prompt clearly described (lines 117–130 of SKILL.md) with explicit hint text ✓
  • AgDR slot 0034 doesn't collide with open PRs #285 (0031) or #289 (0033) ✓
  • Commit message quality: subject + body + Closes #284 + Co-Authored-By ✓

Issues Found

None blocking.

Suggestions (non-blocking)

  1. Smoke test §8 option 3 is a tautology. Lines 932–936:

    custom="/tmp/out.pdf"
    got="$custom"
    if [ "$got" = "/tmp/out.pdf" ]; then ok "option 3 → ..."; ...

    This asserts $custom == $custom. The intent — verify option 3 passes through the literal — is documented in the comments but not actually exercised. Consider replacing with a real call into a resolve_dest extension that handles option 3, or remove the assertion. Keeping it as-is is fine for v1; just flagging that it does not exercise real behavior.

  2. convert.sh does not source the pdf.* config block. Config keys preferred_converter and pdf_engine are read by the model orchestrating the skill (SKILL.md instructs the agent to pass them as --converter / --pdf-engine flags), not by convert.sh itself. This is a reasonable separation-of-concerns choice — convert.sh stays config-free — but the SKILL.md "Path resolution" section could state it explicitly. Future readers may otherwise expect convert.sh to read the config block. Single-line addition under the Config heading would close the loop.

  3. $eng_flag unquoted at lines 525/568/620 is the standard "optional flag" pattern (quoting an empty eng_flag would inject "" as a literal arg to pandoc). Intentional and correct, but a one-line comment # unquoted on purpose — empty PDF_ENGINE means omit the flag entirely would prevent a well-meaning future shellcheck-driven cleanup from breaking it.

  4. npx … >&2 routing converter chatter to stderr (lines 537/579/599) is unusual — most callers route to /dev/null and trust the exit code. Current shape keeps the operator informed during the npx fetch (~5s cold start) which is helpful UX; just noting for any future refactor.

  5. AgDR slot ordering. This PR uses AgDR-0034 while slots 0032 / one of {0033} are still unallocated on dev. Not blocking — apexyard's AgDR sequence has accepted gaps before — and PRs #285 (0031) and #289 (0033) keep the global sequence monotone-ish. Worth a one-liner in the AgDR's intro if there's a story behind the gap; otherwise let it be.

Verdict

APPROVED

The PR is consistent with the agent's plan, mirrors the existing graceful-degrade patterns (/process lint, _lib-mermaid-lint.sh), routes through portfolio_* helpers (so split-portfolio adopters get correct paths transparently), and ships an AgDR that genuinely earns its keep across three real design axes. The 4-option destination prompt is a thoughtful echo of the existing "would it follow the code?" rule and avoids the silent-auto-pick foot-gun. Tests cover the load-bearing behaviors. The five style nits above are suggestions, not requested changes.


🤖 Reviewed by Rex (Code Reviewer Agent)
📌 Reviewed commit: 10b95a4da3edafe681892cf2a3fc6e6088e343f8

@atlas-apex atlas-apex merged commit b77e54e into dev May 19, 2026
3 checks passed
@atlas-apex atlas-apex deleted the feature/GH-284-pdf-skill branch May 19, 2026 06:06
me2resh added a commit that referenced this pull request May 19, 2026
Dev advanced significantly while this branch was in flight (v1.3.0
release + #281 templates reorg + #283 tracker config + #287 /pdf config).
Resolution:
- Framework / docs (CHANGELOG, CLAUDE, multi-project, sdlc, templates/README,
  custom-templates example README, site/architecture, workflows/sdlc):
  --theirs (dev has the integrated state)
- 5 ticket SKILL.md / test files (spike, task, investigation,
  investigation tests README + smoke.sh): --theirs (dev has the
  templates/tickets/ paths from #281)
- .claude/project-config.defaults.json: --theirs (dev has #287's pdf block)
- .claude/skills/update/SKILL.md: --ours (this IS #282's deliverable —
  the chain-walk flow + step 8b)

Refs #282
me2resh added a commit that referenced this pull request May 19, 2026
Both sides added a new top-level key after the portfolio block:
- HEAD (#283): tracker dispatch (AgDR-0033)
- origin/dev (#287 via #284): pdf config (AgDR-0034)

Both blocks are independent + additive, so kept both with a comma
separator. JSON validates clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
me2resh added a commit that referenced this pull request May 19, 2026
Dev advanced ~15 commits since this branch (v1.3.0 release + #281 ticket
templates + #283 tracker abstraction + #284 /pdf + #286 update chain +
#287 + #288 /feature-diagram + #293 Rex domain handbooks + #275 ui-paths-
exclude + #266 mermaid lint + #270 DFD snapshot + #246 tech-vision + #245
investigation + #257 dfd + #268 skill-gated ticket-create).

Resolution strategy: --theirs for framework drift (CLAUDE.md, multi-project,
project-config.defaults, all new tests, hook files, other SKILL.mds,
handbooks/README, site/architecture.html, templates/*, workflows/sdlc,
etc. — 26 files). Manual merge for the #290 deliverable
`.claude/skills/extract-features/SKILL.md` — kept BOTH the argument-hint
+ `--with-mockups` doc section + step 4b (this PR's deliverable) AND
the `/feature-diagram` See-also pointer dev added (complementary, not
overlapping).

8 conflict regions in extract-features/SKILL.md handled: 1 kept dev's
new See-also block, 7 kept ours (argument-hint, Usage block, the full
--with-mockups doc, the IF-mockups insert marker, the giant 4b ASCII-
wireframes section, the report-line append, the anti-pattern bullets).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
me2resh added a commit that referenced this pull request Jun 5, 2026
…stination prompt (#287)

Adds /pdf skill that converts framework-generated docs (markdown, HTML,
BPMN) to PDF via dispatch across pandoc → md-to-pdf → wkhtmltopdf →
bpmn-to-image. At export time the operator picks where the PDF lands
via a 4-option prompt that mirrors the "would it follow the code if the
project spun out?" rule from docs/multi-project.md:

  (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

Graceful-degrades when no converter is installed (exit 3 + advisory
naming each install option) — same shape as /process (bpmnlint) and /c4
(Mermaid lint), so adopters who never want PDFs pay zero install cost.

Includes:

- .claude/skills/pdf/SKILL.md (full process + rules)
- .claude/skills/pdf/convert.sh (converter dispatch)
- .claude/skills/pdf/tests/smoke.sh (format sniffing, missing-converter
  degrade, --check-only, destination resolution for each prompt slot)
- pdf config block in .claude/project-config.defaults.json
  (preferred_converter, pdf_engine, default_destination)
- docs/multi-project.md § "Architecture diagrams" extended with the
  "PDF exports follow the same rule" subsection
- docs/agdr/AgDR-0034 covering the three load-bearing decisions:
  standalone-skill vs --pdf flag on every doc skill, dispatch vs
  hardcoded pandoc, prompt-always vs auto-pick by path
- CLAUDE.md skill table + count bumped 48 → 49

Closes #284

Co-authored-by: me2resh <ahmed.abdelaliem@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants