tweek 0.3.1__py3-none-any.whl → 0.4.0__py3-none-any.whl

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.
Files changed (61) hide show
  1. tweek/__init__.py +2 -2
  2. tweek/audit.py +2 -2
  3. tweek/cli.py +78 -6605
  4. tweek/cli_config.py +643 -0
  5. tweek/cli_configure.py +413 -0
  6. tweek/cli_core.py +718 -0
  7. tweek/cli_dry_run.py +390 -0
  8. tweek/cli_helpers.py +316 -0
  9. tweek/cli_install.py +1666 -0
  10. tweek/cli_logs.py +301 -0
  11. tweek/cli_mcp.py +148 -0
  12. tweek/cli_memory.py +343 -0
  13. tweek/cli_plugins.py +748 -0
  14. tweek/cli_protect.py +564 -0
  15. tweek/cli_proxy.py +405 -0
  16. tweek/cli_security.py +236 -0
  17. tweek/cli_skills.py +289 -0
  18. tweek/cli_uninstall.py +551 -0
  19. tweek/cli_vault.py +313 -0
  20. tweek/config/allowed_dirs.yaml +16 -17
  21. tweek/config/families.yaml +4 -1
  22. tweek/config/manager.py +17 -0
  23. tweek/config/patterns.yaml +29 -5
  24. tweek/config/templates/config.yaml.template +212 -0
  25. tweek/config/templates/env.template +45 -0
  26. tweek/config/templates/overrides.yaml.template +121 -0
  27. tweek/config/templates/tweek.yaml.template +20 -0
  28. tweek/config/templates.py +136 -0
  29. tweek/config/tiers.yaml +5 -4
  30. tweek/diagnostics.py +112 -32
  31. tweek/hooks/overrides.py +4 -0
  32. tweek/hooks/post_tool_use.py +46 -1
  33. tweek/hooks/pre_tool_use.py +149 -49
  34. tweek/integrations/openclaw.py +84 -0
  35. tweek/licensing.py +1 -1
  36. tweek/mcp/__init__.py +7 -9
  37. tweek/mcp/clients/chatgpt.py +2 -2
  38. tweek/mcp/clients/claude_desktop.py +2 -2
  39. tweek/mcp/clients/gemini.py +2 -2
  40. tweek/mcp/proxy.py +165 -1
  41. tweek/memory/provenance.py +438 -0
  42. tweek/memory/queries.py +2 -0
  43. tweek/memory/safety.py +23 -4
  44. tweek/memory/schemas.py +1 -0
  45. tweek/memory/store.py +101 -71
  46. tweek/plugins/screening/heuristic_scorer.py +1 -1
  47. tweek/security/integrity.py +77 -0
  48. tweek/security/llm_reviewer.py +162 -68
  49. tweek/security/local_reviewer.py +44 -2
  50. tweek/security/model_registry.py +73 -7
  51. tweek/skill_template/overrides-reference.md +1 -1
  52. tweek/skills/context.py +221 -0
  53. tweek/skills/scanner.py +2 -2
  54. {tweek-0.3.1.dist-info → tweek-0.4.0.dist-info}/METADATA +8 -7
  55. {tweek-0.3.1.dist-info → tweek-0.4.0.dist-info}/RECORD +60 -38
  56. tweek/mcp/server.py +0 -320
  57. {tweek-0.3.1.dist-info → tweek-0.4.0.dist-info}/WHEEL +0 -0
  58. {tweek-0.3.1.dist-info → tweek-0.4.0.dist-info}/entry_points.txt +0 -0
  59. {tweek-0.3.1.dist-info → tweek-0.4.0.dist-info}/licenses/LICENSE +0 -0
  60. {tweek-0.3.1.dist-info → tweek-0.4.0.dist-info}/licenses/NOTICE +0 -0
  61. {tweek-0.3.1.dist-info → tweek-0.4.0.dist-info}/top_level.txt +0 -0
