<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>Engineering-Tools on NicoLabs</title>
		<link>http://blog.hellonico.info/tags/engineering-tools/</link>
		<description>Recent content in Engineering-Tools on NicoLabs</description>
		<generator>Hugo</generator>
		<language>ja-JP</language>
		
		
		
		
			<lastBuildDate>Wed, 27 Aug 2025 00:00:00 +0000</lastBuildDate>
		
			<atom:link href="http://blog.hellonico.info/tags/engineering-tools/index.xml" rel="self" type="application/rss+xml" />
			<item>
				<title>compare_reviews.clj — A tiny, configurable LLM-powered reviewer in Clojure</title>
				<link>http://blog.hellonico.info/posts/pyjama/15_gen/</link>
				<pubDate>Wed, 27 Aug 2025 00:00:00 +0000</pubDate>
				<guid>http://blog.hellonico.info/posts/pyjama/15_gen/</guid>
				<description>&lt;h1 id=&#34;overview&#34;&gt;Overview&lt;/h1&gt;&#xA;&lt;p&gt;This tool assembles Markdown from patterns, calls an LLM with a structured prompt, and writes a report as Markdown (and optionally PDF). It’s driven by EDN config, meaning you can change behavior by editing data, not code.&lt;/p&gt;&#xA;&lt;p&gt;Why it’s cool:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Configuration-as-data (EDN): composable, Git-friendly, reproducible.&lt;/li&gt;&#xA;&lt;li&gt;Clear pipeline: collect → call LLM → write → optional PDF and summary.&lt;/li&gt;&#xA;&lt;li&gt;Smart outputs: timestamped filenames avoid collisions with minimal friction.&lt;/li&gt;&#xA;&lt;li&gt;Extensible “agent” model: the LLM call is just a map merged into &lt;code&gt;agent/call&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Minimal code, lots of leverage (Pandoc, glob patterns, simple IO).&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;hr&gt;&#xA;&lt;h1 id=&#34;high-level-data-flow&#34;&gt;High-level data flow&lt;/h1&gt;&#xA;&lt;div class=&#34;mermaid&#34; id=&#34;id-1&#34;&gt;&lt;/div&gt;&#xA;&lt;script&gt;&#xA;    window.config = window.config || {};&#xA;    window.config.data = window.config.data || {};&#xA;    window.config.data[&#34;id-1&#34;] = &#34;flowchart TD\n    A[\&#34;Start\&#34;] --\u003e B[\&#34;load-config (EDN path or map)\&#34;]\n    B --\u003e C[\&#34;mru/aggregate-md-from-patterns\&#34;]\n    C --\u003e D[\&#34;agent/call (merge model + {:system :pre :prompt})\&#34;]\n    D --\u003e E[\&#34;resolve-output-file\&#34;]\n    E --\u003e F[\&#34;Write main .md\&#34;]\n    F --\u003e G{\&#34;pdf?\&#34;}\n    G -- Yes --\u003e H[\&#34;Pandoc md-\u003epdf\&#34;]\n    G -- No --\u003e I[\&#34;Skip\&#34;]\n    F --\u003e J{\&#34;summary?\&#34;}\n    J -- Yes --\u003e K[\&#34;agent/call for summary\&#34;]\n    K --\u003e L[\&#34;Write _summary.md\&#34;]\n    J -- No --\u003e I\n    H --\u003e I[\&#34;Done\&#34;]\n    L --\u003e I&#34;;&#xA;&lt;/script&gt;&#xA;&lt;hr&gt;&#xA;&lt;h1 id=&#34;code-walkthrough-what-each-function-does&#34;&gt;Code walkthrough (what each function does)&lt;/h1&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-clj&#34; data-lang=&#34;clj&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;ns &lt;/span&gt;margin-mania.reporting.compare-reviews&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#e6db74&#34;&gt;:require&lt;/span&gt; [clojure.edn &lt;span style=&#34;color:#e6db74&#34;&gt;:as&lt;/span&gt; edn]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            [pyjama.core &lt;span style=&#34;color:#e6db74&#34;&gt;:as&lt;/span&gt; agent]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            [margin-mania.reporting.utils &lt;span style=&#34;color:#e6db74&#34;&gt;:as&lt;/span&gt; mru]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            [pyjama.tools.pandoc]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            [clojure.java.io &lt;span style=&#34;color:#e6db74&#34;&gt;:as&lt;/span&gt; io])&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#e6db74&#34;&gt;:import&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;java.io&lt;/span&gt; File PushbackReader)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#a6e22e&#34;&gt;java.time&lt;/span&gt; LocalDateTime)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#a6e22e&#34;&gt;java.time.format&lt;/span&gt; DateTimeFormatter)))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;pyjama.core/agent&lt;/code&gt;: abstraction over the LLM call (&lt;code&gt;agent/call&lt;/code&gt;).&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;mru/aggregate-md-from-patterns&lt;/code&gt;: globs files and concatenates Markdown (plus optional metadata).&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;pyjama.tools.pandoc&lt;/code&gt;: converts Markdown to PDF.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;load-config&#34;&gt;load-config&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-clj&#34; data-lang=&#34;clj&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;defn &lt;/span&gt;load-config [cfg]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#a6e22e&#34;&gt;cond&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (string? cfg)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (with-open [r (&lt;span style=&#34;color:#a6e22e&#34;&gt;io/reader&lt;/span&gt; cfg)]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#a6e22e&#34;&gt;edn/read&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;PushbackReader.&lt;/span&gt; r)))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (map? cfg) cfg&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;:else&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;throw&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;ex-info&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Unsupported config type&amp;#34;&lt;/span&gt; {&lt;span style=&#34;color:#e6db74&#34;&gt;:given&lt;/span&gt; cfg}))))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;Accepts either a path to EDN or a pre-built map.&lt;/li&gt;&#xA;&lt;li&gt;Encourages configuration-as-data and REPL ergonomics.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;timestamp-and-output-resolution&#34;&gt;Timestamp and output resolution&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-clj&#34; data-lang=&#34;clj&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;^&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;:private&lt;/span&gt; timestamp []&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#a6e22e&#34;&gt;.format&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;LocalDateTime/now&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           (&lt;span style=&#34;color:#a6e22e&#34;&gt;DateTimeFormatter/ofPattern&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;yyyy-MM-dd_HH-mm-ss&amp;#34;&lt;/span&gt;)))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;defn &lt;/span&gt;resolve-output-file&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Return the actual File to write to.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;   If out-file is a directory or has no extension, use &amp;lt;dir&amp;gt;/&amp;lt;yyyy-MM-dd_HH-mm-ss&amp;gt;.md.&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [out-file]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#66d9ef&#34;&gt;let &lt;/span&gt;[f (&lt;span style=&#34;color:#a6e22e&#34;&gt;io/file&lt;/span&gt; out-file)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        as-dir? (or (&lt;span style=&#34;color:#a6e22e&#34;&gt;.isDirectory&lt;/span&gt; f)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    (not (re-find &lt;span style=&#34;color:#f92672&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;\.[^/\\]+$&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;.getName&lt;/span&gt; f))))]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#66d9ef&#34;&gt;if &lt;/span&gt;as-dir?&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#a6e22e&#34;&gt;io/file&lt;/span&gt; f (str (&lt;span style=&#34;color:#a6e22e&#34;&gt;timestamp&lt;/span&gt;) &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;.md&amp;#34;&lt;/span&gt;))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      f)))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;If &lt;code&gt;:out-file&lt;/code&gt; is a directory or lacks an extension, it auto-generates a timestamped filename, e.g. &lt;code&gt;2025-08-27_16-30-12.md&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;summary-file-helper&#34;&gt;Summary file helper&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-clj&#34; data-lang=&#34;clj&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;defn &lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;^&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;:private&lt;/span&gt; summary-file&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Given the primary output file, return the summary file: &amp;lt;same path&amp;gt; with `_summary.md`.&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;^&lt;/span&gt;File [&lt;span style=&#34;color:#f92672&#34;&gt;^&lt;/span&gt;File final-file]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#66d9ef&#34;&gt;let &lt;/span&gt;[parent (&lt;span style=&#34;color:#a6e22e&#34;&gt;.getParentFile&lt;/span&gt; final-file)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        name (&lt;span style=&#34;color:#a6e22e&#34;&gt;.getName&lt;/span&gt; final-file)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        base (&lt;span style=&#34;color:#66d9ef&#34;&gt;if &lt;/span&gt;(re-find &lt;span style=&#34;color:#f92672&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;\.md$&amp;#34;&lt;/span&gt; name)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               (subs name &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; (- (count name) &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               name)]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#a6e22e&#34;&gt;io/file&lt;/span&gt; parent (str base &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;_summary.md&amp;#34;&lt;/span&gt;))))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;Takes the main report path and returns the companion summary filename (e.g., &lt;code&gt;report.md&lt;/code&gt; → &lt;code&gt;report_summary.md&lt;/code&gt;).&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;the-main-engine-process-review&#34;&gt;The main engine: process-review&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-clj&#34; data-lang=&#34;clj&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;defn &lt;/span&gt;process-review&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;If :summary true, performs a second LLM call over the first call&amp;#39;s output and writes&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;   `&amp;lt;previous out-file&amp;gt;_summary.md`.&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [{&lt;span style=&#34;color:#e6db74&#34;&gt;:keys&lt;/span&gt; [patterns model out-file system pre pdf summary]}]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#66d9ef&#34;&gt;let &lt;/span&gt;[combined-md (&lt;span style=&#34;color:#a6e22e&#34;&gt;mru/aggregate-md-from-patterns&lt;/span&gt; patterns)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        result-1 (&lt;span style=&#34;color:#a6e22e&#34;&gt;agent/call&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   (merge model&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          {&lt;span style=&#34;color:#e6db74&#34;&gt;:system&lt;/span&gt; system&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           &lt;span style=&#34;color:#e6db74&#34;&gt;:pre&lt;/span&gt;    pre&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                           &lt;span style=&#34;color:#e6db74&#34;&gt;:prompt&lt;/span&gt; [combined-md]}))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        final-file (&lt;span style=&#34;color:#a6e22e&#34;&gt;resolve-output-file&lt;/span&gt; out-file)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        out-1-str (with-out-str (println result-1))]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;;; write main result&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#a6e22e&#34;&gt;io/make-parents&lt;/span&gt; final-file)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#a6e22e&#34;&gt;spit&lt;/span&gt; final-file out-1-str)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;;; optional PDF for main result&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (when pdf&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#a6e22e&#34;&gt;pyjama.tools.pandoc/md-&amp;gt;pdf&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#e6db74&#34;&gt;:input&lt;/span&gt;  final-file&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#e6db74&#34;&gt;:output&lt;/span&gt; (str final-file &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;.pdf&amp;#34;&lt;/span&gt;)}))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;;; optional summary step&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (when summary&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (&lt;span style=&#34;color:#66d9ef&#34;&gt;let &lt;/span&gt;[sum-pre &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Generated a short summary, (with title and points just like a ppt slide)  of %s&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            result-2 (&lt;span style=&#34;color:#a6e22e&#34;&gt;agent/call&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       (merge model&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              {&lt;span style=&#34;color:#e6db74&#34;&gt;:system&lt;/span&gt; system&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                               &lt;span style=&#34;color:#e6db74&#34;&gt;:pre&lt;/span&gt;    sum-pre&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                               &lt;span style=&#34;color:#e6db74&#34;&gt;:prompt&lt;/span&gt; [out-1-str]}))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            sum-file (&lt;span style=&#34;color:#a6e22e&#34;&gt;summary-file&lt;/span&gt; final-file)]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#a6e22e&#34;&gt;io/make-parents&lt;/span&gt; sum-file)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (&lt;span style=&#34;color:#a6e22e&#34;&gt;spit&lt;/span&gt; sum-file (with-out-str (println result-2)))))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;;; return the path(s) for convenience&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#e6db74&#34;&gt;:out&lt;/span&gt;     (&lt;span style=&#34;color:#a6e22e&#34;&gt;.getPath&lt;/span&gt; final-file)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#e6db74&#34;&gt;:summary&lt;/span&gt; (when summary (&lt;span style=&#34;color:#a6e22e&#34;&gt;.getPath&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;summary-file&lt;/span&gt; final-file)))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#e6db74&#34;&gt;:pdf&lt;/span&gt;     (when pdf (str final-file &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;.pdf&amp;#34;&lt;/span&gt;))}))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;Aggregates input Markdown per &lt;code&gt;:patterns&lt;/code&gt;, then calls the LLM once to produce the main report.&lt;/li&gt;&#xA;&lt;li&gt;Writes the main &lt;code&gt;.md&lt;/code&gt;, and if &lt;code&gt;:pdf true&lt;/code&gt;, renders a PDF via Pandoc.&lt;/li&gt;&#xA;&lt;li&gt;If &lt;code&gt;:summary true&lt;/code&gt;, performs a second LLM call on the first output and writes &lt;code&gt;..._summary.md&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Returns a map of produced paths for convenience.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Notes:&lt;/p&gt;</description>
			</item>
	</channel>
</rss>
