lithermes-ai 0.8.3 → 0.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +1 -1
  2. package/README_Ko-KR.md +1 -1
  3. package/assets/lithermes-plugin/README.md +4 -4
  4. package/assets/lithermes-plugin/__init__.py +40 -3
  5. package/assets/lithermes-plugin/core.py +104 -0
  6. package/assets/lithermes-plugin/payload-version.json +151 -7
  7. package/assets/lithermes-plugin/plugin.yaml +1 -1
  8. package/assets/lithermes-plugin/skills/debugging/SKILL.md +42 -0
  9. package/assets/lithermes-plugin/skills/litresearch/SKILL.md +241 -0
  10. package/assets/lithermes-plugin/skills/lsp-setup/SKILL.md +153 -0
  11. package/assets/lithermes-plugin/skills/lsp-setup/references/bash/README.md +68 -0
  12. package/assets/lithermes-plugin/skills/lsp-setup/references/c-cpp/README.md +78 -0
  13. package/assets/lithermes-plugin/skills/lsp-setup/references/csharp/README.md +90 -0
  14. package/assets/lithermes-plugin/skills/lsp-setup/references/dart/README.md +59 -0
  15. package/assets/lithermes-plugin/skills/lsp-setup/references/elixir/README.md +61 -0
  16. package/assets/lithermes-plugin/skills/lsp-setup/references/go/README.md +63 -0
  17. package/assets/lithermes-plugin/skills/lsp-setup/references/haskell/README.md +69 -0
  18. package/assets/lithermes-plugin/skills/lsp-setup/references/java/README.md +70 -0
  19. package/assets/lithermes-plugin/skills/lsp-setup/references/julia/README.md +70 -0
  20. package/assets/lithermes-plugin/skills/lsp-setup/references/kotlin/README.md +72 -0
  21. package/assets/lithermes-plugin/skills/lsp-setup/references/lua/README.md +68 -0
  22. package/assets/lithermes-plugin/skills/lsp-setup/references/php/README.md +61 -0
  23. package/assets/lithermes-plugin/skills/lsp-setup/references/python/README.md +73 -0
  24. package/assets/lithermes-plugin/skills/lsp-setup/references/ruby/README.md +67 -0
  25. package/assets/lithermes-plugin/skills/lsp-setup/references/rust/README.md +65 -0
  26. package/assets/lithermes-plugin/skills/lsp-setup/references/swift/README.md +64 -0
  27. package/assets/lithermes-plugin/skills/lsp-setup/references/terraform/README.md +66 -0
  28. package/assets/lithermes-plugin/skills/lsp-setup/references/typescript/README.md +82 -0
  29. package/assets/lithermes-plugin/skills/lsp-setup/references/yaml/README.md +65 -0
  30. package/assets/lithermes-plugin/skills/lsp-setup/references/zig/README.md +59 -0
  31. package/assets/lithermes-plugin/skills/lsp-setup/scripts/detect-lsp.ts +221 -0
  32. package/assets/lithermes-plugin/skills/lsp-setup/scripts/lsp-server-table.ts +146 -0
  33. package/assets/lithermes-plugin/skills/lsp-setup/scripts/tsconfig.json +18 -0
  34. package/assets/lithermes-plugin/skills/lsp-setup/scripts/verify-lsp.ts +252 -0
  35. package/assets/lithermes-plugin/skills/visual-qa/SKILL.md +282 -0
  36. package/assets/lithermes-plugin/skills/visual-qa/scripts/ansi.ts +17 -0
  37. package/assets/lithermes-plugin/skills/visual-qa/scripts/cli.ts +96 -0
  38. package/assets/lithermes-plugin/skills/visual-qa/scripts/east-asian-width.ts +72 -0
  39. package/assets/lithermes-plugin/skills/visual-qa/scripts/image-diff.ts +109 -0
  40. package/assets/lithermes-plugin/skills/visual-qa/scripts/png-crc.ts +27 -0
  41. package/assets/lithermes-plugin/skills/visual-qa/scripts/png-decode.ts +206 -0
  42. package/assets/lithermes-plugin/skills/visual-qa/scripts/png-synth.ts +57 -0
  43. package/assets/lithermes-plugin/skills/visual-qa/scripts/tui-grid.ts +88 -0
  44. package/assets/lithermes-plugin/skills/visual-qa/scripts/types.ts +54 -0
  45. package/package.json +1 -1
