@tekmidian/pai 0.8.0 → 0.8.2
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/ARCHITECTURE.md +82 -14
- package/FEATURE.md +7 -2
- package/PLUGIN-ARCHITECTURE.md +31 -16
- package/README.md +94 -9
- package/dist/cli/index.mjs +1 -1
- package/dist/daemon/index.mjs +1 -1
- package/dist/{daemon-B8pkxhSc.mjs → daemon-Ds9dTptY.mjs} +2 -2
- package/dist/{daemon-B8pkxhSc.mjs.map → daemon-Ds9dTptY.mjs.map} +1 -1
- package/dist/hooks/whisper-rules.mjs +1 -5
- package/dist/hooks/whisper-rules.mjs.map +2 -2
- package/dist/skills/Whisper/SKILL.md +49 -0
- package/package.json +1 -1
- package/src/hooks/ts/user-prompt/whisper-rules.ts +5 -8
|
@@ -13,11 +13,7 @@ function getWhisperRules() {
|
|
|
13
13
|
} catch {
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
-
return
|
|
17
|
-
"NEVER suggest pausing, stopping, or ending the session. The user decides when to stop. Not you. Ever.",
|
|
18
|
-
"NEVER send emails. Always create drafts. No exceptions.",
|
|
19
|
-
"NEVER add Co-Authored-By or AI attribution to git commits."
|
|
20
|
-
].join("\n");
|
|
16
|
+
return "";
|
|
21
17
|
}
|
|
22
18
|
function main() {
|
|
23
19
|
const rules = getWhisperRules();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/hooks/ts/user-prompt/whisper-rules.ts"],
|
|
4
|
-
"sourcesContent": ["#!/usr/bin/env node\n\n/**\n * whisper-rules.ts\n *\n * UserPromptSubmit hook that injects critical non-negotiable rules into every\n * prompt as a <system-reminder>. This ensures rules survive compaction \u2014 even\n * if CLAUDE.md content is lost during context compression, the whisper\n * re-injects the absolute rules on every single turn.\n *\n * Inspired by Letta's \"claude-subconscious\" whisper pattern.\n *\n * Rules are loaded from ~/.claude/whisper-rules.md if it exists,\n * otherwise falls back to hardcoded critical rules.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\n\nconst WHISPER_FILE = join(homedir(), \".claude\", \"whisper-rules.md\");\n\nfunction getWhisperRules(): string {\n // User-
|
|
5
|
-
"mappings": ";;;AAgBA,SAAS,YAAY,oBAAoB;AACzC,SAAS,YAAY;AACrB,SAAS,eAAe;AAExB,IAAM,eAAe,KAAK,QAAQ,GAAG,WAAW,kBAAkB;AAElE,SAAS,kBAA0B;
|
|
4
|
+
"sourcesContent": ["#!/usr/bin/env node\n\n/**\n * whisper-rules.ts\n *\n * UserPromptSubmit hook that injects critical non-negotiable rules into every\n * prompt as a <system-reminder>. This ensures rules survive compaction \u2014 even\n * if CLAUDE.md content is lost during context compression, the whisper\n * re-injects the absolute rules on every single turn.\n *\n * Inspired by Letta's \"claude-subconscious\" whisper pattern.\n *\n * Rules are loaded from ~/.claude/whisper-rules.md if it exists,\n * otherwise falls back to hardcoded critical rules.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\n\nconst WHISPER_FILE = join(homedir(), \".claude\", \"whisper-rules.md\");\n\nfunction getWhisperRules(): string {\n // User-managed whisper file \u2014 PAI provides the hook, user provides the rules\n // Configure via /whisper skill or edit ~/.claude/whisper-rules.md directly\n if (existsSync(WHISPER_FILE)) {\n try {\n const content = readFileSync(WHISPER_FILE, \"utf-8\").trim();\n if (content) return content;\n } catch { /* ignore read errors */ }\n }\n\n // No rules configured \u2014 silent (no injection)\n return \"\";\n}\n\nfunction main() {\n const rules = getWhisperRules();\n if (!rules) return;\n\n // Output as system-reminder \u2014 Claude Code injects this into the conversation\n console.log(`<system-reminder>\n${rules}\n</system-reminder>`);\n}\n\nmain();\n"],
|
|
5
|
+
"mappings": ";;;AAgBA,SAAS,YAAY,oBAAoB;AACzC,SAAS,YAAY;AACrB,SAAS,eAAe;AAExB,IAAM,eAAe,KAAK,QAAQ,GAAG,WAAW,kBAAkB;AAElE,SAAS,kBAA0B;AAGjC,MAAI,WAAW,YAAY,GAAG;AAC5B,QAAI;AACF,YAAM,UAAU,aAAa,cAAc,OAAO,EAAE,KAAK;AACzD,UAAI,QAAS,QAAO;AAAA,IACtB,QAAQ;AAAA,IAA2B;AAAA,EACrC;AAGA,SAAO;AACT;AAEA,SAAS,OAAO;AACd,QAAM,QAAQ,gBAAgB;AAC9B,MAAI,CAAC,MAAO;AAGZ,UAAQ,IAAI;AAAA,EACZ,KAAK;AAAA,mBACY;AACnB;AAEA,KAAK;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Whisper
|
|
3
|
+
description: "Manage whisper rules — persistent behavioral constraints injected on every prompt. USE WHEN user says 'whisper', 'add whisper rule', 'remove whisper rule', 'list whisper rules', 'show whisper rules', '/whisper', OR wants to manage persistent behavioral rules."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Whisper Rules Management
|
|
7
|
+
|
|
8
|
+
USE WHEN user says 'whisper', 'add whisper rule', 'remove whisper rule', 'list whisper rules', 'show whisper rules', '/whisper', OR wants to manage persistent behavioral rules.
|
|
9
|
+
|
|
10
|
+
Manage the rules that PAI injects into every prompt via the whisper-rules hook.
|
|
11
|
+
|
|
12
|
+
Rules are stored in `~/.claude/whisper-rules.md` — one rule per line, plain text.
|
|
13
|
+
The hook reads this file on every UserPromptSubmit and injects it as a `<system-reminder>`.
|
|
14
|
+
Rules survive compaction, /clear, and session restarts.
|
|
15
|
+
|
|
16
|
+
### Usage
|
|
17
|
+
|
|
18
|
+
- `/whisper` — show current rules
|
|
19
|
+
- `/whisper add <rule>` — add a new rule
|
|
20
|
+
- `/whisper remove <number>` — remove rule by line number
|
|
21
|
+
- `/whisper list` — list rules with line numbers
|
|
22
|
+
- `/whisper clear` — remove all rules (with confirmation)
|
|
23
|
+
|
|
24
|
+
### Workflow
|
|
25
|
+
|
|
26
|
+
**Show current rules:**
|
|
27
|
+
Read `~/.claude/whisper-rules.md` and display each rule with a line number.
|
|
28
|
+
If the file doesn't exist, say "No whisper rules configured."
|
|
29
|
+
|
|
30
|
+
**Add a rule:**
|
|
31
|
+
Append the rule as a new line to `~/.claude/whisper-rules.md`.
|
|
32
|
+
Create the file if it doesn't exist.
|
|
33
|
+
Do NOT add duplicate rules — check if a similar rule already exists.
|
|
34
|
+
|
|
35
|
+
**Remove a rule:**
|
|
36
|
+
Read the file, remove the line at the given number, write the file back.
|
|
37
|
+
Show the removed rule for confirmation.
|
|
38
|
+
|
|
39
|
+
**Clear all rules:**
|
|
40
|
+
Ask for confirmation first ("This will remove all N rules. Confirm?").
|
|
41
|
+
Only proceed if the user explicitly confirms.
|
|
42
|
+
|
|
43
|
+
### Important
|
|
44
|
+
|
|
45
|
+
- Rules should be short, imperative statements (1-2 lines max)
|
|
46
|
+
- Every rule is injected on EVERY prompt — keep the list focused on truly critical rules
|
|
47
|
+
- Too many rules dilute their effectiveness and waste tokens
|
|
48
|
+
- The file does not exist by default — PAI ships the hook, the user adds their own rules
|
|
49
|
+
- Rules are global (shared across all sessions and projects)
|
package/package.json
CHANGED
|
@@ -21,20 +21,17 @@ import { homedir } from "node:os";
|
|
|
21
21
|
const WHISPER_FILE = join(homedir(), ".claude", "whisper-rules.md");
|
|
22
22
|
|
|
23
23
|
function getWhisperRules(): string {
|
|
24
|
-
// User-
|
|
24
|
+
// User-managed whisper file — PAI provides the hook, user provides the rules
|
|
25
|
+
// Configure via /whisper skill or edit ~/.claude/whisper-rules.md directly
|
|
25
26
|
if (existsSync(WHISPER_FILE)) {
|
|
26
27
|
try {
|
|
27
28
|
const content = readFileSync(WHISPER_FILE, "utf-8").trim();
|
|
28
29
|
if (content) return content;
|
|
29
|
-
} catch { /*
|
|
30
|
+
} catch { /* ignore read errors */ }
|
|
30
31
|
}
|
|
31
32
|
|
|
32
|
-
//
|
|
33
|
-
return
|
|
34
|
-
"NEVER suggest pausing, stopping, or ending the session. The user decides when to stop. Not you. Ever.",
|
|
35
|
-
"NEVER send emails. Always create drafts. No exceptions.",
|
|
36
|
-
"NEVER add Co-Authored-By or AI attribution to git commits.",
|
|
37
|
-
].join("\n");
|
|
33
|
+
// No rules configured — silent (no injection)
|
|
34
|
+
return "";
|
|
38
35
|
}
|
|
39
36
|
|
|
40
37
|
function main() {
|