FE-1437: Move brunch-agent into hashintel/hash with its history - #9274
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #9274 +/- ##
==========================================
+ Coverage 59.71% 60.10% +0.39%
==========================================
Files 1423 1314 -109
Lines 138862 132988 -5874
Branches 6572 6190 -382
==========================================
- Hits 82915 79933 -2982
+ Misses 54881 52034 -2847
+ Partials 1066 1021 -45 Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
b898a9d to
65c318b
Compare
PR SummaryHigh Risk Overview The app mounts a Gherkin elicitor, durable SQLite conversations, a local capture store, and Petrinaut gains a host-owned interactive-tool registry (patch changeset). The local-storage demo registers an inline Reviewed by Cursor Bugbot for commit 27fa5c5. Bugbot is set up for automated code reviews on this repo. Configure here. |
Benchmark results
|
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| resolve_policies_for_actor | user: empty, selectivity: high, policies: 2002 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: medium, policies: 1002 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: high, policies: 3314 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: medium, policies: 1527 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: high, policies: 2078 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: medium, policies: 1033 | Flame Graph |
policy_resolution_medium
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| resolve_policies_for_actor | user: empty, selectivity: high, policies: 102 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: medium, policies: 52 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: high, policies: 269 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: medium, policies: 108 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: high, policies: 133 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: medium, policies: 63 | Flame Graph |
policy_resolution_none
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| resolve_policies_for_actor | user: empty, selectivity: high, policies: 2 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: medium, policies: 2 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: high, policies: 8 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: medium, policies: 3 | Flame Graph |
policy_resolution_small
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| resolve_policies_for_actor | user: empty, selectivity: high, policies: 52 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: medium, policies: 26 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: high, policies: 94 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: medium, policies: 27 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: high, policies: 66 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: medium, policies: 29 | Flame Graph |
read_scaling_complete
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| entity_by_id;one_depth | 1 entities | Flame Graph | |
| entity_by_id;one_depth | 10 entities | Flame Graph | |
| entity_by_id;one_depth | 25 entities | Flame Graph | |
| entity_by_id;one_depth | 5 entities | Flame Graph | |
| entity_by_id;one_depth | 50 entities | Flame Graph | |
| entity_by_id;two_depth | 1 entities | Flame Graph | |
| entity_by_id;two_depth | 10 entities | Flame Graph | |
| entity_by_id;two_depth | 25 entities | Flame Graph | |
| entity_by_id;two_depth | 5 entities | Flame Graph | |
| entity_by_id;two_depth | 50 entities | Flame Graph | |
| entity_by_id;zero_depth | 1 entities | Flame Graph | |
| entity_by_id;zero_depth | 10 entities | Flame Graph | |
| entity_by_id;zero_depth | 25 entities | Flame Graph | |
| entity_by_id;zero_depth | 5 entities | Flame Graph | |
| entity_by_id;zero_depth | 50 entities | Flame Graph |
read_scaling_linkless
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| entity_by_id | 1 entities | Flame Graph | |
| entity_by_id | 10 entities | Flame Graph | |
| entity_by_id | 100 entities | Flame Graph | |
| entity_by_id | 1000 entities | Flame Graph | |
| entity_by_id | 10000 entities | Flame Graph |
representative_read_entity
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/block/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/book/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/building/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/organization/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/page/v/2
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/person/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/playlist/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/song/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/uk-address/v/1
|
Flame Graph |
representative_read_entity_type
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| get_entity_type_by_id | Account ID: bf5a9ef5-dc3b-43cf-a291-6210c0321eba
|
Flame Graph |
representative_read_multiple_entities
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| entity_by_property | traversal_paths=0 | 0 | |
| entity_by_property | traversal_paths=255 | 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true | |
| entity_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false | |
| entity_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true | |
| entity_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true | |
| entity_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true | |
| link_by_source_by_property | traversal_paths=0 | 0 | |
| link_by_source_by_property | traversal_paths=255 | 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true | |
| link_by_source_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false | |
| link_by_source_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true | |
| link_by_source_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true | |
| link_by_source_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true |
scenarios
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| full_test | query-limited | Flame Graph | |
| full_test | query-unlimited | Flame Graph | |
| linked_queries | query-limited | Flame Graph | |
| linked_queries | query-unlimited | Flame Graph |

