Skip to content

feat: [ENG-2697] rewrite ByteRover skill — sub-skill split + Hermes connector#675

Open
DatPham-6996 wants to merge 12 commits into
proj/byterover-tool-modefrom
feat/ENG-2697
Open

feat: [ENG-2697] rewrite ByteRover skill — sub-skill split + Hermes connector#675
DatPham-6996 wants to merge 12 commits into
proj/byterover-tool-modefrom
feat/ENG-2697

Conversation

@DatPham-6996
Copy link
Copy Markdown
Collaborator

Summary

  • Problem: The ByteRover skill was a single 734-line SKILL.md with no
    progressive disclosure, and autonomous agents (OpenClaw, and now Hermes)
    had no reliable way to always load the ByteRover memory contract into their
    system prompt. Hub install also hardcoded scope: 'project', which threw
    "does not support project scope" for global-only skill agents.
  • Why it matters: Following the Superpowers skill model (visible workflow,
    focused sub-skills, predictable folder structure) makes the skill easier
    for agents to navigate and keeps the always-on memory rule in front of
    autonomous agents without bloating every invocation.
  • What changed:
    • Split SKILL.md into a thin entrypoint plus focused sub-skills
      (query/curate/review/swarm/vc/history/troubleshooting.md);
      SKILL_FILE_NAMES enumerates the full managed set and status/uninstall
      key off it.
    • Added the Hermes agent (skill + mcp), connector icon, and a YAML MCP
      config writer; McpConfigFormat now supports 'yaml'
      (~/.hermes/config.yaml).
    • Added managed BYTEROVER RULES block injection into Hermes/OpenClaw
      system-prompt files via autonomous-agent-attachments.ts +
      upsert/remove/hasByteroverBlock (idempotent re-install; stale/missing
      block reported as not-installed).
    • Added shared agent-path-resolver / skill-path-resolver honoring
      HERMES_HOME / OPENCLAW_STATE_DIR / OPENCLAW_CONFIG_PATH and
      per-agent globalRoot; OpenClaw skills moved to the openclaw-state root.
    • Hub install no longer hardcodes project scope; the daemon infers the
      per-agent default (global for global-only skill agents); writeSkillFiles
      takes object params with idempotent per-file existence checks.
  • What did NOT change (scope boundary): No changes to curate/query execution,
    context-tree storage, billing, or the transport schema beyond the existing
    hub-install scope being optional. Existing home/project-rooted agents
    (Claude, Cursor, etc.) keep their current paths and behavior.

Type of change

  • Bug fix
  • New feature
  • Refactor (no behavior change)
  • Documentation
  • Test
  • Chore (build, dependencies, CI)

Scope (select all touched areas)

  • TUI / REPL
  • Agent / Tools
  • LLM Providers
  • Server / Daemon
  • Shared (constants, types, transport events)
  • CLI Commands (oclif)
  • Hub / Connectors
  • Cloud Sync
  • CI/CD / Infra

Linked issues

  • Closes ENG-2697 (Linear: "Rewrite ByteRover skill based on Superpowers skill")
  • Related #

Root cause (bug fixes only, otherwise write N/A)

  • Root cause: N/A
  • Why this was not caught earlier: N/A

Test plan

  • Coverage added:
    • Unit test
    • Integration test
    • Manual verification only
  • Test file(s):
    • test/unit/infra/connectors/mcp/yaml-mcp-config-writer.test.ts
    • test/unit/infra/connectors/shared/agent-path-resolver.test.ts
    • test/unit/infra/connectors/connector-manager-attachment.test.ts
    • test/unit/infra/connectors/shared/rule-segment-patcher.test.ts
    • test/unit/infra/connectors/skill/skill-connector.test.ts
    • test/unit/infra/connectors/mcp/mcp-connector.test.ts
    • test/commands/hub-install-scope.test.ts
    • test/unit/infra/hub/hub-handler.test.ts
    • test/unit/infra/hub/hub-install-service.test.ts
  • Key scenario(s) covered: YAML MCP config emission; env-override path
    resolution for Hermes/OpenClaw; autonomous-block upsert/remove/has
    (idempotency + stale-block detection); per-agent default scope inference
    in hub install; skill connector install/status/uninstall with attachment
    block; object-param writeSkillFiles idempotent file checks.

