pwn 0.5.636 → 0.5.638

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 (80) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/install-matrix.yml +13 -1
  3. data/bin/pwn_ai_red_team +150 -0
  4. data/bin/pwn_setup +16 -2
  5. data/build_gem.sh +3 -0
  6. data/documentation/Agent-Tool-Registry.md +12 -5
  7. data/documentation/CLI-Drivers.md +37 -31
  8. data/documentation/Configuration.md +16 -3
  9. data/documentation/Contributing.md +9 -2
  10. data/documentation/Cron.md +21 -1
  11. data/documentation/Diagrams.md +6 -2
  12. data/documentation/Drivers.md +1 -1
  13. data/documentation/General-PWN-Usage.md +7 -1
  14. data/documentation/Home.md +1 -1
  15. data/documentation/How-PWN-Works.md +31 -17
  16. data/documentation/Installation.md +85 -53
  17. data/documentation/Persistence.md +34 -8
  18. data/documentation/Plugins.md +5 -5
  19. data/documentation/Reinforcement-Learning.md +7 -0
  20. data/documentation/Sessions.md +6 -2
  21. data/documentation/Skills-Memory-Learning.md +26 -10
  22. data/documentation/Troubleshooting.md +23 -0
  23. data/documentation/What-is-PWN.md +12 -6
  24. data/documentation/Why-PWN.md +3 -2
  25. data/documentation/diagrams/agent-tool-registry.svg +105 -102
  26. data/documentation/diagrams/cron-scheduling.svg +137 -78
  27. data/documentation/diagrams/dot/agent-tool-registry.dot +4 -4
  28. data/documentation/diagrams/dot/cron-scheduling.dot +25 -9
  29. data/documentation/diagrams/dot/history-to-drivers.dot +1 -1
  30. data/documentation/diagrams/dot/memory-skills-detailed.dot +10 -4
  31. data/documentation/diagrams/dot/overall-pwn-architecture.dot +2 -2
  32. data/documentation/diagrams/dot/persistence-filesystem.dot +18 -11
  33. data/documentation/diagrams/dot/pwn-ai-feedback-learning-loop.dot +19 -4
  34. data/documentation/diagrams/dot/reinforcement-learning.dot +102 -0
  35. data/documentation/diagrams/history-to-drivers.svg +6 -6
  36. data/documentation/diagrams/memory-skills-detailed.svg +233 -198
  37. data/documentation/diagrams/overall-pwn-architecture.svg +168 -168
  38. data/documentation/diagrams/persistence-filesystem.svg +212 -136
  39. data/documentation/diagrams/pwn-ai-feedback-learning-loop.svg +386 -283
  40. data/documentation/diagrams/reinforcement-learning.svg +392 -0
  41. data/documentation/pwn-REPL.md +33 -4
  42. data/documentation/pwn-ai-Agent.md +42 -30
  43. data/lib/pwn/ai/agent/reflect.rb +16 -5
  44. data/lib/pwn/ai/red_team/excessive_agency.rb +89 -0
  45. data/lib/pwn/ai/red_team/insecure_output_handling.rb +90 -0
  46. data/lib/pwn/ai/red_team/jailbreak.rb +90 -0
  47. data/lib/pwn/ai/red_team/model_denial_of_service.rb +89 -0
  48. data/lib/pwn/ai/red_team/overreliance.rb +89 -0
  49. data/lib/pwn/ai/red_team/payload_splitting.rb +89 -0
  50. data/lib/pwn/ai/red_team/prompt_injection.rb +89 -0
  51. data/lib/pwn/ai/red_team/sensitive_information_disclosure.rb +89 -0
  52. data/lib/pwn/ai/red_team/system_prompt_extraction.rb +89 -0
  53. data/lib/pwn/ai/red_team/test_case_engine.rb +436 -0
  54. data/lib/pwn/ai/red_team/token_smuggling.rb +89 -0
  55. data/lib/pwn/ai/red_team.rb +45 -0
  56. data/lib/pwn/ai.rb +1 -0
  57. data/lib/pwn/config.rb +2 -0
  58. data/lib/pwn/plugins/repl.rb +78 -15
  59. data/lib/pwn/reports/ai_red_team.rb +428 -0
  60. data/lib/pwn/reports.rb +1 -0
  61. data/lib/pwn/setup.rb +193 -7
  62. data/lib/pwn/version.rb +1 -1
  63. data/packer/provisioners/pwn.sh +2 -2
  64. data/pwn.gemspec +20 -0
  65. data/spec/lib/pwn/ai/red_team/excessive_agency_spec.rb +25 -0
  66. data/spec/lib/pwn/ai/red_team/insecure_output_handling_spec.rb +25 -0
  67. data/spec/lib/pwn/ai/red_team/jailbreak_spec.rb +25 -0
  68. data/spec/lib/pwn/ai/red_team/model_denial_of_service_spec.rb +25 -0
  69. data/spec/lib/pwn/ai/red_team/overreliance_spec.rb +25 -0
  70. data/spec/lib/pwn/ai/red_team/payload_splitting_spec.rb +25 -0
  71. data/spec/lib/pwn/ai/red_team/prompt_injection_spec.rb +25 -0
  72. data/spec/lib/pwn/ai/red_team/sensitive_information_disclosure_spec.rb +25 -0
  73. data/spec/lib/pwn/ai/red_team/system_prompt_extraction_spec.rb +25 -0
  74. data/spec/lib/pwn/ai/red_team/test_case_engine_spec.rb +20 -0
  75. data/spec/lib/pwn/ai/red_team/token_smuggling_spec.rb +25 -0
  76. data/spec/lib/pwn/ai/red_team_spec.rb +15 -0
  77. data/spec/lib/pwn/reports/ai_red_team_spec.rb +15 -0
  78. data/third_party/pwn_rdoc.jsonl +57 -1
  79. data/third_party/terminator/pwn_shift_enter.py +137 -0
  80. metadata +34 -45
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 41a8a5c5d750508d4f3904d7a05151719e2c86fa4cf20001a3aab0985910963d
4
- data.tar.gz: 7af0757b53bdfa6c97d86a9415a2cbf41ca9447b3f9e438b95b2424f5d835cbf
3
+ metadata.gz: c889fade648cffc3bfe73e8a168b4e5353f3eb1fe652fa1b1839f9733c630bc8
4
+ data.tar.gz: c02957f5bc40cb4d8a3dc18d5c078540f5395118ade25df55379c6399c264d03
5
5
  SHA512:
6
- metadata.gz: 8053f31ef3138368e50c1b6920fa7804945f508daabc31191ba2a9578f3c31f7e6629e1ca901a409ec82e4cefdf3a824fa48bcfe4fdcd8ab4a1a9da0f168e1da
7
- data.tar.gz: 592bfb24c2c2a610813fcd5b8431478d4774ef312405f446393db9cbb305c2c223b129a0714b9b464adc9976e682b1754a4e5d760d0ca28b00ba99778df21d7a
6
+ metadata.gz: 97e57a81e839aaafcd83921d258ab2a95d9b7671120ef9c72a0df742c2ddfd4a84bb2d92a1b5fc426979910aea82e1b192226e1dfaddac218a057791ca892012
7
+ data.tar.gz: 1d89d4153ec4cd0b1604f2a8e4a735d00606d45111f9ad1db92b302968a510fbedfd6a588022ab1120fac4ed9413e7aac3e0694b6cd4200e65cfcf162ed2375e
@@ -84,7 +84,12 @@ jobs:
84
84
  ruby: dnf install -y ruby ruby-devel redhat-rpm-config gcc gcc-c++ make git
85
85
  - image: archlinux:latest
86
86
  pm: pacman
87
- ruby: pacman -Sy --noconfirm ruby base-devel git
87
+ # ruby-stdlib/ruby-bundled-gems: Arch splits erb/etc. out of the
88
+ # base `ruby` package; sed: Arch's /etc/gemrc defaults to
89
+ # `--user-install` which puts pwn/rspec binstubs off PATH.
90
+ ruby: >-
91
+ pacman -Sy --noconfirm ruby ruby-stdlib ruby-bundled-gems rubygems base-devel git &&
92
+ { sed -i '/--user-install/d' /etc/gemrc || true; }
88
93
  env:
89
94
  DEBIAN_FRONTEND: noninteractive
90
95
  PWN_FRESH_INSTALL: '1'
@@ -117,6 +122,13 @@ jobs:
117
122
  gem install --no-document rspec
118
123
  ruby -r pwn -e 'puts "pwn #{PWN::VERSION} ruby #{RUBY_VERSION} #{RUBY_PLATFORM}"'
119
124
 
125
+ - name: expose gem binstubs on PATH
126
+ # Distros disagree on where `gem install` writes executables (system
127
+ # bindir on apt/dnf, ~/.local/share/gem/.../bin on Arch's default
128
+ # --user-install). Put both on PATH so `pwn` / `rspec` resolve on
129
+ # every leg without hard-coding per-distro paths.
130
+ run: ruby -e 'puts Gem.bindir; puts File.join(Gem.user_dir, "bin")' >> "$GITHUB_PATH"
131
+
120
132
  - name: dry-run — every package name resolves for this distro
121
133
  run: pwn setup --profile full --dry-run --yes
122
134
 
@@ -0,0 +1,150 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'htmlentities'
5
+ require 'pwn'
6
+
7
+ opts = PWN::Env[:driver_opts]
8
+ PWN::Driver::Parser.new do |options|
9
+ options.on('-eENGINE', '--target-engine=ENGINE', '<Required - AI Engine Under Test (openai|anthropic|grok|gemini|ollama)>') do |e|
10
+ opts[:target_engine] = e
11
+ end
12
+
13
+ options.on('-mMODEL', '--target-model=MODEL', '<Optional - Specific Model on the Target Engine (Defaults to engine default)>') do |m|
14
+ opts[:target_model] = m
15
+ end
16
+
17
+ options.on('-rROLE', '--system-role=ROLE', '<Optional - System Prompt Applied to the Target for Every Payload>') do |r|
18
+ opts[:system_role_content] = r
19
+ end
20
+
21
+ options.on('-dDIR', '--dir-path=DIR', '<Optional - Report Output Directory (Defaults to ".")>') do |d|
22
+ opts[:dir_path] = d
23
+ end
24
+
25
+ options.on('-tTHREADS', '--max-threads=THREADS', '<Optional # Test Cases to Run Simultaneously (Default 5)>') do |t|
26
+ opts[:max_threads] = t
27
+ end
28
+
29
+ options.on('-TCASE', '--test-cases=CASE', '<Optional Comma-Delimited Test Cases to Invoke (-l for List)>') do |c|
30
+ opts[:chosen_test_cases] = c
31
+ end
32
+
33
+ options.on('-l', '--[no-]list-test-cases', '<Optional List Available Test Cases to Invoke and Exit>') do |l|
34
+ opts[:list_test_cases] = l
35
+ end
36
+
37
+ options.on('-nREPORTNAME', '--report-name=REPORTNAME', '<Optional Report Name (Defaults to, "<engine>-<model>-<timestamp>")>') do |n|
38
+ opts[:report_name] = n
39
+ end
40
+
41
+ options.on('-s', '--[no-]start-reporting-server', '<Optional - Start Simple HTTP Server for Reporting>') do |s|
42
+ opts[:start_reporting_server] = s
43
+ end
44
+ end.parse!
45
+
46
+ begin
47
+ timestamp = Time.now.strftime('%Y-%m-%d_%H:%M:%S%z')
48
+
49
+ pwn_env_path = opts[:pwn_env_path]
50
+ pwn_dec_path = opts[:pwn_dec_path]
51
+
52
+ pwn_provider = 'ruby-gem'
53
+ pwn_provider = ENV.fetch('PWN_PROVIDER') if ENV.keys.any? { |s| s == 'PWN_PROVIDER' }
54
+
55
+ green = "\e[32m"
56
+ end_of_color = "\e[0m"
57
+
58
+ dir_path = opts[:dir_path] ||= '.'
59
+
60
+ target_engine = opts[:target_engine]
61
+ target_model = opts[:target_model]
62
+ system_role_content = opts[:system_role_content]
63
+
64
+ max_threads = opts[:max_threads]
65
+ max_threads ||= 5
66
+
67
+ chosen_test_cases = opts[:chosen_test_cases]
68
+ list_test_cases = opts[:list_test_cases]
69
+
70
+ report_name = opts[:report_name]
71
+ report_name ||= "#{target_engine}-#{target_model || 'default'}-#{timestamp}"
72
+
73
+ start_reporting_server = opts[:start_reporting_server]
74
+
75
+ # Define Test Cases to Run & Start Thread Pool
76
+ if chosen_test_cases && !list_test_cases
77
+ test_cases = chosen_test_cases.to_s.scrub.chomp.strip.delete("\s").split(',').map(&:to_sym)
78
+ else
79
+ test_cases = %i[
80
+ ExcessiveAgency
81
+ InsecureOutputHandling
82
+ Jailbreak
83
+ ModelDenialOfService
84
+ Overreliance
85
+ PayloadSplitting
86
+ PromptInjection
87
+ SensitiveInformationDisclosure
88
+ SystemPromptExtraction
89
+ TokenSmuggling
90
+ ].sort.uniq
91
+ end
92
+
93
+ if list_test_cases
94
+ test_cases.each { |tc| puts "#{green}#{tc}#{end_of_color}" }
95
+ exit
96
+ end
97
+
98
+ raise "ERROR: Invalid Directory #{dir_path}" unless File.directory?(dir_path)
99
+
100
+ results_hash = {
101
+ report_name: HTMLEntities.new.encode(
102
+ report_name.to_s.scrub.strip.chomp
103
+ ),
104
+ data: []
105
+ }
106
+
107
+ mutex = Mutex.new
108
+
109
+ PWN::Plugins::ThreadPool.fill(
110
+ enumerable_array: test_cases,
111
+ max_threads: max_threads
112
+ ) do |test_case|
113
+ rt_arr = PWN::AI::RedTeam.const_get(
114
+ test_case.to_s.scrub
115
+ ).scan(
116
+ target_engine: target_engine,
117
+ target_model: target_model,
118
+ system_role_content: system_role_content
119
+ )
120
+
121
+ rt_arr.each { |hash_line| mutex.synchronize { results_hash[:data].push(hash_line) } }
122
+ end
123
+
124
+ # Generate HTML Report
125
+ print "#{File.basename($PROGRAM_NAME)} Generating Report..."
126
+ PWN::Reports::AIRedTeam.generate(
127
+ dir_path: dir_path,
128
+ results_hash: results_hash,
129
+ report_name: report_name
130
+ )
131
+ puts 'complete.'
132
+
133
+ # Start Simple HTTP Server (If Requested)
134
+ if start_reporting_server
135
+ listen_ip = '127.0.0.1'
136
+ listen_ip = '0.0.0.0' if pwn_provider == 'docker'
137
+ listen_port = PWN::Plugins::Sock.get_random_unused_port.to_s
138
+ puts "For Scan Results Navigate to: http://127.0.0.1:#{listen_port}/#{report_name}.html"
139
+
140
+ system(
141
+ 'pwn_simple_http_server',
142
+ '--bind-ip',
143
+ listen_ip,
144
+ '--port',
145
+ listen_port
146
+ )
147
+ end
148
+ rescue SystemExit, Interrupt
149
+ puts "\nGoodbye."
150
+ end
data/bin/pwn_setup CHANGED
@@ -44,6 +44,12 @@ pwn_driver = PWN::Driver::Parser.new do |options|
44
44
  opts[:yes] = o
45
45
  end
46
46
 
47
+ options.on('-t', '--terminal',
48
+ '<Optional - Opt-in SHIFT+ENTER multi-line support: prints ~/.tmux.conf lines and, ' \
49
+ 'under Terminator, installs the PWNShiftEnter GTK plugin (with confirmation)>') do |o|
50
+ opts[:terminal] = o
51
+ end
52
+
47
53
  options.on('-n', '--dry-run',
48
54
  '<Optional - Print the commands that would run, do not execute>') do |o|
49
55
  opts[:dry_run] = o
@@ -61,14 +67,22 @@ begin
61
67
  dry_run: opts[:dry_run]
62
68
  )
63
69
  exit 1 unless r && r[:after] && r[:after][:incompatible].empty?
64
- elsif opts[:deps] || opts[:profile]
70
+ elsif opts[:terminal]
71
+ PWN::Setup.terminal(
72
+ yes: opts[:yes],
73
+ dry_run: opts[:dry_run]
74
+ )
75
+ elsif (opts[:deps] || opts[:profile]) && !opts[:check]
65
76
  PWN::Setup.deps(
66
77
  profile: opts[:profile],
67
78
  yes: opts[:yes],
68
79
  dry_run: opts[:dry_run]
69
80
  )
70
81
  else
71
- r = PWN::Setup.check
82
+ # `pwn setup` → doctor gate on EVERYTHING
83
+ # `pwn setup --check` → same
84
+ # `pwn setup --check --profile net` → gate ONLY on the :net profile
85
+ r = PWN::Setup.check(profile: opts[:profile])
72
86
  exit 1 unless r[:ok]
73
87
  end
74
88
  rescue Interrupt
data/build_gem.sh CHANGED
@@ -35,6 +35,9 @@ if [[ $old_ruby_version == $new_ruby_version ]]; then
35
35
  rvmsudo /bin/bash --login -c "cd ${pwn_root} && bundle exec rake rerdoc"
36
36
  echo "Invoking bundle-audit Gemfile Scanner..."
37
37
  rvmsudo /bin/bash --login -c "cd ${pwn_root} && bundle exec bundle-audit"
38
+ # Restore ownership of artifacts (rdoc/, pkg/, Gemfile.lock, etc.) generated
39
+ # under rvmsudo above so a subsequent unprivileged `rake` / `git` can operate.
40
+ sudo chown -R $USER:$USER "$pwn_root"
38
41
  else
39
42
  cd $pwn_root && ./upgrade_ruby.sh $new_ruby_version $old_ruby_version
40
43
  fi
@@ -6,21 +6,25 @@ toolsets; the JSON-Schema for each tool is what the model actually sees.
6
6
 
7
7
  ![Tool registry](diagrams/agent-tool-registry.svg)
8
8
 
9
- ## Toolsets → Tools (10 toolsets · 61 tools)
9
+ ## Toolsets → Tools (10 toolsets · 71 tools)
10
10
 
11
11
  | Toolset | Tools | Backed by |
12
12
  |---|---|---|
13
13
  | `terminal` | `shell` | `Open3.capture3` on the host |
14
14
  | `pwn` | `pwn_eval` | `TOPLEVEL_BINDING.eval` in the live REPL process |
15
15
  | `memory` | `memory_remember` · `memory_recall` · `memory_forget` · `memory_clear` | `PWN::Memory` → `~/.pwn/memory.json` |
