tradingcodex 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 (254) hide show
  1. apps/__init__.py +1 -0
  2. apps/audit/__init__.py +1 -0
  3. apps/audit/admin.py +6 -0
  4. apps/audit/apps.py +8 -0
  5. apps/audit/migrations/0001_initial.py +35 -0
  6. apps/audit/migrations/__init__.py +0 -0
  7. apps/audit/models.py +22 -0
  8. apps/harness/__init__.py +1 -0
  9. apps/harness/admin.py +6 -0
  10. apps/harness/apps.py +8 -0
  11. apps/harness/migrations/0001_initial.py +35 -0
  12. apps/harness/migrations/__init__.py +0 -0
  13. apps/harness/models.py +22 -0
  14. apps/harness/templatetags/__init__.py +1 -0
  15. apps/integrations/__init__.py +1 -0
  16. apps/integrations/admin.py +6 -0
  17. apps/integrations/apps.py +8 -0
  18. apps/integrations/migrations/0001_initial.py +29 -0
  19. apps/integrations/migrations/__init__.py +0 -0
  20. apps/integrations/models.py +16 -0
  21. apps/integrations/services.py +31 -0
  22. apps/mcp/__init__.py +1 -0
  23. apps/mcp/admin.py +20 -0
  24. apps/mcp/apps.py +8 -0
  25. apps/mcp/migrations/0001_initial.py +168 -0
  26. apps/mcp/migrations/__init__.py +0 -0
  27. apps/mcp/models.py +154 -0
  28. apps/mcp/services.py +327 -0
  29. apps/orders/__init__.py +1 -0
  30. apps/orders/admin.py +6 -0
  31. apps/orders/apps.py +8 -0
  32. apps/orders/migrations/0001_initial.py +79 -0
  33. apps/orders/migrations/__init__.py +0 -0
  34. apps/orders/models.py +66 -0
  35. apps/orders/services.py +107 -0
  36. apps/policy/__init__.py +1 -0
  37. apps/policy/admin.py +6 -0
  38. apps/policy/apps.py +8 -0
  39. apps/policy/migrations/0001_initial.py +75 -0
  40. apps/policy/migrations/__init__.py +0 -0
  41. apps/policy/models.py +61 -0
  42. apps/policy/services.py +110 -0
  43. apps/portfolio/__init__.py +1 -0
  44. apps/portfolio/admin.py +6 -0
  45. apps/portfolio/apps.py +8 -0
  46. apps/portfolio/migrations/0001_initial.py +67 -0
  47. apps/portfolio/migrations/__init__.py +0 -0
  48. apps/portfolio/models.py +53 -0
  49. apps/research/__init__.py +1 -0
  50. apps/research/admin.py +1 -0
  51. apps/research/apps.py +8 -0
  52. apps/research/migrations/__init__.py +0 -0
  53. apps/research/models.py +1 -0
  54. apps/workflows/__init__.py +1 -0
  55. apps/workflows/admin.py +6 -0
  56. apps/workflows/apps.py +8 -0
  57. apps/workflows/migrations/0001_initial.py +51 -0
  58. apps/workflows/migrations/__init__.py +0 -0
  59. apps/workflows/models.py +44 -0
  60. tradingcodex-0.1.0.dist-info/METADATA +337 -0
  61. tradingcodex-0.1.0.dist-info/RECORD +254 -0
  62. tradingcodex-0.1.0.dist-info/WHEEL +5 -0
  63. tradingcodex-0.1.0.dist-info/entry_points.txt +2 -0
  64. tradingcodex-0.1.0.dist-info/licenses/LICENSE +202 -0
  65. tradingcodex-0.1.0.dist-info/licenses/NOTICE +24 -0
  66. tradingcodex-0.1.0.dist-info/top_level.txt +4 -0
  67. tradingcodex_cli/__init__.py +1 -0
  68. tradingcodex_cli/__main__.py +124 -0
  69. tradingcodex_cli/commands/__init__.py +2 -0
  70. tradingcodex_cli/commands/bootstrap.py +157 -0
  71. tradingcodex_cli/commands/db.py +36 -0
  72. tradingcodex_cli/commands/doctor.py +230 -0
  73. tradingcodex_cli/commands/mcp.py +186 -0
  74. tradingcodex_cli/commands/orders.py +89 -0
  75. tradingcodex_cli/commands/policy.py +21 -0
  76. tradingcodex_cli/commands/profile.py +110 -0
  77. tradingcodex_cli/commands/research.py +76 -0
  78. tradingcodex_cli/commands/skills.py +93 -0
  79. tradingcodex_cli/commands/strategies.py +67 -0
  80. tradingcodex_cli/commands/subagents.py +106 -0
  81. tradingcodex_cli/commands/utils.py +134 -0
  82. tradingcodex_cli/commands/workspaces.py +53 -0
  83. tradingcodex_cli/generator.py +234 -0
  84. tradingcodex_cli/mcp_stdio.py +26 -0
  85. tradingcodex_cli/service_autostart.py +127 -0
  86. tradingcodex_service/__init__.py +5 -0
  87. tradingcodex_service/admin.py +1 -0
  88. tradingcodex_service/api.py +486 -0
  89. tradingcodex_service/application/__init__.py +2 -0
  90. tradingcodex_service/application/agents.py +1470 -0
  91. tradingcodex_service/application/audit.py +71 -0
  92. tradingcodex_service/application/common.py +88 -0
  93. tradingcodex_service/application/components.py +299 -0
  94. tradingcodex_service/application/harness.py +747 -0
  95. tradingcodex_service/application/markdown_preview.py +179 -0
  96. tradingcodex_service/application/orders.py +404 -0
  97. tradingcodex_service/application/policy.py +150 -0
  98. tradingcodex_service/application/portfolio.py +166 -0
  99. tradingcodex_service/application/research.py +356 -0
  100. tradingcodex_service/application/runtime.py +321 -0
  101. tradingcodex_service/asgi.py +6 -0
  102. tradingcodex_service/mcp_http.py +59 -0
  103. tradingcodex_service/mcp_runtime.py +565 -0
  104. tradingcodex_service/settings.py +91 -0
  105. tradingcodex_service/templates/web/activity.html +24 -0
  106. tradingcodex_service/templates/web/agent_skills.html +111 -0
  107. tradingcodex_service/templates/web/agents.html +121 -0
  108. tradingcodex_service/templates/web/base.html +150 -0
  109. tradingcodex_service/templates/web/dashboard.html +109 -0
  110. tradingcodex_service/templates/web/fragments/role_inspector.html +81 -0
  111. tradingcodex_service/templates/web/fragments/starter_prompt.html +24 -0
  112. tradingcodex_service/templates/web/fragments/topology_canvas.html +85 -0
  113. tradingcodex_service/templates/web/harness.html +87 -0
  114. tradingcodex_service/templates/web/mcp_router.html +250 -0
  115. tradingcodex_service/templates/web/orders.html +68 -0
  116. tradingcodex_service/templates/web/policy.html +81 -0
  117. tradingcodex_service/templates/web/portfolio.html +52 -0
  118. tradingcodex_service/templates/web/research.html +73 -0
  119. tradingcodex_service/templates/web/starter_prompt.html +40 -0
  120. tradingcodex_service/templates/web/strategies.html +74 -0
  121. tradingcodex_service/urls.py +42 -0
  122. tradingcodex_service/version.py +1 -0
  123. tradingcodex_service/web.py +885 -0
  124. tradingcodex_service/wsgi.py +6 -0
  125. workspace_templates/__init__.py +1 -0
  126. workspace_templates/modules/audit/files/.tradingcodex/audit/README.md +5 -0
  127. workspace_templates/modules/audit/files/trading/audit/.gitkeep +1 -0
  128. workspace_templates/modules/audit/module.json +16 -0
  129. workspace_templates/modules/codex-base/files/.codex/config.toml +272 -0
  130. workspace_templates/modules/codex-base/files/.codex/hooks/tradingcodex_hook.py +173 -0
  131. workspace_templates/modules/codex-base/files/.codex/hooks.json +105 -0
  132. workspace_templates/modules/codex-base/files/.codex/prompts/base_instructions/head-manager.md +129 -0
  133. workspace_templates/modules/codex-base/files/.codex/rules/tradingcodex.rules +50 -0
  134. workspace_templates/modules/codex-base/files/.tradingcodex/capabilities.yaml +56 -0
  135. workspace_templates/modules/codex-base/files/.tradingcodex/cli.py +16 -0
  136. workspace_templates/modules/codex-base/files/.tradingcodex/config.yaml +53 -0
  137. workspace_templates/modules/codex-base/files/.tradingcodex/policies/policy-bindings.yaml +16 -0
  138. workspace_templates/modules/codex-base/files/.tradingcodex/policies/principals.yaml +17 -0
  139. workspace_templates/modules/codex-base/files/.tradingcodex/policies/roles.yaml +27 -0
  140. workspace_templates/modules/codex-base/files/AGENTS.md +56 -0
  141. workspace_templates/modules/codex-base/files/pyproject.toml +13 -0
  142. workspace_templates/modules/codex-base/files/tcx +35 -0
  143. workspace_templates/modules/codex-base/module.json +17 -0
  144. workspace_templates/modules/enforcement-guardrails/files/.tradingcodex/policies/access-policies.yaml +39 -0
  145. workspace_templates/modules/enforcement-guardrails/files/.tradingcodex/policies/restricted-list.yaml +6 -0
  146. workspace_templates/modules/enforcement-guardrails/files/.tradingcodex/schemas/approval_receipt.schema.json +14 -0
  147. workspace_templates/modules/enforcement-guardrails/files/.tradingcodex/schemas/audit_event.schema.json +11 -0
  148. workspace_templates/modules/enforcement-guardrails/files/.tradingcodex/schemas/evidence_pack.schema.json +16 -0
  149. workspace_templates/modules/enforcement-guardrails/files/.tradingcodex/schemas/execution_result.schema.json +12 -0
  150. workspace_templates/modules/enforcement-guardrails/files/.tradingcodex/schemas/fundamental_report.schema.json +15 -0
  151. workspace_templates/modules/enforcement-guardrails/files/.tradingcodex/schemas/news_report.schema.json +15 -0
  152. workspace_templates/modules/enforcement-guardrails/files/.tradingcodex/schemas/order_intent.schema.json +30 -0
  153. workspace_templates/modules/enforcement-guardrails/files/.tradingcodex/schemas/portfolio_review.schema.json +15 -0
  154. workspace_templates/modules/enforcement-guardrails/files/.tradingcodex/schemas/postmortem_report.schema.json +14 -0
  155. workspace_templates/modules/enforcement-guardrails/files/.tradingcodex/schemas/risk_report.schema.json +15 -0
  156. workspace_templates/modules/enforcement-guardrails/files/.tradingcodex/schemas/technical_report.schema.json +15 -0
  157. workspace_templates/modules/enforcement-guardrails/files/.tradingcodex/schemas/thesis.schema.json +15 -0
  158. workspace_templates/modules/enforcement-guardrails/files/.tradingcodex/schemas/valuation.schema.json +15 -0
  159. workspace_templates/modules/enforcement-guardrails/files/.tradingcodex/scripts/validate-order-intent.py +15 -0
  160. workspace_templates/modules/enforcement-guardrails/module.json +19 -0
  161. workspace_templates/modules/fixed-subagents/files/.codex/agents/execution-operator.toml +71 -0
  162. workspace_templates/modules/fixed-subagents/files/.codex/agents/fundamental-analyst.toml +62 -0
  163. workspace_templates/modules/fixed-subagents/files/.codex/agents/instrument-analyst.toml +64 -0
  164. workspace_templates/modules/fixed-subagents/files/.codex/agents/macro-analyst.toml +64 -0
  165. workspace_templates/modules/fixed-subagents/files/.codex/agents/news-analyst.toml +63 -0
  166. workspace_templates/modules/fixed-subagents/files/.codex/agents/portfolio-manager.toml +62 -0
  167. workspace_templates/modules/fixed-subagents/files/.codex/agents/risk-manager.toml +65 -0
  168. workspace_templates/modules/fixed-subagents/files/.codex/agents/technical-analyst.toml +63 -0
  169. workspace_templates/modules/fixed-subagents/files/.codex/agents/valuation-analyst.toml +59 -0
  170. workspace_templates/modules/fixed-subagents/files/.tradingcodex/mainagent/head-manager.yaml +66 -0
  171. workspace_templates/modules/fixed-subagents/files/.tradingcodex/mainagent/skill-change-proposals/.gitkeep +1 -0
  172. workspace_templates/modules/fixed-subagents/files/.tradingcodex/mainagent/subagent-registry.yaml +56 -0
  173. workspace_templates/modules/fixed-subagents/module.json +23 -0
  174. workspace_templates/modules/guidance-guardrails/files/.tradingcodex/guidance/guardrails.md +17 -0
  175. workspace_templates/modules/guidance-guardrails/files/.tradingcodex/guidance/task-quality-checklist.md +37 -0
  176. workspace_templates/modules/guidance-guardrails/module.json +18 -0
  177. workspace_templates/modules/information-barriers/files/.tradingcodex/policies/information-barriers.yaml +211 -0
  178. workspace_templates/modules/information-barriers/files/.tradingcodex/secrets.md +9 -0
  179. workspace_templates/modules/information-barriers/files/trading/approvals/.gitkeep +1 -0
  180. workspace_templates/modules/information-barriers/files/trading/market-data/.gitkeep +1 -0
  181. workspace_templates/modules/information-barriers/files/trading/orders/approved/.gitkeep +1 -0
  182. workspace_templates/modules/information-barriers/files/trading/orders/draft/.gitkeep +1 -0
  183. workspace_templates/modules/information-barriers/files/trading/orders/executed/.gitkeep +1 -0
  184. workspace_templates/modules/information-barriers/files/trading/orders/rejected/.gitkeep +1 -0
  185. workspace_templates/modules/information-barriers/files/trading/portfolio/.gitkeep +1 -0
  186. workspace_templates/modules/information-barriers/files/trading/reports/fundamental/.gitkeep +1 -0
  187. workspace_templates/modules/information-barriers/files/trading/reports/instrument/.gitkeep +1 -0
  188. workspace_templates/modules/information-barriers/files/trading/reports/macro/.gitkeep +1 -0
  189. workspace_templates/modules/information-barriers/files/trading/reports/news/.gitkeep +1 -0
  190. workspace_templates/modules/information-barriers/files/trading/reports/policy/.gitkeep +1 -0
  191. workspace_templates/modules/information-barriers/files/trading/reports/portfolio/.gitkeep +1 -0
  192. workspace_templates/modules/information-barriers/files/trading/reports/postmortem/.gitkeep +1 -0
  193. workspace_templates/modules/information-barriers/files/trading/reports/risk/.gitkeep +1 -0
  194. workspace_templates/modules/information-barriers/files/trading/reports/technical/.gitkeep +1 -0
  195. workspace_templates/modules/information-barriers/files/trading/reports/valuation/.gitkeep +1 -0
  196. workspace_templates/modules/information-barriers/files/trading/research/.gitkeep +1 -0
  197. workspace_templates/modules/information-barriers/module.json +19 -0
  198. workspace_templates/modules/paper-trading/files/.tradingcodex/mcp/adapters/paper-trading.py +4 -0
  199. workspace_templates/modules/paper-trading/module.json +16 -0
  200. workspace_templates/modules/postmortem/files/.tradingcodex/workflows/postmortem.yaml +12 -0
  201. workspace_templates/modules/postmortem/module.json +16 -0
  202. workspace_templates/modules/repo-skills/files/.agents/skills/investment-workflow-map/SKILL.md +106 -0
  203. workspace_templates/modules/repo-skills/files/.agents/skills/investment-workflow-map/agents/openai.yaml +6 -0
  204. workspace_templates/modules/repo-skills/files/.agents/skills/manage-optional-skills/SKILL.md +101 -0
  205. workspace_templates/modules/repo-skills/files/.agents/skills/manage-optional-skills/agents/openai.yaml +6 -0
  206. workspace_templates/modules/repo-skills/files/.agents/skills/manage-subagents/SKILL.md +140 -0
  207. workspace_templates/modules/repo-skills/files/.agents/skills/manage-subagents/agents/openai.yaml +6 -0
  208. workspace_templates/modules/repo-skills/files/.agents/skills/orchestrate-workflow/SKILL.md +140 -0
  209. workspace_templates/modules/repo-skills/files/.agents/skills/orchestrate-workflow/agents/openai.yaml +6 -0
  210. workspace_templates/modules/repo-skills/files/.agents/skills/postmortem/SKILL.md +31 -0
  211. workspace_templates/modules/repo-skills/files/.agents/skills/postmortem/agents/openai.yaml +6 -0
  212. workspace_templates/modules/repo-skills/files/.agents/skills/scenario-quality-gates/SKILL.md +138 -0
  213. workspace_templates/modules/repo-skills/files/.agents/skills/scenario-quality-gates/agents/openai.yaml +6 -0
  214. workspace_templates/modules/repo-skills/files/.agents/skills/strategy-creator/SKILL.md +109 -0
  215. workspace_templates/modules/repo-skills/files/.agents/skills/strategy-creator/agents/openai.yaml +6 -0
  216. workspace_templates/modules/repo-skills/files/.agents/skills/synthesize-decision/SKILL.md +54 -0
  217. workspace_templates/modules/repo-skills/files/.agents/skills/synthesize-decision/agents/openai.yaml +6 -0
  218. workspace_templates/modules/repo-skills/files/.tradingcodex/subagents/skills/execution-operator/execute-paper-order/SKILL.md +35 -0
  219. workspace_templates/modules/repo-skills/files/.tradingcodex/subagents/skills/execution-operator/execute-paper-order/agents/openai.yaml +6 -0
  220. workspace_templates/modules/repo-skills/files/.tradingcodex/subagents/skills/fundamental-analyst/fundamental-analysis/SKILL.md +46 -0
  221. workspace_templates/modules/repo-skills/files/.tradingcodex/subagents/skills/fundamental-analyst/fundamental-analysis/agents/openai.yaml +6 -0
  222. workspace_templates/modules/repo-skills/files/.tradingcodex/subagents/skills/instrument-analyst/instrument-analysis/SKILL.md +40 -0
  223. workspace_templates/modules/repo-skills/files/.tradingcodex/subagents/skills/instrument-analyst/instrument-analysis/agents/openai.yaml +6 -0
  224. workspace_templates/modules/repo-skills/files/.tradingcodex/subagents/skills/macro-analyst/macro-analysis/SKILL.md +40 -0
  225. workspace_templates/modules/repo-skills/files/.tradingcodex/subagents/skills/macro-analyst/macro-analysis/agents/openai.yaml +6 -0
  226. workspace_templates/modules/repo-skills/files/.tradingcodex/subagents/skills/news-analyst/news-analysis/SKILL.md +43 -0
  227. workspace_templates/modules/repo-skills/files/.tradingcodex/subagents/skills/news-analyst/news-analysis/agents/openai.yaml +6 -0
  228. workspace_templates/modules/repo-skills/files/.tradingcodex/subagents/skills/portfolio-manager/create-order-intent/SKILL.md +46 -0
  229. workspace_templates/modules/repo-skills/files/.tradingcodex/subagents/skills/portfolio-manager/create-order-intent/agents/openai.yaml +6 -0
  230. workspace_templates/modules/repo-skills/files/.tradingcodex/subagents/skills/portfolio-manager/portfolio-review/SKILL.md +44 -0
  231. workspace_templates/modules/repo-skills/files/.tradingcodex/subagents/skills/portfolio-manager/portfolio-review/agents/openai.yaml +6 -0
  232. workspace_templates/modules/repo-skills/files/.tradingcodex/subagents/skills/risk-manager/approve-order/SKILL.md +38 -0
  233. workspace_templates/modules/repo-skills/files/.tradingcodex/subagents/skills/risk-manager/approve-order/agents/openai.yaml +6 -0
  234. workspace_templates/modules/repo-skills/files/.tradingcodex/subagents/skills/risk-manager/policy-review/SKILL.md +43 -0
  235. workspace_templates/modules/repo-skills/files/.tradingcodex/subagents/skills/risk-manager/policy-review/agents/openai.yaml +6 -0
  236. workspace_templates/modules/repo-skills/files/.tradingcodex/subagents/skills/risk-manager/review-risk/SKILL.md +45 -0
  237. workspace_templates/modules/repo-skills/files/.tradingcodex/subagents/skills/risk-manager/review-risk/agents/openai.yaml +6 -0
  238. workspace_templates/modules/repo-skills/files/.tradingcodex/subagents/skills/shared/collect-evidence/SKILL.md +46 -0
  239. workspace_templates/modules/repo-skills/files/.tradingcodex/subagents/skills/shared/collect-evidence/agents/openai.yaml +6 -0
  240. workspace_templates/modules/repo-skills/files/.tradingcodex/subagents/skills/shared/external-data-source-gate/SKILL.md +66 -0
  241. workspace_templates/modules/repo-skills/files/.tradingcodex/subagents/skills/shared/external-data-source-gate/agents/openai.yaml +6 -0
  242. workspace_templates/modules/repo-skills/files/.tradingcodex/subagents/skills/technical-analyst/technical-analysis/SKILL.md +43 -0
  243. workspace_templates/modules/repo-skills/files/.tradingcodex/subagents/skills/technical-analyst/technical-analysis/agents/openai.yaml +6 -0
  244. workspace_templates/modules/repo-skills/files/.tradingcodex/subagents/skills/valuation-analyst/valuation-review/SKILL.md +47 -0
  245. workspace_templates/modules/repo-skills/files/.tradingcodex/subagents/skills/valuation-analyst/valuation-review/agents/openai.yaml +6 -0
  246. workspace_templates/modules/repo-skills/module.json +37 -0
  247. workspace_templates/modules/stub-execution/files/.tradingcodex/mcp/adapters/stub-execution.py +4 -0
  248. workspace_templates/modules/stub-execution/module.json +15 -0
  249. workspace_templates/modules/tradingcodex-mcp/files/.tradingcodex/mcp/adapters/live-adapter.contract.md +25 -0
  250. workspace_templates/modules/tradingcodex-mcp/files/.tradingcodex/mcp/enforcer/README.md +5 -0
  251. workspace_templates/modules/tradingcodex-mcp/files/.tradingcodex/mcp/gateway/README.md +8 -0
  252. workspace_templates/modules/tradingcodex-mcp/files/.tradingcodex/mcp/server.py +27 -0
  253. workspace_templates/modules/tradingcodex-mcp/files/.tradingcodex/mcp/smoke-call.py +18 -0
  254. workspace_templates/modules/tradingcodex-mcp/module.json +24 -0
