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,486 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ from pathlib import Path
5
+ from typing import Any
6
+
7
+ from django.contrib.admin.views.decorators import staff_member_required
8
+ from django.http import Http404
9
+ from ninja import NinjaAPI, Router, Schema
10
+
11
+ from tradingcodex_service import __version__
12
+ from tradingcodex_service.application.components import (
13
+ count_harness_component_tags,
14
+ get_harness_component,
15
+ list_components_by_tag,
16
+ list_harness_components,
17
+ )
18
+ from tradingcodex_service.application.harness import (
19
+ EXPECTED_SUBAGENTS,
20
+ EXPECTED_SKILLS,
21
+ ROLE_SKILL_MAP,
22
+ build_subagent_starter_prompt,
23
+ )
24
+ from tradingcodex_service.application.agents import (
25
+ build_projection_state,
26
+ create_or_update_optional_skill,
27
+ create_or_update_strategy_skill,
28
+ delete_optional_skill,
29
+ delete_strategy_skill,
30
+ get_optional_skill_record,
31
+ get_strategy_skill_record,
32
+ inspect_agent_configuration,
33
+ list_optional_role_skills,
34
+ list_user_visible_skills,
35
+ read_strategy_skill_records,
36
+ set_optional_skill_status,
37
+ set_strategy_skill_status,
38
+ skills_for_role,
39
+ )
40
+ from tradingcodex_service.application.orders import create_approval_receipt, validate_order_intent
41
+ from tradingcodex_service.application.policy import simulate_policy as simulate_policy_service
42
+ from tradingcodex_service.application.portfolio import list_positions
43
+ from tradingcodex_service.application.research import (
44
+ create_research_artifact,
45
+ export_research_artifact_md,
46
+ get_research_artifact,
47
+ list_research_artifacts,
48
+ list_workflow_artifacts,
49
+ record_source_snapshot,
50
+ search_research_artifacts,
51
+ )
52
+ from tradingcodex_service.application.runtime import (
53
+ ensure_runtime_database,
54
+ persist_workspace_context_if_available,
55
+ tradingcodex_db_path,
56
+ )
57
+ from tradingcodex_service.mcp_runtime import call_mcp_tool, list_mcp_tools, prepare_mcp_runtime
58
+
59
+
60
+ def local_or_staff(request):
61
+ if getattr(request, "user", None) and request.user.is_staff:
62
+ return "staff"
63
+ remote_addr = request.META.get("REMOTE_ADDR", "")
64
+ if remote_addr in {"127.0.0.1", "::1", ""}:
65
+ return "local"
66
+ api_key = os.environ.get("TRADINGCODEX_API_KEY")
67
+ if api_key and request.headers.get("X-TradingCodex-Key") == api_key:
68
+ return "api-key"
69
+ return None
70
+
71
+
72
+ api = NinjaAPI(
73
+ title="TradingCodex Service API",
74
+ version=__version__,
75
+ description="Typed control API for TradingCodex harness, policy, portfolio, audit, and workflow state.",
76
+ docs_decorator=staff_member_required,
77
+ auth=local_or_staff,
78
+ )
79
+
80
+ harness_router = Router()
81
+ subagents_router = Router()
82
+ policy_router = Router()
83
+ orders_router = Router()
84
+ approvals_router = Router()
85
+ executions_router = Router()
86
+ portfolio_router = Router()
87
+ audit_router = Router()
88
+ workflows_router = Router()
89
+ integrations_router = Router()
90
+ research_router = Router()
91
+
92
+
93
+ class PolicyRequest(Schema):
94
+ principal_id: str = "unknown"
95
+ action: str = "unknown"
96
+ resource: str | None = None
97
+ order_intent: dict[str, Any] | None = None
98
+ approval_receipt: dict[str, Any] | None = None
99
+ require_approval_check: bool = False
100
+
101
+
102
+ class OrderIntentRequest(Schema):
103
+ principal_id: str = "portfolio-manager"
104
+ order_intent: dict[str, Any]
105
+
106
+
107
+ class ApprovalRequest(Schema):
108
+ approved_by: str = "risk-manager"
109
+ expires_hours: int = 24
110
+ order_intent: dict[str, Any]
111
+
112
+
113
+ class SubmitApprovedRequest(Schema):
114
+ principal_id: str = "execution-operator"
115
+ order_intent: dict[str, Any] | None = None
116
+ approval_receipt: dict[str, Any] | None = None
117
+ order_intent_id: str | None = None
118
+
119
+
120
+ class WorkflowValidationRequest(Schema):
121
+ original_request: str
122
+
123
+
124
+ class ResearchArtifactRequest(Schema):
125
+ artifact_id: str | None = None
126
+ artifact_type: str = "research_memo"
127
+ universe: str = "public_equity"
128
+ workflow_type: str = ""
129
+ symbol: str = ""
130
+ title: str
131
+ markdown: str
132
+ metadata: dict[str, Any] | None = None
133
+ source_as_of: str = ""
134
+ readiness_label: str = ""
135
+ created_by: str = "head-manager"
136
+ export_path: str | None = None
137
+
138
+
139
+ class ResearchSearchRequest(Schema):
140
+ query: str
141
+ universe: str | None = None
142
+ artifact_type: str | None = None
143
+ limit: int = 20
144
+
145
+
146
+ class SourceSnapshotRequest(Schema):
147
+ provider: str
148
+ source_category: str
149
+ as_of: str = ""
150
+ artifact_id: str = ""
151
+ warnings: list[Any] | None = None
152
+ payload: dict[str, Any] | None = None
153
+ principal_id: str = "system"
154
+
155
+
156
+ class StrategySkillRequest(Schema):
157
+ name: str | None = None
158
+ description: str = ""
159
+ body: str = ""
160
+ language: str = "unknown"
161
+ status: str = "draft"
162
+ actor: str = "api"
163
+
164
+
165
+ class OptionalSkillRequest(Schema):
166
+ name: str | None = None
167
+ description: str = ""
168
+ body: str = ""
169
+ status: str = "draft"
170
+ actor: str = "api"
171
+
172
+
173
+ def workspace_root() -> Path:
174
+ return Path(os.environ.get("TRADINGCODEX_WORKSPACE_ROOT", os.getcwd())).resolve()
175
+
176
+
177
+ @api.get("/health", auth=None)
178
+ def health(request):
179
+ return {
180
+ "status": "ok",
181
+ "service": "tradingcodex",
182
+ "version": __version__,
183
+ "db_path": str(tradingcodex_db_path()),
184
+ "central_local_service": True,
185
+ "process_scope": os.environ.get("TRADINGCODEX_MCP_SCOPE", "local-service"),
186
+ }
187
+
188
+
189
+ @harness_router.get("/status")
190
+ def harness_status(request):
191
+ root = workspace_root()
192
+ prepare_mcp_runtime(root)
193
+ optional_status = list_optional_role_skills(root, include_archived=False)
194
+ return {
195
+ "expected_count": len(EXPECTED_SUBAGENTS),
196
+ "installed_count": len(EXPECTED_SUBAGENTS),
197
+ "fixed_roster_ok": True,
198
+ "skills_installed": len(EXPECTED_SKILLS),
199
+ "core_skills_installed": len(EXPECTED_SKILLS),
200
+ "optional_skills_active": len(optional_status["optional_skills"]),
201
+ "user_visible_skills": list_user_visible_skills(root),
202
+ "subagents": EXPECTED_SUBAGENTS,
203
+ "components_total": len(list_harness_components()),
204
+ "component_tag_counts": count_harness_component_tags(),
205
+ "mcp_tools": [tool["name"] for tool in list_mcp_tools()],
206
+ "db_path": str(tradingcodex_db_path()),
207
+ "workspace_context": persist_workspace_context_if_available(root),
208
+ }
209
+
210
+
211
+ @harness_router.get("/components")
212
+ def harness_components(request, tag: str | None = None):
213
+ return {
214
+ "components": list_components_by_tag(tag) if tag else list_harness_components(),
215
+ "component_tag_counts": count_harness_component_tags(),
216
+ }
217
+
218
+
219
+ @harness_router.get("/components/{component_id}")
220
+ def harness_component(request, component_id: str):
221
+ component = get_harness_component(component_id)
222
+ if component is None:
223
+ raise Http404(f"Unknown harness component: {component_id}")
224
+ return component
225
+
226
+
227
+ @harness_router.get("/skills")
228
+ def harness_skills(request, include_internal: bool = False):
229
+ root = workspace_root()
230
+ return {
231
+ "scope": "all" if include_internal else "user-visible",
232
+ "skills": sorted(build_projection_state(root)["skills"]) if include_internal else list_user_visible_skills(root),
233
+ }
234
+
235
+
236
+ @harness_router.get("/optional-skills")
237
+ def harness_optional_skills(request, role: str | None = None, include_archived: bool = True):
238
+ return list_optional_role_skills(workspace_root(), role=role, include_archived=include_archived)
239
+
240
+
241
+ @harness_router.get("/strategies")
242
+ def harness_strategies(request, active_only: bool = False):
243
+ return {"strategies": read_strategy_skill_records(workspace_root(), active_only=active_only)}
244
+
245
+
246
+ @harness_router.post("/strategies")
247
+ def harness_strategy_create(request, payload: StrategySkillRequest):
248
+ if not payload.name:
249
+ raise ValueError("name is required")
250
+ return create_or_update_strategy_skill(
251
+ workspace_root(),
252
+ payload.name,
253
+ description=payload.description,
254
+ body=payload.body,
255
+ language=payload.language,
256
+ status=payload.status,
257
+ actor=payload.actor,
258
+ )
259
+
260
+
261
+ @harness_router.get("/strategies/{name}")
262
+ def harness_strategy_detail(request, name: str):
263
+ return get_strategy_skill_record(workspace_root(), name)
264
+
265
+
266
+ @harness_router.patch("/strategies/{name}")
267
+ def harness_strategy_update(request, name: str, payload: StrategySkillRequest):
268
+ return create_or_update_strategy_skill(
269
+ workspace_root(),
270
+ name,
271
+ description=payload.description,
272
+ body=payload.body,
273
+ language=payload.language,
274
+ status=payload.status,
275
+ actor=payload.actor,
276
+ )
277
+
278
+
279
+ @harness_router.delete("/strategies/{name}")
280
+ def harness_strategy_delete(request, name: str, force: bool = False):
281
+ return delete_strategy_skill(workspace_root(), name, force=force, actor="api")
282
+
283
+
284
+ @harness_router.post("/strategies/{name}/activate")
285
+ def harness_strategy_activate(request, name: str):
286
+ return set_strategy_skill_status(workspace_root(), name, "active", actor="api")
287
+
288
+
289
+ @harness_router.post("/strategies/{name}/archive")
290
+ def harness_strategy_archive(request, name: str):
291
+ return set_strategy_skill_status(workspace_root(), name, "archived", actor="api")
292
+
293
+
294
+ def _subagent_records(root: Path) -> list[dict[str, Any]]:
295
+ return [
296
+ {
297
+ "name": role,
298
+ "skills": skills_for_role(root, role),
299
+ "builtin_skills": ROLE_SKILL_MAP[role],
300
+ }
301
+ for role in EXPECTED_SUBAGENTS
302
+ ]
303
+
304
+
305
+ @subagents_router.get("")
306
+ def subagents_index(request):
307
+ root = workspace_root()
308
+ return _subagent_records(root)
309
+
310
+
311
+ @subagents_router.get("/{role}/skills")
312
+ def subagent_skills(request, role: str):
313
+ root = workspace_root()
314
+ config = inspect_agent_configuration(root, role)
315
+ return {
316
+ "agent": role,
317
+ "skills": skills_for_role(root, role),
318
+ "core_skills": config.get("builtin_skills", []),
319
+ "optional_skills": config.get("optional_skills", []),
320
+ "projected_skills": config.get("projected_skills", []),
321
+ "config": config,
322
+ }
323
+
324
+
325
+ @subagents_router.get("/{role}/optional-skills")
326
+ def subagent_optional_skills(request, role: str, include_archived: bool = True):
327
+ return list_optional_role_skills(workspace_root(), role=role, include_archived=include_archived)
328
+
329
+
330
+ @subagents_router.post("/{role}/optional-skills")
331
+ def subagent_optional_skill_create(request, role: str, payload: OptionalSkillRequest):
332
+ if not payload.name:
333
+ raise ValueError("name is required")
334
+ return create_or_update_optional_skill(
335
+ workspace_root(),
336
+ role,
337
+ payload.name,
338
+ description=payload.description,
339
+ body=payload.body,
340
+ status=payload.status,
341
+ actor=payload.actor,
342
+ )
343
+
344
+
345
+ @subagents_router.get("/{role}/optional-skills/{name}")
346
+ def subagent_optional_skill_detail(request, role: str, name: str):
347
+ return get_optional_skill_record(workspace_root(), role, name)
348
+
349
+
350
+ @subagents_router.patch("/{role}/optional-skills/{name}")
351
+ def subagent_optional_skill_update(request, role: str, name: str, payload: OptionalSkillRequest):
352
+ return create_or_update_optional_skill(
353
+ workspace_root(),
354
+ role,
355
+ name,
356
+ description=payload.description,
357
+ body=payload.body,
358
+ status=payload.status,
359
+ actor=payload.actor,
360
+ )
361
+
362
+
363
+ @subagents_router.delete("/{role}/optional-skills/{name}")
364
+ def subagent_optional_skill_delete(request, role: str, name: str, force: bool = False):
365
+ return delete_optional_skill(workspace_root(), role, name, force=force, actor="api")
366
+
367
+
368
+ @subagents_router.post("/{role}/optional-skills/{name}/activate")
369
+ def subagent_optional_skill_activate(request, role: str, name: str):
370
+ return set_optional_skill_status(workspace_root(), role, name, "active", actor="api")
371
+
372
+
373
+ @subagents_router.post("/{role}/optional-skills/{name}/archive")
374
+ def subagent_optional_skill_archive(request, role: str, name: str):
375
+ return set_optional_skill_status(workspace_root(), role, name, "archived", actor="api")
376
+
377
+
378
+ @harness_router.get("/subagents/prompt")
379
+ def subagent_prompt(request, q: str):
380
+ return {"prompt": build_subagent_starter_prompt(q)}
381
+
382
+
383
+ @policy_router.post("/simulate")
384
+ def simulate_policy(request, payload: PolicyRequest):
385
+ return simulate_policy_service(workspace_root(), payload.dict())
386
+
387
+
388
+ @orders_router.post("/validate-intent")
389
+ def validate_intent(request, payload: OrderIntentRequest):
390
+ return validate_order_intent(workspace_root(), payload.dict())
391
+
392
+
393
+ @approvals_router.post("")
394
+ def create_approval(request, payload: ApprovalRequest):
395
+ return create_approval_receipt(workspace_root(), payload.order_intent, payload.approved_by, payload.expires_hours)
396
+
397
+
398
+ @executions_router.post("/submit-approved")
399
+ def submit_approved(request, payload: SubmitApprovedRequest):
400
+ return call_mcp_tool(workspace_root(), "submit_approved_order", payload.dict())
401
+
402
+
403
+ @portfolio_router.get("/snapshot")
404
+ def portfolio_snapshot(request):
405
+ return list_positions(workspace_root())
406
+
407
+
408
+ @audit_router.get("/events")
409
+ def audit_events(request):
410
+ try:
411
+ ensure_runtime_database(workspace_root())
412
+ from apps.audit.models import AuditEvent
413
+
414
+ return [
415
+ {
416
+ "created_at": event.created_at.isoformat(),
417
+ "actor_principal": event.actor_principal,
418
+ "source": event.source,
419
+ "action": event.action,
420
+ "decision": event.decision,
421
+ "resource": event.resource,
422
+ "workspace_context": event.workspace_context,
423
+ }
424
+ for event in AuditEvent.objects.all()[:100]
425
+ ]
426
+ except Exception:
427
+ return []
428
+
429
+
430
+ @workflows_router.get("/{workflow_id}")
431
+ def workflow_detail(request, workflow_id: str):
432
+ return {"workflow_id": workflow_id, "artifacts": list_workflow_artifacts(workspace_root())["artifacts"]}
433
+
434
+
435
+ @workflows_router.post("/{workflow_id}/validate")
436
+ def workflow_validate(request, workflow_id: str, payload: WorkflowValidationRequest):
437
+ return {"workflow_id": workflow_id, "starter_prompt": build_subagent_starter_prompt(payload.original_request)}
438
+
439
+
440
+ @integrations_router.get("/mcp-tools")
441
+ def mcp_tools(request):
442
+ prepare_mcp_runtime(workspace_root())
443
+ return {"tools": list_mcp_tools()}
444
+
445
+
446
+ @research_router.post("/artifacts")
447
+ def create_research(request, payload: ResearchArtifactRequest):
448
+ return create_research_artifact(workspace_root(), payload.dict())
449
+
450
+
451
+ @research_router.get("/artifacts")
452
+ def list_research(request, artifact_type: str | None = None, universe: str | None = None, symbol: str | None = None, limit: int = 50):
453
+ return list_research_artifacts(workspace_root(), {"artifact_type": artifact_type, "universe": universe, "symbol": symbol, "limit": limit})
454
+
455
+
456
+ @research_router.get("/artifacts/{artifact_id}")
457
+ def get_research(request, artifact_id: str):
458
+ return get_research_artifact(workspace_root(), {"artifact_id": artifact_id})
459
+
460
+
461
+ @research_router.post("/artifacts/{artifact_id}/export")
462
+ def export_research(request, artifact_id: str, export_path: str | None = None):
463
+ return export_research_artifact_md(workspace_root(), {"artifact_id": artifact_id, "export_path": export_path})
464
+
465
+
466
+ @research_router.post("/search")
467
+ def search_research(request, payload: ResearchSearchRequest):
468
+ return search_research_artifacts(workspace_root(), payload.dict())
469
+
470
+
471
+ @research_router.post("/source-snapshots")
472
+ def create_source_snapshot(request, payload: SourceSnapshotRequest):
473
+ return record_source_snapshot(workspace_root(), payload.dict())
474
+
475
+
476
+ api.add_router("/harness", harness_router)
477
+ api.add_router("/subagents", subagents_router)
478
+ api.add_router("/policy", policy_router)
479
+ api.add_router("/orders", orders_router)
480
+ api.add_router("/approvals", approvals_router)
481
+ api.add_router("/executions", executions_router)
482
+ api.add_router("/portfolio", portfolio_router)
483
+ api.add_router("/audit", audit_router)
484
+ api.add_router("/workflows", workflows_router)
485
+ api.add_router("/integrations", integrations_router)
486
+ api.add_router("/research", research_router)
@@ -0,0 +1,2 @@
1
+ from __future__ import annotations
2
+