solidity-argus 0.2.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/AGENTS.md +3 -3
  2. package/README.md +93 -37
  3. package/package.json +34 -7
  4. package/skills/INVENTORY.md +88 -57
  5. package/skills/README.md +26 -23
  6. package/skills/case-studies/beanstalk-governance/SKILL.md +52 -0
  7. package/skills/case-studies/bzx-flash-loan/SKILL.md +53 -0
  8. package/skills/case-studies/cream-finance/SKILL.md +52 -0
  9. package/skills/case-studies/curve-reentrancy/SKILL.md +52 -0
  10. package/skills/case-studies/dao-hack/SKILL.md +51 -0
  11. package/skills/case-studies/euler-finance/SKILL.md +52 -0
  12. package/skills/case-studies/harvest-finance/SKILL.md +52 -0
  13. package/skills/case-studies/level-finance/SKILL.md +51 -0
  14. package/skills/case-studies/mango-markets/SKILL.md +53 -0
  15. package/skills/case-studies/nomad-bridge/SKILL.md +51 -0
  16. package/skills/case-studies/parity-multisig/SKILL.md +55 -0
  17. package/skills/case-studies/poly-network/SKILL.md +51 -0
  18. package/skills/case-studies/rari-fuse/SKILL.md +51 -0
  19. package/skills/case-studies/ronin-bridge/SKILL.md +52 -0
  20. package/skills/case-studies/wormhole-bridge/SKILL.md +51 -0
  21. package/skills/manifests/smartbugs.json +1 -3
  22. package/skills/manifests/sunweb3sec.json +1 -3
  23. package/skills/vulnerability-patterns/access-control/SKILL.md +14 -0
  24. package/skills/vulnerability-patterns/arbitrary-storage-location/SKILL.md +13 -1
  25. package/skills/vulnerability-patterns/assert-violation/SKILL.md +8 -1
  26. package/skills/vulnerability-patterns/asserting-contract-from-code-size/SKILL.md +12 -1
  27. package/skills/vulnerability-patterns/authorization-txorigin/SKILL.md +2 -1
  28. package/skills/vulnerability-patterns/cross-chain-bridge-vulnerabilities/SKILL.md +217 -0
  29. package/skills/vulnerability-patterns/default-visibility/SKILL.md +13 -1
  30. package/skills/vulnerability-patterns/delegatecall-untrusted-callee/SKILL.md +2 -1
  31. package/skills/vulnerability-patterns/dos-gas-limit/SKILL.md +8 -1
  32. package/skills/vulnerability-patterns/dos-revert/SKILL.md +1 -0
  33. package/skills/vulnerability-patterns/erc4626-exchange-rate-manipulation/SKILL.md +64 -0
  34. package/skills/vulnerability-patterns/fee-on-transfer-tokens/SKILL.md +93 -0
  35. package/skills/vulnerability-patterns/flash-loan-attacks/SKILL.md +1 -0
  36. package/skills/vulnerability-patterns/floating-pragma/SKILL.md +8 -1
  37. package/skills/vulnerability-patterns/front-running-attacks/SKILL.md +209 -0
  38. package/skills/vulnerability-patterns/gas-optimization-patterns/SKILL.md +203 -0
  39. package/skills/vulnerability-patterns/governance-attacks/SKILL.md +208 -0
  40. package/skills/vulnerability-patterns/hash-collision/SKILL.md +8 -1
  41. package/skills/vulnerability-patterns/inadherence-to-standards/SKILL.md +12 -1
  42. package/skills/vulnerability-patterns/incorrect-constructor/SKILL.md +8 -1
  43. package/skills/vulnerability-patterns/incorrect-inheritance-order/SKILL.md +8 -1
  44. package/skills/vulnerability-patterns/insufficient-gas-griefing/SKILL.md +12 -1
  45. package/skills/vulnerability-patterns/lack-of-precision/SKILL.md +7 -1
  46. package/skills/vulnerability-patterns/logic-errors/SKILL.md +10 -0
  47. package/skills/vulnerability-patterns/missing-parameter-bounds/SKILL.md +44 -0
  48. package/skills/vulnerability-patterns/missing-protection-signature-replay/SKILL.md +17 -1
  49. package/skills/vulnerability-patterns/msgvalue-loop/SKILL.md +12 -1
  50. package/skills/vulnerability-patterns/off-by-one/SKILL.md +7 -1
  51. package/skills/vulnerability-patterns/oracle-manipulation/SKILL.md +9 -0
  52. package/skills/vulnerability-patterns/outdated-compiler-version/SKILL.md +8 -1
  53. package/skills/vulnerability-patterns/overflow-underflow/SKILL.md +1 -0
  54. package/skills/vulnerability-patterns/proxy-vulnerabilities/SKILL.md +209 -0
  55. package/skills/vulnerability-patterns/reentrancy/SKILL.md +9 -0
  56. package/skills/vulnerability-patterns/shadowing-state-variables/SKILL.md +8 -1
  57. package/skills/vulnerability-patterns/share-accounting-desynchronization/SKILL.md +44 -0
  58. package/skills/vulnerability-patterns/signature-malleability/SKILL.md +2 -1
  59. package/skills/vulnerability-patterns/stateful-parameter-update-drift/SKILL.md +44 -0
  60. package/skills/vulnerability-patterns/unbounded-return-data/SKILL.md +12 -1
  61. package/skills/vulnerability-patterns/unchecked-return-values/SKILL.md +2 -1
  62. package/skills/vulnerability-patterns/unencrypted-private-data-on-chain/SKILL.md +8 -1
  63. package/skills/vulnerability-patterns/unexpected-ecrecover-null-address/SKILL.md +8 -1
  64. package/skills/vulnerability-patterns/uninitialized-storage-pointer/SKILL.md +8 -1
  65. package/skills/vulnerability-patterns/unsafe-erc20-transfers/SKILL.md +132 -0
  66. package/skills/vulnerability-patterns/unsafe-low-level-call/SKILL.md +12 -1
  67. package/skills/vulnerability-patterns/unsecure-signatures/SKILL.md +12 -1
  68. package/skills/vulnerability-patterns/unsupported-opcodes/SKILL.md +11 -1
  69. package/skills/vulnerability-patterns/unused-variables/SKILL.md +8 -1
  70. package/skills/vulnerability-patterns/use-of-deprecated-functions/SKILL.md +8 -1
  71. package/skills/vulnerability-patterns/weak-sources-randomness/SKILL.md +8 -1
  72. package/skills/vulnerability-patterns/weird-tokens/SKILL.md +10 -0
  73. package/skills/vulnerability-patterns/zero-address-misconfiguration/SKILL.md +48 -0
  74. package/src/agents/argus-prompt.ts +34 -7
  75. package/src/agents/pythia-prompt.ts +13 -4
  76. package/src/agents/scribe-prompt.ts +20 -2
  77. package/src/agents/sentinel-prompt.ts +45 -5
  78. package/src/cli/cli-program.ts +29 -26
  79. package/src/cli/commands/check-skills.ts +135 -0
  80. package/src/cli/commands/doctor.ts +48 -26
  81. package/src/cli/commands/init.ts +5 -3
  82. package/src/cli/commands/install.ts +7 -5
  83. package/src/cli/commands/lint-skills.ts +16 -12
  84. package/src/cli/index.ts +5 -5
  85. package/src/cli/types.ts +3 -3
  86. package/src/config/index.ts +1 -1
  87. package/src/config/loader.ts +4 -6
  88. package/src/config/schema.ts +6 -5
  89. package/src/config/types.ts +2 -2
  90. package/src/constants/defaults.ts +2 -0
  91. package/src/create-hooks.ts +145 -34
  92. package/src/create-managers.ts +10 -8
  93. package/src/create-tools.ts +13 -9
  94. package/src/features/background-agent/background-manager.ts +93 -87
  95. package/src/features/background-agent/index.ts +1 -1
  96. package/src/features/context-monitor/context-monitor.ts +3 -3
  97. package/src/features/context-monitor/index.ts +2 -2
  98. package/src/features/error-recovery/session-recovery.ts +2 -4
  99. package/src/features/error-recovery/tool-error-recovery.ts +12 -7
  100. package/src/features/index.ts +5 -5
  101. package/src/features/persistent-state/audit-state-manager.ts +143 -60
  102. package/src/features/persistent-state/global-run-index.ts +38 -0
  103. package/src/features/persistent-state/index.ts +1 -1
  104. package/src/features/persistent-state/run-journal.ts +86 -0
  105. package/src/hooks/config-handler.ts +28 -11
  106. package/src/hooks/context-budget.ts +2 -5
  107. package/src/hooks/event-hook.ts +47 -23
  108. package/src/hooks/hook-system.ts +4 -4
  109. package/src/hooks/index.ts +5 -5
  110. package/src/hooks/knowledge-sync-hook.ts +18 -21
  111. package/src/hooks/recon-context-builder.ts +2 -2
  112. package/src/hooks/safe-create-hook.ts +6 -7
  113. package/src/hooks/system-prompt-hook.ts +18 -1
  114. package/src/hooks/tool-tracking-hook.ts +110 -51
  115. package/src/hooks/types.ts +2 -1
  116. package/src/index.ts +24 -37
  117. package/src/knowledge/retry.ts +22 -22
  118. package/src/knowledge/scvd-client.ts +88 -95
  119. package/src/knowledge/scvd-errors.ts +35 -35
  120. package/src/knowledge/scvd-index.ts +78 -80
  121. package/src/knowledge/scvd-sync.ts +106 -101
  122. package/src/managers/index.ts +1 -1
  123. package/src/managers/types.ts +19 -14
  124. package/src/plugin-interface.ts +7 -9
  125. package/src/shared/binary-utils.ts +44 -35
  126. package/src/shared/deep-merge.ts +55 -36
  127. package/src/shared/file-utils.ts +21 -19
  128. package/src/shared/index.ts +11 -5
  129. package/src/shared/jsonc-parser.ts +123 -28
  130. package/src/shared/logger.ts +16 -3
  131. package/src/shared/project-utils.ts +30 -0
  132. package/src/skills/analysis/cluster.ts +414 -0
  133. package/src/skills/analysis/gates.ts +227 -0
  134. package/src/skills/analysis/index.ts +33 -0
  135. package/src/skills/analysis/normalize.ts +217 -0
  136. package/src/skills/analysis/similarity.ts +224 -0
  137. package/src/skills/argus-skill-resolver.ts +17 -6
  138. package/src/skills/skill-schema.ts +11 -10
  139. package/src/solodit-lifecycle.ts +203 -0
  140. package/src/state/audit-state.ts +8 -8
  141. package/src/state/finding-store.ts +68 -55
  142. package/src/state/types.ts +88 -67
  143. package/src/tools/argus-skill-load-tool.ts +12 -7
  144. package/src/tools/contract-analyzer-tool.ts +142 -77
  145. package/src/tools/forge-coverage-tool.ts +226 -0
  146. package/src/tools/forge-fuzz-tool.ts +127 -127
  147. package/src/tools/forge-test-tool.ts +201 -158
  148. package/src/tools/gas-analysis-tool.ts +264 -0
  149. package/src/tools/pattern-checker-tool.ts +203 -191
  150. package/src/tools/pattern-loader.ts +5 -111
  151. package/src/tools/pattern-schema.ts +3 -0
  152. package/src/tools/proxy-detection-tool.ts +224 -0
  153. package/src/tools/report-generator-tool.ts +305 -206
  154. package/src/tools/slither-tool.ts +266 -218
  155. package/src/tools/solodit-search-tool.ts +235 -119
  156. package/src/tools/sync-knowledge-tool.ts +7 -11
  157. package/src/utils/audit-artifact-detector.ts +28 -29
  158. package/src/utils/dependency-scanner.ts +37 -37
  159. package/src/utils/project-detector.ts +111 -124
  160. package/src/utils/solidity-parser.ts +175 -75
  161. package/skills/patterns/access-control.yaml +0 -31
  162. package/skills/patterns/erc4626.yaml +0 -29
  163. package/skills/patterns/flash-loan.yaml +0 -20
  164. package/skills/patterns/oracle.yaml +0 -30
  165. package/skills/patterns/proxy.yaml +0 -30
  166. package/skills/patterns/reentrancy.yaml +0 -30
  167. package/skills/patterns/signature.yaml +0 -31
  168. package/src/hooks/event-hook-v2.ts +0 -99
  169. package/src/state/plugin-state.ts +0 -14
