Skip to content

Chatbot Tester

The Chatbot Tester plugin validates AI chatbot behaviour in any web application by running browser-based checks with Playwright in headless Chromium and judging Q&A accuracy with a batched LLM call.

PhaseWhat it does
Gather contextParses the input URL, fetches the issue/work item, and extracts the chatbot-test block containing widget hints, credentials, and Q&A pairs
Run PlaywrightOpens a headless session, runs a bot responsiveness probe, then executes all test categories
Judge responsesSends all Q&A pairs to an LLM in a single batched call to assess functional accuracy
Post reportComputes the overall verdict and posts a structured report as a comment on the issue or work item
Persist resultsWrites JSON and CSV result files to a GitHub results repository and updates a Mermaid accuracy chart in its README

Works with GitHub and Azure DevOps. Also supports a lite mode for direct URL runs (UI tests only, no Q&A judgment).


flowchart TD
    A["/test-chatbot <url>"] --> B[Parse URL — determine entry type and platform]
    B --> C{Entry type?}
    C -- GitHub issue --> D[Fetch issue body via gh CLI]
    C -- Azure DevOps work item --> E[Fetch work item body via REST API]
    C -- Direct URL --> F[Lite mode — skip block extraction]
    D --> G[Extract chatbot-test block]
    E --> G
    G --> H{Block found and valid?}
    H -- No --> I[Post BLOCKED comment and stop]
    H -- Yes --> J[Post test-in-progress comment]
    F --> K
    J --> K[Phase 1 — Gather test context]
    K --> L{Phase 1 blocked?}
    L -- Yes --> M[Post BLOCKED comment and stop]
    L -- No --> N[Phase 2 — Bot responsiveness probe]
    N --> NB{Probe passed within 60s?}
    NB -- No --> NC[Mark all categories BLOCKED]
    NB -- Yes --> O[Phase 2 — Run all test categories]
    NC --> P
    O --> P[Phase 3 — Judge responses with LLM]
    P --> Q[Phase 4 — Post structured report]
    Q --> R[Phase 5 — Persist results to GitHub repo]
  1. Parse URL — determines entry type (issue, wi, or direct URL) and platform (GitHub, AzureDevOps, DirectURL) from the URL pattern.
  2. Fetch artifact — reads the GitHub issue or Azure DevOps work item body and scans it for a fenced chatbot-test code block. Stops with a BLOCKED comment if the block is absent or missing required fields.
  3. Post progress comment — immediately posts a “test in progress” comment before launching the browser so the team knows the run has started.
  4. Gather context (Phase 1) — verifies prerequisites, resolves the test URL, and determines whether a login is required.
  5. Bot responsiveness probe — before running any test categories, sends a probe message and waits up to 60 seconds for a complete response (two-stage: 30s for any bot element, then 30s for the response to finish). If the bot does not respond within 60 seconds, all categories are marked BLOCKED and the run skips straight to reporting.
  6. Run Playwright (Phase 2) — writes an instrumented Python/Playwright script, opens a headless Chromium session, locates the chatbot widget using the trigger_hint, and runs all test categories. Captures verbatim bot responses for each Q&A pair.
  7. Judge responses (Phase 3) — sends all Q&A pairs in a single batched LLM call. Each pair is assessed for PASS, PARTIAL, or FAIL based on the must_contain terms.
  8. Publish report (Phase 4) — posts one structured report back to the issue or work item. For direct URL runs, writes chatbot-test-report.md to the current directory.
  9. Persist results (Phase 5) — writes a JSON and CSV result file to the configured GitHub results repository and updates a Mermaid accuracy chart in its README. Skipped if CHATBOT-RESULTS-REPO is not set.

#CategoryFull testLite mode
1UI AvailabilityWidget loads, trigger button works, input field is interactableSame
2Functional AccuracyQ&A pairs judged by LLM against must_contain termsSkipped
3Fallback HandlingGibberish and out-of-scope inputs — bot responds gracefullySame
4Response LatencyTime from message sent to response complete (30s limit)Same
5Conversation ContinuityFollow-up question retains context from previous responseSame
6Conversation FlowMulti-turn scripted flow defined in conversation_flow block — run in orderSkipped (requires conversation_flow in test block)
7Empty Input HandlingBlank message submission is handled gracefullySame