tweek/cli_vault.py ADDED
@@ -0,0 +1,313 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Tweek CLI — Vault and License command groups.
4
+
5
+ Extracted from cli.py to keep the main CLI module manageable.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ from pathlib import Path
10
+ from typing import Optional
11
+
12
+ import click
13
+
14
+ from rich.table import Table
15
+
16
+ from tweek.cli_helpers import console, TWEEK_BANNER
17
+
18
+
19
+ # ============================================================
20
+ # VAULT COMMANDS
21
+ # ============================================================
22
+
23
+ @click.group()
24
+ def vault():
25
+ """Manage credentials in secure storage (Keychain on macOS, Secret Service on Linux)."""
26
+ pass
27
+
28
+
29
+ @vault.command("store",
30
+ epilog="""\b
31
+ Examples:
32
+ tweek vault store myskill API_KEY Prompt for value securely
33
+ tweek vault store myskill API_KEY sk-abc123 Store an API key (visible in history!)
34
+ """
35
+ )
36
+ @click.argument("skill")
37
+ @click.argument("key")
38
+ @click.argument("value", required=False, default=None)
39
+ def vault_store(skill: str, key: str, value: Optional[str]):
40
+ """Store a credential securely for a skill."""
41
+ from tweek.vault import get_vault, VAULT_AVAILABLE
42
+ from tweek.platform import get_capabilities
43
+
44
+ if not VAULT_AVAILABLE:
45
+ console.print("[red]\u2717[/red] Vault not available.")
46
+ console.print(" [white]Hint: Install keyring support: pip install keyring[/white]")
47
+ console.print(" [white]On macOS, keyring uses Keychain. On Linux, install gnome-keyring or kwallet.[/white]")
48
+ return
49
+
50
+ caps = get_capabilities()
51
+
52
+ # If value not provided as argument, prompt securely (avoids shell history exposure)
53
+ if value is None:
54
+ value = click.prompt(f"Enter value for {key}", hide_input=True)
55
+ if not value:
56
+ console.print("[red]No value provided.[/red]")
57
+ return
58
+
59
+ try:
60
+ vault_instance = get_vault()
61
+ if vault_instance.store(skill, key, value):
62
+ console.print(f"[green]\u2713[/green] Stored {key} for skill '{skill}'")
63
+ console.print(f"[white]Backend: {caps.vault_backend}[/white]")
64
+ else:
65
+ console.print(f"[red]\u2717[/red] Failed to store credential")
66
+ console.print(" [white]Hint: Check your keyring backend is unlocked and accessible[/white]")
67
+ except Exception as e:
68
+ console.print(f"[red]\u2717[/red] Failed to store credential: {e}")
69
+ console.print(" [white]Hint: Check your keyring backend is unlocked and accessible[/white]")
70
+
71
+
72
+ @vault.command("get",
73
+ epilog="""\b
74
+ Examples:
75
+ tweek vault get myskill API_KEY Retrieve a stored credential
76
+ tweek vault get deploy AWS_SECRET Retrieve a deployment secret
77
+ """
78
+ )
79
+ @click.argument("skill")
80
+ @click.argument("key")
81
+ def vault_get(skill: str, key: str):
82
+ """Retrieve a credential from secure storage."""
83
+ from tweek.vault import get_vault, VAULT_AVAILABLE
84
+
85
+ if not VAULT_AVAILABLE:
86
+ console.print("[red]\u2717[/red] Vault not available.")
87
+ console.print(" [white]Hint: Install keyring support: pip install keyring[/white]")
88
+ return
89
+
90
+ vault_instance = get_vault()
91
+ value = vault_instance.get(skill, key)
92
+
93
+ if value is not None:
94
+ console.print(f"[yellow]GAH![/yellow] Credential access logged")
95
+ import sys as _sys
96
+ if not _sys.stdout.isatty():
97
+ console.print("[yellow]WARNING: stdout is piped — credential may be logged.[/yellow]", err=True)
98
+ console.print(value)
99
+ else:
100
+ console.print(f"[red]\u2717[/red] Credential not found: {key} for skill '{skill}'")
101
+ console.print(" [white]Hint: Store it with: tweek vault store {skill} {key} <value>[/white]".format(skill=skill, key=key))
102
+
103
+
104
+ @vault.command("migrate-env",
105
+ epilog="""\b
106
+ Examples:
107
+ tweek vault migrate-env --skill myapp Migrate .env to vault
108
+ tweek vault migrate-env --skill myapp --dry-run Preview without changes
109
+ tweek vault migrate-env --skill deploy --env-file .env.production Migrate specific file
110
+ """
111
+ )
112
+ @click.option("--dry-run", is_flag=True, help="Show what would be migrated without doing it")
113
+ @click.option("--env-file", default=".env", help="Path to .env file")
114
+ @click.option("--skill", required=True, help="Skill name to store credentials under")
115
+ def vault_migrate_env(dry_run: bool, env_file: str, skill: str):
116
+ """Migrate credentials from .env file to secure storage."""
117
+ from tweek.vault import get_vault, migrate_env_to_vault, VAULT_AVAILABLE
118
+
119
+ if not VAULT_AVAILABLE:
120
+ console.print("[red]\u2717[/red] Vault not available. Install keyring: pip install keyring")
121
+ return
122
+
123
+ env_path = Path(env_file)
124
+ console.print(f"[cyan]Scanning {env_path} for credentials...[/cyan]")
125
+
126
+ if dry_run:
127
+ console.print("\n[yellow]DRY RUN - No changes will be made[/yellow]\n")
128
+
129
+ try:
130
+ vault_instance = get_vault()
131
+ results = migrate_env_to_vault(env_path, skill, vault_instance, dry_run=dry_run)
132
+
133
+ if results:
134
+ console.print(f"\n[green]{'Would migrate' if dry_run else 'Migrated'}:[/green]")
135
+ for key, success in results:
136
+ status = "\u2713" if success else "\u2717"
137
+ console.print(f" {status} {key}")
138
+ successful = sum(1 for _, s in results if s)
139
+ total = len(results)
140
+ console.print(f"\n[green]\u2713[/green] {'Would migrate' if dry_run else 'Migrated'} {successful} credentials to skill '{skill}'")
141
+
142
+ if not dry_run and successful == total and env_path.exists():
143
+ console.print()
144
+ if click.confirm(f"Remove {env_path}? (credentials are now in the vault)"):
145
+ env_path.unlink()
146
+ console.print(f"[green]\u2713[/green] Removed {env_path}")
147
+ else:
148
+ console.print(f"[yellow]\u26a0[/yellow] {env_path} still contains plaintext credentials")
149
+ elif not dry_run and successful < total:
150
+ failed = total - successful
151
+ console.print(f"[yellow]\u26a0[/yellow] {failed} credential(s) failed to migrate \u2014 keeping {env_path}")
152
+ else:
153
+ console.print("[white]No credentials found to migrate[/white]")
154
+
155
+ except Exception as e:
156
+ console.print(f"[red]\u2717[/red] Migration failed: {e}")
157
+
158
+
159
+ @vault.command("delete",
160
+ epilog="""\b
161
+ Examples:
162
+ tweek vault delete myskill API_KEY Delete a stored credential
163
+ tweek vault delete deploy AWS_SECRET Remove a deployment secret
164
+ """
165
+ )
166
+ @click.argument("skill")
167
+ @click.argument("key")
168
+ def vault_delete(skill: str, key: str):
169
+ """Delete a credential from secure storage."""
170
+ from tweek.vault import get_vault, VAULT_AVAILABLE
171
+
172
+ if not VAULT_AVAILABLE:
173
+ console.print("[red]\u2717[/red] Vault not available. Install keyring: pip install keyring")
174
+ return
175
+
176
+ vault_instance = get_vault()
177
+ deleted = vault_instance.delete(skill, key)
178
+
179
+ if deleted:
180
+ console.print(f"[green]\u2713[/green] Deleted {key} from skill '{skill}'")
181
+ else:
182
+ console.print(f"[yellow]![/yellow] Credential not found: {key} for skill '{skill}'")
183
+
184
+
185
+ # ============================================================
186
+ # LICENSE COMMANDS [experimental]
187
+ # ============================================================
188
+
189
+ @click.group("license")
190
+ def license_group():
191
+ """Manage Tweek license and features. [experimental]"""
192
+ pass
193
+
194
+
195
+ @license_group.command("status",
196
+ epilog="""\b
197
+ Examples:
198
+ tweek license status Show license tier and features
199
+ """
200
+ )
201
+ def license_status():
202
+ """Show current license status and available features. [experimental]"""
203
+ console.print("[yellow]Note: License management is experimental. Pro/Enterprise tiers coming soon.[/yellow]")
204
+
205
+ from tweek.licensing import get_license, TIER_FEATURES, Tier
206
+
207
+ console.print(TWEEK_BANNER, style="cyan")
208
+
209
+ lic = get_license()
210
+ info = lic.info
211
+
212
+ # License info
213
+ tier_colors = {
214
+ Tier.FREE: "white",
215
+ Tier.PRO: "cyan",
216
+ }
217
+
218
+ tier_color = tier_colors.get(lic.tier, "white")
219
+ console.print(f"[bold]License Tier:[/bold] [{tier_color}]{lic.tier.value.upper()}[/{tier_color}]")
220
+
221
+ if info:
222
+ console.print(f"[white]Licensed to: {info.email}[/white]")
223
+ if info.expires_at:
224
+ from datetime import datetime
225
+ exp_date = datetime.fromtimestamp(info.expires_at).strftime("%Y-%m-%d")
226
+ if info.is_expired:
227
+ console.print(f"[red]Expired: {exp_date}[/red]")
228
+ else:
229
+ console.print(f"[white]Expires: {exp_date}[/white]")
230
+ else:
231
+ console.print("[white]Expires: Never[/white]")
232
+ console.print()
233
+
234
+ # Features table
235
+ table = Table(title="Feature Availability")
236
+ table.add_column("Feature", style="cyan")
237
+ table.add_column("Status")
238
+ table.add_column("Tier Required")
239
+
240
+ # Collect all features and their required tiers
241
+ feature_tiers = {}
242
+ for tier in [Tier.FREE, Tier.PRO]:
243
+ for feature in TIER_FEATURES.get(tier, []):
244
+ feature_tiers[feature] = tier
245
+
246
+ for feature, required_tier in feature_tiers.items():
247
+ has_it = lic.has_feature(feature)
248
+ status = "[green]\u2713[/green]" if has_it else "[white]\u25cb[/white]"
249
+ tier_display = required_tier.value.upper()
250
+ if required_tier == Tier.PRO:
251
+ tier_display = f"[cyan]{tier_display}[/cyan]"
252
+
253
+ table.add_row(feature, status, tier_display)
254
+
255
+ console.print(table)
256
+
257
+ if lic.tier == Tier.FREE:
258
+ console.print()
259
+ console.print("[green]All security features are included free and open source.[/green]")
260
+ console.print("[white]Pro (teams) and Enterprise (compliance) coming soon: gettweek.com[/white]")
261
+
262
+
263
+ @license_group.command("activate",
264
+ epilog="""\b
265
+ Examples:
266
+ tweek license activate YOUR_KEY Activate a license key (Pro/Enterprise coming soon)
267
+ """
268
+ )
269
+ @click.argument("license_key")
270
+ def license_activate(license_key: str):
271
+ """Activate a license key. [experimental]"""
272
+ console.print("[yellow]Note: License management is experimental. Pro/Enterprise tiers coming soon.[/yellow]")
273
+
274
+ from tweek.licensing import get_license
275
+
276
+ lic = get_license()
277
+ success, message = lic.activate(license_key)
278
+
279
+ if success:
280
+ console.print(f"[green]\u2713[/green] {message}")
281
+ console.print()
282
+ console.print("[white]Run 'tweek license status' to see available features[/white]")
283
+ else:
284
+ console.print(f"[red]\u2717[/red] {message}")
285
+
286
+
287
+ @license_group.command("deactivate",
288
+ epilog="""\b
289
+ Examples:
290
+ tweek license deactivate Deactivate license (with prompt)
291
+ tweek license deactivate --confirm Deactivate without confirmation
292
+ """
293
+ )
294
+ @click.option("--confirm", is_flag=True, help="Skip confirmation prompt")
295
+ def license_deactivate(confirm: bool):
296
+ """Remove current license and revert to FREE tier. [experimental]"""
297
+ console.print("[yellow]Note: License management is experimental. Pro/Enterprise tiers coming soon.[/yellow]")
298
+
299
+ from tweek.licensing import get_license
300
+
301
+ if not confirm:
302
+ console.print("[yellow]Deactivate license and revert to FREE tier?[/yellow] ", end="")
303
+ if not click.confirm(""):
304
+ console.print("[white]Cancelled[/white]")
305
+ return
306
+
307
+ lic = get_license()
308
+ success, message = lic.deactivate()
309
+
310
+ if success:
311
+ console.print(f"[green]\u2713[/green] {message}")
312
+ else:
313
+ console.print(f"[red]\u2717[/red] {message}")
@@ -1,23 +1,22 @@
1
- # Tweek Directory Safety Configuration
1
+ # Tweek Directory Safety Configuration (bundled default)
2
2
  #
