cli-forge
Skill9 starsChanged 51 days agoMITView on GitHub
Write Foundry-based tests and scripts. Trigger phrases - foundry testing, write test, fuzz test, fork test, invariant test, deploy script, gas benchmark, coverage, or when working in tests/ or scripts/ directories.
In this repository9 other files it gives its agents.
- bttSkill
- evm-deploymentSkill
- sablier-designSkill
- sablier-iconSkill
- sablier-writingSkill
- spec-from-screenshotSkill
- tailwind-cssSkill
- viemSkill
- xstate-reactSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
13 rules. About 0 are common, 2 are distinctive, and 11 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
11
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 51
Assert state AFTER action: - Check state changes after function executes
- Very specific: line 57
Place all mocks in tests/mocks/
- Very specific: line 92
Create fork with vm.createSelectFork("ethereum")
- Very specific: line 93
Use deal() to give tokens to test users
- Very specific: line 94
Use assumeNoBlacklisted() for USDC/USDT
- Very specific: line 95
Use forceApprove() for non-standard tokens (USDT)
- Very specific: line 132
Use env vars: ETH_FROM, MNEMONIC
- Very specific: line 208
Check state with logs: - Add console2.log before reverts
- Very specific: line 209
Isolate failures: - Run single test with --match-test
- Very specific: line 210
Compare gas: - Use --gas-report to spot unexpected costs
- Very specific: line 211
Snapshot comparisons: - Use vm.snapshot() / vm.revertTo() to isolate state changes
- Very specific: line 217
Use constants from Defaults/Constants - never hardcode
- Distinctive: line 232
Test this skill with these prompts:
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Foundry Testing & Script Skill
Rules and patterns for Foundry tests. Find examples in the actual codebase.
Bundled References
| Reference | Content | When to Read |
./references/test-infrastructure.md | Constants, defaults, mocks | When setting up tests |
./references/cheat-codes.md | Common cheatcode patterns | When using vm cheatcodes |
./references/invariant-patterns.md | Handlers, stores, invariants | When writing invariant tests |
./references/formal-verification.md | Halmos, Certora, symbolic exec | When proving correctness |
./references/deployment-scripts.md | Script patterns, verification | When writing deploy scripts |
./references/deployment-checklist.md | Pre-mainnet deployment steps | Before deploying to production |
./references/gas-benchmarking.md | Snapshot, profiling, CI | When measuring gas performance |
./references/sablier-conventions.md | Sablier-specific patterns | When working in Sablier repos |
Test Types
| Type | Directory | Naming | Purpose |
| Integration | tests/integration/concrete/ | *.t.sol | BTT-based concrete tests |
| Fuzz | tests/integration/fuzz/ | *.t.sol | Property-based testing |
| Fork | tests/fork/ | *.t.sol | Mainnet state testing |
| Invariant | tests/invariant/ | Invariant*.t.sol | Stateful protocol properties |
| Scripts | scripts/solidity/ | *.s.sol | Deployment/initialization |
1. Integration Tests (Concrete)
Naming Convention
| Pattern | Usage |
test_RevertWhen_{Condition} | Revert on input |
test_RevertGiven_{State} | Revert on state |
test_When_{Condition} | Success path |
Rules
- Stack modifiers to document BTT path (modifiers are often empty - just document the path)
- Expect events BEFORE action -
vm.expectEmit()then call function - Assert state AFTER action - Check state changes after function executes
- Use revert helpers for common patterns (
expectRevert_DelegateCall,expectRevert_Null) - Named parameters in assertions -
assertEq(actual, expected, "description")
Mock Rules
- Place all mocks in
tests/mocks/ - One mock per scenario (not one mega-mock)
- Naming:
*Good,*Reverting,*InvalidSelector,*Reentrant
2. Fuzz Tests
Naming Convention
testFuzz_{FunctionName}_{Scenario}
Rules
- Bound before assume -
_bound()is more efficient thanvm.assume() - Bound in dependency order - Independent params first, then dependent
- Never hardcode params with validation constraints
- Document fuzzed scenarios in NatSpec
Bounding Pattern
// 1. Bound independent params first
cliffDuration = boundUint40(cliffDuration, 0, MAX - 1);
// 2. Bound dependent params based on constraints
totalDuration = boundUint40(totalDuration, cliffDuration + 1, MAX);3. Fork Tests
Rules
- Create fork with
vm.createSelectFork("ethereum") - Use
deal()to give tokens to test users - Use
assumeNoBlacklisted()for USDC/USDT - Use
forceApprove()for non-standard tokens (USDT)
Token Quirks
| Token | Issue | Solution |
| USDC/USDT | Blacklist | assumeNoBlacklisted() |
| USDT | Non-standard | forceApprove() |
| Fee-on-transfer | Balance diff | Check actual received amount |
4. Invariant Tests
Architecture
tests/invariant/
├── handlers/ # State manipulation (call functions with bounded params)
├── stores/ # State tracking (record totals, IDs)
└── Invariant.t.solRules
- Target handlers only -
targetContract(address(handler)) - Exclude protocol contracts -
excludeSender(address(vault)) - Use stores to track totals for invariant assertions
- Early return in handlers if preconditions not met
5. Solidity Scripts
Rules
- Inherit from
BaseScriptwithbroadcastmodifier - Use env vars:
ETH_FROM,MNEMONIC - Simulation first, then broadcast
Commands
# Simulation
forge script scripts/Deploy.s.sol --sig "run(...)" ARGS --rpc-url $RPC
# Broadcast
forge script scripts/Deploy.s.sol --sig "run(...)" ARGS --rpc-url $RPC --broadcast --verifyRunning Tests
# By type
forge test --match-path "tests/integration/concrete/**"
forge test --match-path "tests/fork/**"
forge test --match-contract Invariant_Test
# Specific test
forge test --match-test test_WhenCallerRecipient -vvvv
# Fuzz with more runs
forge test --match-test testFuzz_ --fuzz-runs 1000
# Coverage
forge coverage --report lcovDebugging
Verbosity Levels
| Flag | Shows |
-v | Logs for failing tests |
-vv | Logs for all tests |
-vvv | Stack traces for failures |
-vvvv | Stack traces + setup traces |
-vvvvv | Full execution traces |
Console Logging
import { console2 } from "forge-std/console2.sol";
console2.log("value:", someValue);
console2.log("address:", someAddress);
console2.logBytes32(someBytes32);Debugging Commands
# Trace specific failing test
forge test --match-test test_MyTest -vvvv
# Gas report for a test
forge test --match-test test_MyTest --gas-report
# Debug in interactive debugger
forge debug --debug tests/MyTest.t.sol --sig "test_MyTest()"
# Inspect storage layout
forge inspect MyContract storage-layoutDebugging Tips
- Label addresses -
vm.label(addr, "Recipient")for readable traces - Check state with logs - Add
console2.logbefore reverts - Isolate failures - Run single test with
--match-test - Compare gas - Use
--gas-reportto spot unexpected costs - Snapshot comparisons - Use
vm.snapshot()/vm.revertTo()to isolate state changes
Best Practices Summary
- Use constants from
Defaults/Constants- never hardcode - Specialized mocks - one per scenario, all in
tests/mocks/ - Modifiers in
Modifiers.sol- centralize BTT path modifiers - Label addresses with
vm.label()for traces - Events before actions -
vm.expectEmit()then call - Bound before assume - more efficient
External References
Example Invocations
Test this skill with these prompts:
- Integration test: "Write a concrete test for
withdrawthat expectsErrors.Flow_Overdrawwhen amount exceeds balance" - Fuzz test: "Create a fuzz test for
depositthat bounds amount between 1 and type(uint128).max" - Fork test: "Write a fork test for USDC deposits on mainnet with blacklist handling"
- Invariant test: "Create an invariant handler for the
depositandwithdrawfunctions" - Deploy script: "Write a deployment script for SablierFlow with verification"
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