@@ -1,6 +1,16 @@
1
1
  ---
2
2
  name: weird-tokens
3
3
  description: Non-standard ERC20 behaviors, integration pitfalls, and token-handling safeguards.
4
+ pattern_category: token-standard
5
+ detection_rules:
6
+ - regex: 'IERC20\('
7
+ severity: Informational
8
+ confidence: Low
9
+ description: ERC20 integration point where non-standard token behavior may break assumptions
10
+ - regex: '\.approve\('
11
+ severity: Low
12
+ confidence: Low
13
+ description: approve usage requires allowance race and non-standard token handling checks
4
14
  ---
5
15
  <!-- Source: DeFiFoFum/fofum-solidity-skills (MIT) -->
6
16
 
@@ -0,0 +1,48 @@
1
+ ---
2
+ name: zero-address-misconfiguration
3
+ description: "Critical addresses are set to address(0), causing hard reverts, fund loss paths, or permanently broken flows."
4
+ category: vulnerability-pattern
5
+ pattern_category: access-control
6
+ source_url: "https://github.com/bailsec/BailSec"
7
+ source_license: "CC0"
8
+ imported_at: "2025-02-20T00:00:00Z"
9
+ detection_rules:
10
+ - regex: "(set|update|initialize|constructor).*(address|receiver|collector|team).*=\\s*address\\(0\\)"
11
+ severity: "High"
12
+ description: "Administrative path allows writing a critical address to zero"
13
+ - regex: "transfer\\(address\\(0\\)|safeTransfer\\(address\\(0\\)"
14
+ severity: "Medium"
15
+ description: "Outbound transfer path can target zero address after misconfiguration"
16
+ - regex: 'address\(0\)'
17
+ severity: Medium
18
+ confidence: Low
19
+ description: Reference to zero address — potential missing zero-address validation
20
+ ---
21
+ <!-- Source: BailSec audit reports (CC0) -->
22
+
23
+ # Zero Address Misconfiguration Vulnerabilities
24
+
25
+ ## Overview
26
+ Zero-address handling is an input validation and configuration integrity problem: critical system variables are set to `address(0)` even though downstream logic assumes a live recipient. In production this often appears in admin setters or constructor parameters for fee collectors, fallback receivers, team wallets, bridge modules, or reward sinks. The system usually works until one of these addresses is consumed by a transfer, mint, distribution, or callback path, then starts reverting in critical operations.
27
+
28
+ This pattern is dangerous because it can be triggered accidentally (operator error), by weak deployment scripts, or after key compromise. It is also commonly missed in reviews because the setter itself may look harmless while the breakage happens in unrelated functions.
29
+
30
+ ## Common Patterns
31
+ - Missing `require(newAddr != address(0))` in privileged setter functions.
32
+ - Constructor checks differ from setter checks, so unsafe values are allowed in one path.
33
+ - Protocol assumes a non-zero recipient in periodic distribution or epoch updates.
34
+ - Emergency plans rely on setting an address to zero, but no explicit pause-mode logic exists.
35
+
36
+ ## Detection Heuristics
37
+ - Trace every role-controlled address from write path to first transfer/mint usage.
38
+ - Flag any critical address that can be set to zero without explicit documented semantics.
39
+ - Check whether "zero means disabled" is consistently implemented across all read sites.
40
+ - Verify deployment scripts and upgrade initializers enforce non-zero invariants.
41
+
42
+ ## Examples from Audits
43
+ - Fee-aggregation routing where a primary aggregator could be set to zero, causing later fee forwarding to fail.
44
+ - Fallback distribution receiver settable to zero, leading weekly distribution flow to revert.
45
+ - Team emission address allowed to become zero, which can break epoch update and lock normal emissions.
46
+
47
+ ## Remediation
48
+ Use strict non-zero validation in constructors, initializers, and all mutating setters for critical addresses. If zero has a valid "disabled" meaning, encode that explicitly with a separate boolean mode and guarded control flow; do not overload zero as a hidden state. Add invariant tests that assert all transfer sinks remain valid after governance actions and upgrades. During operations, enforce config guards in runbooks and monitoring so zero-address writes are blocked or alerted before they reach production.
@@ -1,4 +1,3 @@
1
-
2
1
  export const ARGUS_PROMPT = `You are **Argus Panoptes**, the All-Seeing Guardian — an autonomous Solidity smart contract security auditor. You orchestrate a team of specialist subagents to conduct comprehensive security audits. Your mission is to identify vulnerabilities, logic flaws, and security risks in smart contracts with the precision and depth of a top-tier human auditor.
3
2
 
4
3
  ## IDENTITY & ROLE
@@ -23,6 +22,7 @@ Before analyzing code, understand the system.
23
22
  - Determine the "crown jewels" (e.g., user funds, admin privileges).
24
23
  - Map trust boundaries: Who is trusted? What external calls are made?
25
24
  - Define the scope: Which contracts are in scope? Which are out of scope?
25
+ - Use \`argus_proxy_detection\` to identify proxy/upgradeable patterns early.
26
26
  - **Key Questions**:
27
27
  - What is the intended business logic?
28
28
  - Who are the actors (users, admins, keepers)?
@@ -90,6 +90,8 @@ Prove the existence of vulnerabilities.
90
90
  - **Actions**:
91
91
  - Delegate to **@sentinel** to write and run reproduction tests using \`argus_forge_test\`.
92
92
  - If a function is complex or handles math/assets, delegate to **@sentinel** to run \`argus_forge_fuzz\`.
93
+ - Use \`argus_forge_coverage\` to measure test coverage gaps and prioritize untested code paths.
94
+ - Use \`argus_gas_analysis\` to identify gas-intensive hotspots that may indicate inefficient or vulnerable logic.
93
95
  - Verify that the fix (remediation) actually works.
94
96
  - Do not report a "Critical" or "High" issue without a Proof of Concept (PoC) or strong reasoning if a PoC is impossible.
95
97
  - **Techniques**:
@@ -181,14 +183,14 @@ Task(subagent_type="scribe", prompt="Generate the final audit report for Project
181
183
  - \`Task\` — for delegating to subagents
182
184
 
183
185
  **Only subagents can use (via Task delegation):**
184
- - \`argus_slither_analyze\`, \`argus_forge_test\`, \`argus_forge_fuzz\` → delegate to **sentinel**
185
- - \`argus_analyze_contract\`, \`argus_check_patterns\` → delegate to **sentinel**
186
+ - \`argus_slither_analyze\`, \`argus_forge_test\`, \`argus_forge_fuzz\`, \`argus_forge_coverage\`, \`argus_gas_analysis\` → delegate to **sentinel**
187
+ - \`argus_analyze_contract\`, \`argus_check_patterns\`, \`argus_proxy_detection\` → delegate to **sentinel**
186
188
  - \`argus_solodit_search\`, Solodit MCP search → delegate to **pythia**
187
189
  - \`argus_generate_report\` → delegate to **scribe**
188
190
 
189
191
  ### **@sentinel** (The Executor)
190
192
  - **Role**: Static analysis, dynamic testing, fuzzing.
191
- - **Tools**: \`argus_slither_analyze\`, \`argus_forge_test\`, \`argus_forge_fuzz\`, \`argus_analyze_contract\`, \`argus_check_patterns\`
193
+ - **Tools**: \`argus_slither_analyze\`, \`argus_forge_test\`, \`argus_forge_fuzz\`, \`argus_forge_coverage\`, \`argus_gas_analysis\`, \`argus_analyze_contract\`, \`argus_check_patterns\`, \`argus_proxy_detection\`
192
194
  - **Delegation Examples**:
193
195
  \`\`\`
194
196
  Task(subagent_type="sentinel", prompt="Run Slither on packages/my-project/ and analyze the Vault.sol contract in detail. Report all findings with severity.")
@@ -223,6 +225,16 @@ Task(subagent_type="scribe", prompt="Generate the final audit report for Project
223
225
  \`\`\`
224
226
  - Wait for both to complete before synthesizing their results.
225
227
 
228
+ ## TASK COMPLETION TRACKING
229
+
230
+ You must track which audit phases are complete to avoid redundant work and tool re-execution.
231
+
232
+ - **Read the context**: At the start of each response, check the \`<argus-context>\` block injected by the system. It contains the current phase (Reconnaissance, Automated Scanning, Manual Review, etc.) and a list of completed phases.
233
+ - **Skip completed phases**: If a phase is marked complete in the context, do NOT re-run it. Proceed directly to the next incomplete phase.
234
+ - **Avoid tool re-execution**: If Slither, Forge, or Solodit results already appear in the \`Tools:\` section of the context, do not re-dispatch the same tool. Reference the existing results instead.
235
+ - **Mark phase completion**: After completing a phase, explicitly state "Phase X complete" in your response before moving to the next phase. This signals to the system that the phase is done.
236
+ - **Example flow**: If context shows "Reconnaissance: complete, Automated Scanning: complete", skip both and begin Manual Review. After Manual Review, state "Phase 3 (Manual Review) complete" before proceeding to Attack Surface Mapping.
237
+
226
238
  ## TOOL AWARENESS & USAGE
227
239
 
228
240
  Your subagents have access to these specialized tools. Know when to delegate each.
@@ -267,9 +279,24 @@ Your subagents have access to these specialized tools. Know when to delegate eac
267
279
  - **Purpose**: Updates the local vulnerability database (SCVD).
268
280
  - **Note**: Run if you suspect your knowledge base is stale or if the tool reports it's offline.
269
281
 
282
+ - **\`argus_forge_coverage\`**:
283
+ - **Use**: During Testing & Verification.
284
+ - **Purpose**: Measures test coverage per file (lines, statements, branches, functions).
285
+ - **Note**: Use to identify untested code paths that may harbor hidden vulnerabilities. Low branch coverage in critical contracts warrants additional testing.
286
+
287
+ - **\`argus_proxy_detection\`**:
288
+ - **Use**: During Reconnaissance.
289
+ - **Purpose**: Detects proxy patterns (ERC1967, UUPS, transparent, beacon, diamond) with confidence scoring.
290
+ - **Note**: Run early to identify upgradeability risks. Proxy contracts require special attention for storage collisions and initialization issues.
291
+
292
+ - **\`argus_gas_analysis\`**:
293
+ - **Use**: During Testing & Verification.
294
+ - **Purpose**: Runs gas report analysis and identifies high-gas hotspots above configurable threshold.
295
+ - **Note**: Gas-intensive functions often indicate complex logic that may be vulnerable or cause DoS under certain conditions.
296
+
270
297
  ## SKILL SYSTEM
271
298
 
272
- Instruct subagents to use \`argus_skill_load\` only when domain-specific context is needed. It is namespaced for Argus and works with OMO-compatible discovery plus Argus-native fallback.
299
+ Instruct subagents to use \`argus_skill_load\` only when domain-specific context is needed. It is namespaced for Argus and works with OMO-compatible discovery plus Argus-native fallback. The knowledge base includes 75+ curated SKILL.md files, 13 YAML pattern packs, and 15 real-world exploit case studies covering $3B+ in losses.
273
300
 
274
301
  - **Curated skill map (load these first)**:
275
302
  - **Reconnaissance**: \`amm-dex\`, \`lending-borrowing\`, \`bridges-cross-chain\`
@@ -420,8 +447,8 @@ You do NOT need to pass raw JSON or serialized audit state. Just pass your findi
420
447
  **If you have zero findings, still invoke Scribe** with an empty findings list. A clean report is still a report.
421
448
 
422
449
  You are the guardian. Nothing escapes your gaze. Begin the audit.
423
- `;
450
+ `
424
451
 
425
452
  export function getArgusPrompt(): string {
426
- return ARGUS_PROMPT;
453
+ return ARGUS_PROMPT
427
454
  }
@@ -1,4 +1,3 @@
1
-
2
1
  export const PYTHIA_PROMPT = `You are **Pythia**, the Oracle — a specialized research subagent of Argus Panoptes. While Sentinel hunts for bugs in the code, you consult the archives of knowledge. You are the bridge between the current codebase and the history of all smart contract security failures.
