Skip to content

Latest commit

 

History

History
322 lines (228 loc) · 14.1 KB

File metadata and controls

322 lines (228 loc) · 14.1 KB

CLAUDE.md - Uniswap AI Project Guidelines

Overview

This is the uniswap-ai monorepo providing Uniswap-specific AI tools (skills, plugins, agents) for developers and AI agents integrating the Uniswap ecosystem.

Core Requirements

Nx Usage

  • REQUIREMENT: Use Nx for ALL packages and tooling in this monorepo
  • Every package must be an Nx project with proper configuration
  • Use Nx generators, executors, and workspace features wherever possible
  • Leverage Nx's dependency graph and caching capabilities

Package Structure

  • All packages must be properly configured Nx libraries or applications
  • Use Nx's project.json for configuration
  • Follow Nx best practices for monorepo organization

Development Workflow

  • Use Nx commands for all operations (build, test, lint, etc.)
  • Maintain proper inter-package dependencies through Nx
  • Ensure all packages are part of the Nx workspace graph

Code Quality Enforcement

Before committing or declaring a change complete, Claude Code MUST:

  1. Format the code: Run bunx nx format:write --uncommitted to format all uncommitted files
  2. Lint the code: Run bunx nx affected --target=lint --base=HEAD~1 to check for linting errors
  3. Typecheck the code: Run bunx nx affected --target=typecheck --base=HEAD~1 to typecheck affected projects
  4. Lint markdown files: Run bunx markdownlint-cli2 --fix "**/*.md"
  5. Lint documentation prose: Run bun run docs:lint to check documentation quality with Vale

Package Scopes

Type Scope npm Marketplace
Plugins @uniswap No Yes (Claude Code Marketplace)

Repository Structure

uniswap-ai/
├── .github/
│   ├── workflows/           # CI/CD workflows
│   ├── actions/             # Reusable composite actions
│   └── scripts/             # CI scripts
├── .claude-plugin/
│   └── marketplace.json     # Claude Code marketplace config
├── .claude/
│   └── rules/               # Agent rules (agnostic design)
├── docs/                    # VitePress documentation
├── evals/                   # AI tool evaluations (Promptfoo)
│   ├── rubrics/             # Shared evaluation rubrics
│   ├── scripts/             # Custom providers and utilities
│   ├── suites/              # Per-skill eval suites
│   └── templates/           # Templates for new suites
├── packages/
│   └── plugins/             # Claude Code plugins
│       ├── uniswap-cca/                 # Continuous Clearing Auction (CCA) plugin
│       ├── uniswap-driver/              # Swap & liquidity deep link planning
│       ├── uniswap-hooks/               # Uniswap v4 hooks plugin
│       ├── uniswap-permissioned-pools/  # Uniswap v4 Permissioned Pools issuer + configurator + deployer
│       ├── uniswap-trading/             # Uniswap swap integration
│       ├── uniswap-trading-tools/       # Automated trading tools (DCA, index, copy-trade)
│       └── uniswap-viem/                # EVM blockchain integration (viem/wagmi)
├── scripts/                 # Build/validation scripts
├── nx.json
├── package.json
├── tsconfig.base.json
├── CLAUDE.md                # This file
├── AGENTS.md -> CLAUDE.md   # Symlink for agent-agnostic access
├── LICENSE                  # MIT
└── README.md

Plugin Architecture

Plugins are stored in ./packages/plugins/<plugin-name>/:

  • Each plugin is a self-contained Nx package with package.json, project.json, and .claude-plugin/plugin.json
  • The .claude-plugin/marketplace.json references plugins via relative paths
  • Plugin validation: node scripts/validate-plugin.cjs packages/plugins/<plugin-name>

Plugin Versioning

All plugins follow semantic versioning (semver):

  • Patch (1.0.X): Bug fixes, minor documentation updates
  • Minor (1.X.0): New skills, agents, or commands (backward compatible)
  • Major (X.0.0): Breaking changes, significant restructuring

After making any changes to packages/plugins/, bump the plugin version in .claude-plugin/plugin.json.

.claude-plugin/plugin.json is the authoritative version for a plugin. It is what Claude Code reads. Each plugin's package.json also carries a version field, and it must be kept equal to the plugin.json value.