User-visible changes

  • New Hermes agent selectable in hub install and the WebUI connectors panel
    (with icon).
  • brv hub install no longer defaults --scope to project; the daemon
    infers the default per agent (global-only agents like Hermes/OpenClaw
    install globally without erroring).
  • Installing the ByteRover skill for Hermes/OpenClaw now also writes/removes
    a managed BYTEROVER RULES block in their system-prompt files.
  • Skill install now creates multiple sub-skill files instead of a single
    SKILL.md; re-install refreshes (no longer short-circuits as "already
    installed").

Evidence

Attach at least one:

  • Failing test/log before + passing after (new unit suites listed above)
  • Trace/log snippets
  • Screenshot/recording

Checklist

  • Tests added or updated and passing (npm test)
  • Lint passes (npm run lint)
  • Type check passes (npm run typecheck)
  • Build succeeds (npm run build)
  • Commits follow Conventional Commits format
  • Documentation updated (if applicable) — skill templates are the docs
  • No breaking changes (or clearly documented above)
  • Branch is up to date with main

Risks and mitigations

  • Risk: Writing/removing the managed block in autonomous-agent system-prompt
    files could clobber user content.
    • Mitigation: Edits are confined to <!-- BEGIN/END BYTEROVER RULES -->
      markers; upsert replaces only the bounded block and preserves surrounding
      content; removal rejoins cleanly. Covered by rule-segment-patcher tests.
  • Risk: Per-agent default scope inference changes hub-install behavior for
    callers that previously relied on the project default.
    • Mitigation: Explicit --scope / data.scope still wins; default only
      flips to global for agents with no project skill path. Covered by
      hub-install-scope and hub-handler tests.
  • Risk: New env-driven path resolution (HERMES_HOME, OPENCLAW_STATE_DIR,
    OPENCLAW_CONFIG_PATH) could resolve unexpected locations.
    • Mitigation: Resolver mirrors OpenClaw's own resolution semantics and is
      unit-tested with injected env/home.

DatPham-6996 and others added 3 commits May 15, 2026 07:25
feat: [ENG-2840] Update SKILL.md to force "brv swarm query" to run si…
…nnector

Rewrite the ByteRover skill on the Superpowers model: a thin SKILL.md
entrypoint with progressive disclosure into focused sub-skill files,
plus first-class support for autonomous agents.

- Skill: split monolithic SKILL.md into query/curate/review/swarm/vc/
  history/troubleshooting.md; SKILL_FILE_NAMES enumerates all managed
  files and status/uninstall key off the full set
- Hermes: add Hermes agent (skill + mcp), connector icon, and YAML MCP
  config writer; McpConfigFormat now supports 'yaml' (~/.hermes/config.yaml)
- Autonomous attachments: write a managed BYTEROVER RULES block into
  Hermes/OpenClaw system-prompt files via autonomous-agent-attachments
  and upsert/remove/hasByteroverBlock; idempotent re-install, status
  reports stale/missing blocks as not-installed
- Path resolution: shared agent-path-resolver + skill-path-resolver
  honor HERMES_HOME / OPENCLAW_STATE_DIR / OPENCLAW_CONFIG_PATH and
  per-agent globalRoot; OpenClaw skills move to openclaw-state root
- Hub: drop hardcoded project scope; daemon infers per-agent default
  (global for global-only skill agents); writeSkillFiles takes object
  params with idempotent per-file existence checks
- Tests: cover yaml writer, agent-path-resolver, attachment manager,
  rule-segment-patcher block ops, hub install scope, skill connector

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 18, 2026

Claude finished @DatPham-6996's task in 6m 55s —— View job


Claude PR Review — Summary

Overall score: 4 / 5 — solid, well-tested feature work with a clean architectural split. A few concrete safety and consistency issues (mostly in connector edges, none blocking for the core skill split). See inline comments for specifics.

What this PR does well

  • Outside-In: the SKILL.md split is driven by what an autonomous agent actually consumes; SKILL_FILE_NAMES makes the managed set the single source of truth, and status/uninstall correctly key off it.
  • Idempotent block management: upsertByteroverBlock / removeByteroverBlock / hasByteroverBlock are well-factored, with the stale-block-as-not-installed semantics that let same-target re-install act as a repair tool. Excellent test coverage in rule-segment-patcher.test.ts and the new connector-manager-attachment.test.ts.
  • OpenClaw faithfulness: agent-path-resolver mirrors OpenClaw's resolveHomeRelativePath / resolveDefaultAgentWorkspaceDir semantics (cwd-relative for bare relative paths, home-based default workspace, no STATE_DIR mixing for the default workspace) and is unit-tested against each edge.
  • Scope inference: defaultScopeForAgent cleanly removes the "global-only agents throw on default install" footgun. Explicit --scope still wins. Good test in hub-install-scope.test.ts and hub-handler.test.ts.

Issues (inline)

  1. src/server/templates/skill/*.md — hardcoded workdir="~/.hermes/byterover/" in 7 sub-skill templates does not follow HERMES_HOME, despite everything else in this PR doing so. Either parameterize at install time or document the decoupling. Most important issue.
  2. yaml-mcp-config-writer.ts:88-101write() silently resets to {} on parse failure of an existing config, which can destroy a user's hand-edited Hermes config. Contradicts the connector's "Non-destructive" docstring guarantee. Suggest backup-or-refuse on invalid YAML.
  3. skill-connector.ts:install — re-install overwrites all sub-skill files unconditionally. Documented behavior, but easy way to lose user edits silently; consider per-file existence checks (matches writeSkillFiles pattern) or a "do not edit" header in generated files.
  4. constants.tsBYTEROVER_BLOCK_MARKERS and BRV_RULE_MARKERS are byte-identical; safe today only because target paths don't overlap. Worth an explicit invariant comment or distinct markers.
  5. hub-handler.ts:defaultScopeForAgentas Record<...> widening cast violates CLAUDE.md's "Avoid as Type assertions"; type-guard refactor in inline.

Nitpicks (inline)

  • SKILL_FILE_NAMES[0] magic indexing in two places — use the exported MAIN_SKILL_FILE_NAME instead.
  • autonomous-agent-attachments.ts:74 — parsing openclaw.json with yamlLoad works but obscures intent; either JSON.parse or document the YAML-superset choice.
  • agent-path-resolver.ts:resolveUserPath — does not handle Windows ~\foo (the OpenClaw-side resolver does); minor cross-platform gap.
  • mcp-connector-config.ts:204 — Hermes configPathResolver doesn't take options; ok for now, asymmetric with Skill connector's pathResolverOptions() plumbing.
  • autonomous-agent-attachments.ts:INVALID_OPENCLAW_ID_CHARS_REg flag is load-bearing for replaceAll; a comment would prevent a future "tidying" regression.

Test coverage

TDD ledger looks healthy:

  • New unit suites: yaml-mcp-config-writer.test.ts (~252 LOC), agent-path-resolver.test.ts, rule-segment-patcher block-mgmt cases, connector-manager-attachment.test.ts, hub-install-scope.test.ts, hub-handler.test.ts scope-inference cases.
  • skill-connector.test.ts expanded with stale-block repair, OpenClaw workspace resolution permutations, Hermes SOUL.md round-trip — covers the trickiest paths.
  • No integration tests added; given the file-system-heavy nature of these helpers and the existing tmpdir()-based unit tests, this is acceptable.

Final checklist

  • Read the PR diff against origin/proj/byterover-tool-mode
  • Review skill connector + sub-skill template changes
  • Review autonomous-agent attachment block (rule-segment-patcher)
  • Review YAML MCP config writer + Hermes wiring
  • Review agent-path-resolver / skill-path-resolver
  • Review hub-install per-agent default scope inference
  • Inline-comment specific issues (9 buffered)
  • Post summary with overall score
    branch feat/ENG-2697


No ByteRover LLM provider is required. The calling agent's own LLM authors the HTML response.

***HIGHLY IMPORTANT***: For hermes agent, run brv commands at `workdir="~/.hermes/byterover/"`.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (consistency): This workdir="~/.hermes/byterover/" is hardcoded in all 7 sub-skill files (curate.md, query.md, swarm.md, vc.md, history.md, review.md, troubleshooting.md).

Two problems:

  1. It does not follow HERMES_HOME. Everywhere else in this PR (resolveHermesHome, Hermes MCP configPathResolver, the skill install root) honors HERMES_HOME. A user who sets HERMES_HOME=/opt/hermes will get the skill installed at /opt/hermes/skills/byterover/ and the MCP config at /opt/hermes/config.yaml, but the skill itself will still tell the agent to run brv at ~/.hermes/byterover/ — pointing at the non-relocated home. The agent will then operate on the wrong project root.
  2. Minor typo: double space between at and the backtick.

If ~/.hermes/byterover/ is the intended Hermes convention regardless of HERMES_HOME, please add a one-line note explaining why this one path is decoupled. Otherwise, either:

  • Make the template parameterized (e.g., emit the resolved path at install time), or
  • Re-phrase to run brv commands inside the Hermes project workdir (default: ~/.hermes/byterover/, overridable via $HERMES_HOME).

Comment on lines +93 to +98
private defaultScopeForAgent(agent?: Agent): 'global' | 'project' {
if (!agent) return 'project'
const skillConfigs: Record<string, {projectPath: null | string}> = SKILL_CONNECTOR_CONFIGS
const config = skillConfigs[agent]
return config && !config.projectPath ? 'global' : 'project'
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (typing): The widening cast as Record<string, {projectPath: null | string}> violates the CLAUDE.md guideline “Avoid as Type assertions — use type guards or proper typing instead.” A type guard works here without information loss:

Suggested change
private defaultScopeForAgent(agent?: Agent): 'global' | 'project' {
if (!agent) return 'project'
const skillConfigs: Record<string, {projectPath: null | string}> = SKILL_CONNECTOR_CONFIGS
const config = skillConfigs[agent]
return config && !config.projectPath ? 'global' : 'project'
}
private defaultScopeForAgent(agent?: Agent): 'global' | 'project' {
if (!agent) return 'project'
if (!(agent in SKILL_CONNECTOR_CONFIGS)) return 'project'
const config = SKILL_CONNECTOR_CONFIGS[agent as keyof typeof SKILL_CONNECTOR_CONFIGS]
return config.projectPath ? 'project' : 'global'
}

Bonus: it makes the “non-skill agents fall through to project” fallback explicit rather than relying on config? being undefined.

Comment on lines +74 to +85
async function readOpenClawConfig(options?: AgentPathResolverOptions): Promise<UnknownRecord> {
const configPath = resolveOpenClawConfigPath(options)
let raw: string
try {
raw = await readFile(configPath, 'utf8')
} catch {
return {}
}

const parsed = yamlLoad(raw)
return isRecord(parsed) ? parsed : {}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: OpenClaw's config file is named openclaw.json (see resolveOpenClawConfigPath default at agent-path-resolver.ts:94), but it's parsed with yamlLoad. YAML is a superset of JSON for common shapes, so this works in practice, but it obscures the intent: a reader of readOpenClawConfig would reasonably expect the parser to match the file's .json extension.

Either use JSON.parse (and accept its stricter syntax) or rename the constant/comment to clarify that the file path is .json but YAML-compatible. As-is, if a user ever supplies an OPENCLAW_CONFIG_PATH ending in .yaml, this would silently keep working — which may be the intent, but is worth documenting.

Comment on lines +22 to +29
/**
* Boundary markers for the always-loaded BYTEROVER block that the SkillConnector
* writes into autonomous agents' system-prompt context files.
*
* The marker strings intentionally match rule files so legacy detection keeps
* treating all ByteRover-managed instruction blocks consistently.
*/
export const BYTEROVER_BLOCK_MARKERS = BRV_RULE_MARKERS
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: Aliasing BYTEROVER_BLOCK_MARKERS = BRV_RULE_MARKERS so they're byte-identical means the file content alone cannot distinguish "rules-connector managed block" from "skill autonomous-attachment managed block." Today this is safe because the two paths never collide (rules connectors live under projectRoot, autonomous attachments live in ~/.hermes/SOUL.md or <openclaw-workspace>/AGENTS.md).

But OpenClaw's autonomous attachment writes into AGENTS.md, which is the same filename used for shared rules-connector targets (Amp/Codex/OpenCode). If a future change ever pointed an OpenClaw workspace at the same project root, both flows would compete for the same markers and clobber each other.

Worth either:

  • a comment here calling out the "ok because target paths never overlap" invariant, or
  • giving the autonomous-attachment block distinct markers (e.g. BEGIN BYTEROVER SKILL) so the two are textually disjoint.

Comment on lines 122 to 142
@@ -120,10 +131,14 @@ export class SkillConnector implements IConnector {
}),
)

