{"id":14779849,"url":"https://github.com/ruricolist/kiln","last_synced_at":"2026-02-16T03:34:53.180Z","repository":{"id":242254804,"uuid":"689421299","full_name":"ruricolist/kiln","owner":"ruricolist","description":"Infrastructure for scripting in Common Lisp","archived":false,"fork":false,"pushed_at":"2025-09-14T19:27:02.000Z","size":142,"stargazers_count":66,"open_issues_count":2,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-09-14T21:27:18.153Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Common Lisp","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ruricolist.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-09-09T18:47:20.000Z","updated_at":"2025-09-14T19:27:05.000Z","dependencies_parsed_at":"2024-06-01T19:13:11.064Z","dependency_job_id":"c64280c2-a2e2-4653-993b-717dd3501e92","html_url":"https://github.com/ruricolist/kiln","commit_stats":null,"previous_names":["ruricolist/kiln"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ruricolist/kiln","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ruricolist%2Fkiln","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ruricolist%2Fkiln/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ruricolist%2Fkiln/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ruricolist%2Fkiln/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ruricolist","download_url":"https://codeload.github.com/ruricolist/kiln/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ruricolist%2Fkiln/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29499615,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-16T02:07:14.481Z","status":"online","status_checked_at":"2026-02-16T02:03:22.852Z","response_time":115,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-09-17T01:01:01.253Z","updated_at":"2026-02-16T03:34:53.164Z","avatar_url":"https://github.com/ruricolist.png","language":"Common Lisp","funding_links":[],"categories":["Recently Updated","Interfaces to other package managers"],"sub_categories":["[Sep 15, 2024](/content/2024/09/15/README.md)","Third-party APIs"],"readme":"# Kiln - Practical Scripting in Common Lisp\n\nThe Kiln project enables using Common Lisp for scripting. Kiln is *not* a curated set of Lisp libraries: Kiln is an *infrastructure* (managing a hidden multicall binary) to make Lisp scripting efficient and ergonomic.\n\n“Scripting” means minimal overhead: writing small programs as single-file scripts, without an (explicit) compile step, as in Bash, sed, awk, TCL, Perl, Ruby, and Python. Kiln bridges the scripting edit-run-edit cycle and the interactive, incremental Lisp development style.\n\nCommon Lisp is designed to solve big problems. Kiln makes it easy to reach for Common Lisp to solve *small* problems. Kiln makes it practical to write *very* small scripts. Kiln scripts are cheap to the point where it makes sense to expose even small pieces of Lisp functionality to the shell.\n\nFor example, would you ever think of [`format` as an alternative to `awk`](scripts/format.lisp)?\n\n``` sh\n$ echo -e \"a b c\\nd e f\" | kiln format \"~:@(~a~),~a:~a~%\"\nA,b:c\nD,e:f\n```\n\nOr having the Lisp numeric tower in a [command-line calculator](scripts/math.lisp)?\n\n``` sh\n$ kiln math \"factorial(30)\"\n265252859812191058636308480000000\n```\n\nOr writing [shell loops with the loop macro](scripts/loop.lisp)?\n\n``` sh\n$ kiln loop for '@i' from 0 to 5 do '!echo $i'\n0\n1\n2\n3\n4\n5\n```\n\nYou can use `kiln help` to summarize the built-in subcommands. On a clean Kiln install, the output looks like this:\n\n``` sh\n$ kiln help\nargv:         Print parsed arguments as a list\ncommand:      Launch a subprocess with cmd\ncount:        Print number of arguments and input lines\necho:         Echo arguments to standard output\neval:         Eval arguments as Lisp forms\nfire:         Alias for rebuild\nformat:       Use format like awk\ngrep:         Grep files with CL-PPCRE\nhelp:         Print brief information about what scripts do\nloop:         Write shell loops with the loop macro\nmath:         Do math with C-style syntax but a Lisp numeric tower\nrandom:       Generate random numbers in a given range\nrange:        Print a range of numbers\nrebuild:      Rebuild kiln executable\nrepl:         Launch a simple REPL\nscript-cache: Inspect script cache\nself-test:    Perform self-test of Kiln itself\nsprof:        Invoke Kiln command with profiling\nversion:      Print the Kiln version\n```\n\nSee [INSTALL.md](./INSTALL.md) for installation instructions.\n\n## Caveats\n\nKiln, while usable, is currently in alpha, because its implementation (particularly the hot-reloading part) involves hacking ASDF internals. Kiln will only have a non-alpha release once it uses only ASDF’s APIs.\n\nKiln is currently only tested with SBCL on Linux. You will also need\nan ASDF recent enough to support package-local nicknames (so at least\n3.3.3.2).\n\n## What it does\n\nKiln provides two kinds of scripts (shebang scripts and package scripts) and two ways of loading scripts (hot reloading and rebuilding).\n\n### Scripting, two ways\n\nKiln supports two kinds of scripts: shebang scripts and package scripts.\n\n1. *Shebang scripts* are classic Unix scripts that start with `#!/usr/bin/env kiln`.\n2. *Package scripts* are a halfway point between Lisp and Unix. You can write Kiln scripts at the REPL as package-inferred systems. For example, after defining `local-scripts/myscript` as a local package, you can invoke it as `kiln myscript`.\n\nBoth shebang scripts and package scripts *must* define a `main` function. For shebang scripts, this should be `kiln-user:main`. For package scripts, this should just be a `main` function in the script’s package.\n\n#### Writing shebang scripts\n\nWriting shebang scripts is just like writing any script: start a file with `#!/usr/bin/env kiln`, make it executable, and put it in your path. (Or leave out the shebang and invoke it as `kiln ./myscript.lisp`.)\n\n``` shell\n$ cat \u003c\u003c \"EOF\" \u003e hello-world\n#!/usr/bin/env kiln\n(defun kiln-user:main (args)\n  (format t \"Hello, world!~%\"))\nEOF\n$ chmod +x hello-world\n$ ./hello-world\nHello, world!\n```\n\nOne difference from some scripting languages is that you do need to define a `main` function. (For shebang scripts, it has to be defined specifically in the `kiln-user` package.)\n\nThe main function takes a single argument, the list of command-line\narguments.\n\n#### Writing package scripts\n\n“Package scripts” are subsytems of package-inferred systems; their packages must define a `main` function.\n\nKiln has a way (`KILN_PATH_SYSTEMS`, discussed below) to tell which systems\nshould have their subsystems exposed as scripts. Kiln will dispatch to those subsystem’s packages’ scripts, through subcommands or multicalls, by calling their interned `main` function with the list of command-line arguments.\n\n### `KILN_PATH_SYSTEMS`\n\nThere is an internal “path” defining which systems to check for\nscripts. The highest-priority system on the path is always `local-scripts`, so\ndefining a file at `~/common-lisp/local-scripts/myscript.lisp` or\n`~/quicklisp/local-projects/local-scripts/myscript.lisp` implicitly\nmakes `myscript` accessible with Kiln, either as subcommands of the\nKiln executable (so `$ kiln myscript`) or through multicall. The lowest-priority system is Kiln itself. In between are the systems in the (colon-separated) `KILN_PATH_SYSTEMS` environment variable.\n\nFor example, if you set `KILN_PATH_SYSTEMS` to `my-fancy-scripts:scripts-i-found-somewhere`, and you attempt to invoke a script named `my-script`, Kiln will look in the following subsystems:\n\n1. `local-scripts/my-script`\n1. `my-fancy-scripts/my-script`\n1. `scripts-i-found-somewhere/my-script`\n1. `kiln/scripts/my-script` (built-in scripts)\n\n### Reloading, two ways\n\nKiln makes scripting practical in two ways: (aggressively optimized) hot-reloading and easy image dumping.\n\n1. It uses a whole bag of tricks to make hot-reloading of edited scripts (pacakage scripts or shebang scripts) as fast as possible.\n2. Kiln makes it trivial to dump a new image that bakes in *all* of your scripts and their dependencies, which can then be invoked either as subcommands (`kiln myscript`) or in multicall mode (`myscript` or `kiln-myscript` as a symlink to `kiln`).\n\n``` shell\n# Dump a new image containing all shebang scripts on the system path\n# and all package scripts on the Kiln path.\nkiln rebuild\n```\n\nIt *may* be possible to rebuild in parallel with [POIU][] (whether POIU works at all is very sensitive to the details of your environment):\n\n``` shell\n# Very experimental: use POIU to build the image in parallel.\nkiln rebuild --poiu\n```\n\nHot reloading is much faster than you would expect, as Kiln uses ASDF and\nOS tricks to reuse preloaded dependencies and control compilation to\nprioritize compilation speed.\n\n### Packaging scripts as applications\n\nIf you have a script sufficiently mature (or large) that you want you deliver it as a separate application, you can ask Kiln to build an image that just contains one system:\n\n``` shell\nkiln rebuild --target-file executable --target-system my-project\n```\n\nThis will result in Kiln loading `my-project` and creating an executable with `my-project:main` as its entry point. The resulting executable will not have any of Kiln’s support for scripting, but it will still use the [Kiln environment](#kiln-environment) settings.\n\n## Kiln environment\n\nWhen a Kiln script runs (through Kiln), the following are always true:\n\n- All ASDF systems present when Kiln was last rebuilt are marked as immutable and will not be reloaded.\n- All classes are finalized.\n- `*random-state*` has been re-initialized.\n- `*standard-output*` points to stdout, `*error-output*` and `*trace-output*` point to stderr, and `*terminal-io*` and `*debug-io*` are two-way streams on `*standard-input*` and `*error-output*`.\n- Unless `--debug` is passed to Kiln, `*compile-verbose*` `*compile-print*`, `*load-verbose*` and `*load-print*` are bound to `nil`.\n- There is a handler in place to exit on EOF on any of stdin, stderr, or stdout.\n- `*default-pathname-defaults*` is bound to the OS-level working directory.\n- A handler is in place for `SIGINT` (`C-c`). If `SIGINT` is not handled, then the process will exit in such a way callers can see it exited with sigint; see https://www.cons.org/cracauer/sigint.html.\n- There is a top-level error handler in place. Normally it prints the error (and a backtrace if Kiln gets `--debug` or `--backtrace`), and returns an error code based on the generic function `error-exit-code`. (If `--repl-on-error` is specified to Kiln, then it drops into a REPL instead.)\n- You can always use `kiln:exit` to exit with a particular exit code. (Unlike `uiop:quit` this is guaranteed to unwind.)\n\n[Buildapp]: https://www.xach.com/lisp/buildapp/\n[Roswell]: https://roswell.github.io/\n[adopt]: https://github.com/sjl/adopt\n[cl-launch]: https://www.cliki.net/cl-launch\n[clingon]: https://github.com/dnaeon/clingon\n[clon]: https://github.com/didierverna/clon\n[command-line-arguments]: https://github.com/fare/command-line-arguments\n[unix-opts]: https://github.com/libre-man/unix-opts\n[POIU]: https://gitlab.common-lisp.net/qitab/poiu\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fruricolist%2Fkiln","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fruricolist%2Fkiln","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fruricolist%2Fkiln/lists"}