package/README.md CHANGED
@@ -59,7 +59,7 @@ Restart any running Hermes CLI or Hermes gateway process. Then open Hermes and t
59
59
  - LitHermes workflow skill set: `ai-slop-remover`, `comment-checker`,
60
60
  `debugging`, `deep-interview`, `frontend-ui-ux`, `git-master`, `init-deep`,
61
61
  `lsp`, `programming`, `refactor`,
62
- `remove-ai-slops`, `review-work`, `rules`, `start-work`, `lit-plan`,
62
+ `remove-ai-slops`, `review-work`, `rules`, `visual-qa`, `lsp-setup`, `litresearch`, `start-work`, `lit-plan`,
63
63
  `litgoal`, and `litwork` are installed as `lithermes:*` skills.
64
64
  - The full plugin payload — the `pre_llm_call` / `subagent_stop` hooks, every
65
65
  skill, and the durable goal tooling — ships in the bundle exactly as installed,
package/README_Ko-KR.md CHANGED
@@ -59,7 +59,7 @@ npx lithermes-ai install --yes
59
59
  - LitHermes workflow skill set: `ai-slop-remover`, `comment-checker`,
60
60
  `debugging`, `deep-interview`, `frontend-ui-ux`, `git-master`, `init-deep`,
61
61
  `lsp`, `programming`, `refactor`,
62
- `remove-ai-slops`, `review-work`, `rules`, `start-work`, `lit-plan`,
62
+ `remove-ai-slops`, `review-work`, `rules`, `visual-qa`, `lsp-setup`, `litresearch`, `start-work`, `lit-plan`,
63
63
  `litgoal`, `litwork`가 `lithermes:*` skill로 함께 설치됩니다.
64
64
  - 전체 plugin payload — `pre_llm_call` / `subagent_stop`
65
65
  hook, 모든 skill, durable goal tooling — 이 설치 상태 그대로 번들에 들어가므로,
@@ -16,11 +16,11 @@ first-class Hermes skills:
16
16
  `lithermes:ai-slop-remover`, `lithermes:comment-checker`,
17
17
  `lithermes:debugging`, `lithermes:deep-interview`,
18
18
  `lithermes:frontend-ui-ux`, `lithermes:git-master`,
19
- `lithermes:init-deep`, `lithermes:lsp`,
20
- `lithermes:programming`, `lithermes:refactor`,
19
+ `lithermes:init-deep`, `lithermes:lsp`, `lithermes:lsp-setup`,
20
+ `lithermes:litresearch`, `lithermes:programming`, `lithermes:refactor`,
21
21
  `lithermes:remove-ai-slops`, `lithermes:review-work`,
22
- `lithermes:rules`, `lithermes:start-work`, `lithermes:lit-plan`,
23
- `lithermes:litgoal`, and `lithermes:litwork`.
22
+ `lithermes:rules`, `lithermes:start-work`, `lithermes:visual-qa`,
23
+ `lithermes:lit-plan`, `lithermes:litgoal`, and `lithermes:litwork`.
24
24
  - Delegation fans lanes out through the native `delegate_task` tool (children
25
25
  run in parallel, the parent blocks for all); there is no named-agent registry
26
26
  and no per-child model selection.
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import argparse
3
4
  import functools
4
5
  from pathlib import Path
5
6
  from typing import Any
@@ -79,6 +80,18 @@ PORTED_SKILLS = [
79
80
  "litwork",
80
81
  "Hermes-native Litwork execution discipline.",
81
82
  ),