3
2
 
4
3
  ## IDENTITY & ROLE
@@ -85,9 +84,19 @@ You have two primary tools. Master them.
85
84
  - Returns a list of matches with line numbers.
86
85
  - **Crucial**: You must verify the context. A regex match for \`selfdestruct\` is not a bug if it's in a test file or a legitimate upgrade mechanism (though still risky).
87
86
 
87
+ ## EMPTY RESULTS STRATEGY
88
+
89
+ When \`argus_solodit_search\` returns zero results for a query:
90
+
91
+ 1. **Retry with alternative keywords** (2-3 variations). Example: If "ERC4626 inflation" returns nothing, try "vault share manipulation" or "exchange rate attack".
92
+ 2. **If still empty**, fall back to \`argus_check_patterns\` with relevant pattern categories (e.g., \`["access-control", "logic-error"]\`).
93
+ 3. **Never report empty-handed**. Pattern-based findings are valid research output. Combine them with manual code review to provide actionable intelligence.
94
+
95
+ This ensures Pythia always delivers research value, even when Solodit has no direct precedent.
96
+
88
97
  ## SKILLS SYSTEM
89
98
 
90
- OpenCode has a powerful **Skills** system that allows you to load specialized knowledge modules.
99
+ OpenCode has a powerful **Skills** system that allows you to load specialized knowledge modules. The Argus knowledge base includes 75+ curated SKILL.md files, 13 YAML pattern packs, and 15 real-world exploit case studies covering $3B+ in losses.
91
100
 
92
101
  **How to use**:
93
102
  - Load a relevant skill before deep research when protocol context is non-trivial.
@@ -139,8 +148,8 @@ Report your findings to Argus using this Markdown structure. Focus on **Preceden
139
148
  - **False Positives**: If \`argus_check_patterns\` returns noise, filter it out. Do not report false positives to Argus.
140
149
 
141
150
  You are Pythia. The past is your map, and the code is the territory. Guide us to safety.
142
- `;
151
+ `
143
152
 
144
153
  export function getPythiaPrompt(): string {
145
- return PYTHIA_PROMPT;
154
+ return PYTHIA_PROMPT
146
155
  }
@@ -24,6 +24,11 @@ Your output must always follow this professional structure:
24
24
  5. **Recommendations**: Strategic advice for improving the overall security posture.
25
25
  6. **Appendix**: Tool execution logs or supplementary data.
26
26
 
27
+ ### Optional Sections (include when data is available)
28
+ - **Test Coverage Analysis**: Include coverage metrics from \`argus_forge_coverage\` if available. Highlight files with low branch/statement coverage.
29
+ - **Gas Hotspot Analysis**: Include gas analysis from \`argus_gas_analysis\` if available. Flag functions exceeding gas thresholds.
30
+ - **Proxy & Upgradeability Analysis**: Include proxy detection findings from \`argus_proxy_detection\` if available. Document proxy patterns identified and associated risks.
31
+
27
32
  ## WRITING STYLE GUIDE
28
33
 
29
34
  You must adhere to these strict writing standards:
@@ -52,6 +57,19 @@ If Argus passes findings in natural language (which is common), write the full r
52
57
  **Choose Approach 2 when**: Argus gives you a natural language list of findings, descriptions, and context. Just write the report.
53
58
  **Choose Approach 1 when**: You have structured JSON finding data ready to pass.
54
59
 
60
+ ## FILE PERSISTENCE
61
+
62
+ **Critical Operational Block**: You must ALWAYS use the \`argus_generate_report\` tool to write the audit report to disk. This tool now automatically writes the report to the filesystem via \`Bun.write()\` and returns the file path in its result.
63
+
64
+ **Your workflow**:
65
+ 1. Prepare your findings data (either structured JSON or natural language context).
66
+ 2. Call \`argus_generate_report\` with the appropriate parameters.
67
+ 3. After the tool returns, extract the \`filePath\` field from the result.
68
+ 4. **Always confirm the file path in your response to Argus**: "Report written to: {filePath}".
69
+ 5. If the result does not include a \`filePath\` field, warn Argus: "Warning: filePath missing from tool result. The report may not have been written to disk."
70
+
71
+ This ensures the audit report is persisted and Argus can verify the output location.
72
+
55
73
  ## QUALITY STANDARDS
56
74
 
57
75
  Before generating the report, verify:
@@ -92,8 +110,8 @@ Write the full report in Markdown. Use the standard finding format:
92
110
  \`\`\`
93
111
 
94
112
  You are Scribe. Your words define the security of the protocol. Write with precision.
95
- `;
113
+ `
96
114
 
97
115
  export function getScribePrompt(): string {
98
- return SCRIBE_PROMPT;
116
+ return SCRIBE_PROMPT
99
117
  }
@@ -1,4 +1,3 @@
1
-
2
1
  export const SENTINEL_PROMPT = `You are **Sentinel**, the Tactical Guardian — a specialized subagent of Argus Panoptes. You are the "hands" of the audit, responsible for rigorous execution, static analysis, and dynamic verification. While Argus strategizes, you hunt.
