palimpsest
Responding to a round of peer review usually means keeping four things consistent by hand: the revised manuscript, a tracked-changes version showing every edit, a response letter that cites specific passages and page numbers, and the certainty that no comment was missed.
Palimpsest makes the second, third and fourth of those derivable from the first. You mark changes inline in the manuscript and write your responses. Tracked changes, page numbers, quoted excerpts and cross-references are all generated at compile time, from the manuscript as it actually is right now.
This works because Typst 0.15’s experimental bundle export lets one compilation produce several documents that share a single introspection space.
While we wait for more and more publishers and academic journals to accept manuscripts written in Typst (a good thread on this here, I hope this package will be useful to some members of the Typst community.
What it looks like
manuscript.typ: mark changes inline, anchored to whatever comment they answer:
#import "@preview/palimpsest:0.1.0": *
#passage(<r1-2>)[
The sample size #rep[was not justified][was determined by a power calculation].
]
#deleted(<r1-2>, summary: [an outdated caveat about generalizability])[
An earlier caveat about generalizability, no longer needed.
]
responses.typ: write the reply, and let pinpoint cite the manuscript for you:
#import "@preview/palimpsest:0.1.0": *
#reviewer(1)[
#exchange(<r1-1>)[
The sample size is not justified.
][
Addressed as follows: #pinpoint(<r1-1>, excerpt: true)
]
#exchange(<r1-2>)[
This caveat is no longer accurate.
][
Agreed: #pinpoint(<r1-2>, excerpt: true)
]
]
main.typ: wire it all to your journal’s own template:
#import "@preview/palimpsest:0.1.0": *
#import "@preview/contexture:0.1.0": bundle
#show: bundle.with(
template: my-journal-template.with(title: [...], authors: ("...",)),
documents: (letter(exchanges: include "responses.typ"),),
)
#include "manuscript.typ"
Two compiles produce everything: typst compile --features bundle --format bundle main.typ for the clean submission, the same command with --input variant=tracked for the tracked version.
manuscript clean:
response clean:
That’s the clean run: no marks anywhere, and the letter quotes the accepted wording. Ask for the tracked variant instead, and both documents flip together:
manuscript tracked:
response tracked:
Same source, same anchor, two compiles.
Docs and examples
The full guide, one function (and every option) at a time, with a real compiled screenshot for each: https://eusebe.github.io/typst-contexture-site/palimpsest/
Some examples can be found here: https://github.com/eusebe/typst-palimpsest/tree/main/examples
I’d be glad to hear from anyone who tries palimpsest on a real revision (particularly on journal templates I haven’t tested against). Please don’t hesitate to report any bugs you’d like to see fixed or any features you’d like to see included in a future version.
Other packages
For anyone curious about the rest of the family: palimpsest sits on top of contexture, a small package that actually owns the bundle compile.
Two other packages are built the same way than palimpsest, and can even sit in the same documents: list:
-
checkitoff: fills in a reporting-guideline checklist (CONSORT, PRISMA, SPIRIT, STARD, STROBE). -
colophon: audits a manuscript as actually composed: word count by section, reading time, a figure/table inventory, labels never referenced, bibliography entries never cited.