16
- | `skills` | `skill_list` · `skill_view` · `skill_create` · `skill_add_reference` · `skill_delete` · `skill_migrate_legacy` | `~/.pwn/skills/<name>/SKILL.md` (agentskills.io; legacy flat `*.md` still read) |
16
+ | `skills` | `skill_list` · `skill_view` · `skill_create` · `skill_add_reference` · `skill_delete` · `skill_migrate_legacy` | `~/.pwn/skills/<name>/SKILL.md` (**[agentskills.io](https://agentskills.io) spec**; legacy flat `*.md` auto-migrated) |
17
17
  | `sessions` | `sessions_list` · `sessions_view` · `sessions_current` · `sessions_delete` · `sessions_stats` | `PWN::Sessions` → `~/.pwn/sessions/` |
18
- | `learning` | `learning_note_outcome` · `learning_reflect` · `learning_distill_skill` · `learning_stats` · `learning_outcomes` · `learning_consolidate` · `learning_reset` · `learning_auto_introspect_toggle` · `learning_purge_noise` · **`mistakes_list`** · **`mistakes_record`** · **`mistakes_resolve`** · **`mistakes_reset`** · **`reward_judge`** · **`reward_prm`** · **`reward_sentinel`** · **`reward_preferences`** · **`reward_export_dpo`** · **`curriculum_practice`** · **`curriculum_train`** · **`curriculum_hindsight`** | `PWN::AI::Agent::Learning` + `Mistakes` + `Reward` + `Curriculum` → `~/.pwn/learning.jsonl` + `~/.pwn/mistakes.json` + `~/.pwn/preferences.jsonl` + `~/.pwn/curriculum/` |
18
+ | `learning` | `learning_note_outcome` · `learning_reflect` · `learning_distill_skill` · `learning_stats` · `learning_outcomes` · `learning_consolidate` · `learning_reset` · `learning_auto_introspect_toggle` · **`mistakes_list`** · **`mistakes_record`** · **`mistakes_resolve`** · **`mistakes_reset`** · **`reward_judge`** · **`reward_prm`** · **`reward_sentinel`** · **`reward_preferences`** · **`reward_export_dpo`** · **`curriculum_practice`** · **`curriculum_train`** · **`curriculum_hindsight`** · **`learning_purge_noise`** | `PWN::AI::Agent::Learning` + `Mistakes` + `Reward` + `Curriculum` → `~/.pwn/learning.jsonl` + `~/.pwn/mistakes.json` + `~/.pwn/preferences.jsonl` + `~/.pwn/curriculum/` + `~/.pwn/finetune/` |
19
19
  | `metrics` | `metrics_summary` · `metrics_reset` | `PWN::AI::Agent::Metrics` → `~/.pwn/metrics.json` |
20
- | `extrospection` | `extro_snapshot` · `extro_drift` · `extro_observe` · `extro_observations` · `extro_intel` · **`extro_watch`** · **`extro_verify`** · **`extro_rf_tune`** · **`extro_osint`** · **`extro_serial`** · **`extro_telecomm`** · **`extro_packet`** · **`extro_vision`** · **`extro_voice`** · `extro_correlate` · `extro_stats` · `extro_reset` · `extro_auto_toggle` | `PWN::AI::Agent::Extrospection` (+ Serial/Packet/OCR/Voice/BareSIP/TransparentBrowser) → `~/.pwn/extrospection.json` |
20
+ | `extrospection` | `extro_snapshot` · `extro_drift` · `extro_observe` · `extro_observations` · `extro_intel` · **`extro_watch`** · **`extro_verify`** · **`extro_rf_tune`** · **`extro_osint`** · **`extro_serial`** · **`extro_telecomm`** · **`extro_packet`** · **`extro_vision`** · **`extro_voice`** · `extro_correlate` · `extro_stats` · `extro_reset` · `extro_auto_toggle` | `PWN::AI::Agent::Extrospection` (+ Serial/Packet/OCR/Voice/BareSIP/TransparentBrowser/GQRX) → `~/.pwn/extrospection.json` |
21
21
  | `cron` | `cron_list` · `cron_create` · `cron_run` · `cron_enable` · `cron_disable` · `cron_remove` | `PWN::Cron` → `~/.pwn/cron/jobs.yml` |
22
22
  | `swarm` | `agent_list` · `agent_spawn` · `agent_ask` · `agent_debate` · `agent_broadcast` · `swarm_bus` · `swarm_list` | `PWN::AI::Agent::Swarm` → `~/.pwn/agents.yml` + `~/.pwn/swarm/` |
23
23
 
24
+ The `learning` toolset is deliberately fat: **Mistakes** (negative feedback),
25
+ **Reward** (ORM/PRM/sentinel/DPO ledger) and **Curriculum** (self-play, HER,
26
+ regression-gated LoRA) are all facets of the same self-improvement loop -
27
+ see [Reinforcement Learning](Reinforcement-Learning.md).
24
28
 
25
29
  ## Dynamic tool-set slimming (`ai.agent.tool_router`)
26
30
 
@@ -41,6 +45,8 @@ CORE_TOOLS = shell · pwn_eval · memory_remember · memory_recall
41
45
  ```ruby
42
46
  PWN::AI::Agent::Registry.definitions(relevance: 'nmap sweep 10.0.0.0/8', top_k: 10)
43
47
  PWN::AI::Agent::Registry.rank(query: 'run a shell command') # inspect ranking
48
+ PWN::AI::Agent::Registry.toolsets # → the 10 names above
49
+ PWN::AI::Agent::Registry.all.count # → 71
44
50
  ```
45
51
 
46
52
  Frontier engines leave `tool_router` off and receive the full set.
@@ -75,6 +81,7 @@ recon:
75
81
  engine: ollama
76
82
  ```
77
83
 
78
- **See also:** [pwn-ai Agent](pwn-ai-Agent.md) · [Mistakes](Mistakes.md) · [Swarm](Swarm.md)
84
+ **See also:** [pwn-ai Agent](pwn-ai-Agent.md) · [Mistakes](Mistakes.md) ·
85
+ [Reinforcement Learning](Reinforcement-Learning.md) · [Swarm](Swarm.md)
79
86
 
80
87
  [← Home](Home.md)
@@ -1,47 +1,52 @@
1
1
  # CLI Drivers - `bin/pwn_*`
2
2
 
3
- 53 headless executables, each a thin `OptionParser` wrapper over one plugin
4
- (or one workflow). They exist so CI/CD can call PWN without a REPL or an LLM.
3
+ 53 headless executables (52 `pwn_*` + `pwn`), each a thin `OptionParser`
4
+ wrapper over one plugin (or one workflow). They exist so CI/CD can call PWN
5
+ without a REPL or an LLM.
5
6
 
6
7
  ![Driver anatomy](diagrams/driver-framework.svg)
7
8
 
8
9
  ## Full list
9
10
 
10
11
  ```text
11
- pwn pwn_jenkins_thinBackup_aws_s3
12
- pwn_android_war_dialer pwn_jenkins_update_plugins
13
- pwn_autoinc_version pwn_jenkins_useradd
14
- pwn_aws_describe_resources pwn_mail_agent
15
- pwn_bdba_groups pwn_msf_postgres_login
16
- pwn_bdba_scan pwn_nessus_cloud_scan_crud
17
- pwn_burp_suite_pro_active_rest_api_scan pwn_nessus_cloud_vulnscan
18
- pwn_burp_suite_pro_active_scan pwn_nexpose
19
- pwn_char_base64_encoding pwn_nmap_discover_tcp_udp
20
- pwn_char_dec_encoding pwn_openvas_vulnscan
21
- pwn_char_hex_escaped_encoding pwn_pastebin_sample_filter
22
- pwn_char_html_entity_encoding pwn_phone
23
- pwn_char_unicode_escaped_encoding pwn_rdoc_to_jsonl
24
- pwn_char_url_encoding pwn_sast
25
- pwn_crt_sh pwn_serial_check_voicemail
26
- pwn_defectdojo_engagement_create pwn_serial_msr206
27
- pwn_defectdojo_importscan pwn_serial_qualcomm_commands
28
- pwn_defectdojo_reimportscan pwn_serial_son_micro_sm132_rfid
29
- pwn_diff_csv_files_w_column_exclude pwn_setup
30
- pwn_domain_reversewhois pwn_shodan_graphql_introspection
31
- pwn_fuzz_net_app_proto pwn_shodan_search
32
- pwn_gqrx_scanner pwn_simple_http_server
33
- pwn_jenkins_create_job pwn_web_cache_deception
34
- pwn_jenkins_create_view pwn_www_checkip
35
- pwn_jenkins_install_plugin pwn_www_uri_buster
12
+ pwn pwn_mail_agent
13
+ pwn_android_war_dialer pwn_msf_postgres_login
14
+ pwn_autoinc_version pwn_nessus_cloud_scan_crud
15
+ pwn_aws_describe_resources pwn_nessus_cloud_vulnscan
16
+ pwn_bdba_groups pwn_nexpose
17
+ pwn_bdba_scan pwn_nmap_discover_tcp_udp
18
+ pwn_burp_suite_pro_active_rest_api_scan pwn_openvas_vulnscan
19
+ pwn_burp_suite_pro_active_scan pwn_pastebin_sample_filter
20
+ pwn_char_base64_encoding pwn_phone
21
+ pwn_char_dec_encoding pwn_rdoc_to_jsonl
22
+ pwn_char_hex_escaped_encoding pwn_sast
23
+ pwn_char_html_entity_encoding pwn_serial_check_voicemail
24
+ pwn_char_unicode_escaped_encoding pwn_serial_msr206
25
+ pwn_char_url_encoding pwn_serial_qualcomm_commands
26
+ pwn_crt_sh pwn_serial_son_micro_sm132_rfid
27
+ pwn_defectdojo_engagement_create pwn_setup
28
+ pwn_defectdojo_importscan pwn_shodan_graphql_introspection
29
+ pwn_defectdojo_reimportscan pwn_shodan_search
30
+ pwn_diff_csv_files_w_column_exclude pwn_simple_http_server
31
+ pwn_domain_reversewhois pwn_web_cache_deception
32
+ pwn_fuzz_net_app_proto pwn_www_checkip
33
+ pwn_gqrx_scanner pwn_www_uri_buster
34
+ pwn_jenkins_create_job pwn_xss_dom_vectors
35
+ pwn_jenkins_create_view pwn_zaproxy_active_rest_api_scan
36
+ pwn_jenkins_install_plugin pwn_zaproxy_active_scan
37
+ pwn_jenkins_thinBackup_aws_s3
38
+ pwn_jenkins_update_plugins
39
+ pwn_jenkins_useradd
36
40
  ```
37
41
 
38
42
  Run any with `--help` for its flags.
39
43
 
40
- ## `pwn_setup` - post-install doctor & capability provisioner
44
+ ## `pwn_setup` - post-install doctor / provisioner / state migrator
41
45
 
42
46
  The one driver that isn't a plugin wrapper. It grows a bare `gem install pwn`
43
47
  into a fully-armed host by installing OS headers / external tools for whatever
44
- capability profile you ask for. Also reachable as `pwn setup` and
48
+ capability profile you ask for, **and** verifies/repairs every persisted
49
+ `~/.pwn` state file after an upgrade. Also reachable as `pwn setup` and
45
50
  `pwn --setup[=PROFILE]`.
46
51
 
47
52
  ```bash
@@ -49,10 +54,11 @@ pwn_setup # read-only doctor; exit 1 if degraded
49
54
  pwn_setup --list-profiles
50
55
  pwn_setup --profile web --yes # CI-friendly, non-interactive
51
56
  pwn_setup --deps --dry-run # print the apt/dnf/pacman/brew/port commands only
57
+ pwn_setup --migrate --fix # ~/.pwn state doctor + autofix (PWN::Migrate)
52
58
  ```
53
59
 
54
- See [Installation](Installation.md) for the full profile table and
55
- `PWN::Setup` API.
60
+ See [Installation](Installation.md) for the full profile table, the
61
+ `PWN::Setup` API and the `PWN::Migrate` state-file registry.
56
62
 
57
63
  ## Typical CI usage
58
64
 
@@ -20,6 +20,9 @@ generates the decryptor.
20
20
  > [doctor](Installation.md#pwn-setup--the-post-install-doctor--provisioner)
21
21
  > reports whether `~/.pwn/`, `pwn.yaml`, its decryptor, and an AI-engine key
22
22
  > are present, and exits non-zero for CI if any are missing.
23
+ > After `gem update pwn`, run `pwn setup --migrate --fix` — `PWN::Migrate`
24
+ > deep-merges any keys the new `PWN::Config.env_template` added into your
25
+ > encrypted `pwn.yaml` **without overwriting your values**.
23
26
 
24
27
  ---
25
28
 
@@ -263,6 +266,11 @@ PWN::Config.refresh_env
263
266
  | `ai.agent.plan_first` | Boolean \| `nil` | `nil` (auto: `true` when `ai.active == ollama`) | `PWN::AI::Agent::Loop.plan_first` | Plan-then-act pre-pass: the model must emit a numbered tool plan (as an assistant message) *before* it may dispatch anything. Cheap chain-of-thought scaffolding for local models. |
264
267
  | `ai.agent.tool_router` | Boolean | `false` | `PWN::AI::Agent::Registry.definitions` | Dynamic tool-set slimming: expose only `Registry::CORE_TOOLS` + the top-K keyword-relevant schemas for *this* request. Ties break on historical `Metrics` success rate so the router itself is a learned component. |
265
268
  | `ai.agent.escalation_persona` | String \| `nil` | `nil` | `PWN::AI::Agent::Loop.escalate` → `Swarm.ask` | Circuit-breaker: once a local model accumulates ≥ `Loop::ESCALATE_AFTER_FAILS` in-turn failures, ask this Swarm persona for a 3-line corrective hint (injected as a synthetic tool result). The local model still authors the final answer so Learning/Metrics stay attributed. |
269
+ | `ai.agent.critic` | Boolean | `false` | `PWN::AI::Agent::Curriculum.critic` (S3) | Tool-armed constitutional self-critic reviews (and may `shell`/`extro_verify`) every final answer before it is returned. |
270
+ | `ai.agent.red_team_plan` | Boolean | `false` | `PWN::AI::Agent::Curriculum.red_team_plan` (S4) | Adversarial review of the `plan_first` numbered plan, grounded in Metrics/Mistakes/`extro_drift` telemetry, before the first dispatch. |
271
+ | `ai.agent.counterfactual` | Boolean | `false` | `PWN::AI::Agent::Curriculum.counterfactual` (S2) | On `[REPEATING]`, fork an alt-persona branch, judge both, and record the `(loser, winner)` DPO preference pair. |
272
+ | `ai.agent.hindsight` | Boolean | `true` | `PWN::AI::Agent::Curriculum.hindsight` (C3) | Hindsight Experience Replay — relabel a failed trajectory as `success:true` for whatever it *did* accomplish. Free positive samples from failures. |
273
+ | `ai.agent.verify_as_reward` | Boolean | `false` | `PWN::AI::Agent::Reward.verify_as_reward` (E3) | Ground the LLM judge score by browser-verifying any checkable claim in the final via `extro_verify`; verdict caps/floors `Reward.judge`. |
266
274
  | `ai.agent.extrospection.web.anchors` | Array\<String\> | `DEFAULT_WEB_ANCHORS` | `PWN::AI::Agent::Extrospection.probe_web` | URLs the headless browser fingerprints on `extro_snapshot(sections:[:web])`. Alias: `web_anchors`. |
267
275
  | `ai.agent.extrospection.web.proxy` | String | - | `Extrospection.probe_web` / `.verify` / `.watch` | Upstream proxy for `PWN::Plugins::TransparentBrowser` (e.g. `tor`, `http://127.0.0.1:8080`). |
268
276
  | `ai.agent.extrospection.web.max_anchors` | Integer | `8` | `Extrospection.probe_web` | Cap on anchors rendered per snapshot. |
@@ -371,9 +379,14 @@ agent system prompt.
371
379
 
372
380
  `pwn.yaml` is the only file you edit; everything else is machine-written
373
381
  state. See **[Persistence](Persistence.md)** for the full map
374
- (`memory.json`, `memory.idx`, `learning.jsonl`, `mistakes.json`,
375
- `metrics.json`, `extrospection.json`, `sessions/`, `skills/`,
376
- `finetune/`, `cron/`, `agents.yml`, `swarm/`).
382
+ (`.schema`, `memory.json`, `memory.idx`, `learning.jsonl`,
383
+ `preferences.jsonl`, `mistakes.json`, `metrics.json`,
384
+ `reward_sentinel.json`, `extrospection.json`, `sessions/`,
385
+ `skills/<name>/SKILL.md`, `curriculum/`, `finetune/`, `cron/`,
386
+ `agents.yml`, `swarm/`, `backup/`, `quarantine/`).
387
+
388
+ `pwn setup --migrate` verifies (and `--fix` autorepairs) every
389
+ one of them against the running gem version.
377
390
 
378
391
  Multi-agent personas are **not** configured here - they live in
379
392
  `~/.pwn/agents.yml` and are managed with `agent_spawn` / `agent_list`
@@ -5,10 +5,11 @@
5
5
  ```text
6
6
  lib/pwn/ # all namespaces
7
7
  lib/pwn/setup.rb # PWN::Setup - doctor/provisioner data tables
8
+ lib/pwn/migrate.rb # PWN::Migrate - ~/.pwn state doctor / auto-migrator
8
9
  lib/pwn/plugins/ # 66 plugin modules
9
10
  lib/pwn/ai/agent/ # agent core
10
11
  lib/pwn/ai/agent/tools/ # LLM tool registrations
11
- bin/ # 53 pwn_* drivers (incl. pwn_setup)
12
+ bin/ # 52 pwn_* drivers + pwn (incl. pwn_setup)
12
13
  spec/ # RSpec (incl. conventions_spec)
13
14
  documentation/ # this wiki + diagrams
14
15
  ```
@@ -44,7 +45,13 @@ rake # rubocop + rspec - must be zero offenses
44
45
  set, reference it from `PWN::Setup::PROFILES`. That single edit makes
45
46
  `pwn setup` install it on every OS and every install path (gem, git,
46
47
  Docker, Packer, Vagrant, CI). **Do not** add a new bash provisioner.
47
- 7. Update [Plugins.md](Plugins.md) and, if it changes a data flow, the
48
+ 7. **If it persists a new file under `~/.pwn/`**, add **one entry** to
49
+ `PWN::Migrate::STATE_FILES` in `lib/pwn/migrate.rb` (owner, kind,
50
+ `:fix` strategy, shallow verifier). If the change breaks *existing*
51
+ files, bump `PWN::Migrate::SCHEMA_VERSION` and append an idempotent
52
+ lambda to `PWN::Migrate::MIGRATIONS`. `pwn setup --migrate --fix`
53
+ then heals every user's `~/.pwn` on upgrade.
54
+ 8. Update [Plugins.md](Plugins.md) and, if it changes a data flow, the
48
55
  relevant `.dot` in `documentation/diagrams/dot/` → `./build.sh`.
49
56
 
50
57
  ## Commit / release
@@ -24,6 +24,26 @@ invokes `PWN::Cron.run(<id>)` on schedule.
24
24
  | `cron_enable` / `cron_disable` | Toggle without deleting |
25
25
  | `cron_remove` | Delete from `jobs.yml` (does **not** scrub crontab - `crontab -e` yourself) |
26
26
 
27
+ ## Seeded self-improvement jobs (`PWN::Cron.install_defaults`)
28
+
29
+ `pwn setup --migrate` (schema `v1`) seeds two jobs into every fresh
30
+ `~/.pwn/cron/jobs.yml`:
31
+
32
+ | Name | Schedule | Ruby |
33
+ |---|---|---|
34
+ | `curriculum_practice_nightly` | `0 3 * * *` | `PWN::AI::Agent::Curriculum.practice(limit: 3)` |
35
+ | `curriculum_train_weekly` | `0 4 * * 0` | `PWN::AI::Agent::Curriculum.train_and_gate(dry_run: true)` |
36
+
37
+ The first practises the top unresolved `Mistakes` under `Reward.judge` and
38
+ auto-`resolve`s any it now solves; the second exports SFT + DPO datasets to
39
+ `~/.pwn/finetune/`, LoRA-trains a `pwn-vN+1` local model, replays the
40
+ `Mistakes.top` set on both, and only promotes the new adapter when it wins.
41
+ Set `dry_run: false` (via `pwn-ai-cron` or `cron_create`) once a local
42
+ trainer is installed. See [Reinforcement Learning](Reinforcement-Learning.md).
43
+
44
+ `cron_disable(id:)` turns either off; `install_defaults` is idempotent and
45
+ never overwrites a job you already have with the same name.
46
+
27
47
  ## Example
28
48
 
29
49
  ```ruby
@@ -57,6 +77,6 @@ yyyy-mm-dd]` so the injected MEMORY block stops calcifying into
57
77
  confidently-wrong priors - see [Extrospection § revalidate_memory](Extrospection.md).
58
78
 
59
79
  **See also:** [Sessions](Sessions.md) · [Extrospection](Extrospection.md) ·
60
- [CLI Drivers](CLI-Drivers.md)
80
+ [Reinforcement Learning](Reinforcement-Learning.md) · [CLI Drivers](CLI-Drivers.md)
61
81
 
62
82
  [← Home](Home.md)
@@ -1,6 +1,6 @@
1
1
  # PWN Data-Flow Diagrams
2
2
 
3
- 27 SVG diagrams, all rendered from Graphviz sources in
3
+ 28 SVG diagrams, all rendered from Graphviz sources in
4
4
  [`diagrams/dot/`](diagrams/dot/) with a single shared visual theme
5
5
  (see [`_THEME.md`](diagrams/dot/_THEME.md)). Rebuild everything with:
6
6
 
@@ -55,11 +55,15 @@ groups) so lines never criss-cross.
55
55
  [source](diagrams/dot/mistakes-negative-feedback.dot) · doc: [Mistakes](Mistakes.md)
56
56
  ![mistakes-negative-feedback](diagrams/mistakes-negative-feedback.svg)
57
57
 
58
+ ### Reinforcement Learning - Reward + Curriculum
59
+ [source](diagrams/dot/reinforcement-learning.dot) · doc: [Reinforcement Learning](Reinforcement-Learning.md)
60
+ ![reinforcement-learning](diagrams/reinforcement-learning.svg)
61
+
58
62
  ### Multi-Provider LLM Integration
59
63
  [source](diagrams/dot/ai-integration-tool-calling.dot) · doc: [AI Integration](AI-Integration.md)
60
64
  ![ai-integration-tool-calling](diagrams/ai-integration-tool-calling.svg)
61
65
 
62
- ### Agent Tool Registry (10 toolsets · 61 tools)
66
+ ### Agent Tool Registry (10 toolsets · 71 tools)
63
67
  [source](diagrams/dot/agent-tool-registry.dot) · doc: [Agent Tool Registry](Agent-Tool-Registry.md)
64
68
  ![agent-tool-registry](diagrams/agent-tool-registry.svg)
65
69
 
@@ -43,7 +43,7 @@ puts result
43
43
  | Artifact | Made with | Consumed by |
44
44
  |---|---|---|
45
45
  | `bin/pwn_<name>` | template above | shell / CI |
46
- | `~/.pwn/skills/<name>.md` | `learning_distill_skill` | every future pwn-ai prompt |
46
+ | `~/.pwn/skills/<name>/SKILL.md` | `learning_distill_skill` | every future pwn-ai prompt |
47
47
  | `cron` job | `cron_create(ruby: '...')` | system crontab → unattended |
48
48
 
49
49
  **See also:** [CLI Drivers](CLI-Drivers.md) · [Cron](Cron.md) ·
@@ -14,9 +14,11 @@ $ pwn_nmap_discover_tcp_udp -t 10.0.0.0/24 -o out/ # headless driver
14
14
  $ pwn setup # doctor: which PWN:: capabilities are usable here?
15
15
  $ pwn setup --profile web # install what TransparentBrowser / Burp / ZAP need
16
16
  $ pwn setup --list-profiles # core · ai · web · net · db · sdr · vision · voice · exploit · hardware · full
17
+ $ pwn setup --migrate --fix # after `gem update pwn`: verify + autofix ~/.pwn state
17
18
  ```
18
19
 
19
- See [Installation](Installation.md) for every flag and the `PWN::Setup` API.
20
+ See [Installation](Installation.md) for every flag and the
21
+ `PWN::Setup` / `PWN::Migrate` API.
20
22
 
21
23
  ## Inside the REPL
22
24
 
@@ -25,6 +27,7 @@ PWN.help # top-level help
25
27
  PWN::Plugins.constants.sort # list all 66 plugins
26
28
  PWN::Plugins::NmapIt.help # per-plugin usage
27
29
  PWN::Setup.check # capability doctor from inside the REPL
30
+ PWN::Migrate.status # ~/.pwn state-file compatibility rows
28
31
  ls PWN::Plugins::BurpSuite # Pry: list methods
29
32
  show-source PWN::SAST::SQL.scan # Pry: read the code
30
33
  history # what you've typed → copy into a driver
@@ -36,11 +39,14 @@ history # what you've typed → copy into a driver
36
39
  |---|---|
37
40
  | `pwn-ai` | Enter the agent TUI (SHIFT+ENTER = newline, ENTER = submit) |
38
41
  | `pwn-asm` | Multi-line assembly ↔ opcode workbench |
42
+ | `pwn-mesh` | Meshtastic serial / MQTT client (Ruby ≥ 4.0) |
39
43
  | `pwn-vault` | Decrypt → edit `~/.pwn/pwn.yaml` in `$EDITOR` → re-encrypt |
40
44
  | `pwn-ai-memory` | Inspect / edit `~/.pwn/memory.json` |
41
45
  | `pwn-ai-sessions` | List / view / delete transcripts |
42
46
  | `pwn-ai-cron` | List / run scheduled jobs |
43
47
  | `pwn-ai-delegate` | Hand a task to a Swarm persona |
48
+ | `toggle-pwn-ai-debug` | Show/hide raw tool_calls JSON |
49
+ | `toggle-pwn-ai-speaks` | TTS every final answer on/off |
44
50
  | `welcome-banner` | Redraw a random `PWN::Banner` |
45
51
  | `toggle-pager` | Pry pager on/off |
46
52
 
@@ -20,7 +20,7 @@
20
20
  | [Installation](Installation.md) | `gem install pwn` → `pwn setup` doctor/provisioner · capability profiles · `--migrate` state doctor |
21
21
  | [General Usage](General-PWN-Usage.md) | Day-one cheat sheet |
22
22
  | [Configuration](Configuration.md) | `~/.pwn/pwn.yaml` (encrypted) - engines, keys, agent options · `pwn-vault` |
23
- | **[All Data-Flow Diagrams](Diagrams.md)** | **27 SVGs** in one scrollable page |
23
+ | **[All Data-Flow Diagrams](Diagrams.md)** | **28 SVGs** in one scrollable page |
24
24
 
25
25
  ## 🚪 Entry Points
26
26