ShimLayer is a HITL API layer for last-mile failures in agentic workflows.
-
Fast CI
https://github.com/Ultraivanov/shimlayer/actions/workflows/ci-fast.yml -
UI E2E
https://github.com/Ultraivanov/shimlayer/actions/workflows/ui-e2e.yml
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
export SHIMLAYER_REPOSITORY=inmemory
uvicorn app.main:app --reloadOpen:
- API docs:
http://localhost:8000/docs - Health:
http://localhost:8000/v1/healthz
Built with React + Vite + Gravity UI.
cd frontend
cp .env.example .env
npm install
npm run devOpen: http://localhost:5173
Frontend in Docker:
docker compose --profile ui up --build frontendpytest -qQuick release checklist (short):
./scripts/preflight_fast.sh+./scripts/preflight_ui.sh- Verify env/secrets + DB schema (see
docs/release-checklist.md)
Release status: docs/release-summary.md
- End-to-end user journey (Requester → Operator → Ops):
docs/user-journey.md - Release checklist (primary):
docs/release-checklist.md - Requester hybrid integration (push + pull fallback):
docs/requester-hybrid-integration.md - OpenAI interruptions (resume loop):
docs/requester-hybrid-integration.md(section 0) - Alpha local runbook:
docs/alpha-local-runbook.md - Deploy runbook:
docs/deploy-runbook-v0.md - Deploy handoff (for specialist):
docs/deploy-handoff.md - Security notes:
docs/security-notes.md - Deployment readiness report template:
docs/deployment-readiness-report-template.md - Pre-deploy one-pager:
docs/pre-deploy-onepager.md - Deployment readiness report example:
docs/deployment-readiness-report-example.md - Deploy handoff pack (read order):
docs/deploy-handoff-pack.md - Lead capture landing (Gravity UI):
frontend/src/pages/LeadPage.tsx(served at/lead) - Lead capture API:
POST /v1/leads(public, seedocs/openapi-v0.yaml)
Fast backend checks (no docker):
./scripts/preflight_fast.shFrontend build + UI smoke (Playwright):
./scripts/preflight_ui.shUnified preflight:
# fast + ui
./scripts/preflight_all.sh
# fast + ui + docker/postgres integration
./scripts/preflight_all.sh --with-docker
# strict (fails on any SKIP, requires docker + localhost binds)
./scripts/preflight_strict.shCI automation:
.github/workflows/ci-fast.ymlruns fast preflight on push/PR..github/workflows/ui-e2e.ymlruns UI smoke on manual trigger.
Common CI failures:
playwright executable doesn't exist: runnpm --prefix frontend run e2e:install.browser install fails in CI: ensure outbound access to Playwright CDN is allowed.address already in use (8000/4173): verify no parallel job starts conflicting local servers in the same runner step.pytest not found: ensurepip install -r requirements.txtcompleted before preflight.npm cilockfile error: regeneratefrontend/package-lock.jsonlocally and commit it.
docker compose up --buildBy default docker-compose.yml configures Postgres mode:
SHIMLAYER_REPOSITORY=postgresSHIMLAYER_DB_DSN=postgresql://shim:shim@postgres:5432/shimlayerSHIMLAYER_CORS_ORIGINS=http://localhost:5173,http://127.0.0.1:5173SHIMLAYER_ADMIN_API_KEY=dev-admin-key
Apply schema before using Postgres mode:
- Execute docs/supabase-schema-v0.sql against your Postgres/Supabase database.
- Schema includes
ops_task_auditfor admin case actions (manual review, reassign, force status, refund note trail).
Webhook delivery settings:
SHIMLAYER_WEBHOOK_SECRETSHIMLAYER_WEBHOOK_TIMEOUT_SECONDSSHIMLAYER_WEBHOOK_MAX_ATTEMPTSSHIMLAYER_WEBHOOK_TIMESTAMP_TOLERANCE_SECONDS- Outbound webhook headers:
X-ShimLayer-Signature(sha256=<hmac>)X-ShimLayer-Timestamp(unix seconds)Idempotency-Key
Run webhook worker (queue consumer):
python -m app.workers.webhook_workerPull fallback (recommended hybrid mode):
- Poll a single task:
GET /v1/tasks/{task_id} - Incremental sync:
GET /v1/tasks/sync(cursor-based) - See
docs/requester-hybrid-integration.md.
Run Postgres integration test (requires local Postgres on 5432):
pytest -q -m postgres tests/test_postgres_webhook_queue.pyRun compose smoke check:
./scripts/smoke_postgres.shRun full alpha readiness check:
./scripts/alpha_readiness_check.shRun local preflight (ops/admin + stripe tests + postgres smoke/integration):
./scripts/preflight_local.shRun DB cleanup job (recommended via daily cron):
python -m app.tools.cleanup_dbCleanup retention settings (env vars):
SHIMLAYER_RETENTION_WEBHOOK_DELIVERIES_DAYS(default30)SHIMLAYER_RETENTION_SUCCEEDED_JOBS_DAYS(default7)SHIMLAYER_RETENTION_API_RATE_WINDOWS_HOURS(default48)SHIMLAYER_RETENTION_ARTIFACTS_DAYS(default30, also deleteslocal:artifact files)
Run ops threshold check (for cron/CI):
SHIMLAYER_API_URL=http://localhost:8000 \
SHIMLAYER_API_KEY=ops-checker \
./scripts/check_ops_thresholds.pyGenerate alpha sign-off report:
SHIMLAYER_API_URL=http://localhost:8000 \
SHIMLAYER_API_KEY=ops-checker \
SHIMLAYER_ENV=local \
SHIMLAYER_REVIEWER=your-name \
./scripts/generate_alpha_signoff.pydocs/prd-v0.mddocs/openapi-v0.yamldocs/supabase-schema-v0.sqldocs/alpha-launch-kit.mddocs/alpha-ready-checklist.mddocs/alpha-release-notes.mddocs/webhook-receiver-example.mddocs/runbook-commands.mddocs/alpha-signoff-template.mddocs/ops-admin-test-plan.mddocs/ops-runbook.mddocs/deployment-readiness-checklist.mddocs/release-checklist.md
- Purchase package:
curl -X GET http://localhost:8000/v1/billing/packages \
-H "X-API-Key: demo-key"- Purchase selected package:
curl -X POST http://localhost:8000/v1/billing/packages/purchase \
-H "Content-Type: application/json" \
-H "X-API-Key: demo-key" \
-d '{"package_code":"indie_entry_150","reference":"invoice-123"}'2a. Create Stripe Checkout Session (if Stripe keys configured):
curl -X POST http://localhost:8000/v1/billing/stripe/checkout-session \
-H "Content-Type: application/json" \
-H "X-API-Key: demo-key" \
-d '{"package_code":"indie_entry_150","success_url":"https://example.com/success","cancel_url":"https://example.com/cancel","customer_email":"dev@example.com"}'- Create task (consumes 1 flow credit).
- Refund task (restores 1 flow credit):
curl -X POST http://localhost:8000/v1/tasks/<task_id>/refund \
-H "X-API-Key: demo-key"- Requeue dead-letter webhook item:
curl -X POST http://localhost:8000/v1/webhooks/dlq/<dead_letter_id>/requeue \
-H "X-API-Key: demo-key" \
-H "X-Admin-Key: dev-admin-key" \
-H "X-Admin-Role: admin" \
-H "X-Admin-User: ops-user-1"- Fetch ops metrics:
curl http://localhost:8000/v1/ops/metrics \
-H "X-API-Key: demo-key" \
-H "X-Admin-Key: dev-admin-key" \
-H "X-Admin-Role: admin" \
-H "X-Admin-User: ops-user-1"6a. List webhook dead-letter entries:
curl "http://localhost:8000/v1/ops/dlq?limit=20" \
-H "X-API-Key: demo-key" \
-H "X-Admin-Key: dev-admin-key" \
-H "X-Admin-Role: admin" \
-H "X-Admin-User: ops-user-1"6b. List active/problem flows for Ops Control Tower:
curl "http://localhost:8000/v1/ops/flows?limit=50&only_problem=true" \
-H "X-API-Key: demo-key" \
-H "X-Admin-Key: dev-admin-key" \
-H "X-Admin-Role: admin" \
-H "X-Admin-User: ops-user-1"6b.1. List SLA-breach queue (overdue or <2 min to deadline):
curl "http://localhost:8000/v1/ops/flows?limit=50&only_sla_breach=true" \
-H "X-API-Key: demo-key" \
-H "X-Admin-Key: dev-admin-key" \
-H "X-Admin-Role: admin" \
-H "X-Admin-User: ops-user-1"6c. Run admin action on a flow:
curl -X POST "http://localhost:8000/v1/ops/flows/<task_id>/actions" \
-H "Content-Type: application/json" \
-H "X-API-Key: demo-key" \
-H "X-Admin-Key: dev-admin-key" \
-H "X-Admin-Role: ops_manager" \
-H "X-Admin-User: ops-user-1" \
-d '{"action":"manual_review","manual_verdict":"rejected","note":"Proof mismatch"}'For sensitive actions (refund, force_status) reason_code is required:
customer_request, proof_mismatch, policy_violation, sla_breach, fraud_risk, incident_mitigation.
Admin role header is mandatory for Ops endpoints (X-Admin-Role): ops_agent, ops_manager, finance, admin.
6d. Run bulk admin action:
curl -X POST "http://localhost:8000/v1/ops/flows/bulk-actions" \
-H "Content-Type: application/json" \
-H "X-API-Key: demo-key" \
-H "X-Admin-Key: dev-admin-key" \
-H "X-Admin-Role: ops_manager" \
-H "X-Admin-User: ops-user-1" \
-d '{"task_ids":["<task_id_1>","<task_id_2>"],"action":"force_status","status":"disputed","reason_code":"incident_mitigation","note":"incident triage"}'6e. Incident board and auto scan:
curl "http://localhost:8000/v1/ops/incidents?status_filter=open&limit=50" \
-H "X-API-Key: demo-key" \
-H "X-Admin-Key: dev-admin-key" \
-H "X-Admin-Role: ops_manager" \
-H "X-Admin-User: ops-user-1"curl -X POST "http://localhost:8000/v1/ops/incidents/scan" \
-H "Content-Type: application/json" \
-H "X-API-Key: demo-key" \
-H "X-Admin-Key: dev-admin-key" \
-H "X-Admin-Role: ops_manager" \
-H "X-Admin-User: ops-user-1" \
-d '{"overdue_threshold": 5}'6f. Incident event log:
curl "http://localhost:8000/v1/ops/incidents/<incident_id>/events?limit=100" \
-H "X-API-Key: demo-key" \
-H "X-Admin-Key: dev-admin-key" \
-H "X-Admin-Role: ops_manager" \
-H "X-Admin-User: ops-user-1"6g. Finance + observability:
curl "http://localhost:8000/v1/ops/finance/ledger?limit=100" \
-H "X-API-Key: demo-key" \
-H "X-Admin-Key: dev-admin-key" \
-H "X-Admin-Role: finance" \
-H "X-Admin-User: finance-user-1"curl "http://localhost:8000/v1/ops/finance/margin" \
-H "X-API-Key: demo-key" \
-H "X-Admin-Key: dev-admin-key" \
-H "X-Admin-Role: finance" \
-H "X-Admin-User: finance-user-1"curl "http://localhost:8000/v1/ops/observability/metrics" \
-H "X-API-Key: demo-key" \
-H "X-Admin-Key: dev-admin-key" \
-H "X-Admin-Role: admin" \
-H "X-Admin-User: ops-user-1"- Verify inbound webhook signature in your receiver (example):
from app.webhooks.verification import verify_webhook_signature
ok = verify_webhook_signature(
payload=request_body_bytes,
signature_header=request_headers.get("X-ShimLayer-Signature"),
timestamp_header=request_headers.get("X-ShimLayer-Timestamp"),
secret=WEBHOOK_SECRET,
tolerance_seconds=300,
)- Stripe webhook endpoint (server-side):
POST /v1/webhooks/stripe- verifies
Stripe-Signature - idempotent by Stripe
event.id - processes:
checkout.session.completedpayment_intent.succeededcharge.refundedcustomer.subscription.created|updated|deleted
- expected metadata:
api_keypackage_code- optional
topup_usdfor payment intents