patchr 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. apps/__init__.py +2 -0
  2. apps/api/__init__.py +2 -0
  3. apps/api/main.py +652 -0
  4. apps/benchmarks/__init__.py +1 -0
  5. apps/benchmarks/main.py +20 -0
  6. apps/sandbox/__init__.py +1 -0
  7. apps/sandbox/main.py +20 -0
  8. apps/worker/__init__.py +2 -0
  9. apps/worker/main.py +15 -0
  10. apps/worker/verify.py +14 -0
  11. patchr/__init__.py +12 -0
  12. patchr/sdk/__init__.py +20 -0
  13. patchr/sdk/client.py +12 -0
  14. patchr-0.1.0.dist-info/METADATA +137 -0
  15. patchr-0.1.0.dist-info/RECORD +116 -0
  16. patchr-0.1.0.dist-info/WHEEL +5 -0
  17. patchr-0.1.0.dist-info/entry_points.txt +5 -0
  18. patchr-0.1.0.dist-info/licenses/LICENSE +17 -0
  19. patchr-0.1.0.dist-info/top_level.txt +3 -0
  20. picux/__init__.py +6 -0
  21. picux/agents/__init__.py +5 -0
  22. picux/agents/registry.py +204 -0
  23. picux/api/__init__.py +5 -0
  24. picux/api/service.py +5075 -0
  25. picux/audit/__init__.py +31 -0
  26. picux/audit/activity.py +97 -0
  27. picux/audit/observability.py +55 -0
  28. picux/audit/verification/__init__.py +21 -0
  29. picux/audit/verification/ledger.py +633 -0
  30. picux/benchmarks/__init__.py +5 -0
  31. picux/benchmarks/local.py +286 -0
  32. picux/config.py +140 -0
  33. picux/contracts/__init__.py +22 -0
  34. picux/contracts/handshake.py +122 -0
  35. picux/contracts/integration.py +385 -0
  36. picux/contracts/openapi.py +187 -0
  37. picux/contracts/protocol_map.py +152 -0
  38. picux/contracts/routes.py +980 -0
  39. picux/contracts/schema_catalog.py +125 -0
  40. picux/core/__init__.py +17 -0
  41. picux/core/models.py +148 -0
  42. picux/core/router.py +131 -0
  43. picux/core/runtime.py +42 -0
  44. picux/core/state_machine.py +38 -0
  45. picux/domains/__init__.py +2 -0
  46. picux/domains/bridge/HostRun.py +1104 -0
  47. picux/domains/bridge/__init__.py +6 -0
  48. picux/domains/bridge/engine.py +345 -0
  49. picux/domains/hunt/__init__.py +6 -0
  50. picux/domains/hunt/engine.py +307 -0
  51. picux/domains/hunt/models.py +88 -0
  52. picux/domains/pay/__init__.py +16 -0
  53. picux/domains/pay/adapters.py +607 -0
  54. picux/domains/pay/engine.py +950 -0
  55. picux/domains/pay/models.py +95 -0
  56. picux/domains/proxy/__init__.py +5 -0
  57. picux/domains/proxy/engine.py +466 -0
  58. picux/domains/resolve/__init__.py +5 -0
  59. picux/domains/resolve/engine.py +546 -0
  60. picux/orchestrator/__init__.py +3 -0
  61. picux/orchestrator/engine.py +2840 -0
  62. picux/portals/__init__.py +17 -0
  63. picux/portals/templates.py +272 -0
  64. picux/protocols/__init__.py +1 -0
  65. picux/protocols/a2a/__init__.py +6 -0
  66. picux/protocols/a2a/client.py +51 -0
  67. picux/protocols/a2a/envelope.py +132 -0
  68. picux/protocols/mcp/__init__.py +7 -0
  69. picux/protocols/mcp/client.py +69 -0
  70. picux/protocols/mcp/contract.py +67 -0
  71. picux/protocols/mcp/server.py +76 -0
  72. picux/sandbox/__init__.py +6 -0
  73. picux/sandbox/midnight_arbitrage.py +215 -0
  74. picux/sandbox/models.py +90 -0
  75. picux/sdk/__init__.py +13 -0
  76. picux/sdk/client.py +768 -0
  77. picux/sdk/external.py +245 -0
  78. picux/security/__init__.py +18 -0
  79. picux/security/auth.py +86 -0
  80. picux/security/config_validator.py +58 -0
  81. picux/security/policy.py +158 -0
  82. picux/security/secrets.py +144 -0
  83. picux/signals/__init__.py +1 -0
  84. picux/signals/community/__init__.py +24 -0
  85. picux/signals/community/adapters/__init__.py +7 -0
  86. picux/signals/community/adapters/reddit.py +37 -0
  87. picux/signals/community/adapters/shopify.py +23 -0
  88. picux/signals/community/adapters/web.py +23 -0
  89. picux/signals/community/disambiguation.py +51 -0
  90. picux/signals/community/intake.py +227 -0
  91. picux/signals/community/models.py +102 -0
  92. picux/signals/community/rules.py +91 -0
  93. picux/signals/community/scoring.py +64 -0
  94. picux/storage/__init__.py +41 -0
  95. picux/storage/agents.py +50 -0
  96. picux/storage/cases.py +440 -0
  97. picux/storage/channels.py +476 -0
  98. picux/storage/connectors.py +411 -0
  99. picux/storage/envelopes.py +137 -0
  100. picux/storage/escrows.py +168 -0
  101. picux/storage/events.py +989 -0
  102. picux/storage/keyspace.py +60 -0
  103. picux/storage/mandates.py +107 -0
  104. picux/storage/portals.py +222 -0
  105. picux/storage/postgres.py +2049 -0
  106. picux/storage/providers.py +148 -0
  107. picux/storage/proxy.py +231 -0
  108. picux/storage/receipts.py +131 -0
  109. picux/storage/signals.py +147 -0
  110. picux/storage/tasks.py +179 -0
  111. picux/tools/__init__.py +11 -0
  112. picux/tools/shared.py +2048 -0
  113. picux/verification/__init__.py +5 -0
  114. picux/verification/rollout.py +183 -0
  115. picux/workflows/__init__.py +5 -0
  116. picux/workflows/templates.py +74 -0
