typeclaw 0.37.4 → 0.37.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/package.json +1 -1
  2. package/src/agent/doctor.ts +6 -1
  3. package/src/agent/plugin-tools.ts +23 -1
  4. package/src/agent/subagents.ts +146 -14
  5. package/src/agent/todo/scope.ts +4 -2
  6. package/src/agent/tools/channel-reply.ts +7 -9
  7. package/src/bundled-plugins/doc-render/index.ts +10 -0
  8. package/src/bundled-plugins/doc-render/skills/typeclaw-render-pdf/SKILL.md +171 -165
  9. package/src/bundled-plugins/doc-render/templates/lib.typ +339 -0
  10. package/src/bundled-plugins/github-cli-auth/gh-command.ts +95 -11
  11. package/src/bundled-plugins/github-cli-auth/git-command.ts +11 -0
  12. package/src/bundled-plugins/github-cli-auth/index.ts +68 -7
  13. package/src/bundled-plugins/memory/index.ts +9 -6
  14. package/src/bundled-plugins/memory/load-memory.ts +16 -2
  15. package/src/bundled-plugins/memory/slug.ts +19 -0
  16. package/src/bundled-plugins/security/policies/private-surface-read.ts +4 -1
  17. package/src/channels/adapters/github/inbound.ts +68 -43
  18. package/src/channels/adapters/github/index.ts +57 -9
  19. package/src/channels/adapters/github/recover-failed-deliveries.ts +270 -0
  20. package/src/channels/adapters/kakaotalk.ts +5 -1
  21. package/src/channels/adapters/mention-hints.ts +17 -0
  22. package/src/channels/manager.ts +77 -1
  23. package/src/channels/router.ts +181 -12
  24. package/src/cli/compose.ts +11 -2
  25. package/src/cli/dreams.ts +2 -2
  26. package/src/cli/inspect.ts +2 -2
  27. package/src/cli/logs.ts +2 -2
  28. package/src/cli/mount.ts +5 -5
  29. package/src/cli/require-agent-dir.ts +31 -0
  30. package/src/cli/restart.ts +2 -1
  31. package/src/cli/shell.ts +2 -2
  32. package/src/cli/start.ts +2 -1
  33. package/src/cli/stop.ts +2 -2
  34. package/src/cli/tui.ts +20 -6
  35. package/src/cli/ui.ts +13 -0
  36. package/src/compose/restart.ts +1 -1
  37. package/src/compose/start.ts +4 -2
  38. package/src/config/config.ts +200 -9
  39. package/src/container/shared.ts +18 -0
  40. package/src/container/start.ts +1 -1
  41. package/src/cron/consumer.ts +3 -3
  42. package/src/hostd/client.ts +48 -52
  43. package/src/hostd/daemon.ts +82 -39
  44. package/src/hostd/paths.ts +22 -2
  45. package/src/hostd/spawn.ts +7 -0
  46. package/src/init/dockerfile.ts +11 -8
  47. package/src/init/kakaotalk-auth.ts +2 -2
  48. package/src/init/packagejson.ts +2 -2
  49. package/src/plugin/loader.ts +7 -4
  50. package/src/sandbox/session-tmp.ts +6 -1
  51. package/src/secrets/export-claude-credentials-file.ts +2 -2
@@ -1,26 +1,29 @@
1
1
  ---
2
2
  name: typeclaw-render-pdf
