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,76 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+
5
+ from tradingcodex_service.application.research import (
6
+ create_research_artifact,
7
+ export_research_artifact_md,
8
+ get_research_artifact,
9
+ append_research_artifact_version,
10
+ list_research_artifacts,
11
+ search_research_artifacts,
12
+ )
13
+ from tradingcodex_cli.commands.utils import _option_value, print_json
14
+
15
+ def research(root: Path, argv: list[str]) -> None:
16
+ sub = argv[0] if argv else "list"
17
+ args = argv[1:]
18
+ if sub == "create":
19
+ markdown_file = _option_value(args, "--markdown-file") or _option_value(args, "--file")
20
+ if not markdown_file:
21
+ raise ValueError("Usage: tcx research create --markdown-file <file.md> [--id <id>] [--title <title>] [--source-as-of <date>]")
22
+ payload = {
23
+ "artifact_id": _option_value(args, "--id"),
24
+ "artifact_type": _option_value(args, "--type") or "research_memo",
25
+ "universe": _option_value(args, "--universe") or "public_equity",
26
+ "workflow_type": _option_value(args, "--workflow-type") or "",
27
+ "symbol": _option_value(args, "--symbol") or "",
28
+ "title": _option_value(args, "--title"),
29
+ "markdown_path": markdown_file,
30
+ "source_as_of": _option_value(args, "--source-as-of") or "",
31
+ "readiness_label": _option_value(args, "--readiness") or "",
32
+ "created_by": _option_value(args, "--created-by") or "head-manager",
33
+ "export_path": _option_value(args, "--export-path"),
34
+ }
35
+ print_json(create_research_artifact(root, payload))
36
+ return
37
+ if sub == "append":
38
+ artifact_id = args[0] if args and not args[0].startswith("--") else _option_value(args, "--id")
39
+ markdown_file = _option_value(args, "--markdown-file") or _option_value(args, "--file")
40
+ if not artifact_id or not markdown_file:
41
+ raise ValueError("Usage: tcx research append <artifact-id> --markdown-file <file.md> [--source-as-of <date>]")
42
+ print_json(append_research_artifact_version(root, {
43
+ "artifact_id": artifact_id,
44
+ "markdown_path": markdown_file,
45
+ "source_as_of": _option_value(args, "--source-as-of") or "",
46
+ "created_by": _option_value(args, "--created-by") or "head-manager",
47
+ "export_path": _option_value(args, "--export-path"),
48
+ }))
49
+ return
50
+ if sub == "get":
51
+ artifact_id = args[0] if args and not args[0].startswith("--") else _option_value(args, "--id")
52
+ if not artifact_id:
53
+ raise ValueError("Usage: tcx research get <artifact-id>")
54
+ print_json(get_research_artifact(root, {"artifact_id": artifact_id}))
55
+ return
56
+ if sub == "list":
57
+ print_json(list_research_artifacts(root, {
58
+ "artifact_type": _option_value(args, "--type"),
59
+ "universe": _option_value(args, "--universe"),
60
+ "symbol": _option_value(args, "--symbol"),
61
+ "limit": _option_value(args, "--limit") or 50,
62
+ }))
63
+ return
64
+ if sub == "search":
65
+ query = " ".join(args).strip()
66
+ if not query:
67
+ raise ValueError("Usage: tcx research search <query>")
68
+ print_json(search_research_artifacts(root, {"query": query}))
69
+ return
70
+ if sub == "export":
71
+ artifact_id = args[0] if args and not args[0].startswith("--") else _option_value(args, "--id")
72
+ if not artifact_id:
73
+ raise ValueError("Usage: tcx research export <artifact-id> [--export-path <file.md>]")
74
+ print_json(export_research_artifact_md(root, {"artifact_id": artifact_id, "export_path": _option_value(args, "--export-path")}))
75
+ return
76
+ raise ValueError(f"Unknown research command: {sub}")
@@ -0,0 +1,93 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+
5
+ from tradingcodex_cli.commands.utils import _option_value, apply_skill_proposal, list_skills, print_json, write_skill_proposal
6
+ from tradingcodex_service.application.agents import (
7
+ create_or_update_optional_skill,
8
+ delete_optional_skill,
9
+ get_optional_skill_record,
10
+ read_optional_skill_records,
11
+ set_optional_skill_status,
12
+ )
13
+
14
+ def skills(root: Path, argv: list[str]) -> None:
15
+ sub = argv[0] if argv else "list"
16
+ args = argv[1:]
17
+ if sub == "optional":
18
+ optional_skills(root, args)
19
+ return
20
+ if sub == "list":
21
+ for skill in list_skills(root, include_internal="--all" in args):
22
+ print(skill)
23
+ return
24
+ if sub == "inspect":
25
+ name = args[0] if args else ""
26
+ from tradingcodex_service.application.agents import build_projection_state
27
+
28
+ skill = build_projection_state(root)["skills"].get(name)
29
+ if not skill or not skill.get("source_file"):
30
+ raise ValueError(f"Unknown skill: {name}")
31
+ print((root / str(skill["source_file"])).read_text(encoding="utf-8"))
32
+ return
33
+ if sub in {"propose-add", "propose-update"}:
34
+ target = _option_value(args, "--to")
35
+ skill = _option_value(args, "--skill")
36
+ if not target or not skill:
37
+ raise ValueError(f"Usage: tcx skills {sub} --to <agent> --skill <skill>")
38
+ print_json(write_skill_proposal(root, sub.replace("propose-", ""), target, skill))
39
+ return
40
+ if sub == "apply-proposal":
41
+ proposal_path = Path(args[0]) if args else None
42
+ if not proposal_path:
43
+ raise ValueError("Usage: tcx skills apply-proposal <proposal.yaml> [--approved-by <principal>]")
44
+ apply_skill_proposal(root, proposal_path if proposal_path.is_absolute() else root / proposal_path, _option_value(args, "--approved-by"))
45
+ return
46
+ raise ValueError(f"Unknown skills command: {sub}")
47
+
48
+
49
+ def optional_skills(root: Path, argv: list[str]) -> None:
50
+ sub = argv[0] if argv else "list"
51
+ args = argv[1:]
52
+ role = _option_value(args, "--role") or _option_value(args, "--to")
53
+ if sub == "list":
54
+ for record in read_optional_skill_records(root, role=role, include_archived="--active" not in args):
55
+ print(f"{record['role']}:{record['name']}")
56
+ return
57
+ if sub == "inspect":
58
+ name = args[0] if args and not args[0].startswith("--") else ""
59
+ if not role or not name:
60
+ raise ValueError("Usage: tcx skills optional inspect <name> --role <agent>")
61
+ record = get_optional_skill_record(root, role, name)
62
+ print((root / str(record["source_file"])).read_text(encoding="utf-8"))
63
+ return
64
+ if sub in {"create", "update"}:
65
+ name = args[0] if args and not args[0].startswith("--") else ""
66
+ if not role or not name:
67
+ raise ValueError(f"Usage: tcx skills optional {sub} <name> --role <agent> [--description <text>] [--body-file <path>]")
68
+ body = _body_arg(root, args)
69
+ status = "active" if "--active" in args else (_option_value(args, "--status") or "draft")
70
+ print_json(create_or_update_optional_skill(root, role, name, description=_option_value(args, "--description") or "", body=body, status=status, actor="local-cli"))
71
+ return
72
+ if sub in {"activate", "archive"}:
73
+ name = args[0] if args else ""
74
+ if not role or not name:
75
+ raise ValueError(f"Usage: tcx skills optional {sub} <name> --role <agent>")
76
+ print_json(set_optional_skill_status(root, role, name, "active" if sub == "activate" else "archived", actor="local-cli"))
77
+ return
78
+ if sub == "delete":
79
+ name = args[0] if args else ""
80
+ if not role or not name:
81
+ raise ValueError("Usage: tcx skills optional delete <name> --role <agent> [--force]")
82
+ print_json(delete_optional_skill(root, role, name, force="--force" in args, actor="local-cli"))
83
+ return
84
+ raise ValueError(f"Unknown optional skills command: {sub}")
85
+
86
+
87
+ def _body_arg(root: Path, args: list[str]) -> str:
88
+ body_file = _option_value(args, "--body-file")
89
+ if body_file:
90
+ path = Path(body_file)
91
+ path = path if path.is_absolute() else root / path
92
+ return path.read_text(encoding="utf-8")
93
+ return _option_value(args, "--body") or ""
@@ -0,0 +1,67 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+
5
+ from tradingcodex_cli.commands.utils import _option_value, print_json
6
+ from tradingcodex_service.application.agents import (
7
+ create_or_update_strategy_skill,
8
+ delete_strategy_skill,
9
+ get_strategy_skill_record,
10
+ read_strategy_skill_records,
11
+ set_strategy_skill_status,
12
+ )
13
+
14
+
15
+ def strategies(root: Path, argv: list[str]) -> None:
16
+ sub = argv[0] if argv else "list"
17
+ args = argv[1:]
18
+ if sub == "list":
19
+ for record in read_strategy_skill_records(root, active_only="--active" in args):
20
+ print(record["name"])
21
+ return
22
+ if sub == "inspect":
23
+ name = args[0] if args else ""
24
+ if not name:
25
+ raise ValueError("Usage: tcx strategies inspect <name>")
26
+ record = get_strategy_skill_record(root, name)
27
+ print((root / str(record["source_file"])).read_text(encoding="utf-8"))
28
+ return
29
+ if sub in {"create", "update"}:
30
+ name = args[0] if args and not args[0].startswith("--") else ""
31
+ if not name:
32
+ raise ValueError(f"Usage: tcx strategies {sub} <name> [--description <text>] [--body-file <path>]")
33
+ status = "active" if "--active" in args else (_option_value(args, "--status") or "draft")
34
+ print_json(
35
+ create_or_update_strategy_skill(
36
+ root,
37
+ name,
38
+ description=_option_value(args, "--description") or "",
39
+ body=_body_arg(root, args),
40
+ language=_option_value(args, "--language") or "unknown",
41
+ status=status,
42
+ actor="local-cli",
43
+ )
44
+ )
45
+ return
46
+ if sub in {"activate", "archive"}:
47
+ name = args[0] if args else ""
48
+ if not name:
49
+ raise ValueError(f"Usage: tcx strategies {sub} <name>")
50
+ print_json(set_strategy_skill_status(root, name, "active" if sub == "activate" else "archived", actor="local-cli"))
51
+ return
52
+ if sub == "delete":
53
+ name = args[0] if args else ""
54
+ if not name:
55
+ raise ValueError("Usage: tcx strategies delete <name> [--force]")
56
+ print_json(delete_strategy_skill(root, name, force="--force" in args, actor="local-cli"))
57
+ return
58
+ raise ValueError(f"Unknown strategies command: {sub}")
59
+
60
+
61
+ def _body_arg(root: Path, args: list[str]) -> str:
62
+ body_file = _option_value(args, "--body-file")
63
+ if body_file:
64
+ path = Path(body_file)
65
+ path = path if path.is_absolute() else root / path
66
+ return path.read_text(encoding="utf-8")
67
+ return _option_value(args, "--body") or ""
@@ -0,0 +1,106 @@
1
+ from __future__ import annotations
2
+
3
+ import sys
4
+ from pathlib import Path
5
+
6
+ from tradingcodex_service.application.agents import (
7
+ AGENT_SPECS,
8
+ diff_agent_configuration,
9
+ inspect_agent_configuration,
10
+ project_agent_configuration,
11
+ EXPECTED_SUBAGENTS,
12
+ )
13
+ from tradingcodex_service.application.harness import build_subagent_starter_prompt
14
+ from tradingcodex_cli.commands.utils import (
15
+ _option_value,
16
+ _parse_agent_list,
17
+ list_skills,
18
+ list_subagents,
19
+ print_json,
20
+ read_subagent_state,
21
+ read_thread_policy,
22
+ skills_for_role,
23
+ )
24
+
25
+ def subagents(root: Path, argv: list[str]) -> None:
26
+ sub = argv[0] if argv else "list"
27
+ args = argv[1:]
28
+ if sub == "list":
29
+ for agent in list_subagents(root):
30
+ print(f"{agent['name']}\t{agent['description']}")
31
+ return
32
+ if sub == "prompt":
33
+ request = " ".join(args).strip()
34
+ if not request:
35
+ raise ValueError("Usage: tcx subagents prompt <investment request>")
36
+ print(build_subagent_starter_prompt(request))
37
+ return
38
+ if sub == "status":
39
+ agents = list_subagents(root)
40
+ print_json({
41
+ "expected_count": len(EXPECTED_SUBAGENTS),
42
+ "installed_count": len(agents),
43
+ "fixed_roster_ok": len(agents) == len(EXPECTED_SUBAGENTS),
44
+ "skills_installed": len(list_skills(root)),
45
+ "thread_policy": read_thread_policy(root),
46
+ "agents": agents,
47
+ })
48
+ return
49
+ if sub == "state":
50
+ print_json(read_subagent_state(root, _option_value(args, "--run")))
51
+ return
52
+ if sub == "inspect":
53
+ role = args[0] if args else ""
54
+ if not role:
55
+ raise ValueError("Usage: tcx subagents inspect <role>")
56
+ print_json(inspect_agent_configuration(root, role))
57
+ return
58
+ if sub == "diff":
59
+ role = args[0] if args and not args[0].startswith("--") else _option_value(args, "--role")
60
+ if not role:
61
+ raise ValueError("Usage: tcx subagents diff <role>")
62
+ print_json(diff_agent_configuration(root, role))
63
+ return
64
+ if sub == "project":
65
+ role = _option_value(args, "--role")
66
+ proposal = _option_value(args, "--proposal")
67
+ applied_by = _option_value(args, "--applied-by") or "local-cli"
68
+ result = project_agent_configuration(
69
+ root,
70
+ role=role,
71
+ proposal_path=(Path(proposal) if proposal else None),
72
+ applied_by=applied_by,
73
+ )
74
+ print_json({"status": "projected", "projection_hash": result["projection_hash"], "manifest": ".tradingcodex/generated/projection-manifest.json"})
75
+ return
76
+ if sub == "plan":
77
+ installed = list_subagents(root)
78
+ requested = [agent["name"] for agent in installed] if "--all" in args else _parse_agent_list(args)
79
+ if not requested:
80
+ raise ValueError("Usage: tcx subagents plan <agent...>|--all")
81
+ installed_names = {agent["name"] for agent in installed}
82
+ unknown = [agent for agent in requested if agent not in installed_names]
83
+ thread_policy = read_thread_policy(root)
84
+ size = max(1, int(thread_policy["max_parallel_subagents"]))
85
+ batches = [{"batch": i + 1, "agents": requested[i:i + size]} for i in range(0, len(requested), size)]
86
+ print_json({
87
+ "requested_count": len(requested),
88
+ "requested_agents": requested,
89
+ "all_fixed_roster": "--all" in args,
90
+ "unknown_agents": unknown,
91
+ "thread_policy": thread_policy,
92
+ "parallel_spawn_ok": not unknown and len(batches) == 1,
93
+ "required_batches": len(batches),
94
+ "batches": batches,
95
+ "recommendation": "spawn requested subagents in one batch" if len(batches) == 1 else "spawn each batch sequentially and hand off artifacts before starting the next batch",
96
+ })
97
+ if unknown:
98
+ sys.exit(1)
99
+ return
100
+ if sub == "skills":
101
+ role = args[0] if args else ""
102
+ if role not in AGENT_SPECS:
103
+ raise ValueError(f"Unknown subagent or role: {role}")
104
+ print_json({"agent": role, "skills": skills_for_role(root, role)})
105
+ return
106
+ raise ValueError(f"Unknown subagents command: {sub}")
@@ -0,0 +1,134 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from pathlib import Path
5
+ from typing import Any
6
+
7
+ from tradingcodex_service.application.agents import (
8
+ build_projection_state,
9
+ list_user_visible_skills,
10
+ project_agent_configuration,
11
+ skills_for_role as file_native_skills_for_role,
12
+ write_skill_proposal_file,
13
+ )
14
+
15
+ def list_subagents(root: Path) -> list[dict[str, str]]:
16
+ agents = []
17
+ for path in sorted((root / ".codex" / "agents").glob("*.toml")):
18
+ text = path.read_text(encoding="utf-8")
19
+ name = _toml_string(text, "name") or path.stem
20
+ agents.append({"name": name, "runtime_label": name, "description": _toml_string(text, "description") or ""})
21
+ return agents
22
+
23
+
24
+ def list_skills(root: Path, include_internal: bool = True) -> list[str]:
25
+ if include_internal:
26
+ return sorted(build_projection_state(root)["skills"])
27
+ return list_user_visible_skills(root)
28
+
29
+
30
+ def read_thread_policy(root: Path) -> dict[str, Any]:
31
+ config = _safe_read(root / ".codex" / "config.toml")
32
+ tc_config = _safe_read(root / ".tradingcodex" / "config.yaml")
33
+ max_threads = int(_regex(config, r"^max_threads\s*=\s*(\d+)", "1"))
34
+ max_depth = int(_regex(config, r"^max_depth\s*=\s*(\d+)", "1"))
35
+ reserved = int(_regex(tc_config, r"^\s*reserved_threads:\s*(\d+)", "0"))
36
+ return {"max_threads": max_threads, "max_depth": max_depth, "reserved_threads": reserved, "max_parallel_subagents": max(1, max_threads - reserved), "overflow_strategy": _regex(tc_config, r"^\s*overflow_strategy:\s*([A-Za-z0-9_-]+)", "batch_queue")}
37
+
38
+
39
+ def read_subagent_state(root: Path, run_id: str | None) -> dict[str, Any]:
40
+ state = _read_json(root / ".tradingcodex" / "mainagent" / "subagent-session-state.json", {"updated_at": None, "active": {}, "completed": [], "events": []})
41
+ if not run_id:
42
+ return {"run_filter": None, **state}
43
+ return {
44
+ "run_filter": run_id,
45
+ "updated_at": state.get("updated_at"),
46
+ "active": {role: record for role, record in state.get("active", {}).items() if record.get("run_id") == run_id},
47
+ "completed": [record for record in state.get("completed", []) if record.get("run_id") == run_id],
48
+ "events": [record for record in state.get("events", []) if record.get("run_id") == run_id],
49
+ }
50
+
51
+
52
+ def skills_for_role(root: Path, role: str) -> list[str]:
53
+ return file_native_skills_for_role(root, role)
54
+
55
+
56
+ def write_skill_proposal(root: Path, type_: str, target: str, skill: str) -> dict[str, Any]:
57
+ return write_skill_proposal_file(root, type_, target, skill)
58
+
59
+
60
+ def apply_skill_proposal(root: Path, proposal_path: Path, approved_by: str | None) -> None:
61
+ result = project_agent_configuration(root, proposal_path=proposal_path, applied_by=approved_by or "local-cli")
62
+ print_json({"status": "applied", "proposal_path": proposal_path.relative_to(root).as_posix(), "projection_hash": result["projection_hash"]})
63
+
64
+
65
+ def path_check(root: Path, layer: str, name: str, rel: str, codex_native: bool) -> dict[str, Any]:
66
+ ok = (root / rel).exists()
67
+ return {"layer": layer, "name": name, "ok": ok, "codexNative": codex_native, "detail": "found" if ok else "missing"}
68
+
69
+
70
+ def text_check(root: Path, layer: str, name: str, rel: str, pattern: str, codex_native: bool) -> dict[str, Any]:
71
+ ok = pattern in _safe_read(root / rel)
72
+ return {"layer": layer, "name": name, "ok": ok, "codexNative": codex_native, "detail": f"contains {pattern}" if ok else f"missing {pattern}"}
73
+
74
+
75
+ def classify_artifact_path(rel: str) -> str:
76
+ if rel.startswith("trading/research/"):
77
+ return "evidence_pack"
78
+ if "order_intent" in rel:
79
+ return "order_intent"
80
+ if "approval_receipt" in rel:
81
+ return "approval_receipt"
82
+ if rel.startswith("trading/reports/"):
83
+ return "report"
84
+ return "artifact"
85
+
86
+
87
+ def _option_value(args: list[str], name: str) -> str | None:
88
+ try:
89
+ return args[args.index(name) + 1]
90
+ except Exception:
91
+ return None
92
+
93
+
94
+ def _parse_agent_list(args: list[str]) -> list[str]:
95
+ return [item.strip() for arg in args for item in arg.split(",") if item.strip()]
96
+
97
+
98
+ def _toml_string(text: str, key: str) -> str | None:
99
+ for line in text.splitlines():
100
+ if line.startswith(f"{key} = "):
101
+ return line.split('"')[1]
102
+ return None
103
+
104
+
105
+ def _safe_read(path: Path) -> str:
106
+ try:
107
+ return path.read_text(encoding="utf-8")
108
+ except Exception:
109
+ return ""
110
+
111
+
112
+ def _read_json(path: Path, default: Any) -> Any:
113
+ try:
114
+ return json.loads(path.read_text(encoding="utf-8"))
115
+ except Exception:
116
+ return default
117
+
118
+
119
+ def _regex(text: str, pattern: str, default: str) -> str:
120
+ import re
121
+
122
+ match = re.search(pattern, text, flags=re.M)
123
+ return match.group(1) if match else default
124
+
125
+
126
+ def _yaml_value(text: str, key: str) -> str | None:
127
+ for line in text.splitlines():
128
+ if line.startswith(f"{key}:"):
129
+ return line.split(":", 1)[1].strip()
130
+ return None
131
+
132
+
133
+ def print_json(value: Any) -> None:
134
+ print(json.dumps(value, indent=2, ensure_ascii=False, default=str))
@@ -0,0 +1,53 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+
5
+ from tradingcodex_cli.commands.utils import print_json
6
+ from tradingcodex_service.application.runtime import (
7
+ ensure_runtime_database,
8
+ ensure_workspace_manifest,
9
+ persist_workspace_context_if_available,
10
+ tradingcodex_db_path,
11
+ )
12
+
13
+
14
+ def workspace(root: Path, argv: list[str]) -> None:
15
+ sub = argv[0] if argv else "status"
16
+ if sub == "status":
17
+ manifest = ensure_workspace_manifest(root)
18
+ ensure_runtime_database(root)
19
+ context = persist_workspace_context_if_available(root)
20
+ print_json({
21
+ "status": "ok",
22
+ "workspace_name": manifest["project_name"],
23
+ "workspace_id": manifest["workspace_id"],
24
+ "active_profile": manifest["active_profile"],
25
+ "db_path": str(tradingcodex_db_path()),
26
+ "mcp_scope": manifest["mcp_scope"],
27
+ "execution_mode": manifest["execution_mode"],
28
+ "workspace_context": context,
29
+ "db_canonical": True,
30
+ })
31
+ return
32
+ if sub == "list":
33
+ ensure_runtime_database(root)
34
+ from apps.harness.models import WorkspaceContext
35
+
36
+ print_json({
37
+ "db_path": str(tradingcodex_db_path()),
38
+ "workspaces": [
39
+ {
40
+ "workspace_id": item.workspace_id,
41
+ "project_name": item.project_name,
42
+ "path": item.path,
43
+ "git_remote": item.git_remote,
44
+ "git_branch": item.git_branch,
45
+ "active_profile": item.active_profile,
46
+ "last_seen_at": item.last_seen_at.isoformat(),
47
+ }
48
+ for item in WorkspaceContext.objects.all()[:200]
49
+ ],
50
+ "db_canonical": True,
51
+ })
52
+ return
53
+ raise ValueError("Usage: tcx workspace status|list")