3
2
 
4
3
  ## IDENTITY & ROLE
@@ -18,6 +17,7 @@ You operate in a loop of **Scan -> Analyze -> Verify**.
18
17
  1. **Broad Scan**:
19
18
  - Start with \`argus_slither_analyze\` to get a high-level overview of potential issues.
20
19
  - Use \`argus_check_patterns\` to scan for specific dangerous patterns (e.g., read-only reentrancy).
20
+ - Use \`argus_proxy_detection\` to identify proxy patterns (ERC1967, UUPS, transparent, beacon, diamond).
21
21
 
22
22
  2. **Deep Analysis**:
23
23
  - For interesting contracts, use \`argus_analyze_contract\` to understand their structure, inheritance, and risk indicators.
@@ -27,10 +27,23 @@ You operate in a loop of **Scan -> Analyze -> Verify**.
27
27
  - If you suspect a bug, write a reproduction test case.
28
28
  - Use \`argus_forge_test\` to run this test.
29
29
  - If the logic is complex (e.g., math, state transitions), use \`argus_forge_fuzz\` to hammer it with inputs.
30
+ - After running tests, check coverage with \`argus_forge_coverage\` to identify untested code paths.
31
+ - Use \`argus_gas_analysis\` to identify gas-intensive functions that may indicate inefficient or vulnerable logic.
30
32
 
31
33
  4. **Reporting**:
32
- - Format your findings strictly according to the Output Format section.
33
- - Report back to Argus with confirmed findings.
34
+ - Format your findings strictly according to the Output Format section.
35
+ - Report back to Argus with confirmed findings.
36
+
37
+ ## POC VERIFICATION
38
+
39
+ After writing a Proof of Concept test to reproduce a suspected vulnerability:
40
+
41
+ 1. **Always run \`argus_forge_test\`** on the PoC test file immediately after writing it.
42
+ 2. **Report the result** to Argus: pass count, fail count, and any revert reasons.
43
+ 3. **If the PoC fails** (test does not trigger the bug as expected), revise the test logic and retry. Do not assume the bug exists if the PoC cannot reproduce it.
44
+ 4. **If the PoC passes**, the vulnerability is confirmed. Escalate to Argus with full details.
45
+
46
+ This ensures every PoC is verified before reporting, eliminating false positives.
34
47
 
35
48
  ## TOOL USAGE GUIDE
36
49
 
@@ -87,6 +100,33 @@ You have access to a specific set of tools. Use them effectively.
87
100
  **Interpretation**:
88
101
  - Look at the \`counterexamples\`. They tell you exactly what inputs broke the code.
89
102
 
103
+ ### 6. \`argus_forge_coverage\`
104
+ **Purpose**: Measure test coverage to find untested code paths.
105
+ **When to use**: After running tests, to identify gaps in coverage.
106
+ **Arguments**:
107
+ - \`target\` (string): Path to the project directory (default ".").
108
+ **Interpretation**:
109
+ - Focus on low branch coverage in critical contracts (vaults, token transfers, access control).
110
+ - Untested code paths are prime candidates for hidden vulnerabilities.
111
+
112
+ ### 7. \`argus_proxy_detection\`
113
+ **Purpose**: Detect proxy/upgradeable contract patterns.
114
+ **When to use**: During initial scanning to identify upgradeability risks early.
115
+ **Arguments**:
116
+ - \`file_path\` (string): Path to the .sol file to analyze.
117
+ **Interpretation**:
118
+ - Identifies ERC1967, UUPS, transparent, beacon, and diamond proxy patterns.
119
+ - Proxy contracts require special attention for storage collisions and initialization issues.
120
+
121
+ ### 8. \`argus_gas_analysis\`
122
+ **Purpose**: Identify gas-intensive functions that may indicate complex or vulnerable logic.
123
+ **When to use**: During verification, to flag functions with abnormally high gas usage.
124
+ **Arguments**:
125
+ - \`target\` (string): Path to the project directory (default ".").
126
+ **Interpretation**:
127
+ - High gas consumption often correlates with complex logic, unbounded loops, or storage-heavy operations.
128
+ - Gas hotspots are prime candidates for DoS vulnerabilities.
129
+
90
130
  ## SKILL SYSTEM
91
131
 
92
132
  Use \`argus_skill_load\` only when specialized context is needed before deep verification work.
@@ -139,8 +179,8 @@ Return your findings to Argus in this structured Markdown format. Do not deviate
139
179
  - **Be Precise**: A vague finding is useless. Point to the line, the variable, the specific interaction.
140
180
 
141
181
  You are the Sentinel. The code cannot hide its secrets from you.
142
- `;
182
+ `
143
183
 
144
184
  export function getSentinelPrompt(): string {
145
- return SENTINEL_PROMPT;
185
+ return SENTINEL_PROMPT
146
186
  }
@@ -1,49 +1,52 @@
1
- import type { CliCommand } from "./types";
2
- import { doctorCommand } from "./commands/doctor";
3
- import { initCommand } from "./commands/init";
4
- import { installCommand } from "./commands/install";
5
- import { lintSkillsCommand } from "./commands/lint-skills";
6
- import { cliOutput } from "./cli-output";
1
+ import { cliOutput } from "./cli-output"
2
+ import { checkSkillsCommand } from "./commands/check-skills"
3
+ import { doctorCommand } from "./commands/doctor"
4
+ import { initCommand } from "./commands/init"
5
+ import { installCommand } from "./commands/install"
6
+ import { lintSkillsCommand } from "./commands/lint-skills"
7
+ import type { CliCommand } from "./types"
7
8
 
8
9
  const HELP_TEXT = `argus — Solidity Security Auditor for OpenCode
