Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
6934cf9
feat(rca): scaffold plugin — manifest, MCP wiring, config, command, R…
ruturaj-browserstack Jun 23, 2026
f0d5cf6
feat(rca): generic per-test RCA coordinator + evidence-routing registry
ruturaj-browserstack Jun 23, 2026
cb0d8f6
feat(rca): pre-flight intake, discovery, CSV/WAL spine
ruturaj-browserstack Jun 23, 2026
bbee37d
feat(rca): failure-signature clustering + sibling one-turn-confirm pr…
ruturaj-browserstack Jun 23, 2026
7ddb2c2
feat(rca): build-evidence pre-compute + cache + capability manifest
ruturaj-browserstack Jun 23, 2026
d6f0452
feat(rca): auto-mode dynamic workflow (rca-batch)
ruturaj-browserstack Jun 23, 2026
28ebc1d
feat(rca): interactive mode — subagents with user-in-the-loop gap-return
ruturaj-browserstack Jun 23, 2026
e8b70e6
feat(rca): suspect-PR falsification packet + GitHub-evidence spec
ruturaj-browserstack Jun 23, 2026
c5a4e9e
feat(rca): coverage stamp + degrade-don't-crash report (resume reaper…
ruturaj-browserstack Jun 23, 2026
e277811
feat(rca): conformance fixture + executable loop mirror / sequential …
ruturaj-browserstack Jun 23, 2026
e9331af
fix(rca): make pending-resume resumable, enforce flip terminal status…
ruturaj-browserstack Jun 23, 2026
3d22dfe
chore(rca): gitignore local planning docs
ruturaj-browserstack Jun 23, 2026
79e4c87
feat(rca): cross-client integration for Cursor and Codex
ruturaj-browserstack Jun 23, 2026
c219deb
feat(rca): seed rengg-tfa failing build + k8s context harness
ruturaj-browserstack Jun 24, 2026
5655322
fix(rca): remove command/skill name collision so the skill body loads
ruturaj-browserstack Jun 24, 2026
2a14598
fix(rca): auto mode must not block on intake — proceed with whatever …
ruturaj-browserstack Jun 24, 2026
d97db23
fix(rca): dispatch the coordinator by its plugin-namespaced agent type
ruturaj-browserstack Jun 24, 2026
1e941a3
fix(rca): namespace the representative dispatch too (missed by replac…
ruturaj-browserstack Jun 24, 2026
f07f435
feat(rca): rename skill to /factory — single-gate, auto-only flow
ruturaj-browserstack Jul 12, 2026
7906844
feat(rca): consume trimmed tfaRcaTurn shapes; glimpse output replaces…
ruturaj-browserstack Jul 12, 2026
4126119
feat(rca): coordinator + batch workflow go autonomous on trimmed shapes
ruturaj-browserstack Jul 12, 2026
97dbe1d
docs(rca): tell the single-gate /factory story; scrub mode/report/BLO…
ruturaj-browserstack Jul 12, 2026
d2faebd
fix(rca): keep the skill named rca-build — /factory is the user's spe…
ruturaj-browserstack Jul 12, 2026
e4428c7
feat(rca): per-build state file in OS temp — csvPathFor(buildId, stat…
ruturaj-browserstack Jul 14, 2026
5f34563
refactor(rca): align skills with canonical layout — templates/, examp…
ruturaj-browserstack Jul 14, 2026
6796327
fix(rca): confirmed TRA UI deep-link — automation.browserstack.com + …
ruturaj-browserstack Jul 14, 2026
a8c2014
chore(rca): remove the k8s-rengg-tfa skill
ruturaj-browserstack Jul 14, 2026
8380146
refactor(rca): generalize k8s → infra capability — route to whatever …
ruturaj-browserstack Jul 14, 2026
af0f188
docs(rca): fix orphaned demo-step lines left by the k8s-skill removal…
ruturaj-browserstack Jul 14, 2026
37edaa8
chore(rca): pin bstack MCP server to @browserstack/mcp-server@1.2.27-…
ruturaj-browserstack Jul 14, 2026
6fea228
chore(rca): remove automation/ seed harness + harden product-repo inf…
ruturaj-browserstack Jul 14, 2026
c68cd17
fix(rca): ask for the product repo when it's unknown + load-bearing (…
ruturaj-browserstack Jul 14, 2026
31915f0
fix(rca): finish output is a completion notice + link only — no RCA d…
ruturaj-browserstack Jul 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "tfa-rca",
"description": "Drive collaborative root-cause analysis over all failed tests of a build, generic across product and infra.",
"version": "0.1.0",
"author": {
"name": "BrowserStack",
"url": "https://www.browserstack.com"
},
"homepage": "https://github.com/browserstack/browserstack-ai-tfa-demo",
"license": "MIT"
}
13 changes: 13 additions & 0 deletions .cursor-mcp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"mcpServers": {
"bstack": {
"command": "npx",
"args": ["-y", "@browserstack/mcp-server@1.2.27-beta.1"],
"env": {
"BROWSERSTACK_USERNAME": "${BROWSERSTACK_USERNAME}",
"BROWSERSTACK_ACCESS_KEY": "${BROWSERSTACK_ACCESS_KEY}",
"O11Y_TFA_RCA_BASE_URL": "${O11Y_TFA_RCA_BASE_URL}"
}
}
}
}
8 changes: 8 additions & 0 deletions .cursor-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "tfa-rca",
"description": "Collaborative root-cause analysis over all failed tests of a BrowserStack build, generic across product and infra.",
"version": "0.1.0",
"mcpServers": "../.cursor-mcp.json",
"skills": "./skills/",
"author": { "name": "BrowserStack" }
}
8 changes: 8 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# BrowserStack credentials — used by the bundled bstack MCP server for
# listTestIds + tfaRcaTurn. Per-user; never commit real values.
BROWSERSTACK_USERNAME=
BROWSERSTACK_ACCESS_KEY=