await this.upsertAutonomousAttachment(config)

return {
alreadyInstalled: false,
alreadyInstalled,
configPath: fullDir,
message: `Skill connector installed for ${agent} (created ${fullDir}/)`,
message: alreadyInstalled
? `Skill connector refreshed for ${agent}`
: `Skill connector installed for ${agent} (created ${fullDir}/)`,
success: true,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (data loss on re-install): install writes all SKILL_FILE_NAMES with 'overwrite' unconditionally on every re-install. The PR description calls this out as intentional ("re-install refreshes (no longer short-circuits as 'already installed')"), but the side effect is that any user edits to query.md/curate.md/etc. are silently destroyed — the function returns success: true, alreadyInstalled: true with no indication that local content was overwritten.

writeSkillFiles below already has a per-file existence check that skips already-existing files. That pattern is the safer one for managed-but-user-editable docs: write missing files, leave existing ones alone, and require an explicit --force (or uninstall + install) to regenerate.

If the templates are not meant to be user-editable, consider documenting that in the generated SKILL.md ("Do not edit — regenerated by brv hub install") so users discover the contract before they lose work.

Comment on lines +208 to +223
function normalizeOpenClawAgentId(value: string | undefined): string {
const trimmed = value?.trim() ?? ''
if (!trimmed) return DEFAULT_OPENCLAW_AGENT_ID
const lowered = trimmed.toLowerCase()
if (VALID_OPENCLAW_ID_RE.test(trimmed)) {
return lowered
}

return (
lowered
.replaceAll(INVALID_OPENCLAW_ID_CHARS_RE, '-')
.replace(LEADING_DASH_RE, '')
.replace(TRAILING_DASH_RE, '')
.slice(0, 64) || DEFAULT_OPENCLAW_AGENT_ID
)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: INVALID_OPENCLAW_ID_CHARS_RE is declared with the g flag, which is required for replaceAll(regex, ...) to not throw, but obscures intent. Since replaceAll works with either a string or a global regex, this is correct — just consider a comment noting that the g flag is mandatory here, otherwise a future hand at "tidying the regex" by dropping g will get a TypeError at runtime that the test suite may not cover for every invalid input.

Comment on lines +22 to +38
export function resolveUserPath(input: string, options?: AgentPathResolverOptions): string {
const value = input.trim()
const homeDir = resolveHomeDir(options)
if (value === '~') {
return homeDir
}

if (value.startsWith('~/')) {
return path.join(homeDir, value.slice(2))
}

if (path.isAbsolute(value)) {
return value
}

return path.join(homeDir, value)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick (cross-platform): resolveUserPath (used by resolveHermesHome) handles ~ and ~/foo but not ~\foo (Windows backslash). resolveOpenClawUserPath correctly handles both via /^~[\\/]/u. For Windows users who set HERMES_HOME=~\custom, the path would silently fall through to path.join(homeDir, '~\\custom') — a path with a literal ~\ in it.

Cheap fix: tweak the second branch to match either separator:

if (value.startsWith('~/') || value.startsWith('~\\')) {
  return path.join(homeDir, value.slice(2))
}

or mirror the OpenClaw replace(/^~(?=$|[\\/])/u, homeDir) pattern.

Comment on lines +88 to +101
async write(filePath: string, serverConfig: McpServerConfig): Promise<void> {
let data: Record<string, unknown> = {}

if (await this.fileService.exists(filePath)) {
try {
data = parseYamlAsRecord(await this.fileService.read(filePath))
} catch {
// File exists but contains invalid/empty YAML — start fresh
}
}

set(data, this.serverKeyPath, {...serverConfig})
await this.fileService.write(yamlDump(data), filePath, 'overwrite')
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (silent data loss): write opens an existing file, parses the YAML, and on parse failure silently resets data = {} (per the inline comment at line 96). That means if a Hermes user has hand-edited ~/.hermes/config.yaml and introduced a typo that makes the file invalid YAML, brv hub install ... --agent Hermes (or brv connectors install) will overwrite the entire file with just {mcp_servers: {brv: ...}}, destroying everything else they had.

exists() and remove() correctly degrade to "no-op / fileExists=false" on parse errors; write() should at least:

  • back up the file (the codebase already has IFileService.createBackup), or
  • refuse to write and return an error so the caller can surface it, or
  • log a warning.

Right now this is fail-open destructive, which is the opposite of the "Non-destructive: Preserves user's existing MCP servers and other config" safety claim in mcp-connector.ts's header docstring.

Comment on lines +204 to +211
Hermes: {
configPathResolver: () => path.join(resolveHermesHome(), 'config.yaml'),
format: 'yaml',
mode: 'auto',
scope: 'global',
serverConfig: DEFAULT_SERVER_CONFIG,
serverKeyPath: ['mcp_servers', 'brv'],
},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick (consistency): The Hermes configPathResolver calls resolveHermesHome() with no options argument, which means it reads process.env.HERMES_HOME and os.homedir() directly — bypassing the env/homeDir injection path that the rest of this PR plumbs through AgentPathResolverOptions.

In production this is fine (the daemon reads the real env), but it makes getConfigPath('Hermes') non-injectable in tests — the Hermes-specific test at mcp-connector.test.ts:484 has to mutate process.env.HERMES_HOME directly to verify the override. If you ever introduce a McpConnectorOptions.env/homeDir parallel to the Skill connector's, this is the call site that won't honor it.

Not blocking, just flagging the asymmetry between Skill and MCP connector resolution paths.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 19, 2026

Claude finished @DatPham-6996's task in 3m 48s —— View job


Claude PR Review — re-review after sync

Overall score: 4 / 5 — the architectural split and idempotent-block design remain strong; this sync commit was a bulk pull of main v3.14.0 plus a merge — no substantive new feature changes were added to address the prior review. Most of the previously-flagged items are still open in HEAD. Re-flagging the load-bearing ones below.

Since last review (2026-05-18)

  • 8797880 chore: sync main v3.14.0 — bulk reconciliation from main, no targeted fixes to the connector/skill files reviewed previously.
  • 090a942 Merge remote-tracking branch 'origin/proj/byterover-tool-mode' into feat/ENG-2697 — merge only.
  • One template did get scrubbed: the hardcoded workdir="~/.hermes/byterover/" is now in 2 of 7 sub-skill files (curate.md:12, query.md:10) instead of all 7. Net improvement, but still hardcoded.

Status of prior-review findings against current HEAD

Prior issue File:line Status
Hardcoded workdir="~/.hermes/byterover/" ignoring HERMES_HOME src/server/templates/skill/curate.md:12, query.md:10 Partially addressed (7→2 files); still hardcoded, double-space typo (at ) still in curate.md:12
YAML config writer silently resets to {} on parse failure src/server/infra/connectors/mcp/yaml-mcp-config-writer.ts:88-101 Not addressed — still fail-open destructive on invalid YAML
install() overwrites all SKILL_FILE_NAMES unconditionally src/server/infra/connectors/skill/skill-connector.ts:126-132 Not addressed — still uses 'overwrite'. writeSkillFiles keeps its safer per-file existence check, but install does not
BYTEROVER_BLOCK_MARKERS = BRV_RULE_MARKERS (byte-identical) src/server/infra/connectors/shared/constants.ts:22-29 Addressed via documentation — docstring now explains the rationale; markers still identical
defaultScopeForAgent uses as Record<...> widening cast src/server/infra/transport/handlers/hub-handler.ts:95 Not addressed — still violates CLAUDE.md "Avoid as Type assertions"
agent-path-resolver.ts:resolveUserPath Windows ~\foo gap src/server/infra/connectors/shared/agent-path-resolver.ts:29 Not addressed~/ only; resolveOpenClawUserPath (l.70) correctly handles both via /^~[\\/]/u — asymmetric
mcp-connector-config.ts Hermes configPathResolver ignores injection src/server/infra/connectors/mcp/mcp-connector-config.ts:205 Not addressed — still () => path.join(resolveHermesHome(), …) with no options
openclaw.json parsed with yamlLoad (intent obscured) src/server/infra/connectors/skill/autonomous-agent-attachments.ts:83 Not addressed
SKILL_FILE_NAMES[0] magic indexing src/server/infra/connectors/skill/skill-connector.ts:255, 274 Partially addressedMAIN_SKILL_FILE_NAME is now used at line 123 in install(), but uninstall still uses SKILL_FILE_NAMES[0] at lines 255/274
INVALID_OPENCLAW_ID_CHARS_RE g flag intent src/server/infra/connectors/skill/autonomous-agent-attachments.ts:22 Not addressed — no clarifying comment

Issues (re-flagged in priority order)

  1. yaml-mcp-config-writer.ts:88-101 — silent data destruction on invalid YAML. write() still falls through to data = {} on parse failure and overwrites the entire file with just {mcp_servers: {brv: ...}}. The connector's own header docstring calls itself "Non-destructive" — this still contradicts that claim. IFileService.createBackup exists; suggest backing up or refusing to write on parse failure. Same destructive path runs for both brv hub install --agent Hermes and brv connectors install. Fix this →

  2. skill-connector.ts:126-132 — re-install overwrites user-edited sub-skill files unconditionally. The PR description says re-install "refreshes (no longer short-circuits)" — that is intended, but it silently clobbers query.md/curate.md/etc. and still returns success: true, alreadyInstalled: true with no signal. writeSkillFiles (l. 333-348) already shows the right pattern (per-file existence check). Either match that pattern in install(), gate the refresh behind --force, or add a "Do not edit — regenerated by brv hub install" header to generated files. Fix this →

  3. src/server/templates/skill/curate.md:12 & query.md:10workdir hardcoded, doesn't honor HERMES_HOME. Cleaned up from 7 files to 2, but the remaining two still encode ~/.hermes/byterover/ literally. If a Hermes user sets HERMES_HOME=/opt/hermes, the skill installs under /opt/hermes/skills/byterover/ (resolver honors it) but the template tells the agent to cd ~/.hermes/byterover/. Also: at (double space) in curate.md:12. Either parameterize at install time or reword as (default: ~/.hermes/byterover/, overridable via $HERMES_HOME). Fix this →

  4. hub-handler.ts:95as Type widening cast still violates CLAUDE.md. Same one-liner from the prior review still works:

    private defaultScopeForAgent(agent?: Agent): 'global' | 'project' {
      if (!agent) return 'project'
      if (!(agent in SKILL_CONNECTOR_CONFIGS)) return 'project'
      const config = SKILL_CONNECTOR_CONFIGS[agent as keyof typeof SKILL_CONNECTOR_CONFIGS]
      return config.projectPath ? 'project' : 'global'
    }

    Fix this →

Nitpicks (re-flagged)

  • agent-path-resolver.ts:29 — Windows backslash gap. resolveUserPath (used for Hermes) handles ~/ but not ~\; resolveOpenClawUserPath already handles both via /^~[\\/]/u. Trivial fix: value.startsWith('~/') || value.startsWith('~\\').
  • skill-connector.ts:255 & 274 — still uses SKILL_FILE_NAMES[0]; MAIN_SKILL_FILE_NAME is imported but only used at line 123.
  • mcp-connector-config.ts:205 — Hermes configPathResolver doesn't accept options; asymmetric with the Skill connector's injection seam, makes Hermes tests have to mutate process.env.
  • autonomous-agent-attachments.ts:22g flag on INVALID_OPENCLAW_ID_CHARS_RE is load-bearing for replaceAll; a comment would prevent a future "tidy" regression.
  • autonomous-agent-attachments.ts:83-84 — parsing openclaw.json with yamlLoad: works (YAML ⊃ JSON) but obscures intent.

Tests & build (unchanged from prior review)

  • New unit suites still healthy: yaml-mcp-config-writer.test.ts, agent-path-resolver.test.ts, rule-segment-patcher block-mgmt cases, connector-manager-attachment.test.ts, hub-install-scope.test.ts, hub-handler.test.ts scope-inference cases, plus the expanded skill-connector.test.ts (stale-block repair + HERMES_HOME paths + OpenClaw workspace permutations).
  • Gap: no new test covers (a) the YAML-parse-failure path in yaml-mcp-config-writer.write(), or (b) the re-install-clobbers-edited-sub-skill path in skill-connector.install(). Adding those would have surfaced issues Feat/init #1 and Feat/refactor structure #2 above as red tests.

Checklist

  • Re-scan diff against origin/proj/byterover-tool-mode
  • Verify prior-review issues against HEAD (f5e92f5 + 8797880 + 090a942)
  • Re-read connector/skill template/path-resolver/hub-handler files
  • Check test coverage for any new fixes
  • Post re-review summary with score
    branch feat/ENG-2697

DatPham-6996 and others added 2 commits May 19, 2026 14:03
Add a post-curate self-review sub-skill and substantially strengthen the
curate authoring guide so saved topics are standalone explainers, not
changelogs.

- New src/server/templates/skill/curate-judgement.md: post-write
  self-review. After `brv curate` reports done, judge the stored,
  rendered topic against curate.md's Quality Bar with a hard cap of one
  enhancement pass (references the rubric instead of restating it to
  avoid drift).
- Register curate-judgement.md in SKILL_FILE_NAMES
  (skill-connector-config.ts) and reference it from SKILL.md (detail
  file list + command reference).
- curate.md: document the JSON envelope contract ({html, meta}
  replaces bare HTML on --response), add the four-dimension Quality
  Bar, decision-flow diagram, rationalizations/red-flags tables, a
  richer worked example exercising all dimensions, and a pre-send
  self-check; expand Required Preservation and Common Mistakes.
- Add unit coverage asserting curate-judgement.md installs as a lean
  self-review guide that points at the Quality Bar, `brv read`, and the
  one-pass --overwrite cap.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 19, 2026

Claude finished @DatPham-6996's task in 2m 31s —— View job


Claude PR Review — synchronize re-review

Overall score: 4 / 5 — the new curate-judgement sub-skill is a thoughtful, well-bounded addition (post-write self-review, hard one-pass cap, references the Quality Bar rather than restating it — avoids drift). It does not address any of the four open priority issues from the prior re-review, all of which are still present in HEAD.

Since last review (2026-05-19 03:03 UTC)

  • eafd498 feat: [ENG-2697] add curate-judgement sub-skill, harden curate guide — additive: new curate-judgement.md, expanded curate.md (JSON envelope contract, Quality Bar, decision flow, rationalizations/red-flags tables, worked example, pre-send self-check), registered in SKILL_FILE_NAMES, referenced from SKILL.md. Test coverage added for the new sub-skill install.
  • bdfdcd3 Merge branch 'feat/ENG-2697-variant' into feat/ENG-2697 — merge only.
  • No targeted fixes to the connector / template / path-resolver / hub-handler files flagged previously.

Notes on the new curate-judgement.md

  • Good design: the sub-skill references the Quality Bar in curate.md:25 rather than restating it, which is exactly the right call to avoid the two-source drift problem you'd otherwise hit on edits.
  • One-pass cap (curate-judgement.md:30, 34) is explicit and bounded — matches curate's own validation cap. Sensible.
  • Position-1 SKILL_FILE_NAMES invariant still holds (MAIN_SKILL_FILE_NAME is index 0; curate-judgement.md was inserted as index 3 in skill-connector-config.ts:133-143).

Status of prior-review findings against current HEAD

Prior issue File:line Status
Hardcoded workdir="~/.hermes/byterover/" ignoring HERMES_HOME src/server/templates/skill/curate.md:12, query.md:10 Not addressed — still hardcoded in both; double-space typo (at ) still present in both
YAML config writer silently resets to {} on parse failure src/server/infra/connectors/mcp/yaml-mcp-config-writer.ts:88-101 Not addressed — still fail-open destructive on invalid YAML
install() overwrites all SKILL_FILE_NAMES unconditionally src/server/infra/connectors/skill/skill-connector.ts:126-132 Not addressed — still uses 'overwrite' for every file; writeSkillFiles keeps its safer per-file existence check, but install does not
BYTEROVER_BLOCK_MARKERS = BRV_RULE_MARKERS identity src/server/infra/connectors/shared/constants.ts:22-29 Resolved via documentation — docstring now states the invariant (legacy detection compat)
defaultScopeForAgent uses as Record<...> widening cast src/server/infra/transport/handlers/hub-handler.ts:95 Not addressed — still violates CLAUDE.md "Avoid as Type assertions"
agent-path-resolver.ts:resolveUserPath Windows ~\foo gap src/server/infra/connectors/shared/agent-path-resolver.ts:29 Not addressed~/ only; resolveOpenClawUserPath (line 70-77) correctly handles both via /^~[\\/]/u — asymmetric
mcp-connector-config.ts Hermes configPathResolver ignores injection src/server/infra/connectors/mcp/mcp-connector-config.ts:205 Not addressed — still () => path.join(resolveHermesHome(), 'config.yaml') with no options
openclaw.json parsed with yamlLoad src/server/infra/connectors/skill/autonomous-agent-attachments.ts:83 Not addressed
SKILL_FILE_NAMES[0] magic indexing in uninstall src/server/infra/connectors/skill/skill-connector.ts:255, 274 Not addressedinstall() uses MAIN_SKILL_FILE_NAME (line 123) but uninstall still uses SKILL_FILE_NAMES[0]
INVALID_OPENCLAW_ID_CHARS_RE g flag intent src/server/infra/connectors/skill/autonomous-agent-attachments.ts:22 Not addressed — no clarifying comment

Re-flagged in priority order (carried forward, unchanged from prior review)

  1. yaml-mcp-config-writer.ts:88-101 — silent data destruction on invalid YAML. write() still falls through to data = {} on parse failure and overwrites the entire file with just {mcp_servers: {brv: ...}}. Contradicts the connector's own "Non-destructive" header docstring claim. Same destructive path runs for both brv hub install --agent Hermes and brv connectors install. Suggest backup-or-refuse on invalid YAML (IFileService.createBackup is available). Fix this →

  2. skill-connector.ts:126-132 — re-install overwrites user-edited sub-skill files unconditionally. Intended ("re-install refreshes"), but it silently clobbers query.md / curate.md / curate-judgement.md / etc. and still returns success: true, alreadyInstalled: true with no signal. With curate-judgement.md now in the managed set, this risk surface is wider — a user who tweaks their judgement guide loses it on next brv hub install. writeSkillFiles (lines 333-348) already shows the right pattern. Match it in install(), gate the refresh behind --force, or add a "Do not edit — regenerated by brv hub install" header to generated files. Fix this →

  3. src/server/templates/skill/curate.md:12 & query.md:10workdir hardcoded, doesn't honor HERMES_HOME. Skill install root + Hermes MCP config path both honor HERMES_HOME, but the skill content tells the agent to cd ~/.hermes/byterover/. For a Hermes user with HERMES_HOME=/opt/hermes, the skill is installed at /opt/hermes/skills/byterover/SKILL.md but the agent reads "run brv at ~/.hermes/byterover/" — pointing at the non-relocated home. Also still: at (double space) in both files. Either parameterize at install time or reword as (default: ~/.hermes/byterover/, overridable via $HERMES_HOME). Fix this →

  4. hub-handler.ts:93-98as Type widening cast still violates CLAUDE.md. Replace the Record<string, {projectPath: null | string}> cast with an agent in SKILL_CONNECTOR_CONFIGS type guard. Fix this →

Nitpicks (carried forward)

  • agent-path-resolver.ts:29 — Windows backslash gap. resolveUserPath (used for Hermes) handles ~/ but not ~\; resolveOpenClawUserPath (line 70) handles both. Trivial fix: value.startsWith('~/') || value.startsWith('~\\').
  • skill-connector.ts:255 & 274uninstall still uses SKILL_FILE_NAMES[0]; MAIN_SKILL_FILE_NAME is imported but only used at line 123. Easy follow-up to the partial fix already applied.
  • mcp-connector-config.ts:205 — Hermes configPathResolver doesn't accept options, so getConfigPath('Hermes') is not injectable in tests (forces process.env mutation in mcp-connector.test.ts:484). Asymmetric with the Skill connector's pathResolverOptions() plumbing.
  • autonomous-agent-attachments.ts:22g flag on INVALID_OPENCLAW_ID_CHARS_RE is load-bearing for replaceAll; a one-line comment would prevent a future "tidy" regression.
  • autonomous-agent-attachments.ts:83-84 — parsing openclaw.json with yamlLoad: works (YAML ⊃ JSON) but obscures intent.

Tests & build

  • New unit coverage in eafd498 for the curate-judgement.md install path looks healthy (asserts the file installs as a lean self-review guide that points at the Quality Bar, brv read, and the one-pass --overwrite cap).
  • Existing unit suites unchanged and still healthy.
  • Gap (same as prior review): no new test covers (a) the YAML-parse-failure path in yaml-mcp-config-writer.write(), or (b) the re-install-clobbers-edited-sub-skill path in skill-connector.install(). Adding those would have surfaced issues Feat/init #1 and Feat/refactor structure #2 as red tests.

Todos

  • Fetch latest branch and diff against origin/proj/byterover-tool-mode
  • Re-verify status of prior-review findings against current HEAD
  • Read key changed files (yaml-mcp-config-writer, skill-connector, hub-handler, agent-path-resolver, templates, curate-judgement)
  • Check whether any new commits since last review address open issues — they don't
  • Post final summary with overall score

branch feat/ENG-2697

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 20, 2026

Claude finished @DatPham-6996's task in 3m 36s —— View job


Claude PR Review — synchronize re-review (4th pass)

Overall score: 4 / 5 — the architectural split, idempotent block management, and OpenClaw-faithful path resolution remain strong. This sync pulled proj/byterover-tool-mode (which itself pulled main) and added a new dream.md sub-skill, but none of the four open priority issues from the prior reviews have been addressed in HEAD. Re-flagging the unresolved items inline.

Since last review (2026-05-19 10:26 UTC)

  • bdfdcd3 Merge branch 'feat/ENG-2697-variant' into feat/ENG-2697 — merge only.
  • 0b98569 Merge branch 'main' into proj/byterover-tool-mode (via the base) — bulk reconciliation from main with conflicts in ai-sdk-content-generator.ts, oclif/commands/curate/index.ts, oclif/commands/query.ts, and the curate/query test files. Outside this PR's review scope.
  • 125d2fe Merge branch 'proj/byterover-tool-mode' into feat/ENG-2697 — the only substantive change vs prior review in scope: a new dream.md sub-skill (added to SKILL_FILE_NAMES, referenced from SKILL.md) covering the three-phase brv dream workflow. Self-contained, does not introduce a hardcoded workdir, no new issues.

No targeted fixes landed for the four open priority issues from the prior reviews.

Status of prior-review findings against current HEAD

Prior issue File:line Status
Hardcoded workdir="~/.hermes/byterover/" ignoring HERMES_HOME src/server/templates/skill/curate.md:12, query.md:10 Not addressed — both files still hardcode the literal; double-space typo (at ) still present in both
YAML config writer silently resets to {} on parse failure src/server/infra/connectors/mcp/yaml-mcp-config-writer.ts:88-101 Not addressed — still fail-open destructive on invalid YAML
install() overwrites all SKILL_FILE_NAMES unconditionally src/server/infra/connectors/skill/skill-connector.ts:126-132 Not addressed — still uses 'overwrite' for every file; with dream.md and curate-judgement.md now in the managed set the blast radius grew
defaultScopeForAgent uses widening type annotation src/server/infra/transport/handlers/hub-handler.ts:93-98 Not addressed — still violates CLAUDE.md "Avoid as Type assertions"
agent-path-resolver.ts:resolveUserPath Windows ~\foo gap src/server/infra/connectors/shared/agent-path-resolver.ts:29 Not addressed~/ only; resolveOpenClawUserPath (l.64-77) correctly handles both
mcp-connector-config.ts Hermes configPathResolver ignores injection src/server/infra/connectors/mcp/mcp-connector-config.ts:205 Not addressed — still () => path.join(resolveHermesHome(), 'config.yaml') with no options
openclaw.json parsed with yamlLoad src/server/infra/connectors/skill/autonomous-agent-attachments.ts:83 Not addressed
SKILL_FILE_NAMES[0] magic indexing in uninstall src/server/infra/connectors/skill/skill-connector.ts:255, 274 Not addressedinstall() uses MAIN_SKILL_FILE_NAME (l.123) but uninstall still indexes by position
INVALID_OPENCLAW_ID_CHARS_RE g flag intent src/server/infra/connectors/skill/autonomous-agent-attachments.ts:22 Not addressed
BYTEROVER_BLOCK_MARKERS = BRV_RULE_MARKERS identity src/server/infra/connectors/shared/constants.ts:22-29 Resolved via documentation

Re-flagged inline (priority order)

  1. yaml-mcp-config-writer.ts:88-101 — silent destruction of hand-edited Hermes config on invalid YAML. Top priority because it's the only one that can lose user content with no warning. See inline comment.
  2. skill-connector.ts:install() — re-install overwrites user-edited sub-skill files unconditionally and returns success: true with no signal. Surface area grew with dream.md and curate-judgement.md. See inline comment.
  3. curate.md:12 & query.md:10 — hardcoded workdir="~/.hermes/byterover/" does not honor HERMES_HOME; the skill on disk and the agent's instructions diverge for any Hermes user that relocates their home. See inline comment.
  4. hub-handler.ts:93-98 — widening type annotation that violates CLAUDE.md. One-liner type-guard fix in the inline comment. See inline comment.

Nitpicks (agent-path-resolver.ts:29 Windows backslash gap also re-flagged inline; the rest carry forward from prior reviews — uninstall magic indexing, Hermes configPathResolver non-injection, openclaw.json via yamlLoad, missing g-flag rationale comment).

Tests & build

  • Unit suites added since the prior review: curate-judgement.md install path (skill-connector.test.ts:expanded from eafd498). Healthy.
  • Persistent gap (3rd time flagged): no new test covers (a) the YAML-parse-failure path in yaml-mcp-config-writer.write(), or (b) the re-install-clobbers-edited-sub-skill path in skill-connector.install(). Adding either of those would surface the corresponding priority issue as a red test, which is the cleanest way to drive the fix.

Notes on the new dream.md

  • Clean addition: matches the existing sub-skill voice, uses dream.md for the three-phase scan/finalize/undo workflow, references brv dream --help for flags rather than restating them.
  • Does not introduce a hardcoded workdir; the Hermes workdir issue remains confined to curate.md:12 + query.md:10.
  • Position-1 SKILL_FILE_NAMES invariant still holds (MAIN_SKILL_FILE_NAME is index 0).

Checklist

  • Fetch latest branch and diff against origin/proj/byterover-tool-mode
  • Verify status of prior-review findings against current HEAD
  • Re-read key changed files (yaml-mcp-config-writer, skill-connector, hub-handler, agent-path-resolver, templates incl. new dream.md)
  • Post inline comments for the unresolved priority issues (4) + Windows-backslash nit
  • Post final summary with overall score
    branch feat/ENG-2697

Comment on lines +88 to +101
async write(filePath: string, serverConfig: McpServerConfig): Promise<void> {
let data: Record<string, unknown> = {}

if (await this.fileService.exists(filePath)) {
try {
data = parseYamlAsRecord(await this.fileService.read(filePath))
} catch {
// File exists but contains invalid/empty YAML — start fresh
}
}

set(data, this.serverKeyPath, {...serverConfig})
await this.fileService.write(yamlDump(data), filePath, 'overwrite')
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (silent data loss, still unaddressed since 2026-05-18): On YAML parse failure, write() falls through to data = {} and overwrites the entire file with just {mcp_servers: {brv: ...}}. If a Hermes user has hand-edited ~/.hermes/config.yaml and accidentally introduced invalid YAML, brv hub install --agent Hermes or brv connectors install will destroy everything else they had.

This contradicts the "Non-destructive: preserves user's existing MCP servers and other config" claim in mcp-connector.ts's header docstring. exists() and remove() already degrade safely on parse errors — write() should too.

Suggested options (any one):

  • Back up via IFileService.createBackup before overwriting, or
  • Throw so the caller can surface it to the user, or
  • At minimum log a warning before clobbering.

This is the top-priority open issue from the prior reviews and the only one that can lead to silent data loss on a hand-edited user config. Also worth adding a unit test exercising the invalid-YAML branch in yaml-mcp-config-writer.test.ts. Fix this →

Comment on lines 126 to 132
@@ -120,10 +131,14 @@ export class SkillConnector implements IConnector {
}),
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (re-install clobbers user edits, still unaddressed since 2026-05-18): Every re-install writes every SKILL_FILE_NAMES entry with 'overwrite', then returns success: true, alreadyInstalled: true — silent data loss with a misleadingly-green return value. With curate-judgement.md and dream.md now in the managed set the surface area has only grown.

writeSkillFiles at lines 333–348 already shows the right pattern (per-file existence check; skip files that exist). At minimum, match that pattern in install(). Better still, pick one:

  • Gate the refresh behind an explicit --force flag (current behavior becomes opt-in), or
  • Emit a Do not edit — regenerated by \brv hub install`` header in every generated sub-skill file so users see the contract before they lose work, or
  • Return a refreshed: true (and changed-files list) in the result so the CLI can surface that something was overwritten.

uninstall at l. 255 & 274 also still uses SKILL_FILE_NAMES[0] — swap to the already-imported MAIN_SKILL_FILE_NAME while you're in here. Fix this →


No ByteRover LLM provider is required. The calling agent's own LLM authors the HTML response.

***HIGHLY IMPORTANT***: For hermes agent, run brv commands at `workdir="~/.hermes/byterover/"`.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (consistency, still unaddressed since 2026-05-18): This workdir="~/.hermes/byterover/" (and the matching line at query.md:10) is hardcoded and does not follow HERMES_HOME. Everywhere else in this PR — resolveHermesHome, the Hermes MCP configPathResolver, the skill install root — honors HERMES_HOME.

A user who sets HERMES_HOME=/opt/hermes will get the skill installed at /opt/hermes/skills/byterover/SKILL.md and the MCP config at /opt/hermes/config.yaml, but the skill content still tells the agent to cd ~/.hermes/byterover/ — pointing at the non-relocated home. The agent then operates on the wrong root.

Two viable fixes:

  1. Parameterize at install time: render the resolved path during SkillContentLoader.loadSkillFile so the file emitted to disk already has the user's real workdir baked in (and drop the env override from this template altogether).
  2. Reword to make the override discoverable: e.g. For hermes agent, run brv commands inside the Hermes workdir (default: ~/.hermes/byterover/; overridable via $HERMES_HOME).

Also: the line still has a double space after at (at `workdir=…``) — trivial but visible to the LLM consumer. Fix this →

Comment on lines +93 to +98
private defaultScopeForAgent(agent?: Agent): 'global' | 'project' {
if (!agent) return 'project'
const skillConfigs: Record<string, {projectPath: null | string}> = SKILL_CONNECTOR_CONFIGS
const config = skillConfigs[agent]
return config && !config.projectPath ? 'global' : 'project'
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (typing, still unaddressed since 2026-05-18): The widening cast const skillConfigs: Record<string, {projectPath: null | string}> = SKILL_CONNECTOR_CONFIGS violates CLAUDE.md's "Avoid as Type assertions — use type guards or proper typing instead" rule. (It's the same pattern even though there's no literal as keyword — the explicit type annotation widens the type.) A type guard preserves the inferred typing and makes the fallback explicit:

Suggested change
private defaultScopeForAgent(agent?: Agent): 'global' | 'project' {
if (!agent) return 'project'
const skillConfigs: Record<string, {projectPath: null | string}> = SKILL_CONNECTOR_CONFIGS
const config = skillConfigs[agent]
return config && !config.projectPath ? 'global' : 'project'
}
private defaultScopeForAgent(agent?: Agent): 'global' | 'project' {
if (!agent) return 'project'
if (!(agent in SKILL_CONNECTOR_CONFIGS)) return 'project'
const config = SKILL_CONNECTOR_CONFIGS[agent as keyof typeof SKILL_CONNECTOR_CONFIGS]
return config.projectPath ? 'project' : 'global'
}

This also makes the "non-skill agents fall through to project" path explicit rather than relying on the cast leaving config as undefined. Fix this →

return homeDir
}

if (value.startsWith('~/')) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick (cross-platform, still unaddressed since 2026-05-18): resolveUserPath (used by resolveHermesHome) handles ~/ but not ~\ (Windows backslash). resolveOpenClawUserPath at l. 64–77 correctly handles both via /^~[\\/]/u. A Windows user with HERMES_HOME=~\custom would silently get path.join(homeDir, '~\\custom') — a literal ~\ inside the path.

Cheap fix:

if (value.startsWith('~/') || value.startsWith('~\\')) {
  return path.join(homeDir, value.slice(2))
}

or mirror the OpenClaw pattern: value.replace(/^~(?=$|[\\/])/u, homeDir) + path.resolve.

Audited each sub-skill (excluding curate / query) against the actual
`brv <topic> --help` surface and patched the gaps:

- vc.md: added init, clone, config, checkout, merge, fetch, remote;
  added real examples for reset (was only mentioned as "avoid").
  Regrouped Quick Reference by workflow phase (Setup / Inspect /
  Stage+commit / Branch+checkout / Sync / Merge / Undo). Expanded
  Safety + Common Mistakes to cover missing-upstream, missing-config,
  and switching with dirty tree.
- swarm.md: added `brv swarm onboard` (interactive setup wizard) +
  a Setup section explaining when to use it.
- review.md: added the toggle subcommands (`brv review`,
  `--enable`, `--disable`) that the description verb already implied
  but the body missed entirely. Updated frontmatter to include
  enable/disable so the matcher fires on those prompts.
- history.md: surfaced the filter flags that were buried under
  `--help` — `--limit`, `--since`, `--before`, `--status`, `--tier`,
  `--last`, `--format narrative`. Regrouped Quick Reference into
  Curate / Query / Aggregate sections.
- troubleshooting.md: added recovery commands (`brv restart` for
  crash recovery, `brv logout` + `brv login` reset flow, `brv update`
  for stale-CLI mismatch) + `brv connectors` to Quick Diagnosis.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 20, 2026

Claude finished @cuongdo-byterover's task in 2m 17s —— View job


Claude PR Review — synchronize re-review (5th pass)

Overall score: 4 / 5 — the architectural split, idempotent block management, and OpenClaw-faithful path resolution remain strong. The new commit since the prior review (f2bbbf3) is a thoughtful, scope-bounded audit of sub-skill command coverage and does not introduce new issues. None of the four open priority items from the prior reviews have been addressed in HEAD.

Since last review (2026-05-20 09:32 UTC)

  • f2bbbf3 fix: [ENG-2697] sub-skill gaps — missing brv commands + examples — only substantive change. Audits each sub-skill (excluding curate / query) against the real brv <topic> --help surface and patches gaps:
    • vc.md — adds init, clone, config, checkout, merge, fetch, remote; adds real reset examples; regroups Quick Reference by workflow phase (Setup / Inspect / Stage+commit / Branch+checkout / Sync / Merge / Undo). Expands Safety + Common Mistakes (missing-upstream, missing-config, dirty-tree switch).
    • swarm.md — adds brv swarm onboard + a Setup section.
    • review.md — adds the toggle subcommands (brv review, --enable, --disable); frontmatter description updated so the matcher fires on enable/disable prompts.
    • history.md — surfaces filter flags previously buried under --help (--limit, --since, --before, --status, --tier, --last, --format narrative); regroups Quick Reference into Curate / Query / Aggregate.
    • troubleshooting.md — adds recovery commands (brv restart, brv logout + brv login, brv update) + brv connectors to Quick Diagnosis.
  • No new tests in this commit — these are content-only edits to sub-skill markdown that are exercised by the existing skill-connector.test.ts install path (SKILL_FILE_NAMES already covers them).
  • This commit does not introduce any new hardcoded workdir references — those remain confined to curate.md:12 and query.md:10 (unchanged for 3 reviews now).

Status of prior-review priority findings against current HEAD

Prior issue File:line Status
Hardcoded workdir="~/.hermes/byterover/" ignoring HERMES_HOME (+ double-space typo at ) src/server/templates/skill/curate.md:12, query.md:10 Still unaddressed
YAML config writer silently resets to {} on parse failure src/server/infra/connectors/mcp/yaml-mcp-config-writer.ts:88-101 Still unaddressed
install() overwrites all SKILL_FILE_NAMES unconditionally src/server/infra/connectors/skill/skill-connector.ts:126-132 Still unaddressed (with dream.md and curate-judgement.md in the managed set + a richer vc.md/history.md/review.md/troubleshooting.md, the blast radius is wider)
defaultScopeForAgent uses Record<string, …> widening annotation src/server/infra/transport/handlers/hub-handler.ts:93-98 Still unaddressed
agent-path-resolver.ts:resolveUserPath Windows ~\foo gap src/server/infra/connectors/shared/agent-path-resolver.ts:29 (nitpick) Still unaddressed
BYTEROVER_BLOCK_MARKERS = BRV_RULE_MARKERS identity src/server/infra/connectors/shared/constants.ts:22-29 Resolved via documentation

The inline comments from the 4th-pass review (posted 2026-05-20 09:34 UTC) at yaml-mcp-config-writer.ts:101, skill-connector.ts:132, curate.md:12, hub-handler.ts:98, and agent-path-resolver.ts:29 remain the open action items. To avoid noise I'm not re-posting them inline — please refer to the existing inline threads for fix suggestions / "Fix this →" links.

Notes on f2bbbf3 (the only new commit)

The sub-skill audit is a nice piece of follow-up — verifying the skill content actually matches the CLI's --help surface is exactly the kind of consistency check that's easy to skip. A few small observations on the new content, none blocking:

  • vc.md — the new Setup section calls out brv vc config user.name "Your Name" as "required before first commit" without mentioning that brv vc init is project-scoped. If the user is in a worktree pointer (.brv/ as pointer file), brv vc init is the wrong operation — worth a one-liner. Not a regression from this commit.
  • review.md — the new frontmatter description ("enable/disable") will cause the matcher to fire on any prompt containing those words. Consider scoping to brv review enable/disable to avoid false positives from unrelated "enable / disable" mentions.
  • history.md--format narrative is documented; the YAML envelope --format json variant is not. Probably intentional (narrative is the agent-facing one), but worth confirming.

Tests & build

  • Existing unit suites unchanged. The new commit is content-only and exercised by the SKILL_FILE_NAMES install path in skill-connector.test.ts.
  • Persistent gap (4th time flagged): no test covers (a) the YAML-parse-failure branch in yaml-mcp-config-writer.write(), or (b) the re-install-clobbers-edited-sub-skill path in skill-connector.install(). Adding either of those would surface the corresponding priority issue as a red test, which is the cleanest way to drive the fix.

Checklist

  • Fetch latest branch and diff against origin/proj/byterover-tool-mode
  • Verify status of prior-review findings against current HEAD (f2bbbf3)
  • Re-read key changed files (yaml-mcp-config-writer, skill-connector, hub-handler, agent-path-resolver, templates incl. new sub-skill edits)
  • Check whether the new commit addresses any open issues — it doesn't (and isn't intended to; it's scoped to sub-skill content gaps)
  • Avoid re-posting inline comments already filed this morning; reference them from the summary instead
  • Post final summary with overall score
    branch feat/ENG-2697

@cuongdo-byterover cuongdo-byterover changed the title Feat/eng 2697 feat: [ENG-2697] ByteRover skill v2 (Superpowers pattern) + Hermes May 20, 2026
@cuongdo-byterover cuongdo-byterover changed the title feat: [ENG-2697] ByteRover skill v2 (Superpowers pattern) + Hermes feat: [ENG-2697] rewrite ByteRover skill — sub-skill split + Hermes connector May 20, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 21, 2026

Claude finished @DatPham-6996's task in 2m 10s —— View job


Claude PR Review — synchronize re-review (6th pass)

Overall score: 4 / 5 — architecture and idempotent-block design remain solid. The only new commit since the 5th-pass review (cda1cd3) is a revert; none of the four open priority issues from the prior reviews have been addressed in HEAD, and the prior-review inline comments at yaml-mcp-config-writer.ts:101, skill-connector.ts:132, curate.md:12, hub-handler.ts:98, and agent-path-resolver.ts:29 are still the live action items.

To avoid further noise I am not re-posting those inline comments — please refer to the existing inline threads (most recently re-filed 2026-05-20 09:34 UTC) for fix suggestions / Fix this → links.

Since last review (2026-05-20 10:25 UTC)

  • cda1cd3 Revert "Merge branch 'feat/ENG-2697-variant' into feat/ENG-2697" — only new commit. Backs out the curate-judgement.md sub-skill and rewinds curate.md to the pre-JSON-envelope version (i.e. --response is bare HTML again, not {"html":…,"meta":…}). Net: SKILL_FILE_NAMES loses one entry; the rest of the connector / template / path-resolver surface is unchanged.

    Worth noting: the JSON-envelope contract that this revert backs out is what proj/byterover-tool-mode's curate-html-direct work (feat/ENG-2837) is converging on. If the intent was to defer that contract until after the tool-mode work lands on main, that ordering makes sense; if not, this is worth a follow-up. Not blocking either way.

Status of prior-review priority findings against current HEAD

Re-verified each against current files; nothing has shifted since the 5th-pass review except for the curate-judgement.md removal.

Prior issue File:line Status
Hardcoded workdir="~/.hermes/byterover/" ignoring HERMES_HOME (+ double-space typo at ) src/server/templates/skill/curate.md:12, query.md:10 Still unaddressed (verified l. 12, l. 10)
YAML config writer silently resets to {} on parse failure src/server/infra/connectors/mcp/yaml-mcp-config-writer.ts:88-101 Still unaddressed (verified — catch { /* start fresh */ } … overwrite)
install() overwrites all SKILL_FILE_NAMES unconditionally src/server/infra/connectors/skill/skill-connector.ts:126-132 Still unaddressed (verified — still 'overwrite' on every file). With curate-judgement.md reverted out, the managed set is one entry smaller, but dream.md / vc.md / history.md / review.md / troubleshooting.md etc. are all still clobbered
defaultScopeForAgent uses widening type annotation src/server/infra/transport/handlers/hub-handler.ts:95-98 Still unaddressed (verified — Record<string, {projectPath: null | string}> widening)
agent-path-resolver.ts:resolveUserPath Windows ~\foo gap src/server/infra/connectors/shared/agent-path-resolver.ts:29 (nitpick) Still unaddressed (verified — ~/ only; resolveOpenClawUserPath at l. 64-77 handles both via /^~[\\/]/u)
mcp-connector-config.ts Hermes configPathResolver ignores injection src/server/infra/connectors/mcp/mcp-connector-config.ts:205 Still unaddressed (verified — still () => path.join(resolveHermesHome(), 'config.yaml') with no options)
SKILL_FILE_NAMES[0] magic indexing in uninstall src/server/infra/connectors/skill/skill-connector.ts:255, 274 Still unaddressed (install() correctly uses MAIN_SKILL_FILE_NAME at l. 123)
openclaw.json parsed with yamlLoad src/server/infra/connectors/skill/autonomous-agent-attachments.ts:83 Still unaddressed
INVALID_OPENCLAW_ID_CHARS_RE g flag intent comment src/server/infra/connectors/skill/autonomous-agent-attachments.ts:22 Still unaddressed
BYTEROVER_BLOCK_MARKERS = BRV_RULE_MARKERS identity src/server/infra/connectors/shared/constants.ts:22-29 Resolved via documentation ✓ (docstring on l. 22-28 explains the legacy-detection invariant)

Tests & build

  • Existing unit suites unchanged in scope; the revert removed the curate-judgement.md-specific test cases added in eafd498 (consistent with reverting the feature).
  • Persistent gap (5th time flagged): no test covers (a) the YAML-parse-failure branch in yaml-mcp-config-writer.write(), or (b) the re-install-clobbers-edited-sub-skill path in skill-connector.install(). A red test for either would force the corresponding priority issue into the fix queue.

Recommendation

Approve once at least these two top-priority items land — they're the only ones that can lose user content silently:

  1. yaml-mcp-config-writer.ts:88-101 — back up or refuse on invalid YAML.
  2. skill-connector.ts:126-132 — match writeSkillFiles' per-file existence check (or gate behind --force, or add a "Do not edit — regenerated" header).

Items 3 (curate.md/query.md HERMES_HOME consistency) and 4 (hub-handler.ts:95-98 widening cast) are smaller scope and could land in a follow-up if you'd rather keep this PR's diff focused.

Checklist

  • Fetch latest branch and diff against origin/proj/byterover-tool-mode
  • Verify status of prior-review findings against current HEAD (cda1cd3)
  • Re-read key changed files (yaml-mcp-config-writer, skill-connector, hub-handler, agent-path-resolver, autonomous-agent-attachments, constants, curate.md, query.md, mcp-connector-config)
  • Check whether the new commit (cda1cd3) addresses any open issues — it doesn't (it's a revert of curate-judgement.md)
  • Avoid re-posting inline comments already filed multiple times; reference them from the summary instead
  • Post final summary with overall score
    branch feat/ENG-2697

wzlng and others added 3 commits May 24, 2026 00:51
Add a guided 90-second onboarding skill that runs when a user asks
"Show me how ByteRover works" (or any semantic equivalent). The tour
captures the user's persona and the pain that brought them to
ByteRover, persists both locally, and demonstrates how ByteRover
ends the re-explain tax — all without an account, API key, or
provider config.

src/server/templates/skill/onboarding.md (new):
- Msg 1: trust opener (no command names) → one-sentence concept
  primer → quick interview (identity + pain in one open question) →
  human-reaction beat before curate → visible artifact with pain
  bullet + sticky label ("re-explain tax") + behavioral commitment
  → 2-beat concept map with visual separation before pause
- Msg 2: named action ("brv query"), one-line retrieval summary,
  conditional bonus-context branch when existing project knowledge
  is found, identity-and-pain reflection, future-self demonstration
  of the pain ending, loop name + cross-session promise
- Msg 3: where memory lives (one sentence, no commands) →
  activation step that detects CLAUDE.md/AGENTS.md/etc. and offers
  to curate as starter project context (or prompts for one rule)
  → done signal with two equal-weight paths (curate more vs.
  resume work) so users exit without homework
- Spec guards: don't manufacture pains, don't overpromise on
  out-of-scope pains, don't turn the artifact into a confirmation,
  don't tailor with hollow phrases, don't auto-fire next message

src/server/templates/skill/SKILL.md:
- Add First-Turn Routing block before the Iron Law that hands off
  to onboarding.md on tour/intro/walkthrough requests
- Update frontmatter description so the skill router activates the
  skill on tour-related phrasings

src/server/infra/connectors/skill/skill-connector-config.ts:
- Add onboarding.md to SKILL_FILE_NAMES so the connector copies it
  during install
feat: [ENG-2536] add ByteRover onboarding tour skill
Msg 1 closes with a teaser line ("Also version-controlled, cloud-syncable,
and shareable across agents — more at the end") so users know more controls
exist without diluting the local-only trust climax. Msg 3 Part 1 delivers
on it with three short bullets covering brv vc, brv vc push/pull, and
connector cross-agent sharing.

Without this, the tour leaves users thinking ByteRover is local-only with
no team or sync story — they discover the full surface area accidentally
or not at all.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants