From a4a3504fb30a56976f7739b873a0e4cc74c25960 Mon Sep 17 00:00:00 2001 From: tac0turtle Date: Wed, 14 Jan 2026 14:24:12 +0100 Subject: [PATCH 1/3] add onboarding skill --- .claude/skills/contracts.md | 70 +++++++++ .claude/skills/ev-reth-core.md | 111 +++++++++++++ .claude/skills/ev-reth-evm.md | 117 ++++++++++++++ .claude/skills/ev-reth-evolve.md | 110 +++++++++++++ .claude/skills/ev-reth-testing.md | 168 ++++++++++++++++++++ .github/workflows/update-skills.yml | 234 ++++++++++++++++++++++++++++ 6 files changed, 810 insertions(+) create mode 100644 .claude/skills/contracts.md create mode 100644 .claude/skills/ev-reth-core.md create mode 100644 .claude/skills/ev-reth-evm.md create mode 100644 .claude/skills/ev-reth-evolve.md create mode 100644 .claude/skills/ev-reth-testing.md create mode 100644 .github/workflows/update-skills.yml diff --git a/.claude/skills/contracts.md b/.claude/skills/contracts.md new file mode 100644 index 0000000..292b7c8 --- /dev/null +++ b/.claude/skills/contracts.md @@ -0,0 +1,70 @@ +--- +description: This skill should be used when the user asks about "ev-reth contracts", "FeeVault", "AdminProxy", "fee bridging to Celestia", "Hyperlane integration", "Foundry deployment scripts", "genesis allocations", or wants to understand how base fees are redirected and bridged. +--- + +# Contracts Onboarding + +## Overview + +The contracts live in `contracts/` and use Foundry for development. There are two main contracts: + +1. **AdminProxy** (`src/AdminProxy.sol`) - Bootstrap contract for admin addresses at genesis +2. **FeeVault** (`src/FeeVault.sol`) - Collects base fees, bridges to Celestia via Hyperlane (cross-chain messaging protocol) + +## Key Files + +### Contract Sources +- `contracts/src/AdminProxy.sol` - Transparent proxy pattern for admin control +- `contracts/src/FeeVault.sol` - Fee collection and bridging logic + +### Deployment Scripts +- `contracts/script/DeployFeeVault.s.sol` - FeeVault deployment with CREATE2 +- `contracts/script/GenerateAdminProxyAlloc.s.sol` - Admin proxy allocation for genesis +- `contracts/script/GenerateFeeVaultAlloc.s.sol` - Fee vault allocation for genesis + +### Tests +- `contracts/test/AdminProxy.t.sol` - AdminProxy test suite +- `contracts/test/FeeVault.t.sol` - FeeVault test suite + +## Architecture + +### AdminProxy +The AdminProxy contract provides a bootstrap mechanism for setting admin addresses at genesis. It uses a transparent proxy pattern allowing upgrades. + +### FeeVault +The FeeVault serves as the destination for redirected base fees (instead of burning them). Key responsibilities: +- Receive base fees from block production +- Bridge accumulated fees to Celestia via Hyperlane +- Manage withdrawal permissions + +## Connection to Rust Code + +The contracts integrate with ev-reth through: +1. **Base Fee Redirect** - `crates/ev-revm/src/base_fee.rs` redirects fees to the configured sink address +2. **Chainspec Config** - `crates/node/src/config.rs` defines `base_fee_sink` field for the fee recipient address +3. **Genesis Allocation** - Scripts generate allocations included in chainspec + +## Development Commands + +```bash +cd contracts + +# Build contracts +forge build + +# Run tests +forge test + +# Run specific test +forge test --match-test testFeeCollection + +# Generate allocations +forge script script/GenerateFeeVaultAlloc.s.sol +``` + +## Exploration Starting Points + +1. Read `contracts/src/FeeVault.sol` for fee handling logic +2. Read `contracts/src/AdminProxy.sol` for admin patterns +3. Check `contracts/script/` for deployment patterns +4. See how `crates/ev-revm/src/base_fee.rs` interacts with the sink address diff --git a/.claude/skills/ev-reth-core.md b/.claude/skills/ev-reth-core.md new file mode 100644 index 0000000..46e11e1 --- /dev/null +++ b/.claude/skills/ev-reth-core.md @@ -0,0 +1,111 @@ +--- +description: This skill should be used when learning ev-reth core node architecture, understanding how payload building works, or getting started with the codebase. Use when the user asks "how does ev-reth work", "explain the architecture", "where is the payload builder", "how are transactions submitted", "what is EvolveNode", "show me the node composition", or wants to understand Engine API integration. +--- + +# Core Node Architecture Onboarding + +## Overview + +The core node logic lives in `crates/node/` and `bin/ev-reth/`. This is where ev-reth extends Reth to work with Evolve's transaction submission model. + +## Key Files + +### Entry Point +- `bin/ev-reth/src/main.rs` - Node binary, initializes tracing, extends RPC + +### Node Composition +- `crates/node/src/node.rs` - `EvolveNode` unit struct with trait implementations +- `crates/node/src/lib.rs` - Public API exports + +### Payload Building +- `crates/node/src/builder.rs` - `EvolvePayloadBuilder` - executes transactions, builds blocks +- `crates/node/src/payload_service.rs` - Integrates builder with Reth's payload service +- `crates/node/src/attributes.rs` - `EvolveEnginePayloadBuilderAttributes` + +### Validation +- `crates/node/src/validator.rs` - `EvolveEngineValidator` - custom block validation + +### Configuration +- `crates/node/src/config.rs` - `EvolvePayloadBuilderConfig`, parses chainspec extras +- `crates/node/src/chainspec.rs` - `EvolveChainSpecParser` with EIP-1559 config parsing +- `crates/node/src/args.rs` - CLI argument handling +- `crates/node/src/error.rs` - Error types + +### Execution +- `crates/node/src/executor.rs` - EVM config and executor wiring + +## Architecture + +### Transaction Flow (Key Innovation) + +Unlike standard Ethereum, ev-reth accepts transactions directly through Engine API: + +``` +engine_forkchoiceUpdatedV3 (with transactions in payload attributes) + ↓ +EvolveEnginePayloadBuilderAttributes (decodes transactions) + ↓ +EvolvePayloadBuilder.build_payload() + ↓ +Execute transactions against current state + ↓ +Sealed block returned via engine_getPayloadV3 +``` + +### Node Composition Pattern + +`EvolveNode` is a unit struct that implements `NodeTypes` and `Node` traits: + +```rust +pub struct EvolveNode; + +impl NodeTypes for EvolveNode { + type Primitives = EthPrimitives; + type ChainSpec = ChainSpec; + type StateCommitment = MerklePatriciaTrie; + type Storage = EthStorage; + type Payload = EthEngineTypes; +} +``` + +The composition happens via trait implementations, connecting: +- `EvolveEngineTypes` for custom payload types +- `EvolveEngineValidator` for relaxed validation +- `EvolvePayloadBuilderBuilder` for custom block building +- `EvolveConsensusBuilder` from `evolve_ev_reth::consensus` + +### Validator Customizations + +`EvolveEngineValidator` bypasses certain checks for Evolve compatibility: +- Block hash validation bypassed (Evolve uses prev block's apphash) +- Equal timestamp blocks allowed +- Custom gas limits per payload supported + +### Chainspec Extensions + +The chainspec parser supports Evolve-specific extras via `EvolveEip1559Config`: +- EIP-1559 custom parameters (base fee settings) +- Additional fields parsed from `evolve` key in chainspec extras + +## Key Design Decisions + +1. **No Mempool** - Transactions submitted directly via Engine API +2. **Relaxed Validation** - Block hashes not validated (Evolve-specific) +3. **Configurable Gas Limits** - Per-payload gas limits supported +4. **Modular Builder** - Separates concerns between general and Evolve-specific logic + +## Development Commands + +```bash +make build # Release build +make run-dev # Run with debug logs +make test-node # Test node crate +``` + +## Exploration Starting Points + +1. Start with `bin/ev-reth/src/main.rs` for entry point +2. Read `crates/node/src/node.rs` for component composition +3. Read `crates/node/src/builder.rs` for payload building (this is the heart) +4. Check `crates/node/src/validator.rs` for validation customizations +5. See `crates/node/src/chainspec.rs` for config parsing diff --git a/.claude/skills/ev-reth-evm.md b/.claude/skills/ev-reth-evm.md new file mode 100644 index 0000000..f187d0c --- /dev/null +++ b/.claude/skills/ev-reth-evm.md @@ -0,0 +1,117 @@ +--- +description: This skill should be used when the user asks about "EVM customizations", "base fee redirect", "fee sink", "mint precompile", "native token minting", "contract size limit", "EvEvmFactory", "EvHandler", or wants to understand how ev-reth modifies EVM execution behavior. +--- + +# EVM Customizations Onboarding + +## Overview + +EVM customizations live in `crates/ev-revm/` and `crates/ev-precompiles/`. These modify how the EVM executes transactions. + +## Key Files + +### EVM Factory +- `crates/ev-revm/src/factory.rs` - `EvEvmFactory` wraps `EthEvmFactory` +- `crates/ev-revm/src/evm.rs` - `EvEvm`, `DefaultEvEvm` implementations +- `crates/ev-revm/src/config.rs` - EVM configuration structs + +### Handlers +- `crates/ev-revm/src/handler.rs` - `EvHandler` for execution handling +- `crates/ev-revm/src/base_fee.rs` - `BaseFeeRedirect` logic + +### Precompiles +- `crates/ev-precompiles/src/mint.rs` - `MintPrecompile` at address 0xF100 + +### Shared +- `crates/common/src/constants.rs` - Shared constants + +## Architecture + +### EvEvmFactory + +Wraps Reth's `EthEvmFactory` to inject custom behavior. See `crates/ev-revm/src/factory.rs:103-108`: + +```rust +pub struct EvEvmFactory { + inner: F, + redirect: Option, + mint_precompile: Option, + contract_size_limit: Option, +} +``` + +### Base Fee Redirect + +Instead of burning base fees, redirects them to a configurable address. See `crates/ev-revm/src/factory.rs:27-49`: + +```rust +pub struct BaseFeeRedirectSettings { + redirect: BaseFeeRedirect, // Contains fee_sink address + activation_height: u64, // When redirect activates +} +``` + +The `EvHandler` overrides `reward_beneficiary` (in `handler.rs:126-141`) to credit the sink address with base fees before paying the standard tip to the block producer. + +### Mint Precompile (0xF100) + +Custom precompile for native token minting/burning at address `0xF100`. See `crates/ev-precompiles/src/mint.rs`. + +**INativeToken Interface** (5 functions): +```solidity +interface INativeToken { + function mint(address to, uint256 amount) external; + function burn(address from, uint256 amount) external; + function addToAllowList(address account) external; + function removeFromAllowList(address account) external; + function allowlist(address account) external view returns (bool); +} +``` + +Settings in `crates/ev-revm/src/factory.rs:52-74`: +```rust +pub struct MintPrecompileSettings { + admin: Address, // Who can mint/burn and manage allowlist + activation_height: u64, // When precompile activates +} +``` + +### Contract Size Limits + +Override EIP-170 default (24KB) contract size limit. See `crates/ev-revm/src/factory.rs:77-99`: + +```rust +pub struct ContractSizeLimitSettings { + limit: usize, // Custom limit in bytes + activation_height: u64, // When limit changes +} +``` + +## Configuration Flow + +1. Chainspec defines settings in `extras` field +2. `EvolveChainSpecParser` parses into config structs +3. `EvEvmFactory` receives settings at construction +4. Settings applied during EVM execution based on block height + +## Key Design Decisions + +1. **Configurable Activation** - All features have activation heights for upgrades +2. **Wrapper Pattern** - `EvEvmFactory` wraps standard factory, minimizing changes +3. **Admin Control** - Mint precompile requires admin authorization (or allowlist) +4. **Fee Preservation** - Base fees collected rather than burned (for bridging) + +## Development Commands + +```bash +cargo test -p ev-revm # Test EVM crate +cargo test -p ev-precompiles # Test precompiles +``` + +## Exploration Starting Points + +1. Start with `crates/ev-revm/src/factory.rs` for the wrapper pattern +2. Read `crates/ev-revm/src/handler.rs:126-141` for `reward_beneficiary` override +3. Read `crates/ev-precompiles/src/mint.rs` for precompile implementation +4. Check `crates/ev-revm/src/base_fee.rs` for redirect logic +5. See `crates/node/src/config.rs` for how settings are configured diff --git a/.claude/skills/ev-reth-evolve.md b/.claude/skills/ev-reth-evolve.md new file mode 100644 index 0000000..3ab8306 --- /dev/null +++ b/.claude/skills/ev-reth-evolve.md @@ -0,0 +1,110 @@ +--- +description: This skill should be used when the user asks about "Evolve integration", "payload attributes", "EvolvePayloadAttributes", "consensus modifications", "txpoolExt RPC", "how transactions flow through Evolve", or wants to understand how ev-reth connects to the Evolve system. +--- + +# Evolve Integration Onboarding + +## Overview + +Evolve-specific integration lives in `crates/evolve/`. This handles the protocol-level differences between standard Ethereum and Evolve. + +## Key Files + +### Types +- `crates/evolve/src/types.rs` - `EvolvePayloadAttributes`, validation errors +- `crates/evolve/src/lib.rs` - Public API exports + +### Configuration +- `crates/evolve/src/config.rs` - `EvolveConfig`, txpool limits + +### Consensus +- `crates/evolve/src/consensus.rs` - `EvolveConsensus` modifications + +### RPC Extensions +- `crates/evolve/src/rpc/mod.rs` - RPC module exports +- `crates/evolve/src/rpc/txpool.rs` - `EvolveTxpoolApiServer` extension + +## Architecture + +### Payload Attributes + +`EvolvePayloadAttributes` (from `crates/evolve/src/types.rs:7-22`): + +```rust +pub struct EvolvePayloadAttributes { + pub transactions: Vec, // Signed transactions (not raw bytes) + pub gas_limit: Option, // Optional gas limit + pub timestamp: u64, // Block timestamp + pub prev_randao: B256, // Prev randao value + pub suggested_fee_recipient: Address, // Fee recipient + pub parent_hash: B256, // Parent block hash + pub block_number: u64, // Block number +} +``` + +This is the key innovation: transactions are submitted through `engine_forkchoiceUpdatedV3` rather than pulled from a mempool. + +### Consensus Modifications + +`EvolveConsensus` wraps `EthBeaconConsensus` with relaxed rules. The key difference: +- Allows blocks with equal timestamps (`>=` instead of `>`) +- Standard Ethereum requires strictly increasing timestamps + +This is needed because Evolve may produce multiple blocks with the same timestamp. + +### RPC Extensions + +`EvolveTxpoolApiServer` adds custom txpool RPC methods. See `crates/evolve/src/rpc/txpool.rs:10-15`: + +```rust +#[rpc(server, namespace = "txpoolExt")] +pub trait EvolveTxpoolApi { + /// Get transactions from the pool up to the configured limits + #[method(name = "getTxs")] + async fn get_txs(&self) -> RpcResult>; +} +``` + +Note: `get_txs` takes no parameters - limits are configured at API creation time via `EvolveConfig`. + +## Transaction Flow + +``` +Evolve submits transactions + ↓ +engine_forkchoiceUpdatedV3 with EvolvePayloadAttributes + ↓ +Transactions (Vec) validated + ↓ +Passed to EvolvePayloadBuilder + ↓ +Executed and included in block +``` + +## Key Design Decisions + +1. **Direct Submission** - No mempool, transactions in payload attributes +2. **Equal Timestamps** - Consensus allows same-timestamp blocks +3. **RPC Extensions** - Custom namespace for Evolve-specific operations +4. **Signed Transactions** - Payload attributes contain `TransactionSigned`, not raw bytes + +## Connection to Other Components + +- **crates/node** - Uses `EvolvePayloadAttributes` in builder +- **crates/ev-revm** - Executes transactions from attributes +- **bin/ev-reth** - Registers RPC extensions + +## Development Commands + +```bash +make test-evolve +# Or directly: +cargo test -p evolve-ev-reth +``` + +## Exploration Starting Points + +1. Start with `crates/evolve/src/types.rs` for payload attributes +2. Read `crates/evolve/src/consensus.rs` for consensus modifications +3. Check `crates/evolve/src/rpc/txpool.rs` for RPC extensions +4. See `crates/node/src/builder.rs` for how attributes are processed diff --git a/.claude/skills/ev-reth-testing.md b/.claude/skills/ev-reth-testing.md new file mode 100644 index 0000000..fbacf2b --- /dev/null +++ b/.claude/skills/ev-reth-testing.md @@ -0,0 +1,168 @@ +--- +description: This skill should be used when the user asks to "add a test", "write tests for", "understand the test setup", "run integration tests", "test ev-reth", "test the Engine API", or needs guidance on e2e test patterns, test fixtures, or EvolveTestFixture setup. +--- + +# Testing Infrastructure Onboarding + +## Overview + +Tests live in `crates/tests/` and include e2e and integration tests. The test suite uses `reth-e2e-test-utils` for realistic node testing. + +## Key Files + +### E2E Tests +- `crates/tests/src/e2e_tests.rs` - End-to-end tests (~1,060 lines) +- `crates/tests/src/test_evolve_engine_api.rs` - Engine API specific tests (~370 lines) + +### Test Utilities +- `crates/tests/src/common.rs` - Test utilities and fixtures (~265 lines) +- `crates/tests/src/lib.rs` - Module exports + +## Test Utilities (common.rs) + +### Chain Spec Helpers + +```rust +// Basic test chain spec +pub fn create_test_chain_spec() -> Arc + +// With base fee redirect configured +pub fn create_test_chain_spec_with_base_fee_sink( + base_fee_sink: Option
+) -> Arc + +// With mint precompile admin configured +pub fn create_test_chain_spec_with_mint_admin( + mint_admin: Address +) -> Arc +``` + +### EvolveTestFixture + +The main test fixture for payload builder tests. See `crates/tests/src/common.rs:89-103`: + +```rust +pub struct EvolveTestFixture { + pub builder: EvolvePayloadBuilder, + pub provider: MockEthProvider, + pub genesis_hash: B256, + pub genesis_state_root: B256, + pub temp_dir: TempDir, +} + +impl EvolveTestFixture { + pub async fn new() -> Result + pub fn setup_test_accounts(&self) + pub fn add_mock_header(&self, hash: B256, number: u64, state_root: B256, timestamp: u64) + pub fn create_payload_attributes( + &self, + transactions: Vec, + block_number: u64, + timestamp: u64, + parent_hash: B256, + gas_limit: Option, + ) -> EvolvePayloadAttributes +} +``` + +### Transaction Helpers + +```rust +// Create multiple test transactions +pub fn create_test_transactions(count: usize, nonce_start: u64) -> Vec + +// Create a single test transaction +pub fn create_test_transaction(nonce: u64) -> TransactionSigned +``` + +## Test Patterns + +### Basic Fixture Test + +```rust +#[tokio::test] +async fn test_payload_with_transactions() { + // Setup fixture + let fixture = EvolveTestFixture::new().await.unwrap(); + + // Create transactions + let transactions = create_test_transactions(2, 0); + + // Create payload attributes + let attrs = fixture.create_payload_attributes( + transactions, + 1, // block_number + TEST_TIMESTAMP + 12, // timestamp + fixture.genesis_hash, // parent_hash + None, // gas_limit + ); + + // Build payload using the builder + let result = fixture.builder.build_payload(attrs).await; + + // Assert on result + assert!(result.is_ok()); +} +``` + +### Testing with Custom Chain Spec + +```rust +#[tokio::test] +async fn test_base_fee_redirect() { + let fee_sink = Address::random(); + let chain_spec = create_test_chain_spec_with_base_fee_sink(Some(fee_sink)); + + // Build EVM config with redirect + let evm_config = EthEvmConfig::new(chain_spec.clone()); + let config = EvolvePayloadBuilderConfig::from_chain_spec(chain_spec.as_ref()).unwrap(); + + let base_fee_redirect = config + .base_fee_redirect_settings() + .map(|(sink, activation)| { + BaseFeeRedirectSettings::new(BaseFeeRedirect::new(sink), activation) + }); + + let wrapped_evm = with_ev_handler(evm_config, base_fee_redirect, None, None); + // ... continue with test +} +``` + +## Test Constants + +Defined in `crates/tests/src/common.rs`: + +```rust +pub const TEST_CHAIN_ID: u64 = 1234; +pub const TEST_TIMESTAMP: u64 = 1710338135; +pub const TEST_GAS_LIMIT: u64 = 30_000_000; +pub const TEST_BASE_FEE: u64 = 0; +``` + +## Development Commands + +```bash +make test # Run all tests +make test-verbose # Run with output +make test-integration # Integration tests only + +# Run specific test +cargo test -p ev-reth-tests test_payload_with_transactions + +# Run tests matching pattern +cargo test -p ev-reth-tests mint +``` + +## Key Design Decisions + +1. **MockEthProvider** - Uses Reth's mock provider for unit testing +2. **Fixture Pattern** - `EvolveTestFixture` encapsulates common setup +3. **Chain Spec Variants** - Helpers for different config scenarios +4. **Test Transactions** - `create_test_transactions` uses `Signature::test_signature()` + +## Exploration Starting Points + +1. Start with `crates/tests/src/common.rs` for fixture and helpers +2. Read a simple test in `crates/tests/src/e2e_tests.rs` +3. Check how chain spec is configured for different test scenarios +4. See `EvolveTestFixture::new()` for the full setup flow diff --git a/.github/workflows/update-skills.yml b/.github/workflows/update-skills.yml new file mode 100644 index 0000000..2bf17b5 --- /dev/null +++ b/.github/workflows/update-skills.yml @@ -0,0 +1,234 @@ +name: Weekly Skills Update Check + +on: + schedule: + # Run every Friday at 5pm UTC + - cron: '0 17 * * 5' + workflow_dispatch: + inputs: + force: + description: 'Force PR creation even without changes' + required: false + default: 'false' + type: boolean + +permissions: + contents: write + pull-requests: write + +jobs: + check-and-update: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Check for commits in the past week + id: check-commits + run: | + WEEK_AGO=$(date -d '7 days ago' +%Y-%m-%d 2>/dev/null || date -v-7d +%Y-%m-%d) + + # Count commits from the past week (excluding skill updates) + COMMIT_COUNT=$(git log --since="$WEEK_AGO" --oneline --no-merges -- \ + 'crates/' 'bin/' 'contracts/' 'docs/' \ + ':!.claude/skills/' \ + | wc -l | tr -d ' ') + + if [ "$COMMIT_COUNT" -eq 0 ] && [ "${{ inputs.force }}" != "true" ]; then + echo "No relevant commits in the past week" + echo "has_commits=false" >> $GITHUB_OUTPUT + exit 0 + fi + + echo "has_commits=true" >> $GITHUB_OUTPUT + echo "commit_count=$COMMIT_COUNT" >> $GITHUB_OUTPUT + + - name: Analyze changes by area + if: steps.check-commits.outputs.has_commits == 'true' + id: analyze + run: | + # Check each area for changes (file names only, safe output) + CONTRACTS_COUNT=$(git diff --name-only HEAD~50..HEAD -- 'contracts/' 2>/dev/null | wc -l | tr -d ' ') + CORE_COUNT=$(git diff --name-only HEAD~50..HEAD -- 'crates/node/' 'bin/ev-reth/' 2>/dev/null | wc -l | tr -d ' ') + EVM_COUNT=$(git diff --name-only HEAD~50..HEAD -- 'crates/ev-revm/' 'crates/ev-precompiles/' 'crates/common/' 2>/dev/null | wc -l | tr -d ' ') + EVOLVE_COUNT=$(git diff --name-only HEAD~50..HEAD -- 'crates/evolve/' 2>/dev/null | wc -l | tr -d ' ') + TESTS_COUNT=$(git diff --name-only HEAD~50..HEAD -- 'crates/tests/' 2>/dev/null | wc -l | tr -d ' ') + + # Output counts + echo "contracts_count=$CONTRACTS_COUNT" >> $GITHUB_OUTPUT + echo "core_count=$CORE_COUNT" >> $GITHUB_OUTPUT + echo "evm_count=$EVM_COUNT" >> $GITHUB_OUTPUT + echo "evolve_count=$EVOLVE_COUNT" >> $GITHUB_OUTPUT + echo "tests_count=$TESTS_COUNT" >> $GITHUB_OUTPUT + + TOTAL=$((CONTRACTS_COUNT + CORE_COUNT + EVM_COUNT + EVOLVE_COUNT + TESTS_COUNT)) + if [ "$TOTAL" -eq 0 ]; then + echo "No relevant file changes detected" + echo "has_changes=false" >> $GITHUB_OUTPUT + else + echo "has_changes=true" >> $GITHUB_OUTPUT + fi + + - name: Check for existing PR + if: steps.check-commits.outputs.has_commits == 'true' && steps.analyze.outputs.has_changes == 'true' + id: check-pr + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + EXISTING_PR=$(gh pr list --state open --label "skills-update" --json number --jq '.[0].number') + if [ -n "$EXISTING_PR" ]; then + echo "Existing PR found: #$EXISTING_PR" + echo "existing_pr=$EXISTING_PR" >> $GITHUB_OUTPUT + else + echo "No existing PR found" + echo "existing_pr=" >> $GITHUB_OUTPUT + fi + + - name: Create or update branch + if: steps.check-commits.outputs.has_commits == 'true' && steps.analyze.outputs.has_changes == 'true' && steps.check-pr.outputs.existing_pr == '' + id: create-branch + run: | + DATE=$(date +%Y-%m-%d) + BRANCH="skills-update-${DATE}" + + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + # Create branch + git checkout -b "$BRANCH" + + # Add a timestamp to skills to track when they were last reviewed + for skill in .claude/skills/*.md; do + if [ -f "$skill" ]; then + # Add or update last-reviewed comment at end of file + if grep -q "//" "$skill" + else + echo "" >> "$skill" + echo "" >> "$skill" + fi + fi + done + + git add .claude/skills/ + git commit -m "chore: flag skills for review (${DATE})" + git push origin "$BRANCH" + + echo "branch=$BRANCH" >> $GITHUB_OUTPUT + + - name: Generate PR body + if: steps.check-commits.outputs.has_commits == 'true' && steps.analyze.outputs.has_changes == 'true' && steps.check-pr.outputs.existing_pr == '' + id: pr-body + run: | + DATE=$(date +%Y-%m-%d) + + # Build PR body safely without user-controlled content + cat > /tmp/pr_body.md << 'HEREDOC_END' + ## Weekly Skills Update Check + + This PR was automatically created because there were code changes this week that may require updates to the onboarding skills. + + ### Summary + HEREDOC_END + + echo "- **Total commits this week:** ${{ steps.check-commits.outputs.commit_count }}" >> /tmp/pr_body.md + echo "" >> /tmp/pr_body.md + + echo "### Skills Review Checklist" >> /tmp/pr_body.md + echo "" >> /tmp/pr_body.md + + if [ "${{ steps.analyze.outputs.contracts_count }}" -gt 0 ]; then + echo "#### contracts.md" >> /tmp/pr_body.md + echo "- **Files changed:** ${{ steps.analyze.outputs.contracts_count }}" >> /tmp/pr_body.md + echo "- [ ] Review and update contracts skill" >> /tmp/pr_body.md + echo "" >> /tmp/pr_body.md + fi + + if [ "${{ steps.analyze.outputs.core_count }}" -gt 0 ]; then + echo "#### ev-reth-core.md" >> /tmp/pr_body.md + echo "- **Files changed:** ${{ steps.analyze.outputs.core_count }}" >> /tmp/pr_body.md + echo "- [ ] Review and update core skill" >> /tmp/pr_body.md + echo "" >> /tmp/pr_body.md + fi + + if [ "${{ steps.analyze.outputs.evm_count }}" -gt 0 ]; then + echo "#### ev-reth-evm.md" >> /tmp/pr_body.md + echo "- **Files changed:** ${{ steps.analyze.outputs.evm_count }}" >> /tmp/pr_body.md + echo "- [ ] Review and update EVM skill" >> /tmp/pr_body.md + echo "" >> /tmp/pr_body.md + fi + + if [ "${{ steps.analyze.outputs.evolve_count }}" -gt 0 ]; then + echo "#### ev-reth-evolve.md" >> /tmp/pr_body.md + echo "- **Files changed:** ${{ steps.analyze.outputs.evolve_count }}" >> /tmp/pr_body.md + echo "- [ ] Review and update Evolve skill" >> /tmp/pr_body.md + echo "" >> /tmp/pr_body.md + fi + + if [ "${{ steps.analyze.outputs.tests_count }}" -gt 0 ]; then + echo "#### ev-reth-testing.md" >> /tmp/pr_body.md + echo "- **Files changed:** ${{ steps.analyze.outputs.tests_count }}" >> /tmp/pr_body.md + echo "- [ ] Review and update testing skill" >> /tmp/pr_body.md + echo "" >> /tmp/pr_body.md + fi + + cat >> /tmp/pr_body.md << 'HEREDOC_END' + + ### Instructions + 1. Review each skill file against the changed code + 2. Update descriptions, file references, and code examples as needed + 3. Check the boxes above as you complete each review + 4. Merge when all relevant skills are updated + + ### Useful Commands + ```bash + # See what changed in each area + git diff main -- crates/node/ bin/ev-reth/ + git diff main -- crates/ev-revm/ crates/ev-precompiles/ + git diff main -- crates/evolve/ + git diff main -- crates/tests/ + git diff main -- contracts/ + ``` + + --- + *This PR was auto-generated by the weekly skills update workflow.* + HEREDOC_END + + - name: Create Pull Request + if: steps.check-commits.outputs.has_commits == 'true' && steps.analyze.outputs.has_changes == 'true' && steps.check-pr.outputs.existing_pr == '' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BRANCH: ${{ steps.create-branch.outputs.branch }} + run: | + DATE=$(date +%Y-%m-%d) + gh pr create \ + --title "chore: weekly skills review (${DATE})" \ + --label "skills-update" \ + --body-file /tmp/pr_body.md + + - name: Update existing PR with comment + if: steps.check-commits.outputs.has_commits == 'true' && steps.analyze.outputs.has_changes == 'true' && steps.check-pr.outputs.existing_pr != '' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ steps.check-pr.outputs.existing_pr }} + run: | + DATE=$(date +%Y-%m-%d) + + # Build comment safely + cat > /tmp/comment.md << HEREDOC_END + ## Additional changes detected (${DATE}) + + New commits detected. Please review the updated file counts: + + | Skill | Files Changed | + |-------|---------------| + | contracts | ${{ steps.analyze.outputs.contracts_count }} | + | ev-reth-core | ${{ steps.analyze.outputs.core_count }} | + | ev-reth-evm | ${{ steps.analyze.outputs.evm_count }} | + | ev-reth-evolve | ${{ steps.analyze.outputs.evolve_count }} | + | ev-reth-testing | ${{ steps.analyze.outputs.tests_count }} | + HEREDOC_END + + gh pr comment "$PR_NUMBER" --body-file /tmp/comment.md From 609ea657fa67fd3910e2c7eb4d1ae9e79eaf2735 Mon Sep 17 00:00:00 2001 From: tac0turtle Date: Wed, 14 Jan 2026 14:41:38 +0100 Subject: [PATCH 2/3] update --- .github/workflows/update-skills.yml | 46 ++++++++++++++++++----------- contracts/lib/forge-std | 1 - 2 files changed, 29 insertions(+), 18 deletions(-) delete mode 160000 contracts/lib/forge-std diff --git a/.github/workflows/update-skills.yml b/.github/workflows/update-skills.yml index 2bf17b5..e2e7e2b 100644 --- a/.github/workflows/update-skills.yml +++ b/.github/workflows/update-skills.yml @@ -121,6 +121,13 @@ jobs: - name: Generate PR body if: steps.check-commits.outputs.has_commits == 'true' && steps.analyze.outputs.has_changes == 'true' && steps.check-pr.outputs.existing_pr == '' id: pr-body + env: + COMMIT_COUNT: ${{ steps.check-commits.outputs.commit_count }} + CONTRACTS_COUNT: ${{ steps.analyze.outputs.contracts_count }} + CORE_COUNT: ${{ steps.analyze.outputs.core_count }} + EVM_COUNT: ${{ steps.analyze.outputs.evm_count }} + EVOLVE_COUNT: ${{ steps.analyze.outputs.evolve_count }} + TESTS_COUNT: ${{ steps.analyze.outputs.tests_count }} run: | DATE=$(date +%Y-%m-%d) @@ -133,43 +140,43 @@ jobs: ### Summary HEREDOC_END - echo "- **Total commits this week:** ${{ steps.check-commits.outputs.commit_count }}" >> /tmp/pr_body.md + echo "- **Total commits this week:** ${COMMIT_COUNT:-0}" >> /tmp/pr_body.md echo "" >> /tmp/pr_body.md echo "### Skills Review Checklist" >> /tmp/pr_body.md echo "" >> /tmp/pr_body.md - if [ "${{ steps.analyze.outputs.contracts_count }}" -gt 0 ]; then + if [ "${CONTRACTS_COUNT:-0}" -gt 0 ]; then echo "#### contracts.md" >> /tmp/pr_body.md - echo "- **Files changed:** ${{ steps.analyze.outputs.contracts_count }}" >> /tmp/pr_body.md + echo "- **Files changed:** $CONTRACTS_COUNT" >> /tmp/pr_body.md echo "- [ ] Review and update contracts skill" >> /tmp/pr_body.md echo "" >> /tmp/pr_body.md fi - if [ "${{ steps.analyze.outputs.core_count }}" -gt 0 ]; then + if [ "${CORE_COUNT:-0}" -gt 0 ]; then echo "#### ev-reth-core.md" >> /tmp/pr_body.md - echo "- **Files changed:** ${{ steps.analyze.outputs.core_count }}" >> /tmp/pr_body.md + echo "- **Files changed:** $CORE_COUNT" >> /tmp/pr_body.md echo "- [ ] Review and update core skill" >> /tmp/pr_body.md echo "" >> /tmp/pr_body.md fi - if [ "${{ steps.analyze.outputs.evm_count }}" -gt 0 ]; then + if [ "${EVM_COUNT:-0}" -gt 0 ]; then echo "#### ev-reth-evm.md" >> /tmp/pr_body.md - echo "- **Files changed:** ${{ steps.analyze.outputs.evm_count }}" >> /tmp/pr_body.md + echo "- **Files changed:** $EVM_COUNT" >> /tmp/pr_body.md echo "- [ ] Review and update EVM skill" >> /tmp/pr_body.md echo "" >> /tmp/pr_body.md fi - if [ "${{ steps.analyze.outputs.evolve_count }}" -gt 0 ]; then + if [ "${EVOLVE_COUNT:-0}" -gt 0 ]; then echo "#### ev-reth-evolve.md" >> /tmp/pr_body.md - echo "- **Files changed:** ${{ steps.analyze.outputs.evolve_count }}" >> /tmp/pr_body.md + echo "- **Files changed:** $EVOLVE_COUNT" >> /tmp/pr_body.md echo "- [ ] Review and update Evolve skill" >> /tmp/pr_body.md echo "" >> /tmp/pr_body.md fi - if [ "${{ steps.analyze.outputs.tests_count }}" -gt 0 ]; then + if [ "${TESTS_COUNT:-0}" -gt 0 ]; then echo "#### ev-reth-testing.md" >> /tmp/pr_body.md - echo "- **Files changed:** ${{ steps.analyze.outputs.tests_count }}" >> /tmp/pr_body.md + echo "- **Files changed:** $TESTS_COUNT" >> /tmp/pr_body.md echo "- [ ] Review and update testing skill" >> /tmp/pr_body.md echo "" >> /tmp/pr_body.md fi @@ -213,10 +220,15 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} PR_NUMBER: ${{ steps.check-pr.outputs.existing_pr }} + CONTRACTS_COUNT: ${{ steps.analyze.outputs.contracts_count }} + CORE_COUNT: ${{ steps.analyze.outputs.core_count }} + EVM_COUNT: ${{ steps.analyze.outputs.evm_count }} + EVOLVE_COUNT: ${{ steps.analyze.outputs.evolve_count }} + TESTS_COUNT: ${{ steps.analyze.outputs.tests_count }} run: | DATE=$(date +%Y-%m-%d) - # Build comment safely + # Build comment safely using environment variables cat > /tmp/comment.md << HEREDOC_END ## Additional changes detected (${DATE}) @@ -224,11 +236,11 @@ jobs: | Skill | Files Changed | |-------|---------------| - | contracts | ${{ steps.analyze.outputs.contracts_count }} | - | ev-reth-core | ${{ steps.analyze.outputs.core_count }} | - | ev-reth-evm | ${{ steps.analyze.outputs.evm_count }} | - | ev-reth-evolve | ${{ steps.analyze.outputs.evolve_count }} | - | ev-reth-testing | ${{ steps.analyze.outputs.tests_count }} | + | contracts | ${CONTRACTS_COUNT:-0} | + | ev-reth-core | ${CORE_COUNT:-0} | + | ev-reth-evm | ${EVM_COUNT:-0} | + | ev-reth-evolve | ${EVOLVE_COUNT:-0} | + | ev-reth-testing | ${TESTS_COUNT:-0} | HEREDOC_END gh pr comment "$PR_NUMBER" --body-file /tmp/comment.md diff --git a/contracts/lib/forge-std b/contracts/lib/forge-std deleted file mode 160000 index 8e40513..0000000 --- a/contracts/lib/forge-std +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8e40513d678f392f398620b3ef2b418648b33e89 From a22027676fcdfaaca4289fe9feebc1bc5044d058 Mon Sep 17 00:00:00 2001 From: tac0turtle Date: Wed, 14 Jan 2026 14:56:57 +0100 Subject: [PATCH 3/3] add back forge --- contracts/lib/forge-std | 1 + 1 file changed, 1 insertion(+) create mode 160000 contracts/lib/forge-std diff --git a/contracts/lib/forge-std b/contracts/lib/forge-std new file mode 160000 index 0000000..887e872 --- /dev/null +++ b/contracts/lib/forge-std @@ -0,0 +1 @@ +Subproject commit 887e87251562513a7b5ab1ea517c039fe6ee0984