# Observability base URL the TFA RCA chat runs against. Optional —
# the bstack MCP server defaults to its rengg-tfa staging URL when unset.
# O11Y_TFA_RCA_BASE_URL=https://api-observability-rengg-tfa.bsstag.com
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules/
.env
# Per-run RCA batch state (the CSV/WAL spine + report) is workspace-local.
.rca/
# Planning docs (brainstorm/ideation/plan) stay local — not pushed.
docs/
14 changes: 14 additions & 0 deletions .mcp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"mcpServers": {
"bstack": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@browserstack/mcp-server@1.2.27-beta.1"],
"env": {
"BROWSERSTACK_USERNAME": "${BROWSERSTACK_USERNAME}",
"BROWSERSTACK_ACCESS_KEY": "${BROWSERSTACK_ACCESS_KEY}",
"O11Y_TFA_RCA_BASE_URL": "${O11Y_TFA_RCA_BASE_URL}"
}
}
}
}
102 changes: 102 additions & 0 deletions INTEGRATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Multi-client integration (Claude Code · Cursor · Codex)

This plugin is built so the **MCP core is truly cross-client** and the **harness
layer ports via the cross-vendor Agent Skills standard**. Only one piece is
genuinely Claude-Code-specific (the batch *dynamic workflow*); on Cursor and
Codex that role is filled by the sequential harness or subagents. Every path is
autonomous after the single `/rca-build` gate — no host ever prompts mid-run.

## What transfers, what doesn't

| Layer | Claude Code | Cursor | Codex |
|---|---|---|---|
| `bstack` MCP server (`listTestIds` + `tfaRcaTurn` + `triggerRcaReport`) | `.mcp.json` (auto-discovered) | `.cursor-mcp.json` / `.cursor/mcp.json` | `~/.codex/config.toml` `[mcp_servers.bstack]` |
| `rca-build` skill (`SKILL.md`) | plugin `skills/` | Agent Skills (`.cursor/skills/` or cursor-plugin `"skills":"./skills/"`) | Agent Skills (`.agents/skills/`) |
| `ai-tfa-coordinator` agent | plugin `agents/` | `.cursor/agents/` (also reads `.claude/agents/`) | `.codex/agents/` |
| Per-test RCA **loop** | `agents/ai-tfa-coordinator.md` | same skill/agent | same skill/agent |
| Batch orchestration | dynamic workflow `workflows/rca-batch.mjs` (or subagents) | subagents, or **sequential** `lib/loop.mjs` | subagents, or **sequential** `lib/loop.mjs` |

The dynamic workflow (`workflows/rca-batch.mjs`) uses Claude Code's Workflow
runtime, which Cursor/Codex don't have. The same batch still runs there via
**subagents** (both hosts support subagents) or the **sequential thin-client
harness** `lib/loop.mjs` (`runRcaLoop`) — the conformance-tested loop that
drives `tfaRcaTurn` over the same contract without any host-specific
orchestration. On every host the run finishes the same way: glimpse table →
`triggerRcaReport(buildUuid)` → "Full report on the Test Observability UI:
<viewReport>". No local report file is ever written.

## Claude Code

```bash
cp .env.example .env # BROWSERSTACK_USERNAME / BROWSERSTACK_ACCESS_KEY
claude --plugin-dir ./
/rca-build <build-id>
```

`.claude-plugin/plugin.json` + root `.mcp.json` + `skills/` + `agents/` are
auto-discovered. (No `commands/rca-build.md` on purpose — a command and skill
with the same name collide and the skill body fails to load.)

## Cursor

The repo ships Cursor parity files mirroring `slack-mcp-plugin`:
`.cursor-plugin/plugin.json` (points at `../.cursor-mcp.json` and `./skills/`)
and `.cursor-mcp.json` (the stdio `bstack` server).

**Wire the MCP server** — either:
- copy `.cursor-mcp.json`'s `bstack` entry into your project `.cursor/mcp.json`
(top-level `mcpServers`), or
- Cursor → Settings → Cursor Settings → **MCP** → paste the same JSON, or
- use an **Add to Cursor** deeplink:
`cursor://anysphere.cursor-deeplink/mcp/install?name=bstack&config=<base64-of-the-bstack-entry-body>`

Set `BROWSERSTACK_USERNAME` / `BROWSERSTACK_ACCESS_KEY` / `O11Y_TFA_RCA_BASE_URL`
in your environment (or replace the `${…}` placeholders with literals).

**Skill + agent discovery** — Cursor reads `.cursor/skills/` and `.cursor/agents/`
(and also `.claude/agents/`). The simplest no-duplication setup is to symlink the
shared trees:

```bash
mkdir -p .cursor
ln -s ../skills .cursor/skills
ln -s ../agents .cursor/agents
```

Then drive it from Agent chat: invoke the `rca-build` skill with a build id.

## Codex

Codex reads the global `~/.codex/config.toml` (no per-project MCP file).

**Wire the MCP server** — either copy the block from `codex-mcp.example.toml`
into `~/.codex/config.toml`, or:

```bash
codex mcp add bstack \
--env BROWSERSTACK_USERNAME=… --env BROWSERSTACK_ACCESS_KEY=… \
--env O11Y_TFA_RCA_BASE_URL=https://api-observability-rengg-tfa.bsstag.com \
-- npx -y @browserstack/mcp-server@1.2.27-beta.1
```

**Skill + agent discovery** — Codex reads `.agents/skills/` (skills) and
`.codex/agents/` (subagents). Symlink the shared trees:

```bash
mkdir -p .agents .codex
ln -s ../skills .agents/skills
ln -s ../agents .codex/agents
```

Then run the `rca-build` skill; the coordinator + `tfaRcaTurn` loop are identical.

## Notes

- The `bstack` server is **stdio** (`npx @browserstack/mcp-server@1.2.27-beta.1`), not a remote
OAuth server — so the configs use `command`/`args`/`env`, unlike Slack's
`url`+`oauth`/`auth` shape.
- Env-var interpolation (`${VAR}`) is honored by Claude Code's `.mcp.json`; on
Cursor/Codex, replace the placeholders with literals if your client doesn't
expand them.
- Everything in `lib/` and the `SKILL.md`/agent prose is host-agnostic — only the
MCP wiring file and the dynamic workflow are host-specific.
120 changes: 118 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,118 @@
# browserstack-ai-tfa-demo
AI TFA Demo
# tfa-rca — generic multi-client RCA agent plugin

Drive BrowserStack's collaborative root-cause-analysis loop over **all failed
tests of a build**, generic across product and infra, from inside an agentic
MCP client (Claude Code / Cursor / Codex).

The plugin wraps three stable MCP tools — `listTestIds`, `tfaRcaTurn`, and
`triggerRcaReport` (from the `bstack` MCP server) — and adds the harness that
batches RCA over a whole build, clusters failures by signature, routes evidence
requests to whatever skills/tools the client already has, and lands a per-test
RCA in the TRA (Test Observability) dashboard.

> **The full RCA report lives on the Test Observability UI, not in Claude.**
> The plugin surfaces a terse glimpse, triggers the dashboard report
> (`triggerRcaReport`), and prints the link. It **discovers and delegates** to
> the infra skills/tools already in your client (GitHub, whatever runtime you have — k8s/ECS/docker/… — kibana/other
> logs, metrics). It does **not** install or own those connectors, and it never
> writes a local report file.

