Library / SDK
TryGhost/Casper avatar
TryGhost/Casper

Casper's ship script only pushes, the release draft comes from a postship hook, and locales/ sits beside instructions filed in another repository

A classic theme for Ghost

2,581 stars2,707 forksCSSMIT

At a glance

What is it?
Casper is the classic Handlebars theme for Ghost, compiled from CSS sources through Gulp and PostCSS and packaged as a zip for upload. Its front page credits the ship script with drafting the GitHub release when the script only pushes, its list of main files leaves out both error templates, and its translation instructions point at a different repository from the one holding the locales directory.
Who is it for?
Casper is worth starting from if you want a Ghost site that looks deliberate on the first page, and the code is commented well enough that reading it is a reasonable way to learn Handlebars in the shape a theme actually uses. Three things to know before you fork it.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly CSS, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • TryGhost/Casper2,581 ★ · +2
Star history
Repository2026-09-302026-11-14
TryGhost/Casper2.6k2.6k

2 Stars in the last 45 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

The ship script only pushes, and a postship hook does the drafting

The front page says that running ship checks the working tree is clean, pushes the commit and tag, and drafts the GitHub release from the changelog. The script does the first two and not the third:

code
    "ship": "STATUS=$(git status --porcelain); echo $STATUS; if [ -z \"$STATUS\" ]; then git push --follow-tags; else echo \"Uncomitted changes found.\" && exit 1; fi",
    "postship": "git fetch && gulp release"

The dirty check runs before the push and exits with status 1 on uncommitted work, printing a message with the word uncommitted misspelled as one word. The changelog draft comes from the separate `postship` entry, which fetches and then runs a gulp release task, and the release utilities it depends on are a pinned development dependency. So the release is two commands, and the one the page names is not the one that produces the artefact. If the gulp task fails, the tag is already pushed.

The list of main files leaves out both error templates

The front page enumerates six templates: `default.hbs` as the parent carrying the global header and footer, `index.hbs` for the post list, `post.hbs`, `page.hbs`, `tag.hbs` and `author.hbs`. The repository root holds two more, `error.hbs` and `error-404.hbs`, and neither appears in that list. The parent template relationship is the useful part of the design: `default.hbs` supplies the shell and the other five fill it, which is why a one-off template is created by prefixing rather than by editing. A page slug becomes a file name, so `page-about.hbs` serves an about page, `tag-news.hbs` serves a news archive and `author-ali.hbs` serves one author's posts. The naming means the specific file wins over the general one for the same route.

locales/ is in the repository and the translation instructions are not

The translations section is a single sentence and a link: it points at the readme of the theme-translations package inside a different repository, the one that holds the shared themes workspace, for how to build, edit or contribute translations. Meanwhile a `locales/` directory sits in this repository's root. So the files that hold the strings are here and the procedure for changing them is documented somewhere else, and the front page gives no path, no command and no format for a translator who has only cloned this theme. The same pattern appears in the icons section, which does stay local: the inline SVGs live under `/partials/icons` and are pulled in by partial name.

Three descriptions of what the theme is, and one of them is out of date

The repository calls itself a classic theme for Ghost, and immediately adds that it was originally the default and that the default these days is Source. The manifest description calls it a clean, minimal default theme for the Ghost publishing platform, in the present tense, and the registry categories are Minimal and Magazine together. Only the repository description and the front page agree that it is no longer the default. The declared demo is `https://demo.ghost.io`, the platform's own demo address rather than a preview of this theme on its own, so a screenshot in the manifest points at the same desktop and mobile images the demo site renders.

The manifest requires Node 22.12 and Ghost 5, and the page states neither

The engines block asks for Ghost at or above 5.0.0 and Node at or above 22.12.0, and the exact package manager is pinned as `[email protected]`. The development section instead says you need Node, pnpm and Gulp installed globally, then shows two commands:

bash
# install dependencies
pnpm install

# run development server
pnpm dev

So the front page gives no version floor for either runtime while the manifest enforces two, and it asks for a global Gulp that the dev script may not need. The dev script runs `gulp` from the local install, and the manifest pins gulp 5.0.1 as a development dependency, which pnpm puts ahead of anything global on the path for scripts. Styles are edited under `/assets/css/` and compiled into `/assets/built/`, and the zip task writes `dist/<theme-name>.zip` for upload.

