capt-hook 6.2.0__tar.gz → 6.3.0__tar.gz
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.
- {capt_hook-6.2.0 → capt_hook-6.3.0}/PKG-INFO +1 -1
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/packs/general/capt-hook.toml +1 -1
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/packs/general/models.py +99 -30
- {capt_hook-6.2.0 → capt_hook-6.3.0}/pyproject.toml +1 -1
- {capt_hook-6.2.0 → capt_hook-6.3.0}/LICENSE +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/README.md +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/.claude-plugin/plugin.json +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/__init__.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/__main__.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/app.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/ast_grep.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/classifiers/__init__.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/classifiers/conductor.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/classifiers/droid.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/classifiers/native.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/cli.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/command.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/conditions.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/context.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/contexts.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/decisions.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/dispatch.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/durable.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/events.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/fields.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/file.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/loader.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/log.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/packs/__init__.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/packs/general/__init__.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/packs/general/_lib.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/packs/general/commands.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/packs/general/docs.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/packs/general/plans.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/packs/general/prompts.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/packs/general/review.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/packs/general/tasks.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/packs/general/tombstones.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/packs/go/__init__.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/packs/go/capt-hook.toml +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/packs/go/testing.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/packs/go/toolchain.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/packs/manager.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/packs/python/__init__.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/packs/python/capt-hook.toml +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/packs/python/style.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/packs/python/testing.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/packs/python/toolchain.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/packs/steering/__init__.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/packs/steering/capt-hook.toml +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/packs/steering/steering.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/primitives/__init__.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/primitives/commands.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/primitives/lint.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/primitives/llm.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/primitives/nudge.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/primitives/rewrite.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/primitives/workflow.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/prompt.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/py.typed +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/review/__init__.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/review/cli.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/review/dashboard.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/review/fix.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/review/formats.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/review/judge.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/review/pipeline.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/review/repo.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/review/scan.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/review/settings.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/review/store.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/review/sync.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/session.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/settings.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/signals/__init__.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/signals/nlp.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/skills/authoring-hooks/SKILL.md +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/skills/authoring-hooks/references/capt-hook-api.md +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/skills/authoring-hooks/references/pattern-catalog.md +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/skills/authoring-hooks/references/pitfalls.md +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/skills/authoring-hooks/references/testing-hooks.md +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/skills/bootstrapping-hooks/SKILL.md +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/skills/scanning-sessions/SKILL.md +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/skills/scanning-sessions/references/pr-workflow.md +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/skills/scanning-sessions/references/review-cli.md +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/skills/translating-styleguides/SKILL.md +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/skills/translating-styleguides/references/llm-rule-patterns.md +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/skills/translating-styleguides/references/matcher-reference.md +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/skills/translating-styleguides/references/tier-rubric.md +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/state.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/style/__init__.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/style/ast_grep.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/style/matchers.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/style/scope.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/style/types.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/tasks.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/templates/example_hook.py.tmpl +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/testing/__init__.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/testing/helpers.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/testing/session_cache.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/testing/types.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/types.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/util/__init__.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/util/fs.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/util/http.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/util/model_cache.py +0 -0
- {capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/util/text.py +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import re
|
|
3
4
|
from dataclasses import dataclass
|
|
4
5
|
|
|
5
6
|
from captain_hook import (
|
|
@@ -7,8 +8,10 @@ from captain_hook import (
|
|
|
7
8
|
Allow,
|
|
8
9
|
BaseHookEvent,
|
|
9
10
|
Block,
|
|
11
|
+
Clause,
|
|
10
12
|
Event,
|
|
11
13
|
Input,
|
|
14
|
+
Phrase,
|
|
12
15
|
Rewrite,
|
|
13
16
|
TaskCall,
|
|
14
17
|
Tool,
|
|
@@ -23,6 +26,7 @@ from captain_hook import (
|
|
|
23
26
|
workflow_opt_values,
|
|
24
27
|
workflow_script_source,
|
|
25
28
|
)
|
|
29
|
+
from captain_hook.signals.nlp import nlp_scan
|
|
26
30
|
|
|
27
31
|
|
|
28
32
|
@dataclass(frozen=True, slots=True)
|
|
@@ -39,12 +43,84 @@ class DelegatedSpawn:
|
|
|
39
43
|
return f"model: {model}\nagent_type: {call.agent_type or '(default)'}\nprompt:\n{call.prompt}"
|
|
40
44
|
|
|
41
45
|
|
|
42
|
-
WORKFLOW_SCRIPT_CAP = 14_000 # below the
|
|
46
|
+
WORKFLOW_SCRIPT_CAP = 14_000 # below the prose hooks' max_context=16_000, so truncation stays ours
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def prose_deliverable_sentences(text: str) -> list[str]:
|
|
50
|
+
"""Sentences where a writing verb governs a prose artifact, minus negated asks ("do NOT edit CHANGELOG.md").
|
|
51
|
+
|
|
52
|
+
The text is de-noised for the tagger first: path/URL tokens dropped, brackets and
|
|
53
|
+
word-edge quotes blanked (so `agent('write …')` doesn't glue into one token; intra-word
|
|
54
|
+
apostrophes survive for "n't" negations), readme/changelog extensions stripped, intra-word
|
|
55
|
+
hyphens split, writing verbs lowercased, and imperative writing verbs given a determiner —
|
|
56
|
+
"Update CHANGELOG.md" otherwise parses as a noun compound.
|
|
57
|
+
"""
|
|
58
|
+
verbs = r"write|draft|redraft|rewrite|revise|reword|polish|copyedit|compose|author|update|edit"
|
|
59
|
+
text = re.sub(r"\S+/\S+", " ", text)
|
|
60
|
+
text = re.sub(r"[(){}\[\]<>]|(?<![A-Za-z])['\"`]|['\"`](?![A-Za-z])", " ", text)
|
|
61
|
+
text = re.sub(r"(?i)\b(readme|changelog)\.(?:md|rst|txt)\b", r"\1", text)
|
|
62
|
+
text = re.sub(r"(?<=\w)-(?=\w)", " ", text)
|
|
63
|
+
text = re.sub(rf"(?i)\b({verbs})\b", lambda m: m.group(1).lower(), text)
|
|
64
|
+
text = re.sub(rf"\b({verbs})[ \t]+((?i:readme|changelog|docs))\b", r"\1 the \2", text)
|
|
65
|
+
artifact = Phrase(
|
|
66
|
+
"readme",
|
|
67
|
+
"readme.md",
|
|
68
|
+
"doc",
|
|
69
|
+
"docs",
|
|
70
|
+
"documentation",
|
|
71
|
+
"changelog",
|
|
72
|
+
"changelog.md",
|
|
73
|
+
"blog",
|
|
74
|
+
"blog post",
|
|
75
|
+
"release note",
|
|
76
|
+
"announcement",
|
|
77
|
+
"tutorial",
|
|
78
|
+
"guide",
|
|
79
|
+
"prose",
|
|
80
|
+
"marketing copy",
|
|
81
|
+
"article",
|
|
82
|
+
"newsletter",
|
|
83
|
+
"email",
|
|
84
|
+
"pr description",
|
|
85
|
+
"commit message",
|
|
86
|
+
)
|
|
87
|
+
writing = Phrase(
|
|
88
|
+
"write",
|
|
89
|
+
"draft",
|
|
90
|
+
"redraft",
|
|
91
|
+
"rewrite",
|
|
92
|
+
"revise",
|
|
93
|
+
"reword",
|
|
94
|
+
"polish",
|
|
95
|
+
"copyedit",
|
|
96
|
+
"compose",
|
|
97
|
+
"author",
|
|
98
|
+
"update",
|
|
99
|
+
"edit",
|
|
100
|
+
)
|
|
101
|
+
if not (matched := nlp_scan([Clause(noun=artifact, verb=writing)], text)):
|
|
102
|
+
return []
|
|
103
|
+
negated = set(nlp_scan([Clause(noun=artifact, verb=writing, negated=True)], text))
|
|
104
|
+
return [s for s in matched if s not in negated]
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
@dataclass(frozen=True, slots=True)
|
|
108
|
+
class ProseSpawn(DelegatedSpawn):
|
|
109
|
+
"""Gating context: the pending spawn, present only when its prompt asks to produce a prose artifact."""
|
|
110
|
+
|
|
111
|
+
def content(self, evt: BaseHookEvent) -> str | None:
|
|
112
|
+
# zero-arg super() breaks under @dataclass(slots=True) — the decorator rebuilds the class
|
|
113
|
+
if (base := DelegatedSpawn.content(self, evt)) is None or (call := evt.as_input(TaskCall)) is None:
|
|
114
|
+
return None
|
|
115
|
+
if not (sentences := prose_deliverable_sentences((call.prompt or "")[:WORKFLOW_SCRIPT_CAP])):
|
|
116
|
+
return None
|
|
117
|
+
matched = "\n".join(f" {s[:300]}" for s in sentences)
|
|
118
|
+
return f"{base}\n\nsentences the prose prefilter matched:\n{matched}"
|
|
43
119
|
|
|
44
120
|
|
|
45
121
|
@dataclass(frozen=True, slots=True)
|
|
46
122
|
class WorkflowScriptSource:
|
|
47
|
-
"""Gating context: the pending Workflow call's script source, headed by its model pins."""
|
|
123
|
+
"""Gating context: the pending Workflow call's script source, headed by its model pins and prose asks."""
|
|
48
124
|
|
|
49
125
|
tag: str = "workflow_script"
|
|
50
126
|
required: bool = True
|
|
@@ -62,9 +138,13 @@ class WorkflowScriptSource:
|
|
|
62
138
|
f"… [script truncated: {len(source):,} chars total; every model pin is quoted above] …\n"
|
|
63
139
|
f"{source[-tail:]}"
|
|
64
140
|
)
|
|
141
|
+
if not (sentences := prose_deliverable_sentences(source)):
|
|
142
|
+
return None
|
|
143
|
+
matched = "\n".join(f" {s[:300]}" for s in sentences)
|
|
65
144
|
return (
|
|
66
145
|
"lines that pin a model in this script (a stage not quoted here inherits the "
|
|
67
|
-
f"session model, fable):\n{pin_lines or ' (none)'}\n\n
|
|
146
|
+
f"session model, fable):\n{pin_lines or ' (none)'}\n\n"
|
|
147
|
+
f"sentences the prose prefilter matched:\n{matched}\n\n{source}"
|
|
68
148
|
)
|
|
69
149
|
|
|
70
150
|
|
|
@@ -103,9 +183,10 @@ llm_gate(
|
|
|
103
183
|
deliverable is prose.
|
|
104
184
|
|
|
105
185
|
<delegated_spawn> holds the pending Agent/Task call: its model pin, agent type, and
|
|
106
|
-
prompt
|
|
107
|
-
|
|
108
|
-
|
|
186
|
+
prompt, ending with the sentences a clause prefilter matched — each asks a writing
|
|
187
|
+
verb of a prose artifact, with negated asks ("do NOT edit the docs") already
|
|
188
|
+
screened out. Your job is precision: is a prose artifact what this subagent is
|
|
189
|
+
asked to PRODUCE?
|
|
109
190
|
|
|
110
191
|
The Models rubric: all writing a user reads — READMEs, docs, changelogs, release
|
|
111
192
|
notes, blog posts, PR descriptions, any user-facing text — routes to fable. Work
|
|
@@ -145,22 +226,11 @@ Review findings go to the orchestrator; the subagent writes no user-facing prose
|
|
|
145
226
|
"to fable: drop model to inherit the session model, or pass model='fable'. "
|
|
146
227
|
"See CLAUDE.md § Plan Execution & Orchestration (Models)."
|
|
147
228
|
),
|
|
148
|
-
contexts=[
|
|
229
|
+
contexts=[ProseSpawn()],
|
|
149
230
|
events=Event.PreToolUse,
|
|
150
231
|
only_if=[
|
|
151
232
|
Tool("Agent|Task"),
|
|
152
233
|
ToolInput("model", r"(?i)\b(haiku|sonnet|opus)\b"),
|
|
153
|
-
ToolInput(
|
|
154
|
-
"prompt",
|
|
155
|
-
r"(?i)\b(?:writ(?:e|es|ing|ten)|draft|redraft|rewrit|revis|polish|copyedit|compose|author|update|edit)\w*"
|
|
156
|
-
r"\W+(?:\w+\W+){0,4}(?:readme|docs?|documentation|blog|changelog|release notes|announcement"
|
|
157
|
-
r"|tutorial|guide|prose|copywrit|marketing copy|article|newsletter|email"
|
|
158
|
-
r"|pr description|commit message)\b"
|
|
159
|
-
r"|\b(?:readme|docs?|documentation|blog|changelog|release notes|announcement"
|
|
160
|
-
r"|tutorial|guide|prose|copywrit|marketing copy|article|newsletter|email"
|
|
161
|
-
r"|pr description|commit message)\b"
|
|
162
|
-
r"\W+(?:\w+\W+){0,4}(?:writ(?:e|es|ing|ten)|draft|redraft|rewrit|revis|polish|copyedit|compose|author|update|edit)",
|
|
163
|
-
),
|
|
164
234
|
],
|
|
165
235
|
skip_if=[
|
|
166
236
|
ToolInput("prompt", r"(?i)\b(classif|label|tag|categoriz|count|extract|mechanical)"),
|
|
@@ -168,6 +238,7 @@ Review findings go to the orchestrator; the subagent writes no user-facing prose
|
|
|
168
238
|
],
|
|
169
239
|
agent=False,
|
|
170
240
|
transcript=False,
|
|
241
|
+
max_context=16_000,
|
|
171
242
|
tests={
|
|
172
243
|
Input(model="sonnet", prompt="Write the README quickstart for this repo"): Block(),
|
|
173
244
|
Input(model="opus", prompt="draft the release notes for v2"): Block(),
|
|
@@ -183,6 +254,10 @@ Review findings go to the orchestrator; the subagent writes no user-facing prose
|
|
|
183
254
|
Input(
|
|
184
255
|
model="opus",
|
|
185
256
|
prompt="Fix the failing test in cli.py. Do NOT edit the CHANGELOG — a sibling owns updating it",
|
|
257
|
+
): Allow(),
|
|
258
|
+
Input(
|
|
259
|
+
model="opus",
|
|
260
|
+
prompt="Fix the failing test in cli.py; do NOT edit CHANGELOG.md. Then draft the release notes.",
|
|
186
261
|
llm={"block": False},
|
|
187
262
|
): Allow(),
|
|
188
263
|
},
|
|
@@ -289,11 +364,12 @@ llm_nudge(
|
|
|
289
364
|
deliverable is prose.
|
|
290
365
|
|
|
291
366
|
<workflow_script> holds the pending Workflow call's script source. Its header quotes
|
|
292
|
-
every line of the script that pins a model
|
|
367
|
+
every line of the script that pins a model — a stage that is not quoted there carries
|
|
293
368
|
no pin and inherits the session model, fable — already correctly routed, whatever it
|
|
294
|
-
writes
|
|
295
|
-
verb
|
|
296
|
-
PINNED stage have prose as its own
|
|
369
|
+
writes — followed by the sentences a clause prefilter matched: each asks a writing
|
|
370
|
+
verb of a prose artifact, with negated asks ("do NOT edit CHANGELOG.md") already
|
|
371
|
+
screened out. Your job is precision: does a PINNED stage have prose as its own
|
|
372
|
+
deliverable?
|
|
297
373
|
|
|
298
374
|
The Models rubric: all writing a user reads — READMEs, docs, changelogs, release
|
|
299
375
|
notes, blog posts, announcements, any user-facing text — routes to fable. A stage's
|
|
@@ -350,13 +426,7 @@ Reading and classifying docs is analysis, not a prose deliverable.
|
|
|
350
426
|
events=Event.PreToolUse,
|
|
351
427
|
only_if=[
|
|
352
428
|
Tool("Workflow"),
|
|
353
|
-
WorkflowScript(
|
|
354
|
-
pattern=r"(?i)\b(?:writ(?:e|es|ing|ten)|draft|redraft|rewrit|revis|polish|copyedit|compose|author|update|edit)\w*"
|
|
355
|
-
r"\W+(?:\w+\W+){0,4}(?:readme|docs?|documentation|blog|changelog|release notes|prose)\b"
|
|
356
|
-
r"|\b(?:readme|docs?|documentation|blog|changelog|release notes|prose)\b"
|
|
357
|
-
r"\W+(?:\w+\W+){0,4}(?:writ(?:e|es|ing|ten)|draft|redraft|rewrit|revis|polish|copyedit|compose|author|update|edit)",
|
|
358
|
-
model="haiku|sonnet|opus",
|
|
359
|
-
),
|
|
429
|
+
WorkflowScript(model="haiku|sonnet|opus"),
|
|
360
430
|
],
|
|
361
431
|
max_fires=2,
|
|
362
432
|
max_context=16_000,
|
|
@@ -372,7 +442,6 @@ Reading and classifying docs is analysis, not a prose deliverable.
|
|
|
372
442
|
): Allow(),
|
|
373
443
|
Input(
|
|
374
444
|
script="agent('Fix the import in cli.py. Do NOT edit CHANGELOG.md — a sibling owns it', {model: 'opus'})",
|
|
375
|
-
llm={"fire": False},
|
|
376
445
|
): Allow(),
|
|
377
446
|
},
|
|
378
447
|
)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "capt-hook"
|
|
3
3
|
# Inert sentinel — the real version is stamped from the release tag (uv version --frozen).
|
|
4
|
-
version = "6.
|
|
4
|
+
version = "6.3.0"
|
|
5
5
|
description = "Declarative hook framework for Claude Code"
|
|
6
6
|
readme = "README.md"
|
|
7
7
|
license = "PolyForm-Noncommercial-1.0.0"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/skills/authoring-hooks/references/capt-hook-api.md
RENAMED
|
File without changes
|
|
File without changes
|
{capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/skills/authoring-hooks/references/pitfalls.md
RENAMED
|
File without changes
|
{capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/skills/authoring-hooks/references/testing-hooks.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/skills/scanning-sessions/references/pr-workflow.md
RENAMED
|
File without changes
|
{capt_hook-6.2.0 → capt_hook-6.3.0}/captain_hook/skills/scanning-sessions/references/review-cli.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|