{"id":44469729,"url":"https://github.com/mcp-tool-shop-org/payroll-engine","last_synced_at":"2026-02-27T01:00:58.302Z","repository":{"id":334603925,"uuid":"1142021710","full_name":"mcp-tool-shop-org/payroll-engine","owner":"mcp-tool-shop-org","description":"Library-first PSP core for payroll and regulated money movement. Append-only ledger, funding gates, domain events, advisory-only AI.","archived":false,"fork":false,"pushed_at":"2026-02-23T12:06:37.000Z","size":1510,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-23T13:00:21.005Z","etag":null,"topics":["financial-infrastructure","fintech","ledger","payments","payroll","psp","python"],"latest_commit_sha":null,"homepage":"https://mcp-tool-shop-org.github.io/payroll-engine/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mcp-tool-shop-org.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":"CITATION.cff","codeowners":"CODEOWNERS","security":"SECURITY.md","support":"SUPPORT.md","governance":null,"roadmap":"docs/roadmap.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-25T20:33:00.000Z","updated_at":"2026-02-23T12:06:50.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/mcp-tool-shop-org/payroll-engine","commit_stats":null,"previous_names":["mcp-tool-shop/payroll-engine","mcp-tool-shop-org/payroll-engine"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/mcp-tool-shop-org/payroll-engine","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mcp-tool-shop-org%2Fpayroll-engine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mcp-tool-shop-org%2Fpayroll-engine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mcp-tool-shop-org%2Fpayroll-engine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mcp-tool-shop-org%2Fpayroll-engine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mcp-tool-shop-org","download_url":"https://codeload.github.com/mcp-tool-shop-org/payroll-engine/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mcp-tool-shop-org%2Fpayroll-engine/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29879896,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-26T23:51:21.483Z","status":"ssl_error","status_checked_at":"2026-02-26T23:50:46.793Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["financial-infrastructure","fintech","ledger","payments","payroll","psp","python"],"created_at":"2026-02-12T21:08:32.356Z","updated_at":"2026-02-27T01:00:58.295Z","avatar_url":"https://github.com/mcp-tool-shop-org.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003ca href=\"README.ja.md\"\u003e日本語\u003c/a\u003e | \u003ca href=\"README.zh.md\"\u003e中文\u003c/a\u003e | \u003ca href=\"README.es.md\"\u003eEspañol\u003c/a\u003e | \u003ca href=\"README.fr.md\"\u003eFrançais\u003c/a\u003e | \u003ca href=\"README.hi.md\"\u003eहिन्दी\u003c/a\u003e | \u003ca href=\"README.it.md\"\u003eItaliano\u003c/a\u003e | \u003ca href=\"README.pt-BR.md\"\u003ePortuguês (BR)\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/mcp-tool-shop-org/brand/main/logos/payroll-engine/readme.png\" alt=\"Payroll Engine logo\" width=\"400\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/mcp-tool-shop-org/payroll-engine/actions/workflows/ci.yml\"\u003e\u003cimg src=\"https://github.com/mcp-tool-shop-org/payroll-engine/actions/workflows/ci.yml/badge.svg\" alt=\"CI\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://pypi.org/project/payroll-engine/\"\u003e\u003cimg src=\"https://img.shields.io/pypi/v/payroll-engine\" alt=\"PyPI\"\u003e\u003c/a\u003e\n  \u003ca href=\"LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/License-MIT-blue.svg\" alt=\"License: MIT\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://mcp-tool-shop-org.github.io/payroll-engine/\"\u003e\u003cimg src=\"https://img.shields.io/badge/Landing_Page-live-blue\" alt=\"Landing Page\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n**A library-first PSP core for payroll and regulated money movement.**\n\nDeterministic append-only ledger. Explicit funding gates. Replayable events. Advisory-only AI (disabled by default). Correctness over convenience.\n\n## Trust Anchors\n\nBefore adopting this library, review:\n\n| Document | Purpose |\n|----------|---------|\n| [docs/psp_invariants.md](docs/psp_invariants.md) | System invariants (what's guaranteed) |\n| [docs/threat_model.md](docs/threat_model.md) | Security analysis |\n| [docs/public_api.md](docs/public_api.md) | Public API contract |\n| [docs/compat.md](docs/compat.md) | Compatibility guarantees |\n| [docs/adoption_kit.md](docs/adoption_kit.md) | Evaluation and embedding guide |\n\n*We know this moves money. These documents prove we took it seriously.*\n\n---\n\n## Why This Exists\n\nMost payroll systems treat money movement as an afterthought. They call a payment API, hope for the best, and deal with failures reactively. This creates:\n\n- **Silent failures**: Payments vanish into the void\n- **Reconciliation nightmares**: Bank statements don't match records\n- **Liability confusion**: When returns happen, who pays?\n- **Audit gaps**: No one can trace what actually happened\n\nThis project solves these problems by treating money movement as a first-class concern with proper financial engineering.\n\n## Core Principles\n\n### Why Append-Only Ledgers Matter\n\nYou can't undo a wire transfer. You can't un-send an ACH. The real world is append-only—so your ledger should be too.\n\n```\n❌ UPDATE ledger SET amount = 100 WHERE id = 1;  -- What was it before?\n✅ INSERT INTO ledger (...) VALUES (...);         -- We reversed entry #1 for reason X\n```\n\nEvery modification is a new entry. History is preserved. Auditors are happy.\n\n### Why Two Funding Gates Exist\n\n**Commit Gate**: \"Do we have the money to promise these payments?\"\n**Pay Gate**: \"Do we still have the money right before we send them?\"\n\nThe time between commit and pay can be hours or days. Balances change. Other batches run. The pay gate is the final checkpoint—it runs even if someone tries to bypass it.\n\n```python\n# Commit time (Monday)\npsp.commit_payroll_batch(batch)  # Reservation created\n\n# Pay time (Wednesday)\npsp.execute_payments(batch)      # Pay gate checks AGAIN before sending\n```\n\n### Why Settlement ≠ Payment\n\n\"Payment sent\" is not \"money moved.\" ACH takes 1-3 days. FedNow is instant but can still fail. Wire is same-day but expensive.\n\nPSP tracks the full lifecycle:\n```\nCreated → Submitted → Accepted → Settled (or Returned)\n```\n\nUntil you see `Settled`, you don't have confirmation. Until you ingest the settlement feed, you don't know what really happened.\n\n### Why Reversals Exist Instead of Deletes\n\nWhen money moves wrong, you need a reversal—a new ledger entry that offsets the original. This:\n\n- Preserves the audit trail (original + reversal)\n- Shows *when* the correction happened\n- Documents *why* (return code, reason)\n\n```sql\n-- Original\nINSERT INTO ledger (amount, ...) VALUES (1000, ...);\n\n-- Reversal (not delete!)\nINSERT INTO ledger (amount, reversed_entry_id, ...) VALUES (-1000, \u003coriginal_id\u003e, ...);\n```\n\n### Why Idempotency is Mandatory\n\nNetwork failures happen. Retries are necessary. Without idempotency, you get double payments.\n\nEvery operation in PSP has an idempotency key:\n```python\nresult = psp.commit_payroll_batch(batch)\n# First call: creates reservation, returns is_new=True\n# Second call: finds existing, returns is_new=False, same reservation_id\n```\n\nThe caller doesn't need to track \"did my call succeed?\"—just retry until you get a result.\n\n## What This Is\n\nA **reference-grade PSP core** suitable for:\n\n- Payroll engines\n- Gig economy platforms\n- Benefits administrators\n- Treasury management\n- Any regulated fintech backend that moves money\n\n## What This Is NOT\n\nThis is **not**:\n- A Stripe clone (no merchant onboarding, no card processing)\n- A payroll SaaS (no tax calculation, no UI)\n- A demo or prototype (production-grade constraints)\n\nSee [docs/non_goals.md](docs/non_goals.md) for explicit non-goals.\n\n## Quick Start\n\n```bash\n# Start PostgreSQL\nmake up\n\n# Apply migrations\nmake migrate\n\n# Run the demo\nmake demo\n```\n\nThe demo shows the full lifecycle:\n1. Create tenant and accounts\n2. Fund the account\n3. Commit a payroll batch (reservation)\n4. Execute payments\n5. Simulate settlement feed\n6. Handle a return with liability classification\n7. Replay events\n\n## Library Usage\n\nPSP is a library, not a service. Use it inside your application:\n\n```python\nfrom payroll_engine.psp import PSP, PSPConfig, LedgerConfig, FundingGateConfig\n\n# Explicit configuration (no magic, no env vars)\nconfig = PSPConfig(\n    tenant_id=tenant_id,\n    legal_entity_id=legal_entity_id,\n    ledger=LedgerConfig(require_balanced_entries=True),\n    funding_gate=FundingGateConfig(pay_gate_enabled=True),  # NEVER False\n    providers=[...],\n    event_store=EventStoreConfig(),\n)\n\n# Single entry point\npsp = PSP(session=session, config=config)\n\n# Commit payroll (creates reservation)\ncommit_result = psp.commit_payroll_batch(batch)\n\n# Execute payments (pay gate runs automatically)\nexecute_result = psp.execute_payments(batch)\n\n# Ingest settlement feed\ningest_result = psp.ingest_settlement_feed(records)\n```\n\n## Documentation\n\n| Document | Purpose |\n|----------|---------|\n| [docs/public_api.md](docs/public_api.md) | Public API contract (what's stable) |\n| [docs/compat.md](docs/compat.md) | Versioning and compatibility |\n| [docs/psp_invariants.md](docs/psp_invariants.md) | System invariants (what's guaranteed) |\n| [docs/idempotency.md](docs/idempotency.md) | Idempotency patterns |\n| [docs/threat_model.md](docs/threat_model.md) | Security analysis |\n| [docs/non_goals.md](docs/non_goals.md) | What PSP doesn't do |\n| [docs/upgrading.md](docs/upgrading.md) | Upgrade and migration guide |\n| [docs/runbooks/](docs/runbooks/) | Operational procedures |\n| [docs/recipes/](docs/recipes/) | Integration examples |\n\n## API Stability Promise\n\n**Stable (will not break without major version):**\n- `payroll_engine.psp` - PSP facade and config\n- `payroll_engine.psp.providers` - Provider protocol\n- `payroll_engine.psp.events` - Domain events\n- `payroll_engine.psp.ai` - AI advisory (config and public types)\n\n**Internal (may change without notice):**\n- `payroll_engine.psp.services.*` - Implementation details\n- `payroll_engine.psp.ai.models.*` - Model internals\n- Anything with `_` prefix\n\n**AI Advisory constraints (enforced):**\n- Cannot move money\n- Cannot write ledger entries\n- Cannot override funding gates\n- Cannot make settlement decisions\n- Emits advisory events only\n\nSee [docs/public_api.md](docs/public_api.md) for the full contract.\n\n## Key Guarantees\n\n| Guarantee | Enforcement |\n|-----------|-------------|\n| Money is always positive | `CHECK (amount \u003e 0)` |\n| No self-transfers | `CHECK (debit != credit)` |\n| Ledger is append-only | No UPDATE/DELETE on entries |\n| Status only moves forward | Trigger validates transitions |\n| Events are immutable | Schema versioning in CI |\n| Pay gate cannot be bypassed | Enforced in facade |\n| AI cannot move money | Architectural constraint |\n\n## CLI Tools\n\n```bash\n# Check database health\npsp health\n\n# Verify schema constraints\npsp schema-check --database-url $DATABASE_URL\n\n# Replay events\npsp replay-events --tenant-id $TENANT --since \"2025-01-01\"\n\n# Export events for audit\npsp export-events --tenant-id $TENANT --output events.jsonl\n\n# Query balance\npsp balance --tenant-id $TENANT --account-id $ACCOUNT\n```\n\n## Installation\n\n```bash\n# Core only (ledger, funding gate, payments - that's it)\npip install payroll-engine\n\n# With PostgreSQL driver\npip install payroll-engine[postgres]\n\n# With async support\npip install payroll-engine[asyncpg]\n\n# With AI advisory features (optional, disabled by default)\npip install payroll-engine[ai]\n\n# Development\npip install payroll-engine[dev]\n\n# Everything\npip install payroll-engine[all]\n```\n\n## Optional Dependencies\n\nPSP is designed with strict optionality. **Core money movement requires zero optional dependencies.**\n\n| Extra | What It Adds | Default State |\n|-------|--------------|---------------|\n| `[ai]` | ML-based AI models (future) | Not needed for rules-baseline |\n| `[crypto]` | Blockchain integrations (future) | **OFF** - reserved for future |\n| `[postgres]` | PostgreSQL driver | Not loaded unless used |\n| `[asyncpg]` | Async PostgreSQL | Not loaded unless used |\n\n### AI Advisory: Two-Tier System\n\n**Rules-baseline AI works without any extras.** You get:\n- Risk scoring\n- Return analysis\n- Runbook assistance\n- Counterfactual simulation\n- Tenant risk profiling\n\nAll with zero dependencies beyond stdlib.\n\n```python\nfrom payroll_engine.psp.ai import AdvisoryConfig, ReturnAdvisor\n\n# Rules-baseline needs NO extras - just enable it\nconfig = AdvisoryConfig(enabled=True, model_name=\"rules_baseline\")\n```\n\n**ML models (future) require `[ai]` extras:**\n\n```python\n# Only needed for ML models, not rules-baseline\npip install payroll-engine[ai]\n\n# Then use ML models\nconfig = AdvisoryConfig(enabled=True, model_name=\"gradient_boost\")\n```\n\n### AI Advisory Constraints (Enforced)\n\nAll AI features can **never**:\n- Move money\n- Write ledger entries\n- Override funding gates\n- Make settlement decisions\n\nAI emits advisory events for human/policy review only.\n\nSee [docs/public_api.md](docs/public_api.md) for the full optionality table.\n\n## Testing\n\n```bash\n# Unit tests\nmake test\n\n# With database\nmake test-psp\n\n# Red team tests (constraint verification)\npytest tests/psp/test_red_team_scenarios.py -v\n```\n\n## Who Should Use This\n\n**Use PSP if you**:\n- Move money in regulated contexts\n- Need audit trails that satisfy compliance\n- Care about correctness over convenience\n- Have handled payment failures at 3 AM\n\n**Don't use PSP if you**:\n- Want a drop-in Stripe replacement\n- Need a complete payroll solution\n- Prefer convention over configuration\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.\n\nKey rules:\n- No new public API without updating `docs/public_api.md`\n- Event schema changes must pass compatibility check\n- All money operations require idempotency keys\n\n## License\n\nMIT License. See [LICENSE](LICENSE).\n\n---\n\n*Built by engineers who've been paged at 3 AM because payments failed silently.*\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmcp-tool-shop-org%2Fpayroll-engine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmcp-tool-shop-org%2Fpayroll-engine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmcp-tool-shop-org%2Fpayroll-engine/lists"}