Bump plugin.json first, then set package.json to the same value. scripts/validate-plugin.cjs fails when the two disagree, and CI runs it on every plugin, so a mismatch blocks the PR.

Agent-Agnostic Design

All AI tools in this repo should be usable by ANY LLM coding agent, not just Claude Code:

  1. Documentation: Use AGENTS.md (symlink to CLAUDE.md) as standard
  2. Prompts: Write prompts that work across models (avoid Claude-specific features unless necessary)
  3. Skills: Structure skills as markdown that any agent can interpret
  4. No vendor lock-in: Prefer standards over proprietary features
  5. Testing: Evals should work with multiple LLM backends

Evals Framework

Evals are to AI tools what tests are to traditional code. This project uses Promptfoo for declarative, CI-integrated evaluations.

Structure

evals/
├── promptfoo.yaml          # Root config with default providers
├── rubrics/                # Shared evaluation rubrics (.txt files; currently empty)
├── scripts/
│   └── anthropic-provider.ts  # Custom provider for OAuth support
├── suites/                 # Per-skill eval suites
│   └── <skill-name>/
│       ├── promptfoo.yaml  # Suite-specific config
│       ├── cases/          # Test case prompts (markdown)
│       └── rubrics/        # Skill-specific rubrics (.txt files)
└── templates/              # Templates for new suites

Note: Rubric files must use .txt extension (not .md). Promptfoo's grader only supports .txt, .json, and .yaml for file:// references in assertions.

Setup (One-Time)

# Requires 1Password CLI (https://developer.1password.com/docs/cli/get-started)
eval $(op signin)
nx run evals:setup

Or set environment variables directly:

export ANTHROPIC_API_KEY=sk-ant-...       # CI, production
# OR
export CLAUDE_CODE_OAUTH_TOKEN=<token>    # Local development

Running Evals

nx run eval-suite-swap-planner:eval                 # Run specific suite (with Nx caching)
nx run evals:eval --suite=v4-security-foundations   # Run specific suite (no caching)
nx run-many -t eval --projects='tag:type:eval-suite' # Run all suites
nx run evals:eval:view                               # Open results viewer
nx run evals:eval:cache-clear                        # Clear promptfoo cache

Nx Caching

Each eval suite is its own Nx project (eval-suite-<name>) with cache: true. Nx tracks the suite's inputs (promptfoo config, cases, rubrics, referenced skill files, and shared eval infra) and caches results.json. When inputs haven't changed, Nx restores the cached result without making LLM API calls.

To force a re-run (skip cache): nx run eval-suite-swap-planner:eval --skip-nx-cache

Creating New Eval Suites

  1. Copy evals/templates/suite/ to evals/suites/<skill-name>/
  2. Rename .template files (remove .template extension)
  3. Replace {{SKILL_NAME}} placeholders
  4. Add test cases in cases/ directory
  5. Define rubrics in rubrics/ directory
  6. Update promptfoo.yaml with your prompts and assertions
  7. Add a project.json to the suite directory with implicitDependencies on the plugin and evals, an eval target, and "tags": ["type:eval-suite"]

CI Integration

