What Your AI Coding Assistant Doesn’t Know About Your Shiny App
I asked Cursor and Claude Code the same question about a Shiny app: “If I rename this reactive expression, what breaks?” Both gave confident answers. Both were wrong.

I run a Shiny app for a small analytics dashboard. Nothing exotic — a few reactive expressions, a server function, some UI bindings, a plumber endpoint that exposes a model prediction.
Last week I needed to rename a reactive expression. I asked my AI coding assistant: “If I rename filtered_data to dataset_filtered, what breaks?"
Cursor gave me four files to update. Confidently. With code suggestions.
Three of those files weren’t connected to the reactive expression at all. One file that actually depended on it was missing from the list.
I asked Claude Code the same question. Different answer, same problem. Confident, fast, partially wrong.
This is not an unusual story for anyone writing R, Shiny, or plumber code with AI assistance. It is the operating reality.
Why AI coding assistants struggle with R
The popular AI coding tools were optimized for JavaScript, TypeScript, and Python web frameworks. Those languages have predictable structure — imports at the top, classes with clear inheritance, functions defined with named keywords. Easy to scan, easy to chunk, easy to feed into an embedding model.
R is different in ways that matter.
Functions are variables. There is no def or function keyword preceding a name. A function is whatever the right-hand side of an assignment happens to be: my_function <- function(x) x * 2. AI tools trained on Python miss this constantly.
There are two assignment operators. R developers use both <- and = in the same file. Sometimes a developer's preference shows by section, sometimes by file, sometimes by mood. AI tools treat one of them as "the real one" and miss the other.
There are three OOP systems. S3 dispatches by function naming convention (print.myclass). S4 is formally typed (setClass, setGeneric, setMethod). R6 is reference-based with class methods. Most AI tools treat them as if they were one system, which means they get the inheritance and dispatch wrong almost every time.
There is R Markdown. Code lives inside \``{r}` chunks embedded in markdown documents. AI tools either ignore the chunks (treating the file as prose) or process them as if they were standalone R scripts (missing the inter-chunk dependencies).
There is reticulate. R projects routinely call into Python via the reticulate package. The boundary is real — variables cross over, types are converted, errors propagate strangely. AI tools see Python and R as separate worlds rather than one workflow with a permeable boundary.
There are reactive expressions in Shiny. The whole point of Shiny is that values propagate through a reactive graph. If you change one reactive, every reactive that depends on it updates. AI tools have no model of this graph. They see a function call. They miss the reactive subscription.
The result is that an AI tool can read all the files in your R project and still answer wrong on basic questions about what depends on what.
The deterministic alternative
What I needed was a tool that builds a real graph of my R code — every function definition, every import, every reactive subscription, every plumber route, every cross-language edge to Python via reticulate. Not an embedding. A graph.
That is what I built. Depwire is an open source CLI that parses your codebase with tree-sitter and similar deterministic parsers, builds a symbol-level dependency graph, and exposes it to AI coding assistants through 23 MCP tools.
The graph does not hallucinate. It does not give confident wrong answers. If you ask “what depends on filtered_data?", the graph returns the actual list of every place in your code where that symbol is referenced. Same answer every time, regardless of which AI tool is asking.
Version 1.5.0 of Depwire adds R support. Specifically:
- All three OOP systems (S3, S4, R6) are recognized correctly
- Both assignment operators (<- and =) are parsed
- Functions defined as variables get registered as functions in the graph
- R Markdown code chunks are extracted from .Rmd files and parsed
- Anonymous function shorthand (\(x) x + 1, R 4.1+) is recognized
- Namespace access (dplyr::filter, package:::internal_fn) creates the correct edges
- Operator overloading methods (+.myclass, -.myclass) are detected
- Shiny reactive expressions are tracked as graph nodes
- plumber API annotations (#* @get, #* @post) are detected as routes
- Cross-language edges to Python via reticulate are captured
When I parsed the rstudio/plumber repository as a test, Depwire processed 197 files, extracted 1,194 symbols, and built 219 edges between them in 0.58 seconds. The health score for the repo came back as 87, grade B. That number is reproducible. Run it again on the same commit, get the same score.
What this looks like in practice
The example I started with — renaming filtered_data to dataset_filtered in my Shiny app — is exactly the kind of question Depwire answers well.
I ran the impact analysis through Depwire’s MCP server. The graph returned every symbol that referenced filtered_data in the project. Not files. Symbols. Specific lines. Specific function calls. The blast radius came back as 6 references across 3 files. Two of those files were UI bindings that Cursor missed. The other AI tools had been giving me lists that included unrelated dependencies and missing the actual ones.
I made the rename, updated the 6 references, ran the tests. Done. No surprises.
This is what code intelligence looks like when it is grounded in a graph instead of an embedding. The answer is the same every time you ask. The answer is correct. The answer can be audited.
Why does this matter for R specifically
R has been waiting for code intelligence tooling that takes it seriously. Most of the AI coding ecosystem was built by JavaScript and Python developers for JavaScript and Python developers. R has been treated as a “second-class language” for years — the tooling exists, but it is always a step behind.
This is starting to change. R is the backbone of pharmaceutical clinical trials, biostatistics, academic research, and quantitative finance. The code bases are large, the consequences of bugs are real, and the need for trustworthy AI assistance is significant.
Depwire is one small step. The CLI is open source. The MCP server works with any AI coding assistant that speaks MCP — Cursor, Claude Code, Aider, Continue, and custom agents. There is also a hosted Cloud platform at depwire.dev if you do not want to run it locally.
If you write R code with AI assistance, install Depwire CLI with npm install -g depwire-cli. Run depwire parse . in your R project. Connect it to your AI tool via MCP. Ask the same questions you have been asking and see if the answers improve.
The goal is not to replace your AI coding assistant. The goal is to give it the deterministic ground truth it has been missing.
Repo: github.com/depwire/depwire
Spec for the open standard that pairs with this (Depwire Action Token, for AI agent action accountability): github.com/depwire/dat-spec