Guidance for AI coding agents working in this repository. See https://agents.md/ for the file convention.
- Project name: write it as
fcfin prose and commands. - Purpose: CLI tooling and EVM smart contracts for the
@freecodexyzfunding layer. - Repository shape: small monorepo with a TypeScript CLI in
packages/cli/and a Foundry Solidity project incontracts/. - CLI stack: Node 24 in CI, ESM TypeScript,
pnpm@10.24.0, Commander, Viem, tsup, tsx, TypeScript, and Vitest. - Contract stack: Foundry, Solidity
^0.8.24, OpenZeppelin Contracts, andforge-stdas git submodules undercontracts/lib/. - Core contract:
RIK, an ERC-721 "Repository Identity Key" that registers a GitHub repository identity from a GitHub Actions OIDC JWT.
- Use Node 24 for CLI work to match GitHub Actions.
- Use Corepack and pnpm from the workspace root or
packages/cli/. - Initialize submodules before contract work:
git submodule update --init --recursive. - Install Foundry for contract build/test commands:
forge,cast, andanvilare expected for local contract workflows. contracts/foundry.tomlhasffi = truebecause the Foundry tests call a Node fixture generator viavm.ffi.
| Purpose | Command |
|---|---|
| Install CLI dependencies | corepack enable && pnpm install --frozen-lockfile |
| Run CLI from source | cd packages/cli && pnpm dev -- --help |
| CLI typecheck | cd packages/cli && pnpm typecheck |
| CLI tests | cd packages/cli && pnpm test |
| CLI build | cd packages/cli && pnpm build |
| Regenerate committed ABI | cd packages/cli && pnpm abi |
| Contract format check | cd contracts && forge fmt --check |
| Contract build with sizes | cd contracts && forge build --sizes |
| Contract tests | cd contracts && forge test -vvv |
| Local Anvil deploy helper | ./local-rpc.sh src/RIK.sol:RIK |
| Base Sepolia RIK deploy script | cd contracts && PRIVATE_KEY=... ./deploy-rik-base-sepolia.sh |
| Base Sepolia RIKLauncher + RIKRoyaltySplitter deploy script | cd contracts && PRIVATE_KEY=... AIRLOCK_ADDRESS=... RIK_ADDRESS=... ./deploy-rik-launcher-and-splitter-base-sepolia.sh |
| Finds agents TODOs when asked | rg -F 'TODO (AGENT)' |
Do not run release/versioning commands such as cd packages/cli && pnpm version:minor
or cd packages/cli && pnpm prepublishOnly unless the user explicitly asks for a
release path. They mutate packages/cli/package.json.
.github/workflows/test-cli.yml: CLI CI; installs with pnpm and runspnpm testunderpackages/cli/..github/workflows/test-contracts.yml: contract CI; runsforge fmt --check,forge build --sizes, andforge test -vvvundercontracts/..github/workflows/fcf-register.yml: checked-in registration workflow emitted by the CLIinitcommand.local-rpc.sh: root helper that starts Anvil, deploys a contract, prints the RPC URL/private key/owner/contract address, and waits until interrupted.packages/cli/src/index.ts: Commander CLI entrypoint.packages/cli/templates/fcf-register.yml: workflow template emitted by CLIinit.packages/cli/src/github/oidc.ts: JWT base64url helpers, parsing, and GitHubkidhashing.packages/cli/src/utils/importAbi.ts: loads the committed static ABI by default.packages/cli/src/abi/RIK.json: committed generated ABI used by the published CLI.packages/cli/scripts/generate-abi.mjs: copies the ABI from the Foundry artifact intopackages/cli/src/abi/RIK.json.contracts/src/RIK.sol: repository identity ERC-721 and JWT verification.contracts/src/JsonClaim.sol: minimal byte-search JSON claim helper.contracts/test/RIK.t.sol: Foundry regression tests for registration, ownership, JWT claims, keys, and expiry.contracts/test/fixtures/load-fixture.mjs: Node helper used byvm.ffito generate deterministic RSA/JWT fixtures for Solidity tests.contracts/script/DeployRIK.s.sol: Foundry deploy script forRIK.contracts/script/DeployRIKLauncher.s.sol: Foundry deploy script forRIKLauncherandRIKRoyaltySplitter.contracts/deploy-rik-base-sepolia.sh: Base Sepolia deploy wrapper forRIKusingPRIVATE_KEYand optionalBASE_SEPOLIA_RPC_URL/VERIFY.contracts/deploy-rik-launcher-and-splitter-base-sepolia.sh: Base Sepolia deploy wrapper forRIKLauncherandRIKRoyaltySplitterusingPRIVATE_KEY,AIRLOCK_ADDRESS,RIK_ADDRESS, and optionalBASE_SEPOLIA_RPC_URL/VERIFY.contracts/lib/: git submodules and vendor code. Do not edit directly.
RIK.tokenIdOf(githubRepoId)is intentionally identity mapping; the token ID is the GitHub repository ID.RIK.register()must validate the JWT before minting: activekid, RSA signature,aud,repository_id,repository_owner_id, issuer,exp,nbf, and duplicate registration.- Preserve the issuer string exactly:
https://token.actions.githubusercontent.com. - The CLI requests GitHub OIDC tokens with the lowercase signer address as the
audience; the contract compares
audagainstStrings.toHexStringofmsg.sender. - GitHub JWKS
kidvalues are stored on-chain askeccak256(Buffer.from(kid)); keepjwtKid()and contract key lookups aligned. keys syncis the path that imports active GitHub RSA keys into the contract. Do not weaken key filtering or signature validation.JsonClaimis deliberately small and byte-oriented. If claim parsing changes, add regression tests for missing claims, mismatched claims, and valid compact JWT payloads.packages/cli/src/utils/importAbi.tsdefaults to the committed static ABI.SKIP_STATIC_ABIswitches to the Foundry artifact path for local development.- Keep
packages/cli/templates/fcf-register.ymland.github/workflows/fcf-register.ymlbehavior in sync when registration workflow semantics change. - Contract ABI changes must be followed by
cd packages/cli && pnpm abiso the packaged CLI ABI stays current.
- Prefer small, direct changes. Avoid broad refactors unless the user asks.
- When working inside a package or subproject, read its nearest sub-
AGENTS.mdfirst, such ascontracts/AGENTS.mdorpackages/cli/AGENTS.md. - Never add more then the user explicitly asked for.
- Avoid separating implementations in multiple functions and helper functions unless the user explicitly ask for it.
- Match nearby formatting in each file. There is no configured TypeScript formatter in the CLI package.
- TypeScript is strict ESM with
module: nodenext,verbatimModuleSyntax,exactOptionalPropertyTypes, andnoUncheckedIndexedAccess. - Use
node:built-in imports in new TypeScript files. - Use type-only imports when importing TypeScript types, e.g.
import type. - Keep CLI command behavior explicit through Commander options and
die()messages rather than silent fallbacks. - Solidity code should pass
forge fmt; use custom errors for contract-specific failures when practical. - Use
// forge-lint: disable-next-line(...)only next to the exact line that needs it, and keep a short reason nearby when the reason is not obvious. - Comments should explain constraints or non-obvious behavior, not restate names.
- For CLI-only changes, run
cd packages/cli && pnpm typecheckandcd packages/cli && pnpm test. - For contract-only changes, run
cd contracts && forge fmt --check,cd contracts && forge build --sizes, andcd contracts && forge test -vvv. - For ABI-affecting contract changes, also run
cd packages/cli && pnpm abi,cd packages/cli && pnpm typecheck, andcd packages/cli && pnpm build. - Keep Foundry tests deterministic and local. Do not hit GitHub, Sepolia, or other live RPC endpoints from unit tests.
- Contract tests may use
vm.ffiwithcontracts/test/fixtures/load-fixture.mjs; avoid adding more external process dependencies unless necessary. - Add CLI tests as Vitest tests under
packages/cli/src/or a futurepackages/cli/test/directory. Mockfetch, Viem clients, and filesystem writes rather than using live network calls.
- Recent human commit format:
(type) imperative summary. - Examples from this repo:
(feat) add deployment script for RIK contract,(fix) add shebang to index.ts for execution in github actions,(chore) bump cli version. - AI-created commit format when the user asks for a commit:
(type) (openai/gpt-5.5, reviewed T|F, tested T|F) imperative summary. - Before creating an AI commit, ask the user whether a human reviewed the
changes so
reviewed T|Fis accurate. - Mark
tested Tonly after the relevant checks have run successfully. Otherwise usetested F. - Before committing, inspect
git status --short,git diff, andgit log --oneline -10; stage only intended files. - Run
git diff --checkbefore commit/PR handoff.
- Never edit, print, copy, infer, or commit real secrets:
.env,.env.*,PRIVATE_KEY, GitHub tokens, RPC credentials, wallet data, or provider keys. - Do not commit
contracts/.dev-wallet-dataor values printed bylocal-rpc.sh. Anvil keys are disposable but still should not enter commits. - Do not deploy, broadcast transactions, sync production keys, or call live RPCs unless the user explicitly asks.
- Do not change production/provider configuration without explicit approval: environment variable names, default RPC behavior, GitHub OIDC issuer, workflow permissions, contract addresses, or default package tags.
- Do not edit generated or dependency directories directly:
packages/cli/node_modules/,packages/cli/dist/,contracts/cache/,contracts/out/,contracts/broadcast/, orcontracts/lib/. - The committed static ABI at
packages/cli/src/abi/RIK.jsonis generated but tracked; update it only throughcd packages/cli && pnpm abiwhen the contract ABI changes. - Never replace pnpm with npm/yarn or Foundry with another contract toolchain without explicit user approval.