InputSourceRequiredDescription
Target URLCommand argumentYesGitHub issue URL, Azure DevOps work item URL, or a direct app URL
chatbot-test blockIssue / work item bodyYes (except lite mode)JSON block with widget hints, optional credentials, and optional Q&A pairs
Test passwordXianix Agentri Studio SecretsNoReferenced by password_env in the credentials block — never stored in the issue body

Add this block to a GitHub issue or Azure DevOps work item body. The plugin reads it automatically — no local files needed.

```chatbot-test
{
"url": "https://your-app-url.com",
"widget": {
"trigger_hint": "blue chat button in the bottom right corner",
"ready_hint": "input field shows placeholder text 'Type your question...'",
"response_done_hint": "send button becomes clickable again"
},
"credentials": {
"username": "test@example.com",
"password_env": "CHATBOT-TEST-PASSWORD"
},
"knowledge": [
{
"question": "What are your opening hours?",
"must_contain": ["9am", "5pm", "Monday"]
}
]
}
```
FieldRequiredDescription
urlYesThe web app URL to open
widget.trigger_hintYesPlain-language description of how to open the chatbot (colour, position, icon)
widget.ready_hintYesPlain-language description of when the input field is ready
widget.response_done_hintYesPlain-language description of when the bot has finished responding
credentials.usernameNoLogin email for apps requiring authentication
credentials.password_envNoKey name of the Xianix Agentri Studio Secret holding the password
knowledgeNoArray of Q&A pairs. Each entry needs question and must_contain (array of required terms). Omit to skip Functional Accuracy.

Test a GitHub issue:

/test-chatbot https://github.com/owner/repo/issues/42

Test an Azure DevOps work item:

/test-chatbot https://dev.azure.com/org/project/_workitems/edit/1234

Lite mode — direct URL (UI tests only):

/test-chatbot https://staging.example.com

(No chatbot-test block needed for lite mode. Functional Accuracy is skipped and the report is written locally as chatbot-test-report.md.)


The Xianix Agent reads these from its secrets store and injects them at runtime via the rule’s with-envs block. For local CLI use, export them in your shell.

VariablePlatformRequiredPurpose
GITHUB-TOKENGitHubYesAuthenticate gh CLI for fetching issue content and posting comments
AZURE-DEVOPS-TOKENAzure DevOpsYesPAT for the ADO REST API — reading work items and posting comments
CHATBOT-TEST-PASSWORDBothNoPassword for apps requiring login. Only needed when credentials.password_env is set in the test case block
CHATBOT-RESULTS-REPOBothNoGitHub repository for persisting test results (e.g. org/chatbot-test-results). If unset, Phase 5 is skipped silently
CHATBOT-RESULTS-GITHUB-TOKENBothNoPAT with write access to CHATBOT-RESULTS-REPO — used to clone and push result files. If unset, Phase 5 is skipped silently
PermissionAccessWhy it’s needed
MetadataReadResolve repository owner and name
IssuesRead & WriteFetch issue body and post test report comments

Create the token in User Settings → Personal access tokens with the following scopes:

ScopeAccessWhy it’s needed
Work ItemsRead & WriteFetch work item body and post report comments

Results Repository Token Permissions (CHATBOT-RESULTS-GITHUB-TOKEN)

Section titled “Results Repository Token Permissions (CHATBOT-RESULTS-GITHUB-TOKEN)”

Create a separate fine-grained PAT scoped only to the results repository:

PermissionAccessWhy it’s needed
ContentsRead & WriteClone the repo, write JSON/CSV result files, and push the updated README

CategoryVerdict logic
UI AvailabilityDirect from Phase 2 (structural check — no LLM judgment)
Functional AccuracyPASSED if all pairs PASS; PARTIAL if any PARTIAL and no FAIL; FAILED if any FAIL
Fallback HandlingPASSED if all probes PASS; FAILED if any probe FAILS; BLOCKED if no response was captured
Response LatencyPASSED if all responses complete within 30s; FAILED if any exceeded the timeout
Conversation ContinuityFrom LLM judge verdict (PASS / PARTIAL / FAIL)
Empty Input HandlingDirect from probe verdict
ConditionOverall Verdict
All categories PASSEDPASSED
Any category PARTIAL, no FAILED or BLOCKEDPARTIAL
Any category FAILED or BLOCKEDFAILED
Login failedBLOCKED
Bot responsiveness probe failed (no response within 60s)BLOCKED — all categories skipped