@@ -0,0 +1 @@
1
+ """Picux sandbox applications."""
apps/sandbox/main.py ADDED
@@ -0,0 +1,20 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import json
5
+
6
+ from picux.sandbox import MidnightArbitrageSandbox
7
+
8
+
9
+ def main() -> None:
10
+ parser = argparse.ArgumentParser(description="Run the Picux Midnight Arbitrage sandbox.")
11
+ parser.add_argument("--chaos", choices=["", "latency", "modelError", "unauthorizedSpend", "freeze"], default="")
12
+ parser.add_argument("--pretty", action="store_true", help="Pretty-print the sandbox trace.")
13
+ args = parser.parse_args()
14
+
15
+ result = MidnightArbitrageSandbox().run(chaos=args.chaos)
16
+ print(json.dumps(result, ensure_ascii=True, sort_keys=True, indent=2 if args.pretty else None))
17
+
18
+
19
+ if __name__ == "__main__":
20
+ main()
@@ -0,0 +1,2 @@
1
+ """Picux worker application."""
2
+
apps/worker/main.py ADDED
@@ -0,0 +1,15 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+
5
+ from picux.core import PicuxRuntime
6
+
7
+
8
+ def main() -> None:
9
+ runtime = PicuxRuntime(service="picux-worker")
10
+ runtime.assertBootable()
11
+ print(json.dumps(runtime.summary(), ensure_ascii=True, sort_keys=True))
12
+
13
+
14
+ if __name__ == "__main__":
15
+ main()
apps/worker/verify.py ADDED
@@ -0,0 +1,14 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+
5
+ from picux.verification import RolloutVerifier
6
+
7
+
8
+ def main() -> None:
9
+ report = RolloutVerifier().verify().toMap()
10
+ print(json.dumps(report, ensure_ascii=True, sort_keys=True))
11
+
12
+
13
+ if __name__ == "__main__":
14
+ main()
patchr/__init__.py ADDED
@@ -0,0 +1,12 @@
1
+ """Patchr Python SDK."""
2
+
3
+ from .sdk import ExternalAppClient, ExternalPricing, HttpTransport, InProcessTransport, PatchrApiError, PatchrClient
4
+
5
+ __all__ = [
6
+ "ExternalAppClient",
7
+ "ExternalPricing",
8
+ "HttpTransport",
9
+ "InProcessTransport",
10
+ "PatchrApiError",
11
+ "PatchrClient",
12
+ ]
patchr/sdk/__init__.py ADDED
@@ -0,0 +1,20 @@
1
+ """Public Patchr SDK import surface."""
2
+
3
+ from picux.sdk import ExternalAppClient, ExternalPricing, HttpTransport, InProcessTransport
4
+ from picux.sdk.client import PicuxApiError, PicuxClient
5
+
6
+
7
+ class PatchrClient(PicuxClient):
8
+ """Patchr-branded client for the hosted API, MCP, A2A, and workflow surfaces."""
9
+
10
+
11
+ PatchrApiError = PicuxApiError
12
+
13
+ __all__ = [
14
+ "ExternalAppClient",
15
+ "ExternalPricing",
16
+ "HttpTransport",
17
+ "InProcessTransport",
18
+ "PatchrApiError",
19
+ "PatchrClient",
20
+ ]
patchr/sdk/client.py ADDED
@@ -0,0 +1,12 @@
1
+ """Patchr SDK client aliases."""
2
+
3
+ from . import ExternalAppClient, ExternalPricing, HttpTransport, InProcessTransport, PatchrApiError, PatchrClient
4
+
5
+ __all__ = [
6
+ "ExternalAppClient",
7
+ "ExternalPricing",
8
+ "HttpTransport",
9
+ "InProcessTransport",
10
+ "PatchrApiError",
11
+ "PatchrClient",
12
+ ]
@@ -0,0 +1,137 @@
1
+ Metadata-Version: 2.4
2
+ Name: patchr
3
+ Version: 0.1.0
4
+ Summary: Patchr Protocol infrastructure for agentic orchestration and settlement.
5
+ Author: Patchr Core Team
6
+ License-Expression: Apache-2.0
7
+ Keywords: patchr,sdk,mcp,a2a,workflow,agents
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
15
+ Requires-Python: >=3.11
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Provides-Extra: api
19
+ Requires-Dist: fastapi>=0.111; extra == "api"
20
+ Requires-Dist: uvicorn>=0.30; extra == "api"
21
+ Provides-Extra: worker
22
+ Requires-Dist: redis>=5.0; extra == "worker"
23
+ Requires-Dist: rq>=1.16; extra == "worker"
24
+ Provides-Extra: db
25
+ Requires-Dist: psycopg[binary]>=3.2; extra == "db"
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=8.0; extra == "dev"
28
+ Dynamic: license-file
29
+
30
+ # Patchr
31
+
32
+ Patchr is the protocol infrastructure layer for agentic orchestration and settlement.
33
+ External apps, services, and agents communicate with Patchr through the SDK, API contract, MCP, and A2A protocol surfaces.
34
+
35
+ Current status: Phase 78 primitives. Patchr now has three flagship workflow templates, citeable proof cards, first-class HUNT, RESOLVE, BRIDGE, PAY, and PROXY domain primitives, portable proof packs, an Auto-Audit Vault contract, Resolve scam and mobility triage, regulated PROXY human routes, misinformation escalation to PROXY review, durable task lifecycle state, durable mandate records, payment mandate preparation, settlement adapter contracts, BRIDGE connector registry, connector preflight, PROXY human-in-the-loop suspend/resume contracts, durable proxy mission records, durable proxy callback reference lookup, proxy mission/outcome/proof schemas, scoped credential references, redacted secret-reference checks, mandate-session and capability-grant policy evaluation and runtime enforcement across BRIDGE, PAY, and PROXY, durable escrow records, durable A2A envelope records, durable community signal provenance, durable integration event outbox, subscriptions, delivery attempts, ready, chain, single and batch claim, complete, cancel, retry, fail, lease, sweep, retry-scheduling, and queue-stat controls, durable agent capability discovery, A2A envelopes, community signal disambiguation, audit proof-of-value verification, listable receipt and evidence export, bearer-token API/MCP/A2A transport auth, public API status, a security whitepaper, a neutral SDK/API/MCP boundary, a public schema catalog, integration manifest with domain capability and policy discovery, domain-aware compatibility handshake with contract references, developer docs, and a versioned agent-readable protocol map with deterministic digest, method-aware API route metadata, SDK, MCP, schema, manifest parity, and policy metadata, external RESOLVE and PROXY SDK helpers, file-to-base64 RESOLVE intake, claim drafting, contact-channel planning, a damaged-TV RESOLVE journey test, a local developer sandbox with API/SDK/MCP trace access, local benchmark evidence with claim labels, source-hygiene guardrails, source brief contract parity, boundary gap wording cleanup, migration inventory closure, brief surface completeness, FastAPI contract parity for PROXY, rollout verification gates, and machine-readable contracts.
36
+
37
+ ## Local Commands
38
+
39
+ ```bash
40
+ npm install
41
+ npm run dev
42
+ npm run api:dev
43
+ npm run web:dev
44
+ npm run web:build
45
+ npm run verify
46
+ PYTHONPATH=src:. python -m apps.api.main
47
+ PYTHONPATH=src:. python -m apps.worker.main
48
+ PYTHONPATH=src:. python -m apps.worker.verify
49
+ PYTHONPATH=src:. python -m apps.sandbox.main --pretty
50
+ PYTHONPATH=src:. python -m apps.benchmarks.main --iterations 100 --pretty
51
+ PYTHONPATH=src:. python -m unittest discover -s tests -p 'test_*.py'
52
+ ```
53
+
54
+ ## Docs
55
+
56
+ - [GCP Terraform deployment](infra/gcp/terraform/README.md)
57
+ - [Migration plan](docs/picux-migration-plan.md)
58
+ - [Phase 0 inventory](docs/picux-migration-inventory.md)
59
+ - [Phase 5 community signals](docs/phase5-community-signals.md)
60
+ - [Phase 6 external client](docs/phase6-external-client.md)
61
+ - [Phase 7 developer sandbox](docs/phase7-developer-sandbox.md)
62
+ - [Phase 8 verification](docs/phase8-verification-rollout.md)
63
+ - [Phase 9 protocol contracts](docs/phase9-protocol-contracts.md)
64
+ - [Phase 10 HUNT domain](docs/phase10-hunt-domain.md)
65
+ - [Phase 11 agent registry](docs/phase11-agent-registry.md)
66
+ - [Phase 12 audit verification](docs/phase12-audit-verification.md)
67
+ - [Phase 13 receipt export](docs/phase13-receipt-export.md)
68
+ - [Phase 14 A2A envelope](docs/phase14-a2a-envelope.md)
69
+ - [Phase 15 agent registry durability](docs/phase15-agent-registry-durability.md)
70
+ - [Phase 16 task lifecycle](docs/phase16-task-lifecycle.md)
71
+ - [Phase 17 mandate durability](docs/phase17-mandate-durability.md)
72
+ - [Phase 18 escrow durability](docs/phase18-escrow-durability.md)
73
+ - [Phase 19 MCP endpoint](docs/phase19-mcp-endpoint.md)
74
+ - [Phase 20 transport auth](docs/phase20-transport-auth.md)
75
+ - [Phase 21 schema catalog](docs/phase21-schema-catalog.md)
76
+ - [Phase 22 A2A envelope durability](docs/phase22-a2a-envelope-durability.md)
77
+ - [Phase 23 A2A transport auth](docs/phase23-a2a-transport-auth.md)
78
+ - [Phase 24 receipt reconciliation](docs/phase24-receipt-reconciliation.md)
79
+ - [Phase 25 evidence catalog](docs/phase25-evidence-catalog.md)
80
+ - [Phase 26 community signal durability](docs/phase26-community-signal-durability.md)
81
+ - [Phase 27 integration manifest](docs/phase27-integration-manifest.md)
82
+ - [Phase 28 integration handshake](docs/phase28-integration-handshake.md)
83
+ - [Phase 29 integration events](docs/phase29-integration-events.md)
84
+ - [Phase 30 event subscriptions](docs/phase30-event-subscriptions.md)
85
+ - [Phase 31 event deliveries](docs/phase31-event-deliveries.md)
86
+ - [Phase 32 delivery claim and retry](docs/phase32-delivery-claim-retry.md)
87
+ - [Phase 33 delivery leases](docs/phase33-delivery-leases.md)
88
+ - [Phase 34 delivery lease sweep](docs/phase34-delivery-lease-sweep.md)
89
+ - [Phase 35 delivery retry scheduling](docs/phase35-delivery-retry-scheduling.md)
90
+ - [Phase 36 delivery stats](docs/phase36-delivery-stats.md)
91
+ - [Phase 37 delivery fail scheduling](docs/phase37-delivery-fail-scheduling.md)
92
+ - [Phase 38 delivery completion](docs/phase38-delivery-completion.md)
93
+ - [Phase 39 delivery chain](docs/phase39-delivery-chain.md)
94
+ - [Phase 40 delivery cancellation](docs/phase40-delivery-cancellation.md)
95
+ - [Phase 41 delivery ready preview](docs/phase41-delivery-ready.md)
96
+ - [Phase 42 delivery batch claim](docs/phase42-delivery-batch-claim.md)
97
+ - [Phase 43 payment adapters](docs/phase43-payment-adapters.md)
98
+ - [Phase 44 bridge connectors](docs/phase44-bridge-connectors.md)
99
+ - [Phase 45 security policy](docs/phase45-security-policy.md)
100
+ - [Phase 46 developer docs](docs/phase46-developer-docs.md)
101
+ - [Phase 47 sandbox API](docs/phase47-sandbox-api.md)
102
+ - [Phase 48 benchmark evidence](docs/phase48-benchmark-evidence.md)
103
+ - [Phase 49 status and security](docs/phase49-status-security.md)
104
+ - [Phase 50 source hygiene](docs/phase50-source-hygiene.md)
105
+ - [Phase 51 FastAPI contract parity](docs/phase51-fastapi-contract-parity.md)
106
+ - [Phase 52 runtime policy enforcement](docs/phase52-runtime-policy-enforcement.md)
107
+ - [Phase 53 secret reference checks](docs/phase53-secret-reference-checks.md)
108
+ - [Phase 54 BRIDGE preflight](docs/phase54-bridge-preflight.md)
109
+ - [Phase 55 PROXY suspend/resume](docs/phase55-proxy-suspend-resume.md)
110
+ - [Phase 56 PROXY durability](docs/phase56-proxy-durability.md)
111
+ - [Phase 57 PROXY callback refs](docs/phase57-proxy-callback-refs.md)
112
+ - [Phase 58 PROXY policy enforcement](docs/phase58-proxy-policy-enforcement.md)
113
+ - [Phase 59 PROXY FastAPI parity](docs/phase59-proxy-fastapi-parity.md)
114
+ - [Phase 60 PROXY external SDK](docs/phase60-proxy-external-sdk.md)
115
+ - [Phase 61 domain manifest](docs/phase61-domain-manifest.md)
116
+ - [Phase 62 domain handshake](docs/phase62-domain-handshake.md)
117
+ - [Phase 63 domain policy discovery](docs/phase63-domain-policy-discovery.md)
118
+ - [Phase 64 agent-readable policy map](docs/phase64-agent-readable-policy-map.md)
119
+ - [Phase 65 agent map manifest parity](docs/phase65-agent-map-manifest-parity.md)
120
+ - [Phase 66 protocol map surface](docs/phase66-protocol-map-surface.md)
121
+ - [Phase 67 handshake contract references](docs/phase67-handshake-contract-refs.md)
122
+ - [Phase 68 protocol map route metadata](docs/phase68-protocol-map-route-metadata.md)
123
+ - [Phase 69 protocol map version source](docs/phase69-protocol-map-version-source.md)
124
+ - [Phase 70 protocol map digest](docs/phase70-protocol-map-digest.md)
125
+ - [Phase 71 brief contract parity](docs/phase71-brief-contract-parity.md)
126
+ - [Phase 72 boundary gap wording](docs/phase72-boundary-gap-wording.md)
127
+ - [Phase 73 migration inventory closure](docs/phase73-migration-inventory-closure.md)
128
+ - [Phase 74 brief surface completeness](docs/phase74-brief-surface-completeness.md)
129
+ - [Phase 75 resolve TV journey](docs/phase75-resolve-tv-journey.md)
130
+ - [Phase 76 resolve attachment contact](docs/phase76-resolve-attachment-contact.md)
131
+ - [Phase 77 domain proof packs](docs/phase77-domain-proof-packs.md)
132
+ - [Phase 78 workflow templates and proof cards](docs/phase78-workflow-templates-proof-cards.md)
133
+ - [Phase 79 developer activation loop](docs/phase79-developer-activation-loop.md)
134
+ - [Distribution homepage](docs/distribution-homepage.md)
135
+ - [Security whitepaper](docs/security-whitepaper.md)
136
+ - [Developer docs](docs/developers/index.md)
137
+ - [Docs index](docs/index.md)
@@ -0,0 +1,116 @@
1
+ apps/__init__.py,sha256=kCC0kvP5Web_YR8Muyc9cRTCEj8QIJzSBUx_JdKpnn4,38
2
+ apps/api/__init__.py,sha256=ta89ZwlALFiZcJy4C__IRZlPkbm60ObUk3FqRqOcMts,30
3
+ apps/api/main.py,sha256=OhfDeP3eK3tHgEdVbD7-8XoE4gdoSP6_hBxK2wU3XLs,26479
4
+ apps/benchmarks/__init__.py,sha256=nFUCHmIucxo5Qg9-QnFgJmmrjauUeFi7V5la0oCgZYQ,37
5
+ apps/benchmarks/main.py,sha256=OU4lwoDUVNJxoeMB9tmZSQGT3uCt60VTmOFJu3tfzZo,574
6
+ apps/sandbox/__init__.py,sha256=6XdFcg420YfXeGzSid8S8dE6dIf9YpujlCZkR85PwbM,34
7
+ apps/sandbox/main.py,sha256=nV9D1fvrAg3VhrwBbzyFAM--tchZd3uYJzOMwd69BcI,680
8
+ apps/worker/__init__.py,sha256=GRIN6YXqWJOMxypHPNPMdCO38KqUL-keC_ZS9NduFdg,33
9
+ apps/worker/main.py,sha256=d7O0TxCx1NJyVJnM1-IzMIaEJ_SPsvppLeO3tl3E1aU,303
10
+ apps/worker/verify.py,sha256=Qx1-9sahoxfE8FoSsrO_QEH2tq30MGkdTGJf1bF_oH8,271
11
+ patchr/__init__.py,sha256=d5FfcklbOWg__wvVaiTBHfnku0diwJZZeiqmBP-VliE,295
12
+ patchr/sdk/__init__.py,sha256=igbwz6sERDC0oB4A1zWLKDMlJ0VSeP-IzEzMtCIH7FY,494
13
+ patchr/sdk/client.py,sha256=1_guLahvPV5SwAyPbtedu0waQ8O22wNHaOAl7SwXaNs,300
14
+ patchr-0.1.0.dist-info/licenses/LICENSE,sha256=z0eHPvhRIQEfgj8XeVsC3IBC_nQJAb6EmzzdVlGWTjQ,631
15
+ picux/__init__.py,sha256=TediMUYjpI1MGpK3DtPjoms6cjxlBkP6n1ZK_DNywyQ,82
16
+ picux/config.py,sha256=SWVpRb6csa4N3wBXa7DEUE42bVSvsw_8NyJo8-NZSg0,5219
17
+ picux/agents/__init__.py,sha256=T691Rrdap9ATkVWCXY0Ynsfub_G3XGIX1zQFYDrZ17s,175
18
+ picux/agents/registry.py,sha256=Nc0nTRuA0LWbyDwQ8RlgMU31JiiBgX6-Oz3ksKGAizo,8072
19
+ picux/api/__init__.py,sha256=HKSAbNNxYD18jzYyS_V7lbnwbCvlxTTPxfYXV00v1MQ,106
20
+ picux/api/service.py,sha256=ZvMFxbQOX9_QuL7EiL8APctF85NKLSPZi-wxhxNBhgw,260283
21
+ picux/audit/__init__.py,sha256=CxTiflKkcgilx4cnRxWgUdGQi2rYSB_FaLroODIm8BE,653
22
+ picux/audit/activity.py,sha256=yqbJcjDFkhV_Zr5uAEp5eaRgiKKAKUSt03zeid958ok,3231
23
+ picux/audit/observability.py,sha256=sB9dCA9IIQu9kIidf3L4BNVkZPCZbHYJE_UPOrYPlME,1467
24
+ picux/audit/verification/__init__.py,sha256=wSGbrYMqsO1CPt7s798n0otPaZIYxcfsz3bLXNKlzUg,385
25
+ picux/audit/verification/ledger.py,sha256=m3f6hDZbUh8J3gBWrJVohIyXdmI25oNVKl3nNCXeSPg,25916
26
+ picux/benchmarks/__init__.py,sha256=beBHLt_Keh7VDZDxB2_0NENWtqS-rGTtmZU4qeRy9Ic,108
27
+ picux/benchmarks/local.py,sha256=1ox6HpRNG-81RtX0AOhIjg0M6203TQhuUcZ65PzRU5U,10807
28
+ picux/contracts/__init__.py,sha256=UKuCPB2ERBkJRpRvaSvtP3fvLEdSzxBN-12ngpE4S4Q,626
29
+ picux/contracts/handshake.py,sha256=Ju_8CYhvLwx1FFrnvFqWkXNCbD8NROe1QbfZ5IsKBwM,4910
30
+ picux/contracts/integration.py,sha256=37d7DOVoEPeie6ynzxq4ln_HAVif45AYtf1gIFB08u0,18045
31
+ picux/contracts/openapi.py,sha256=8pcJkunjVeLpKLVwA4ihUjN1m2hQPjpAgFi0zRRywOA,6315
32
+ picux/contracts/protocol_map.py,sha256=PuOB04zUuFvK8oiTBWQKdZAtV2dy4Rjr8XEfh8M59NQ,6990
33
+ picux/contracts/routes.py,sha256=JSqhgr4vT4jO5Kw3GcyYJ1G8sQB9HBc_TGKmmSM7GNc,35061
34
+ picux/contracts/schema_catalog.py,sha256=-MgX4-W6PTg-HDymXH1XWNNUD7MTTPsIL_SygKbgsww,8259
35
+ picux/core/__init__.py,sha256=sekMydfnx07DPwJaSMaVoUavCsxozZ98uiAWDxbWhdA,431
36
+ picux/core/models.py,sha256=JngC4jG-ByXLucDJH-muqxB3R202Wr1q2S7U5c1Npj0,5159
37
+ picux/core/router.py,sha256=dpJncIvOXzuTtm1ZBE3p3gCOln9MLK61_ZvZg7WjFlQ,3190
38
+ picux/core/runtime.py,sha256=CWafAF8wenaWqxOTuymYA-fd0pFTO8dTBwBeHoHyJjg,1252
39
+ picux/core/state_machine.py,sha256=ZU-h6HHJxWL650oOi2s9hvCyfPoCAVM8w3j5grjdqJY,1164
40
+ picux/domains/__init__.py,sha256=BdA_yMK5Ddu2v1aneBh-XPARil2vt6OcVNSuHY1BYzY,31
41
+ picux/domains/bridge/HostRun.py,sha256=vLp8Ih9EUxDAo-R9yNp4brBgV-OGbsdXWOlAFIpFiiY,57307
42
+ picux/domains/bridge/__init__.py,sha256=wUy31w0WxrJvto89-mdeKiRYIDxIW6fiQe7vPuI1lpU,160
43
+ picux/domains/bridge/engine.py,sha256=ORk6pC1zX-iSx4SlE1bXwEuE8JKJusen5dttL269bCY,16177
44
+ picux/domains/hunt/__init__.py,sha256=qKR8bJCD4L__8IMsb6sA8rVqFZ87YNyQOFAfM69b-Uk,161
45
+ picux/domains/hunt/engine.py,sha256=5JshW8WoZJZX5AxDylr8ldCp6vQks-btVyI531COysY,15920
46
+ picux/domains/hunt/models.py,sha256=30KDzMX0MNYj2WkjXi6pr8qkCc4h6W4KvyoYkkQttsE,3021
47
+ picux/domains/pay/__init__.py,sha256=nABSbOCH3mLPQloX3wQ-VttkZHECHN1XDn69KVfpTn0,416
48
+ picux/domains/pay/adapters.py,sha256=JBegwMO4DfDz3bd756XfpskzbdvFGqR2Fn3UhtyChJc,31823
49
+ picux/domains/pay/engine.py,sha256=UzqYdfbKBZQ4vRcNsCMYgfnzigLJXYS8_ApVus34c1Y,45438
50
+ picux/domains/pay/models.py,sha256=rtiJ98WnU9FRqP-O2eThY7vrvXXlgvxOuENo0m-ZMZo,3151
51
+ picux/domains/proxy/__init__.py,sha256=Y-b3Sb5CEnP01deIuY33pdGyTuSqdJCYeCwYHfuo2xU,91
52
+ picux/domains/proxy/engine.py,sha256=jxesdCOHnX-MxxcCN1afdUYl65-mBakU_a7nuVH1L0A,20623
53
+ picux/domains/resolve/__init__.py,sha256=KklbjwHNx82xni_rBaB03fRXEGKbIqsL2lZsU0QKpTw,97
54
+ picux/domains/resolve/engine.py,sha256=8hNcjZS9E5Ha-FPSuP_zgiEYapdP62mW67JXfOOjLug,29466
55
+ picux/orchestrator/__init__.py,sha256=HjxMjs0-PSrS_f9bjL_T_4bvUMIdPDXFSZM9juQiYh0,91
56
+ picux/orchestrator/engine.py,sha256=DuQoqpchEyJx2MG_IinuwpymzdYMR_-qbE3rUz82PkE,157820
57
+ picux/portals/__init__.py,sha256=A3eJgVAeO0mU8CiVuOcYd2tjxkZYZAOwSdXWYuwK_Ts,439
58
+ picux/portals/templates.py,sha256=foAPCyuC_hOuIxlNkG8A3DNPnc5jPHhhGVgIQb8IFUg,15189
59
+ picux/protocols/__init__.py,sha256=3OdqVdKbvQA7qqLzpR5CFkrzoH6kInTK7cih6T66KBA,64
60
+ picux/protocols/a2a/__init__.py,sha256=7q8BB0wJRS_4GEnFdHlK9eHYLC3Pg-lHG_w4jTk4lA0,247
61
+ picux/protocols/a2a/client.py,sha256=YkY6R8uLR5fAbTF3H8jglSEuTwiZFP4RPd24g4Lm14o,1812
62
+ picux/protocols/a2a/envelope.py,sha256=OXf2JFGy0HnGpF6ct_emF8885-q-rvI9Sj6R7DbkEBw,4439
63
+ picux/protocols/mcp/__init__.py,sha256=FNT0drKUVoZw8xFy1lOarP2DkwQfTYsks5uXNJA45WI,198
64
+ picux/protocols/mcp/client.py,sha256=os7_scL4eDShdmgTyoHlbAJRgP_igDXnzqzoRKYmGtM,2308
65
+ picux/protocols/mcp/contract.py,sha256=P1BjfAZIwyh2VqqA-gBOAGjHFcHxPB-rk_iAISgbUHY,2134
66
+ picux/protocols/mcp/server.py,sha256=-hjcDQcecYrasnC_XgphMipOXxamotXla7Zodr7JZjc,3081
67
+ picux/sandbox/__init__.py,sha256=YVpTiYH-yaFCJIYCAiqmEM6ek6ybovbRCSa8nZFIvfw,243
68
+ picux/sandbox/midnight_arbitrage.py,sha256=OCrOLSR8x6Kg4kcpdNkxXDykZJFyLbSonEneDsXkQZ8,9820
69
+ picux/sandbox/models.py,sha256=x5G8sDHyYk4t_OzoG2goj7iFo066GKBQ07lKTj_vA0A,2401
70
+ picux/sdk/__init__.py,sha256=QiKYh1XVs6QQR-VDJWO1KGgzeMEGxQLfcpHPtCbl6gE,307
71
+ picux/sdk/client.py,sha256=Qx3-cVqMDSbRek6b5bc-_A081HoFsPi3q4GDwHZaTSg,37602
72
+ picux/sdk/external.py,sha256=W1K0LeL_Zy2m0qWzRW2LUtCGMotw4H1b_m-N7Rrj8PI,8145
73
+ picux/security/__init__.py,sha256=0XpuNqqhVsPHn5SRDpr9MaOzsWXtwSYflWtbf6RXpOo,527
74
+ picux/security/auth.py,sha256=tixHJg8IkR_0UQT25TN-eQ1qfM1oSP5UKWsm8iLAeEM,2847
75
+ picux/security/config_validator.py,sha256=1ukXY0cJY9Xwk4R6k77_km7Xwdc-5sBcgfAbFPWi7vQ,1906
76
+ picux/security/policy.py,sha256=A_L5A9ZaR6hphHeNcEN26LZPeKtQTej5UnqWkTJG7yw,5934
77
+ picux/security/secrets.py,sha256=1OtYQJYbEzfiVqE7q4ySGcq5SEiaF2ZY8XJsfjcWz5k,5661
78
+ picux/signals/__init__.py,sha256=ygkC5UWs-kfoxwolG6Mx2qNhszf6sY62pr40Wb2Rpjw,72
79
+ picux/signals/community/__init__.py,sha256=TBMolPEPIBIdg0y-e_2bMLC8TCLga0_Ef0GSVgf_cNE,772
80
+ picux/signals/community/disambiguation.py,sha256=l9CaROjKl-DrPhrWvNAiKnze6IF0JC_9wgZhHp1Hyx8,1452
81
+ picux/signals/community/intake.py,sha256=rXRgiCJHp6njwXkNrP_v2M89oJxwZDh3c9ecY4wfKVE,9460
82
+ picux/signals/community/models.py,sha256=y0SwBcrbMH88BLCNkxvpcpD6PZd55-IIYpVpmDyWSjE,3369
83
+ picux/signals/community/rules.py,sha256=G5aLbGpl6hCAQ9XE4bzDZVfqzJPPZ-ODgQRymoZsoGA,2418
84
+ picux/signals/community/scoring.py,sha256=CA4-DuJmLOwwtQzrtDZsnWy1V_w_T2evRPWHfrlO15A,2457
85
+ picux/signals/community/adapters/__init__.py,sha256=okbKhOslOwHuK35X0RsIKfRdGtFsnhZEp6c3IUP6EPg,216
86
+ picux/signals/community/adapters/reddit.py,sha256=1AYII8PfHHenhtp71VwcxqUsiU9FLGyofmPU-Nh1R1A,1427
87
+ picux/signals/community/adapters/shopify.py,sha256=zotPyFc44jdhzChgRbqiCJaLKeOuY-KB3zpvLzga-Xs,899
88
+ picux/signals/community/adapters/web.py,sha256=uVrKGGIZwXqU_7hevMXEv4pF6oLctG8qRoEpL7wBPJI,889
89
+ picux/storage/__init__.py,sha256=vN7VD2Cm7yHcQ4HyRwd6rToeF8A6MAzdsiJzJVSob9k,1028
90
+ picux/storage/agents.py,sha256=90CIYnQWaoo7AtzvupSqnqAi3xo0HgG9vXSBac_9LlQ,1985
91
+ picux/storage/cases.py,sha256=wrYlKHSF6FlJB73TX_yxDFlqpSvDHHD-tfZfkdT6AMo,24588
92
+ picux/storage/channels.py,sha256=T3a5mdjhndE7OLL0Z9ZuSXM0_Vt1JiriSKsTVfS6hYc,25061
93
+ picux/storage/connectors.py,sha256=U5TBehxTPLGJ_hDXVuqRhHXqe1L0w6GJpGWfWg6Homk,18654
94
+ picux/storage/envelopes.py,sha256=nO_TpYM53qFS_-L25PjKmw-ZmJOQzEynJ4cw2P0ILWc,5689
95
+ picux/storage/escrows.py,sha256=ZsCrJVXzBXeJtBqlGM8p_sT4yn12NDvz-FwunTkFqAk,7038
96
+ picux/storage/events.py,sha256=Kbi-Vc63NR4uWAva2iWnNXapFcVWn-bnQPAu2TwuBX0,45616
97
+ picux/storage/keyspace.py,sha256=mEvPEVLn2TjmvBAz-hs9vCa8uvbB7h23voY1xw1j91k,1888
98
+ picux/storage/mandates.py,sha256=4emnEy-la4mJDzHjDoCsSWivHnz1GIqoKmUOFeTKRX0,4326
99
+ picux/storage/portals.py,sha256=OhJiZZdm-bnp9mW2XVl9jLbEaTcOHcJqZozFfl7ZdzQ,11445
100
+ picux/storage/postgres.py,sha256=VZgf4ywmympSPgQYZtogy1MW2xjctc6GFijyZ49uOeU,97935
101
+ picux/storage/providers.py,sha256=MqHwyL1_0RiALqRBUIDdKtAFSUKUPMrXaMIW0P7WDkw,7899
102
+ picux/storage/proxy.py,sha256=qeCcB3700hCVCGo0179hxH0jPG3enFLtqWAYkSbucEM,9842
103
+ picux/storage/receipts.py,sha256=n4FzkZsrI24u-hktW4ZtOs9UmSK9yvjah8n_4vCIN08,5564
104
+ picux/storage/signals.py,sha256=Z3uQoTU2jIza-8H-vb7qUzeZuT3COXIp0P5d1KHtRlA,5825
105
+ picux/storage/tasks.py,sha256=oHxrnCfMQtX_YfYmhEx_QxXBSHXJcrnNSYdOhhM6VWc,7777
106
+ picux/tools/__init__.py,sha256=3HRIZC7dWMeO6m4uyFilt5tGBTmEpA4JF_pCeIwQd2E,262
107
+ picux/tools/shared.py,sha256=hfnuQAvNXXT2VwBY62kKYCiPnUA7lGJ-YU3qboCTza4,93091
108
+ picux/verification/__init__.py,sha256=LS8USyFxXCKV6GkeHryKUXCEQ5n-LHZOydspFBr2HY0,167
109
+ picux/verification/rollout.py,sha256=tYzEh9PDT7PKoWaJD0qe6MEuOKcWpy6FRBoiwQS-9oQ,7455
110
+ picux/workflows/__init__.py,sha256=8KNG9zy0Y9dLc7riA8Z86zqh1XNwj-lRrgkjInyzziM,169
111
+ picux/workflows/templates.py,sha256=GDm8XyDmTpBuYXzDi94qklYMzZWQyaqDh6VloJl9MVo,2675
112
+ patchr-0.1.0.dist-info/METADATA,sha256=q4pNOLlcq-ByawK3jDp5vaSn0d9xqA2z8B6CKktypYc,9568
113
+ patchr-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
114
+ patchr-0.1.0.dist-info/entry_points.txt,sha256=KUBoiMW6w11pNYyS4P_iD1j4KPCJA1ClmBeUz8-M4dw,156
115
+ patchr-0.1.0.dist-info/top_level.txt,sha256=bcUKRf4ja-0KW3ecgsexEeVBXJQT6I2A0TBlG40w5d4,18
116
+ patchr-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,5 @@
1
+ [console_scripts]
2
+ patchr-api = apps.api.main:main
3
+ patchr-worker = apps.worker.main:main
4
+ picux-api = apps.api.main:main
5
+ picux-worker = apps.worker.main:main
@@ -0,0 +1,17 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ Copyright 2026 Patchr Core Team
6
+
7
+ Licensed under the Apache License, Version 2.0 (the "License");
8
+ you may not use this file except in compliance with the License.
9
+ You may obtain a copy of the License at
10
+
11
+ http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ Unless required by applicable law or agreed to in writing, software
14
+ distributed under the License is distributed on an "AS IS" BASIS,
15
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ See the License for the specific language governing permissions and
17
+ limitations under the License.
@@ -0,0 +1,3 @@
1
+ apps
2
+ patchr
3
+ picux
picux/__init__.py ADDED
@@ -0,0 +1,6 @@
1
+ """Picux Protocol scaffold."""
2
+
3
+ __all__ = ["__version__"]
4
+
5
+ __version__ = "0.1.0"
6
+
@@ -0,0 +1,5 @@
1
+ """Agent lifecycle and capability discovery primitives."""
2
+
3
+ from .registry import AgentCard, AgentMatch, AgentRegistry
4
+
5
+ __all__ = ["AgentCard", "AgentMatch", "AgentRegistry"]
@@ -0,0 +1,204 @@
1
+ from __future__ import annotations
2
+
3
+ import hashlib
4
+ import json
5
+ from dataclasses import dataclass, field
6
+ from typing import Any
7
+
8
+ from picux.core import Domain
9
+ from picux.protocols.a2a.envelope import createEnvelope
10
+
11
+
12
+ @dataclass(frozen=True)
13
+ class AgentCard:
14
+ agentId: str
15
+ name: str
16
+ domains: tuple[str, ...] = ()
17
+ caps: tuple[str, ...] = ()
18
+ endpoint: str = ""
19
+ trust: int = 1
20
+ status: str = "active"
21
+ meta: dict[str, Any] = field(default_factory=dict)
22
+
23
+ @classmethod
24
+ def fromObj(cls, value: dict[str, Any]) -> "AgentCard":
25
+ rawDomains = value.get("domains", value.get("domain", []))
26
+ if isinstance(rawDomains, str):
27
+ rawDomains = [rawDomains]
28
+ rawCaps = value.get("caps", value.get("capabilities", []))
29
+ if isinstance(rawCaps, str):
30
+ rawCaps = [rawCaps]
31
+ name = str(value.get("name", value.get("agentId", "")) or "")
32
+ agentId = str(value.get("agentId", "") or cls.stableId(name, rawDomains, rawCaps))
33
+ return cls(
34
+ agentId=agentId,
35
+ name=name or agentId,
36
+ domains=tuple(_cleanList(rawDomains)),
37
+ caps=tuple(_cleanList(rawCaps)),
38
+ endpoint=str(value.get("endpoint", "") or ""),
39
+ trust=int(value.get("trust", 1) or 1),
40
+ status=str(value.get("status", "active") or "active"),
41
+ meta=value.get("meta", {}) if isinstance(value.get("meta", {}), dict) else {},
42
+ )
43
+
44
+ def toMap(self) -> dict[str, Any]:
45
+ return {
46
+ "agentId": self.agentId,
47
+ "name": self.name,
48
+ "domains": list(self.domains),
49
+ "caps": list(self.caps),
50
+ "endpoint": self.endpoint,
51
+ "trust": self.trust,
52
+ "status": self.status,
53
+ "meta": self.meta,
54
+ }
55
+
56
+ @staticmethod
57
+ def stableId(name: str, domains: Any, caps: Any) -> str:
58
+ payload = {"name": name, "domains": list(domains or []), "caps": list(caps or [])}
59
+ digest = hashlib.sha256(json.dumps(payload, ensure_ascii=True, sort_keys=True).encode("utf-8")).hexdigest()
60
+ return f"agent_{digest[:16]}"
61
+
62
+
63
+ @dataclass(frozen=True)
64
+ class AgentMatch:
65
+ agent: AgentCard
66
+ score: float
67
+ reasons: tuple[str, ...]
68
+
69
+ def toMap(self) -> dict[str, Any]:
70
+ return {**self.agent.toMap(), "score": round(self.score, 3), "reasons": list(self.reasons)}
71
+
72
+
73
+ class AgentRegistry:
74
+ """Registry for external agent capability discovery."""
75
+
76
+ def __init__(self, agents: list[AgentCard] | None = None, *, backing: Any | None = None) -> None:
77
+ self.backing = backing
78
+ self._agents: dict[str, AgentCard] = {}
79
+ self._loadBacking()
80
+ for agent in agents or []:
81
+ self._agents[agent.agentId] = agent
82
+ self._save(agent)
83
+
84
+ def register(self, raw: AgentCard | dict[str, Any]) -> dict[str, Any]:
85
+ agent = raw if isinstance(raw, AgentCard) else AgentCard.fromObj(raw)
86
+ errors = self.validate(agent)
87
+ if errors:
88
+ return {"ok": False, "errors": errors, "agent": agent.toMap()}
89
+ self._agents[agent.agentId] = agent
90
+ self._save(agent)
91
+ return {"ok": True, "agent": agent.toMap()}
92
+
93
+ def listAgents(self) -> dict[str, Any]:
94
+ self._loadBacking()
95
+ return {"ok": True, "agents": [agent.toMap() for agent in sorted(self._agents.values(), key=lambda item: item.agentId)]}
96
+
97
+ def getAgent(self, agentId: str) -> dict[str, Any]:
98
+ self._loadBacking()
99
+ agent = self._agents.get(str(agentId or ""))
100
+ if agent is None:
101
+ return {"ok": False, "error": "agentNotFound", "agentId": str(agentId or "")}
102
+ return {"ok": True, "agent": agent.toMap()}
103
+
104
+ def match(self, payload: dict[str, Any]) -> dict[str, Any]:
105
+ domain = str(payload.get("domain", "") or "").lower()
106
+ caps = tuple(_cleanList(payload.get("caps", payload.get("capabilities", []))))
107
+ matches = [self.score(agent, domain=domain, caps=caps) for agent in self._agents.values()]
108
+ matches = [match for match in matches if match.score > 0 and match.agent.status == "active"]
109
+ matches.sort(key=lambda item: (item.score, item.agent.trust, item.agent.agentId), reverse=True)
110
+ return {
111
+ "ok": bool(matches),
112
+ "domain": domain,
113
+ "caps": list(caps),
114
+ "matches": [match.toMap() for match in matches],
115
+ }
116
+
117
+ def delegate(self, payload: dict[str, Any]) -> dict[str, Any]:
118
+ agentId = str(payload.get("agentId", "") or "")
119
+ if not agentId:
120
+ matched = self.match(payload)
121
+ if not matched["matches"]:
122
+ return {"ok": False, "error": "agentNotFound", "matches": []}
123
+ agentId = matched["matches"][0]["agentId"]
124
+ agent = self._agents.get(agentId)
125
+ if agent is None or agent.status != "active":
126
+ return {"ok": False, "error": "agentNotFound", "agentId": agentId}
127
+ task = payload.get("task") if isinstance(payload.get("task"), dict) else {}
128
+ envelope = createEnvelope(
129
+ {
130
+ "fromAgent": str(payload.get("fromAgent", "picux") or "picux"),
131
+ "toAgent": agent.agentId,
132
+ "task": task,
133
+ "caps": payload.get("caps", payload.get("capabilities", [])),
134
+ "payload": payload.get("payload", {}),
135
+ "traceId": payload.get("traceId", task.get("taskId", "")),
136
+ }
137
+ )
138
+ plan = {
139
+ "agentId": agent.agentId,
140
+ "endpoint": agent.endpoint,
141
+ "status": "pendingExternalTransport",
142
+ "reason": "a2aTransportNotInvoked",
143
+ "task": task,
144
+ "envelope": envelope["envelope"],
145
+ }
146
+ return {"ok": True, "delegation": plan}
147
+
148
+ @staticmethod
149
+ def validate(agent: AgentCard) -> list[str]:
150
+ errors: list[str] = []
151
+ if not agent.agentId:
152
+ errors.append("missing:agentId")
153
+ if not agent.name:
154
+ errors.append("missing:name")
155
+ if not agent.domains:
156
+ errors.append("missing:domains")
157
+ invalidDomains = [domain for domain in agent.domains if domain not in Domain._value2member_map_]
158
+ if invalidDomains:
159
+ errors.append("invalid:domains")
160
+ if agent.trust < 0:
161
+ errors.append("invalid:trust")
162
+ if agent.status not in {"active", "paused", "disabled"}:
163
+ errors.append("invalid:status")
164
+ return errors
165
+
166
+ @staticmethod
167
+ def score(agent: AgentCard, *, domain: str, caps: tuple[str, ...]) -> AgentMatch:
168
+ reasons: list[str] = []
169
+ score = 0.0
170
+ if domain and domain in agent.domains:
171
+ score += 0.6
172
+ reasons.append("domainMatch")
173
+ capMatches = sorted(set(caps).intersection(agent.caps))
174
+ if capMatches:
175
+ score += min(0.3, 0.1 * len(capMatches))
176
+ reasons.extend([f"cap:{cap}" for cap in capMatches])
177
+ if agent.endpoint:
178
+ score += 0.05
179
+ reasons.append("endpoint")
180
+ if agent.trust > 1:
181
+ score += min(0.05, agent.trust / 100.0)
182
+ reasons.append("trust")
183
+ return AgentMatch(agent=agent, score=round(score, 3), reasons=tuple(reasons))
184
+
185
+ def _save(self, agent: AgentCard) -> None:
186
+ if self.backing is not None and hasattr(self.backing, "saveAgent"):
187
+ self.backing.saveAgent(agent.toMap())
188
+
189
+ def _loadBacking(self) -> None:
190
+ if self.backing is None or not hasattr(self.backing, "listAgents"):
191
+ return
192
+ result = self.backing.listAgents()
193
+ for raw in result.get("agents", []) if isinstance(result, dict) else []:
194
+ if not isinstance(raw, dict):
195
+ continue
196
+ agent = AgentCard.fromObj(raw)
197
+ if not self.validate(agent):
198
+ self._agents[agent.agentId] = agent
199
+
200
+
201
+ def _cleanList(value: Any) -> list[str]:
202
+ if not isinstance(value, (list, tuple, set)):
203
+ return []
204
+ return [str(item).strip().lower() for item in value if str(item).strip()]
picux/api/__init__.py ADDED
@@ -0,0 +1,5 @@
1
+ """Picux API contract primitives."""
2
+
3
+ from .service import PicuxApiService
4
+
5
+ __all__ = ["PicuxApiService"]