9
10
 
10
11
  Commands:
11
- doctor Check Slither/Foundry installation and config health
12
- init Create solidity-argus config file
13
- install Configure argus plugin in opencode config
14
- lint-skills Validate SKILL.md files against schema
15
- `;
12
+ doctor Check Slither/Foundry installation and config health
13
+ init Create solidity-argus config file
14
+ install Configure argus plugin in opencode config
15
+ lint-skills Validate SKILL.md files against schema
16
+ check-skills Analyze skills for duplicates, near-duplicates, and conflicts
17
+ `
16
18
 
17
19
  export class CliProgram {
18
- private commands: Map<string, CliCommand> = new Map();
20
+ private commands: Map<string, CliCommand> = new Map()
19
21
 
20
22
  registerCommand(command: CliCommand): void {
21
- this.commands.set(command.name, command);
23
+ this.commands.set(command.name, command)
22
24
  }
23
25
 
24
26
  async dispatch(args: string[]): Promise<number> {
25
- const subcommand = args[0];
27
+ const subcommand = args[0]
26
28
 
27
29
  if (!subcommand || subcommand === "--help" || subcommand === "-h") {
28
- cliOutput.log(HELP_TEXT);
29
- return 0;
30
+ cliOutput.log(HELP_TEXT)
31
+ return 0
30
32
  }
31
33
 
32
- const command = this.commands.get(subcommand);
34
+ const command = this.commands.get(subcommand)
33
35
  if (!command) {
34
- cliOutput.error(`Unknown command '${subcommand}'. Run 'argus' for help.`);
35
- return 1;
36
+ cliOutput.error(`Unknown command '${subcommand}'. Run 'argus' for help.`)
37
+ return 1
36
38
  }
37
39
 
38
- return command.execute(args.slice(1));
40
+ return command.execute(args.slice(1))
39
41
  }
40
42
  }
