GitPay is a CI/CD-native value transfer engine, shipped as a versioned GitHub Action. A repository event (e.g. a merged PR) produces a payment intent, a human signs it, the workflow settles it on-chain, and a receipt is posted back — with no server operated by the project and no secrets required in the default configuration.
- Runs in your CI, not ours — ships as a GitHub Action (
uses: StabilityNexus/GitPay@v1); the maintaining project operates no backend and never holds funds. - Safe by default —
mode: dry-rununless explicitly opted out; a fresh integration needs zero secrets. - Built on x402 v2 (Linux Foundation standard) —
first driver implements the
exactscheme over EIP-3009transferWithAuthorization(USDC). - Strict layer boundary — the core engine and adapters never import a chain library, hash
primitive, or token address; every rail lives behind a
SettlementDriverinsrc/drivers/. See AGENTS.md for the enforced invariants. Adding a network is a config-only change, verified in CI by diffing that no core files changed. - Idempotent by construction — re-running a workflow reproduces the same settlement key;
AUTH_ALREADY_USEDis treated as success, not failure. - Minimal dependency surface — runtime dependencies are capped at 2 packages
(
@noble/curves,@noble/hashes), enforced in CI.
- Runtime: Node.js ≥ 20, TypeScript, bundled with
@vercel/nccinto a committeddist/ - Distribution: GitHub Action (
action.yml,using: node24) - Protocol: x402 v2 —
exactscheme, EIP-3009 / EIP-712, CAIP-2 network identifiers - Chain (Tier 1 target): Base Sepolia, USDC — see
assets/chains.json - CLI:
npx gitpay verify | encode— fully offline, no keys or network required
Six layers, one rule: nothing in src/core/** or src/adapters/** may import a chain library,
token address, RPC URL, or chain-specific primitive. See AGENTS.md for the full
rationale and the CI-enforced invariants (I1–I13).
L5 RECEIPT SettlementResponse → PR comment + machine-readable receipt
L4 SETTLEMENT driver registry: (scheme × network) → driver ← only layer that knows rails
L3 AUTHORIZATION PaymentPayload — who approved, cryptographically
L2 INTENT PaymentRequirements — what moves, to whom
L1 POLICY offline gates, no network
L0 TRIGGER repo event → Intent
- Node.js ≥ 20
- npm
Add one file. No secrets are needed: the default mode is dry-run, which reads the command,
checks policy and reports what it would pay, and moves nothing.
# .github/workflows/gitpay.yml
name: GitPay
on:
issue_comment:
types: [created]
permissions:
issues: write
pull-requests: write
jobs:
pay:
# A `/send <recipient> <amount>` comment on a pull request.
if: github.event.issue.pull_request && startsWith(github.event.comment.body, '/send')
runs-on: ubuntu-latest
steps:
- uses: StabilityNexus/GitPay@v1
with:
comment: ${{ github.event.comment.body }}
actor_association: ${{ github.event.comment.author_association }}
# Ties the payout to this PR, so a re-run can never pay it twice.
ref: refs/pull/${{ github.event.issue.number }}Then comment /send 0xRecipientAddress 1 USDC on a pull request. The run log shows the parsed
payout, the policy checks, and the idempotency key, and ends with
mode: dry-run — nothing was settled.
kpj2006/gitpay-quickstart is this file and
nothing else.
Going live. Create a Safe on Ethereum Sepolia, and in Safe{Wallet} give a delegate address
a spending limit (Settings → Setup → Spending limits). Then add these inputs, keeping the key and
the RPC URL in repository secrets, and serialize payouts so two runs never sign at once. Put
concurrency on the job, not the workflow, so other PR comments never join the queue, and keep
queue: max so a waiting /send is never cancelled by a later one:
jobs:
pay:
# …
concurrency:
group: gitpay-payout-${{ github.repository }}
cancel-in-progress: false
queue: max
# …
with:
# the three inputs above, plus:
mode: self
max_per_payout: "5" # the largest single payout, in /send units
rpc_url: ${{ secrets.GITPAY_RPC_URL }}
safe: "0xYourSafe"
token: "0xYourToken"
delegate_key: ${{ secrets.GITPAY_DELEGATE_KEY }}
pr: ${{ github.event.issue.number }}
github_token: ${{ secrets.GITHUB_TOKEN }}SETTLEMENT-FLOW.md explains what the delegate can and cannot do, and
schema/action-inputs.v1.schema.json describes every
input.
git clone https://github.com/StabilityNexus/GitPay.git
cd GitPay
npm install
npm run check # lint + layer-boundary check + dependency-count check + tests
npm test # tests only
npm run build # bundle src/ into dist/index.js — commit dist/ with your change (CI diffs it)To run the Action, push a branch that contains a workflow using it (see
Using the Action); with no mode input it runs as a dry run and moves no
funds. To run the marketing site locally: cd frontend && npm install && npm run dev.
See CONTRIBUTING.md for the full contribution workflow and ROADMAP.md for what's being built and in what order.
⭐ Don't forget to star this repository if you find it useful! ⭐
Thank you for considering contributing to this project! Contributions are highly appreciated and welcomed. To ensure smooth collaboration, please refer to our Contribution Guidelines.
See MAINTAINERS.md for maintainers, mentors, and ideators.
This project is licensed under the MIT License. See the LICENSE file for details.
Thanks a lot for spending your time helping GitPay grow. Keep rocking 🥂
© 2026 AOSSIE