🌟 What is the purpose of this PR?
Brunch — the elicitation-agent harness developed to date in the standalone
brunch-literepository — moves intohashintel/hash, which becomes its sole writable home. This branch imports the standalone history, renames the package family to@hashintel/brunch-agent*underlibs/@hashintel/brunch-agent/(application atapps/brunch-agent), and adopts the HASH toolchain (Yarn/Turbo, Biome, Vitest) in place of Bun.🔗 Related links
libs/@hashintel/brunch-agent/docs/planning/_shared/hash-monorepo-import-plan.mdlibs/@hashintel/brunch-agent/docs/adr/0004-in-petrinaut-staging-and-the-monorepo-import.md43a0022918861846344b96a32cb94f92e2ee96ae(read-only reference)🚫 Blocked by
Nothing — the import gates (FE-1434/FE-1435 spike verdicts, standalone review stack) all landed before the cutover.
🔍 What does this change?
Adds the Brunch package family as five new workspaces: the substrate-independent harness (
@hashintel/brunch-agent), the Flue binding, the AI SDK transport, the Gherkin target plugin, and the application atapps/brunch-agent. It also lands the first slice of the Petrinaut website integration — a generic interactive-tool extension point in@hashintel/petrinaut(with changeset) and an app-level Brunch ask tool inapps/petrinaut-website— which the trimmed FE-1440 builds on. Boundary rules survive as enforced tests: plugins depend only on the harness, transports never on a binding,@hashintel/petrinautstays Brunch-agnostic, and applications are the only Brunch–Petrinaut meeting point.🏗️ Agent notes
Final physical shape
The existing root workspace globs,
apps/**andlibs/**, already discover these nested packages. No new root workspace rule or context-rootpackage.jsonwas needed.Package identities and dependency graph
The standalone names became HASH-native:
@brunch/core→@hashintel/brunch-agent@brunch/binding-flue→@hashintel/brunch-agent-binding-flue@brunch/transport-aisdk→@hashintel/brunch-agent-transport-aisdk@brunch/plugin-gherkin→@hashintel/brunch-agent-plugin-gherkin@brunch/dev→@apps/brunch-agentThe planned invariants remain:
apps/brunch-agentremains independent of Petrinaut packages;apps/petrinaut-websiteis the Brunch/Petrinaut meeting point.All packages are private, use
0.0.0-private, carry the HASH license, useworkspace:*internally, and have versions reconciled through the HASH lockfile and constraints.Toolchain rewiring
The largest incidental adaptation was removing the standalone Bun toolchain.
bun:test→ Vitest.Bun.spawn→ a shared Node child-process helper.Bun.file→ NodefsAPIs.Bun.spawnSync→ Nodechild_process.Each workspace now exposes HASH-shaped tasks:
buildlint:eslintlint:tsctest:unitdevtasks where appropriateTypeScript configuration was split per package, using strict bundler resolution,
tsgo, explicit Node/DOM types, and explicit.tsextensions where Node executes source directly.Build reshaping
Each library became an independently built Vite ESM library:
client-tools,storage, andtestingentry points.client-toolsentry point.An attempted declaration-bundling setup exposed incompatibilities with Brunch's Valibot value/type same-name pattern. The resulting private-package contract is therefore deliberately:
That preserved type ownership without forcing changes to the domain schemas merely to satisfy a declaration bundler.
The app also gained a dedicated
vitest.config.ts: loading its full Vite/Flue configuration under Vitest caused the Flue build plugin to execute in an incompatible SSR context.Test ownership reshaping
The old repository-level tests were distributed according to what they govern:
core/test/architecture/.apps/brunch-agent/test/.The architecture scanner was rewritten for the new topology. It discovers:
libs/@hashintel/brunch-agent/packages/;apps/brunch-agentworkspace.Its dependency proof also changed. Bun's isolated installation allowed tests to assert that forbidden packages physically could not resolve. HASH's Yarn linker may hoist dependencies, so that would have become a false proof. The replacement checks:
Documentation and agent-context reshaping
The nested directory became a true domain context:
CONTEXT.mdremains the canonical Brunch glossary.AGENTS.mdandCLAUDE.mdwere rewritten for operation inside HASH.docs/spec.mdremains authoritative.docs/history/.Import-process adaptations
The Git history was imported in four deliberately separate stages:
That unusual order was discovered during execution:
Post-review follow-ups
The review follow-ups:
turbo.jsonfiles so build outputs and dependency builds are explicit;.flue/,.data-wipe-me/, and documentation drafts;Petrinaut integration
The imported transport is wired into the Petrinaut demo without coupling the Brunch application to Petrinaut:
brunch_askwidget.tool-brunch_askpayload shape.Type ownership
The host-tool extension preserves source-of-truth typing:
unknownvalues are confined to genuine runtime boundaries such as raw AI SDK dynamic-tool data.Post-import branch state
git log --follow/blame continuity into pre-import commits.gh stackto Graphite (matching HASH's repo-wide Graphite use).listen EPERM), breaking@hashintel/ds-components#codegenlocally; no branch commit touches ds-components.Pre-Merge Checklist 🚀
🚢 Has this modified a publishable library?
This PR:
@hashintel/petrinautgains the interactive-tool extension point (patch changeset); the imported Brunch packages are all private.📜 Does this require a change to the docs?
The changes in this PR:
Brunch context, architecture, planning, and operating documentation were updated for HASH, and the Petrinaut AI assistant guide documents host-specific interactive widgets.
🕸️ Does this require a change to the Turbo Graph?
The changes in this PR:
turbo.jsonfiles have been updated to reflect thismain; the full standalone history remains preserved on this branch and in the PR record, and the standalone repository stays available read-only at the frozen SHA.🐾 Next steps
apps/petrinaut-website— mode switch, browser identifier bootstrap, remote transport swap🛡 What tests cover this?
The final focused verification completed 23/23 Turbo tasks. Brunch core completed 114/114 tests.
❓ How to test this?
Run:
Run:
Start the Brunch agent and Petrinaut website development servers.
Open the Petrinaut local-storage demo and send an elicitation prompt.
Confirm the inline Brunch question renders, accepts an answer, and continues the same assistant message without errors or duplication.
📹 Demo
The local browser flow has been manually verified. A refreshed screenshot should be added before merge.
🤖 Generated with Claude Code