83
+ (
84
+ "visual-qa",
85
+ "Rigorously verify any web/TUI UI you built or changed with screenshot/terminal diffs and oracle passes.",
86
+ ),
87
+ (
88
+ "lsp-setup",
89
+ "Configure a language server for LitHermes LSP diagnostics across 20+ languages.",
90
+ ),
91
+ (
92
+ "litresearch",
93
+ "Run the LitHermes maximum-saturation research orchestrator: decompose, parallel delegate_task swarms, verify, synthesize cited.",
94
+ ),
82
95
  ]
83
96
 
84
97
 
@@ -104,16 +117,40 @@ def _pre_llm_call(**kwargs: Any) -> dict[str, str] | None:
104
117
 
105
118
 
106
119
  def _setup_lithermes_cli(parser) -> None:
120
+ try:
121
+ parser.formatter_class = argparse.RawDescriptionHelpFormatter
122
+ except Exception:
123
+ pass
124
+ parser.description = "LitHermes — Hermes-native Litwork toolkit (litgoal runtime, skills, hooks)."
125
+ parser.epilog = (
126
+ "slash commands: /lit /lit-loop /lit-plan /litgoal /review-work /start-work /deep-interview\n"
127
+ "skills: 20 lithermes:* skills — `hermes lithermes status` lists them\n"
128
+ "hooks: pre_llm_call, subagent_stop, transform_llm_output\n"
129
+ "run `hermes lithermes status` for versions + full surface, or `doctor` for health checks"
130
+ )
131
+ parser.add_argument("--version", action="store_true", help="print the LitHermes plugin version")
107
132
  sub = parser.add_subparsers(dest="lh_cmd")
133
+ sub.add_parser("version", help="print the LitHermes plugin version")
134
+ sub.add_parser("status", help="show LitHermes + Hermes versions, hooks, commands, skills")
135
+ sub.add_parser("doctor", help="run LitHermes health checks")
108
136
  goal_parser = sub.add_parser("goal", help="LitHermes litgoal durable runtime")
109
137
  litgoal_cli.setup(goal_parser)
110
138
 
111
139
 
112
140
  def _handle_lithermes_cli(args) -> int:
113
- if getattr(args, "lh_cmd", None) == "goal":
141
+ cmd = getattr(args, "lh_cmd", None)
142
+ if getattr(args, "version", False) or cmd == "version":
143
+ print(core.version_line())
144
+ return 0
145
+ if cmd == "doctor":
146
+ lines, code = core.doctor_report()
147
+ print("\n".join(lines))
148
+ return code
149
+ if cmd == "goal":
114
150
  return litgoal_cli.handle(args)
115
- print("usage: hermes lithermes goal <set|status|criterion|evidence|steer|checkpoint|complete>")
116
- return 1
151
+ # status, or bare `hermes lithermes` the most useful "who am I" answer
152
+ print(core.status_report())
153
+ return 0
117
154
 
118
155
 
119
156
  def _ignited(handler):
@@ -981,3 +981,107 @@ def command_start_work(raw_args: str) -> str | dict[str, str]:
981
981
  "display": display,
982
982
  "agent_message": build_run_agent_message(load_run_state(run_dir)),
983
983
  }
