Metadata-Version: 2.4
Name: patchr
Version: 0.1.5
Summary: Patchr - the Work Execution Protocol for developers building automated software delivery workflows.
Author: Patchr Core Team
License-Expression: Apache-2.0
Project-URL: Homepage, https://patchr.co
Project-URL: Documentation, https://patchr.co/api-reference
Project-URL: Sandbox, https://patchr.co/sandbox
Project-URL: Source, https://github.com/orepos/Patchr
Keywords: patchr,sdk,mcp,a2a,workflow,work-execution,developer-workflows,software-delivery
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: api
Requires-Dist: fastapi>=0.111; extra == "api"
Requires-Dist: uvicorn>=0.30; extra == "api"
Requires-Dist: cryptography>=42; extra == "api"
Provides-Extra: worker
Requires-Dist: redis>=5.0; extra == "worker"
Requires-Dist: rq>=1.16; extra == "worker"
Provides-Extra: db
Requires-Dist: psycopg[binary]>=3.2; extra == "db"
Requires-Dist: psycopg_pool>=3.2; extra == "db"
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Dynamic: license-file

# Patchr

Patchr - the Work Execution Protocol for developers building automated software delivery workflows.

Patchr is an SDK and hosted API for turning engineering intent into executed work with contracts, evidence trails, human-safe handoffs, and portable proof outputs.

Use it when your app needs to configure environments, validate release readiness, coordinate deployment handoffs, monitor workflow state, repair broken processes, or run external work through auditable JSON results and streaming status messages.

Patchr workers are deterministic, policy-gated engines — not free-running LLM agents. Every run produces the same auditable result for the same inputs, mutating actions always pause for human approval, and live execution is delegated to systems you connect (CI pipelines, webhooks, SaaS APIs). An optional LLM triage layer (Gemini or a custom endpoint) can refine intent classification, and can be disabled.

The same protocol primitives power all of those workflows:

- `Hunt` discovers dependencies, services, sources, risks, and candidate work.
- `Resolve` validates requirements, contradictions, evidence, and next actions.
- `Bridge` connects repositories, CI/CD, cloud resources, SaaS tools, APIs, MCP, and A2A.
- `Proxy` pauses automation for human judgment, protected operations, and proof capture.
- `Pay` settles outcome-based work with mandates, receipts, and proof-of-value.

Engineering intent routes to dedicated developer domains:

- `environment` maps runtimes, dependencies, backing services, and required secrets from repository files.
- `cicd` evaluates release gates and produces deployment plans with rollback steps.
- `kubernetes` triages cluster snapshots and proposes approval-gated remediations.
- `incident` correlates alerts into a triaged incident with safe next actions.
- `migration` classifies schema changes and gates risky database rollouts.
- `security` scans provided files for exposed secrets and insecure configuration.
- `delivery` chains configure, validate, and deploy with human approval gates.

## Status: shipped vs planned

