install.packages(c("ellmer", "ragnar", "shiny", "bslib", "shinychat", "jsonlite"))11 Your AI Co-Pilot: Agentic Risk Analysis
“The best tool for the job is the one you’ll actually use.” — P.G.
You’ve made it through eight chapters of quantitative risk analysis. You know Monte Carlo, SMM, EVM, Bayesian inference, learning curves, design structure matrices, and probabilistic networks. Now imagine not having to remember the syntax for all of them.
Imagine a project manager typing “run Monte Carlo for three tasks with Normal(10,2), Triangular(5,10,15), Uniform(8,12)” and getting back a P95 date, a contingency reserve, and a tornado chart, all in ten seconds, without opening R. That’s the promise of the PRA agentic framework: a layer of intelligence on top of all the methods you’ve learned.
11.1 The Three Routing Modes
| Input type | Route | Example |
|---|---|---|
/command |
Deterministic: executes the tool directly, no LLM | /mcs tasks=[...] |
| Numerical data | LLM tool call: the model selects and calls the right tool | “Simulate 3 tasks: Normal(10,2)…” |
| Conceptual question | RAG: answered from the knowledge base | “What is earned value?” |
When to use each:
- Use slash commands when you need guaranteed, reproducible results; they bypass the LLM entirely.
- Use the chat interface for exploratory questions and interpretation, especially with larger models.
- Use RAG for conceptual questions; it retrieves the most relevant knowledge base content and cites sources.
Three interfaces expose these modes:
- Slash commands: deterministic tool calls that bypass the LLM for instant, reliable results
- Chat interface (
pra_chat()): programmatic R chat powered by ellmer - Shiny app (
pra_app()): browser-based experience combining all three modes
11.2 Prerequisites
11.2.1 Install Ollama
Download from https://ollama.com, then pull a model:
ollama serve
ollama pull llama3.2
ollama pull nomic-embed-text # for RAG embeddings11.2.2 Install R dependencies
11.3 Slash Commands
Slash commands provide deterministic tool execution with no LLM required. Type /help to see all available commands, or /help <command> for detailed usage.
11.3.1 Available Commands
library(PRA)
cat(PRA:::format_help_overview())## PRA Commands
Type a command to run an analysis directly. Type `/help <command>` for detailed usage.
- **/mcs** — Monte Carlo Simulation
- **/smm** — Second Moment Method
- **/contingency** — Contingency Reserve
- **/sensitivity** — Sensitivity Analysis
- **/evm** — Earned Value Management
- **/risk** — Bayesian Risk (Prior)
- **/risk_post** — Bayesian Risk (Posterior)
- **/learning** — Learning Curve Fit
- **/dsm** — Design Structure Matrix
Type `/help` for this overview.
11.3.2 Example: Monte Carlo Simulation
set.seed(42)
cmd <- paste0(
'/mcs n=10000 tasks=[',
'{"type":"normal","mean":10,"sd":2},',
'{"type":"triangular","a":5,"b":10,"c":15},',
'{"type":"uniform","min":8,"max":12}]'
)
r <- PRA:::execute_command(cmd)
cat(r$result)Monte Carlo Simulation Results (n = 10,000):
Summary Statistics:
Mean 29.9804
SD 3.113
Min 19.502
Max 41.3892
Percentiles:
P5 24.8726
P10 26.0194
P25 27.8881
P50 29.9536
P75 32.0796
P90 33.9873
P95 35.1014
result <- PRA:::.pra_agent_env$last_mcs
hist(result$total_distribution,
freq = FALSE, breaks = 50,
main = "Monte Carlo Simulation Results",
xlab = "Total Project Duration/Cost",
col = "#18bc9c80", border = "white"
)
curve(dnorm(x, mean = result$total_mean, sd = result$total_sd),
add = TRUE, col = "#2c3e50", lwd = 2
)
abline(
v = quantile(result$total_distribution, c(0.50, 0.95)),
col = c("#3498db", "#e74c3c"), lty = 2, lwd = 1.5
)
legend("topright",
legend = c("Normal fit", "P50", "P95"),
col = c("#2c3e50", "#3498db", "#e74c3c"),
lty = c(1, 2, 2), lwd = c(2, 1.5, 1.5),
cex = 0.8, bg = "white"
)
11.3.3 Example: Chaining MCS to Contingency
After running /mcs, chain to /contingency for the reserve estimate:
r <- PRA:::execute_command("/contingency phigh=0.95 pbase=0.50")
cat(r$result)Contingency Analysis:
Base Percentile P50
High Percentile P95
Contingency Reserve 5.1478
11.3.4 Example: Earned Value Management
Full EVM analysis with a single command:
cmd <- paste(
"/evm bac=500000",
"schedule=[0.2,0.4,0.6,0.8,1.0]",
"period=3 complete=0.35",
"costs=[90000,195000,310000]"
)
r <- PRA:::execute_command(cmd)
cat(r$result)Earned Value Management Analysis:
Core Metrics:
Planned Value (PV) 300,000
Earned Value (EV) 175,000
Actual Cost (AC) 310,000
Variances:
Schedule Variance (SV) -125,000
Cost Variance (CV) -135,000
Performance Indices:
Schedule Performance Index (SPI) 0.5833
Cost Performance Index (CPI) 0.5645
Forecasts:
EAC (Typical) 885,714.3
EAC (Atypical) 635,000
EAC (Combined) 1,296,939
Estimate to Complete (ETC) 575,714.3
Variance at Completion (VAC) -385,714.3
TCPI (to meet BAC) 1.7105
11.3.5 Example: Bayesian Risk Probability
r <- PRA:::execute_command(
"/risk causes=[0.3,0.2] given=[0.8,0.6] not_given=[0.2,0.4]"
)
cat(r$result)Bayesian Risk Analysis (Prior):
Risk Probability 0.82
Risk Percentage 82%
Number of Causes 2
Then update with observations:
r <- PRA:::execute_command(
"/risk_post causes=[0.3,0.2] given=[0.8,0.6] not_given=[0.2,0.4] observed=[1,null]"
)
cat(r$result)Bayesian Risk Analysis (Posterior):
Posterior Risk Probability 0.6316
Posterior Risk Percentage 63.16%
Observations:
Cause 1: Occurred
Cause 2: Unknown
11.3.6 Example: Second Moment Method
r <- PRA:::execute_command("/smm means=[10,12,8] vars=[4,9,2]")
cat(r$result)Second Moment Method Results:
Total Mean 30
Total Variance 15
Total Std Dev 3.873
11.3.7 Input Validation
Missing or invalid arguments produce helpful error messages:
r <- PRA:::execute_command("/risk causes=[0.3]")
cat(r$result)**Missing required argument(s):** given, not_given
### /risk — Bayesian Risk (Prior)
Calculate prior risk probability from root causes using Bayes' theorem.
**Arguments:**
- **causes** *(required)* — JSON array of cause probabilities, e.g. [0.3, 0.2]
- **given** *(required)* — JSON array of P(Risk | Cause), e.g. [0.8, 0.6]
- **not_given** *(required)* — JSON array of P(Risk | not Cause), e.g. [0.2, 0.4]
**Examples:**
/risk causes=[0.3,0.2] given=[0.8,0.6] not_given=[0.2,0.4]
11.4 Chat Interface
eval: false in This Chapter
The Chat Interface, Shiny App, and MCP sections require a running Ollama server and cannot be evaluated during book rendering. Code blocks marked eval: false show the correct syntax; to follow along interactively, start Ollama with ollama serve before running them. The slash command examples above are fully evaluated and show actual output.
The chat interface routes queries through the LLM, which decides whether to call a tool or answer from the RAG knowledge base:
- Numerical data → LLM calls the appropriate tool and interprets the results
- Conceptual questions → LLM answers from the RAG knowledge base with source citations
chat <- pra_chat(model = "llama3.2")
# Tool call: user provides numerical data
chat$chat("Run a Monte Carlo simulation for a 3-task project with
Task A ~ Normal(10, 2), Task B ~ Triangular(5, 10, 15),
Task C ~ Uniform(8, 12). Use 10,000 simulations.")
# RAG: conceptual question
chat$chat("What is the difference between SPI and CPI?")11.4.1 Using Cloud Models
For better accuracy with complex queries:
# Anthropic (replace with the current model ID from https://docs.anthropic.com/en/docs/about-claude/models)
chat <- pra_chat(chat = ellmer::chat_anthropic(model = "claude-sonnet-4-5"))
# OpenAI
chat <- pra_chat(chat = ellmer::chat_openai(model = "gpt-4o"))11.5 Interactive Shiny App
For a browser-based experience with streaming responses and inline visualizations:
pra_app()The app supports all three input modes in the same chat panel:
- Type
/mcs tasks=[...]for instant deterministic results - Type “Simulate 3 tasks…” for LLM tool calling
- Type “What is earned value?” for RAG-powered answers
11.5.1 Features
- Three input modes in a single panel
- Clickable example prompts that execute
/commandson click - Streaming chat with token-by-token responses
- Inline tool results as rich HTML tables and plots
- RAG source citations for conceptual answers
- Export: download the conversation as markdown
11.6 RAG Knowledge Base
PRA includes a built-in knowledge base covering all the methods in this book:
| File | Topics |
|---|---|
mcs_methods.md |
Distribution selection, correlation, interpreting percentiles |
evm_standards.md |
EVM metrics, performance indices, forecasting methods |
bayesian_risk.md |
Prior/posterior risk, Bayes’ theorem |
learning_curves.md |
Sigmoidal models, curve fitting |
sensitivity_contingency.md |
Variance decomposition, contingency reserves |
pra_functions.md |
PRA package function reference |
11.6.1 Adding Your Own Documents
store <- build_knowledge_base()
add_documents(store, "path/to/my_risk_register.md")
add_documents(store, "path/to/project_docs/")11.7 MCP Integration
PRA can expose all its tools as an MCP (Model Context Protocol) server, letting Claude Desktop, Claude Code, or any MCP-compatible AI client call PRA functions directly.
11.7.1 Starting the Server
pra_mcp_server()11.7.2 Connecting from Claude Code
claude mcp add -s project pra -- Rscript -e "PRA::pra_mcp_server()"Once registered, Claude Code can call PRA tools in any conversation:
“Run a Monte Carlo simulation for three tasks: Task A normal(10, 2), Task B triangular(5, 10, 15), Task C uniform(8, 12). What is the contingency reserve at the 90th percentile?”
11.7.3 Connecting from Claude Desktop
Add the following to your Claude Desktop config file:
{
"mcpServers": {
"pra": {
"command": "Rscript",
"args": ["-e", "PRA::pra_mcp_server()"]
}
}
}11.8 Available Commands Reference
| Command | Description |
|---|---|
/mcs |
Monte Carlo simulation with task distributions |
/smm |
Second Moment Method (analytical estimate) |
/contingency |
Contingency reserve from last MCS |
/sensitivity |
Variance contribution per task |
/evm |
Full Earned Value Management analysis |
/risk |
Bayesian prior risk probability |
/risk_post |
Bayesian posterior risk after observations |
/learning |
Sigmoidal learning curve fit and prediction |
/dsm |
Design Structure Matrix |
/help |
List all commands or get help for one |
11.9 Summary
Congratulations, you’ve completed the toolkit. You can now quantify project uncertainty (MCS, Chapter 2; SMM, Chapter 3), track project performance (EVM, Chapter 5), update risk estimates with new evidence (Bayesian, Chapter 6; Networks, Chapter 9), model structural dependencies (DSM, Chapter 8; Portfolio, Chapter 10), forecast learning (Sigmoidal, Chapter 7), and automate it all through an AI interface (Chapter 11). The rest is practice.
11.10 Exercises
Slash vs. chat. Run the same MCS problem using (a) a
/mcsslash command and (b) a natural language prompt throughpra_chat(). Do you get the same numerical results? If not, why might they differ?Command chaining. Run
/mcsfor a 3-task project of your choice, then immediately run/contingencyat P80 and P95. What is the difference between the two contingency values? Interpret this difference in plain English.EVM from a prompt. Use
/evmwith the following inputs: BAC = $300K, schedule = [0.2, 0.4, 0.6, 0.8, 1.0], period = 4, complete = 0.55, costs = [$55K, $115K, $175K, $240K]. Report CPI, SPI, and EAC (typical). Is the project in good shape?RAG vs. tool call. Ask
pra_chat()two questions: (a) “What distributions should I use for tasks with optimistic/likely/pessimistic estimates?” and (b) “Run a Monte Carlo simulation for Task A ~ Normal(10, 2) and Task B ~ Uniform(8, 12).” Identify which routing mode was used for each. How can you tell from the response?MCP integration. ★ If you have Claude Desktop or Claude Code installed, configure PRA as an MCP server using the instructions above. Ask Claude to run a Monte Carlo simulation and report the P95 duration. Then ask a conceptual question about EVM. Describe the experience: did the tool calls work? Was the RAG answer accurate?