Multi-framework policy-as-code compliance scanner for infrastructure and application code. Scans Terraform, Kubernetes, Docker, .env, and application source (TypeScript, Python, Go, Java, Ruby) against SOC 2, HIPAA, and NIST CSF policies.
This repository hosts both the npm (Node.js) package and the PyPI (Python) package wrappers around the ProdCycle compliance REST API (https://api.prodcycle.com/v1/compliance/validate & https://api.prodcycle.com/v1/compliance/hook).
- 3 compliance frameworks: SOC 2, HIPAA, NIST CSF
- Automated policy enforcement: Server-side OPA/Rego and Cedar evaluation engines
- Infrastructure scanning: Terraform, Kubernetes manifests, Dockerfiles,
.envfiles - Application code scanning: TypeScript, Python, Go, Java, Ruby
- CI/CD integration: CLI with SARIF output for GitHub Code Scanning
- Coding-agent hooks: Real-time post-edit scanning for Claude Code, Cursor, and any stdin-capable agent
- One-command agent setup:
prodcycle initwrites compliance hook config for supported agents - Programmatic API: Full TypeScript and Python API for custom integrations
- Self-remediation:
gatereturns actionable remediation prompts that coding agents can consume directly
npm install -g @prodcycle/prodcycleIf you prefer to install from GitHub Packages, configure your npm to point to the ProdCycle scope:
echo "@prodcycle:registry=https://npm.pkg.github.com" > .npmrc
npm login --scope=@prodcycle --registry=https://npm.pkg.github.com
npm install @prodcycle/prodcyclepip install prodcyclePinning for CI: for reproducible runs, pin the package version — e.g.
npm install -g @prodcycle/prodcycle@0.6.xorpip install 'prodcycle==0.6.*'. The npm and PyPI packages share a single version number and are released together.
The CLI is organised as subcommands: scan, gate, hook, and init.
(The bare prodcycle <path> form is kept as a back-compat shim for prodcycle scan <path>.)
# Scan current directory against all 3 frameworks (default: soc2, hipaa, nist-csf).
# When run inside a CI environment (GitHub Actions, GitLab CI, CircleCI, Jenkins,
# Buildkite, Travis, Bitbucket Pipelines), the format auto-flips to SARIF so
# output drops straight into code-scanning dashboards.
prodcycle scan .
# Pin a specific framework or subset
prodcycle scan . --framework soc2,hipaa
prodcycle scan . --framework hipaa --severity-threshold high
# Explicit SARIF output
prodcycle scan . --format sarif --output results.sarif
# CI: scan only files changed in the PR (faster + diff-scoped findings)
prodcycle scan . --pr origin/main..HEAD
# LLM-ready remediation prompt
prodcycle scan . --format promptAuto-configure compliance hooks for the coding agents it detects in your repo. Hook agents (JSON config): Claude Code, Cursor. Instruction agents (sentinel-delimited markdown block in AGENTS.md or equivalent): Codex, OpenCode, GitHub Copilot, Gemini CLI.
prodcycle init
# or pin specific agents:
prodcycle init --agent claude,cursor --force --dir .
# or scaffold all supported:
prodcycle init --agent allSame command also scaffolds CI workflows when invoked with --ci:
# Writes .github/workflows/prodcycle.yml that delegates to
# the prodcycle/actions/compliance reusable action.
prodcycle init --ci github
# Or: GitLab .gitlab-ci.yml include / CircleCI .circleci/config.yml
prodcycle init --ci gitlab
prodcycle init --ci circleciOnce configured, the agent will pipe each edit through prodcycle hook, which returns a remediation prompt when a finding is produced. On violations the hook speaks each agent's native protocol and exits 0 so the remediation is fed back automatically (the compliance self-healing loop):
- Claude Code (
PostToolUse):{"decision":"block","reason":...} - Cursor (
postToolUseonWrite):{"additional_context":...}
For CI and manual use, hook prints the prompt and exits non-zero. You can also invoke the hook directly:
# From an agent — stdin is Claude Code PostToolUse payload or {file_path, content}
echo '{"file_path": "infra/main.tf", "content": "resource \"aws_s3_bucket\" ..."}' \
| prodcycle hook
# Scan a file on disk instead of reading content from stdin
prodcycle hook --file infra/main.tf --framework soc2,hipaagate accepts a JSON payload of files on stdin and calls the low-latency hook endpoint:
echo '{"files": {"main.tf": "resource \"aws_s3_bucket\" ..."}}' \
| prodcycle gate --framework soc2import { scan, gate } from '@prodcycle/prodcycle';
// Full Repository Scan
const { findings, exitCode } = await scan({
repoPath: '/path/to/repo',
frameworks: ['soc2', 'hipaa'],
options: {
severityThreshold: 'high',
failOn: ['critical', 'high'],
},
});
console.log(`Found ${findings.length} findings`);
console.log(`Exit code: ${exitCode}`);
// Gate — evaluate in-memory file contents (for coding agents)
const result = await gate({
files: {
'src/config.ts': 'export const DB_PASSWORD = "hardcoded-secret";',
'terraform/main.tf': 'resource "aws_s3_bucket" "data" { }',
},
frameworks: ['soc2', 'hipaa'],
});
if (!result.passed) {
console.log('Compliance issues found:');
console.log(result.prompt); // Pre-formatted remediation instructions
}from prodcycle import scan, gate
# Full Repository Scan
response = scan(
repo_path='/path/to/repo',
frameworks=['soc2', 'hipaa'],
options={
'severityThreshold': 'high',
'failOn': ['critical', 'high'],
}
)
print(f"Found {len(response['findings'])} findings")
print(f"Exit code: {response['exitCode']}")
# Gate — evaluate in-memory file contents (for coding agents)
result = gate(
files={
'src/config.ts': 'export const DB_PASSWORD = "hardcoded-secret";',
'terraform/main.tf': 'resource "aws_s3_bucket" "data" { }',
},
frameworks=['soc2', 'hipaa'],
)
if not result['passed']:
print('Compliance issues found:')
print(result['prompt']) # Pre-formatted remediation instructionsAn API key is required for production use to authenticate with ProdCycle. API keys are created through the ProdCycle dashboard. The key is resolved in this order: the --api-key flag, the PRODCYCLE_API_KEY environment variable (the legacy PC_API_KEY is still accepted but deprecated), then the user config file.
For interactive use, set the environment variable:
export PRODCYCLE_API_KEY=pc_your_api_key_hereFor agent hooks, save the key to the user config file instead — unlike an environment variable, it is picked up no matter how the editor was launched (a GUI-launched editor does not inherit shell exports), with no relaunch:
prodcycle init --api-key pc_your_api_key_hereThis writes ~/.config/prodcycle/config.json (chmod 600). When no key is configured, the Claude Code hook stays out of the way — it emits a one-line setup notice and exits 0 rather than blocking every edit.
The scanner honours .gitignore at the repo root and prunes common dependency / build directories (node_modules, .git, dist, build, venv, __pycache__, …) during tree-walk. It also applies:
- 256 KB per-file limit — larger files are skipped.
- 50,000 file cap — files beyond the cap are skipped with a stderr warning. Override with the
PRODCYCLE_MAX_FILESenvironment variable. - Binary skipping — non-text files are skipped via a null-byte probe.
Use --include / --exclude on prodcycle scan for custom glob patterns.
If a .prodcycleignore file is present at the repo root, its patterns are applied at scan time. Same gitignore-style syntax. Use this for files that should be skipped at scan time but stay in version control — e.g. scanner rule definitions that embed example credentials in source:
# .prodcycleignore — example: skip gitleaks rule-definition source
cmd/generate/config/rules/
Precedence vs. .gitignore and the .env* carve-out: .gitignore is also honored, but the scanner always scans .env* files (.env, .env.local, .env.production, .envrc, …) regardless of .gitignore — gitignored .env files routinely contain real credentials, and bypassing them would defeat secret detection. .prodcycleignore is treated as explicit user intent and overrides the .env* carve-out, so .prodcycleignore entries for .env.example etc. (e.g. scanner-source placeholders) do work. Order of precedence: --exclude CLI flag → .prodcycleignore → .env* always-scan carve-out → .gitignore.
Negation patterns (lines starting with !) are silently dropped; the simple glob matcher used here doesn't have gitignore's re-include semantics.
- Node.js >= 22.0.0
- Python >= 3.12
MIT — see LICENSE.