A namespace at a glance, from the running system's own metadata: every
var with its signature, source order preserved, privates included and
marked — the gist of a namespace, not just its API (§7). Runtime over
parsing, deliberately: everything the glance needs — arglists, doc,
the macro and private flags, line — already sits on the vars, for any
loaded namespace with no file plumbing, and reflects what is live after
a hot reload rather than what is on disk. Source-level outlining
(unloaded files, comment blocks, the shape of a file as written) is
form/changed-forms territory and stays there.
A namespace at a glance, from the running system's own metadata: every var with its signature, source order preserved, privates included and marked — the gist of a namespace, not just its API (§7). Runtime over parsing, deliberately: everything the glance needs — arglists, doc, the macro and private flags, line — already sits on the vars, for any loaded namespace with no file plumbing, and reflects what is live after a hot reload rather than what is on disk. Source-level outlining (unloaded files, comment blocks, the shape of a file as written) is `form`/`changed-forms` territory and stays there.
(file x)The source file of the namespace x designates, as a vector of lines —
lines, like out, because composition is the window: the 1-indexed
:line of an outline or vars entry indexes it directly,
(drop (dec line) …) starts reading there. The munged namespace path
is tried first (.clj, then .cljc), so a namespace assembled from
several files — clojure.core loads five — answers with its defining
file; the :file metadata its vars carry is the fallback, covering
unconventional layouts. Throws a plain explanation when no file is on
the classpath — REPL-minted namespaces and source-stripped AOT jars
have none, and that is worth saying outright rather than returning
nil.
The source file of the namespace `x` designates, as a vector of lines — lines, like `out`, because composition is the window: the 1-indexed `:line` of an `outline` or `vars` entry indexes it directly, `(drop (dec line) …)` starts reading there. The munged namespace path is tried first (`.clj`, then `.cljc`), so a namespace assembled from several files — clojure.core `load`s five — answers with its defining file; the `:file` metadata its vars carry is the fallback, covering unconventional layouts. Throws a plain explanation when no file is on the classpath — REPL-minted namespaces and source-stripped AOT jars have none, and that is worth saying outright rather than returning nil.
(nses)(nses match)(nses match {:keys [search-docstrings] :or {search-docstrings true}})Every loaded namespace — the system at a glance, and the top of the
drilldown that outline continues. match (a string — * a gap — a
regex, or a symbol matched as its name, as everywhere) searches names
and namespace docstrings, ranked the way vars ranks: names with a
whole dot-segment matching exactly first — "outline" puts
x.outline above x.outline-test — then remaining name hits, then
docstring-only hits, alphabetical within each tier; so
(nses 'some.ns) still answers whether a namespace is really loaded.
Without match, all of them, sorted. {:search-docstrings false}
restricts the search to names — the third tier vanishes; it is how
vars scopes a qualified match's ns side, where a docstring mention
would be a surprising reason to widen a scope. Names only in the output,
deliberately: a flat vector of symbols is the composable form —
filter it, count it, map outline over it — which means a docstring
hit carries no quoted evidence; outline the namespace to see it.
Loaded namespaces, not the classpath: what the running system has
actually required.
Every loaded namespace — the system at a glance, and the top of the
drilldown that `outline` continues. `match` (a string — `*` a gap — a
regex, or a symbol matched as its name, as everywhere) searches names
and namespace docstrings, ranked the way `vars` ranks: names with a
whole dot-segment matching exactly first — "outline" puts
`x.outline` above `x.outline-test` — then remaining name hits, then
docstring-only hits, alphabetical within each tier; so
`(nses 'some.ns)` still answers whether a namespace is really loaded.
Without `match`, all of them, sorted. `{:search-docstrings false}`
restricts the search to names — the third tier vanishes; it is how
`vars` scopes a qualified match's ns side, where a docstring mention
would be a surprising reason to widen a scope. Names only in the output,
deliberately: a flat vector of symbols is the composable form —
filter it, count it, map `outline` over it — which means a docstring
hit carries no quoted evidence; `outline` the namespace to see it.
Loaded namespaces, not the classpath: what the running system has
actually required.(outline ns)(outline ns
{:keys [include-docstrings include-private match]
:or {include-private true}})The outline of the namespace ns designates: {:ns sym :doc gist :vars [entry …]}, entries in source order, privates included and
marked — the glance, signatures only, safe for any size of namespace.
Options: :include-docstrings carries every docstring whole (and the
full ns docstring); :match (a string, a regex, or a symbol matched
as its name, as everywhere) keeps only vars whose name or docstring
matches. The default flipped twice on 2026-08-05:
docstrings-on when this call was the initialize instructions'
bootstrap and both fresh tenants stripped the option; back to the
glance when the rendered manual moved into the instructions
themselves and outline returned to being a reading tool.
The outline of the namespace `ns` designates: `{:ns sym :doc gist
:vars [entry …]}`, entries in source order, privates included and
marked — the glance, signatures only, safe for any size of namespace.
Options: `:include-docstrings` carries every docstring whole (and the
full ns docstring); `:match` (a string, a regex, or a symbol matched
as its name, as everywhere) keeps only vars whose name or docstring
matches. The default flipped twice on 2026-08-05:
docstrings-on when this call was the initialize instructions'
bootstrap and both fresh tenants stripped the option; back to the
glance when the rendered manual moved into the instructions
themselves and outline returned to being a reading tool.(vars match)(vars match {:keys [search-docstrings] :or {search-docstrings true}})Every loaded var whose name or docstring matches, across all
namespaces — the entry point for "where does that function live?",
where nses searches namespace names and outline reads one
namespace at a time. Hits are outline entries with :ns attached,
scored: exact name matches first — a conventionally decorated name is
exact too, claim?, ->Claim and *claim* all meet "claim" at the
exact tier, one rung below exactness as spelled (see stem) — then
name hits, then docstring-only hits: the definition asked for
outranks a mention of it. Within each tier, namespace order, publics
before privates — the API is usually the quarry, and the private
sibling follows still flagged — then source line. A bare scope
listing ("helpers/") keeps whole-namespace source order instead: a
listing, not a ranking. Docstring hits
quote their matching lines as :matched, the same evidence outline
shows. match is required — the JVM's whole var population is no
glance — and takes what nses takes: a string (case-insensitive
substring, * a gap), a regex, or a symbol matched as its name. A
/ qualifies the match, spelling the search the way Clojure spells
the target: "helpers/await" — string or symbol — scopes to the
namespaces whose name matches the ns side (docstrings not
consulted: a scope widened by a docstring mention would surprise) and
matches the name side within them, docstrings included as ever.
Either side may be empty — "helpers/" lists a scope whole,
"/await" degenerates to the bare search. A regex containing /
instead matches whole qualified names, #"helpers[^/]*/await" — the
one spelling that mixes forms — where a slashless regex matches bare
names. {:search-docstrings false} restricts the name side to names
alone — the docstring tier vanishes.
Every loaded var whose name or docstring matches, across all
namespaces — the entry point for "where does that function live?",
where `nses` searches namespace names and `outline` reads one
namespace at a time. Hits are outline entries with `:ns` attached,
scored: exact name matches first — a conventionally decorated name is
exact too, `claim?`, `->Claim` and `*claim*` all meet "claim" at the
exact tier, one rung below exactness as spelled (see `stem`) — then
name hits, then docstring-only hits: the definition asked for
outranks a mention of it. Within each tier, namespace order, publics
before privates — the API is usually the quarry, and the private
sibling follows still flagged — then source line. A bare scope
listing ("helpers/") keeps whole-namespace source order instead: a
listing, not a ranking. Docstring hits
quote their matching lines as `:matched`, the same evidence `outline`
shows. `match` is required — the JVM's whole var population is no
glance — and takes what `nses` takes: a string (case-insensitive
substring, `*` a gap), a regex, or a symbol matched as its name. A
`/` qualifies the match, spelling the search the way Clojure spells
the target: "helpers/await" — string or symbol — scopes to the
namespaces whose *name* matches the ns side (docstrings not
consulted: a scope widened by a docstring mention would surprise) and
matches the name side within them, docstrings included as ever.
Either side may be empty — "helpers/" lists a scope whole,
"/await" degenerates to the bare search. A regex containing `/`
instead matches whole qualified names, #"helpers[^/]*/await" — the
one spelling that mixes forms — where a slashless regex matches bare
names. `{:search-docstrings false}` restricts the name side to names
alone — the docstring tier vanishes.cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |