@capagents/forgeqe 2.2.10 → 2.3.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.
@@ -15,13 +15,18 @@ llm:
15
15
  routing: auto # off (the default for existing projects) | shadow | auto
16
16
  ```
17
17
 
18
- `forgeqe init` writes `routing: auto` for new projects. With no `routing` line, it is on while the active profile is
19
- GitHub Copilot: Copilot cannot run ForgeQE's agent and Scribe, so the router finds them another configured model, and
20
- Copilot keeps driving the browser. `routing: off` turns that off too. `shadow` decides and logs each pick in the session log
18
+ `forgeqe init` writes `routing: auto` for new projects. With no `routing` line it is off. `shadow` decides and logs each pick in the session log
21
19
  (`model.route`) but changes nothing, so you can see what the router would do before you let it. Shadow still runs the
22
20
  live checks and the rating call described below.
23
21
 
24
- See the picks:
22
+ Whatever `routing` says, the model an area gets must work: its key or sign-in is set and it passed a live call
23
+ (one per model, kept for a day in `.forgeqe/model-checks.json` once it passes; a failed one is never kept, and a failed
24
+ check in `model-profile.json` is checked again). When it does not, the next model that works is used, a GitHub Copilot
25
+ profile first, and ForgeQE says why and how to fix the first. When none works, the error lists each model with the fix.
26
+ Only `--profile` skips this. With `auto`, a GitHub Copilot seat counts as costing nothing more per call, so it is picked
27
+ whenever it is rated good enough.
28
+
29
+ See the picks, and every model's check with its fix:
25
30
 
26
31
  ```
27
32
  forgeqe models --routes
@@ -445,9 +445,10 @@ export WP_AZURE_API_KEY=... # the key your llms.json profile names
445
445
  forgeqe models # check the profiles
446
446
  forgeqe start # the shell
447
447
  </code></pre>
448
- <p>With GitHub Copilot licences instead of a model key, sign in rather than exporting one, and set <code>llm.active: copilot</code> in <code>forgeqe.yaml</code> (or <code>&quot;default&quot;: &quot;copilot&quot;</code> in <code>llms.json</code>). The browser engine then runs on your Copilot seat; ForgeQE's agent and Scribe need another profile for now:</p>
449
- <pre><code class="language-bash">forgeqe auth login copilot # opens GitHub in your browser to sign in
450
- forgeqe models # the copilot profile is active
448
+ <p>With GitHub Copilot licences instead of a model key, sign in rather than exporting one. The sign-in lists your seat's models, recommends one (it takes screenshots and, where the plan has one, uses no premium requests), and writes your choice to <code>llms.json</code> as the <code>copilot</code> profile, made the default. Everything then runs on your Copilot seat: ForgeQE's agent, Scribe, and the browser, desktop and mobile engines. No other model is needed:</p>
449
+ <pre><code class="language-bash">forgeqe setup # the engine and GitHub's Copilot SDK
450
+ forgeqe auth login copilot # opens GitHub in your browser to sign in, then pick the model
451
+ forgeqe doctor # checks the engine, the SDK, the agent runtime, the sign-in and each model
451
452
  </code></pre>
452
453
  <p>In the shell, type a request and press Enter:</p>
453
454
  <pre><code>Go to booking.com and search for hotels in Mumbai for next weekend
@@ -580,7 +581,7 @@ bun src/index.ts init --global --profile azure-gpt4o
580
581
  <li><strong>Sign in with GitHub in the browser</strong> (recommended on your own computer). ForgeQE runs GitHub's own Copilot sign-in (<code>copilot login</code> from GitHub's Copilot CLI, downloaded once into <code>~/.forgeqe/tools</code> and checked against GitHub's checksums). Your browser opens GitHub; approve <strong>GitHub Copilot CLI</strong> there and you are signed in. GitHub's CLI keeps the sign-in in your system's credential store (Windows Credential Manager, the macOS Keychain); ForgeQE never sees a token. On a remote machine it shows a code to enter at github.com/login/device instead.</li>
581
582
  <li><strong>A fine-grained token</strong>, for machines without a browser. ForgeQE opens GitHub's token page: set <strong>Resource owner</strong> to your personal account and add the <strong>Copilot Requests</strong> permission, then paste the token (<code>github_pat_...</code>). Each character shows as <code>*</code>, and ForgeQE confirms what it got (<code>github_pat_11AB…Wz9Q (93 characters)</code>). The token goes to your system's credential store like ForgeQE's other secrets. Classic tokens (<code>ghp_</code>) do not work with Copilot.</li>
582
583
  </ul>
583
- <p>Either way ForgeQE checks the sign-in by asking Copilot for your seat's models and lists them; the first time, the Copilot SDK downloads Copilot's runtime from GitHub (checked against GitHub's checksums). <code>forgeqe auth</code> shows the sign-in on its <code>Copilot</code> line; <code>forgeqe auth logout copilot</code> makes ForgeQE stop using it (GitHub keeps a browser sign-in until you revoke <strong>GitHub Copilot CLI</strong> at github.com/settings/applications).</p>
584
+ <p>Either way ForgeQE checks the sign-in by asking Copilot for your seat's models, then asks which one to use (recommended first; models your seat has but has not turned on are named, with the settings page) and writes it to <code>llms.json</code>; the first time, the Copilot SDK downloads Copilot's runtime from GitHub (checked against GitHub's checksums). <code>forgeqe auth</code> shows the sign-in on its <code>Copilot</code> line; <code>forgeqe auth logout copilot</code> makes ForgeQE stop using it (GitHub keeps a browser sign-in until you revoke <strong>GitHub Copilot CLI</strong> at github.com/settings/applications).</p>
584
585
  <p>If your organization uses SAML single sign-on, GitHub asks you to authorize the organization during the browser sign-in. A Copilot Business or Enterprise seat needs your organization to allow <strong>Copilot CLI</strong> in its Copilot policies.</p>
585
586
  <p>A token reaches only the gateway's process. The engine gets the gateway's address and a one-time key that works nowhere else; the gateway refuses requests without that key and any request a web page sends. Model-run shell commands never see the token or the key.</p>
586
587
  <p>Which part uses what:</p>
@@ -591,10 +592,11 @@ bun src/index.ts init --global --profile azure-gpt4o
591
592
  <tbody>
592
593
  <tr><td>The browser engine (every browser run: <code>run --direct</code>, suites, monitoring)</td><td><code>engine_model</code> or <code>model</code>, on the Copilot seat</td><td><code>forgeqe auth login copilot</code></td></tr>
593
594
  <tr><td>The desktop and mobile agents</td><td><code>engine_model</code> or <code>model</code>, on the Copilot seat</td><td><code>forgeqe auth login copilot</code></td></tr>
594
- <tr><td>ForgeQE's agent and Scribe</td><td>Not on Copilot yet: give them another profile with <code>--profile</code>, or <code>code.model</code></td><td></td></tr>
595
+ <tr><td>ForgeQE's agent and Scribe</td><td><code>model</code>, on the Copilot seat</td><td><code>forgeqe auth login copilot</code></td></tr>
595
596
  </tbody>
596
597
  </table></div>
597
- <p>Copilot runs one SDK session per model request, with no tools of its own and your request's system prompt in place of Copilot's. Each request is billed to the seat (GitHub AI credits or premium requests, by your plan), and GitHub may rate-limit frequent automated requests. If a model is refused, check that your organization's Copilot policies allow it. ForgeQE shows no cost for a <code>github_copilot</code> profile unless you give it a <code>price</code>.</p>
598
+ <p>Copilot runs one SDK session per model request, with none of Copilot's own tools and your request's system prompt in place of Copilot's. The agent's tools are offered to the model as the session's only tools; when it calls one, the gateway ends the turn and hands the call back to ForgeQE's agent runtime, which runs it (with the same permissions as on any other model) and sends the result with the next request. The gateway itself runs nothing.</p>
599
+ <p><strong>With Copilot and a key-based model both in <code>llms.json</code></strong>, Copilot comes first: a sign-in makes it the default, and without a <code>&quot;default&quot;</code> it is the active profile. Before a model is used, ForgeQE checks that it works (its sign-in or key, and one live call, kept for a day once it passes). If Copilot does not work (not signed in, the Copilot SDK missing, the model not on your seat), the other model is used and ForgeQE says why and how to fix Copilot; if a key-based model you made the default does not work, Copilot is tried first. A model that fails its check is never used, and when none works the error lists each one with what to do. <code>--profile</code> turns this off: the model you name is used as it is. Each request is billed to the seat (GitHub AI credits or premium requests, by your plan), and GitHub may rate-limit frequent automated requests. If a model is refused, check that your organization's Copilot policies allow it. ForgeQE shows no cost for a <code>github_copilot</code> profile unless you give it a <code>price</code>.</p>
598
600
  <p><strong>In pipelines.</strong> <code>forgeqe suite ... --no-code</code> uses only the browser engine. Set <code>COPILOT_GITHUB_TOKEN</code> to a fine-grained token with the Copilot Requests permission, stored as a pipeline secret. GitHub also documents the workflow's own <code>GITHUB_TOKEN</code> with <code>permissions: copilot-requests: write</code> for organization repositories whose Copilot policy allows it (<a href="https://docs.github.com/en/copilot/how-tos/copilot-sdk/auth/server-to-server-tokens" rel="noopener">server tokens</a>). A Copilot seat belongs to one person: prefer an organization-billed token over signing a shared pipeline in to someone's seat.</p>
599
601
  <p>GitHub Models, which ForgeQE used for the engine before, was <a href="https://github.blog/changelog/2026-07-30-github-models-is-now-retired/" rel="noopener">retired by GitHub</a> on July 30, 2026. A profile that still has <code>engine_model: &quot;openai/...&quot;</code> or <code>github_org</code> needs updating: drop <code>github_org</code>, and use a Copilot model id.</p>
600
602
  <p><strong>When something goes wrong.</strong></p>
@@ -608,9 +610,11 @@ bun src/index.ts init --global --profile azure-gpt4o
608
610
  <tr><td><code>GitHub Copilot does not take classic tokens (ghp_)</code></td><td>Sign in in the browser instead, or make a fine-grained token with the Copilot Requests permission, owned by your personal account.</td></tr>
609
611
  <tr><td><code>GitHub Copilot did not accept the token</code></td><td>The token has no Copilot Requests permission, has expired, or the account has no Copilot seat.</td></tr>
610
612
  <tr><td><code>… must be a Copilot model id</code>, <code>engine_model must be a Copilot model id</code></td><td>Fix that field in <code>llms.json</code>: the sign-in lists the seat's models. A GitHub Models id such as <code>openai/gpt-4.1</code> is not a Copilot id; use <code>gpt-4.1</code>.</td></tr>
611
- <tr><td><code>ForgeQE's agent and Scribe cannot run on a github_copilot profile yet</code></td><td>Pick another profile for them (<code>--profile</code>, or Tab in the shell), or set <code>code.model</code>.</td></tr>
613
+ <tr><td><code>No model in llms.json can … right now</code></td><td>Each model is listed with why it cannot be used and the fix. <code>forgeqe doctor</code> checks everything at once.</td></tr>
614
+ <tr><td><code>GitHub's Copilot SDK is not installed in the ForgeQE engine</code></td><td>Run <code>forgeqe setup</code>. It installs the SDK from pypi.org; if that is blocked, <code>forgeqe doctor</code> says what to ask IT for.</td></tr>
615
+ <tr><td><code>Model for agent: main, because copilot failed its live check …</code></td><td>ForgeQE used your other model because Copilot did not answer; the message ends with the fix.</td></tr>
612
616
  <tr><td>The model is refused, or not found</td><td>The seat's plan or your organization's Copilot policies do not allow that model: pick one the sign-in listed, or ask a Copilot admin to enable it.</td></tr>
613
- <tr><td><code>GitHub Copilot runs through the ForgeQE engine, which is not set up</code></td><td>Run <code>forgeqe setup</code>.</td></tr>
617
+ <tr><td><code>GitHub Copilot runs through the ForgeQE engine, which is not set up</code> (or <code>could not be set up (…)</code>)</td><td>Run <code>forgeqe setup</code>; the reason in brackets says what failed.</td></tr>
614
618
  <tr><td><code>CERTIFICATE_VERIFY_FAILED</code> while downloading Copilot's runtime</td><td>Your network inspects HTTPS. Update ForgeQE and run <code>forgeqe setup</code>, then sign in again: it uses the certificates your computer trusts (see <a href="../HOW_TO_USE.md#company-networks">Company networks</a>). If it still fails, run <code>forgeqe doctor</code> and send its output to IT.</td></tr>
615
619
  </tbody>
616
620
  </table></div>
@@ -731,7 +735,7 @@ Add a GitHub Actions workflow that runs tests/cases.yaml on every PR, and make i
731
735
  </tbody>
732
736
  </table></div>
733
737
  <p><code>start_url</code> in <code>forgeqe.yaml</code> or <code>--url</code> pins a start page for browser runs, such as a staging app. Passed runs become tests in the current folder; <code>forgeqe start --repo ../app</code> puts them in that repo instead, and <code>--no-code</code> turns tests off.</p>
734
- <p>ForgeQE's agent runs on the agent runtime with the active profile's model (or <code>code.model</code>), or, with <code>llm.routing: auto</code>, the model the router picks for the <code>agent</code> area when the session starts (<code>--profile</code> and <code>code.model</code> still win); it cannot run on a <code>github_copilot</code> profile yet. ForgeQE downloads the agent runtime into <code>~/.forgeqe/tools</code> 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.</p>
738
+ <p>ForgeQE's agent runs on the agent runtime with the active profile's model (or <code>code.model</code>), or, with <code>llm.routing: auto</code>, the model the router picks for the <code>agent</code> area when the session starts (<code>--profile</code> and <code>code.model</code> still win). A <code>github_copilot</code> profile runs it on your Copilot seat. ForgeQE downloads the agent runtime into <code>~/.forgeqe/tools</code> 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.</p>
735
739
  <p>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 (<code>Thinking about step 3…</code>, <code>Acting in the browser (step 3)…</code>). Each step starts with <code>+ Thought: 4.2s</code>, the time the model took to decide. When the run ends, a summary card closes the transcript:</p>
736
740
  <pre><code>┃ ✓ Task complete 10 steps · 1m 42s · 65.3K tokens
737
741
  ┃
@@ -911,6 +915,7 @@ forgeqe run &quot;Run the cases in smoke.yaml and don't post results&quot; --pla
911
915
  <p>How memory saves time and tokens:</p>
912
916
  <ul>
913
917
  <li><strong>Replay.</strong> 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 <code>↻</code> and shows the locator used (<code>click &quot;Search&quot; [role 88%]</code>).</li>
918
+ <li><strong>The site's rulebook.</strong> Page memory keeps what worked; the rulebook keeps what did not. When an action fails during a run and the agent then finds one that works, it may end its answer with a line or two starting <code>Lesson:</code> (&quot;On the booking page, type the date in the Check-in field; clicking a day in the calendar does nothing&quot;). ForgeQE keeps a lesson only when that run passed, in <code>rules/&lt;host&gt;.json</code> in page memory, and every later run that starts on that site gets the rules, so it does not spend steps on the same dead end. The lesson lines are taken out of the run's summary. The book works like Scribe's rulebook (under Keeping Scribe's cost down): at most 15 one-line rules, merged when learned again, the least confirmed and oldest dropped first, expired after 180 days unconfirmed, and a rule with a link, a token, a destructive command, or wording that drops instructions is refused. ForgeQE says each new rule (<code>Learned for this site: …</code>). <code>browser.rulebook: false</code> turns it off; with page memory off there is none.</li>
914
919
  <li><strong>Hand-off.</strong> With <code>replay: verify</code> (the default) the agent then looks at the page once and confirms the result. <code>replay: trust</code> 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. <code>replay: off</code> records memory but never replays.</li>
915
920
  <li><strong>Failed runs.</strong> A run that fails keeps the steps that worked before it went wrong (<code>resume.json</code> 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 (<code>resume_from</code>), so the retry starts from the same point instead of step 1.</li>
916
921
  <li><strong>Cut-off runs.</strong> 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 <code>resume.json</code>, so <code>resume_from</code> 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.</li>
@@ -1842,12 +1847,16 @@ model can do: ForgeQE finds out.</p>
1842
1847
  models_file: ./llms.json
1843
1848
  routing: auto # off (the default for existing projects) | shadow | auto
1844
1849
  </code></pre>
1845
- <p><code>forgeqe init</code> writes <code>routing: auto</code> for new projects. With no <code>routing</code> line, it is on while the active profile is
1846
- GitHub Copilot: Copilot cannot run ForgeQE's agent and Scribe, so the router finds them another configured model, and
1847
- Copilot keeps driving the browser. <code>routing: off</code> turns that off too. <code>shadow</code> decides and logs each pick in the session log
1850
+ <p><code>forgeqe init</code> writes <code>routing: auto</code> for new projects. With no <code>routing</code> line it is off. <code>shadow</code> decides and logs each pick in the session log
1848
1851
  (<code>model.route</code>) but changes nothing, so you can see what the router would do before you let it. Shadow still runs the
1849
1852
  live checks and the rating call described below.</p>
1850
- <p>See the picks:</p>
1853
+ <p>Whatever <code>routing</code> says, the model an area gets must work: its key or sign-in is set and it passed a live call
1854
+ (one per model, kept for a day in <code>.forgeqe/model-checks.json</code> once it passes; a failed one is never kept, and a failed
1855
+ check in <code>model-profile.json</code> is checked again). When it does not, the next model that works is used, a GitHub Copilot
1856
+ profile first, and ForgeQE says why and how to fix the first. When none works, the error lists each model with the fix.
1857
+ Only <code>--profile</code> skips this. With <code>auto</code>, a GitHub Copilot seat counts as costing nothing more per call, so it is picked
1858
+ whenever it is rated good enough.</p>
1859
+ <p>See the picks, and every model's check with its fix:</p>
1851
1860
  <pre><code>forgeqe models --routes
1852
1861
  </code></pre>
1853
1862
  </div>
@@ -3779,7 +3788,7 @@ tokens and the like) show as <code>•••</code> in results. A check compares
3779
3788
  ┃ Handoff .forgeqe/reports/20260928-172700/handoff.md
3780
3789
  </code></pre>
3781
3790
  <p>When no test was written, the Test row says why: the run did not pass, the session has <code>--no-code</code>, or the run was not handed to the coding agent.</p>
3782
- <p>Scribe uses the active <code>llms.json</code> profile, or, with <code>llm.routing: auto</code>, the profile the router picks for the <code>coding</code> area (<code>--profile</code> and <code>code.model</code> still win; see <a href="#doc-docs-model_routing-model-routing-the-right-configured-model-for-each-task">docs/MODEL_ROUTING.md</a>). The key stays in your environment: the agent runtime's config refers to it as <code>{env:WP_AZURE_API_KEY}</code> and never contains the value. An <code>auth: entra</code> profile reaches the model through ForgeQE's local token gateway (see <a href="../HOW_TO_USE.md#signing-in-to-the-model-without-a-key-microsoft-entra-id">Signing in to the model without a key</a>). An Azure profile goes through the agent runtime's <code>azure</code> provider on <code>&lt;endpoint&gt;/openai/v1</code> (the Responses API, with the deployment as the model). <code>openai_compatible</code> and <code>ollama</code> profiles use their <code>base_url</code>. A <code>github_copilot</code> profile cannot run Scribe yet, and <code>code.model: github-copilot/...</code> is refused: the agent runtime's own Copilot provider signs in through a third-party app on your GitHub account. <code>code.model: provider/model</code> (or <code>--code-model</code>) uses one of the agent runtime's built-in providers instead, with that provider's usual key variable (for example <code>ANTHROPIC_API_KEY</code> for <code>anthropic/...</code>).</p>
3791
+ <p>Scribe uses the active <code>llms.json</code> profile, or, with <code>llm.routing: auto</code>, the profile the router picks for the <code>coding</code> area (<code>--profile</code> and <code>code.model</code> still win; see <a href="#doc-docs-model_routing-model-routing-the-right-configured-model-for-each-task">docs/MODEL_ROUTING.md</a>). The key stays in your environment: the agent runtime's config refers to it as <code>{env:WP_AZURE_API_KEY}</code> and never contains the value. An <code>auth: entra</code> profile reaches the model through ForgeQE's local token gateway (see <a href="../HOW_TO_USE.md#signing-in-to-the-model-without-a-key-microsoft-entra-id">Signing in to the model without a key</a>). An Azure profile goes through the agent runtime's <code>azure</code> provider on <code>&lt;endpoint&gt;/openai/v1</code> (the Responses API, with the deployment as the model). <code>openai_compatible</code> and <code>ollama</code> profiles use their <code>base_url</code>. A <code>github_copilot</code> profile runs Scribe through ForgeQE's Copilot gateway (see <a href="../HOW_TO_USE.md#github-copilot-seats-as-the-model">GitHub Copilot seats as the model</a>). <code>code.model: github-copilot/...</code> is refused: the agent runtime's own Copilot provider signs in through a third-party app on your GitHub account. <code>code.model: provider/model</code> (or <code>--code-model</code>) uses one of the agent runtime's built-in providers instead, with that provider's usual key variable (for example <code>ANTHROPIC_API_KEY</code> for <code>anthropic/...</code>).</p>
3783
3792
  <p>Scribe may edit files and run commands anywhere in the repo without asking. <code>git push</code> in any form is denied (pushing goes through ForgeQE's guarded <code>push_branch</code> tool, section 8), and it cannot touch files outside the repo except the run and memory directories, which it may read.</p>
3784
3793
  <p>More ways to run it:</p>
3785
3794
  <pre><code class="language-bash">forgeqe code --repo ../app # the latest run in .forgeqe/reports/
@@ -3810,6 +3819,7 @@ forgeqe run &quot;...&quot; --no-code # no tests
3810
3819
  <p><strong>When the flow cannot be reproduced.</strong> If ForgeQE's own replay of the run could not reach the run's final page and Scribe's first test fails too, the job stops there and says which replayed step failed and why, instead of spending its remaining attempts on a flow no script can repeat as recorded.</p>
3811
3820
  <p><strong>Why a test failed.</strong> When ForgeQE's run of Scribe's test fails, the ✗ line and the next attempt say why in the test's own words: dotnet test's Error Message, pytest's <code>E</code> lines, or the error with its Expected and Received values (Playwright, Jest, JUnit), not the runner's summary line.</p>
3812
3821
  <p><strong>Keeping Scribe's cost down.</strong> 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>code.max_attempts</code> (default 3) and <code>code.max_tokens</code> (default 1,500,000; <code>0</code> 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 <code>max_attempts</code>) 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>code.tidy: false</code> 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>code.max_steps</code> (default 50) caps the tool calls in one of Scribe's turns. <code>code.review_profile</code> runs the reviewer on a cheaper llms.json profile.</p>
3822
+ <p><strong>Scribe's rulebook: the same mistake once.</strong> When a job passes after a failed test run or a reviewer's change, Scribe's report gives up to three one-line rules that would have avoided the mistake (&quot;Wait for the cart badge with toHaveText before clicking Checkout; it updates after a request&quot;). ForgeQE keeps them in <code>.forgeqe/scribe-rules.json</code> in the repository, and every attempt of later jobs, and every healing session, starts with them. A lesson from a job that did not pass, or that passed at once, is not kept: only a fix that worked becomes a rule. The book stays small, since it is sent with each model call: at most 15 rules of one line each; a lesson learned again is merged into its rule (shown as &quot;learned 3 times&quot;) instead of added; when it is full, the rule confirmed least and longest ago goes, and a rule not learned again for 180 days expires. The rules are the coding agent's own words, so a rule with a link, something like a token, a destructive command, or wording that tells an agent to drop its instructions is refused, and the agents are told they are hints that never override their instructions or the team's guardrails. Commit the file to share the rules with the team and see each change in review; edit or delete a rule there (the agents cannot change <code>.forgeqe</code>). ForgeQE says each new rule as it learns it (<code>Learned for next time: …</code>). <code>code.rulebook: false</code> turns it off.</p>
3813
3823
  </div>
3814
3824
  </section>
3815
3825
  <p class="see">See <a href="#doc-how_to_use-generated-code">Generated code</a>.</p>
@@ -94,6 +94,7 @@ browser:
94
94
  allowed_hosts: []
95
95
  judge: false # true: a second model call checks each finished run against the goal and can fail it
96
96
  overlay: true # visible browser: ForgeQE start page, edge glow, a bar with the current step, your mouse and keyboard locked while the agent works
97
+ # rulebook: false # the agent keeps one-line rules per site, learned when it recovered from a failed action (page memory rules/<host>.json; default on)
97
98
  # start_url: https://staging.example.com # optional; omit to let the agent choose the site
98
99
  # remote: # inline settings for the selected remote provider; override the provider file when both are set
99
100
  # browser: chrome # BrowserStack: chrome or edge (ForgeQE drives the browser over CDP)
@@ -168,6 +169,7 @@ code:
168
169
  # repo: ../my-app # where passed runs become tests (default: the current folder; --no-code turns it off)
169
170
  # test_command: npx playwright test # the repo's test command, for forgeqe heal; default: the agent finds it
170
171
  max_attempts: 3 # test runs before giving up (also healing attempts); each attempt after the first starts a fresh session from a summary
172
+ # rulebook: false # Scribe keeps rules learned from its own fixed mistakes in .forgeqe/scribe-rules.json (default on)
171
173
  # max_tokens: 1500000 # stop a coding job past this many tokens (cached included) and report how far it got
172
174
  # review_profile: azure-mini # llms.json profile for the reviewer, which only reads and judges: a cheaper model is enough
173
175
  test_timeout_seconds: 600 # per test run
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capagents/forgeqe",
3
- "version": "2.2.10",
3
+ "version": "2.3.1",
4
4
  "description": "ForgeQE: a browser agent CLI that runs goals and test cases in local Chrome or Chromium, or BrowserStack and TestMu AI/LambdaTest when configured, and turns passing runs into tests in your repo",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "repository": {
package/prompts/README.md CHANGED
@@ -24,6 +24,7 @@ project; leave it as it is to keep getting ForgeQE's improvements when you updat
24
24
  | domain-rule.md | How agents apply the product's industry risks and regulations, declared or worked out (included in every agent that analyses requirements or designs, writes, reviews, or heals tests) |
25
25
  | browser-*.md | The browser agent: error recovery, when a goal counts as done, recording checks, clicking so runs become tests, step verdicts for test cases, picking skills |
26
26
  | browser-extra.md | Your own instructions for the browser agent, added to every run (empty to start with) |
27
+ | site-lessons.md | Asks the browser agent for a one-line rule about the site after it recovers from a failed action, for the site's rulebook |
27
28
 
28
29
  How it works:
29
30
 
@@ -0,0 +1,12 @@
1
+ ---
2
+ name: site-lessons
3
+ description: "Asks the browser agent for one-line rules about the site after it recovers from a failed action. ForgeQE keeps a rule only when the run passes, in the site's rulebook in page memory (src/code/rulebook.ts)."
4
+ used_by: "the browser agent (every browser run with page memory on)"
5
+ kind: fragment
6
+ ---
7
+ ## Lessons for this site
8
+ - If an action failed in this run and you then found an action that works, you MAY end your final answer with one or two lines that start with "Lesson:".
9
+ - Each lesson MUST be one rule for this site, on one line, with fewer than 200 characters.
10
+ - A lesson MUST tell a later run what to do on a page of this site. For example: "Lesson: On the booking page, type the date in the Check-in field. A click on a day in the calendar does nothing."
11
+ - A lesson MUST NOT be a summary of this task, and MUST NOT contain a link, a password, or a token.
12
+ - If no action failed, you MUST NOT write a lesson.