Skip to main content

pymc-artifact-style

Apply PyMC Labs' house style to every artifact you produce — reports, PDFs, slide decks, charts, images, notebooks. Use whenever you generate something a person will look at, before you deliver it.

Jump to install

Source facts

Repository
pymc-labs/daimon
Last source activity
August 8, 2026 at 10:19
Detected SKILL.md language
English
Stars
15
Forks
5

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
26 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
pymc-artifact-style
description
Apply PyMC Labs' house style to every artifact you produce — reports, PDFs, slide decks, charts, images, notebooks. Use whenever you generate something a person will look at, before you deliver it.
# PyMC artifact style Everything you hand a user is a PyMC Labs deliverable and should look like one. A client skims a report; polish is what makes the content land. This is PyMC's own style — never substitute a client's brand colors unless the user explicitly asks for a client-branded artifact. **The house style is a real Typst template, not a description of one.** It comes from `pymc-labs/pymc-labs-report-template`, and the parts you need — the report class, the brand fonts, the logo, the cover art, the matplotlib style — are **bundled inside this skill**. Build through them. Do not improvise a "corporate report" look: numbered navy section bars, stat-tile rows and generic blue/orange charts are what this style exists to replace. ## Reports and PDFs — everything you need is bundled here The Typst report class, the brand fonts, the logo and the cover art all ship **inside this skill**. You do not need to clone anything and you do not need network access to the brand repos. ``` typst/pymc-report.typ the report class — import this typst/starter.typ minimal working report; copy it and replace content typst/report-example.typ the full worked example — read it for the helpers fonts/ Inter, Archivo Expanded, Fira Math, Fira Mono assets/pymc-labs-logo.png the cover logo (already wired as the default) assets/pymc-labs-logo-transparent.png same mark, white keyed out — use on slides assets/cover-4.png, -9.png the two approved cover backgrounds mpl/ matplotlibrc + plotstyle.py + axes.py ``` ### Build The `typst` CLI is not installed. Use the Python package — it ships the compiler as a wheel and installs in seconds: ```bash pip install typst ``` ```python import typst typst.compile( "starter.typ", output="report.pdf", root="..", # the skill dir, so ../assets and ../fonts resolve font_paths=["../fonts"], # REQUIRED — without it headings silently go serif ) ``` `font_paths` is not optional. Typst has no access to the bundled faces without it, and the failure is silent: the document still compiles, but every heading falls back to a serif and the result stops looking like a PyMC report. ### Two font traps, both verified the hard way - **Headings are `font: "Archivo"` with `stretch: 125%`** — *not* `font: "Archivo Expanded"`. Typst folds the OS/2 width class into the stretch axis, so the family registers as plain `Archivo`; asking for "Archivo Expanded" resolves to nothing and falls back to serif. - **Body is `font: "Inter"`.** The bundled statics register under family `Inter`. Do not ask for `Inter 18pt` — that is the Google Fonts optical-size packaging, which is not what ships here. Both are already set correctly in `typst/pymc-report.typ`. Do not "fix" them. ### Writing the document ```typ #import "pymc-report.typ": * #show: pymc-report.with( title: [Report title], subtitle: [One-line description], client: [Client name], author: [PyMC Labs], date: [August 2026], status: "Confidential", // cover + footer; none to hide paper: "a4", // or "us-letter" cover-background: 4, // approved cover art: 4 or 9 draft: false, abstract: [ Executive summary … ], outline-depth: 2, number-headings: false, // unnumbered headings are the house default ) = Section heading Body text … ``` **Heading numbering is a parameter, not a decision to improvise.** Short and presentational documents use unnumbered headings (the default) — hierarchy is typographic and the register is editorial. Long technical reports that need cross-references set `number-headings: true` and get `1`, `1.1`. Either is correct; hand-typed "01"/"02" prefixes are not. ### Layout helpers — the Tufte margin is the whole point The page is a ⅔ text column plus a ⅓ margin. Figures, captions, sidenotes and key numbers live in that margin, beside the prose that discusses them. Setting the content as a plain single column throws away the design. | Helper | Use | |---|---| | `#sidenote[…]` | numbered margin note — citations, sourcing, asides | | `#marginnote[…]` | un-numbered margin commentary | | `#dtable(…)` | table with Butterick rules (heavy top/bottom, light header rule, **no verticals**) | | `#flowfigure(x, caption: […], label: <id>)` | figure/table in the text column, caption in the margin | | `#marginfigure(…)` | small figure entirely in the margin | | `#widefigure(…)` | spans text + margin | | `#fullpagefigure(…)` | its own page | | `#widetable(dtable(…), caption: […])` | full-width, page-breakable — tables taller than a page | | `#keyfigure[value][label]` | large key-number callout in the margin | | `#executive-summary[…]` | the summary panel | | `#callout[…]` | in-flow emphasis box | | `#quotebox(by: [Name])[…]` | pull quote, colored spine | | `#appendix("A", [Title])` | appendix divider | Cross-reference with `@label`, and attach labels via the helper's `label:` argument — never a trailing `<label>`, which errors with `cannot reference context`. ## Brand palette — these exact hexes | Token | Hex | Use | |---|---|---| | navy | `#0C1F40` | body text, headings, first series | | periwinkle | `#9FAAE2` | accent, series | | aqua | `#B4E7DD` | rules, spines, series | | peach | `#F6AE72` | single status accent — use sparingly | | soft-white | `#F7F7F7` | code slabs, fills | Variants — light: navy `#798496`, peri `#CAD0EF`, aqua `#D6F2EC`, peach `#FAD2B1`. Dark: navy `#08142A`, peri `#676E93`, aqua `#759690`, peach `#A0714A`. Navy text on white. Color earns its place (Butterick) — the accent punctuates, it does not decorate. ## Typography | Role | Face | |---|---| | Body | **Inter** — ask for family `Inter` | | Headings | **Archivo Expanded** — ask for `Archivo` at `stretch: 125%` | | Math | **Fira Math**, weight 300 | | Code | **Fira Mono** on soft-white | Headings are unnumbered by default — hierarchy is typographic, the register is editorial. ## Charts — use the bundled matplotlib style ```python import matplotlib as mpl mpl.rc_file("mpl/matplotlibrc") # brand palette, Inter, navy bold titles ``` `mpl/plotstyle.py` carries `PALETTE`, `PALETTE_LIGHT`, `PALETTE_DARK` and a `fill_between` patch that gives clean edges; `mpl/axes.py` adds `add_axis_end_tick_caps`. Import them alongside the rc if you want the helpers. ArviZ draws through matplotlib, so `az.plot_posterior`, `az.plot_trace` and friends inherit the style once the rc is loaded. Save figures as **vector PDF** and embed with `image("fig.pdf")`. The rc sets `figure.figsize: 4.8, 3.0` — 122 mm, exactly the Typst text column — so figures land at native scale instead of being resampled. Needs matplotlib ≥ 3.10.1; do not switch to SVG path output (the Inter statics share a PostScript name and SVG path-mode collides bold/regular glyphs). The palette the rc cycles, if you need it by hand: ``` 0C1F40 navy F6AE72 peach 9FAAE2 periwinkle 759690 aqua-dark 798496 navy-light E0886A peach-mid 676E93 peri-dark B4E7DD aqua ``` ## Chart rules that matter more than color - **Assign series colors in the cycle's fixed order.** Never reorder by rank — a filter that drops a series must not repaint the survivors. - **Never a dual y-axis.** Two measures of different scale become two charts, small multiples, or an index to a common base. - **Sequential: one hue, light→dark. Diverging: two hues, neutral midpoint.** Never a rainbow, never a hue at a diverging midpoint. - **A legend whenever there are 2+ series.** With ≤ 4, label directly too. Identity must never rest on color alone. - **Beyond the cycle, do not invent another color.** Fold the tail into "Other", or use small multiples. - **Label the axes and name the units.** The title states the finding, not the variable names. ## Slide decks (.pptx) — render the slides, do not typeset them There is no PowerPoint template. Build a deck by typesetting each slide in Typst at slide dimensions, rendering it to PNG, and placing one full-bleed image per slide. The house style then survives the trip, because the fonts are baked into the pixels. ```python import typst from pptx import Presentation from pptx.util import Inches # 1. One Typst file per slide, 16:9 with no margin: # #set page(width: 13.333in, height: 7.5in, margin: 0pt) typst.compile("slide1.typ", output="slide1.png", root="..", font_paths=["../fonts"], format="png", ppi=144) # 144 → 1920x1080 # 2. Blank layout, picture at full bleed. prs = Presentation() prs.slide_width, prs.slide_height = Inches(13.333), Inches(7.5) for png in slides: s = prs.slides.add_slide(prs.slide_layouts[6]) # 6 is the blank layout s.shapes.add_picture(png, 0, 0, width=prs.slide_width, height=prs.slide_height) prs.save("deck.pptx") ``` **Do not build slides out of pptx text boxes.** A text run stores the font by *name*, and Inter and Archivo Expanded are not installed on the machines that open the file — PowerPoint and Google Slides silently substitute a generic sans and the deck stops looking like PyMC. This is the same failure as the `font_paths` trap above, one layer further out: the PDF survives because Typst embeds the faces, and a pptx has nothing to embed. The cost is real: rendered slides are images, so the text is no longer editable and does not reflow. Slide order, deletion, and speaker notes still work. If the recipient needs to edit the words, say so and hand over the Typst sources — do not quietly ship a deck that cannot be edited. ### The logo has no transparency — use the keyed copy `assets/pymc-labs-logo.png` is RGBA but every alpha byte is 255. It carries an opaque white rectangle, so it renders as a visible white box on any background that is not already white. RGBA in the mode string is not evidence of transparency — check the alpha channel's actual range. Use `assets/pymc-labs-logo-transparent.png`, the same mark with the white keyed out. `assets/pymc-marketing-logo.png` already has real alpha and needs nothing. Two separate things go wrong, and fixing one does not fix the other: - **The box** — solved only by keying. Moving the logo onto the gradient cover art makes the box less obvious against pale artwork, but it is still there. - **Legibility** — the wordmark is dark grey. Even keyed, it disappears into navy. There is no light version of the mark bundled here, so put the logo on a light ground: `cover-4.png` / `cover-9.png`, or white. Not a navy fill. ## When the template repo is unreachable Match the palette and typography by hand: navy body and headings, aqua rules, peach for a single status accent, soft-white code slabs, Inter (or the closest humanist sans available). Tables get horizontal rules only. Say plainly in the delivery that this is an unbranded fallback and the binding is missing — do not quietly ship something that looks nothing like a PyMC report. There is no Word or Google Docs template. For a Docs deliverable, apply the palette manually, or export a PDF from the Typst template and attach that — the PDF path is the one with a real template behind it. ## Sales collateral is a different standard Proposals and sales material follow `teams/sales/` in `daimon-memory` (navy `#1e3a5f`, Calibri), which deliberately differs from the report style above. Do not mix them. If unsure which applies, ask — a modeling report and a proposal are not interchangeable.
View on GitHub