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.
Scanned 9/5/2026
Install to Claude Code
npx -y skills add pymc-labs/daimon --skill pymc-artifact-style --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Pymc Artifact Style?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/pymc-labs-pymc-artifact-style)More formats (shields.io, HTML) on the badges page.
---
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.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!