984
+
985
+
986
+ # ---------------------------------------------------------------------------
987
+ # Management / diagnostics surface (hermes lithermes version|status|doctor).
988
+ # Hermes plugins otherwise can't answer "who am I and what version" — these
989
+ # helpers back the CLI subcommands wired in __init__.py.
990
+ # ---------------------------------------------------------------------------
991
+
992
+ PLUGIN_ROOT = Path(__file__).resolve().parent
993
+ # These mirror what register()/register_hook()/litgoal tools wire up in __init__.py.
994
+ # They are hardcoded (not introspected) so `status` works without a live ctx —
995
+ # keep them in sync when adding a hook / slash command / goal tool.
996
+ HOOKS = ("pre_llm_call", "subagent_stop", "transform_llm_output")
997
+ SLASH_COMMANDS = (
998
+ "lit", "lit-loop", "lit-plan", "litgoal", "review-work",
999
+ "start-work", "deep-interview", "litwork-loop", "litwork-plan",
1000
+ )
1001
+ GOAL_TOOLS = (
1002
+ "goal_set", "goal_status", "goal_add_criterion", "goal_evidence",
1003
+ "goal_criterion_status", "goal_steer", "goal_checkpoint", "goal_complete",
1004
+ )
1005
+ _VERSION_RE = re.compile(r"^version:\s*(.+)$", re.MULTILINE)
1006
+
1007
+
1008
+ def plugin_version() -> str:
1009
+ """Read the LitHermes plugin version from the bundled plugin.yaml."""
1010
+ try:
1011
+ m = _VERSION_RE.search((PLUGIN_ROOT / "plugin.yaml").read_text(encoding="utf-8"))
1012
+ return m.group(1).strip().strip("\"'") if m else "unknown"
1013
+ except (OSError, ValueError):
1014
+ return "unknown"
1015
+
1016
+
1017
+ def hermes_host_version() -> str:
1018
+ """Best-effort Hermes host runtime version (unknown outside Hermes)."""
1019
+ try:
1020
+ import hermes_cli
1021
+ return str(getattr(hermes_cli, "__version__", "") or "unknown")
1022
+ except Exception:
1023
+ return "unknown"
1024
+
1025
+
1026
+ def version_line() -> str:
1027
+ return f"lithermes {plugin_version()}"
1028
+
1029
+
1030
+ def _evidence_kinds() -> tuple[str, ...]:
1031
+ try:
1032
+ from .litgoal import model
1033
+ return tuple(model.EVIDENCE_KINDS)
1034
+ except Exception:
1035
+ return ("red", "green", "scenario", "cleanup", "note")
1036
+
1037
+
1038
+ def _skill_names() -> list[str]:
1039
+ skills_dir = PLUGIN_ROOT / "skills"
1040
+ if not skills_dir.is_dir():
1041
+ return []
1042
+ return sorted(d.name for d in skills_dir.iterdir() if (d / "SKILL.md").is_file())
1043
+
1044
+
1045
+ def status_report() -> str:
1046
+ """One-glance health/identity line for `hermes lithermes status`."""
1047
+ skills = _skill_names()
1048
+ return "\n".join([
1049
+ f"LitHermes plugin {plugin_version()} (Hermes host {hermes_host_version()})",
1050
+ f"plugin dir: {PLUGIN_ROOT}",
1051
+ f"hooks ({len(HOOKS)}): {', '.join(HOOKS)}",
1052
+ f"slash commands ({len(SLASH_COMMANDS)}): {', '.join('/' + c for c in SLASH_COMMANDS)}",
1053
+ f"skills ({len(skills)}): {', '.join(skills)}",
1054
+ f"goal tools ({len(GOAL_TOOLS)}): {', '.join(GOAL_TOOLS)}",
1055
+ "litgoal state: .hermes/lithermes/litgoal/ (drive via: hermes lithermes goal status)",
1056
+ f"litgoal evidence kinds: {', '.join(_evidence_kinds())}",
1057
+ ])
1058
+
1059
+
1060
+ def doctor_report() -> tuple[list[str], int]:
1061
+ """Health checks for `hermes lithermes doctor`. Returns (lines, exit_code)."""
1062
+ lines: list[str] = []
1063
+ ok = True
1064
+ ver = plugin_version()
1065
+ if ver != "unknown":
1066
+ lines.append(f"[OK] plugin.yaml readable (version {ver})")
1067
+ else:
1068
+ lines.append("[WARN] plugin.yaml unreadable or missing a version field")
1069
+ ok = False
1070
+ skills = _skill_names()
1071
+ if skills:
1072
+ lines.append(f"[OK] skills bundled: {len(skills)}")
1073
+ else:
1074
+ lines.append("[WARN] no skills found under skills/")
1075
+ ok = False
1076
+ try:
1077
+ from .litgoal import runtime as _rt # noqa: F401
1078
+ lines.append("[OK] litgoal durable runtime importable")
1079
+ except Exception as exc:
1080
+ lines.append(f"[WARN] litgoal runtime import failed: {exc}")
1081
+ ok = False
1082
+ hv = hermes_host_version()
1083
+ if hv != "unknown":
1084
+ lines.append(f"[OK] Hermes host detected (v{hv})")
1085
+ else:
1086
+ lines.append("[NOTE] Hermes host version unknown (running outside Hermes?)")
1087
+ return lines, (0 if ok else 1)
@@ -1,7 +1,7 @@
1
1
  {
2
- "syncedAt": "2026-06-14T07:44:14.269Z",
2
+ "syncedAt": "2026-06-15T16:35:55.443Z",
3
3
  "source": "source-reference",
4
- "sourceHash": "1072e4218aeda8d0a4c03e11189b07505021bc4acc3b1280bfeabdd420d1ff9a",
4
+ "sourceHash": "c93c37881e1f6f5730a1adc6c0e62e4dfab1ca44146eed900b8468448438fe8a",
5
5
  "files": [
6
6
  {
7
7
  "path": "NOTICE.md",
@@ -9,15 +9,15 @@
9
9
  },
10
10
  {
11
11
  "path": "README.md",
12
- "sha256": "e0bc7d60f61a8d35df9f6287876e236e59e80e871261558701375a12cc4e4feb"
12
+ "sha256": "29f9157e4aa5a667c0d4c2df30d803c4eaa8cc4b30937c84ac1a08b8257e1eca"
13
13
  },
14
14
  {
15
15
  "path": "__init__.py",
16
- "sha256": "9a0b19060eb12799bf76b15b729fcbab4388d74aac9e888b40369b809fd54669"
16
+ "sha256": "96b816aee730ea9a5e1fedbc283829240baffddecc37872e4f60bb05f420366c"
17
17
  },
18
18
  {
19
19
  "path": "core.py",
20
- "sha256": "6b9d8b488d5905232d170f78943d2b5f9b9a4bde564e01a816c4fcc45098a7df"
20
+ "sha256": "70ddccfb4cc2fe1a923a5a61244e5cb36ef8ac0f94d34a76703fa6d82dbabf3f"
21
21
  },
22
22
  {
23
23
  "path": "litgoal/__init__.py",
@@ -49,7 +49,7 @@
49
49
  },
50
50
  {
51
51
  "path": "plugin.yaml",
52
- "sha256": "7ef63d09b537d994dc5ed25149b0841e84745ae352c851d9a54788ddd793b0e9"
52
+ "sha256": "7761c417acfcd614e8d434b3ca11c498f48422a72f5b70f817a59326aca51b60"
53
53
  },
54
54
  {
55
55
  "path": "skills/ai-slop-remover/SKILL.md",
@@ -61,7 +61,7 @@
61
61
  },
62
62
  {
63
63
  "path": "skills/debugging/SKILL.md",
64
- "sha256": "aff2ca5765f490ed1e45d2eaa77c48db3ef98cec12fa10ebff3f91b82eab1254"
64
+ "sha256": "48bdb0df0f41633aca17d6193aa98aabac4c49cc25c36e50f26b020f89f77d43"
65
65
  },
66
66
  {
67
67
  "path": "skills/debugging/references/methodology/00-setup.md",
@@ -163,10 +163,114 @@
163
163
  "path": "skills/litgoal/SKILL.md",
164
164
  "sha256": "7a1fc23afe57f957a063a70b1bf810dc9c66fd44bcfd93b1ec739d59167e5ad9"
165
165
  },
166
+ {
167
+ "path": "skills/litresearch/SKILL.md",
168
+ "sha256": "3ff390e7a5847aebfa8943fe593fa386f9aeab2716fb30f7b20feaa3990f311f"
169
+ },
166
170
  {
167
171
  "path": "skills/litwork/SKILL.md",
168
172
  "sha256": "625e8ed44365d5ebcab9b8a3a2e1db4ccd5d4b6a7cbff6710fabfa51fd8727ad"
169
173
  },
174
+ {
175
+ "path": "skills/lsp-setup/SKILL.md",
176
+ "sha256": "52e473a5727ab80e90d1bfd6c3a91d8a2ba9579c30bf65af1dd895eb3918900a"
177
+ },
178
+ {
179
+ "path": "skills/lsp-setup/references/bash/README.md",
180
+ "sha256": "7d32640c2f50ad18e4ccf1ab2f7b4b1ea989ce2228054c8bc2f05b97d484f8ad"
181
+ },
182
+ {
183
+ "path": "skills/lsp-setup/references/c-cpp/README.md",
184
+ "sha256": "0334f275754d4231a30700b9f1518c06ae9fd04f8809e3c89b197763cbdfdbb3"
185
+ },
186
+ {
187
+ "path": "skills/lsp-setup/references/csharp/README.md",
188
+ "sha256": "1717ca8bf762832f7209ef1d10f8896958e1a5a9c0445b8b9ce7bbce18423fb8"
189
+ },
190
+ {
191
+ "path": "skills/lsp-setup/references/dart/README.md",
192
+ "sha256": "eaa9b13bdbcd162b43220fdefb6292a86d53b053c32d60b3d067f9785a26c9df"
193
+ },
194
+ {
195
+ "path": "skills/lsp-setup/references/elixir/README.md",
196
+ "sha256": "385b3d4c3d0d531afb07e33570c502e754174b52125ae6572a35edd24d0da1e5"
197
+ },
198
+ {
199
+ "path": "skills/lsp-setup/references/go/README.md",
200
+ "sha256": "e0f2ced60994adfe22a76e37d69deb3308fe7f4885a9579e28b864a1948e7c22"
201
+ },
202
+ {
203
+ "path": "skills/lsp-setup/references/haskell/README.md",
204
+ "sha256": "df6dc810662b52de10d358edae6742cfab9cd66fc1636c68096ffe7f241fe102"
205
+ },
206
+ {
207
+ "path": "skills/lsp-setup/references/java/README.md",
208
+ "sha256": "a33e64405e090ffc4ec028d2aead42ec3c52b8c38f72ec0f92e4f0324bbbf4f3"
209
+ },
210
+ {
211
+ "path": "skills/lsp-setup/references/julia/README.md",
212
+ "sha256": "779799ec0ce809b10136167f768c65a756438e5a478ef338249619cc76511e78"
213
+ },
214
+ {
215
+ "path": "skills/lsp-setup/references/kotlin/README.md",
216
+ "sha256": "f4472bb7c34328aaeb1461d0c729efbf738a2e89fc94a1eb729f2a868ca88a76"
217
+ },
218
+ {
219
+ "path": "skills/lsp-setup/references/lua/README.md",
220
+ "sha256": "892613acb00e9cdb50ba5e69f147e33788a9b3db6500371f2ae6e20a07db3220"
221
+ },
222
+ {
223
+ "path": "skills/lsp-setup/references/php/README.md",
224
+ "sha256": "3719c12c64bd823ff9cf7af4073e14eaa4799726dee5b20a593b8a528527472f"
225
+ },
226
+ {
227
+ "path": "skills/lsp-setup/references/python/README.md",
228
+ "sha256": "b64b0add1c8eb5472cf03bfe4aad7ee4eab20c8f12874be20739071cdd58be7d"
229
+ },
230
+ {
231
+ "path": "skills/lsp-setup/references/ruby/README.md",
232
+ "sha256": "6c7a146dc58ef38c3670ba4c16690e419c96099ac6e62f0f059d4f16a5792e48"
233
+ },
234
+ {
235
+ "path": "skills/lsp-setup/references/rust/README.md",
236
+ "sha256": "2797c7c27d1041924600192cb649d81bbb94a53ddbb894f82748e977eac64d3a"
237
+ },
238
+ {
239
+ "path": "skills/lsp-setup/references/swift/README.md",
240
+ "sha256": "d7589fe85fae9937bfcfb951e41171577e743f6e4b7cea9dbef575b811d041ed"
241
+ },
242
+ {
243
+ "path": "skills/lsp-setup/references/terraform/README.md",
244
+ "sha256": "fe86c8bcb4966efd400e083bd3e22863ee4fae56c3fba1eb3abdaa666fe9c24e"
245
+ },
246
+ {
247
+ "path": "skills/lsp-setup/references/typescript/README.md",
248
+ "sha256": "fbdc8348d5d0b3978e73d7bd3701d34d8df692d031437e87c19b8708a5946108"
249
+ },
250
+ {
251
+ "path": "skills/lsp-setup/references/yaml/README.md",
252
+ "sha256": "c9456d750ba91716e30538d262e83f70ae51b44697e3bdee87d68dbf861f4b63"
253
+ },
254
+ {
255
+ "path": "skills/lsp-setup/references/zig/README.md",
256
+ "sha256": "87b955a8bd792561e291fe2922b467714aefdf59bede752938b20ce3da2a402c"
257
+ },
258
+ {
259
+ "path": "skills/lsp-setup/scripts/detect-lsp.ts",
260
+ "sha256": "32d9dba93c1e604e49e6049603c0ee8da67927540a7c53c87fc46c9a059b5178"
261
+ },
262
+ {
263
+ "path": "skills/lsp-setup/scripts/lsp-server-table.ts",
264
+ "sha256": "fc281d78ff2f50657d4c9bcc253f2ff8c0f9e6be1dcea0b9963f52d874ef801e"
265
+ },
266
+ {
267
+ "path": "skills/lsp-setup/scripts/tsconfig.json",
268
+ "sha256": "8eecbbef0296b909dbe17af651126cf2c00a825ae65fa5be2836b212267c6f83"
269
+ },
270
+ {
271
+ "path": "skills/lsp-setup/scripts/verify-lsp.ts",
272
+ "sha256": "33c6c22236234ed5f4db7b0deae560b9b5e0c8c018be4ded1a6c1179792655fe"
273
+ },
170
274
  {
171
275
  "path": "skills/lsp/SKILL.md",
172
276
  "sha256": "3e793aaa158156dd60ec11add7375050bbeeb7b3eb77497f1c432d0842abff5c"
@@ -478,6 +582,46 @@
478
582
  {
479
583
  "path": "skills/start-work/SKILL.md",
480
584
  "sha256": "194a1d719c00564959da99715c86424a5ecd76196a4db9ca60e64be062dc70b5"
585
+ },
586
+ {
587
+ "path": "skills/visual-qa/SKILL.md",
588
+ "sha256": "fd1ed0841afc08ca838069969284afa04b16c81016a63a16d2f9187a3bde3327"
589
+ },
590
+ {
591
+ "path": "skills/visual-qa/scripts/ansi.ts",
592
+ "sha256": "8d6e2f3881093538a96040ec8fea28285754e28ceac1b1f1da1e6d5024eeacfd"
593
+ },
594
+ {
595
+ "path": "skills/visual-qa/scripts/cli.ts",
596
+ "sha256": "0dc05cf89afbd8df5371722229ada00751ba58eda633405457964ccd8bc6ac23"
597
+ },
598
+ {
599
+ "path": "skills/visual-qa/scripts/east-asian-width.ts",
600
+ "sha256": "8cd4ac48a57bad794639be581f7dd2b52105ad258d090b403a74a46b10a83952"
601
+ },
602
+ {
603
+ "path": "skills/visual-qa/scripts/image-diff.ts",
604
+ "sha256": "3b4e68afa5ad3e2bbd2866ba9b5a39b7e371b773c6d6b1d3a080a2f381cc00e4"
605
+ },
606
+ {
607
+ "path": "skills/visual-qa/scripts/png-crc.ts",
608
+ "sha256": "881027d0bb58b1633fd46b58e3034fefb61cba2e173af666c24a5ea4f95429d0"
609
+ },
610
+ {
611
+ "path": "skills/visual-qa/scripts/png-decode.ts",
612
+ "sha256": "9c190b960e276a81b3f962e509a45b72fe8bcc6a93d704fbee3a383fcde4bb64"
613
+ },
614
+ {
615
+ "path": "skills/visual-qa/scripts/png-synth.ts",
616
+ "sha256": "acc348340f1efd1cc6d312753912ef294640d5585a05a6839c72784fb64fcb84"
617
+ },
618
+ {
619
+ "path": "skills/visual-qa/scripts/tui-grid.ts",
620
+ "sha256": "63a0db7624eda98cfd37434552f9e56a48195bbeab8a9bbdd017c97b369bf58c"
621
+ },
622
+ {
623
+ "path": "skills/visual-qa/scripts/types.ts",
624
+ "sha256": "ef5ee3c9adfeb2d92138b2ce543232a8323247d5b9dbdde13b26f3197ee13c62"
481
625
  }
482
626
  ]
483
627
  }
@@ -1,5 +1,5 @@
1
1
  name: lithermes
2
- version: 0.8.3
2
+ version: 0.8.5
3
3
  description: "Hermes-native workflow toolkit: litgoal durable runtime, 5-lane review orchestrator, Litwork commands, skills, and prompt steering."
4
4
  author: "Hermes Agent"
5
5
  kind: standalone
@@ -89,6 +89,48 @@ These are not phases — read them when the situation calls for them:
89
89
 
90
90
  ---
91
91
 
92
+ ## Reproduction standards
93
+
94
+ A good reproduction is:
95
+
96
+ - runnable from the project root
97
+ - deterministic, or carries a bounded flake note
98
+ - small enough for the next agent to rerun
99
+ - tied to one expected observable
100
+
101
+ For LitHermes examples:
102
+
103
+ - `cd ~/.hermes/hermes-agent && venv/bin/python -c "import sys; sys.path.insert(0,'$HOME/.hermes/plugins'); import lithermes.core as c; print(bool(c.pre_llm_call(user_message='lit go', session_id='x')))"`
104
+ - `hermes -z "Reply READY then stop. lit"` → expect `READY`, exit 0
105
+ - `npm test` from `packages/lithermes-installer/`
106
+ - `node test/scripts/scan-forbidden-tokens.js --tracked`
107
+
108
+ ## Root cause discipline
109
+
110
+ Explain the mechanism, not just the symptom. "The command didn't bind the goal"
111
+ is not a root cause. "The slash-command handler is dispatched as `handler(user_args)`
112
+ with no `session_id`, so it cannot call `GoalManager.set()` — binding has to happen
113
+ in `pre_llm_call`, which does receive the session id" is a root cause.
114
+
115
+ ## Common LitHermes failure classes
116
+
117
+ - Plugin manifest (`plugin.yaml`) version drifts from `package.json` — a guard test asserts they match.
118
+ - `npx <pkg>` fails with `command not found` when the bin name ≠ the package name (needs a matching bin alias).
119
+ - `npm publish` requires the user's OTP and fails with `EOTP` — it cannot be run unattended.
120
+ - Hook JSON parsing must fail with a controlled error, never a raw stack trace.
121
+ - Package `files` / `payload-version.json` omit a newly added skill or command.
122
+ - A per-turn flag left in module state leaks into the next turn when a hook does not fire (e.g. an interrupted turn).
123
+
124
+ ## Patch rules
125
+
126
+ - Patch the failing boundary, not an unrelated symptom.
127
+ - Keep compatibility aliases unless a breaking change is intentional.
128
+ - Add the failing test before changing production behavior.
129
+ - Do not broaden `except`/`catch` blocks without asserting the new error path.
130
+ - Never call the network, publish, or mutate shared user state inside tests.
131
+
132
+ ---
133
+
92
134
  ## Non-Negotiable Safety Invariants
93
135
 
94
136
  <safety>