3
- # This file controls WHERE Tweek hooks are active.
4
- # This is a SAFETY FEATURE to prevent accidental activation in production.
3
+ # This file ships with the Tweek package and provides the production default.
4
+ # To override, create ~/.tweek/allowed_dirs.yaml (user-level config takes
5
+ # full precedence when it exists).
5
6
  #
6
7
  # Options:
7
- # global_enabled: true - Activate Tweek everywhere (production mode)
8
- # allowed_directories: - List of directories where Tweek activates
8
+ # global_enabled: true - Activate Tweek everywhere (default for end users)
9
+ # allowed_directories: - Restrict Tweek to specific directories only
9
10
  #
10
- # IMPORTANT: Without this file, Tweek is DISABLED everywhere.
11
+ # Lookup order:
12
+ # 1. ~/.tweek/allowed_dirs.yaml (user override — not in repo)
13
+ # 2. This file (bundled default)
11
14
 
12
- # Set to true to enable Tweek globally (for production deployment)
13
- global_enabled: false
15
+ # Production default: Tweek is active everywhere after install
16
+ global_enabled: true
14
17
 
15
- # Directories where Tweek hooks will activate
16
- # Tweek will also activate in subdirectories of these paths
17
- allowed_directories:
18
- # Test environment only (safe for development)
19
- - ~/AI/tweek/test-environment
20
-
21
- # Add more directories as needed:
22
- # - ~/projects/sensitive-project
23
- # - /path/to/another/project
18
+ # When global_enabled is false, only activate in these directories.
19
+ # Tweek also activates in subdirectories of listed paths.
20
+ # allowed_directories:
21
+ # - ~/projects/my-project
22
+ # - /path/to/another/project
@@ -1,5 +1,5 @@
1
1
  # Tweek Pattern Family Definitions v1
