2026-03-31

discontinued: sph-cms

web publishing with command-line and filesystem interface

discontinued

motivation

to publish lots of content on the web easily (text, pictures, audio and any other files)

features

content

  • direct file editing in the filesystem
  • command-line interface for metadata listing, content addition, mass tag editing and more
  • include other pages or links to them filtered by tags on a page
  • parameterised include with placeholders and conditionals
  • any file type is supported for inclusion. there are several default content types with special rendering: itml, plain, preformatted, url and csv. media is included using the html tag: png, jpg, svg, gif. other types are by default hyperlinked when included
  • itml is an indent based markup language with extendable custom dynamic expression support. for the syntax see itml
  • csv file inclusion rendered as one or multiple grouped tables based on a csv column
  • separate instances with the same codebase but different data sets possible. for example for multiple different sites on the same sph-cms version
  • bonus: inclusion of automatically extracted guile scheme code documentation for guile modules
  • interface

    • read-only html/http interface
    • html5 output using
      and tags to embed content
    • browse by tags
    • browse with pagination, optional content inlining while browsing, optionally sorted by title or modification time
    • atom feed for recently modified files with custom tag queries
    • view markup source for a page
    • thumbnails of customisable size for images
    • organisation

      • content tagging
      • tag filter queries with and/or/not, ##### fully supporting

      extension

      as a sph-web-app project, other projects can derive from it, import it, use and extend its routes and other features

      server

      • pages are text and any other type of files
      • metadata is stored in an automatically managed database, sph-dg
      • derivative configuration files

      example use cases

      online database

      have overview pages with hyperlinks to sub-pages filtered by tags to create mind map like websites, or pages that include content matching certain tags

      weblog

      browse a list of content ordered by modification time like a super minimal weblog

      custom site or webservice

      extend it with new url paths that call scheme procedures for custom responses

      terminal interface

      $ sph-cms --help

      parameters
        options ... command argument ...
      options
        --about | -a
        --dg-root
        --help | -h
        --interface
      options shared by all commands
        --dg-root[=string]
      commands
        content add :: tag ...
        content add-edit :: tag ...
        content delete :: content-id
        content display :: content-id
        content edit :: content-id
        content import :: format sources ...
        content list :: tag ...
        content path :: content-id
        start :: [environment project-name]
        statistics
        tag add :: tags content-id ...
        tag delete :: tag ...
        tag list :: content-id
        tag remove :: tags content-id ...
        tag replace :: tags tags-replacements content-id ...
        type list :: content-id
        type set :: type-name content-id ...
        type set-guess :: content-id ...

      the filesystem path of the database to use, the directory that contains a file named "metadata", can be specified as an option or in a environment variable named DG_ROOT

      default paths

      /browse

      lists all tags split into two groups based on how many elements they are used for

      /browse/link [/tag-or-tag-query...]

      • lists all content with all selected tags
      • supports a nestable expression syntax with and/or/not, for example "/essays/(not topic-a)"
      • when filtering content, two rows are displayed: one for adding non-ubiquitous tags to the query, and one for removing tags/expressions from the current query

      /browse/link.nonav [/tag-or-tag-query...]

      like /browse/link but without rendering the browse navigation, only a list of matching content

      /browse/content [/tag...]

      like browse/link but directly includes text content if it is below a certain file size. by default sorted by modification time

      /c/view/{base32-number}

      every content element has a database-unique base32 id

      /c/data/{hex-number}

      direct access to content files

      dependencies

      • guile
      • sph-web-app
      • sph-dg

      installation

      • install the dependencies
      • get the source code "git clone git://sph.mn/sph-cms"
      • unpack the archive and change to the unpacked/source directory

      setup

      • "./exe/sph-cms start" starts the application ("C-c" exits) with an scgi interface. if there are no errors, that likely means that the install of the sph-cms code is working
      • then to access it via http, an http server that supports scgi like nginx has to be configured like in the sph-web-app documentation
      • here are the example configurations for nginx from the web-app documentation nginx configuration example

      remote content editing

      • for files: mount the "data/files/" directory with sshfs or use rsync or git to synchronise the directory. because files are registered in the database, content can only be edited, not deleted or added this way
      • for metadata: load-balance two started instances of the same installation. pack the database with tar (the database is a sparse file), stop one instance, replace the database, start. repeat for the other instance. since the database stores little data, this usually takes only a few seconds

      possible enhancements

      • versioning of edits (can be implemented with (sph filesystem versioning))
      • access control (can be implemented with sph-lib-dg (sph storage permission))
      • user accounts (can be implemented with sph-lib-dg (sph storage user))
      • search (an extension could search through the content files)
      • use of record data structures for content elements (classes)
      • create one default configuration file stored with the project and a script to start nginx using that local configuration file so that no separate web server configuration is required
      • display links to pages that link to the currently visited content
      • check for broken links in the markup
      • management of remote instances with the sph-cms command
      • permalinks, content urls that do not change when content is moved between databases
      • template and style extensions

      license

      gpl3+

      alternatives

      • haunt static site generator
      • tekuti weblog application that uses git for versioning and tags for categorization
      • gollum wiki that uses git for versioning and has markdown support. used by github. see also omnigollum because gollum does not include access control
      • dokuwiki wiki with filesystem-based content storage
      • sph-web-publish