path_find_in_project() now stops its upward search when it reaches the home directory (either fs::path_home() or fs::path_home_r(), which differ on Windows) and never treats files there as project files, so ~/AGENTS.md or ~/CLAUDE.md are no longer picked up as project context when the working directory is under ~ but outside a project. Home-level files are handled only by the user-level lookup. This also fixes ~/btw.md instructions being included twice — once as the project file and once as the user-level config (#225).
btw_client(path_btw = ...) no longer duplicates instructions when path_btw is set explicitly to the same file as the user-level btw.md (#225).
The project-root detection in path_find_in_project() now checks for *.Rproj files in the directory being searched. Previously, a stray *.Rproj file in the session's working directory could stop the search early, and project roots marked only by an *.Rproj file could be walked past (#225).
New vignettes: vignette("btw-md") explains the btw.md configuration format, and vignette("custom-agents") builds on it to create custom agents.
The btw.md template created by use_btw_md() now uses the current cran and sessioninfo tool group names instead of the deprecated search and session aliases.
?use_btw_md now correctly describes how a user-level btw.md is combined with a project's context file: client and tools fall back to user-level values, options are merged, and both sets of instructions are included.
Skill listings in the system prompt now use compact YAML-style entries instead of <skill> XML blocks, reducing prompt tokens while conveying the same information.
Package tests now support a compact reporter that shows per-file progress, timing, warning and failure details, and final counts. btw pkg test uses it by default, while btw_tool_pkg_test() defaults to concise output for non-streaming clients; both accept other testthat reporter names (#220).
btw_mcp_server() no longer errors when tools is a character vector naming more than one tool group, e.g. btw_mcp_server(c("docs", "env", "sessioninfo")) (@taekop, #206).
Added btw cran versions <packages...> to look up CRAN release dates and versions, and versioned NEWS through btw(), btw_this(), the btw docs tools, and btw docs news. Use btw("@news dplyr v1.1.4") to paste a specific release's NEWS into a chat, or btw("@news dplyr") for the full file (#213).
btw docs and btw pkg src commands now auto-load an in-development package found in the current directory (or its pkg-r/, R/ subfolder) with pkgload::load_all() before running, so results reflect uncommitted local changes. Pass --no-dev to disable this and use the installed package instead (#212).
btw now supports shinychat >= 0.5.0 (#215):
btw_app() uses shinychat's new page_chat() layout, with the tool selection menu and the system prompt editor in offcanvas panels. When shinychat 0.4.x is installed, btw_app() falls back to the legacy sidebar layout and warns, suggesting you upgrade to shinychat 0.5.0.
Conversations are kept in a chat history. Past chats appear in the app's history drawer, so you can revisit a previous conversation at any time. When duckdb is installed, btw stores this history in a shared database in btw's user cache directory, with one history per project, so your chats are still there the next time you open the app in the same project. Without duckdb, conversations are not saved between sessions. btw prints a note that suggests installing duckdb.
btw's @ commands are also available as /btw-* slash commands, e.g. /btw-help dplyr::across, /btw-news dplyr v1.1.4, or /btw-url https://example.com. A slash command stages its context as an attachment on the chat input and shows a toast while it runs. Nothing is sent to the model until you submit your next message. If a command fails, btw_app() restores your input text and shows an error toast.
Skills are registered as slash commands under their own names, e.g. /skill-creator. Running a skill submits its instructions with your message to the model.
/new and /clear start a new chat. If chat history is enabled, btw_app() first saves the current conversation with shinychat's history-aware chat$new_chat() (posit-dev/shinychat#399), so the conversation isn't dropped from the history. The token and cost counters follow the active conversation and restore their totals when you load an old chat from the history.
Subagent reports use shinychat 0.5.0's HTML display protocol (contents_html()), with the full subagent conversation in a styled disclosure. btw_app() escapes untrusted markdown in subagent reports and in error toasts.
Tool results survive shinychat's conversation history serialization, so chats with tool results can be saved and restored. btw collapses multi-element character values to a single string, returns data frame results as JSON, and drops unserializable objects from run-R results.
Two new functions make the skill features reusable outside btw_app(). btw_skill_prompt() renders a skill's <skill> block, including its name, description, location, and optional compatibility and allowed-tools metadata. btw_skills_register_slash_commands() registers skills as slash commands on any shinychat chat_server().
btw --version now works without a subcommand. Previously, Rapp's required top-level switch caused the CLI to print usage and exit before the version flag was ever checked.Local conversation history and project code-search indexes now use RSQLite, replacing DuckDB. Persistent data is stored in btw's user cache and separated by project; install RSQLite to enable this storage.
btw now requires ellmer (>= 0.4.2). The set_model() compatibility shim was removed, and client_get_models() now delegates to ellmer's models_list() generic, replacing a bespoke per-provider dispatch table (#214).
btw no longer reads the legacy user skills directory used by btw <= 1.2.0 (skills/ under tools::R_user_dir("btw", "config")) (#204).
btw_app() now keeps tool selection synchronized when switching models and prevents model, prompt, chat, or tool changes while a response is streaming. Long-form tool results can be expanded fullscreen, and file actions now appear in tool result footers. Fullscreen R results include keyboard focus trapping and focus restoration (#208).
Added btw pkg desc <packages...> to show useful DESCRIPTION metadata for installed packages. By default, the command includes package identity, authorship, licensing, URLs, dependencies, and system requirements; use --fields to select other fields or --fields=all for the complete DESCRIPTION. Multiple terminal results are separated by ---, and --json returns an object keyed by package name (#209).
Added a btw pkg src CLI command family for inspecting R namespace implementations in installed packages and the current development package. Use list to discover objects, get to retrieve exact source when available or deparsed functions otherwise, methods to inspect package-owned S3 and S4 implementations, path to locate package installations, and search to search real or reconstructed R source. All commands support JSON output, and methods --source returns method implementations directly (#207).
btw now discovers project- and user-level custom agents from an agents/ subdirectory (e.g. .btw/agents/my_agent.md or ~/.btw/agents/my_agent.md) in addition to the flat agent-*.md files. Files in the agents/ directory use plain {name}.md filenames, with the agent name taken from the YAML frontmatter (#202).
skills/ under tools::R_user_dir("btw", "config")) is deprecated. btw still reads skills from it but now warns once per session when it contains skills, prompting you to move them to ~/.btw/skills. Read support for the legacy location will be removed in btw 1.5.0 (#203).use_btw_md("user") now creates user-level configuration in ~/.btw/btw.md (btw's recommended user directory) and offers to migrate an existing ~/btw.md there instead of creating a second file. A ~/btw.md in your home directory still takes precedence when present; if more than one user-level btw.md exists, btw uses the highest-priority one and warns once per session. See ?btw-config for the full set of configuration locations (#203).
On Windows, btw now discovers user-level agents and skills under R's home directory (~, typically Documents) in addition to the user profile, matching how it already searched for user-level btw.md config files. macOS and Linux behavior is unchanged (#203).
Added three new btw skills CLI commands for discovering and fetching skills without entering R: btw skills list <source> lists available skills from a package or GitHub repository (with --json output support); btw skills get <source> [names...] fetches one or more skills by name, or lists them when no names are given (use --all to fetch all); btw skills resource <source> <name> <paths...> fetches individual resource files bundled with a skill. When the source is a GitHub repository, local path information is omitted from the output since the temporary download directory is removed when btw exits. (#199)
btw_app() gains a model_choices parameter for switching between AI providers and models from the status bar. Set to "auto" (default) to show named btw.md client configs when two or more are present, "btw_md" to always use btw.md configs, "provider" to browse the active provider's model list, or "none" to hide the selector. When switching providers, the chat history, system prompt, and tools are carried over to the new client (#196).
The btw_tool_skill tool now supports custom skill search directories via the btw.skills.paths R option or BTW_SKILLS_PATHS environment variable. When set, the value entirely replaces all user-level and project-level skill directories; package-bundled skills are always preserved. Multiple paths can be provided as a character vector (R option) or OS-native path-separated string (env var). Values are captured at tool-registration time, so custom directories set in btw.md survive after btw_client() returns (#193).
Added btw_tool_files_patch(), a new files tool that applies a structured diff-style patch envelope to make coordinated changes across multiple files in a single call. One patch can add, update, delete, and rename files atomically: all operations are validated before any file is written, so a partial failure leaves the working tree untouched (#190).
The btw info CLI command group has been replaced by three focused top-level commands: btw system-info (platform and R session info), btw check-installed <pkgs> (check if packages are installed, exits 0 by default with --fail for non-zero exit on missing packages), and btw installed-packages <pkgs> (show installed package versions). btw info is retained as a deprecated stub that prints migration guidance. All three commands support --json output with documented field shapes (#195).
Added two new commands to the btw CLI: btw app to launch a btw_app() session in the current working directory and btw skills install to install skills from the terminal.
btw skills install . installs skills from all project dependencies. In packages (directories with a DESCRIPTION file), Imports and Suggests are scanned; otherwise renv::dependencies() is used as a fallback. The same behaviour is available in R via btw_skill_install_project().
Added btw docs topics <pkg> to the btw CLI for discovering a package's help topics and vignettes. Use --only help or --only vignettes to limit output to one section, or --json for machine-readable output (#195).
Added btw help to the btw CLI, which prints the r-btw-cli skill — a usage guide designed for AI agents.
btw_app() is now compatible with and requires shinychat v0.4.0. Per-block copy buttons and IDE action buttons (insert at cursor, insert in new file, run in console) are restored for R output blocks in the new React-based shinychat (#188).
btw_tool_agent_subagent() now correctly uses the options from your btw.md file when called directly rather than through btw_client() or btw_app() (#185).
User-level config locations are now consistent across skills, agents, and btw.md discovery. Skills installed with btw v1.2.0 are still discovered for backwards compatibility (#182).
The btw CLI now loads datasets, utils, stats, and methods by declaring them in the Rapp #| launcher: frontmatter, reducing surprises for users who expect standard R packages to be available (#181).
Several tool groups and tool names have been renamed for clarity (#159):
| Old Name | New Name |
|----------|----------|
| session group | sessioninfo group |
| search group | cran group |
| btw_tool_session_platform_info() | btw_tool_sessioninfo_platform() |
| btw_tool_session_package_info() | btw_tool_sessioninfo_package() |
| btw_tool_session_check_package_installed() | btw_tool_sessioninfo_is_package_installed() |
| btw_tool_search_packages() | btw_tool_cran_search() |
| btw_tool_search_package_info() | btw_tool_cran_package() |
| btw_tool_files_list_files() | btw_tool_files_list() |
| btw_tool_files_read_text_file() | btw_tool_files_read() |
| btw_tool_files_write_text_file() | btw_tool_files_write() |
| btw_tool_files_code_search() | btw_tool_files_search() |
The old names and group aliases continue to work but emit deprecation
warnings. The btw.files_code_search.extensions and
btw.files_code_search.exclusions options have also been renamed to
btw.files_search.extensions and btw.files_search.exclusions, with the old
option names emitting deprecation warnings.
New btw CLI provides command-line access to btw's tool groups — docs,
pkg, info, and cran — powered by
Rapp. Install with install_btw_cli() and
run commands like btw docs help dplyr::mutate or btw cran search "tidyverse". Output is designed for humans and LLMs: colored and formatted
for terminals, plain markdown when piped, with a --json flag to return
pipable JSON in select commands (#176).
btw.md now supports configuring multiple client options. When
btw_client() is called interactively, you'll be presented with a menu to
choose which client to use. Clients can be specified as an array:
client:
- anthropic/claude-sonnet-4
- openai/gpt-4.1
- aws_bedrock/us.anthropic.claude-sonnet-4-20250514-v1:0
Or as named aliases:
client:
haiku: aws_bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0
sonnet: anthropic/claude-sonnet-4
chatgpt: openai/gpt-5.2
With aliases, you can select a client by name in the interactive menu or pass
the alias directly via btw_client(client = "alias"). In non-interactive
contexts, the first client is used automatically (#153).
btw_agent_tool() allows you to create specialized custom subagents from
btw.md style markdown files. Agent files are automatically discovered from
.btw/agent-*.md (project and user directories) and .claude/agents/ (for
Claude Code compatibility), and are registered as callable tools in
btw_tools(). Custom agents can specify their own system prompts, icons,
models, and available tools (#149).
btw_task() runs pre-formatted LLM tasks defined in markdown files with YAML
frontmatter. Task files support template variable interpolation via
{{ variable }} syntax, optional client and tool configuration, and all four
execution modes ("app", "console", "client", "tool"). Task files can
also specify title, icon, description, and name fields in their YAML
frontmatter to customize the tool definition when used in "tool" mode
(#169).
btw_tool_agent_subagent() enables hierarchical agent workflows by allowing
an orchestrating LLM to delegate tasks to subagents. Each subagent runs in
its own isolated chat session with restricted tool access and maintains
conversation state that can be resumed via session_id. This allows you to
delegate tasks to smaller cheaper models or reduce context bloat in the main
conversation (#149).
btw_tool_files_edit() makes targeted, validated line-based edits to files
using replace, insert_after, and replace_range actions. Edits are
anchored to content hashes, so stale edits are rejected if the file has
changed. To support this, btw_tool_files_read() now annotates each line
with a short hash (e.g. 2:f1a| return("world")) when called as a tool
(#167).
btw_tool_files_replace() finds and replaces exact string occurrences in a
file. By default it requires the string to appear exactly once to prevent
unintended changes; set replace_all = TRUE to replace all occurrences
(#167).
btw_tool_pkg_load_all() runs pkgload::load_all() in an isolated
subprocess to verify package code loads correctly and trigger recompilation
of compiled code. Useful for quick validation during development without
running full tests or affecting the current R session (#156).
btw_tool_skill() adds support for Agent Skills.
Skills are modular, on-demand capabilities that provide specialized
instructions, bundled scripts, reference docs, and asset templates to the
LLM. Skills are discovered automatically from the btw package, attached R
packages with inst/skills/ directories, user-level skills, and
project-level skills in .btw/skills/ or .agents/skills/. When the skill
tool is included in the chat client, available skills are listed in the
system prompt. Use btw_skill_install_github() or
btw_skill_install_package() to install skills from external sources, and
btw_task_create_skill() to interactively create new skills (#145).
btw_app() no longer errors with "argument is of length zero" when run
outside of an IDE (thanks @HenrikBengtsson, #168).
btw_app() no longer errors when provider built-in tools (e.g.
claude_tool_web_search()) are registered with a btw client.
Built-in tools now appear in the app sidebar under a "Built-in" group (#175).
btw_tool_files_read() now correctly handles UTF-8 files containing CJK
(Chinese, Japanese, Korean) characters. Previously, the text-file detection
could truncate a read buffer mid-way through a multi-byte character, causing
the file to be rejected as binary (thanks @bianchenhao, #170).
btw_tool_files_read() now correctly reads valid UTF-8 files containing
non-ASCII characters (e.g., Cyrillic). Previously, these files were
incorrectly rejected on Windows with non-English locales when Encoding()
returned "unknown" even though they were valid UTF-8 (thanks @RKonstantinR,
#160).
btw_client() now supports reading CLAUDE.md files as project context files. CLAUDE.md files are searched after AGENTS.md but before user-level btw.md. YAML frontmatter in CLAUDE.md files is stripped but not used for configuration (#146).
btw_app() now shows a rich diff view in the btw_tool_files_write_text_file() tool, if the {diffviewer} package is installed (#144).
btw() now correctly handles character matrices (#139).
btw_app() now correctly displays input tokens with ellmer v0.4.0. Previously, we were showing the total input tokens sent across all API calls, rather than the current number of input tokens as of the last API call. We now show the size of the input context window (i.e. the number of input tokens that will be used for the conversation history in the next API call). Note that token usage is dependent on the provider and model used and is only an estimate.
New "pkg" tool group with package development tools: btw_tool_pkg_document(), btw_tool_pkg_check(), btw_tool_pkg_test() and btw_tool_pkg_coverage() provide LLMs with the ability to document, check, test, and check test coverage of R packages during development (#133, #136).
New btw_tool_run_r() tool allows LLMs to run R code and to see the output, including of plots. Because this tool lets LLMs run R arbitrary R code in the global environment (which can be great but can also have security implications), it is opt-in and disabled by default. See ?btw_tool_run_r for more details (#126).
btw_tool_docs_help_page() now uses markdown headings and sections for argument descriptions, rather than a table. This is considerably more token efficient when the argument descriptions have more than one paragraph and can't be converted into a markdown table (@jeanchristophe13v, #123).
btw now removes large inline base64-encoded images, replacing them with a placeholder containing the image's alt text (@jeanchristophe13v, #119).
btw_app() now works correctly with {ellmer} v0.4.0 (#121).
btw_app() now shows more precise cost estimates when the cost is less than $0.10 (#121).