[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6FXHB5ADYRA22XM5DATPAMR":3,"skill-same:01M6FXHB5ADYRA22XM5DATPAMR":57},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":31,"linkOnly":32,"markdownContent":33,"markdownBody":34,"frontMatter":35,"refName":36,"commitSha":37,"skillDirectory":38,"forksCount":39,"repositoryHtmlUrl":40,"repositoryHomepageUrl":6,"ownerHtmlUrl":41,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":42,"install":43,"resources":56},"01M6FXHB5ADYRA22XM5DATPAMR","jb-project",null,"Create and configure Juicebox V5 projects. Generate deployment scripts for launching projects with rulesets, terminals, and splits using JBController. Also helps with project ownership transfer and metadata updates.","kbarbel640-del\u002Fskills","kbarbel640-del","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F255315490?v=4","01M6CJPPQGCCESXMG3K7BBGQ5J","01M6CJPPX2PB2BCZERFVM2C2B3",1,"MIT","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fmejango\u002Fjuicy\u002Fjb-project\u002FSKILL.md",[],[18,19,20,21,22,23,24,25,26,27,28,29,30],"project","jb project","deployment","create","generate","metadata","transfer","configure","projects","scripts","ownership","with","juicebox v5","2026-11-10 10:12:30",false,"---\nname: jb-project\ndescription: Create and configure Juicebox V5 projects. Generate deployment scripts for launching projects with rulesets, terminals, and splits using JBController. Also helps with project ownership transfer and metadata updates.\n---\n\n# Juicebox V5 Project Management\n\nCreate and manage Juicebox V5 projects including deployment, configuration, and ownership.\n\n## Project Identity\n\n**A Juicebox project is uniquely identified by: `projectId + chainId + version`**\n\nThis matters because:\n- **V4 and V5 are different protocols.** Project #64 on V4 is NOT the same as Project #64 on V5, even on the same chain.\n- **Project IDs cannot be coordinated across chains.** Each chain assigns the next available ID independently. If you deploy to Ethereum you might get project #42, and deploying to Optimism might give you project #17.\n- **Suckers link projects across chains.** To create an \"omnichain project,\" you deploy separate projects on each chain (with different IDs) and connect them using Suckers. This enables token bridging while maintaining treasury backing.\n- When referencing a project, always specify the version and chain to avoid confusion.\n\n## V5.1 Contract Update (Dec 2025)\n\n**Only JBRulesets has a code change** (one-line approval hook fix). Other contracts were redeployed due to dependency chains (JBTerminalStore→JBMultiTerminal, JB721TiersHook→JB721TiersHookDeployer→JBOmnichainDeployer).\n\n| Deploying... | Use These Contracts |\n|--------------|---------------------|\n| New project | **V5.1** (JBController5_1, JBMultiTerminal5_1, etc.) |\n| Revnet | **V5.0** (REVDeployer uses V5.0 JBController) |\n\n**Do not mix V5.0 and V5.1 contracts** - use one complete set or the other.\n\nSee `references\u002Fv5-addresses.md` or `shared\u002Fchain-config.json` for addresses.\n\n## Before Writing Custom Code\n\n**Always check if native mechanics can achieve your goal:**\n\n| User Need | Recommended Solution |\n|-----------|---------------------|\n| Autonomous tokenized treasury | Deploy a **Revnet** via revnet-core-v5 |\n| Project with structured rules and no EOA owner | Use contract-as-owner pattern |\n| Simple fundraising project | Use this skill to generate deployment |\n| Vesting\u002Ftime-locked distributions | Use **payout limits + cycling rulesets** (no custom contracts) |\n| NFT-gated treasury | Use **nana-721-hook-v5** with native cash outs |\n| Governance-minimal\u002Fimmutable | Transfer ownership to **burn address** after setup |\n| One-time treasury access | Use **surplus allowance** (doesn't reset each cycle) |\n| Custom token mechanics | Use **custom ERC20** via `setTokenFor()` |\n\n**See `\u002Fjb-patterns` for detailed examples of these patterns.**\n**See `\u002Fjb-simplify` for a checklist to reduce custom code.**\n\n## Project Creation Overview\n\nProjects are created through `JBController.launchProjectFor()` which:\n1. Creates a new project NFT via JBProjects\n2. Sets the controller for the project\n3. Configures the first ruleset\n4. Sets up terminal configurations\n\n## Core Functions\n\n### Launch a Project\n\n```solidity\nfunction launchProjectFor(\n    address owner,                              \u002F\u002F Project owner (receives NFT)\n    string calldata projectUri,                 \u002F\u002F IPFS metadata URI\n    JBRulesetConfig[] calldata rulesetConfigs,  \u002F\u002F Initial ruleset(s)\n    JBTerminalConfig[] calldata terminalConfigs, \u002F\u002F Terminal setup\n    string calldata memo                        \u002F\u002F Launch memo\n) external returns (uint256 projectId);\n```\n\n### Project Metadata (projectUri)\n\nThe `projectUri` should point to a JSON file (typically on IPFS) with:\n\n```json\n{\n  \"name\": \"Project Name\",\n  \"description\": \"Project description\",\n  \"logoUri\": \"ipfs:\u002F\u002F...\",\n  \"infoUri\": \"https:\u002F\u002F...\",\n  \"twitter\": \"@handle\",\n  \"discord\": \"https:\u002F\u002Fdiscord.gg\u002F...\",\n  \"telegram\": \"https:\u002F\u002Ft.me\u002F...\"\n}\n```\n\n## Configuration Structs\n\n### JBRulesetConfig\n\n```solidity\nstruct JBRulesetConfig {\n    uint256 mustStartAtOrAfter;     \u002F\u002F Earliest start time (0 = now)\n    uint256 duration;               \u002F\u002F Duration in seconds (0 = indefinite)\n    uint256 weight;                 \u002F\u002F Token minting weight (18 decimals)\n    uint256 weightCutPercent;       \u002F\u002F Weight cut per cycle (0-1000000000)\n    IJBRulesetApprovalHook approvalHook;  \u002F\u002F Approval hook (e.g., JBDeadline)\n    JBRulesetMetadata metadata;     \u002F\u002F Ruleset settings\n    JBSplitGroup[] splitGroups;     \u002F\u002F Payout and reserved splits\n    JBFundAccessLimitGroup[] fundAccessLimitGroups;  \u002F\u002F Payout limits\n}\n```\n\n### JBTerminalConfig\n\n```solidity\nstruct JBTerminalConfig {\n    IJBTerminal terminal;                   \u002F\u002F Terminal contract\n    JBAccountingContext[] accountingContexts;  \u002F\u002F Accepted tokens\n}\n```\n\n### JBAccountingContext\n\n```solidity\nstruct JBAccountingContext {\n    address token;          \u002F\u002F Token address (address(0) for native)\n    uint8 decimals;         \u002F\u002F Token decimals\n    uint32 currency;        \u002F\u002F Currency ID for accounting\n}\n```\n\n## Deployment Script Example\n\n```solidity\n\u002F\u002F SPDX-License-Identifier: MIT\npragma solidity ^0.8.23;\n\nimport {Script} from \"forge-std\u002FScript.sol\";\nimport {IJBController} from \"@bananapus\u002Fcore\u002Fsrc\u002Finterfaces\u002FIJBController.sol\";\nimport {IJBMultiTerminal} from \"@bananapus\u002Fcore\u002Fsrc\u002Finterfaces\u002FIJBMultiTerminal.sol\";\nimport {JBRulesetConfig} from \"@bananapus\u002Fcore\u002Fsrc\u002Fstructs\u002FJBRulesetConfig.sol\";\nimport {JBRulesetMetadata} from \"@bananapus\u002Fcore\u002Fsrc\u002Fstructs\u002FJBRulesetMetadata.sol\";\nimport {JBTerminalConfig} from \"@bananapus\u002Fcore\u002Fsrc\u002Fstructs\u002FJBTerminalConfig.sol\";\nimport {JBAccountingContext} from \"@bananapus\u002Fcore\u002Fsrc\u002Fstructs\u002FJBAccountingContext.sol\";\nimport {JBSplitGroup} from \"@bananapus\u002Fcore\u002Fsrc\u002Fstructs\u002FJBSplitGroup.sol\";\nimport {JBSplit} from \"@bananapus\u002Fcore\u002Fsrc\u002Fstructs\u002FJBSplit.sol\";\nimport {JBFundAccessLimitGroup} from \"@bananapus\u002Fcore\u002Fsrc\u002Fstructs\u002FJBFundAccessLimitGroup.sol\";\nimport {JBCurrencyAmount} from \"@bananapus\u002Fcore\u002Fsrc\u002Fstructs\u002FJBCurrencyAmount.sol\";\nimport {JBConstants} from \"@bananapus\u002Fcore\u002Fsrc\u002Flibraries\u002FJBConstants.sol\";\n\ncontract DeployProject is Script {\n    \u002F\u002F V5.1 Mainnet Addresses (use for new projects)\n    \u002F\u002F See \u002Freferences\u002Fv5-addresses.md for all networks\n    \u002F\u002F NOTE: For revnets, use V5.0 addresses instead\n    IJBController constant CONTROLLER = IJBController(0xf3cc99b11bd73a2e3b8815fb85fe0381b29987e1);\n    IJBMultiTerminal constant TERMINAL = IJBMultiTerminal(0x52869db3d61dde1e391967f2ce5039ad0ecd371c);\n\n    function run() external {\n        vm.startBroadcast();\n\n        \u002F\u002F Configure ruleset metadata\n        JBRulesetMetadata memory metadata = JBRulesetMetadata({\n            reservedRate: 0,                    \u002F\u002F No reserved tokens\n            cashOutTaxRate: 0,                  \u002F\u002F No cash out tax\n            baseCurrency: uint32(uint160(JBConstants.NATIVE_TOKEN)),\n            pausePay: false,\n            pauseCashOut: false,\n            pauseTransfers: false,\n            allowOwnerMinting: false,\n            allowTerminalMigration: false,\n            allowSetTerminals: false,\n            allowSetController: false,\n            allowAddAccountingContexts: false,\n            allowAddPriceFeed: false,\n            ownerMustSendPayouts: false,\n            holdFees: false,\n            useTotalSurplusForCashOuts: false,\n            useDataHookForPay: false,\n            useDataHookForCashOut: false,\n            dataHook: address(0),\n            metadata: 0\n        });\n\n        \u002F\u002F Configure splits (empty for now)\n        JBSplitGroup[] memory splitGroups = new JBSplitGroup[](0);\n\n        \u002F\u002F Configure fund access limits\n        JBFundAccessLimitGroup[] memory fundAccessLimits = new JBFundAccessLimitGroup[](0);\n\n        \u002F\u002F Build ruleset config\n        JBRulesetConfig[] memory rulesetConfigs = new JBRulesetConfig[](1);\n        rulesetConfigs[0] = JBRulesetConfig({\n            mustStartAtOrAfter: 0,\n            duration: 0,                        \u002F\u002F Indefinite\n            weight: 1e18,                       \u002F\u002F 1 token per unit paid\n            weightCutPercent: 0,                \u002F\u002F No weight cut\n            approvalHook: IJBRulesetApprovalHook(address(0)),\n            metadata: metadata,\n            splitGroups: splitGroups,\n            fundAccessLimitGroups: fundAccessLimits\n        });\n\n        \u002F\u002F Configure terminal to accept ETH\n        JBAccountingContext[] memory accountingContexts = new JBAccountingContext[](1);\n        accountingContexts[0] = JBAccountingContext({\n            token: JBConstants.NATIVE_TOKEN,\n            decimals: 18,\n            currency: uint32(uint160(JBConstants.NATIVE_TOKEN))\n        });\n\n        JBTerminalConfig[] memory terminalConfigs = new JBTerminalConfig[](1);\n        terminalConfigs[0] = JBTerminalConfig({\n            terminal: TERMINAL,\n            accountingContexts: accountingContexts\n        });\n\n        \u002F\u002F Launch the project\n        uint256 projectId = CONTROLLER.launchProjectFor(\n            msg.sender,                         \u002F\u002F Owner\n            \"ipfs:\u002F\u002F...\",                       \u002F\u002F Project metadata URI\n            rulesetConfigs,\n            terminalConfigs,\n            \"Project launch\"                    \u002F\u002F Memo\n        );\n\n        vm.stopBroadcast();\n    }\n}\n```\n\n## Custom ERC20 Project Tokens\n\nBy default, Juicebox projects use **credits** (unclaimed internal balances). You can upgrade to an ERC20 token two ways:\n\n### Option 1: Deploy Standard JBERC20\n\n```solidity\n\u002F\u002F Deploy the default Juicebox ERC20 token\nIJBToken token = CONTROLLER.deployERC20For(\n    projectId,\n    \"Project Token\",    \u002F\u002F name\n    \"PROJ\",             \u002F\u002F symbol\n    bytes32(0)          \u002F\u002F salt (for deterministic address, or 0)\n);\n```\n\nThis creates a standard `JBERC20` that the controller can mint\u002Fburn. Simple and works for most projects.\n\n### Option 2: Use a Custom ERC20\n\nFor advanced tokenomics, you can bring your own ERC20:\n\n```solidity\n\u002F\u002F Set an existing\u002Fcustom ERC20 as the project token\nCONTROLLER.setTokenFor(projectId, IJBToken(myCustomToken));\n```\n\n**Requirements for custom tokens:**\n1. Must use **18 decimals**\n2. Must implement `canBeAddedTo(uint256 projectId)` returning `true`\n3. Must not be assigned to another Juicebox project\n4. Controller needs mint\u002Fburn permissions (typically via ownership or access control)\n\n### Custom Token Interface\n\n```solidity\ninterface IJBToken is IERC20 {\n    \u002F\u002F\u002F @notice Verify this token can be added to a project.\n    \u002F\u002F\u002F @param projectId The project ID to check.\n    \u002F\u002F\u002F @return True if the token can be added.\n    function canBeAddedTo(uint256 projectId) external view returns (bool);\n\n    \u002F\u002F\u002F @notice Mint tokens to an account.\n    \u002F\u002F\u002F @param holder The account to mint to.\n    \u002F\u002F\u002F @param amount The amount to mint.\n    function mint(address holder, uint256 amount) external;\n\n    \u002F\u002F\u002F @notice Burn tokens from an account.\n    \u002F\u002F\u002F @param holder The account to burn from.\n    \u002F\u002F\u002F @param amount The amount to burn.\n    function burn(address holder, uint256 amount) external;\n}\n```\n\n### When to Use Custom ERC20s\n\n| Use Case | Why Custom ERC20 |\n|----------|------------------|\n| **Transfer taxes** | Implement fees on transfers (e.g., reflection tokens) |\n| **Rebasing tokens** | Elastic supply that adjusts balances automatically |\n| **Pre-existing tokens** | Integrate a community token with established holders |\n| **Governance features** | Voting snapshots, delegation, checkpointing |\n| **Vesting schedules** | Built-in unlock mechanics in the token itself |\n| **Allowlist\u002Fdenylist** | Transfer restrictions for compliance |\n| **Concentration limits** | Cap max holdings per address for distribution |\n| **Editable metadata** | Rebrand name\u002Fsymbol without redeploying |\n\n### Example: Custom Token with Transfer Tax\n\n```solidity\n\u002F\u002F SPDX-License-Identifier: MIT\npragma solidity ^0.8.23;\n\nimport {ERC20} from \"@openzeppelin\u002Fcontracts\u002Ftoken\u002FERC20\u002FERC20.sol\";\nimport {Ownable} from \"@openzeppelin\u002Fcontracts\u002Faccess\u002FOwnable.sol\";\n\ncontract TaxedProjectToken is ERC20, Ownable {\n    uint256 public constant TAX_RATE = 100; \u002F\u002F 1% (basis points)\n    uint256 public constant TAX_DENOMINATOR = 10000;\n    address public taxRecipient;\n    address public controller;\n    uint256 public projectId;\n\n    constructor(\n        string memory name,\n        string memory symbol,\n        address _controller,\n        uint256 _projectId,\n        address _taxRecipient\n    ) ERC20(name, symbol) Ownable(msg.sender) {\n        controller = _controller;\n        projectId = _projectId;\n        taxRecipient = _taxRecipient;\n    }\n\n    function decimals() public pure override returns (uint8) {\n        return 18; \u002F\u002F REQUIRED: Must be 18 decimals\n    }\n\n    function canBeAddedTo(uint256 _projectId) external view returns (bool) {\n        return _projectId == projectId; \u002F\u002F Only allow for our project\n    }\n\n    function mint(address holder, uint256 amount) external {\n        require(msg.sender == controller, \"Only controller\");\n        _mint(holder, amount);\n    }\n\n    function burn(address holder, uint256 amount) external {\n        require(msg.sender == controller || msg.sender == holder, \"Not authorized\");\n        _burn(holder, amount);\n    }\n\n    function _update(address from, address to, uint256 amount) internal override {\n        \u002F\u002F Skip tax for mints, burns, and controller operations\n        if (from == address(0) || to == address(0) || msg.sender == controller) {\n            super._update(from, to, amount);\n            return;\n        }\n\n        \u002F\u002F Apply transfer tax\n        uint256 tax = (amount * TAX_RATE) \u002F TAX_DENOMINATOR;\n        uint256 netAmount = amount - tax;\n\n        super._update(from, taxRecipient, tax);\n        super._update(from, to, netAmount);\n    }\n}\n```\n\n### Example: Integrating Existing Community Token\n\n```solidity\n\u002F\u002F SPDX-License-Identifier: MIT\npragma solidity ^0.8.23;\n\nimport {ERC20} from \"@openzeppelin\u002Fcontracts\u002Ftoken\u002FERC20\u002FERC20.sol\";\nimport {AccessControl} from \"@openzeppelin\u002Fcontracts\u002Faccess\u002FAccessControl.sol\";\n\n\u002F\u002F\u002F @notice Wrapper to make an existing token compatible with Juicebox.\n\u002F\u002F\u002F @dev For tokens that already exist - create a wrapper that the JB controller can mint.\ncontract JBCompatibleToken is ERC20, AccessControl {\n    bytes32 public constant MINTER_ROLE = keccak256(\"MINTER_ROLE\");\n    uint256 public immutable targetProjectId;\n\n    constructor(\n        string memory name,\n        string memory symbol,\n        uint256 _projectId,\n        address controller\n    ) ERC20(name, symbol) {\n        targetProjectId = _projectId;\n        _grantRole(DEFAULT_ADMIN_ROLE, msg.sender);\n        _grantRole(MINTER_ROLE, controller);\n    }\n\n    function decimals() public pure override returns (uint8) {\n        return 18;\n    }\n\n    function canBeAddedTo(uint256 projectId) external view returns (bool) {\n        return projectId == targetProjectId;\n    }\n\n    function mint(address to, uint256 amount) external onlyRole(MINTER_ROLE) {\n        _mint(to, amount);\n    }\n\n    function burn(address from, uint256 amount) external onlyRole(MINTER_ROLE) {\n        _burn(from, amount);\n    }\n}\n```\n\n### Example: Editable Name\u002FSymbol Token\n\nAllows project owners to rebrand without redeploying or migrating liquidity:\n\n```solidity\n\u002F\u002F SPDX-License-Identifier: MIT\npragma solidity ^0.8.23;\n\nimport {ERC20} from \"@openzeppelin\u002Fcontracts\u002Ftoken\u002FERC20\u002FERC20.sol\";\nimport {IJBProjects} from \"@bananapus\u002Fcore\u002Fsrc\u002Finterfaces\u002FIJBProjects.sol\";\n\ncontract EditableProjectToken is ERC20 {\n    IJBProjects public immutable PROJECTS;\n    address public immutable controller;\n    uint256 public immutable projectId;\n\n    string private _tokenName;\n    string private _tokenSymbol;\n\n    event NameUpdated(string oldName, string newName);\n    event SymbolUpdated(string oldSymbol, string newSymbol);\n\n    constructor(\n        string memory initialName,\n        string memory initialSymbol,\n        address _controller,\n        uint256 _projectId,\n        IJBProjects projects\n    ) ERC20(initialName, initialSymbol) {\n        _tokenName = initialName;\n        _tokenSymbol = initialSymbol;\n        controller = _controller;\n        projectId = _projectId;\n        PROJECTS = projects;\n    }\n\n    modifier onlyProjectOwner() {\n        require(msg.sender == PROJECTS.ownerOf(projectId), \"NOT_OWNER\");\n        _;\n    }\n\n    function name() public view override returns (string memory) { return _tokenName; }\n    function symbol() public view override returns (string memory) { return _tokenSymbol; }\n    function decimals() public pure override returns (uint8) { return 18; }\n\n    function canBeAddedTo(uint256 _projectId) external view returns (bool) {\n        return _projectId == projectId;\n    }\n\n    function mint(address to, uint256 amount) external {\n        require(msg.sender == controller, \"UNAUTHORIZED\");\n        _mint(to, amount);\n    }\n\n    function burn(address from, uint256 amount) external {\n        require(msg.sender == controller, \"UNAUTHORIZED\");\n        _burn(from, amount);\n    }\n\n    \u002F\u002F\u002F @notice Update token name. Only callable by project owner.\n    function setName(string calldata newName) external onlyProjectOwner {\n        emit NameUpdated(_tokenName, newName);\n        _tokenName = newName;\n    }\n\n    \u002F\u002F\u002F @notice Update token symbol. Only callable by project owner.\n    function setSymbol(string calldata newSymbol) external onlyProjectOwner {\n        emit SymbolUpdated(_tokenSymbol, newSymbol);\n        _tokenSymbol = newSymbol;\n    }\n}\n```\n\n**Note**: Some DEXs\u002Faggregators cache metadata. Changes may take time to propagate.\n\n### Tradeoffs\n\n| Approach | Pros | Cons |\n|----------|------|------|\n| **Credits only** | Zero deployment cost, simplest | Not transferable, no DeFi integration |\n| **Standard JBERC20** | Simple, compatible, audited | No custom mechanics |\n| **Custom ERC20** | Full control over tokenomics | More complexity, audit burden, must maintain 18 decimals |\n\n### Critical Considerations\n\n1. **Controller must have mint\u002Fburn access** - The JBController needs to mint tokens on payments and burn on cash outs\n2. **18 decimals is mandatory** - The entire Juicebox math assumes 18 decimal tokens\n3. **One token per project** - A token can only be assigned to one project\n4. **Credits convert to tokens** - Existing credit holders can claim tokens after ERC20 is set\n5. **Token can't be changed** - Once set, you cannot swap to a different token contract\n\n## Other Project Operations\n\n### Transfer Ownership\n\nProject ownership is an ERC-721 NFT. Transfer using standard ERC-721:\n\n```solidity\nIJBProjects(PROJECTS).transferFrom(currentOwner, newOwner, projectId);\n```\n\n### Set Project Metadata\n\n```solidity\nIJBProjects(PROJECTS).setTokenURI(projectId, \"ipfs:\u002F\u002FnewUri\");\n```\n\n### Add Terminals\n\n```solidity\nIJBDirectory(DIRECTORY).setTerminalsOf(projectId, terminals);\n```\n\n## Generation Guidelines\n\n1. **Ask about project requirements** - ownership model, token economics, payout structure\n2. **Consider Revnets** if autonomous operation is desired\n3. **Configure appropriate metadata** - reserved rate, cash out tax, permissions\n4. **Set up splits** for payouts and reserved tokens\n5. **Generate deployment scripts** using Foundry\n\n## Example Prompts\n\n- \"Create a project that mints 1000 tokens per ETH with 10% reserved\"\n- \"Set up a project with weekly payout cycles to 3 addresses\"\n- \"Deploy a project with a 3-day approval delay for ruleset changes\"\n- \"Create a project that accepts both ETH and USDC\"\n\n## Reference\n\n- **nana-core-v5**: https:\u002F\u002Fgithub.com\u002FBananapus\u002Fnana-core-v5\n- **revnet-core-v5**: https:\u002F\u002Fgithub.com\u002Frev-net\u002Frevnet-core-v5\n","# Juicebox V5 Project Management\n\nCreate and manage Juicebox V5 projects including deployment, configuration, and ownership.\n\n## Project Identity\n\n**A Juicebox project is uniquely identified by: `projectId + chainId + version`**\n\nThis matters because:\n- **V4 and V5 are different protocols.** Project #64 on V4 is NOT the same as Project #64 on V5, even on the same chain.\n- **Project IDs cannot be coordinated across chains.** Each chain assigns the next available ID independently. If you deploy to Ethereum you might get project #42, and deploying to Optimism might give you project #17.\n- **Suckers link projects across chains.** To create an \"omnichain project,\" you deploy separate projects on each chain (with different IDs) and connect them using Suckers. This enables token bridging while maintaining treasury backing.\n- When referencing a project, always specify the version and chain to avoid confusion.\n\n## V5.1 Contract Update (Dec 2025)\n\n**Only JBRulesets has a code change** (one-line approval hook fix). Other contracts were redeployed due to dependency chains (JBTerminalStore→JBMultiTerminal, JB721TiersHook→JB721TiersHookDeployer→JBOmnichainDeployer).\n\n| Deploying... | Use These Contracts |\n|--------------|---------------------|\n| New project | **V5.1** (JBController5_1, JBMultiTerminal5_1, etc.) |\n| Revnet | **V5.0** (REVDeployer uses V5.0 JBController) |\n\n**Do not mix V5.0 and V5.1 contracts** - use one complete set or the other.\n\nSee `references\u002Fv5-addresses.md` or `shared\u002Fchain-config.json` for addresses.\n\n## Before Writing Custom Code\n\n**Always check if native mechanics can achieve your goal:**\n\n| User Need | Recommended Solution |\n|-----------|---------------------|\n| Autonomous tokenized treasury | Deploy a **Revnet** via revnet-core-v5 |\n| Project with structured rules and no EOA owner | Use contract-as-owner pattern |\n| Simple fundraising project | Use this skill to generate deployment |\n| Vesting\u002Ftime-locked distributions | Use **payout limits + cycling rulesets** (no custom contracts) |\n| NFT-gated treasury | Use **nana-721-hook-v5** with native cash outs |\n| Governance-minimal\u002Fimmutable | Transfer ownership to **burn address** after setup |\n| One-time treasury access | Use **surplus allowance** (doesn't reset each cycle) |\n| Custom token mechanics | Use **custom ERC20** via `setTokenFor()` |\n\n**See `\u002Fjb-patterns` for detailed examples of these patterns.**\n**See `\u002Fjb-simplify` for a checklist to reduce custom code.**\n\n## Project Creation Overview\n\nProjects are created through `JBController.launchProjectFor()` which:\n1. Creates a new project NFT via JBProjects\n2. Sets the controller for the project\n3. Configures the first ruleset\n4. Sets up terminal configurations\n\n## Core Functions\n\n### Launch a Project\n\n```solidity\nfunction launchProjectFor(\n    address owner,                              \u002F\u002F Project owner (receives NFT)\n    string calldata projectUri,                 \u002F\u002F IPFS metadata URI\n    JBRulesetConfig[] calldata rulesetConfigs,  \u002F\u002F Initial ruleset(s)\n    JBTerminalConfig[] calldata terminalConfigs, \u002F\u002F Terminal setup\n    string calldata memo                        \u002F\u002F Launch memo\n) external returns (uint256 projectId);\n```\n\n### Project Metadata (projectUri)\n\nThe `projectUri` should point to a JSON file (typically on IPFS) with:\n\n```json\n{\n  \"name\": \"Project Name\",\n  \"description\": \"Project description\",\n  \"logoUri\": \"ipfs:\u002F\u002F...\",\n  \"infoUri\": \"https:\u002F\u002F...\",\n  \"twitter\": \"@handle\",\n  \"discord\": \"https:\u002F\u002Fdiscord.gg\u002F...\",\n  \"telegram\": \"https:\u002F\u002Ft.me\u002F...\"\n}\n```\n\n## Configuration Structs\n\n### JBRulesetConfig\n\n```solidity\nstruct JBRulesetConfig {\n    uint256 mustStartAtOrAfter;     \u002F\u002F Earliest start time (0 = now)\n    uint256 duration;               \u002F\u002F Duration in seconds (0 = indefinite)\n    uint256 weight;                 \u002F\u002F Token minting weight (18 decimals)\n    uint256 weightCutPercent;       \u002F\u002F Weight cut per cycle (0-1000000000)\n    IJBRulesetApprovalHook approvalHook;  \u002F\u002F Approval hook (e.g., JBDeadline)\n    JBRulesetMetadata metadata;     \u002F\u002F Ruleset settings\n    JBSplitGroup[] splitGroups;     \u002F\u002F Payout and reserved splits\n    JBFundAccessLimitGroup[] fundAccessLimitGroups;  \u002F\u002F Payout limits\n}\n```\n\n### JBTerminalConfig\n\n```solidity\nstruct JBTerminalConfig {\n    IJBTerminal terminal;                   \u002F\u002F Terminal contract\n    JBAccountingContext[] accountingContexts;  \u002F\u002F Accepted tokens\n}\n```\n\n### JBAccountingContext\n\n```solidity\nstruct JBAccountingContext {\n    address token;          \u002F\u002F Token address (address(0) for native)\n    uint8 decimals;         \u002F\u002F Token decimals\n    uint32 currency;        \u002F\u002F Currency ID for accounting\n}\n```\n\n## Deployment Script Example\n\n```solidity\n\u002F\u002F SPDX-License-Identifier: MIT\npragma solidity ^0.8.23;\n\nimport {Script} from \"forge-std\u002FScript.sol\";\nimport {IJBController} from \"@bananapus\u002Fcore\u002Fsrc\u002Finterfaces\u002FIJBController.sol\";\nimport {IJBMultiTerminal} from \"@bananapus\u002Fcore\u002Fsrc\u002Finterfaces\u002FIJBMultiTerminal.sol\";\nimport {JBRulesetConfig} from \"@bananapus\u002Fcore\u002Fsrc\u002Fstructs\u002FJBRulesetConfig.sol\";\nimport {JBRulesetMetadata} from \"@bananapus\u002Fcore\u002Fsrc\u002Fstructs\u002FJBRulesetMetadata.sol\";\nimport {JBTerminalConfig} from \"@bananapus\u002Fcore\u002Fsrc\u002Fstructs\u002FJBTerminalConfig.sol\";\nimport {JBAccountingContext} from \"@bananapus\u002Fcore\u002Fsrc\u002Fstructs\u002FJBAccountingContext.sol\";\nimport {JBSplitGroup} from \"@bananapus\u002Fcore\u002Fsrc\u002Fstructs\u002FJBSplitGroup.sol\";\nimport {JBSplit} from \"@bananapus\u002Fcore\u002Fsrc\u002Fstructs\u002FJBSplit.sol\";\nimport {JBFundAccessLimitGroup} from \"@bananapus\u002Fcore\u002Fsrc\u002Fstructs\u002FJBFundAccessLimitGroup.sol\";\nimport {JBCurrencyAmount} from \"@bananapus\u002Fcore\u002Fsrc\u002Fstructs\u002FJBCurrencyAmount.sol\";\nimport {JBConstants} from \"@bananapus\u002Fcore\u002Fsrc\u002Flibraries\u002FJBConstants.sol\";\n\ncontract DeployProject is Script {\n    \u002F\u002F V5.1 Mainnet Addresses (use for new projects)\n    \u002F\u002F See \u002Freferences\u002Fv5-addresses.md for all networks\n    \u002F\u002F NOTE: For revnets, use V5.0 addresses instead\n    IJBController constant CONTROLLER = IJBController(0xf3cc99b11bd73a2e3b8815fb85fe0381b29987e1);\n    IJBMultiTerminal constant TERMINAL = IJBMultiTerminal(0x52869db3d61dde1e391967f2ce5039ad0ecd371c);\n\n    function run() external {\n        vm.startBroadcast();\n\n        \u002F\u002F Configure ruleset metadata\n        JBRulesetMetadata memory metadata = JBRulesetMetadata({\n            reservedRate: 0,                    \u002F\u002F No reserved tokens\n            cashOutTaxRate: 0,                  \u002F\u002F No cash out tax\n            baseCurrency: uint32(uint160(JBConstants.NATIVE_TOKEN)),\n            pausePay: false,\n            pauseCashOut: false,\n            pauseTransfers: false,\n            allowOwnerMinting: false,\n            allowTerminalMigration: false,\n            allowSetTerminals: false,\n            allowSetController: false,\n            allowAddAccountingContexts: false,\n            allowAddPriceFeed: false,\n            ownerMustSendPayouts: false,\n            holdFees: false,\n            useTotalSurplusForCashOuts: false,\n            useDataHookForPay: false,\n            useDataHookForCashOut: false,\n            dataHook: address(0),\n            metadata: 0\n        });\n\n        \u002F\u002F Configure splits (empty for now)\n        JBSplitGroup[] memory splitGroups = new JBSplitGroup[](0);\n\n        \u002F\u002F Configure fund access limits\n        JBFundAccessLimitGroup[] memory fundAccessLimits = new JBFundAccessLimitGroup[](0);\n\n        \u002F\u002F Build ruleset config\n        JBRulesetConfig[] memory rulesetConfigs = new JBRulesetConfig[](1);\n        rulesetConfigs[0] = JBRulesetConfig({\n            mustStartAtOrAfter: 0,\n            duration: 0,                        \u002F\u002F Indefinite\n            weight: 1e18,                       \u002F\u002F 1 token per unit paid\n            weightCutPercent: 0,                \u002F\u002F No weight cut\n            approvalHook: IJBRulesetApprovalHook(address(0)),\n            metadata: metadata,\n            splitGroups: splitGroups,\n            fundAccessLimitGroups: fundAccessLimits\n        });\n\n        \u002F\u002F Configure terminal to accept ETH\n        JBAccountingContext[] memory accountingContexts = new JBAccountingContext[](1);\n        accountingContexts[0] = JBAccountingContext({\n            token: JBConstants.NATIVE_TOKEN,\n            decimals: 18,\n            currency: uint32(uint160(JBConstants.NATIVE_TOKEN))\n        });\n\n        JBTerminalConfig[] memory terminalConfigs = new JBTerminalConfig[](1);\n        terminalConfigs[0] = JBTerminalConfig({\n            terminal: TERMINAL,\n            accountingContexts: accountingContexts\n        });\n\n        \u002F\u002F Launch the project\n        uint256 projectId = CONTROLLER.launchProjectFor(\n            msg.sender,                         \u002F\u002F Owner\n            \"ipfs:\u002F\u002F...\",                       \u002F\u002F Project metadata URI\n            rulesetConfigs,\n            terminalConfigs,\n            \"Project launch\"                    \u002F\u002F Memo\n        );\n\n        vm.stopBroadcast();\n    }\n}\n```\n\n## Custom ERC20 Project Tokens\n\nBy default, Juicebox projects use **credits** (unclaimed internal balances). You can upgrade to an ERC20 token two ways:\n\n### Option 1: Deploy Standard JBERC20\n\n```solidity\n\u002F\u002F Deploy the default Juicebox ERC20 token\nIJBToken token = CONTROLLER.deployERC20For(\n    projectId,\n    \"Project Token\",    \u002F\u002F name\n    \"PROJ\",             \u002F\u002F symbol\n    bytes32(0)          \u002F\u002F salt (for deterministic address, or 0)\n);\n```\n\nThis creates a standard `JBERC20` that the controller can mint\u002Fburn. Simple and works for most projects.\n\n### Option 2: Use a Custom ERC20\n\nFor advanced tokenomics, you can bring your own ERC20:\n\n```solidity\n\u002F\u002F Set an existing\u002Fcustom ERC20 as the project token\nCONTROLLER.setTokenFor(projectId, IJBToken(myCustomToken));\n```\n\n**Requirements for custom tokens:**\n1. Must use **18 decimals**\n2. Must implement `canBeAddedTo(uint256 projectId)` returning `true`\n3. Must not be assigned to another Juicebox project\n4. Controller needs mint\u002Fburn permissions (typically via ownership or access control)\n\n### Custom Token Interface\n\n```solidity\ninterface IJBToken is IERC20 {\n    \u002F\u002F\u002F @notice Verify this token can be added to a project.\n    \u002F\u002F\u002F @param projectId The project ID to check.\n    \u002F\u002F\u002F @return True if the token can be added.\n    function canBeAddedTo(uint256 projectId) external view returns (bool);\n\n    \u002F\u002F\u002F @notice Mint tokens to an account.\n    \u002F\u002F\u002F @param holder The account to mint to.\n    \u002F\u002F\u002F @param amount The amount to mint.\n    function mint(address holder, uint256 amount) external;\n\n    \u002F\u002F\u002F @notice Burn tokens from an account.\n    \u002F\u002F\u002F @param holder The account to burn from.\n    \u002F\u002F\u002F @param amount The amount to burn.\n    function burn(address holder, uint256 amount) external;\n}\n```\n\n### When to Use Custom ERC20s\n\n| Use Case | Why Custom ERC20 |\n|----------|------------------|\n| **Transfer taxes** | Implement fees on transfers (e.g., reflection tokens) |\n| **Rebasing tokens** | Elastic supply that adjusts balances automatically |\n| **Pre-existing tokens** | Integrate a community token with established holders |\n| **Governance features** | Voting snapshots, delegation, checkpointing |\n| **Vesting schedules** | Built-in unlock mechanics in the token itself |\n| **Allowlist\u002Fdenylist** | Transfer restrictions for compliance |\n| **Concentration limits** | Cap max holdings per address for distribution |\n| **Editable metadata** | Rebrand name\u002Fsymbol without redeploying |\n\n### Example: Custom Token with Transfer Tax\n\n```solidity\n\u002F\u002F SPDX-License-Identifier: MIT\npragma solidity ^0.8.23;\n\nimport {ERC20} from \"@openzeppelin\u002Fcontracts\u002Ftoken\u002FERC20\u002FERC20.sol\";\nimport {Ownable} from \"@openzeppelin\u002Fcontracts\u002Faccess\u002FOwnable.sol\";\n\ncontract TaxedProjectToken is ERC20, Ownable {\n    uint256 public constant TAX_RATE = 100; \u002F\u002F 1% (basis points)\n    uint256 public constant TAX_DENOMINATOR = 10000;\n    address public taxRecipient;\n    address public controller;\n    uint256 public projectId;\n\n    constructor(\n        string memory name,\n        string memory symbol,\n        address _controller,\n        uint256 _projectId,\n        address _taxRecipient\n    ) ERC20(name, symbol) Ownable(msg.sender) {\n        controller = _controller;\n        projectId = _projectId;\n        taxRecipient = _taxRecipient;\n    }\n\n    function decimals() public pure override returns (uint8) {\n        return 18; \u002F\u002F REQUIRED: Must be 18 decimals\n    }\n\n    function canBeAddedTo(uint256 _projectId) external view returns (bool) {\n        return _projectId == projectId; \u002F\u002F Only allow for our project\n    }\n\n    function mint(address holder, uint256 amount) external {\n        require(msg.sender == controller, \"Only controller\");\n        _mint(holder, amount);\n    }\n\n    function burn(address holder, uint256 amount) external {\n        require(msg.sender == controller || msg.sender == holder, \"Not authorized\");\n        _burn(holder, amount);\n    }\n\n    function _update(address from, address to, uint256 amount) internal override {\n        \u002F\u002F Skip tax for mints, burns, and controller operations\n        if (from == address(0) || to == address(0) || msg.sender == controller) {\n            super._update(from, to, amount);\n            return;\n        }\n\n        \u002F\u002F Apply transfer tax\n        uint256 tax = (amount * TAX_RATE) \u002F TAX_DENOMINATOR;\n        uint256 netAmount = amount - tax;\n\n        super._update(from, taxRecipient, tax);\n        super._update(from, to, netAmount);\n    }\n}\n```\n\n### Example: Integrating Existing Community Token\n\n```solidity\n\u002F\u002F SPDX-License-Identifier: MIT\npragma solidity ^0.8.23;\n\nimport {ERC20} from \"@openzeppelin\u002Fcontracts\u002Ftoken\u002FERC20\u002FERC20.sol\";\nimport {AccessControl} from \"@openzeppelin\u002Fcontracts\u002Faccess\u002FAccessControl.sol\";\n\n\u002F\u002F\u002F @notice Wrapper to make an existing token compatible with Juicebox.\n\u002F\u002F\u002F @dev For tokens that already exist - create a wrapper that the JB controller can mint.\ncontract JBCompatibleToken is ERC20, AccessControl {\n    bytes32 public constant MINTER_ROLE = keccak256(\"MINTER_ROLE\");\n    uint256 public immutable targetProjectId;\n\n    constructor(\n        string memory name,\n        string memory symbol,\n        uint256 _projectId,\n        address controller\n    ) ERC20(name, symbol) {\n        targetProjectId = _projectId;\n        _grantRole(DEFAULT_ADMIN_ROLE, msg.sender);\n        _grantRole(MINTER_ROLE, controller);\n    }\n\n    function decimals() public pure override returns (uint8) {\n        return 18;\n    }\n\n    function canBeAddedTo(uint256 projectId) external view returns (bool) {\n        return projectId == targetProjectId;\n    }\n\n    function mint(address to, uint256 amount) external onlyRole(MINTER_ROLE) {\n        _mint(to, amount);\n    }\n\n    function burn(address from, uint256 amount) external onlyRole(MINTER_ROLE) {\n        _burn(from, amount);\n    }\n}\n```\n\n### Example: Editable Name\u002FSymbol Token\n\nAllows project owners to rebrand without redeploying or migrating liquidity:\n\n```solidity\n\u002F\u002F SPDX-License-Identifier: MIT\npragma solidity ^0.8.23;\n\nimport {ERC20} from \"@openzeppelin\u002Fcontracts\u002Ftoken\u002FERC20\u002FERC20.sol\";\nimport {IJBProjects} from \"@bananapus\u002Fcore\u002Fsrc\u002Finterfaces\u002FIJBProjects.sol\";\n\ncontract EditableProjectToken is ERC20 {\n    IJBProjects public immutable PROJECTS;\n    address public immutable controller;\n    uint256 public immutable projectId;\n\n    string private _tokenName;\n    string private _tokenSymbol;\n\n    event NameUpdated(string oldName, string newName);\n    event SymbolUpdated(string oldSymbol, string newSymbol);\n\n    constructor(\n        string memory initialName,\n        string memory initialSymbol,\n        address _controller,\n        uint256 _projectId,\n        IJBProjects projects\n    ) ERC20(initialName, initialSymbol) {\n        _tokenName = initialName;\n        _tokenSymbol = initialSymbol;\n        controller = _controller;\n        projectId = _projectId;\n        PROJECTS = projects;\n    }\n\n    modifier onlyProjectOwner() {\n        require(msg.sender == PROJECTS.ownerOf(projectId), \"NOT_OWNER\");\n        _;\n    }\n\n    function name() public view override returns (string memory) { return _tokenName; }\n    function symbol() public view override returns (string memory) { return _tokenSymbol; }\n    function decimals() public pure override returns (uint8) { return 18; }\n\n    function canBeAddedTo(uint256 _projectId) external view returns (bool) {\n        return _projectId == projectId;\n    }\n\n    function mint(address to, uint256 amount) external {\n        require(msg.sender == controller, \"UNAUTHORIZED\");\n        _mint(to, amount);\n    }\n\n    function burn(address from, uint256 amount) external {\n        require(msg.sender == controller, \"UNAUTHORIZED\");\n        _burn(from, amount);\n    }\n\n    \u002F\u002F\u002F @notice Update token name. Only callable by project owner.\n    function setName(string calldata newName) external onlyProjectOwner {\n        emit NameUpdated(_tokenName, newName);\n        _tokenName = newName;\n    }\n\n    \u002F\u002F\u002F @notice Update token symbol. Only callable by project owner.\n    function setSymbol(string calldata newSymbol) external onlyProjectOwner {\n        emit SymbolUpdated(_tokenSymbol, newSymbol);\n        _tokenSymbol = newSymbol;\n    }\n}\n```\n\n**Note**: Some DEXs\u002Faggregators cache metadata. Changes may take time to propagate.\n\n### Tradeoffs\n\n| Approach | Pros | Cons |\n|----------|------|------|\n| **Credits only** | Zero deployment cost, simplest | Not transferable, no DeFi integration |\n| **Standard JBERC20** | Simple, compatible, audited | No custom mechanics |\n| **Custom ERC20** | Full control over tokenomics | More complexity, audit burden, must maintain 18 decimals |\n\n### Critical Considerations\n\n1. **Controller must have mint\u002Fburn access** - The JBController needs to mint tokens on payments and burn on cash outs\n2. **18 decimals is mandatory** - The entire Juicebox math assumes 18 decimal tokens\n3. **One token per project** - A token can only be assigned to one project\n4. **Credits convert to tokens** - Existing credit holders can claim tokens after ERC20 is set\n5. **Token can't be changed** - Once set, you cannot swap to a different token contract\n\n## Other Project Operations\n\n### Transfer Ownership\n\nProject ownership is an ERC-721 NFT. Transfer using standard ERC-721:\n\n```solidity\nIJBProjects(PROJECTS).transferFrom(currentOwner, newOwner, projectId);\n```\n\n### Set Project Metadata\n\n```solidity\nIJBProjects(PROJECTS).setTokenURI(projectId, \"ipfs:\u002F\u002FnewUri\");\n```\n\n### Add Terminals\n\n```solidity\nIJBDirectory(DIRECTORY).setTerminalsOf(projectId, terminals);\n```\n\n## Generation Guidelines\n\n1. **Ask about project requirements** - ownership model, token economics, payout structure\n2. **Consider Revnets** if autonomous operation is desired\n3. **Configure appropriate metadata** - reserved rate, cash out tax, permissions\n4. **Set up splits** for payouts and reserved tokens\n5. **Generate deployment scripts** using Foundry\n\n## Example Prompts\n\n- \"Create a project that mints 1000 tokens per ETH with 10% reserved\"\n- \"Set up a project with weekly payout cycles to 3 addresses\"\n- \"Deploy a project with a 3-day approval delay for ruleset changes\"\n- \"Create a project that accepts both ETH and USDC\"\n\n## Reference\n\n- **nana-core-v5**: https:\u002F\u002Fgithub.com\u002FBananapus\u002Fnana-core-v5\n- **revnet-core-v5**: https:\u002F\u002Fgithub.com\u002Frev-net\u002Frevnet-core-v5\n",{"name":5,"description":7},"main","e7e336ac628c3e3bd771aff1aaa469c93778f94a","skills\u002Fmejango\u002Fjuicy\u002Fjb-project",0,"https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del","2026-08-23 22:39:37",{"source":8,"skillName":5,"commands":44,"prompt":54,"zipAvailable":55},[45,48,51],{"tool":46,"command":47},"npx","npx skills add kbarbel640-del\u002Fskills --skill jb-project",{"tool":49,"command":50},"bunx","bunx skills add kbarbel640-del\u002Fskills --skill jb-project",{"tool":52,"command":53},"pnpm","pnpm dlx skills add kbarbel640-del\u002Fskills --skill jb-project","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fmejango\u002Fjuicy\u002Fjb-project\u002FSKILL.md",true,[],[58,88,116,137,143,163],{"skillNo":59,"name":60,"nameZh":6,"description":61,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":62,"categories":63,"keywords":69,"publishedAt":31},"01M6G8J55967D6281ACMKAKTEQ","crowd-prompting","A marketplace where AI agents improve prompts, system instructions, tool descriptions, and other text-based content with domain expertise from real-world operations — and earn tokens for valuable contributions.","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzzadrian\u002Fcrowd-prompting\u002FSKILL.md",[64],{"categoryNo":65,"categoryName":66,"taxonomyType":67,"taxonomyTypeDesc":68},"01JBSEEDCAT000000000000036","内容创作者","PROFESSION","适用职业",[70,71,72,29,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87],"crowd prompting","prompting","api","tokens","domain","world","prompts","operations","instructions","text","tool","system","improve","productivity","marketplace","https","content","ai agents",{"skillNo":89,"name":90,"nameZh":6,"description":91,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":92,"categories":93,"keywords":99,"publishedAt":31},"01M6G8J0PKPAYVET6BWE8W4C26","dilemm-ai","Compete in DilemmAI, the prisoner's dilemma AI arena at dilemm.ai. Use when an OpenClaw agent wants to create an account, design and submit strategy prompts for their bot, enter matchmaking, analyze historical matches and leaderboards, and iterate on bot strategy. Requires headless browser automation (no API available yet).","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzyori\u002Fdilemm-ai\u002FSKILL.md",[94],{"categoryNo":95,"categoryName":96,"taxonomyType":97,"taxonomyTypeDesc":98},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[100,72,101,102,103,104,21,105,106,107,108,109,110,111,112,113,114,76,115],"dilemm ai","arena","analyze","browser","openclaw agent","automation","browser automation","bot","openclaw","design","strategy","headless","compete","submit","matchmaking","use",{"skillNo":117,"name":118,"nameZh":6,"description":119,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":120,"categories":121,"keywords":125,"publishedAt":31},"01M6G8HWAF3K9SW7NP3Z83CPJ6","arxiv-paper-reviews","Interact with arXiv Crawler API to fetch papers, read reviews, and submit comments. Use when working with arXiv papers, fetching paper lists by date\u002Fcategory\u002Finterest, viewing paper details with comments, or submitting paper reviews via API at http:\u002F\u002F150.158.152.82:8000.","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzxrys\u002Fweak-accept\u002FSKILL.md",[122],{"categoryNo":123,"categoryName":124,"taxonomyType":97,"taxonomyTypeDesc":98},"01JBSEEDCAT000000000000021","资料检索与研究",[126,127,128,129,130,131,132,29,133,113,115,134,72,135,136],"arxiv paper reviews","reviews","arxiv","paper","crawler","papers","comments","fetch","read","http","via",{"skillNo":138,"name":118,"nameZh":6,"description":119,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":139,"categories":140,"keywords":142,"publishedAt":31},"01M6G8HQJ7N7WMY6YV7D7SSJ16","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzxrys\u002Farxiv-paper-reviews\u002FSKILL.md",[141],{"categoryNo":123,"categoryName":124,"taxonomyType":97,"taxonomyTypeDesc":98},[129,128,127,126,136,131,132,29,130,113,115,133,134,72,135],{"skillNo":144,"name":145,"nameZh":6,"description":146,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":147,"categories":148,"keywords":149,"publishedAt":31},"01M6G8HM95Y64JNVFC2HN4E2BG","git-summary","Get a quick summary of the current Git repository including status, recent commits, branches, and contributors.","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzweack\u002Fgit-summary\u002FSKILL.md",[],[150,151,152,153,154,155,156,157,158,159,160,161,162],"git","summary","git summary","commits","repository","win32","status","linux","contributors","true","quick","get","branches",{"skillNo":164,"name":165,"nameZh":6,"description":166,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":167,"categories":168,"keywords":173,"publishedAt":31},"01M6G8HGEGF05CNEJCGVYFSC4R","agent-constitution","Interact with AgentConstitution governance contracts on Base Sepolia. Check compliance, read rules, log actions, query governance state.","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fztsalexey\u002Fagent-constitution\u002FSKILL.md",[169,170],{"categoryNo":95,"categoryName":96,"taxonomyType":97,"taxonomyTypeDesc":98},{"categoryNo":171,"categoryName":172,"taxonomyType":67,"taxonomyTypeDesc":68},"01JBSEEDCAT000000000000037","律师与法务",[174,175,176,177,29,178,179,36,180,134,181,182,26,183,184,85,185,186,187],"agent constitution","constitution","contracts","tree","query","base","log","check","Rules","compliance","actions","state","governance","github"]