Portrait

The portrait system exposes everything the compiler knows about your code: signal profiles, capture analysis, composition properties, and the call graph. It analyzes source without executing it.

See also: Agent Reasoning in Elle for how to use portrait + MCP together for codebase-wide analysis. For global codebase queries, see MCP server.

Compile-time analysis

(def src "(defn validate [data]
  (when (nil? (get data :name))
    (error {:error :validation-error :message \"missing name\"}))
  data)")

(def a (compile/analyze src {:file "example.lisp"}))

Signal queries

# Query a function's inferred signal profile
(compile/signal a :validate)
# => {:silent false :jit-eligible true :propagates ... }

# Query what a closure captures
(compile/captures a :process)
# => (:count :config)

# Query what a function calls
(compile/callees a :process)
# => (:validate :transform ...)

# Full call graph
(compile/call-graph a)

Portrait library

The lib/portrait.lisp library wraps the raw analysis APIs into structured reports.

(def portrait ((import "std/portrait.lisp")))

# Function portrait — signal profile, captures, callees
(println (portrait:render (portrait:function a :validate)))

# Module portrait — signal topology across all functions
(println (portrait:render (portrait:module a)))

Phases

1. Analyzecompile/analyze parses and type-checks without executing 2. Querycompile/signal, compile/captures, compile/callees 3. Composeportrait:function, portrait:module build structured data 4. Renderportrait:render formats for display


See also