3
- description: "The ONLY supported way to render Markdown into a polished, professional PDF (and optionally attach it to a channel). Load this whenever you need to deliver a document as a PDF rather than raw markdown — reports, summaries, briefs, meeting notes, docs, render report, export document, anything a human would want to download, print, or forward, including a researcher's report file shipped as a Slack/Discord attachment. Triggers: 'make a PDF', 'export to PDF', 'markdown to PDF', 'PDF report', 'render report', 'export document', 'the report', 'attach the report', 'send me a PDF', 'as a PDF', 'turn this into a document', a researcher/subagent result you want to ship as a file, 'PDF로', 'PDF로 만들어', 'PDF로 변환', 'PDF 첨부', '리포트', '보고서'. Provided by the bundled `doc-render` plugin: a small Typst toolchain is installed on first use via `bun add` (no PDF library is baked into the image), and a bundled render script does the compile. Handles CJK/Korean/Japanese/Chinese: CJK fonts are opt-in, so if the output has tofu (□□□) boxes it tells you to enable `docker.file.cjkFonts` and restart, then regenerates — it never auto-downloads a font. Also load before saying you cannot produce PDFs — you can. NEVER build a PDF with jsPDF, pdfkit, a canvas text dump, a headless-browser raw-text print, or Python ReportLab — those produce unrendered markdown and broken CJK; this skill is the only correct path. Covers the one-time install, the styled wrapper, the render command, and how to attach the PDF to Slack/Discord/Telegram/KakaoTalk. For operating on EXISTING PDFs (merge, split, extract text, fill forms), this is not the skill — use pypdf/qpdf instead; doc-render produces documents, it does not read them."
3
+ description: "The ONLY supported way to render Markdown into a polished, professional PDF (and optionally attach it to a channel). Load this whenever you need to deliver a document as a PDF rather than raw markdown — reports, summaries, briefs, meeting notes, docs, render report, export document, anything a human would want to download, print, or forward, including a researcher's report file shipped as a Slack/Discord attachment. Triggers: 'make a PDF', 'export to PDF', 'markdown to PDF', 'PDF report', 'render report', 'export document', 'the report', 'attach the report', 'send me a PDF', 'as a PDF', 'turn this into a document', 'make it look good', 'beautiful PDF', 'nicer PDF', a researcher/subagent result you want to ship as a file, 'PDF로', 'PDF로 만들어', 'PDF로 변환', 'PDF 첨부', '리포트', '보고서', '예쁘게'. Provided by the bundled `doc-render` plugin: a small Typst toolchain is installed on first use via `bun add` (no PDF library is baked into the image), a bundled themed report library does the styling, and a bundled render script does the compile. The library ships four polished themes (editorial / modern / report / minimal) so the output looks deliberately designed, not like a default-template export. Handles CJK/Korean/Japanese/Chinese: CJK fonts are opt-in, so if the output has tofu (□□□) boxes it tells you to enable `docker.file.cjkFonts` and restart, then regenerates — it never auto-downloads a font. Also load before saying you cannot produce PDFs — you can. NEVER build a PDF with jsPDF, pdfkit, a canvas text dump, a headless-browser raw-text print, or Python ReportLab — those produce unrendered markdown and broken CJK; this skill is the only correct path. Covers the one-time install, picking a theme, the render command, and how to attach the PDF to Slack/Discord/Telegram/KakaoTalk. For operating on EXISTING PDFs (merge, split, extract text, fill forms), this is not the skill — use pypdf/qpdf instead; doc-render produces documents, it does not read them."
4
4
  ---
5
5
 
6
6
  # typeclaw-render-pdf
7
7
 
8
8
  You can produce professional PDFs from Markdown. The bundled `doc-render` plugin
9
- ships the render script; the only thing installed on demand is the
10
- [Typst](https://typst.app) compiler a single npm package the agent `bun add`s
11
- into its own `node_modules` the **first time** you need a PDF, then reuses. No
12
- Pandoc, no LaTeX, no headless browser, and no PDF toolchain baked into the image.
13
-
14
- The flow is: **(1)** install the compiler once (`bun add` — it lands in the
15
- agent's `node_modules`, surviving restarts), **(2)** write a styled `.typ`
16
- wrapper that reads your Markdown, **(3)** run the bundled render script. If a
17
- channel asked for the PDF, attach the result with `channel_send`.
18
-
19
- You do **not** need to learn Typst markup. The
20
- [`cmarker`](https://typst.app/universe/package/cmarker/) package renders your
21
- CommonMark (headings, lists, tables, code, blockquotes, footnotes, links,
22
- images). The wrapper only sets _styling_fonts, margins, headings, page numbers
23
- so the output looks deliberate, not like a default-template export.
9
+ ships two things: a **themed report library** (`lib.typ`) that does all the
10
+ styling, and a **render script** that does the compile. The only thing installed
11
+ on demand is the [Typst](https://typst.app) compiler a single npm package the
12
+ agent `bun add`s into its own `node_modules` the **first time** you need a PDF,
13
+ then reuses. No Pandoc, no LaTeX, no headless browser, no PDF toolchain baked
14
+ into the image.
15
+
16
+ The flow is: **(1)** install the compiler once (`bun add`), **(2)** have your
17
+ Markdown ready, **(3)** copy the theme library next to it and write a tiny
18
+ 4-line wrapper that picks a **theme**, **(4)** run the render script. If a channel
19
+ asked for the PDF, attach the result with `channel_send`.
20
+
21
+ You do **not** write Typst markup or hand-style anything. The library's
22
+ `report` template styles every Markdown elementheadings, lists, tables, code,
23
+ quotes, links, figures and adds a cover, running header, and page footer. The
24
+ [`cmarker`](https://typst.app/universe/package/cmarker/) package converts your
25
+ CommonMark to Typst; the theme makes it look designed. **Your only real choice is
26
+ which theme fits the document.**
24
27
 
25
28
  > **This is the only supported way to make a PDF from Markdown in TypeClaw.**
26
29
  > Do **not** reach for `jsPDF`, `pdfkit`, a `<canvas>` text dump, a
@@ -34,7 +37,9 @@ images). The wrapper only sets _styling_ — fonts, margins, headings, page numb
34
37
 
35
38
  - A research report, brief, or summary the user wants as a downloadable file.
36
39
  - A subagent (e.g. the `researcher`) handed you a `research-<slug>.md` to ship as a PDF.
37
- - Any channel message asking for "a PDF" / "the report attached" / "PDF로 보내줘".
40
+ - Any channel message asking for "a PDF" / "the report attached" / "예쁘게 PDF로".
41
+ - Anyone complaining a previous PDF looked "plain" — switch theme and/or follow
42
+ the design tips below; do not hand-roll a new styling system.
38
43
 
39
44
  When plain markdown in chat is fine, **don't** make a PDF. This is for when a
40
45
  _file_ is the deliverable.
@@ -52,11 +57,9 @@ this only runs once per container life:
52
57
  bun add @myriaddreamin/typst-ts-node-compiler@0.7.0
53
58
  ```
54
59
 
55
- The `@0.7.0` pin embeds Typst 0.14.2 and keeps the toolchain reproducible a
56
- future npm release can't silently change the embedded Typst version or the API
57
- the render script depends on. If you forget this step, the render script in
58
- Step 3 stops with the exact `bun add` line to run, so you can also just try the
59
- render and follow its guidance.
60
+ The `@0.7.0` pin embeds Typst 0.14.2 and keeps the toolchain reproducible. If you
61
+ forget this step, the render script in Step 3 stops with the exact `bun add` line
62
+ to run, so you can also just try the render and follow its guidance.
60
63
 
61
64
  > **Where it goes:** the agent's own `node_modules` — the canonical home for
62
65
  > executable dependencies, gitignored, not user-facing. Do **not** create a
@@ -67,80 +70,92 @@ render and follow its guidance.
67
70
 
68
71
  Use an existing markdown file (yours or a subagent's), or `write` your content to
69
72
  a markdown file. Standard CommonMark plus tables and footnotes all work. Put the
70
- `.md` and the `.typ` (Step 2) in the same directory so the wrapper's relative
71
- `read("...")` resolves any agent-writable directory works (`workspace/`,
72
- `public/`, `mounts/`, or wherever the source `.md` already lives, e.g. a
73
- researcher's report under `public/`). There is no required directory; keep the
74
- two files together and run the render from there.
73
+ `.md`, the copied `lib.typ`, and the `.typ` wrapper (Step 2) in the **same
74
+ directory** so the wrapper's relative `read("...")` and `#import "lib.typ"` both
75
+ resolve. Any agent-writable directory works (`workspace/`, `public/`, `mounts/`,
76
+ or wherever the source `.md` already lives, e.g. a researcher's report under
77
+ `public/`). There is no required directory; keep the three files together and run
78
+ the render from there.
75
79
 
76
- ## Step 2 — write the styled wrapper
80
+ ## Step 2 — pick a theme and write the wrapper
77
81
 
78
- `write` a `.typ` next to your markdown, pointing `read("...")` at the markdown
79
- filename. The wrapper below is a clean, professional **starting point** — not a
80
- fixed template. Design the document to fit its content and audience: a dense
81
- technical brief wants tighter margins than an airy exec summary; a launch report
82
- might open with a cover banner. Adjust fonts, spacing, and structure freely, and
83
- reach for the **Rich elements** palette below when plain prose isn't enough.
82
+ First, **copy the bundled theme library** next to your markdown (Typst's
83
+ workspace sandbox only resolves imports under the render's working directory, so
84
+ the library must sit beside the wrapper an absolute import from outside won't
85
+ resolve):
86
+
87
+ ```sh
88
+ cd /agent/workspace # or wherever your .md lives (public/, mounts/, …)
89
+ cp /agent/node_modules/typeclaw/src/bundled-plugins/doc-render/templates/lib.typ .
90
+ ```
91
+
92
+ Then `write` a tiny `.typ` wrapper next to the markdown. This is the **entire**
93
+ wrapper — you do not style anything yourself; the theme does it:
84
94
 
85
95
  ```typst
86
- #set document(title: "Report")
87
- #set page(
88
- paper: "a4",
89
- margin: (x: 2.5cm, y: 2.75cm),
90
- numbering: "1",
91
- footer: context align(center, text(size: 9pt, fill: luma(120))[
92
- #counter(page).display("1 / 1", both: true)
93
- ]),
94
- )
95
- #set text(font: ("Libertinus Serif", "New Computer Modern", "Noto Serif CJK KR"), size: 11pt, lang: "en")
96
- #set par(justify: true, leading: 0.68em, spacing: 1.1em)
97
-
98
- #show heading: set text(weight: "semibold")
99
- #show heading.where(level: 1): it => block(width: 100%, above: 1.4em, below: 0.9em)[
100
- #text(size: 1.5em, it.body)
101
- #v(-0.4em)
102
- #line(length: 100%, stroke: 0.5pt + luma(200))
103
- ]
104
- #show link: it => text(fill: rgb("#1a56db"), underline(it))
105
- #show quote.where(block: true): it => block(
106
- inset: (left: 1em), stroke: (left: 2pt + luma(200)),
107
- text(style: "italic", fill: luma(80), it.body),
96
+ #import "lib.typ": report, callout, kpi, kpi-row, pullquote
97
+ #show: report.with(
98
+ theme: "editorial", // editorial | modern | report | minimal
99
+ title: "Edge-AI Quarterly Brief",
100
+ subtitle: "Q2 2026 · Internal Distribution",
101
+ date: "2026-06-17",
102
+ author: "Research",
108
103
  )
109
- #show raw.where(block: true): it => block(
110
- fill: luma(245), inset: 8pt, radius: 4pt, width: 100%, text(size: 9pt, it),
111
- )
112
- #show table: set table(stroke: 0.5pt + luma(200))
113
-
114
104
  #import "@preview/cmarker:0.1.8"
115
- #cmarker.render(read("report.md"), h1-level: 1, blockquote: quote.with(block: true))
105
+ #cmarker.render(
106
+ read("report.md"),
107
+ h1-level: 1,
108
+ blockquote: quote.with(block: true),
109
+ // makes the helpers available to <!--raw-typst …--> snippets in the markdown
110
+ scope: (callout: callout, kpi: kpi, kpi-row: kpi-row, pullquote: pullquote),
111
+ )
116
112
  ```
117
113
 
118
- Notes:
119
-
120
- - `read("report.md")` is **relative to the render's working directory**, so Step 3
121
- `cd`s into the directory holding the `.typ` and `.md` before running. Keep them
122
- together.
123
- - Fonts `Libertinus Serif` / `New Computer Modern` are bundled with Typst (no font
124
- install) and carry the Latin text. `"Noto Serif CJK KR"` is appended as the
125
- fallback so Korean/CJK glyphs resolve per-glyph wherever the Latin fonts have no
126
- glyph, leaving Latin runs untouched. It is only present when the container's
127
- `cjkFonts` toggle is on see "## Handling CJK content".
128
- - `cmarker` fetches from the Typst package registry on first compile (the same
129
- network the `bun add` step needs). It caches under the render's `$HOME`, which
130
- in a sandboxed (channel/guest) session is per-session scratch so a later
131
- session may re-fetch it. That's a one-time network hit, not an error.
114
+ ### Choosing the theme
115
+
116
+ Pick the one that fits the document's purpose. All four are built on the fonts
117
+ that ship in the container, so they render identically everywhere.
118
+
119
+ - **`editorial`** magazine look: a dedicated cover page, smallcaps tracked
120
+ headings, booktabs tables, wine accent. The elegant default for prose: reports,
121
+ briefs, memos, articles.
122
+ - **`modern`** startup look: a bold bleed-bar masthead, accent-bar headings,
123
+ airy ragged-right, indigo accent, accent-header tables. Product/launch briefs,
124
+ updates, anything that should feel current.
125
+ - **`report`** data / consulting look: a cover page with a full accent band,
126
+ accent-ruled section heads, strong navy zebra tables, plus `kpi()` and
127
+ `pullquote()` helpers. Boardroom-ready analyses and data reports.
128
+ - **`minimal`** — Apple-clean: a spacious title block, large light headings, no
129
+ running header, generous margins, ultra-light tables. Short notes, letters,
130
+ one-pagers.
131
+
132
+ When unsure, use `editorial`. If a user said the last PDF looked plain, try
133
+ `modern` or `report` (the most visibly "designed") and apply the tips below.
134
+
135
+ ### Optional knobs
136
+
137
+ - `accent: rgb("#0f766e")` — override the theme's accent color (links, rules,
138
+ headings, cover, table headers). Omit or pass `accent: auto` for the theme
139
+ default.
140
+ - `cover: "page" | "masthead" | "title" | none` — override the cover treatment
141
+ (`page` = dedicated cover page, `masthead` = bold top block, `title` = compact
142
+ title block), or `none` to drop it (e.g. a short memo). Omit for the theme
143
+ default.
144
+ - Omit `title` entirely and no cover is drawn — useful when the markdown already
145
+ opens with its own H1.
132
146
 
133
147
  ## Step 3 — render
134
148
 
135
149
  The render script is **bundled with the plugin** — you do not write it. It lives
136
150
  at `/agent/node_modules/typeclaw/src/bundled-plugins/doc-render/render.ts`.
137
151
 
138
- **`cd` into the directory holding your `.typ` and `.md` first** — your shell
139
- starts at the agent root, and the wrapper's `read("report.md")` resolves relative
140
- to the render's working directory, so you must run it from there:
152
+ You should already be `cd`'d into the directory holding your `.typ`, `.md`, and
153
+ the copied `lib.typ` (from Step 2). The wrapper's `read("report.md")` and
154
+ `#import "lib.typ"` both resolve relative to the render's working directory, so
155
+ you must run it from there:
141
156
 
142
157
  ```sh
143
- cd /agent/workspace # or wherever your .typ + .md live (public/, mounts/, …)
158
+ cd /agent/workspace # or wherever your .typ + .md + lib.typ live
144
159
  bun run /agent/node_modules/typeclaw/src/bundled-plugins/doc-render/render.ts report.typ report.pdf
145
160
  ```
146
161
 
@@ -155,12 +170,68 @@ issue and do **not** switch to another PDF library (it won't help). Any other
155
170
  error is a real Typst compile error (usually raw HTML or an unsupported markdown
156
171
  extension) and names the offending line — simplify that part and re-run.
157
172
 
173
+ ## Make it genuinely beautiful (design tips)
174
+
175
+ A theme gets you 90% of the way. The rest is content discipline — the same things
176
+ that separate a designed document from a markdown dump:
177
+
178
+ - **Front-load structure.** A short lead paragraph under the title, then clear
179
+ `##` sections. Don't open with a wall of text.
180
+ - **Tables over repeated bullet stanzas.** If you're repeating the same fields
181
+ per item (name, value, status…), a table reads far better than N bullet lists.
182
+ The theme styles tables with clean rules and a header row.
183
+ - **Caption your images** so they read as figures, not floating screenshots:
184
+
185
+ ```markdown
186
+ <!--raw-typst
187
+ #figure(image("chart.png", width: 80%), caption: [Revenue trend, Q1–Q2 2026.])
188
+ -->
189
+ ```
190
+
191
+ Images default to a sensible max width; keep them to one strong figure per idea
192
+ rather than many raw dumps at random sizes.
193
+
194
+ - **Use callouts for what matters** — a risk, a key result, a caveat — instead of
195
+ bolding a whole paragraph. `callout` is exported by the library (pass it via
196
+ `scope:` as shown above), then used inside the markdown:
197
+
198
+ ```markdown
199
+ <!--raw-typst
200
+ #callout(kind: "warning", title: "Risk")[A single supplier covers 40% of NPUs.]
201
+ #callout(kind: "success")[Revenue grew 31% YoY, ahead of plan.]
202
+ -->
203
+ ```
204
+
205
+ Kinds: `note`, `tip`, `success`, `warning`, `danger`. Keep them rare — two or
206
+ three in a document read as deliberate; a wall of colored boxes reads as noise.
207
+
208
+ - **Lead with the numbers (data reports).** For a metrics-heavy document, open a
209
+ section with a row of KPI cards instead of burying figures in prose. `kpi` and
210
+ `kpi-row` are exported by the library (pass them via `scope:` as shown above):
211
+
212
+ ```markdown
213
+ <!--raw-typst
214
+ #kpi-row(
215
+ kpi("$5.5M", "Revenue", sub: "+31% YoY"),
216
+ kpi("124%", "Net retention", sub: "+6pt"),
217
+ kpi("63.4%", "Gross margin", sub: "+240bp"),
218
+ )
219
+ -->
220
+ ```
221
+
222
+ Use `pullquote("…", by: "…")` for a centered featured quote between sections.
223
+
224
+ - **Let whitespace breathe, but don't pad.** Trust the theme's rhythm; don't add
225
+ manual `#v(...)` spacers around everything.
226
+
158
227
  ## Handling CJK content
159
228
 
160
- CJK fonts are **opt-in** (the `docker.file.cjkFonts` toggle). When they are off,
161
- Typst still renders it just substitutes `.notdef` tofu (□) boxes for every
162
- Korean/Japanese/Chinese glyph. **Do not** download, vendor, or `curl` a font to
163
- work around this, and **do not** silently deliver a tofu PDF.
229
+ CJK fonts are **opt-in** (the `docker.file.cjkFonts` toggle). The themes already
230
+ list `Noto Serif CJK` / `Noto Sans Mono CJK` as fallbacks, so Korean/Japanese/
231
+ Chinese resolve automatically **when those fonts are present**. When the toggle
232
+ is off, Typst still renders it just substitutes `.notdef` tofu (□) boxes for
233
+ every CJK glyph. **Do not** download, vendor, or `curl` a font to work around
234
+ this, and **do not** silently deliver a tofu PDF.
164
235
 
165
236
  You don't need a pre-render gate: render first, then verify. If the source
166
237
  markdown contains CJK and the resulting PDF shows tofu boxes (or you know CJK
@@ -178,75 +249,6 @@ true` (use the `typeclaw-config` skill), ask them to `typeclaw restart`, and
178
249
  regenerate the PDF after the restarted container comes back. If the markdown has
179
250
  no CJK, this section doesn't apply.
180
251
 
181
- ## Rich elements (optional)
182
-
183
- When plain markdown isn't enough — a cover banner, callout boxes, multi-column
184
- sections, captioned figures — you don't switch to HTML (Typst doesn't render
185
- HTML). Instead, drop **raw Typst** into the markdown via `<!--raw-typst ... -->`
186
- comments. `cmarker` evaluates them as Typst (the `raw-typst: true` option is the
187
- default). The rest of the document stays plain markdown.
188
-
189
- Each snippet below is self-contained — paste it into your `.md` where you want the
190
- element. They use Typst built-ins only (no extra packages).
191
-
192
- **Cover banner** (top of a report):
193
-
194
- ```markdown
195
- <!--raw-typst
196
- #block(width: 100%, fill: rgb("#0f172a"), inset: 18pt, radius: 6pt)[
197
- #text(fill: white, size: 1.6em, weight: "bold")[Quarterly Business Review]
198
- #v(2pt)
199
- #text(fill: rgb("#94a3b8"), size: 0.95em)[Acme Robotics · Q2 2026 · Confidential]
200
- ]
201
- #v(1em)
202
- -->
203
- ```
204
-
205
- **Callout boxes** (info / warning — change the two colors for other variants):
206
-
207
- ```markdown
208
- <!--raw-typst
209
- #block(fill: rgb("#eff6ff"), stroke: (left: 3pt + rgb("#3b82f6")), inset: 12pt, radius: 4pt, width: 100%)[
210
- #text(weight: "bold")[Note.] Revenue grew 31% YoY.
211
- ]
212
- #v(0.6em)
213
- #block(fill: rgb("#fef2f2"), stroke: (left: 3pt + rgb("#ef4444")), inset: 12pt, radius: 4pt, width: 100%)[
214
- #text(weight: "bold")[Risk.] A single supplier covers 40% of NPUs.
215
- ]
216
- -->
217
- ```
218
-
219
- **Two-column section** (use `#colbreak()` to split):
220
-
221
- ```markdown
222
- <!--raw-typst
223
- #columns(2, gutter: 1.4em)[
224
- #text(weight: "bold")[Strengths]
225
- - Net retention 124%
226
- - Margin +240bps
227
- #colbreak()
228
- #text(weight: "bold")[Risks]
229
- - Supplier concentration
230
- - Partial FX hedging
231
- ]
232
- -->
233
- ```
234
-
235
- **Figure with caption** (swap the `rect(...)` for `image("chart.png")` to embed an
236
- image written next to the markdown):
237
-
238
- ```markdown
239
- <!--raw-typst
240
- #figure(
241
- rect(width: 60%, height: 48pt, fill: luma(245), stroke: 0.5pt + luma(180)),
242
- caption: [Revenue trend, Q1–Q2 2026.],
243
- )
244
- -->
245
- ```
246
-
247
- Keep it tasteful — a banner, a couple of callouts, and one good figure read as
248
- deliberate; a wall of colored boxes reads as noise.
249
-
250
252
  ## Rendering an _existing_ web page or HTML to PDF
251
253
 
252
254
  This skill renders **markdown you author**. To capture an **existing web page or
@@ -276,16 +278,17 @@ reports. For authored documents, stay on the Typst path above.
276
278
  ## If you got the markdown from a subagent
277
279
 
278
280
  The `researcher` subagent writes its report to `research-<slug>.md` and returns a
279
- `<report>` block naming the file. Point the wrapper's `read(...)` at that file,
280
- render in that file's directory, and attach. You do the PDF step — the
281
- researcher's `bash` is read-only and it only emits markdown by design.
281
+ `<report>` block naming the file. Copy `lib.typ` into that file's directory, point
282
+ the wrapper's `read(...)` at the report, render there, and attach. You do the PDF
283
+ step — the researcher's `bash` is read-only and it only emits markdown by design.
282
284
 
283
285
  ## Customizing this skill
284
286
 
285
- This is a bundled default. Want a different house style, a cover page with a
286
- logo, or a different converter? Copy this file to
287
- `.agents/skills/<your-name>/SKILL.md` (use a **different** `name`; bundled skills
288
- win name collisions) and edit it there.
287
+ This is a bundled default. Want a fifth theme, a cover page with a logo, or a
288
+ house style? Two options: (a) copy `lib.typ` into the document directory and edit
289
+ your local copy before rendering (one-off), or (b) for a durable change, copy this
290
+ file to `.agents/skills/<your-name>/SKILL.md` (use a **different** `name`; bundled
291
+ skills win name collisions) and point it at your own theme library.
289
292
 
290
293
  ## Known limitations
291
294
 
@@ -303,12 +306,15 @@ might expect:
303
306
 
304
307
  ## Don'ts
305
308
 
306
- - **Don't** hand-write Typst markup for the body. Let `cmarker` render the
307
- markdown; only style via `#set` / `#show` rules in the wrapper (and the optional
308
- raw-typst rich elements).
309
+ - **Don't** hand-write a styling wrapper. Use `#show: report.with(theme: …)` from
310
+ the bundled library; only reach for raw Typst (via `<!--raw-typst -->`) for
311
+ the occasional figure or callout.
312
+ - **Don't** import `lib.typ` by absolute path — copy it next to the markdown
313
+ first (Typst's workspace sandbox won't resolve an import from outside the
314
+ render's working directory).
309
315
  - **Don't** build a `package.json` / `node_modules` / a render script under
310
316
  `workspace/`. The compiler installs at the agent root via `bun add`; the render
311
- script is bundled with the plugin (at
312
- `/agent/node_modules/typeclaw/src/bundled-plugins/doc-render/render.ts`).
317
+ script and theme library are bundled with the plugin (under
318
+ `/agent/node_modules/typeclaw/src/bundled-plugins/doc-render/`).
313
319
  - **Don't** attach a PDF to a GitHub channel — that adapter rejects attachments.
314
320
  Link or inline instead.