Background
PR #2019 ("feat(hermesagent): add Hermes Agent support for rules and MCP") was reviewed and merged. The implementation is solid and follows existing patterns (Goose for MCP, GrokCLI for rules). Several low-severity findings were identified during review that could be addressed as follow-up improvements.
Details
Code Quality
-
YAML round-trip in fromRulesyncMcp (src/features/mcp/hermesagent-mcp.ts): The method builds a merged JS object, calls dump() to serialize to YAML, then the constructor calls load() to parse it back. Consider a direct constructor path to avoid the serialize-then-deserialize cycle. (Same pattern exists in Goose.)
-
Missing inline comment for _relativeFilePath (src/features/rules/hermesagent-rule.ts): The fromFile method ignores relativeFilePath (prefixed with _) but lacks an inline comment explaining why, unlike the class-level JSDoc.
-
Missing path constant for ~/.hermes/SOUL.md (src/constants/hermesagent-paths.ts): The file header mentions this path, but no constant is defined for it. Adding it now would make the file a complete source of truth.
-
Non-alphabetical e2e matrix insertion (src/e2e/e2e-rules.spec.ts, src/e2e/e2e-mcp.spec.ts): Hermes Agent entries are inserted at inconsistent alphabetical positions. Consider sorting the existing entries while adding the new ones.
-
Hermes-specific timeout passthrough: No timeout/networkTimeout passthrough unlike Goose. If Hermes adds timeout support, this would be a gap.
Security Hardening
-
isRecord vs isPlainObject in parseHermesConfig (src/features/mcp/hermesagent-mcp.ts): isRecord() accepts class instances while isPlainObject() is preferred for prototype-pollution hardening per the codebase guidelines. (Same pattern exists in Goose — consider a cross-cutting fix.)
-
env/headers prototype pollution keys not filtered: While server names are filtered via PROTOTYPE_POLLUTION_KEYS, nested env/headers object keys are not. Low practical risk since js-yaml v4 load() is safe and spread syntax handles __proto__ as a normal property. (Same pattern exists in Goose.)
Solution / Next Steps
- Items 1–5 are low-priority polish. Address at leisure.
- Items 6–7 could be addressed as a cross-cutting improvement across all MCP tool implementations (Goose, Hermes, etc.).
- No urgency — none of these affect correctness or security in practice.
Background
PR #2019 ("feat(hermesagent): add Hermes Agent support for rules and MCP") was reviewed and merged. The implementation is solid and follows existing patterns (Goose for MCP, GrokCLI for rules). Several low-severity findings were identified during review that could be addressed as follow-up improvements.
Details
Code Quality
YAML round-trip in
fromRulesyncMcp(src/features/mcp/hermesagent-mcp.ts): The method builds a merged JS object, callsdump()to serialize to YAML, then the constructor callsload()to parse it back. Consider a direct constructor path to avoid the serialize-then-deserialize cycle. (Same pattern exists in Goose.)Missing inline comment for
_relativeFilePath(src/features/rules/hermesagent-rule.ts): ThefromFilemethod ignoresrelativeFilePath(prefixed with_) but lacks an inline comment explaining why, unlike the class-level JSDoc.Missing path constant for
~/.hermes/SOUL.md(src/constants/hermesagent-paths.ts): The file header mentions this path, but no constant is defined for it. Adding it now would make the file a complete source of truth.Non-alphabetical e2e matrix insertion (
src/e2e/e2e-rules.spec.ts,src/e2e/e2e-mcp.spec.ts): Hermes Agent entries are inserted at inconsistent alphabetical positions. Consider sorting the existing entries while adding the new ones.Hermes-specific timeout passthrough: No
timeout/networkTimeoutpassthrough unlike Goose. If Hermes adds timeout support, this would be a gap.Security Hardening
isRecordvsisPlainObjectinparseHermesConfig(src/features/mcp/hermesagent-mcp.ts):isRecord()accepts class instances whileisPlainObject()is preferred for prototype-pollution hardening per the codebase guidelines. (Same pattern exists in Goose — consider a cross-cutting fix.)env/headersprototype pollution keys not filtered: While server names are filtered viaPROTOTYPE_POLLUTION_KEYS, nestedenv/headersobject keys are not. Low practical risk since js-yaml v4load()is safe and spread syntax handles__proto__as a normal property. (Same pattern exists in Goose.)Solution / Next Steps