<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Blog on Posit Open Source</title>
    <link>https://opensource.posit.co/blog/</link>
    <description>Recent content in Blog on Posit Open Source</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <atom:link href="https://opensource.posit.co/blog/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Positron August Release Highlights</title>
      <link>https://opensource.posit.co/blog/2026-08-13_positron-2026-08-release/</link>
      <pubDate>Thu, 13 Aug 2026 00:00:00 +0000</pubDate>
      <guid>https://opensource.posit.co/blog/2026-08-13_positron-2026-08-release/</guid>
      <dc:creator>Julia Silge</dc:creator><description><![CDATA[<div class="callout callout-note" role="note" aria-label="Note">
<div class="callout-header">
<span class="callout-title">Note</span>
</div>
<div class="callout-body">
<p><a href="https://positron.posit.co" target="_blank" rel="noopener">Positron</a> is Posit&rsquo;s new, next-generation IDE for data science. Positron is designed to be an extensible, polyglot tool for exploring data and reproducible authoring in Python, R, and more.</p>
</div>
</div>
<p>Welcome back to another edition of our monthly Positron updates! Each month we share highlights from our <a href="https://positron.posit.co/release-notes" target="_blank" rel="noopener">latest release</a> and useful resources. <a href="https://opensource.posit.co/blog/2026-07-13_positron-2026-07-release">Last release</a> we told you about several major features that came out of preview to general availability, including the <a href="https://opensource.posit.co/blog/2026-07-29_positron-jupyter-notebook-editor-ga">new notebook editor</a>. This milestone we are excited to share new functionality for SQL support, reproducible authoring, helping you know when packages are missing, and more.</p>
<h2 id="data-connections">Data Connections
</h2>
<p>Data Connections is our new way to work with SQL and database-like resources in Positron, from local files and database servers to cloud data warehouses. It is currently available as a preview feature, and you can enable it with the <a href="positron://settings/dataConnections.enabled"><code>dataConnections.enabled</code></a> setting. This release more than doubles the number of data sources you can reach. Amazon Redshift, Snowflake, Databricks, and Posit Connect pins join the existing DuckDB, PostgreSQL, and SQLite support.</p>
<img src="https://opensource.posit.co/blog/2026-08-13_positron-2026-08-release/data-connections.gif" data-fig-align="center" data-fig-alt="Browsing the schemas and tables of a DuckDB connection in the Data Connections panel, then opening a table in the Data Explorer to see its column profiles and data." />
<p>The panel itself is more capable as well. <strong>Refresh</strong> and <strong>Refresh All</strong> reload the tree while preserving what you have expanded, briefly highlighting the rows that were reloaded. Open connections now show an indicator. Collapsing a connection in the UI keeps you connected to your data source, while anything you&rsquo;ve previewed with the Data Explorer stays still open. When you remove a connection, Positron asks for confirmation and reports how many Data Explorers will close with it.</p>
<p>Data Connections is still an experimental preview, and your feedback continues to shape it. Tell us which databases and warehouses you need, and anything confusing, missing, or broken, in the <a href="https://github.com/posit-dev/positron/discussions/14571" target="_blank" rel="noopener">Data Connections discussion</a>.</p>
<h2 id="inline-output-for-quarto">Inline output for Quarto
</h2>
<p><a href="https://positron.posit.co/quarto-inline-output" target="_blank" rel="noopener">Inline output for <code>.qmd</code> documents</a> came out of preview last release, and this release brings you a substantial round of polish for this way of working. Be aware that the Quarto settings have moved into a dedicated <code>quarto.*</code> namespace with its own group in the Settings editor. The previous <code>positron.quarto.*</code> keys still work but are deprecated, and Positron will prompt you to update your settings.</p>
<p>Before a kernel starts, the kernel status names the interpreter it will start and offers an explicit <strong>Start Kernel</strong> action. When a cell fails, <strong>Fix</strong> and <strong>Explain</strong> buttons send the error to <a href="https://assistant.posit.co/" target="_blank" rel="noopener">Posit Assistant</a>, matching the Positron notebook experience. The editor also scrolls to reveal output as it is produced, which you can turn off with the new <a href="positron://settings/quarto.inlineOutput.autoScroll"><code>quarto.inlineOutput.autoScroll</code></a> setting.</p>
<p>Output renders more faithfully as well. The editor gutter now shows which statement is currently executing and per-statement progress. Positron draws images at your display&rsquo;s pixel ratio, so plots are sharp on retina screens, and Python figures now respect the <code>fig-width</code> and <code>fig-height</code> cell options.</p>
<img src="https://opensource.posit.co/blog/2026-08-13_positron-2026-08-release/inline-output-plot-metadata.png" data-fig-align="center" data-fig-alt="A Quarto document open in Positron with a Python cell that sets the fig-width and fig-height options, and the resulting matplotlib scatter plot rendered inline below the cell at that size." />
<p>HTML widgets no longer stick in the editor corner when you scroll past them, or trap scrolling instead of letting the document scroll. HTML widgets no longer render as raw HTML after a reload, and collapsed output no longer springs back open when its cell re-runs. Running code in a Quarto document also pins the editor tab now, so Positron does not silently close the document and its session when you open another file.</p>
<h2 id="ai-model-providers">AI model providers
</h2>
<p>Positron now reads AI model provider configuration from a single <code>providers.json</code> file rather than a scattered set of settings. The new release will migrate your existing configuration automatically when you start it, and deprecates the <code>authentication.*</code> and <code>positron.assistant.provider.*.enable</code> settings in favor of it. Two new commands give you direct access: <em>Open AI Provider Settings (JSON)</em> opens <code>providers.json</code> from the Command Palette, and <em>Migrate Provider Settings to providers.json</em> runs the migration on demand.</p>
<h2 id="install-missing-packages">Install missing packages
</h2>
<p>Positron now notices when your code refers to a package you do not have installed and offers to install it for you. The prompt appears for packages referenced by your scripts and notebooks in both R and Python.</p>
<img src="https://opensource.posit.co/blog/2026-08-13_positron-2026-08-release/missing-package.gif" data-fig-align="center" data-fig-alt="A Shiny app in Positron showing a missing package button in the editor toolbar. Clicking it installs bslib in the console, and the app then runs with its bubble chart in the Viewer pane." />
<p>A <code>library()</code> or <code>import</code> call for something missing becomes a single click instead of an error you have to go resolve by hand.</p>
<h2 id="performance-and-memory">Performance and memory
</h2>
<p>We continue to invest in the memory footprint, performance, and reliability of Positron. Several components now load only when they are actually needed, and turning off <a href="positron://settings/ai.enabled"><code>ai.enabled</code></a> now means Positron never loads some heavy AI-related components at all. We fixed a cluster of long-standing reliability problems around session restarts and lifecycles.</p>
<p>Startup and editing are faster as well. R and Python kernels start much faster on Windows systems with aggressive antivirus software. The interpreter session picker appears immediately instead of waiting for interpreter discovery to finish. We also fixed slow typing, formatting, and saving in long R and Python files.</p>
<h2 id="whats-coming-next">What&rsquo;s coming next
</h2>
<ul>
<li>Join <a href="https://posit.co/workflow-demo/ai-governance-workbench" target="_blank" rel="noopener">our upcoming webinar</a> on August 26 to learn about AI governance in Posit Workbench.</li>
<li>We are looking forward to posit::conf(2026) next month, where our team will have several sessions on Positron. <a href="https://conf.posit.co/2026/" target="_blank" rel="noopener">Register now</a> to join us in person in Houston or virtually from anywhere in the world.</li>
</ul>
<div class="callout callout-tip" role="note" aria-label="Tip">
<div class="callout-header">
<span class="callout-title">Tip</span>
</div>
<div class="callout-body">
<p><a href="https://positron.posit.co/download" target="_blank" rel="noopener">Download Positron</a> to try out the new features and improvements in this release!</p>
</div>
</div>
]]></description>
      <enclosure url="https://opensource.posit.co/blog/2026-08-13_positron-2026-08-release/featured.svg" length="91423" type="image/svg&#43;xml" />
    </item>
    <item>
      <title>Kimi K3 and GLM 5.2 are now in Posit AI</title>
      <link>https://opensource.posit.co/blog/2026-08-10_kimi-k3-glm-5-2-posit-ai/</link>
      <pubDate>Mon, 10 Aug 2026 00:00:00 +0000</pubDate>
      <guid>https://opensource.posit.co/blog/2026-08-10_kimi-k3-glm-5-2-posit-ai/</guid>
      <dc:creator>Simon Couch</dc:creator><description><![CDATA[<p>We&rsquo;re super stoked to share that two more open weights models—Kimi K3 and GLM 5.2—are now available as part of <a href="https://posit.ai/" target="_blank" rel="noopener">Posit AI</a>. Both of these models are substantially cheaper than the proprietary models they feel most similar to, albeit a bit rougher on the edges. Notably, as well, these models are served much more quickly than Anthropic models; we&rsquo;ve been seeing these models stream almost twice as many tokens per second in our internal testing, and working with them is a qualitatively different feel. <a href="https://docs.posit.co/posit-ai/user/faq/#privacy-data-storage" target="_blank" rel="noopener">As with the other models</a> made available in Posit AI, <strong>your conversation histories will not be stored unless you choose to opt-in to data retention at sign-up.</strong></p>
<p>Kimi K3 is currently the most capable open weights model out there. In our internal testing, it feels somewhere between Opus 5 and Fable 5, and is notably well-rounded compared to other open weights releases. It&rsquo;s priced at the same price-per-token as Claude Sonnet 5.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
<p>GLM 5.2 excels at agentic coding and less so at data analysis tasks. Because the model is not vision-capable, it cannot &lsquo;see&rsquo; plots and thus feels less capable for data science work. Its per-token pricing is also similar to Haiku 4.5, but feels something like Opus 4.6 or Sonnet 5 for agentic coding tasks.</p>
<h2 id="pricing">Pricing
</h2>
<p>The models in Posit AI today, at a glance:</p>
<table>
  <thead>
      <tr>
          <th style="text-align: left">Model</th>
          <th style="text-align: right">Cached input</th>
          <th style="text-align: right">Input</th>
          <th style="text-align: right">Cache write</th>
          <th style="text-align: right">Output</th>
          <th style="text-align: right">Context length</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: left">Claude Opus 5</td>
          <td style="text-align: right">$0.55</td>
          <td style="text-align: right">$5.50</td>
          <td style="text-align: right">$6.875</td>
          <td style="text-align: right">$27.50</td>
          <td style="text-align: right">1M</td>
      </tr>
      <tr>
          <td style="text-align: left">Claude Sonnet 5</td>
          <td style="text-align: right">$0.33</td>
          <td style="text-align: right">$3.30</td>
          <td style="text-align: right">$4.125</td>
          <td style="text-align: right">$16.50</td>
          <td style="text-align: right">1M</td>
      </tr>
      <tr>
          <td style="text-align: left"><strong>Kimi K3</strong></td>
          <td style="text-align: right"><strong>$0.33</strong></td>
          <td style="text-align: right"><strong>$3.30</strong></td>
          <td style="text-align: right"><strong>$0.00</strong></td>
          <td style="text-align: right"><strong>$16.50</strong></td>
          <td style="text-align: right"><strong>250K</strong><sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></td>
      </tr>
      <tr>
          <td style="text-align: left"><strong>GLM 5.2</strong></td>
          <td style="text-align: right"><strong>$0.154</strong></td>
          <td style="text-align: right"><strong>$1.54</strong></td>
          <td style="text-align: right"><strong>$0.00</strong></td>
          <td style="text-align: right"><strong>$4.84</strong></td>
          <td style="text-align: right"><strong>256K</strong></td>
      </tr>
      <tr>
          <td style="text-align: left">Claude Haiku 4.5</td>
          <td style="text-align: right">$0.11</td>
          <td style="text-align: right">$1.10</td>
          <td style="text-align: right">$1.375</td>
          <td style="text-align: right">$5.50</td>
          <td style="text-align: right">200K</td>
      </tr>
      <tr>
          <td style="text-align: left">Gemma 4 26B A4B</td>
          <td style="text-align: right">$0.033</td>
          <td style="text-align: right">$0.33</td>
          <td style="text-align: right">$0.00</td>
          <td style="text-align: right">$1.65</td>
          <td style="text-align: right">100K</td>
      </tr>
  </tbody>
</table>
<p><strong>The cost savings are greater than the per-token pricing differences alone might suggest.</strong> For one, the Claude 5 series models use a tokenizer that results in substantially more tokens (~35%) per word than Kimi K3&rsquo;s or GLM 5.2&rsquo;s tokenizer. Also, users are not billed at a higher rate for Cache writes than &rsquo;normal&rsquo; input tokens; all input tokens are written to the cache by default, but we can&rsquo;t make a guarantee that you&rsquo;ll hit the cache after any specific delay between requests. In practice, we&rsquo;ve seen that the cache efficiency of conversations with these deployments is slightly lower than with Claude models.</p>
<h2 id="get-started">Get started
</h2>
<p>To get started, open up <a href="https://assistant.posit.co/" target="_blank" rel="noopener">Posit Assistant</a> and update when prompted! Then, select your model of choice under the Posit AI model provider. If you&rsquo;re not already a Posit AI subscriber, you can learn more <a href="https://posit.ai/" target="_blank" rel="noopener">here</a>.</p>
<p>It&rsquo;s worth saying that we suspect these models will rotate somewhat regularly in the service; as the months go by, we plan to introduce support for new models and deprecate others.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Claude Sonnet 5 is currently priced at a promotional $2/$10, but will be back to its usual $3/$15 in a few weeks. The pricing is the same <em>after</em> Sonnet 5&rsquo;s promotional pricing ends.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>While Kimi K3 technically supports a 1M-token context window, we&rsquo;ve limited it to 250K in Posit AI to ensure we have enough capacity.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></description>
      <enclosure url="https://opensource.posit.co/blog/2026-08-10_kimi-k3-glm-5-2-posit-ai/featured.png" length="200054" type="image/png" />
    </item>
    <item>
      <title>cuda.ml 0.4.0: GPU-accelerated machine learning from R</title>
      <link>https://opensource.posit.co/blog/2026-08-05_cuda-ml-0-4-0/</link>
      <pubDate>Wed, 05 Aug 2026 00:00:00 +0000</pubDate>
      <guid>https://opensource.posit.co/blog/2026-08-05_cuda-ml-0-4-0/</guid>
      <dc:creator>Tomasz Kalinowski</dc:creator><description><![CDATA[<p><a href="https://mlverse.github.io/cuda.ml/" target="_blank" rel="noopener">cuda.ml</a> is an R package for
running common data science and machine-learning operations on NVIDIA
GPUs. It provides high-level interfaces for fitting regression and
classification models, finding nearest neighbors, clustering
observations, reducing dimensions, and running predictions from tree
ensembles. You can use its direct R functions or work through parsnip
and tidymodels.</p>
<p>cuda.ml is for data scientists who work primarily in R and want to use a
GPU without moving their modeling workflow to Python or learning
low-level GPU APIs. Version 0.4.0 is a substantial update to the
package. It makes installation much simpler, expands tidymodels support,
adds more ways to run tree-ensemble models, and makes it straightforward
to save and restore supported fitted models.</p>
<h2 id="install-from-cran">Install from CRAN
</h2>
<p>For most users, setup is two commands:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">install.packages</span><span class="p">(</span><span class="s">&#34;cuda.ml&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">cuda.ml</span><span class="o">::</span><span class="nf">cuda_ml_install</span><span class="p">()</span></span></span></code></pre></div></div>
<p>The package from CRAN is a regular, portable R package.
<code>cuda_ml_install()</code> downloads and verifies the matching compiled backend
and GPU libraries, then keeps them in a cache for later R sessions. On a
supported system, you do not need to compile cuda.ml from source,
configure a Python environment, or assemble the GPU libraries yourself.</p>
<p>The result is a familiar R package workflow: install the package,
prepare its supporting libraries once, and start an analysis. The extra
installation call is explicit because the GPU libraries are much larger
than the R package. Repeated calls reuse the completed cache, and
loading cuda.ml itself is quiet and does not initialize CUDA.</p>
<p>Prebuilt support is available for Linux x86_64 with glibc 2.28 or newer.
GPU operations require a supported NVIDIA GPU and driver 580 or newer.
On Windows, install and run R inside a compatible WSL2 Linux
distribution. See the <a href="https://mlverse.github.io/cuda.ml/articles/install-manage.html" target="_blank" rel="noopener">installation guide</a> for the complete system requirements and source-build options.</p>
<h2 id="use-familiar-modeling-interfaces">Use familiar modeling interfaces
</h2>
<p>cuda.ml registers parsnip engines for linear, logistic, and multinomial
regression, random forests, nearest neighbors, and radial, polynomial,
and linear support-vector machines. For example, this fits a
random-forest classifier on the GPU using the standard parsnip
interface:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">cuda.ml</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">parsnip</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">forest_spec</span> <span class="o">&lt;-</span> <span class="nf">rand_forest</span><span class="p">()</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">set_mode</span><span class="p">(</span><span class="s">&#34;classification&#34;</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">set_engine</span><span class="p">(</span><span class="s">&#34;cuda.ml&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">forest_fit</span> <span class="o">&lt;-</span> <span class="n">forest_spec</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">fit</span><span class="p">(</span><span class="n">class</span> <span class="o">~</span> <span class="n">.,</span> <span class="n">data</span> <span class="o">=</span> <span class="n">modeldata</span><span class="o">::</span><span class="n">hpc_data</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nf">predict</span><span class="p">(</span><span class="n">forest_fit</span><span class="p">,</span> <span class="n">modeldata</span><span class="o">::</span><span class="n">hpc_data[1</span><span class="o">:</span><span class="m">5</span><span class="p">,</span> <span class="n">]</span><span class="p">,</span> <span class="n">type</span> <span class="o">=</span> <span class="s">&#34;prob&#34;</span><span class="p">)</span></span></span></code></pre></div></div>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl"># A tibble: 5 × 4
</span></span><span class="line"><span class="cl">  .pred_VF .pred_F .pred_M  .pred_L
</span></span><span class="line"><span class="cl">     &lt;dbl&gt;   &lt;dbl&gt;   &lt;dbl&gt;    &lt;dbl&gt;
</span></span><span class="line"><span class="cl">1    0.309  0.597  0.0666  0.0275
</span></span><span class="line"><span class="cl">2    0.899  0.0838 0.0138  0.00335
</span></span><span class="line"><span class="cl">3    0.965  0.0261 0.00850 0.000883
</span></span><span class="line"><span class="cl">4    0.973  0.0228 0.00416 0.000352
</span></span><span class="line"><span class="cl">5    0.966  0.0298 0.00416 0.000352</span></span></code></pre></div></div>
<p><code>set_engine(&quot;cuda.ml&quot;)</code> selects the GPU-backed cuda.ml engine; the rest
is a standard parsnip workflow. Recipes can learn preprocessing on the
training data and carry it into resampling and prediction.</p>
<h2 id="work-directly-with-cudaml">Work directly with cuda.ml
</h2>
<p>cuda.ml also provides a direct R interface. This is useful when you
prefer a function-oriented workflow or want to use the package on its
own.</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">cuda.ml</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">ggplot2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">clusters</span> <span class="o">&lt;-</span> <span class="nf">cuda_ml_kmeans</span><span class="p">(</span><span class="nf">scale</span><span class="p">(</span><span class="n">faithful</span><span class="p">),</span> <span class="n">k</span> <span class="o">=</span> <span class="m">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">faithful</span><span class="o">$</span><span class="n">cluster</span> <span class="o">&lt;-</span> <span class="nf">factor</span><span class="p">(</span><span class="n">clusters</span><span class="o">$</span><span class="n">labels</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">ggplot</span><span class="p">(</span><span class="n">faithful</span><span class="p">,</span> <span class="nf">aes</span><span class="p">(</span><span class="n">eruptions</span><span class="p">,</span> <span class="n">waiting</span><span class="p">,</span> <span class="n">color</span> <span class="o">=</span> <span class="n">cluster</span><span class="p">))</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl">  <span class="nf">geom_point</span><span class="p">(</span><span class="n">size</span> <span class="o">=</span> <span class="m">2.5</span><span class="p">)</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl">  <span class="nf">labs</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">x</span> <span class="o">=</span> <span class="s">&#34;Eruption duration (minutes)&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">y</span> <span class="o">=</span> <span class="s">&#34;Waiting time (minutes)&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl">  <span class="nf">theme_minimal</span><span class="p">()</span></span></span></code></pre></div></div>
<img src="https://opensource.posit.co/blog/2026-08-05_cuda-ml-0-4-0/index.markdown_strict_files/figure-markdown_strict/faithful-clusters-1.png" data-fig-align="center" data-fig-alt="Scatterplot of Old Faithful eruption durations and waiting times, colored by two clusters. Shorter eruptions have shorter waits, while longer eruptions have longer waits." width="768" />
<p>The direct API covers supervised models as well as clustering and
dimensionality reduction, including DBSCAN, k-means, PCA, tSVD, UMAP,
and t-SNE. It also includes stochastic-gradient-descent regression, the
hyperbolic-tangent SVM kernel, and external tree-ensemble inference.</p>
<h2 id="run-tree-ensembles-on-a-gpu-or-cpu">Run tree ensembles on a GPU or CPU
</h2>
<p>This release expands where and how you can make predictions with tree
ensembles. The new nvForest support powers prediction for random forests
trained with <code>cuda_ml_rand_forest()</code> and can load trained XGBoost
models, LightGBM text models, and Treelite checkpoints. Once a model is
loaded, the API provides standard prediction along with model
information, leaf identifiers, individual-tree predictions, and
checkpoint import and export.</p>
<p>GPU inference uses the complete cuda.ml installation. A deployment that
only needs CPU inference can prepare a smaller, CUDA-free backend:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">cuda.ml</span><span class="o">::</span><span class="nf">cuda_ml_install</span><span class="p">(</span><span class="n">device</span> <span class="o">=</span> <span class="s">&#34;cpu&#34;</span><span class="p">)</span></span></span></code></pre></div></div>
<p>The CPU backend can run a cuda.ml random forest trained on a GPU as well
as a supported external tree ensemble. The complete installation can
also run these models on a CPU, so the smaller backend is an optional
deployment choice.</p>
<h2 id="save-and-deploy-fitted-models">Save and deploy fitted models
</h2>
<p>cuda.ml 0.4.0 expands model persistence for training, analysis, and
deployment workflows. Supported fitted models can be saved to a
compressed file, restored in another R process, stored as raw bytes, or
wrapped with the bundle package.</p>
<p>The simplest file workflow passes a path directly:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">model</span> <span class="o">&lt;-</span> <span class="nf">cuda_ml_rand_forest</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="n">class</span> <span class="o">~</span> <span class="n">.,</span>
</span></span><span class="line"><span class="cl">  <span class="n">data</span> <span class="o">=</span> <span class="n">modeldata</span><span class="o">::</span><span class="n">hpc_data</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">trees</span> <span class="o">=</span> <span class="m">100</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">cuda_ml_serialize</span><span class="p">(</span><span class="n">model</span><span class="p">,</span> <span class="s">&#34;hpc-runtime-forest.cuda-ml&#34;</span><span class="p">)</span></span></span></code></pre></div></div>
<p>In another R process or deployment environment, prepare cuda.ml and
restore the fitted model:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">cuda.ml</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">cuda_ml_install</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">model</span> <span class="o">&lt;-</span> <span class="nf">cuda_ml_unserialize</span><span class="p">(</span><span class="s">&#34;hpc-runtime-forest.cuda-ml&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">predict</span><span class="p">(</span><span class="n">model</span><span class="p">,</span> <span class="n">modeldata</span><span class="o">::</span><span class="n">hpc_data[1</span><span class="o">:</span><span class="m">5</span><span class="p">,</span> <span class="n">]</span><span class="p">,</span> <span class="n">type</span> <span class="o">=</span> <span class="s">&#34;class&#34;</span><span class="p">)</span></span></span></code></pre></div></div>
<p>File paths use gzip compression. Passing <code>connection = NULL</code> instead
returns the state as an uncompressed raw vector of bytes, which is
convenient for object stores and database BLOB columns. The blob package
can represent raw vectors for database workflows, and the bundle package
is supported for teams that already use bundled model artifacts.</p>
<p>Persistence is available for linear models, logistic and multinomial
regression, PCA, SVC and SVR models, UMAP, random forests, and nvForest
models. cuda.ml checks the saved state and required backend before
restoring it. For an nvForest-backed model, the restore call can select
CPU or GPU inference.</p>
<h2 id="highlights-for-users-upgrading-from-cudaml-03">Highlights for users upgrading from cuda.ml 0.3
</h2>
<p>This is a breaking update to the earlier package. The most visible
changes are:</p>
<ul>
<li>The random-forest API now uses <code>mtry</code> for predictor sampling and
<code>sample_fraction</code> for row sampling. <code>trees</code> defaults to 100, and an
omitted <code>seed</code> draws from R&rsquo;s random-number generator, so <code>set.seed()</code>
controls the fit.</li>
<li>Linear, logistic, and multinomial regression now use numeric <code>penalty</code>
and <code>mixture</code> arguments that match parsnip. Logistic and multinomial
regression are unregularized by default.</li>
<li><code>normalize_input</code> was removed from the linear-model functions. It
previously requested GPU-side L2 normalization. Use explicit
preprocessing such as <code>recipes::step_normalize()</code> when centering and
scaling are appropriate; but please note, the two operations are not
numerically identical.</li>
<li><code>cuda_ml_sgd()</code> now fits squared-loss regression only. Its <code>loss</code>
argument was removed, and <code>n_iters_no_change</code> is now
<code>n_iter_no_change</code>.</li>
<li>The former FIL interface has been replaced by nvForest. Random
projection and the KNN IVFSQ index have no replacement in the pinned
upstream API.</li>
</ul>
<p>See the
<a href="https://mlverse.github.io/cuda.ml/news/index.html" target="_blank" rel="noopener">full changelog</a> for
the complete list of API changes.</p>
<p>The guides cover first steps and more complete examples:</p>
<ul>
<li><a href="https://mlverse.github.io/cuda.ml/articles/cuda-ml.html" target="_blank" rel="noopener">Get started with cuda.ml</a></li>
<li><a href="https://mlverse.github.io/cuda.ml/articles/tidymodels.html" target="_blank" rel="noopener">Use cuda.ml with tidymodels</a></li>
<li><a href="https://mlverse.github.io/cuda.ml/articles/model-persistence.html" target="_blank" rel="noopener">Save and restore models</a></li>
<li><a href="https://mlverse.github.io/cuda.ml/articles/nvforest.html" target="_blank" rel="noopener">nvForest inference and deployment</a></li>
</ul>
]]></description>
      <enclosure url="https://opensource.posit.co/blog/2026-08-05_cuda-ml-0-4-0/featured-alt.png" length="2702295" type="image/png" />
    </item>
    <item>
      <title>posit::glimpse() Newsletter – August 2026</title>
      <link>https://opensource.posit.co/blog/2026-08-05_glimpse-aug-2026/</link>
      <pubDate>Wed, 05 Aug 2026 00:00:00 +0000</pubDate>
      <guid>https://opensource.posit.co/blog/2026-08-05_glimpse-aug-2026/</guid>
      <dc:creator>Isabella Velásquez</dc:creator><description><![CDATA[<blockquote>
<p>Welcome to our newsletter, posit::glimpse()!</p>
<p>If you&rsquo;re currently reading this on our blog, consider subscribing to Product Updates - Open Source on our <a href="https://posit.co/about/subscription-management" target="_blank" rel="noopener">subscription page</a> to receive this newsletter directly in your inbox.</p>
</blockquote>
<p>Every month, we round up some of the most important open-source news for Posit&rsquo;s community! We hope that you enjoy this newsletter and maybe even share it with a friend.</p>
<p>The table of contents on the right can help you navigate through all the updates. As you scroll, it will open up to show you subcategories →</p>
<h2 id="announcements">Announcements
</h2>
<h3 id="register-for-positconf2026">Register for posit::conf(2026)
</h3>
<p>Register for our annual conference, <a href="https://posit.co/conference/" target="_blank" rel="noopener">posit::conf(2026)</a>, happening September 14-16 in Houston and online! The amazing <a href="https://posit.co/blog/posit-conf-2026-agenda-breakdown" target="_blank" rel="noopener">speakers</a> and <a href="https://posit.co/blog/workshops-at-positconf2026" target="_blank" rel="noopener">workshops</a> will make for a wonderful time. <a href="https://conf.posit.co/2026/registration/" target="_blank" rel="noopener">Register for posit::conf here</a>.</p>
<p>For the first time, the live streams will feature automatically translated subtitles, available in French, German, Italian, Portuguese, and Spanish.</p>
<p>Tidy Dev Day is on September 17, a unique opportunity to collaboratively tackle open-source issues and work directly alongside the very developers who build and maintain the tools you use every day. <a href="https://opensource.posit.co/blog/2026-06-25_tidy-dev-day-2026/" target="_blank" rel="noopener">Learn more about Tidy Dev Day here</a>.</p>
<h3 id="migrating-to-connect-cloud">Migrating to Connect Cloud
</h3>
<p>A thank-you to everyone who published on rpubs.com, quartopub.com, shinyapps.io, and bookdown.org. We&rsquo;re consolidating all our publishing tools into one: <a href="https://connect.posit.cloud/" target="_blank" rel="noopener">Posit Connect Cloud</a>. Connect Cloud is built to handle all of the content types in one place, with one account, and we hope to make your transition as smooth as possible.</p>
<ul>
<li>Learn more in the <a href="https://posit.co/blog/migrating-connect-cloud-posits-unified-publishing-solution" target="_blank" rel="noopener">Migrating to Connect Cloud: Posit&rsquo;s unified publishing solution blog post</a>.</li>
<li>Join our <a href="https://posit.co/webinar/connect-cloud-migration" target="_blank" rel="noopener">webinar on the migration process happening September 9th</a>.</li>
</ul>
<h2 id="key-product-updates-and-new-releases">Key product updates and new releases
</h2>
<h3 id="httr2-130">httr2 1.3.0
</h3>
<p><a href="https://httr2.r-lib.org/" target="_blank" rel="noopener">httr2</a> is a comprehensive HTTP client for R for working with web APIs. httr2 1.3.0 introduces a breaking change to OAuth token caching that requires one-time re-authentication. Recent patches added 200x faster streaming for short-line responses, OAuth server metadata discovery, OpenTelemetry tracing support, and <code>httr2_translate()</code> for converting requests to curl commands.</p>
<ul>
<li>Read more in the <a href="https://opensource.posit.co/blog/2026-07-14_httr2-1-3-0/" target="_blank" rel="noopener">httr2 1.3.0 blog post</a>.</li>
</ul>
<h3 id="ir-010">ir 0.1.0
</h3>
<p>Introducing <a href="https://r-lib.github.io/ir/" target="_blank" rel="noopener">ir</a> 0.1.0, a command-line tool for running self-describing R scripts and Quarto documents with embedded package dependencies and R version requirements, inspired by Python&rsquo;s PEP 723 and <code>uv run --script</code>. The tool supports isolated environments, CRAN snapshot dates, mixed R/Python workflows, and caches resolved dependencies for efficiency, enabling one-file workflows without full project structures.</p>
<ul>
<li>Read more in the <a href="https://opensource.posit.co/blog/2026-07-23_ir-0-1-0/" target="_blank" rel="noopener">ir 0.1.0 blog post</a>.</li>
</ul>
<h3 id="lorax">lorax
</h3>
<p><a href="https://lorax.tidymodels.org/" target="_blank" rel="noopener">lorax</a> introduces a unified interface for characterizing tree- and rule-based models across 12 implementations including ranger, XGBoost, LightGBM, and random forests. The package enables extracting decision rules, identifying active predictors, converting trees to partykit format for visualization, and accessing variable importance scores through consistent APIs that work across diverse tree model packages.</p>
<ul>
<li>Read more in the <a href="https://opensource.posit.co/blog/2026-07-28_lorax/" target="_blank" rel="noopener">Introducing lorax: Speaking for the Tree-Based Models blog post</a>.</li>
</ul>
<h3 id="mcptools-100">mcptools 1.0.0
</h3>
<p><a href="https://posit-dev.github.io/mcptools/" target="_blank" rel="noopener">mcptools</a>, an R SDK for the Model Context Protocol, is now on CRAN. It brings image support for rich content in both directions, native authenticated remote server connections eliminating the npm dependency, and streamlined <a href="https://posit.co/products/enterprise/connect" target="_blank" rel="noopener">Posit Connect</a> deployment via <code>_server.yml</code>. This R SDK for the Model Context Protocol enables deploying R functions as MCP servers and fetching third-party MCP tools as R functions.</p>
<ul>
<li>Read more in the <a href="https://opensource.posit.co/blog/2026-07-06_mcptools-1-0-0/" target="_blank" rel="noopener">mcptools 1.0.0 blog post</a>.</li>
</ul>
<h3 id="quarto-110">Quarto 1.10
</h3>
<p><a href="https://quarto.org/" target="_blank" rel="noopener">Quarto</a> transforms Markdown, code, and computational output into publication-ready articles, reports, presentations, websites, and books. Version 1.10 introduces offline HTML accessibility checking with bundled axe-core and WCAG conformance level targeting, plus localized string support for template authors. The release includes important fixes for <code>quarto preview</code> reliability, shortcode resolution in math expressions, and updated dependencies including pandoc 3.10 and typst 0.15.1.</p>
<ul>
<li>Read more in the <a href="https://opensource.posit.co/blog/2026-08-03_quarto-1-10/" target="_blank" rel="noopener">Quarto 1.10 blog post</a>.</li>
</ul>
<h3 id="raghilda-v02">raghilda v0.2
</h3>
<p><a href="https://posit-dev.github.io/raghilda/" target="_blank" rel="noopener">Raghilda</a> is a Python package for building RAG (Retrieval-Augmented Generation) solutions. This release focuses on production-ready features for scaling RAG pipelines, with crawl and ingest API with caching and concurrency, a CloudflareCrawler for JavaScript-rendered sites, a PostgreSQL store backend, and NVIDIA NIM embeddings.</p>
<ul>
<li>Check out the <a href="https://opensource.posit.co/blog/2026-07-01_raghilda-0-2-0/" target="_blank" rel="noopener">raghilda v0.2 blog post</a>.</li>
</ul>
<h3 id="roxygen2-810">roxygen2 8.1.0
</h3>
<p><a href="https://roxygen2.r-lib.org/" target="_blank" rel="noopener">roxygen2</a> 8.1.0 improves performance with consolidated <code>importFrom()</code> directives that reduce package loading time from ~120ms to ~9ms for 1,000 imports, and introduces the rdtools package for faster cross-reference resolution during documentation generation. The release also adds multi-line support for <code>@importFrom</code> directives with hanging indents.</p>
<ul>
<li>Check out the <a href="https://opensource.posit.co/blog/2026-08-04_roxygen2-8-1-0/" target="_blank" rel="noopener">roxygen2 8.1.0 blog post</a>.</li>
</ul>
<h3 id="shiny-updates">Shiny updates
</h3>
<p><a href="https://shiny.posit.co/" target="_blank" rel="noopener">Shiny</a> is the framework for building interactive web applications in R and Python. Shiny for R 1.14 adds <code>startApp()</code> for non-blocking app launches and <code>session$destroy()</code> for proper module cleanup. Shiny for Python 1.7 includes bundled Agent Skills for coding agents and test mode with live JSON snapshots. bslib 0.12 introduces offcanvas panels that slide in from viewport edges, plus direct sidebar handle resizing.</p>
<ul>
<li>Read more in the <a href="https://opensource.posit.co/blog/2026-08-04_shiny-r-1-14-python-1-7/" target="_blank" rel="noopener">Shiny updates blog post</a>.</li>
</ul>
<h2 id="positron-learning-resources">Positron learning resources
</h2>
<p>The Positron team is on a roll. Here are the key features from the <a href="https://opensource.posit.co/blog/2026-07-13_positron-2026-07-release/" target="_blank" rel="noopener">July Release Highlights</a>:</p>
<ul>
<li><strong>The Positron Notebook Editor now serves as the default option for .ipynb files</strong>: You get a fully integrated experience for Jupyter Notebooks out of the box. Key tools like environment management, version control, and AI coding support work automatically the moment you open any .ipynb file.</li>
<li><strong>The Packages pane has officially transitioned out of preview status</strong>: Inspect, update, and explore installed libraries without leaving your IDE or relying on Terminal commands.</li>
<li><strong>Posit Assistant has reached general availability</strong>: AI assistance is enterprise-ready: enjoy full-fledged coding assistance, debugging help, and inline explanations directly in your workflow with improved stability and performance.</li>
<li><strong>Support for opening Excel workbooks has been added to Data Explorer</strong>: No need to export to CSV or switch to Microsoft Excel to check your data: preview, filter, inspect .xlsx sheets directly inside Positron before running any code.</li>
<li><strong>Enhanced language intelligence for R</strong>: Navigating large R projects is much faster and less error-prone with features like Go to Definition, Find References, and Rename Symbol that work across all packages and scripts in your workspace. Diagnostics update instantly even when files change externally.</li>
</ul>
<p>The team has also shared several blog posts packed with tips and tricks for getting the most out of Positron:</p>
<ul>
<li><a href="https://opensource.posit.co/blog/2026-07-08_positron-uv/" target="_blank" rel="noopener">Discover how Positron paired with uv configures your Python environment in just one click</a></li>
<li><a href="https://opensource.posit.co/blog/2026-07-15_positron-environment-management-tips/" target="_blank" rel="noopener">Explore strategies for seamlessly managing your R and Python environments within Positron</a></li>
</ul>
<h2 id="lets-learn-about-ai">Let&rsquo;s learn about AI
</h2>
<p><strong>You can now receive the AI newsletter via email!</strong> Paste the newsletter&rsquo;s <a href="https://opensource.posit.co/tags/ai-newsletter/index.xml" target="_blank" rel="noopener">RSS feed URL</a> into a free RSS-to-email service like <a href="https://blogtrottr.com/" target="_blank" rel="noopener">https://blogtrottr.com/</a> to receive the newsletter by email.</p>
<ul>
<li>AGENTS.md, Skills, MCP servers, oh my! If you&rsquo;ve heard all these terms and want to investigate the differences, check out the <a href="https://opensource.posit.co/blog/2026-07-03_ai-newsletter/" target="_blank" rel="noopener">July 3rd edition of the AI Newsletter</a>.</li>
<li>LLMs often miss subtle visual artifacts in data visualizations, and there are ways of evaluating their oversights. Learn about bluffbench in the <a href="https://opensource.posit.co/blog/2026-07-17_ai-newsletter/" target="_blank" rel="noopener">July 17th edition of the AI Newsletter</a>.</li>
<li><a href="https://assistant.posit.co/" target="_blank" rel="noopener">Posit Assistant</a> in Positron now includes an EDA log feature to help you keep track of exploratory analysis done with the agent. Learn more in the <a href="https://opensource.posit.co/blog/2026-07-31_ai-newsletter/" target="_blank" rel="noopener">July 31st edition of the AI newsletter</a>.</li>
</ul>
<h2 id="do-you-want-event-recordings-you-got-them">Do you want event recordings? You got them!
</h2>
<p>&ldquo;Will this be recorded?&rdquo; If it is, you can access our recordings directly on the <a href="https://opensource.posit.co/events/" target="_blank" rel="noopener">event pages</a>, and we do our best to post them as quickly as possible.</p>
<p>Be sure to catch the presentations featured below, including Teun van den Brand&rsquo;s session on ggsql and Rich Iannone&rsquo;s presentation on Great Docs:</p>















  
  
  
  
  

  
  
  
  
  
    
  

  
  
  
  
  
    
  

  
  
  
  
  



<div class="grid grid-cols-3 gap-6 xl:gap-8 xl:gap-8 mb-6">
  
    <div>
      











  
  
  
  
  
















  
  
    
  











  
  





  
    
  









  
  






  





  
    
  






















  
    
  





  
    
  
























<div id="item-de299f206b1033e586cb69ebed60c69b" class="@container h-full">
  <a href="https://opensource.posit.co/resources/videos/2026-06-30_duckcon-7-ggsql-a-grammar-of-graphics-for-sql-teun-van-den-brand/" title="DuckCon #7 – ggsql: A grammar of graphics for SQL (Teun van den Brand)"
     class="card-link flex flex-col @venti:flex-row rounded-xl  h-full">

      



      
      

    
    <div class="w-full @venti:w-1/2 aspect-[40/21] flex-shrink-0 flex items-center justify-center overflow-hidden rounded-xl">
      
        









  
  
    
    

    

    
      
      

      
      
      

      
      
      
      

      <picture class="hidden @max-tall:block w-full h-full">
        <source
          type="image/webp"
          srcset="/resources/videos/2026-06-30_duckcon-7-ggsql-a-grammar-of-graphics-for-sql-teun-van-den-brand/thumbnail_hu_b2e1015481833d64.webp 1x,
                  /resources/videos/2026-06-30_duckcon-7-ggsql-a-grammar-of-graphics-for-sql-teun-van-den-brand/thumbnail_hu_a676e22e82ce813f.webp 2x" />
        <img
          src="https://opensource.posit.co/resources/videos/2026-06-30_duckcon-7-ggsql-a-grammar-of-graphics-for-sql-teun-van-den-brand/thumbnail_hu_897602341fe091b4.jpg"
          srcset="/resources/videos/2026-06-30_duckcon-7-ggsql-a-grammar-of-graphics-for-sql-teun-van-den-brand/thumbnail_hu_897602341fe091b4.jpg 1x,
                  /resources/videos/2026-06-30_duckcon-7-ggsql-a-grammar-of-graphics-for-sql-teun-van-den-brand/thumbnail_hu_13025d5418a80e9d.jpg 2x"
          alt="DuckCon #7 – ggsql: A grammar of graphics for SQL (Teun van den Brand)"
          class="mx-auto h-full w-full object-cover"
          loading="lazy" />
      </picture>
    
      
      

      
      
      

      
      
      
      

      <picture class="hidden @tall:@max-grande:block w-full h-full">
        <source
          type="image/webp"
          srcset="/resources/videos/2026-06-30_duckcon-7-ggsql-a-grammar-of-graphics-for-sql-teun-van-den-brand/thumbnail_hu_a676e22e82ce813f.webp 1x,
                  /resources/videos/2026-06-30_duckcon-7-ggsql-a-grammar-of-graphics-for-sql-teun-van-den-brand/thumbnail_hu_c76545a5a0e054b1.webp 2x" />
        <img
          src="https://opensource.posit.co/resources/videos/2026-06-30_duckcon-7-ggsql-a-grammar-of-graphics-for-sql-teun-van-den-brand/thumbnail_hu_13025d5418a80e9d.jpg"
          srcset="/resources/videos/2026-06-30_duckcon-7-ggsql-a-grammar-of-graphics-for-sql-teun-van-den-brand/thumbnail_hu_13025d5418a80e9d.jpg 1x,
                  /resources/videos/2026-06-30_duckcon-7-ggsql-a-grammar-of-graphics-for-sql-teun-van-den-brand/thumbnail_hu_f18dd7e1387eef85.jpg 2x"
          alt="DuckCon #7 – ggsql: A grammar of graphics for SQL (Teun van den Brand)"
          class="mx-auto h-full w-full object-cover"
          loading="lazy" />
      </picture>
    
      
      

      
      
      

      
      
      
      

      <picture class="hidden @grande:block w-full h-full">
        <source
          type="image/webp"
          srcset="/resources/videos/2026-06-30_duckcon-7-ggsql-a-grammar-of-graphics-for-sql-teun-van-den-brand/thumbnail_hu_c76545a5a0e054b1.webp 1x,
                  /resources/videos/2026-06-30_duckcon-7-ggsql-a-grammar-of-graphics-for-sql-teun-van-den-brand/thumbnail_hu_bf6653beaa56c5aa.webp 2x" />
        <img
          src="https://opensource.posit.co/resources/videos/2026-06-30_duckcon-7-ggsql-a-grammar-of-graphics-for-sql-teun-van-den-brand/thumbnail_hu_f18dd7e1387eef85.jpg"
          srcset="/resources/videos/2026-06-30_duckcon-7-ggsql-a-grammar-of-graphics-for-sql-teun-van-den-brand/thumbnail_hu_f18dd7e1387eef85.jpg 1x,
                  /resources/videos/2026-06-30_duckcon-7-ggsql-a-grammar-of-graphics-for-sql-teun-van-den-brand/thumbnail_hu_50c1b8a79d2695c2.jpg 2x"
          alt="DuckCon #7 – ggsql: A grammar of graphics for SQL (Teun van den Brand)"
          class="mx-auto h-full w-full object-cover"
          loading="lazy" />
      </picture>
    
  
  


      
    </div>

    
    <div class="hidden gap-y-2 @nip:flex @venti:w-1/2 flex-auto flex-col p-3 @venti:pl-5 text-gray-700 mt-2">

      
      

      
      
      <div class="hidden @short:flex flex-wrap gap-x-2 items-center text-xs font-medium text-gray-500">
        
          <span>Jun 30, 2026</span>
          <span>|</span>
        
        
        
          <span>12 min</span>
          <span>|</span>
        
        
          <span>2.1k views</span>
          
        
        
      </div>
      

      
      <h3 class="m-0! mt-3 font-semibold text-sm @grande:text-lg @venti:text-3xl line-clamp-2 text-sm @tall:text-base @grande:text-lg @venti:text-3xl text-gray-600">DuckCon #7 – ggsql: A grammar of graphics for SQL (Teun van den Brand)</h3>
      

      
        <p class="m-0! text-xs @short:text-sm @grande:text-md @venti:text-lg line-clamp-2 short@line-clamp-3 @tall:line-clamp-3 font-medium text-gray-600">Event: DuckCon #7 (DuckDB and DuckLake community conference), https://duckdb.org/events/2026/06/24/duckcon7/ Speaker: Teun van den Brand (Posit PBC) Slides: https://blobs.duckdb.org/events/duckcon7/teun-van-den-brand-ggsql.pdf</p>
      

      
        <div class="text-sm @grande:text-md">
          <div class="mt-2 flex flex-row gap-x-4 items-center"><div class="flex flex-row flex-shrink-0"><img 
          src="https://opensource.posit.co/people/teun-van-den-brand/teun-van-den-brand.jpg" 
          alt="Teun Van den Brand" 
          class="my-0! w-6 h-6 rounded-full object-cover ring-2 ring-white "
          style="z-index: 10;"
        ></div><div class="line-clamp-2 font-medium text-gray-600">Teun Van den Brand</div></div>
        </div>
      

      <div class="grow"></div>
      
        
          <div class="hidden @grande:flex flex-wrap gap-x-1 gap-y-4 py-2 overflow-hidden h-10 items-end">
            
              <span class="pill">
                ggsql
              </span>
            
          </div>
        
      
    </div>
  </a>
</div>


    </div>
  
    <div>
      











  
  
  
  
  
















  
  
    
  











  
  





  
    
  









  
  






  





  
    
  
    
  






















  
    
  





  
    
  
























<div id="item-ca048271111b051a31910a26462be382" class="@container h-full">
  <a href="https://opensource.posit.co/resources/videos/2026-07-06_great-docs-the-future-of-documentation-the-python-exchange-june-2026/" title="Great Docs: The Future of Documentation | The Python Exchange June 2026"
     class="card-link flex flex-col @venti:flex-row rounded-xl  h-full">

      



      
      

    
    <div class="w-full @venti:w-1/2 aspect-[40/21] flex-shrink-0 flex items-center justify-center overflow-hidden rounded-xl">
      
        









  
  
    
    

    

    
      
      

      
      
      

      
      
      
      

      <picture class="hidden @max-tall:block w-full h-full">
        <source
          type="image/webp"
          srcset="/resources/videos/2026-07-06_great-docs-the-future-of-documentation-the-python-exchange-june-2026/thumbnail_hu_4a79da9b97975bb1.webp 1x,
                  /resources/videos/2026-07-06_great-docs-the-future-of-documentation-the-python-exchange-june-2026/thumbnail_hu_7c3afa6c6493dda.webp 2x" />
        <img
          src="https://opensource.posit.co/resources/videos/2026-07-06_great-docs-the-future-of-documentation-the-python-exchange-june-2026/thumbnail_hu_ad0f5cdbfef37964.jpg"
          srcset="/resources/videos/2026-07-06_great-docs-the-future-of-documentation-the-python-exchange-june-2026/thumbnail_hu_ad0f5cdbfef37964.jpg 1x,
                  /resources/videos/2026-07-06_great-docs-the-future-of-documentation-the-python-exchange-june-2026/thumbnail_hu_c974e8c34f17a663.jpg 2x"
          alt="Great Docs: The Future of Documentation | The Python Exchange June 2026"
          class="mx-auto h-full w-full object-cover"
          loading="lazy" />
      </picture>
    
      
      

      
      
      

      
      
      
      

      <picture class="hidden @tall:@max-grande:block w-full h-full">
        <source
          type="image/webp"
          srcset="/resources/videos/2026-07-06_great-docs-the-future-of-documentation-the-python-exchange-june-2026/thumbnail_hu_7c3afa6c6493dda.webp 1x,
                  /resources/videos/2026-07-06_great-docs-the-future-of-documentation-the-python-exchange-june-2026/thumbnail_hu_e2f3f8ee4b22f520.webp 2x" />
        <img
          src="https://opensource.posit.co/resources/videos/2026-07-06_great-docs-the-future-of-documentation-the-python-exchange-june-2026/thumbnail_hu_c974e8c34f17a663.jpg"
          srcset="/resources/videos/2026-07-06_great-docs-the-future-of-documentation-the-python-exchange-june-2026/thumbnail_hu_c974e8c34f17a663.jpg 1x,
                  /resources/videos/2026-07-06_great-docs-the-future-of-documentation-the-python-exchange-june-2026/thumbnail_hu_af5a09ce00461bfb.jpg 2x"
          alt="Great Docs: The Future of Documentation | The Python Exchange June 2026"
          class="mx-auto h-full w-full object-cover"
          loading="lazy" />
      </picture>
    
      
      

      
      
      

      
      
      
      

      <picture class="hidden @grande:block w-full h-full">
        <source
          type="image/webp"
          srcset="/resources/videos/2026-07-06_great-docs-the-future-of-documentation-the-python-exchange-june-2026/thumbnail_hu_e2f3f8ee4b22f520.webp 1x,
                  /resources/videos/2026-07-06_great-docs-the-future-of-documentation-the-python-exchange-june-2026/thumbnail_hu_6c04a9d6eaf920ed.webp 2x" />
        <img
          src="https://opensource.posit.co/resources/videos/2026-07-06_great-docs-the-future-of-documentation-the-python-exchange-june-2026/thumbnail_hu_af5a09ce00461bfb.jpg"
          srcset="/resources/videos/2026-07-06_great-docs-the-future-of-documentation-the-python-exchange-june-2026/thumbnail_hu_af5a09ce00461bfb.jpg 1x,
                  /resources/videos/2026-07-06_great-docs-the-future-of-documentation-the-python-exchange-june-2026/thumbnail_hu_991395b2a0842829.jpg 2x"
          alt="Great Docs: The Future of Documentation | The Python Exchange June 2026"
          class="mx-auto h-full w-full object-cover"
          loading="lazy" />
      </picture>
    
  
  


      
    </div>

    
    <div class="hidden gap-y-2 @nip:flex @venti:w-1/2 flex-auto flex-col p-3 @venti:pl-5 text-gray-700 mt-2">

      
      

      
      
      <div class="hidden @short:flex flex-wrap gap-x-2 items-center text-xs font-medium text-gray-500">
        
          <span>Jul 6, 2026</span>
          <span>|</span>
        
        
        
          <span>1h 5min</span>
          <span>|</span>
        
        
          <span>114 views</span>
          
        
        
      </div>
      

      
      <h3 class="m-0! mt-3 font-semibold text-sm @grande:text-lg @venti:text-3xl line-clamp-2 text-sm @tall:text-base @grande:text-lg @venti:text-3xl text-gray-600">Great Docs: The Future of Documentation | The Python Exchange June 2026</h3>
      

      
        <p class="m-0! text-xs @short:text-sm @grande:text-md @venti:text-lg line-clamp-2 short@line-clamp-3 @tall:line-clamp-3 font-medium text-gray-600">About the Python Exchange for the Department of Energy: https://meetup.doepy.org/ Sign up here to be notified when the next Python Exchange is scheduled: https://bit.ly/py-exchange
Guest Panelist: Rich Iannone
Title: Great Docs: Building the Documentation Site Generator I Always Wanted
Bio: Rich Iannone Rich is a software engineer and someone who cares a great deal about documentation and summary tables. He&rsquo;s been working on table presentation and documentation packages for quite a long time, and nobody has told him to stop yet, so he&rsquo;s still on top of all that. He started off mostly creating open-source packages in R, but more lately, he&rsquo;s been doing open-source things in Python. Rich really enjoys creating all these packages because he realizes that people can use &rsquo;em to do great things in their own work.
Abstract: Documentation generators have, for me, been a thing where there are so many trade-offs. They might make beautiful sites, but be shallow feature-wise. Or full of features but really hard to configure. After some years of working across R, Python, and the broader open-source ecosystem, I started Great Docs with a simple end goal: your docs should look really great, be easy to discover, and be ready for the AI era.
In this presentation, I will walk through the various places I drew inspiration for Great Docs (pkgdown, MATLAB, Elixir, and the Vue.js docs). I&rsquo;ll show how Great Docs makes documentation consumable by both humans and AI agents through Skills and MCP server documentation. I&rsquo;ll share some of the features I obsessively built because I wanted them in my own package docs. Finally, I&rsquo;ll discuss where this project is headed beyond Python (toward documenting CLIs, TUIs, and more).
At Don&rsquo;t Use This Code, we want to create a unique opportunity to see Python succeed and thrive within the DOE. In collaboration with an organizing committee of Python users and advocates from various DOE sites, we host regular conversations on the topic of Python in order to create a new resource for scientists, researchers, and technical staff. Our goal is to share best practices and build a strong, lasting community for Python users within the Department of Energy National Lab system.
If you, or someone you know, might make a great panelist, we&rsquo;d love to get in touch! Just send us an email at DOEPy@dutc.io if you would like to participate or have any questions
</p>
      

      
        <div class="text-sm @grande:text-md">
          <div class="mt-2 flex flex-row gap-x-4 items-center"><div class="flex flex-row flex-shrink-0"><img 
          src="https://opensource.posit.co/people/rich-iannone/rich-headshot.png" 
          alt="Rich Iannone" 
          class="my-0! w-6 h-6 rounded-full object-cover ring-2 ring-white "
          style="z-index: 10;"
        ></div><div class="line-clamp-2 font-medium text-gray-600">Rich Iannone</div></div>
        </div>
      

      <div class="grow"></div>
      
        
          <div class="hidden @grande:flex flex-wrap gap-x-1 gap-y-4 py-2 overflow-hidden h-10 items-end">
            
              <span class="pill">
                Great Docs
              </span>
            
              <span class="pill">
                pkgdown
              </span>
            
          </div>
        
      
    </div>
  </a>
</div>


    </div>
  
</div>


<p>Additionally, we have some fantastic recordings from the <a href="https://pos.it/dslab" target="_blank" rel="noopener">Data Science Lab</a>. Watch the Lab Managers share their expertise while live coding:</p>















  
  
  
  
  

  
  
  
  
  
    
  

  
  
  
  
  
    
  

  
  
  
  
  



<div class="grid grid-cols-3 gap-6 xl:gap-8 xl:gap-8 mb-6">
  
    <div>
      











  
  
  
  
  
















  
  
    
  











  
  





  
    
  









  
  






  





  
    
  
    
  
    
  
    
  






















  
    
  





  
    
  
























<div id="item-9b757f4d2908c3491363411a7cadd25a" class="@container h-full">
  <a href="https://opensource.posit.co/resources/videos/2026-07-24_live-tidytuesday-data-viz-workflow-nicola-rennie-data-science-lab/" title="Live TidyTuesday Data Viz Workflow | Nicola Rennie | Data Science Lab"
     class="card-link flex flex-col @venti:flex-row rounded-xl  h-full">

      



      
      

    
    <div class="w-full @venti:w-1/2 aspect-[40/21] flex-shrink-0 flex items-center justify-center overflow-hidden rounded-xl">
      
        









  
  
    
    

    

    
      
      

      
      
      

      
      
      
      

      <picture class="hidden @max-tall:block w-full h-full">
        <source
          type="image/webp"
          srcset="/resources/videos/2026-07-24_live-tidytuesday-data-viz-workflow-nicola-rennie-data-science-lab/thumbnail_hu_91cdc9bfec4beb.webp 1x,
                  /resources/videos/2026-07-24_live-tidytuesday-data-viz-workflow-nicola-rennie-data-science-lab/thumbnail_hu_2bdf2408bfb74ae8.webp 2x" />
        <img
          src="https://opensource.posit.co/resources/videos/2026-07-24_live-tidytuesday-data-viz-workflow-nicola-rennie-data-science-lab/thumbnail_hu_1cb3889dbd947c4c.jpg"
          srcset="/resources/videos/2026-07-24_live-tidytuesday-data-viz-workflow-nicola-rennie-data-science-lab/thumbnail_hu_1cb3889dbd947c4c.jpg 1x,
                  /resources/videos/2026-07-24_live-tidytuesday-data-viz-workflow-nicola-rennie-data-science-lab/thumbnail_hu_436953f457f71693.jpg 2x"
          alt="Live TidyTuesday Data Viz Workflow | Nicola Rennie | Data Science Lab"
          class="mx-auto h-full w-full object-cover"
          loading="lazy" />
      </picture>
    
      
      

      
      
      

      
      
      
      

      <picture class="hidden @tall:@max-grande:block w-full h-full">
        <source
          type="image/webp"
          srcset="/resources/videos/2026-07-24_live-tidytuesday-data-viz-workflow-nicola-rennie-data-science-lab/thumbnail_hu_2bdf2408bfb74ae8.webp 1x,
                  /resources/videos/2026-07-24_live-tidytuesday-data-viz-workflow-nicola-rennie-data-science-lab/thumbnail_hu_c0da8212f74d2e17.webp 2x" />
        <img
          src="https://opensource.posit.co/resources/videos/2026-07-24_live-tidytuesday-data-viz-workflow-nicola-rennie-data-science-lab/thumbnail_hu_436953f457f71693.jpg"
          srcset="/resources/videos/2026-07-24_live-tidytuesday-data-viz-workflow-nicola-rennie-data-science-lab/thumbnail_hu_436953f457f71693.jpg 1x,
                  /resources/videos/2026-07-24_live-tidytuesday-data-viz-workflow-nicola-rennie-data-science-lab/thumbnail_hu_ba0631db832f77db.jpg 2x"
          alt="Live TidyTuesday Data Viz Workflow | Nicola Rennie | Data Science Lab"
          class="mx-auto h-full w-full object-cover"
          loading="lazy" />
      </picture>
    
      
      

      
      
      

      
      
      
      

      <picture class="hidden @grande:block w-full h-full">
        <source
          type="image/webp"
          srcset="/resources/videos/2026-07-24_live-tidytuesday-data-viz-workflow-nicola-rennie-data-science-lab/thumbnail_hu_c0da8212f74d2e17.webp 1x,
                  /resources/videos/2026-07-24_live-tidytuesday-data-viz-workflow-nicola-rennie-data-science-lab/thumbnail_hu_830f9934dc51456c.webp 2x" />
        <img
          src="https://opensource.posit.co/resources/videos/2026-07-24_live-tidytuesday-data-viz-workflow-nicola-rennie-data-science-lab/thumbnail_hu_ba0631db832f77db.jpg"
          srcset="/resources/videos/2026-07-24_live-tidytuesday-data-viz-workflow-nicola-rennie-data-science-lab/thumbnail_hu_ba0631db832f77db.jpg 1x,
                  /resources/videos/2026-07-24_live-tidytuesday-data-viz-workflow-nicola-rennie-data-science-lab/thumbnail_hu_e8ac5809a85eaadf.jpg 2x"
          alt="Live TidyTuesday Data Viz Workflow | Nicola Rennie | Data Science Lab"
          class="mx-auto h-full w-full object-cover"
          loading="lazy" />
      </picture>
    
  
  


      
    </div>

    
    <div class="hidden gap-y-2 @nip:flex @venti:w-1/2 flex-auto flex-col p-3 @venti:pl-5 text-gray-700 mt-2">

      
      

      
      
      <div class="hidden @short:flex flex-wrap gap-x-2 items-center text-xs font-medium text-gray-500">
        
          <span>Jul 24, 2026</span>
          <span>|</span>
        
        
        
          <span>51 min</span>
          <span>|</span>
        
        
          <span>48 views</span>
          
        
        
      </div>
      

      
      <h3 class="m-0! mt-3 font-semibold text-sm @grande:text-lg @venti:text-3xl line-clamp-2 text-sm @tall:text-base @grande:text-lg @venti:text-3xl text-gray-600">Live TidyTuesday Data Viz Workflow | Nicola Rennie | Data Science Lab</h3>
      

      
        <p class="m-0! text-xs @short:text-sm @grande:text-md @venti:text-lg line-clamp-2 short@line-clamp-3 @tall:line-clamp-3 font-medium text-gray-600">The Data Science Lab is a live weekly call. Register at pos.it/dslab! Discord invites go out each week on lives calls. We&rsquo;d love to have you!
The Lab is an open, messy space for learning and asking questions. Think of it like pair coding with a friend or two. Learn something new, and share what you know to help others grow.
On this call, Libby Heeren is joined by Nicola Rennie, who walks through her process for making a TidyTuesday data visualization in R: live coding a chart from scratch and sharing the workflow tricks she&rsquo;s built up over five years of doing TidyTuesday!
Nicola takes this week&rsquo;s TidyTuesday &ldquo;twin cities&rdquo; dataset and builds a colorful sunburst (radial) chart from scratch, showing how she decides what to plot, wrangles the data with dplyr, and makes it pretty using showtext fonts, rcartocolor palettes, colored-text legends, and the ggview package for previewing plots at exactly the size they&rsquo;ll save at. Along the way she shares the templates and helper packages she&rsquo;s made to save time every week (can you tell she&rsquo;s a pro?!). Since TidyTuesday data is public, you can grab the same dataset and follow along, too!
Hosting crew from Posit: Libby Heeren, Isabella Velasquez
Socials and websites: Nicola Rennie&rsquo;s blog: https://nrennie.rbind.io/ Nicola Rennie&rsquo;s GitHub: https://github.com/nrennie Nicola Rennie&rsquo;s Bluesky: https://bsky.app/profile/nrennie.bsky.social Nicola Rennie&rsquo;s LinkedIn: https://www.linkedin.com/in/nicola-rennie/ Nicola Rennie&rsquo;s Mastodon: https://fosstodon.org/deck/@nrennie
Resources mentioned in the video and chat: Nicola&rsquo;s code from this session: https://nrennie.rbind.io/talks/posit-ds-lab/ TidyTuesday on GitHub: https://github.com/rfordatascience/tidytuesday Nicola&rsquo;s templates package: https://github.com/nrennie/templates showtext package (fonts in R): https://github.com/yixuan/showtext ggview package (preview plots at save size): https://github.com/idmn/ggview rcartocolor package (accessible color palettes): https://nowosad.r-universe.dev/rcartocolor ggtext package (styled/colored text): https://wilkelab.org/ggtext/ ggiraph package (interactive ggplots): https://davidgohel.github.io/ggiraph/ marquee package (markdown text in R graphics): https://marquee.r-lib.org/ Nicola&rsquo;s book, The Art of Data Visualization with ggplot2: https://nrennie.rbind.io/art-of-viz/ Bootstrap Icons: https://icons.getbootstrap.com/ okpalette (extract a palette from a photo): https://okpalette.color.pizza/
► Subscribe to Our Channel Here: https://bit.ly/2TzgcOu Follow Us Here: Website: https://www.posit.co Hangout: https://pos.it/dsh The Lab: https://pos.it/dslab LinkedIn: https://www.linkedin.com/company/posit-software Bluesky: https://bsky.app/profile/posit.co
Thanks for hanging out with us!
Timestamps 00:00 Introduction 01:18 Reviewing the TidyTuesday twin cities dataset 03:41 Demoing TidyTuesday template files and R package setup 07:25 &ldquo;Do showtext and systemfonts do different things?&rdquo; 09:04 Loading and prepping the links and cities datasets 11:45 Exploring and filtering the dataset to a chosen city 17:25 Demoing a Shiny app to copy previous TidyTuesday chart code 23:56 Demoing sunburst chart creation with coord_radial 25:47 &ldquo;Can you say why you used mutate rather than summarize?&rdquo; 31:09 Adding custom colors with the rcartocolor package 33:57 Demoing colored subtitle text with the ggtext package 40:38 Attempting to make the chart interactive with the ggiraph package 43:32 Adding automated social and source captions 46:26 &ldquo;So you can save a plot with the canvas call and it doesn&rsquo;t mess up the ggplot object?&rdquo; 49:55 &ldquo;If people would like to keep up with you and see your posts, what&rsquo;s the best way to do that?&rdquo;
</p>
      

      

      <div class="grow"></div>
      
        
          <div class="hidden @grande:flex flex-wrap gap-x-1 gap-y-4 py-2 overflow-hidden h-10 items-end">
            
              <span class="pill">
                dplyr
              </span>
            
              <span class="pill">
                ggplot2
              </span>
            
              <span class="pill">
                Shiny
              </span>
            
              <span class="pill">
                systemfonts
              </span>
            
          </div>
        
      
    </div>
  </a>
</div>


    </div>
  
    <div>
      











  
  
  
  
  
















  
  
    
  











  
  





  
    
  









  
  






  





  
    
  
    
  
    
  






















  
    
  





  
    
  
























<div id="item-d40c591fd8755cf94c245b16a57ac876" class="@container h-full">
  <a href="https://opensource.posit.co/resources/videos/2026-07-23_mind-blowing-quarto-slide-extensions-emil-hvitfeldt-data-science-lab/" title="Mind-Blowing Quarto Slide Extensions 💬 🖍️ 🤯 | Emil Hvitfeldt | Data Science Lab"
     class="card-link flex flex-col @venti:flex-row rounded-xl  h-full">

      



      
      

    
    <div class="w-full @venti:w-1/2 aspect-[40/21] flex-shrink-0 flex items-center justify-center overflow-hidden rounded-xl">
      
        









  
  
    
    

    

    
      
      

      
      
      

      
      
      
      

      <picture class="hidden @max-tall:block w-full h-full">
        <source
          type="image/webp"
          srcset="/resources/videos/2026-07-23_mind-blowing-quarto-slide-extensions-emil-hvitfeldt-data-science-lab/thumbnail_hu_a4ef79aec4159f0b.webp 1x,
                  /resources/videos/2026-07-23_mind-blowing-quarto-slide-extensions-emil-hvitfeldt-data-science-lab/thumbnail_hu_12eca1b1ff66693f.webp 2x" />
        <img
          src="https://opensource.posit.co/resources/videos/2026-07-23_mind-blowing-quarto-slide-extensions-emil-hvitfeldt-data-science-lab/thumbnail_hu_400ddecd3f838eab.jpg"
          srcset="/resources/videos/2026-07-23_mind-blowing-quarto-slide-extensions-emil-hvitfeldt-data-science-lab/thumbnail_hu_400ddecd3f838eab.jpg 1x,
                  /resources/videos/2026-07-23_mind-blowing-quarto-slide-extensions-emil-hvitfeldt-data-science-lab/thumbnail_hu_b22a6dec3c217c9d.jpg 2x"
          alt="Mind-Blowing Quarto Slide Extensions 💬 🖍️ 🤯 | Emil Hvitfeldt | Data Science Lab"
          class="mx-auto h-full w-full object-cover"
          loading="lazy" />
      </picture>
    
      
      

      
      
      

      
      
      
      

      <picture class="hidden @tall:@max-grande:block w-full h-full">
        <source
          type="image/webp"
          srcset="/resources/videos/2026-07-23_mind-blowing-quarto-slide-extensions-emil-hvitfeldt-data-science-lab/thumbnail_hu_12eca1b1ff66693f.webp 1x,
                  /resources/videos/2026-07-23_mind-blowing-quarto-slide-extensions-emil-hvitfeldt-data-science-lab/thumbnail_hu_b4bdbf1c5b2fd5df.webp 2x" />
        <img
          src="https://opensource.posit.co/resources/videos/2026-07-23_mind-blowing-quarto-slide-extensions-emil-hvitfeldt-data-science-lab/thumbnail_hu_b22a6dec3c217c9d.jpg"
          srcset="/resources/videos/2026-07-23_mind-blowing-quarto-slide-extensions-emil-hvitfeldt-data-science-lab/thumbnail_hu_b22a6dec3c217c9d.jpg 1x,
                  /resources/videos/2026-07-23_mind-blowing-quarto-slide-extensions-emil-hvitfeldt-data-science-lab/thumbnail_hu_c7f3360f4b455ac6.jpg 2x"
          alt="Mind-Blowing Quarto Slide Extensions 💬 🖍️ 🤯 | Emil Hvitfeldt | Data Science Lab"
          class="mx-auto h-full w-full object-cover"
          loading="lazy" />
      </picture>
    
      
      

      
      
      

      
      
      
      

      <picture class="hidden @grande:block w-full h-full">
        <source
          type="image/webp"
          srcset="/resources/videos/2026-07-23_mind-blowing-quarto-slide-extensions-emil-hvitfeldt-data-science-lab/thumbnail_hu_b4bdbf1c5b2fd5df.webp 1x,
                  /resources/videos/2026-07-23_mind-blowing-quarto-slide-extensions-emil-hvitfeldt-data-science-lab/thumbnail_hu_e2aa1e91b2f546a2.webp 2x" />
        <img
          src="https://opensource.posit.co/resources/videos/2026-07-23_mind-blowing-quarto-slide-extensions-emil-hvitfeldt-data-science-lab/thumbnail_hu_c7f3360f4b455ac6.jpg"
          srcset="/resources/videos/2026-07-23_mind-blowing-quarto-slide-extensions-emil-hvitfeldt-data-science-lab/thumbnail_hu_c7f3360f4b455ac6.jpg 1x,
                  /resources/videos/2026-07-23_mind-blowing-quarto-slide-extensions-emil-hvitfeldt-data-science-lab/thumbnail_hu_d69b5bc0a20d0f5b.jpg 2x"
          alt="Mind-Blowing Quarto Slide Extensions 💬 🖍️ 🤯 | Emil Hvitfeldt | Data Science Lab"
          class="mx-auto h-full w-full object-cover"
          loading="lazy" />
      </picture>
    
  
  


      
    </div>

    
    <div class="hidden gap-y-2 @nip:flex @venti:w-1/2 flex-auto flex-col p-3 @venti:pl-5 text-gray-700 mt-2">

      
      

      
      
      <div class="hidden @short:flex flex-wrap gap-x-2 items-center text-xs font-medium text-gray-500">
        
          <span>Jul 23, 2026</span>
          <span>|</span>
        
        
        
          <span>56 min</span>
          <span>|</span>
        
        
          <span>1.1k views</span>
          
        
        
      </div>
      

      
      <h3 class="m-0! mt-3 font-semibold text-sm @grande:text-lg @venti:text-3xl line-clamp-2 text-sm @tall:text-base @grande:text-lg @venti:text-3xl text-gray-600">Mind-Blowing Quarto Slide Extensions 💬 🖍️ 🤯 | Emil Hvitfeldt | Data Science Lab</h3>
      

      
        <p class="m-0! text-xs @short:text-sm @grande:text-md @venti:text-lg line-clamp-2 short@line-clamp-3 @tall:line-clamp-3 font-medium text-gray-600">The Data Science Lab is a live weekly call. Register at pos.it/dslab! Discord invites go out each week on lives calls. We&rsquo;d love to have you!
The Lab is an open, messy space for learning and asking questions. Think of it like pair coding with a friend or two. Learn something new, and share what you know to help others grow.
On this call, Libby Heeren is joined by Emil Hvitfeldt, who walks through the art of &ldquo;slide crafting&rdquo; in Quarto and shows off the collection of Reveal JS extensions he&rsquo;s been building to make slides way more fun and powerful.
Emil starts with the basics of building slides in Quarto with the Reveal JS format (fragments, columns, a little CSS) and explains how Quarto extensions differ from packages. Then he shows off the good stuff: iMessage-style chat bubbles hand-drawn &ldquo;rough notation&rdquo; highlighting and annotations ️ the Flourish extension for animating code chunks, gorgeous reusable themes, and his in-progress &ldquo;editable&rdquo; extension that lets you drag, resize, and restyle slide elements right in the browser and save the changes back to your source. And, spoiler, his &ldquo;editable&rdquo; extension is much further along as of the publishing of this video!! If you&rsquo;ve ever fought with slide layouts, there is definitely something here you can try at home!
Hosting crew from Posit: Libby Heeren, Isabella Velasquez
Emil&rsquo;s socials and urls: website: https://emilhvitfeldt.com/ GitHub: https://github.com/emilhvitfeldt Bluesky: https://bsky.app/profile/emilhvitfeldt.bsky.social LinkedIn: https://www.linkedin.com/in/emilhvitfeldt/
Resources mentioned in the video and chat: Emil&rsquo;s GitHub (home of his Quarto extensions): https://github.com/EmilHvitfeldt quarto-revealjs-editable extension: https://github.com/EmilHvitfeldt/quarto-revealjs-editable quarto-revealjs-rows extension (shared by Emil after the session): https://github.com/EmilHvitfeldt/quarto-revealjs-rows Quarto Reveal JS documentation: https://quarto.org/docs/presentations/revealjs/ Quarto Reveal JS demo slides: https://quarto.org/docs/presentations/revealjs/demo/#/title-slide News! Quarto 2 (Quarto in Rust): https://quarto.org/docs/blog/posts/2026-04-06-whats-next-quarto-2/ Dynamic Tabsets in Quarto (Josh Cowley): https://josh.quarto.pub/posts/2022-11-10-quarto-tabsets-update/2022-11-10-quarto-tabsets-update.html Embedding Reveal JS via iframe (Quarto source example): https://github.com/quarto-dev/quarto-web/blob/main/docs/presentations/revealjs/index.qmd#L12-L14 posit::conf 2026: https://conf.posit.co/2026/ R/Medicine conference: https://rconsortium.github.io/RMedicine_website/ Muntasir Masum&rsquo;s slides repo: https://github.com/muntasirmasum/epi553-data-viz Example Quarto slides — Nicola Rennie (Styling Charts): https://nrennie.rbind.io/MFC-CDT-data-viz/slides/styling-charts-r.html Example Quarto slides — Colin Madland: https://cmadland.github.io/slides/ Colin Madland&rsquo;s slides repo: https://github.com/cmadland/slides Example Quarto slides — Raha Dastgheyb (R/Medicine 2024): https://rdastgh1.quarto.pub/rmedicine-2024-scidatareportr/#/title-slide
► Subscribe to Our Channel Here: https://bit.ly/2TzgcOu Follow Us Here: Website: https://www.posit.co Hangout: https://pos.it/dsh The Lab: https://pos.it/dslab LinkedIn: https://www.linkedin.com/company/posit-software Bluesky: https://bsky.app/profile/posit.co
Thanks for hanging out with us!
Timestamps 00:00 Introduction 01:22 Demoing a primer on Reveal JS slides in Quarto 05:11 &ldquo;Does that PDF export still use Pandoc, or is there an option of exporting via Typst?&rdquo; 08:17 Demoing slide crafting with a new Quarto document 11:24 Demoing how to download and use a Quarto template 14:01 &ldquo;Is this UI you&rsquo;re using for slide generation exclusive to Positron?&rdquo; 16:16 Demoing how to install a Quarto extension from the terminal 18:45 &ldquo;Is there a maximum number of columns you can have?&rdquo; 19:18 Demoing adding custom CSS classes to slide columns 23:03 &ldquo;Do we know if extensions will still be submitted to the OpenVSX marketplace?&rdquo; 25:11 &ldquo;Are these Quarto extensions global, or are they per project?&rdquo; 27:42 &ldquo;When you change the text fonts inside those columns, could you do it for all the columns at once, maybe by changing the top div?&rdquo; 29:31 &ldquo;Do you also get grid logic like you have with CSS Grid?&rdquo; 31:54 Demoing Quarto VS Code extensions for autocomplete and shortcodes 34:32 Demoing the chat bubbles extension 37:38 Demoing the rough notation extension for highlighting text fragments 40:20 Demoing the Flourish extension for highlighting code chunks 43:07 Demoing the editable extension for dragging and adjusting slide elements 49:28 Demoing custom Reveal JS slide themes 52:26 &ldquo;Is there a Quarto extension that can help dynamically create tabs or chunks?&rdquo; (see dynamic tabs link in the resources above!) 53:58 Explaining the default code chunk highlighting feature in Quarto 55:11 &ldquo;How do you embed a Reveal JS site into another Quarto document?&rdquo;
</p>
      

      
        <div class="text-sm @grande:text-md">
          <div class="mt-2 flex flex-row gap-x-4 items-center"><div class="flex flex-row flex-shrink-0"><img 
          src="https://opensource.posit.co/people/emil-hvitfeldt/profile.jpg" 
          alt="Emil Hvitfeldt" 
          class="my-0! w-6 h-6 rounded-full object-cover ring-2 ring-white "
          style="z-index: 10;"
        ></div><div class="line-clamp-2 font-medium text-gray-600">Emil Hvitfeldt</div></div>
        </div>
      

      <div class="grow"></div>
      
        
          <div class="hidden @grande:flex flex-wrap gap-x-1 gap-y-4 py-2 overflow-hidden h-10 items-end">
            
              <span class="pill">
                Positron
              </span>
            
              <span class="pill">
                Quarto
              </span>
            
              <span class="pill">
                revealjs
              </span>
            
          </div>
        
      
    </div>
  </a>
</div>


    </div>
  
</div>


<p>We hope you learn a lot from these resources!</p>
<h2 id="showcases-from-the-community">Showcases from the community
</h2>
<p>We love learning what you are up to. If you have a project using our tools to share, please let us know. In particular, I&rsquo;d love to hear how you&rsquo;re adopting and using Positron! Find me on <a href="https://www.linkedin.com/in/ivelasq/" target="_blank" rel="noopener">LinkedIn</a> and <a href="https://bsky.app/profile/ivelasq.bsky.social" target="_blank" rel="noopener">Bluesky</a>.</p>









  
  
    
  

  
  
    
  





  


<div class="grid gap-12 items-start mt-12 md:grid-cols-2 ">
  
  
    
    
    
      <div class="prose max-w-none "><p>Alfredo H. S. shared a small, opinionated skill for turning papers and other source material into concise Quarto RevealJS presentations with AI coding agents.</p>
<p>Try it out, and let Alfredo know how it goes!</p>
<ul>
<li><a href="https://forum.posit.co/t/a-small-quarto-ai-skill-for-better-slides/215878" target="_blank" rel="noopener">Forum discussion</a></li>
<li><a href="https://alfredohs.com/blog/quarto_talks/" target="_blank" rel="noopener">About the skill</a></li>
<li><a href="http://SKILL.md" target="_blank" rel="noopener">SKILL.md</a></li>
</ul>
</div>
    
  
    
    
    
      <div class="prose max-w-none "><div class="not-prose"><figure>
      <img class="h-auto max-w-full rounded-lg"
        src="https://opensource.posit.co/blog/2026-08-05_glimpse-aug-2026/images/image1.png"
        alt="" 
        loading="lazy"
      >
    </figure></div></div>
    
  
</div>










  
  
    
  

  
  
    
  





  


<div class="grid gap-12 items-start mt-12 md:grid-cols-2 ">
  
  
    
    
    
      <div class="prose max-w-none "><div class="not-prose"><figure>
      <img class="h-auto max-w-full rounded-lg"
        src="https://opensource.posit.co/blog/2026-08-05_glimpse-aug-2026/images/image2.png"
        alt="" 
        loading="lazy"
      >
    </figure></div></div>
    
  
    
    
    
      <div class="prose max-w-none "><p>REYL Intesa Sanpaolo&rsquo;s Risk Management team built their own Incident Management Tool with Shiny and Posit Connect, cutting incident follow-up from days to 30 minutes. Now, they&rsquo;re eyeing the same R-and-Connect pattern for liquidity monitoring, credit risk appetite, and stress testing.</p>
<ul>
<li><a href="https://posit.co/about/customer-stories/reyl-intesa-sanpaolo" target="_blank" rel="noopener">Check out the spotlight</a></li>
</ul></div>
    
  
</div>










  
  
    
  

  
  
    
  





  


<div class="grid gap-12 items-start mt-12 md:grid-cols-2 ">
  
  
    
    
    
      <div class="prose max-w-none "><p>Interested in testing your regression skills? Angela Heberger is looking for feedback on RelationLab, an interactive Shiny app for learning correlation and regression. Give it a shot and let Angela know what you think!</p>
<ul>
<li><a href="https://forum.posit.co/t/feedback-requested-on-relationlab-an-interactive-shiny-app-for-learning-correlation-and-regression/216954" target="_blank" rel="noopener">Forum discussion</a></li>
<li><a href="https://angela-heberger.shinyapps.io/correlation-regression-learning-app/" target="_blank" rel="noopener">Shiny app</a></li>
</ul></div>
    
  
    
    
    
      <div class="prose max-w-none "><div class="not-prose"><figure>
      <img class="h-auto max-w-full rounded-lg"
        src="https://opensource.posit.co/blog/2026-08-05_glimpse-aug-2026/images/image3.png"
        alt="" 
        loading="lazy"
      >
    </figure></div></div>
    
  
</div>

<p>We usually find these projects on social media. If you&rsquo;re on LinkedIn, be sure to follow and tag <a href="https://www.linkedin.com/showcase/posit-open-source/" target="_blank" rel="noopener">Posit Open Source</a> for us to share the amazing things you&rsquo;re working on!</p>
<h2 id="whats-next">What’s next
</h2>
<p>Besides posit::conf (have you <a href="https://conf.posit.co/2026/" target="_blank" rel="noopener">registered for conf</a> yet? You should!), we have lots of goodies on the horizon.</p>
<ul>
<li>Emil Hvidtfelt is leading a 2-hour workshop all about making great slides in Quarto on Aug 12th. <a href="https://events.zoom.us/ev/AhS1wYPFlx9m2sfuhnidFjnvI2UlS3PKv6JRVL_bv4UUydDxeKnK~AtgzvV6vmUoaeLU-9KZrRyj3QUGklZmSV2a1hFRfixtmtlszjyaUoneXVw" target="_blank" rel="noopener">Register here</a>!</li>
<li>Join us for an upcoming <a href="https://pos.it/dsh" target="_blank" rel="noopener">Data Science Hangout</a> or <a href="https://pos.it/dslab" target="_blank" rel="noopener">Data Science Lab</a>.</li>
</ul>
<p>I would love to know how to make the Glimpse newsletter better. Email me at isabella [dot] velasquez [at] posit.co.</p>
]]></description>
      <enclosure url="https://opensource.posit.co/blog/2026-08-05_glimpse-aug-2026/thumbnail.jpg" length="68574" type="image/jpeg" />
    </item>
    <item>
      <title>roxygen2 8.1.0</title>
      <link>https://opensource.posit.co/blog/2026-08-04_roxygen2-8-1-0/</link>
      <pubDate>Tue, 04 Aug 2026 00:00:00 +0000</pubDate>
      <guid>https://opensource.posit.co/blog/2026-08-04_roxygen2-8-1-0/</guid>
      <dc:creator>Hadley Wickham</dc:creator><description><![CDATA[<p>I&rsquo;m well chuffed to announce that <a href="https://roxygen2.r-lib.org" target="_blank" rel="noopener">roxygen2 8.1.0</a> is now on CRAN.
roxygen2 turns specially formatted comments in your R code into the <code>.Rd</code> files that power R&rsquo;s help system.
You can install it with:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">install.packages</span><span class="p">(</span><span class="s">&#34;roxygen2&#34;</span><span class="p">)</span></span></span></code></pre></div></div>
<p>This is a small release, and the two main changes are about performance: one makes your package load faster for your users, and one makes documenting faster for you.
You can see the full list of changes in the <a href="https://github.com/r-lib/roxygen2/releases/tag/v8.1.0" target="_blank" rel="noopener">release notes</a>.</p>
<h2 id="merged-importfrom-directives">Merged <code>importFrom()</code> directives
</h2>
<p><code>@importFrom</code> used to generate one <code>importFrom()</code> directive per symbol.
Now it generates a single multi-line directive per package:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># before</span>
</span></span><span class="line"><span class="cl"><span class="nf">importFrom</span><span class="p">(</span><span class="n">utils</span><span class="p">,</span><span class="n">URLdecode</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nf">importFrom</span><span class="p">(</span><span class="n">utils</span><span class="p">,</span><span class="n">URLencode</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nf">importFrom</span><span class="p">(</span><span class="n">utils</span><span class="p">,</span><span class="n">head</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nf">importFrom</span><span class="p">(</span><span class="n">utils</span><span class="p">,</span><span class="n">tail</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># after</span>
</span></span><span class="line"><span class="cl"><span class="nf">importFrom</span><span class="p">(</span><span class="n">utils</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">URLdecode</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">URLencode</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">head</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="n">tail</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span></span></span></code></pre></div></div>
<p>We made this change because we discovered that the number of <code>importFrom()</code> directives in your <code>NAMESPACE</code> has a surprisingly large effect on loading time.
<code>loadNamespace()</code> does a chunk of per-directive work, so the cost grows with the number of directives, not the number of symbols.
Importing 1,000 functions with 1,000 separate directives costs around 120ms; importing the same 1,000 functions with one directive per package costs around 9ms, the same as importing 10.</p>
<p>Of course, most packages import far fewer than 1,000 objects.
But <code>library()</code> costs are paid by every user, on every session, and they&rsquo;re cumulative: loading a package also loads its dependencies.
Merging the directives removes the cost for the user entirely, at little cost to you as the developer: just one noisy <code>NAMESPACE</code> diff.</p>
<p>My colleague Kevin Ushey also fixed a related annoyance: <code>@importFrom</code>, <code>@importClassesFrom</code>, and <code>@importMethodsFrom</code> once again accept multi-line input, so you can spread a long list of imports over several lines for readability.
You&rsquo;ll just need a hanging indent on the continuation lines.</p>
<h2 id="faster-documenting-with-rdtools">Faster documenting with rdtools
</h2>
<p>The other change helps developers, rather than users: documenting a package with lots of cross-references is now considerably faster.</p>
<p>The bottleneck was topic resolution: every time roxygen2 sees a link like <code>[dplyr::filter()]</code>, or needs to work out which package an unqualified <code>[filter()]</code> refers to, it has to ask &ldquo;does this package have a topic with this alias?&rdquo;.
Previously roxygen2 answered that question by calling <code>utils::help()</code>, which takes about 1.5ms.
That doesn&rsquo;t sound like much, but to resolve an unqualified link roxygen2 has to check every dependency plus the base packages, which adds up.
On a link-heavy package like testthat, that meant roughly half of the total time spent documenting was just looking up cross-references.</p>
<p>The fix is to stop asking one question at a time, and to cache each lookup.
Installed packages already ship an alias index (<code>help/aliases.rds</code>), and packages loaded from source have one maintained by pkgload, so all the information needed is available in bulk &mdash; it just needs to be read once and kept in a hash table, rather than rediscovered on every query.</p>
<p>That logic now lives in a new package, <a href="https://rdtools.r-lib.org" target="_blank" rel="noopener">rdtools</a>, which provides cached lookup of help topics and aliases across installed, source, and in-development packages, along with efficient retrieval of parsed <code>Rd</code> objects.
Pulling it out of roxygen2 deleted a decent amount of fiddly code that I&rsquo;d also implemented (to varying levels of quality) in pkgdown and downlit.</p>
<h2 id="acknowledgements">Acknowledgements
</h2>
<p>A big thanks to everyone who helped make this release possible! <a href="https://github.com/aphalo" target="_blank" rel="noopener">@aphalo</a>, <a href="https://github.com/DavisVaughan" target="_blank" rel="noopener">@DavisVaughan</a>, <a href="https://github.com/dragosmg" target="_blank" rel="noopener">@dragosmg</a>, <a href="https://github.com/etiennebacher" target="_blank" rel="noopener">@etiennebacher</a>, <a href="https://github.com/gadenbuie" target="_blank" rel="noopener">@gadenbuie</a>, <a href="https://github.com/hadley" target="_blank" rel="noopener">@hadley</a>, <a href="https://github.com/jan-swissre" target="_blank" rel="noopener">@jan-swissre</a>, <a href="https://github.com/jemus42" target="_blank" rel="noopener">@jemus42</a>, <a href="https://github.com/jranke" target="_blank" rel="noopener">@jranke</a>, <a href="https://github.com/kevinushey" target="_blank" rel="noopener">@kevinushey</a>, <a href="https://github.com/lionel-" target="_blank" rel="noopener">@lionel-</a>, <a href="https://github.com/mcol" target="_blank" rel="noopener">@mcol</a>, <a href="https://github.com/MichaelChirico" target="_blank" rel="noopener">@MichaelChirico</a>, <a href="https://github.com/peterdesmet" target="_blank" rel="noopener">@peterdesmet</a>, and <a href="https://github.com/thisisnic" target="_blank" rel="noopener">@thisisnic</a>.</p>
]]></description>
      <enclosure url="https://opensource.posit.co/blog/2026-08-04_roxygen2-8-1-0/thumbnail.jpg" length="158270" type="image/jpeg" />
    </item>
    <item>
      <title>Shiny updates: R 1.14, Python 1.7, bslib 0.12</title>
      <link>https://opensource.posit.co/blog/2026-08-04_shiny-r-1-14-python-1-7/</link>
      <pubDate>Tue, 04 Aug 2026 00:00:00 +0000</pubDate>
      <guid>https://opensource.posit.co/blog/2026-08-04_shiny-r-1-14-python-1-7/</guid>
      <dc:creator>Barret Schloerke</dc:creator><description><![CDATA[<p>We&rsquo;re happy to announce a trio of releases: <a href="https://cran.r-project.org/package=shiny" target="_blank" rel="noopener">Shiny for R v1.14</a> and <a href="https://cran.r-project.org/package=bslib" target="_blank" rel="noopener">bslib v0.12</a> are now on CRAN, and <a href="https://pypi.org/project/shiny/" target="_blank" rel="noopener">Shiny for Python v1.7</a> is now on PyPI!</p>
<div class="panel-tabset" data-tabset-group="language">
<ul id="tabset-1" class="panel-tabset-tabby">
<li><a data-tabby-default href="#tabset-1-1">R</a></li>
<li><a href="#tabset-1-2">Python</a></li>
</ul>
<div id="tabset-1-1">
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">install.packages</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="s">&#34;shiny&#34;</span><span class="p">,</span> <span class="s">&#34;bslib&#34;</span><span class="p">))</span></span></span></code></pre></div></div>
</div>
<div id="tabset-1-2">
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">pip install -U shiny</span></span></code></pre></div></div>
</div>
</div>
<p>The highlights: <a href="#agent-skills">bundled agent skills</a> that teach coding agents how to write Shiny for Python apps, <a href="#non-blocking-apps"><code>startApp()</code></a> for running R apps without blocking your console, <a href="#offcanvas-panels">offcanvas panels</a> that slide in from the edge of the viewport, and <a href="#module-cleanup"><code>destroy()</code></a> for cleaning up dynamic modules.</p>
<p>Full details are in the <a href="https://shiny.posit.co/r/reference/shiny/1.14.0/upgrade.html" target="_blank" rel="noopener">Shiny for R release notes</a>, the <a href="https://rstudio.github.io/bslib/news/index.html#bslib-0120" target="_blank" rel="noopener">bslib release notes</a>, and the <a href="https://github.com/posit-dev/py-shiny/blob/main/CHANGELOG.md" target="_blank" rel="noopener">Shiny for Python changelog</a>.</p>
<h2 id="agent-skills">Agent skills
</h2>
<p><em>Shiny for Python only &mdash; coming to R soon.</em></p>
<p>Coding agents are writing more and more Shiny apps &mdash; so we&rsquo;re teaching them how to do it well. Shiny for Python v1.7 ships with bundled <a href="https://agentskills.io" target="_blank" rel="noopener">Agent Skills</a>: a <code>shiny-for-python</code> skill whose <code>SKILL.md</code> routes agents to focused reference files covering each area of Shiny&rsquo;s public API &mdash; reactivity, Express mode, modules, layouts, plots, data frames, chat and streaming, extended tasks, testing, debugging, OpenTelemetry, and more.</p>
<p>To install the bundled skills into your coding agent, use <a href="https://library-skills.io" target="_blank" rel="noopener">library-skills</a>:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">uvx library-skills --claude</span></span></code></pre></div></div>
<p>Because the skills ship inside the package, they always match the version of Shiny you have installed &mdash; and <code>shiny skills list</code> shows what&rsquo;s bundled.</p>
<p>Now your agent stops hand-rolling HTML tables and fake tabs, and starts using the framework the way you would.</p>
<h2 id="non-blocking-apps">Non-blocking apps
</h2>
<p><em>Shiny for R only.</em></p>
<p><a href="https://shiny.posit.co/r/reference/shiny/1.14.0/runApp.html" target="_blank" rel="noopener"><code>runApp()</code></a> blocks your R console until the app stops. New in Shiny v1.14, <a href="https://shiny.posit.co/r/reference/shiny/1.14.0/startApp.html" target="_blank" rel="noopener"><code>startApp()</code></a> runs the app in the background and hands control right back to you:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># Start app in the background</span>
</span></span><span class="line"><span class="cl"><span class="n">handle</span> <span class="o">&lt;-</span> <span class="nf">startApp</span><span class="p">(</span><span class="s">&#34;myapp&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># The console remains available</span>
</span></span><span class="line"><span class="cl"><span class="n">handle</span><span class="o">$</span><span class="nf">status</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;running&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">handle</span><span class="o">$</span><span class="nf">url</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;http://127.0.0.1:7365&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Stop the app</span>
</span></span><span class="line"><span class="cl"><span class="n">handle</span><span class="o">$</span><span class="nf">stop</span><span class="p">()</span></span></span></code></pre></div></div>
<p>The returned <code>ShinyAppHandle</code> has <code>stop()</code>, <code>status()</code>, <code>url()</code>, and <code>result()</code> methods. Starting a new app automatically stops the previous one, so iterating is as simple as calling <code>startApp()</code> again.</p>
<p>This is handy for interactive development, but it really shines for anything that needs to drive an app <em>and</em> keep working: testing tools, coding agents, or scripts that launch an app, interact with it, and shut it down.</p>
<p>That&rsquo;s the tooling around your app. The next two features are about the app itself &mdash; starting with a new way to keep UI off screen until someone asks for it.</p>
<h2 id="offcanvas-panels">Offcanvas panels
</h2>
<p>An offcanvas is a panel that slides in from an edge of the viewport &mdash; perfect for settings, filters, details-on-demand, or anything else that doesn&rsquo;t need to be on screen all the time. It&rsquo;s built on <a href="https://getbootstrap.com/docs/5.3/components/offcanvas/" target="_blank" rel="noopener">Bootstrap 5&rsquo;s offcanvas component</a> and comes with the full set of server verbs: <code>show_offcanvas()</code>, <code>hide_offcanvas()</code>, and <code>toggle_offcanvas()</code>.</p>
<p>The simplest way to use one is with a <code>trigger</code> element &mdash; no server code required:</p>
<div class="panel-tabset" data-tabset-group="language">
<ul id="tabset-2" class="panel-tabset-tabby">
<li><a data-tabby-default href="#tabset-2-1">R</a></li>
<li><a href="#tabset-2-2">Python</a></li>
</ul>
<div id="tabset-2-1">
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">shiny</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">bslib</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">ui</span> <span class="o">&lt;-</span> <span class="nf">page_fluid</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="nf">offcanvas</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;Panel content goes here.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">title</span> <span class="o">=</span> <span class="s">&#34;Settings&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">trigger</span> <span class="o">=</span> <span class="nf">actionButton</span><span class="p">(</span><span class="s">&#34;open&#34;</span><span class="p">,</span> <span class="s">&#34;Open settings&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span></span></span></code></pre></div></div>
</div>
<div id="tabset-2-2">
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">shiny.express</span> <span class="kn">import</span> <span class="n">ui</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">ui</span><span class="o">.</span><span class="n">offcanvas</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;Panel content goes here.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">title</span><span class="o">=</span><span class="s2">&#34;Settings&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">trigger</span><span class="o">=</span><span class="n">ui</span><span class="o">.</span><span class="n">input_action_button</span><span class="p">(</span><span class="s2">&#34;open&#34;</span><span class="p">,</span> <span class="s2">&#34;Open settings&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span></span></span></code></pre></div></div>
</div>
</div>
<figure>
<img src="https://opensource.posit.co/blog/2026-08-04_shiny-r-1-14-python-1-7/offcanvas-trigger.png" data-fig-alt="A Shiny app with an open offcanvas panel titled Settings sliding in from the right, dimming the page behind it" data-fig-align="center" alt="Clicking the trigger button reveals the offcanvas panel" />
<figcaption aria-hidden="true">Clicking the trigger button reveals the offcanvas panel</figcaption>
</figure>
<p>Give the panel an <code>id</code> and it becomes fully programmable: control it from the server and reactively respond to whether it&rsquo;s open.</p>
<div class="panel-tabset" data-tabset-group="language">
<ul id="tabset-3" class="panel-tabset-tabby">
<li><a data-tabby-default href="#tabset-3-1">R</a></li>
<li><a href="#tabset-3-2">Python</a></li>
</ul>
<div id="tabset-3-1">
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">shiny</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">bslib</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">ui</span> <span class="o">&lt;-</span> <span class="nf">page_fluid</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="nf">actionButton</span><span class="p">(</span><span class="s">&#34;toggle&#34;</span><span class="p">,</span> <span class="s">&#34;Toggle details&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="nf">offcanvas</span><span class="p">(</span><span class="s">&#34;Panel content&#34;</span><span class="p">,</span> <span class="n">title</span> <span class="o">=</span> <span class="s">&#34;Details&#34;</span><span class="p">,</span> <span class="n">id</span> <span class="o">=</span> <span class="s">&#34;details&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">server</span> <span class="o">&lt;-</span> <span class="kr">function</span><span class="p">(</span><span class="n">input</span><span class="p">,</span> <span class="n">output</span><span class="p">,</span> <span class="n">session</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">observeEvent</span><span class="p">(</span><span class="n">input</span><span class="o">$</span><span class="n">toggle</span><span class="p">,</span> <span class="nf">toggle_offcanvas</span><span class="p">(</span><span class="s">&#34;details&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nf">observeEvent</span><span class="p">(</span><span class="n">input</span><span class="o">$</span><span class="n">details</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nf">message</span><span class="p">(</span><span class="s">&#34;Panel is open: &#34;</span><span class="p">,</span> <span class="n">input</span><span class="o">$</span><span class="n">details</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">})</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">shinyApp</span><span class="p">(</span><span class="n">ui</span><span class="p">,</span> <span class="n">server</span><span class="p">)</span></span></span></code></pre></div></div>
</div>
<div id="tabset-3-2">
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">shiny</span> <span class="kn">import</span> <span class="n">reactive</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">shiny.express</span> <span class="kn">import</span> <span class="nb">input</span><span class="p">,</span> <span class="n">render</span><span class="p">,</span> <span class="n">ui</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">ui</span><span class="o">.</span><span class="n">input_action_button</span><span class="p">(</span><span class="s2">&#34;toggle&#34;</span><span class="p">,</span> <span class="s2">&#34;Toggle details&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">ui</span><span class="o">.</span><span class="n">offcanvas</span><span class="p">(</span><span class="s2">&#34;Panel content&#34;</span><span class="p">,</span> <span class="n">title</span><span class="o">=</span><span class="s2">&#34;Details&#34;</span><span class="p">,</span> <span class="nb">id</span><span class="o">=</span><span class="s2">&#34;details&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@reactive.effect</span>
</span></span><span class="line"><span class="cl"><span class="nd">@reactive.event</span><span class="p">(</span><span class="nb">input</span><span class="o">.</span><span class="n">toggle</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">_</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="n">ui</span><span class="o">.</span><span class="n">toggle_offcanvas</span><span class="p">(</span><span class="s2">&#34;details&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@render.text</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">state</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="sa">f</span><span class="s2">&#34;Panel is </span><span class="si">{</span><span class="s1">&#39;open&#39;</span> <span class="k">if</span> <span class="nb">input</span><span class="o">.</span><span class="n">details</span><span class="p">()</span> <span class="k">else</span> <span class="s1">&#39;closed&#39;</span><span class="si">}</span><span class="s2">&#34;</span></span></span></code></pre></div></div>
</div>
</div>
<p>Panels can slide in from the <code>left</code>, <code>right</code>, <code>top</code>, or <code>bottom</code>, and you can even build one entirely in the server and reveal it with <code>show_offcanvas()</code> &mdash; no UI placement needed.</p>
<p>Offcanvas panels are available now in Shiny for Python v1.7 and in <a href="https://rstudio.github.io/bslib/" target="_blank" rel="noopener">bslib</a> v0.12 for R. See the <code>offcanvas()</code> (<a href="https://rstudio.github.io/bslib/reference/offcanvas.html" target="_blank" rel="noopener">R</a>, <a href="https://shiny.posit.co/py/api/express/express.ui.offcanvas.html" target="_blank" rel="noopener">Python</a>) reference for the panel itself, and <code>show_offcanvas()</code>, <code>hide_offcanvas()</code>, and <code>toggle_offcanvas()</code> (<a href="https://rstudio.github.io/bslib/reference/show_offcanvas.html" target="_blank" rel="noopener">R</a>, <a href="https://shiny.posit.co/py/api/express/express.ui.show_offcanvas.html" target="_blank" rel="noopener">Python</a>) for controlling it from the server.</p>
<h2 id="module-cleanup">Module cleanup
</h2>
<p>An offcanvas hides UI that&rsquo;s already there. Creating and destroying UI on the fly is a different problem, and modules make it easy to <em>add</em> UI and server logic dynamically. Removing them has always been the awkward part: <a href="https://shiny.posit.co/r/reference/shiny/1.14.0/insertUI.html" target="_blank" rel="noopener"><code>removeUI()</code></a> takes the HTML away, but the module&rsquo;s observers, reactive values, and outputs keep running behind the scenes &mdash; leaving behind &ldquo;dangling reactivity&rdquo;.</p>
<p>The session&rsquo;s new <code>destroy()</code> method (<a href="https://shiny.posit.co/r/reference/shiny/1.14.0/session.html" target="_blank" rel="noopener">R</a>, <a href="https://shiny.posit.co/py/api/core/Session.html" target="_blank" rel="noopener">Python</a>) closes that gap. The parent that inserted a module can now clean it up by the same id it used to insert it &mdash; no cleanup handles to pass around:</p>
<div class="panel-tabset" data-tabset-group="language">
<ul id="tabset-4" class="panel-tabset-tabby">
<li><a data-tabby-default href="#tabset-4-1">R</a></li>
<li><a href="#tabset-4-2">Python</a></li>
</ul>
<div id="tabset-4-1">
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># In the parent server</span>
</span></span><span class="line"><span class="cl"><span class="nf">observeEvent</span><span class="p">(</span><span class="n">input</span><span class="o">$</span><span class="n">add</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">insertUI</span><span class="p">(</span><span class="s">&#34;#container&#34;</span><span class="p">,</span> <span class="n">ui</span> <span class="o">=</span> <span class="nf">myModuleUI</span><span class="p">(</span><span class="s">&#34;editor&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">  <span class="nf">myModuleServer</span><span class="p">(</span><span class="s">&#34;editor&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">observeEvent</span><span class="p">(</span><span class="n">input</span><span class="o">$</span><span class="n">remove</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">removeUI</span><span class="p">(</span><span class="n">selector</span> <span class="o">=</span> <span class="s">&#34;#editor&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">session</span><span class="o">$</span><span class="nf">destroy</span><span class="p">(</span><span class="s">&#34;editor&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span></span></span></code></pre></div></div>
</div>
<div id="tabset-4-2">
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="nd">@reactive.effect</span>
</span></span><span class="line"><span class="cl"><span class="nd">@reactive.event</span><span class="p">(</span><span class="nb">input</span><span class="o">.</span><span class="n">add</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">_</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="n">ui</span><span class="o">.</span><span class="n">insert_ui</span><span class="p">(</span><span class="n">my_module_ui</span><span class="p">(</span><span class="s2">&#34;editor&#34;</span><span class="p">),</span> <span class="n">selector</span><span class="o">=</span><span class="s2">&#34;#container&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">my_module_server</span><span class="p">(</span><span class="s2">&#34;editor&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@reactive.effect</span>
</span></span><span class="line"><span class="cl"><span class="nd">@reactive.event</span><span class="p">(</span><span class="nb">input</span><span class="o">.</span><span class="n">remove</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">_</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="n">ui</span><span class="o">.</span><span class="n">remove_ui</span><span class="p">(</span><span class="n">selector</span><span class="o">=</span><span class="s2">&#34;#editor&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">await</span> <span class="n">session</span><span class="o">.</span><span class="n">destroy</span><span class="p">(</span><span class="s2">&#34;editor&#34;</span><span class="p">)</span></span></span></code></pre></div></div>
</div>
</div>
<p>Destroying a scope invokes all of its registered <a href="https://shiny.posit.co/r/reference/shiny/1.14.0/session.html" target="_blank" rel="noopener"><code>onDestroy()</code></a> (R) / <a href="https://shiny.posit.co/py/api/core/Session.html" target="_blank" rel="noopener"><code>on_destroy()</code></a> (Python) callbacks, cleaning up reactive values, expressions, observers, inputs, and outputs for that module <em>and</em> its descendant modules. Everything is scoped, so the parent session and sibling modules are untouched. And a module can call <code>destroy()</code> on its own session (no id) to clean up after itself.</p>
<p>If your app inserts and removes modules over a long-lived session, <code>destroy()</code> keeps those removed modules from accumulating as memory and reactivity leaks.</p>
<h2 id="test-mode">Test mode
</h2>
<p><em>Shiny for Python only.</em></p>
<p>Back to agents for a moment. The bundled skills teach them how to <em>write</em> your app; test mode, also new in v1.7, lets them &mdash; and your tests &mdash; <em>see inside</em> it while it runs. Enable it with the <code>SHINY_TESTMODE=1</code> environment variable (or <code>App(test_mode=True)</code>), and each session serves a live JSON snapshot of its <code>input</code>, <code>output</code>, and exported values.</p>
<p>The snapshot is only served when test mode is enabled, and by default it includes only inputs and outputs. To surface an internal reactive &mdash; a <code>reactive.calc</code> or <code>reactive.value</code> that never reaches the UI &mdash; export it with <a href="https://shiny.posit.co/py/api/core/testmode.export_test_values.html" target="_blank" rel="noopener"><code>export_test_values()</code></a>:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">shiny</span> <span class="kn">import</span> <span class="n">reactive</span><span class="p">,</span> <span class="n">render</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">shiny.express</span> <span class="kn">import</span> <span class="nb">input</span><span class="p">,</span> <span class="n">ui</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">shiny.testmode</span> <span class="kn">import</span> <span class="n">export_test_values</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">ui</span><span class="o">.</span><span class="n">input_slider</span><span class="p">(</span><span class="s2">&#34;n&#34;</span><span class="p">,</span> <span class="s2">&#34;N&#34;</span><span class="p">,</span> <span class="nb">min</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="nb">max</span><span class="o">=</span><span class="mi">100</span><span class="p">,</span> <span class="n">value</span><span class="o">=</span><span class="mi">20</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@reactive.calc</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">doubled</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nb">input</span><span class="o">.</span><span class="n">n</span><span class="p">()</span> <span class="o">*</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@render.text</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">txt</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="sa">f</span><span class="s2">&#34;n * 2 = </span><span class="si">{</span><span class="n">doubled</span><span class="p">()</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Surface the internal reactive in the test-mode snapshot. This is a no-op</span>
</span></span><span class="line"><span class="cl"><span class="c1"># unless test mode is enabled, so it&#39;s safe to leave in production code.</span>
</span></span><span class="line"><span class="cl"><span class="n">export_test_values</span><span class="p">(</span><span class="n">doubled</span><span class="o">=</span><span class="n">doubled</span><span class="p">)</span></span></span></code></pre></div></div>
<p>The pytest app fixtures (<code>local_app</code>, <code>create_app_fixture</code>) enable test mode automatically, and the new <a href="https://shiny.posit.co/py/api/testing/playwright.controller.AppTestValues.html" target="_blank" rel="noopener"><code>shiny.playwright.controller.AppTestValues</code></a> controller reads the snapshot in end-to-end tests. Expectations accept exact values or predicates:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">is_even</span><span class="p">(</span><span class="n">value</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">value</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">app_values</span> <span class="o">=</span> <span class="n">controller</span><span class="o">.</span><span class="n">AppTestValues</span><span class="p">(</span><span class="n">page</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">app_values</span><span class="o">.</span><span class="n">expect_export</span><span class="p">(</span><span class="s2">&#34;doubled&#34;</span><span class="p">,</span> <span class="mi">40</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">app_values</span><span class="o">.</span><span class="n">expect_export</span><span class="p">(</span><span class="s2">&#34;doubled&#34;</span><span class="p">,</span> <span class="n">is_even</span><span class="p">)</span></span></span></code></pre></div></div>
<div class="callout callout-tip" role="note" aria-label="Tip">
<div class="callout-header">
<span class="callout-title">Scrubbing volatile values</span>
</div>
<div class="callout-body">
<p>Need to remove timestamps or temp paths before they are written to the snapshot? Register a preprocessor with <a href="https://shiny.posit.co/py/api/core/testmode.snapshot_preprocess_input.html" target="_blank" rel="noopener"><code>input.set_snapshot_preprocess()</code></a> or <code>my_output.snapshot_preprocess()</code>, and the snapshot stays stable from run to run.</p>
</div>
</div>
<p>Test mode mirrors R&rsquo;s long-standing <a href="https://shiny.posit.co/r/reference/shiny/1.14.0/exportTestValues.html" target="_blank" rel="noopener"><code>exportTestValues()</code></a> &mdash; and it gives coding agents a structured way to debug a running app directly from the server instead of inferring information from the UI.</p>
<p>New to testing Shiny apps? Start with <a href="https://shiny.posit.co/py/docs/unit-testing.html" target="_blank" rel="noopener">Unit testing</a> and <a href="https://shiny.posit.co/py/docs/end-to-end-testing.html" target="_blank" rel="noopener">End-to-end testing</a> on the Shiny for Python website, then browse the <a href="https://shiny.posit.co/py/api/testing/index.html" target="_blank" rel="noopener">testing API reference</a>.</p>
<h2 id="other-improvements">Other improvements
</h2>
<p>A few more changes worth a quick mention &mdash; the full lists are in the release notes for <a href="https://shiny.posit.co/r/reference/shiny/1.14.0/upgrade.html" target="_blank" rel="noopener">Shiny for R v1.14.0</a>, <a href="https://rstudio.github.io/bslib/news/index.html#bslib-0120" target="_blank" rel="noopener">bslib v0.12.0</a>, and <a href="https://github.com/posit-dev/py-shiny/blob/main/CHANGELOG.md" target="_blank" rel="noopener">Shiny for Python v1.7.0</a>:</p>
<h3 id="r">R
</h3>
<ul>
<li><a href="https://shiny.posit.co/r/reference/shiny/1.14.0/downloadButton.html" target="_blank" rel="noopener"><code>downloadButton()</code></a> and <a href="https://shiny.posit.co/r/reference/shiny/1.14.0/downloadButton.html" target="_blank" rel="noopener"><code>downloadLink()</code></a> gain an <code>enabled</code> argument. The default, <code>&quot;auto&quot;</code>, automatically enables the button once the download is ready.</li>
<li>Output resize and visibility detection now uses native browser observers (<code>ResizeObserver</code>, <code>IntersectionObserver</code>), so plot sizing and hidden-state tracking work in any layout &mdash; including CSS-only show/hide and non-Bootstrap frameworks.</li>
<li><a href="https://shiny.posit.co/r/reference/shiny/1.14.0/conditionalPanel.html" target="_blank" rel="noopener"><code>conditionalPanel()</code></a> no longer briefly flashes its contents on app start when the condition is initially <code>FALSE</code>.</li>
<li>bslib v0.12 also lets you grab the sidebar handle directly to resize a sidebar, and fixes the resize handle indicator for <code>position = &quot;right&quot;</code> sidebars.</li>
</ul>
<h3 id="python">Python
</h3>
<ul>
<li><a href="https://shiny.posit.co/py/api/express/express.render.download_button.html" target="_blank" rel="noopener"><code>@render.download_button</code></a> and <a href="https://shiny.posit.co/py/api/express/express.render.download_link.html" target="_blank" rel="noopener"><code>@render.download_link</code></a> pair 1:1 with <code>ui.download_button()</code> and <code>ui.download_link()</code>, replacing the now-deprecated <code>@render.download</code>.</li>
<li>The <code>shiny[otel]</code> extra now sets up OpenTelemetry zero-code auto-instrumentation out of the box: <code>opentelemetry-instrument shiny run app.py</code>.</li>
</ul>
<h2 id="in-closing">In closing
</h2>
<p>We&rsquo;re excited to see what you build (and clean up) with these releases. As always, if you have questions or feedback, <a href="https://discord.gg/yMGCamUMnS" target="_blank" rel="noopener">join us on Discord</a> or open an issue on <a href="https://github.com/rstudio/shiny/issues/new" target="_blank" rel="noopener">rstudio/shiny</a> or <a href="https://github.com/posit-dev/py-shiny/issues/new" target="_blank" rel="noopener">posit-dev/py-shiny</a>. Happy Shiny-ing!</p>
<h2 id="acknowledgements">Acknowledgements
</h2>
<p>A big thank you to all the folks who helped make these releases happen:</p>
<h4 id="shiny-for-r-v1140">Shiny for R <a href="https://shiny.posit.co/r/reference/shiny/1.14.0/upgrade.html" target="_blank" rel="noopener">v1.14.0</a>
</h4>
<p><a href="https://github.com/adit-0132" target="_blank" rel="noopener">@adit-0132</a>, <a href="https://github.com/ahnungslos-git" target="_blank" rel="noopener">@ahnungslos-git</a>, <a href="https://github.com/byronvickers" target="_blank" rel="noopener">@byronvickers</a>, <a href="https://github.com/cpsievert" target="_blank" rel="noopener">@cpsievert</a>, <a href="https://github.com/cuckooland" target="_blank" rel="noopener">@cuckooland</a>, <a href="https://github.com/djacob65" target="_blank" rel="noopener">@djacob65</a>, <a href="https://github.com/dmurdoch" target="_blank" rel="noopener">@dmurdoch</a>, <a href="https://github.com/elnelson575" target="_blank" rel="noopener">@elnelson575</a>, <a href="https://github.com/FBrockmeyer" target="_blank" rel="noopener">@FBrockmeyer</a>, <a href="https://github.com/gadenbuie" target="_blank" rel="noopener">@gadenbuie</a>, <a href="https://github.com/HenrikBengtsson" target="_blank" rel="noopener">@HenrikBengtsson</a>, <a href="https://github.com/IvanM26" target="_blank" rel="noopener">@IvanM26</a>, <a href="https://github.com/jcheng5" target="_blank" rel="noopener">@jcheng5</a>, <a href="https://github.com/jeffkeller-einc" target="_blank" rel="noopener">@jeffkeller-einc</a>, <a href="https://github.com/jeis4wpi" target="_blank" rel="noopener">@jeis4wpi</a>, <a href="https://github.com/JohnCoene" target="_blank" rel="noopener">@JohnCoene</a>, <a href="https://github.com/JosiahParry" target="_blank" rel="noopener">@JosiahParry</a>, <a href="https://github.com/karangattu" target="_blank" rel="noopener">@karangattu</a>, <a href="https://github.com/klin333" target="_blank" rel="noopener">@klin333</a>, <a href="https://github.com/lachlansimpson" target="_blank" rel="noopener">@lachlansimpson</a>, <a href="https://github.com/lionel-" target="_blank" rel="noopener">@lionel-</a>, <a href="https://github.com/marcosnav" target="_blank" rel="noopener">@marcosnav</a>, <a href="https://github.com/mconflitti-pbc" target="_blank" rel="noopener">@mconflitti-pbc</a>, <a href="https://github.com/ml-ebs-ext" target="_blank" rel="noopener">@ml-ebs-ext</a>, <a href="https://github.com/nbenn" target="_blank" rel="noopener">@nbenn</a>, <a href="https://github.com/Noskario" target="_blank" rel="noopener">@Noskario</a>, <a href="https://github.com/prinjos" target="_blank" rel="noopener">@prinjos</a>, <a href="https://github.com/pyltime" target="_blank" rel="noopener">@pyltime</a>, <a href="https://github.com/rikivillalba" target="_blank" rel="noopener">@rikivillalba</a>, <a href="https://github.com/roberson4627-cpu" target="_blank" rel="noopener">@roberson4627-cpu</a>, <a href="https://github.com/samuelbharti" target="_blank" rel="noopener">@samuelbharti</a>, <a href="https://github.com/schloerke" target="_blank" rel="noopener">@schloerke</a>, <a href="https://github.com/shikokuchuo" target="_blank" rel="noopener">@shikokuchuo</a>, <a href="https://github.com/simon-smart88" target="_blank" rel="noopener">@simon-smart88</a>, <a href="https://github.com/toph-allen" target="_blank" rel="noopener">@toph-allen</a>, and <a href="https://github.com/Upipa" target="_blank" rel="noopener">@Upipa</a>.</p>
<h4 id="bslib-v0120">bslib <a href="https://rstudio.github.io/bslib/news/index.html#bslib-0120" target="_blank" rel="noopener">v0.12.0</a>
</h4>
<p><a href="https://github.com/AleKoure" target="_blank" rel="noopener">@AleKoure</a>, <a href="https://github.com/ArthurAndrews" target="_blank" rel="noopener">@ArthurAndrews</a>, <a href="https://github.com/averissimo" target="_blank" rel="noopener">@averissimo</a>, <a href="https://github.com/elnelson575" target="_blank" rel="noopener">@elnelson575</a>, <a href="https://github.com/etiennebacher" target="_blank" rel="noopener">@etiennebacher</a>, <a href="https://github.com/gadenbuie" target="_blank" rel="noopener">@gadenbuie</a>, <a href="https://github.com/jeis4wpi" target="_blank" rel="noopener">@jeis4wpi</a>, <a href="https://github.com/LeonidasZhak" target="_blank" rel="noopener">@LeonidasZhak</a>, <a href="https://github.com/lgaborini" target="_blank" rel="noopener">@lgaborini</a>, <a href="https://github.com/lgschuck" target="_blank" rel="noopener">@lgschuck</a>, <a href="https://github.com/sawelch-NIVA" target="_blank" rel="noopener">@sawelch-NIVA</a>, <a href="https://github.com/sims1253" target="_blank" rel="noopener">@sims1253</a>, and <a href="https://github.com/willgearty" target="_blank" rel="noopener">@willgearty</a>.</p>
<h4 id="shiny-for-python-v170">Shiny for Python <a href="https://github.com/posit-dev/py-shiny/blob/main/CHANGELOG.md" target="_blank" rel="noopener">v1.7.0</a>
</h4>
<p><a href="https://github.com/chernojagne" target="_blank" rel="noopener">@chernojagne</a>, <a href="https://github.com/cpsievert" target="_blank" rel="noopener">@cpsievert</a>, <a href="https://github.com/eeshsaxena" target="_blank" rel="noopener">@eeshsaxena</a>, <a href="https://github.com/elnelson575" target="_blank" rel="noopener">@elnelson575</a>, <a href="https://github.com/EltonChang1" target="_blank" rel="noopener">@EltonChang1</a>, <a href="https://github.com/FBruzzesi" target="_blank" rel="noopener">@FBruzzesi</a>, <a href="https://github.com/gadenbuie" target="_blank" rel="noopener">@gadenbuie</a>, <a href="https://github.com/hutch3232" target="_blank" rel="noopener">@hutch3232</a>, <a href="https://github.com/JosiahParry" target="_blank" rel="noopener">@JosiahParry</a>, <a href="https://github.com/karangattu" target="_blank" rel="noopener">@karangattu</a>, <a href="https://github.com/kb071216" target="_blank" rel="noopener">@kb071216</a>, <a href="https://github.com/kbzsl" target="_blank" rel="noopener">@kbzsl</a>, <a href="https://github.com/marcosnav" target="_blank" rel="noopener">@marcosnav</a>, <a href="https://github.com/mariameraz" target="_blank" rel="noopener">@mariameraz</a>, <a href="https://github.com/MukundaKatta" target="_blank" rel="noopener">@MukundaKatta</a>, <a href="https://github.com/mvanhorn" target="_blank" rel="noopener">@mvanhorn</a>, <a href="https://github.com/nightcityblade" target="_blank" rel="noopener">@nightcityblade</a>, <a href="https://github.com/pevolution-ahmed" target="_blank" rel="noopener">@pevolution-ahmed</a>, <a href="https://github.com/QuintonBaker-USDA" target="_blank" rel="noopener">@QuintonBaker-USDA</a>, <a href="https://github.com/saisharan0103" target="_blank" rel="noopener">@saisharan0103</a>, <a href="https://github.com/SamEdwardes" target="_blank" rel="noopener">@SamEdwardes</a>, <a href="https://github.com/schloerke" target="_blank" rel="noopener">@schloerke</a>, <a href="https://github.com/slupczynskim" target="_blank" rel="noopener">@slupczynskim</a>, <a href="https://github.com/Steven314" target="_blank" rel="noopener">@Steven314</a>, and <a href="https://github.com/tomaioo" target="_blank" rel="noopener">@tomaioo</a>.</p>
]]></description>
      <enclosure url="https://opensource.posit.co/blog/2026-08-04_shiny-r-1-14-python-1-7/feature.gif" length="449496" type="image/gif" />
    </item>
    <item>
      <title>Quarto 1.10</title>
      <link>https://opensource.posit.co/blog/2026-08-03_quarto-1-10/</link>
      <pubDate>Mon, 03 Aug 2026 00:00:00 +0000</pubDate>
      <guid>https://opensource.posit.co/blog/2026-08-03_quarto-1-10/</guid>
      <dc:creator>Charlotte Wickham</dc:creator><description><![CDATA[<p>Quarto 1.10 is out! You can get the current release from the <a href="https://quarto.org/docs/download/index.html" target="_blank" rel="noopener">download page</a>.</p>
<p>Quarto 1.10 is dominated by fixes, as much of our development effort is now going into <a href="https://opensource.posit.co/blog/2026-04-06_whats-next-quarto-2">Quarto 2</a>, but there are some improvements we wanted to point out: more refined HTML accessibility checks, and access to Quarto&rsquo;s localized strings for template authors.</p>
<p>You can read about these improvements and the most important fixes below. You can find all the changes in this version in the <a href="https://quarto.org/docs/download/changelog/1.10/" target="_blank" rel="noopener">Release Notes</a>.</p>
<h2 id="accessibility-checking-improvements">Accessibility Checking Improvements
</h2>
<p>Since Quarto 1.8, setting the <code>axe</code> option on HTML documents runs <a href="https://github.com/dequelabs/axe-core" target="_blank" rel="noopener">axe-core</a> accessibility checks on your rendered document. Quarto 1.10 makes these checks easier to rely on.</p>
<p><strong>Checking works offline.</strong> Quarto now bundles its own copy of axe-core instead of loading it from a CDN in the reader&rsquo;s browser. Accessibility checking works without a network connection, and viewing a rendered document no longer triggers a request to an external CDN. The axe-core version is unchanged, so results are identical.</p>
<p><strong>Check against a WCAG conformance level.</strong> The new <code>standard</code> option scopes checks to a WCAG conformance level, including rules axe-core keeps off by default for that level. The <code>best-practice</code> option controls whether axe&rsquo;s best-practice rules, recommendations not required by any WCAG success criterion, are also checked:</p>
<div class="code-block code-with-filename" role="group" aria-labelledby="code-filename-0">
  <div class="code-with-filename-label" id="code-filename-0"><span class="font-mono text-sm">document.qmd</span></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">format</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">html</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">axe</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">standard</span><span class="p">:</span><span class="w"> </span><span class="l">wcag21aa</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">best-practice</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span></span></span></code></pre></div></div>
<p><strong>A clearer report.</strong> When using <code>output: document</code>, violations are now listed first by impact, then WCAG conformance level. The report overlay also received its own accessibility and styling fixes: it can be scrolled with the keyboard, uses theme and brand independent colors, and no longer inherits page styling like text centering.</p>
<p>Learn more at <a href="https://quarto.org/docs/output-formats/html-accessibility.html" target="_blank" rel="noopener">HTML Accessibility</a>.</p>
<h2 id="localized-strings-in-templates">Localized Strings in Templates
</h2>
<p>If you write custom Pandoc templates or <a href="https://quarto.org/docs/journals/templates.html#template-partials" target="_blank" rel="noopener">template partials</a>, you can now use Quarto&rsquo;s localized strings through the new <code>quarto.language</code> template variable namespace. Quarto resolves each string for the document&rsquo;s language and exposes it as a template variable:</p>
<div class="code-block code-with-filename" role="group" aria-labelledby="code-filename-1">
  <div class="code-with-filename-label" id="code-filename-1"><span class="font-mono text-sm">template.typ</span></div><pre tabindex="0"><code class="language-default" data-lang="default">$quarto.language.toc-title-document$
$quarto.language.crossref-fig-title$</code></pre></div>
<p>This lets templates honor the document&rsquo;s <code>lang</code> option without hard-coding text. For example, the <code>orange-book</code> Typst book extension now uses these variables in its running headers, so a book with <code>lang: fr</code> gets <em>Chapitre</em> rather than <em>Chapter</em>.</p>
<p>Learn more at <a href="https://quarto.org/docs/authoring/language.html#localized-strings-in-templates" target="_blank" rel="noopener">Localized Strings in Templates</a>.</p>
<h2 id="other-important-fixes">Other Important Fixes
</h2>
<ul>
<li>
<p><code>quarto preview</code> reliability&mdash;a long-standing bug that showed stale HTML for non-index pages is fixed, changes to a document&rsquo;s <code>format:</code> are detected on the first render after the edit, a <code>_brand.yml</code> added or removed during preview is picked up, and transient <code>.quarto_ipynb</code> files no longer accumulate on disk.</p>
</li>
<li>
<p><a href="https://quarto.org/docs/extensions/shortcodes.html" target="_blank" rel="noopener">Shortcodes</a>&mdash;shortcodes are now resolved inside inline and display math expressions.</p>
</li>
<li>
<p><a href="https://quarto.org/docs/output-formats/pdf-basics.html#fonts" target="_blank" rel="noopener">PDF font fallbacks</a>&mdash;<code>mainfontfallback</code>, <code>sansfontfallback</code>, and <code>monofontfallback</code> no longer crash LuaLaTeX on TeX Live 2026, and a missing fallback font is now installed automatically.</p>
</li>
<li>
<p>Typst fonts&mdash;fonts not installed locally are filtered from CSS <code>font-family</code> fallback lists before they reach Typst, suppressing <code>unknown font family</code> warnings, alongside a batch of fixes to Quarto&rsquo;s CSS-to-Typst translation.</p>
</li>
<li>
<p><a href="https://opensource.posit.co/blog/2026-04-14_chrome-headless-shell">Chrome Headless Shell</a>&mdash;the <code>quarto install chromium</code> command, deprecated in 1.9, now transparently redirects to <code>chrome-headless-shell</code>, <code>quarto check install</code> warns about legacy Chromium installs, and arm64 Linux is now supported.</p>
</li>
<li>
<p><a href="https://quarto.org/docs/websites/website-llms.html" target="_blank" rel="noopener">Output for LLMs</a>&mdash;fixes for websites with <code>llms-txt</code> enabled: headings and shortcodes inside conditional content, and clean-URL rewriting of <code>index.html.md</code> links.</p>
</li>
</ul>
<p>Dependency updates:</p>
<ul>
<li><code>pandoc</code> updated to 3.10</li>
<li><code>typst</code> updated to 0.15.1</li>
<li><code>deno</code> updated to 2.7.14</li>
<li><code>dart-sass</code> updated to 1.101.0</li>
<li><code>esbuild</code> updated to 0.28.1</li>
</ul>
<h2 id="acknowledgements">Acknowledgements
</h2>
<p>We&rsquo;d like to say a huge thank you to everyone who contributed to this release by opening issues and pull requests:</p>
<p><a href="https://github.com/AlexLietard" target="_blank" rel="noopener">AlexLietard</a>,
<a href="https://github.com/ArthurRudolph" target="_blank" rel="noopener">ArthurRudolph</a>,
<a href="https://github.com/Artmann" target="_blank" rel="noopener">Artmann</a>,
<a href="https://github.com/C-Monaghan" target="_blank" rel="noopener">C-Monaghan</a>,
<a href="https://github.com/ChrisJefferson" target="_blank" rel="noopener">ChrisJefferson</a>,
<a href="https://github.com/CoryMcCartan" target="_blank" rel="noopener">CoryMcCartan</a>,
<a href="https://github.com/DCEW" target="_blank" rel="noopener">DCEW</a>,
<a href="https://github.com/DrFloLinke" target="_blank" rel="noopener">DrFloLinke</a>,
<a href="https://github.com/Guest-1013" target="_blank" rel="noopener">Guest-1013</a>,
<a href="https://github.com/MBe-iUS" target="_blank" rel="noopener">MBe-iUS</a>,
<a href="https://github.com/MurzNN" target="_blank" rel="noopener">MurzNN</a>,
<a href="https://github.com/ThierryO" target="_blank" rel="noopener">ThierryO</a>,
<a href="https://github.com/ThomasFaria" target="_blank" rel="noopener">ThomasFaria</a>,
<a href="https://github.com/TinasheMTapera" target="_blank" rel="noopener">TinasheMTapera</a>,
<a href="https://github.com/Voorhoeve" target="_blank" rel="noopener">Voorhoeve</a>,
<a href="https://github.com/alderete" target="_blank" rel="noopener">alderete</a>,
<a href="https://github.com/andrewheiss" target="_blank" rel="noopener">andrewheiss</a>,
<a href="https://github.com/barendgehrels" target="_blank" rel="noopener">barendgehrels</a>,
<a href="https://github.com/basm92" target="_blank" rel="noopener">basm92</a>,
<a href="https://github.com/blauzo" target="_blank" rel="noopener">blauzo</a>,
<a href="https://github.com/chainsawriot" target="_blank" rel="noopener">chainsawriot</a>,
<a href="https://github.com/crisbour" target="_blank" rel="noopener">crisbour</a>,
<a href="https://github.com/cs-res-pub-ser-st" target="_blank" rel="noopener">cs-res-pub-ser-st</a>,
<a href="https://github.com/dustinstoltz" target="_blank" rel="noopener">dustinstoltz</a>,
<a href="https://github.com/eculler" target="_blank" rel="noopener">eculler</a>,
<a href="https://github.com/eneveu" target="_blank" rel="noopener">eneveu</a>,
<a href="https://github.com/apps/github-actions" target="_blank" rel="noopener">github-actions[bot]</a>,
<a href="https://github.com/gregswinehart" target="_blank" rel="noopener">gregswinehart</a>,
<a href="https://github.com/hwine" target="_blank" rel="noopener">hwine</a>,
<a href="https://github.com/ianpittwood" target="_blank" rel="noopener">ianpittwood</a>,
<a href="https://github.com/ihrke" target="_blank" rel="noopener">ihrke</a>,
<a href="https://github.com/jdonaldson" target="_blank" rel="noopener">jdonaldson</a>,
<a href="https://github.com/jiangyun-fun" target="_blank" rel="noopener">jiangyun-fun</a>,
<a href="https://github.com/jidanni" target="_blank" rel="noopener">jidanni</a>,
<a href="https://github.com/jkrumbiegel" target="_blank" rel="noopener">jkrumbiegel</a>,
<a href="https://github.com/jnkatz" target="_blank" rel="noopener">jnkatz</a>,
<a href="https://github.com/jph00" target="_blank" rel="noopener">jph00</a>,
<a href="https://github.com/jtkulas" target="_blank" rel="noopener">jtkulas</a>,
<a href="https://github.com/juleswg23" target="_blank" rel="noopener">juleswg23</a>,
<a href="https://github.com/juliohm" target="_blank" rel="noopener">juliohm</a>,
<a href="https://github.com/kazuyanagimoto" target="_blank" rel="noopener">kazuyanagimoto</a>,
<a href="https://github.com/kelli-rstudio" target="_blank" rel="noopener">kelli-rstudio</a>,
<a href="https://github.com/lsbjordao" target="_blank" rel="noopener">lsbjordao</a>,
<a href="https://github.com/luismmontilla" target="_blank" rel="noopener">luismmontilla</a>,
<a href="https://github.com/maelle" target="_blank" rel="noopener">maelle</a>,
<a href="https://github.com/maucejo" target="_blank" rel="noopener">maucejo</a>,
<a href="https://github.com/memeplex" target="_blank" rel="noopener">memeplex</a>,
<a href="https://github.com/micedre" target="_blank" rel="noopener">micedre</a>,
<a href="https://github.com/multimeric" target="_blank" rel="noopener">multimeric</a>,
<a href="https://github.com/nathant181" target="_blank" rel="noopener">nathant181</a>,
<a href="https://github.com/neilernst" target="_blank" rel="noopener">neilernst</a>,
<a href="https://github.com/nessan" target="_blank" rel="noopener">nessan</a>,
<a href="https://github.com/nickvigilante" target="_blank" rel="noopener">nickvigilante</a>,
<a href="https://github.com/nrennie" target="_blank" rel="noopener">nrennie</a>,
<a href="https://github.com/pbosetti" target="_blank" rel="noopener">pbosetti</a>,
<a href="https://github.com/reckoner" target="_blank" rel="noopener">reckoner</a>,
<a href="https://github.com/rgouveiamendes" target="_blank" rel="noopener">rgouveiamendes</a>,
<a href="https://github.com/robjhyndman" target="_blank" rel="noopener">robjhyndman</a>,
<a href="https://github.com/sbwiecko" target="_blank" rel="noopener">sbwiecko</a>,
<a href="https://github.com/seandavi" target="_blank" rel="noopener">seandavi</a>,
<a href="https://github.com/sebastiansauer" target="_blank" rel="noopener">sebastiansauer</a>,
<a href="https://github.com/skyfroger" target="_blank" rel="noopener">skyfroger</a>,
<a href="https://github.com/songwupei" target="_blank" rel="noopener">songwupei</a>,
<a href="https://github.com/stefkuypers" target="_blank" rel="noopener">stefkuypers</a>,
<a href="https://github.com/stragu" target="_blank" rel="noopener">stragu</a>,
<a href="https://github.com/tiagojct" target="_blank" rel="noopener">tiagojct</a>,
<a href="https://github.com/victorrssx" target="_blank" rel="noopener">victorrssx</a>,
<a href="https://github.com/widlarizer" target="_blank" rel="noopener">widlarizer</a>,
<a href="https://github.com/wlatendresse" target="_blank" rel="noopener">wlatendresse</a>,
<a href="https://github.com/xuefeng-xu" target="_blank" rel="noopener">xuefeng-xu</a>,
<a href="https://github.com/yasyf" target="_blank" rel="noopener">yasyf</a>,
<a href="https://github.com/zinc75" target="_blank" rel="noopener">zinc75</a>.</p>
<p>The hammer and wrench emoji in the <a href="thumbnail.png">listing and social card image</a> for this post comes from <a href="https://openmoji.org/" class="external">OpenMoji</a>&ndash; the open-source emoji and icon project. License: <a href="https://creativecommons.org/licenses/by-sa/4.0/#" class="external">CC BY-SA 4.0</a></p>
]]></description>
      <enclosure url="https://opensource.posit.co/blog/2026-08-03_quarto-1-10/thumbnail.png" length="48234" type="image/png" />
    </item>
    <item>
      <title>AI Newsletter: EDA log in Posit Assistant</title>
      <link>https://opensource.posit.co/blog/2026-07-31_ai-newsletter/</link>
      <pubDate>Fri, 31 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://opensource.posit.co/blog/2026-07-31_ai-newsletter/</guid>
      <dc:creator>Sara Altman</dc:creator>
      <dc:creator>Simon Couch</dc:creator><description><![CDATA[<div class="callout callout-note" role="note" aria-label="Note">
<div class="callout-body">
<p><strong>Subscribe to the AI Newsletter!</strong></p>
<p>The AI newsletter is now published as an RSS feed. Follow it in your favorite reader:</p>
<p><a href="https://opensource.posit.co/tags/ai-newsletter/index.xml" target="_blank" rel="noopener noreferrer" class="btn-shortcode inline-flex mb-5 mr-5 items-center px-4 py-3 text-sm leading-5 gap-2 rounded-lg bg-blue-400 !text-white font-semibold align-middle hover:bg-blue-500 transition no-underline">Subscribe via RSS</a></p>
<p><strong>Want the newsletter as an email?</strong> Paste the feed URL — <a href="https://opensource.posit.co/tags/ai-newsletter/index.xml" target="_blank" rel="noopener">https://opensource.posit.co/tags/ai-newsletter/index.xml</a> — into a free RSS-to-email service such as <a href="https://blogtrottr.com/" target="_blank" rel="noopener">Blogtrottr</a>, <a href="https://feedrabbit.com/" target="_blank" rel="noopener">Feedrabbit</a>, or <a href="https://follow.it/" target="_blank" rel="noopener">Follow.it</a>, and each new issue will arrive in your inbox.</p>
</div>
</div>
<br>
[Posit Assistant](https://assistant.posit.co/) in Positron now includes an EDA log feature to help you keep track of exploratory analysis done with the agent.
<p><div class="not-prose"><figure>
    <img class="h-auto max-w-full rounded-lg"
      src="https://opensource.posit.co/blog/2026-07-31_ai-newsletter/images/eda-log-zoom.png"
      alt="Screenshot of Positron. On the left, Posit Assistant has analyzed a dataset of U.S. language speakers, showing a bar chart and written findings. On the right, the EDA Log opens in an editor tab titled &ldquo;ACS language speakers&rdquo;: a table with Area, Status, and Notes columns lists three areas—&ldquo;Dataset structure &amp; quality&rdquo; and &ldquo;Top languages nationwide&rdquo; marked Explored, and &ldquo;Language coverage across states&rdquo; marked Partial—each with bullet-point findings and an arrow that links back to the conversation, followed by a &ldquo;Next steps&rdquo; section of suggested directions." 
      loading="lazy"
    >
  </figure></div>
</p>
<p>The log summarizes findings for different areas of exploration and keeps track of next steps. To use the log, run the <code>/eda-log</code> slash command after you&rsquo;ve started the EDA process.</p>
<h3 id="why-we-made-this">Why we made this
</h3>
<p>Exploratory data analysis, the open-ended orientation to your data that often comes before anything else, can be a branching, nonlinear process. There are many questions you can ask of your data, and new areas of inquiry can open with each question you ask. Because of this, it is often hard to keep track of what you&rsquo;ve looked into, where that code lives, and what you want to explore next.</p>
<p>Historically, the EDA process was limited by how quickly you could write code and interpret the output. Coding agents like Posit Assistant lift the first of those constraints. They can carry out EDA far faster than you can on your own, which can exacerbate the issue of keeping track of what you&rsquo;ve explored.</p>
<p>This speed also introduces a new problem: the point of EDA is typically for you, the human, to understand your data, but coding agents can produce output faster than you can absorb it. If the agent completes an analysis but you haven&rsquo;t understood the insights in the data, the exploration process hasn&rsquo;t really happened.</p>
<p>Posit Assistant already has various features that tackle this problem, including an exploratory mode of interaction where it runs shorter turns and stops more frequently to involve the user.</p>
<p>The EDA log is another lightweight tool for the same goal. It keeps a running summary of what you and Posit Assistant have explored, helping your understanding keep pace with the agent&rsquo;s and giving you a clearer picture of what&rsquo;s already been done.</p>
<h3 id="details">Details
</h3>
<p>Here&rsquo;s what the EDA log looks like in action:</p>
<script src="https://fast.wistia.com/player.js" async></script>
<script src="https://fast.wistia.com/embed/bu9ch5gqvx.js" async type="module"></script>
<style>wistia-player[media-id='bu9ch5gqvx']:not(:defined) { background: center / contain no-repeat url('https://fast.wistia.com/embed/medias/bu9ch5gqvx/swatch'); display: block; filter: blur(5px); padding-top:60.42%; }</style>
<p><wistia-player media-id="bu9ch5gqvx" aspect="1.6551724137931034"></wistia-player></p>
<p>At a high level:</p>
<ul>
<li>When you run <code>/eda-log</code>, Posit Assistant will create a log for the exploration done in the conversation so far. The log then opens in the editor area in Positron.</li>
<li>The underlying logs are stored as YAML files in <code>.posit/assistant/eda-logs/</code>, next to where plans are stored.</li>
<li>Posit Assistant is instructed to loosely keep the log up to date as the conversation progresses, but you can also manually trigger an update at any time with the &ldquo;Refresh&rdquo; button.</li>
<li>Clicking the arrow next to an area scrolls you back to the spot in the conversation where that insight originated, so you can revisit the code and context that produced it.</li>
<li>Suggested next steps appear as clickable text. Clicking one sends it to Posit Assistant as your next message.</li>
<li>The creation of an EDA log is always user-triggered. Posit Assistant will never create one on its own.</li>
<li>The feature is currently only in Positron, but will come to RStudio soon.</li>
</ul>
<h2 id="recent-past-newsletters">Recent past newsletters
</h2>
<ul>
<li><a href="https://opensource.posit.co/blog/2026-07-17_ai-newsletter/">Which models are best at spotting data quality problems?</a></li>
<li><a href="https://opensource.posit.co/blog/2026-07-03_ai-newsletter/">How to choose between AGENTS.md, skills, and MCP servers</a></li>
</ul>
<br>
<br>
<p><a href="https://opensource.posit.co/tags/ai-newsletter/index.xml" target="_blank" rel="noopener noreferrer" class="btn-shortcode inline-flex mb-5 mr-5 items-center px-4 py-3 text-sm leading-5 gap-2 rounded-lg bg-blue-400 text-white font-semibold align-middle hover:bg-blue-500 transition no-underline">Subscribe via RSS</a></p>
]]></description>
      <enclosure url="https://opensource.posit.co/blog/2026-07-31_ai-newsletter/images/hero.png" length="954735" type="image/png" />
    </item>
    <item>
      <title>Positron&#39;s Jupyter Notebook Editor Is Now Generally Available</title>
      <link>https://opensource.posit.co/blog/2026-07-29_positron-jupyter-notebook-editor-ga/</link>
      <pubDate>Wed, 29 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://opensource.posit.co/blog/2026-07-29_positron-jupyter-notebook-editor-ga/</guid>
      <dc:creator>Wasim Lorgat</dc:creator>
      <dc:creator>Cindy Tong</dc:creator><description><![CDATA[<div class="callout callout-note" role="note" aria-label="Note">
<div class="callout-header">
<span class="callout-title">Note</span>
</div>
<div class="callout-body">
<p><a href="https://positron.posit.co" target="_blank" rel="noopener">Positron</a> is Posit&rsquo;s new, next-generation IDE for data science. Positron is designed to be an extensible, polyglot tool for exploring data and reproducible authoring in Python, R, and more.</p>
</div>
</div>
<p>Data scientists are often forced to choose between the simplicity of the classic Jupyter notebook experience and the advanced capabilities of a general-purpose IDE. With the <a href="https://opensource.posit.co/blog/2026-07-13_positron-2026-07-release/" target="_blank" rel="noopener">2026.07 release</a>, you no longer have to choose: Positron now delivers a first-class Notebook Editor inside an IDE built for data science.</p>
<p>If you&rsquo;re new to Positron, here&rsquo;s what the Notebook Editor is like in your daily work.</p>
<h2 id="environment-management">Environment management
</h2>
<p>You clone your colleague&rsquo;s repo and try to rerun their notebook. Which Python version do you use? What dependencies do you install and which versions? Did you previously set up an environment that you could reuse? You&rsquo;re faced with all of these questions before you&rsquo;ve run a single line of code.</p>
<p>Positron has several <a href="https://opensource.posit.co/blog/2026-07-08_positron-uv/" target="_blank" rel="noopener">built-in workflows</a> to help you manage your environments. When you open a repo, Positron discovers your installed environments, suggests the right one for the repo, and prompts you to set up a new environment if needed. The active environment is displayed front and center; click to restart or switch environments. Positron uses the same environment across your Jupyter and Quarto notebooks, scripts, and consoles. You can see inside your environments, which packages are installed, their versions, whether newer versions are available, and you can upgrade them. Environments are first-class citizens of Positron. <a href="https://positron.posit.co/positron-notebook-editor.html#setting-up-your-environment" target="_blank" rel="noopener">Explore Positron&rsquo;s environment management</a>.</p>
<img src="https://opensource.posit.co/blog/2026-07-29_positron-jupyter-notebook-editor-ga/notebook-from-git.gif" data-fig-align="center" data-fig-alt="Positron helps you resolve environment and package dependencies as you pull down a colleague&#39;s notebook" />
<h2 id="interactive-data-exploration">Interactive data exploration
</h2>
<p>When you run a cell in your notebook, your variables appear in the <a href="https://positron.posit.co/variables-pane.html" target="_blank" rel="noopener">Variables Pane</a>. Filter, sort, and search your data in the <a href="https://positron.posit.co/data-explorer.html" target="_blank" rel="noopener">Data Explorer</a>, and try out plot variations in the Visualize wizard. You can easily convert your point-and-click interactions into code by using the copy-code feature to bring them back into your notebook. If you get stuck, look up library documentation in the <a href="https://positron.posit.co/help-pane.html" target="_blank" rel="noopener">Help Pane</a>. All of this works out of the box.</p>
<img src="https://opensource.posit.co/blog/2026-07-29_positron-jupyter-notebook-editor-ga/notebook-data-exploration.gif" data-fig-align="center" data-fig-alt="Run a notebook and see your variables update live, inspect them in the data explorer and convert filters back to code." />
<h2 id="streamlined-version-control">Streamlined version control
</h2>
<p>Notebooks store outputs and execution metadata alongside code, which is great for sharing but does not work well with version control. Positron includes settings to exclude outputs and execution metadata from the saved file, so the diff is just your code change. <a href="https://positron.posit.co/positron-notebook-editor.html#version-control" target="_blank" rel="noopener">Explore the custom settings</a> to clean up your git diffs.</p>
<p>Your notebooks stay ordinary <code>.ipynb</code> files and the editing experience stays classic Jupyter. When a plain-text workflow suits you better, conversion to and from <code>.ipynb</code> and other formats is built in.</p>
<img src="https://opensource.posit.co/blog/2026-07-29_positron-jupyter-notebook-editor-ga/notebook-save-settings.png" data-fig-align="center" data-fig-alt="Customize what is saved in your notebooks for better version control." />
<h2 id="ai-assistance">AI assistance
</h2>
<p>Posit Assistant sees your notebook as more than just text. It works with the live session behind the notebook: your variables, your data, your plots. Ask it to fix a chart and it can inspect the dataframe, look at the plot itself, edit the cell, and run it again. It does the same things you would do, using the same panes you use. <a href="https://positron.posit.co/positron-notebook-editor.html#ai-integration" target="_blank" rel="noopener">Explore notebook-aware AI assistance in Positron</a>.</p>
<img src="https://opensource.posit.co/blog/2026-07-29_positron-jupyter-notebook-editor-ga/notebook-ai.gif" data-fig-align="center" data-fig-alt="Assistant can fix, explain, run your notebook and suggest next steps." />
<h2 id="get-started">Get started
</h2>
<p><a href="https://positron.posit.co/download" target="_blank" rel="noopener">Download Positron</a> and open a project with a Jupyter notebook. The Notebook Editor is now on by default. If you&rsquo;re coming from another IDE, your existing <code>.ipynb</code> files will open as-is without any conversion needed.</p>
<p>For the full feature reference, check out our <a href="https://positron.posit.co" target="_blank" rel="noopener">documentation</a>.</p>
<p>If you run into any issues or have ideas on how we can improve Positron, reach out on <a href="https://github.com/posit-dev/positron" target="_blank" rel="noopener">GitHub</a>.</p>
<p>Already using Positron? Everything in this release is in the <a href="https://positron.posit.co/release-notes" target="_blank" rel="noopener">release notes</a>.</p>
<p>Thank you so much for helping us build Positron&rsquo;s Jupyter notebook support from the ground up by chatting with us live, sharing your pain points, and giving us feedback on GitHub!</p>
<div class="callout callout-tip" role="note" aria-label="Tip">
<div class="callout-header">
<span class="callout-title">Tip</span>
</div>
<div class="callout-body">
<p><a href="https://positron.posit.co/download" target="_blank" rel="noopener">Download Positron</a> to try out the Notebook Editor and other new features!</p>
</div>
</div>
]]></description>
      <enclosure url="https://opensource.posit.co/blog/2026-07-29_positron-jupyter-notebook-editor-ga/featured.png" length="686743" type="image/png" />
    </item>
    <item>
      <title>Introducing lorax: Speaking for the Tree-Based Models</title>
      <link>https://opensource.posit.co/blog/2026-07-28_lorax/</link>
      <pubDate>Tue, 28 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://opensource.posit.co/blog/2026-07-28_lorax/</guid>
      <dc:creator>Max Kuhn</dc:creator><description><![CDATA[<p>When building tree-based models, such as <a href="https://cran.r-project.org/package=rpart" target="_blank" rel="noopener">CART</a>, <a href="https://en.wikipedia.org/wiki/Random_forest" target="_blank" rel="noopener">random forests</a>, or <a href="https://en.wikipedia.org/wiki/XGBoost" target="_blank" rel="noopener">XGBoost</a>, we might be interested in knowing a little more about how the model works. For example, if a CART and XGBoost model had roughly the same performance, we might want to characterize how complex each is so that we are more informed about which to prefer. Knowing how many predictors were used, how many terminal nodes are in the tree, and similar characteristics can help understand the model. We might desire to visualize the tree (or a tree in the ensemble), and so on.</p>
<p>The problem is that many packages store the tree&rsquo;s splits in different ways or offer incompatible APIs to access different characteristics. lorax helps capture this information for many different implementations.</p>
<p>You can install the CRAN version of lorax via</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">install.packages</span><span class="p">(</span><span class="s">&#34;lorax&#34;</span><span class="p">)</span></span></span></code></pre></div></div>
<p>or get the development version using</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">pak</span><span class="o">::</span><span class="nf">pak</span><span class="p">(</span><span class="s">&#34;tidymodels/lorax&#34;</span><span class="p">)</span></span></span></code></pre></div></div>
<p>Let&rsquo;s start by using the ranger package to create a random forest model using the food delivery data in the modeldata package. For illustration, the trees will be coerced to be more shallow than usual so that we can better plot them using the <code>min.node.size</code> argument:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">tidymodels</span><span class="p">)</span> <span class="c1"># &lt;- to easily get dplyr, tidyr, ggplot2, etc</span>
</span></span><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">ranger</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">lorax</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">set.seed</span><span class="p">(</span><span class="m">872</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">rgr_fit</span> <span class="o">&lt;-</span>
</span></span><span class="line"><span class="cl">  <span class="nf">ranger</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">time_to_delivery</span> <span class="o">~</span> <span class="n">.,</span>
</span></span><span class="line"><span class="cl">    <span class="n">data</span> <span class="o">=</span> <span class="n">modeldata</span><span class="o">::</span><span class="n">deliveries</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">num.trees</span> <span class="o">=</span> <span class="m">1000</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">min.node.size</span> <span class="o">=</span> <span class="m">5000</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">importance</span> <span class="o">=</span> <span class="s">&#34;impurity&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">rgr_fit</span></span></span></code></pre></div></div>
<pre><code>Ranger result

Call:
 ranger(time_to_delivery ~ ., data = modeldata::deliveries, num.trees = 1000,      min.node.size = 5000, importance = &quot;impurity&quot;) 

Type:                             Regression 
Number of trees:                  1000 
Sample size:                      10012 
Number of independent variables:  30 
Mtry:                             5 
Target node size:                 5000 
Variable importance mode:         impurity 
Splitrule:                        variance 
OOB prediction error (MSE):       24.26389 
R squared (OOB):                  0.4879119 
</code></pre>
<h2 id="visualizing-the-trees">Visualizing the Trees
</h2>
<p>lorax contains methods for the <code>as.party()</code> function in the partykit package. This enables us to use all of the methods from that package. For example, <code>plot.party()</code> is an excellent visualization tool for the tree. Random forest has <em>many</em> trees and we can plot any of them:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">rgr_fit</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">as.party</span><span class="p">(</span><span class="n">tree</span> <span class="o">=</span> <span class="m">1</span><span class="p">,</span> <span class="n">data</span> <span class="o">=</span> <span class="n">modeldata</span><span class="o">::</span><span class="n">deliveries</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">plot</span><span class="p">()</span></span></span></code></pre></div></div>
<img src="https://opensource.posit.co/blog/2026-07-28_lorax/index.markdown_strict_files/figure-markdown_strict/rgr-plots-1.png" style="width:100.0%" data-fig-alt="Diagram of tree 1 from the random forest. Internal nodes show the splitting predictors with branches labeled by split values, ending in boxplots of the delivery time distribution in each terminal node." />
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">rgr_fit</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">as.party</span><span class="p">(</span><span class="n">tree</span> <span class="o">=</span> <span class="m">100</span><span class="p">,</span> <span class="n">data</span> <span class="o">=</span> <span class="n">modeldata</span><span class="o">::</span><span class="n">deliveries</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">plot</span><span class="p">()</span></span></span></code></pre></div></div>
<img src="https://opensource.posit.co/blog/2026-07-28_lorax/index.markdown_strict_files/figure-markdown_strict/rgr-plots-2.png" style="width:100.0%" data-fig-alt="Diagram of tree 100 from the random forest, in the same format but with different splits and predictors." />
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">rgr_fit</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">as.party</span><span class="p">(</span><span class="n">tree</span> <span class="o">=</span> <span class="m">1000</span><span class="p">,</span> <span class="n">data</span> <span class="o">=</span> <span class="n">modeldata</span><span class="o">::</span><span class="n">deliveries</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">plot</span><span class="p">()</span></span></span></code></pre></div></div>
<img src="https://opensource.posit.co/blog/2026-07-28_lorax/index.markdown_strict_files/figure-markdown_strict/rgr-plots-3.png" style="width:100.0%" data-fig-alt="Diagram of tree 1000 from the random forest, in the same format but with different splits and predictors." />
<h2 id="which-predictors-were-used">Which Predictors Were Used?
</h2>
<p>Since trees automatically conduct <em>feature selection</em> as the model is trained, it helps to know which ones are <em>actually</em> used by the model. The <code>active_predictors()</code> function does just that:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">rgr_vars</span> <span class="o">&lt;-</span> <span class="nf">active_predictors</span><span class="p">(</span><span class="n">rgr_fit</span><span class="p">,</span> <span class="n">tree</span> <span class="o">=</span> <span class="m">1</span><span class="o">:</span><span class="m">1000</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">rgr_vars</span></span></span></code></pre></div></div>
<pre><code># A tibble: 1,000 × 2
   active_predictors  tree
   &lt;list&gt;            &lt;int&gt;
 1 &lt;chr [4]&gt;             1
 2 &lt;chr [5]&gt;             2
 3 &lt;chr [3]&gt;             3
 4 &lt;chr [4]&gt;             4
 5 &lt;chr [4]&gt;             5
 6 &lt;chr [3]&gt;             6
 7 &lt;chr [3]&gt;             7
 8 &lt;chr [7]&gt;             8
 9 &lt;chr [3]&gt;             9
10 &lt;chr [6]&gt;            10
# ℹ 990 more rows
</code></pre>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># The column names are in a nested vector:</span>
</span></span><span class="line"><span class="cl"><span class="n">rgr_vars</span><span class="o">$</span><span class="n">active_predictors[[1]]</span></span></span></code></pre></div></div>
<pre><code>[1] &quot;day&quot;     &quot;hour&quot;    &quot;item_10&quot; &quot;item_23&quot;
</code></pre>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># We can expand the list too:</span>
</span></span><span class="line"><span class="cl"><span class="n">rgr_vars</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">unnest</span><span class="p">(</span><span class="n">cols</span> <span class="o">=</span> <span class="nf">c</span><span class="p">(</span><span class="n">active_predictors</span><span class="p">))</span></span></span></code></pre></div></div>
<pre><code># A tibble: 4,306 × 2
   active_predictors  tree
   &lt;chr&gt;             &lt;int&gt;
 1 day                   1
 2 hour                  1
 3 item_10               1
 4 item_23               1
 5 day                   2
 6 distance              2
 7 item_10               2
 8 item_12               2
 9 item_26               2
10 hour                  3
# ℹ 4,296 more rows
</code></pre>
<p>How often are predictors used?</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">rgr_vars</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">unnest</span><span class="p">(</span><span class="n">cols</span> <span class="o">=</span> <span class="nf">c</span><span class="p">(</span><span class="n">active_predictors</span><span class="p">))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">count</span><span class="p">(</span><span class="n">active_predictors</span><span class="p">)</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">arrange</span><span class="p">(</span><span class="n">active_predictors</span><span class="p">)</span></span></span></code></pre></div></div>
<pre><code># A tibble: 30 × 2
   active_predictors     n
   &lt;chr&gt;             &lt;int&gt;
 1 day                 516
 2 distance            507
 3 hour                623
 4 item_01             329
 5 item_02             131
 6 item_03              57
 7 item_04              66
 8 item_05              26
 9 item_06              92
10 item_07              91
# ℹ 20 more rows
</code></pre>
<p>How many predictors are used in each rule (on average)? A rule is the full logical statement that defines the path to the terminal nodes.</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">rgr_vars</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">mutate</span><span class="p">(</span><span class="n">num_vars</span> <span class="o">=</span> <span class="nf">map_int</span><span class="p">(</span><span class="n">active_predictors</span><span class="p">,</span> <span class="o">~</span> <span class="nf">length</span><span class="p">(</span><span class="n">.x</span><span class="p">)))</span> <span class="o">|&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">summarize</span><span class="p">(</span><span class="n">mean_num_vars</span> <span class="o">=</span> <span class="nf">mean</span><span class="p">(</span><span class="n">num_vars</span><span class="p">))</span></span></span></code></pre></div></div>
<pre><code># A tibble: 1 × 1
  mean_num_vars
          &lt;dbl&gt;
1          4.31
</code></pre>
<p>Many packages can compute <em>variable importance scores</em> for each predictor but each has a different interface. The lorax package has an accessor function to pull these from the model called <code>var_imp()</code>:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">var_imp</span><span class="p">(</span><span class="n">rgr_fit</span><span class="p">)</span></span></span></code></pre></div></div>
<pre><code># A tibble: 30 × 2
   term     estimate
   &lt;chr&gt;       &lt;dbl&gt;
 1 hour     108892. 
 2 day       16054. 
 3 distance  25689. 
 4 item_01     673. 
 5 item_02      86.3
 6 item_03      30.4
 7 item_04      43.7
 8 item_05      11.0
 9 item_06      50.1
10 item_07      55.2
# ℹ 20 more rows
</code></pre>
<h2 id="examining-rules">Examining Rules
</h2>
<p>We can also get detailed information on the model&rsquo;s rules (for each tree). Using the same ranger model fit:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">rgr_rules</span> <span class="o">&lt;-</span> <span class="nf">extract_rules</span><span class="p">(</span><span class="n">rgr_fit</span><span class="p">,</span> <span class="n">data</span> <span class="o">=</span> <span class="n">modeldata</span><span class="o">::</span><span class="n">deliveries</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">rgr_rules</span></span></span></code></pre></div></div>
<pre><code># A tibble: 5 × 3
     id rules       tree
  &lt;int&gt; &lt;list&gt;     &lt;int&gt;
1     3 &lt;language&gt;     1
2     5 &lt;language&gt;     1
3     7 &lt;language&gt;     1
4     8 &lt;language&gt;     1
5     9 &lt;language&gt;     1
</code></pre>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># With components</span>
</span></span><span class="line"><span class="cl"><span class="n">rgr_rules</span><span class="o">$</span><span class="n">rules[[1]]</span> <span class="o">|&gt;</span> <span class="nf">class</span><span class="p">()</span></span></span></code></pre></div></div>
<pre><code>[1] &quot;call&quot;
</code></pre>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">rgr_rules</span><span class="o">$</span><span class="n">rules[[1]]</span></span></span></code></pre></div></div>
<pre><code>item_23 &lt;= 0.5 &amp; hour &lt;= 14.6645
</code></pre>
<p>We can compute on these and/or use them to determine which specific data were contained in the terminal node:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">modeldata</span><span class="o">::</span><span class="n">deliveries</span> <span class="o">|&gt;</span> <span class="nf">filter</span><span class="p">(</span><span class="o">!!</span><span class="n">rgr_rules</span><span class="o">$</span><span class="n">rules[[1]]</span><span class="p">)</span></span></span></code></pre></div></div>
<pre><code># A tibble: 2,415 × 31
   time_to_delivery  hour day   distance item_01 item_02 item_03 item_04 item_05
              &lt;dbl&gt; &lt;dbl&gt; &lt;fct&gt;    &lt;dbl&gt;   &lt;int&gt;   &lt;int&gt;   &lt;int&gt;   &lt;int&gt;   &lt;int&gt;
 1             16.1  11.9 Thu       3.15       0       0       2       0       0
 2             19.6  13.0 Sat       3.35       1       0       0       1       0
 3             17.4  11.9 Sun       2.75       0       2       1       0       0
 4             18.0  12.1 Tue       2.4        0       0       0       1       0
 5             22.1  14.4 Thu       2.69       0       0       0       0       0
 6             17.6  12.9 Sat       2.47       0       1       0       0       0
 7             17.0  12.3 Sat       3.88       0       0       0       0       0
 8             19.5  13.5 Tue       3.55       0       0       0       0       0
 9             17.6  12.9 Fri       2.88       0       0       1       1       0
10             21.6  14.3 Sat       3          0       0       0       1       0
# ℹ 2,405 more rows
# ℹ 22 more variables: item_06 &lt;int&gt;, item_07 &lt;int&gt;, item_08 &lt;int&gt;,
#   item_09 &lt;int&gt;, item_10 &lt;int&gt;, item_11 &lt;int&gt;, item_12 &lt;int&gt;, item_13 &lt;int&gt;,
#   item_14 &lt;int&gt;, item_15 &lt;int&gt;, item_16 &lt;int&gt;, item_17 &lt;int&gt;, item_18 &lt;int&gt;,
#   item_19 &lt;int&gt;, item_20 &lt;int&gt;, item_21 &lt;int&gt;, item_22 &lt;int&gt;, item_23 &lt;int&gt;,
#   item_24 &lt;int&gt;, item_25 &lt;int&gt;, item_26 &lt;int&gt;, item_27 &lt;int&gt;
</code></pre>
<h2 id="a-list-of-methods">A List of Methods
</h2>
<p>Here are the details of which models and methods are supported in the first CRAN version:</p>
<table>
  <thead>
      <tr>
          <th style="text-align: left">class</th>
          <th style="text-align: left">var_imp</th>
          <th style="text-align: left">active_predictors</th>
          <th style="text-align: left">as.party</th>
          <th style="text-align: left">extract_rules</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: left">bart</td>
          <td style="text-align: left">n/a</td>
          <td style="text-align: left">✔</td>
          <td style="text-align: left">✔</td>
          <td style="text-align: left">✔</td>
      </tr>
      <tr>
          <td style="text-align: left">C5.0</td>
          <td style="text-align: left">n/a</td>
          <td style="text-align: left">✔</td>
          <td style="text-align: left">✔</td>
          <td style="text-align: left">✔</td>
      </tr>
      <tr>
          <td style="text-align: left">cforest</td>
          <td style="text-align: left">✔</td>
          <td style="text-align: left">✔</td>
          <td style="text-align: left">n/a</td>
          <td style="text-align: left">✔</td>
      </tr>
      <tr>
          <td style="text-align: left">cubist</td>
          <td style="text-align: left">✖</td>
          <td style="text-align: left">✔</td>
          <td style="text-align: left">✖</td>
          <td style="text-align: left">✔</td>
      </tr>
      <tr>
          <td style="text-align: left">grf</td>
          <td style="text-align: left">✔</td>
          <td style="text-align: left">✔</td>
          <td style="text-align: left">✔</td>
          <td style="text-align: left">✔</td>
      </tr>
      <tr>
          <td style="text-align: left">lgb.Booster</td>
          <td style="text-align: left">✔</td>
          <td style="text-align: left">✔</td>
          <td style="text-align: left">✔</td>
          <td style="text-align: left">✔</td>
      </tr>
      <tr>
          <td style="text-align: left">ObliqueForest</td>
          <td style="text-align: left">✔</td>
          <td style="text-align: left">✔</td>
          <td style="text-align: left">✖</td>
          <td style="text-align: left">✔</td>
      </tr>
      <tr>
          <td style="text-align: left">party</td>
          <td style="text-align: left">✔</td>
          <td style="text-align: left">✔</td>
          <td style="text-align: left">n/a</td>
          <td style="text-align: left">✔</td>
      </tr>
      <tr>
          <td style="text-align: left">randomForest</td>
          <td style="text-align: left">✔</td>
          <td style="text-align: left">✔</td>
          <td style="text-align: left">✔</td>
          <td style="text-align: left">✔</td>
      </tr>
      <tr>
          <td style="text-align: left">ranger</td>
          <td style="text-align: left">✔</td>
          <td style="text-align: left">✔</td>
          <td style="text-align: left">✔</td>
          <td style="text-align: left">✔</td>
      </tr>
      <tr>
          <td style="text-align: left">rpart</td>
          <td style="text-align: left">✔</td>
          <td style="text-align: left">✔</td>
          <td style="text-align: left">n/a</td>
          <td style="text-align: left">✔</td>
      </tr>
      <tr>
          <td style="text-align: left">xgb.Booster</td>
          <td style="text-align: left">✔</td>
          <td style="text-align: left">✔</td>
          <td style="text-align: left">✔</td>
          <td style="text-align: left">✔</td>
      </tr>
  </tbody>
</table>
<p>Note that <code>as.party.rpart()</code> is in the partykit package and that cforest is made out of party objects.</p>
<h2 id="whats-next">What&rsquo;s Next?
</h2>
<p>We&rsquo;ll work on adding <a href="https://catboost.ai/" target="_blank" rel="noopener">CatBoost</a> models to the list of supported methods. Please <a href="https://github.com/tidymodels/lorax/issues" target="_blank" rel="noopener">add an issue</a> if there are other aspects of trees that should be quantified in these models.</p>
]]></description>
      <enclosure url="https://opensource.posit.co/blog/2026-07-28_lorax/featured.png" length="511489" type="image/png" />
    </item>
    <item>
      <title>ir 0.1.0: self-describing R scripts and Quarto documents</title>
      <link>https://opensource.posit.co/blog/2026-07-23_ir-0-1-0/</link>
      <pubDate>Thu, 23 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://opensource.posit.co/blog/2026-07-23_ir-0-1-0/</guid>
      <dc:creator>Tomasz Kalinowski</dc:creator>
      <dc:creator>Christophe Dervieux</dc:creator>
      <dc:creator>Charlie Gao</dc:creator><description><![CDATA[<style>
.chroma code[data-lang="r"] .c1 {
  font-style: normal;
}
</style>
<p>Today we are announcing the first public release of <code>ir</code>, a small
command-line tool that runs R scripts and renders Quarto documents using
runtime requirements declared in the file itself.</p>
<p><code>ir</code> is for one-file workflows that do not quite need a project but
still need to be easy to share and rerun later. Simply put the package
requirements, and optionally the R version, next to the code. When you
render or execute the file, <code>ir</code> resolves the requirements, prepares
cached package libraries, and launches R or Quarto with a runtime ready
to use.</p>
<p>The interface is inspired by
<a href="https://peps.python.org/pep-0723/" target="_blank" rel="noopener">PEP 723</a> and
<a href="https://docs.astral.sh/uv/" target="_blank" rel="noopener"><code>uv run --script</code></a>. A script can carry
enough metadata to describe its runtime, and the runner can resolve that
runtime into a cached environment on demand. <code>ir</code> brings that pattern to
R scripts and Quarto documents, using <code>pak</code>, <code>renv</code>, and <code>rig</code> on the R
side, and <code>reticulate</code>&rsquo;s uv-backed helper when Python is part of the
runtime.</p>
<p><code>ir</code> focuses on two workflows:</p>
<ul>
<li>running or rendering self-describing scripts and documents <br>
(<code>ir run</code>, <code>ir render</code>)</li>
<li>running or installing command-line tools distributed through R
packages <br>
(<code>rx</code>, <code>ir tool install</code>)</li>
</ul>
<h2 id="why-ir">Why <code>ir</code>?
</h2>
<p>R scripts often begin as small, local utilities: a report, a data pull,
a model-training or evaluation run, a quick diagnostic, or an example
shared with a colleague. Over time, the script can become important, but
the setup still lives somewhere else: in a README, in a shell history,
in a project library, or in the author&rsquo;s current R installation.</p>
<p><code>ir</code> makes the runtime specification part of the source file. That means
a script can say, directly:</p>
<ul>
<li>which packages it needs</li>
<li>which R should run it, when that needs to be explicit</li>
<li>whether user libraries should be visible</li>
<li>whether CRAN packages should be resolved as of a specific date</li>
</ul>
<p>This should help you rerun the script reliably at a later date. Keeping
the metadata in the file makes it less likely to be lost or fall out of
sync with the code.</p>
<h2 id="how-ir-fits-with-existing-tools">How <code>ir</code> fits with existing tools
</h2>
<p><code>ir</code> sits alongside the R tools people already use and builds on several
of them directly:</p>
<ul>
<li><a href="https://github.com/r-lib/rig" target="_blank" rel="noopener"><code>rig</code></a> installs, removes, and switches
between R versions on macOS, Windows, and Linux. <code>ir</code> calls <code>rig</code> when
a file requests a specific R version, or when date-only
<code>exclude-newer</code> needs to select the latest R minor version available
on that date. <code>rig</code> is optional for files that only declare packages.</li>
<li><a href="https://pak.r-lib.org/" target="_blank" rel="noopener"><code>pak</code></a> is a fast package installer with a
built-in solver. <code>ir</code> uses <code>pak</code> to resolve the dependency graph from
a file&rsquo;s declared packages and fetch them from the appropriate
repositories. <code>pak</code> is bootstrapped automatically on first use, so you
do not need to install it separately.</li>
<li><a href="https://rstudio.github.io/renv/" target="_blank" rel="noopener"><code>renv</code></a> gives R projects isolated
package libraries and lockfiles. <code>ir</code> uses <code>renv</code>&rsquo;s global package
cache to assemble reusable libraries without creating a <code>renv</code> project
or lockfile.</li>
</ul>
<p><code>ir</code> builds on that stack for non-project workflows: resolving the
runtime for a self-describing script or Quarto document, and running or
installing command-line entry points distributed by R packages.</p>
<h2 id="a-self-describing-r-script">A self-describing R script
</h2>
<p>Here is a complete script:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1">#!/usr/bin/env -S ir run</span>
</span></span><span class="line"><span class="cl"><span class="c1">#| packages:</span>
</span></span><span class="line"><span class="cl"><span class="c1">#|   - dplyr&gt;=1.0</span>
</span></span><span class="line"><span class="cl"><span class="c1">#|   - tidyr</span>
</span></span><span class="line"><span class="cl"><span class="c1">#| isolated: true</span>
</span></span><span class="line"><span class="cl"><span class="c1">#| exclude-newer: &#34;2024-01-15&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">dplyr</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">tidyr</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">mtcars</span> <span class="o">|&gt;</span> <span class="nf">count</span><span class="p">(</span><span class="n">cyl</span><span class="p">,</span> <span class="n">gear</span><span class="p">)</span> <span class="o">|&gt;</span> <span class="nf">pivot_wider</span><span class="p">(</span><span class="n">names_from</span> <span class="o">=</span> <span class="n">gear</span><span class="p">,</span> <span class="n">values_from</span> <span class="o">=</span> <span class="n">n</span><span class="p">)</span></span></span></code></pre></div></div>
<p>Run it with:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> ir run script.R
</span></span></code></pre></div></div>
<p>Or, on macOS and Linux, make it executable and run it directly:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> chmod +x script.R
</span></span><span class="line"><span class="cl"><span class="gp">$</span> ./script.R
</span></span></code></pre></div></div>
<p>The metadata block is YAML written in <code>#|</code> comments after an optional
shebang. <code>ir</code> reads that metadata, resolves the declared packages with
<code>pak</code>, materializes a package library with <code>renv</code>, and starts R with the
resolved library at the front of <code>.libPaths()</code>.</p>
<p>By default, user libraries remain visible as a fallback. Add
<code>isolated: true</code> in the file, or use <code>--isolated</code> at the command line,
to run without the user library.</p>
<h2 id="running-r-package-tools-with-rx">Running R package tools with <code>rx</code>
</h2>
<p>The <code>ir</code> release also includes <code>rx</code>, a short alias for <code>ir tool run</code>
that runs executables provided by R packages.</p>
<p>Package authors can expose command-line entry points through standard
package subdirectories such as <a href="https://cran.r-project.org/doc/manuals/r-release/R-exts.html#Package-subdirectories-1" target="_blank" rel="noopener"><code>exec/</code> and <code>bin/</code></a>. Files in <code>exec/</code> can be regular <code>Rscript</code> files,
<a href="https://github.com/r-lib/Rapp" target="_blank" rel="noopener"><code>Rapp</code></a> apps, or direct executable
scripts. <code>rx</code> resolves the package, finds the requested executable, and
runs it in an isolated library.</p>
<p>For example, this resolves the <code>btw</code> CLI from the <code>btw</code> R package on
demand and runs <code>btw --help</code>:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> rx btw --help
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="gp">#</span> same as:
</span></span><span class="line"><span class="cl"><span class="gp">$</span> ir tool run btw --help
</span></span></code></pre></div></div>
<p>For tools you use regularly, install them with <code>ir tool install</code>:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">#</span> run once
</span></span><span class="line"><span class="cl"><span class="gp">$</span> ir tool install btw
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="gp">#</span> now you only need
</span></span><span class="line"><span class="cl"><span class="gp">$</span> btw --help
</span></span></code></pre></div></div>
<h2 id="cached-by-design">Cached by design
</h2>
<p>The first run of a new dependency set does the normal work of resolving
and installing packages. Later runs reuse cached resolutions and
content-addressed package libraries when the same requirements are seen
again.</p>
<p>That makes <code>ir</code> useful for both one-off and repeated command-line work.
You can run a script, run an inline expression, render a report, or
launch a package-provided executable without creating a project
directory just to hold the dependency state.</p>
<p><code>ir</code> also bootstraps its own resolver tooling on first use, so you do
not need to pre-install <code>pak</code> or <code>renv</code>.</p>
<h2 id="reproducibility-without-a-project">Reproducibility without a project
</h2>
<p>For R scripts that need more explicit reproducibility, <code>exclude-newer</code>
is usually the first thing to reach for:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">exclude-newer</span><span class="p">:</span><span class="w"> </span><span class="ld">2024-01-15</span></span></span></code></pre></div></div>
<p>You can also provide the same date at the command line:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> ir run --exclude-newer 2024-01-15 script.R
</span></span></code></pre></div></div>
<p>This resolves packages from the Posit Package Manager snapshot for that
date. When no other R selector is set, the same date also tells <code>ir</code> to
select the latest R minor version available on that date. If you were
writing with the current release of R and current CRAN packages, the
date alone is usually enough.</p>
<p>Use <code>r-version</code> when the script really needs a specific installed R
version or version range. This selection uses
<a href="https://github.com/r-lib/rig" target="_blank" rel="noopener"><code>rig</code></a>:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">r-version</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;4.3&#34;</span></span></span></code></pre></div></div>
<p>Together, these options let a file carry the important parts of its
runtime requirements without needing a surrounding project. For
reproducibility, most files should need only a list of packages and a
date.</p>
<h2 id="quarto-documents-too">Quarto documents too
</h2>
<p><code>ir</code> uses the same metadata model for Quarto documents. Put package
metadata under an <code>ir:</code> key in the document YAML:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nn">---</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">title</span><span class="p">:</span><span class="w"> </span><span class="l">My report</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">ir</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">packages</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">dplyr&gt;=1.0</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">gt@1.0</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">isolated</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">exclude-newer</span><span class="p">:</span><span class="w"> </span><span class="ld">2025-05-15</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nn">---</span></span></span></code></pre></div></div>
<p>Then render with:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> ir render report.qmd
</span></span><span class="line"><span class="cl"><span class="gp">$</span> ir render report.qmd --to pdf
</span></span></code></pre></div></div>
<p>When <code>ir</code> selects an R executable using <code>--r-version</code>, frontmatter
<code>ir.r-version</code>, or date-only <code>exclude-newer</code>, it sets <a href="https://quarto.org/docs/advanced/environment-vars.html#variables-quarto-inspects" target="_blank" rel="noopener"><code>QUARTO_R</code></a> so Quarto renders with that R. <code>ir</code> also seeds <code>rmarkdown</code>
automatically for knitr-based renders unless you declare it yourself.</p>
<h2 id="python-environments-too">Python environments too
</h2>
<p>Some R scripts and Quarto documents also need Python. In an R script,
declare the R packages and Python requirements in the same metadata
block:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1">#!/usr/bin/env -S ir run</span>
</span></span><span class="line"><span class="cl"><span class="c1">#| packages:</span>
</span></span><span class="line"><span class="cl"><span class="c1">#|   - reticulate</span>
</span></span><span class="line"><span class="cl"><span class="c1">#| python-packages:</span>
</span></span><span class="line"><span class="cl"><span class="c1">#|   - pandas</span>
</span></span><span class="line"><span class="cl"><span class="c1">#|   - matplotlib</span>
</span></span><span class="line"><span class="cl"><span class="c1">#| python-version: &#34;3.11&#34;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#| exclude-newer: &#34;2026-06-01&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">reticulate</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">pd</span> <span class="o">&lt;-</span> <span class="nf">import</span><span class="p">(</span><span class="s">&#34;pandas&#34;</span><span class="p">)</span></span></span></code></pre></div></div>
<p><code>ir</code> creates the environment with <code>reticulate</code>&rsquo;s uv-backed environment
helper, sets <code>RETICULATE_PYTHON</code>, and activates the environment for
subprocesses. Declare <code>reticulate</code> under <code>packages</code> when the R script
loads <code>reticulate</code>.</p>
<p>For Quarto, put Python metadata under the document&rsquo;s <code>ir:</code> key. A knitr
document that uses reticulate can mix R and Python requirements:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nn">---</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">title</span><span class="p">:</span><span class="w"> </span><span class="l">My report</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">ir</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">packages</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">reticulate</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">python-packages</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">pandas</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">exclude-newer</span><span class="p">:</span><span class="w"> </span><span class="ld">2025-01-01</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nn">---</span></span></span></code></pre></div></div>
<p>For a Quarto document that uses the Jupyter engine, the <code>ir:</code> metadata
can contain only Python requirements:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nn">---</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">title</span><span class="p">:</span><span class="w"> </span><span class="l">My notebook</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">jupyter</span><span class="p">:</span><span class="w"> </span><span class="l">python3</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">ir</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">python-packages</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">matplotlib</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">pandas</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">python-version</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;3.11&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nn">---</span></span></span></code></pre></div></div>
<p>For Quarto renders, <code>ir</code> injects <code>jupyter</code> into the Python environment,
passes the resolved interpreter to Quarto with <code>QUARTO_PYTHON</code>, and also
sets <code>RETICULATE_PYTHON</code> so documents that use reticulate see the same
interpreter. If the document uses the knitr engine and contains Python
chunks, <code>ir</code> automatically adds <code>reticulate</code> to the R package manifest.</p>
<p>When Python metadata is present, <code>exclude-newer</code> is also used for Python
environment resolution unless <code>python-exclude-newer</code> is set. Use
<code>python-exclude-newer</code> when Python packages should use a different
snapshot date from R packages.</p>
<h2 id="install-ir">Install <code>ir</code>
</h2>
<p>Install a pre-built binary on Linux or macOS:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> curl -fsSL https://raw.githubusercontent.com/r-lib/ir/main/scripts/install.sh <span class="p">|</span> sh
</span></span></code></pre></div></div>
<p>Install on Windows PowerShell:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">&gt;</span> irm https://raw.githubusercontent.com/r-lib/ir/main/scripts/install.ps1 <span class="p">|</span> iex
</span></span></code></pre></div></div>
<p>The installers download the latest GitHub release and install both <code>ir</code>
and <code>rx</code>. You can also download release artifacts from the
<a href="https://github.com/r-lib/ir/releases" target="_blank" rel="noopener">GitHub releases</a> page or with
<code>gh release download</code>.</p>
<p>You will also need <code>R</code> / <code>Rscript</code>; <code>rig</code> is required when selecting R
by version or by date-only <code>exclude-newer</code>, and Quarto is required when
rendering Quarto sources.</p>
<h2 id="learn-more">Learn more
</h2>
<p>The project is open source under the MIT license. To get started:</p>
<ul>
<li>Read the documentation: <a href="https://r-lib.github.io/ir/" target="_blank" rel="noopener">https://r-lib.github.io/ir/</a></li>
<li>Browse the source: <a href="https://github.com/r-lib/ir" target="_blank" rel="noopener">https://github.com/r-lib/ir</a></li>
<li>Open an issue: <a href="https://github.com/r-lib/ir/issues" target="_blank" rel="noopener">https://github.com/r-lib/ir/issues</a></li>
</ul>
<p>This is a first public release, and feedback is especially useful now.
If you try <code>ir</code> on your own scripts or Quarto documents, we would like
to hear which workflows feel natural, where the metadata model needs
more room, and which command-line edges still need smoothing.</p>
]]></description>
      <enclosure url="https://opensource.posit.co/blog/2026-07-23_ir-0-1-0/terrarium.png" length="2120322" type="image/png" />
    </item>
    <item>
      <title>AI Newsletter: LLMs often miss subtle visual artifacts in data visualizations</title>
      <link>https://opensource.posit.co/blog/2026-07-17_ai-newsletter/</link>
      <pubDate>Fri, 17 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://opensource.posit.co/blog/2026-07-17_ai-newsletter/</guid>
      <dc:creator>Sara Altman</dc:creator>
      <dc:creator>Simon Couch</dc:creator><description><![CDATA[<p>Imagine that you receive some patient data and load it into R or Python for the first time. You make a couple plots to get a sense of the data before coming across this one:</p>
<img src="https://opensource.posit.co/blog/2026-07-17_ai-newsletter/index.markdown_strict_files/figure-markdown_strict/artifact-plot-1.png" data-fig-align="center" width="768" />
<p>Huh. It mostly looks normal, except there&rsquo;s a few points perfectly aligned with what looks to be a &ldquo;fitted&rdquo; line. You dig into it a bit more, and realize that the rows from one study site have their cholesterol values imputed. You set them to <code>NA</code> and go along your way.</p>
<p>Would today&rsquo;s frontier LLMs catch such an oddity? We designed <a href="https://github.com/posit-dev/bluffbench2" target="_blank" rel="noopener">an LLM evaluation</a> to help us answer this question. As it turns out, LLMs mostly miss these sorts of artifacts:</p>
<img src="https://opensource.posit.co/blog/2026-07-17_ai-newsletter/index.markdown_strict_files/figure-markdown_strict/results-plot-1.png" data-fig-align="center" data-fig-alt="A bar plot showing scores for several frontier models. The two leaders, Gemini 3.5 Flash and Claude Fable 5, score in the mid teens. Models from OpenAI cluster at the bottom, never eclipsing 10%." width="768" />
<p>During exploratory or open-ended data analysis, Posit assistant <a href="https://opensource.posit.co/blog/2026-06-08_comparing-posit-assistant-and-claude-code/#specialized-data-analysis-capabilities" target="_blank" rel="noopener">&ldquo;only runs a few bits of code at a time, then summarizes what it found and suggests next steps&rdquo;</a>. This is motivated by our stance that, for now, a data scientist should mostly keep pace with and understand what the agent is doing when analyzing data. This stance was initially informed by our observation that last year&rsquo;s frontier models <a href="https://posit.co/blog/introducing-bluffbench" target="_blank" rel="noopener">tended to see what they expected to see</a> when visualizing data. While <a href="https://opensource.posit.co/blog/2026-06-19_ai-newsletter/" target="_blank" rel="noopener">LLMs have since become much better at interpreting counterintuitive plots</a>, bluffbench2 shows they still lag behind human data scientists in interpreting data visualizations. As such, we are still cautious on the prospect of highly autonomous data agents.</p>
<h2 id="how-the-eval-works">How the eval works
</h2>
<p>The eval harness is a relatively generic coding agent harness, similar to that of Claude Code or Posit Assistant. The agent has a tool to run R code in a persistent REPL and some vague prompting about data analysis:</p>
<blockquote>
<p>You are an AI assistant embedded in the user&rsquo;s data science IDE. You can read and modify files in the user&rsquo;s workspace and execute R code in their active session, including rendering plots. Prioritize correctness and clear communication&hellip;</p>
</blockquote>
<p>In each sample, the agent first carries out a few &ldquo;lull&rdquo; turns, making a couple plots and tables unrelated to the eval. Short user messages like &ldquo;load in the csv in this folder&rdquo; are decorated with &ldquo;System Reminders&rdquo; and other noise like that injected by popular agent harnesses.</p>
<div style="display: flex; flex-direction: column; gap: 8px; padding: 20px; max-width: 100%; margin: 20px auto;">
<div style="align-self: flex-end; background-color: #e8f3fc; padding: 12px 18px; border-radius: 18px 18px 4px 18px; max-width: 70%;">
take a look at <code>dat</code> in my env
</div>
<div style="align-self: flex-start; background-color: white; padding: 12px 18px; border-radius: 18px 18px 18px 4px; max-width: 70%; border: 1px solid #e0e0e0;">
<em>Tool: Run R code</em>
</div>
<div style="align-self: flex-end; background-color: #e8f3fc; padding: 12px 18px; border-radius: 18px 18px 4px 18px; max-width: 70%;">
<em>Tool result</em>
</div>
<div style="align-self: flex-start; background-color: white; padding: 12px 18px; border-radius: 18px 18px 18px 4px; max-width: 70%; border: 1px solid #e0e0e0;">
Looks like <code>dat</code> is a data frame of...
</div>
<div style="align-self: flex-end; background-color: #e8f3fc; padding: 12px 18px; border-radius: 18px 18px 4px 18px; max-width: 70%;">
<span style="display: block; margin-bottom: 8px; font-family: monospace; font-size: 0.8em; opacity: 0.55;">&lt;system-reminder&gt;<br>Your to-do list is currently empty. If you are working on tasks that would benefit from tracking progress, consider creating to-dos. This is just a gentle reminder - ignore if not applicable.<br>&lt;/system-reminder&gt;</span>
summarize <code>$cholesterol</code>
</div>
<div style="align-self: flex-start; background-color: white; padding: 12px 18px; border-radius: 18px 18px 18px 4px; max-width: 70%; border: 1px solid #e0e0e0;">
<em>Tool: Run R code</em>
</div>
</div>
<p>After a few turns, the agent is asked to produce a data visualization that includes a subtle visual artifact that could feasibly result from a real data-generating process. The artifacts span a range of realistic data quality issues: stuck sensors, bad joins, points imputed onto a line, swapped columns, pseudoreplication, differing units, etc.</p>
<div style="display: flex; flex-direction: column; gap: 8px; padding: 20px; max-width: 100%; margin: 20px auto;">
<div style="align-self: flex-end; background-color: #e8f3fc; padding: 12px 18px; border-radius: 18px 18px 4px 18px; max-width: 70%;">
plot bmi vs cholesterol
</div>
<div style="align-self: flex-start; background-color: white; padding: 12px 18px; border-radius: 18px 18px 18px 4px; max-width: 70%; border: 1px solid #e0e0e0;">
<em>Tool: Run R code</em>
</div>
<div style="align-self: flex-end; background-color: #e8f3fc; padding: 12px 18px; border-radius: 18px 18px 4px 18px; max-width: 70%;">
<img src="https://opensource.posit.co/blog/2026-07-17_ai-newsletter/images/labs-thumb.png" width="220" style="border-radius: 12px; display: block;">
</div>
</div>
<p>If the agent mentions the artifact in its follow-up response, it receives a full point. If the agent does not mention the artifact, it can also receive a half point by mentioning it in response to a follow-up user message along the lines of &ldquo;what do you see in the plot?&rdquo; If the agent never mentions the artifact, it is graded as incorrect.</p>
<h2 id="designing-the-eval">Designing the eval
</h2>
<p>Once we understood the mechanism behind bluffbench, implementing the eval was relatively straightforward. bluffbench demonstrates the degree to which an LLM will ignore evidence shown in a plot in favor of its expectations. So, to implement a given sample, we&rsquo;d just think of some situation that would elicit a strong prior and then subvert it. For example, a dataset called <code>doug_firs</code> with variables <code>height</code> and <code>circumference</code>; one might expect that, as height increases, so does circumference. So, instead, we did a transformation under the hood that made the relationship parabolic.</p>
<img src="https://opensource.posit.co/blog/2026-07-17_ai-newsletter/index.markdown_strict_files/figure-markdown_strict/trees-plot-1.png" data-fig-align="center" data-fig-alt="Two scatterplots side by side, both with circumference on the x axis and height on the y axis. The left, labeled &#39;Original Plot&#39;, shows height rising with circumference, a positive trend. The right, labeled &#39;Tampered Plot&#39;, shows height rising then falling as circumference increases, an inverted-U shape." width="768" />
<p>A year ago, triggering this prior was enough to frequently &rsquo;trick&rsquo; the current frontier LLMs.</p>
<p>Slipping a plotted artifact past today&rsquo;s LLMs is much harder. Any human could ace bluffbench, but only an attentive data analyst would excel at bluffbench2.</p>
<p>In our early work on a successor to bluffbench, we started off with trying to elicit priors in the same way as bluffbench did, but in more realistic, longer-context scenarios. We were surprised to find that the same mechanism broadly doesn&rsquo;t seem to trick today&rsquo;s models even in these more realistic settings.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> We then tried a &lsquo;reverse bluffbench&rsquo;, where we let the model being evaluated in on the trick, asking it to carry out the transformation itself and then look at the plotted result which was tampered with to show the original relationship. We anticipated that this stronger prior (&ldquo;I did a thing with an obvious effect&rdquo;) might cause the models to miss the (re)manipulation, but models reliably noted that the plot looked as if it hadn&rsquo;t been manipulated.</p>
<p>As such, there isn&rsquo;t a similar &rsquo;trick&rsquo; in bluffbench2 per se. The transcripts read like relatively normal data analysis sessions and the plotted artifacts are designed to plausibly result from real data-generating processes. Instead, the eval elicits 1) the &lsquo;shape&rsquo; of LLMs&rsquo; vision being different than humans&rsquo; and 2) the model&rsquo;s tendencies to perform progress, simulating a data analysis moving along smoothly.</p>
<p>Today&rsquo;s frontier models are in the mid-teens at best; the top scores belong to Claude Fable 5 and Gemini 3.5 Flash at 16%. That said, we&rsquo;d caution folks from interpreting the current scores on this eval as &lsquo;LLMs don&rsquo;t see plots well.&rsquo; The plotted artifacts are actually quite subtle, and when they&rsquo;re made even a bit more marked, models tend to call them out consistently.</p>
<p>For example, the previous version of the scatterplot had a slightly more dense cluster of points:</p>
<div class="panel-tabset">
<ul id="tabset-1" class="panel-tabset-tabby">
<li><a data-tabby-default href="#tabset-1-1">Previous</a></li>
<li><a href="#tabset-1-2">Current</a></li>
</ul>
<div id="tabset-1-1">
<img src="https://opensource.posit.co/blog/2026-07-17_ai-newsletter/index.markdown_strict_files/figure-markdown_strict/previous-labs-plot-1.png" data-fig-align="center" data-fig-alt="A scatterplot of BMI versus cholesterol with a dense run of roughly fifty points falling exactly on a straight line through the noisy cloud." width="768" />
</div>
<div id="tabset-1-2">
<img src="https://opensource.posit.co/blog/2026-07-17_ai-newsletter/index.markdown_strict_files/figure-markdown_strict/current-labs-plot-1.png" data-fig-align="center" data-fig-alt="A scatterplot of BMI versus cholesterol with a sparse run of about thirty points falling exactly on a straight line through the noisy cloud, subtler than the previous version." width="768" />
</div>
</div>
<p>Opus 4.8 (medium) consistently got this sample right in the previous iteration.</p>
<div class="callout callout-note" role="note" aria-label="Note">
<div class="callout-header">
<span class="callout-title">Note</span>
</div>
<div class="callout-body">
<p>The fact that this was the case&mdash;that models would call out more marked artifacts reliably&mdash;gave us confidence that our grading setup was reasonable. In other words, it does indeed seem like models are struggling with these tasks because their vision is not capable enough to &lsquo;see&rsquo; the plotted artifact rather than a behavioral tendency to not mention those artifacts when they do see them.</p>
</div>
</div>
<h2 id="exploring-the-evals-results">Exploring the eval&rsquo;s results
</h2>
<p>At least for now, there&rsquo;s a loosely linear relationship between the cost to run the eval and the resulting score:</p>
<img src="https://opensource.posit.co/blog/2026-07-17_ai-newsletter/index.markdown_strict_files/figure-markdown_strict/cost-plot-1.png" data-fig-align="center" data-fig-alt="A scatterplot of score against total cost for each frontier model, colored by lab. The two leaders, Gemini 3.5 Flash and Claude Fable 5, sit highest at around the mid teens, while the OpenAI models sit low regardless of cost. Higher spend does not buy a higher score." width="768" />
<div class="callout callout-note" role="note" aria-label="Note">
<div class="callout-header">
<span class="callout-title">Note</span>
</div>
<div class="callout-body">
<p>Given that Gemini 3.5 Flash is so much cheaper than Claude Fable 5 per-token ($1.50/$9 per mTok I/O vs. $10/$50), it&rsquo;s surprising that the eval was so expensive to run for Gemini 3.5 Flash. This is primarily driven by cache (in)efficiency; the harness is implemented against Gemini&rsquo;s <code>generateContent</code> API, which makes it difficult to make use of discounted cached input pricing compared to Anthropic and OpenAI&rsquo;s APIs. Implementing and switching to Gemini&rsquo;s newer Interactions API would push the Flash 3.5 point to the left.</p>
</div>
</div>
<p>One of the most interesting learnings from examining the logs is a behavioral one. Even though we never request that LLMs introduce modeled results to plots, like fitted lines and confidence intervals with <code>geom_smooth(method = &quot;lm&quot;, se = TRUE)</code>, they sometimes do so anyway. For example:</p>
<img src="https://opensource.posit.co/blog/2026-07-17_ai-newsletter/index.markdown_strict_files/figure-markdown_strict/smooth-example-1.png" data-fig-align="center" data-fig-alt="The BMI versus cholesterol scatterplot with a straight fitted line and a shaded confidence-interval ribbon laid over the points, an overlay the model added on its own." width="768" />
<p>In general, adding modeled results to data visualizations without first looking at data is bad practice; it makes it hard to see the data itself. In the eval, adding a modeled result like this seems to substantially lower the chances that the model will notice the plotted artifact:</p>
<img src="https://opensource.posit.co/blog/2026-07-17_ai-newsletter/index.markdown_strict_files/figure-markdown_strict/smooth-plot-1.png" data-fig-align="center" data-fig-alt="A dumbbell plot, one row per model, comparing accuracy on artifact plots the model drew with a geom_smooth() overlay versus without. For nearly every model the &#39;with overlay&#39; point sits well to the left of the &#39;without&#39; point; Claude Fable 5 falls from about a quarter correct to zero, and Gemini 3.5 Flash from about a quarter to under a tenth." width="768" />
<h2 id="more-bluffbench">More bluffbench
</h2>
<p>If you&rsquo;d like to learn more about the bluffbench set of evals, take a look at these past posts:</p>
<ul>
<li><a href="https://posit.co/blog/introducing-bluffbench" target="_blank" rel="noopener"><strong>Introducing bluffbench</strong></a>: Writeup of the the original eval.</li>
<li><a href="https://posit.co/blog/llm-plot-interpretation" target="_blank" rel="noopener"><strong>LLMs interpret plots well, until expectations interfere</strong></a>: In-depth post on why models at the time didn&rsquo;t perform well on bluffbench, as well as various interventions we tried to improve performance.</li>
<li><a href="https://opensource.posit.co/blog/2026-06-19_ai-newsletter/" target="_blank" rel="noopener"><strong>LLMs are getting much better at interpreting counterintuitive plots</strong></a>: In spring 2026, bluffbench scores suddenly jumped as models improved.</li>
<li><a href="https://skaltman.github.io/scipy-2026/" target="_blank" rel="noopener"><em><strong>It&rsquo;s (still) very bad to be wrong</strong></em></a>: Slides from our recent SciPy 2026 talk on building agents for correct, transparent, and reproducible data analysis in light of the bluffbench results.</li>
</ul>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>This somewhat alleviated the fear that models had just memorized the bluffbench eval setup, mentioned in <a href="https://opensource.posit.co/blog/2026-06-19_ai-newsletter/" target="_blank" rel="noopener">our previous post</a>.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></description>
      <enclosure url="https://opensource.posit.co/blog/2026-07-17_ai-newsletter/images/hero.png" length="114420" type="image/png" />
    </item>
    <item>
      <title>Tips for managing your Python &amp; R environments in Positron</title>
      <link>https://opensource.posit.co/blog/2026-07-15_positron-environment-management-tips/</link>
      <pubDate>Wed, 15 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://opensource.posit.co/blog/2026-07-15_positron-environment-management-tips/</guid>
      <dc:creator>Cindy Tong</dc:creator>
      <dc:creator>Brice Stacey</dc:creator><description><![CDATA[<div class="callout callout-note" role="note" aria-label="Note">
<div class="callout-header">
<span class="callout-title">Note</span>
</div>
<div class="callout-body">
<p><a href="https://positron.posit.co" target="_blank" rel="noopener">Positron</a> is the Posit next-generation IDE for data science. Positron is an extensible, polyglot tool for exploring data and reproducible authoring in Python, R, and more.</p>
</div>
</div>
<p>If you work across Python and R or juggle multiple projects with different dependency needs, environment management is probably one of the most challenging parts of your workflow. <a href="https://positron.posit.co/" target="_blank" rel="noopener">Positron</a> comes with several out-of-the-box ways to help simplify environment management. Here are a few tips to streamline your workflow.</p>
<h2 id="1-understand-how-positron-discovers-your-environment">1: Understand how Positron discovers your environment
</h2>
<p>Positron does not just look at your system PATH. For Python, it actively discovers venv, uv, pyenv, and conda environments. If Positron is not seeing your project&rsquo;s virtual environment, you can add custom search locations via the <a href="positron://settings/python.interpreters.include"><code>python.interpreters.include</code></a> setting, or trigger a manual rescan with <em>Interpreter: Discover All Interpreters</em>. Learn more about <a href="https://positron.posit.co/python-installations.html#python-installation-discovery" target="_blank" rel="noopener">Python discovery in the Positron documentation</a>.</p>
<p>For R, discovery works differently. Positron consults various sources to build the list of R interpreters. These include your PATH, R root folders based on specific operating systems, well-known executable locations, and on Windows the registry. You can customize your R discovery through a few settings including <a href="positron://settings/positron.r.customRootFolders"><code>positron.r.customRootFolders</code></a> and <a href="positron://settings/positron.r.customBinaries"><code>positron.r.customBinaries</code></a>. Learn more about <a href="https://positron.posit.co/r-installations.html#customizing-r-discovery" target="_blank" rel="noopener">R discovery in the Positron documentation</a>.</p>
<h2 id="2-use-the-interpreter-selector">2. Use the Interpreter Selector
</h2>
<p>To begin your first session, click &ldquo;Start Session&rdquo; in the top right corner and select your preferred R or Python interpreter. Positron can run multiple R and Python interpreter sessions at once, but only one is ever the active session at a given moment. The Interpreter Selector always shows you the active session and its status (idle, busy, or shut down) and you can use it to switch between or start additional sessions.</p>
<img src="https://opensource.posit.co/blog/2026-07-15_positron-environment-management-tips/active-interpreter-session.png" width="100%" data-fig-align="center" data-fig-alt="Use the Interpreter Selector to change your active session" />
<h2 id="3-install-python-with-uv">3. Install Python with uv
</h2>
<p>If Positron does not find a usable Python on your machine, it will offer to install Python via uv to help streamline your setup. If you prefer to manage the installation yourself, you can disable uv with the <a href="positron://settings/python.allowUvPythonInstall"><code>python.allowUvPythonInstall</code></a> setting. Check out our <a href="https://opensource.posit.co/blog/2026-07-08_positron-uv/" target="_blank" rel="noopener">blog post exploring on-demand Python installation in Positron</a> or explore configurations in our <a href="https://positron.posit.co/python-installations.html#troubleshooting" target="_blank" rel="noopener">Python installation documentation</a>.</p>
<img src="https://opensource.posit.co/blog/2026-07-15_positron-environment-management-tips/install-python-with-uv.png" width="100%" data-fig-align="center" data-fig-alt="Install Python via uv" />
<h2 id="4-manage-packages-with-the-packages-pane">4. Manage packages with the Packages Pane
</h2>
<p>The Packages Pane in Positron lets you manage the packages installed in your active session. Whether you use pip, uv, conda, pak, base R, or renv, you can browse installed packages and search package repositories. You can also track outdated packages and install, update, or uninstall packages without leaving Positron or writing any code.</p>
<img src="https://opensource.posit.co/blog/2026-07-15_positron-environment-management-tips/packages-pane.gif" width="100%"  data-fig-align="center" data-fig-alt="Manage Python and R packages in the Packages Pane" />
<h2 id="5-view-package-documentation">5. View package documentation
</h2>
<p>If you need to learn more about a specific package, the Packages Pane has buttons to navigate to the source documentation or link to the package&rsquo;s website. You can also pull up the <a href="https://positron.posit.co/help-pane.html" target="_blank" rel="noopener">Help Pane</a> for any reference in the Console using the <code>?</code> operator, including both packages and functions.</p>
<img src="https://opensource.posit.co/blog/2026-07-15_positron-environment-management-tips/packages-pane-help.png" width="100%" data-fig-align="center" data-fig-alt="View source documentation for specific packages in the Help Pane" />
<h2 id="6-start-projects-with-new-folder-from-template">6. Start projects with New Folder from Template
</h2>
<p>The New Folder from Template flow helps you start new projects faster. Instead of running multiple setup commands you can make a few selections and Positron helps you set up an environment directory, version control, directory structure, and an interpreter instance. Learn more about the <a href="https://positron.posit.co/folder-templates.html" target="_blank" rel="noopener">Python and R templates</a> available in the documentation.</p>
<img src="https://opensource.posit.co/blog/2026-07-15_positron-environment-management-tips/new-folder-from-template.png" width="100%" data-fig-align="center" data-fig-alt="New Folder from Template helps you start new projects faster with ready to use environments" />
<h2 id="7-make-use-of-the-command-palette">7. Make use of the Command Palette
</h2>
<p>We recommend taking advantage of the following commands when managing your environments:</p>
<ul>
<li><em>Interpreter: Discover All Interpreters</em>: Find new interpreters</li>
<li><em>Interpreter: Select Session</em>: Select a running interpreter session</li>
<li><em>Python: Create Environment</em>: Create a new virtual environment</li>
</ul>
<h2 id="8-let-posit-assistant-help-manage-your-environment">8. Let Posit Assistant help manage your environment
</h2>
<p><a href="https://assistant.posit.co/docs/features/context-management/" target="_blank" rel="noopener">Posit Assistant</a> has knowledge of your R and Python session including the language, version, names, and types of variables in your environment. You can prompt Posit Assistant to set up environments and troubleshoot issues you run into.</p>
<img src="https://opensource.posit.co/blog/2026-07-15_positron-environment-management-tips/assistant-installed-packages.png" width="100%" data-fig-align="center" data-fig-alt="Posit Assistant in Positron showing a summary of packages installed in the user's Python environment, organized by category." />
<p>Have an idea for how we can improve environment management in Positron? We would love to hear from you in a <a href="https://github.com/posit-dev/positron/discussions" target="_blank" rel="noopener">discussion on GitHub</a>.</p>
]]></description>
      <enclosure url="https://opensource.posit.co/blog/2026-07-15_positron-environment-management-tips/featured.svg" length="75593" type="image/svg&#43;xml" />
    </item>
    <item>
      <title>httr2 1.3.0</title>
      <link>https://opensource.posit.co/blog/2026-07-14_httr2-1-3-0/</link>
      <pubDate>Tue, 14 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://opensource.posit.co/blog/2026-07-14_httr2-1-3-0/</guid>
      <dc:creator>Hadley Wickham</dc:creator><description><![CDATA[<p>We&rsquo;re chuffed to announce the release of <a href="https://httr2.r-lib.org" target="_blank" rel="noopener">httr2</a> 1.3.0. httr2 makes it easy to work with web APIs from R, providing a pipeable interface for building requests and a suite of tools for processing the responses.</p>
<p>Get it now:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># install.packages(&#34;pak&#34;)</span>
</span></span><span class="line"><span class="cl"><span class="n">pak</span><span class="o">::</span><span class="nf">pak</span><span class="p">(</span><span class="s">&#34;httr2&#34;</span><span class="p">)</span></span></span></code></pre></div></div>
<p>The headline changes in this release all relate to OAuth token caching. They happen behind the scenes, so you shouldn&rsquo;t need to change any code, but you&rsquo;ll likely need to re-authenticate once after upgrading. The rest of this post explains why, and rounds up a handful of smaller features that landed in recent patch releases. See a full list of changes in the <a href="https://github.com/r-lib/httr2/releases/tag/v1.3.0" target="_blank" rel="noopener">release notes</a>.</p>
<h2 id="oauth-token-caching">OAuth token caching
</h2>
<p>First, a bit of background. When you authenticate with an API using OAuth, the API typically returns a refresh token that you can reuse for a set period. That means you don&rsquo;t have to log in every single time you use the API, which makes for a much nicer experience. To reuse a token across R sessions, however, httr2 has to write it to disk, and that creates a risk: anyone who can read the token could use it to access the API as you.</p>
<p>httr2 takes every precaution it can to keep these tokens safe. They&rsquo;re stored in a user-local cache directory, which is usually excluded from backups and, because it lives outside your working directory, carries no risk of being accidentally committed to git. On top of that, the tokens are encrypted so that only httr2 can read them.</p>
<p>Each token&rsquo;s path on disk is derived from a hash computed with <code>rlang::hash()</code>. We recently discovered a bug in that hashing code, and fixing it changes every hash. As a result, httr2 can no longer find your existing cached tokens, so you&rsquo;ll need to re-authenticate once after upgrading.</p>
<p>Since that change already invalidates your cached tokens, we took the opportunity to move where they&rsquo;re stored. Previously we used the rappdirs package to locate the cache directory, but since R 4.0.0 there&rsquo;s been a better built-in alternative: <code>tools::R_user_dir(&quot;httr2&quot;, which = &quot;cache&quot;)</code>. We&rsquo;ve switched to that, which makes httr2&rsquo;s cache location consistent with other packages and removes the rappdirs dependency.</p>
<p>Making these changes surfaced a long-standing bug. Every time httr2 loads, it&rsquo;s supposed to automatically delete any cached tokens older than 30 days, so that stale tokens don&rsquo;t linger indefinitely. Unfortunately, that pruning never actually worked. Now it does, so old tokens will be cleaned up once they pass 30 days, regardless of which cache directory or hashing algorithm produced them. This is good security practice: the longer a credential sits on disk, the more opportunities there are for it to leak, so removing tokens you&rsquo;re no longer using shrinks that window of exposure. If you&rsquo;d like to prune every cached token yourself, you can call <code>oauth_cache_prune(max_age_days = 0)</code>.</p>
<h2 id="other-features">Other features
</h2>
<p>Alongside the token caching work, this release also rolls up a few smaller features that first appeared in recent patch releases:</p>
<ul>
<li>
<p><strong>Faster streaming</strong> (1.2.3): <code>resp_stream_lines()</code>, <code>resp_stream_sse()</code>, and <code>resp_stream_aws()</code> now decode whole chunks at a time and hold the results in a queue, instead of rescanning and recopying the buffer for every line or event. This makes memory use and run time scale linearly rather than quadratically, so large streams are dramatically faster (e.g. reading a 1 MB response of short lines is now around 200x faster and uses around 180x less memory). <code>resp_stream_sse()</code> is used heavily by <a href="https://ellmer.tidyverse.org" target="_blank" rel="noopener">ellmer</a>, so this should make your LLM streaming feel a little zippier.</p>
</li>
<li>
<p><strong>OAuth server metadata discovery</strong> (1.2.3): the new <code>oauth_server_metadata()</code> discovers an OAuth/OIDC issuer&rsquo;s endpoints from its <code>.well-known</code> document, and <code>oauth_client()</code> gains a <code>metadata</code> argument so you can supply all of those endpoints at once.</p>
</li>
<li>
<p><strong>OpenTelemetry tracing</strong> (1.2.2): httr2 now emits OpenTelemetry traces for all requests when tracing is enabled. This requires the otelsdk package and is part of our cross-package work to improve the <a href="https://opensource.posit.co/blog/2026-05-07_opentelemetry/" target="_blank" rel="noopener">observability of R packages</a>.</p>
</li>
<li>
<p><strong><code>httr2_translate()</code></strong> (1.2.3): this new function translates an httr2 request into the equivalent curl command. It&rsquo;s handy for debugging, or for creating reprexes to share with people who don&rsquo;t use R.</p>
</li>
</ul>
]]></description>
      <enclosure url="https://opensource.posit.co/blog/2026-07-14_httr2-1-3-0/featured.jpg" length="312741" type="image/jpeg" />
    </item>
    <item>
      <title>useR! 2026: CRDTs, community, and contributing back to R</title>
      <link>https://opensource.posit.co/blog/2026-07-14_user-2026-warsaw/</link>
      <pubDate>Tue, 14 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://opensource.posit.co/blog/2026-07-14_user-2026-warsaw/</guid>
      <dc:creator>Charlie Gao</dc:creator><description><![CDATA[<p>Although the title of this post starts with &ldquo;CRDTs&rdquo; (for maximal alliterative effect), it is in fact the other two (community and contributing back) which are way more important to me. Sometimes it takes a conference, a substantial chunk of time away from the desk, to step back and re-calibrate our perspectives: to really appreciate the sheer breadth of <em>good work</em> taking place within the community.</p>
<p>And this community is ours. From joining my very first useR! online in 2022, through to Salzburg in 2024 - SatRdays London in between, the R Project Sprint in Warwick (UK) in 2023, the R Dev Days since, and of course posit::conf(2024) Seattle, posit::conf(2025) Atlanta, and Japan.R 2025&hellip; I may not have been part of this community for the most number of years, but I&rsquo;ve certainly appreciated its warmth and openness.</p>
<p>And so coming back to a European useR! was exciting.</p>
<h2 id="distributing-state-crdts-for-real-time-collaboration">Distributing state: CRDTs for real-time collaboration
</h2>
<p>The R community knows how to distribute compute - I&rsquo;ve talked extensively on this subject, mainly surrounding my creation {<a href="https://mirai.r-lib.org/" target="_blank" rel="noopener">mirai</a>}, an async framework that brings high-performance parallel and distributed computing to R. This lets you send tasks just as easily to a Slurm cluster as to processes on your own machine.</p>
<p>My talk this time was going to be about something different, but complementary: distributing state. A CRDT, or Conflict-free Replicated Data Type, is a data structure that facilitates collaboration by having a property called strong eventual consistency. Without going into the details, this allows it to always merge conflict-free, and is the technology behind many collaborative text editors. Automerge, a particular CRDT implementation, is what we&rsquo;re using in Quarto 2 to make it collaborative out-of-the-box.</p>
<p>In my talk, I showed a Shiny app in an R session editing a document on one of our Quarto collaborative sync servers. It used the {<a href="https://posit-dev.github.io/automerge-r/" target="_blank" rel="noopener">automerge</a>} and {<a href="https://posit-dev.github.io/autosync/" target="_blank" rel="noopener">autosync</a>} packages, which we created to let R manipulate these structures and sync them over the network - on a par with reference implementations in JavaScript and Rust. Automerge was created by Ink and Switch, an independent research lab for local-first software, and we&rsquo;re glad to provide a link between the two communities.</p>
<h2 id="distributing-compute-mirai-and-mori-in-the-wild">Distributing compute: mirai and mori in the wild
</h2>
<p>Apart from talking a lot about CRDTs and the three killer features of Quarto 2 (orders of magnitude faster, collaborative editing built-in with live preview, editable in the preview and source views), I also got pulled aside by people in the hallways to talk about {<a href="https://mirai.r-lib.org/" target="_blank" rel="noopener">mirai</a>} and {<a href="https://shikokuchuo.net/mori/" target="_blank" rel="noopener">mori</a>}.</p>
<p>Some of these were people working in the life sciences industry, using these packages for serious scientific research and innovation. This has always been a sector that I&rsquo;ve had immense respect for - from my earliest collaboration with Will Landau (Eli Lilly &amp; Co.). Open source software is often regarded as &lsquo;high-leverage&rsquo; in terms of how often and widely it&rsquo;s used, and when deployed in such high-impact settings, the end goals can be especially motivating and rewarding.</p>
<p>It&rsquo;s been extremely gratifying to see that {<a href="https://mirai.r-lib.org/" target="_blank" rel="noopener">mirai</a>} has percolated throughout the community consciousness. Considering that I was only introducing the package at useR! 2024 in Salzburg, it was nice to be able to introduce <em>myself</em> to people this time simply as &ldquo;the author of mirai&rdquo;. By 2027, I&rsquo;m hoping this will also be possible with mori!</p>
<h2 id="the-best-part-the-people">The best part: the people
</h2>
<p>Given that only a few of my colleagues could make it to useR! this year, I was slightly apprehensive going in. This fear was dispelled at the very first reception event, where I met so many people from past R Dev Days, amongst them Tina Roszos, who simply beamed at me from across the room! R Core also turned out in force and it was nice to meet Peter Dalgaard and Robert Gentleman for the first time, as well as saying hello again to Luke Tierney, Uwe Ligges and everyone who came.</p>
<p>It&rsquo;s always great to catch up with familiar faces - Gergely Daróczi (maintainer of R&rsquo;s Weblate platform), members of the mlr group (Martin Binder, Marc Becker, Maximilian Mücke), and many others. However, some of my best conversations this year were with people I had met for the first time. I was fortunate that for some, this was their first in-person useR!, having been part of the R community for many years.</p>
<p>It was especially nice to be welcomed by entire groups of people, for example the <a href="https://numbat.space" target="_blank" rel="noopener">NUMBATs</a> headed by Prof. Dianne Cook, who was also the opening keynote speaker of the conference. I got to be an honorary NUMBAT for one photo:</p>
<p><div class="not-prose"><figure>
    <img class="h-auto max-w-full rounded-lg"
      src="https://opensource.posit.co/blog/2026-07-14_user-2026-warsaw/images/numbat.jpg"
      alt="The Monash &ldquo;NUMBAT&rdquo; group posing inside a &ldquo;useR! 2026 Warsaw&rdquo; photo-frame prop covered in R-package hex stickers." 
      loading="lazy"
    >
  </figure></div>
</p>
<h2 id="contributing-back-r-dev-day">Contributing back: R Dev Day
</h2>
<p>R Dev Day followed the conference on the Friday. Thanks again to Heather Turner and Ella Kaye for tirelessly organising these. They are simply great opportunities to contribute back to R&rsquo;s source code itself. I do believe that these events have played an important role in fostering and sustaining our community.</p>
<p>I worked closely with Tymek (Tymoteusz Makowski) on two C-level I/O bugs. Tymek was the only person brave enough to tackle these. This proved to be a fruitful collaboration as we&rsquo;d posted a patch by the end of the day (<a href="https://bugs.r-project.org/show_bug.cgi?id=19101" target="_blank" rel="noopener">PR #19101</a>). This patch has since been accepted into the R source, without modification! It&rsquo;s proved the most productive of any R Dev Day I&rsquo;ve attended thus far.</p>
<p>Special thanks to Mitchell O&rsquo;Hara-Wild for supplying the Dev Day group photograph, which I&rsquo;m using as the banner image for this blog post.</p>
<h2 id="looking-ahead">Looking ahead
</h2>
<p>There are many people I&rsquo;ve not mentioned by name - that&rsquo;s just to prevent this entire post from being a name-drop. I&rsquo;ve enjoyed speaking to every one of you. There is so much talent out there, and I look forward to catching up again and marvelling at all you&rsquo;ve been working on!</p>
<p>See you next at <a href="https://conf.posit.co/2026/" target="_blank" rel="noopener">posit::conf(2026)</a> Houston!</p>
]]></description>
      <enclosure url="https://opensource.posit.co/blog/2026-07-14_user-2026-warsaw/images/hero.jpg" length="575131" type="image/jpeg" />
    </item>
    <item>
      <title>Positron July Release Highlights</title>
      <link>https://opensource.posit.co/blog/2026-07-13_positron-2026-07-release/</link>
      <pubDate>Mon, 13 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://opensource.posit.co/blog/2026-07-13_positron-2026-07-release/</guid>
      <dc:creator>Julia Silge</dc:creator><description><![CDATA[<div class="callout callout-note" role="note" aria-label="Note">
<div class="callout-header">
<span class="callout-title">Note</span>
</div>
<div class="callout-body">
<p><a href="https://positron.posit.co" target="_blank" rel="noopener">Positron</a> is Posit&rsquo;s new, next-generation IDE for data science. Positron is designed to be an extensible, polyglot tool for exploring data and reproducible authoring in Python, R, and more.</p>
</div>
</div>
<p>Welcome back to another edition of our monthly Positron updates! Each month we share highlights from our <a href="https://positron.posit.co/release-notes" target="_blank" rel="noopener">latest release</a> and useful resources. <a href="https://opensource.posit.co/blog/2026-06-08_positron-2026-06-release/" target="_blank" rel="noopener">Last release</a> we told you that several major features were on track to leave preview in July, and the time is now here! The new Notebook editor, the Packages pane, and Posit Assistant are all now generally available.</p>
<h2 id="positron-notebook-editor">Positron Notebook Editor
</h2>
<p>Positron&rsquo;s <a href="https://positron.posit.co/positron-notebook-editor" target="_blank" rel="noopener">new Notebook editor</a> is now the default experience for Jupyter (<code>.ipynb</code>) files. This release brings a long list of additions, including split-pane editing, cell tag management, and executing a line or selection within a cell with <kbd>Cmd/Ctrl+Shift+Enter</kbd>. You can export notebooks to Quarto, Python, or R, and inline PDF rendering makes it easier to work with generated output. If you are coming from JupyterLab, you will find familiar keyboard shortcuts, and we have improved output fidelity for Mermaid diagrams, htmlwidgets, and ipywidgets.</p>
<img src="https://opensource.posit.co/blog/2026-07-13_positron-2026-07-release/positron-notebook-editor.png" data-fig-align="center" data-fig-alt="The Notebook editor in Positron, showing a Jupyter notebook with a Mermaid diagram." />
<p>Posit has built on and for the Jupyter ecosystem for years now, and we are excited to have recently <a href="https://opensource.posit.co/blog/2026-06-25_posit-joins-jupyter-foundation/" target="_blank" rel="noopener">joined the Jupyter Foundation</a>.</p>
<h2 id="packages-pane">Packages pane
</h2>
<p>The <a href="https://positron.posit.co/packages-pane" target="_blank" rel="noopener">Packages pane</a> has also come out of preview. It gives you a live view of the R and Python packages installed in your active session, so you can search, install, update, and remove packages, and jump to their documentation, without leaving Positron.</p>
<img src="https://opensource.posit.co/blog/2026-07-13_positron-2026-07-release/packages-pane.gif" data-fig-align="center" data-fig-alt="The Packages pane in Positron, showing installed Python packages with a detail editor." />
<p>This release also makes the pane more capable. Clicking a package opens a detail editor with its overview, metadata, and actions, similar to the Extensions pane. Installing a package searches results as you type, and each row has a button that opens the package&rsquo;s website. Update indicators appear immediately on a new session from a cached snapshot, and <strong>Update All Packages</strong> reports exactly what changed. Package operations keep your environment consistent too, resolving against a workspace <code>requirements.txt</code> for Python and updating the <code>renv.lock</code> snapshot for R.</p>
<h2 id="posit-assistant">Posit Assistant
</h2>
<p><a href="https://pos.it/assistant" target="_blank" rel="noopener">Posit Assistant</a>, our unified, data-science-focused approach to AI assistance, is now out of preview and generally available; Posit Assistant fully replaces the legacy Positron Assistant. We know the names are similar, and Joe Cheng <a href="https://opensource.posit.co/blog/2026-06-11_history-of-posit-data-science-agents/" target="_blank" rel="noopener">recently walked through a bit of the story behind how our AI agent tools have evolved</a>.</p>
<p>This release also gives you finer control over AI in Positron. The new <a href="positron://settings/ai.enabled"><code>ai.enabled</code></a> setting turns off every Positron AI feature at once, and administrators can enforce it; <a href="positron://settings/notebook.ai.enabled"><code>notebook.ai.enabled</code></a> does the same for notebooks specifically. The set of language model providers keeps growing, with DeepSeek joining as an experimental provider and Microsoft Foundry reaching general availability. The configuration modal now shows every provider by default with preview and experimental badges.</p>
<h2 id="data-explorer">Data Explorer
</h2>
<p>The <a href="https://positron.posit.co/data-explorer" target="_blank" rel="noopener">Data Explorer</a> can now open Excel workbooks directly, with no code required, without first needing to load it via Python or R. Sort, filter, and profile columns, switch between worksheets, and toggle whether the first row holds column names. An <strong>Open in Excel</strong> button opens the workbook in your native spreadsheet application.</p>
<p>This release broadens what you can open in the Data Explorer overall. Backed by a native DuckDB engine, it now also previews compressed CSV, TSV, and Parquet files. Also, a new <strong>Open in Data Explorer</strong> code action, from the editor lightbulb or <kbd>Cmd+.</kbd>, opens the data frame under your cursor in R, Python, and Quarto files, so you can jump straight from your code to exploring your data.</p>
<img src="https://opensource.posit.co/blog/2026-07-13_positron-2026-07-release/open-in-data-explorer-code-action.gif" data-fig-align="center" data-fig-alt="The Open in Data Explorer code action in Positron, showing a lightbulb menu in a Python file with the option to open a data frame in the Data Explorer." />
<h2 id="r-language-intelligence">R language intelligence
</h2>
<p>Last release we introduced within-file symbol resolution for R; this release expands it across files. Go to Definition, Find References, and Rename Symbol now work across the packages and scripts in your workspace, and diagnostics and workspace symbols react to external file changes so your language intelligence stays in sync as your project evolves.</p>
<h2 id="whats-coming-next">What&rsquo;s coming next
</h2>
<ul>
<li>New in preview this release, Data Connections lets you browse the schemas, tables, views, and indexes of a database, open tables in the Data Explorer, and generate connection code. It currently supports DuckDB, PostgreSQL, and SQLite. Learn how to try it out and tell us what you think in the <a href="https://github.com/posit-dev/positron/discussions/14571" target="_blank" rel="noopener">Data Connections discussion post</a>: which databases and warehouses you need, whether the connection setup is clear, and anything confusing, missing, or broken.</li>
<li>We are looking forward to posit::conf(2026) in September, where our team will have several sessions on Positron. <a href="https://conf.posit.co/2026/" target="_blank" rel="noopener">Register now</a> to join us in person in Houston or virtually from anywhere in the world.</li>
</ul>
<div class="callout callout-tip" role="note" aria-label="Tip">
<div class="callout-header">
<span class="callout-title">Tip</span>
</div>
<div class="callout-body">
<p><a href="https://positron.posit.co/download" target="_blank" rel="noopener">Download Positron</a> to try out the new features and improvements in this release!</p>
</div>
</div>
]]></description>
      <enclosure url="https://opensource.posit.co/blog/2026-07-13_positron-2026-07-release/featured.svg" length="88493" type="image/svg&#43;xml" />
    </item>
    <item>
      <title>Positron &#43; uv: Python setup in one click</title>
      <link>https://opensource.posit.co/blog/2026-07-08_positron-uv/</link>
      <pubDate>Wed, 08 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://opensource.posit.co/blog/2026-07-08_positron-uv/</guid>
      <dc:creator>Isabel Zimmerman</dc:creator><description><![CDATA[<p>The Python community has a long-standing joke about how hard it can be to get Python running on your machine.
The options can feel overwhelming, and the post-install result often looks like this:</p>
<img src="https://imgs.xkcd.com/comics/python_environment.png" data-fig-align="center" data-fig-alt="The xkcd 'Python Environment' comic showing a tangled web of arrows between dozens of conflicting Python installations on one machine" />
<p>If you&rsquo;re new to Python, Positron has a few built-in workflows to help you skip that installation pain entirely.
Most of it is powered by <a href="https://docs.astral.sh/uv/" target="_blank" rel="noopener">uv, created by Astral</a>.
We chose uv because it&rsquo;s fast and has quickly become widely adopted across the Python community.
Behind the scenes, uv handles the heavy lifting, downloading Python versions and building environments.
Positron wraps that power in a friendly interface, so you never have to remember a command.</p>
<h2 id="from-zero-to-python-in-one-click">From zero to Python in one click
</h2>
<p>If you don&rsquo;t have a suitable Python available, Positron will offer to install it for you.
When you go to start a Python runtime through the <strong>Start Session</strong> button, you&rsquo;ll see an option for <strong>+ Install Python via uv</strong>.</p>
<img src="https://opensource.posit.co/blog/2026-07-08_positron-uv/select-interpreter.png" data-fig-align="center" data-fig-alt="Positron's 'Start New Console Session' picker listing installed Python and R interpreters, with a highlighted '+ Install Python via uv' option at the bottom" />
<p>When you choose it, Positron will ask to install uv for you if you don&rsquo;t already have it.
Then it shows you the supported Python versions (currently 3.9 through 3.14) and installs whichever one you pick.
If you have a folder open, it will also offer to create a virtual environment for the project and start a Python console session using that environment.
Once you have a Python available, this option disappears from the session picker.</p>
<p>If you&rsquo;d rather not see the prompt to install Python, you can turn it off with the <a href="positron://settings/python.allowUvPythonInstall"><code>python.allowUvPythonInstall</code></a> setting (enabled by default).</p>
<div class="callout callout-tip" role="note" aria-label="Tip">
<div class="callout-header">
<span class="callout-title">Why do I see this when I already have Python on my machine?</span>
</div>
<div class="callout-body">
<p>If you only have system Pythons available, you&rsquo;ll still see the <strong>+ Install Python via uv</strong> option.
<a href="https://pydevtools.com/handbook/explanation/why-should-i-avoid-system-python/" target="_blank" rel="noopener">Using system Python tends to cause problems down the road</a>, so Positron nudges you toward a managed Python and virtual environment instead.</p>
</div>
</div>
<h2 id="on-demand-python-installation">On-demand Python installation
</h2>
<p>You don&rsquo;t have to wait for Positron to ask, either.
Open the command palette with <kbd>Cmd/Ctrl+Shift+P</kbd> and run <em>Python: Install Python via uv</em> any time you&rsquo;d like another version.
This command will download uv if needed, show you the available Python versions, and optionally offer to create a virtual environment.</p>
<img src="https://opensource.posit.co/blog/2026-07-08_positron-uv/cmd-uv.png" data-fig-align="center" data-fig-alt="Positron's command palette with 'python install via' typed, showing the 'Python: Install Python via uv' command" />
<p>Since it runs on demand, it&rsquo;s a good way to add another interpreter to a project you&rsquo;ve already set up.
And because it follows the same flow every time, it works well for teaching, since everyone ends up in the same place, the same way.</p>
<h2 id="automatic-project-setup-support">Automatic project setup support
</h2>
<p>Setting up a virtual environment isn&rsquo;t limited to that first run.
If Positron finds a <code>pyproject.toml</code> or <code>requirements.txt</code> in a project that doesn&rsquo;t have a virtual environment yet, it&rsquo;ll offer to create one with uv and install your dependencies.
This comes in handy when you&rsquo;ve cloned a colleague&rsquo;s project and want to get up and running without extra setup.</p>
<img src="https://opensource.posit.co/blog/2026-07-08_positron-uv/requirements.png" data-fig-align="center" data-fig-alt="A Positron notification reading 'This project has requirements.txt but no virtual environment. Use uv to create a .venv and install these requirements?' with Yes, Not now, and Don't show again buttons" />
<p>If there&rsquo;s a single requirements source, like a lone <code>requirements.txt</code> or <code>pyproject.toml</code>, Positron will prompt you to create a <code>.venv</code> and install everything right away.
And if there are several sources, you can choose which files to include in your installation.</p>
<p>Positron also knows when to stay out of your way.
If you already have a local virtual environment, or if you use non-uv files like <code>environment.yml</code>, <code>Pipfile</code>, or <code>poetry.lock</code>, you won&rsquo;t get a prompt at all.</p>
<h2 id="try-it-yourself">Try it yourself
</h2>
<p>Setting up Python doesn&rsquo;t have to feel like a chore, whether you&rsquo;re starting on a brand new machine, picking up a colleague&rsquo;s project, or getting a room full of students ready to code.</p>
<p>Give it a try in <a href="https://positron.posit.co/download" target="_blank" rel="noopener">Positron&rsquo;s July 2026 release</a> and let us know what you think.</p>
]]></description>
      <enclosure url="https://opensource.posit.co/blog/2026-07-08_positron-uv/image.png" length="386340" type="image/png" />
    </item>
    <item>
      <title>mcptools 1.0.0</title>
      <link>https://opensource.posit.co/blog/2026-07-06_mcptools-1-0-0/</link>
      <pubDate>Mon, 06 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://opensource.posit.co/blog/2026-07-06_mcptools-1-0-0/</guid>
      <dc:creator>Simon Couch</dc:creator><description><![CDATA[<p>The first major release of <a href="https://posit-dev.github.io/mcptools/" target="_blank" rel="noopener">mcptools</a>, an R SDK for the Model Context Protocol, is now on CRAN! This release includes several notable features: fetching tools from remote authenticated servers, deploying MCP servers on Posit Connect, and support for images and other rich content types.</p>
<p>To install the package, run:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">install.packages</span><span class="p">(</span><span class="s">&#34;mcptools&#34;</span><span class="p">)</span></span></span></code></pre></div></div>
<p>To demo these new features, I&rsquo;ll deploy an R function that returns a picture to an MCP server on Posit Connect. Then, in another R session, I&rsquo;ll connect to that server and ask an ellmer chat to take a look at the picture and tell me what it sees.</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">mcptools</span><span class="p">)</span></span></span></code></pre></div></div>
<h2 id="images-in-tool-results">Images in tool results
</h2>
<p>mcptools supports &ldquo;both directions&rdquo; of MCP. In one direction, users can deploy R functions as MCP servers. In the other direction, users can fetch tools from third-party MCP servers as R functions. <strong>mcptools now supports both serving and fetching tools that return images.</strong></p>
<p>As an example of a function that returns an image, let&rsquo;s consider a tool <code>fetch_reference_image()</code>:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">ellmer</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">tools</span> <span class="o">&lt;-</span> <span class="nf">list</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="n">fetch_reference_image</span> <span class="o">=</span> <span class="nf">tool</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="kr">function</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nf">content_image_url</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="s">&#34;https://simonpcouch.com/blog/2026-04-16-local-agents-2/featured.png&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="n">name</span> <span class="o">=</span> <span class="s">&#34;fetch_reference_image&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">description</span> <span class="o">=</span> <span class="s">&#34;Fetch the reference image.&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span></span></span></code></pre></div></div>
<p>Running that function:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">tools</span><span class="o">$</span><span class="nf">fetch_reference_image</span><span class="p">()</span></span></span></code></pre></div></div>
<figure>
<img src="https://simonpcouch.com/blog/2026-04-16-local-agents-2/featured.png" alt="A brown and white Border Collie on a deck, looking attentively at the camera, with wire railings and blurred greenery in the background." />
<figcaption aria-hidden="true">A brown and white Border Collie on a deck, looking attentively at the camera, with wire railings and blurred greenery in the background.</figcaption>
</figure>
<p>Without MCP, I can ask a model to look at the image and tell me what it sees:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">ch</span> <span class="o">&lt;-</span> <span class="nf">chat_claude</span><span class="p">(</span><span class="s">&#34;Be brief.&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ch</span><span class="o">$</span><span class="nf">register_tool</span><span class="p">(</span><span class="n">tools[[1]]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ch</span><span class="o">$</span><span class="nf">chat</span><span class="p">(</span><span class="s">&#34;What do you see in the reference image?&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; I can see a beautiful Border Collie dog in the reference</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; image. The dog has:</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; - A chocolate brown and white coat with distinctive</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;   coloring</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; - Amber/brown eyes</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; - Alert, perked ears</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; - A white blaze down the center of its face</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; - A pink/brown nose</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; - Long, fluffy fur typical of the breed</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; The dog appears to be outdoors, positioned near what</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; looks like a wooden post or railing with wire fencing</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; visible in the background. There&#39;s greenery and trees</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; visible in the blurred background. The dog has an</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; attentive, intelligent expression that&#39;s characteristic</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; of Border Collies.</span></span></span></code></pre></div></div>
<p>In the next two sections, I&rsquo;ll deploy this function on Posit Connect and then fetch it from a fresh R session so that future ellmer chats can fetch this same image.</p>
<h2 id="mcp-servers-on-posit-connect">MCP Servers on Posit Connect
</h2>
<p>mcptools has now adopted plumber2&rsquo;s <code>_server.yml</code> open standard. This means that, <strong>to deploy an MCP server on Posit Connect, you just need to add a <code>_server.yml</code> file in your project root</strong> that looks like this:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yml" data-lang="yml"><span class="line"><span class="cl"><span class="nt">engine</span><span class="p">:</span><span class="w"> </span><span class="l">mcptools</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">tools</span><span class="p">:</span><span class="w"> </span><span class="l">tools.R</span></span></span></code></pre></div></div>
<p><code>tools.R</code> (or whatever you choose to name the file) is a file that defines ellmer tools and returns them in a list. In my case, <code>tools.R</code> looks exactly like the code chunk defining <code>tools</code> above. I can then run <code>rsconnect::deployAPI(&quot;.&quot;, contentCategory = &quot;mcp&quot;)</code> to deploy the tools from <code>tools.R</code> as an authenticated MCP server on Posit Connect.</p>
<h2 id="fetch-tools-as-r-functions-from-authenticated-mcp-servers">Fetch tools as R functions from authenticated MCP servers
</h2>
<p>Perhaps the biggest gap in mcptools before this release was that <code>mcp_tools()</code> did not support remote, authenticated MCP servers. Up to this point, I had written in documentation that folks ought to use <code>npx mcp-remote</code>, which converts remote MCP servers (like Slack, Confluence, or really any of the most well-adopted third-party MCP servers) into local ones. That meant that, even though mcptools only implemented the local half of the protocol, mcptools users could connect to remotely hosted MCP servers.</p>
<p>This is undesirable for a few reasons. For one, mcptools should &ldquo;just work&rdquo; without users having to install software from sources other than CRAN. Further, installing code via <code>npx</code> is particularly problematic; the node package registry has been the source of <a href="https://www.axios.com/2026/03/31/north-korean-hackers-implicated-in-major-supply-chain-attack" target="_blank" rel="noopener">a</a> <a href="https://arstechnica.com/security/2026/06/dozens-of-red-hat-packages-backdoored-through-its-offical-npm-channel/" target="_blank" rel="noopener">number</a> <a href="https://www.theregister.com/cyber-crime/2026/05/18/shai-hulud-copycat-hits-another-npm-package/5242180" target="_blank" rel="noopener">of</a> <a href="https://www.stepsecurity.io/blog/mini-shai-hulud-is-back-a-self-spreading-supply-chain-attack-hits-the-npm-ecosystem" target="_blank" rel="noopener">particularly</a> <a href="https://unit42.paloaltonetworks.com/monitoring-npm-supply-chain-attacks/" target="_blank" rel="noopener">concerning</a> supply chain attacks recently.</p>
<p><strong><code>mcp_tools()</code> now natively supports fetching tools from authenticated, third-party MCP servers.</strong> For example, a configuration that used to look like:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;mcpServers&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;connect&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;npx&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;args&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;mcp-remote&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;&lt;my_deployed_connect_listing&gt;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;--header&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;Authorization: Key ${CONNECT_API_KEY}&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div>
<p>Now looks like:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;mcpServers&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;connect&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;url&#34;</span><span class="p">:</span> <span class="s2">&#34;&lt;my_deployed_connect_listing&gt;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;headers&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;Authorization&#34;</span><span class="p">:</span> <span class="s2">&#34;Key ${CONNECT_API_KEY}&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div>
<p>I&rsquo;ll save that latter configuration as <code>config.json</code>. Then, I&rsquo;ll provide it to <code>mcp_tools()</code>:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">tools_fetched</span> <span class="o">&lt;-</span> <span class="nf">mcp_tools</span><span class="p">(</span><span class="n">config</span> <span class="o">=</span> <span class="s">&#34;config.json&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">class</span><span class="p">(</span><span class="n">tools_fetched[[1]]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; [1] &#34;ellmer::ToolDef&#34; &#34;function&#34;        &#34;S7_object&#34;</span></span></span></code></pre></div></div>
<p>Now I can register the fetched tools with a chat in a new R session, and it has access to the same image:</p>
<div class="code-block"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">ch_new</span> <span class="o">&lt;-</span> <span class="nf">chat_claude</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">ch_new</span><span class="o">$</span><span class="nf">register_tools</span><span class="p">(</span><span class="n">tools_fetched</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ch_new</span><span class="o">$</span><span class="nf">chat</span><span class="p">(</span><span class="s">&#34;What&#39;s in the reference image?&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; The reference image features a **Border Collie** dog.</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Here are some details:</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; - **Coloring**: The dog has a striking **brown</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;   (chocolate) and white** coat, with a distinctive white</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;   stripe running down the center of its face.</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; - **Expression**: It has an alert and attentive look,</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;   with beautiful **amber/brown eyes**.</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; - **Tongue**: Its tongue is slightly visible, giving it a</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;   cute appearance.</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; - **Setting**: The dog appears to be on a **deck or</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;   porch**, with cable/wire railings visible, and a lush</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;   green, leafy background suggesting an outdoor, wooded</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;   area.</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; - **Accessories**: It appears to be wearing a small</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;   **collar tag**.</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&gt; Overall, it&#39;s a beautiful and expressive dog photo! 🐕</span></span></span></code></pre></div></div>
<p>Taken together, the changes in this release should allow R users to do much more with MCP! For a more complete list of changes in this release, see the package <a href="https://posit-dev.github.io/mcptools/news/index.html" target="_blank" rel="noopener">changelog</a>.</p>
]]></description>
      <enclosure url="https://opensource.posit.co/blog/2026-07-06_mcptools-1-0-0/featured.png" length="874368" type="image/png" />
    </item>
    <item>
      <title>AI Newsletter: AGENTS.md vs Skills vs MCP servers</title>
      <link>https://opensource.posit.co/blog/2026-07-03_ai-newsletter/</link>
      <pubDate>Fri, 03 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://opensource.posit.co/blog/2026-07-03_ai-newsletter/</guid>
      <dc:creator>Sara Altman</dc:creator>
      <dc:creator>Simon Couch</dc:creator><description><![CDATA[<h2 id="prompt-agentsmd-skill-or-mcp-server">Prompt, AGENTS.md, skill, or MCP server?
</h2>
<p>There are a variety of ways to give a coding agent new information or abilities, but it can be confusing when to use each one. Generally, with coding agents like Claude Code or Posit Assistant, you can:</p>
<ul>
<li><strong>Write prompts</strong> in the chat (i.e., normal usage).</li>
<li>Add information to either a project-level or user-level <strong><code>CLAUDE.md</code> or <code>AGENTS.md</code>.</strong> The contents of a directory&rsquo;s <code>CLAUDE.md</code> or <code>AGENTS.md</code> are included in the agent&rsquo;s system prompt in every session in that directory. You can also create user-level versions that apply to every session.</li>
<li>Write a <strong>skill</strong> or use an existing one. Skills are packaged instructions that can include both text and code. The agent loads a skill only when it&rsquo;s relevant.</li>
<li>Add an <strong>MCP server.</strong> An <a href="https://modelcontextprotocol.io/docs/getting-started/intro" target="_blank" rel="noopener">MCP (Model Context Protocol)</a> server provides an agent with access to otherwise hard-to-find context, mostly through <a href="https://modelcontextprotocol.io/docs/learn/server-concepts#tools" target="_blank" rel="noopener">tools</a>, using a standardized interface.</li>
</ul>
<p>This list is roughly ordered from most straightforward to most complicated.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
<p>So when do you use one over the other? There are two axes that might matter for your decision.</p>
<p>The first axis is reusability: do you want the agent to perform the task or access the information just once, or many times? The more often you or others will reuse something, the more it&rsquo;s worth encoding somewhere more permanent.</p>
<p>The second axis is reach. Prompting, <code>CLAUDE.md</code>/<code>AGENTS.md</code> files, and skills all provide guidance on how to best make use of the existing context and tools. MCP servers can provide the agent with entirely new tools (in the <a href="https://ellmer.tidyverse.org/articles/tool-calling.html" target="_blank" rel="noopener">agent tools</a> sense), granting the agent access to hard-to-reach information.</p>
<p><div class="not-prose"><figure>
    <img class="h-auto max-w-full rounded-lg"
      src="https://opensource.posit.co/blog/2026-07-03_ai-newsletter/images/diagram.excalidraw.svg"
      alt="Decision tree for choosing how to customize a coding agent. The first question asks whether this is a one-time thing or something you&rsquo;ll need the agent to do similarly in the future. A one-time thing leads to normal prompting. If you&rsquo;ll need it again, the next question is when you want the agent to do the task: every session in the project leads to a CLAUDE.md or AGENTS.md file, while &ldquo;as needed&rdquo; leads to a further question. That question asks whether the agent has the capability to do the task with the tools it already has: if yes, write a skill; if no, use an MCP server."  title="A decision tree for choosing between prompting, AGENTS.md, skills, and MCP servers." 
      loading="lazy"
    ><figcaption class="text-sm text-center text-gray-500">A decision tree for choosing between prompting, AGENTS.md, skills, and MCP servers.</figcaption>
  </figure></div>
</p>
<p><strong>MCP servers often seem like the solution when you need to grant an agent access to an outside system, but they aren&rsquo;t always necessary.</strong> In many cases, what seems like a task for an MCP server can actually be solved by a command-line interface (CLI) tool, or a CLI plus a skill that tells the agent how to use it. For example, GitHub has an <a href="https://github.com/github/github-mcp-server" target="_blank" rel="noopener">MCP server</a>, but the <a href="https://cli.github.com/" target="_blank" rel="noopener"><code>gh</code></a> CLI does roughly the same thing.</p>
<p>The GitHub MCP server works by providing the agent with new tools, whereas the <code>gh</code> CLI takes advantage of the agent&rsquo;s existing bash tool that lets it run arbitrary shell commands. The skill plus CLI option is therefore generally preferable from a simplicity standpoint, but also from a token standpoint: adding the GitHub MCP server would inject tens of thousands of tokens of tool definitions into every request, whereas a skill that tells the agent to use <code>gh</code> costs almost nothing and loads only when it&rsquo;s relevant.</p>
<p>However, some information sources are hard to reach via the command line, because no CLI exists, the one that does isn&rsquo;t fully featured, or it&rsquo;s difficult for the agent to use. In some of these cases, the same sources can be accessed more effectively via MCP servers, such as design tools like Figma, knowledge repositories like Notion or Confluence, or issue trackers like Linear or Jira.</p>
<h2 id="posit-news">Posit news
</h2>
<h3 id="posit-assistant-in-positron">Posit Assistant in Positron
</h3>
<p>As of the <a href="https://positron.posit.co/download.html#release-notes" target="_blank" rel="noopener">June release</a> of Positron, Posit Assistant is now the default experience in Positron. Positron Assistant will be deprecated starting in the 2026.07 release (release date July 6).</p>
<p>We understand that the names are confusing! Our hope is that the transition state will be over soon and the confusion will lessen. If you want to understand why we gave different assistants very similar names, read this blog post from Posit CTO Joe Cheng: <a href="https://opensource.posit.co/blog/2026-06-11_history-of-posit-data-science-agents/" target="_blank" rel="noopener">A brief and biased history of Posit data science agents</a>.</p>
<p>Posit Assistant works with the same providers as Positron Assistant. If you have a working provider setup with Positron Assistant, you&rsquo;ll be able to use that same setup with Posit Assistant. You can read more about available providers <a href="https://assistant.posit.co/docs/downloads/positron/" target="_blank" rel="noopener">here</a>.</p>
<h3 id="package-updates">Package updates
</h3>
<ul>
<li><a href="https://opensource.posit.co/blog/2026-07-01_raghilda-0-2-0/" target="_blank" rel="noopener">raghilda v0.2</a>, a Python package for Retrieval Augmented Generation, is now on PyPI. This release, among other things, broadens support for crawling sites.</li>
<li><a href="https://opensource.posit.co/blog/2026-06-22_debrief-0-1-0/" target="_blank" rel="noopener">debrief</a>, an R package for LLM-friendly profiling, is now on CRAN. debrief turns profvis profiling output into text-based summaries, allowing AI agents to optimize R code more effectively.</li>
</ul>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>One interface we didn&rsquo;t mention here is &lsquo;custom agents,&rsquo; a concept popularized by GitHub Copilot and now appearing under various names. These bundle some combination of prompts and tools (sometimes gathered via MCP). We&rsquo;d reach for the options mentioned above first, which are open standards that are broadly supported across most agent platforms and thus can be shared and migrated more easily.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></description>
      <enclosure url="https://opensource.posit.co/blog/2026-07-03_ai-newsletter/images/hero.png" length="83964" type="image/png" />
    </item>
    <item>
      <title>posit::glimpse() Newsletter – July 2026</title>
      <link>https://opensource.posit.co/blog/2026-07-01_2026-07-glimpse/</link>
      <pubDate>Wed, 01 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://opensource.posit.co/blog/2026-07-01_2026-07-glimpse/</guid>
      <dc:creator>Isabella Velásquez</dc:creator><description><![CDATA[<blockquote>
<p>Welcome to our newsletter, posit::glimpse()!</p>
<p>If you&rsquo;re currently reading this on our blog, consider subscribing to Product Updates - Open Source on our <a href="https://posit.co/about/subscription-management" target="_blank" rel="noopener">subscription page</a> to receive this newsletter directly in your inbox.</p>
</blockquote>
<p>Welcome to the latest edition of the posit::glimpse() newsletter, the monthly roundup of open-source news for the Posit community. I have many updates for you from across Posit. As my wonderful colleague Kristin Bott stated, “<em>dang</em> this is a productive bunch of humans”.</p>
<p>The table of contents on the right can help you navigate through all the updates. As you scroll, it will open up to show you subcategories →</p>
<h2 id="announcements">Announcements
</h2>
<h3 id="positconf2026-is-happening-soon">posit::conf(2026) is happening soon!
</h3>
<p>Our annual conference, <a href="https://conf.posit.co/2026/" target="_blank" rel="noopener">posit::conf(2026)</a>, is happening September 14-16, and we would love to see you there, whether in Houston or online! Check out the <a href="https://posit.co/blog/posit-conf-2026-agenda-breakdown" target="_blank" rel="noopener">speaker lineup</a>, <a href="https://posit.co/blog/workshops-at-positconf2026" target="_blank" rel="noopener">workshop offerings</a>, and <a href="https://conf.posit.co/2026/registration/" target="_blank" rel="noopener">register for posit::conf here</a>.</p>
<p>Tidy Dev Day is happening on September 17, a unique opportunity to collaboratively tackle open-source issues and work directly alongside the very developers who build and maintain the tools you use every day. As <a href="https://thetidytrekker.com/post/vibe-conf-ing/posit_conf_2025" target="_blank" rel="noopener">Meghan Harris stated about last year’s event</a>, “Tidy Dev Day (TDD) gave me the PERFECT opportunity to explore this further in a low-stress, supportive environment.” <a href="https://opensource.posit.co/blog/2026-06-25_tidy-dev-day-2026/" target="_blank" rel="noopener">Learn more about Tidy Dev Day here</a>.</p>
<h3 id="weve-joined-the-jupyter-foundation">We’ve joined the Jupyter Foundation
</h3>
<p>We are proud to announce that we are deepening our commitment to the <a href="https://jupyter.org/" target="_blank" rel="noopener">Jupyter</a> ecosystem by becoming an official <a href="https://jupyterfoundation.org/" target="_blank" rel="noopener">Jupyter Foundation</a> Member!</p>
<ul>
<li>Learn more in the <a href="https://opensource.posit.co/blog/2026-06-25_posit-joins-jupyter-foundation/" target="_blank" rel="noopener">We’ve Joined the Jupyter Foundation announcement</a> blog post.</li>
</ul>
<h3 id="announcing-an-expanded-posit-academy">Announcing an expanded Posit Academy
</h3>
<p>We&rsquo;ve launched a new part of <a href="http://academy.posit.co/" target="_blank" rel="noopener">Posit Academy</a>: a free, open library of product courses, hands-on labs, and live workshops available to anyone.</p>
<ul>
<li>Learn more in the <a href="https://posit.co/blog/announcing-expanded-posit-academy" target="_blank" rel="noopener">Announcing an expanded Posit Academy</a> blog post.</li>
</ul>
<h3 id="introducing-the-posit-impact-awards">Introducing the Posit Impact Awards
</h3>
<p>Have a story to share? We just launched the Posit Impact Awards to recognize individuals and teams who used Posit to create measurable, meaningful change. Six winners will be selected, one per category, and each will receive a conference-only pass to posit::conf(2026).</p>
<ul>
<li><a href="https://docs.google.com/forms/d/e/1FAIpQLSfQrWnEQ_wlc5lhyn5BLgU0mvfWDXb1XSXhq9PoSERdWSZS3g/viewform" target="_blank" rel="noopener">Submit your nomination before July 20th.</a></li>
</ul>
<h2 id="key-product-updates-and-new-releases">Key product updates and new releases
</h2>
<h3 id="data-visualization-and-reporting">Data visualization and reporting
</h3>
<h4 id="ggsql-041">ggsql 0.4.1
</h4>
<p><a href="https://ggsql.org/" target="_blank" rel="noopener">ggsql</a> 0.4.1 introduces spatial plotting capabilities with database-backed geometry processing, supporting WKB format data, 21 map projections for cartographic accuracy, and a built-in Natural Earth world dataset for creating choropleth maps and geographic visualizations with backends like DuckDB spatial, PostGIS, and SpatiaLite.</p>
<ul>
<li>Learn more in the <a href="https://opensource.posit.co/blog/2026-06-23_ggsql_0_4_1/" target="_blank" rel="noopener">ggsql 0.4.1: Spatial plotting and in-layer aggregation</a> blog post.</li>
</ul>
<h4 id="ask-more-of-your-dashboard-with-querychat-and-ggsql">Ask more of your dashboard with querychat and ggsql
</h4>
<p><a href="https://posit-dev.github.io/querychat/" target="_blank" rel="noopener">querychat</a> now supports ggsql-powered visualizations, enabling natural language data exploration in dashboards through SQL-only execution (no arbitrary code), with three pre-built tools for visualizing, querying, and filtering data reactively. The package works in both Python and R, integrates with <a href="https://shiny.posit.co/" target="_blank" rel="noopener">Shiny</a> dashboards, and supports Snowflake Semantic Models for business logic definitions.</p>
<ul>
<li>Learn more in the <a href="https://opensource.posit.co/blog/2026-06-17_querychat-ggsql/" target="_blank" rel="noopener">Ask more of your dashboard with querychat and ggsql</a> blog post.</li>
</ul>
<h4 id="great-tables-0220">Great Tables 0.22.0
</h4>
<p><a href="https://posit-dev.github.io/great-tables/" target="_blank" rel="noopener">Great Tables</a> v0.22.0 significantly expands Python table presentation capabilities with footnote support, group-wise and grand summary row calculations, column merging utilities for uncertainty and ranges, text transformation methods, value substitution helpers, duration and parts-per formatters, image export functionality via gtsave(), enhanced LaTeX rendering, and makes Pandas an optional dependency for Polars-only workflows. (impressive update!)</p>
<ul>
<li>Learn more in the <a href="https://opensource.posit.co/blog/2026-06-25_great-tables-0-22-0/" target="_blank" rel="noopener">Great Tables v0.22.0</a> blog post.</li>
</ul>
<h3 id="data-access">Data access
</h3>
<h4 id="dbplyr-260">dbplyr 2.6.0
</h4>
<p><a href="https://dbplyr.tidyverse.org/" target="_blank" rel="noopener">dbplyr</a> 2.6.0 introduces ADBC support via adbi for faster Arrow-based data transfer, JDBC support, new SQL dialect separation, and query composition functions.</p>
<ul>
<li>Learn more in the <a href="https://opensource.posit.co/blog/2026-06-17_dbplyr-2-6-0/" target="_blank" rel="noopener">dbplyr 2.6.0</a> blog post.</li>
</ul>
<h4 id="webr-060">webR 0.6.0
</h4>
<p><a href="https://docs.r-wasm.org/webr/latest/" target="_blank" rel="noopener">webR</a> 0.6.0 upgrades to R 4.6.0 and adds async/await support for JavaScript Promises, curl and httr2 compatibility through WebSocket traffic proxying, modern Fortran fixes for expanded package support, and updated system libraries including OpenSSL 3.5.1 and Emscripten 5.0.7. The release powers interactive R experiences in Quarto Live and Shinylive.</p>
<ul>
<li>Learn more in the <a href="https://opensource.posit.co/blog/2026-06-18_webr-0-6-0/" target="_blank" rel="noopener">webR 0.6.0</a> blog post.</li>
</ul>
<h3 id="developer-tools-and-ai">Developer tools and AI
</h3>
<h4 id="debrief-010">debrief 0.1.0
</h4>
<p>The <a href="https://r-lib.github.io/debrief/" target="_blank" rel="noopener">debrief</a> package converts profvis profiling output into text-based summaries designed for AI agents, enabling AI-assisted performance optimization by providing structured reports on hotspots, call trees, and memory allocations that AI systems can read and act upon.</p>
<ul>
<li>Learn more in the <a href="https://opensource.posit.co/blog/2026-06-22_debrief-0-1-0/" target="_blank" rel="noopener">debrief 0.1.0</a> blog post.</li>
</ul>
<h4 id="pkgsite-010">pkgsite 0.1.0
</h4>
<p><a href="https://edgararuiz.github.io/pkgsite/" target="_blank" rel="noopener">pkgsite</a> 0.1.0 converts R package .Rd documentation files into <a href="https://quarto.org/" target="_blank" rel="noopener">Quarto</a> .qmd files, enabling custom documentation sites with Quarto’s freeze feature for local example rendering, unified R/Python documentation when combined with Quartodoc, and flexible template customization. The package is available on CRAN and provides an alternative to pkgdown.</p>
<ul>
<li>Learn more in the <a href="https://opensource.posit.co/blog/2026-06-18_pkgsite-0-1-0/" target="_blank" rel="noopener">pkgsite 0.1.0</a> blog post.</li>
</ul>
<h4 id="watcher-020">watcher 0.2.0
</h4>
<p><a href="https://watcher.r-lib.org/" target="_blank" rel="noopener">Watcher</a> is a lightweight R package that watches files and directories for changes and reacts in the background. It’s quietly been the engine behind Shiny&rsquo;s auto-reload for the past year. With the CRAN release of 0.2.0, we&rsquo;re excited to introduce it as a general-purpose filesystem watcher for R developers.</p>
<ul>
<li>Learn more in the <a href="https://opensource.posit.co/blog/2026-06-29_watcher-0-2-0/" target="_blank" rel="noopener">watcher 0.2.0</a> blog post.</li>
</ul>
<h3 id="development-environment">Development environment
</h3>
<h4 id="air-0100">Air 0.10.0
</h4>
<p><a href="https://posit-dev.github.io/air/" target="_blank" rel="noopener">Air</a> 0.10.0 introduces configurable assignment style enforcement allowing teams to standardize on arrow (<code>&lt;-</code>), equal (<code>=</code>), or preserve existing styles, along with enhanced IDE integrations for Positron and RStudio, multiple installation methods via PyPI and conda-forge, pre-commit hook support, stdin integration for editors, and shell completions.</p>
<ul>
<li>Learn more in the <a href="https://opensource.posit.co/blog/2026-06-26_air-0-10-0/" target="_blank" rel="noopener">Air 0.10.0</a> blog post.</li>
</ul>
<h4 id="whats-new-in-positron">What’s new in Positron
</h4>
<p><a href="https://positron.posit.co/" target="_blank" rel="noopener">Positron</a>’s June release includes a lot of highly requested features:</p>
<ul>
<li>Inline output for Quarto (one of Positron’s most-requested features ever!)</li>
<li>Posit Assistant, the successor to Positron Assistant</li>
<li>Packages pane improvements</li>
<li>A more customizable interface</li>
</ul>
<p>For more, check out the <a href="https://opensource.posit.co/blog/2026-06-08_positron-2026-06-release/" target="_blank" rel="noopener">Positron June Release Highlights</a> post and <a href="https://posit.co/positron-updates-signup" target="_blank" rel="noopener">subscribe to Positron emails</a>.</p>
<p>Did you know that many of the most upvoted RStudio feature requests are already implemented in Positron? Learn about ten of them in the <a href="https://opensource.posit.co/blog/2026-06-10_rstudios-top-features-in-positron/" target="_blank" rel="noopener">RStudio’s Top Feature Requests … In Positron blog post</a>!</p>
<h3 id="machine-learning-and-modeling">Machine learning and modeling
</h3>
<h4 id="brulee-100">brulee 1.0.0
</h4>
<p><a href="https://brulee.tidymodels.org/" target="_blank" rel="noopener">brulee</a> 1.0.0 significantly expands tabular deep learning capabilities in R with five new model architectures, GPU support including Apple Silicon, 32-bit precision for improved performance, and enhanced numerical stability, all integrated with the tidymodels ecosystem.</p>
<ul>
<li>Learn more in the <a href="https://opensource.posit.co/blog/2026-06-24_brulee-1-0-0/" target="_blank" rel="noopener">brulee 1.0.0</a> blog post.</li>
</ul>
<h4 id="catboost-support-in-tidymodels">CatBoost support in tidymodels
</h4>
<p>CatBoost gradient boosting support is now available in <a href="https://www.tidymodels.org/" target="_blank" rel="noopener">tidymodels</a> through the <code>boost_tree()</code> interface, providing access to CatBoost’s strong categorical feature handling with full tidymodels integration including hyperparameter tuning, cross-validation, efficient submodel optimization, and orbital package support for SQL generation and in-database predictions.</p>
<ul>
<li>Learn more in the <a href="https://opensource.posit.co/blog/2026-06-25_catboost-tidymodels/" target="_blank" rel="noopener">CatBoost support in tidymodels</a> blog post.</li>
</ul>
<h4 id="tidyclust-030">tidyclust 0.3.0
</h4>
<p><a href="https://tidyclust.tidymodels.org/index.html" target="_blank" rel="noopener">tidyclust</a> 0.3.0 introduces three new clustering model families and achieves full integration with tidymodels by replacing tidyclust-specific functions with native tune package support.</p>
<ul>
<li>Learn more in the <a href="https://opensource.posit.co/blog/2026-06-15_tidyclust-0-3-0/" target="_blank" rel="noopener">tidyclust 0.3.0</a> blog post.</li>
</ul>
<h2 id="event-roundup">Event roundup
</h2>
<p>We were all over the world this month, discussing how to adopt new data tools, get better at old ones, and just loving being part of the community. If you want to learn more about where we were, or see where we’ll be next, check out our <a href="https://opensource.posit.co/events/" target="_blank" rel="noopener">event page</a>.</p>
<p>Watch the recordings from some of these events:</p>















  
  
  
  
  

  
  
  
  
  
    
  

  
  
  
  
  
    
  

  
  
  
  
  



<div class="grid grid-cols-2 gap-6 xl:gap-8 xl:gap-8 mb-6">
  
    <div>
      











  
  
  
  
  
















  
  
    
  











  
  





  
    
  









  
  






  





  



  

  

  

  

  

  

  

  

  

  

  

  

  

  




















  
    
  





  
    
  
























<div id="item-27ed749654bd2d6c044eb1d6fb3bf2e9" class="@container h-full">
  <a href="https://opensource.posit.co/resources/videos/2026-06-15_neal-richardson-mcp-or-not-mcp-pydata-london-26/" title="Neal Richardson - MCP, or not MCP | Pydata London 26"
     class="card-link flex flex-col @venti:flex-row rounded-xl  h-full">

      



      
      

    
    <div class="w-full @venti:w-1/2 aspect-[40/21] flex-shrink-0 flex items-center justify-center overflow-hidden rounded-xl">
      
        









  
  
    
    

    

    
      
      

      
      
      

      
      
      
      

      <picture class="hidden @max-tall:block w-full h-full">
        <source
          type="image/webp"
          srcset="/resources/videos/2026-06-15_neal-richardson-mcp-or-not-mcp-pydata-london-26/thumbnail_hu_2e4f2a3a58db4627.webp 1x,
                  /resources/videos/2026-06-15_neal-richardson-mcp-or-not-mcp-pydata-london-26/thumbnail_hu_3bea74d726538bdd.webp 2x" />
        <img
          src="https://opensource.posit.co/resources/videos/2026-06-15_neal-richardson-mcp-or-not-mcp-pydata-london-26/thumbnail_hu_7524b87c91de63ad.jpg"
          srcset="/resources/videos/2026-06-15_neal-richardson-mcp-or-not-mcp-pydata-london-26/thumbnail_hu_7524b87c91de63ad.jpg 1x,
                  /resources/videos/2026-06-15_neal-richardson-mcp-or-not-mcp-pydata-london-26/thumbnail_hu_e7f65162a2cb51e6.jpg 2x"
          alt="Neal Richardson - MCP, or not MCP | Pydata London 26"
          class="mx-auto h-full w-full object-cover"
          loading="lazy" />
      </picture>
    
      
      

      
      
      

      
      
      
      

      <picture class="hidden @tall:@max-grande:block w-full h-full">
        <source
          type="image/webp"
          srcset="/resources/videos/2026-06-15_neal-richardson-mcp-or-not-mcp-pydata-london-26/thumbnail_hu_3bea74d726538bdd.webp 1x,
                  /resources/videos/2026-06-15_neal-richardson-mcp-or-not-mcp-pydata-london-26/thumbnail_hu_168415f79709c6d1.webp 2x" />
        <img
          src="https://opensource.posit.co/resources/videos/2026-06-15_neal-richardson-mcp-or-not-mcp-pydata-london-26/thumbnail_hu_e7f65162a2cb51e6.jpg"
          srcset="/resources/videos/2026-06-15_neal-richardson-mcp-or-not-mcp-pydata-london-26/thumbnail_hu_e7f65162a2cb51e6.jpg 1x,
                  /resources/videos/2026-06-15_neal-richardson-mcp-or-not-mcp-pydata-london-26/thumbnail_hu_409671ed69280e4b.jpg 2x"
          alt="Neal Richardson - MCP, or not MCP | Pydata London 26"
          class="mx-auto h-full w-full object-cover"
          loading="lazy" />
      </picture>
    
      
      

      
      
      

      
      
      
      

      <picture class="hidden @grande:block w-full h-full">
        <source
          type="image/webp"
          srcset="/resources/videos/2026-06-15_neal-richardson-mcp-or-not-mcp-pydata-london-26/thumbnail_hu_168415f79709c6d1.webp 1x,
                  /resources/videos/2026-06-15_neal-richardson-mcp-or-not-mcp-pydata-london-26/thumbnail_hu_3829c4c9d7cfb126.webp 2x" />
        <img
          src="https://opensource.posit.co/resources/videos/2026-06-15_neal-richardson-mcp-or-not-mcp-pydata-london-26/thumbnail_hu_409671ed69280e4b.jpg"
          srcset="/resources/videos/2026-06-15_neal-richardson-mcp-or-not-mcp-pydata-london-26/thumbnail_hu_409671ed69280e4b.jpg 1x,
                  /resources/videos/2026-06-15_neal-richardson-mcp-or-not-mcp-pydata-london-26/thumbnail_hu_99b33ee74fa66f52.jpg 2x"
          alt="Neal Richardson - MCP, or not MCP | Pydata London 26"
          class="mx-auto h-full w-full object-cover"
          loading="lazy" />
      </picture>
    
  
  


      
    </div>

    
    <div class="hidden gap-y-2 @nip:flex @venti:w-1/2 flex-auto flex-col p-3 @venti:pl-5 text-gray-700 mt-2">

      
      

      
      
      <div class="hidden @short:flex flex-wrap gap-x-2 items-center text-xs font-medium text-gray-500">
        
          <span>Jun 15, 2026</span>
          <span>|</span>
        
        
        
          <span>34 min</span>
          <span>|</span>
        
        
          <span>308 views</span>
          
        
        
      </div>
      

      
      <h3 class="m-0! mt-3 font-semibold text-sm @grande:text-lg @venti:text-3xl line-clamp-2 text-sm @tall:text-base @grande:text-lg @venti:text-3xl text-gray-600">Neal Richardson - MCP, or not MCP | Pydata London 26</h3>
      

      
        <p class="m-0! text-xs @short:text-sm @grande:text-md @venti:text-lg line-clamp-2 short@line-clamp-3 @tall:line-clamp-3 font-medium text-gray-600">Neal Richardson - MCP, or not MCP | Pydata London 26 \Model Context Protocol is a standard for defining tools that can be made available to LLMs and AI applications. There’s a lot of noise out there about what you should use to get the best results from AI, so in this talk, I will provide some guidance on when you should use MCP, and when you should reach for some other tool. I will describe cases where MCP is the right tool for the job, and when other things, like skills or other context files, are better. I will also devote attention to questions of security and authentication, which are important for MCP, and provide concrete examples of how MCP servers can be used to unlock agentic workflows while also strengthening data governance. This talk is intended for those who are interested in using LLMs for workflows involving data. No prior experience with MCP is required.
Outline:
Intro: how can I get data from this API into my Claude Code session? What is MCP? When should you use it, when should you use other tools Work through an example Sharing and deploying MCP servers, alternatives and best practices Optimizing your tools for best results www.pydata.org
PyData is an educational program of NumFOCUS, a 501(c)3 non-profit organization in the United States. PyData provides a forum for the international community of users and developers of data analysis tools to share ideas and learn from each other. The global PyData network promotes discussion of best practices, new approaches, and emerging technologies for data management, processing, analytics, and visualization. PyData communities approach data science using many languages, including (but not limited to) Python, Julia, and R.
PyData conferences aim to be accessible and community-driven, with novice to advanced level presentations. PyData tutorials and talks bring attendees the latest project features along with cutting-edge use cases.
00:00 Welcome! 00:10 Help us add time stamps or captions to this video! See the description for details.
Want to help add timestamps to our YouTube videos to help with discoverability? Find out more here: https://github.com/numfocus/YouTubeVideoTimestamps
</p>
      

      
        <div class="text-sm @grande:text-md">
          <div class="mt-2 flex flex-row gap-x-4 items-center"><div class="flex flex-row flex-shrink-0"><img 
          src="https://opensource.posit.co/people/neal-richardson/profile.jpg" 
          alt="Neal Richardson" 
          class="my-0! w-6 h-6 rounded-full object-cover ring-2 ring-white "
          style="z-index: 10;"
        ></div><div class="line-clamp-2 font-medium text-gray-600">Neal Richardson</div></div>
        </div>
      

      <div class="grow"></div>
      
        
          <div class="hidden @grande:flex flex-wrap gap-x-1 gap-y-4 py-2 overflow-hidden h-10 items-end">
            
              <span class="pill">
                Python
              </span>
            
              <span class="pill">
                Tutorial
              </span>
            
              <span class="pill">
                Education
              </span>
            
              <span class="pill">
                NumFOCUS
              </span>
            
              <span class="pill">
                PyData
              </span>
            
              <span class="pill">
                Opensource
              </span>
            
              <span class="pill">
                Learn
              </span>
            
              <span class="pill">
                Software
              </span>
            
              <span class="pill">
                Python 3
              </span>
            
              <span class="pill">
                Julia
              </span>
            
              <span class="pill">
                Coding
              </span>
            
              <span class="pill">
                Learn to Code
              </span>
            
              <span class="pill">
                How to Program
              </span>
            
              <span class="pill">
                Scientific Programming
              </span>
            
          </div>
        
      
    </div>
  </a>
</div>


    </div>
  
    <div>
      











  
  
  
  
  
















  
  
    
  











  
  





  
    
  









  
  






  





  
    
  
    
  






















  
    
  





  
    
  
























<div id="item-0bea2d9d122698cc4c259ae2a49344c9" class="@container h-full">
  <a href="https://opensource.posit.co/resources/videos/2026-06-26_agents-for-correct-transparent-and-reproducible-data-analysis-simon-couch-sara-altman/" title="Agents for Correct, Transparent, and Reproducible Data Analysis - Simon Couch &amp; Sara Altman"
     class="card-link flex flex-col @venti:flex-row rounded-xl  h-full">

      



      
      

    
    <div class="w-full @venti:w-1/2 aspect-[40/21] flex-shrink-0 flex items-center justify-center overflow-hidden rounded-xl">
      
        









  
  
    
    

    

    
      
      

      
      
      

      
      
      
      

      <picture class="hidden @max-tall:block w-full h-full">
        <source
          type="image/webp"
          srcset="/resources/videos/2026-06-26_agents-for-correct-transparent-and-reproducible-data-analysis-simon-couch-sara-altman/thumbnail_hu_b03c3320e4321048.webp 1x,
                  /resources/videos/2026-06-26_agents-for-correct-transparent-and-reproducible-data-analysis-simon-couch-sara-altman/thumbnail_hu_709131f576b34e9b.webp 2x" />
        <img
          src="https://opensource.posit.co/resources/videos/2026-06-26_agents-for-correct-transparent-and-reproducible-data-analysis-simon-couch-sara-altman/thumbnail_hu_946b93830a7ce124.jpg"
          srcset="/resources/videos/2026-06-26_agents-for-correct-transparent-and-reproducible-data-analysis-simon-couch-sara-altman/thumbnail_hu_946b93830a7ce124.jpg 1x,
                  /resources/videos/2026-06-26_agents-for-correct-transparent-and-reproducible-data-analysis-simon-couch-sara-altman/thumbnail_hu_6f49f3aa2116d34a.jpg 2x"
          alt="Agents for Correct, Transparent, and Reproducible Data Analysis - Simon Couch &amp; Sara Altman"
          class="mx-auto h-full w-full object-cover"
          loading="lazy" />
      </picture>
    
      
      

      
      
      

      
      
      
      

      <picture class="hidden @tall:@max-grande:block w-full h-full">
        <source
          type="image/webp"
          srcset="/resources/videos/2026-06-26_agents-for-correct-transparent-and-reproducible-data-analysis-simon-couch-sara-altman/thumbnail_hu_709131f576b34e9b.webp 1x,
                  /resources/videos/2026-06-26_agents-for-correct-transparent-and-reproducible-data-analysis-simon-couch-sara-altman/thumbnail_hu_7b164a87556be464.webp 2x" />
        <img
          src="https://opensource.posit.co/resources/videos/2026-06-26_agents-for-correct-transparent-and-reproducible-data-analysis-simon-couch-sara-altman/thumbnail_hu_6f49f3aa2116d34a.jpg"
          srcset="/resources/videos/2026-06-26_agents-for-correct-transparent-and-reproducible-data-analysis-simon-couch-sara-altman/thumbnail_hu_6f49f3aa2116d34a.jpg 1x,
                  /resources/videos/2026-06-26_agents-for-correct-transparent-and-reproducible-data-analysis-simon-couch-sara-altman/thumbnail_hu_2dcdb2aac4711fb1.jpg 2x"
          alt="Agents for Correct, Transparent, and Reproducible Data Analysis - Simon Couch &amp; Sara Altman"
          class="mx-auto h-full w-full object-cover"
          loading="lazy" />
      </picture>
    
      
      

      
      
      

      
      
      
      

      <picture class="hidden @grande:block w-full h-full">
        <source
          type="image/webp"
          srcset="/resources/videos/2026-06-26_agents-for-correct-transparent-and-reproducible-data-analysis-simon-couch-sara-altman/thumbnail_hu_7b164a87556be464.webp 1x,
                  /resources/videos/2026-06-26_agents-for-correct-transparent-and-reproducible-data-analysis-simon-couch-sara-altman/thumbnail_hu_a0b0c1c85b31ff70.webp 2x" />
        <img
          src="https://opensource.posit.co/resources/videos/2026-06-26_agents-for-correct-transparent-and-reproducible-data-analysis-simon-couch-sara-altman/thumbnail_hu_2dcdb2aac4711fb1.jpg"
          srcset="/resources/videos/2026-06-26_agents-for-correct-transparent-and-reproducible-data-analysis-simon-couch-sara-altman/thumbnail_hu_2dcdb2aac4711fb1.jpg 1x,
                  /resources/videos/2026-06-26_agents-for-correct-transparent-and-reproducible-data-analysis-simon-couch-sara-altman/thumbnail_hu_f7c8a43de74d743a.jpg 2x"
          alt="Agents for Correct, Transparent, and Reproducible Data Analysis - Simon Couch &amp; Sara Altman"
          class="mx-auto h-full w-full object-cover"
          loading="lazy" />
      </picture>
    
  
  


      
    </div>

    
    <div class="hidden gap-y-2 @nip:flex @venti:w-1/2 flex-auto flex-col p-3 @venti:pl-5 text-gray-700 mt-2">

      
      

      
      
      <div class="hidden @short:flex flex-wrap gap-x-2 items-center text-xs font-medium text-gray-500">
        
          <span>Jun 26, 2026</span>
          <span>|</span>
        
        
        
          <span>47 min</span>
          <span>|</span>
        
        
          <span>179 views</span>
          
        
        
      </div>
      

      
      <h3 class="m-0! mt-3 font-semibold text-sm @grande:text-lg @venti:text-3xl line-clamp-2 text-sm @tall:text-base @grande:text-lg @venti:text-3xl text-gray-600">Agents for Correct, Transparent, and Reproducible Data Analysis - Simon Couch &amp; Sara Altman</h3>
      

      
        <p class="m-0! text-xs @short:text-sm @grande:text-md @venti:text-lg line-clamp-2 short@line-clamp-3 @tall:line-clamp-3 font-medium text-gray-600">Agents for Correct, Transparent, and Reproducible Data Analysis - Simon Couch &amp; Sara Altman (Posit)
Abstract: How do we build competent data analysis agents? Data analysis requires a willingness to pause, question conclusions, and dig into subtleties. Frontier LLMs, however, are optimized to push tasks toward completion, not to slow down when something seems off. This tendency works well for coding agents, where success is often verifiable. But for data analysis, verification is more complicated, and autonomous work by the agent can be at odds with the spirit of the discipline. Drawing on our experience building data analysis agents, we&rsquo;ll share evaluations that expose where LLM-driven analysis goes wrong and design patterns that keep analyses correct, transparent, and reproducible.
Resources mentioned in the session:
Presentation Slides: https://simonpcouch.github.io/gen-ai-pharma-26 Presentation GitHub repository: https://github.com/simonpcouch/gen-ai-pharma-26 bluffbench: https://github.com/simonpcouch/bluffbench Posit Assistant Terminal (TUI): https://posit-dev.github.io/assistant/docs/downloads/tui/ Posit AI Newsletter: https://opensource.posit.co/tags/ai-newsletter/ Speakers:
Simon Couch builds tools that make the work of data science more joyful and effective. As an engineer on the AI Core Team at Posit, his work spans coding agents, model evaluations, inference engineering, and next-edit-suggestion systems. Drawing on his background in statistics, Simon spent several years authoring and maintaining core packages in the open-source tidymodels framework—like stacks, broom, and infer — before shifting his focus to LLMs. He blogs about his work at simonpcouch.com. Simon authors the Posit AI Newsletter along with Sara Altman.
Sara Altman is a Senior Developer Advocate on the AI Core team at Posit, where she focuses on how AI can be effectively and responsibly used for data science. Previously, she helped build Posit Academy and taught data science and R at Stanford. Sara authors the Posit AI Newsletter along with Simon Couch.
Presented at the 2026 R/Pharma GenAI Day
</p>
      

      
        <div class="text-sm @grande:text-md">
          <div class="mt-2 flex flex-row gap-x-4 items-center"><div class="flex flex-row flex-shrink-0"><img 
          src="https://opensource.posit.co/people/sara-altman/profile.jpg" 
          alt="Sara Altman" 
          class="my-0! w-6 h-6 rounded-full object-cover ring-2 ring-white "
          style="z-index: 10;"
        ><img 
          src="https://opensource.posit.co/people/simon-couch/profile.jpg" 
          alt="Simon Couch" 
          class="my-0! w-6 h-6 rounded-full object-cover ring-2 ring-white -ml-2"
          style="z-index: 9;"
        ></div><div class="line-clamp-2 font-medium text-gray-600">Sara Altman,&nbsp;Simon Couch</div></div>
        </div>
      

      <div class="grow"></div>
      
        
          <div class="hidden @grande:flex flex-wrap gap-x-1 gap-y-4 py-2 overflow-hidden h-10 items-end">
            
              <span class="pill">
                infer
              </span>
            
              <span class="pill">
                tidymodels
              </span>
            
          </div>
        
      
    </div>
  </a>
</div>


    </div>
  
</div>


<h2 id="showcases-from-the-community">Showcases from the community
</h2>









  
  
    
  

  
  
    
  





  


<div class="grid gap-12 items-start mt-12 md:grid-cols-2 ">
  
  
    
    
    
      <div class="prose max-w-none "><p>Brilliant Earth turned their Marketing Mix Model into a <a href="https://streamlit.io/" target="_blank" rel="noopener">Streamlit</a> app deployed on <a href="https://posit.co/products/enterprise/connect" target="_blank" rel="noopener">Posit Connect</a> via the <a href="https://docs.posit.co/partnerships/snowflake/" target="_blank" rel="noopener">Snowflake Native App</a>, so their marketing team can dig into channel performance and run scenario planning on their own. One of the campaigns in the mix: their recent Ring Pop collaboration.</p>
<ul>
<li><a href="https://posit.co/about/customer-stories/brilliant-earth" target="_blank" rel="noopener">Check out the spotlight.</a></li>
</ul></div>
    
  
    
    
    
      <div class="prose max-w-none "><div class="not-prose"><figure>
      <img class="h-auto max-w-full rounded-lg"
        src="https://opensource.posit.co/blog/2026-07-01_2026-07-glimpse/images/image01.png"
        alt="Brilliant Earth logo with rings in the background." 
        loading="lazy"
      >
    </figure></div></div>
    
  
</div>










  
  
    
  

  
  
    
  





  


<div class="grid gap-12 items-start mt-12 md:grid-cols-2 ">
  
  
    
    
    
      <div class="prose max-w-none "><div class="not-prose"><figure>
      <img class="h-auto max-w-full rounded-lg"
        src="https://opensource.posit.co/blog/2026-07-01_2026-07-glimpse/images/image02.png"
        alt="Dashboard showing Lorcana market data analysis with multiple charts displaying price trends and forecasting visualizations" 
        loading="lazy"
      >
    </figure></div></div>
    
  
    
    
    
      <div class="prose max-w-none "><p><a href="https://www.linkedin.com/in/leo-ohyama-phd-52358387/" target="_blank" rel="noopener">Leo Ohyama</a> recently shared a fantastic Lorcana Market Data Analysis &amp; Forecasting dashboard that showcases the power of Python, R, Positron, and Quarto working together.</p>
<p>Leo included detailed documentation in the GitHub repository, a great resource for anyone interested in market forecasting or multi-tool workflows. Thanks for sharing your work with the community, Leo!</p>
<ul>
<li><a href="https://lorecaster.ink/" target="_blank" rel="noopener">Lorcana dashboard</a></li>
<li><a href="https://github.com/leoohyama/lorcana" target="_blank" rel="noopener">Lorcana GitHub repo</a></li>
</ul>
</div>
    
  
</div>










  
  
    
  

  
  
    
  





  


<div class="grid gap-12 items-start mt-12 md:grid-cols-2 ">
  
  
    
    
    
      <div class="prose max-w-none "><p>We were recently joined by <a href="https://opensource.posit.co/people/thomas-lin-pedersen/" target="_blank" rel="noopener">Thomas Lin Pedersen</a> on the <a href="https://pos.it/dslab" target="_blank" rel="noopener">Data Science Lab</a>, where he introduced the new <a href="https://ggsql.org/" target="_blank" rel="noopener">ggsql</a> package.</p>
<p>(Almost) immediately after the DS Lab, <a href="https://www.linkedin.com/in/drspoulsen/" target="_blank" rel="noopener">Dylan Poulsen</a> wrote a blog post on exploring two years of swim data with ggsql! Dylan, we’re convinced you write blogs at the speed of ggsql.</p>
<ul>
<li><a href="https://dylanpoulsen.com/posts/2026-06-16-ggsql-swimming.html" target="_blank" rel="noopener">Exploring the New ggsql Package with Two Years of Swim Data</a> blog post</li>
</ul>
</div>
    
  
    
    
    
      <div class="prose max-w-none "><div class="not-prose"><figure>
      <img class="h-auto max-w-full rounded-lg"
        src="https://opensource.posit.co/blog/2026-07-01_2026-07-glimpse/images/image03.png"
        alt="Visualization created with ggsql showing swim data analysis with line charts tracking performance over time" 
        loading="lazy"
      >
    </figure></div></div>
    
  
</div>

<p>We usually find these projects on social media. If you’re on LinkedIn, be sure to follow and tag <a href="https://www.linkedin.com/showcase/posit-open-source/" target="_blank" rel="noopener">Posit Open Source</a> for us to share the amazing things you’re working on!</p>
<h2 id="whats-next">What’s next
</h2>
<p>We’re taking a short break in July before returning with more community hangouts!</p>
<ul>
<li>On July 21, Gina Reynolds will join the Data Science Lab (a fun, chill time with live code) to show we can extend ggplot2 by creating our own custom extensions. Register here: <a href="https://pos.it/dslab" target="_blank" rel="noopener">https://pos.it/dslab</a></li>
</ul>
<p>In the meantime, check out some past Data Science Lab episodes:</p>















  
  
  
  
  

  
  
  
  
  
    
  

  
  
  
  
  
    
  

  
  
  
  
  
    
  

  
  
  
  
  



<div class="grid grid-cols-3 gap-6 xl:gap-8 xl:gap-8 mb-6">
  
    <div>
      











  
  
  
  
  
















  
  
    
  











  
  





  
    
  









  
  






  





  
    
  
    
  
    
  
    
  
    
  
    
  






















  
    
  





  
    
  
























<div id="item-e1a7fb00aebe5239e2fb98a5bfb01eea" class="@container h-full">
  <a href="https://opensource.posit.co/resources/videos/2026-05-29_async-parallel-r-with-mirai-charlie-gao-data-science-lab/" title="Async &amp; Parallel R with {mirai} | Charlie Gao | Data Science Lab"
     class="card-link flex flex-col @venti:flex-row rounded-xl  h-full">

      



      
      

    
    <div class="w-full @venti:w-1/2 aspect-[40/21] flex-shrink-0 flex items-center justify-center overflow-hidden rounded-xl">
      
        









  
  
    
    

    

    
      
      

      
      
      

      
      
      
      

      <picture class="hidden @max-tall:block w-full h-full">
        <source
          type="image/webp"
          srcset="/resources/videos/2026-05-29_async-parallel-r-with-mirai-charlie-gao-data-science-lab/thumbnail_hu_c3d165a6da89ccf6.webp 1x,
                  /resources/videos/2026-05-29_async-parallel-r-with-mirai-charlie-gao-data-science-lab/thumbnail_hu_e010d66820a12428.webp 2x" />
        <img
          src="https://opensource.posit.co/resources/videos/2026-05-29_async-parallel-r-with-mirai-charlie-gao-data-science-lab/thumbnail_hu_39e3051bf743594c.jpg"
          srcset="/resources/videos/2026-05-29_async-parallel-r-with-mirai-charlie-gao-data-science-lab/thumbnail_hu_39e3051bf743594c.jpg 1x,
                  /resources/videos/2026-05-29_async-parallel-r-with-mirai-charlie-gao-data-science-lab/thumbnail_hu_8760612808811c9a.jpg 2x"
          alt="Async &amp; Parallel R with {mirai} | Charlie Gao | Data Science Lab"
          class="mx-auto h-full w-full object-cover"
          loading="lazy" />
      </picture>
    
      
      

      
      
      

      
      
      
      

      <picture class="hidden @tall:@max-grande:block w-full h-full">
        <source
          type="image/webp"
          srcset="/resources/videos/2026-05-29_async-parallel-r-with-mirai-charlie-gao-data-science-lab/thumbnail_hu_e010d66820a12428.webp 1x,
                  /resources/videos/2026-05-29_async-parallel-r-with-mirai-charlie-gao-data-science-lab/thumbnail_hu_1e8d89ec085c5bba.webp 2x" />
        <img
          src="https://opensource.posit.co/resources/videos/2026-05-29_async-parallel-r-with-mirai-charlie-gao-data-science-lab/thumbnail_hu_8760612808811c9a.jpg"
          srcset="/resources/videos/2026-05-29_async-parallel-r-with-mirai-charlie-gao-data-science-lab/thumbnail_hu_8760612808811c9a.jpg 1x,
                  /resources/videos/2026-05-29_async-parallel-r-with-mirai-charlie-gao-data-science-lab/thumbnail_hu_ed5d4972ccad3c7.jpg 2x"
          alt="Async &amp; Parallel R with {mirai} | Charlie Gao | Data Science Lab"
          class="mx-auto h-full w-full object-cover"
          loading="lazy" />
      </picture>
    
      
      

      
      
      

      
      
      
      

      <picture class="hidden @grande:block w-full h-full">
        <source
          type="image/webp"
          srcset="/resources/videos/2026-05-29_async-parallel-r-with-mirai-charlie-gao-data-science-lab/thumbnail_hu_1e8d89ec085c5bba.webp 1x,
                  /resources/videos/2026-05-29_async-parallel-r-with-mirai-charlie-gao-data-science-lab/thumbnail_hu_897267d62d43465d.webp 2x" />
        <img
          src="https://opensource.posit.co/resources/videos/2026-05-29_async-parallel-r-with-mirai-charlie-gao-data-science-lab/thumbnail_hu_ed5d4972ccad3c7.jpg"
          srcset="/resources/videos/2026-05-29_async-parallel-r-with-mirai-charlie-gao-data-science-lab/thumbnail_hu_ed5d4972ccad3c7.jpg 1x,
                  /resources/videos/2026-05-29_async-parallel-r-with-mirai-charlie-gao-data-science-lab/thumbnail_hu_6f4f6696051268a6.jpg 2x"
          alt="Async &amp; Parallel R with {mirai} | Charlie Gao | Data Science Lab"
          class="mx-auto h-full w-full object-cover"
          loading="lazy" />
      </picture>
    
  
  


      
    </div>

    
    <div class="hidden gap-y-2 @nip:flex @venti:w-1/2 flex-auto flex-col p-3 @venti:pl-5 text-gray-700 mt-2">

      
      

      
      
      <div class="hidden @short:flex flex-wrap gap-x-2 items-center text-xs font-medium text-gray-500">
        
          <span>May 29, 2026</span>
          <span>|</span>
        
        
        
          <span>57 min</span>
          <span>|</span>
        
        
          <span>1.3k views</span>
          
        
        
      </div>
      

      
      <h3 class="m-0! mt-3 font-semibold text-sm @grande:text-lg @venti:text-3xl line-clamp-2 text-sm @tall:text-base @grande:text-lg @venti:text-3xl text-gray-600">Async &amp; Parallel R with {mirai} | Charlie Gao | Data Science Lab</h3>
      

      
        <p class="m-0! text-xs @short:text-sm @grande:text-md @venti:text-lg line-clamp-2 short@line-clamp-3 @tall:line-clamp-3 font-medium text-gray-600">The Data Science Lab is a live weekly call. Register at pos.it/dslab! Discord invites go out each week on lives calls. We&rsquo;d love to have you!
The Lab is an open, messy space for learning and asking questions. Think of it like pair coding with a friend or two. Learn something new, and share what you know to help others grow.
On this call, Libby Heeren is joined by Charlie Gao, who walks through async and parallel programming using the mirai package for R. Charlie is the author of {mirai} and {mori}!
Charlie demonstrates how mirai lets you run R code in parallel across multiple cores or even distributed across remote machines. He covers the key differences between parallel and async programming, shows how to set up worker daemons (said like &ldquo;demons&rdquo;), scale resources dynamically, and connect to remote machines via SSH. Whether you&rsquo;re running long computations, training models, or building Shiny apps, mirai helps you make the most of your computing resources without blocking your main R session:)
Hosting crew from Posit: Libby Heeren, Isabella Velasquez
Charlie Gao&rsquo;s GitHub: https://github.com/shikokuchuo Charlie Gao&rsquo;s Bluesky: https://bsky.app/profile/shikokuchuo.net Charlie Gao&rsquo;s LinkedIn: https://www.linkedin.com/in/charliegao/ Charlie Gao&rsquo;s Mastodon: https://fosstodon.org/@shikokuchuo
Resources mentioned in the video and chat: mirai package website: https://mirai.r-lib.org/ mirai GitHub repository: https://github.com/r-lib/mirai AskDeepSeek chatbot for mirai documentation: https://mirai.r-lib.org/ (click &ldquo;ask deep wiki&rdquo; button) mirai - Promises (Shiny and Plumber): https://mirai.r-lib.org/articles/v02-promises.html mirai - Serialization: https://mirai.r-lib.org/articles/v03-serialization.html mirai - OpenTelemetry: https://mirai.r-lib.org/articles/v05-opentelemetry.html mirai stop_mirai function: https://mirai.r-lib.org/reference/stop_mirai.html mirai skill for Claude Code: https://github.com/r-lib/mirai/blob/main/.claude/skills/mirai/SKILL.md Plumber2 package: https://plumber2.posit.co/ Daemon (computing) on Wikipedia: https://en.wikipedia.org/wiki/Daemon_(computing)
► Subscribe to Our Channel Here: https://bit.ly/2TzgcOu Follow Us Here: Website: https://www.posit.co Hangout: https://pos.it/dsh The Lab: https://pos.it/dslab LinkedIn: https://www.linkedin.com/company/posit-software Bluesky: https://bsky.app/profile/posit.co
Thanks for hanging out with us!
Timestamps of Questions / Topics: 00:00 Introduction 03:33 &ldquo;What is async programming and how is it different from parallel?&rdquo; 06:57 AskDeepSeek chatbot for the Mirai package 09:40 Setting up the Positron IDE with activity bar on top 15:25 &ldquo;What was the motivation or need for developing Mirai?&rdquo; 22:10 Mirai map function for parallel processing 25:25 &ldquo;Do the contents of Mirai inherit definitions from the global environment?&rdquo; 29:00 &ldquo;What&rsquo;s the difference between Mirai versus promises and future?&rdquo; 31:50 Demonstrating sequential vs parallel processing 36:00 &ldquo;Can you use Mirai with HPC?&rdquo; 37:07 Dynamically scaling workers by adding and removing daemons 38:38 Setting up daemons with URLs for network connections 42:05 Launching workers over SSH to remote machines 43:09 SSH tunneling to connect workers without open ports 51:14 &ldquo;Does Mirai allow R to perform the same thing as NumPy?&rdquo; 51:54 &ldquo;Does Mirai ship with some kind of task viewing dashboard?&rdquo; 52:35 &ldquo;Can we use parallel::detectCores() to see how many daemons we can use?&rdquo; 53:58 &ldquo;Would parallel processing be more useful than async processing in typical data science work?&rdquo; 55:00 Mirai skill for Claude Code and AI agents
</p>
      

      
        <div class="text-sm @grande:text-md">
          <div class="mt-2 flex flex-row gap-x-4 items-center"><div class="flex flex-row flex-shrink-0"><img 
          src="https://opensource.posit.co/people/charlie-gao/profile.jpg" 
          alt="Charlie Gao" 
          class="my-0! w-6 h-6 rounded-full object-cover ring-2 ring-white "
          style="z-index: 10;"
        ></div><div class="line-clamp-2 font-medium text-gray-600">Charlie Gao</div></div>
        </div>
      

      <div class="grow"></div>
      
        
          <div class="hidden @grande:flex flex-wrap gap-x-1 gap-y-4 py-2 overflow-hidden h-10 items-end">
            
              <span class="pill">
                mirai
              </span>
            
              <span class="pill">
                mori
              </span>
            
              <span class="pill">
                plumber
              </span>
            
              <span class="pill">
                plumber2
              </span>
            
              <span class="pill">
                Positron
              </span>
            
              <span class="pill">
                Shiny
              </span>
            
          </div>
        
      
    </div>
  </a>
</div>


    </div>
  
    <div>
      











  
  
  
  
  
















  
  
    
  











  
  





  
    
  









  
  






  





  
    
  
    
  
    
  
    
  
    
  






















  
    
  





  
    
  
























<div id="item-451ed6564c115dcc7bdce93d95ee2802" class="@container h-full">
  <a href="https://opensource.posit.co/resources/videos/2026-06-23_data-dictionaries-parquet-claude-hadley-wickham-data-science-lab/" title="Data dictionaries, parquet, &amp; Claude | Hadley Wickham | Data Science Lab"
     class="card-link flex flex-col @venti:flex-row rounded-xl  h-full">

      



      
      

    
    <div class="w-full @venti:w-1/2 aspect-[40/21] flex-shrink-0 flex items-center justify-center overflow-hidden rounded-xl">
      
        









  
  
    
    

    

    
      
      

      
      
      

      
      
      
      

      <picture class="hidden @max-tall:block w-full h-full">
        <source
          type="image/webp"
          srcset="/resources/videos/2026-06-23_data-dictionaries-parquet-claude-hadley-wickham-data-science-lab/thumbnail_hu_a23a02bc126732e3.webp 1x,
                  /resources/videos/2026-06-23_data-dictionaries-parquet-claude-hadley-wickham-data-science-lab/thumbnail_hu_36f7dc1a902e03a.webp 2x" />
        <img
          src="https://opensource.posit.co/resources/videos/2026-06-23_data-dictionaries-parquet-claude-hadley-wickham-data-science-lab/thumbnail_hu_7d73634aa10248d.jpg"
          srcset="/resources/videos/2026-06-23_data-dictionaries-parquet-claude-hadley-wickham-data-science-lab/thumbnail_hu_7d73634aa10248d.jpg 1x,
                  /resources/videos/2026-06-23_data-dictionaries-parquet-claude-hadley-wickham-data-science-lab/thumbnail_hu_53383455a06a605f.jpg 2x"
          alt="Data dictionaries, parquet, &amp; Claude | Hadley Wickham | Data Science Lab"
          class="mx-auto h-full w-full object-cover"
          loading="lazy" />
      </picture>
    
      
      

      
      
      

      
      
      
      

      <picture class="hidden @tall:@max-grande:block w-full h-full">
        <source
          type="image/webp"
          srcset="/resources/videos/2026-06-23_data-dictionaries-parquet-claude-hadley-wickham-data-science-lab/thumbnail_hu_36f7dc1a902e03a.webp 1x,
                  /resources/videos/2026-06-23_data-dictionaries-parquet-claude-hadley-wickham-data-science-lab/thumbnail_hu_5a96a040aff01af5.webp 2x" />
        <img
          src="https://opensource.posit.co/resources/videos/2026-06-23_data-dictionaries-parquet-claude-hadley-wickham-data-science-lab/thumbnail_hu_53383455a06a605f.jpg"
          srcset="/resources/videos/2026-06-23_data-dictionaries-parquet-claude-hadley-wickham-data-science-lab/thumbnail_hu_53383455a06a605f.jpg 1x,
                  /resources/videos/2026-06-23_data-dictionaries-parquet-claude-hadley-wickham-data-science-lab/thumbnail_hu_d35a1a3e9dce2346.jpg 2x"
          alt="Data dictionaries, parquet, &amp; Claude | Hadley Wickham | Data Science Lab"
          class="mx-auto h-full w-full object-cover"
          loading="lazy" />
      </picture>
    
      
      

      
      
      

      
      
      
      

      <picture class="hidden @grande:block w-full h-full">
        <source
          type="image/webp"
          srcset="/resources/videos/2026-06-23_data-dictionaries-parquet-claude-hadley-wickham-data-science-lab/thumbnail_hu_5a96a040aff01af5.webp 1x,
                  /resources/videos/2026-06-23_data-dictionaries-parquet-claude-hadley-wickham-data-science-lab/thumbnail_hu_264773719908e6d9.webp 2x" />
        <img
          src="https://opensource.posit.co/resources/videos/2026-06-23_data-dictionaries-parquet-claude-hadley-wickham-data-science-lab/thumbnail_hu_d35a1a3e9dce2346.jpg"
          srcset="/resources/videos/2026-06-23_data-dictionaries-parquet-claude-hadley-wickham-data-science-lab/thumbnail_hu_d35a1a3e9dce2346.jpg 1x,
                  /resources/videos/2026-06-23_data-dictionaries-parquet-claude-hadley-wickham-data-science-lab/thumbnail_hu_d52ea0ae3df67b45.jpg 2x"
          alt="Data dictionaries, parquet, &amp; Claude | Hadley Wickham | Data Science Lab"
          class="mx-auto h-full w-full object-cover"
          loading="lazy" />
      </picture>
    
  
  


      
    </div>

    
    <div class="hidden gap-y-2 @nip:flex @venti:w-1/2 flex-auto flex-col p-3 @venti:pl-5 text-gray-700 mt-2">

      
      

      
      
      <div class="hidden @short:flex flex-wrap gap-x-2 items-center text-xs font-medium text-gray-500">
        
          <span>Jun 23, 2026</span>
          <span>|</span>
        
        
        
          <span>58 min</span>
          <span>|</span>
        
        
          <span>4.9k views</span>
          
        
        
      </div>
      

      
      <h3 class="m-0! mt-3 font-semibold text-sm @grande:text-lg @venti:text-3xl line-clamp-2 text-sm @tall:text-base @grande:text-lg @venti:text-3xl text-gray-600">Data dictionaries, parquet, &amp; Claude | Hadley Wickham | Data Science Lab</h3>
      

      
        <p class="m-0! text-xs @short:text-sm @grande:text-md @venti:text-lg line-clamp-2 short@line-clamp-3 @tall:line-clamp-3 font-medium text-gray-600">The Data Science Lab is a live weekly call. Register at pos.it/dslab! Discord invites go out each week on lives calls. We&rsquo;d love to have you!
The Lab is an open, messy space for learning and asking questions. Think of it like pair coding with a friend or two. Learn something new, and share what you know to help others grow.
On this call, Libby Heeren is joined by Hadley Wickham, who walks through using data dictionaries with Claude Code to clean and document datasets effectively.
Hadley demonstrates a workflow using three files: a data cleaning script, a data dictionary in YAML format, and the final cleaned data as a Parquet file. He shows how Claude Code and MCP REPL can help generate and maintain data dictionaries that document what you know about your data, making it easier for both humans and AI agents to work with your datasets. Using the NYC elevators dataset as an example, he walks through data cleaning tasks like normalizing whitespace, handling missing values, fixing date formats, and investigating geocoding issues - all while keeping the data dictionary, cleaning script, and Parquet file in sync through git.
Hosting crew from Posit: Libby Heeren, Isabella Velasquez
Hadley Wickham&rsquo;s GitHub: https://github.com/hadley Hadley Wickham&rsquo;s Bluesky: https://bsky.app/profile/hadley.nz Hadley Wickham&rsquo;s LinkedIn: https://www.linkedin.com/in/hadleywickham/
Resources mentioned in the video and chat: MCP REPL: https://github.com/posit-dev/mcp-repl Data Dictionary YAML Format Specification: https://github.com/hadley/data-dict.yaml Parquet files in R for Data Science: https://r4ds.hadley.nz/arrow.html#sec-parquet Elevators Dataset Used in Demo: https://github.com/EmilHvitfeldt/elevators Pointblank Package for Data Validation: https://posit-dev.github.io/pointblank/ Arrow R Book: https://arrowrbook.com/ Monaspace Font Family (with ligatures): https://monaspace.githubnext.com/ YAML Multiline Strings Reference: https://yaml-multiline.info/ UBC Course on Shiny with RAG and Parquet: https://ubc-mds.github.io/DSCI_532_vis-2_book/060-03-rag.html Tom Scott Video on Timezones: https://www.youtube.com/watch?v=-5wpm-gesOY Falsehoods Programmers Believe About Names: https://www.kalzumeus.com/2010/06/17/falsehoods-programmers-believe-about-names/ UTC Is Enough for Everyone Right: https://zachholman.com/talk/utc-is-enough-for-everyone-right Daniel Chen&rsquo;s Cherry Blossom Analysis: https://chendaniely.github.io/posts/2026/2026-03-30-yvr-cherry-blossoms-marathon/ Project Drawdown Climate Impact Explorer: https://drawdown.org/explorer Green Coding Bookdown Resource: https://bookdown.org/content/d1e53ac9-28ce-472f-bc2c-f499f18264a3/ IBM Green Coding Topics: https://www.ibm.com/think/topics/green-coding Secret Elevator in Central Park Article: https://undercovernyc.home.blog/2021/02/08/a-secret-elevator-hidden-in-central-park/ Artificial Cave Beneath Central Park: https://gizmodo.com/an-artificial-cave-200-beneath-central-park-with-micha-1446538828
► Subscribe to Our Channel Here: https://bit.ly/2TzgcOu Follow Us Here: Website: https://www.posit.co Hangout: https://pos.it/dsh The Lab: https://pos.it/dslab LinkedIn: https://www.linkedin.com/company/posit-software Bluesky: https://bsky.app/profile/posit.co
Thanks for hanging out with us!
Timestamps of Questions / Topics: 00:00 Introduction 03:38 &ldquo;Can you talk a little bit about what MCP is?&rdquo; 05:42 Introducing the elevators dataset 07:00 Creating initial data dictionary with Claude 09:03 &ldquo;Are there any cases where the CSV format is actually a better choice than Parquet?&rdquo; 09:50 &ldquo;What font do you use?&rdquo; 12:02 Adding context from the readme to the data dictionary 14:02 &ldquo;What is a good way to store data dictionaries along with datasets?&rdquo; 14:38 &ldquo;Is this particular data dict YAML format useful for projects with only one table of data?&rdquo; 17:45 &ldquo;Is Claude also going to decide when it&rsquo;s a good time to make a commit?&rdquo; 24:02 &ldquo;Does MCP REPL work on a Windows machine and can one use other AI LLM for example ChatGPT with it?&rdquo; 26:14 Converting date columns to proper date types 27:16 &ldquo;Do you see a meaningful distinction between data dicts and data contracts?&rdquo; 29:36 &ldquo;How do you view your approach to data dictionaries and the development of pointblank?&rdquo; 34:16 Eliminating placeholder values and using proper missing values 36:25 &ldquo;Could you show off a diff of a Parquet file?&rdquo; 38:25 Investigating geocodes and creating a map of elevators 40:20 Using a leaflet map to explore Central Park elevators 42:03 &ldquo;Which model is Hadley using?&rdquo; 43:55 Discussion of cost consciousness and environmental impact of LLMs 46:30 &ldquo;Is there a way to quantify environmental and electrical costs?&rdquo; 48:50 The mystery elevator in Central Park 54:23 &ldquo;How do you know this is actually faster or more productive than just writing the code?&rdquo; 55:45 The importance of deep knowledge of data in qualitative work
</p>
      

      
        <div class="text-sm @grande:text-md">
          <div class="mt-2 flex flex-row gap-x-4 items-center"><div class="flex flex-row flex-shrink-0"><img 
          src="https://opensource.posit.co/people/hadley-wickham/profile.jpg" 
          alt="Hadley Wickham" 
          class="my-0! w-6 h-6 rounded-full object-cover ring-2 ring-white "
          style="z-index: 10;"
        ></div><div class="line-clamp-2 font-medium text-gray-600">Hadley Wickham</div></div>
        </div>
      

      <div class="grow"></div>
      
        
          <div class="hidden @grande:flex flex-wrap gap-x-1 gap-y-4 py-2 overflow-hidden h-10 items-end">
            
              <span class="pill">
                bookdown
              </span>
            
              <span class="pill">
                bookdown.org
              </span>
            
              <span class="pill">
                leaflet
              </span>
            
              <span class="pill">
                pointblank
              </span>
            
              <span class="pill">
                Shiny
              </span>
            
          </div>
        
      
    </div>
  </a>
</div>


    </div>
  
    <div>
      











  
  
  
  
  
















  
  
    
  











  
  





  
    
  









  
  






  





  
    
  
    
  
    
  
    
  
    
  






















  
    
  





  
    
  
























<div id="item-4d9af617f6704fb38d6f46af20c8ee48" class="@container h-full">
  <a href="https://opensource.posit.co/resources/videos/2026-02-19_using-r-package-structure-for-data-science-projects-kylie-ainslie-data-science-lab/" title="Using R package structure for data science projects | Kylie Ainslie | Data Science Lab"
     class="card-link flex flex-col @venti:flex-row rounded-xl  h-full">

      



      
      

    
    <div class="w-full @venti:w-1/2 aspect-[40/21] flex-shrink-0 flex items-center justify-center overflow-hidden rounded-xl">
      
        









  
  
    
    

    

    
      
      

      
      
      

      
      
      
      

      <picture class="hidden @max-tall:block w-full h-full">
        <source
          type="image/webp"
          srcset="/resources/videos/2026-02-19_using-r-package-structure-for-data-science-projects-kylie-ainslie-data-science-lab/thumbnail_hu_b342729d310b0653.webp 1x,
                  /resources/videos/2026-02-19_using-r-package-structure-for-data-science-projects-kylie-ainslie-data-science-lab/thumbnail_hu_2d213a05d6559bee.webp 2x" />
        <img
          src="https://opensource.posit.co/resources/videos/2026-02-19_using-r-package-structure-for-data-science-projects-kylie-ainslie-data-science-lab/thumbnail_hu_5eb9cd45b958caea.jpg"
          srcset="/resources/videos/2026-02-19_using-r-package-structure-for-data-science-projects-kylie-ainslie-data-science-lab/thumbnail_hu_5eb9cd45b958caea.jpg 1x,
                  /resources/videos/2026-02-19_using-r-package-structure-for-data-science-projects-kylie-ainslie-data-science-lab/thumbnail_hu_2d34cd327bb21020.jpg 2x"
          alt="Using R package structure for data science projects | Kylie Ainslie | Data Science Lab"
          class="mx-auto h-full w-full object-cover"
          loading="lazy" />
      </picture>
    
      
      

      
      
      

      
      
      
      

      <picture class="hidden @tall:@max-grande:block w-full h-full">
        <source
          type="image/webp"
          srcset="/resources/videos/2026-02-19_using-r-package-structure-for-data-science-projects-kylie-ainslie-data-science-lab/thumbnail_hu_2d213a05d6559bee.webp 1x,
                  /resources/videos/2026-02-19_using-r-package-structure-for-data-science-projects-kylie-ainslie-data-science-lab/thumbnail_hu_7968fe6f5db9f34d.webp 2x" />
        <img
          src="https://opensource.posit.co/resources/videos/2026-02-19_using-r-package-structure-for-data-science-projects-kylie-ainslie-data-science-lab/thumbnail_hu_2d34cd327bb21020.jpg"
          srcset="/resources/videos/2026-02-19_using-r-package-structure-for-data-science-projects-kylie-ainslie-data-science-lab/thumbnail_hu_2d34cd327bb21020.jpg 1x,
                  /resources/videos/2026-02-19_using-r-package-structure-for-data-science-projects-kylie-ainslie-data-science-lab/thumbnail_hu_7edb6814911cc29d.jpg 2x"
          alt="Using R package structure for data science projects | Kylie Ainslie | Data Science Lab"
          class="mx-auto h-full w-full object-cover"
          loading="lazy" />
      </picture>
    
      
      

      
      
      

      
      
      
      

      <picture class="hidden @grande:block w-full h-full">
        <source
          type="image/webp"
          srcset="/resources/videos/2026-02-19_using-r-package-structure-for-data-science-projects-kylie-ainslie-data-science-lab/thumbnail_hu_7968fe6f5db9f34d.webp 1x,
                  /resources/videos/2026-02-19_using-r-package-structure-for-data-science-projects-kylie-ainslie-data-science-lab/thumbnail_hu_74bb543c4243eb29.webp 2x" />
        <img
          src="https://opensource.posit.co/resources/videos/2026-02-19_using-r-package-structure-for-data-science-projects-kylie-ainslie-data-science-lab/thumbnail_hu_7edb6814911cc29d.jpg"
          srcset="/resources/videos/2026-02-19_using-r-package-structure-for-data-science-projects-kylie-ainslie-data-science-lab/thumbnail_hu_7edb6814911cc29d.jpg 1x,
                  /resources/videos/2026-02-19_using-r-package-structure-for-data-science-projects-kylie-ainslie-data-science-lab/thumbnail_hu_b7f23d7c59f3ea7c.jpg 2x"
          alt="Using R package structure for data science projects | Kylie Ainslie | Data Science Lab"
          class="mx-auto h-full w-full object-cover"
          loading="lazy" />
      </picture>
    
  
  


      
    </div>

    
    <div class="hidden gap-y-2 @nip:flex @venti:w-1/2 flex-auto flex-col p-3 @venti:pl-5 text-gray-700 mt-2">

      
      

      
      
      <div class="hidden @short:flex flex-wrap gap-x-2 items-center text-xs font-medium text-gray-500">
        
          <span>Feb 19, 2026</span>
          <span>|</span>
        
        
        
          <span>55 min</span>
          <span>|</span>
        
        
          <span>1.7k views</span>
          
        
        
      </div>
      

      
      <h3 class="m-0! mt-3 font-semibold text-sm @grande:text-lg @venti:text-3xl line-clamp-2 text-sm @tall:text-base @grande:text-lg @venti:text-3xl text-gray-600">Using R package structure for data science projects | Kylie Ainslie | Data Science Lab</h3>
      

      
        <p class="m-0! text-xs @short:text-sm @grande:text-md @venti:text-lg line-clamp-2 short@line-clamp-3 @tall:line-clamp-3 font-medium text-gray-600">The Data Science Lab is a live weekly call. Register at pos.it/dslab! Discord invites go out each week on lives calls. We&rsquo;d love to have you!
The Lab is an open, messy space for learning and asking questions. Think of it like pair coding with a friend or two. Learn something new, and share what you know to help others grow.
On this call, Libby Heeren is joined by Kylie Ainslie who walks through how structuring data science projects as R packages provides a consistent framework that integrates documentation for you and facilitates collaboration with others by organizing things really well. Kylie says, &ldquo;I stumbled on using an R package structure to organize my projects a number of years ago and it has changed how I work in such a positive way that I want to share it with others! In a world where our attention is constantly being pulled in many directions, efficiency is crucial. Structuring projects as R packages is how I work more efficiently.&rdquo;
Hosting crew from Posit: Libby Heeren, Isabella Velasquez
Kylie&rsquo;s Bluesky: @kylieainslie.bsky.social Kylie&rsquo;s LinkedIn: https://www.linkedin.com/in/kylieainslie/ Kylie&rsquo;s Website: https://kylieainslie.github.io/ Kylie&rsquo;s GitHub: https://github.com/kylieainslie
Resources from the hosts and chat:
posit::conf(2026) call for talks: https://posit.co/blog/posit-conf-2026-call-for-talks/ Kylie&rsquo;s posit::conf(2025) talk: https://www.youtube.com/watch?v=YzIiWg4rySA {usethis} package: https://usethis.r-lib.org/ R Packages (2e) book: https://r-pkgs.org/ Paquetes de R (R Packages in Spanish): https://davidrsch.github.io/rpkgs-es/ {box} package: https://github.com/klmr/box extdata docs in Writing R Extensions: https://cran.r-project.org/doc/manuals/R-exts.html#Data-in-packages-1 Tan Ho&rsquo;s talk on NFL data: https://tanho.ca/talks/rsconf2022-github/ {rv} package: https://a2-ai.github.io/rv-docs/ Whether to Import or Depend: https://r-pkgs.org/dependencies-mindset-background.html#sec-dependencies-imports-vs-depends {pkgdown} package: https://pkgdown.r-lib.org/ Edgar Ruiz&rsquo;s {pkgsite} package: https://github.com/edgararuiz/pkgsite
Attendees shared examples of data packages in the chat! Here they are: https://kjhealy.github.io/nycdogs/ https://kjhealy.github.io/gssr/ https://github.com/deepshamenghani/richmondway https://github.com/kyleGrealis/nascaR.data https://github.com/ivelasq/leaidr
► Subscribe to Our Channel Here: https://bit.ly/2TzgcOu
Follow Us Here: Website: https://www.posit.co The Lab: https://pos.it/dslab Hangout: https://pos.it/dsh LinkedIn: https://www.linkedin.com/company/posit-software Bluesky: https://bsky.app/profile/posit.co
Thanks for learning with us!
Timestamps: 00:00 Introduction 06:17 Reviewing the disorganized project example 10:01 Creating the package structure using create_package 17:50 Organizing external data and scripts in the inst folder 22:55 Adding a README and License 29:06 &ldquo;What are the advantages to packaging a project?&rdquo; 33:35 Writing Roxygen2 documentation 36:06 &ldquo;Do you type return at the end of your functions?&rdquo; 41:55 Handling dependencies with use_package 43:53 &ldquo;Can you just use require(dplyr) at the top?&rdquo; 47:45 Setting up a pkgdown site 50:11 Creating vignettes 52:22 &ldquo;What is the role of the usethis package?&rdquo; 54:18 Loading the package with devtools::load_all
</p>
      

      
        <div class="text-sm @grande:text-md">
          <div class="mt-2 flex flex-row gap-x-4 items-center"><div class="flex flex-row flex-shrink-0"><img 
          src="https://opensource.posit.co/people/edgar-ruiz/profile.jpg" 
          alt="Edgar Ruiz" 
          class="my-0! w-6 h-6 rounded-full object-cover ring-2 ring-white "
          style="z-index: 10;"
        ></div><div class="line-clamp-2 font-medium text-gray-600">Edgar Ruiz</div></div>
        </div>
      

      <div class="grow"></div>
      
        
          <div class="hidden @grande:flex flex-wrap gap-x-1 gap-y-4 py-2 overflow-hidden h-10 items-end">
            
              <span class="pill">
                devtools
              </span>
            
              <span class="pill">
                dplyr
              </span>
            
              <span class="pill">
                pkgdown
              </span>
            
              <span class="pill">
                roxygen2
              </span>
            
              <span class="pill">
                usethis
              </span>
            
          </div>
        
      
    </div>
  </a>
</div>


    </div>
  
</div>


<p>I’m a real person, and I would love to know how to make the Glimpse newsletter better! Find me on <a href="https://www.linkedin.com/in/ivelasq/" target="_blank" rel="noopener">LinkedIn</a> and <a href="https://bsky.app/profile/ivelasq3.bsky.social" target="_blank" rel="noopener">Bluesky</a>, or email me at isabella [dot] velasquez [at] posit.co.</p>
]]></description>
      <enclosure url="https://opensource.posit.co/blog/2026-07-01_2026-07-glimpse/thumbnail.jpg" length="68574" type="image/jpeg" />
    </item>
  </channel>
</rss>
