Publ: Command-Line Interface

Last updated:

Publ extends the default flask command with some additional commands, which can be used for various useful things. In addition to this page, you can get detailed help from the command line with:

flask publ [command] --help

from within your Publ virtual environment (e.g. poetry run flask publ --help or env/bin/flask publ --help).

For usage of the flask command itself, see the Flask CLI documentation.


This command lets you force a database reindex, and will wait until the index finishes. This is useful for deployment scripts and the like.

It takes two arguments:

  • --fresh/-f: Start with a fresh index (i.e. remove all the cached data); this is useful if something weird has happened and you want a fresh start (if something weird has happened, please open an issue!)
  • --quiet/-q: Don’t show the progress indicator


This command can be used to generate an IndieAuth token for scripting purposes, such as for use with Pushl, or for testing authentication automatically.

For example:

TOKEN=$(flask publ token
curl -H "Authorization: Bearer $TOKEN"

will fetch the page with a token identifying the user as (as generated by your Publ site).

Note that the session key will need to match between wherever you’re running this and the actual site. If they do not match for some reason (for example, because you’re running in a different configuration) this token will not be valid.

This takes the following arguments:

  • --scope/-s: Generate the token with the specified scope (defaults to none)
  • --lifetime/-l: How long the token should be valid for, in seconds (default: 3600)

Note that token scopes are not currently used by Publ itself; this is provided largely to make it easier to extend Publ via the Python API, such as implementing a mechanism to automatically post content from external sources.


This command allows you to bulk-rename entries within one or more categories with a templatized filename. By default it gives things a name of {date} {sid} {title}, so e.g. names like:

20190204 3 Welcome to my new
20200101 1942 Happy new year!.md
20200704 DELETED Ugh never

Example usage:

### Give 'blog' entries a name like '20210101 Hello'
flask publ normalize -af "{date} {title}" blog

### Apply the default name to published entries in 'articles' and 'recipes'
flask publ normalize articles recipes

### Apply hyper-specific naming to every entry in the site
flask publ normalize -rf "{date}-{time}-{id}-{slug}"

It accepts the following arguments:

  • -r/--recurse: Include subdirectories
  • -a/--all: Apply to all entries, not just reachable ones (published, scheduled, hidden)
  • -n/--dry-run: Show, but don’t apply, changes
  • -f/--format TEXT: Filename format to use
  • -v/--verbose: Show detailed actions

And the following format tokens can be used in the string provided to -f/--format:

  • {date}: The entry’s publish date, in YYYYMMDD format
  • {time}: The entry’s publish time, in HHMMSS format
  • {id}: The entry’s ID
  • {status}: The entry’s publish status
  • {sid}: If the entry is reachable, the ID, otherwise the status
  • {title}: The entry’s title, normalized to filename-safe characters
  • {slug}: The entry’s slug text
  • {type}: The entry’s type

Note that entries in DRAFT status always get an {id} of DRAFT, even if an ID has been assigned.