{"id":13442720,"url":"https://github.com/fukamachi/qlot","last_synced_at":"2026-02-10T12:01:21.341Z","repository":{"id":19083510,"uuid":"22311104","full_name":"fukamachi/qlot","owner":"fukamachi","description":"A project-local library installer for Common Lisp","archived":false,"fork":false,"pushed_at":"2026-02-06T15:19:26.000Z","size":2197,"stargazers_count":540,"open_issues_count":15,"forks_count":47,"subscribers_count":21,"default_branch":"master","last_synced_at":"2026-02-06T19:31:18.307Z","etag":null,"topics":["common-lisp","package-manager"],"latest_commit_sha":null,"homepage":"https://qlot.tech","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/fukamachi.png","metadata":{"files":{"readme":"README.markdown","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"github":["fukamachi"]}},"created_at":"2014-07-27T13:05:21.000Z","updated_at":"2026-01-23T20:37:03.000Z","dependencies_parsed_at":"2023-12-20T12:24:47.747Z","dependency_job_id":"84e47400-e39e-4201-932f-da5f4f5c7229","html_url":"https://github.com/fukamachi/qlot","commit_stats":null,"previous_names":[],"tags_count":109,"template":false,"template_full_name":null,"purl":"pkg:github/fukamachi/qlot","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fukamachi%2Fqlot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fukamachi%2Fqlot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fukamachi%2Fqlot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fukamachi%2Fqlot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fukamachi","download_url":"https://codeload.github.com/fukamachi/qlot/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fukamachi%2Fqlot/sbom","scorecard":{"id":413369,"data":{"date":"2025-08-11","repo":{"name":"github.com/fukamachi/qlot","commit":"32284594df1f0e43b3ae61595d44a0488b0edf7e"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.2,"checks":[{"name":"Maintained","score":8,"reason":"3 commit(s) and 7 issue activity found in the last 90 days -- score normalized to 8","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":0,"reason":"Found 1/19 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/build-image.yaml:1","Warn: no topLevel permission defined: .github/workflows/ci-exec.yaml:1","Warn: no topLevel permission defined: .github/workflows/ci-scripts.yaml:1","Warn: no topLevel permission defined: .github/workflows/ci-windows.yaml:1","Warn: no topLevel permission defined: .github/workflows/ci.yaml:1","Warn: no topLevel permission defined: .github/workflows/release.yaml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE.txt:0","Info: FSF or OSI recognized license: MIT License: LICENSE.txt:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Signed-Releases","score":0,"reason":"Project has not signed or included provenance with any releases.","details":["Warn: release artifact 1.7.2 not signed: https://api.github.com/repos/fukamachi/qlot/releases/224777972","Warn: release artifact 1.7.1 not signed: https://api.github.com/repos/fukamachi/qlot/releases/216378560","Warn: release artifact 1.7.0 not signed: https://api.github.com/repos/fukamachi/qlot/releases/216299096","Warn: release artifact 1.6.1 not signed: https://api.github.com/repos/fukamachi/qlot/releases/210929002","Warn: release artifact 1.6.0 not signed: https://api.github.com/repos/fukamachi/qlot/releases/187111310","Warn: release artifact 1.7.2 does not have provenance: https://api.github.com/repos/fukamachi/qlot/releases/224777972","Warn: release artifact 1.7.1 does not have provenance: https://api.github.com/repos/fukamachi/qlot/releases/216378560","Warn: release artifact 1.7.0 does not have provenance: https://api.github.com/repos/fukamachi/qlot/releases/216299096","Warn: release artifact 1.6.1 does not have provenance: https://api.github.com/repos/fukamachi/qlot/releases/210929002","Warn: release artifact 1.6.0 does not have provenance: https://api.github.com/repos/fukamachi/qlot/releases/187111310"],"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Info: Possibly incomplete results: error parsing shell code: | can only immediately follow a statement: roswell/qlot.ros:0","Info: Possibly incomplete results: error parsing shell code: * must follow an expression: scripts/fetch.sh:35","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build-image.yaml:12: update your workflow using https://app.stepsecurity.io/secureworkflow/fukamachi/qlot/build-image.yaml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/build-image.yaml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/fukamachi/qlot/build-image.yaml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/build-image.yaml:21: update your workflow using https://app.stepsecurity.io/secureworkflow/fukamachi/qlot/build-image.yaml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/build-image.yaml:26: update your workflow using https://app.stepsecurity.io/secureworkflow/fukamachi/qlot/build-image.yaml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/build-image.yaml:29: update your workflow using https://app.stepsecurity.io/secureworkflow/fukamachi/qlot/build-image.yaml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/build-image.yaml:36: update your workflow using https://app.stepsecurity.io/secureworkflow/fukamachi/qlot/build-image.yaml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci-exec.yaml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/fukamachi/qlot/ci-exec.yaml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci-scripts.yaml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/fukamachi/qlot/ci-scripts.yaml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci-windows.yaml:21: update your workflow using https://app.stepsecurity.io/secureworkflow/fukamachi/qlot/ci-windows.yaml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci-windows.yaml:29: update your workflow using https://app.stepsecurity.io/secureworkflow/fukamachi/qlot/ci-windows.yaml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yaml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/fukamachi/qlot/ci.yaml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yaml:12: update your workflow using https://app.stepsecurity.io/secureworkflow/fukamachi/qlot/release.yaml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yaml:44: update your workflow using https://app.stepsecurity.io/secureworkflow/fukamachi/qlot/release.yaml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/release.yaml:65: update your workflow using https://app.stepsecurity.io/secureworkflow/fukamachi/qlot/release.yaml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yaml:76: update your workflow using https://app.stepsecurity.io/secureworkflow/fukamachi/qlot/release.yaml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/release.yaml:80: update your workflow using https://app.stepsecurity.io/secureworkflow/fukamachi/qlot/release.yaml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/release.yaml:85: update your workflow using https://app.stepsecurity.io/secureworkflow/fukamachi/qlot/release.yaml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/release.yaml:90: update your workflow using https://app.stepsecurity.io/secureworkflow/fukamachi/qlot/release.yaml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/release.yaml:93: update your workflow using https://app.stepsecurity.io/secureworkflow/fukamachi/qlot/release.yaml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/release.yaml:100: update your workflow using https://app.stepsecurity.io/secureworkflow/fukamachi/qlot/release.yaml/master?enable=pin","Warn: containerImage not pinned by hash: Dockerfile:1: pin your Docker image by updating fukamachi/sbcl to fukamachi/sbcl@sha256:9822f86a561928cb4263342b764b78f29a56f15baa4451505d71eedd94bc12d9","Warn: containerImage not pinned by hash: tests/Dockerfile:1: pin your Docker image by updating fukamachi/sbcl to fukamachi/sbcl@sha256:9822f86a561928cb4263342b764b78f29a56f15baa4451505d71eedd94bc12d9","Warn: downloadThenRun not pinned by hash: .github/workflows/ci-exec.yaml:27","Warn: downloadThenRun not pinned by hash: .github/workflows/ci.yaml:27","Warn: downloadThenRun not pinned by hash: .github/workflows/release.yaml:52","Warn: downloadThenRun not pinned by hash: .github/workflows/release.yaml:20","Info:   0 out of   8 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of  12 third-party GitHubAction dependencies pinned","Info:   0 out of   2 containerImage dependencies pinned","Info:   0 out of   4 downloadThenRun dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Packaging","score":10,"reason":"packaging workflow detected","details":["Info: Project packages its releases by way of GitHub Actions.: .github/workflows/build-image.yaml:8"],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 21 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-18T23:14:15.170Z","repository_id":19083510,"created_at":"2025-08-18T23:14:15.170Z","updated_at":"2025-08-18T23:14:15.170Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29298522,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-10T10:40:02.018Z","status":"ssl_error","status_checked_at":"2026-02-10T10:38:28.459Z","response_time":65,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6: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":false,"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":["common-lisp","package-manager"],"created_at":"2024-07-31T03:01:49.639Z","updated_at":"2026-02-10T12:01:21.333Z","avatar_url":"https://github.com/fukamachi.png","language":"Common Lisp","funding_links":["https://github.com/sponsors/fukamachi"],"categories":["Common Lisp","package-manager","Offline ##","Languages"],"sub_categories":["Common Lisp"],"readme":"# Qlot\n\n[![Build Status](https://github.com/fukamachi/qlot/workflows/CI/badge.svg)](https://github.com/fukamachi/qlot/actions)\n[![](https://api.quickdocs.org/badge/qlot.svg)](https://quickdocs.org/qlot)\n\n**Qlot** (pronounced `kyü-'lät`, like culotte) is a project-local library installer using Quicklisp facility. This aims to be like [Bundler](http://bundler.io) of Ruby or [Carton](http://search.cpan.org/~miyagawa/Carton/lib/Carton.pm) of Perl.\n\n## Table of Contents\n\n* [Usage](#usage)\n* [What Qlot is trying to solve](#what-qlot-is-trying-to-solve)\n* [Requirements](#requirements)\n* [Installation](#installation)\n  * [Automatic installer](#automatic-installer-recommended)\n  * [via Roswell](#via-roswell)\n  * [via Quicklisp](#via-quicklisp)\n  * [Manual installation](#manual-installation)\n  * [Install from source](#install-from-source)\n  * [via Docker](#via-docker)\n* [Optional settings](#optional-settings)\n  * [ASDF configuration to prevent from loading by mistake](#asdf-configuration-to-prevent-from-loading-by-mistake)\n* [Tutorial](#tutorial)\n* [Shared Dependency Cache](#shared-dependency-cache)\n* [qlfile syntax](#qlfile-syntax)\n* [Priorities of distributions](#priorities-of-distributions)\n* [Working with SLIME](#working-with-slime)\n  * [Lem](#lem)\n  * [Emacs](#emacs)\n  * [Vim/Neovim](#vimneovim)\n* [Working with local git repositories](#working-with-local-git-repositories)\n* [Examples](#examples)\n  * [Building a Docker image](#building-a-docker-image)\n\n## Usage\n\n### Shell\n\n```\n$ cd /path/to/myapp\n\n# Initialize the project to start using Qlot.\n$ qlot init\n\n# Install libraries project-locally.\n$ qlot install\n\n# Add the upstream version of a library\n$ qlot add mito --upstream\n\n# Add a library from GitHub\n$ qlot add fukamachi/anypool\n\n# Update specific libraries\n$ qlot update mito\n\n# Run a REPL with a project-local Quicklisp\n$ qlot exec sbcl\n```\n\n### REPL (experimental)\n\n```common-lisp\n;; Move to the project root\n;; (not necessary if the REPL is invoked by 'qlot exec')\n(setf qlot:*project-root* #P\"/path/to/project/\")\n\n;; Initialize the project to start using Qlot.\n(qlot:init #P\"/path/to/project/\")\n\n;; Install libraries project-locally.\n(qlot:install)\n\n;; Add the upstream version of a library\n(qlot:add :mito :upstream t)\n\n;; Add a library from GitHub\n(qlot:add \"fukamachi/anypool\")\n\n;; Update specific libraries\n(qlot:update :mito)\n```\n\n## What Qlot is trying to solve\n\nWe have Quicklisp, the central library registry. It made installation of libraries damn easy.\n\nHowever, what only you can specify is the month of distribution. Which means you have to use all libraries of the same moment and you cannot use a newer/older version of a library for your project.\n\n\"local-projects/\" or ASDF configurations may be a solution to this problem, but there are a couple of problems.\n\n1) *They are not project-local.* If you have multiple projects that use different versions of the same library, it would be a problem.\n\n2) *They are difficult to fix the version or to update them.* If your project needs to work on other than your machine, for instance on other people's machines or on servers, the version of depending libraries should be the same.\n\nThis is what Qlot is trying to solve.\n\n## Requirements\n\n* [Roswell](https://github.com/roswell/roswell/) or [SBCL](https://www.sbcl.org/)\n* OpenSSL (Unix only)\n  * **[Ubuntu/Debian]** `sudo apt install libssl-dev`\n  * **[macOS]** `brew install openssl`\n* git (for installation from git repositories)\n\n## Installation\n\n### Automatic installer (recommended)\n\n```shell\n$ curl -L https://qlot.tech/installer | sh\n```\n\nIt also requires `curl` (or `wget`) and `tar`.\n\nTo uninstall Qlot, run a Qlot uninstaller like:\n\n```\n$ ~/.qlot/qlot/scripts/qlot-uninstaller.sh\n```\n\n### via Roswell\n\nIf you're already using Roswell, Qlot can be installed by `ros install`.\n\n```shell\n# Install from the Quicklisp dist\n$ ros install qlot\n# Or, install the latest version from the git repository\n$ ros install fukamachi/qlot\n\n# For older Roswell (Not required since v23.10.14.114 or above)\n$ ros -e '(ql:quickload :qlot/distify)'\n```\n\nRoswell adds an executable script under `$HOME/.roswell/bin`. Make sure the directory exists in `$PATH`.\n\n```shell\n$ which qlot\n/Users/fukamachi/.roswell/bin/qlot\n```\n\nRun `ros update qlot` to update Qlot.\n\n### via Quicklisp\n\nIf [Quicklisp](https://www.quicklisp.org/) is set up on your home directory, Qlot can be installed by `ql:quickload`.\n\n```common-lisp\n(ql:quickload :qlot)\n```\n\nUse functions exported by `qlot` package for using Qlot.\n\nTo update Qlot, run `(ql:update-all-dists)` in the REPL.\n\n### Manual installation\n\nIf you don't use both Roswell and Quicklisp for some reason, Qlot also can be installed manually.\n\nThe advantage of this method is no dependencies are required other than `sbcl` and `OpenSSL`.\n\n```shell\n# Getting the latest version\n$ curl -sL https://api.github.com/repos/fukamachi/qlot/releases/latest | jq -rM '.name'\n1.3.5\n```\n\n```shell\n$ curl https://github.com/fukamachi/qlot/releases/download/1.3.5/qlot-1.3.5.tar.gz -o qlot.tar.gz\n$ tar xfz qlot.tar.gz\n$ cd qlot\n$ scripts/setup.sh\n$ sudo scripts/install.sh\n```\n\n### Install from source\n\n```shell\n$ git clone https://github.com/fukamachi/qlot\n$ cd qlot\n$ scripts/setup.sh\n$ sudo scripts/install.sh\n```\n\nTo update Qlot, run `git pull \u0026\u0026 scripts/setup.sh`.\n\n**WARNING**: Don't add the Qlot source directory to any ASDF loadable directories, such as `~/common-lisp` or `~/quicklisp/local-projects`. ASDF accidentally loads dependencies of Qlot in a REPL even in case you don't need it. (See also [ASDF configuration](#asdf-configuration-to-prevent-from-loading-by-mistake) section)\n\n### via Docker\n\n[![Docker Pulls](https://img.shields.io/docker/pulls/fukamachi/qlot.svg)](https://hub.docker.com/r/fukamachi/qlot/)\n\n```shell\n$ docker run --rm -it fukamachi/qlot\n```\n\nYou can build it by yourself with `docker build`:\n\n```shell\n$ git clone https://github.com/fukamachi/qlot\n$ cd qlot\n$ docker build -t qlot .\n```\n\n## Optional settings\n\n### ASDF configuration to prevent from loading by mistake\n\nASDF loads any ASD files under a directory `~/common-lisp` including its subdirectories. It is easily understandable and convenient. However, it will lead to a problematic situation which ASDF accidentally loads libraries under \".qlot/\" even in case you don't need it.\n\nTo avoid the situation, we recommend not to use `~/common-lisp` directory, or add the following lines to your Lisp's init file such as `~/.sbclrc` for SBCL.\n\n```\n;; .sbclrc\n(require 'asdf)\n(push \".qlot\" asdf::*default-source-registry-exclusions*)\n(asdf:initialize-source-registry)\n```\n\nRoswell doesn't require this setting since it ignores directories starting with a dot.\n\n## Tutorial\n\n### Start using Qlot\n\n```\n$ qlot init\n```\n\nIt creates 2 files \"qlfile\" and \"qlfile.lock\", and a directory \".qlot/\" at the root of your project directory.\n\n`qlfile` is a file clarifying the project dependencies. See [qlfile syntax](#qlfile-syntax) for the details.\n\n`qlfile.lock` is similar to `qlfile` except the library versions are clarified. This will ensure that other developers or your deployment environment use exactly the same versions of libraries you just installed.\n\nMake sure you add `qlfile` and `qlfile.lock` to your version-controlled repository.\n\n```\n$ git add qlfile qlfile.lock\n$ git commit -m 'Start using Qlot.'\n```\n\n### Adding a new dependency\n\n```\n$ qlot add \u003clibrary name\u003e              # Add a new library from Quicklisp explicitly\n$ qlot add \u003clibrary name\u003e --upstream   # Add an upstream version of a Quicklisp library\n$ qlot add \u003cusername/repository\u003e       # Add a new library from a GitHub repository\n```\n\nYou can also edit a `qlfile` file directly. See [qlfile syntax](#qlfile-syntax) section to know how to write it. Be sure to run `qlot install` to install new dependencies.\n\n### Updating the project-local Quicklisp\n\nYou can update the version of dependencies via:\n\n```\n$ qlot update\n\n# Update a specific project\n$ qlot update mito\n$ qlot update mito sxql\n```\n\nIt will also overwrite `qlfile.lock`.\n\n## Commands\n\n### install\n\n`qlot install` will install Quicklisp and libraries that are declared in `qlfile` project-locally. `qlfile.lock` will be used with precedence if it exists.\n\n```\n$ qlot install\n$ qlot install --no-cache   # Disable shared cache for this invocation\n```\n\n### update\n\n`qlot update` will update the project-local `.qlot/` directory using `qlfile`.\n\n```\n$ qlot update\n$ qlot update --no-cache    # Disable shared cache for this invocation\n\n# Update a specific project\n$ qlot update mito\n$ qlot update mito sxql\n```\n\n### add\n\n`qlot add` will add a line to `qlfile` and invoke `qlot install` internally. It replaces an existing line if a library with the same name already exists.\n\nIts arguments are same as the qlfile syntax.\n\n```\n$ qlot add mito                                # ql mito\n$ qlot add mito --latest                       # ql mito :latest\n$ qlot add mito --upstream                     # ql mito :upstream\n$ qlot add fukamachi/datafly                   # github datafly fukamachi/datafly\n$ qlot add fukamachi/datafly --branch stable   # github datafly fukamachi/datafly :branch stable\n$ qlot add ultralisp egao1980-cl-idna          # ultralisp egao1980-cl-idna\n```\n\n### remove\n\n`qlot remove` will remove libraries from `qlfile` and invoke `qlot install` internally.\n\n```\n$ qlot remove mito\n$ qlot remove mito datafly   # can specify multiple names\n```\n\n### exec\n\n`qlot exec` does following:\n\n* configures ASDF's source registries;\n* adds Roswell's `bin` directory to the `PATH` environment variable;\n* executes given command with arguments.\n\nHere are few useful commands:\n\n* `qlot exec ros emacs` - starts Emacs for development. Inferior lisp will use only\n  systems, installed by `qlot install`. If you want to use systems from directories other than\n  current and `./.qlot/`, then set `CL_SOURCE_REGISTRY` variable before starting `qlot`.\n  This can be useful in case, if you have development versions of some systems, for example,\n  in `~/common-lisp/` directory and want to use them during project development:\n\n  ```\n  CL_SOURCE_REGISTRY=~/common-lisp// qlot exec ros emacs\n  ```\n\n  Read more about `CL_SOURCE_REGISTRY` in\n  [asdf's documentation](https://common-lisp.net/project/asdf/asdf/Shell_002dfriendly-syntax-for-configuration.html).\n* `qlot exec ros build some-app.ros` - another command, useful, to build a binary\n  from systems, fixed in `qlfile` and `qlfile.lock`. This way you can be sure that your builds are stable.\n\n### bundle\n\n`qlot bundle` collects and copies all dependencies into a dedicated directory, making your application runnable without requiring Qlot or Quicklisp at runtime.\n\n```\n$ qlot bundle                           # Install into '.bundle-libs'\n$ qlot bundle --exclude myapp-test      # Install dependencies except for myapp-test\n$ qlot bundle --output vendor           # Install into 'vendor'\n```\n\nTo load the bundled libraries, simply load `.bundle-libs/setup.lisp`.\n\n`qlot bundle` is ideal for creating self-contained Common Lisp projects, enabling reliable and portable deployment.\n\n## Shared Dependency Cache\n\nQlot includes a shared dependency cache that reduces disk space and speeds up installations across multiple projects. Dependencies are cached globally in `~/.cache/qlot/` and shared via symbolic links.\n\nWhen you run `qlot install`, Qlot checks if each dependency already exists in the cache. If cached, it creates a symbolic link; otherwise, it downloads normally and saves to the cache. This means multiple projects using the same version of a library share a single copy on disk.\n\n### Disabling the Cache\n\nTo disable caching for a specific invocation, use `--no-cache`:\n\n```shell\nqlot install --no-cache\nqlot update --no-cache\n```\n\n### Clearing the Cache\n\nTo clear the cache, simply delete the cache directory:\n\n```shell\nrm -rf ~/.cache/qlot/\n```\n\nAfter clearing the cache, run `qlot install` in your projects to reinstall dependencies.\n\n## `qlfile` syntax\n\n\"qlfile\" is a collection of Quicklisp dist declarations. Each line of that represents a dist.\n\n```\n\u003csource\u003e \u003cproject name\u003e [arg1, arg2..]\n```\n\nCurrently, `\u003csource\u003e` must be one of `dist`, `ql`, `ql-dist`, `ultralisp`, `http`, `git`, `github`, `local` or `asdf`.\n\n### ql\n\n```\nql \u003cproject name\u003e \u003cversion\u003e\nql \u003cproject name\u003e\n```\n\n`ql` source will download libraries from Quicklisp official dist.\n\nIf you want to use Clack in Quicklisp dist of January 13, 2014, qlfile would be like this.\n\n```\nql clack 2014-01-13\n```\n\nIf `:latest` is specified for the version, the latest Quicklisp dist version will be used.\n\nIf `:upstream` is specified, Qlot downloads the latest code from the upstream git repository.\n\n### ultralisp\n\n```\nultralisp \u003cproject name\u003e \u003cversion\u003e\nultralisp \u003cproject name\u003e\n```\n\n`ultralisp` is same as `ql` except downloading from Ultralisp.\n\n### http\n\n```\nhttp \u003cproject name\u003e \u003curl\u003e [\u003cfile md5\u003e]\n```\n\n`http` source will download a tarball.\n\n```\nhttp yason http://netzhansa.com/yason.tar.gz\n```\n\n### git\n\n```\ngit \u003cproject name\u003e \u003crepos url\u003e\ngit \u003cproject name\u003e \u003crepos url\u003e :ref \u003ccommit ref\u003e\ngit \u003cproject name\u003e \u003crepos url\u003e :branch \u003cbranch name\u003e\ngit \u003cproject name\u003e \u003crepos url\u003e :tag \u003ctag name\u003e\n```\n\n`git` source will download libraries from a public git repository.\n\n```\ngit clack https://github.com/fukamachi/clack.git\n```\n\nYou can also specify `:ref`, `:branch` or `:tag`.\n\n```\ngit clack https://github.com/fukamachi/clack.git :branch develop\ngit datafly https://github.com/fukamachi/datafly.git :tag v0.7.4\ngit cl-dbi https://github.com/fukamachi/cl-dbi.git :ref 54928984e5756e92ba298aae51de8b95a6b0cf4b\n```\n\n#### Retrieving from private repository\n\nQlot doesn't authenticate itself, but retrieving from private repository can be done via git's SSH key authentication. This means, if the current user can `git clone`, Qlot also would be possible to do it.\n\n```\ngit myapp git@github.com:somewrite-adtech/myapp\n```\n\n### github\n\n```\ngithub \u003cusername/repository\u003e\ngithub \u003cusername/repository\u003e :ref \u003ccommit ref\u003e\ngithub \u003cusername/repository\u003e :branch \u003cbranch name\u003e\ngithub \u003cusername/repository\u003e :tag \u003ctag name\u003e\n```\n\n`github` source is similar to `git`, but it is specifically for GitHub. As it uses GitHub API and tarballs GitHub serves, it doesn't require \"git\" command.\n\n```\ngithub fukamachi/datafly\ngithub fukamachi/datafly :branch develop\n```\n\nGitHub API may return 401 Forbidden when exceeding the rate limit ([API docs](https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api?apiVersion=2022-11-28)). It happens often because unauthenticated users can only make 60 requests per hour.\n\nSetting an environment variable `GITHUB_TOKEN` to use a custom token raises it to 5,000 requests per hour.\n\n### local\n\n```\nlocal \u003cproject name\u003e \u003cdirectory path\u003e\n```\n\nAdd a directory to the ASDF's source registry.\n\n```\nlocal rove ~/Programs/lib/rove\n```\n\n### asdf (Experimental)\n\n```\nasdf \u003cversion\u003e\n```\n\nUse a newer version of ASDF.\n\n```\nasdf 3.3.7.1\n```\n\n### dist\n\n```\ndist \u003cdistribution URL\u003e [\u003cdist version\u003e]\n```\n\n`dist` allows to use a custom Quicklisp dist, like Ultralisp.\n\n```\ndist http://beta.quicklisp.org/dist/quicklisp.txt\ndist http://dist.ultralisp.org/\n```\n\n### ql-dist\n\n```\nql-dist \u003cdist name\u003e \u003cproject name\u003e [\u003cversion\u003e]\n```\n\n`ql-dist` source will download a specific library from a custom Quicklisp distribution declared elsewhere in the qlfile with `dist`.\n\nThis is useful when you have multiple distributions and a project is available from more than one. By default, the bottom distribution in the qlfile takes priority (see [Priorities of distributions](#priorities-of-distributions)). `ql-dist` allows you to explicitly specify which distribution a particular project should come from, overriding the default priority.\n\n```\ndist http://dist.ultralisp.org/\nql-dist quicklisp clack\n```\n\nIn this example, ultralisp is added as a distribution (and would normally take priority over the implicit quicklisp dist). However, `ql-dist quicklisp clack` explicitly specifies that clack should come from quicklisp instead.\n\nThe `\u003cdist name\u003e` must match the name in the distinfo of a `dist` source declared in the same qlfile. If no matching distribution is found, Qlot will signal an error.\n\n## Priorities of distributions\n\nIf multiple distributions provide the same library, lower ones would take priority over higher ones.\n\n## Working with SLIME\n\n[SLIME](https://github.com/slime/slime) is the most popular development environment in Common Lisp. However, its REPL always loads the global Quicklisp, not the project-local one.\n\nHere's quick steps to start project-local REPL with SLIME for each text editor:\n\n### Lem\n\n1. Add [lem-project/micros](https://github.com/lem-project/micros) to `.qlot/local-projects`.\n\n```shell\n$ git clone https://github.com/lem-project/micros .qlot/local-projects/micros\n```\n\n2. Add the following function to `~/.lem/init.lisp`.\n\n```common-lisp\n(define-command slime-qlot-exec () ()\n  (let ((command (first (lem-lisp-mode/implementation::list-roswell-with-qlot-commands))))\n    (when command\n      (lem-lisp-mode:run-slime command))))\n```\n\n3. Relaunch the Lem, or reload the init file with `M-x lisp-load-file RET ~/.lem/init.lisp`.\n\n4. Invoke `M-x slime-qlot-exec RET /path/to/project/`.\n\n### Emacs\n\n1. Add one of the following functions to `init.el`.\n\n#### a) SLIME\n\n```emacs-lisp\n(setq slime-lisp-implementations\n      '((sbcl (\"sbcl\") :coding-system utf-8-unix)\n        (qlot (\"qlot\" \"exec\" \"sbcl\") :coding-system utf-8-unix)))\n```\n\nSee the [SLIME manual](https://slime.common-lisp.dev/doc/html/Multiple-Lisps.html#Multiple-Lisps) to set up multiple Lisps.\n\n#### b) Sly\n\n```emacs-lisp\n(setq sly-lisp-implementations\n      '((sbcl (\"sbcl\") :coding-system utf-8-unix)\n        (qlot (\"qlot\" \"exec\" \"sbcl\") :coding-system utf-8-unix)))\n```\n\nSee the [Sly manual](https://joaotavora.github.io/sly/#Multiple-Lisps) to set up multiple Lisps.\n\n2. Relaunch the Emacs or load the config file.\n3. Invoke `M-- M-x slime RET qlot RET`.\n\n### Vim/Neovim\n\n1. Install [vlime/vlime](https://github.com/vlime/vlime)\n2. Add the appropriate configuration to your Vim/Neovim `init.vim`:\n\n   #### If you use Roswell:\n   ```vim\n   let g:vlime_cl_use_terminal = v:true\n   let s:vlime_path = '/path/to/vlime'\n   function! VlimeBuildServerCommandFor_qlot(vlime_loader, vlime_eval)\n       return [\"qlot\", \"exec\", \"ros\", \"run\",\n                 \\ \"--load\", s:vlime_path . \"/lisp/load-vlime.lisp\",\n                 \\ \"--eval\", a:vlime_eval]\n   endfunction\n   function! VlimeQlotExec()\n       call vlime#server#New(v:true, get(g:, \"vlime_cl_use_terminal\", v:false), v:null, \"qlot\")\n   endfunction\n   ```\n\n   #### If you use plain SBCL:\n   ```vim\n   let g:vlime_cl_use_terminal = v:true\n   let s:vlime_path = '/path/to/vlime'\n   function! VlimeBuildServerCommandFor_qlot(vlime_loader, vlime_eval)\n       return [\"qlot\", \"exec\", \"sbcl\",\n                 \\ \"--load\", s:vlime_path . \"/lisp/load-vlime.lisp\",\n                 \\ \"--eval\", a:vlime_eval]\n   endfunction\n   function! VlimeQlotExec()\n       call vlime#server#New(v:true, get(g:, \"vlime_cl_use_terminal\", v:false), v:null, \"qlot\")\n   endfunction\n   ```\n\n3. Relaunch Vim/Neovim\n4. Navigate to your project directory with `:cd /path/to/project/` and start Vlime with `:call VlimeQlotExec()`\n\n## Working with local git repositories\n\n`PROJECT_ROOT/.qlot/local-projects` can be used for local git repositories. Symbolic links are also accessible in Qlot environment.\n\n## Examples\n\n### Building a Docker image\n\n```dockerfile\nFROM fukamachi/qlot AS qlot-env\n\nWORKDIR /app\nCOPY qlfile* myapp.asd .\nRUN qlot bundle\n\nFROM debian:bookworm-slim AS main\n\n# Copy SBCL binary\nCOPY --from=fukamachi/sbcl:2.5.3 /root/.roswell/impls/*/linux/sbcl-bin/2.5.3 /usr/local\n\nWORKDIR /app\n\n# Copy .bundle-libs directory\nCOPY --from=qlot-env /app/.bundle-libs /app/.bundle-libs\n\n# Run whatever you want\nCOPY . .\n\nRUN set -x; \\\n  sbcl --dynamic-space-size 4096 --load .bundle-libs/setup.lisp --eval '(asdf:load-system :myapp)'\n\nCMD [\"sbcl\", \"--load\", \".bundle-libs/setup.lisp\", \"--eval\", \"(asdf:load-system :myapp)\", \"--eval\", \"(myapp:main)\"]\n```\n\nNOTE: `.bundle-libs/bundle.lisp` renamed to `setup.lisp` from v1.7.0. If it doesn't exist, try using `bundle.lisp`.\n\n## Author\n\n* Eitaro Fukamachi (e.arrows@gmail.com)\n\n## License\n\nSee [LICENSE.txt](LICENSE.txt).\n\nThe license of bundled Quicklisp installer can be found at [quicklisp/LICENSE.txt](quicklisp/LICENSE.txt).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffukamachi%2Fqlot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffukamachi%2Fqlot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffukamachi%2Fqlot/lists"}