## Install

```bash
git clone https://github.com/browserstack/browserstack-ai-tfa-demo.git
cd browserstack-ai-tfa-demo
cp .env.example .env # fill in BROWSERSTACK_USERNAME / BROWSERSTACK_ACCESS_KEY
claude --plugin-dir ./
```

The plugin auto-configures on load: the `bstack` MCP server (from `.mcp.json`),
the `rca-build` skill, and the `ai-tfa-coordinator` agent are all discovered by
convention. (There is deliberately **no** command file named `rca-build` — a
command and skill sharing a name collide and the skill body fails to load.)

### Cursor & Codex

The MCP core (`listTestIds` + `tfaRcaTurn` + `triggerRcaReport`) and the
skill/agent layer port to both — Cursor uses `.cursor-plugin/plugin.json` +
`.cursor-mcp.json`, Codex uses `~/.codex/config.toml` (see
`codex-mcp.example.toml`). The only Claude-specific piece is the batch *dynamic
workflow*; on Cursor/Codex the same batch runs via subagents or the sequential
harness (`lib/loop.mjs`). Full per-host wiring (MCP config, skill/agent
discovery, deeplink) is in **[INTEGRATION.md](INTEGRATION.md)**.

## Usage

```
/rca-build <build-id>
/rca-build build_id=<id> https://github.com/org/repo/pull/123
```

Args: a build id (bare, `build_id=`, or a dashboard link) plus optional PR URLs
/ repo hints.

## The single gate

The run has exactly **one gate** before execution, with two parts:

1. **Connector discovery + validation** — every connector relevant to test RCA
(github, infra, logs, metrics, …) is enumerated and probe-validated (`gh auth
status`, an infra probe matching whatever runtime exists — kubectl/docker/ecs/… — MCP tools listed). The result is a validated
capability manifest: `connector → valid | invalid | absent`. A gap is
recorded and declared to the TFA agent ("I don't have logs/metrics access") —
never a blocker.
2. **Requirements** — intake fields (product repo, automation repo, branches,
PRs in play, build id) are resolved **by assumption** wherever possible
(invocation args, `gh repo view`, current branch). At most **one**
consolidated question may be asked at gate close, and only for genuinely
non-assumable, load-bearing fields. Headless (`claude -p`) never asks: a
missing build id fails fast; everything else is a recorded gap.

**After the gate closes, the run never asks you anything again** — RCA
execution is fully autonomous. Evidence gaps degrade to "unavailable" back to
the TFA agent, which finalizes best-effort.

## Output

When every test is terminal, the run prints a terse **glimpse table**
(`testRunId → cluster → status → confidence one-liner`), calls
`triggerRcaReport(buildUuid)`, and prints:

```
Full report on the Test Observability UI: <viewReport link>
```

That dashboard report — populated per-test by the BrowserStack agent, with
mandatory culprit-PR links on application bugs — is the real deliverable.

## Requirements

- The `bstack` MCP server (bundled via `.mcp.json`).
- Credentials in `.env` (or your client's MCP env).
- For full evidence coverage: whatever GitHub / infra / logging / metrics
skills your client already has. Missing ones degrade gracefully (the RCA's
confidence band reflects what evidence was actually available).

## Run

Point it at any red BrowserStack build — the harness discovers what it needs:

```
# BROWSERSTACK_USERNAME / BROWSERSTACK_ACCESS_KEY exported; default base is
# production, override O11Y_TFA_RCA_BASE_URL only for a staging tenant.
/rca-build <build-id>
```

The single gate validates connectors (github via `gh`, infra via whatever
runtime connector exists — kubectl/docker/ecs/…) and resolves the intake
**by inference** (product/automation repo from the cwd's git remote, branches,
any PRs you pass). It never assumes a product repo from unrelated workspace
docs — if it can't infer one that matches the failures, it records the gap and
proceeds RCA-only rather than blaming the wrong repo. Then it clusters the
failures, drives `tfaRcaTurn` per cluster, and lands per-test RCAs on the
dashboard, printing the glimpse + the Test Observability link.

## Layout

Implementation plan + requirements live under `docs/` (local, gitignored).
Cross-client wiring is in `INTEGRATION.md`.
Loading
Loading