feat(kvb-coach): run the short coach at the first prompt of every full hour
🧪 Test / 🧪 Lock + lint (push) Canceled after 0s
🧪 Test / 🧪 Lock + lint (push) Canceled after 0s
hooks/reminder.sh claims the current clock hour with an atomic mkdir under ~/.claude/.coach-hours/, so only the first prompt of the hour across all agents gets the COACH HOUR hint (at most three lines, most urgent area first, then the request); earlier hours are removed. enable-plugins.js registers it next to the kvb-dream reminder. test_coach covers once per hour, silence within the hour and the cleanup; test_dream checks the single registration. Operator order 2026-11-03. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5f30644ca6
commit
735bbc9b77
6 files changed
+53
-2
No files matched your search
@@ -92,6 +92,7 @@ flowchart LR
|
||||
stage_req([staging or fix ready])
|
||||
edit_hook([edit in a git worktree])
|
||||
reminders([12 h agent hint, 17:00 GNOME popup])
|
||||
full_hour([full hour])
|
||||
code_task([code task])
|
||||
spawn([subagent spawn])
|
||||
end
|
||||
@@ -172,6 +173,7 @@ flowchart LR
|
||||
stage_req -.-> confidence
|
||||
edit_hook -. council gate .-> democracy
|
||||
reminders -.-> dream
|
||||
full_hour -.-> coach
|
||||
code_task -.-> no_defaults
|
||||
code_task -.-> scope_guard
|
||||
spawn -.-> subagent_model
|
||||
@@ -295,7 +297,7 @@ Copy the skills into a specific project (`<repo>/.agents/skills` and `<repo>/.cl
|
||||
make project TARGET=/path/to/repo
|
||||
```
|
||||
|
||||
Both commands also patch the target's `.claude/settings.local.json` — the machine-local, untracked file, so a project's reviewed `.claude/settings.json` is never rewritten by an install: the caveman and ponytail plugins are enabled so their modes auto-activate on session start, and one reminder hook is registered — `kvb-dream` points each agent at `/kvb-dream` at most once every twelve hours (stamped per session in `~/.claude/.dream-stamps/`); the global install also enables the `kvb-dream-notify.timer` systemd user timer, which recommends `/kvb-dream` in a GNOME notification daily at 17:00 local time and catches up once after a missed run. A PreToolUse gate from the `kvb-org-organize` skill blocks edits to files in a git worktree until the session holds a claim (`skills/kvb-org-organize/scripts/council.py`), and its resource watch (`skills/kvb-org-organize/scripts/watch.py`) measures disk, Docker and caches, cleans up low-risk data and blocks new heavy jobs before the disk runs out; it stays inactive until `~/.config/agents-council/config.json` exists. Two hooks of the `kvb-org-perform` skill (`skills/kvb-org-perform/scripts/log.py`) log every Agent spawn with its task class, model and effort, and store the quality feedback a sandboxed session prints, in `~/.local/state/agents-council/subagent-model.jsonl`. Existing settings are preserved.
|
||||
Both commands also patch the target's `.claude/settings.local.json` — the machine-local, untracked file, so a project's reviewed `.claude/settings.json` is never rewritten by an install: the caveman and ponytail plugins are enabled so their modes auto-activate on session start, and two reminder hooks are registered — `kvb-dream` points each agent at `/kvb-dream` at most once every twelve hours (stamped per session in `~/.claude/.dream-stamps/`), and `kvb-coach` runs its short form at the first prompt of every full hour, once across all agents (stamped in `~/.claude/.coach-hours/`); the global install also enables the `kvb-dream-notify.timer` systemd user timer, which recommends `/kvb-dream` in a GNOME notification daily at 17:00 local time and catches up once after a missed run. A PreToolUse gate from the `kvb-org-organize` skill blocks edits to files in a git worktree until the session holds a claim (`skills/kvb-org-organize/scripts/council.py`), and its resource watch (`skills/kvb-org-organize/scripts/watch.py`) measures disk, Docker and caches, cleans up low-risk data and blocks new heavy jobs before the disk runs out; it stays inactive until `~/.config/agents-council/config.json` exists. Two hooks of the `kvb-org-perform` skill (`skills/kvb-org-perform/scripts/log.py`) log every Agent spawn with its task class, model and effort, and store the quality feedback a sandboxed session prints, in `~/.local/state/agents-council/subagent-model.jsonl`. Existing settings are preserved.
|
||||
|
||||
Restart your agent afterwards so it loads the new skills.
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ const MARKETPLACES = {
|
||||
ponytail: { source: { source: "github", repo: "DietrichGebert/ponytail" } },
|
||||
};
|
||||
const PLUGINS = { "caveman@caveman": true, "ponytail@ponytail": true };
|
||||
const REMINDERS = ["kvb-dream"];
|
||||
const REMINDERS = ["kvb-dream", "kvb-coach"];
|
||||
const RETIRED = [
|
||||
"autotune/hooks/reminder.sh",
|
||||
"kvb-skills-tune/hooks/reminder.sh",
|
||||
|
||||
@@ -21,6 +21,11 @@ coach.py --profile <same> show [--json]
|
||||
Areas: `psyche`, `body`, `sleep`, `food`, `tasks`, `delegate`. Every coaching
|
||||
skill beyond this one is named `kvb-coach-<name>`.
|
||||
|
||||
`hooks/reminder.sh` triggers the short form at the first prompt of every full
|
||||
hour, once across all agents (stamped in `~/.claude/.coach-hours/`): at most
|
||||
three lines, the most urgent area first, then the agent continues with the
|
||||
operator's request.
|
||||
|
||||
## Step 1: read the situation
|
||||
|
||||
- **Time**: local time and weekday, and how long the operator has been at it
|
||||
|
||||
Executable
+15
@@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
hours="${COACH_STAMP_DIR:-${HOME}/.claude/.coach-hours}"
|
||||
hour="${COACH_HOUR:-$(date +%Y-%m-%dT%H)}"
|
||||
|
||||
mkdir -p "${hours}"
|
||||
mkdir "${hours}/${hour}" 2>/dev/null || exit 0
|
||||
find "${hours}" -mindepth 1 -maxdepth 1 -type d ! -name "${hour}" -exec rmdir {} +
|
||||
|
||||
cat <<'HINT'
|
||||
COACH HOUR: a new full hour began. Before answering the operator's request,
|
||||
run the kvb-coach skill in its short form: at most three lines, the most
|
||||
urgent area first, then continue with the request.
|
||||
HINT
|
||||
@@ -11,6 +11,7 @@ from pathlib import Path
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[1]
|
||||
SCRIPT = REPO_ROOT / "skills" / "kvb-coach" / "scripts" / "coach.py"
|
||||
HOOK = REPO_ROOT / "skills" / "kvb-coach" / "hooks" / "reminder.sh"
|
||||
|
||||
|
||||
class TestCoach(unittest.TestCase):
|
||||
@@ -62,5 +63,32 @@ class TestCoach(unittest.TestCase):
|
||||
self.assertEqual(self.profile.read_text(encoding="utf-8"), "{broken")
|
||||
|
||||
|
||||
class TestCoachHour(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.tmp = tempfile.TemporaryDirectory()
|
||||
self.addCleanup(self.tmp.cleanup)
|
||||
self.hours = Path(self.tmp.name) / "hours"
|
||||
|
||||
def _run(self, hour: str) -> str:
|
||||
return subprocess.run(
|
||||
["bash", str(HOOK)],
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
env={
|
||||
"PATH": "/usr/bin:/bin",
|
||||
"HOME": self.tmp.name,
|
||||
"COACH_STAMP_DIR": str(self.hours),
|
||||
"COACH_HOUR": hour,
|
||||
},
|
||||
).stdout
|
||||
|
||||
def test_first_prompt_of_each_hour_triggers_the_coach_once(self):
|
||||
self.assertIn("kvb-coach", self._run("2026-11-03T14"))
|
||||
self.assertEqual(self._run("2026-11-03T14"), "")
|
||||
self.assertIn("kvb-coach", self._run("2026-11-03T15"))
|
||||
self.assertEqual(sorted(p.name for p in self.hours.iterdir()), ["2026-11-03T15"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -148,6 +148,7 @@ class TestSettingsRegistration(unittest.TestCase):
|
||||
data = self._patch()
|
||||
entries = json.dumps(data["hooks"]["UserPromptSubmit"])
|
||||
self.assertEqual(entries.count("kvb-dream/hooks/reminder.sh"), 1)
|
||||
self.assertEqual(entries.count("kvb-coach/hooks/reminder.sh"), 1)
|
||||
self.assertNotIn("tune/hooks/reminder.sh", entries)
|
||||
gate = json.dumps(data["hooks"]["PreToolUse"])
|
||||
self.assertEqual(gate.count("kvb-org-organize/scripts/council.py"), 1)
|
||||
|
||||
Reference in new issue
Block a user