Liking cljdoc? Tell your friends :D

scry

Clojars Project

scry is a Clojure test runner for AI agents and REPL-driven development. It returns structured, inspectable test results so callers can identify failures, assertions, stack traces, and captured output without scraping terminal text.

It supports two complementary workflows:

  • REPL / in-process API: run tests in the current Clojure process, inspect the returned result map, and revisit the most recent result.
  • Command line: run tests with process exit semantics and write detailed EDN artifacts for failed tests under .scry-results/.

Why scry?

AI coding agents often need to determine:

  • whether a test run passed;
  • which test vars failed;
  • what the expected and actual forms were;
  • where a failure occurred; and
  • what stdout or stderr a targeted test produced.

scry exposes those answers as Clojure data. Broad runs stay compact, while focused namespace and var runs include progressively more detail.

Status

scry is an initial public alpha / pre-1.0 project. The core clojure.test runner, in-process API, CLI, scoped result model, and optional Kaocha adapter are usable and tested. APIs and result shapes may still change before a stable release.

The project leans heavily on AI-generated code and AI review processes.

Installation

Add scry as a test or development dependency. A conventional deps.edn setup is:

{:aliases
 {:test
  {:extra-paths ["test"]
   :extra-deps
   {org.hugoduncan/scry {:mvn/version "RELEASE"}}}}}

If your project already has a :test alias, merge the dependency into that alias rather than replacing its paths or options. Adjust :extra-paths if your tests live somewhere other than test.

The examples use Clojars' "RELEASE" token for convenience. For reproducible builds, replace it with the latest concrete version shown on Clojars and keep that version pinned.

First structured test result

Start a REPL on your test alias:

clojure -M:test

Run one test namespace and retain the result:

(require '[scry.core :as scry])

(def result
  (scry/run {:namespaces ['my.project-test]}))

Inspect the outcome and canonical result entries:

(select-keys result [:pass? :summary])
(:results result)
(scry/failures result)

scry also retains the most recent result for follow-up inspection:

(scry/last-result)
(println (scry/report-string))

A single explicit namespace includes every executed var and its assertion details. To capture stdout and stderr as well, run one explicit test var:

(require '[my.project-test])

(def var-result
  (scry/run {:vars [#'my.project-test/specific-test]}))

(-> var-result :results first (select-keys [:out :err]))

For a failed or erroring var, scry/output retrieves the same captured streams by fully qualified symbol:

(scry/output 'my.project-test/specific-test)

You now have a focused result that can be queried as Clojure data instead of parsed from terminal output.

Common workflows

Run clojure.test tests in the REPL

Use explicit namespaces or vars during development (after requiring the target namespace as shown above):

(scry/run {:namespaces ['my.project-test]})
(scry/run {:vars [#'my.project-test/specific-test]})

Use a directory or namespace pattern for broader discovery:

(scry/run)
(scry/run {:dirs ["test"]})
(scry/run {:ns-pattern #".*-test$"})

Normal clojure.test fixtures retain their standard grouping and ordering behavior. Nested in-process test runs are isolated from the enclosing scry result.

Run tests from the command line

Run all discovered tests with either CLI entry point:

clojure -M:test -m scry.cli
clojure -X:test scry.cli/run

Target a namespace or test var:

clojure -M:test -m scry.cli --namespace my.project-test
clojure -M:test -m scry.cli --var my.project-test/specific-test

clojure -X:test scry.cli/run :namespaces '[my.project-test]'
clojure -X:test scry.cli/run :vars '[my.project-test/specific-test]'

The CLI prints live per-var progress and a summary. At the start of each run it clears and recreates .scry-results/ in the current working directory. When a concrete var completes with a failure or error, its detailed artifact is synchronously written before the next var starts. Publication writes a same-directory temporary file and atomically moves it to the final name, so consumers must inspect only final .edn names and ignore temporary files. Failed and erroring vars produce namespace-prefixed EDN files such as:

.scry-results/my.project-test__specific-test.edn

These files contain assertion details, error stack traces, and captured output. Passing vars do not create artifacts, so passing runs can leave the directory empty. If a callback-time publication fails, the CLI records a bounded diagnostic and retries after a normal runner return; synthetic suite/load failures are also written during that final reconciliation. A published artifact is retained if a later catchable runner error aborts the run, and its final path remains in :result-files. This improves availability after later hangs or aborts, but cannot guarantee an artifact for an incomplete var, a process killed during that file's write window, power loss, or a filesystem publication failure.

The CLI exits 0 only when at least one concrete test var runs and all tests pass. Structured outcomes expose the authoritative :scry.cli/outcome-kind; the -X entry point returns the outcome map on success and throws ex-info with structured outcome data on non-zero results. When artifact publication remains unresolved, :scry.cli/diagnostic-error distinguishes :incremental-result-file-writing (runner threw before returning) from :final-result-file-reconciliation (after a normal runner return). Inspect the outcome and final .scry-results/*.edn files rather than parsing progress or diagnostic text.

See the scry.cli/run reference for outcome kinds, result-file behavior, and error data. Run clojure -M:test -m scry.cli --help for the supported main-style options.

Run Kaocha tests

Kaocha support is packaged separately so the core artifact does not depend on Kaocha. Add the adapter under a composable alias:

{:aliases
 {:test
  {:extra-paths ["test"]
   :extra-deps
   {org.hugoduncan/scry {:mvn/version "RELEASE"}}}
  :kaocha
  {:extra-deps
   {org.hugoduncan/scry-kaocha {:mvn/version "RELEASE"}}}}}

Use the same version for org.hugoduncan/scry and org.hugoduncan/scry-kaocha. The adapter brings its own Kaocha dependency; projects can override that dependency through normal deps.edn resolution.

Compose the :test and :kaocha aliases, then run configured suites from the command line:

clojure -M:test:kaocha -m scry.cli --runner kaocha unit
clojure -M:test:kaocha -m scry.cli --runner kaocha unit integration
clojure -X:test:kaocha scry.cli/run :runner :kaocha :suite :unit

Main-style Kaocha mode forwards Kaocha options and positional suite selectors to Kaocha's CLI parser:

clojure -M:test:kaocha -m scry.cli --runner kaocha --focus my.ns/test-foo
clojure -M:test:kaocha -m scry.cli --runner kaocha --no-randomize unit

Run Kaocha in-process from a REPL with scry.kaocha:

(require '[scry.kaocha :as kaocha])

(kaocha/run)                              ;; loads tests.edn when present
(kaocha/run {:suite :unit})
(kaocha/run {:suites [:unit :integration]})
(kaocha/run {:config full-kaocha-config})

Without an explicit :config, the adapter loads the current project's tests.edn when present. Otherwise it builds a synthetic :unit suite from source paths, test paths, and namespace patterns. Kaocha results use the same scoped result model; captured stdout and stderr are currently merged into :out.

See the scry.kaocha/run reference for all adapter options and suite-selection rules. Use clojure -M:test:kaocha -m scry.cli --runner kaocha --help for Kaocha CLI options.

Result model at a glance

By default, scry/run returns:

{:summary  ...
 :pass?    ...
 :results  ...  ;; canonical formatted entries
 :failures ...} ;; compatibility failing/erroring subset

Default detail depends on how narrowly the run is targeted:

InvocationDefault result detail
Discovery, multiple namespaces, or multiple varsCompact failing/erroring entries
One explicit namespaceEvery executed var and all assertion details
One explicit executable varOne var, all assertion details, and captured :out / :err

Use :result-format to override the returned keys and inclusions for each scope. See the scry.core/run reference for the complete result shape, scope rules, and formatting options.

Reference

  • scry.core API — in-process runner and inspection helpers
  • scry.cli/run API — structured CLI outcomes and -X behavior
  • scry.kaocha API — optional Kaocha adapter
  • clojure -M:test -m scry.cli --help — core CLI options
  • clojure -M:test:kaocha -m scry.cli --runner kaocha --help — Kaocha CLI options

License

scry is licensed under the Eclipse Public License 2.0 (EPL-2.0). See LICENSE.

Contributing

If you want a change, please open an issue rather than a pull request.

Can you improve this documentation?Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close