Before running any test categories, Phase 2 sends a probe message to the bot and measures the time to a fully completed response. The probe uses a two-stage timeout:

StageTimeoutWhat is checked
Stage 130 secondsAny bot response element appears in the DOM
Stage 230 secondsThe response is fully rendered and the input field is ready again

If the bot does not complete a response within the combined 60-second window, all test categories are marked BLOCKED and the run skips straight to Phase 4 (report). The report will include a “Bot Unresponsive” banner explaining what happened.

A partial response (streaming, loading spinner, “Thinking…”) at 60 seconds does not count — the bot must produce a finished reply.


When CHATBOT-RESULTS-REPO and CHATBOT-RESULTS-GITHUB-TOKEN are configured, Phase 5 writes result artifacts to the GitHub repository after every run:

ArtifactLocationContents
JSON resultresults/{chatbot-name}/{timestamp}.jsonFull run data: URL, platform, per-category verdicts and details
CSV resultresults/{chatbot-name}/{timestamp}.csvFlat row for reporting and spreadsheet import
README chartREADME.mdMermaid xychart-beta bar chart showing pass rate across the last 10 runs per category

The README is updated in place — each chatbot gets its own ## {chatbot-name} section with an accuracy table and chart. If the section already exists it is replaced; new chatbots are appended.

If either env var is not set, Phase 5 silently skips — the run still completes and the report is still posted.


  • Credentials, tokens, and secrets are never included in posted comments.
  • The temporary working directory (_cbt_run/) is deleted after every run, even if execution fails.
  • If password_env is set but the secret is not found, the run reports BLOCKED rather than attempting an unauthenticated session.
  • CHATBOT-RESULTS-GITHUB-TOKEN should be a fine-grained PAT scoped only to the results repository — do not reuse the main GITHUB-TOKEN.

The plugin posts one comment with:

  • URL tested
  • overall verdict
  • per-category status table
  • collapsible detail block for each Q&A pair (Functional Accuracy)
  • detail blocks for any failing fallback, continuity, or empty input probes
  • a lite-mode callout when Functional Accuracy was skipped

For direct URL runs, the same content is written to chatbot-test-report.md in the current directory instead of posted as a comment.


Terminal window
# Point Claude Code at the plugin
claude --plugin-dir /path/to/xianix-plugins-official/plugins/chatbot-tester
# Then in chat
/test-chatbot https://github.com/owner/repo/issues/42

Or trigger it automatically via the Xianix Agent by adding a rule — see the examples below and the Rules Configuration guide.

For setup details (Python 3.10+, Playwright Python package, gh CLI, and ADO PAT), see the plugin setup guide in the repository:

https://github.com/xianix-team/plugins-official/tree/main/plugins/chatbot-tester/docs/setup.md


Add the execution block below to your rules.json so the Xianix Agent automatically tests chatbots when a webhook fires.

The Chatbot Tester is tag-driven. It runs when the ai-dlc/issue/test-chatbot label is present on an issue and one of the scenarios below fires (OR logic across match-any entries).

