|
| 1 | +# AGENTS.md |
| 2 | + |
| 3 | +Guidance for AI coding agents working in this repository. See |
| 4 | +<https://agents.md/> for the file convention. |
| 5 | + |
| 6 | +## Project Overview |
| 7 | + |
| 8 | +- Project name: write it as `fcf` in prose and commands. |
| 9 | +- Purpose: CLI tooling and EVM smart contracts for the |
| 10 | + `@freecodexyz` funding layer. |
| 11 | +- Repository shape: small monorepo with a TypeScript CLI in `cli/` and a |
| 12 | + Foundry Solidity project in `contracts/`. |
| 13 | +- CLI stack: Node 24 in CI, ESM TypeScript, `pnpm@10.24.0`, Commander, Viem, |
| 14 | + tsup, tsx, TypeScript, and Vitest. |
| 15 | +- Contract stack: Foundry, Solidity `^0.8.24`, OpenZeppelin Contracts, and |
| 16 | + `forge-std` as git submodules under `contracts/lib/`. |
| 17 | +- Core contract: `RIK`, an ERC-721 "Repository Identity Key" that registers a |
| 18 | + GitHub repository identity from a GitHub Actions OIDC JWT. |
| 19 | + |
| 20 | +## Environment Setup |
| 21 | + |
| 22 | +- Use Node 24 for CLI work to match GitHub Actions. |
| 23 | +- Use Corepack and pnpm in `cli/`; there is no root `package.json`. |
| 24 | +- Initialize submodules before contract work: |
| 25 | + `git submodule update --init --recursive`. |
| 26 | +- Install Foundry for contract build/test commands: `forge`, `cast`, and |
| 27 | + `anvil` are expected for local contract workflows. |
| 28 | +- `contracts/foundry.toml` has `ffi = true` because the Foundry tests call a |
| 29 | + Node fixture generator via `vm.ffi`. |
| 30 | + |
| 31 | +## Commands |
| 32 | + |
| 33 | +| Purpose | Command | |
| 34 | +| --- | --- | |
| 35 | +| Install CLI dependencies | `cd cli && corepack enable && pnpm install --frozen-lockfile` | |
| 36 | +| Run CLI from source | `cd cli && pnpm dev -- --help` | |
| 37 | +| CLI typecheck | `cd cli && pnpm typecheck` | |
| 38 | +| CLI tests | `cd cli && pnpm test` | |
| 39 | +| CLI build | `cd cli && pnpm build` | |
| 40 | +| Regenerate committed ABI | `cd cli && pnpm abi` | |
| 41 | +| Contract format check | `cd contracts && forge fmt --check` | |
| 42 | +| Contract build with sizes | `cd contracts && forge build --sizes` | |
| 43 | +| Contract tests | `cd contracts && forge test -vvv` | |
| 44 | +| Local Anvil deploy helper | `./local-rpc.sh src/RIK.sol:RIK` | |
| 45 | +| Sepolia deploy script | `cd contracts && PRIVATE_KEY=... ./deploy-sepolia.sh` | |
| 46 | +| Finds agents TODOs when asked | `rg -F 'TODO (AGENT)'` | |
| 47 | + |
| 48 | +Do not run release/versioning commands such as `cd cli && pnpm version:minor` |
| 49 | +or `cd cli && pnpm prepublishOnly` unless the user explicitly asks for a |
| 50 | +release path. They mutate `cli/package.json`. |
| 51 | + |
| 52 | +## Repository Structure |
| 53 | + |
| 54 | +- `.github/workflows/test-cli.yml`: CLI CI; installs with pnpm and runs |
| 55 | + `pnpm test` under `cli/`. |
| 56 | +- `.github/workflows/test-contracts.yml`: contract CI; runs `forge fmt --check`, |
| 57 | + `forge build --sizes`, and `forge test -vvv` under `contracts/`. |
| 58 | +- `.github/workflows/fcf-register.yml`: checked-in registration workflow emitted |
| 59 | + by the CLI `init` command. |
| 60 | +- `local-rpc.sh`: root helper that starts Anvil, deploys a contract, prints the |
| 61 | + RPC URL/private key/owner/contract address, and waits until interrupted. |
| 62 | +- `cli/src/index.ts`: Commander CLI entrypoint and workflow template. |
| 63 | +- `cli/src/oidc.ts`: JWT base64url helpers, parsing, and GitHub `kid` hashing. |
| 64 | +- `cli/src/importAbi.ts`: loads the committed static ABI by default. |
| 65 | +- `cli/src/abi/RIK.json`: committed generated ABI used by the published CLI. |
| 66 | +- `cli/scripts/generate-abi.mjs`: copies the ABI from the Foundry artifact into |
| 67 | + `cli/src/abi/RIK.json`. |
| 68 | +- `contracts/src/RIK.sol`: repository identity ERC-721 and JWT verification. |
| 69 | +- `contracts/src/JsonClaim.sol`: minimal byte-search JSON claim helper. |
| 70 | +- `contracts/test/RIK.t.sol`: Foundry regression tests for registration, |
| 71 | + ownership, JWT claims, keys, and expiry. |
| 72 | +- `contracts/test/fixtures/load-fixture.mjs`: Node helper used by `vm.ffi` to |
| 73 | + generate deterministic RSA/JWT fixtures for Solidity tests. |
| 74 | +- `contracts/script/Deploy.s.sol`: Foundry deploy script. |
| 75 | +- `contracts/deploy-sepolia.sh`: Sepolia deploy wrapper using `PRIVATE_KEY` and |
| 76 | + optional `SEPOLIA_RPC_URL` / `VERIFY`. |
| 77 | +- `contracts/lib/`: git submodules and vendor code. Do not edit directly. |
| 78 | + |
| 79 | +## Architecture Boundaries |
| 80 | + |
| 81 | +- `RIK.tokenIdOf(githubRepoId)` is intentionally identity mapping; the token ID |
| 82 | + is the GitHub repository ID. |
| 83 | +- `RIK.register()` must validate the JWT before minting: active `kid`, RSA |
| 84 | + signature, `aud`, `repository_id`, `repository_owner_id`, issuer, `exp`, |
| 85 | + `nbf`, and duplicate registration. |
| 86 | +- Preserve the issuer string exactly: |
| 87 | + `https://token.actions.githubusercontent.com`. |
| 88 | +- The CLI requests GitHub OIDC tokens with the lowercase signer address as the |
| 89 | + audience; the contract compares `aud` against `Strings.toHexString` of |
| 90 | + `msg.sender`. |
| 91 | +- GitHub JWKS `kid` values are stored on-chain as `keccak256(Buffer.from(kid))`; |
| 92 | + keep `jwtKid()` and contract key lookups aligned. |
| 93 | +- `keys sync` is the path that imports active GitHub RSA keys into the contract. |
| 94 | + Do not weaken key filtering or signature validation. |
| 95 | +- `JsonClaim` is deliberately small and byte-oriented. If claim parsing changes, |
| 96 | + add regression tests for missing claims, mismatched claims, and valid compact |
| 97 | + JWT payloads. |
| 98 | +- `cli/src/importAbi.ts` defaults to the committed static ABI. `SKIP_STATIC_ABI` |
| 99 | + switches to the Foundry artifact path for local development. |
| 100 | +- Keep `cli/src/index.ts`'s `REGISTER_WORKFLOW` template and |
| 101 | + `.github/workflows/fcf-register.yml` behavior in sync when registration |
| 102 | + workflow semantics change. |
| 103 | +- Contract ABI changes must be followed by `cd cli && pnpm abi` so the packaged |
| 104 | + CLI ABI stays current. |
| 105 | + |
| 106 | +## Code Style |
| 107 | + |
| 108 | +- Prefer small, direct changes. Avoid broad refactors unless the user asks. |
| 109 | +- Match nearby formatting in each file. There is no configured TypeScript |
| 110 | + formatter in the CLI package. |
| 111 | +- TypeScript is strict ESM with `module: nodenext`, `verbatimModuleSyntax`, |
| 112 | + `exactOptionalPropertyTypes`, and `noUncheckedIndexedAccess`. |
| 113 | +- Use `node:` built-in imports in new TypeScript files. |
| 114 | +- Use type-only imports when importing TypeScript types, e.g. `import type`. |
| 115 | +- Keep CLI command behavior explicit through Commander options and `die()` |
| 116 | + messages rather than silent fallbacks. |
| 117 | +- Solidity code should pass `forge fmt`; use custom errors for contract-specific |
| 118 | + failures when practical. |
| 119 | +- Use `// forge-lint: disable-next-line(...)` only next to the exact line that |
| 120 | + needs it, and keep a short reason nearby when the reason is not obvious. |
| 121 | +- Comments should explain constraints or non-obvious behavior, not restate names. |
| 122 | + |
| 123 | +## Testing |
| 124 | + |
| 125 | +- For CLI-only changes, run `cd cli && pnpm typecheck` and `cd cli && pnpm test`. |
| 126 | +- For contract-only changes, run `cd contracts && forge fmt --check`, |
| 127 | + `cd contracts && forge build --sizes`, and `cd contracts && forge test -vvv`. |
| 128 | +- For ABI-affecting contract changes, also run `cd cli && pnpm abi`, |
| 129 | + `cd cli && pnpm typecheck`, and `cd cli && pnpm build`. |
| 130 | +- Keep Foundry tests deterministic and local. Do not hit GitHub, Sepolia, or |
| 131 | + other live RPC endpoints from unit tests. |
| 132 | +- Contract tests may use `vm.ffi` with `contracts/test/fixtures/load-fixture.mjs`; |
| 133 | + avoid adding more external process dependencies unless necessary. |
| 134 | +- Add CLI tests as Vitest tests under `cli/src/` or a future `cli/test/` |
| 135 | + directory. Mock `fetch`, Viem clients, and filesystem writes rather than using |
| 136 | + live network calls. |
| 137 | + |
| 138 | +## Git/PR Workflow |
| 139 | + |
| 140 | +- Recent human commit format: `(type) imperative summary`. |
| 141 | +- Examples from this repo: `(feat) add deployment script for RIK contract`, |
| 142 | + `(fix) add shebang to index.ts for execution in github actions`, |
| 143 | + `(chore) bump cli version`. |
| 144 | +- AI-created commit format when the user asks for a commit: |
| 145 | + `(type) (openai/gpt-5.5, reviewed T|F, tested T|F) imperative summary`. |
| 146 | +- Before creating an AI commit, ask the user whether a human reviewed the |
| 147 | + changes so `reviewed T|F` is accurate. |
| 148 | +- Mark `tested T` only after the relevant checks have run successfully. |
| 149 | + Otherwise use `tested F`. |
| 150 | +- Before committing, inspect `git status --short`, `git diff`, and |
| 151 | + `git log --oneline -10`; stage only intended files. |
| 152 | +- Run `git diff --check` before commit/PR handoff. |
| 153 | + |
| 154 | +## Boundaries |
| 155 | + |
| 156 | +- Never edit, print, copy, infer, or commit real secrets: `.env`, `.env.*`, |
| 157 | + `PRIVATE_KEY`, GitHub tokens, RPC credentials, wallet data, or provider keys. |
| 158 | +- Do not commit `contracts/.dev-wallet-data` or values printed by |
| 159 | + `local-rpc.sh`. Anvil keys are disposable but still should not enter commits. |
| 160 | +- Do not deploy, broadcast transactions, sync production keys, or call live RPCs |
| 161 | + unless the user explicitly asks. |
| 162 | +- Do not change production/provider configuration without explicit approval: |
| 163 | + environment variable names, default RPC behavior, GitHub OIDC issuer, |
| 164 | + workflow permissions, contract addresses, or default package tags. |
| 165 | +- Do not edit generated or dependency directories directly: `cli/node_modules/`, |
| 166 | + `cli/dist/`, `contracts/cache/`, `contracts/out/`, `contracts/broadcast/`, |
| 167 | + or `contracts/lib/`. |
| 168 | +- The committed static ABI at `cli/src/abi/RIK.json` is generated but tracked; |
| 169 | + update it only through `cd cli && pnpm abi` when the contract ABI changes. |
| 170 | +- Never replace pnpm with npm/yarn or Foundry with another contract toolchain |
| 171 | + without explicit user approval. |
0 commit comments