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.

NoteLearning Objectives

By the end of this chapter, you will be able to:

  1. Distinguish the three routing modes (slash commands, LLM tool calls, RAG)
  2. Run any PRA method via a slash command and chain results across commands
  3. Use pra_chat() to interact with PRA methods through natural language
  4. Explain how RAG augments the LLM with domain-specific knowledge
  5. Configure PRA as an MCP server for Claude Desktop or Claude Code

11.1 The Three Routing Modes

NoteHow PRA Routes Your Input
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:

  1. Slash commands: deterministic tool calls that bypass the LLM for instant, reliable results
  2. Chat interface (pra_chat()): programmatic R chat powered by ellmer
  3. 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 embeddings

11.2.2 Install R dependencies

install.packages(c("ellmer", "ragnar", "shiny", "bslib", "shinychat", "jsonlite"))

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"
)

MCS results via slash command. The /mcs command stores results for downstream chaining.

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

NoteAbout 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 /commands on 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

TipKey Takeaways
  • Slash commands (/mcs, /evm, /risk, etc.) provide deterministic, LLM-free execution of every method covered in this book; use them when you need guaranteed reproducibility.
  • The chat interface routes input intelligently: numerical data → tool call; conceptual question → RAG. The LLM is a router, not a calculator.
  • RAG (Retrieval-Augmented Generation) grounds LLM answers in the PRA knowledge base, reducing hallucination and enabling source citations.
  • The MCP server exposes all PRA tools to any MCP-compatible AI client (Claude Desktop, Claude Code, or custom agents) without requiring an R session on the user’s end.
  • Small models (3B) handle simple single-tool queries; use larger models (8B+) or cloud models for multi-step chains and interpretation.

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

  1. Slash vs. chat. Run the same MCS problem using (a) a /mcs slash command and (b) a natural language prompt through pra_chat(). Do you get the same numerical results? If not, why might they differ?

  2. Command chaining. Run /mcs for a 3-task project of your choice, then immediately run /contingency at P80 and P95. What is the difference between the two contingency values? Interpret this difference in plain English.

  3. EVM from a prompt. Use /evm with 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?

  4. 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?

  5. 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?