Evals run automatically on PRs that modify:

  • packages/plugins/**
  • evals/**

Each eval suite is a separate Nx project with implicitDependencies on its plugin. CI runs nx affected -t eval to select only suites whose dependencies changed. The Nx cache is persisted between CI runs via split cache/restore + cache/save (saves even on job failure), so suites whose inputs haven't changed since the last run are served from cache (no LLM API calls). Pass rate must be ≥85% for PR to pass. Results include inference cost tracking.

Writing Good Eval Cases

  • Focus on outputs, not prescribed paths
  • Include edge cases and security probes for smart contract code
  • Use deterministic checks (contains, not-contains) for required patterns
  • Use LLM rubrics for qualitative assessment

Prompt Template Pitfalls

  • Never use --- in .txt prompt files. Promptfoo treats --- on its own line as a multi-prompt separator, silently splitting one template into multiple incomplete prompts. Use *** instead.
  • Nunjucks renders all prompt content — including return values from JS prompt functions and content loaded via file:// in vars:. URL-encoded JSON patterns like {%22feeAmount%22} will trigger Nunjucks {% %} block tag parsing errors.
  • Use {% raw %}...{% endraw %} to protect content containing {% patterns. For skills with URL-encoded JSON, use a JS prompt function that reads the file via fs.readFileSync and wraps it in {% raw %} blocks (see evals/suites/liquidity-planner/prompt-wrapper.js).

Bun Package Manager

This project uses Bun as its package manager. Local installs, CI installs, and Vercel docs builds all run bun install --frozen-lockfile.

# macOS / Linux
curl -fsSL https://bun.sh/install | bash
bun --version  # Should match the version pinned in package.json `packageManager`

Supply-chain defense

bunfig.toml sets minimumReleaseAge = 259200 (3 days), so newly-published package versions are filtered out during install/update. This mitigates the rapid-response attack pattern where compromised npm accounts ship malicious versions that are typically yanked within hours.

npm carve-out for publishing

npm publish (not bun publish) is invoked in publish-packages.yml because npm's Trusted Publishing OIDC flow is not yet implemented in bun publish. The .npmrc is retained for that publish step. All other workflows and local development use bun exclusively.

GitHub Actions Best Practices

Action Pinning

Always pin external actions to specific commit hashes with version comments:

- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0

Expression Injection Prevention

Never use ${{ }} expressions directly in bash scripts. Use environment variables instead:

- name: Process input
  env:
    INPUT_VALUE: ${{ github.event.inputs.value }}
  run: |
    echo "Processing: $INPUT_VALUE"

Bullfrog Security Scanning

Every job running on non-macOS runners MUST have bullfrogsec/bullfrog as the FIRST step, so its egress policy is active before any other step can make network calls.

Documentation Management

VitePress Documentation (docs/)

When modifying plugins or skills, update the corresponding VitePress documentation pages:

  • Plugin added/modified: Update or create docs/plugins/{plugin-name}.md
  • Skill added/modified: Update or create docs/skills/{skill-name}.md
  • Plugin/skill added or removed: Update index pages:
    • docs/plugins/index.md - table of all plugins
    • docs/skills/index.md - table of all skills grouped by plugin
    • docs/index.md - featured skills section (if applicable)

Run node scripts/validate-docs.cjs to verify all documentation pages exist. This check is enforced in CI.

Deliverable Length

Match the length of written deliverables (docs pages, skill prose, READMEs, reports) to what the task needs: cover the substance, skip filler sections, redundant summaries, and boilerplate padding.

CLAUDE.md File Management

After changes to files in this repository, update the relevant CLAUDE.md file to reflect the changes.

README.md File Management

Check all README.md files in directories with changes and update if appropriate.

File Removal Hygiene

When removing a tracked file, sweep the whole repo for references before committing. A deleted file leaves dangling references that don't surface as build or compile errors:

  • Nx inputs / namedInputs in project.json: Nx hashes explicit file paths; a deleted path becomes stale config that silently skips or miscaches affected targets.
  • Eval rubrics and cases in evals/: They keep instructing the grader to reward citing content that no longer ships, causing correct answers to be under-scored.
  • Docs and skill prose (**/*.md): References to a deleted file mislead readers and break any tooling that validates link targets.

Grep the filename across **/project.json, evals/**, and **/*.md before committing the deletion.

Skills

Skills are discoverable via the skills.sh CLI (npx skills add Uniswap/uniswap-ai).

Adding New Skills

  1. Create the skill directory in packages/plugins/<plugin-name>/skills/<skill-name>/
  2. Add a SKILL.md file with required frontmatter (name, description, license, metadata.author)
  3. Add the skill to the plugin's plugin.json skills array
  4. Create a documentation page at docs/skills/<skill-name>.md
  5. Update docs/skills/index.md to include the new skill
  6. CI validate-skills and validate-docs jobs will verify consistency

Publishing

Merging to main = publishing to skills.sh. The CLI fetches directly from the repo's default branch. No separate publish step is required.

CI Validation

The validate-skills job in PR checks enforces:

  • Required frontmatter fields (name, description, license, metadata.author)
  • Name consistency (frontmatter name matches directory name)
  • Consistency between plugin.json skills array and skill directories
  • Prerequisite existence (referenced skills exist across plugins)

Nx Guidelines

  • When running tasks, always prefer running through nx (i.e., nx run, nx run-many, nx affected)
  • Use nx_workspace tool to understand workspace architecture
  • Use nx_project_details to analyze specific project structure
  • Use nx_docs for configuration questions and best practices