lithermes-ai 0.6.0 → 0.8.1
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.
- package/README.md +2 -1
- package/README_Ko-KR.md +2 -1
- package/assets/lithermes-plugin/README.md +2 -1
- package/assets/lithermes-plugin/__init__.py +31 -9
- package/assets/lithermes-plugin/core.py +90 -0
- package/assets/lithermes-plugin/payload-version.json +14 -6
- package/assets/lithermes-plugin/plugin.yaml +2 -1
- package/assets/lithermes-plugin/skills/git-master/SKILL.md +130 -0
- package/assets/lithermes-plugin/skills/init-deep/SKILL.md +198 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -57,7 +57,8 @@ Restart any running Hermes CLI or Hermes gateway process. Then open Hermes and t
|
|
|
57
57
|
- Interactive install spinner keeps terminal installs lively while redirected or scripted installs stay plain; use `npx lithermes-ai install --yes --no-spinner` for quiet terminal installs.
|
|
58
58
|
- `start-work`: open or dry-run a LitHermes plan inside Hermes.
|
|
59
59
|
- LitHermes workflow skill set: `ai-slop-remover`, `comment-checker`,
|
|
60
|
-
`debugging`, `deep-interview`, `frontend-ui-ux`, `
|
|
60
|
+
`debugging`, `deep-interview`, `frontend-ui-ux`, `git-master`, `init-deep`,
|
|
61
|
+
`lsp`, `programming`, `refactor`,
|
|
61
62
|
`remove-ai-slops`, `review-work`, `rules`, `start-work`, `lit-plan`,
|
|
62
63
|
`litgoal`, and `litwork` are installed as `lithermes:*` skills.
|
|
63
64
|
- The full plugin payload — the `pre_llm_call` / `subagent_stop` hooks, every
|
package/README_Ko-KR.md
CHANGED
|
@@ -57,7 +57,8 @@ npx lithermes-ai install --yes
|
|
|
57
57
|
- interactive install spinner가 terminal 설치는 더 생동감 있게 보여주고, redirect/script 설치는 기존처럼 plain output을 유지합니다. 조용한 terminal 설치가 필요하면 `npx lithermes-ai install --yes --no-spinner`를 사용합니다.
|
|
58
58
|
- `start-work`: LitHermes plan을 Hermes 작업으로 엽니다.
|
|
59
59
|
- LitHermes workflow skill set: `ai-slop-remover`, `comment-checker`,
|
|
60
|
-
`debugging`, `deep-interview`, `frontend-ui-ux`, `
|
|
60
|
+
`debugging`, `deep-interview`, `frontend-ui-ux`, `git-master`, `init-deep`,
|
|
61
|
+
`lsp`, `programming`, `refactor`,
|
|
61
62
|
`remove-ai-slops`, `review-work`, `rules`, `start-work`, `lit-plan`,
|
|
62
63
|
`litgoal`, `litwork`가 `lithermes:*` skill로 함께 설치됩니다.
|
|
63
64
|
- 전체 plugin payload — `pre_llm_call` / `subagent_stop`
|
|
@@ -15,7 +15,8 @@ first-class Hermes skills:
|
|
|
15
15
|
- Explicit skills are available as:
|
|
16
16
|
`lithermes:ai-slop-remover`, `lithermes:comment-checker`,
|
|
17
17
|
`lithermes:debugging`, `lithermes:deep-interview`,
|
|
18
|
-
`lithermes:frontend-ui-ux`, `lithermes:
|
|
18
|
+
`lithermes:frontend-ui-ux`, `lithermes:git-master`,
|
|
19
|
+
`lithermes:init-deep`, `lithermes:lsp`,
|
|
19
20
|
`lithermes:programming`, `lithermes:refactor`,
|
|
20
21
|
`lithermes:remove-ai-slops`, `lithermes:review-work`,
|
|
21
22
|
`lithermes:rules`, `lithermes:start-work`, `lithermes:lit-plan`,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import functools
|
|
3
4
|
from pathlib import Path
|
|
4
5
|
from typing import Any
|
|
5
6
|
|
|
@@ -30,6 +31,14 @@ PORTED_SKILLS = [
|
|
|
30
31
|
"frontend-ui-ux",
|
|
31
32
|
"Apply the LitHermes frontend UI/UX review discipline.",
|
|
32
33
|
),
|
|
34
|
+
(
|
|
35
|
+
"git-master",
|
|
36
|
+
"Run the LitHermes git-history specialist for commits, rebases, blame, and bisect.",
|
|
37
|
+
),
|
|
38
|
+
(
|
|
39
|
+
"init-deep",
|
|
40
|
+
"Generate a hierarchical AGENTS.md knowledge base with the LitHermes onboarding workflow.",
|
|
41
|
+
),
|
|
33
42
|
(
|
|
34
43
|
"lsp",
|
|
35
44
|
"Use Hermes' native LSP diagnostics with LitHermes LSP guidance.",
|
|
@@ -107,6 +116,16 @@ def _handle_lithermes_cli(args) -> int:
|
|
|
107
116
|
return 1
|
|
108
117
|
|
|
109
118
|
|
|
119
|
+
def _ignited(handler):
|
|
120
|
+
"""Wrap a slash-command handler so its display prints the LITBURN banner."""
|
|
121
|
+
|
|
122
|
+
@functools.wraps(handler)
|
|
123
|
+
def wrapped(user_args):
|
|
124
|
+
return core.ignite(handler(user_args))
|
|
125
|
+
|
|
126
|
+
return wrapped
|
|
127
|
+
|
|
128
|
+
|
|
110
129
|
def register(ctx) -> None:
|
|
111
130
|
base = Path(__file__).resolve().parent
|
|
112
131
|
|
|
@@ -114,6 +133,9 @@ def register(ctx) -> None:
|
|
|
114
133
|
ctx.register_hook("pre_llm_call", _pre_llm_call)
|
|
115
134
|
# Record each delegate_task child (review lanes, reviewer gate) to the ledger.
|
|
116
135
|
ctx.register_hook("subagent_stop", core.subagent_stop)
|
|
136
|
+
# Force the LITBURN banner onto a bare-`lit` keyword turn's response (that
|
|
137
|
+
# path has no deterministic display channel; slash commands print it directly).
|
|
138
|
+
ctx.register_hook("transform_llm_output", core.transform_llm_output)
|
|
117
139
|
|
|
118
140
|
# Model-facing litgoal tools (durable criteria/evidence/checkpoint/steering/gate).
|
|
119
141
|
litgoal_tools.register_tools(ctx)
|
|
@@ -128,55 +150,55 @@ def register(ctx) -> None:
|
|
|
128
150
|
|
|
129
151
|
ctx.register_command(
|
|
130
152
|
"lit-plan",
|
|
131
|
-
core.command_lit_plan,
|
|
153
|
+
_ignited(core.command_lit_plan),
|
|
132
154
|
description="Create a durable Litwork implementation plan",
|
|
133
155
|
args_hint='"what to build"',
|
|
134
156
|
)
|
|
135
157
|
ctx.register_command(
|
|
136
158
|
"litwork-plan",
|
|
137
|
-
core.command_lit_plan,
|
|
159
|
+
_ignited(core.command_lit_plan),
|
|
138
160
|
description="Alias for /lit-plan",
|
|
139
161
|
args_hint='"what to build"',
|
|
140
162
|
)
|
|
141
163
|
ctx.register_command(
|
|
142
164
|
"lit",
|
|
143
|
-
core.command_lit,
|
|
165
|
+
_ignited(core.command_lit),
|
|
144
166
|
description="Start an Litwork run and execute the task immediately",
|
|
145
167
|
args_hint='"task" [--completion-promise TEXT] [--strategy reset|continue]',
|
|
146
168
|
)
|
|
147
169
|
ctx.register_command(
|
|
148
170
|
"lit-loop",
|
|
149
|
-
core.command_lit_loop,
|
|
171
|
+
_ignited(core.command_lit_loop),
|
|
150
172
|
description="Start an Litwork run and execute the task immediately",
|
|
151
173
|
args_hint='"task" [--completion-promise TEXT] [--strategy reset|continue]',
|
|
152
174
|
)
|
|
153
175
|
ctx.register_command(
|
|
154
176
|
"litwork-loop",
|
|
155
|
-
core.command_lit_loop,
|
|
177
|
+
_ignited(core.command_lit_loop),
|
|
156
178
|
description="Alias for /lit-loop",
|
|
157
179
|
args_hint='"task" [--completion-promise TEXT] [--strategy reset|continue]',
|
|
158
180
|
)
|
|
159
181
|
ctx.register_command(
|
|
160
182
|
"litgoal",
|
|
161
|
-
core.command_litgoal,
|
|
183
|
+
_ignited(core.command_litgoal),
|
|
162
184
|
description="Open or inspect the LitHermes litgoal durable runtime",
|
|
163
185
|
args_hint='["objective"] [--worktree PATH]',
|
|
164
186
|
)
|
|
165
187
|
ctx.register_command(
|
|
166
188
|
"review-work",
|
|
167
|
-
core.command_review_work,
|
|
189
|
+
_ignited(core.command_review_work),
|
|
168
190
|
description="Run the LitHermes 5-lane review orchestrator on the current diff",
|
|
169
191
|
args_hint="[--base REF]",
|
|
170
192
|
)
|
|
171
193
|
ctx.register_command(
|
|
172
194
|
"start-work",
|
|
173
|
-
core.command_start_work,
|
|
195
|
+
_ignited(core.command_start_work),
|
|
174
196
|
description="Open or dry-run a LitHermes plan against a workspace",
|
|
175
197
|
args_hint="[plan-name] [--worktree PATH] [--dry-run]",
|
|
176
198
|
)
|
|
177
199
|
ctx.register_command(
|
|
178
200
|
"deep-interview",
|
|
179
|
-
core.command_deep_interview,
|
|
201
|
+
_ignited(core.command_deep_interview),
|
|
180
202
|
description="Run the LitHermes Socratic clarity gate before planning/execution",
|
|
181
203
|
args_hint="[--quick|--standard|--deep] <idea>",
|
|
182
204
|
)
|
|
@@ -33,9 +33,22 @@ DIRECT_LIT_PATTERN = re.compile(r"^\s*(?:lit|litwork)\b\s+(?P<task>.+?)\s*$", re
|
|
|
33
33
|
MAX_TASK_LEN = 4000
|
|
34
34
|
_SLUG_PATTERN = re.compile(r"[^a-z0-9]+")
|
|
35
35
|
|
|
36
|
+
# Deterministic ignite banner. Printed verbatim on every LitHermes slash-command
|
|
37
|
+
# display (the only user-visible plugin channel); also instructed into LIT_CONTEXT
|
|
38
|
+
# for the bare-`lit` keyword path (best-effort — that path only reaches the model).
|
|
39
|
+
LITBURN_BANNER = "🔥 LITBURN IGNITED 🔥"
|
|
40
|
+
|
|
41
|
+
# Session ids whose CURRENT turn triggered the litwork keyword path. The bare
|
|
42
|
+
# `lit` keyword has no deterministic display channel (pre_llm_call only reaches
|
|
43
|
+
# the model), so pre_llm_call flags the turn here and transform_llm_output forces
|
|
44
|
+
# the banner onto that turn's response before the user sees it. Consumed once.
|
|
45
|
+
_PENDING_IGNITE: set[str] = set()
|
|
46
|
+
|
|
47
|
+
|
|
36
48
|
LIT_CONTEXT = "\n".join(
|
|
37
49
|
[
|
|
38
50
|
"<lithermes-litwork>",
|
|
51
|
+
f"FIRST, open your reply with this exact line so the user sees Litwork engage: {LITBURN_BANNER}",
|
|
39
52
|
"The user invoked Litwork/LitHermes. Operate in a durable, evidence-first loop:",
|
|
40
53
|
"- restate the concrete completion promise before changing files;",
|
|
41
54
|
"- keep the implementation scoped to the current repository and existing Hermes patterns;",
|
|
@@ -210,9 +223,57 @@ def _extract_run_context_task(message: str) -> str:
|
|
|
210
223
|
return _clamp_task(m.group("task")) if m else ""
|
|
211
224
|
|
|
212
225
|
|
|
226
|
+
# Slash-command handlers are dispatched as handler(user_args) with NO session_id,
|
|
227
|
+
# so they cannot bind the native /goal themselves. They instead embed this marker
|
|
228
|
+
# in their agent_message; pre_llm_call (which DOES receive session_id) reads it and
|
|
229
|
+
# performs the bind. /lit & /lit-loop bind via the run-context block; /litgoal &
|
|
230
|
+
# /lit-plan declare an objective and bind via this marker.
|
|
231
|
+
_BIND_GOAL_PATTERN = re.compile(
|
|
232
|
+
r"<lithermes-bind-goal>(?P<obj>.+?)</lithermes-bind-goal>", re.DOTALL
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def _extract_bind_goal(message: str) -> str:
|
|
237
|
+
m = _BIND_GOAL_PATTERN.search(message)
|
|
238
|
+
return _clamp_task(m.group("obj")) if m else ""
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def bind_goal_marker(objective: str) -> str:
|
|
242
|
+
"""Render the bind-goal marker a command embeds so pre_llm_call binds /goal."""
|
|
243
|
+
objective = (objective or "").strip()
|
|
244
|
+
return f"<lithermes-bind-goal>{objective}</lithermes-bind-goal>" if objective else ""
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def ignite(result: str | dict[str, str]) -> str | dict[str, str]:
|
|
248
|
+
"""Prepend the LITBURN banner to a command result's user-visible display.
|
|
249
|
+
|
|
250
|
+
``display`` is the one channel Hermes prints to the user verbatim
|
|
251
|
+
(cli.py _cprint), so the banner deterministically fires on every LitHermes
|
|
252
|
+
slash command. agent_message (model-facing) is left untouched.
|
|
253
|
+
"""
|
|
254
|
+
if isinstance(result, dict):
|
|
255
|
+
display = result.get("display")
|
|
256
|
+
if display and not str(display).startswith(LITBURN_BANNER):
|
|
257
|
+
return {**result, "display": f"{LITBURN_BANNER}\n{display}"}
|
|
258
|
+
return result
|
|
259
|
+
if isinstance(result, str) and result.strip() and not result.startswith(LITBURN_BANNER):
|
|
260
|
+
return f"{LITBURN_BANNER}\n{result}"
|
|
261
|
+
return result
|
|
262
|
+
|
|
263
|
+
|
|
213
264
|
def pre_llm_call(**kwargs: Any) -> dict[str, str] | None:
|
|
214
265
|
user_message = str(kwargs.get("user_message") or "")
|
|
215
266
|
session_id = str(kwargs.get("session_id") or "")
|
|
267
|
+
# Clear any stale ignite flag from an interrupted previous turn so it can't
|
|
268
|
+
# leak the banner onto this turn's response. Re-added below only if THIS turn
|
|
269
|
+
# is a keyword-lit turn — keeping the flag scoped to the current turn.
|
|
270
|
+
_PENDING_IGNITE.discard(session_id)
|
|
271
|
+
# /litgoal & /lit-plan declare an objective via the bind-goal marker. Bind it
|
|
272
|
+
# (we have session_id here) and stop — those messages are self-contained.
|
|
273
|
+
bind_obj = _extract_bind_goal(user_message)
|
|
274
|
+
if bind_obj:
|
|
275
|
+
bind_native_goal(session_id, bind_obj)
|
|
276
|
+
return None
|
|
216
277
|
# The /lit command injects a run-context message. Bind the native goal from
|
|
217
278
|
# it (we have session_id here), then skip re-injecting context.
|
|
218
279
|
if "<lithermes-run-context>" in user_message:
|
|
@@ -240,9 +301,31 @@ def pre_llm_call(**kwargs: Any) -> dict[str, str] | None:
|
|
|
240
301
|
session_id=session_id,
|
|
241
302
|
platform=str(kwargs.get("platform") or ""),
|
|
242
303
|
)
|
|
304
|
+
# Flag this turn so transform_llm_output forces the banner onto the response
|
|
305
|
+
# (the keyword path has no deterministic display channel like slash commands).
|
|
306
|
+
if session_id:
|
|
307
|
+
_PENDING_IGNITE.add(session_id)
|
|
243
308
|
return {"context": LIT_CONTEXT + run_context}
|
|
244
309
|
|
|
245
310
|
|
|
311
|
+
def transform_llm_output(**kwargs: Any) -> str | None:
|
|
312
|
+
"""Force the LITBURN banner onto a keyword-`lit` turn's response.
|
|
313
|
+
|
|
314
|
+
Hermes replaces the user-visible response with the first non-empty string a
|
|
315
|
+
transform_llm_output hook returns. Returning None leaves the text unchanged.
|
|
316
|
+
We only act on turns pre_llm_call flagged, consume the flag once, and dedup so
|
|
317
|
+
a model that already opened with the banner is not double-bannered.
|
|
318
|
+
"""
|
|
319
|
+
session_id = str(kwargs.get("session_id") or "")
|
|
320
|
+
if session_id not in _PENDING_IGNITE:
|
|
321
|
+
return None
|
|
322
|
+
_PENDING_IGNITE.discard(session_id)
|
|
323
|
+
response_text = str(kwargs.get("response_text") or "")
|
|
324
|
+
if response_text.lstrip().startswith(LITBURN_BANNER):
|
|
325
|
+
return None # model already emitted it — leave unchanged
|
|
326
|
+
return f"{LITBURN_BANNER}\n\n{response_text}"
|
|
327
|
+
|
|
328
|
+
|
|
246
329
|
def subagent_stop(**kwargs: Any) -> None:
|
|
247
330
|
"""Record each delegate_task child (e.g. a review lane) to the LitHermes ledger.
|
|
248
331
|
|
|
@@ -629,6 +712,7 @@ def build_plan_agent_message(brief: str, plan: Path, workspace: Path) -> str:
|
|
|
629
712
|
"goal tools (goal_set / goal_add_criterion / goal_evidence / goal_complete) and inspect",
|
|
630
713
|
"with `hermes lithermes goal status`.",
|
|
631
714
|
"</lithermes-plan-context>",
|
|
715
|
+
bind_goal_marker(brief),
|
|
632
716
|
]
|
|
633
717
|
)
|
|
634
718
|
|
|
@@ -799,6 +883,12 @@ def command_litgoal(raw_args: str) -> dict[str, str]:
|
|
|
799
883
|
"Load the lithermes:litgoal skill for the full discipline.",
|
|
800
884
|
"</lithermes-litgoal-command>",
|
|
801
885
|
]
|
|
886
|
+
# When an objective is given, bind the native /goal too (pre_llm_call reads
|
|
887
|
+
# this marker — slash handlers have no session_id). Inspect-only /litgoal
|
|
888
|
+
# (no objective) leaves any active goal untouched.
|
|
889
|
+
marker = bind_goal_marker(objective)
|
|
890
|
+
if marker:
|
|
891
|
+
agent_lines.append(marker)
|
|
802
892
|
return {
|
|
803
893
|
"display": f"{intro}\nState dir: {lithermes_dir(workspace) / 'litgoal'}",
|
|
804
894
|
"agent_message": "\n".join(agent_lines),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"syncedAt": "2026-06-
|
|
2
|
+
"syncedAt": "2026-06-14T05:53:21.695Z",
|
|
3
3
|
"source": "source-reference",
|
|
4
|
-
"sourceHash": "
|
|
4
|
+
"sourceHash": "f07cf5a5062f904d4eed678ebf24314e773ca3f92e5c2d1f95c981437e0c5a5a",
|
|
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": "
|
|
12
|
+
"sha256": "e0bc7d60f61a8d35df9f6287876e236e59e80e871261558701375a12cc4e4feb"
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
15
|
"path": "__init__.py",
|
|
16
|
-
"sha256": "
|
|
16
|
+
"sha256": "9a0b19060eb12799bf76b15b729fcbab4388d74aac9e888b40369b809fd54669"
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
"path": "core.py",
|
|
20
|
-
"sha256": "
|
|
20
|
+
"sha256": "6b9d8b488d5905232d170f78943d2b5f9b9a4bde564e01a816c4fcc45098a7df"
|
|
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": "
|
|
52
|
+
"sha256": "e8ab5e17a3812c1caf91d98e2fb3cf72f2c7d4a429723f0887b6eb3abd736648"
|
|
53
53
|
},
|
|
54
54
|
{
|
|
55
55
|
"path": "skills/ai-slop-remover/SKILL.md",
|
|
@@ -143,6 +143,14 @@
|
|
|
143
143
|
"path": "skills/frontend-ui-ux/SKILL.md",
|
|
144
144
|
"sha256": "914667044f135563658ceac733a085a6bbdd71a00a5f4030f73d43444e0388f7"
|
|
145
145
|
},
|
|
146
|
+
{
|
|
147
|
+
"path": "skills/git-master/SKILL.md",
|
|
148
|
+
"sha256": "31d59a91767423094fd84ed668c8b8c7e14d515cd17e3845d91a0ce4aa0144c8"
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"path": "skills/init-deep/SKILL.md",
|
|
152
|
+
"sha256": "f571334ad9150fd93ef57fcc9dd85d240812649975811e63045ff2a72e84260b"
|
|
153
|
+
},
|
|
146
154
|
{
|
|
147
155
|
"path": "skills/lit-plan/SKILL.md",
|
|
148
156
|
"sha256": "1f09901f9bb8f19b92add59c3613231228c8b5b7adbefae1cb3eb5cf7c3c61dc"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
name: lithermes
|
|
2
|
-
version: 0.
|
|
2
|
+
version: 0.8.1
|
|
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
|
|
@@ -7,3 +7,4 @@ auto_load: true
|
|
|
7
7
|
hooks:
|
|
8
8
|
- pre_llm_call
|
|
9
9
|
- subagent_stop
|
|
10
|
+
- transform_llm_output
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: git-master
|
|
3
|
+
description: "MUST USE whenever a task needs a commit or git-history investigation. Covers atomic commits, staging, commit-message style, rebase, squash, fixup/autosquash, blame, bisect, reflog, git log -S/-G, and questions like who wrote this or when was this added. Do not use for ordinary code edits unless the user asks for git work."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Git Master
|
|
7
|
+
|
|
8
|
+
The LitHermes git-history specialist for Hermes. Use this skill when the user
|
|
9
|
+
asks you to operate on Git history or answer a Git-history question. Be exact,
|
|
10
|
+
conservative, and evidence-led. Read the repository state before you infer anything.
|
|
11
|
+
|
|
12
|
+
## LitHermes publish boundary
|
|
13
|
+
|
|
14
|
+
Commit, push, force-push, and history rewrites are outward-facing or hard-to-reverse
|
|
15
|
+
operations. Per LitHermes discipline, do **not** commit, push, force-push, reset,
|
|
16
|
+
stash-pop, or rewrite history unless the user explicitly authorized that exact
|
|
17
|
+
operation. Investigative requests report findings and stop.
|
|
18
|
+
|
|
19
|
+
## Mode Gate
|
|
20
|
+
|
|
21
|
+
Classify the request first:
|
|
22
|
+
|
|
23
|
+
- `COMMIT`: stage and commit local changes.
|
|
24
|
+
- `REBASE`: rebase, squash, fixup, autosquash, reorder, split, or otherwise rewrite branch history.
|
|
25
|
+
- `HISTORY`: answer when, where, who, why, or which commit changed something.
|
|
26
|
+
- `STATUS`: inspect branch, diff, or working-tree state without changing it.
|
|
27
|
+
|
|
28
|
+
If the request is only investigative, report findings and stop.
|
|
29
|
+
|
|
30
|
+
## Ground Truth
|
|
31
|
+
|
|
32
|
+
Gather independent facts first (these are read-only and safe to run in parallel):
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
git status --short
|
|
36
|
+
git diff --stat
|
|
37
|
+
git diff --staged --stat
|
|
38
|
+
git branch --show-current
|
|
39
|
+
git log -30 --oneline
|
|
40
|
+
git rev-parse --abbrev-ref @{upstream}
|
|
41
|
+
git merge-base HEAD origin/main
|
|
42
|
+
git merge-base HEAD origin/master
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Missing upstream or missing `main`/`master` is normal. Fall back to the best
|
|
46
|
+
available branch or report the missing fact. Never treat a failed lookup as proof.
|
|
47
|
+
|
|
48
|
+
## Commit Mode
|
|
49
|
+
|
|
50
|
+
Commit only the user's requested changes. Preserve unrelated dirty work.
|
|
51
|
+
|
|
52
|
+
1. Detect message style from recent history (`git log -30 --pretty=format:%s`). Use the
|
|
53
|
+
dominant local pattern, language, and casing. Do not default to Conventional
|
|
54
|
+
Commits unless the repo already uses them.
|
|
55
|
+
2. Inspect the full diff, not only filenames. Separate unrelated user edits from the
|
|
56
|
+
requested commit.
|
|
57
|
+
3. Build atomic groups by behavior, module, and revertability. Keep implementation and
|
|
58
|
+
its direct tests together.
|
|
59
|
+
4. Prefer multiple commits for unrelated concerns. A single commit is acceptable only
|
|
60
|
+
when the changed files form one indivisible behavior or the user explicitly asks for one.
|
|
61
|
+
5. Stage by path or hunk so each commit contains only its atomic group.
|
|
62
|
+
6. Before each commit, verify `git diff --staged --stat` and enough staged diff to prove
|
|
63
|
+
the group is right.
|
|
64
|
+
7. Commit with the detected style. After each commit, verify `git log -1 --oneline`.
|
|
65
|
+
|
|
66
|
+
Grouping rules:
|
|
67
|
+
|
|
68
|
+
- Split different features, modules, generated artifacts, config, docs, and test-only
|
|
69
|
+
changes unless they are inseparable.
|
|
70
|
+
- Keep generated files with the source change that produced them when omitting them
|
|
71
|
+
would leave the repo inconsistent.
|
|
72
|
+
- Never hide failing or unrelated changes inside a broad commit.
|
|
73
|
+
- Follow the user's git conventions (e.g. no AI/co-author attribution when the repo or
|
|
74
|
+
the user's rules forbid it).
|
|
75
|
+
|
|
76
|
+
Final report: list commit hashes, messages, and any remaining uncommitted files.
|
|
77
|
+
|
|
78
|
+
## Rebase Mode
|
|
79
|
+
|
|
80
|
+
History rewriting is a shared-impact operation.
|
|
81
|
+
|
|
82
|
+
- Never rebase or rewrite `main`, `master`, `dev`, release branches, or a protected
|
|
83
|
+
branch unless the user explicitly named that exact operation.
|
|
84
|
+
- If commits may already be pushed, ask before force-pushing. Use `--force-with-lease`,
|
|
85
|
+
never plain `--force`.
|
|
86
|
+
- If the worktree is dirty, preserve it intentionally before rebasing. Do not stash-pop
|
|
87
|
+
over conflicts without checking what changed.
|
|
88
|
+
- For fixups, prefer `git commit --fixup=<hash>` then
|
|
89
|
+
`GIT_SEQUENCE_EDITOR=: git rebase -i --autosquash <base>`.
|
|
90
|
+
- For conflicts, read the conflicting files and resolve by intent. Do not choose
|
|
91
|
+
ours/theirs blindly.
|
|
92
|
+
- If a rebase goes wrong, run `git rebase --abort` first. Use reflog only after
|
|
93
|
+
explaining the recovery path.
|
|
94
|
+
|
|
95
|
+
After rewriting, run the relevant tests or at least the project's cheapest smoke check,
|
|
96
|
+
then show the new branch log from base to HEAD.
|
|
97
|
+
|
|
98
|
+
## History Mode
|
|
99
|
+
|
|
100
|
+
Choose the Git tool by the question:
|
|
101
|
+
|
|
102
|
+
- `git log -S "text"`: when the count of an exact string changed.
|
|
103
|
+
- `git log -G "regex"`: when diffs touched lines matching a pattern.
|
|
104
|
+
- `git blame -L start,end -- file`: who last changed specific lines.
|
|
105
|
+
- `git log --follow -- file`: history across renames for one file.
|
|
106
|
+
- `git show <hash>`: inspect the commit that appears relevant.
|
|
107
|
+
- `git bisect`: find the first bad commit when there is a deterministic pass/fail
|
|
108
|
+
command and known good/bad bounds.
|
|
109
|
+
- `git reflog`: recover or explain recent local history movement.
|
|
110
|
+
|
|
111
|
+
Always cite the exact command evidence in the answer: commit hash, subject, file path,
|
|
112
|
+
and line or diff context when relevant. If the evidence is ambiguous, say what remains
|
|
113
|
+
unproven.
|
|
114
|
+
|
|
115
|
+
## Safety Checks
|
|
116
|
+
|
|
117
|
+
Before any write to Git history:
|
|
118
|
+
|
|
119
|
+
- Current branch is known.
|
|
120
|
+
- Dirty work is accounted for.
|
|
121
|
+
- Upstream/pushed status is known or explicitly unknown.
|
|
122
|
+
- The operation matches an explicit user request and authorization.
|
|
123
|
+
- Recovery path is known (`rebase --abort`, reflog hash, or untouched worktree).
|
|
124
|
+
|
|
125
|
+
Before finishing:
|
|
126
|
+
|
|
127
|
+
- Run the most relevant verification available for the changed behavior or history
|
|
128
|
+
operation (Manual QA evidence where a behavior changed).
|
|
129
|
+
- Report commands that passed and any command you could not run.
|
|
130
|
+
- Leave the worktree state explicit.
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: init-deep
|
|
3
|
+
description: "Initialize a hierarchical AGENTS.md knowledge base for a repository — a root AGENTS.md plus complexity-scored subdirectory files. Use when the user wants to bootstrap or refresh project knowledge for Hermes, onboard a codebase, generate AGENTS.md guidance (reading any existing CLAUDE.md for context), or map an unfamiliar repo. Adapted for Hermes: discovery and parallel generation via delegate_task children + Hermes lsp tools."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Init-Deep — hierarchical AGENTS.md generator (Hermes)
|
|
7
|
+
|
|
8
|
+
Generate hierarchical `AGENTS.md` files: a root knowledge base plus complexity-scored subdirectory
|
|
9
|
+
files. This is the LitHermes onboarding/knowledge-base skill, re-authored for Hermes surfaces:
|
|
10
|
+
read-only `delegate_task` children for discovery, Hermes' `lsp` tools for the code map, and parallel
|
|
11
|
+
`delegate_task` fan-out for generation. (`AGENTS.md` is the file Hermes loads natively as project
|
|
12
|
+
context — see the `lithermes:rules` skill.)
|
|
13
|
+
|
|
14
|
+
## Usage
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
init-deep # Update mode: modify existing AGENTS.md + create new where warranted
|
|
18
|
+
init-deep --create-new # Read existing → remove all → regenerate from scratch
|
|
19
|
+
init-deep --max-depth=2 # Limit directory depth (default: 3)
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Workflow (high level)
|
|
23
|
+
|
|
24
|
+
1. **Discovery + analysis** (concurrent) — read-only `delegate_task` children + local bash structure +
|
|
25
|
+
`lsp` code map + read existing AGENTS.md.
|
|
26
|
+
2. **Score & decide** — determine AGENTS.md locations from merged findings.
|
|
27
|
+
3. **Generate** — root first, then subdirectories in parallel.
|
|
28
|
+
4. **Review** — deduplicate, trim, validate.
|
|
29
|
+
|
|
30
|
+
Track all four phases explicitly and report each one `pending → in_progress → completed` as you go
|
|
31
|
+
(Hermes has no TodoWrite tool; keep the running state in your reply or a working note).
|
|
32
|
+
|
|
33
|
+
## Phase 1 — Discovery + analysis (concurrent)
|
|
34
|
+
|
|
35
|
+
Mark "discovery" in_progress.
|
|
36
|
+
|
|
37
|
+
### Fan out read-only discovery children immediately
|
|
38
|
+
|
|
39
|
+
Dispatch the discovery lanes as read-only `delegate_task` children — pass a `tasks` array so they run
|
|
40
|
+
concurrently and the parent blocks until all return. Each child is self-contained (goal + scope +
|
|
41
|
+
"read-only, return findings only"). Suggested lanes (one child each):
|
|
42
|
+
|
|
43
|
+
- **Structure** — predict standard patterns for the detected language; report deviations only.
|
|
44
|
+
- **Entry points** — find main/entry files; report non-standard organization.
|
|
45
|
+
- **Conventions** — find config files (`.eslintrc`, `pyproject.toml`, `.editorconfig`, …); report
|
|
46
|
+
project-specific rules.
|
|
47
|
+
- **Anti-patterns** — find `DO NOT` / `NEVER` / `ALWAYS` / `DEPRECATED` markers; list forbidden patterns.
|
|
48
|
+
- **Build/CI** — find `.github/workflows`, `Makefile`, `Taskfile`; report non-standard patterns.
|
|
49
|
+
- **Tests** — find test configs and structure; report unique conventions.
|
|
50
|
+
|
|
51
|
+
**Dynamic scaling** — after the bash pass below, add MORE `delegate_task` children based on project
|
|
52
|
+
scale (never a static count):
|
|
53
|
+
|
|
54
|
+
| Factor | Threshold | Additional children |
|
|
55
|
+
|--------|-----------|---------------------|
|
|
56
|
+
| Total files | >100 | +1 per 100 files |
|
|
57
|
+
| Total lines | >10k | +1 per 10k lines |
|
|
58
|
+
| Directory depth | ≥4 | +2 for deep exploration |
|
|
59
|
+
| Large files (>500 lines) | >10 files | +1 for complexity hotspots |
|
|
60
|
+
| Monorepo | detected | +1 per package/workspace |
|
|
61
|
+
| Multiple languages | >1 | +1 per language |
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
total_files=$(find . -type f -not -path '*/node_modules/*' -not -path '*/.git/*' | wc -l)
|
|
65
|
+
total_lines=$(find . -type f \( -name "*.ts" -o -name "*.py" -o -name "*.go" \) -not -path '*/node_modules/*' -exec wc -l {} + 2>/dev/null | tail -1 | awk '{print $1}')
|
|
66
|
+
large_files=$(find . -type f \( -name "*.ts" -o -name "*.py" \) -not -path '*/node_modules/*' -exec wc -l {} + 2>/dev/null | awk '$1 > 500 {c++} END {print c+0}')
|
|
67
|
+
max_depth=$(find . -type d -not -path '*/node_modules/*' -not -path '*/.git/*' | awk -F/ '{print NF}' | sort -rn | head -1)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
For very broad repos, split the fan-out across several `delegate_task` batches rather than one giant
|
|
71
|
+
batch, but keep every child read-only.
|
|
72
|
+
|
|
73
|
+
### Main session: concurrent local analysis
|
|
74
|
+
|
|
75
|
+
While the discovery children run, the main session does:
|
|
76
|
+
|
|
77
|
+
**1. Bash structural analysis**
|
|
78
|
+
```bash
|
|
79
|
+
# Directory depth distribution
|
|
80
|
+
find . -type d -not -path '*/.*' -not -path '*/node_modules/*' -not -path '*/dist/*' -not -path '*/build/*' | awk -F/ '{print NF-1}' | sort -n | uniq -c
|
|
81
|
+
# Files per directory (top 30)
|
|
82
|
+
find . -type f -not -path '*/.*' -not -path '*/node_modules/*' | sed 's|/[^/]*$||' | sort | uniq -c | sort -rn | head -30
|
|
83
|
+
# Existing knowledge bases
|
|
84
|
+
find . -type f \( -name "AGENTS.md" -o -name "CLAUDE.md" \) -not -path '*/node_modules/*' 2>/dev/null
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**2. Read existing AGENTS.md** — for each file found, read it and extract key insights,
|
|
88
|
+
conventions, and anti-patterns into an EXISTING map. With `--create-new`, read ALL existing files
|
|
89
|
+
first (preserve context), THEN delete, THEN regenerate.
|
|
90
|
+
|
|
91
|
+
**3. LSP code map (if available)** — use Hermes' `lsp` tools: `lsp.status` to list configured servers,
|
|
92
|
+
then `lsp.symbols` for entry-point/workspace symbols (`class` / `interface` / `function`) and
|
|
93
|
+
`lsp.find_references` on the top exports to gauge centrality. If no server is configured, fall back to
|
|
94
|
+
the discovery children + plain search. (See the `lithermes:lsp` skill.)
|
|
95
|
+
|
|
96
|
+
Merge bash + LSP + existing + child findings. Mark "discovery" completed.
|
|
97
|
+
|
|
98
|
+
## Phase 2 — Scoring & location decision
|
|
99
|
+
|
|
100
|
+
Mark "scoring" in_progress.
|
|
101
|
+
|
|
102
|
+
### Scoring matrix
|
|
103
|
+
|
|
104
|
+
| Factor | Weight | High threshold | Source |
|
|
105
|
+
|--------|--------|----------------|--------|
|
|
106
|
+
| File count | 3× | >20 | bash |
|
|
107
|
+
| Subdir count | 2× | >5 | bash |
|
|
108
|
+
| Code ratio | 2× | >70% | bash |
|
|
109
|
+
| Unique patterns | 1× | has own config | child |
|
|
110
|
+
| Module boundary | 2× | has `index.ts`/`__init__.py` | bash |
|
|
111
|
+
| Symbol density | 2× | >30 symbols | LSP |
|
|
112
|
+
| Export count | 2× | >10 exports | LSP |
|
|
113
|
+
| Reference centrality | 3× | >20 refs | LSP |
|
|
114
|
+
|
|
115
|
+
### Decision rules
|
|
116
|
+
|
|
117
|
+
| Score | Action |
|
|
118
|
+
|-------|--------|
|
|
119
|
+
| Root (`.`) | ALWAYS create |
|
|
120
|
+
| >15 | Create AGENTS.md |
|
|
121
|
+
| 8–15 | Create if it is a distinct domain |
|
|
122
|
+
| <8 | Skip (parent covers it) |
|
|
123
|
+
|
|
124
|
+
Mark "scoring" completed.
|
|
125
|
+
|
|
126
|
+
## Phase 3 — Generate AGENTS.md
|
|
127
|
+
|
|
128
|
+
Mark "generate" in_progress.
|
|
129
|
+
|
|
130
|
+
**File-writing rule:** if `AGENTS.md` already exists at the target path, edit it in place; if not,
|
|
131
|
+
create it. NEVER overwrite an existing file — check existence first (via the discovery results or a
|
|
132
|
+
read).
|
|
133
|
+
|
|
134
|
+
### Root AGENTS.md (full treatment)
|
|
135
|
+
|
|
136
|
+
```markdown
|
|
137
|
+
# PROJECT KNOWLEDGE BASE
|
|
138
|
+
**Generated:** {TIMESTAMP} **Commit:** {SHORT_SHA} **Branch:** {BRANCH}
|
|
139
|
+
|
|
140
|
+
## OVERVIEW
|
|
141
|
+
{1–2 sentences: what + core stack}
|
|
142
|
+
|
|
143
|
+
## STRUCTURE
|
|
144
|
+
{tree with non-obvious purposes only}
|
|
145
|
+
|
|
146
|
+
## WHERE TO LOOK
|
|
147
|
+
| Task | Location | Notes |
|
|
148
|
+
|
|
149
|
+
## CODE MAP
|
|
150
|
+
{from LSP — skip if unavailable or project <10 files}
|
|
151
|
+
|
|
152
|
+
## CONVENTIONS
|
|
153
|
+
{ONLY deviations from standard}
|
|
154
|
+
|
|
155
|
+
## ANTI-PATTERNS (THIS PROJECT)
|
|
156
|
+
{explicitly forbidden here}
|
|
157
|
+
|
|
158
|
+
## COMMANDS
|
|
159
|
+
{dev / test / build}
|
|
160
|
+
|
|
161
|
+
## NOTES
|
|
162
|
+
{gotchas}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Quality gate: 50–150 lines, no generic advice, no obvious info.
|
|
166
|
+
|
|
167
|
+
### Subdirectory AGENTS.md (parallel)
|
|
168
|
+
|
|
169
|
+
Generate each non-root location in parallel — dispatch one writing `delegate_task` child per location
|
|
170
|
+
(batch them in one `delegate_task` call). Each child gets a `TASK:` line plus `DELIVERABLE` (the
|
|
171
|
+
AGENTS.md), `SCOPE` (this directory only), and `VERIFY` (30–80 lines, never repeats parent content;
|
|
172
|
+
sections: OVERVIEW 1 line, STRUCTURE if >5 subdirs, WHERE TO LOOK, CONVENTIONS if different,
|
|
173
|
+
ANTI-PATTERNS). Wait for all. Mark "generate" completed.
|
|
174
|
+
|
|
175
|
+
## Phase 4 — Review & deduplicate
|
|
176
|
+
|
|
177
|
+
Mark "review" in_progress. For each generated file: remove generic advice, remove parent duplicates,
|
|
178
|
+
trim to the size limits, verify telegraphic style. Mark "review" completed.
|
|
179
|
+
|
|
180
|
+
## Final report
|
|
181
|
+
|
|
182
|
+
```
|
|
183
|
+
=== init-deep complete ===
|
|
184
|
+
Mode: {update | create-new}
|
|
185
|
+
Files: [OK] ./AGENTS.md (root, {N} lines) · [OK] ./src/hooks/AGENTS.md ({N} lines)
|
|
186
|
+
Dirs analyzed: {N} · Created: {N} · Updated: {N}
|
|
187
|
+
Hierarchy: ./AGENTS.md └── src/hooks/AGENTS.md
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Anti-patterns
|
|
191
|
+
|
|
192
|
+
- **Static child count** — vary discovery `delegate_task` children by project size/depth (see the scaling table).
|
|
193
|
+
- **Sequential execution** — run discovery children + LSP concurrently; generate subdirectories in parallel.
|
|
194
|
+
- **Ignoring existing** — ALWAYS read existing AGENTS.md first, even with `--create-new`.
|
|
195
|
+
- **Over-documenting** — not every directory needs an AGENTS.md.
|
|
196
|
+
- **Redundancy** — a child file never repeats its parent.
|
|
197
|
+
- **Generic content** — remove anything that applies to all projects.
|
|
198
|
+
- **Verbose style** — telegraphic or die.
|