diff --git a/src/server/templates/skill/SKILL.md b/src/server/templates/skill/SKILL.md index e86cb0e56..f78f380e8 100644 --- a/src/server/templates/skill/SKILL.md +++ b/src/server/templates/skill/SKILL.md @@ -120,6 +120,7 @@ digraph brv_flow { | Inspect past curates/queries | `brv curate view` / `brv query-log view` | `history.md` | | Track context-tree changes (git-style) | `brv vc` | `vc.md` | | Consolidate / dedupe / prune the context tree | `brv dream` | `dream.md` | +| Visually browse / view curated knowledge in a browser | `brv webui` | `curate.md` | | Find project paths | `brv locations` | `brv locations --help` | | Diagnose a `brv` error | `brv status` | `brv status --help` | @@ -173,6 +174,7 @@ Each detail file lives in this skill directory. Read the relevant one before inv - `brv swarm ` — cross-source memory federation. See `swarm.md`. - `brv vc ` — git-style version control of the context tree. See `vc.md`. - `brv dream ` — three-phase context-tree cleanup (link / merge / prune / synthesize). See `dream.md`. +- `brv webui [--port ]` — open or reconfigure the ByteRover dashboard when needed. For routine curate and onboarding closeouts, share `http://localhost:7700`; if a known custom Web UI port is already serving, share that localhost URL instead. The **Contexts page** renders everything saved under `.brv/context-tree/`. If that link does not open, tell the user they can run `brv webui` to open the dashboard; use `brv webui --port ` only when the user asks to open/change the dashboard port or the current port has a conflict. See `curate.md`. - `brv curate view` / `brv query-log view|summary` — inspect history. See `history.md`. - `brv locations` — list registered projects and their context tree paths. Use `-f json` for machine-readable output. Run `brv locations --help` for flags. - `brv status` — diagnose any `brv` error (auth + project state). Run first when a command misbehaves. diff --git a/src/server/templates/skill/curate.md b/src/server/templates/skill/curate.md index 054f9e1dc..093c30e6b 100644 --- a/src/server/templates/skill/curate.md +++ b/src/server/templates/skill/curate.md @@ -28,6 +28,9 @@ brv curate "Authentication middleware validates JWTs in src/middleware/auth.ts a brv curate "Retry helper in src/retry.ts treats HTTP 429 as retryable with exponential backoff." brv curate view --detail brv review pending --format json +# After a successful curate, share the Web UI link: http://localhost:7700 +# If a known custom Web UI port is already serving, share that localhost URL instead +# If that link does not open, tell the user they can run brv webui ``` ## Session Protocol @@ -51,12 +54,70 @@ Curate runs as request -> response -> request: brv curate --session --response-file envelope.json --delete-response-file --format json ``` 4. Branch on `data.status`: - - `done` - report `data.filePath`. + - `done` - report `data.filePath`, then give the user `http://localhost:7700` so they can see the saved topic in the Contexts page. If a known custom Web UI port is already serving, share that localhost URL instead. If that link does not open, tell the user they can run `brv webui` to open the dashboard; use `brv webui --port ` only when the user asks to open/change the dashboard port or the current port has a conflict. - `needs-llm-step` with `step: "correct-html"` - fix validation errors from `data.errors[]` and continue the same session. - `failed` - report the error messages. If `data.errors[]` includes `kind: "path-exists"`, prefer merging the existing topic with the new facts and continue with `--overwrite`. Choose a different path only when the collision is accidental. Replace existing content only when the user explicitly asked for replacement. +## Example Session Responses + +Every `--format json` response is wrapped in `{ "command", "data", "success", "timestamp" }`. Branch on `data.status`. The three envelopes below show a full session: kickoff, one correction turn, then completion. + +1. Kickoff (`brv curate "" --format json`) returns a live session asking you to author HTML: + +```json +{ + "command": "curate", + "data": { + "ok": true, + "status": "needs-llm-step", + "step": "generate-html", + "sessionId": "550e8400-e29b-41d4-a716-446655440000", + "prompt": "" + }, + "success": true, + "timestamp": "2026-05-29T14:30:45.123Z" +} +``` + +2. If your HTML fails validation, the same session stays open with `step: "correct-html"` and the errors to fix: + +```json +{ + "command": "curate", + "data": { + "ok": false, + "status": "needs-llm-step", + "step": "correct-html", + "sessionId": "550e8400-e29b-41d4-a716-446655440000", + "errors": [ + {"kind": "unknown-bv-element", "message": "Unknown element ", "tag": "bv-note"} + ], + "prompt": "" + }, + "success": false, + "timestamp": "2026-05-29T14:30:50.456Z" +} +``` + +3. On success, `data.status` is `done` and `data.filePath` is the topic path under `.brv/context-tree/`: + +```json +{ + "command": "curate", + "data": { + "ok": true, + "status": "done", + "filePath": "security/auth.html" + }, + "success": true, + "timestamp": "2026-05-29T14:30:55.789Z" +} +``` + +→ Only now is the topic saved. Report `data.filePath` and hand the user `http://localhost:7700`, so they can open the Contexts page and see it. If a known custom Web UI port is already serving, share that localhost URL instead. If that link does not open, tell the user they can run `brv webui` to open the dashboard; use `brv webui --port ` only when the user asks to open/change the dashboard port or the current port has a conflict. + ## HTML Topic Contract Curate output is one bare HTML topic document rooted at ``. The first character must be `<`, the last characters must be ``, and there must be no prose wrapper and no code fences around the response. @@ -135,6 +196,13 @@ brv review pending --format json Then tell the user what needs review. +## View What You Saved + +On `data.status: "done"`, the topic is written to `.brv/context-tree/`. To let the user actually see it, point them at the dashboard: + +- Give the user `http://localhost:7700`; if a known custom Web UI port is already serving, share that localhost URL instead. It opens the **Contexts page**, which renders the whole `.brv/context-tree/`. The path you just saved (e.g. `security/auth`) shows up as a node in the tree with its rendered content, edit controls, change history, and last-updated metadata. +- If that link does not open, tell the user they can run `brv webui` to open the dashboard. Use `brv webui --port ` only when the user asks to open/change the dashboard port or the current port has a conflict. + ## Common Mistakes | Mistake | Correct behavior | @@ -143,3 +211,4 @@ Then tell the user what needs review. | Omitting `keywords` when retrieval terms are obvious | Add comma-separated `keywords` on `` | | Reporting completion before a session reaches `data.status: "done"` | Wait for `done` before telling the user the topic is saved | | Overwriting an existing path without preserving prior facts | Merge existing content unless the user explicitly wants replacement | +| Saying the topic is saved without showing the user where to see it | After `done`, give the user `data.filePath` and the Web UI link, usually `http://localhost:7700` | diff --git a/src/server/templates/skill/onboarding.md b/src/server/templates/skill/onboarding.md index a145d89f2..6491e1e38 100644 --- a/src/server/templates/skill/onboarding.md +++ b/src/server/templates/skill/onboarding.md @@ -100,7 +100,7 @@ Saved: Lives at .brv/context-tree/ — local-only. -See it in your browser: http://localhost:7700 +See it in your browser: http://localhost:7700 — or run brv webui if that link doesn't open. Also version-controlled, cloud-syncable, and shareable across agents — more at the end. ``` @@ -135,7 +135,7 @@ Also version-controlled, cloud-syncable, and shareable across agents — more at The browser URL is the **verifiable** trust proof — the user can click it in 2 seconds and see their memory in a real local dashboard. Stronger than any worded assurance. -Do NOT tell the user to "run `brv webui`" — the daemon auto-starts the web server on the persisted port (default 7700). The URL works as soon as the daemon is alive, which it already is. +Use `http://localhost:7700` for the Web UI link unless a known custom Web UI port is already serving, in which case use that localhost URL. Do NOT run `brv webui` as part of every tour closeout just to produce this link. If that link does not open, tell the user they can run `brv webui` to open the dashboard. Use `brv webui --port ` only when the user asks to open/change the dashboard port or the current port has a conflict. Do NOT ask "is this right?" — that turns the artifact into a form. Users who want to correct it will; users who don't, won't be slowed down. diff --git a/test/unit/infra/connectors/skill/skill-connector.test.ts b/test/unit/infra/connectors/skill/skill-connector.test.ts index ceccd3b80..c052c01c6 100644 --- a/test/unit/infra/connectors/skill/skill-connector.test.ts +++ b/test/unit/infra/connectors/skill/skill-connector.test.ts @@ -157,6 +157,13 @@ describe('SkillConnector', () => { expect(content).to.include('brv query') expect(content).to.include('brv curate') expect(content).to.include('brv curate view') + expect(content).to.include('brv webui') + expect(content).to.include('http://localhost:7700') + expect(content).to.include('known custom Web UI port is already serving') + expect(content).to.include('If that link does not open, tell the user they can run `brv webui`') + expect(content).to.include('brv webui --port ') + expect(content).not.to.include('http://localhost:') + expect(content).not.to.include('printed Web UI URL') expect(content).to.include('## When To Use') expect(content).to.include('## Quick Reference') expect(content).not.to.include('<<<<<<<') @@ -181,6 +188,29 @@ describe('SkillConnector', () => { expect(swarmContent).to.include('parallel') }) + it('should guide installed skill docs to share the default Web UI link with command fallback', async () => { + const agent = 'Claude Code' as const + const {projectPath} = SKILL_CONNECTOR_CONFIGS[agent] + await skillConnector.install(agent) + + const skillDir = path.join(testDir, projectPath, BRV_SKILL_NAME) + const contents = await Promise.all( + SKILL_FILE_NAMES.map((fileName) => readFile(path.join(skillDir, fileName), 'utf8')), + ) + + for (const content of contents) { + expect(content).not.to.include('printed Web UI URL') + expect(content).not.to.include('http://localhost:') + expect(content).not.to.include('run `brv webui` after every successful curate') + } + + const onboardingContent = await readFile(path.join(skillDir, 'onboarding.md'), 'utf8') + expect(onboardingContent).to.include('http://localhost:7700') + expect(onboardingContent).to.include('known custom Web UI port is already serving') + expect(onboardingContent).to.include('If that link does not open, tell the user they can run `brv webui`') + expect(onboardingContent).to.include('brv webui --port ') + }) + it('should create curate.md documenting the session protocol and bv-topic contract', async () => { const agent = 'Claude Code' as const const {projectPath} = SKILL_CONNECTOR_CONFIGS[agent] @@ -195,6 +225,13 @@ describe('SkillConnector', () => { expect(curateContent).to.include('') + expect(curateContent).not.to.include('http://localhost:') + expect(curateContent).not.to.include('printed Web UI URL') }) it('should create sibling guides with When-To and Common Mistakes sections', async () => {