feat(claw-server): self-healing per-host recipes (behind flag) - #1859
feat(claw-server): self-healing per-host recipes (behind flag)#1859Dani Akash (DaniAkash) wants to merge 4 commits into
Conversation
…ehind flag) Ports the storage + surfacing halves of browser-use/browser-harness's 'domain skills' convention to BrowserClaw so a coding-agent MCP client can leave a per-site Markdown note once and read it on every future visit. Self-healing loop as a filesystem convention, not an engine. Storage. Files live at <browserclawDir>/recipes/<slug>/<host-stem>/ <name>.md. Slug comes from identityService so recipes are scoped per MCP client (claude-code, codex-mcp-client, etc.). Host stem matches the upstream's helpers.py:134 reduction (strip www., take first label) so a folder is portable between browser-harness and BrowserClaw in either direction. Surfacing. A new NamedToolEffect fires on navigate when the flag is on. It annotates the tool result's structuredContent with domain_skills.{files, workspace_dir} and appends a synthetic text block for clients that only pass content[] to the LLM. Runs BEFORE audit so the annotation lands in resultMeta and the operator sees which recipes each agent was told about. Never touches error results or non-navigate calls. No-op with zero I/O when the flag is off. Writes. Deliberately no save_recipe / list_recipes MCP tool in v1. The coding agent uses its own Read/Write tools, matching how browser-harness itself works upstream. If Claude Desktop-like clients turn out to matter, Phase 2 adds the tool. Feature-flagged behind BROWSERCLAW_RECIPES=1. Off by default in v1 for careful rollout; flip to on-by-default after production soak. Adds a shared readBoolFlagDefaultFalse helper in env.ts for the opt-in shape. Tests: 12 unit tests on the recipes service (host-stem edge cases across http/https/chrome/about/file/data, IPs, localhost, cap enforcement, symlink following, subdir skipping, multi-agent + multi-host isolation) + 10 effect tests (flag gating, non-navigate passthrough, error passthrough, no-identity guard, chrome:// no-op, cold host hint, warm host hint, args-url fallback, structuredContent field preservation, multi-agent isolation). Full claw-server suite: 422 pass, 0 fail.
…flag is on Adds a Domain recipes block to BROWSERCLAW_MCP_INSTRUCTIONS when BROWSERCLAW_RECIPES is on. Tells the calling agent to Read every domain_skills file before acting on the site and to Write new .md notes to the workspace_dir when it figures something out. Uses the agent's own filesystem tools (matches how browser-harness's SKILL.md discipline works upstream). Refactor. mcp-prompt.ts now exposes getBrowserClawMcpInstructions() which reads env.recipesEnabled at call time so the composition reacts to flag flips without a re-import. single-server.ts is switched to the getter. The old BROWSERCLAW_MCP_INSTRUCTIONS constant stays exported as the base (flag-off) shape so the existing server-identity test's snapshot stays pinned. Test coverage: 2 unit tests on the getter (flag off returns base, flag on appends the recipes block with the full tail text). Full suite: 424 pass, 0 fail.
✅ Tests passed — 1986/1990
|
Greptile SummaryIntroduces Phase 1 of self-healing recipes: a filesystem-based per-agent per-host Markdown note store that surfaces relevant files to the LLM on every
Confidence Score: 4/5Safe to merge — the feature is entirely behind a default-off flag, all early-return guards are well-tested, and the path construction is secure thanks to slug sanitization on the identity side. The logic is solid and the 24 new tests cover edge cases thoroughly. The two remaining concerns are both style-level:
Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant LLM as LLM Agent
participant MCP as BrowserClaw MCP
participant Disp as Dispatch Loop
participant DSH as domain-skills-hint effect
participant FS as Filesystem (recipes dir)
participant Audit as applyAudit effect
LLM->>MCP: navigate("https://example.com")
MCP->>Disp: dispatchTool(call)
Disp->>Disp: applyOwnershipClaims
Disp->>Disp: applyTabsListView
Disp->>DSH: applyDomainSkillsHint(call, result)
alt BROWSERCLAW_RECIPES off
DSH-->>Disp: undefined (no-op)
else flag on + navigate + http/https + identity
DSH->>FS: readdirSync(recipes/slug/hostStem)
FS-->>DSH: [invitation.md, login.md]
DSH-->>Disp: result + structuredContent.domain_skills + content[] hint
end
Disp->>Audit: applyAudit(call, result)
Note over Audit: logs domain_skills in resultMeta
Disp-->>LLM: ToolResult with domain_skills annotation
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant LLM as LLM Agent
participant MCP as BrowserClaw MCP
participant Disp as Dispatch Loop
participant DSH as domain-skills-hint effect
participant FS as Filesystem (recipes dir)
participant Audit as applyAudit effect
LLM->>MCP: navigate("https://example.com")
MCP->>Disp: dispatchTool(call)
Disp->>Disp: applyOwnershipClaims
Disp->>Disp: applyTabsListView
Disp->>DSH: applyDomainSkillsHint(call, result)
alt BROWSERCLAW_RECIPES off
DSH-->>Disp: undefined (no-op)
else flag on + navigate + http/https + identity
DSH->>FS: readdirSync(recipes/slug/hostStem)
FS-->>DSH: [invitation.md, login.md]
DSH-->>Disp: result + structuredContent.domain_skills + content[] hint
end
Disp->>Audit: applyAudit(call, result)
Note over Audit: logs domain_skills in resultMeta
Disp-->>LLM: ToolResult with domain_skills annotation
|
…branch Removes the env-var gate on the recipes surfacing and the composed MCP instructions. The dispatch effect and the Domain-recipes discipline block are now always active on this branch. The branch serves as an epic that will grow the full feature (UI, docs, cleanup integration) before it merges to main; the flag was a rollout mechanism for a straight-to-main path we are no longer taking. - env.ts: drop the recipesEnabled field and the readBoolFlagDefaultFalse helper (only user was recipes). - mcp/mcp-prompt.ts: BROWSERCLAW_MCP_INSTRUCTIONS is now a single composed constant with base + recipes. getBrowserClawMcpInstructions() is gone; single-server.ts uses the constant directly again. - mcp/effects/domain-skills-hint.ts: drop the env.recipesEnabled guard. - Tests updated: 423 pass, 0 fail.
|
Converting this branch into an epic. Future work will target |
What ships
A convention-based self-healing mechanism for BrowserClaw's MCP dispatch loop: a coding-agent MCP client can leave a per-site Markdown note once and read it on every future visit to the same host. The mechanism is a filesystem convention plus one dispatch effect plus one appended instructions block. No engine, no ML, no schema migration, no UI.
Off by default behind
BROWSERCLAW_RECIPES=1for a careful rollout.The two commits
1.
feat(claw-server): add recipes service + domain-skills-hint effect (behind flag)services/recipes.ts:hostStemFromUrl(hostnameafter strippingwww., then the first dot-separated label, filtered tohttp:/https:),recipesDirFor,listRecipeFiles(sorted, capped at 10, subdir / non-file safe).mcp/effects/domain-skills-hint.ts: a newNamedToolEffectthat fires onnavigatewhen the flag is on and annotates the result'sstructuredContentwithdomain_skills.{files, workspace_dir}while also appending a syntheticcontent[]text block for clients that only passcontentto the LLM. Registered inBASE_EFFECTSbetweentabs-list-viewandauditso the annotation lands inresultMetaand the operator sees which recipes each agent was told about.env.ts:BROWSERCLAW_RECIPESflag via a newreadBoolFlagDefaultFalsehelper.chrome://no-op, cold host hint, warm host hint, args-url fallback, structuredContent field preservation, multi-agent isolation).2.
feat(claw-server): append recipe discipline to MCP instructions when flag is onmcp/mcp-prompt.ts: adds aDomain recipes:block that tells the agent toReadeverydomain_skills.filesbefore acting on the site and toWritenew.mdnotes toworkspace_dirwhen it figures something out. Refactored togetBrowserClawMcpInstructions()so the flag composition happens at call time.mcp/single-server.ts(+1 -1): switched the McpServer constructor to the getter.Storage layout
Recipes live at
<browserclawDir>/recipes/<slug>/<host-stem>/<name>.md, alongside the existingaudit.sqliteandreplays/. Slug comes fromidentityServiceso recipes are scoped per MCP client (claude-code,codex-mcp-client, etc.). Host stem is deliberately the same reduction upstream libraries use, so a folder is portable in either direction.Writes
Coding-agent MCP clients (Claude Code, Codex, Cursor, VS Code, Zed, OpenCode, Antigravity) use their own
Read/Writetools. That is why this PR ships zero new BrowserClaw MCP tools: the write path exists in the client, not the server. Clients that lack filesystem access (Claude Desktop-like) are a no-op today; a dedicated MCPsave_recipetool for those clients is a follow-up if needed.Full suite
bun testinapps/claw-server: 424 pass, 0 fail (was 400, +24 new tests across 3 files)bun run typecheck: cleanbunx biome check: cleanWhat is deliberately NOT in this PR
list_recipes,read_recipe,save_recipe). Coding-agent clients use their own filesystem tools.apps/claw-app/UI. Browsing / deleting recipes is a follow-up.Rollback
unset BROWSERCLAW_RECIPES(or set to0/false). The effect is a cheap early-return with no filesystem I/O; the instructions revert to the base block; existing recipe files stay on disk but are never read by the server until the flag flips back on.Manual verification
BROWSERCLAW_RECIPES=1 bun run startinsideapps/claw-server.navigate("https://news.ycombinator.com"). Confirm the tool result carriesstructuredContent.domain_skills.workspace_dirpointing at the per-slug per-host directory.frontpage-selectors.mdat that path with# HN\n- .titleline > a for top story titles".domain_skills.filesincludesfrontpage-selectors.mdand the synthetic text block names it.BROWSERCLAW_RECIPES=0, restart, navigate. Confirm nodomain_skillsfield appears and the instructions no longer include theDomain recipes:block.Test plan
apps/claw-serverunit tests green locallyFollow-ups (separate work)
shadcnAlertDialog with typed-confirmation for delete, matching the audit-cleanup UX).