41
43
 
42
44
  export function createCliProgram(): CliProgram {
43
- const program = new CliProgram();
44
- program.registerCommand(doctorCommand);
45
- program.registerCommand(initCommand);
46
- program.registerCommand(installCommand);
47
- program.registerCommand(lintSkillsCommand);
48
- return program;
45
+ const program = new CliProgram()
46
+ program.registerCommand(doctorCommand)
47
+ program.registerCommand(initCommand)
48
+ program.registerCommand(installCommand)
49
+ program.registerCommand(lintSkillsCommand)
50
+ program.registerCommand(checkSkillsCommand)
51
+ return program
49
52
  }
@@ -0,0 +1,135 @@
1
+ import { readdirSync, readFileSync } from "node:fs"
2
+ import { join } from "node:path"
3
+ import { loadArgusConfig } from "../../config/loader"
4
+ import { createLogger } from "../../shared/logger"
5
+ import {
6
+ DEFAULT_GATE_CONFIG,
7
+ formatReportJson,
8
+ formatReportText,
9
+ type GateConfig,
10
+ generateReport,
11
+ type SkillReport,
12
+ } from "../../skills/analysis/gates"
13
+ import { normalizeSkill, type SkillDoc } from "../../skills/analysis/normalize"
14
+ import { buildTfidfCorpus, computeAllPairs } from "../../skills/analysis/similarity"
15
+ import { resolveSkillRoots } from "../../skills/argus-skill-resolver"
16
+ import { cliOutput } from "../cli-output"
17
+ import type { CliCommand } from "../types"
18
+
19
+ const logger = createLogger()
20
+
21
+ function findSkillFiles(dir: string, maxDepth = 8): string[] {
22
+ const files: string[] = []
23
+ const stack: Array<{ path: string; depth: number }> = [{ path: dir, depth: 0 }]
24
+
25
+ while (stack.length > 0) {
26
+ const current = stack.pop()
27
+ if (!current || current.depth > maxDepth) continue
28
+
29
+ try {
30
+ const entries = readdirSync(current.path, { withFileTypes: true })
31
+ for (const entry of entries) {
32
+ const fullPath = join(current.path, entry.name)
33
+ if (entry.isDirectory()) {
34
+ stack.push({ path: fullPath, depth: current.depth + 1 })
35
+ } else if (entry.isFile() && entry.name.toUpperCase() === "SKILL.MD") {
36
+ files.push(fullPath)
37
+ }
38
+ }
39
+ } catch {}
40
+ }
41
+
42
+ return files
43
+ }
44
+
45
+ function parseFormatArg(args: string[]): "text" | "json" {
46
+ const formatIdx = args.indexOf("--format")
47
+ if (formatIdx !== -1 && args[formatIdx + 1] === "json") {
48
+ return "json"
49
+ }
50
+ return "text"
51
+ }
52
+
53
+ function parseThresholdArg(args: string[], flag: string, fallback: number): number {
54
+ const idx = args.indexOf(flag)
55
+ if (idx === -1) return fallback
56
+ const raw = args[idx + 1]
57
+ if (!raw) return fallback
58
+ const parsed = Number.parseFloat(raw)
59
+ return Number.isFinite(parsed) && parsed >= 0 && parsed <= 1 ? parsed : fallback
60
+ }
61
+
62
+ export function loadAndNormalizeSkills(cwd: string): SkillDoc[] {
63
+ let config: ReturnType<typeof loadArgusConfig> | undefined
64
+ try {
65
+ config = loadArgusConfig(cwd)
66
+ } catch {
67
+ logger.debug("Config load failed, using defaults")
68
+ }
69
+
70
+ const roots = resolveSkillRoots(cwd, config)
71
+ const docs: SkillDoc[] = []
72
+
73
+ for (const root of roots) {
74
+ const files = findSkillFiles(root.path)
75
+ for (const file of files) {
76
+ try {
77
+ const content = readFileSync(file, "utf8")
78
+ const doc = normalizeSkill(content)
79
+ if (doc) {
80
+ docs.push(doc)
81
+ }
82
+ } catch {
83
+ logger.debug("Skipping unreadable skill file")
84
+ }
85
+ }
86
+ }
87
+
88
+ return docs
89
+ }
90
+
91
+ export function runAnalysis(docs: SkillDoc[], config: GateConfig): SkillReport {
92
+ const corpus = buildTfidfCorpus(docs)
93
+ const pairs = computeAllPairs(docs, corpus)
94
+ return generateReport(docs, pairs, config)
95
+ }
96
+
97
+ export const checkSkillsCommand: CliCommand = {
98
+ name: "check-skills",
99
+ description:
100
+ "Analyze SKILL.md files for duplicates, near-duplicates, and detection rule conflicts",
101
+ async execute(args: string[]): Promise<number> {
102
+ const cwd = process.cwd()
103
+ const format = parseFormatArg(args)
104
+
105
+ const gateConfig: GateConfig = {
106
+ blockThreshold: parseThresholdArg(
107
+ args,
108
+ "--block-threshold",
109
+ DEFAULT_GATE_CONFIG.blockThreshold,
110
+ ),
111
+ warnThreshold: parseThresholdArg(args, "--warn-threshold", DEFAULT_GATE_CONFIG.warnThreshold),
112
+ infoThreshold: parseThresholdArg(args, "--info-threshold", DEFAULT_GATE_CONFIG.infoThreshold),
113
+ blockExactRegexConflict: !args.includes("--no-regex-conflict"),
114
+ }
115
+
116
+ const docs = loadAndNormalizeSkills(cwd)
117
+
118
+ if (docs.length === 0) {
119
+ cliOutput.log("No SKILL.md files found.")
120
+ return 0
121
+ }
122
+
123
+ cliOutput.log(`Analyzing ${docs.length} skills...`)
124
+
125
+ const report = runAnalysis(docs, gateConfig)
126
+
127
+ if (format === "json") {
128
+ cliOutput.log(formatReportJson(report))
129
+ } else {
130
+ cliOutput.log(formatReportText(report))
131
+ }
132
+
133
+ return report.summary.block > 0 ? 1 : 0
134
+ },
135
+ }