Like 'make' except: - Predicates can be based on arbitrary expressions, not just "file X is older than file Y". - Rules are more flexible and encourage structuring and reuse through functions. - Goals can be parameterized. - Program can run continuously to implement business rules. Differences from 'whenjobs': - Goals instead of variables. - Persistent (across session) variables exist, but are not central. - Doesn't use <<..>> for shell scripts (has a function 'sh' instead). Similarities to 'whenjobs': - Each shell script runs in its own temporary directory. Example Makefile rule and translation to goaljobs language: %.o: %.c cc -c $< -o $@ let goal compile c_file = require (file_exists c_file); let o_file = replace_substring ".c" ".o" c_file in target (file_exists o_file && file_newer o_file c_file); sh "cc -c %s -o %s" c_file o_file Example program: let package = "foo" let rec goal website_updated version = let tarfile = sprintf "%s-%s.tar.gz" package version in let tarpath = getenv "HOME" // "html" // tarfile in let url = sprintf "http://example.com/%s" tarfile in target (url_exists url); require (tarball_exists version); require (tarball_tested version); sh "rsync %s example.com:/html/" tarpath and goal tarball_tested version = let tarfile = sprintf "%s-%s.tar.gz" package version in let tarpath = getenv "HOME" // "html" // tarfile in let memkey = package ^ "_tested_" ^ version in target (memory_exists memkey); require (tarball_exists version); sh " tar zxf %s cd %s-%s ./configure make make check " tarpath package version; memory_set memkey "1" and goal tarball_exists version = let tarpath = getenv "HOME" // "html" // tarfile in target (file_exists tarpath); sh " cd $HOME/repos/%s git fetch git archive --prefix %s-%s/ v%s | gzip > %s-t mv %s-t %s " package package version version tarpath tarpath tarpath every 1 hour = let version = shout " cd $HOME/repos/%s git fetch git describe --tags --abbrev=0 --match='v*' " package in require (website_updated version)