Switch branches/tags
Nothing to show
Latest commit 3f306f9 Jul 15, 2017 @LLFourn LLFourn Re-implement auto-loading .spit.json
well, formally it was .spitsh.json

👻 Spook in the Shell 👻 (Spit-sh) Build Status

Spook in the Shell (Spit or Spit-sh), is Perl-6-like language that compiles into modular, dynamic and testable shell scripts. Its purpose is to specify and test configurations for modern UNIX-like systems. It's currently pre-Alpha software - use it at your own risk

Configuration as a Shell Script

Here are a few of the goals of Spit-sh as a configurtion utility:

  • It shouldn't require any software on the target system other than /bin/sh, the POSIX shell utilities and a package manager.
  • It shouldn't try and handle delivery of the scripts to the target system. (Other tools can do this).
  • It should be appropriate for specifying container images.
  • It must be easy to write, document, test and distribute modules.
  • Like Perl 6:
    • It must be test-centric and have a specification test suite written in the language itself.
    • The core classes, symbols and routines should be defined in the language itself.
    • It must be -Ofun 👻🐚💕🦋


To get a picture of where Spit is going take a look at this code:

.install unless Pkg<nc>; # install nc unless it's already there
ok Cmd<nc>,"nc command exists now"; # test the nc command is there

You can compile this for CentOS with:

spit --os=centos eval '.install unless Pkg<nc>; ok Cmd<nc>,"nc command exists now"'

Which ouputs the following shell at the time of writing:

  e(){ printf %s "$1"; }
  exec 4>/dev/null
  installed(){ yum list installed "$1" >&4 2>&4; }
  install(){ yum install -y $1 >&4 2>&4; }
  exists(){ command -v "$1" >&4; }
  exec 3>&1
  say(){ printf '%s\n' "$1" >&3; }
  note(){ printf '%s\n' "$1" >&2; }
  die(){ note "$1" && kill "-TERM" $$ >&4; }
  ok(){ test "$1" && say "✔ - $2" || die "✘ - $2"; }
  if ! installed nc; then
    install nc
  ok "$(exists nc && e 1)" 'nc command exists now'

If you have docker installed you can test this with:

# --in-docker --rm's the container
spit eval '.install unless Pkg<nc>; ok Cmd<nc>,"nc command exists now"' --in-docker=centos
✔ - nc command exists now

Unfortunately on Debian the package is named 'netcat'. Let's deal with that:

# install-nc.sp
constant Pkg $nc = on {
    Debian { 'netcat' }
    Any    { 'nc' } # the default

.install unless $nc;
ok Cmd<nc>,"nc command exists now";

And now it should work on both the RHEL and Debian families of Linux distributions.

spit --in-docker=debian:latest compile install-nc.sp
✔ - nc command exists now


Spit is written in Perl 6 and requires rakudo and something to install Perl 6 ecosystem modules with like zef.

zef install Spit

and run

spit eval 'say "hello world"'

To check it's working.

note rakudo star is too far behind at the moment. You need to build from rakudo/nom because Spit uses some features recently added to rakudo. Hopefully it will keep compatibility with rakudo star in the future.


Documentation is very much a work in progress but what exists is under: doc/. DOCUMENTATION

Project Layout

  • The Perl 6 Spit compiler module is in lib
  • The actual Spit source code is under resources/src
  • The core spit modules are under resouces/core-lib (right now just Test.sp)
  • The spec tests are in spec.


There's a lot to do before Spit becomes a genuinely useful tool.

  • If you like grammars and abstract syntax trees you can help develop the compiler
  • You can add support for an operating system/userland by writing Spit code that passes the spec tests
  • Try it out, provide bug reports, useful criticism and feature ideas under the issues github tab
  • Figure out how it works and write documentation