The test suite is a theme validator, and CI differs by two flags

There is no unit test suite. The test script is `gscan .`, the Ghost theme validator, and the CI variant is `gscan --fatal --verbose .`, so the difference between a local run and a continuous integration run is that failures are fatal and the output is verbose. Both are preceded by the same hook, which builds the zip first, so validation always runs against a freshly packaged theme rather than the working directory. The PostCSS section claims that browser prefixes need never be written by hand because autoprefixer handles them for the latest two major versions of every browser, and names Color Mod as the second plugin, while the visible development dependencies also pin a minifier, cssnano 9.1.2, that the page does not mention. No configuration file for the browser list appears at the top level.

The default branch is the development version, at the released version number

The front page opens by saying this is the latest development version and that anyone wanting the latest release should go to the releases page. The manifest on that same branch reads 5.12.5, which is also the newest tag, published on 2026-09-21, with 5.12.4 three days earlier and 5.12.3 before that. The branch took a push on 2026-10-01 and is not archived. So the development branch is sitting on the released version rather than ahead of it, and the bump happens as part of publishing rather than after it. The release page documents that order: run a version command first, which updates the manifest and creates the matching commit and tag, then run ship.

A note explains why the version bump moved out of ship

The callout under the release steps explains a change in the two-command flow: pnpm version must be run first, because unlike the old yarn version, pnpm version is not interactive, and ship no longer performs the bump itself. That is a migration artefact, and the tree shows the shape of it: a pnpm lockfile and a pnpm workspace file at the root, the package manager field pinned to an exact version, and the note itself written as a comparison with the tool it replaced. The repository also carries `renovate.json` for dependency updates, and `AGENTS.md` and `CLAUDE.md` at the root, none of which appear in the front page's description of what the theme contains.

Editorial conclusion

Casper is worth starting from if you want a Ghost site that looks deliberate on the first page, and the code is commented well enough that reading it is a reasonable way to learn Handlebars in the shape a theme actually uses. Three things to know before you fork it. The release pipeline is split across npm lifecycle hooks, so a broken ship script fails at the push rather than at the draft, and the two error templates are not in the front page's file list even though they are in the tree. The theme requires Ghost 5 or later and Node 22.12 or later, and the front page mentions neither floor while asking for a global Gulp install that the pinned local copy makes unnecessary. And if you need to translate it, the locales directory is here but the instructions are not. The last commit landed on 2026-10-01 and the newest tag is v5.12.5 from 2026-09-21, so the default branch is close to a release rather than far from one, and the version in package.json already reads 5.12.5, which means a zip you build yourself is indistinguishable from the released one by version alone.

Frequently asked questions

How do I build the Casper theme for Ghost?

Styles are edited under /assets/css/ and compiled into /assets/built/ automatically. Development needs Node, pnpm and Gulp, after which pnpm install installs dependencies and pnpm dev starts the server. The zip task packages the theme into dist/<theme-name>.zip, which is the file you upload to a site, and pnpm zip runs it.

Which versions of Ghost and Node does Casper require?

The manifest requires Ghost at or above 5.0.0 and Node at or above 22.12.0, and pins pnpm as the package manager at 12.8.2. The front page gives no version floor for either runtime and instead says you need Node, pnpm and Gulp installed globally.

What does the ship script do when I publish a Casper release?

It checks for uncommitted changes, exits with an error if the tree is dirty, and otherwise pushes the commit and tag with follow-tags. It does not draft the GitHub release, despite what the front page says. That comes from the postship hook, which fetches and runs a gulp release task using the pinned release utilities.

How do I add an SVG icon to the Casper theme?

Icons are inline SVG files included as Handlebars partials and live under /partials/icons. You reference one by name, so the file at /partials/icons/rss.hbs is pulled in with the partial call for icons/rss. You can add your own by dropping files into the same directory.

Is Casper still the default theme for Ghost?

No. The front page says it was originally the default and that the default these days is Source. The manifest description still calls it the default theme in the present tense, and its registry categories list both Minimal and Magazine.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. TryGhost/Casper on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/tryghost-casper.svg)](https://hysenlabs.com/projects/tryghost-casper)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/tryghost-casper.svg)](https://hysenlabs.com/projects/tryghost-casper)

Was this useful?