The contents for section are being revised. Thank you for your patience.
In the previous chapters, we used the chores package to develop helpers—pre-written prompts—for repetitive tasks such as creating roxygen2 documentation and updating testthat tests.1 In the gander chapter, we used the addin to send code and environment context to the LLM.2
chores and gander assist us in automating or enhancing the prompts we submit to the LLM. The addins and shortcuts streamline our interactions with the model, allowing for a more intuitive and efficient experience that resembles a browser interface (like ChatGPT).
TipAccess the applications in this chapter
I’ve created the shinypak R package in an effort to make each section accessible and easy to follow. Install shinypak using pak (or remotes):
In this chapter we’ll focus on the btw package, which is fundamentally different than chores and gander because it,
“provides a default set of tools to to peruse the documentation of packages you have installed, check out the objects in your global environment, and retrieve metadata about your session and platform.”3
I’ll cover using btw to add documentation and improve the contents of the downloadable report in our sap application.
30.1 Configuration
We can place the btw configuration options in the .Rprofile (similar to other ellmer configurations).4 Recall that the .Rprofile file can exist at the user and/or the project-level.
For example, I’ve added a project-level .Rprofile file this branch of the sap package and included a system_prompt and model:
if (interactive()) {require(ellmer, quietly =TRUE)}if (interactive()) {require(btw, quietly =TRUE)}options(btw.client = ellmer::chat_anthropic(system_prompt ="You are an expert R/Python programmer who loves explaining complex topics to non-technical audiences. - When writing R code, use base R functions, but follow the tidyverse style guide. - Avoid using `for` loops and prefer functional programming patterns like `apply()` or `purrr`. - When creating graphs/plots, use `ggplot2`. - If writing R Shiny code, use `bslib` for all layout functions (unless explicitly instructed otherwise). - If writing Python Shiny code, use shiny core (not express) to build apps and include explanations in comments. ",model ="claude-sonnet-4-5-20250929" ))
btw comes with a set of pre-defined tools for examining package documentation, environments, directories and files, git and GitHub, our development environment, CRAN packages, R sessions, and general web searches.5
We can use btw to work interactively in the Positron (or RStudio ) console by creating a btw-enhanced chat client and passing messages directly.6
chat <-btw_client()
We can view the btw enhancements by examining the chat object in the console:
chat
btw has added ‘System and Session Context’ and ‘Tools’ sections to the chat client.
# System and Session ContextPlease account for the following R session and system settings in all responses.<system_info>R_VERSION: R version 4.5.1 (2025-06-13)OS: macOS Tahoe 26.0.1SYSTEM: x86_64, darwin20UI: Positron (a VS Code equivalent)LANGUAGE: (EN)LOCALE: en_US.UTF-8ENCODING: en_US.UTF-8TIMEZONE: America/PhoenixDATE: Tuesday, October 28, 2025 (2025-10-28)</system_info># ToolsYou have access to tools that help you interact with the user's R session andworkspace. Use these tools when they are helpful and appropriate to complete the user's request. These tools are available to augment your ability to helpthe user, but you are smart and capable and can answer many things on your own. It is okay to answer the user without relying on these tools.
We can see the model will have some additional instructions and methods at it’s disposal (beyond what we’ve provided in the system_prompt argument of ellmer::chat_anthropic()).
Notebtw tool functions
All btw functions follow the name convention below:
The Group can be one of docs, env, git, github, ide, search, session or web. This is important to remember below in Section 30.6.
30.3 Project context
As we learned in the ellmer chapter, project prompts should be stored in inst/prompts/. btw also provides the use_btw_md() function, which creates a project ‘context file.’
use_btw_md(scope ="project")
The btw.md file comes with some default content for project context:
“Use btw.md to inform the LLM of your preferred code style, to provide domain-specific terminology or definitions, to establish project documentation, goals and constraints, to include reference materials such or technical specifications, or more. Storing this kind of information in btw.md may help you avoid repeating yourself and can be used to maintain coherence across many chat sessions.”
client
The YAML header in our newly created btw.md is where can specify the client (along with the provider and model).
---client: claude/claude-sonnet-4-5-20250929---
The default values in btw.md will automatically use the latest Claude model from Anthropic. The YAML values above are similar to using ellmer’s chat_* functions.7
tools
The tools section of the YAML header contains a list of the groups from btw_tools(). Each of these groups contains a collection of functions “that allow the chat to interface with your computational environment.”
LLMs can’t execute R code, but if we’ve registered tools (i.e., R functions) with the model, they can be used to help provide additional information.
As mentioned above, btw has a collection of tools at our disposal, so when we start the interactive chat, the model informs us it will be examining the sap package contents for more information.
>>>"Let's get started."
The model tells us it’s intentions for the btw.md file:
I'll help you create a comprehensive project summary. Let me start by exploring your project structure to understand what we're working with.
To perform this exploration, the model will use the registered tools from btw.
30.5.1 Registered tools
When registering a tool with an LLM, we include the name of the function, a description of what the function does, and a list of function arguments with their type (boolean, integer, number, etc.). 8
We can view all the tools registered with the LLM using:
chat$get_tools()
NoteNote
The btw_tools() function lists all the tools we could register, but chat$get_tools() returns the tools that are registered with the model.
The output from chat$get_tools() is rather lengthy, but we can use Ctrl/Cmd + F to locate btw_tool_files_list_files(), which is the first tool called by the LLM.
List files or directories in the project.WHEN TO USE:* Use this tool to discover the file structure of a project.* When you want to understand the project structure, use `type = "directory"` to list all directories.* When you want to find a specific file, use `type = "file"` and `regexp` to filter files by name or extension.CAUTION: Do not list all files in a project, instead prefer listing files in a specific directory with a `regexp` tofilter to files of interest.
30.5.2 Tool calls
Recall the model was going to start by ‘exploring your project structure’, and we can see this aligns with the’ @description for btw_tool_files_list_files().
In the console, the tool call and a preview of it’s results are printed. Below is the first call to btw_tool_files_list_files():
The table output is sent to the LLM, which them provides a summary of the contents:
Perfect! I can see this is an **R package** with a Shiny application. The structure shows:- `DESCRIPTION` and `NAMESPACE` files (R package essentials)- Extensive `R/` directory with many Shiny modules (`mod_*.R` files)- `app.R` file (Shiny app entry point)- `data/` directory with datasets- `tests/testthat/` (comprehensive testing)- `vignettes/` (package documentation)- `renv.lock` (dependency management)
I’ve created an overview of this tool call in the diagram below.11
Tool calls with btw
The model is equipped with the supplemented system prompt–which informs it of the tools at it’s disposal–and when we begin, it starts by attempting to understand the project structure.
This objective matches the btw registered tool description for the btw_tool_files_list_files() function, which returns a markdown-formatted table of the project contents. The results from the tool are sent to the LLM, which provides a summary in the console.
◯ [tool call] btw_tool_files_read_text_file(path = "app.R", `_intent` = "Understand the Shinyapplication structure")● #> ```R #> # set option to turn off loadSupport() ---- #> withr::with_options(new = list(shiny.autoload.r = FALSE), code = { #> if (!interactive()) { #> sink(stderr(), type = "output") #> …
◯ [tool call] btw_tool_files_read_text_file(path = "R/launch_app.R", `_intent` = "Understand thelaunch_app function")● #> ```R #> #' Launch the Shiny Application #> #' #> #' This function initializes and launches the Shiny application with specified #> #' options and settings. #> …
◯ [tool call] btw_tool_files_read_text_file(path = "R/nav_ui.R", line_end = 50L, ...)● #> ```R #> #' User Interface for the Shiny Application #> #' #> #' This function defines the user interface for the Shiny application, #> #' integrating Bootstrap and a custom JavaScript file. #> …
◯ [tool call] btw_tool_files_read_text_file(path = "R/data.R", `_intent` = "Look at data structure tounderstand what this app analyzes")● #> ```R #> #' @title IMDB movies data #> #' #> #' @description #> #' Movie review data. Note: these data come from the [Building Web Applications with shinycourse](https://rstudio-education.github.io/shiny-course/). #> …
As we can see, the model called btw_tool_files_list_files() and btw_tool_files_read_text_file() to gather context on the project. The PHASE 1: SUMMARY is what the model learned about the sap package using the btw tools (expand the callout box to view):
CautionPHASE 1: SUMMARY (TOOL CALLS)
Based on my exploration, here’s what I’ve learned about this project:
Project Type: R Package with integrated Shiny application
Primary Purpose: This is sap (Shiny App-Packages), which serves as a comprehensive code example for the book “Shiny App-Packages” and workshops on developing/testing Shiny applications. It demonstrates how to structure a Shiny app as an R package.
Technology Stack:
R Package structure (DESCRIPTION, NAMESPACE, man/, tests/)
Shiny for the web application with modular design
Bootstrap/bslib for modern UI theming
ggplot2 + extensions (ggdist, ggwaffle, plotly) for visualizations
tidyverse (dplyr, tidyr, forcats) for data manipulation
testthat for comprehensive testing
renv for dependency management
Quarto for vignettes/documentation
Key Architecture Insights:
Modular Shiny design: Extensive use of Shiny modules (mod_*.R files) for different app sections
Multi-branch educational repo: Different branches show progressive development stages
Theme integration: Dark theme with custom CSS and thematic integration
Data-focused: Built around IMDB movie review dataset with 34 variables
Production-ready structure: Complete with testing, documentation, and dependency management
Main Components:
Data visualization modules: Compare plots, distribution plots, count plots (bar/waffle)
Award analysis: Special modules for Oscar/award winner analysis
The app appears to provide multiple ways to explore and visualize movie review data through an interactive interface, while serving as a teaching tool for Shiny app development best practices.
After the project summary, the model starts Phase 2: Narrative Construction, which includes a series of questions from the LLM regarding the context of the package/project (expand the callout box to view).
CautionPHASE 2: NARRATIVE CONSTRUCTION
Now moving to Phase 2: Narrative Construction. I need to gather context that would help developers understand the “why” behind decisions and architectural choices.
Question 1: What’s the main learning objective for developers using this codebase–is it primarily about demonstrating Shiny package structure, modular Shiny development patterns, or both equally?
“The learning objectives for developers using the codebase are to demonstrate Shiny package structure and modular Shiny development patterns, specifically using modules to add a downloadable html report. Be sure to also create mermaid diagrams to illustrate concepts. When creating mermaid diagrams, list the nodes using CamelCase abbreviations (i.e., not simply A, B, C, etc.), and keep the diagrams small enough to fit on a single presentation slide.”
Question 2: I noticed the app uses a dark theme with custom CSS and thematic integration. Was this theming choice made primarily for visual appeal, or does it serve as an example of a specific theming pattern that developers should learn from when building their own Shiny app-packages?
“The theme is just for visual appeal, not as an example of a specific theming pattern.”
Question 3: I see the project has multiple branches representing different development stages, and the main branch appears to be a mature version with full testing and documentation. For developers working with this codebase, which components or modules would you recommend they examine first to understand the core patterns–are there particular modules that best demonstrate the key architectural principles?
“The code files for each chapter are stored in Git repository. Major code changes are stored in branches. The branches are named sequentially with a prefix and a name of the topic covered: 01_whole-app-game, 02.1_shiny-app, 02.2_movies-app, 02.3_proj-app, 03.1_description, 03.2_rproj, 03.3_create-package, 04_devtools, 05_roxygen2, 06.1_exports, 06.2_imports, 07_data, 08_launch, 09_inst, etc. Developers should review the three mod_compare_* to understand the core patterns (these best demonstrate the key architectural principles).”
Question 4: The modular structure shows three mod_compare_* modules (vars, point, and presumably the UI/server pairs). These modules appear to handle variable selection, point plotting, and the overall comparison interface. Are there specific patterns in how these three modules communicate with each other–like how data flows between variable selection and plotting–that represent key principles developers should understand about module interaction in Shiny app-packages?
“Developers should understand that using modules enhances the clarity of the application by providing a structured way to organize its components. This approach allows us to write, analyze, and test each element independently, making it easier to understand its unique functionality and how it interacts within the overall app server.”
Question 5: I see the app integrates Quarto for report generation and has a dedicated mod_report module. Given that downloadable HTML reports are a key learning objective, is the report functionality designed to demonstrate a specific pattern for integrating external document generation tools (like Quarto) within Shiny modules, or does it showcase something else important about report generation in app-packages?
“The only learning objective is using Shiny modules to integrate external document generation tools (like Quarto). This is a general pattern, not a specific pattern.”
Perfect! I now have enough context to create the documentation. Let me summarize what I understand:
I included some instructions to the model on building mermaid diagrams for the btw.md file. The PHASE 2: SUMMARY returned after the questions and answers is below (expand the callout box to view).
CautionPHASE 2: SUMMARY
Learning Objectives: Demonstrate both Shiny package structure and modular Shiny development patterns, with special focus on using modules to integrate external document generation (Quarto for HTML reports).
Key Architectural Principles:
Modular design enhances application clarity through structured component organization
Each module can be written, analyzed, and tested independently
Focus on the three mod_compare_* modules as the best examples of core patterns
General pattern for integrating external tools (like Quarto) within Shiny modules
Development Progression: Sequential git branches show evolution from basic app to full package structure, following a clear learning path through the book chapters.
Theme Choice: Visual appeal only, not a teaching pattern.
30.5.5 Updated bwd.md file
When Phase 2 is complete, we’re told we have a “comprehensive btw.md file that captures the essential information about [our] Shiny App-Packages project.” The full conversation with the model is stored in inst/prompts/btw-md-conversation.md.
CautionKey Features of the Documentation
📋 Learning-Focused Structure: Emphasizes the dual educational objectives (package structure + modular patterns) right at the top
🎯 Clear Architecture Diagrams: Two mermaid diagrams showing:
Overall module architecture with CamelCase node names
Core module communication pattern (CompareVars → ComparePoint → Report)
📚 Sequential Learning Path: Explains the git branch progression from basic app to full package
🔧 Practical Developer Guidance:
Points developers to the three mod_compare_* modules as the best starting examples
Includes actual commands for exploring different development stages
Testing patterns for module independence
📊 Data Context: Clear explanation of the movie dataset structure and its role in demonstrating patterns
🚀 Integration Patterns: Specific focus on how Quarto integration demonstrates external tool patterns
The documentation serves both as an introduction for newcomers and a reference for developers working with the codebase. It maintains the existing front matter you had while providing comprehensive context that helps developers understand not just what the code does, but why it’s structured this way for learning purposes.
The file should help other AI assistants and developers quickly understand that this is an educational codebase with specific learning objectives, rather than a production movie analysis application.
Now that we have a project context file, we will use btw to improve our downloadable report. Instead of using the console to chat with the model, we’ll use the btw app:12
btw_app()
If we expand the sidebar, we can see the registered tools provided by btw:
By default, the app includes all of the tools available from btw (with the exception of Code Search).13
We can also specify specific tools, or categories of tools. Below are some groups of tools we might use exploring an app-package:
The btw_app() functions like any LLM chat interface.
What code could I add to the Counts section of inst/rmd/report_template.Rmd to ensure all the graphs and tables from this tab are returned in the downloadable report?
Only return R code (no the R Markdown syntax).
The prompt directory is where chores stores the helpers used in the addin.↩︎
The _intent argument is “An optional string describing the intent of the tool use. When the tool is used by an LLM, the model will use this argument to explain why it called the tool.”↩︎
I’ve cleaned up the formatting on this markdown table so it’s easier to read.↩︎