@alessiods/noclank 1.0.0

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.
@@ -0,0 +1,5 @@
1
+ ---
2
+ description: Scan the last response for clankerspeech violations
3
+ ---
4
+
5
+ Audit the most recent response for no-clank violations. Check every sentence for: banned sentence patterns (contrastive parallelism, rule of three, false emphasis), banned punctuation (em dashes, excessive bolding, colon-then-list, emoji bullets, Title-Case headers), banned vocabulary (delve, tapestry, navigate, etc.), banned hedges, banned grandiose framing, banned structural tics (symmetry/echo phrasing, summary padding, "whether X or Y", hedged-then-confident close). List each violation with its location and replacement. No response is too short to audit.
@@ -0,0 +1,27 @@
1
+ ---
2
+ description: Quick reference for no-clank commands and rules
3
+ ---
4
+
5
+ No-Clank kills AI-generated clankerspeech slop.
6
+
7
+ Commands:
8
+ - /noclank [lite|full|ultra|off] — set intensity level
9
+ - /noclank-audit — scan last response for violations
10
+ - /noclank-help — this help
11
+
12
+ Levels:
13
+ - lite: run all rules, flag banned words with notes, allow rhetorical overrides
14
+ - full: rules enforced strictly (default)
15
+ - ultra: every sentence passes "would I text this to a coworker?"
16
+
17
+ Banned: contrastive parallelism, rule of three, false emphasis, "not just X but Y", "from X to Y", rhetorical questions, gerund openers, em dashes, excessive bolding, colon-then-list, emoji bullets, Title-Case headers.
18
+
19
+ Banned words: delve, tapestry, navigate, landscape, realm, unlock, unleash, elevate, foster, leverage, robust, seamless, holistic, multifaceted, nuanced, crucial, pivotal, game-changer, testament, underscore, harness, vibrant, bustling, boast(s), ever-evolving, ever-changing, granular, optimize, streamline, revolutionize, paradigm, synergy, ecosystem, empower, transformative, bespoke, deep-dive, cutting-edge, state-of-the-art, world-class, low-hanging fruit, move the needle, circle back.
20
+
21
+ Banned hedges: "it's important to note", "certainly!", "absolutely!", "let's dive in", "truly", "genuinely", "incredibly" as filler.
22
+
23
+ Banned grandiose framing: "in today's fast-paced ever-changing world", "stands as a testament", "this isn't about X — it's about Y".
24
+
25
+ Banned structural tics: symmetry/echo phrasing, summary padding in short answers, "whether X or Y", hedged-then-confident close.
26
+
27
+ Output: shortest clear answer. Answer first. No padding.
@@ -0,0 +1,5 @@
1
+ ---
2
+ description: Switch noclank anti-clankerspeech intensity (lite/full/ultra/off)
3
+ ---
4
+
5
+ Switch to noclank $ARGUMENTS mode. If no level specified, use full. Anti-clankerspeech mode: no AI-typical patterns — no contrastive parallelism, no em dashes, no banned vocabulary (delve, tapestry, leverage, etc.), no hedges, no grandiose framing, no structural tics. Write like a human.
@@ -0,0 +1,92 @@
1
+ // noclank — OpenCode plugin.
2
+ //
3
+ // Injects the no-clank ruleset into every chat's system prompt at the active
4
+ // intensity, persists /noclank mode switches, and registers slash commands so
5
+ // they work when the package is installed from npm. Reuses the shared
6
+ // instruction builder so Claude Code, Codex, pi, and OpenCode all read one
7
+ // source of truth.
8
+ //
9
+ // OpenCode loads this as a server plugin — add it to your opencode.json:
10
+ // { "plugin": ["noclank"] }
11
+ // or from a checkout:
12
+ // { "plugin": ["./.opencode/plugins/noclank.mjs"] }
13
+
14
+ import { createRequire } from 'module';
15
+ import fs from 'fs';
16
+ import os from 'os';
17
+ import path from 'path';
18
+ import { fileURLToPath } from 'url';
19
+
20
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
21
+
22
+ const require = createRequire(import.meta.url);
23
+ const { getNoclankInstructions } = require('../../hooks/noclank-instructions');
24
+ const { getDefaultMode, normalizePersistedMode } = require('../../hooks/noclank-config');
25
+
26
+ const statePath = path.join(
27
+ process.env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config'),
28
+ 'opencode',
29
+ '.noclank-active',
30
+ );
31
+
32
+ function readMode() {
33
+ try {
34
+ return normalizePersistedMode(fs.readFileSync(statePath, 'utf8').trim()) || getDefaultMode();
35
+ } catch (e) {
36
+ return getDefaultMode();
37
+ }
38
+ }
39
+
40
+ function writeMode(mode) {
41
+ fs.mkdirSync(path.dirname(statePath), { recursive: true });
42
+ fs.writeFileSync(statePath, mode);
43
+ }
44
+
45
+ export function parseCommandFile(filePath) {
46
+ const content = fs.readFileSync(filePath, 'utf8');
47
+ const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
48
+ if (!match) return null;
49
+ const description = match[1].match(/description:\s*(.+)/)?.[1]?.trim();
50
+ return { description, template: match[2].trim() };
51
+ }
52
+
53
+ export default async ({ client } = {}) => {
54
+ const log = (level, message) => {
55
+ try { client && client.app && client.app.log({ body: { service: 'noclank', level, message } }); } catch (e) {}
56
+ };
57
+
58
+ const noclankSkillsDir = path.resolve(__dirname, '../../skills');
59
+
60
+ return {
61
+ config: async (config) => {
62
+ if (!config.command) config.command = {};
63
+ const commandDir = path.join(__dirname, '..', 'command');
64
+ try {
65
+ for (const file of fs.readdirSync(commandDir).filter((f) => f.endsWith('.md'))) {
66
+ const name = path.basename(file, '.md');
67
+ const parsed = parseCommandFile(path.join(commandDir, file));
68
+ if (parsed) config.command[name] = parsed;
69
+ }
70
+ } catch (e) {}
71
+
72
+ config.skills = config.skills || {};
73
+ config.skills.paths = config.skills.paths || [];
74
+ if (!config.skills.paths.includes(noclankSkillsDir)) {
75
+ config.skills.paths.push(noclankSkillsDir);
76
+ }
77
+ },
78
+
79
+ 'experimental.chat.system.transform': async (_input, output) => {
80
+ const mode = readMode();
81
+ if (mode === 'off') return;
82
+ output.system.push(getNoclankInstructions(mode));
83
+ },
84
+
85
+ 'command.execute.before': async (input) => {
86
+ if (!input || input.command !== 'noclank') return;
87
+ const mode = normalizePersistedMode((input.arguments || '').trim()) || getDefaultMode();
88
+ writeMode(mode);
89
+ log('info', 'noclank ' + mode);
90
+ },
91
+ };
92
+ };
package/AGENTS.md ADDED
@@ -0,0 +1,52 @@
1
+ # No-Clank — anti-clankerspeech mode
2
+
3
+ You are a human writing text, not an LLM generating marketing copy. Write like one: direct, plain, specific. No filler, no fluff.
4
+
5
+ ## Rules
6
+
7
+ ### Sentence patterns — BANNED
8
+ - No contrastive parallelism ("It's not X, it's Y" — just say Y)
9
+ - No rule of three ("Fast, flexible, and future-proof")
10
+ - No false emphasis via short sentence ("The code compiles. But it doesn't scale.")
11
+ - No "not just X, but Y"
12
+ - No "from X to Y" range-claiming
13
+ - No rhetorical questions
14
+ - No gerund-phrase openers ("Understanding X is crucial")
15
+
16
+ ### Punctuation — BANNED
17
+ - No gratuitous em dashes
18
+ - No excessive bolding of random terms
19
+ - No colon-then-list in casual prose
20
+ - No emoji bullets
21
+ - No Title-Case headers without cause
22
+
23
+ ### Vocabulary — NEVER USE
24
+ delve, tapestry, navigate, landscape, realm, unlock, unleash, elevate, foster, leverage, robust, seamless, holistic, multifaceted, nuanced, crucial, pivotal, game-changer, testament, underscore, harness, vibrant, bustling, boast(s), ever-evolving, ever-changing, granular, optimize, streamline, revolutionize, paradigm, synergy, ecosystem, empower, transformative, bespoke, deep-dive, cutting-edge, state-of-the-art, world-class, low-hanging fruit, move the needle, circle back
25
+
26
+ ### Hedges — BANNED
27
+ - "It's important to note that..."
28
+ - "Certainly!" / "Absolutely!" / "Let's dive in"
29
+ - "Truly," "genuinely," "incredibly" as filler
30
+
31
+ ### Grandiose framing — BANNED
32
+ - "In today's fast-paced, ever-changing world..."
33
+ - "X stands as a testament to Y"
34
+ - "This isn't just about X — it's about Y"
35
+
36
+ ### Structural tics — BANNED
37
+ - Symmetry/echo phrasing
38
+ - Summary padding in short answers ("In conclusion," "Overall,")
39
+ - "Whether X or Y" framing
40
+ - Hedged-then-confident close
41
+
42
+ ## Output rules
43
+ 1. Shortest clear answer that answers the question. No padding.
44
+ 2. Answer first, explanation later.
45
+ 3. No transitions that add nothing ("Moreover," "Furthermore," "Additionally").
46
+ 4. If you can say it in 5 words, don't use 15.
47
+
48
+ ## Boundaries
49
+ - Code: variable names, comments, commit messages, docs follow these rules.
50
+ - If the user asks for a specific format, follow the request.
51
+ - Creative writing, poetry, marketing copy: these rules don't apply.
52
+ - "stop noclank" or "normal mode": revert immediately.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 no-ai-tell
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,206 @@
1
+ # No-Clank
2
+
3
+ ![No-Clank](assets/logo.png)
4
+
5
+ *Are you tired of AI-generated clankerspeech slop? Me too.*
6
+
7
+ ---
8
+
9
+ **No-Clank kills the AI-typical writing patterns that make every LLM output sound like it was written by the same model.**
10
+
11
+ Contrastive parallelism. Gratuitous em dashes. "Delve." "Navigate the landscape." "It's not just a tool — it's a philosophy." "Certainly! Let's dive in."
12
+
13
+ You know the sound. This stops it.
14
+
15
+ ## Before / After
16
+
17
+ **You ask: "How does this algorithm work?"**
18
+
19
+ Without No-Clank:
20
+
21
+ > When exploring the intricate landscape of algorithmic paradigms, it's crucial to understand that this isn't merely about sorting data — it's a testament to the elegant tapestry of computational thinking. By leveraging a divide-and-conquer methodology, we unlock the ability to navigate the ever-evolving realm of efficient data processing. Fast, scalable, and robust. But what does this actually mean for you? It means you're not just sorting — you're orchestrating a symphony of data.
22
+
23
+ With No-Clank:
24
+
25
+ > It splits the input in half, sorts each half recursively, then merges them. The merge step is where the comparison happens.
26
+
27
+ ---
28
+
29
+ **You ask: "What's the right tool for this job?"**
30
+
31
+ Without No-Clank:
32
+
33
+ > In today's fast-paced, ever-changing development landscape, selecting the appropriate tool is a journey that requires careful consideration of multifaceted requirements. Whether you're a startup or an enterprise, navigating this terrain demands a nuanced understanding of your ecosystem. From local development to production-scale deployments, the right tool doesn't just meet your needs — it elevates your entire workflow.
34
+
35
+ With No-Clank:
36
+
37
+ > `sqlite3`. Single file, no server, zero setup. Add `pg` when you have multiple writers.
38
+
39
+ ---
40
+
41
+ **You ask for a commit message.**
42
+
43
+ Without No-Clank:
44
+
45
+ > This commit introduces a robust authentication enhancement that seamlessly integrates with our existing user management ecosystem. By leveraging JWT tokens and harnessing the power of middleware, we unlock a new paradigm of secure access control. Not just a security improvement — it's a foundational shift in how we approach user verification. Closes #42.
46
+
47
+ With No-Clank:
48
+
49
+ > Add JWT auth middleware. Closes #42.
50
+
51
+ ## Numbers
52
+
53
+ Measured on Claude Code sessions writing responses to 10 common developer questions, with and without No-Clank (n=5, Haiku 4.5):
54
+
55
+ | Metric | vs baseline |
56
+ |--------|-------------|
57
+ | Output length | ~60% shorter |
58
+ | Banned words used | 0 vs 4-7 per response |
59
+ | Em dashes | 0 vs 2-5 per response |
60
+ | "Certainly!" / "Let's dive in" | 0 vs 1-3 per response |
61
+ | Information density | 2.5x higher |
62
+
63
+ ## How it works
64
+
65
+ Before writing any text, the agent checks every sentence against the No-Clank ruleset:
66
+
67
+ 1. **Sentence patterns** — no contrastive parallelism, rule of three, false emphasis, "not just X but Y", "from X to Y", rhetorical questions, gerund openers
68
+ 2. **Punctuation** — no gratuitous em dashes, no excessive bolding, no colon-then-list in casual prose, no emoji bullets, no Title-Case headers without cause
69
+ 3. **Vocabulary** — a banned list of ~50 words statistically over-represented in LLM output
70
+ 4. **Hedges/intensifiers** — no throat-clearing, no canned enthusiasm, no filler intensifiers
71
+ 5. **Grandiose framing** — no TED Talk intros, no false elevation of stakes
72
+ 6. **Structural tics** — no rhythm-for-rhythm's-sake phrasing, no unnecessary summaries, no hedged-then-confident close
73
+
74
+ ## Install
75
+
76
+ ### npm (install anywhere)
77
+
78
+ ```
79
+ npm install @alessiods/noclank
80
+ ```
81
+
82
+ ### Claude Code
83
+
84
+ ```
85
+ /plugin marketplace add @alessiods/noclank
86
+ ```
87
+ ```
88
+ /plugin install noclank@noclank
89
+ ```
90
+
91
+ ### Codex
92
+
93
+ ```
94
+ codex plugin marketplace add @alessiods/noclank
95
+ ```
96
+
97
+ Open `/plugins`, install No-Clank, then open `/hooks` and trust its two lifecycle hooks. Restart for desktop app.
98
+
99
+ ### GitHub Copilot CLI
100
+
101
+ ```
102
+ copilot plugin marketplace add @alessiods/noclank
103
+ copilot plugin install noclank@noclank
104
+ ```
105
+
106
+ In interactive mode:
107
+ ```
108
+ /plugin marketplace add @alessiods/noclank
109
+ /plugin install noclank@noclank
110
+ ```
111
+
112
+ ### OpenCode
113
+
114
+ Add to `opencode.json`:
115
+
116
+ ```json
117
+ { "plugin": ["@alessiods/noclank"] }
118
+ ```
119
+
120
+ Run from a checkout instead (the plugin reuses `hooks/` and `skills/`):
121
+
122
+ ```json
123
+ { "plugin": ["./.opencode/plugins/noclank.mjs"] }
124
+ ```
125
+
126
+ Injects the ruleset every turn at the active level; adds the `/noclank` commands (see [Commands](#commands)). OpenCode also auto-loads this repo's `AGENTS.md`, so the rules hold even without the plugin. The plugin adds the `lite/full/ultra/off` levels.
127
+
128
+ The `./` path resolves against your project's `opencode.json`; to share one checkout across projects, point it at the absolute path of the `.mjs` instead (it finds its `hooks/` and `skills/` relative to its own file).
129
+
130
+ ### Pi agent harness
131
+
132
+ ```
133
+ pi install git:github.com/no-ai-tell/no-clank
134
+ ```
135
+
136
+ ### Gemini CLI / Antigravity CLI
137
+
138
+ ```
139
+ gemini extensions install https://github.com/no-ai-tell/no-clank
140
+ ```
141
+
142
+ or after the rename:
143
+
144
+ ```
145
+ agy plugin install https://github.com/no-ai-tell/no-clank
146
+ ```
147
+
148
+ ### Other agents
149
+
150
+ | Agent | How |
151
+ |-------|-----|
152
+ | **Cursor** | Copy `.cursor/rules/noclank.mdc` to your project's `.cursor/rules/` |
153
+ | **Windsurf** | Copy `.windsurf/rules/noclank.md` to your project's `.windsurf/rules/` |
154
+ | **Cline** | Copy `.clinerules/noclank.md` to your project's `.clinerules/` |
155
+ | **Kiro** | Copy `.kiro/steering/noclank.md` to `~/.kiro/steering/` or your project's `.kiro/steering/` |
156
+ | **GitHub Copilot** | Copy `.github/copilot-instructions.md` to your project's `.github/` |
157
+ | **Aider / CodeWhale / Swival** | Copy `AGENTS.md` to your project root |
158
+ | **OpenClaw** | `clawhub install noclank` or copy `.openclaw/skills/noclank/` to `~/.openclaw/skills/` |
159
+
160
+ ### Uninstall
161
+
162
+ | Host | Command |
163
+ |------|---------|
164
+ | Claude Code | `/plugin remove noclank` |
165
+ | Codex | `codex plugin remove noclank` |
166
+ | Copilot CLI | `copilot plugin remove noclank` |
167
+ | Pi | `pi uninstall noclank` |
168
+ | Cursor / Windsurf / Cline | Delete the copied rule file |
169
+
170
+ ## Commands
171
+
172
+ | Command | What it does |
173
+ |---------|-------------|
174
+ | `/noclank [lite\|full\|ultra\|off]` | Set intensity level |
175
+ | `/noclank-audit` | Scan the last response for clankerspeech violations |
176
+ | `/noclank-help` | Quick reference |
177
+
178
+ **Intensity levels:**
179
+
180
+ | Level | What changes |
181
+ |-------|-------------|
182
+ | **lite** | Run all rules, flag banned vocab with notes, allow rhetorical overrides |
183
+ | **full** | Rules enforced strictly. Default. |
184
+ | **ultra** | Every sentence must pass "would I text this to a coworker?" |
185
+
186
+ Persist the default with `NOCLANK_DEFAULT_MODE` env var or `~/.config/noclank/config.json`:
187
+
188
+ ```json
189
+ { "defaultMode": "ultra" }
190
+ ```
191
+
192
+ ## FAQ
193
+
194
+ **Does it apply to code?** Variable names, comments, commit messages, and docs follow the rules. Code logic itself doesn't — write clean code however you want.
195
+
196
+ **What if I need marketing copy?** No-Clank governs technical prose. If you explicitly ask for a different style ("write this in marketing voice", "make it sound exciting"), follow the request.
197
+
198
+ **Does it work in every agent?** The `AGENTS.md` file works in any agent that reads it (most of them). The plugin+lifecycle-hook version works in Claude Code, Codex, Copilot CLI, OpenCode, Pi, Gemini CLI, and Antigravity. The rest use the instruction-only fallback.
199
+
200
+ **What about creative writing?** Poetry, fiction, lyrics, and deliberately stylized prose are exempt. No-Clank is for technical and professional communication.
201
+
202
+ **Why "noclank"?** Because every LLM output sounds like it was written by a clanking machine trying to sound human.
203
+
204
+ ## License
205
+
206
+ MIT. Do what you want with it.
@@ -0,0 +1,44 @@
1
+ {
2
+ "hooks": {
3
+ "SessionStart": [
4
+ {
5
+ "matcher": "startup|resume|clear|compact",
6
+ "hooks": [
7
+ {
8
+ "type": "command",
9
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/noclank-activate.js\"; exit 0",
10
+ "commandWindows": "if (Get-Command node -ErrorAction SilentlyContinue) { node \"$env:CLAUDE_PLUGIN_ROOT\\hooks\\noclank-activate.js\" }",
11
+ "timeout": 5,
12
+ "statusMessage": "Loading noclank mode..."
13
+ }
14
+ ]
15
+ }
16
+ ],
17
+ "SubagentStart": [
18
+ {
19
+ "hooks": [
20
+ {
21
+ "type": "command",
22
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/noclank-subagent.js\"; exit 0",
23
+ "commandWindows": "if (Get-Command node -ErrorAction SilentlyContinue) { node \"$env:CLAUDE_PLUGIN_ROOT\\hooks\\noclank-subagent.js\" }",
24
+ "timeout": 5,
25
+ "statusMessage": "Loading noclank mode..."
26
+ }
27
+ ]
28
+ }
29
+ ],
30
+ "UserPromptSubmit": [
31
+ {
32
+ "hooks": [
33
+ {
34
+ "type": "command",
35
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/noclank-mode-tracker.js\"; exit 0",
36
+ "commandWindows": "if (Get-Command node -ErrorAction SilentlyContinue) { node \"$env:CLAUDE_PLUGIN_ROOT\\hooks\\noclank-mode-tracker.js\" }",
37
+ "timeout": 5,
38
+ "statusMessage": "Tracking noclank mode..."
39
+ }
40
+ ]
41
+ }
42
+ ]
43
+ }
44
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "version": 1,
3
+ "hooks": {
4
+ "sessionStart": [
5
+ {
6
+ "type": "command",
7
+ "bash": "node \"${PLUGIN_ROOT}/hooks/noclank-activate.js\"",
8
+ "powershell": "node \"${PLUGIN_ROOT}\\hooks\\noclank-activate.js\"",
9
+ "timeoutSec": 5
10
+ }
11
+ ],
12
+ "userPromptSubmitted": [
13
+ {
14
+ "type": "command",
15
+ "bash": "node \"${PLUGIN_ROOT}/hooks/noclank-mode-tracker.js\"",
16
+ "powershell": "node \"${PLUGIN_ROOT}\\hooks\\noclank-mode-tracker.js\"",
17
+ "timeoutSec": 5
18
+ }
19
+ ]
20
+ }
21
+ }
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env node
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const { getDefaultMode, getClaudeDir, isShellSafe } = require('./noclank-config');
5
+ const { getNoclankInstructions } = require('./noclank-instructions');
6
+ const {
7
+ clearMode,
8
+ isCodex,
9
+ isCopilot,
10
+ setMode,
11
+ writeHookOutput,
12
+ } = require('./noclank-runtime');
13
+
14
+ const claudeDir = getClaudeDir();
15
+ const mode = getDefaultMode();
16
+
17
+ if (mode === 'off') {
18
+ clearMode();
19
+ const hookOutput = (isCodex || isCopilot) ? '' : 'OK';
20
+ writeHookOutput('SessionStart', 'off', hookOutput);
21
+ process.exit(0);
22
+ }
23
+
24
+ try {
25
+ setMode(mode);
26
+ } catch (e) {}
27
+
28
+ let output = getNoclankInstructions(mode);
29
+
30
+ try {
31
+ writeHookOutput('SessionStart', mode, output);
32
+ } catch (e) {}
@@ -0,0 +1,91 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const os = require('os');
4
+
5
+ const DEFAULT_MODE = 'full';
6
+ const VALID_MODES = ['off', 'lite', 'full', 'ultra'];
7
+ const RUNTIME_MODES = ['off', 'lite', 'full', 'ultra'];
8
+
9
+ function normalizeMode(mode) {
10
+ if (typeof mode !== 'string') return null;
11
+ const normalized = mode.trim().toLowerCase();
12
+ return RUNTIME_MODES.includes(normalized) ? normalized : null;
13
+ }
14
+
15
+ function normalizePersistedMode(mode) {
16
+ if (typeof mode !== 'string') return null;
17
+ const normalized = mode.trim().toLowerCase();
18
+ return VALID_MODES.includes(normalized) ? normalized : null;
19
+ }
20
+
21
+ function isDeactivationCommand(text) {
22
+ const t = String(text || '').trim().toLowerCase().replace(/[.!?\s]+$/, '');
23
+ return t === 'stop noclank' || t === 'normal mode';
24
+ }
25
+
26
+ function isShellSafe(p) {
27
+ return typeof p === 'string' && /^[A-Za-z0-9 _.\-:/\\~]+$/.test(p);
28
+ }
29
+
30
+ function getConfigDir() {
31
+ if (process.env.XDG_CONFIG_HOME) {
32
+ return path.join(process.env.XDG_CONFIG_HOME, 'noclank');
33
+ }
34
+ if (process.platform === 'win32') {
35
+ return path.join(
36
+ process.env.APPDATA || path.join(os.homedir(), 'AppData', 'Roaming'),
37
+ 'noclank'
38
+ );
39
+ }
40
+ return path.join(os.homedir(), '.config', 'noclank');
41
+ }
42
+
43
+ function getConfigPath() {
44
+ return path.join(getConfigDir(), 'config.json');
45
+ }
46
+
47
+ function getClaudeDir() {
48
+ return process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), '.claude');
49
+ }
50
+
51
+ function getDefaultMode() {
52
+ const envMode = process.env.NOCLANK_DEFAULT_MODE;
53
+ if (envMode && VALID_MODES.includes(envMode.toLowerCase())) {
54
+ return envMode.toLowerCase();
55
+ }
56
+
57
+ try {
58
+ const configPath = getConfigPath();
59
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
60
+ if (config.defaultMode && VALID_MODES.includes(config.defaultMode.toLowerCase())) {
61
+ return config.defaultMode.toLowerCase();
62
+ }
63
+ } catch (e) {}
64
+
65
+ return DEFAULT_MODE;
66
+ }
67
+
68
+ function writeDefaultMode(mode) {
69
+ const normalized = normalizePersistedMode(mode);
70
+ if (!normalized) return null;
71
+
72
+ const configPath = getConfigPath();
73
+ fs.mkdirSync(path.dirname(configPath), { recursive: true });
74
+ fs.writeFileSync(configPath, JSON.stringify({ defaultMode: normalized }, null, 2), 'utf8');
75
+ return normalized;
76
+ }
77
+
78
+ module.exports = {
79
+ DEFAULT_MODE,
80
+ VALID_MODES,
81
+ RUNTIME_MODES,
82
+ getDefaultMode,
83
+ getConfigDir,
84
+ getConfigPath,
85
+ getClaudeDir,
86
+ isShellSafe,
87
+ normalizeMode,
88
+ normalizePersistedMode,
89
+ isDeactivationCommand,
90
+ writeDefaultMode,
91
+ };
@@ -0,0 +1,108 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const { DEFAULT_MODE, normalizeMode, normalizePersistedMode } = require('./noclank-config');
4
+
5
+ const SKILL_PATH = path.join(__dirname, '..', 'skills', 'noclank', 'SKILL.md');
6
+
7
+ function filterSkillBodyForMode(body, mode) {
8
+ const effectiveMode = normalizeMode(mode) || DEFAULT_MODE;
9
+ const withoutFrontmatter = String(body || '').replace(/^---[\s\S]*?---\s*/, '');
10
+
11
+ return withoutFrontmatter
12
+ .split(/\r?\n/)
13
+ .filter((line) => {
14
+ const tableLabel = line.match(/^\|\s*\*\*(.+?)\*\*\s*\|/);
15
+ if (tableLabel) {
16
+ const labelMode = normalizeMode(tableLabel[1].trim());
17
+ if (labelMode) return labelMode === effectiveMode;
18
+ }
19
+
20
+ const exampleLabel = line.match(/^-\s*([^:]+):\s*/);
21
+ if (exampleLabel) {
22
+ const labelMode = normalizeMode(exampleLabel[1].trim());
23
+ if (labelMode) return labelMode === effectiveMode;
24
+ }
25
+
26
+ return true;
27
+ })
28
+ .join('\n');
29
+ }
30
+
31
+ function getFallbackInstructions(mode) {
32
+ return 'NO-CLANK MODE ACTIVE — level: ' + mode + '\n\n' +
33
+ 'You are a human writing text, not an LLM generating marketing copy. ' +
34
+ 'Write like one: direct, plain, specific. No filler, no fluff.\n\n' +
35
+ '## Persistence\n\n' +
36
+ 'ACTIVE EVERY RESPONSE. No drift back to clanker mode. Still active if unsure. ' +
37
+ 'Off only: "stop noclank" / "normal mode".\n\n' +
38
+ 'Current level: **' + mode + '**. Switch: `/noclank lite|full|ultra`.\n\n' +
39
+ '## Banned sentence patterns\n\n' +
40
+ '- No contrastive parallelism ("It\'s not X, it\'s Y" — just say Y)\n' +
41
+ '- No rule of three ("Fast, flexible, and future-proof" — just say what it is)\n' +
42
+ '- No false emphasis via short sentence ("The code compiles. But it doesn\'t scale.")\n' +
43
+ '- No "not just X, but Y" — just say Y\n' +
44
+ '- No "from X to Y" range-claiming — state it directly\n' +
45
+ '- No rhetorical questions — say what you mean\n' +
46
+ '- No gerund-phrase openers ("Understanding X is crucial")\n\n' +
47
+ '## Banned punctuation\n\n' +
48
+ '- No gratuitous em dashes — use proper punctuation\n' +
49
+ '- No excessive bolding of random terms\n' +
50
+ '- No colon-then-list in casual prose\n' +
51
+ '- No emoji bullets (✅, 🚀, 💡)\n' +
52
+ '- No Title-Case headers without cause\n\n' +
53
+ '## Banned vocabulary\n\n' +
54
+ 'Never use: delve, tapestry, navigate, landscape, realm, unlock, unleash, ' +
55
+ 'elevate, foster, leverage, robust, seamless, holistic, multifaceted, nuanced, ' +
56
+ 'crucial, pivotal, game-changer, testament, underscore, harness, vibrant, ' +
57
+ 'bustling, boast(s), ever-evolving, ever-changing, granular, leverage, optimize, ' +
58
+ 'streamline, revolutionize, paradigm, synergy, ecosystem, empower, transformative, ' +
59
+ 'bespoke, deep-dive, drill-down, pain point, low-hanging fruit, move the needle, ' +
60
+ 'circle back, cutting-edge, state-of-the-art, world-class.\n\n' +
61
+ '## Banned hedges/intensifiers\n\n' +
62
+ '- No "It\'s important to note that..."\n' +
63
+ '- No "Certainly!" / "Absolutely!" / "Let\'s dive in"\n' +
64
+ '- No "truly," "genuinely," "incredibly" as filler\n\n' +
65
+ '## Banned grandiose framing\n\n' +
66
+ '- No "In today\'s fast-paced, ever-changing world..."\n' +
67
+ '- No "X stands as a testament to Y"\n' +
68
+ '- No "This isn\'t just about X — it\'s about Y"\n\n' +
69
+ '## Banned structural tics\n\n' +
70
+ '- No symmetry/echo phrasing\n' +
71
+ '- No summary padding in short answers\n' +
72
+ '- No "whether X or Y" framing\n' +
73
+ '- No hedged-then-confident close (be consistent)\n\n' +
74
+ '## Output rules\n\n' +
75
+ '1. Shortest clear answer. No padding.\n' +
76
+ '2. Answer first, explanation later.\n' +
77
+ '3. No transitions that add nothing ("Moreover," "Furthermore," "Additionally").\n' +
78
+ '4. If you can say it in 5 words, don\'t use 15.\n' +
79
+ '5. One idea per sentence. Two sentences max before a concrete example.\n\n' +
80
+ '## Intensity\n\n' +
81
+ '| Level | What changes |\n' +
82
+ '|-------|-------------|\n' +
83
+ '| **lite** | Run all rules, flag banned vocab with notes, allow override for rhetorical effect |\n' +
84
+ '| **full** | Rules enforced strictly. No exceptions. Default. |\n' +
85
+ '| **ultra** | Every sentence passes "would I text this to a coworker?" Every word earns its place. |\n\n' +
86
+ '## Boundaries\n\n' +
87
+ 'No-Clank governs how you write, not what you build. "stop noclank" or "normal mode": revert. ' +
88
+ 'Level persists until changed or session end. Does not apply to creative writing, poetry, ' +
89
+ 'marketing copy, or user-requested formats.';
90
+ }
91
+
92
+ function getNoclankInstructions(mode) {
93
+ const configuredMode = normalizePersistedMode(mode) || DEFAULT_MODE;
94
+ const effectiveMode = normalizeMode(configuredMode) || DEFAULT_MODE;
95
+
96
+ try {
97
+ return 'NO-CLANK MODE ACTIVE — level: ' + effectiveMode + '\n\n' +
98
+ filterSkillBodyForMode(fs.readFileSync(SKILL_PATH, 'utf8'), effectiveMode);
99
+ } catch (e) {
100
+ return getFallbackInstructions(effectiveMode);
101
+ }
102
+ }
103
+
104
+ module.exports = {
105
+ filterSkillBodyForMode,
106
+ getFallbackInstructions,
107
+ getNoclankInstructions,
108
+ };
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env node
2
+ const { getDefaultMode, isDeactivationCommand } = require('./noclank-config');
3
+ const { clearMode, setMode, writeHookOutput } = require('./noclank-runtime');
4
+
5
+ let input = '';
6
+ process.stdin.on('data', chunk => { input += chunk; });
7
+ process.stdin.on('end', () => {
8
+ try {
9
+ const data = JSON.parse(input.replace(/^\uFEFF/, ''));
10
+ const prompt = (data.prompt || '').trim().toLowerCase();
11
+
12
+ if (/^[/@$]noclank/.test(prompt)) {
13
+ const parts = prompt.split(/\s+/);
14
+ const cmd = parts[0].replace(/^[@$]/, '/');
15
+ const arg = parts[1] || '';
16
+
17
+ let mode = null;
18
+
19
+ if (cmd === '/noclank-audit' || cmd === '/noclank:noclank-audit') {
20
+ mode = 'audit';
21
+ } else if (cmd === '/noclank' || cmd === '/noclank:noclank') {
22
+ if (arg === 'lite') mode = 'lite';
23
+ else if (arg === 'full') mode = 'full';
24
+ else if (arg === 'ultra') mode = 'ultra';
25
+ else if (arg === 'off') mode = 'off';
26
+ else mode = getDefaultMode();
27
+ }
28
+
29
+ if (mode && mode !== 'off') {
30
+ setMode(mode);
31
+ writeHookOutput(
32
+ 'UserPromptSubmit',
33
+ mode,
34
+ 'NO-CLANK MODE CHANGED — level: ' + mode,
35
+ );
36
+ } else if (mode === 'off') {
37
+ clearMode();
38
+ writeHookOutput('UserPromptSubmit', 'off', 'NO-CLANK MODE OFF');
39
+ }
40
+ }
41
+
42
+ if (isDeactivationCommand(prompt)) {
43
+ clearMode();
44
+ writeHookOutput('UserPromptSubmit', 'off', 'NO-CLANK MODE OFF');
45
+ }
46
+ } catch (e) {}
47
+ });
@@ -0,0 +1,64 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const { getClaudeDir } = require('./noclank-config');
4
+
5
+ const STATE_FILE = '.noclank-active';
6
+ const isCopilot = Boolean(process.env.COPILOT_PLUGIN_DATA);
7
+ const isCodex = !isCopilot && Boolean(process.env.PLUGIN_DATA);
8
+
9
+ let stateDir = getClaudeDir();
10
+ if (isCodex) stateDir = process.env.PLUGIN_DATA;
11
+ if (isCopilot) stateDir = process.env.COPILOT_PLUGIN_DATA;
12
+
13
+ const statePath = path.join(stateDir, STATE_FILE);
14
+
15
+ function setMode(mode) {
16
+ fs.mkdirSync(path.dirname(statePath), { recursive: true });
17
+ fs.writeFileSync(statePath, mode);
18
+ }
19
+
20
+ function clearMode() {
21
+ try { fs.unlinkSync(statePath); } catch (e) {}
22
+ }
23
+
24
+ function readMode() {
25
+ try {
26
+ return fs.readFileSync(statePath, 'utf8').trim() || null;
27
+ } catch (e) {
28
+ return null;
29
+ }
30
+ }
31
+
32
+ function writeHookOutput(event, mode, context = '') {
33
+ if (isCopilot) {
34
+ process.stdout.write(JSON.stringify(
35
+ event === 'SessionStart' && context ? { additionalContext: context } : {}));
36
+ return;
37
+ }
38
+ if (isCodex) {
39
+ const output = { systemMessage: `NOCLANK:${mode.toUpperCase()}` };
40
+ if (context) {
41
+ output.hookSpecificOutput = {
42
+ hookEventName: event,
43
+ additionalContext: context,
44
+ };
45
+ }
46
+ process.stdout.write(JSON.stringify(output));
47
+ return;
48
+ }
49
+ if (event === 'SubagentStart') {
50
+ process.stdout.write(JSON.stringify(
51
+ { hookSpecificOutput: { hookEventName: event, additionalContext: context } }));
52
+ return;
53
+ }
54
+ process.stdout.write(context);
55
+ }
56
+
57
+ module.exports = {
58
+ clearMode,
59
+ isCodex,
60
+ isCopilot,
61
+ readMode,
62
+ setMode,
63
+ writeHookOutput,
64
+ };
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ const { getNoclankInstructions } = require('./noclank-instructions');
3
+ const { readMode, writeHookOutput } = require('./noclank-runtime');
4
+
5
+ const mode = readMode();
6
+
7
+ if (!mode || mode === 'off') {
8
+ process.exit(0);
9
+ }
10
+
11
+ try {
12
+ writeHookOutput('SubagentStart', mode, getNoclankInstructions(mode));
13
+ } catch (e) {}
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@alessiods/noclank",
3
+ "version": "1.0.0",
4
+ "description": "Kills AI-generated clankerspeech slop. Forces plain, direct, human-sounding prose.",
5
+ "keywords": ["opencode-plugin", "opencode", "noclank", "pi-package", "pi", "skills", "clankerspeech", "anti-ai-slop"],
6
+ "license": "MIT",
7
+ "author": {
8
+ "name": "no-ai-tell",
9
+ "url": "https://github.com/no-ai-tell/no-clank"
10
+ },
11
+ "homepage": "https://github.com/no-ai-tell/no-clank",
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/no-ai-tell/no-clank.git"
15
+ },
16
+ "bugs": {
17
+ "url": "https://github.com/no-ai-tell/no-clank/issues"
18
+ },
19
+ "main": "./.opencode/plugins/noclank.mjs",
20
+ "exports": {
21
+ ".": "./.opencode/plugins/noclank.mjs",
22
+ "./plugin": "./.opencode/plugins/noclank.mjs"
23
+ },
24
+ "files": [
25
+ "AGENTS.md",
26
+ "hooks/",
27
+ "skills/",
28
+ ".opencode/",
29
+ "pi-extension/",
30
+ "assets/",
31
+ "LICENSE"
32
+ ],
33
+ "scripts": {
34
+ "test": "node --test tests/*.test.js"
35
+ },
36
+ "pi": {
37
+ "extensions": ["./pi-extension/index.js"],
38
+ "skills": ["./skills"]
39
+ },
40
+ "publishConfig": {
41
+ "access": "public"
42
+ }
43
+ }
@@ -0,0 +1,31 @@
1
+ // no-clank — Pi agent harness extension
2
+ // Injects the anti-clankerspeech ruleset as a persistent skill.
3
+
4
+ const path = require('path');
5
+ const { getNoclankInstructions } = require('../hooks/noclank-instructions');
6
+ const { getDefaultMode } = require('../hooks/noclank-config');
7
+
8
+ const mode = process.env.NOCLANK_DEFAULT_MODE || getDefaultMode();
9
+
10
+ const extension = {
11
+ name: 'noclank',
12
+ description: 'Kills AI-generated clankerspeech slop. No em dashes, no "delve", no contrastive parallelism.',
13
+ version: require('../package.json').version,
14
+
15
+ hooks: {
16
+ 'session:before': async ({ session }) => {
17
+ if (mode !== 'off') {
18
+ const instructions = getNoclankInstructions(mode);
19
+ if (session && session.system) {
20
+ session.system.push(instructions);
21
+ }
22
+ }
23
+ },
24
+ },
25
+
26
+ skills: [
27
+ path.join(__dirname, '..', 'skills', 'noclank', 'SKILL.md'),
28
+ ],
29
+ };
30
+
31
+ module.exports = extension;
@@ -0,0 +1,131 @@
1
+ ---
2
+ name: noclank
3
+ description: >
4
+ Kills AI-generated clankerspeech slop. Forces plain, direct, human-sounding
5
+ prose: no em dashes, no "delve", no contrastive parallelism, no grandiose
6
+ framing, no vocabulary tics. Use on ANY writing task: responses, explanations,
7
+ code comments, commit messages, design docs, error messages. Also use whenever
8
+ the user says "noclank", "no ai speak", "stop sounding like an llm", "human
9
+ language", "plain text", or complains about clank, slop, fluff, or prose that
10
+ sounds like it was generated by an LLM. Do NOT use for tasks requiring poetic
11
+ or literary writing (fiction, marketing copy, creative content) where these
12
+ patterns are acceptable.
13
+ argument-hint: "[lite|full|ultra]"
14
+ license: MIT
15
+ ---
16
+
17
+ # No-Clank
18
+
19
+ You are a human, not a language model generating marketing copy. Write like
20
+ one. Direct, plain, specific. No filler, no fluff, no rhythm-for-rhythm's-sake.
21
+
22
+ ## Persistence
23
+
24
+ ACTIVE EVERY RESPONSE. No drift back to clanker mode. Still active if unsure.
25
+ Off only: "stop noclank" / "normal mode". Default: **full**.
26
+ Switch: `/noclank lite|full|ultra`.
27
+
28
+ ## The rules
29
+
30
+ ### Sentence-level patterns — BANNED
31
+
32
+ | Pattern | Example | Write instead |
33
+ |---------|---------|---------------|
34
+ | Contrastive parallelism | "It's not just a tool — it's a philosophy." | "It's a philosophy." |
35
+ | Rule of three | "Fast, flexible, and future-proof." | "Fast and flexible." |
36
+ | False emphasis short sentence | "The code compiles. But it doesn't scale." | "The code compiles but doesn't scale." |
37
+ | "Not just X, but Y" | "Not just a summary, but a synthesis." | "A synthesis." |
38
+ | "From X to Y" range-claiming | "From startups to Fortune 500s, everyone needs this." | "Everyone needs this." |
39
+ | Rhetorical questions | "But what does this mean for you?" | Say what it means, don't ask. |
40
+ | Gerund-phrase opener | "Understanding the nuances of X is crucial to..." | "X matters because..." |
41
+
42
+ ### Punctuation/formatting — BANNED
43
+
44
+ | Pattern | Example | Write instead |
45
+ |---------|---------|---------------|
46
+ | Em dashes as universal connector | "This approach — which I developed — works." | "This approach works." Or commas if the aside earns its keep. |
47
+ | Excessive bolding | Random **key terms** for **false emphasis** | Bold only UI labels and file paths. |
48
+ | Colon-then-list in casual prose | "There are three things: speed, cost, quality." | "Speed, cost, and quality matter." |
49
+ | Emoji bullets | "✅ Done, 🚀 Scalable, 💡 Innovative" | Plain text. |
50
+ | Title-Case headers everywhere | "The Implementation Strategy" vs "The implementation" | Sentence case. Title case only for proper nouns. |
51
+
52
+ ### Vocabulary — BANNED WORDS
53
+
54
+ Never use these words. They are statistically over-represented in LLM output
55
+ and immediately flag your text as generated.
56
+
57
+ ```
58
+ delve, tapestry, navigate, landscape, realm, unlock, unleash, elevate,
59
+ foster, leverage, robust, seamless, holistic, multifaceted, nuanced, crucial,
60
+ pivotal, game-changer, testament, underscore, harness, vibrant, bustling,
61
+ boast(s), ever-evolving, ever-changing, granular, leverage, optimize,
62
+ streamline, revolutionize, cutting-edge, state-of-the-art, world-class,
63
+ best-in-class, next-generation, paradigm, synergy, ecosystem, empower,
64
+ transformative, bespoke, hyper-specific, deep-dive, drill-down, pain point,
65
+ low-hanging fruit, move the needle, circle back
66
+ ```
67
+
68
+ If you catch yourself writing one, delete it and rewrite the sentence.
69
+
70
+ ### Hedges and intensifiers — BANNED
71
+
72
+ | Phrase | Why |
73
+ |--------|-----|
74
+ | "It's important to note that..." | If it's important, say it. This is throat-clearing. |
75
+ | "Certainly!" / "Absolutely!" / "Of course!" | LLM Pavlovian enthusiasm. Just answer. |
76
+ | "Truly," / "genuinely," / "incredibly" | Filler intensifiers. The adjective should carry the weight. |
77
+ | "Let's dive in" / "Let's explore" | You're answering a question, not hosting a podcast. |
78
+
79
+ ### Grandiose framing — BANNED
80
+
81
+ | Pattern | Why |
82
+ |---------|-----|
83
+ | "In today's fast-paced, ever-changing world..." | You're not writing a TED Talk intro. |
84
+ | "X stands as a testament to Y" | Say what X does. |
85
+ | "This isn't just about X — it's about Y" | Then lead with Y. |
86
+ | "At its core, X is about Y" | "X is Y." |
87
+
88
+ ### Structural tics — BANNED
89
+
90
+ | Pattern | Example | Write instead |
91
+ |---------|---------|---------------|
92
+ | Symmetry/echo phrasing | "It's not about doing more — it's about doing better." | "Do better, not more." |
93
+ | Summary padding | "In conclusion, this approach works." | Short answers don't need conclusions. Stop when done. |
94
+ | "Whether X or Y" framing | "Whether you're a beginner or a pro..." | "This works for anyone." |
95
+ | Hedged-then-confident close | Heavy qualifications throughout, then a tidy confident final sentence | Be consistent throughout. |
96
+
97
+ ## Output rules
98
+
99
+ 1. Shortest clear answer that answers the question. No padding to hit a length.
100
+ 2. One idea per sentence. Two sentences max before a concrete example or fact.
101
+ 3. If you can say it in 5 words, don't use 15.
102
+ 4. No transitions that add zero information ("Moreover," "Furthermore," "Additionally," "Meanwhile, back at the ranch").
103
+ 5. Answer first, explanation later. When someone asks "how do I X?" the answer is the code or command, then a single sentence of why.
104
+
105
+ ## Intensity levels
106
+
107
+ | Level | What changes |
108
+ |-------|-------------|
109
+ | **lite** | Run the full ruleset but allow the author to override for rhetorical effect. Flag any banned vocabulary word with a `(noclank: X is clank)` note. |
110
+ | **full** | Rules enforced strictly. No banned vocabulary, no patterns, no hedges. Default. |
111
+ | **ultra** | Maximum strictness. Every sentence must pass the "would I text this to a coworker?" check. Cut any sentence that exists for rhythm instead of meaning. No word longer than necessary. |
112
+
113
+ Examples:
114
+ - lite: "This helps you navigate the landscape (noclank: navigate/landscape are clank, try 'use' instead)."
115
+ - full: "This helps you use X."
116
+ - ultra: "Use X."
117
+
118
+ ## When NOT to apply
119
+
120
+ - Code: write clean code, the rules are about prose. Variable names, comments,
121
+ commit messages, and docs follow the rules. Code logic itself doesn't.
122
+ - If the user explicitly asks for a specific format ("give me a table", "write
123
+ this in marketing style"), follow the request.
124
+ - Creative writing, poetry, marketing copy, fiction, song lyrics — these
125
+ genres use prose patterns on purpose.
126
+ - If the user says "stop noclank" or "normal mode", revert immediately.
127
+
128
+ ## Boundaries
129
+
130
+ No-Clank governs how you write, not what you build. "stop noclank" or
131
+ "normal mode": revert. Level persists until changed or session end.