| Capability | Status |
| --- | --- |
| Orchestrator, streaming, resume, proof packs | Shipped |
| Developer-intent routing (LLM planner, active by default; deterministic fallback) | Shipped — natural-language requests route to the owning developer domain; the planner refines ambiguous routes and is fail-closed. Kill switch: `PICUX_LLM_PLANNER_ENABLED=false` |
| Developer domains (environment, cicd, kubernetes, incident, migration, security, delivery) | Shipped — deterministic advisory plans; live execution via connectors after approval, or **autonomously under a mandate** (see below) |
| Autonomous execution | Shipped, opt-in — `runAutonomous(payload)` auto-approves the gates a mandate grants and runs setup commands through a guarded executor. Off by default; ungranted gates still pause for a human |
| Human-in-the-loop (approval gates, proxy missions, durable resume) | Shipped |
| Connector catalog | 25 connectors — 22 live (Gmail, Slack, Jira, Salesforce, Twilio, GitHub, GitLab, AWS/GCP/Azure CI, shipmentTracking, ...), 3 simulation-only (blockchainExplorer, chainAnalytics, bankRecall) |
| Per-connector network egress policies | Shipped — `allowOutbound` + allow/deny host lists, enforced at the action boundary and the wire; cloud-metadata denied by default |
| Physical logistics | Shipped — `shipmentTracking` connector (23-carrier catalog, auto-detect) + HMAC-verified carrier webhook ingestion with durable storage |
| MCP server (JSON-RPC 2.0, 219 tools; typed input schemas on the highest-traffic tools) | Shipped |
| Change verification (`verifyChange` — one pass/review/block verdict over a change, per-gate checks, proof pack, optional GitHub commit status) | Shipped — status posting is contract-mode by default, live with `GITHUB_TOKEN` + explicit opt-in |
| Coding-agent surface (`exportAgentBrief` briefs as AGENTS.md/CLAUDE.md/Cursor rules; autonomy **code mode** drives a coding agent under a mandate) | Shipped — see `docs/developers/coding-agents.md` |
| Run history + console (orchestrator runs persisted with route, planner decision, and full trace; live console at `/console`) | Shipped — `listOrchestratorRuns` / `getOrchestratorRun` / `observabilityMetrics`; counters wire up via `PICUX_REDIS_URL` |
| Runtime governance (Decionis `SDK_EXECUTION_GATE` evaluated before every autonomous run) | Shipped — shadow by default, `PICUX_AUTONOMY_GOVERNANCE=enforce` stops non-allow runs; CI `infra-destroy` gate enforces |
| A2A envelopes | Shipped (`picux-a2a` protocol; not interoperable with Google A2A) |
| SDKs | Python + Node (full surface), Go + Java + .NET (core + developer domains + activation); `filesFromLocalRepo` in all five |
| Pay: mandates, escrow state machine, receipts | Shipped (local ledger; HMAC-signed receipts when `PICUX_RECEIPT_SIGNING_SECRET` is set) |
| Pay rail: `stripeSpt` | Live test-mode — with `STRIPE_SECRET_KEY` + `{"live": true}` (or `PICUX_STRIPE_LIVE=true`), creates/captures real manual-capture PaymentIntents; otherwise contract-mode |
| Pay rail: `solanaPay` | Live signing — pure-Python Ed25519 signer for the `picux_escrow` Anchor program; opt-in via `PICUX_SOLANA_SIGNER_SECRET` + live flag |
| Pay rail: `baseUsdc` | Live signing — pure-Python secp256k1/keccak/EIP-155 signer + ERC-20 / `PicuxEscrow.sol` calls; opt-in via `PICUX_BASE_SIGNER_SECRET` + live flag |
| Pay rails: `x402`, `mpp`, `l402` | Contract only (transaction intents; no live processor calls yet) |

## Install

```bash
pip install patchr                # Python SDK
npm install @patchr-core/sdk      # Node.js SDK
npm install -g @patchr/cli        # terminal (natural-language CLI over the Node SDK)
```

```bash
export PATCHR_API_BASE_URL="https://api.patchr.co"
export PATCHR_API_TOKEN="your_patchr_api_token"
# or interactively: patchr login
```

Prefer the terminal? `patchr` takes plain language and reuses the SDK 1:1 —
confident intents route straight to the mapped call (interpretation shown),
work requests fall back to the orchestrator, `--explain` previews the routing:

```bash
patchr "configure a python dev environment with postgres"
# ➜ interpreted as env-setup 100% (environment, configure, "dev environment")
patchr "deploy web to staging as canary"
patchr run "validate this repo for production readiness" --stream
```

See [`packages/cli`](packages/cli/README.md) for the full command set.

## Developer Activation

New developers can create a profile directly from the SDK and start testing immediately. Patchr returns a starter API token, sends an activation link to the email address, and keeps unactivated starter tokens limited to 5 workflow requests.

0. `createProfile(email, name, password)` returns a starter token.
1. `activateToken(activationToken)` activates the token after the email link is opened or the activation token is supplied in local/debug mode.
2. `runOrchestrator(payload)` runs the workflow with the activated token.

```python
from patchr.sdk import PatchrClient

patchr = PatchrClient()

profile = patchr.createProfile(
    email="dev@example.com",
    name="Dev Example",
    password="use-a-real-password",
)

token = profile["token"]
print(profile["activation"]["message"])

# In production, click the emailed activation link. Local/debug responses may
# include activationToken for automated tests.
activation_token = profile.get("activation", {}).get("activationToken")
if activation_token:
    patchr.activateToken(activation_token)

patchr = PatchrClient(token=token)
run = patchr.runOrchestrator({
    "clientId": "activation_smoke_test",
    "channel": "sdk",
    "request": "Validate this repository for production readiness",
})
```

## Quick Start

```python
from patchr.sdk import PatchrClient

patchr = PatchrClient.fromEnv()

run = patchr.runOrchestrator({
    "clientId": "release_readiness_demo",
    "channel": "sdk",
    "conversationId": "conv_release_001",
    "request": "Validate this repository for production readiness and identify deployment blockers.",
    "metadata": {
        "repo": "https://github.com/acme/api",
        "environment": "production"
    },
})

print(run["status"])
print(run["route"])
```

## Fast Sandbox Smoke Test

Before wiring code, open the hosted sandbox and click the Hunt example:

https://patchr.co/sandbox

The starter request is:

```text
Buy me iPhone7 less than 500 dollar
```

The sandbox explicitly sends `allowNetwork: false` unless you override it, so the starter run is deterministic. Outside the sandbox, omitting `allowNetwork` defaults to live Hunt discovery. If marketplace pages are slow, blocked, or return no eligible listing, Hunt completes the mission with `status: "ready"` and source-attempt evidence in `results.hunt.sourceResponse` / `results.hunt.sourceAggregate`. `NEEDS_INPUT` is reserved for result selection when Hunt has source-backed options, or for later workflow details such as checkout inputs. For deterministic SDK smoke tests, pass a known source URL explicitly:

```python
run = patchr.runOrchestrator({
    "clientId": "sandbox_smoke_test",
    "channel": "sdk",
    "conversationId": "conv_iphone7_smoke_001",
    "request": "Buy me iPhone7 less than 500 dollar",
    "urls": [
        "data:text/html,<html><title>Used iPhone7 listing</title><body>Used iPhone7 listing available in stock. List 600 dollar, sale 189.99 dollar with receipt and fast shipping.</body></html>"
    ],
    "targetLimit": 1,
    "allowNetwork": False
})

print(run["status"])  # NEEDS_INPUT when the supplied result is ready to choose
```

Remove `urls` and omit `allowNetwork` when you want Patchr to search live marketplaces outside the sandbox.

Typical response shape:

```json
{
  "ok": true,
  "status": "ready",
  "route": ["resolve", "bridge"],
  "results": {
    "resolve": {
      "claimDraft": {
        "summary": "Damaged goods claim with attachment evidence"
      }
    },
    "bridge": {
      "contactPlan": {
        "primary": { "type": "merchantSupport" }
      }
    }
  }
}
```

## Streaming Status

Use streaming when the workflow may take more than a few seconds. Patchr sends human-readable `progress` events during quiet periods and `handoff` events when work moves into a human-facing step.

```python
for event in patchr.streamOrchestrator({
    "clientId": "incident_repair_demo",
    "channel": "sdk",
    "conversationId": "conv_incident_repair_001",
    "request": "Investigate why the production deployment failed and prepare the next safe action.",
    "stream": True,
}):
    if event.get("type") in {"progress", "handoff"}:
        print(event["message"])
    if event.get("type") == "final":
        print(event["result"]["status"])
```

Example stream events:

```json
{"type":"progress","status":"running","elapsedSec":10.0,"message":"I am still checking source-bound deployment evidence and connector state."}
{"type":"handoff","phase":"proxy","name":"mission.approval","status":"waiting","message":"Waiting for the release owner to approve the rollback plan."}
```

## Common Scenarios

Engineering requests route to the owning developer domain. When required inputs are missing, the run returns `NEEDS_INPUT` with `requestedKeys`; re-run with those payload keys included.

Release readiness (routes to `cicd`):

```python
patchr.runOrchestrator({
    "clientId": "release_readiness_demo",
    "channel": "sdk",
    "conversationId": "conv_release_001",
    "request": "Validate this repository for production readiness and identify deployment blockers.",
    "service": "web",
    "environment": "prod",
    "version": "v2.0.0",
    "strategy": "rolling",
    "artifacts": {"build": "pass", "tests": "pass"},
})
```

Environment configuration (routes to `environment`; collect real repo context with `filesFromLocalRepo`):

```python
from patchr.sdk import filesFromLocalRepo

patchr.runOrchestrator({
    "clientId": "environment_setup_demo",
    "channel": "sdk",
    "conversationId": "conv_env_setup_001",
    "request": "Find missing dependencies, required services, and setup blockers for this cloned repository.",
    "files": filesFromLocalRepo("~/code/my-service"),
})
```

`filesFromLocalRepo` collects known manifests, lockfiles, Dockerfiles, compose files, and `.env.example` templates. It never collects secret-bearing files (`.env`, keys, credentials).

Incident repair (routes to `incident`; mutating responses stay approval-gated):

```python
patchr.runOrchestrator({
    "clientId": "incident_repair_demo",
    "channel": "sdk",
    "conversationId": "conv_incident_001",
    "request": "Investigate why the production deployment failed and prepare the next safe action.",
    "alerts": [{"source": "prometheus", "name": "HighErrorRate", "severity": "critical", "service": "web"}],
    "signals": {"recentDeploys": [{"service": "web", "version": "v2.0.0"}]},
})
```

Delivery pipeline with a human approval gate (routes to `delivery`; resume with `resumeDelivery(runId, approved=True)`):

```python
run = patchr.runOrchestrator({
    "clientId": "delivery_demo",
    "channel": "sdk",
    "request": "Run the software delivery pipeline from clone to production",
    "service": "web",
    "environment": "prod",
    "version": "v1.2.0",
    "strategy": "rolling",
    "artifacts": {"build": "pass", "tests": "pass"},
    "files": filesFromLocalRepo("~/code/my-service"),
})
if run["status"] == "awaitingApproval":
    patchr.resumeDelivery(run["results"]["delivery"]["runId"], approved=True)
```

## Autonomous Execution

By default the developer engines are human-gated: a production deploy pauses at
`awaitingApproval`. `runOrchestrator` never acts on a protected operation without
a person. To let a run act on its own, pass an explicit **autonomy mandate** —
autonomy is off unless `autonomy.enabled` is true, and the deployment kill switch
`PICUX_AUTONOMY_ENABLED=false` overrides any request.

```python
from patchr.sdk import filesFromLocalRepo

result = patchr.runAutonomous({
    "mode": "delivery",                      # or "environment" (inferred when omitted)
    "service": "web",
    "environment": "prod",
    "version": "v2.0.0",
    "strategy": "rolling",
    "artifacts": {"build": "pass", "tests": "pass"},
    "files": filesFromLocalRepo("~/code/my-service"),
    "autonomy": {
        "enabled": True,
        "allowedActions": ["delivery.deploy", "delivery.rollback"],
        "allowCommands": ["npm ci", "npm run build", "docker compose up"],
        "maxActions": 6,                     # action budget for the whole run
        "dryRun": False,                     # False = really execute setup commands
        "workdir": "/path/to/checkout",
        "requireApproval": [],               # actions that STILL need a human
    },
})

print(result["status"])                       # "delivered" — no human needed
print(result["autonomy"]["autonomousToCompletion"])   # True
print(result["autonomy"]["actions"])          # audit trail of every auto-decision
```

Guardrails: autonomy runs only under the mandate. Actions must be allow-listed
(and not in `requireApproval`); shell commands must match `allowCommands` and
clear a built-in denylist (`rm -rf`, `sudo`, `git push`, `curl|sh`, ...); the run
is bounded by `maxActions`. Anything outside the grant — or an exhausted budget —
leaves the run `awaitingApproval` for a human (fail-closed). Real command
execution requires `dryRun: false` and a `workdir`; the default dry run only
reports what it *would* run. Every decision is returned in `autonomy.actions` and
emitted as an `autonomy.run` event. See `docs/developers/autonomy-guide.md`.

**Code mode** extends the same mandate to coding agents: `runAutonomous({"task":
"fix the failing suite", ...})` drives a headless agent (default `claude -p
{task}`) through the guarded executor under a `code.fix` grant, with an optional
`verifyCommand` after a successful fix — see `docs/developers/coding-agents.md`.

## Developer Domains

Engineering requests route to the owning developer domain (via the always-on
planner). When a required input is missing the run returns `NEEDS_INPUT` with
`requestedKeys`; re-run with those keys. Each domain is reachable by natural
language through `runOrchestrator`, or directly:

```python
patchr.configureEnvironment({"files": filesFromLocalRepo(".")})          # environment
patchr.planDeployment({"service": "web", "environment": "prod",           # cicd
    "version": "v2", "strategy": "rolling", "artifacts": {"build": "pass", "tests": "pass"}})
patchr.repairKubernetes({"pods": [...], "events": [...]})                  # kubernetes
patchr.respondToIncident({"alerts": [...], "signals": {...}})             # incident
patchr.validateMigration({"migrations": [...], "backup": {...}})          # migration
patchr.validateSecurity({"files": filesFromLocalRepo(".")})               # security
patchr.runDelivery({"service": "web", "environment": "staging", ...})     # delivery pipeline
```

External workflow examples:

```python
patchr.runOrchestrator({
    "clientId": "support_ops_demo",
    "channel": "sdk",
    "conversationId": "conv_ticket_dispute_001",
    "request": "Dispute ticket ZD-44291: airline charged me twice after cancellation and closed the refund case."
})
```

## Useful Methods

```python
# Activation & discovery
patchr.health()
patchr.createProfile(email, name, password)
patchr.activateToken(activation_token)
patchr.manifest()
patchr.protocolMap()

# Orchestration
patchr.runOrchestrator(payload)
patchr.streamOrchestrator(payload)
patchr.resumeOrchestrator(conversation_id, item_id, action, payload)
patchr.runAutonomous(payload)                 # autonomous execution under a mandate

# Developer domains (also reachable via natural language through runOrchestrator)
patchr.configureEnvironment(payload)
patchr.planDeployment(payload)
patchr.repairKubernetes(payload)
patchr.respondToIncident(payload)
patchr.validateMigration(payload)
patchr.validateSecurity(payload)
patchr.runDelivery(payload)
patchr.resumeDelivery(run_id, approved=True)

# Coding-agent surface
patchr.verifyChange(payload)                   # one verdict over a change: pass | review | block
patchr.exportAgentBrief(payload)               # AGENTS.md / CLAUDE.md / Cursor rules from repo files

# Run history & observability
patchr.listOrchestratorRuns(filters)           # summaries: route, status, planner decision
patchr.getOrchestratorRun(run_id)              # one run with its full trace
patchr.observabilityMetrics()                  # domain counters (needs a Redis sink)

# Repository context
filesFromLocalRepo(path)                       # from patchr.sdk

# Logistics
patchr.trackShipment(tracking_number, carrier="")
patchr.ingestCarrierWebhook(payload, headers)
patchr.getShipmentStatus(tracking_number)

# Tools
patchr.mapTool(payload)
patchr.nlpTool(payload)
```

## Runtime Notes

- Engineering requests route to the owning developer domain (environment, cicd, kubernetes, incident, migration, security, delivery) via the always-on planner; consumer/commerce requests still route through HUNT, RESOLVE, BRIDGE, PROXY, and PAY.
- Developer engines are deterministic and human-gated by default. `runAutonomous` opts a run into autonomous execution under an explicit mandate; without it, protected operations always pause for approval.
- Long-running workflows emit user-facing progress text so your client does not appear stuck.
- Handoff events include plain messages such as "Waiting for release owner approval", "Preparing case documents", and "Contacting the provider for availability".
- Set `PATCHR_API_TOKEN` for hosted API calls. Local test transports can run in-process without network I/O.

## Changelog

`0.2.0` adds developer-intent routing with an always-on planner, opt-in autonomous execution (`runAutonomous`), `filesFromLocalRepo` in all five SDKs, live payment signing for Stripe test-mode / Solana / Base (opt-in), the `shipmentTracking` connector with carrier-webhook ingestion, per-connector network egress policies, and security hardening (PBKDF2 vault, signed receipts).

`0.1.4` adds SDK developer activation: `createProfile`, emailed activation links, `activateToken`, and a 5-request limit for unactivated starter tokens.

`0.1.3` adds a fast sandbox smoke test for Hunt, the `Buy me iPhone7 less than 500 dollar` starter example, and first-class `vendorDueDiligence` workflow support.

See `CHANGELOG.md` in the package source for full release notes.

## More

- Hosted API reference: https://patchr.co/api-reference
- Control plane: https://patchr.co/control-plane
- Developer sandbox: https://patchr.co/sandbox
- Python package: https://pypi.org/project/patchr/
- Node package: https://www.npmjs.com/package/@patchr-core/sdk