@@ -0,0 +1,71 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+ from typing import Any
5
+
6
+ from tradingcodex_service.application.common import append_jsonl, now_iso, stable_hash
7
+ from tradingcodex_service.application.runtime import ensure_runtime_database, workspace_context_payload
8
+
9
+ def write_audit_event(workspace_root: Path | str, event: dict[str, Any], principal_id: str = "system", source: str = "service") -> dict[str, Any]:
10
+ root = Path(workspace_root)
11
+ record = {"ts": now_iso(), "event": event}
12
+ append_jsonl(root / "trading" / "audit" / "tradingcodex-mcp.jsonl", record)
13
+ write_audit_event_if_available(root, principal_id, source, event)
14
+ return {"written": True, "db_canonical": True, "export_path": "trading/audit/tradingcodex-mcp.jsonl", "workspace_context": workspace_context_payload(root)}
15
+
16
+ def write_audit_event_if_available(
17
+ workspace_root_or_principal: Path | str | None,
18
+ principal_id_or_source: str,
19
+ source_or_event: str | dict[str, Any],
20
+ event: dict[str, Any] | None = None,
21
+ ) -> None:
22
+ if event is None:
23
+ workspace_root = None
24
+ principal_id = str(workspace_root_or_principal)
25
+ source = str(principal_id_or_source)
26
+ event = source_or_event if isinstance(source_or_event, dict) else {}
27
+ else:
28
+ workspace_root = workspace_root_or_principal
29
+ principal_id = str(principal_id_or_source)
30
+ source = str(source_or_event)
31
+ try:
32
+ if workspace_root is not None:
33
+ ensure_runtime_database(workspace_root)
34
+ from apps.audit.models import AuditEvent
35
+
36
+ AuditEvent.objects.create(
37
+ actor_principal=principal_id,
38
+ source=source,
39
+ action=str(event.get("type") or event.get("action") or "event"),
40
+ resource=str(event.get("resource") or event.get("payload", {}).get("order_intent_id") or ""),
41
+ decision=str(event.get("decision") or event.get("payload", {}).get("status") or "recorded"),
42
+ request_hash=stable_hash(event),
43
+ result_hash=stable_hash(event.get("payload", event)),
44
+ workspace_context=workspace_context_payload(workspace_root),
45
+ payload=event,
46
+ )
47
+ except Exception:
48
+ return
49
+
50
+
51
+ def write_policy_decision_if_available(workspace_root_or_result: Path | str | dict[str, Any] | None, result: dict[str, Any] | None = None) -> None:
52
+ workspace_root = None
53
+ if result is None:
54
+ result = workspace_root_or_result if isinstance(workspace_root_or_result, dict) else {}
55
+ else:
56
+ workspace_root = workspace_root_or_result
57
+ try:
58
+ if workspace_root is not None:
59
+ ensure_runtime_database(workspace_root)
60
+ from apps.policy.models import PolicyDecision
61
+
62
+ PolicyDecision.objects.create(
63
+ principal_id=result["principal_id"],
64
+ action=result["action"],
65
+ resource=result.get("resource") or "",
66
+ decision=result["decision"],
67
+ reasons=result["reasons"],
68
+ workspace_context=workspace_context_payload(workspace_root),
69
+ )
70
+ except Exception:
71
+ return
@@ -0,0 +1,88 @@
1
+ from __future__ import annotations
2
+
3
+ import hashlib
4
+ import json
5
+ import re
6
+ from datetime import datetime, timezone
7
+ from pathlib import Path
8
+ from typing import Any
9
+
10
+ def now_iso() -> str:
11
+ return datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
12
+
13
+
14
+ def stable_hash(value: Any) -> str:
15
+ return hashlib.sha256(json.dumps(value, sort_keys=True, default=str).encode("utf-8")).hexdigest()
16
+
17
+
18
+ def sanitize_id(value: Any) -> str:
19
+ return re.sub(r"[^A-Za-z0-9._-]+", "-", str(value)).strip("-") or "unknown"
20
+
21
+
22
+ def read_json(path: Path, default: Any = None) -> Any:
23
+ try:
24
+ return json.loads(path.read_text(encoding="utf-8"))
25
+ except Exception:
26
+ return default
27
+
28
+
29
+ def write_json(path: Path, value: Any) -> None:
30
+ path.parent.mkdir(parents=True, exist_ok=True)
31
+ path.write_text(json.dumps(value, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
32
+
33
+
34
+ def append_jsonl(path: Path, value: Any) -> None:
35
+ path.parent.mkdir(parents=True, exist_ok=True)
36
+ with path.open("a", encoding="utf-8") as handle:
37
+ handle.write(json.dumps(value, ensure_ascii=False, default=str) + "\n")
38
+
39
+ def _status_class(value: Any) -> str:
40
+ text = str(value).lower()
41
+ if text in {"ok", "allow", "accepted", "approved", "enabled", "filled", "valid", "read", "true", "open"}:
42
+ return "good"
43
+ if text in {"deny", "denied", "rejected", "error", "blocked", "disabled", "false", "execution"}:
44
+ return "bad"
45
+ if text in {"proposed", "pending", "recorded", "stubbed", "write", "approval", "research-only"}:
46
+ return "warn"
47
+ return "neutral"
48
+
49
+
50
+ def _resolve_path(root: Path, raw: str) -> Path:
51
+ path = Path(raw)
52
+ return path if path.is_absolute() else root / path
53
+
54
+
55
+ def _safe_read(path: Path) -> str:
56
+ try:
57
+ return path.read_text(encoding="utf-8")
58
+ except Exception:
59
+ return ""
60
+
61
+
62
+ def _number(value: Any) -> float | None:
63
+ try:
64
+ return float(value)
65
+ except Exception:
66
+ return None
67
+
68
+
69
+ def _validate_positive(value: Any, field: str, reasons: list[str]) -> None:
70
+ if value in (None, ""):
71
+ return
72
+ number = _number(value)
73
+ if number is None or number <= 0:
74
+ reasons.append(f"{field} must be a positive number")
75
+
76
+
77
+ def _parse_datetime(value: Any) -> datetime | None:
78
+ if not value:
79
+ return None
80
+ try:
81
+ parsed = datetime.fromisoformat(str(value).replace("Z", "+00:00"))
82
+ except Exception:
83
+ return None
84
+ return parsed if parsed.tzinfo else parsed.replace(tzinfo=timezone.utc)
85
+
86
+
87
+ def _unique(items: list[str]) -> list[str]:
88
+ return list(dict.fromkeys(items))
@@ -0,0 +1,299 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Any
5
+
6
+
7
+ @dataclass(frozen=True)
8
+ class HarnessComponent:
9
+ id: str
10
+ label: str
11
+ summary: str
12
+ status: str
13
+ tags: tuple[str, ...]
14
+ surfaces: dict[str, tuple[str, ...]]
15
+ depends_on: tuple[str, ...]
16
+ owned_capabilities: tuple[str, ...]
17
+ validation: tuple[str, ...]
18
+
19
+ def as_dict(self) -> dict[str, Any]:
20
+ return {
21
+ "id": self.id,
22
+ "label": self.label,
23
+ "summary": self.summary,
24
+ "status": self.status,
25
+ "tags": list(self.tags),
26
+ "surfaces": {key: list(values) for key, values in self.surfaces.items()},
27
+ "depends_on": list(self.depends_on),
28
+ "owned_capabilities": list(self.owned_capabilities),
29
+ "validation": list(self.validation),
30
+ }
31
+
32
+
33
+ HARNESS_COMPONENTS: tuple[HarnessComponent, ...] = (
34
+ HarnessComponent(
35
+ id="fixed-role-dispatch",
36
+ label="Fixed Role Dispatch",
37
+ summary="Maintains the head-manager, fixed subagent routing, and no-overlap handoff contract.",
38
+ status="core",
39
+ tags=("guardrail.guidance", "guardrail.information_barrier", "improvement.workflow_quality"),
40
+ surfaces={
41
+ "instructions": ("head-manager", "AGENTS"),
42
+ "skills": ("manage-subagents",),
43
+ "services": ("harness",),
44
+ "templates": ("codex-base", "fixed-subagents", "repo-skills"),
45
+ "tests": ("generated-workspace", "subagent-roster"),
46
+ },
47
+ depends_on=(),
48
+ owned_capabilities=("workflow.dispatch_fixed_roles",),
49
+ validation=("pytest", "generated workspace contract"),
50
+ ),
51
+ HarnessComponent(
52
+ id="investment-request-routing",
53
+ label="Investment Request Routing",
54
+ summary="Classifies user intent and activates the fixed-role workflow.",
55
+ status="core",
56
+ tags=("guardrail.guidance", "improvement.workflow_quality"),
57
+ surfaces={
58
+ "instructions": ("head-manager", "AGENTS"),
59
+ "skills": ("orchestrate-workflow", "investment-workflow-map", "scenario-quality-gates"),
60
+ "hooks": ("UserPromptSubmit",),
61
+ "services": ("harness",),
62
+ "templates": ("codex-base", "repo-skills"),
63
+ "tests": ("routing", "generated-workspace"),
64
+ },
65
+ depends_on=("fixed-role-dispatch",),
66
+ owned_capabilities=("workflow.route_investment_request",),
67
+ validation=("pytest", "generated workspace contract"),
68
+ ),
69
+ HarnessComponent(
70
+ id="workflow-quality-gates",
71
+ label="Workflow Quality Gates",
72
+ summary="Defines lane selection, handoff acceptance, artifact readiness, claim discipline, and synthesis gates.",
73
+ status="core",
74
+ tags=("guardrail.guidance", "improvement.workflow_quality"),
75
+ surfaces={
76
+ "skills": ("investment-workflow-map", "scenario-quality-gates", "synthesize-decision"),
77
+ "services": ("harness",),
78
+ "templates": ("repo-skills",),
79
+ "tests": ("quality-scenarios", "routing"),
80
+ },
81
+ depends_on=("investment-request-routing", "fixed-role-dispatch"),
82
+ owned_capabilities=("workflow.quality_gate",),
83
+ validation=("pytest", "routing scenario tests"),
84
+ ),
85
+ HarnessComponent(
86
+ id="research-memory",
87
+ label="Research Memory",
88
+ summary="Indexes source-aware workspace markdown artifacts and file-native source snapshots.",
89
+ status="core",
90
+ tags=("improvement.research_memory",),
91
+ surfaces={
92
+ "services": ("research",),
93
+ "mcp_tools": ("create_research_artifact", "search_research_artifacts", "export_research_artifact_md"),
94
+ "files": ("trading/research/*.md", "trading/reports/**/*.md", "trading/research/source-snapshots/*.json"),
95
+ "templates": ("tradingcodex-mcp",),
96
+ "tests": ("research-memory",),
97
+ },
98
+ depends_on=("audit-ledger",),
99
+ owned_capabilities=("research.memory",),
100
+ validation=("pytest", "research-memory smoke checks"),
101
+ ),
102
+ HarnessComponent(
103
+ id="external-data-source-gate",
104
+ label="External Data Source Gate",
105
+ summary="Keeps external MCP, router, plugin, web, and data evidence read-only and source-aware.",
106
+ status="core",
107
+ tags=("guardrail.guidance", "improvement.workflow_quality"),
108
+ surfaces={
109
+ "skills": ("external-data-source-gate",),
110
+ "instructions": ("AGENTS",),
111
+ "templates": ("repo-skills",),
112
+ "tests": ("external-data",),
113
+ },
114
+ depends_on=("workflow-quality-gates",),
115
+ owned_capabilities=("evidence.external_source_gate",),
116
+ validation=("pytest", "routing scenario tests"),
117
+ ),
118
+ HarnessComponent(
119
+ id="external-mcp-proxy-gate",
120
+ label="External MCP Proxy Gate",
121
+ summary="Imports external MCP tool metadata, classifies risk, manages role scopes, and blocks unsafe direct proxy paths.",
122
+ status="core",
123
+ tags=("guardrail.enforcement", "guardrail.information_barrier"),
124
+ surfaces={
125
+ "services": ("mcp.services",),
126
+ "models": ("McpRouter", "McpExternalTool", "McpExternalToolPermission", "McpExternalToolCall"),
127
+ "templates": ("web/mcp_router.html",),
128
+ "tests": ("external-mcp", "product-web"),
129
+ },
130
+ depends_on=("policy-and-restricted-list", "audit-ledger", "secret-wall"),
131
+ owned_capabilities=("mcp.external.classify", "mcp.external.proxy_gate"),
132
+ validation=("pytest", "python manage.py check"),
133
+ ),
134
+ HarnessComponent(
135
+ id="secret-wall",
136
+ label="Secret Wall",
137
+ summary="Blocks raw broker secrets from workspace files, prompts, shell paths, and role context.",
138
+ status="core",
139
+ tags=("guardrail.enforcement", "guardrail.information_barrier"),
140
+ surfaces={
141
+ "hooks": ("UserPromptSubmit", "PreToolUse", "PermissionRequest"),
142
+ "instructions": ("AGENTS",),
143
+ "templates": ("information-barriers", "codex-base"),
144
+ "tests": ("secret-warning", "generated-workspace"),
145
+ },
146
+ depends_on=("audit-ledger",),
147
+ owned_capabilities=("secret.block_workspace_storage",),
148
+ validation=("pytest", "generated workspace contract"),
149
+ ),
150
+ HarnessComponent(
151
+ id="policy-and-restricted-list",
152
+ label="Policy And Restricted List",
153
+ summary="Evaluates principals, capabilities, explicit deny rules, restricted symbols, and limits.",
154
+ status="core",
155
+ tags=("guardrail.enforcement",),
156
+ surfaces={
157
+ "services": ("policy",),
158
+ "models": ("Principal", "Capability", "PolicyDecision", "RestrictedSymbol"),
159
+ "mcp_tools": ("simulate_policy",),
160
+ "templates": ("enforcement-guardrails",),
161
+ "tests": ("policy",),
162
+ },
163
+ depends_on=("audit-ledger",),
164
+ owned_capabilities=("policy.evaluate", "policy.restricted_list"),
165
+ validation=("pytest", "python manage.py check"),
166
+ ),
167
+ HarnessComponent(
168
+ id="approval-gate",
169
+ label="Approval Gate",
170
+ summary="Validates order intents and approval receipts before any execution-sensitive action.",
171
+ status="core",
172
+ tags=("guardrail.enforcement",),
173
+ surfaces={
174
+ "services": ("orders", "policy"),
175
+ "skills": ("create-order-intent", "approve-order", "review-risk"),
176
+ "mcp_tools": ("validate_order_intent", "validate_approval_receipt", "create_approval_receipt"),
177
+ "templates": ("enforcement-guardrails", "tradingcodex-mcp"),
178
+ "tests": ("orders", "approval"),
179
+ },
180
+ depends_on=("policy-and-restricted-list", "audit-ledger"),
181
+ owned_capabilities=("orders.approval_gate",),
182
+ validation=("pytest", "python manage.py check"),
183
+ ),
184
+ HarnessComponent(
185
+ id="execution-boundary",
186
+ label="Execution Boundary",
187
+ summary="Keeps execution behind MCP role allowlists, approval, idempotency, adapter, and audit checks.",
188
+ status="core",
189
+ tags=("guardrail.enforcement", "guardrail.information_barrier"),
190
+ surfaces={
191
+ "services": ("orders", "mcp_runtime", "integrations"),
192
+ "skills": ("execute-paper-order",),
193
+ "mcp_tools": ("submit_approved_order", "cancel_approved_order", "get_order_status"),
194
+ "templates": ("tradingcodex-mcp", "stub-execution", "paper-trading"),
195
+ "tests": ("mcp", "execution"),
196
+ },
197
+ depends_on=("approval-gate", "policy-and-restricted-list", "audit-ledger"),
198
+ owned_capabilities=("execution.boundary",),
199
+ validation=("pytest", "MCP smoke checks"),
200
+ ),
201
+ HarnessComponent(
202
+ id="audit-ledger",
203
+ label="Audit Ledger",
204
+ summary="Records policy, MCP, order, approval, execution, and hook events for review.",
205
+ status="core",
206
+ tags=("guardrail.enforcement", "improvement.validation_feedback"),
207
+ surfaces={
208
+ "services": ("audit",),
209
+ "models": ("AuditEvent", "McpToolCall"),
210
+ "mcp_tools": ("record_audit_event",),
211
+ "templates": ("audit", "tradingcodex-mcp"),
212
+ "tests": ("audit", "mcp-ledger"),
213
+ },
214
+ depends_on=(),
215
+ owned_capabilities=("audit.write", "audit.review"),
216
+ validation=("pytest", "MCP smoke checks"),
217
+ ),
218
+ HarnessComponent(
219
+ id="skill-improvement-loop",
220
+ label="Skill Improvement Loop",
221
+ summary="Keeps skill changes visible through workspace proposal files, validation, projection, and manifest state.",
222
+ status="core",
223
+ tags=("improvement.skill_evolution", "guardrail.guidance"),
224
+ surfaces={
225
+ "services": ("agents", "harness"),
226
+ "files": (
227
+ ".tradingcodex/mainagent/skill-change-proposals/*.yaml",
228
+ ".tradingcodex/subagents/skills/*/*/SKILL.md",
229
+ ".tradingcodex/subagents/skills/*/*/agents/tradingcodex.json",
230
+ ".tradingcodex/strategies/strategy-*/SKILL.md",
231
+ ".tradingcodex/generated/projection-manifest.json",
232
+ ".codex/agents/*.toml",
233
+ ".agents/skills/*",
234
+ ),
235
+ "skills": ("manage-optional-skills", "strategy-creator"),
236
+ "templates": ("repo-skills",),
237
+ "tests": ("skill-proposals", "projection"),
238
+ },
239
+ depends_on=("fixed-role-dispatch",),
240
+ owned_capabilities=("skill.proposal_loop",),
241
+ validation=("pytest", "generated workspace contract"),
242
+ ),
243
+ HarnessComponent(
244
+ id="postmortem-loop",
245
+ label="Postmortem Loop",
246
+ summary="Turns rejected orders, process failures, thesis changes, and executions into improvements.",
247
+ status="core",
248
+ tags=("improvement.postmortems", "improvement.validation_feedback"),
249
+ surfaces={
250
+ "skills": ("postmortem",),
251
+ "services": ("audit", "orders"),
252
+ "templates": ("postmortem", "repo-skills"),
253
+ "tests": ("postmortem",),
254
+ },
255
+ depends_on=("audit-ledger", "workflow-quality-gates"),
256
+ owned_capabilities=("workflow.postmortem",),
257
+ validation=("pytest", "postmortem smoke checks"),
258
+ ),
259
+ HarnessComponent(
260
+ id="paper-execution",
261
+ label="Paper Execution",
262
+ summary="Provides experimental local paper and stub execution adapters behind the execution boundary.",
263
+ status="experimental",
264
+ tags=("guardrail.enforcement",),
265
+ surfaces={
266
+ "services": ("orders", "portfolio", "integrations"),
267
+ "templates": ("paper-trading", "stub-execution"),
268
+ "mcp_tools": ("submit_approved_order", "get_portfolio_snapshot"),
269
+ "tests": ("paper-execution", "portfolio"),
270
+ },
271
+ depends_on=("execution-boundary", "approval-gate"),
272
+ owned_capabilities=("execution.paper", "execution.stub"),
273
+ validation=("pytest", "MCP smoke checks"),
274
+ ),
275
+ )
276
+
277
+
278
+ def list_harness_components() -> list[dict[str, Any]]:
279
+ return [component.as_dict() for component in HARNESS_COMPONENTS]
280
+
281
+
282
+ def get_harness_component(component_id: str) -> dict[str, Any] | None:
283
+ for component in HARNESS_COMPONENTS:
284
+ if component.id == component_id:
285
+ return component.as_dict()
286
+ return None
287
+
288
+
289
+ def list_components_by_tag(tag: str) -> list[dict[str, Any]]:
290
+ return [component.as_dict() for component in HARNESS_COMPONENTS if tag in component.tags]
291
+
292
+
293
+ def count_harness_component_tags() -> dict[str, int]:
294
+ counts: dict[str, int] = {}
295
+ for component in HARNESS_COMPONENTS:
296
+ for tag in component.tags:
297
+ top_level = tag.split(".", 1)[0]
298
+ counts[top_level] = counts.get(top_level, 0) + 1
299
+ return dict(sorted(counts.items()))