ScenarioWhat it covers
Issue opened with the tag already presentAn issue is created with the tag included from the start
Tag newly applied to an open issueA human (or another rule) adds ai-dlc/issue/test-chatbot to an open issue
PlatformScenarioWebhook eventFilter rule
GitHubTag newly appliedissuesaction==labeled and label.name=='ai-dlc/issue/test-chatbot'
GitHubIssue opened with tagissuesaction==opened and ai-dlc/issue/test-chatbot is in issue.labels
FieldPurpose
nameHuman-readable id for the execution
platform"github" or "azure-devops" — drives which provider the plugin uses
repository.urlWebhook path to the repository URL
repository.refWebhook path to the branch ref
match-anyArray of trigger filters — first one to match wins
use-inputsEntry-point id (e.g. issue-url)
use-pluginsThe plugin to invoke
with-envsRequired environment variables, sourced from the agent’s secrets.* store
execute-promptThe prompt sent to the agent
{
"name": "github-chatbot-test",
"platform": "github",
"repository": {
"url": "repository.clone_url",
"ref": "repository.default_branch"
},
"match-any": [
{
"name": "github-issue-tag-applied",
"rule": "action==labeled&&label.name=='ai-dlc/issue/test-chatbot'"
},
{
"name": "github-issue-opened-with-tag",
"rule": "action==opened&&'ai-dlc/issue/test-chatbot' in issue.labels[*].name"
}
],
"use-inputs": [
{ "name": "issue-url", "value": "issue.html_url" }
],
"use-plugins": [
{
"plugin-name": "chatbot-tester@xianix-plugins-official",
"marketplace": "xianix-team/plugins-official"
}
],
"with-envs": [
{ "name": "GITHUB-TOKEN", "value": "secrets.GITHUB-TOKEN", "mandatory": true },
{ "name": "CHATBOT-TEST-PASSWORD", "value": "secrets.CHATBOT-TEST-PASSWORD", "mandatory": false },
{ "name": "CHATBOT-RESULTS-REPO", "value": "secrets.CHATBOT-RESULTS-REPO", "mandatory": false },
{ "name": "CHATBOT-RESULTS-GITHUB-TOKEN", "value": "secrets.CHATBOT-RESULTS-GITHUB-TOKEN", "mandatory": false }
],
"execute-prompt": "Run /test-chatbot {{issue-url}} to perform the automated chatbot test."
}
{
"name": "ado-chatbot-test",
"platform": "azure-devops",
"repository": {
"url": "resource.url",
"ref": "resource.fields.System.TeamProject"
},
"match-any": [
{
"name": "ado-workitem-tag-applied",
"rule": "eventType==workitem.updated&&resource.fields['System.Tags'] contains 'ai-dlc/issue/test-chatbot'"
}
],
"use-inputs": [
{ "name": "workitem-url", "value": "resource._links.html.href" }
],
"use-plugins": [
{
"plugin-name": "chatbot-tester@xianix-plugins-official",
"marketplace": "xianix-team/plugins-official"
}
],
"with-envs": [
{ "name": "AZURE-DEVOPS-TOKEN", "value": "secrets.AZURE-DEVOPS-TOKEN", "mandatory": true },
{ "name": "CHATBOT-TEST-PASSWORD", "value": "secrets.CHATBOT-TEST-PASSWORD", "mandatory": false },
{ "name": "CHATBOT-RESULTS-REPO", "value": "secrets.CHATBOT-RESULTS-REPO", "mandatory": false },
{ "name": "CHATBOT-RESULTS-GITHUB-TOKEN", "value": "secrets.CHATBOT-RESULTS-GITHUB-TOKEN", "mandatory": false }
],
"execute-prompt": "Run /test-chatbot {{workitem-url}} to perform the automated chatbot test."
}

PathPurpose
commands/test-chatbot.mdEntry command, argument pattern, and test case block reference
agents/orchestrator.mdEnd-to-end orchestration flow across five phases, including the 60-second responsiveness probe hard constraint
skills/gather-test-context/SKILL.mdPhase 1 — prerequisite checks and login detection
skills/run-playwright-session/SKILL.mdPhase 2 — headless browser session, two-stage responsiveness probe, and all test categories
skills/judge-responses/SKILL.mdPhase 3 — batched LLM verdict for Q&A pairs
skills/post-test-report/SKILL.mdPhase 4 — report construction and posting
skills/persist-results/SKILL.mdPhase 5 — write JSON/CSV result files to GitHub results repo and update Mermaid accuracy chart
providers/github.mdGitHub fetch/post operations via gh CLI
providers/azure-devops.mdAzure DevOps fetch/post operations via REST API
styles/report-template.mdStrict output report format with verdict icons and section rules
docs/verdict-logic.mdAuthoritative category and overall verdict computation rules
hooks/validate-prerequisites.shPython 3.10+, playwright Python package, and platform CLI availability checks
docs/setup.mdInstallation, auth setup, and test case authoring guide