@capagents/forgeqe 0.0.0-stage → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/HOW_TO_USE.md +1639 -0
- package/README.md +338 -2
- package/bin/forgeqe.d.ts +3 -0
- package/bin/forgeqe.js +188 -0
- package/docs/ARCHITECTURE.md +408 -0
- package/docs/security-data-flow.html +1870 -0
- package/docs/user-guide.html +2094 -0
- package/evals/domain/access-role-change.yaml +37 -0
- package/evals/domain/banking-payment-transfer.yaml +41 -0
- package/evals/domain/gdpr-account-erasure.yaml +30 -0
- package/evals/domain/insurance-claim-fnol.yaml +30 -0
- package/evals/domain/insurance-policy-renewal.yaml +37 -0
- package/evals/domain/lending-loan-application.yaml +36 -0
- package/forgeqe-architecture.html +718 -0
- package/forgeqe.example.yaml +203 -0
- package/knowledge/README.md +18 -0
- package/knowledge/business-rules.md +10 -0
- package/knowledge/compliance.md +16 -0
- package/knowledge/environments.md +5 -0
- package/knowledge/glossary.md +5 -0
- package/knowledge/product.md +16 -0
- package/knowledge/roles.md +9 -0
- package/knowledge/test-data.md +7 -0
- package/llms.example.json +51 -0
- package/package.json +63 -4
- package/prompts/README.md +34 -0
- package/prompts/api-scenarios.md +21 -0
- package/prompts/api-tests.md +39 -0
- package/prompts/brain.md +166 -0
- package/prompts/browser-capture.md +7 -0
- package/prompts/browser-case-report.md +7 -0
- package/prompts/browser-checks.md +14 -0
- package/prompts/browser-efficiency.md +7 -0
- package/prompts/browser-error-recovery.md +15 -0
- package/prompts/browser-extra.md +5 -0
- package/prompts/browser-goal-verification.md +13 -0
- package/prompts/browser-skill-select.md +6 -0
- package/prompts/domain-rule.md +13 -0
- package/prompts/eval-judge.md +19 -0
- package/prompts/explore-charters.md +27 -0
- package/prompts/find-tests.md +28 -0
- package/prompts/heal.md +40 -0
- package/prompts/pr-review.md +29 -0
- package/prompts/skill-rule.md +6 -0
- package/prompts/test-agent.md +34 -0
- package/prompts/test-reviewer.md +30 -0
- package/prompts/test-rules.md +28 -0
- package/py/forgeqe_engine/__init__.py +3 -0
- package/py/forgeqe_engine/__main__.py +3 -0
- package/py/forgeqe_engine/brand.py +453 -0
- package/py/forgeqe_engine/brand_assets.py +6 -0
- package/py/forgeqe_engine/browser.py +196 -0
- package/py/forgeqe_engine/capture.py +538 -0
- package/py/forgeqe_engine/checks.py +98 -0
- package/py/forgeqe_engine/cli.py +188 -0
- package/py/forgeqe_engine/diagnostics.py +609 -0
- package/py/forgeqe_engine/llm.py +195 -0
- package/py/forgeqe_engine/logins.py +251 -0
- package/py/forgeqe_engine/loops.py +224 -0
- package/py/forgeqe_engine/memory.py +1004 -0
- package/py/forgeqe_engine/network.py +244 -0
- package/py/forgeqe_engine/prompts.py +20 -0
- package/py/forgeqe_engine/replay.py +240 -0
- package/py/forgeqe_engine/report.py +173 -0
- package/py/forgeqe_engine/service.py +1335 -0
- package/py/forgeqe_engine/settings.py +93 -0
- package/py/forgeqe_engine/skills.py +88 -0
- package/py/forgeqe_engine/summary.py +239 -0
- package/py/forgeqe_engine/urls.py +81 -0
- package/py/forgeqe_engine/workflow_yaml.py +689 -0
- package/skills/dotnet-nunit-playwright/SKILL.md +34 -0
- package/skills/dynamics-365/SKILL.md +21 -0
- package/skills/playwright-typescript/SKILL.md +35 -0
- package/skills/writing-skills/SKILL.md +30 -0
- package/src/api/plan.ts +246 -0
- package/src/api/run.ts +204 -0
- package/src/api/scenario.ts +502 -0
- package/src/api/schema.ts +170 -0
- package/src/api/spec.ts +624 -0
- package/src/api/store.ts +232 -0
- package/src/api/traffic.ts +281 -0
- package/src/api/types.ts +163 -0
- package/src/api/write.ts +272 -0
- package/src/auth/signin.ts +494 -0
- package/src/auth/store.ts +170 -0
- package/src/brain/index.ts +189 -0
- package/src/brain/prompt.ts +19 -0
- package/src/capabilities/docs.ts +101 -0
- package/src/capabilities/guide.ts +455 -0
- package/src/capabilities/registry.ts +343 -0
- package/src/capabilities/render.ts +106 -0
- package/src/capabilities/status.ts +137 -0
- package/src/card.ts +11 -0
- package/src/cases/ado.ts +325 -0
- package/src/cases/api.ts +117 -0
- package/src/cases/bugs.ts +223 -0
- package/src/cases/confluence.ts +111 -0
- package/src/cases/context.ts +223 -0
- package/src/cases/dashboards.ts +137 -0
- package/src/cases/failure.ts +97 -0
- package/src/cases/files.ts +295 -0
- package/src/cases/goal.ts +53 -0
- package/src/cases/http.ts +111 -0
- package/src/cases/index.ts +131 -0
- package/src/cases/jira.ts +122 -0
- package/src/cases/qtest.ts +108 -0
- package/src/cases/quality.ts +190 -0
- package/src/cases/rag.ts +100 -0
- package/src/cases/readiness.ts +284 -0
- package/src/cases/save.ts +149 -0
- package/src/cases/sprints.ts +148 -0
- package/src/cases/testrail.ts +176 -0
- package/src/cases/types.ts +107 -0
- package/src/cases/wiki.ts +105 -0
- package/src/cases/xray.ts +206 -0
- package/src/cases/zephyr.ts +153 -0
- package/src/childEnv.ts +86 -0
- package/src/cli/args.ts +114 -0
- package/src/cli/help.ts +167 -0
- package/src/cli/index.ts +1142 -0
- package/src/cli/terminal.ts +187 -0
- package/src/code/areas.ts +337 -0
- package/src/code/attention.ts +214 -0
- package/src/code/find.ts +540 -0
- package/src/code/handoff.ts +541 -0
- package/src/code/history.ts +170 -0
- package/src/code/impact.ts +231 -0
- package/src/code/index.ts +34 -0
- package/src/code/livebrowser.ts +67 -0
- package/src/code/loop.ts +603 -0
- package/src/code/notes.ts +75 -0
- package/src/code/profile.ts +226 -0
- package/src/code/prompt.ts +303 -0
- package/src/code/prreview.ts +649 -0
- package/src/code/prtests.ts +103 -0
- package/src/code/replay.ts +772 -0
- package/src/code/review.ts +202 -0
- package/src/code/runtime.ts +781 -0
- package/src/code/slices.ts +159 -0
- package/src/code/testrun.ts +187 -0
- package/src/code/traceability.ts +100 -0
- package/src/code/worktree.ts +153 -0
- package/src/commands.ts +101 -0
- package/src/config.ts +970 -0
- package/src/detail.ts +65 -0
- package/src/domain.ts +19 -0
- package/src/engine/bridge.ts +359 -0
- package/src/engine/mock.ts +102 -0
- package/src/engine/setup.ts +298 -0
- package/src/entra.ts +154 -0
- package/src/env.ts +24 -0
- package/src/evals/domain.ts +338 -0
- package/src/explore/charters.ts +151 -0
- package/src/explore/run.ts +280 -0
- package/src/explore/story.ts +106 -0
- package/src/guard.ts +51 -0
- package/src/heal/loop.ts +357 -0
- package/src/heal/prompt.ts +143 -0
- package/src/heal/report.ts +95 -0
- package/src/index.ts +12 -0
- package/src/init.ts +102 -0
- package/src/knowledge.ts +114 -0
- package/src/legacyEnv.ts +9 -0
- package/src/llm.ts +61 -0
- package/src/locale.ts +25 -0
- package/src/logins.ts +148 -0
- package/src/managed.ts +101 -0
- package/src/mcp/apitools.ts +335 -0
- package/src/mcp/captools.ts +25 -0
- package/src/mcp/casetools.ts +223 -0
- package/src/mcp/commands.ts +421 -0
- package/src/mcp/exploretools.ts +129 -0
- package/src/mcp/external.ts +172 -0
- package/src/mcp/git.ts +78 -0
- package/src/mcp/notifytools.ts +49 -0
- package/src/mcp/prtools.ts +261 -0
- package/src/mcp/qualitytools.ts +154 -0
- package/src/mcp/repotests.ts +286 -0
- package/src/mcp/server.ts +234 -0
- package/src/mcp/tools.ts +810 -0
- package/src/memory.ts +250 -0
- package/src/money.ts +39 -0
- package/src/monitor/alerts.ts +94 -0
- package/src/monitor/background.ts +68 -0
- package/src/monitor/run.ts +263 -0
- package/src/monitor/state.ts +105 -0
- package/src/notify/events.ts +144 -0
- package/src/notify/notice.ts +177 -0
- package/src/prices.ts +175 -0
- package/src/print.ts +54 -0
- package/src/privacy.ts +35 -0
- package/src/prompts.ts +165 -0
- package/src/quality/budgets.ts +249 -0
- package/src/quality/history.ts +149 -0
- package/src/quality/visual.ts +201 -0
- package/src/report/data.ts +475 -0
- package/src/report/html.ts +106 -0
- package/src/report/template.html +84 -0
- package/src/run.ts +243 -0
- package/src/sessionLog.ts +216 -0
- package/src/sessionLogins.ts +94 -0
- package/src/skills/registry.ts +217 -0
- package/src/skills/scaffold.ts +65 -0
- package/src/skills/select.ts +37 -0
- package/src/skills/view.ts +44 -0
- package/src/suite/report.ts +135 -0
- package/src/suite/run.ts +303 -0
- package/src/summary.ts +188 -0
- package/src/tools.ts +130 -0
- package/src/tui/App.tsx +983 -0
- package/src/tui/clipboard.ts +36 -0
- package/src/tui/components.tsx +263 -0
- package/src/tui/dialogs.ts +65 -0
- package/src/tui/main.tsx +20 -0
- package/src/tui/text.ts +28 -0
- package/src/tui/theme.ts +104 -0
- package/src/tui/transcript.tsx +344 -0
- package/src/types.ts +146 -0
- package/src/update.ts +311 -0
- package/src/usage.ts +158 -0
package/HOW_TO_USE.md
ADDED
|
@@ -0,0 +1,1639 @@
|
|
|
1
|
+
# How to use ForgeQE
|
|
2
|
+
|
|
3
|
+
ForgeQE is a browser agent CLI. Say what you want in plain language: a goal to carry out in a browser, test cases to run from Jira, Azure DevOps, Xray or a file, a test to write, or a CI pipeline to set up. ForgeQE's agent works out what that needs, the ForgeQE engine drives Chrome, and a run that passes becomes a test in your repo, written by **Scribe**, ForgeQE's coding agent.
|
|
4
|
+
|
|
5
|
+
No server, database, or Docker. You configure a model and run it from the terminal.
|
|
6
|
+
|
|
7
|
+
| Doc | Purpose |
|
|
8
|
+
|-----|---------|
|
|
9
|
+
| This guide | Setup and how to run |
|
|
10
|
+
| [`docs/user-guide.html`](docs/user-guide.html) | This guide as one page, with every feature: what it needs, how to ask for it, and its details |
|
|
11
|
+
| [`forgeqe-architecture.html`](forgeqe-architecture.html) | Single-view map: subagents, tools, and capabilities |
|
|
12
|
+
| [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) | Architecture reference: modules, protocols, and loops |
|
|
13
|
+
| [`README.md`](README.md) | Overview |
|
|
14
|
+
|
|
15
|
+
After install:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
forgeqe docs # print the paths of the bundled docs
|
|
19
|
+
forgeqe docs --guide # open the user guide in the browser
|
|
20
|
+
forgeqe docs --open # open the architecture page in the browser
|
|
21
|
+
forgeqe docs --copy ./docs # copy the guide, the architecture page, and the reference into a folder
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Agent map
|
|
27
|
+
|
|
28
|
+
`forgeqe docs --open` shows this on one screen.
|
|
29
|
+
|
|
30
|
+
### Subagents
|
|
31
|
+
|
|
32
|
+
| Name | What it does | May change files |
|
|
33
|
+
|------|----------------|------------------|
|
|
34
|
+
| `forgeqe` | Reads the request and calls the tools below | No |
|
|
35
|
+
| Browser agent | Drives Chrome one step at a time | No |
|
|
36
|
+
| `forgeqe-read` | Learns the repo's test setup before a handoff | No |
|
|
37
|
+
| `forgeqe-test` | Scribe: writes the test in the repo's own framework | Yes, in the repo |
|
|
38
|
+
| `forgeqe-review` | Approves that test, or sends issues back | No |
|
|
39
|
+
| `forgeqe-find` | Picks existing tests by reading them and git history | No |
|
|
40
|
+
| `forgeqe-pr-review` | Reviews a pull request's diff in a temporary checkout | No |
|
|
41
|
+
| `forgeqe-heal` | Updates a test the app has outgrown, or reports an app bug | Yes, in the repo |
|
|
42
|
+
|
|
43
|
+
### Capabilities
|
|
44
|
+
|
|
45
|
+
Everything ForgeQE can do, by area. ForgeQE's agent answers "can you…?" questions from the same list (the `capabilities` tool), with whether each one works in your setup and what to set up; `/features` in the shell and `forgeqe features` show it too.
|
|
46
|
+
|
|
47
|
+
<!-- capabilities:start (generated from src/capabilities/registry.ts by bun scripts/gen-capabilities.ts; do not edit) -->
|
|
48
|
+
| Area | Capability | Tools | |
|
|
49
|
+
|------|------------|-------|-|
|
|
50
|
+
| Browser | **Run any goal in a real browser**: Carries out a plain-language goal in Chrome one step at a time and verifies the outcome, with screenshots, a report, and the steps it took. Page memory replays steps that already worked on a site, so repeat runs are faster and cheaper. | `browser_run`, `run_details`, `page_memory` | [docs](#4-without-the-shell) |
|
|
51
|
+
| Browser | **Saved logins for the application under test**: Signs the browser agent in with saved credentials (including TOTP) and reuses the session; a user can also sign in by hand once in a browser. | `logins` | [docs](#signing-in) |
|
|
52
|
+
| Test cases | **Run manual test cases in browsers**: Reads test cases from Azure DevOps, Jira, Xray, TestRail, Zephyr Scale, qTest, a file, or pasted text, runs each in a real browser with a verdict per step, writes report.html and junit.xml, posts results back, and files or updates bugs for failures. | `find_test_cases`, `run_test_cases` | [docs](#7-test-cases-and-suites) |
|
|
53
|
+
| Test cases | **Check and improve test cases**: Checks test cases before they run (vague or missing expected results, missing test data, placeholders, duplicates) against the story, feature, and epic they test, then rewrites Azure DevOps cases once the user agrees. | `check_test_cases`, `update_test_case` | [docs](#checking-test-cases-before-they-run) |
|
|
54
|
+
| Test cases | **Write test cases from a story**: Writes test cases from a story's acceptance criteria and saves them in Azure DevOps or Jira, linked to the story. | `save_test_cases` | [docs](#where-cases-come-from) |
|
|
55
|
+
| Test cases | **Domain and regulatory test design**: Every agent works as an expert in the product's industry would, automatically: the risks the industry is known for and the obligations of its regulations and standards (for example DORA, PSD2, GDPR, ISO 27001), declared in forgeqe.yaml or worked out from the story and the application. It applies to analysing requirements, writing and checking test cases, exploration, writing, reviewing, and healing test code, API tests, finding tests, and pull request reviews, labelled so coverage can be traced and citing only the control ids in the team's compliance file. forgeqe eval domain measures how well the agent does it. | | [docs](#16-domain-and-regulations) |
|
|
56
|
+
| Test cases | **Exploratory testing of a story**: Explores a story in real browsers beyond its scripted cases (edge cases, invalid input, boundaries, roles, state), confirms each defect by reproducing it, proposes test cases, and files bugs once the user agrees. | `explore_story` | [docs](#exploratory-testing-from-a-story) |
|
|
57
|
+
| Automated tests | **Turn a passed run into an automated test**: Scribe, the coding agent, writes a test for a passed browser run in the repository's own framework, page objects, and helpers; ForgeQE runs it until it passes and a reviewer approves it. | `write_test`, `run_test` | [docs](#6-tests) |
|
|
58
|
+
| Automated tests | **Heal failing tests**: Runs a repository's tests and updates the ones the application has outgrown against the live app, or reports a real application bug instead. | `heal_tests` | [docs](#fixing-broken-tests) |
|
|
59
|
+
| Automated tests | **Find and run existing tests**: Finds the automated tests that match a feature, tags, ids, a folder, or a sprint, confirms the selection, and runs it once the user agrees, with a verdict per test. | `find_tests`, `run_tests`, `list_sprints` | [docs](#finding-and-running-existing-tests) |
|
|
60
|
+
| Automated tests | **Flaky test detection and quarantine**: Finds tests that flip between passing and failing in the repository's run history, with their likely cause, and quarantines them once the user agrees. | `flaky_tests`, `quarantine_tests` | [docs](#flaky-tests) |
|
|
61
|
+
| Pull requests | **Review pull requests**: Reviews an Azure DevOps or GitHub pull request from the local clone for bugs, security, requirements, and tests, and posts the review once the user agrees. | `review_pull_request`, `post_pr_review` | [docs](#reviewing-pull-requests) |
|
|
62
|
+
| Pull requests | **Pull request impact and test selection**: Works out which product areas, pages, requirements, and tests a pull request touches, picks the tests it can break, runs them, and posts the impact or results on the pull request once the user agrees. | `analyze_pr_impact`, `select_pr_tests`, `post_pr_test_results`, `comment_on_pr` | [docs](#what-a-pull-request-impacts-in-the-product) |
|
|
63
|
+
| API | **API and contract testing**: Builds API contracts (status, schema, key fields) from the calls a browser run saw or from an API description (OpenAPI, Swagger, WSDL, GraphQL, .proto, gRPC reflection), and end-to-end API scenarios from runs, descriptions, test cases, or plain English. Runs them straight against the API without a browser, or writes them as tests in the repository. REST, GraphQL, SOAP, and gRPC. | `api_contracts`, `run_api_contracts`, `api_scenarios`, `run_api_scenarios`, `write_api_tests` | [docs](#api-and-contract-tests) |
|
|
64
|
+
| Quality | **Accessibility and page performance**: Checks every page a run visits against WCAG rules (axe-core) and measures its Core Web Vitals, against budgets, with trends over time per page. | `quality_report`, `quality_trends` | [docs](#accessibility-and-performance-budgets) |
|
|
65
|
+
| Quality | **Visual comparison with baselines**: Compares each page a run captures with its approved baseline and shows what changed; intended changes become the new baseline once the user agrees. | `visual_compare`, `visual_approve` | [docs](#visual-comparison) |
|
|
66
|
+
| Release | **Requirement coverage and release readiness**: Gives requirement coverage and a GO / GO WITH RISKS / NO-GO verdict for a sprint, area, epic, or stories, from test cases, results, bugs, and flaky tests; can publish it to the wiki. | `release_readiness` | [docs](#requirement-coverage-and-release-readiness) |
|
|
67
|
+
| Operations | **Scheduled monitoring with alerts**: Runs checks on a schedule and alerts Teams or email when one keeps failing, and again when it recovers. | `monitor` | [docs](#9-monitoring) |
|
|
68
|
+
| Operations | **Teams and email notifications**: Tells the team in Microsoft Teams channels or by email when a suite fails or passes, when a release readiness verdict is in, and when the domain evaluation falls below its gate, with the failing cases, their bugs, and links to the report and the CI build. Each channel picks its events; the agent also posts a summary to a channel when asked. | `notify` | [docs](#17-notifications) |
|
|
69
|
+
| Operations | **CI pipelines**: Writes a GitHub Actions or Azure Pipelines workflow that runs ForgeQE, stores the secrets it needs, pushes a branch, and makes the pipeline green. | `push_branch`, `set_ci_secret` | [docs](#8-pipelines) |
|
|
70
|
+
| Systems | **Work with Azure DevOps, Jira, and Confluence**: Reads anything in the configured systems (work items, issues, queries, boards, pages), makes changes the user asks for, and builds Azure DevOps dashboards and wiki pages. | `query_api`, `read_confluence`, `create_ado_dashboard`, `write_ado_wiki_page` | [docs](README.md#azure-devops-jira-and-other-systems) |
|
|
71
|
+
| Setup | **Setup, skills, and documentation**: Shows the model profiles and MCP servers, installs or repairs the browser engine, creates a forgeqe.yaml, manages skills, and answers questions about ForgeQE from its documentation and this list. | `forgeqe_setup`, `capabilities` | [docs](#2-scaffold-config) |
|
|
72
|
+
|
|
73
|
+
Not supported: Native mobile apps (iOS, Android) and desktop applications (instead: web applications in Chrome or Chromium); Load, stress, or soak testing with many simultaneous users (instead: per-page Core Web Vitals with budgets); Penetration testing or dynamic security scanning (instead: security findings in pull request reviews).
|
|
74
|
+
<!-- capabilities:end -->
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## What you need to run
|
|
79
|
+
|
|
80
|
+
### Required
|
|
81
|
+
|
|
82
|
+
| Requirement | Notes |
|
|
83
|
+
|-------------|-------|
|
|
84
|
+
| **npm (Node.js 18+) or pip (Python 3.9+)** | To install `@capagents/forgeqe` or `forgeqe-cli`; either one gives the same `forgeqe` command |
|
|
85
|
+
| **A terminal** | macOS Terminal, iTerm2, VS Code or Cursor's terminal, Windows Terminal |
|
|
86
|
+
| **A model** | A profile in `llms.json` with a working key, or Microsoft Entra ID sign-in for Azure (Azure OpenAI, OpenAI, an OpenAI-compatible gateway, or Ollama) |
|
|
87
|
+
| **Internet access on first use** | ForgeQE downloads Bun, the agent runtime, uv, Python, and the engine into `~/.forgeqe` once |
|
|
88
|
+
|
|
89
|
+
### Optional
|
|
90
|
+
|
|
91
|
+
| Optional | Why |
|
|
92
|
+
|----------|-----|
|
|
93
|
+
| **Google Chrome** | Used when installed; otherwise ForgeQE installs Chromium |
|
|
94
|
+
| **A repo with tests** | Where passed runs become tests (`--repo`, or `code.repo`); without one, tests go in the current folder |
|
|
95
|
+
| **Jira, Azure DevOps, Xray, TestRail, Zephyr Scale, qTest, Confluence** | Sources of test cases and requirements, and where results go back |
|
|
96
|
+
| **`gh` or `az`** | For pipelines: pushing, secrets, and triggering runs |
|
|
97
|
+
| **Teams webhook or SMTP** | Monitoring alerts |
|
|
98
|
+
|
|
99
|
+
### Not required
|
|
100
|
+
|
|
101
|
+
- Installing Python, Bun, browsers, or agent runtimes yourself: ForgeQE downloads what it needs, without admin rights and without touching PATH
|
|
102
|
+
- A server, database, or Docker
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Quick start
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
npm install -g @capagents/forgeqe # or: pip install forgeqe-cli
|
|
110
|
+
forgeqe init # forgeqe.yaml, llms.json, and .forgeqe/ (prompts, skills, knowledge) in this folder
|
|
111
|
+
export WP_AZURE_API_KEY=... # the key your llms.json profile names
|
|
112
|
+
forgeqe models # check the profiles
|
|
113
|
+
forgeqe start # the shell
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
In the shell, type a request and press Enter:
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
Go to booking.com and search for hotels in Mumbai for next weekend
|
|
120
|
+
Run SHOP-12 and SHOP-14 from Jira, two browsers at once
|
|
121
|
+
Write a Playwright test for that run in ../app
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Without the shell:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
forgeqe run "Search hotels in Mumbai on booking.com" --plain
|
|
128
|
+
forgeqe suite cases.yaml --parallel 3 # what pipelines call
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
`forgeqe models` lists the profiles ForgeQE sees and marks the active one. With no profile set up, the shell's footer reads **Model none set up** and any request explains how to add one.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## 1. Install
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
npm install -g @capagents/forgeqe
|
|
139
|
+
# or
|
|
140
|
+
pip install forgeqe-cli
|
|
141
|
+
forgeqe --help
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
That is the only install step on Windows, macOS and Linux. The first run downloads Bun into `~/.forgeqe/tools` (unless a Bun 1.3+ is already installed), and `forgeqe setup` downloads the agent runtime and uv, which fetches Python. Nothing is added to PATH or shell profiles; deleting `~/.forgeqe` removes it all.
|
|
145
|
+
|
|
146
|
+
Set up the ForgeQE engine once (the first live run does it automatically if you skip this):
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
forgeqe setup
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
It creates `~/.forgeqe/engine/.venv`, installs the engine's Python libraries, and prints the Python, the engine version, the browser it found, and the agent runtime. Google Chrome is used when installed; otherwise Chromium is installed. `forgeqe setup --force` rebuilds the environment.
|
|
153
|
+
|
|
154
|
+
### Updating
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
forgeqe update # every forgeqe on PATH to the latest release
|
|
158
|
+
forgeqe update --check # show what would change and the commands it would run
|
|
159
|
+
forgeqe update 0.2.7 # a given version
|
|
160
|
+
forgeqe --version
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
`forgeqe update` finds each `forgeqe` on PATH (a bun, npm or pip install; often more than one) and updates each with the tool that installed it, skipping that tool's cached copy of the version list. Right after a release, npm and PyPI accept the upload several minutes before installers can fetch it, and `bun add` or `npm install` in that window says `No version matching`; `forgeqe update` waits for the registry instead (up to 20 minutes, `--wait MIN` to change). The first `forgeqe` on PATH is the one your shell runs; open a new terminal (or run `hash -r`) after updating.
|
|
164
|
+
|
|
165
|
+
From a checkout instead of the registries:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
cd ForgeQE
|
|
169
|
+
bun install
|
|
170
|
+
bun src/index.ts --help
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## 2. Scaffold config
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
bun src/index.ts init
|
|
177
|
+
# or
|
|
178
|
+
bun src/index.ts init --global --profile azure-gpt4o
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Edit `llms.json` endpoints, then give ForgeQE the keys its profiles name (`WP_AZURE_API_KEY`, `OPENAI_API_KEY`, `WP_API_KEY`): `forgeqe auth login <NAME>` saves one in your system's credential store, or put them in a `.env` next to `forgeqe.yaml`; the engine process inherits them.
|
|
182
|
+
|
|
183
|
+
### Signing in to the model without a key (Microsoft Entra ID)
|
|
184
|
+
|
|
185
|
+
Where keys are turned off (`disableLocalAuth` on the Azure OpenAI or Foundry resource, managed identities, zero trust), set `auth: entra` on an `azure` profile instead of `api_key_env`. Key profiles keep working, and both kinds can sit side by side in one `llms.json`:
|
|
186
|
+
|
|
187
|
+
```json
|
|
188
|
+
"azure-entra": {
|
|
189
|
+
"provider": "azure",
|
|
190
|
+
"model": "gpt-4o",
|
|
191
|
+
"deployment": "gpt-4o",
|
|
192
|
+
"endpoint": "https://YOUR_RESOURCE.openai.azure.com/",
|
|
193
|
+
"auth": "entra",
|
|
194
|
+
"managed_identity_client_id": "00000000-0000-0000-0000-000000000000"
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
ForgeQE asks Microsoft Entra ID for a token wherever it runs, trying in this order:
|
|
199
|
+
|
|
200
|
+
| Where ForgeQE runs | Identity it uses |
|
|
201
|
+
|---|---|
|
|
202
|
+
| An Azure VM, VM scale set, self-hosted agent, App Service, Functions, Container Apps | The user-assigned managed identity named by `managed_identity_client_id` (or `AZURE_CLIENT_ID`); without one, the system-assigned identity |
|
|
203
|
+
| AKS | Workload identity (`AZURE_FEDERATED_TOKEN_FILE`, set by the webhook) |
|
|
204
|
+
| Azure Pipelines | An `AzureCLI@2` task on a service connection with workload identity federation: ForgeQE uses that task's sign-in, with no secret |
|
|
205
|
+
| GitHub Actions | `azure/login` with OIDC, then ForgeQE in the same job |
|
|
206
|
+
| Your machine | `az login` |
|
|
207
|
+
| Anything else | A service principal in `AZURE_TENANT_ID`, `AZURE_CLIENT_ID` and `AZURE_CLIENT_SECRET` (or `AZURE_CLIENT_CERTIFICATE_PATH`) |
|
|
208
|
+
|
|
209
|
+
Give that identity the **Cognitive Services OpenAI User** role on the resource. Tokens are renewed before they expire, so long suites and coding sessions keep running. The browser engine signs in itself; the coding agent's runtime only takes a key, so ForgeQE gives it a gateway on `127.0.0.1` that accepts a one-time random key and passes each request on with a current token. No key is stored anywhere.
|
|
210
|
+
|
|
211
|
+
`auth: entra` also works on an `openai_compatible` profile, for a gateway such as API Management that checks Entra ID tokens: set `token_scope` to the scope it expects (for example `api://<app id>/.default`; the default is `https://cognitiveservices.azure.com/.default`). The engine needs the `azure-identity` package, which `forgeqe setup` installs (and adds to environments set up before it was needed); with `FORGEQE_PYTHON`, install it there yourself.
|
|
212
|
+
|
|
213
|
+
`init` also puts three folders in `.forgeqe/` to read, change, and commit:
|
|
214
|
+
|
|
215
|
+
| Folder | What it holds |
|
|
216
|
+
|--------|---------------|
|
|
217
|
+
| `.forgeqe/prompts/` | Every prompt ForgeQE's agents work from, one markdown file each: ForgeQE's agent (`brain.md`), Scribe (`test-agent.md`, `test-rules.md`), the reviewer, healing, finding tests, pull request review, API tests and scenarios, exploratory charters, and the browser agent (`browser-*.md`, plus `browser-extra.md` for your own instructions). |
|
|
218
|
+
| `.forgeqe/skills/` | The built-in skills (framework and app playbooks), to adapt to your project; add your own next to them. |
|
|
219
|
+
| `.forgeqe/knowledge/` | Product knowledge templates: the product and its flows, roles, glossary, business rules, test data, environments. |
|
|
220
|
+
|
|
221
|
+
**Your copy or ForgeQE's.** `.forgeqe-manifest.json` in each folder records what was copied. A copy you have not changed still counts as ForgeQE's, so it keeps getting ForgeQE's improvements when you update; once you edit it, yours is used. When ForgeQE's version changes after you edited yours, ForgeQE says so at start-up. Running `init` again adds what is missing and never overwrites an edited file (with `--force` it refreshes only unchanged copies).
|
|
222
|
+
|
|
223
|
+
**Prompts.** Each file has a short header (`name`, `description`, `used_by`) and the prompt; `{{> name}}` includes another prompt (`test-rules` is included in the test, reviewer, and healing prompts, so one edit changes all three). ForgeQE looks in `prompts.dir`, then `.forgeqe/prompts/`, then `~/.forgeqe/prompts/` (for every project), then its own. Changes take effect on the next run or session.
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
forgeqe prompts # every prompt, what it is for, and where it comes from
|
|
227
|
+
forgeqe prompts show test-agent # the prompt as the agent gets it (includes expanded; --raw for the file)
|
|
228
|
+
forgeqe prompts diff test-rules # how your copy differs from ForgeQE's
|
|
229
|
+
forgeqe prompts reset test-rules # back to ForgeQE's (yours is kept as test-rules.md.bak)
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
**Product knowledge.** Fill in the templates (or add your own `.md` and `.txt` files, in folders if you like), one topic per `##` heading. ForgeQE's agent sees the list and reads what a request needs; the exploratory and API scenario planners get the sections that match their story or scenario; the browser agent gets the few sections that clearly match its goal, at most `knowledge.browser_max_chars` (1500 by default; 0 turns it off). Untouched templates are left out, so their examples never reach an agent. Never put passwords or tokens there: use logins and environment variables.
|
|
233
|
+
|
|
234
|
+
### Signing in to your tools
|
|
235
|
+
|
|
236
|
+
Instead of copying tokens into `.env`, sign in once and ForgeQE saves the token in your system's credential store: the macOS Keychain, Windows Credential Manager, or the Secret Service keyring on Linux. On a machine without one, such as a headless Linux box, it uses `~/.forgeqe/credentials.json`, readable only by you.
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
forgeqe auth login # pick a system
|
|
240
|
+
forgeqe auth login jira # or name it: azure_devops, github, jira, confluence, testrail, zephyr, qtest, xray
|
|
241
|
+
forgeqe auth # what is signed in, and how
|
|
242
|
+
forgeqe auth logout jira
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
In the shell, type `/auth jira` (or `/auth` alone for the status). Tokens are typed into the prompt box unseen, shown as dots, and never sent to the agent.
|
|
246
|
+
|
|
247
|
+
| System | How you sign in |
|
|
248
|
+
|--------|-----------------|
|
|
249
|
+
| Azure DevOps | **Sign in with Microsoft in the browser** through the Azure CLI (`az login`); ForgeQE saves nothing, and the Azure CLI renews the sign-in. Or paste a personal access token: the token page opens with the scopes to tick. Azure DevOps Server (on-premises) uses a personal access token. |
|
|
250
|
+
| GitHub | **Sign in with GitHub in the browser** through the GitHub CLI (`gh auth login`): ForgeQE shows the one-time code and opens the page. Or paste a token. Needs `gh` installed. |
|
|
251
|
+
| Jira, Confluence | Your Atlassian API tokens page opens (Cloud) or your personal access tokens page (Server/Data Center); create one and paste it. Confluence on the same Cloud site as Jira reuses the Jira sign-in. |
|
|
252
|
+
| TestRail, Zephyr Scale, qTest, Xray Cloud | The page with your API key opens, or ForgeQE says where to find it; paste it. |
|
|
253
|
+
| Anything else | `forgeqe auth login OPENAI_API_KEY` (any variable name) saves that one secret: a model key, a Teams webhook URL, an SMTP or saved-login password. |
|
|
254
|
+
|
|
255
|
+
Atlassian's OAuth sign-in needs a client secret, which a command-line tool cannot keep secret, so Jira and Confluence use API tokens: they are what Atlassian recommends for scripts and tools.
|
|
256
|
+
|
|
257
|
+
Each token is checked against the system before it is saved, and the system is switched on: a saved Jira sign-in sets the site URL too, so `sources.jira` is not needed in `forgeqe.yaml`. Saved values go in under the variable names the config already reads (`JIRA_API_TOKEN`, `ADO_PAT`, ...). A variable exported in the terminal is used before a saved sign-in, and a saved sign-in before a `.env` file, so pipelines keep using their secrets. The shell commands the agents run never see the saved secrets.
|
|
258
|
+
|
|
259
|
+
**Prices.** ForgeQE prices every model call at the model's **list price**, from two public price lists: [models.dev](https://models.dev) (the list the agent runtime uses) and LiteLLM's model price list, which also has Azure's Data Zone prices. It keeps the few fields it needs in `~/.forgeqe/prices.json`, waits a few seconds for it the first time, refreshes it once a day in the background, and uses the last copy offline; only the public lists are downloaded, nothing about your runs is sent (`FORGEQE_PRICES=off` stops the downloads). Costs at list price say so: `$1.73 (list price of gpt-5.4 (Azure Global) from models.dev, 2026-10-06)`. For an Azure Data Zone deployment, which costs about 10% more, set `"deployment_type": "data_zone"` on the profile.
|
|
260
|
+
|
|
261
|
+
A profile's own `"price": { "input": 2.5, "output": 15, "cached_input": 0.25 }` (per million tokens) wins, for a negotiated or enterprise rate. Leave `currency` out and reports use this machine's currency, or set `"currency": "USD"`. Without `cached_input`, cached input gets the model's cache discount from its list price, and the cost is marked as an estimate (`≈$1.52`); with no list price for the model either, cached input is charged at the full rate and the cost is an upper bound (`up to $6.11`). When your price differs from the list price, ForgeQE says so (`forgeqe models`, the shell, and the start of each command), since that is usually a typo or an old price. Anthropic's cache writes are priced at their own rate. A provisioned (PTU) deployment is billed per hour, not per token, so its costs are what the tokens would cost at list price. Requests over a model's long-context threshold (272K tokens for GPT-5.4) cost more and are priced at the normal rate.
|
|
262
|
+
|
|
263
|
+
**Usage after every job.** Every browser run, Scribe job, heal, suite, and monitor round ends with a `Usage` line: tokens in (and how many of them were cached), tokens out, and the cost at the profile's price. A request to ForgeQE's agent in the shell, and every `forgeqe run`, `code`, `suite`, and `heal` command, ends with the total for everything it started, by role:
|
|
264
|
+
|
|
265
|
+
```
|
|
266
|
+
This request used 1.1M tokens (1.1M in, 30.0K of it cached · 34.7K out) · $3.07 — ForgeQE's agent 42.0K · $0.12, browser agent 52.7K · $0.15, Scribe 1.0M · $2.80
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
**Keeping Scribe's cost down.** ForgeQE reads the repository's test setup itself before Scribe starts (stack, settings files and their browser values, the test id attribute, base classes, page objects and their methods, one test command) and hands it over, so Scribe does not discover it with dozens of file reads. Each attempt after the first starts a fresh session from a summary of the job (handoff, files changed, what each attempt did, the latest failure), so later attempts cost about what the first did. `code.max_attempts` (default 3) and `code.max_tokens` (default 1,500,000; `0` turns it off) cap a job, and the token budget is checked during an attempt too, so one long attempt is stopped when the total passes it. The reviewer sorts its issues into correctness (the test does not test what the goal says, or not reliably) and coding standards (test data or credentials in a page object, naming, hard waits, leftovers). Coding standards never fail a test that works: it is accepted, and the coding agent gets one more round (not counted in `max_attempts`) to fix them; if that round breaks the test, ForgeQE puts back the version that passed and lists the standards issues in the notes (`code.tidy: false` skips the round). A test the reviewer rejects twice for correctness stops the job with its issues, since that usually means the test case and the page disagree. Under each step, the handoff shows that step's part of the page (its section and neighbours, from the replay's page snapshot) instead of whole snapshots. When a test fails, ForgeQE shows the failing element on the test's page at the failure and on the replay's page, so most failures are fixed without opening a browser. Scribe's live browser is switched on only when the same failure repeats, and it does not send a page snapshot after every click or keystroke. `code.max_steps` (default 50) caps the tool calls in one of Scribe's turns. `code.review_profile` runs the reviewer on a cheaper llms.json profile.
|
|
270
|
+
|
|
271
|
+
`forgeqe.yaml` selects the active profile:
|
|
272
|
+
|
|
273
|
+
```yaml
|
|
274
|
+
llm:
|
|
275
|
+
models_file: ./llms.json
|
|
276
|
+
active: azure-gpt4o
|
|
277
|
+
|
|
278
|
+
browser:
|
|
279
|
+
headless: true
|
|
280
|
+
max_steps: 40 # a checkpoint: a run still making progress carries on, up to 3x
|
|
281
|
+
timeout_seconds: 600
|
|
282
|
+
vision_detail: low
|
|
283
|
+
allowed_hosts: []
|
|
284
|
+
judge: false # true: a second model call checks each finished run and can fail it
|
|
285
|
+
overlay: true
|
|
286
|
+
# start_url: https://staging.example.com
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
`judge` is off by default. When it is on, one more model call reads the finished run's steps and screenshots and can fail a run the agent completed, for example when five scores were read off one results page rather than one step per item. That strictness sent runs into loops of re-checking, so turn it on only when you want that second opinion.
|
|
290
|
+
|
|
291
|
+
Each step waits for the tab the agent is on to finish loading (up to 8 seconds, 3 for a tab that stays blank) before the page is read, so a result that opens in a new tab is not mistaken for a blank page.
|
|
292
|
+
|
|
293
|
+
With a visible browser (`headless: false` or `--headed`), ForgeQE opens on its own start page, and every page it drives gets a glowing edge and a bar along the bottom showing, in plain words, what the step is for and what the agent is doing ("Step 19 · Check whether the results can be sorted by Fastest · Looking through the page's buttons"). Your mouse and keyboard are locked while the agent thinks and unlocked while it clicks and types, so a stray click can't change the test. None of this appears in the screenshots the model sees or in the report. `overlay: false` turns it off. `forgeqe login <name>` shows the same bar without the lock, since you are the one signing in.
|
|
294
|
+
|
|
295
|
+
`start_url` is optional. Leave it out and the agent picks the site from the goal; ForgeQE never guesses a URL from the goal text. `allowed_hosts` empty allows every host. Set `["example.com"]` to keep the browser on that domain and its subdomains. `prompts.guiderails` and `prompts.step_instruction` are appended to the engine's system prompt.
|
|
296
|
+
|
|
297
|
+
List profiles:
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
bun src/index.ts models
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
## 3. Shell
|
|
304
|
+
|
|
305
|
+
```bash
|
|
306
|
+
bun src/index.ts start
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
Type what you want and press Enter. The prompt wraps long text and grows as you type; Ctrl+J (or Shift+Enter, Alt+Enter where the terminal reports it) starts a new line, so you can paste or write several steps at once:
|
|
310
|
+
|
|
311
|
+
```
|
|
312
|
+
Go to booking.com and search for hotels in Mumbai
|
|
313
|
+
Run SHOP-12 and SHOP-14 from Jira, two browsers at once
|
|
314
|
+
Run test plan 12 suite 34 from Azure DevOps and don't post results
|
|
315
|
+
Write a Playwright test for that run
|
|
316
|
+
Add a GitHub Actions workflow that runs tests/cases.yaml on every PR, and make it green
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
ForgeQE's agent reads the message and decides what it needs: a browser run, test cases from Jira, Azure DevOps, Xray, a file, or steps you pasted, a test, or a pipeline. There is no command to pick one. When a reference is ambiguous (is `12` a work item or a test plan?), it asks, and you answer in the next message; the session remembers the conversation. Its replies appear in the transcript, and so does everything its tools do: browser steps, suite progress, and the test commands ForgeQE runs.
|
|
320
|
+
|
|
321
|
+
For a browser goal, the browser starts blank and the browser agent decides where to go, then works through cookie banners, sign-in prompts, and forms on the page. The transcript shows each step's goal and the actions it took (`navigate …`, `click "Accept"`, `input "Mumbai" → "Where are you going?"`), with ✗ and the error when an action fails.
|
|
322
|
+
|
|
323
|
+
Everything the other `forgeqe` commands do is also a tool the agent can call, so you can ask for it here instead of leaving the shell:
|
|
324
|
+
|
|
325
|
+
| Ask for | Tool | Same as |
|
|
326
|
+
|---------|------|---------|
|
|
327
|
+
| "Run SHOP-12 and SHOP-14", "what's in test plan 12?" | `run_test_cases`, `find_test_cases` | `forgeqe suite`, `forgeqe cases` |
|
|
328
|
+
| "Write a Playwright test for that run" | `write_test` | `forgeqe code` |
|
|
329
|
+
| "The checkout tests are failing, fix them" | `heal_tests` | `forgeqe heal` |
|
|
330
|
+
| "Run all tests related to login", "run the tests added this sprint", "which tests cover checkout?" | `find_tests`, `run_tests`, `list_sprints` | (shell and `forgeqe run` only) |
|
|
331
|
+
| "Check the smoke cases once", "monitor them every 10 minutes", "is anything failing?", "stop monitoring", "send a test alert" | `monitor` | `forgeqe monitor`, `--once`, `--test-alerts` |
|
|
332
|
+
| "Sign in to shop", "which logins do I have?", "forget the shop session" | `logins` | `forgeqe login`, `forgeqe logins`, `forgeqe logins clear` |
|
|
333
|
+
| "What flows does page memory know?", "forget what you learned about shop.test" | `page_memory` | `forgeqe memory` |
|
|
334
|
+
| "What can you do?", "can you do API testing?", "do you support DORA?" | `capabilities` | `forgeqe features` |
|
|
335
|
+
| "Which profiles do I have?", "which MCP servers will you use?", "how do email alerts work?", "install the engine", "scaffold a config in ./demo" | `forgeqe_setup` | `forgeqe models`, `forgeqe mcp list`, `forgeqe docs`, `forgeqe setup`, `forgeqe init` |
|
|
336
|
+
|
|
337
|
+
Only browser runs of the app under test become tests. When the agent uses the browser for a task, such as checking whether a story is linked to a test case in Azure DevOps or Jira, that run is marked as a task and no test is written for it, even if `write_test` is called on it. `write_test` and `heal_tests` run the same loops as the commands: ForgeQE runs the test command itself and a test only counts as passing when ForgeQE saw it pass. Their results, and each monitor round, appear as a card in the transcript. When a step needs you, such as signing in by hand in the browser window, a **Your turn** prompt shows what to do, and ForgeQE waits until you pick **Done, continue** (save the session) or **Cancel**.
|
|
338
|
+
|
|
339
|
+
The only slash commands control the session:
|
|
340
|
+
|
|
341
|
+
| Command | Action |
|
|
342
|
+
|---------|--------|
|
|
343
|
+
| `/stop` | Stop what is running (or press Esc) |
|
|
344
|
+
| `/headed on\|off` | Show the browser window (live profiles) |
|
|
345
|
+
| `/details [on\|off]` | Show everything the agents do while they work: the browser agent's reasoning, page memory, engine logs, every file the coding agent reads (off by default: step results, files written, test results, problems). `--verbose` or `FORGEQE_VERBOSE=1` starts with it on, for `start`, `run`, `suite`, `code`, and `heal` too |
|
|
346
|
+
| `/profile <name>` | Switch LLM profile (or press Tab); the agent restarts with it |
|
|
347
|
+
| `/clear` | Clear the transcript |
|
|
348
|
+
| `/help` | Examples and commands |
|
|
349
|
+
| `/exit` | Quit |
|
|
350
|
+
|
|
351
|
+
`start_url` in `forgeqe.yaml` or `--url` pins a start page for browser runs, such as a staging app. Passed runs become tests in the current folder; `forgeqe start --repo ../app` puts them in that repo instead, and `--no-code` turns tests off.
|
|
352
|
+
|
|
353
|
+
ForgeQE's agent runs on the agent runtime with the active profile's model (or `code.model`). ForgeQE downloads the agent runtime into `~/.forgeqe/tools` when it is not installed. When the agent runtime cannot be downloaded, ForgeQE says the agent is off and runs each message as one browser goal.
|
|
354
|
+
|
|
355
|
+
While a run is going, the bar under the prompt shows a spinner, the tokens used, and the elapsed time, and the transcript ends with what the agent is doing now (`Thinking about step 3…`, `Acting in the browser (step 3)…`). Each step starts with `+ Thought: 4.2s`, the time the model took to decide. When the run ends, a summary card closes the transcript:
|
|
356
|
+
|
|
357
|
+
```
|
|
358
|
+
┃ ✓ Task complete 10 steps · 1m 42s · 65.3K tokens
|
|
359
|
+
┃
|
|
360
|
+
┃ Done — I searched Booking.com for hotels in Mumbai for tomorrow. I verified the results
|
|
361
|
+
┃ page shows destination "Mumbai" with dates "Tue 29 Sept" to "Wed 30 Sept" …
|
|
362
|
+
┃
|
|
363
|
+
┃ Ended on booking.com/searchresults.en-gb.html
|
|
364
|
+
┃ Saved .forgeqe/reports/20260928-172700/ run.json · workflow.yaml · trace.md · report.html
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
The text is the agent's own result. Failed runs show `✗ Task failed` with the reason, and stopped runs show `■ Run stopped`. `forgeqe run` prints the same summary at the end.
|
|
368
|
+
|
|
369
|
+
| Key | Action |
|
|
370
|
+
|-----|--------|
|
|
371
|
+
| Enter | Send the message or command |
|
|
372
|
+
| Tab | Next LLM profile from `llms.json`; the conversation carries over to the new model |
|
|
373
|
+
| Ctrl-P | Show commands |
|
|
374
|
+
| Esc | Ask to stop the run: **Stop run**, **Stop and close ForgeQE**, or **Keep running** |
|
|
375
|
+
| Ctrl-C | Ask to close ForgeQE: **Close** or **Cancel**. A second Ctrl-C closes straight away |
|
|
376
|
+
|
|
377
|
+
In the button prompt, ←/→ or Tab move between buttons, Enter confirms, Esc cancels, and a mouse click works too. `esc stop` and `ctrl+c close` in the bar under the prompt are also clickable. **Stop and close** waits until the browser has shut down and the run's files are saved, then closes ForgeQE.
|
|
378
|
+
|
|
379
|
+
## 4. Without the shell
|
|
380
|
+
|
|
381
|
+
```bash
|
|
382
|
+
forgeqe run "Search hotels in Mumbai on booking.com" --profile azure-gpt4o --plain
|
|
383
|
+
forgeqe run "Run the cases in smoke.yaml and don't post results" --plain
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
`forgeqe run` sends the request to the same agent and prints its tool work and its final reply. Exit codes: `0` done, `1` failed, `2` stopped (Ctrl-C), `3` the agent needs more information; run again with the details.
|
|
387
|
+
|
|
388
|
+
`--direct` skips the agent and runs the text as one browser goal, which is also what happens without the agent runtime:
|
|
389
|
+
|
|
390
|
+
```bash
|
|
391
|
+
forgeqe run --direct "Search hotels in Mumbai on booking.com" --profile azure-gpt4o --plain --out ./.forgeqe/reports/demo
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
Exit codes for a direct run: `0` complete, `1` failed, `2` stopped. For test cases in a pipeline, use `forgeqe suite` (section 7), which runs the same way every time.
|
|
395
|
+
|
|
396
|
+
Each run gets its own folder, named by its run id (the start time), under `.forgeqe/reports/` (`export.out_dir`). `forgeqe init` adds `.forgeqe/reports/` to `.gitignore`, and so does the first agent command in a project set up before that. A live run's folder contains:
|
|
397
|
+
|
|
398
|
+
- `run.json`: result, summary, token counts, visited URLs, the judge's check of the result (when `judge: true`), and how the browser was set up
|
|
399
|
+
- `workflow.yaml`: compact steps (`forgeqe-v2-compact`) with semantic locators
|
|
400
|
+
- `trace.md`: task, per-step result, failure trace
|
|
401
|
+
- `steps.json` and `steps/`: each step with a screenshot
|
|
402
|
+
- `report.html`: the run's report
|
|
403
|
+
- `failure.png`: last screenshot, only when the run failed
|
|
404
|
+
|
|
405
|
+
## 5. Page memory
|
|
406
|
+
|
|
407
|
+
Live runs build a memory of the pages they visit, next to `forgeqe.yaml`. With no config file it goes to `~/.forgeqe/memory` (under `FORGEQE_HOME` when that is set), so runs from any folder share one memory.
|
|
408
|
+
|
|
409
|
+
```yaml
|
|
410
|
+
memory:
|
|
411
|
+
enabled: true
|
|
412
|
+
dir: ./.forgeqe/memory
|
|
413
|
+
replay: verify # verify | trust | off
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
```
|
|
417
|
+
.forgeqe/memory/
|
|
418
|
+
pages/<host>/<path>.json every interactive element on the page and its locators
|
|
419
|
+
flows/<goal>-<hash>.json the steps of a goal that passed, for replay
|
|
420
|
+
scribe-notes.json what the coding agent learned about each repo, and the tests it wrote there
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
Each page file lists its elements with every locator ForgeQE can build for them: test id, id, role and name, label, placeholder, alt, title, href, text, CSS, and XPath. Each locator has a Playwright string, a confidence %, and its evidence: how many visits it matched on, how often it went missing, and how often it worked or failed when used. Elements and pages carry `first_seen`, `last_seen`, `last_used`, and `last_updated`. Paths with ids in them share one file (`/hotel/*`), and query strings are ignored.
|
|
424
|
+
|
|
425
|
+
Confidence starts from the locator kind (a test id or role and name ranks above text, CSS, and XPath). It is lower when the locator matches more than one element or looks generated (`#ember123`, hashed class names). It rises as the locator keeps matching over visits and works when used, and it drops when the locator goes missing or fails.
|
|
426
|
+
|
|
427
|
+
How memory saves time and tokens:
|
|
428
|
+
|
|
429
|
+
- **Replay.** Running a goal that passed before replays its recorded steps directly in the browser, with no model calls. A different goal replays nothing: the agent gets the steps of earlier runs on the site, and the controls that worked there, as hints, and decides itself which of them (a banner, a sign-in, a search form) apply to its task, so a new task does not re-explore the setup. Each step finds its element by the highest-confidence locator that still matches exactly one element, then by the element's fingerprint, so a renamed button or a changed id still resolves. The transcript marks these steps `↻` and shows the locator used (`click "Search" [role 88%]`).
|
|
430
|
+
- **Hand-off.** With `replay: verify` (the default) the agent then looks at the page once and confirms the result. `replay: trust` finishes without the model when every step of this same task replayed. When a step cannot be found, the agent continues from that point instead of starting over. `replay: off` records memory but never replays.
|
|
431
|
+
- **Failed runs.** A run that fails keeps the steps that worked before it went wrong (`resume.json` in its run folder, and in the task's flow). Running the same task again replays them and the agent picks up at the point of failure, told what went wrong last time. When ForgeQE's agent retries a failed goal with different wording, it passes the failed run (`resume_from`), so the retry starts from the same point instead of step 1.
|
|
432
|
+
- **Cut-off runs.** After every step, a run saves the steps that worked so far and the page memory it has learned, so nothing is lost if ForgeQE is closed, the machine restarts, or the run is stopped. Running the same task again replays those steps and the agent carries on from there; the folder of the cut-off run also has `resume.json`, so `resume_from` works with it too. When the model can't be reached (the connection dropped), the run ends as failed and keeps its steps the same way. A run that finishes removes the saved point.
|
|
433
|
+
- **Hints.** The agent's prompt includes the steps that worked last time on the same site and the controls those runs used, and tells the agent to do them in one turn instead of exploring the page.
|
|
434
|
+
- **Tests.** The coding agent gets each element's best locator from memory in `handoff.md`.
|
|
435
|
+
|
|
436
|
+
A run that fails keeps the last good flow and counts the failure. A stopped run changes nothing. Password fields are never stored, and a value typed from `FORGEQE_ENGINE_DEFAULT_LOGIN_USERNAME` or `FORGEQE_ENGINE_DEFAULT_LOGIN_PASSWORD` is stored as the variable name and read from the environment on replay. Replay also stops before a step whose value cannot be restored, and the agent does it.
|
|
437
|
+
|
|
438
|
+
```bash
|
|
439
|
+
forgeqe memory # hosts with page, element, and flow counts
|
|
440
|
+
forgeqe memory show booking.com # the host's pages
|
|
441
|
+
forgeqe memory show https://app.test/login # elements, confidence, best locator
|
|
442
|
+
forgeqe memory show https://app.test/login --locators --all
|
|
443
|
+
forgeqe memory flows --steps
|
|
444
|
+
forgeqe memory clear booking.com # prints what it would delete
|
|
445
|
+
forgeqe memory clear booking.com --yes
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
In the shell, ask ("what does page memory know about booking.com?") and the agent looks it up. For one run, `--replay verify|trust|off` overrides the config and `--no-memory` turns memory off.
|
|
449
|
+
|
|
450
|
+
Commit `.forgeqe/memory` to share it with a team or CI, or add `.forgeqe/` to `.gitignore` to keep it local.
|
|
451
|
+
|
|
452
|
+
## 6. Tests
|
|
453
|
+
|
|
454
|
+
After a run passes, **Scribe**, ForgeQE's coding agent, turns it into a test in your repo.
|
|
455
|
+
|
|
456
|
+
In the shell and `forgeqe run`, every passed run then becomes a test, and so does each test case that passes when you ask the shell to run test cases: in the current folder, or in the repo you give per run or in `forgeqe.yaml`. `--no-code` turns it off; you can still ask for a test ("write a Playwright test for that run").
|
|
457
|
+
|
|
458
|
+
```bash
|
|
459
|
+
forgeqe run "Log in and open the invoices page on staging.app.test" --repo ../app
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
```yaml
|
|
463
|
+
code:
|
|
464
|
+
repo: ../app # relative to forgeqe.yaml
|
|
465
|
+
max_attempts: 5 # test runs before giving up
|
|
466
|
+
test_timeout_seconds: 600 # per test run
|
|
467
|
+
stall_after: 5 # stop the agent's turn when one command it runs has failed this many times
|
|
468
|
+
replay: true # before the agent starts, run the steps as a Playwright script and hand over what worked
|
|
469
|
+
live_browser: true # once a step fails, the agent looks at that page in a Playwright browser
|
|
470
|
+
# model: anthropic/claude-sonnet-4-5
|
|
471
|
+
# runtime: /path/to/agent-runtime # default: the runtime ForgeQE downloads
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
What happens after the run passes:
|
|
475
|
+
|
|
476
|
+
1. ForgeQE writes `handoff.md` into the run directory: the goal and result, how ForgeQE's browser was set up (browser and version, headless or headed, user agent, `navigator.webdriver`, launch switches, extra headers, language, time zone, viewport), every step in order with the value typed (secrets as `process.env.NAME`) and the JavaScript the browser agent ran, the browser agent's own note before each group of steps (what it saw and why it acted, so a sign-in pop-up it closed or steps it redid after a banner covered the page read as such), each element's best locator and the others with their confidence %, and a short table of each visited page's other elements for assertions (weak locators under 30% are left out, and elements the steps already use are listed with the steps, so the handoff stays small; the full lists are in the page-memory files it points to). The agent's result and the final URL are marked as coming from one run on live data, to be checked as rules (the results load, the order holds, the fields have the right format), not copied as expected values. Pop-ups and banners the run met are handled wherever they appear (Playwright's locator handlers or the repository's helper), since the next run can show them at another moment or not at all; the agent's retries are not copied. A site can also serve different versions of a page to different visits (A/B tests, such as a classic search box or a free-text one), so the test handles every version the run or the agent saw, or waits for one control from either version.
|
|
477
|
+
|
|
478
|
+
The handoff also lists the browser agent's **checks**: before it finishes, the browser agent records each result the goal asks to verify with the exact text the page showed (`record_check`; a text the page does not show is refused). They are saved in `workflow.yaml` under `checks:`. The test asserts these and nothing else.
|
|
479
|
+
2. ForgeQE replays the run's steps as a Playwright script (`<run>/replay/flow.mjs`), in the run's browser setup (channel, headless or headed, user agent, language, time zone, viewport), with 10 seconds per step. Text is typed key by key, as the browser agent typed it, so search suggestions and other typing handlers fire. If the replay does not reach the run's final page, it runs again without Playwright's automation switches (`navigator.webdriver` false, as in ForgeQE's browser). The handoff gets the result: which steps worked, and for each failed step, Playwright's reason (for example a dialog that intercepts the click), the page, the dialogs open on it, how many elements each of the element's other locators matched, and a screenshot and page snapshot. It also saves Playwright's page snapshot of each page the replay visited (roles, accessible names, and text, as the replay left the page; the last page once it stops changing), so Scribe takes locators for its steps and assertions from real pages instead of guessing them. On the last page it looks up each of the browser agent's checks and puts the Playwright locator that matched its text into the handoff (a heading or text match, the container it sits in when there are several, or the form field that holds it), so assertions come with a locator that worked. For a heading it also gives the part of the page the heading names (an element labelled by it, the section it heads, or the element right after it), with its locator and how many links and list items it holds, so a check such as "an In the news section with at least one item" is asserted inside that part, not on the heading alone. A step that fails while every step after it still works and the replay reaches the final page (a click that did nothing on the run, or a control this version of the page doesn't have) doesn't count as a failed replay: Scribe decides from the step whether the goal needs it and ports the rest as it is. When only the second launch got through, the handoff says the browser setup is the difference and which launch settings fix it. The first time, Playwright (about 13 MB) is downloaded into `~/.forgeqe/tools`; it drives the installed Chrome. A run that only opened a page still replays when it recorded checks, to look them up; with neither it skips this, and `replay: false` turns it off.
|
|
480
|
+
|
|
481
|
+
Scribe first reads the repo (as a read-only agent: it cannot change files or use the live browser yet), while the replay runs when there is one, so the two overlap. What it learns (the framework, the command that runs one test, where page objects and config live, the conventions) is saved with page memory in `scribe-notes.json`, with the tests each job writes there. The next job in the same repo starts from those notes and that list instead of reading the repo again, and extends those tests' page objects when its flow overlaps; notes older than 30 days are read again.
|
|
482
|
+
3. Scribe starts in the repo. It reads `AGENTS.md`, the test framework config, run scripts, page objects, fixtures, and helpers, and follows the imports between them. It writes the test in the repo's language and framework (a C# NUnit repo gets a C# NUnit test) and to fit its code: it extends an existing page object instead of duplicating it and reuses the login flow, test data, and config. A repo with no tests gets Playwright Test in TypeScript. It may change anything the test needs, including dependencies and config.
|
|
483
|
+
4. It writes the test from the handoff and the replay script: steps that worked are ported with their locators, steps that failed are fixed first. Every locator, including those for assertions, comes from the replay script, the page snapshots, page memory, or a check on the page; steps where the browser agent ran JavaScript to look around are left out. It does not walk the flow again or build tests to explore. Once a step fails (in the replay, or in its test), ForgeQE switches on its live browser: a Chrome that Playwright drives, set up like ForgeQE's, where it looks at the failing step's page one tool call per action (open, snapshot, click, type, wait, screenshot, run JavaScript, console errors, failed requests). Until then the live browser tools are off, so no tokens go into looking at pages that work. The live browser needs Node.js (`npx`), and Microsoft's Playwright MCP server is downloaded on first use; with `live_browser: false`, or without `npx`, it looks with a small throwaway script instead. When its browser gets a different page than ForgeQE's did (an error, a challenge, a control that will not open), it compares the two browsers (user agent, `navigator.webdriver`, headless, failed requests and CORS errors, headers the framework adds, console errors) and fixes the difference in the repo's browser configuration. It never judges the site with `curl` or `webfetch`.
|
|
484
|
+
5. Scribe does not run the test itself: it may build or compile, then reports the test file and the command that runs only that test, and ForgeQE runs it. If one command it runs fails `stall_after` times in a row within its work (the same build again and again, say), ForgeQE stops that turn and sends the command and its last output back, asking it to change approach. If the same command stalls again, the job stops as a failure with that output in the notes.
|
|
485
|
+
6. ForgeQE runs that command (with `CI=1`) and checks the exit code, and it watches the processes the command starts for a browser launched by Playwright, Puppeteer, Selenium, or Cypress. On a failure it sends the command, exit code, and output back to Scribe. The output is kept short so the error is never cut off: the page dump Playwright puts into a failed assertion ("Aria snapshot:", often thousands of lines) is taken out and saved as `<run>/test-runs/attempt-N-page.aria.yml`, then the start (where the first error and its stack trace are) and the end (the summary) are sent; the full output is in `<run>/test-runs/attempt-N.log`, and the prompt names both files. A command that exits 0 without starting a browser also goes back: the test must drive the app in a browser. If the repo's browser runs on another machine (Selenium Grid, a cloud service, a container), the agent says where and the check is skipped.
|
|
486
|
+
7. A passing test then goes to a separate reviewer agent, which can read files and `git diff` but not change anything. It checks the change against the goal and the test rules: every part of the goal done through the page and asserted, generic page objects with data in the test, no values or URLs copied from the run, browser settings in the repo's configuration, no leftover files. The changed files come inline in its prompt, so it reads nothing again, and it does not ask to replace locators or texts that came from the replay or the checks, since those matched the live site. It judges only what this job changed: ForgeQE records the working tree before the job, so your uncommitted edits, your untracked files, and ForgeQE's own files (`.forgeqe/`, `forgeqe.yaml`, `llms.json`) are never part of the review. If it finds problems, they go back to Scribe as the next attempt.
|
|
487
|
+
|
|
488
|
+
Scribe cannot edit ForgeQE's files or run folders, and cannot run `git clean`, `git reset --hard`, `git stash`, `git restore`, or `git checkout -- <path>`. If it still removes a file that existed before the job, or reverts your uncommitted edits, ForgeQE puts the file back after that attempt and tells the agent.
|
|
489
|
+
8. The job is done when ForgeQE's run passes with a browser and the reviewer approves. It stops as a failure after `max_attempts` attempts, when the job passes `code.max_tokens`, when the reviewer rejects a passing test twice, if the review cannot finish, when the test fails the same way three times in a row (the same output apart from numbers such as timings and line numbers; the second time, Scribe is told its change did not change the failure and to look at the failing step before changing code), or straight away on an auth, API, or context-limit error from the model.
|
|
490
|
+
|
|
491
|
+
`blocked` is a last resort. The first time the agent reports that the app blocks it, ForgeQE sends it back to compare its browser with ForgeQE's and fix the difference; only a second blocked report, with what it compared, ends the job as blocked.
|
|
492
|
+
|
|
493
|
+
The transcript shows the handover and Scribe's work as it goes; files it writes or edits are marked ✎:
|
|
494
|
+
|
|
495
|
+
```
|
|
496
|
+
┃
|
|
497
|
+
┃ ▸ Handing over to the coding agent browser agent → coding agent
|
|
498
|
+
┃
|
|
499
|
+
┃ Flow Log in and open the invoices page on staging.app.test
|
|
500
|
+
┃ Run .forgeqe/reports/20260928-172700/
|
|
501
|
+
┃ Repo ../app
|
|
502
|
+
┃
|
|
503
|
+
▸ Handoff written: .forgeqe/reports/20260928-172700/handoff.md (7 steps, 3 pages from page memory)
|
|
504
|
+
▸ Scribe, the coding agent (azure/gpt-5.4), reads the handoff and writes a test in /work/app
|
|
505
|
+
⚙ Reading .forgeqe/reports/20260928-172700/handoff.md
|
|
506
|
+
⚙ Reading tests/pages/LoginPage.ts
|
|
507
|
+
✎ Editing tests/invoices.spec.ts
|
|
508
|
+
⚙ Running npx playwright test tests/invoices.spec.ts
|
|
509
|
+
▸ ForgeQE runs the test: npx playwright test tests/invoices.spec.ts
|
|
510
|
+
✗ tests/invoices.spec.ts failed, exit 1 (attempt 1/5)
|
|
511
|
+
▸ tests/invoices.spec.ts passed in 9s in Google Chrome; a reviewer checks it against the goal
|
|
512
|
+
✓ tests/invoices.spec.ts passed and was approved (attempt 2/5)
|
|
513
|
+
┃
|
|
514
|
+
┃ ✓ Test passed 2/5 attempts · 3m 12s · 88.4K tokens · azure/gpt-5.4
|
|
515
|
+
┃
|
|
516
|
+
┃ Added openInvoices() to DashboardPage and reused the loginAs fixture.
|
|
517
|
+
┃
|
|
518
|
+
┃ Test tests/invoices.spec.ts (in ../app)
|
|
519
|
+
┃ Command npx playwright test tests/invoices.spec.ts
|
|
520
|
+
┃ Reused LoginPage, fixtures/auth.ts
|
|
521
|
+
┃ Changed tests/invoices.spec.ts, tests/pages/DashboardPage.ts
|
|
522
|
+
┃ Browser Google Chrome
|
|
523
|
+
┃ Review approved: Opens the invoices page through the dashboard and checks the table columns.
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
After ForgeQE's reply, the request ends with the files it produced:
|
|
527
|
+
|
|
528
|
+
```
|
|
529
|
+
┃ ✓ What this produced
|
|
530
|
+
┃
|
|
531
|
+
┃ Report .forgeqe/reports/20260928-172700/report.html
|
|
532
|
+
┃ ✓ Test ../app/tests/invoices.spec.ts passed when ForgeQE ran it
|
|
533
|
+
┃ Command npx playwright test tests/invoices.spec.ts
|
|
534
|
+
┃ Handoff .forgeqe/reports/20260928-172700/handoff.md
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
When no test was written, the Test row says why: the run did not pass, the session has `--no-code`, or the run was not handed to the coding agent.
|
|
538
|
+
|
|
539
|
+
Scribe uses the active `llms.json` profile. The key stays in your environment: the agent runtime's config refers to it as `{env:WP_AZURE_API_KEY}` and never contains the value. An `auth: entra` profile reaches the model through ForgeQE's local token gateway (see [Signing in to the model without a key](#signing-in-to-the-model-without-a-key-microsoft-entra-id)). An Azure profile goes through the agent runtime's `azure` provider on `<endpoint>/openai/v1` (the Responses API, with the deployment as the model). `openai_compatible` and `ollama` profiles use their `base_url`. `code.model: provider/model` (or `--code-model`) uses one of the agent runtime's built-in providers instead, with that provider's usual key variable (for example `ANTHROPIC_API_KEY` for `anthropic/...`).
|
|
540
|
+
|
|
541
|
+
Scribe may edit files and run commands anywhere in the repo without asking. `git push` in any form is denied (pushing goes through ForgeQE's guarded `push_branch` tool, section 8), and it cannot touch files outside the repo except the run and memory directories, which it may read.
|
|
542
|
+
|
|
543
|
+
More ways to run it:
|
|
544
|
+
|
|
545
|
+
```bash
|
|
546
|
+
forgeqe code --repo ../app # the latest run in .forgeqe/reports/
|
|
547
|
+
forgeqe code .forgeqe/reports/20260928-172700 --repo ../app --attempts 3
|
|
548
|
+
forgeqe run "..." --no-code # no tests for this request
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
In the shell, `forgeqe start --repo ../app` writes the tests in that repo instead of the current folder and `--no-code` turns them off; you can also just ask ("write a test for the last run in ../app"). Esc stops the agent the same way it stops a run.
|
|
552
|
+
|
|
553
|
+
Exit codes for `forgeqe code` and for `forgeqe run --direct` with a repo: `0` test passed, `1` run or test failed, `2` stopped. The result (status, attempts, test file, command, what was reused and changed, the browsers ForgeQE saw, the review, the last test output, tokens) is saved as `code.json` in the run directory, next to `handoff.md`.
|
|
554
|
+
|
|
555
|
+
If Scribe's job is cut off (ForgeQE closed, the machine restarted, you stopped it, or the model could not be reached), run it again for the same run and repo, for example `forgeqe code .forgeqe/reports/20260928-172700 --repo ../app`. Scribe reopens the same session, with everything it read and said, and carries on with the files it already wrote; it doesn't read the repo again, and ForgeQE uses the Playwright replay it already finished. The session is kept in `scribe-session.json` in the run folder until the job ends with a result.
|
|
556
|
+
|
|
557
|
+
### Fixing broken tests
|
|
558
|
+
|
|
559
|
+
When a redesign or a renamed button breaks tests, `forgeqe heal` fixes them, or tells you the app is what broke:
|
|
560
|
+
|
|
561
|
+
```bash
|
|
562
|
+
forgeqe heal --repo ../app # the command from code.test_command, or the agent finds it
|
|
563
|
+
forgeqe heal "npx playwright test tests/checkout" --repo ../app
|
|
564
|
+
forgeqe heal -- npx playwright test --project=chromium # everything after -- is the command
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
```yaml
|
|
568
|
+
code:
|
|
569
|
+
repo: ../app
|
|
570
|
+
test_command: npx playwright test # optional
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
1. ForgeQE runs the command. If it passes, there is nothing to heal and no model is called.
|
|
574
|
+
2. Scribe starts in the repo as a healing agent, with the failing output. For each failing test it reads the test and the page objects it uses, then re-runs the test's flow in the real browser with ForgeQE's `browser_run` (the goal in plain words, not the old selectors).
|
|
575
|
+
3. If the browser run passes, the test is out of date. The agent reads that run's steps and locators with `run_details`, updates the test (in the page object when the locators live there), and runs it with `run_test`.
|
|
576
|
+
4. If the browser run fails at the step where the test fails, the app is broken there. The test is left as it is and the failure is reported as an app bug.
|
|
577
|
+
5. It never deletes or skips a test, loosens an assertion, or raises a timeout to make a test pass.
|
|
578
|
+
6. ForgeQE runs each healed test's own command, then the whole command. A healed test that still fails goes back to the agent with the output, and so does any other failure left in the whole run, until everything passes or `code.max_attempts` rounds are used.
|
|
579
|
+
|
|
580
|
+
```
|
|
581
|
+
▸ ForgeQE runs the tests: npx playwright test
|
|
582
|
+
✗ Tests failed, exit 1 (41s)
|
|
583
|
+
▸ Scribe (azure/gpt-5.4) is healing the failing tests in app
|
|
584
|
+
⚙ read tests/pages/LoginPage.ts
|
|
585
|
+
▸ Browser: Sign in to staging.app.test and open the invoices page
|
|
586
|
+
✓ Task complete · 9 steps
|
|
587
|
+
⚙ edit tests/pages/LoginPage.ts
|
|
588
|
+
▸ ForgeQE runs: npx playwright test tests/login.spec.ts
|
|
589
|
+
✓ login › signs in passed in 6s
|
|
590
|
+
▸ ForgeQE runs the tests: npx playwright test
|
|
591
|
+
✗ Tests still fail, exit 1 (39s)
|
|
592
|
+
┃
|
|
593
|
+
┃ ✗ Tests still failing 2/5 attempts · 2m 40s · 61.2K tokens · azure/gpt-5.4
|
|
594
|
+
┃
|
|
595
|
+
┃ ✓ login › signs in healed
|
|
596
|
+
┃ The Sign in button is now "Log in"; LoginPage uses the new label
|
|
597
|
+
┃ ! invoices › totals app bug
|
|
598
|
+
┃ The total column is empty; the browser run failed at the same step
|
|
599
|
+
┃
|
|
600
|
+
┃ 1 failure is in the app, not the tests; the tests were left as they are.
|
|
601
|
+
┃ Command npx playwright test (exit 1 after 39s)
|
|
602
|
+
┃ Changed tests/pages/LoginPage.ts
|
|
603
|
+
┃ Report .forgeqe/reports/heal/20260929-101500/heal.md
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
The report is `heal.md` and `heal.json` in `.forgeqe/reports/heal/<time>/`: each test's verdict and reason, the files changed, the browser runs (their folders sit next to the report), and the test output before and after. Exit codes: `0` the tests pass (or nothing needed healing), `1` some still fail, `2` stopped. In the shell or with `forgeqe run`, "the checkout tests are failing after the redesign, fix them" does the same through ForgeQE's agent.
|
|
607
|
+
|
|
608
|
+
### Finding and running existing tests
|
|
609
|
+
|
|
610
|
+
Ask for the tests you want in your own words, in the shell or with `forgeqe run`:
|
|
611
|
+
|
|
612
|
+
```text
|
|
613
|
+
Run all test cases related to login
|
|
614
|
+
Run the tests added this sprint
|
|
615
|
+
Which tests cover checkout? Don't run them
|
|
616
|
+
Run the tests added since 2026-09-01
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
1. Scribe starts read-only in the repo. It works out the test framework and decides each test by reading it: its body, and the page objects and helpers it calls. A test named `guest can pay` that signs in through `LoginPage` counts as a login test; a test that only mentions login in its name but checks something else does not. For a date range or sprint, it reads git history and selects the tests added in that range, including new test functions in files that already existed. It cannot change files or run anything.
|
|
620
|
+
2. It gives two commands in the framework's own terms: one that lists exactly those tests (`playwright test --list`, `pytest --collect-only`, `dotnet test --list-tests`, …) and one that runs them and writes JUnit XML or TRX results. ForgeQE runs the list command, and Scribe checks the listing is exactly its selection, fixing the command when it is not (up to three rounds).
|
|
621
|
+
3. The list appears as a card: each test with its file and why it matches, the near misses that were left out, and the commands.
|
|
622
|
+
4. Nothing runs until you say so. ForgeQE asks **Run N tests?** with **Run** and **Don't run** (in the shell a dialog; with `forgeqe run` a numbered prompt in the terminal). When you only asked which tests exist, it stops at the list.
|
|
623
|
+
5. ForgeQE runs the tests itself and reads their results: a card with ✓ or ✗ for each test and the failure message, then the command, the result files, and the output. When tests fail, ForgeQE's agent offers to heal them with `heal_tests`.
|
|
624
|
+
|
|
625
|
+
```
|
|
626
|
+
┃ ▸ 3 tests found for "tests related to login" · Playwright (TypeScript)
|
|
627
|
+
┃
|
|
628
|
+
┃ • login › signs in with a valid user
|
|
629
|
+
┃ tests/login.spec.ts · Fills the sign-in form and checks the account menu
|
|
630
|
+
┃ • login › rejects a wrong password
|
|
631
|
+
┃ tests/login.spec.ts · Submits a bad password and checks the error
|
|
632
|
+
┃ • checkout › guest can pay
|
|
633
|
+
┃ tests/checkout.spec.ts · Signs in through LoginPage before paying
|
|
634
|
+
┃
|
|
635
|
+
┃ Left out:
|
|
636
|
+
┃ • signup › creates an account · Signs up; never signs in
|
|
637
|
+
┃
|
|
638
|
+
┃ List npx playwright test --list --grep "login|guest can pay" (ForgeQE ran it: lists exactly these)
|
|
639
|
+
┃ Run npx playwright test --grep "login|guest can pay" --reporter=junit
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
**This sprint.** For "tests added this sprint" or "last sprint", ForgeQE fetches the sprints from the Azure DevOps team (`sources.azure_devops`, iterations of the project's default team unless you name one) and the Jira scrum boards (`sources.jira`), and asks which one you mean: the current, the three latest past, and the next sprint of each team or board, with their dates. The sprint's start and end dates become the range. Name a sprint ("tests added in Sprint 41") and it is matched without asking; give dates ("since 2026-09-01") and no sprint is fetched.
|
|
643
|
+
|
|
644
|
+
The selection, the output, and the results are saved in `.forgeqe/reports/tests/<time>/`: `selection.json`, `output.log`, `results.json`, and the JUnit or TRX file. When a framework cannot write results (for example Jest without `jest-junit`), the exit code decides and the card shows the end of the output instead.
|
|
645
|
+
|
|
646
|
+
Through `forgeqe mcp`, ForgeQE cannot ask you, so `run_tests` returns the list and runs only when called again with `confirmed: true`; the MCP client should ask you first.
|
|
647
|
+
|
|
648
|
+
### Reviewing pull requests
|
|
649
|
+
|
|
650
|
+
Ask for a review with the pull request's link or its number in the repo you are in:
|
|
651
|
+
|
|
652
|
+
```text
|
|
653
|
+
Review PR 42
|
|
654
|
+
Review https://dev.azure.com/acme/Shop/_git/web/pullrequest/42 and focus on error handling
|
|
655
|
+
Review my open pull requests
|
|
656
|
+
```
|
|
657
|
+
|
|
658
|
+
1. ForgeQE reads the pull request: title, description, source and target branch, and the linked work items with their acceptance criteria (Azure DevOps, through its REST API with `sources.azure_devops`), or the linked issues (GitHub, through `gh`, which must be signed in with `gh auth login`).
|
|
659
|
+
2. It fetches both branches from your clone's remote and checks the pull request's head out in a temporary worktree. Your branch, your working tree, and your uncommitted changes are not touched, and the worktree and fetched refs are removed afterwards. The working directory (or `repo`) must be a clone of the pull request's repository.
|
|
660
|
+
3. Scribe reviews the diff read-only, reading the code around each change: bugs, security, what the linked work items ask for, missing tests, performance, and compatibility. Each finding has a severity (blocker, major, minor, nit), the file and line, the problem, and a suggestion. `code.review_profile` picks a cheaper model for it, as for test reviews.
|
|
661
|
+
4. The findings appear as a card, and are saved in `.forgeqe/reports/reviews/<time>/` as `review.md` and `review.json`. Nothing is posted yet.
|
|
662
|
+
5. To post, say so. ForgeQE asks **Post the review?** with **Post review** and **Don't post**. Findings on a changed line become comments on that line; the rest go in one summary comment with the verdict. On GitHub this is one review with event `COMMENT`: ForgeQE never approves, requests changes, or votes in your name. If the pull request got new commits after the review, posting is refused; review it again.
|
|
663
|
+
|
|
664
|
+
Through `forgeqe mcp`, `post_pr_review` posts only when called again with `confirmed: true`; the MCP client should ask you first.
|
|
665
|
+
|
|
666
|
+
### Flaky tests
|
|
667
|
+
|
|
668
|
+
Every `run_tests` and `pr-tests` run keeps each test's result in `.forgeqe/test-history.json` in the repository (commit it to share the history, or keep it between CI runs as a cache). A test that fails runs once more in the same run, with the framework's own option (Playwright `--last-failed`, pytest `--lf`, Jest `--onlyFailures`; otherwise the whole command again when the selection is small): when it then passes it is **flaky**, not failed, and the run does not fail because of it.
|
|
669
|
+
|
|
670
|
+
"Which tests are flaky?" (`flaky_tests`) reads the history: each test's last results (`✓✗✓↻✓`, where ↻ means it passed only when run again), its pass rate, a flakiness score (passes on retry plus pairs of flip-flops in the last 20 runs), and the likely cause from its failure messages, with an example:
|
|
671
|
+
|
|
672
|
+
| Cause | From messages like |
|
|
673
|
+
|-------|--------------------|
|
|
674
|
+
| Timing | timeouts, waiting for an element, detached or stale elements |
|
|
675
|
+
| An overlay | another element intercepts the click, the element is covered or not visible |
|
|
676
|
+
| Data | expected one value, received another |
|
|
677
|
+
| Network | `net::ERR_…`, resets, 5xx responses |
|
|
678
|
+
| Environment | the browser closed or crashed, the server was not ready |
|
|
679
|
+
|
|
680
|
+
A test that only fails is broken, not flaky. **Quarantine** keeps a flaky test running, so its history goes on, but its failures stop failing the run and CI (`pr-tests --run` exits 0 when only quarantined tests fail); no test code changes. A quarantined test that passes 5 runs in a row is offered for release. The agent offers `quarantine_tests` (it asks you first) and `heal_tests` to fix the cause.
|
|
681
|
+
|
|
682
|
+
```yaml
|
|
683
|
+
flaky:
|
|
684
|
+
retries: 1 # runs of a failed test in the same run (0 to 3)
|
|
685
|
+
quarantine: suggest # suggest (the agent asks), auto (ForgeQE quarantines), or off (history only)
|
|
686
|
+
flaky_after: 2 # flakiness score from which a test counts as flaky
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
### API and contract tests
|
|
690
|
+
|
|
691
|
+
ForgeQE tests APIs directly too: REST, GraphQL, SOAP, and gRPC. API tests check the same logic as UI tests in a fraction of the time, and they do not break when the page changes. Contracts come from two places:
|
|
692
|
+
|
|
693
|
+
- **A browser run.** Every browser run records the application's own API calls (XHR, fetch, event streams) in `network.json` in the run folder: method, URL, status, timing, and the request and response bodies when they are JSON, XML, or text. Secrets never reach the file: `Authorization`, cookies, and API key headers are dropped (only the kind of auth is kept, e.g. bearer), and fields named like a password, token, key, session, or card number are redacted in bodies and query strings. Analytics and monitoring calls are left out. "Turn the last run's API calls into tests" (`api_contracts` from `run`) groups the calls into operations: one per method and path, with ids in paths turned into `{id}` (`GET /api/orders/{id}`), GraphQL by operation name, SOAP by action, gRPC-web by method. Several calls to one operation make a better contract: a field in every answer is required, a value that differs between calls is not pinned. No model is used.
|
|
694
|
+
- **An API description,** by link or file: OpenAPI 3 or Swagger 2 (JSON or YAML, or the Swagger UI page, which ForgeQE looks behind for the document), WSDL for SOAP, a GraphQL endpoint (read by introspection) or an SDL or introspection file, `.proto` files, or `grpc://host:port` for a gRPC server with reflection (through [grpcurl](https://github.com/fullstorydev/grpcurl)). Each operation gets an example call from the description's examples; values it gives no example for are made up and the contract is marked as needing real values.
|
|
695
|
+
|
|
696
|
+
Each contract has one example call and what its answer must have: the **status**, the **content type**, the body's **schema**, and **key fields** (ids, statuses, names, totals: present, with their type; a value only where it does not change between calls, like a status). GraphQL answers must have no `errors`; SOAP answers no `Fault` and the expected elements; gRPC calls the OK status. Contract sets are saved in `.forgeqe/reports/api/<id>/`: `contracts.json` (edit the examples freely, e.g. to give real ids) and `api.md`.
|
|
697
|
+
|
|
698
|
+
Then:
|
|
699
|
+
|
|
700
|
+
- **Run them now** (`run_api_contracts`, or `forgeqe api run`): ForgeQE makes each call and checks the answer, without a browser or a model. Calls that change data (POST, PUT, PATCH, DELETE, mutations, SOAP and gRPC calls not named like reads) are left out unless you allow them, on a test environment; the agent asks first. Calls with made-up values are skipped until you give real ones. Results go to `results.json` and `junit.xml`; a 401 or 403 says which header the call needs.
|
|
701
|
+
- **Write them as tests** (`write_api_tests`, or `forgeqe api tests`): Scribe writes them in the repository's own framework and HTTP client (Playwright's `request` fixture, pytest with requests, REST Assured, RestSharp or HttpClient, supertest...) with the base URL from configuration and credentials from environment variables, and ForgeQE runs them until they pass.
|
|
702
|
+
|
|
703
|
+
Credentials for API calls go in `forgeqe.yaml`, as references to environment variables; the values are sent, never stored or shown to a model:
|
|
704
|
+
|
|
705
|
+
```yaml
|
|
706
|
+
api:
|
|
707
|
+
capture: true # record the application's API calls in every browser run (default)
|
|
708
|
+
base_url: https://staging.shop.example # where contracts run when not where they were recorded or described
|
|
709
|
+
headers:
|
|
710
|
+
Authorization: Bearer ${API_TOKEN}
|
|
711
|
+
X-Tenant: ${API_TENANT}
|
|
712
|
+
third_party: false # keep calls to other sites than the page's (sign-in providers, CDNs)
|
|
713
|
+
timeout_seconds: 30
|
|
714
|
+
```
|
|
715
|
+
|
|
716
|
+
```bash
|
|
717
|
+
forgeqe api contracts --spec https://petstore3.swagger.io/api/v3/openapi.json
|
|
718
|
+
forgeqe api contracts --run # the latest browser run's API calls
|
|
719
|
+
forgeqe api run --base-url https://qa.shop.example # exit 1 when a contract fails: a CI gate
|
|
720
|
+
forgeqe api tests --repo ../app # Scribe writes them as tests
|
|
721
|
+
```
|
|
722
|
+
|
|
723
|
+
### End-to-end API scenarios
|
|
724
|
+
|
|
725
|
+
A scenario is API calls in order, where later calls use values earlier answers gave: create a cart, add an item to `{{cartId}}`, place the order, read `{{orderId}}`. Each step has its own checks (status, schema, key fields). `{{$unique}}` is new on every run, for emails, usernames, and references that must not clash; `{{$uuid}}`, `{{$now}}`, and `{{$randomInt}}` are there too. Scenarios are saved in the contract set's `contracts.json` (edit them freely) and listed in `api.md`. There are four ways to make them (`api_scenarios`):
|
|
726
|
+
|
|
727
|
+
| From | How | Model |
|
|
728
|
+
|------|-----|-------|
|
|
729
|
+
| **A browser run** (`--run`) | The calls the application made, in order. A value an answer gave (an order id) that a later request sends, in its path, query, or body, becomes a variable: saved from that answer, used in that request. A GET made again (polling) is kept once. Emails and usernames sent to sign-up endpoints get `{{$unique}}`. The UI flow becomes the same flow at the API level. | no |
|
|
730
|
+
| **An API description** (`--spec`, or a saved set) | For each resource with an item path (`/pets` and `/pets/{petId}`): its **lifecycle** (create, read, update, read, delete, then read gives 404), **browsing** (the list, then its first item), the description's OpenAPI **links**, and **negative cases**: an id that does not exist gives 404, no credentials give 401 or 403, an empty body gives 400 or 422. The id comes from the links, else the field named like the path parameter, else `id`. | no |
|
|
731
|
+
| **Test cases** (`--cases ado:2238,jira:SHOP-12`) | One scenario per test case, planned by the model against the set's operations: the calls, the data, the values to carry, and the case's expected results as checks. Cases with nothing to test are left out with the reason (the same rules as the test case check). The scenario keeps its test case. | yes |
|
|
732
|
+
| **Plain English** (`--text "..."`) or a story | "Create a user, log in, add two items, check out, verify the order total." Planned the same way. | yes |
|
|
733
|
+
|
|
734
|
+
The planner only uses operations the set has: a step no operation does is listed as unmatched, never invented. Give it the API's operations with `--spec` (an OpenAPI or Swagger link or file) or a saved set; without a description, make contracts from a browser run first. Every plan is checked before it is saved (each operation exists, each variable is saved before it is used) and shown step by step; nothing runs until you run it.
|
|
735
|
+
|
|
736
|
+
`run_api_scenarios` (or `forgeqe api run-scenarios`) runs them against the API, without a browser or a model: each step in order, the values passed on, every step's checks. A failed step stops its scenario, and the scenario's **cleanup** steps (deleting what it created) run, those whose values exist. Scenarios that change data run only after you agree (in CI: `--allow-writes`), on a test environment. Results go to `scenario-results.json` and `scenarios-junit.xml`.
|
|
737
|
+
|
|
738
|
+
**On your existing API automation.** `write_api_tests` with `scenarios` (or `forgeqe api tests --scenarios`) has Scribe write each scenario as an end-to-end test in the repository, built on what is already there:
|
|
739
|
+
|
|
740
|
+
1. It maps the repository's API layer first: clients, request helpers, auth and base URL fixtures, data builders, schemas.
|
|
741
|
+
2. Each step calls the helper that already calls that operation; only operations without one get a new helper, in the same style.
|
|
742
|
+
3. It reuses helpers, never tests: a scenario never runs another test as a step, and sets up its own data.
|
|
743
|
+
4. A shared helper is only added to, never changed in a way its tests rely on. When Scribe changes one, ForgeQE also runs the tests that use it, and sends any failure back until both pass.
|
|
744
|
+
5. A scenario test for a test case is named after it and recorded in `.forgeqe/test-cases.json`, and set as the Azure DevOps test case's Associated Automation when write-back is on.
|
|
745
|
+
|
|
746
|
+
```bash
|
|
747
|
+
forgeqe api scenarios --run # the latest browser run's flow, chained
|
|
748
|
+
forgeqe api scenarios --spec https://shop.test/openapi.json # lifecycles, browsing, links, negative cases
|
|
749
|
+
forgeqe api scenarios --cases ado:2238,ado:2239 --spec openapi.yaml
|
|
750
|
+
forgeqe api scenarios --text "create a user, add two items, check out, the total is the sum" --spec openapi.yaml
|
|
751
|
+
forgeqe api run-scenarios --allow-writes --base-url https://qa.shop.test # exit 1 when one fails
|
|
752
|
+
forgeqe api tests --scenarios --repo ../api-tests # on the repo's existing helpers
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
### What a pull request impacts in the product
|
|
756
|
+
|
|
757
|
+
"What does PR 57 impact?" (or `analyze_pr_impact`) says which parts of the product a pull request touches and what to test, also when the product's code is in another repository than the tests. Run it from the automation repository; give `product_repo` (a local clone of the product) when you have one, or just the pull request's link.
|
|
758
|
+
|
|
759
|
+
- **Reading the pull request:** from a clone of the product repository (its diff, and its imports, so a change to a shared component counts for every page that uses it), or, without one, through the GitHub (`gh pr diff`) or Azure DevOps API (the changed files and their contents).
|
|
760
|
+
- **Work items:** the ones the pull request is linked to, up through feature and epic, with their Area Paths.
|
|
761
|
+
- **Pages:** the test ids, ids, labels, placeholders, button and link texts, and routes in the changed code, matched against page memory (every element ForgeQE met on each page of the application). A changed `data-testid="submit-order"` leads to every page that shows it; a changed route to the pages on that path; with a clone, a changed shared component to the page files that import it, then to their routes.
|
|
762
|
+
- **Tests:** in the automation repository, the tests that visit those pages (by path, page title, or a changed selector they use, directly or through a page object), the test cases they automate, and the stories those test cases test.
|
|
763
|
+
- **Manual tests:** the test cases of the impacted stories that no automated test covers yet.
|
|
764
|
+
|
|
765
|
+
ForgeQE's agent writes the impact report from this: the areas with their evidence and a risk, side effects the diff suggests, the automated and manual tests to run, and the areas with no test; `comment_on_pr` posts it on the pull request after you agree. Page memory is what ties code to pages, so the more of the application ForgeQE has run, the more it can tie; changed UI files it cannot tie to a page are listed. Backend-only changes are tied through their work items and the agent's reading of the diff.
|
|
766
|
+
|
|
767
|
+
### Tests for a pull request
|
|
768
|
+
|
|
769
|
+
"Run the tests for PR 42" (or `select_pr_tests`) picks the automated tests a pull request can break, so only those run:
|
|
770
|
+
|
|
771
|
+
- the test files it changes;
|
|
772
|
+
- the tests that import a changed file, following imports through page objects and helpers (JavaScript, TypeScript, Python);
|
|
773
|
+
- the tests that name a changed class or page object (every language, C# and Java included);
|
|
774
|
+
- the tests mapped in `.forgeqe/test-cases.json` to the test cases of the work items the pull request is linked to (Azure DevOps "Tested By").
|
|
775
|
+
|
|
776
|
+
Each test comes with why it was picked, and the changed files no test reaches are listed as a coverage gap. With a model, Scribe checks the candidates by reading the tests, adds tests that drive the changed behaviour through the UI, and gives the exact list and run commands; `run_tests` then runs them after you agree, and `post_pr_test_results` puts the results on the pull request (it asks first). The tests run from your working tree: check out the pull request's branch to run its versions of the tests.
|
|
777
|
+
|
|
778
|
+
In CI, without a model:
|
|
779
|
+
|
|
780
|
+
```bash
|
|
781
|
+
forgeqe pr-tests --base origin/main --run # exit 0: passed or nothing affected; 1: a test failed
|
|
782
|
+
forgeqe pr-tests 42 --run --post # and post the results on pull request 42
|
|
783
|
+
```
|
|
784
|
+
|
|
785
|
+
Without `--agent`, the impacted files run as they are; this builds the command for Playwright and pytest projects (for other frameworks add `--agent`, or run the listed files).
|
|
786
|
+
|
|
787
|
+
## 7. Test cases and suites
|
|
788
|
+
|
|
789
|
+
Test cases you already have can be run two ways. In the shell or with `forgeqe run`, ask in plain words ("run SHOP-12 and SHOP-14", "run test plan 12 suite 34", "run the cases in smoke.yaml") or paste the cases, and the agent works out the source. `forgeqe suite` takes explicit references and runs the same way every time, with no agent involved, which is what pipelines call. Each case is one goal: ForgeQE tells the agent to do the steps in order and to check every expected result, and the agent's verdict decides whether the case passed. A case with no steps (plain text, a Jira story) is run from its description.
|
|
790
|
+
|
|
791
|
+
### Where cases come from
|
|
792
|
+
|
|
793
|
+
```bash
|
|
794
|
+
forgeqe cases cases.yaml # list them
|
|
795
|
+
forgeqe cases cases.yaml --goal # and the exact goal each one runs
|
|
796
|
+
```
|
|
797
|
+
|
|
798
|
+
**Plain text.** A quoted string is one case: `forgeqe suite "Log in as the demo user and open Invoices"`.
|
|
799
|
+
|
|
800
|
+
**Text or Markdown file.** Each block between `---` lines is a case, its first line the title:
|
|
801
|
+
|
|
802
|
+
```
|
|
803
|
+
Search for hotels in Mumbai and check at least one result is shown
|
|
804
|
+
---
|
|
805
|
+
Open the Deals page
|
|
806
|
+
Check every deal has a price
|
|
807
|
+
```
|
|
808
|
+
|
|
809
|
+
**YAML or JSON.** A list, or `{cases: [...]}`:
|
|
810
|
+
|
|
811
|
+
```yaml
|
|
812
|
+
- id: SHOP-12
|
|
813
|
+
title: Valid login
|
|
814
|
+
url: https://staging.shop.test/login # start page (optional)
|
|
815
|
+
preconditions: [The demo user exists]
|
|
816
|
+
steps:
|
|
817
|
+
- action: Sign in as demo@shop.test
|
|
818
|
+
data: password from DEMO_PASSWORD
|
|
819
|
+
expected: The dashboard greets the user by name
|
|
820
|
+
- Open the Orders page # a step can be a plain string
|
|
821
|
+
group: Accounts # optional: area for the Coverage page (or suite, area)
|
|
822
|
+
requirements: [SHOP-3, SHOP-4] # optional: stories it covers (or refs)
|
|
823
|
+
```
|
|
824
|
+
|
|
825
|
+
**CSV.** Header row, then a row per case. A row with an empty id (or the id above) adds a step to that case:
|
|
826
|
+
|
|
827
|
+
```csv
|
|
828
|
+
id,title,url,action,expected
|
|
829
|
+
SHOP-12,Valid login,https://staging.shop.test/login,Sign in as demo,Dashboard shows
|
|
830
|
+
,,,Open Orders,Orders list shows
|
|
831
|
+
```
|
|
832
|
+
|
|
833
|
+
Columns: `id` (or `key`), `title` (or `name`, `summary`), `url`, `description`, `preconditions`, `tags`, `group` (or `suite`, `area`), `requirements` (or `refs`), `action` (or `step`), `data`, `expected` (or `expected_result`, `result`). Lists in a cell are separated by `;`.
|
|
834
|
+
|
|
835
|
+
**Gherkin.** Each `Scenario` in a `.feature` file is a case, and each `Examples` row of a `Scenario Outline` is its own case. `Background` steps come first, and `Then` steps are the expected results of the step before them.
|
|
836
|
+
|
|
837
|
+
**Azure DevOps.** Set the organization, and a PAT with Test Management and Work Items (read and write) in `ADO_PAT`. The MCP server is the whole organization. Leave `project` unset (or set it to `*` or `all`) and ForgeQE's own calls cover every project; set `project` only to limit those calls to one.
|
|
838
|
+
|
|
839
|
+
```yaml
|
|
840
|
+
sources:
|
|
841
|
+
azure_devops:
|
|
842
|
+
org_url: https://dev.azure.com/acme
|
|
843
|
+
# project: Shop # optional
|
|
844
|
+
```
|
|
845
|
+
|
|
846
|
+
`ado:123,456` reads test case work items: their steps and expected results (HTML turned into text), shared steps inlined, and one case per parameter row with `@param` values filled in. Work item ids are unique in the organization, so they do not need a project. `ado:plan=12` reads every suite in a test plan and `ado:plan=12/suite=34` one suite, with each test point's configuration. With no project configured, the plan is looked up in every project. `ado:project=Shop/plan=12` names one.
|
|
847
|
+
|
|
848
|
+
**Jira.** `jira:SHOP-1,SHOP-2` or `jira:jql=project = SHOP AND labels = e2e`. The summary is the title and the description holds the steps. Jira Cloud (`*.atlassian.net`) needs `JIRA_EMAIL` and an API token in `JIRA_API_TOKEN`; Server and Data Center use a personal access token in `JIRA_API_TOKEN`.
|
|
849
|
+
|
|
850
|
+
```yaml
|
|
851
|
+
sources:
|
|
852
|
+
jira:
|
|
853
|
+
url: https://acme.atlassian.net
|
|
854
|
+
```
|
|
855
|
+
|
|
856
|
+
**Xray.** `xray:SHOP-1`, `xray:jql=<query>`, or `xray:plan=SHOP-100` for a test plan's tests, with Xray's own steps, data, and expected results. Xray Cloud needs an API key pair in `XRAY_CLIENT_ID` and `XRAY_CLIENT_SECRET`. Xray Server and Data Center go through the Jira settings above.
|
|
857
|
+
|
|
858
|
+
**TestRail.** `testrail:C12,C13` reads cases by id, `testrail:run=45` the tests of a run (results go back to that run), `testrail:plan=7` every run in a plan, and `testrail:suite=3` a suite (needs `project_id`). Separated steps (`custom_steps_separated`) become steps with expected results; the text template's steps become one step. It needs the user's email in `TESTRAIL_EMAIL` and an API key in `TESTRAIL_API_KEY`.
|
|
859
|
+
|
|
860
|
+
```yaml
|
|
861
|
+
sources:
|
|
862
|
+
testrail:
|
|
863
|
+
url: https://acme.testrail.io
|
|
864
|
+
project_id: 1 # needed for suites, and to create a run for cases read by id
|
|
865
|
+
```
|
|
866
|
+
|
|
867
|
+
**Zephyr Scale (Cloud).** `zephyr:SHOP-T1,SHOP-T2`, `zephyr:cycle=SHOP-R5` (results go back to that cycle), or `zephyr:folder=12` (needs `project_key`). Call-to-test steps are inlined. It needs an API access token in `ZEPHYR_API_TOKEN`; setting the variable is enough to turn it on.
|
|
868
|
+
|
|
869
|
+
**qTest.** `qtest:1234` reads test cases by the id in their URL, `qtest:cycle=88` and `qtest:suite=9` the test runs under a cycle or suite (results go back to those runs). It needs `url`, `project_id`, and an API token in `QTEST_TOKEN`. Result statuses are the automation status names your qTest uses; the defaults are PASS, FAIL, and BLOCKED:
|
|
870
|
+
|
|
871
|
+
```yaml
|
|
872
|
+
sources:
|
|
873
|
+
qtest:
|
|
874
|
+
url: https://acme.qtestnet.com
|
|
875
|
+
project_id: 12345
|
|
876
|
+
statuses: { passed: PASS, failed: FAIL, error: BLOCKED }
|
|
877
|
+
```
|
|
878
|
+
|
|
879
|
+
Several sources can be mixed: `forgeqe suite smoke.yaml jira:SHOP-7 testrail:C12`.
|
|
880
|
+
|
|
881
|
+
**From requirements.** Ask the agent to test a Confluence page, a story, or a spec file ("write and run test cases for the refund rules page in Confluence"). It reads the requirements, writes one case per rule or acceptance criterion with the main negative paths, shows them, and runs them as text cases. It saves them into a test system only when you ask. Confluence needs `sources.confluence`:
|
|
882
|
+
|
|
883
|
+
```yaml
|
|
884
|
+
sources:
|
|
885
|
+
confluence: true # the wiki on the Jira Cloud site above, same account
|
|
886
|
+
# or
|
|
887
|
+
confluence:
|
|
888
|
+
url: https://confluence.acme.com # Cloud: https://acme.atlassian.net/wiki
|
|
889
|
+
token_env: CONFLUENCE_TOKEN # Server/DC personal access token; Cloud also email_env
|
|
890
|
+
space: QA # optional: keep searches in one space
|
|
891
|
+
```
|
|
892
|
+
|
|
893
|
+
### Running
|
|
894
|
+
|
|
895
|
+
```bash
|
|
896
|
+
forgeqe suite cases.yaml # one case at a time
|
|
897
|
+
forgeqe suite ado:plan=12 --parallel 3 # three browsers at once
|
|
898
|
+
forgeqe suite cases.yaml --repo ../app # passed cases get a test in ../app
|
|
899
|
+
forgeqe suite cases.yaml --no-code --no-write-back --out .forgeqe/reports/smoke
|
|
900
|
+
```
|
|
901
|
+
|
|
902
|
+
```yaml
|
|
903
|
+
suite:
|
|
904
|
+
parallel: 1 # browsers at once
|
|
905
|
+
code: true # with a repo set, passed cases go to Scribe
|
|
906
|
+
out_dir: ./.forgeqe/reports/suites
|
|
907
|
+
```
|
|
908
|
+
|
|
909
|
+
Browser runs happen `parallel` at a time and share page memory safely. Each passed case goes to the coding agent as soon as its own browser run ends, and its test is written and run before that browser slot starts the next case: explore, hand off, code, next case. Coding jobs run one after another, so two never edit the repo at once. A case with no test says why in the report (it failed, or no model is set up). With `--parallel` above 1, each line of output starts with the case id. Ctrl-C stops the suite: cases already running finish closing their browsers, and cases that never started are reported as not run.
|
|
910
|
+
|
|
911
|
+
At the end, ForgeQE prints the result of every case and writes to `.forgeqe/reports/suites/<time>/`:
|
|
912
|
+
|
|
913
|
+
- `report.html`: a single file with every screenshot embedded; open it from disk, no server needed. Its pages:
|
|
914
|
+
- **Overview**: the verdict, totals, step checks, browser steps, tokens, cost, what page memory saved, browser errors, accessibility issues, tests written and bugs filed; what changed since the last run; results over the earlier runs in `.forgeqe/reports/suites/`; the cases that need attention and why; results by source and by tag; the slowest cases; and what was posted where.
|
|
915
|
+
- **Test Results**: search and filter the cases. For each case: its step table (action, expected, the agent's verdict, what it actually saw), why it failed (the failed step, the agent's last evaluation, failed actions, the screenshot), **last good vs now** (the same page from the case's last passing run beside this run's, and where their browser steps start to differ), the browser errors per step (console errors, uncaught exceptions, failed and slow requests), page memory (steps replayed, tokens and time saved against the last run where the agent took every step, locators that healed, flows repaired), the browser agent's steps (goal, actions, errors, time and model time, a screenshot each with the element it acted on outlined), a timing waterfall (waiting for the model, acting in the browser, replayed from memory), the accessibility issues of each page, a screenshot gallery, and its trace, workflow and handoff to read in place. Run history links to earlier reports.
|
|
916
|
+
- **Failures**: each failed case with what the agent reported, the evidence (including browser errors), its last passing screenshot, its bug, and text to copy into a bug report.
|
|
917
|
+
- **Since Last Run**: new failures, fixes, cases still failing, cases at least 5 s and 25% slower or faster, and new or dropped cases, against the previous run in the folder.
|
|
918
|
+
- **Trends** and **Flaky Tests**: pass rate, outcomes, duration, tokens and cost per run; cases whose result keeps changing, and cases that started failing. Both need earlier suite runs in the same folder.
|
|
919
|
+
- **Time & Cost**: where the time went (model, browser, page memory), a timeline of the cases on each parallel worker, page memory savings per case, and tokens and cost per case.
|
|
920
|
+
- **Coverage**: results by requirement (a requirement fails when any case covering it fails), by group, by tag and by source. Groups and requirements come from the source: the area path in Azure DevOps, the section and refs in TestRail, the folder in Zephyr Scale, components (or the parent issue) and "tests" links in Jira, and `group` / `requirements` in case files.
|
|
921
|
+
- **Accessibility**: the WCAG rules of the standard you chose, checked by axe-core on every page the agent visited: the rules that passed, each rule that failed with its success criterion, level, impact, the elements and a link to how to fix it, and any accessibility budget exceeded. Automated checks are a pre-check, not conformance.
|
|
922
|
+
- **Visual**: every page against its approved baseline: baseline, this run, and the difference side by side, changed pages first, with the share of pixels changed and the visual budget.
|
|
923
|
+
- **Performance**: each page's Core Web Vitals (LCP, CLS, INP, FCP, TTFB) and load time, coloured good / needs improvement / poor by Google's thresholds, with the budgets each page went over.
|
|
924
|
+
- **Environment**: model, browser, the model's price, start URL, ForgeQE version, machine, CI build, branch, commit, and the sites visited.
|
|
925
|
+
|
|
926
|
+
It exports Markdown and JSON and prints cleanly. Up to 40 MB of screenshots are embedded, failed cases first; beyond that they load from the run folders next to the report.
|
|
927
|
+
- `junit.xml`: for CI test reporting; a failed case is a `<failure>`, a crash an `<error>`, a case not run `<skipped>`; step verdicts are in `system-out`
|
|
928
|
+
- `suite.json`: everything above as data
|
|
929
|
+
- `01-SHOP-12/`, `02-…`: each case's normal run folder (with its own `report.html`, `steps.json`, and `steps/NN.jpg` screenshots), plus `testcase.json`
|
|
930
|
+
|
|
931
|
+
```yaml
|
|
932
|
+
report:
|
|
933
|
+
screenshots: all # all | failures (only failed runs keep step screenshots) | off
|
|
934
|
+
accessibility: true # check each page the agent visits; false skips the checks
|
|
935
|
+
```
|
|
936
|
+
|
|
937
|
+
Bugs filed for failed cases list the run's console errors and failed requests under "Browser errors".
|
|
938
|
+
|
|
939
|
+
Exit codes: `0` every case passed (and every test written for them passes), `1` anything failed, `2` stopped.
|
|
940
|
+
|
|
941
|
+
### Results back in the source
|
|
942
|
+
|
|
943
|
+
Test cases the agent writes from an Azure DevOps or Jira story are saved there with `save_test_cases`, linked to the story, and the reply lists them as links; set `sources.save_cases: false` to keep them in the reply only. Replies in the shell render as markdown (headings, lists, tables, links).
|
|
944
|
+
|
|
945
|
+
With `sources.write_back: true` (the default), results go back after the suite:
|
|
946
|
+
|
|
947
|
+
- **Azure DevOps plan:** a completed test run for the plan with each test point's outcome and the agent's summary as the comment. Cases read by id get a comment on the work item instead.
|
|
948
|
+
- **Jira:** a comment on each issue with the result, the summary, where the run ended, and the test file if one was written.
|
|
949
|
+
- **Xray:** one Test Execution per test plan (linked to the plan), with each test's status, step statuses and actual results, the summary, and the failure screenshot as evidence.
|
|
950
|
+
- **TestRail:** results in the run the cases came from, or a new run per suite for cases read by id, with step results and the failure screenshot attached.
|
|
951
|
+
- **Zephyr Scale:** a test execution per case with step results, in the cycle the cases came from or a new cycle per project.
|
|
952
|
+
- **qTest:** an automation test log per case with step logs, on the test run it came from, or on new test runs in a new test cycle.
|
|
953
|
+
|
|
954
|
+
Every comment and result includes the step verdicts. If a system rejects the step details (a TestRail project without separated steps, say), ForgeQE posts the result again without them rather than losing it. Stopped cases are never posted. `--no-write-back` skips it for one suite.
|
|
955
|
+
|
|
956
|
+
### Bugs for failures
|
|
957
|
+
|
|
958
|
+
```yaml
|
|
959
|
+
sources:
|
|
960
|
+
bugs:
|
|
961
|
+
system: jira # or azure_devops
|
|
962
|
+
project: SHOP # Jira project key; Azure DevOps uses azure_devops.project
|
|
963
|
+
type: Bug # issue type or work item type
|
|
964
|
+
labels: [forgeqe] # Jira labels or Azure DevOps tags
|
|
965
|
+
# area_path: Shop\Web # Azure DevOps
|
|
966
|
+
# on_error: true # also for cases that could not run
|
|
967
|
+
```
|
|
968
|
+
|
|
969
|
+
When results are posted, each case that failed with a functional defect (below) gets a bug: the title is `[ForgeQE] <case id>: <title>`, the description has the result, the steps with verdicts, the preconditions, where the run ended, the build link, and the run folder, and the last screenshot is attached. In Jira the bug is linked to the Jira or Xray test ("relates to"); in Azure DevOps it is "tested by" the test case work item. Each bug carries a label or tag that fingerprints the case (`forgeqe-` and ten hex digits), so the next failure comments "Still failing" on the open bug instead of filing a new one, and a pass adds a note that it passes again. Closed bugs are left alone; a new failure after that files a new bug.
|
|
970
|
+
|
|
971
|
+
|
|
972
|
+
### Checking test cases before they run
|
|
973
|
+
|
|
974
|
+
`run_test_cases` checks the cases before it runs them, and `check_test_cases` checks them without running anything ("are these test cases ready?", "check test plan 12 against its stories"). A check uses everything ForgeQE can know about a case:
|
|
975
|
+
|
|
976
|
+
| Source | What it finds | Cost |
|
|
977
|
+
|--------|---------------|------|
|
|
978
|
+
| Rules on the case's text | No steps or expected results; vague expected results ("works correctly", "submitted successfully"); steps that need values the case does not give ("enter valid user details"); placeholders (`TBD`, `<username>`); passwords in the case; several actions in one step; no start page; duplicate cases | None |
|
|
979
|
+
| Page memory | Steps that name a field or control earlier runs never saw on that page ("email" on a form that has no email field), with what the page does have | None |
|
|
980
|
+
| The requirements it tests | Azure DevOps: the story or PBI the case tests ("Tests" link), then its feature and epic, with descriptions and acceptance criteria. Jira: the issues the test is linked to, then their parents | A few API calls, each requirement read once per check |
|
|
981
|
+
| Linked documents | Confluence pages linked from the case or its requirements | A few API calls |
|
|
982
|
+
| A RAG service (optional) | Passages your own search finds for the case | Your service |
|
|
983
|
+
|
|
984
|
+
Each case is **ready**, **to review**, or **not runnable**, shown as a card with what it tests (`tests PBI 2211 "Contact Us form" ← Feature 300 ← Epic 12`) and the acceptance criteria no step seems to cover. ForgeQE's agent then judges each case against its requirements: criteria no step covers, steps no requirement asks for, expected results that contradict the requirement, controls the application does not have. The check before a run uses the rules and page memory only (no reads); `check_test_cases` with `depth: quick` does the same.
|
|
985
|
+
|
|
986
|
+
**RAG, plug and play.** Point `forgeqe.yaml` at any search service over your requirements (Confluence, a wiki, specs) and the check adds its passages:
|
|
987
|
+
|
|
988
|
+
```yaml
|
|
989
|
+
rag:
|
|
990
|
+
url: http://localhost:8080/search # POST {"query": "...", "top_k": 5}; answers a list of {text, source, score}
|
|
991
|
+
token_env: RAG_TOKEN # optional, sent as a bearer token
|
|
992
|
+
top_k: 5
|
|
993
|
+
# or a local command: gets {"query", "top_k"} on stdin, prints the list on stdout
|
|
994
|
+
# rag:
|
|
995
|
+
# command: ["python", "rag/search.py"]
|
|
996
|
+
```
|
|
997
|
+
|
|
998
|
+
The answer can also be an object with `results`, `passages`, `documents`, or `hits`, and a passage's text can be `text`, `content`, or `page_content` (LangChain's shape). A RAG server with an MCP interface works through `mcp:` instead: ForgeQE's agent calls its tools.
|
|
999
|
+
|
|
1000
|
+
`suite.case_check` decides what happens before a run: `warn` (the default) shows the findings and runs every case, `block` leaves out the cases that cannot run as written, `off` skips the check.
|
|
1001
|
+
|
|
1002
|
+
When a run finds a test case does not fit the application, the agent drafts the steps as they should be, from what the run found, and offers to save them. `update_test_case` shows the current and the new steps and asks before it changes the Azure DevOps Test Case; the reason goes into the work item's history, where the old steps stay.
|
|
1003
|
+
|
|
1004
|
+
### Exploratory testing from a story
|
|
1005
|
+
|
|
1006
|
+
"Explore story 1234" (or `forgeqe explore ado:1234`) tests a story's feature beyond its scripted test cases, in real browsers:
|
|
1007
|
+
|
|
1008
|
+
1. **Reads the story:** description and acceptance criteria, the feature and epic above it, the test cases that already script it (Azure DevOps "Tested By", Jira test links), and passages from the requirements search when one is set up. A Jira key, a link, or the story's text with its acceptance criteria works too.
|
|
1009
|
+
2. **Plans charters** (6 by default, `--charters N`, at most 12), each with a mission, concrete steps and data, and an expected result per step: other paths and valid data, edge cases (empty, long, special characters, duplicates), invalid input, the boundaries the story states, **role differences**, state (refresh, back, double submit, a second tab, an expired session), and what must not happen. Expected results come from the acceptance criteria; where the story says nothing, from what a well-behaved application does, and the charter says so. Nothing irreversible beyond test data is planned, and charters that create or change data are marked. You see the charters and choose to run them all, only those that change no data, or none.
|
|
1010
|
+
3. **Explores:** each charter is a browser run, and the browser agent judges each expected result on the page and lists anything else that looks wrong. **Roles** are your saved logins (`logins:` in `forgeqe.yaml`; by default every one when there are two or more, or `--roles admin,viewer`): a role's charter signs in with only that role's login on the site.
|
|
1011
|
+
4. **Confirms:** a charter that finds a functional defect runs a second time. It counts as a **confirmed defect** only when it fails the same way again. The failure classification decides what is a defect: an environment problem (run once more), a test that could not be done, or a charter that does not fit the application are reported as "could not explore", not as defects.
|
|
1012
|
+
5. **Reports** in `.forgeqe/reports/explore/<id>/exploration.md` (and `.json`): each charter's result, the confirmed defects with both runs' evidence, and **observations**: defects that did not reproduce, browser errors (failed requests, console errors), and what the agent noticed beyond the steps. Observations are never filed as bugs.
|
|
1013
|
+
6. **Bugs for confirmed defects only**, through the bug tracker set up under `bugs:` (Jira or Azure DevOps), after you agree (`--file-bugs` where nobody can be asked). A bug filed before for the same charter gets a comment instead of a duplicate.
|
|
1014
|
+
7. **Proposed test cases:** the charters that ran clean become regression cases, and each confirmed defect becomes a case that checks the correct behaviour (it fails until the defect is fixed). The agent offers to save the ones you pick to the story (`save_test_cases`).
|
|
1015
|
+
|
|
1016
|
+
```bash
|
|
1017
|
+
forgeqe explore ado:1234 --url https://staging.shop.example/orders
|
|
1018
|
+
forgeqe explore SHOP-12 --charters 8 --roles shop_admin,shop_viewer --focus "the address form"
|
|
1019
|
+
forgeqe explore "Change the delivery address
|
|
1020
|
+
Customers can change the address of an open order.
|
|
1021
|
+
Acceptance criteria:
|
|
1022
|
+
- Postcode is required and validated" --url https://staging.shop.example
|
|
1023
|
+
```
|
|
1024
|
+
|
|
1025
|
+
Each charter is a browser run (two for a possible defect), so a session takes several minutes and costs about as much as running that many test cases. `forgeqe explore` exits 1 when a defect is confirmed.
|
|
1026
|
+
|
|
1027
|
+
### Accessibility and performance budgets
|
|
1028
|
+
|
|
1029
|
+
Every browser run checks each page it visits and times it, with no extra step:
|
|
1030
|
+
|
|
1031
|
+
- **Accessibility:** [axe-core](https://github.com/dequelabs/axe-core) (installed with ForgeQE) runs the rules of the standard you choose on each page as the agent finds it. The report lists the rules that **passed** and each rule that **failed**, with its WCAG success criterion and level, its impact (critical, serious, moderate, minor), the elements, and how to fix it. Automated checks find a part of the WCAG problems (often 30–50%): they are a pre-check, not conformance, and a manual review still matters. `quality.accessibility.engine: basic` uses ForgeQE's own smaller set of checks instead.
|
|
1032
|
+
- **Performance:** each page's Core Web Vitals, measured in the browser the agent drives: **LCP** (largest contentful paint), **CLS** (layout shift), **INP** (the slowest interaction the agent made), **FCP**, **TTFB**, load time, requests and transfer size. These are lab values from one visit, not field data from real users.
|
|
1033
|
+
|
|
1034
|
+
A run **fails on them only when a budget is exceeded**. Without budgets they are reported and tracked, never failed. When a budget is exceeded, the run's steps still passed: `forgeqe run` exits 1, the browser run says `budget_exceeded`, a suite case counts as failed (a bug is filed when bugs are set up), and a test is still written for the flow.
|
|
1035
|
+
|
|
1036
|
+
```yaml
|
|
1037
|
+
quality:
|
|
1038
|
+
accessibility:
|
|
1039
|
+
standard: wcag21aa # wcag2a, wcag21aa (default), wcag22aa, wcag21aaa, section508, en301549, best-practice
|
|
1040
|
+
best_practice: false # also axe-core's best-practice rules
|
|
1041
|
+
budgets:
|
|
1042
|
+
accessibility: # most violations per page by impact; unset impacts have no limit (or: accessibility: true for 0 critical, 0 serious)
|
|
1043
|
+
critical: 0
|
|
1044
|
+
serious: 0
|
|
1045
|
+
rules: [color-contrast, label] # must pass everywhere
|
|
1046
|
+
ignore: [region] # not counted
|
|
1047
|
+
performance: # or: performance: web-vitals (LCP 2.5s, CLS 0.1, INP 200ms, FCP 1.8s, TTFB 800ms)
|
|
1048
|
+
preset: web-vitals
|
|
1049
|
+
lcp_ms: 3000
|
|
1050
|
+
load_ms: 5000
|
|
1051
|
+
pages: # by path prefix; the longest match wins
|
|
1052
|
+
/search: { lcp_ms: 4000 }
|
|
1053
|
+
```
|
|
1054
|
+
|
|
1055
|
+
**Over time:** every run adds each page's violations and timings to `.forgeqe/reports/quality-history.json` (keep it between CI runs as a cache). "Did accessibility regress?" or "is checkout getting slower?" (`quality_trends`, or `forgeqe quality trends [page]`) shows each page's violations over the last runs, the rules that newly fail or were fixed since the previous run, and each timing against its usual value (the median of the last 10 runs; slower or faster only beyond noise). `forgeqe quality [run]` (`quality_report`) shows one run's WCAG results, timings and budgets.
|
|
1056
|
+
|
|
1057
|
+
```bash
|
|
1058
|
+
forgeqe quality # the latest run: WCAG rules passed and failed, Core Web Vitals, budgets
|
|
1059
|
+
forgeqe quality trends shop.test # per page over time; exits 1 when a page got worse
|
|
1060
|
+
```
|
|
1061
|
+
|
|
1062
|
+
### Visual comparison
|
|
1063
|
+
|
|
1064
|
+
Every browser run also captures each page it visits and compares it, pixel by pixel, with that page's **approved baseline**:
|
|
1065
|
+
|
|
1066
|
+
- **Capture:** the state the flow leaves each page in, with animations and transitions frozen, the text caret hidden, and the regions you mask hidden (their space kept), so a page compares on what changed, not on what moves. ForgeQE's own overlay is never in the picture. The viewport by default; `full_page: true` captures the whole page (up to 8000 px tall).
|
|
1067
|
+
- **Baselines:** in `.forgeqe/visual-baselines/` next to `forgeqe.yaml` (commit them to share), one per page, screen size and operating system, since fonts render differently. A page's **first capture becomes its baseline** (`auto_baseline: false` turns that off), and `baselines.json` records which run each baseline came from and why.
|
|
1068
|
+
- **Compare:** each page is **same**, **changed** (the share of pixels that differ, and a diff image with the changed pixels in red), or **new**. Anti-aliasing is ignored; `threshold` sets how different two colours must be to count. A taller or wider page counts its new area as changed.
|
|
1069
|
+
- **Budget:** a run **fails only when `quality.budgets.visual` is set** and a page changes by more than that share of its pixels (a page can have its own limit). Without it, changes are reported, never failed.
|
|
1070
|
+
- **Approve:** when a change is intended, "approve the new home page" (`visual_approve`, or `forgeqe visual approve [run] --page /home`) makes the run's capture the new baseline, after you agree. An unintended change is a visual defect.
|
|
1071
|
+
|
|
1072
|
+
The report's **Visual** page shows the baseline, this run, and the difference side by side for every page, changed pages first; click any image to see it full size.
|
|
1073
|
+
|
|
1074
|
+
```yaml
|
|
1075
|
+
quality:
|
|
1076
|
+
visual:
|
|
1077
|
+
mask: [".clock", "#ad-slot", "[data-testid=carousel]"] # hidden on every page
|
|
1078
|
+
pages:
|
|
1079
|
+
/news: { mask: [".ticker"], max_diff_percent: 5 } # by path prefix
|
|
1080
|
+
full_page: false
|
|
1081
|
+
threshold: 0.1 # colour difference that counts (0–1)
|
|
1082
|
+
auto_baseline: true
|
|
1083
|
+
budgets:
|
|
1084
|
+
visual: 0.5 # most a page may change, in percent of its pixels (or: visual: true for 0.1%)
|
|
1085
|
+
```
|
|
1086
|
+
|
|
1087
|
+
```bash
|
|
1088
|
+
forgeqe visual # the latest run's pages against their baselines
|
|
1089
|
+
forgeqe visual approve --page /home # make this run's /home the baseline (asks first; --yes to skip)
|
|
1090
|
+
```
|
|
1091
|
+
|
|
1092
|
+
### Requirement coverage and release readiness
|
|
1093
|
+
|
|
1094
|
+
"Are we ready to release sprint 12?", "coverage of epic 300" (or `release_readiness`) builds the coverage matrix for an Azure DevOps scope: a sprint (`current` or a name), an area path, an epic or feature and every story under it, or story ids.
|
|
1095
|
+
|
|
1096
|
+
- **Each story** with the test cases that test it ("Tested By"), whether each is automated (Automation status, or `.forgeqe/test-cases.json`), and its last result: the newest test point outcome in Azure DevOps, or, where no plan has run it, ForgeQE's own runs (suite reports, then the automated test's history).
|
|
1097
|
+
- **Gaps:** stories with no test case, test cases nobody automated, cases that have not run.
|
|
1098
|
+
- **Open bugs** in the scope and linked to its stories, by severity.
|
|
1099
|
+
- **Flaky and quarantined tests** from the test history.
|
|
1100
|
+
- **The verdict:** NO-GO when something blocks (open critical or high bugs past the limit, a story with a failing test case, the pass rate below the minimum), GO WITH RISKS when something is missing (stories without test cases, cases not run or blocked, flaky or quarantined tests, other open bugs), else GO; each with its reasons.
|
|
1101
|
+
|
|
1102
|
+
The report is saved as `readiness.md` (and `readiness.json`) under `.forgeqe/reports/readiness/`, shown as a card, and published to the project wiki with `publish: "/Release readiness/Sprint 12"` after you agree. The agent can also build an Azure DevOps dashboard for it with `create_ado_dashboard`.
|
|
1103
|
+
|
|
1104
|
+
```yaml
|
|
1105
|
+
release:
|
|
1106
|
+
max_critical: 0 # open severity-1 bugs allowed
|
|
1107
|
+
max_high: 0 # open severity-2 bugs allowed
|
|
1108
|
+
min_pass_rate: 95 # percent of executed test cases that must pass
|
|
1109
|
+
require_tests: true # a story without a test case is a risk
|
|
1110
|
+
```
|
|
1111
|
+
|
|
1112
|
+
### When a case fails
|
|
1113
|
+
|
|
1114
|
+
The browser run of a test case is the test, so when a case does not pass, ForgeQE works out what kind of failure it was and acts on it. The browser agent reports a cause for each failed step (it saw the page); clear evidence in the run, such as an unreachable site or a 503 page, overrides "I could not operate it".
|
|
1115
|
+
|
|
1116
|
+
| Failure | What it means | Bug | Automation script |
|
|
1117
|
+
|---------|---------------|-----|-------------------|
|
|
1118
|
+
| Functional defect | Every step was done and the application behaves wrong (a wrong total, no confirmation) | Filed straight away | Written for the correct behaviour (the test case's expected results) and marked as an expected failure naming the bug: Playwright `test.fail()`, pytest `xfail(strict=True)`. It passes while the defect is there and fails once it is fixed, telling you to remove the marker |
|
|
1119
|
+
| Test case needs updating | The test case does not fit the application (a field or page it names is not there) | No | No: update the test case. The report and the comment on the test case say what the application shows instead |
|
|
1120
|
+
| Environment problem | The application or something it needs was unavailable (an error page, a 5xx, a network failure, sign-in or test data missing, a bot check) | No | No. The case runs once more straight away; if it still fails, check the environment first |
|
|
1121
|
+
| Automation problem | A control that is there could not be operated, or the run ran out of steps | No | Not yet: page memory keeps the steps that worked and the next run resumes from them |
|
|
1122
|
+
|
|
1123
|
+
In Azure DevOps a test plan point is recorded as Blocked, not Failed, for the last three, so the plan's failures are product defects, and the comment on the test case names the kind of failure.
|
|
1124
|
+
|
|
1125
|
+
**Tests that need attention.** A coding job that ends without a passing, approved test does not leave a failing test among your tests. The files it created move to a `needs-attention/<case id>/` folder beside the test, with their relative imports fixed, and a README says which test case it is for, why it stopped (the last failure, the reviewer's issues), and how to pick it up; `needs-attention/README.md` lists them all. The job's edits to files that were committed before it are saved as `changes.patch` in that folder and taken out of the files; files you had already changed are left as they are. The folder is kept out of test runs and builds: Playwright's config gets `testIgnore: ['**/needs-attention/**']`, TypeScript files a `// @ts-nocheck` line, a Python folder a `conftest.py` that collects nothing, and C#, Java, or Kotlin files a `.txt` suffix. `code.needs_attention: false` leaves unfinished tests where they are.
|
|
1126
|
+
|
|
1127
|
+
**Running a case again.** A case that already has a test (in `.forgeqe/test-cases.json`) does not get a new one: after its browser run, ForgeQE runs the existing test first. When it passes, there is no coding job at all. When it fails, the coding agent updates that test (with the failure and the new verified run) instead of writing one from scratch. A known-defect test whose defect is fixed (the case now passes) is updated to drop its expected-failure marker; a test that passes although the run found a defect gets the defect's assertion and the marker.
|
|
1128
|
+
|
|
1129
|
+
**Mapping tests to test cases.** Each test written for a test case is named `<case id> <title>` and tagged with the case id and link in the framework's own way (Playwright tags and annotations, a pytest marker, an NUnit property). `.forgeqe/test-cases.json` in the repository maps every test case to its test, with its status (`automated`, `known_defect` with the bug, or `needs_attention` with the folder); commit it with the tests. For Azure DevOps test cases, a passing test is also set as the work item's Associated Automation (test name, file, type, and a stable id, with Automation status Automated), so the test plan shows the case as automated.
|
|
1130
|
+
|
|
1131
|
+
### Signing in
|
|
1132
|
+
|
|
1133
|
+
```yaml
|
|
1134
|
+
logins:
|
|
1135
|
+
shop:
|
|
1136
|
+
url: https://staging.shop.test/login # or domains: [https://staging.shop.test, https://*.shop.test]
|
|
1137
|
+
username_env: SHOP_USER
|
|
1138
|
+
password_env: SHOP_PASSWORD
|
|
1139
|
+
totp_env: SHOP_TOTP_SECRET # optional: the authenticator secret (base32), for 2FA codes
|
|
1140
|
+
# save_session: false # sign in on every run
|
|
1141
|
+
```
|
|
1142
|
+
|
|
1143
|
+
The browser agent is told which placeholders exist (`shop_username`, `shop_password`, `shop_bu_2fa_code`) and types them; the engine swaps in the real values only on the matching domains and masks them in everything the model sees. For TOTP, a fresh code is computed at the moment it is typed. After each step ForgeQE saves the site's cookies and local storage to `.forgeqe/sessions/<name>.json` (private to your user, with its own `.gitignore`), and the next run starts signed in.
|
|
1144
|
+
|
|
1145
|
+
Page memory records the variable names, not the values, so replays type the current values and fresh codes, and tests the coding agent writes read `SHOP_PASSWORD` from the environment.
|
|
1146
|
+
|
|
1147
|
+
**Credentials in a message or test case.** Paste a test case that says "log in as svc@corp.test with password …" and you do not need `logins:` at all. Before the first browser run, ForgeQE's agent remembers the credentials as a login for that site and its sign-in hosts (for Dynamics, the CRM host and `login.microsoftonline.com`). From then on:
|
|
1148
|
+
|
|
1149
|
+
- goals say "sign in with the saved login dynamics" and never contain the password, so it is not in `run.json`, `trace.md`, `report.html`, or `workflow.yaml`;
|
|
1150
|
+
- the browser agent types the exact value from a placeholder, so quotes or a full stop around the password in the test case cannot end up in the password field;
|
|
1151
|
+
- the signed-in session is saved in `.forgeqe/sessions/`, so follow-up runs ("now open the latest case") start signed in;
|
|
1152
|
+
- tests Scribe writes read `FORGEQE_<NAME>_USERNAME` and `FORGEQE_<NAME>_PASSWORD`, and ForgeQE sets them when it runs those tests in this session.
|
|
1153
|
+
|
|
1154
|
+
ForgeQE keeps the values in memory for the session only: it does not write them to disk or put them in the agent runtime's environment. Your message itself is still part of the conversation, which the agent runtime keeps locally like any chat, and which the model provider receives. Close ForgeQE and the remembered values are gone (the saved session stays until it expires or you clear it). Ask "which logins do I have?" to see them, or "forget the dynamics login" to drop them. For pipelines and later sessions, use `logins:` with environment variables.
|
|
1155
|
+
|
|
1156
|
+
Single sign-on, captchas, and security keys need a person: `forgeqe login shop` opens a browser on the login page, you sign in, press Enter in the terminal, and the session is saved. `forgeqe logins` lists logins, which variables are missing, and when each session was saved; `forgeqe logins clear shop` (or `--all`) forgets sessions. In the shell, "sign in to shop" does the same: the browser opens, a **Your turn** prompt waits while you sign in, and **Done, continue** saves the session. `forgeqe run` asks you to press Enter instead, and `forgeqe mcp` cannot wait for a person, so it tells the calling agent to have you run `forgeqe login shop`. In a pipeline, set the login variables as secrets.
|
|
1157
|
+
|
|
1158
|
+
### In the shell
|
|
1159
|
+
|
|
1160
|
+
Ask for the cases in plain words, for example "run SHOP-12 and SHOP-14, two at a time" or "show me what's in test plan 12 without running it". The transcript shows each case's steps as it runs, and a suite card at the end:
|
|
1161
|
+
|
|
1162
|
+
```
|
|
1163
|
+
┃ ✗ Suite failed 1/2 passed · 1m 12s · 48.2K tokens
|
|
1164
|
+
┃
|
|
1165
|
+
┃ ✓ SF-1 Search Mumbai 38s
|
|
1166
|
+
┃ ✗ SF-2 Open a hotel 34s
|
|
1167
|
+
┃ No hotel link on the results page
|
|
1168
|
+
┃
|
|
1169
|
+
┃ Report .forgeqe/reports/suites/20260928-215438/report.html
|
|
1170
|
+
┃ JUnit .forgeqe/reports/suites/20260928-215438/junit.xml
|
|
1171
|
+
```
|
|
1172
|
+
|
|
1173
|
+
## 8. Pipelines
|
|
1174
|
+
|
|
1175
|
+
ForgeQE's agent writes, runs, and fixes GitHub Actions and Azure Pipelines. Run it in the repo (or pass `--repo`) and ask:
|
|
1176
|
+
|
|
1177
|
+
```bash
|
|
1178
|
+
forgeqe run "Add a GitHub Actions workflow that runs the smoke cases in cases.yaml on every pull request"
|
|
1179
|
+
forgeqe run "Set up an Azure DevOps pipeline that runs test plan 12 every night and posts results back"
|
|
1180
|
+
forgeqe run "The ForgeQE workflow is failing, fix it"
|
|
1181
|
+
```
|
|
1182
|
+
|
|
1183
|
+
What it does:
|
|
1184
|
+
|
|
1185
|
+
1. Works out the platform from the git remote (github.com, or dev.azure.com / visualstudio.com) and reads the repo's existing CI, so it can add a job to it or write a new file.
|
|
1186
|
+
2. Writes the pipeline so it installs Bun and uv, runs `npm install -g @capagents/forgeqe` and `forgeqe setup`, then `forgeqe suite <source...> --no-code --plain --out <dir>`, and publishes `junit.xml` and the report folder. On GitHub the suite adds a results table to the job summary.
|
|
1187
|
+
3. Validates it (actionlint when installed, otherwise by parsing the YAML) and commits it.
|
|
1188
|
+
4. Pushes to a new branch named `forgeqe/ci-<topic>` with ForgeQE's `push_branch` tool. That tool refuses the default branch, `main`, and `master`, and never forces; `git push` itself is blocked for the agent. Merging stays with you.
|
|
1189
|
+
5. Stores the keys the pipeline needs (the model's key from `llms.json`, and `ADO_PAT`, `JIRA_EMAIL` and `JIRA_API_TOKEN`, or `XRAY_CLIENT_ID` and `XRAY_CLIENT_SECRET`) with ForgeQE's `set_ci_secret` tool. The agent only names the variable; ForgeQE passes the value from its own environment to `gh secret set` (on stdin) or `az pipelines variable` (through the environment), and never shows it. A variable that is not set in ForgeQE's environment is reported, not guessed.
|
|
1190
|
+
6. Triggers the run with `gh workflow run` or `az pipelines run`, watches it, reads the logs of failed steps, fixes the pipeline (or the code), pushes again, and repeats until the run passes or `code.max_attempts` runs have failed. It reports the run link and the result.
|
|
1191
|
+
|
|
1192
|
+
It needs `gh` logged in for GitHub, or `az` with the `azure-devops` extension logged in for Azure DevOps. Without them it still writes, validates, and commits the pipeline, then tells you the commands to run. Set `llm.active` to a live profile in the committed `forgeqe.yaml`.
|
|
1193
|
+
|
|
1194
|
+
## 9. Monitoring
|
|
1195
|
+
|
|
1196
|
+
`forgeqe monitor` runs a set of checks on a schedule and alerts Microsoft Teams and email when one breaks. A check is any test case `forgeqe suite` takes (section 7): a YAML or Gherkin file, a folder, Jira keys or JQL, an Azure DevOps plan, TestRail, and so on.
|
|
1197
|
+
|
|
1198
|
+
```yaml
|
|
1199
|
+
monitor:
|
|
1200
|
+
checks: [checks/smoke.yaml]
|
|
1201
|
+
every: 15m # 30s, 15m, 1h, 1h30m; at least 10s
|
|
1202
|
+
replay: verify # verify | trust | off
|
|
1203
|
+
parallel: 1
|
|
1204
|
+
fail_after: 1 # failing rounds in a row before the first alert
|
|
1205
|
+
remind_every: 2h # repeat while it keeps failing; default: never
|
|
1206
|
+
keep: 100 # round folders kept
|
|
1207
|
+
write_back: false # post each round's results to the source system
|
|
1208
|
+
# out_dir: ./.forgeqe/reports/monitor
|
|
1209
|
+
# report_url: https://reports.example.com/monitor
|
|
1210
|
+
alerts:
|
|
1211
|
+
teams:
|
|
1212
|
+
webhook_env: TEAMS_WEBHOOK_URL
|
|
1213
|
+
email:
|
|
1214
|
+
host: smtp.office365.com # or SMTP_HOST
|
|
1215
|
+
port: 587 # STARTTLS; 465 is TLS from the start (secure: true)
|
|
1216
|
+
username_env: SMTP_USERNAME
|
|
1217
|
+
password_env: SMTP_PASSWORD
|
|
1218
|
+
# from: ForgeQE <qa-bot@example.com>
|
|
1219
|
+
to: [qa-team@example.com, oncall@example.com]
|
|
1220
|
+
```
|
|
1221
|
+
|
|
1222
|
+
```bash
|
|
1223
|
+
forgeqe monitor --test-alerts # send a sample alert through every channel
|
|
1224
|
+
forgeqe monitor # monitor.checks every monitor.every, until Ctrl+C
|
|
1225
|
+
forgeqe monitor checks/checkout.yaml --every 5m
|
|
1226
|
+
forgeqe monitor --once # one round, then exit (cron, scheduled pipelines)
|
|
1227
|
+
```
|
|
1228
|
+
|
|
1229
|
+
**Each round** runs the checks like a suite, without writing tests, and replays the flows from page memory (section 5). A flow that passed before costs one model call to confirm the expected results (`replay: verify`), or none (`replay: trust`, which trusts the replay without checking). A new or changed flow falls back to the full agent. Rounds start `every` apart; a round that overruns is followed by the next one straight away.
|
|
1230
|
+
|
|
1231
|
+
**Alerts** go out when something changes, not every round:
|
|
1232
|
+
|
|
1233
|
+
- A check that fails `fail_after` rounds in a row gets an alert. With `fail_after: 2` a single flaky failure is never reported.
|
|
1234
|
+
- While it keeps failing, nothing more is sent, unless `remind_every` is set.
|
|
1235
|
+
- When it passes again, a recovery alert says how long it was down.
|
|
1236
|
+
- A round that cannot run at all (a test system is down, a source is empty, the engine will not start) alerts as the check "ForgeQE monitor", and the other checks keep their state.
|
|
1237
|
+
|
|
1238
|
+
All changes in one round go out as one message. Teams gets an Adaptive Card with each check, why it failed and at which step, a link to the test case, and an "Open report" button. Email gets the same as text and HTML, with the failing checks' last screenshots attached (up to five).
|
|
1239
|
+
|
|
1240
|
+
For Teams, create an incoming webhook on the channel, or a Workflows flow with the trigger "When a Teams webhook request is received" and the action "Post card in a chat or channel"; both take the card as it is. Put the URL in `TEAMS_WEBHOOK_URL`. For email, any SMTP server works: Office 365 (`smtp.office365.com:587`, with SMTP AUTH allowed for the mailbox), Gmail with an app password, SendGrid, or a relay on your network (no username needed). The webhook URL and the SMTP password stay in the environment; if a send fails, the error never contains them.
|
|
1241
|
+
|
|
1242
|
+
The terminal shows one block per round:
|
|
1243
|
+
|
|
1244
|
+
```
|
|
1245
|
+
Monitoring checks/smoke.yaml every 15m · replay verify · alerts: Teams, email to qa-team@example.com · Ctrl+C stops
|
|
1246
|
+
[14:15] ✗ 4/5 passing · 38s · 6.2K tokens
|
|
1247
|
+
✗ SHOP-12 Checkout: failing since 14:15
|
|
1248
|
+
The Pay button is missing on the payment page
|
|
1249
|
+
↑ Alert sent: Teams, email
|
|
1250
|
+
Report .forgeqe/reports/monitor/20260929-141500/report.html
|
|
1251
|
+
Next round at 14:30
|
|
1252
|
+
[14:30] ✗ 4/5 passing · 35s · 5.9K tokens
|
|
1253
|
+
✗ SHOP-12 Checkout: failing since 14:15 (2 rounds, already alerted)
|
|
1254
|
+
Report .forgeqe/reports/monitor/20260929-143000/report.html
|
|
1255
|
+
Next round at 14:45
|
|
1256
|
+
```
|
|
1257
|
+
|
|
1258
|
+
**Files.** Each round is a suite folder in `.forgeqe/reports/monitor/<time>/` (`report.html`, `junit.xml`, `suite.json`, the runs, and `alerts.json` when it alerted), so the report's trends and flaky tests cover the rounds. Folders beyond `keep` are deleted. `state.json` in `.forgeqe/reports/monitor/` remembers which checks are failing, since when, and when they were last alerted; delete it to start fresh. Set `report_url` to where you publish `.forgeqe/reports/monitor/` and alerts link `<report_url>/<round>/report.html`; without it they name the local file.
|
|
1259
|
+
|
|
1260
|
+
**Scheduling.** Run `forgeqe monitor` in a long-lived session (tmux, a service, a container), or `forgeqe monitor --once` from cron or a scheduled pipeline. `--once` exits `0` when every check passed, `1` when any failed, and `2` when stopped. In a pipeline, cache `.forgeqe/reports/monitor/state.json` between runs; without it every run starts fresh, and a failure alerts every time. Only one monitor can use an `out_dir` at a time, so an overlapping cron run exits instead of racing.
|
|
1261
|
+
|
|
1262
|
+
You can also ask ForgeQE's agent. In the shell, "check the smoke cases once" runs one round and shows it as a card, and "monitor the smoke cases every 10 minutes" starts a monitor in the background: you keep working, each round appears as a card, "is anything failing?" shows the state, and "stop monitoring" ends it. A background monitor lives as long as the shell (or `forgeqe mcp`) and stops when it closes; `forgeqe run` refuses to start one, because it would stop when the command exits. While one is running, a one-off round on the same `out_dir` is refused rather than run twice. For monitoring that keeps going after you close the shell, "monitor the smoke cases every 10 minutes and alert the QA channel in Teams, always on" makes the agent set up `monitor:` in `forgeqe.yaml`, send a test alert, and tell you how to keep `forgeqe monitor` running (or add a scheduled pipeline).
|
|
1263
|
+
|
|
1264
|
+
## 10. MCP
|
|
1265
|
+
|
|
1266
|
+
### Servers ForgeQE's agent connects to
|
|
1267
|
+
|
|
1268
|
+
When ForgeQE's agent starts, it connects to an MCP server for each system set up under `sources:`. The server settings come from the same place as everything else: the organization and project, the site URL, and the names of the environment variables that hold the tokens. You don't write MCP config for these.
|
|
1269
|
+
|
|
1270
|
+
**Azure DevOps.** Microsoft's [Azure DevOps MCP server](https://github.com/microsoft/azure-devops-mcp), run as `npx -y @azure-devops/mcp <org> -a pat -d all`, with every tool group the server has. The organization comes from `org_url` (`https://dev.azure.com/acme` or `https://acme.visualstudio.com`). ForgeQE passes the PAT from `token_env` (default `ADO_PAT`) the way the server wants it; without a PAT it uses your `az login` session. Its tools are `azure_devops_*`: work items and comments, queries, backlogs, iterations, test plans, pipelines and their logs, repos, branches, pull requests, wiki pages (read, create, and update), search across code, wikis, and work items, and Advanced Security alerts. `mcp_domains` limits them to some groups. It needs Node.js. Azure DevOps Server (on-premises) isn't supported by Microsoft's server, so it uses ForgeQE's API.
|
|
1271
|
+
|
|
1272
|
+
```yaml
|
|
1273
|
+
sources:
|
|
1274
|
+
azure_devops:
|
|
1275
|
+
org_url: https://dev.azure.com/acme # the MCP server takes the organization, not a project
|
|
1276
|
+
# project: Shop # optional: limit ForgeQE's own API calls to one project
|
|
1277
|
+
token_env: ADO_PAT
|
|
1278
|
+
mcp: true # false: API only
|
|
1279
|
+
mcp_domains: [core, work-items, test-plans, pipelines] # optional: fewer tool groups
|
|
1280
|
+
```
|
|
1281
|
+
|
|
1282
|
+
Microsoft's server has no dashboard tools and can't save queries. Ask for a dashboard ("create a dashboard in QI-Payments with all defects in every state and the current sprint's stories") and ForgeQE's own `create_ado_dashboard` tool does it through the REST API with `ADO_PAT`: it runs each WIQL query once to check it, saves it as a shared query under `Shared Queries/ForgeQE` (updating one of the same name), and creates a team or project dashboard with a work item list or count tile per query, plus optional markdown text. The PAT needs Work Items (read and write) and permission to edit dashboards. Chart widgets are not made through the API; for those the agent uses the browser, which has to be signed in to `dev.azure.com` (`forgeqe login <name>` with a login for it under `logins:`).
|
|
1283
|
+
|
|
1284
|
+
Microsoft's wiki tools (`azure_devops_wiki`, `azure_devops_wiki_upsert_page`) only work in a wiki that already exists. In a project without one they answer "No wiki found". Ask for a wiki page and ForgeQE's `write_ado_wiki_page` tool writes it through the REST API instead. If the project has no wiki, the tool creates the project wiki (`<Project>.wiki`) first, then any missing parent pages (empty), then the page itself. A page that already exists is replaced. Code wikis are written on their published branch. The PAT needs Wiki (read and write). A login added to `forgeqe.yaml` while ForgeQE is running is picked up the next time the agent lists logins or signs in.
|
|
1285
|
+
|
|
1286
|
+
**Jira.** [mcp-atlassian](https://github.com/sooperset/mcp-atlassian), run with `uvx mcp-atlassian`, for Jira Cloud (`JIRA_EMAIL` and an API token in `JIRA_API_TOKEN`) and Server/Data Center (a personal access token in `token_env`). Its tools are `atlassian_jira_*`: get and search issues (JQL), create and update issues, comments, transitions, and fields. It needs uv, which ForgeQE's engine uses anyway. For Jira Cloud you can use Atlassian's hosted [Rovo MCP server](https://github.com/atlassian/atlassian-mcp-server) instead with `mcp: rovo`. It authenticates with your email and API token, but an organization admin must first turn on API token authentication for it.
|
|
1287
|
+
|
|
1288
|
+
```yaml
|
|
1289
|
+
sources:
|
|
1290
|
+
jira:
|
|
1291
|
+
url: https://acme.atlassian.net
|
|
1292
|
+
mcp: mcp-atlassian # rovo | false
|
|
1293
|
+
```
|
|
1294
|
+
|
|
1295
|
+
**Xray.** Xray has no official MCP server, so ForgeQE's own tools cover it. You can add a community server under `mcp:` if you want one.
|
|
1296
|
+
|
|
1297
|
+
**Other servers.** Add any MCP server under `mcp:`. A local server has a `command` (and optional `args`, `env`, `cwd`); a remote one has a `url` (and optional `headers`). Write secrets as `{env:NAME}`; the agent runtime fills them in from the environment. A server with the same name as a built-in one (`azure_devops`, `atlassian`) replaces it, and `enabled: false` turns one off.
|
|
1298
|
+
|
|
1299
|
+
```yaml
|
|
1300
|
+
mcp:
|
|
1301
|
+
github:
|
|
1302
|
+
url: https://api.githubcopilot.com/mcp/
|
|
1303
|
+
headers: { Authorization: "Bearer {env:GITHUB_TOKEN}" }
|
|
1304
|
+
xray:
|
|
1305
|
+
command: npx -y @triparc/xray-mcp
|
|
1306
|
+
env: { XRAY_CLIENT_ID: "{env:XRAY_CLIENT_ID}", XRAY_CLIENT_SECRET: "{env:XRAY_CLIENT_SECRET}" }
|
|
1307
|
+
```
|
|
1308
|
+
|
|
1309
|
+
`forgeqe mcp list` prints the servers your settings give, with secrets shown only as `{env:…}`, and says why any system is left out. When the agent starts, the transcript shows the result:
|
|
1310
|
+
|
|
1311
|
+
```
|
|
1312
|
+
▸ Connecting to Azure DevOps MCP, Jira MCP (mcp-atlassian)…
|
|
1313
|
+
✓ Azure DevOps MCP connected
|
|
1314
|
+
✗ Jira MCP (mcp-atlassian) did not connect (…). ForgeQE's API tools cover it.
|
|
1315
|
+
```
|
|
1316
|
+
|
|
1317
|
+
**Without an MCP server.** A system with no server, or whose server didn't start, still works through ForgeQE's own tools, which call the REST APIs with the same settings:
|
|
1318
|
+
|
|
1319
|
+
- `find_test_cases` and `run_test_cases` read test cases and post results back (test runs, comments, Xray Test Executions), whether or not an MCP server is connected.
|
|
1320
|
+
- `read_confluence` reads Confluence pages (by id, link, or CQL) as text, with table cells kept apart.
|
|
1321
|
+
- `query_api` reads anything else: work items, WIQL results, builds, Jira issues and JQL searches, Xray tests and executions (GraphQL on Cloud, `/rest/raven` on Server/DC), Confluence spaces and pages. It only reads (GET requests and GraphQL queries, never mutations), only reaches the configured hosts, and cuts large answers to fit the agent's context.
|
|
1322
|
+
|
|
1323
|
+
The agent runs test cases with `run_test_cases` even when an MCP server is connected, so reports and write-back work the same either way. It uses the MCP tools for everything else, and creates or changes items (a bug, a comment, a transition) only when you ask.
|
|
1324
|
+
|
|
1325
|
+
### ForgeQE as an MCP server
|
|
1326
|
+
|
|
1327
|
+
`forgeqe mcp` serves ForgeQE's tools to other agents over stdio (MCP):
|
|
1328
|
+
|
|
1329
|
+
```json
|
|
1330
|
+
{ "mcpServers": { "forgeqe": { "command": "forgeqe", "args": ["mcp", "--repo", "/path/to/app"] } } }
|
|
1331
|
+
```
|
|
1332
|
+
|
|
1333
|
+
| Tool | What it does |
|
|
1334
|
+
|------|--------------|
|
|
1335
|
+
| `browser_run` | Carry out a goal in a real browser and report pass or fail, steps, and the run folder |
|
|
1336
|
+
| `find_test_cases` | Read cases from Azure DevOps, Jira, Xray, TestRail, Zephyr Scale, qTest, files, or text without running them |
|
|
1337
|
+
| `run_test_cases` | Run cases as a suite: step verdicts, reports, JUnit, write-back, and bugs |
|
|
1338
|
+
| `run_details` | A run's steps and locators with confidence, for writing a test |
|
|
1339
|
+
| `run_test` | ForgeQE runs a test command and returns the exit code and output |
|
|
1340
|
+
| `page_memory` | What page memory knows about a host or page, the recorded flows, or clear a host's memory |
|
|
1341
|
+
| `read_confluence` | Confluence pages as text, by id, link, or CQL |
|
|
1342
|
+
| `query_api` | Read anything from Azure DevOps, Jira, Xray, or Confluence through their APIs, with ForgeQE's credentials |
|
|
1343
|
+
| `push_branch` | Push to a new branch; never the default branch, never forced |
|
|
1344
|
+
| `set_ci_secret` | Store an environment variable as a GitHub or Azure Pipelines secret without revealing it |
|
|
1345
|
+
| `write_test` | Turn a passed run into a test in the repo; ForgeQE runs it until it passes in a browser and a reviewer approves it (up to `code.max_attempts`) |
|
|
1346
|
+
| `heal_tests` | `forgeqe heal`: fix out-of-date tests, report app bugs, and confirm by running the tests |
|
|
1347
|
+
| `find_tests` | Find a repository's existing tests that match a request, a date range, or a sprint, confirmed with the framework's list command; nothing runs |
|
|
1348
|
+
| `run_tests` | Run a `find_tests` selection after the user confirms (`confirmed: true` over MCP), with a result per test |
|
|
1349
|
+
| `list_sprints` | Recent sprints from Azure DevOps and Jira with their dates |
|
|
1350
|
+
| `monitor` | One monitor round, start/stop/status of a background monitor, or a test alert |
|
|
1351
|
+
| `logins` | List logins, forget sessions, or sign in by hand (not over stdio, which has no one to wait for) |
|
|
1352
|
+
| `forgeqe_setup` | Profiles, MCP servers, the docs by topic, installing the engine, scaffolding a config, and listing, showing, or creating skills |
|
|
1353
|
+
|
|
1354
|
+
`--repo` sets the working directory (default: where it starts), and `--profile`, `--url`, and `--headed` apply to browser runs. Progress goes to stderr; stdout carries only MCP messages. Long calls send progress notifications, and a cancelled call stops its browser. The shell and `forgeqe run` use the same tools, served to the agent runtime over local HTTP with a one-time token.
|
|
1355
|
+
|
|
1356
|
+
## 11. Skills
|
|
1357
|
+
|
|
1358
|
+
A skill is a folder with a `SKILL.md`: instructions that teach ForgeQE's agents something a prompt can't know, like your repo's test conventions, a framework, or how to drive an app such as Dynamics 365. The format is the Agent Skills one (Claude Code and others use it), with one ForgeQE field, `agents`:
|
|
1359
|
+
|
|
1360
|
+
```markdown
|
|
1361
|
+
---
|
|
1362
|
+
name: contoso-erp
|
|
1363
|
+
description: "Use when the site is the Contoso ERP (erp.contoso.com): the order grid, the customer lookup, and saving orders."
|
|
1364
|
+
agents: [browser]
|
|
1365
|
+
---
|
|
1366
|
+
|
|
1367
|
+
- The customer lookup opens a list after three letters; click the row whose name matches exactly.
|
|
1368
|
+
- Save with the floppy icon in the toolbar; wait until "Saved" shows in the status bar.
|
|
1369
|
+
```
|
|
1370
|
+
|
|
1371
|
+
`name` is lowercase words joined by hyphens, the same as the folder. Agents choose skills by `description` alone, so name the concrete signs it applies (a framework, a config file, a host, a product). Quote it when it contains `: `.
|
|
1372
|
+
|
|
1373
|
+
**Who uses it.** `agents` lists `forgeqe` (ForgeQE's agent: how to handle a kind of request), `scribe` (writing, healing, finding and reviewing tests), and `browser` (the browser agent). Without `agents`, a skill is for `forgeqe` and `scribe`; a browser skill must ask for `browser`.
|
|
1374
|
+
|
|
1375
|
+
**How skills are used.**
|
|
1376
|
+
|
|
1377
|
+
- ForgeQE's agent and Scribe see the name and description of each skill meant for them, and load the ones that fit the job through the agent runtime's skill tool. A skill adds to their instructions and never overrides them. Scribe can also read files next to `SKILL.md` (for example `references/locators.md`) when the skill points to them.
|
|
1378
|
+
- Browser runs: ForgeQE's agent passes the browser skills a goal needs to `browser_run` and `run_test_cases`. For `forgeqe suite`, `forgeqe monitor` and `forgeqe run --direct`, the engine picks them from the goal with one short model call (at most three), and remembers the choice for that goal, so a monitor's later rounds and repeated cases skip it. `--skill NAME` (repeatable) fixes the list; `--skill none` runs without any. The chosen skills' text is added to the browser agent's prompt, at most `skills.browser_max_chars` (6,000) characters in total; the browser agent reads only `SKILL.md`.
|
|
1379
|
+
- `run.json`, the `run.done` log line and the report list the skills a run used.
|
|
1380
|
+
|
|
1381
|
+
**Where skills come from**, lowest to highest precedence; a later source replaces a skill of the same name:
|
|
1382
|
+
|
|
1383
|
+
| Source | Folder |
|
|
1384
|
+
|--------|--------|
|
|
1385
|
+
| Built-in | the `skills/` folder ForgeQE ships: `playwright-typescript` and `dotnet-nunit-playwright` (Scribe), `dynamics-365` (browser), `writing-skills` (ForgeQE's agent) |
|
|
1386
|
+
| Global, only with `skills.external: true` | `~/.claude/skills`, `~/.agents/skills`, and the repo's `.claude/skills` and `.agents/skills` |
|
|
1387
|
+
| User | `~/.forgeqe/skills` (or `$FORGEQE_HOME/skills`) |
|
|
1388
|
+
| Project | `.forgeqe/skills` next to `forgeqe.yaml`, and the repo's own `.forgeqe/skills` |
|
|
1389
|
+
| Extra | each folder in `skills.dirs` |
|
|
1390
|
+
|
|
1391
|
+
Commit `.forgeqe/skills` so the team and CI share it. ForgeQE only ignores `.forgeqe/reports/`; if your `.gitignore` has `.forgeqe/`, replace it with `.forgeqe/*` and `!.forgeqe/skills/` (`forgeqe skills new` warns when git would ignore the new skill). To change a built-in skill, make a project skill with the same name.
|
|
1392
|
+
|
|
1393
|
+
Skills from anywhere else stay out: the agent runtime's own discovery (`~/.claude/skills`, a repo's `.opencode/skills`, its built-in skills) is off, and each agent may load only the skills ForgeQE's registry gives it. Skill text is trusted like the repo's own files, so global skills are opt-in.
|
|
1394
|
+
|
|
1395
|
+
```yaml
|
|
1396
|
+
skills:
|
|
1397
|
+
enabled: true # false (or skills: false) turns skills off
|
|
1398
|
+
dirs: [../shared-skills] # more folders, read last
|
|
1399
|
+
disable: [dynamics-365] # leave these out
|
|
1400
|
+
external: false # true: also the global folders above
|
|
1401
|
+
browser_max_chars: 6000 # most skill text added to one browser run
|
|
1402
|
+
```
|
|
1403
|
+
|
|
1404
|
+
**Commands.**
|
|
1405
|
+
|
|
1406
|
+
| Command | What it does |
|
|
1407
|
+
|---------|--------------|
|
|
1408
|
+
| `forgeqe skills` | The skills each agent can use, where each comes from (and what it replaces), disabled skills, problems, and the folders read |
|
|
1409
|
+
| `forgeqe skills show <name>` | One skill's instructions |
|
|
1410
|
+
| `forgeqe skills new <name> --description "Use when …" [--agent browser] [--user]` | Start a skill in `.forgeqe/skills` (`--user`: `~/.forgeqe/skills`) |
|
|
1411
|
+
| `forgeqe skills check` | Validate every skill; exit 1 when one has a problem |
|
|
1412
|
+
| `forgeqe skills enable\|disable <name>` | Edit `skills.disable` in `forgeqe.yaml`, keeping its comments |
|
|
1413
|
+
| `/skills [name]` | The same list, or one skill, in the shell |
|
|
1414
|
+
|
|
1415
|
+
In the shell you can also ask: "make a skill for our Dynamics date picker" or "teach Scribe our test conventions". ForgeQE's agent gathers the facts, writes the skill into `.forgeqe/skills` with `forgeqe_setup`, and it applies from the next session. It writes skills only when you ask.
|
|
1416
|
+
|
|
1417
|
+
## 12. Engine tuning
|
|
1418
|
+
|
|
1419
|
+
Engine settings are `FORGEQE_ENGINE_*` variables. Set them in the shell or `.env`; they win over `forgeqe.yaml`:
|
|
1420
|
+
|
|
1421
|
+
| Variable | Default | Effect |
|
|
1422
|
+
|----------|---------|--------|
|
|
1423
|
+
| `FORGEQE_ENGINE_TIMEOUT_SECONDS` | `timeout_seconds` (600) | Whole-run limit |
|
|
1424
|
+
| `FORGEQE_ENGINE_STEP_TIMEOUT` | 180 | Per-step limit |
|
|
1425
|
+
| `FORGEQE_ENGINE_FAST_MODE` | true | Flash mode, no planning |
|
|
1426
|
+
| `FORGEQE_ENGINE_FULL_AGENT_MODE` | false | The engine's full agent mode instead of fast mode |
|
|
1427
|
+
| `FORGEQE_ENGINE_MAX_ACTIONS_PER_STEP` | engine default | Actions per model call |
|
|
1428
|
+
| `FORGEQE_ENGINE_MAX_FAILURES` | engine default | Consecutive failures before stopping |
|
|
1429
|
+
| `FORGEQE_ENGINE_LOW_VISION_DETAIL` | from `vision_detail` | Low-detail screenshots |
|
|
1430
|
+
| `FORGEQE_ENGINE_CONTROL_LOOP_MAX_RETRIES` | 4 | Repeats of the same click, input, search, or select before the agent is told to change approach; the same number again after that stops the run |
|
|
1431
|
+
| `FORGEQE_ENGINE_CHANNEL` / `FORGEQE_ENGINE_EXECUTABLE_PATH` | chrome | Browser to launch |
|
|
1432
|
+
| `FORGEQE_ENGINE_SKIP_ERROR_RECOVERY_PROMPT` | false | Drop the recovery instructions |
|
|
1433
|
+
|
|
1434
|
+
## 13. Logs for debugging
|
|
1435
|
+
|
|
1436
|
+
Every session (`forgeqe start`, `run`, `suite`, `heal`, `monitor`, `code`, `mcp`, `login`, `setup`) writes a log to `.forgeqe/logs/` next to `forgeqe.yaml` (the newest 30 are kept). It has the versions and settings in use, what you asked, ForgeQE's agent's answers and every tool call with its result, every browser step and result, the browser engine's own log lines, and errors. Secrets are replaced before anything is written: API keys, tokens and passwords from the environment, keys in `llms.json`, and credentials you gave in a message.
|
|
1437
|
+
|
|
1438
|
+
To share a session, type `/logs` in the shell (`/logs shots` adds screenshots), or run `forgeqe logs bundle` afterwards. Either writes one `.tar.gz` with the session log, the run folders it mentions (`run.json`, `steps.json`, `trace.md`, `resume.json`, `workflow.yaml`, the failure screenshot), your `forgeqe.yaml`, your profiles without keys, and the versions. `forgeqe logs` lists recent logs.
|
|
1439
|
+
|
|
1440
|
+
Start with `--debug` (or set `FORGEQE_DEBUG=1`) for more: the browser engine logs at debug level, and long values such as tool results are kept whole instead of cut at 8,000 characters.
|
|
1441
|
+
|
|
1442
|
+
## 14. Env overrides
|
|
1443
|
+
|
|
1444
|
+
| Variable | Effect |
|
|
1445
|
+
|----------|--------|
|
|
1446
|
+
| `WP_CONFIG` | Path to `forgeqe.yaml` |
|
|
1447
|
+
| `WP_LLMS_JSON` | Path to `llms.json` |
|
|
1448
|
+
| `WP_LLM_PROFILE` | Active profile, unless `--profile` is set |
|
|
1449
|
+
| `WP_AZURE_API_KEY` / `OPENAI_API_KEY` / `WP_API_KEY` | Keys referenced by profiles |
|
|
1450
|
+
| `FORGEQE_CONFIG_DIR` | Global config folder (default `~/.config/forgeqe`): `forgeqe.yaml`, `llms.json` and `.env` used when a project has none |
|
|
1451
|
+
| `FORGEQE_PYTHON` | A Python that already has the engine's libraries, used instead of the managed venv (skipped, with a note, when it cannot run the engine) |
|
|
1452
|
+
| `FORGEQE_DEBUG` | `1` logs at debug level, like `--debug` |
|
|
1453
|
+
| `FORGEQE_HOME` | Where the managed engine lives, user skills (`skills/`), and page memory when there is no config file (default `~/.forgeqe`) |
|
|
1454
|
+
| `ADO_ORG_URL` / `ADO_PROJECT` / `ADO_PAT` | Azure DevOps organization, project, and token when `sources.azure_devops` doesn't set them |
|
|
1455
|
+
| `JIRA_URL` / `JIRA_EMAIL` / `JIRA_API_TOKEN` | Jira site and credentials when `sources.jira` doesn't set them |
|
|
1456
|
+
| `XRAY_URL` / `XRAY_CLIENT_ID` / `XRAY_CLIENT_SECRET` | Xray Cloud endpoint and API key pair |
|
|
1457
|
+
| `CONFLUENCE_URL` / `CONFLUENCE_EMAIL` / `CONFLUENCE_TOKEN` | Confluence site and credentials when `sources.confluence` doesn't set them |
|
|
1458
|
+
| `TESTRAIL_URL` / `TESTRAIL_EMAIL` / `TESTRAIL_API_KEY` | TestRail site, user, and API key |
|
|
1459
|
+
| `ZEPHYR_API_TOKEN` / `ZEPHYR_URL` | Zephyr Scale Cloud token (turns Zephyr on) and API base |
|
|
1460
|
+
| `QTEST_URL` / `QTEST_PROJECT_ID` / `QTEST_TOKEN` | qTest site, project, and API token |
|
|
1461
|
+
| `TEAMS_WEBHOOK_URL` | Teams webhook for monitoring alerts (`monitor.alerts.teams.webhook_env` names another) |
|
|
1462
|
+
| `SMTP_HOST` / `SMTP_PORT` / `SMTP_USERNAME` / `SMTP_PASSWORD` / `ALERT_EMAIL_TO` | SMTP server, login, and recipients for monitoring email when `monitor.alerts.email` doesn't set them |
|
|
1463
|
+
|
|
1464
|
+
## 15. Commands cheat sheet
|
|
1465
|
+
|
|
1466
|
+
### Setup
|
|
1467
|
+
|
|
1468
|
+
| Command | What it does |
|
|
1469
|
+
|---------|--------------|
|
|
1470
|
+
| `forgeqe init [--global] [--profile NAME]` | Write `forgeqe.yaml`, `llms.json`, and `.forgeqe/` with the prompts, skills, and product knowledge templates |
|
|
1471
|
+
| `forgeqe setup [--force]` | Download the agent runtime and the engine now (`--force` rebuilds the engine) |
|
|
1472
|
+
| `forgeqe models` | List the profiles in `llms.json` and the active one |
|
|
1473
|
+
| `forgeqe features` | What ForgeQE can do, and what each capability still needs in this setup (works without a model) |
|
|
1474
|
+
| `forgeqe docs [--guide\|--open] [--copy DIR]` | The bundled docs; `--guide` opens the user guide, `--open` the architecture page |
|
|
1475
|
+
| `forgeqe mcp list` | The MCP servers ForgeQE's agent gets from your settings |
|
|
1476
|
+
| `forgeqe auth login [system\|NAME]` | Sign in to Azure DevOps, GitHub, Jira, Confluence, TestRail, Zephyr, qTest, or Xray in the browser, or save one secret, in the system's credential store |
|
|
1477
|
+
| `forgeqe auth [status]`, `forgeqe auth logout <system>` | What is signed in; forget a sign-in |
|
|
1478
|
+
|
|
1479
|
+
### Run
|
|
1480
|
+
|
|
1481
|
+
| Command | What it does |
|
|
1482
|
+
|---------|--------------|
|
|
1483
|
+
| `forgeqe start [--repo DIR] [--headed]` | The shell |
|
|
1484
|
+
| `forgeqe run "<request>" [--plain]` | One request without the shell |
|
|
1485
|
+
| `forgeqe run --direct "<goal>" [--skill NAME]` | One browser goal, no agent |
|
|
1486
|
+
| `forgeqe suite <source...> [--parallel N] [--skill NAME]` | Run test cases the same way every time (pipelines) |
|
|
1487
|
+
| `forgeqe cases <source...>` | List the cases a source gives, without running them |
|
|
1488
|
+
|
|
1489
|
+
### Tests
|
|
1490
|
+
|
|
1491
|
+
| Command | What it does |
|
|
1492
|
+
|---------|--------------|
|
|
1493
|
+
| `forgeqe code [run-dir] --repo DIR` | Scribe writes a test for a run (default: the latest) |
|
|
1494
|
+
| `forgeqe heal ["<test command>"] --repo DIR` | Fix tests the app has outgrown, or report app bugs |
|
|
1495
|
+
| `forgeqe visual [run] \| approve [run] [--page p]` | Each page against its approved screenshot; approve an intended change as the new baseline |
|
|
1496
|
+
| `forgeqe quality [run] \| trends [page]` | A run's WCAG rules and Core Web Vitals against the budgets; per page over time |
|
|
1497
|
+
| `forgeqe explore <story> [--url URL] [--roles a,b]` | Exploratory testing of a story: charters beyond the scripted cases, confirmed defects, proposed cases |
|
|
1498
|
+
| `forgeqe api contracts --spec <link\|file>` | API contracts from OpenAPI/Swagger, WSDL, GraphQL, .proto, or grpc:// |
|
|
1499
|
+
| `forgeqe api contracts --run [RUN]` | API contracts from the calls a browser run saw the app make |
|
|
1500
|
+
| `forgeqe api run [SET] [--base-url URL]` | Run contracts against the API, no browser; exit 1 on a failure |
|
|
1501
|
+
| `forgeqe api tests [SET] --repo DIR` | Scribe writes contracts as API tests in the repo |
|
|
1502
|
+
| `forgeqe api scenarios --run \| --spec <link> \| --cases <refs> \| --text "..."` | End-to-end API scenarios: chained from a run, lifecycles and negative cases from a description, or planned from test cases or plain English |
|
|
1503
|
+
| `forgeqe api run-scenarios [SET] [--allow-writes]` | Run them against the API; exit 1 on a failure |
|
|
1504
|
+
| `forgeqe api tests --scenarios --repo DIR` | Scenario tests on the repo's existing API helpers |
|
|
1505
|
+
| `forgeqe eval domain [--only id,id] [--repeat N] [--min 0.8]` | Whether the agent applies domain and regulatory knowledge, with the domain declared and without; `--min` makes it a CI gate (see [Domain and regulations](#16-domain-and-regulations)) |
|
|
1506
|
+
|
|
1507
|
+
### Memory, logins, monitoring
|
|
1508
|
+
|
|
1509
|
+
| Command | What it does |
|
|
1510
|
+
|---------|--------------|
|
|
1511
|
+
| `forgeqe memory [show <host>] [flows]` | What page memory knows |
|
|
1512
|
+
| `forgeqe memory clear [host] --yes` | Forget a host, or everything |
|
|
1513
|
+
| `forgeqe login <name>` / `forgeqe logins` | Sign in by hand once; list or clear saved sessions |
|
|
1514
|
+
| `forgeqe monitor [--once] [--test-alerts]` | Checks on a schedule, with Teams and email alerts |
|
|
1515
|
+
| `forgeqe notify test [channel]` | Send a test card to the notification channels (see [Notifications](#17-notifications)) |
|
|
1516
|
+
| `forgeqe mcp [--repo DIR]` | ForgeQE's tools as an MCP server for other agents |
|
|
1517
|
+
| `forgeqe skills [show\|new\|check\|enable\|disable]` | The skills each agent can use; start, validate, or turn one off |
|
|
1518
|
+
| `forgeqe logs [bundle] [--shots]` | Recent session logs; one archive of the newest to share |
|
|
1519
|
+
| `forgeqe update [version] [--check]` | Update every forgeqe on PATH, waiting while the registries catch up |
|
|
1520
|
+
|
|
1521
|
+
### In the shell
|
|
1522
|
+
|
|
1523
|
+
| Input | Action |
|
|
1524
|
+
|-------|--------|
|
|
1525
|
+
| A request, then Enter | ForgeQE's agent works it out |
|
|
1526
|
+
| `/stop` or Esc | Stop what is running |
|
|
1527
|
+
| `/headed on\|off` | Show the browser window |
|
|
1528
|
+
| `/details [on\|off]` | Show everything the agents do while they work: the browser agent's reasoning, page memory, engine logs, every file the coding agent reads (off by default: step results, files written, test results, problems). `--verbose` or `FORGEQE_VERBOSE=1` starts with it on, for `start`, `run`, `suite`, `code`, and `heal` too |
|
|
1529
|
+
| `/profile <name>` or Tab | Switch the model profile |
|
|
1530
|
+
| `/logs [shots]` | Save this session's log and runs in one archive to share |
|
|
1531
|
+
| `/features` | What ForgeQE can do here: ✓ ready, ◐ works with some parts to set up, ○ needs setup, with the fix (works without a model) |
|
|
1532
|
+
| `/skills [name]` | The skills each agent can use, or one skill's instructions |
|
|
1533
|
+
| `/auth [system]`, `/auth logout <system>` | Sign in to a system in the browser (the token is typed unseen), forget one; `/auth` alone shows what is signed in |
|
|
1534
|
+
| `/clear`, `/help`, `/exit` | Clear the transcript, show help, quit |
|
|
1535
|
+
| Drag with the mouse | Copy the selected text |
|
|
1536
|
+
|
|
1537
|
+
---
|
|
1538
|
+
|
|
1539
|
+
## 16. Domain and regulations
|
|
1540
|
+
|
|
1541
|
+
ForgeQE's agents already know the common industries and regulations: banking, insurance, lending, retail; DORA, PSD2, GDPR, ISO 27001, SOX, IDD, and more. Every agent applies that knowledge to its own job, automatically: analysing requirements, writing and checking test cases, planning exploration, writing test code (Scribe), reviewing it, healing it, writing and planning API tests, finding tests, and reviewing pull requests. Without a declaration, each works out the industry and regulations from the story, the product knowledge, and the application, and says what it assumed. Declaring yours removes the guesswork:
|
|
1542
|
+
|
|
1543
|
+
```yaml
|
|
1544
|
+
domain:
|
|
1545
|
+
industry: retail banking
|
|
1546
|
+
regulations: [DORA, PSD2, GDPR, ISO 27001]
|
|
1547
|
+
notes: Payments to UK and EU accounts; customers are consumers and small businesses.
|
|
1548
|
+
```
|
|
1549
|
+
|
|
1550
|
+
The agents add the risks the industry is known for (duplicate submissions, limits, cut-off times, effective dates, recalculated premiums) and the obligations of each regulation a feature touches (audit trail, segregation of duties, data protection, incident logging, resilience), and label each test case, charter, test, or finding with what it covers, for example `Domain: duplicate payment` or `GDPR: right to erasure`. What that means for each job:
|
|
1551
|
+
|
|
1552
|
+
| Agent | What it does with the domain |
|
|
1553
|
+
|---|---|
|
|
1554
|
+
| ForgeQE's agent | Adds domain and regulatory cases when it writes test cases or tests from requirements, and judges cases and release readiness against them |
|
|
1555
|
+
| Exploratory charters | Plans charters for the domain's risks and obligations |
|
|
1556
|
+
| Scribe (writing tests) | Asserts a covered risk or obligation explicitly (the amount, the approval, the audit entry), and carries its label into the test's name or tag |
|
|
1557
|
+
| Test reviewer | Treats a test that drops or weakens such an assertion as a correctness issue |
|
|
1558
|
+
| Healing | Never makes a test pass by loosening such an assertion: if the app no longer meets it, it is an app bug |
|
|
1559
|
+
| API tests and scenarios | Idempotent money-moving calls, access per role, no excess personal data in responses, no leaked internals, audited changes |
|
|
1560
|
+
| Finding tests | "The DORA tests" matches tests by their labels and what they assert |
|
|
1561
|
+
| Pull request review | A change that weakens a domain safeguard or an obligation is at least a major finding |
|
|
1562
|
+
|
|
1563
|
+
Every agent session gets the domain in its instructions from one place, and the rule is `domain-rule.md` in `.forgeqe/prompts/`, included in every agent that analyses requirements or designs, writes, reviews, or heals tests.
|
|
1564
|
+
|
|
1565
|
+
Which requirements apply to your product, and the ids your auditors use, are your organisation's decision: list them in `.forgeqe/knowledge/compliance.md` (`forgeqe init` adds a template), with what is out of scope. Agents cite a control, article, or clause id only when it is listed there, and name the obligation in words otherwise, so nothing in a test traces to an id recalled from memory. ForgeQE designs and checks tests for these obligations; it does not certify compliance or replace an audit.
|
|
1566
|
+
|
|
1567
|
+
### Evaluating the agent's domain knowledge
|
|
1568
|
+
|
|
1569
|
+
`forgeqe eval domain` measures whether the agent applies all this, with your model. Each evaluation case is a realistic story whose acceptance criteria leave the industry's risks and the regulations' obligations unstated, with what a domain expert expects its test cases to check. ForgeQE's own agent writes test cases for each story twice, with the domain declared (and a compliance file) and without, and a separate read-only judge decides, expectation by expectation, whether a test case actually checks it, and lists every id the cases cite.
|
|
1570
|
+
|
|
1571
|
+
```bash
|
|
1572
|
+
forgeqe eval domain # the bundled cases: banking, insurance, access control, data protection, lending
|
|
1573
|
+
forgeqe eval domain --only banking-payment-transfer --repeat 3
|
|
1574
|
+
forgeqe eval domain --cases ./evals/our-domain # your own cases
|
|
1575
|
+
forgeqe eval domain --judge-profile judge # judge with another llms.json profile
|
|
1576
|
+
forgeqe eval domain --variant declared --min 0.8 # exit 1 under 80% coverage, or on any invented id: a CI gate
|
|
1577
|
+
```
|
|
1578
|
+
|
|
1579
|
+
The report (`.forgeqe/reports/evals/domain/<time>/report.md` and `report.json`) shows coverage of the story's own expectations, the industry's, and the regulations', for each variant, the expectations each run missed with the judge's reason, and any invented ids (cited, but not in the compliance file). The gap between the two variants is what declaring the domain adds; the declared coverage is what you can rely on. Model answers vary, so use `--repeat` before drawing conclusions from one case.
|
|
1580
|
+
|
|
1581
|
+
A case is a YAML file:
|
|
1582
|
+
|
|
1583
|
+
```yaml
|
|
1584
|
+
id: banking-payment-transfer
|
|
1585
|
+
title: Send money to a saved beneficiary
|
|
1586
|
+
domain: { industry: retail banking, regulations: [PSD2, DORA, GDPR] }
|
|
1587
|
+
compliance: | # the team's compliance file for this product (optional)
|
|
1588
|
+
- CTL-AUD-01 (DORA): every payment is written to the audit log with who, when, and the values.
|
|
1589
|
+
story:
|
|
1590
|
+
title: Pay a saved beneficiary
|
|
1591
|
+
description: As a customer I want to send money to a beneficiary I saved earlier.
|
|
1592
|
+
acceptance: |
|
|
1593
|
+
- The customer picks a saved beneficiary, enters an amount and a reference, and confirms.
|
|
1594
|
+
expect: # source: story, domain, or regulation
|
|
1595
|
+
- { id: duplicate, source: domain, covers: Submitting twice does not create a second payment. }
|
|
1596
|
+
- { id: sca, source: regulation, covers: Confirming the payment requires strong customer authentication. }
|
|
1597
|
+
```
|
|
1598
|
+
|
|
1599
|
+
---
|
|
1600
|
+
|
|
1601
|
+
## 17. Notifications
|
|
1602
|
+
|
|
1603
|
+
ForgeQE tells the team in Microsoft Teams channels, or by email, when something they should know happens. Each channel picks its events:
|
|
1604
|
+
|
|
1605
|
+
```yaml
|
|
1606
|
+
notify:
|
|
1607
|
+
report_url: https://reports.example.com/forgeqe # where .forgeqe/reports is published, so cards link to each report
|
|
1608
|
+
channels:
|
|
1609
|
+
qa:
|
|
1610
|
+
teams: { webhook_env: TEAMS_WEBHOOK_URL }
|
|
1611
|
+
on: [suite_failed, eval_failed]
|
|
1612
|
+
release:
|
|
1613
|
+
teams: { webhook_env: TEAMS_RELEASE_WEBHOOK }
|
|
1614
|
+
on: [release]
|
|
1615
|
+
leads:
|
|
1616
|
+
email: { host: smtp.office365.com, port: 587, username_env: SMTP_USERNAME, password_env: SMTP_PASSWORD, to: [qa-leads@example.com] }
|
|
1617
|
+
on: [suite_failed, release]
|
|
1618
|
+
```
|
|
1619
|
+
|
|
1620
|
+
| Event | When | The card shows |
|
|
1621
|
+
|---|---|---|
|
|
1622
|
+
| `suite_failed` | A suite ends with a case that did not pass, or a test that did not | Each failing case (up to 10) with its kind of failure, the test case and bug links, tests written, and the report and build |
|
|
1623
|
+
| `suite_passed` | Every case passed | The count, how long it took, where it ran |
|
|
1624
|
+
| `release` | A release readiness verdict | GO, GO WITH RISKS, or NO-GO, the counts, every blocker and risk, and the wiki page when published |
|
|
1625
|
+
| `eval_failed` | `forgeqe eval domain --min` falls below its gate | Coverage for each variant and invented ids |
|
|
1626
|
+
|
|
1627
|
+
A channel without `on` gets `suite_failed`, `release`, and `eval_failed`. Email adds the failure screenshots. A stopped suite is not announced. Monitoring keeps its own `monitor.alerts`, with the same cards.
|
|
1628
|
+
|
|
1629
|
+
Events are sent from runs nobody is watching: `forgeqe suite` in a pipeline or on a schedule, `forgeqe run`, and the MCP server. In the shell, where people try things out, nothing is sent on its own; ask instead ("post the results to the QA channel", "tell the release channel the verdict"), and ForgeQE's agent posts a card with `notify`.
|
|
1630
|
+
|
|
1631
|
+
Links: with `report_url`, cards open the report where the reports folder is published. In Azure Pipelines and GitHub Actions they also open the build, where the report is an artifact. Without either, the card names the report's path.
|
|
1632
|
+
|
|
1633
|
+
**Setting up a Teams channel:**
|
|
1634
|
+
|
|
1635
|
+
1. In the channel, open **Workflows** and choose **Post to a channel when a webhook request is received**, then copy the URL it gives you. Microsoft is retiring the older Office 365 "Incoming Webhook" connectors; Workflows webhooks take the same cards.
|
|
1636
|
+
2. The URL is the secret (anyone with it can post): keep it in the environment, the system's credential store (`forgeqe auth login TEAMS_WEBHOOK_URL`), or a pipeline secret, never in `forgeqe.yaml`.
|
|
1637
|
+
3. Create the workflow with a shared or service account: a workflow belongs to whoever made it and stops when they leave. Your tenant must allow the Workflows app.
|
|
1638
|
+
4. `forgeqe notify test [channel]` sends a test card to check it arrives.
|
|
1639
|
+
|