2
- # Groups the 259 attack patterns by attack class for:
2
+ # Groups the 262 attack patterns by attack class for:
3
3
  # 1. Heuristic scoring (near-miss detection via semantic signals)
4
4
  # 2. Pattern management (enable/disable by family)
5
5
  # 3. Reporting (family-level risk summaries)
@@ -257,6 +257,9 @@ families:
257
257
  - 257 # self_describe_purpose
258
258
  - 258 # self_describe_protection
259
259
  - 259 # self_describe_instructions
260
+ - 260 # summarize_instructions_extraction
261
+ - 261 # special_instructions_probe
262
+ - 262 # system_prompt_reference_broad
260
263
  heuristic_signals:
261
264
  instruction_keywords:
262
265
  - "ignore"
tweek/config/manager.py CHANGED
@@ -152,6 +152,23 @@ class ConfigManager:
152
152
  },
153
153
  "default_tier": "default",
154
154
  },
155
+ "balanced": {
156
+ # Same tool tiers as cautious, but the preset name signals
157
+ # provenance-aware enforcement: clean sessions get relaxed
158
+ # thresholds (fewer false positives), tainted sessions get
159
+ # escalated scrutiny. See tweek.memory.provenance.
160
+ "tools": {
161
+ "Read": "safe",
162
+ "Glob": "safe",
163
+ "Grep": "safe",
164
+ "Edit": "default",
165
+ "Write": "default",
166
+ "WebFetch": "risky",
167
+ "WebSearch": "risky",
168
+ "Bash": "dangerous",
169
+ },
170
+ "default_tier": "default",
171
+ },
155
172
  "trusted": {
156
173
  "tools": {
157
174
  "Read": "safe",
@@ -1,5 +1,5 @@
1
1
  # Tweek Attack Pattern Definitions v3
2
- # All 259 patterns included FREE
2
+ # All 262 patterns included FREE
3
3
  #
4
4
  # Update via: tweek update (pulls from github.com/gettweek/tweek)
5
5
  #
@@ -25,7 +25,7 @@
25
25
  # PRO tier adds: LLM review, session analysis, rate limiting
26
26
 
27
27
  version: 5
28
- pattern_count: 259
28
+ pattern_count: 262
29
29
 
30
30
  patterns:
31
31
  # ============================================================================
@@ -711,7 +711,7 @@ patterns:
711
711
  - id: 83
712
712
  name: document_metadata_injection
713
713
  description: "Hidden instructions in document metadata"
714
- regex: '(author|title|subject|keywords|description)\s*[=:]\s*.*?(execute|run|ignore|override|bypass)'
714
+ regex: '(author|title|subject|keywords|description)\s*[=:]\s*[^\n]{0,80}(execute|run|ignore|override|bypass)'
715
715
  severity: high
716
716
  confidence: heuristic
717
717
  family: prompt_injection
@@ -736,7 +736,7 @@ patterns:
736
736
  - id: 86
737
737
  name: log_to_leak
738
738
  description: "Log-To-Leak covert channel attack"
739
- regex: '(log|write|append|print).*?(secret|credential|token|key|password).*?(file|output|stream)'
739
+ regex: '(log|write|append|print)[^\n]{0,60}(secret|credential|token|key|password)[^\n]{0,60}(file|output|stream)'
740
740
  severity: high
741
741
  confidence: heuristic
742
742
  family: covert_channels
@@ -1514,7 +1514,7 @@ patterns:
1514
1514
  - id: 174
1515
1515
  name: leetspeak_instruction_bypass
1516
1516
  description: "Heavy character substitution of security-critical words"
1517
- regex: '([sS5$][yY][sS5$][tT7][eE3][mM]\s*[pP][rR][0oO][mM][pP][tT7]|[1iI][nN][sS5$][tT7][rR][uU][cC][tT7]|[cC][0oO][nN][fF][1iI][gG]|[eE3][xX][eE3][cC][uU][tT7][eE3])'
1517
+ regex: '((?=[a-zA-Z01357$]*[01357$])[sS5$][yY][sS5$][tT7][eE3][mM]\s*[pP][rR][0oO][mM][pP][tT7]|(?=[a-zA-Z01357$]*[01357$])[1iI][nN][sS5$][tT7][rR][uU][cC][tT7]|(?=[a-zA-Z01357$]*[01357$])[cC][0oO][nN][fF][1iI][gG]|(?=[a-zA-Z01357$]*[01357$])[eE3][xX][eE3][cC][uU][tT7][eE3])'
1518
1518
  severity: medium
1519
1519
  confidence: contextual
1520
1520
  family: prompt_injection
@@ -2251,3 +2251,27 @@ patterns:
2251
2251
  severity: low
2252
2252
  confidence: contextual
2253
2253
  family: prompt_injection
2254
+
2255
+ - id: 260
2256
+ name: summarize_instructions_extraction
2257
+ description: "Summarization-based system prompt extraction"
2258
+ regex: '(summarize|recap|outline|condense|describe|paraphrase)\s+.{0,30}(instructions|prompt|rules|guidelines|directives|configuration)\s+.{0,20}(given|told|provided|have|follow|received|programmed)'
2259
+ severity: medium
2260
+ confidence: contextual
2261
+ family: prompt_injection
2262
+
2263
+ - id: 261
2264
+ name: special_instructions_probe
2265
+ description: "Probing for special instructions or unique capabilities"
2266
+ regex: 'what\s+.{0,20}(instructions|capabilities|directives|rules)\s+.{0,30}(do\s+you\s+have|make\s+you|were\s+you|that\s+you)'
2267
+ severity: medium
2268
+ confidence: contextual
2269
+ family: prompt_injection
2270
+
2271
+ - id: 262
2272
+ name: system_prompt_reference_broad
2273
+ description: "Broad references to system prompt in extraction context"
2274
+ regex: '((your|my|the|its)\s+.{0,20}system[\s_]+prompt|system[\s_]+prompt\s*(say|would\s+say|output|reveal|share|display)|output\s+(system[\s_]+)?(prompt|configuration)\b|(instructions|directives)\s+(you|I|they|it)\s+(received|were\s+given|have\b|follow|got)|what.s\s+your\s+system[\s_]+prompt)'
2275
+ severity: medium
2276
+ confidence: contextual
2277
+ family: prompt_injection
@@ -0,0 +1,212 @@
1
+ # ============================================================================
2
+ # Tweek User Configuration (~/.tweek/config.yaml)
3
+ # ============================================================================
4
+ #
5
+ # This file overrides Tweek's bundled defaults. Only uncomment what you
6
+ # want to change -- everything else uses safe production defaults.
7
+ #
8
+ # Config hierarchy (highest priority wins):
9
+ # 1. Project: .tweek/config.yaml (per-project overrides)
10
+ # 2. User: ~/.tweek/config.yaml (this file)
11
+ # 3. Bundled: tweek/config/tiers.yaml (production defaults)
12
+ #
13
+ # Commands:
14
+ # tweek config edit Open this file in your editor
15
+ # tweek config show-defaults View all bundled defaults
16
+ # tweek config validate Check for errors
17
+ # tweek config list Show current tool/skill tiers
18
+ # tweek config preset <name> Apply a preset (paranoid|cautious|trusted)
19
+ #
20
+ # Full docs: https://github.com/gettweek/tweek/blob/main/docs/CONFIGURATION.md
21
+ # ============================================================================
22
+
23
+
24
+ # ---------------------------------------------------------------------------
25
+ # LLM Review Provider (Layer 3 — semantic analysis)
26
+ # ---------------------------------------------------------------------------
27
+ # Analyzes suspicious commands/content using an LLM for deeper screening.
28
+ # Works alongside pattern matching (Layer 2) — not a replacement.
29
+ #
30
+ # Auto-detect order: Local ONNX model > Google > OpenAI > xAI > Anthropic
31
+ #
32
+ # IMPORTANT: API keys go in ~/.tweek/.env (not here). Run:
33
+ # tweek config edit env
34
+ #
35
+ # BILLING NOTE: Anthropic API keys are billed per-token, SEPARATELY from
36
+ # Claude Pro/Max subscriptions. Google Gemini has a free tier — recommended.
37
+ #
38
+ # llm_review:
39
+ # enabled: true
40
+ # provider: auto # auto | google | openai | xai | anthropic | local
41
+ # model: auto # auto = provider default. Defaults per provider:
42
+ # # google: gemini-2.0-flash
43
+ # # openai: gpt-4o-mini
44
+ # # xai: grok-2
45
+ # # anthropic: claude-3-5-haiku-latest
46
+ # # local: deberta-v3-injection
47
+ # timeout_seconds: 5.0 # Max wait for LLM response
48
+ # base_url: null # For OpenAI-compatible endpoints (Ollama, LM Studio, etc.)
49
+ # api_key_env: null # Override env var name (default: provider-specific)
50
+ #
51
+ # # Local LLM server settings (Ollama, LM Studio)
52
+ # local:
53
+ # enabled: true
54
+ # probe_timeout: 0.5 # Max probe time per server (seconds)
55
+ # timeout_seconds: 3.0 # Per-request timeout (local should be fast)
56
+ # ollama_host: null # Override (default: OLLAMA_HOST env or localhost:11434)
57
+ # lm_studio_host: null # Override (default: localhost:1234)
58
+ # preferred_models: [] # User override for model ranking
59
+ # validate_on_first_use: true
60
+ # min_validation_score: 0.6 # Must pass 3/5 validation commands
61
+ #
62
+ # # Fallback chain (try local first, then cloud)
63
+ # fallback:
64
+ # enabled: true
65
+ # order: [local, cloud]
66
+
67
+
68
+ # ---------------------------------------------------------------------------
69
+ # Local ONNX Model (Layer 3 — on-device classifier)
70
+ # ---------------------------------------------------------------------------
71
+ # On-device prompt injection classifier. No API key needed.
72
+ # Install: pip install tweek[local-models] && tweek model download
73
+ # When installed, runs before cloud LLM and escalates uncertain results.
74
+ #
75
+ # local_model:
76
+ # enabled: true
77
+ # model: auto # auto = default model, or explicit name
78
+ # escalate_to_llm: true # Escalate uncertain results to cloud LLM
79
+ # escalate_min_confidence: 0.1 # Below this = safe, skip escalation
80
+ # escalate_max_confidence: 0.9 # Above this = use local result, skip escalation
81
+
82
+
83
+ # ---------------------------------------------------------------------------
84
+ # Rate Limiting (Layer 1 — burst detection)
85
+ # ---------------------------------------------------------------------------
86
+ # Detects rapid-fire tool calls that may indicate automated attacks.
87
+ #
88
+ # rate_limiting:
89
+ # enabled: true
90
+ # burst_window_seconds: 5 # Time window for burst detection
91
+ # burst_threshold: 15 # Max calls in burst window
92
+ # max_per_minute: 60 # Overall rate limit
93
+ # max_dangerous_per_minute: 10 # Limit for dangerous-tier tools
94
+ # max_same_command_per_minute: 5 # Repeated identical commands
95
+
96
+
97
+ # ---------------------------------------------------------------------------
98
+ # Session Analysis (Layer 4 — cross-turn anomaly detection)
99
+ # ---------------------------------------------------------------------------
100
+ # Tracks patterns across multiple tool calls to detect multi-step attacks.
101
+ #
102
+ # session_analysis:
103
+ # enabled: true
104
+ # lookback_minutes: 30 # How far back to analyze
105
+ # alert_on_risk_score: 0.5 # Threshold for session risk alerts
106
+
107
+
108
+ # ---------------------------------------------------------------------------
109
+ # Heuristic Scorer (Layer 2.5 — signal-based escalation)
110
+ # ---------------------------------------------------------------------------
111
+ # Bridges pattern matching and LLM review. When no regex matches but
112
+ # content looks suspicious, scores it and may escalate to LLM.
113
+ #
114
+ # heuristic_scorer:
115
+ # enabled: true
116
+ # threshold: 0.4 # Score [0.0-1.0] to trigger LLM escalation
117
+ # log_all_scores: false # Log below-threshold scores (for tuning)
118
+
119
+
120
+ # ---------------------------------------------------------------------------
121
+ # Tool Tier Overrides
122
+ # ---------------------------------------------------------------------------
123
+ # Override the default security tier for specific tools.
124
+ # Tiers: safe | default | risky | dangerous
125
+ #
126
+ # Bundled defaults:
127
+ # Read: default (read-only but needs path screening)
128
+ # Glob: safe (file pattern matching)
129
+ # Grep: safe (search file contents)
130
+ # Edit: default (modify existing files)
131
+ # Write: risky (create/overwrite files)
132
+ # NotebookEdit: default (edit Jupyter notebooks)
133
+ # WebFetch: risky (fetch content from URLs)
134
+ # WebSearch: risky (search the web)
135
+ # Bash: dangerous (execute shell commands)
136
+ # Task: default (spawn subagent tasks)
137
+ #
138
+ # tools:
139
+ # Read: default
140
+ # Bash: dangerous
141
+
142
+
143
+ # ---------------------------------------------------------------------------
144
+ # Skill Tier Overrides
145
+ # ---------------------------------------------------------------------------
146
+ # Override the default tier for Claude Code skills.
147
+ #
148
+ # Bundled defaults:
149
+ # review-pr: safe (read-only PR review)
150
+ # explore: safe (read-only codebase exploration)
151
+ # commit: default (git commit operations)
152
+ # frontend-design: risky (generate frontend code)
153
+ # dev-browser: risky (browser automation)
154
+ # deploy: dangerous (deployment operations)
155
+ #
156
+ # skills:
157
+ # commit: default
158
+ # deploy: dangerous
159
+
160
+
161
+ # ---------------------------------------------------------------------------
162
+ # Non-English Language Handling
163
+ # ---------------------------------------------------------------------------
164
+ # English-only regex patterns can miss injection in other languages.
165
+ # Options:
166
+ # escalate - Auto-escalate to LLM review tier (default, recommended)
167
+ # translate - Translate to English before pattern matching (requires API key)
168
+ # both - Escalate AND translate (maximum coverage)
169
+ # none - No special handling (English-only patterns may miss attacks)
170
+ #
171
+ # non_english_handling: escalate
172
+
173
+
174
+ # ---------------------------------------------------------------------------
175
+ # Content-Based Escalations
176
+ # ---------------------------------------------------------------------------
177
+ # Regex patterns that bump a tool's tier based on content.
178
+ # These ADD to the bundled escalations (they don't replace them).
179
+ #
180
+ # escalations:
181
+ # - pattern: '\b(prod|production)\b'
182
+ # description: "Production environment reference"
183
+ # escalate_to: risky
184
+ #
185
+ # - pattern: 'rm\s+(-rf|-fr|--recursive)'
186
+ # description: "Recursive deletion"
187
+ # escalate_to: dangerous
188
+
189
+
190
+ # ---------------------------------------------------------------------------
191
+ # Path Boundary Escalation
192
+ # ---------------------------------------------------------------------------
193
+ # Escalates tier when tools access files outside the project directory.
194
+ #
195
+ # path_boundary:
196
+ # enabled: true
197
+ # default_escalate_to: risky # Generic out-of-project access
198
+ # sensitive_directories:
199
+ # - pattern: ".ssh"
200
+ # escalate_to: dangerous
201
+ # description: "SSH directory access"
202
+ # - pattern: ".aws"
203
+ # escalate_to: dangerous
204
+ # description: "AWS credentials directory"
205
+
206
+
207
+ # ---------------------------------------------------------------------------
208
+ # Default Tier
209
+ # ---------------------------------------------------------------------------
210
+ # Fallback tier for tools/skills not explicitly classified.
211
+ #
212
+ # default_tier: default