tradingcodex 0.1.0a1__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 (234) hide show
  1. apps/__init__.py +1 -0
  2. apps/audit/__init__.py +1 -0
  3. apps/audit/admin.py +11 -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 +52 -0
  10. apps/harness/apps.py +8 -0
  11. apps/harness/migrations/0001_initial.py +68 -0
  12. apps/harness/migrations/__init__.py +0 -0
  13. apps/harness/models.py +55 -0
  14. apps/harness/services.py +49 -0
  15. apps/harness/templatetags/__init__.py +1 -0
  16. apps/harness/templatetags/tradingcodex_admin.py +111 -0
  17. apps/integrations/__init__.py +1 -0
  18. apps/integrations/admin.py +24 -0
  19. apps/integrations/apps.py +8 -0
  20. apps/integrations/migrations/0001_initial.py +29 -0
  21. apps/integrations/migrations/__init__.py +0 -0
  22. apps/integrations/models.py +16 -0
  23. apps/integrations/services.py +31 -0
  24. apps/mcp/__init__.py +1 -0
  25. apps/mcp/admin.py +33 -0
  26. apps/mcp/apps.py +8 -0
  27. apps/mcp/migrations/0001_initial.py +57 -0
  28. apps/mcp/migrations/0002_mcptooldefinition_experimental.py +18 -0
  29. apps/mcp/migrations/__init__.py +0 -0
  30. apps/mcp/models.py +45 -0
  31. apps/mcp/services.py +26 -0
  32. apps/orders/__init__.py +1 -0
  33. apps/orders/admin.py +27 -0
  34. apps/orders/apps.py +8 -0
  35. apps/orders/migrations/0001_initial.py +79 -0
  36. apps/orders/migrations/__init__.py +0 -0
  37. apps/orders/models.py +66 -0
  38. apps/orders/services.py +84 -0
  39. apps/policy/__init__.py +1 -0
  40. apps/policy/admin.py +60 -0
  41. apps/policy/apps.py +8 -0
  42. apps/policy/migrations/0001_initial.py +75 -0
  43. apps/policy/migrations/__init__.py +0 -0
  44. apps/policy/models.py +61 -0
  45. apps/policy/services.py +110 -0
  46. apps/portfolio/__init__.py +1 -0
  47. apps/portfolio/admin.py +21 -0
  48. apps/portfolio/apps.py +8 -0
  49. apps/portfolio/migrations/0001_initial.py +67 -0
  50. apps/portfolio/migrations/__init__.py +0 -0
  51. apps/portfolio/models.py +53 -0
  52. apps/research/__init__.py +1 -0
  53. apps/research/admin.py +42 -0
  54. apps/research/apps.py +8 -0
  55. apps/research/migrations/0001_initial.py +99 -0
  56. apps/research/migrations/__init__.py +0 -0
  57. apps/research/models.py +85 -0
  58. apps/universes/__init__.py +1 -0
  59. apps/universes/admin.py +10 -0
  60. apps/universes/apps.py +8 -0
  61. apps/universes/migrations/0001_initial.py +29 -0
  62. apps/universes/migrations/__init__.py +0 -0
  63. apps/universes/models.py +16 -0
  64. apps/workflows/__init__.py +1 -0
  65. apps/workflows/admin.py +17 -0
  66. apps/workflows/apps.py +8 -0
  67. apps/workflows/migrations/0001_initial.py +50 -0
  68. apps/workflows/migrations/__init__.py +0 -0
  69. apps/workflows/models.py +36 -0
  70. tradingcodex-0.1.0a1.dist-info/METADATA +204 -0
  71. tradingcodex-0.1.0a1.dist-info/RECORD +234 -0
  72. tradingcodex-0.1.0a1.dist-info/WHEEL +5 -0
  73. tradingcodex-0.1.0a1.dist-info/entry_points.txt +2 -0
  74. tradingcodex-0.1.0a1.dist-info/licenses/LICENSE +202 -0
  75. tradingcodex-0.1.0a1.dist-info/licenses/NOTICE +24 -0
  76. tradingcodex-0.1.0a1.dist-info/top_level.txt +4 -0
  77. tradingcodex_cli/__init__.py +1 -0
  78. tradingcodex_cli/__main__.py +120 -0
  79. tradingcodex_cli/generator.py +209 -0
  80. tradingcodex_cli/mcp_stdio.py +26 -0
  81. tradingcodex_cli/service_autostart.py +75 -0
  82. tradingcodex_cli/workspace.py +782 -0
  83. tradingcodex_service/__init__.py +3 -0
  84. tradingcodex_service/admin.py +7 -0
  85. tradingcodex_service/api.py +303 -0
  86. tradingcodex_service/asgi.py +6 -0
  87. tradingcodex_service/domain.py +1797 -0
  88. tradingcodex_service/mcp_http.py +59 -0
  89. tradingcodex_service/mcp_runtime.py +507 -0
  90. tradingcodex_service/settings.py +92 -0
  91. tradingcodex_service/templates/admin/base_site.html +35 -0
  92. tradingcodex_service/templates/admin/index.html +242 -0
  93. tradingcodex_service/templates/admin/login.html +56 -0
  94. tradingcodex_service/templates/web/activity.html +33 -0
  95. tradingcodex_service/templates/web/base.html +93 -0
  96. tradingcodex_service/templates/web/dashboard.html +99 -0
  97. tradingcodex_service/templates/web/fragments/role_inspector.html +66 -0
  98. tradingcodex_service/templates/web/fragments/starter_prompt.html +24 -0
  99. tradingcodex_service/templates/web/fragments/topology_canvas.html +79 -0
  100. tradingcodex_service/templates/web/harness.html +48 -0
  101. tradingcodex_service/templates/web/orders.html +77 -0
  102. tradingcodex_service/templates/web/policy.html +80 -0
  103. tradingcodex_service/templates/web/portfolio.html +61 -0
  104. tradingcodex_service/templates/web/research.html +52 -0
  105. tradingcodex_service/templates/web/starter_prompt.html +49 -0
  106. tradingcodex_service/urls.py +26 -0
  107. tradingcodex_service/web.py +243 -0
  108. tradingcodex_service/wsgi.py +6 -0
  109. workspace_templates/__init__.py +1 -0
  110. workspace_templates/modules/audit/files/.tradingcodex/audit/README.md +5 -0
  111. workspace_templates/modules/audit/files/trading/audit/.gitkeep +1 -0
  112. workspace_templates/modules/audit/module.json +16 -0
  113. workspace_templates/modules/codex-base/files/.codex/config.toml +356 -0
  114. workspace_templates/modules/codex-base/files/.codex/hooks/tradingcodex_hook.py +139 -0
  115. workspace_templates/modules/codex-base/files/.codex/hooks.json +105 -0
  116. workspace_templates/modules/codex-base/files/.codex/rules/tradingcodex.rules +50 -0
  117. workspace_templates/modules/codex-base/files/.tradingcodex/capabilities.yaml +56 -0
  118. workspace_templates/modules/codex-base/files/.tradingcodex/cli.py +16 -0
  119. workspace_templates/modules/codex-base/files/.tradingcodex/config.yaml +68 -0
  120. workspace_templates/modules/codex-base/files/.tradingcodex/integrations/openbb-mcp.safe-profile.md +61 -0
  121. workspace_templates/modules/codex-base/files/.tradingcodex/policies/policy-bindings.yaml +16 -0
  122. workspace_templates/modules/codex-base/files/.tradingcodex/policies/principals.yaml +17 -0
  123. workspace_templates/modules/codex-base/files/.tradingcodex/policies/roles.yaml +27 -0
  124. workspace_templates/modules/codex-base/files/AGENTS.md +46 -0
  125. workspace_templates/modules/codex-base/files/pyproject.toml +13 -0
  126. workspace_templates/modules/codex-base/files/tcx +7 -0
  127. workspace_templates/modules/codex-base/module.json +17 -0
  128. workspace_templates/modules/enforcement-guardrails/files/.tradingcodex/policies/access-policies.yaml +39 -0
  129. workspace_templates/modules/enforcement-guardrails/files/.tradingcodex/policies/restricted-list.yaml +6 -0
  130. workspace_templates/modules/enforcement-guardrails/files/.tradingcodex/schemas/approval_receipt.schema.json +14 -0
  131. workspace_templates/modules/enforcement-guardrails/files/.tradingcodex/schemas/audit_event.schema.json +11 -0
  132. workspace_templates/modules/enforcement-guardrails/files/.tradingcodex/schemas/evidence_pack.schema.json +16 -0
  133. workspace_templates/modules/enforcement-guardrails/files/.tradingcodex/schemas/execution_result.schema.json +12 -0
  134. workspace_templates/modules/enforcement-guardrails/files/.tradingcodex/schemas/fundamental_report.schema.json +15 -0
  135. workspace_templates/modules/enforcement-guardrails/files/.tradingcodex/schemas/news_report.schema.json +15 -0
  136. workspace_templates/modules/enforcement-guardrails/files/.tradingcodex/schemas/order_intent.schema.json +30 -0
  137. workspace_templates/modules/enforcement-guardrails/files/.tradingcodex/schemas/portfolio_review.schema.json +15 -0
  138. workspace_templates/modules/enforcement-guardrails/files/.tradingcodex/schemas/postmortem_report.schema.json +14 -0
  139. workspace_templates/modules/enforcement-guardrails/files/.tradingcodex/schemas/risk_report.schema.json +15 -0
  140. workspace_templates/modules/enforcement-guardrails/files/.tradingcodex/schemas/technical_report.schema.json +15 -0
  141. workspace_templates/modules/enforcement-guardrails/files/.tradingcodex/schemas/thesis.schema.json +15 -0
  142. workspace_templates/modules/enforcement-guardrails/files/.tradingcodex/schemas/valuation.schema.json +15 -0
  143. workspace_templates/modules/enforcement-guardrails/files/.tradingcodex/scripts/validate-order-intent.py +15 -0
  144. workspace_templates/modules/enforcement-guardrails/module.json +19 -0
  145. workspace_templates/modules/fixed-subagents/files/.codex/agents/execution-operator.toml +70 -0
  146. workspace_templates/modules/fixed-subagents/files/.codex/agents/fundamental-analyst.toml +61 -0
  147. workspace_templates/modules/fixed-subagents/files/.codex/agents/instrument-analyst.toml +63 -0
  148. workspace_templates/modules/fixed-subagents/files/.codex/agents/macro-analyst.toml +63 -0
  149. workspace_templates/modules/fixed-subagents/files/.codex/agents/news-analyst.toml +62 -0
  150. workspace_templates/modules/fixed-subagents/files/.codex/agents/portfolio-manager.toml +61 -0
  151. workspace_templates/modules/fixed-subagents/files/.codex/agents/risk-manager.toml +64 -0
  152. workspace_templates/modules/fixed-subagents/files/.codex/agents/technical-analyst.toml +62 -0
  153. workspace_templates/modules/fixed-subagents/files/.codex/agents/valuation-analyst.toml +58 -0
  154. workspace_templates/modules/fixed-subagents/files/.tradingcodex/mainagent/head-manager.yaml +67 -0
  155. workspace_templates/modules/fixed-subagents/files/.tradingcodex/mainagent/skill-change-proposals/.gitkeep +1 -0
  156. workspace_templates/modules/fixed-subagents/files/.tradingcodex/mainagent/subagent-registry.yaml +56 -0
  157. workspace_templates/modules/fixed-subagents/module.json +23 -0
  158. workspace_templates/modules/guidance-guardrails/files/.tradingcodex/guidance/guardrails.md +15 -0
  159. workspace_templates/modules/guidance-guardrails/files/.tradingcodex/guidance/task-quality-checklist.md +35 -0
  160. workspace_templates/modules/guidance-guardrails/module.json +18 -0
  161. workspace_templates/modules/information-barriers/files/.tradingcodex/policies/information-barriers.yaml +211 -0
  162. workspace_templates/modules/information-barriers/files/.tradingcodex/secrets.md +9 -0
  163. workspace_templates/modules/information-barriers/files/trading/approvals/.gitkeep +1 -0
  164. workspace_templates/modules/information-barriers/files/trading/market-data/.gitkeep +1 -0
  165. workspace_templates/modules/information-barriers/files/trading/orders/approved/.gitkeep +1 -0
  166. workspace_templates/modules/information-barriers/files/trading/orders/draft/.gitkeep +1 -0
  167. workspace_templates/modules/information-barriers/files/trading/orders/executed/.gitkeep +1 -0
  168. workspace_templates/modules/information-barriers/files/trading/orders/rejected/.gitkeep +1 -0
  169. workspace_templates/modules/information-barriers/files/trading/portfolio/.gitkeep +1 -0
  170. workspace_templates/modules/information-barriers/files/trading/reports/fundamental/.gitkeep +1 -0
  171. workspace_templates/modules/information-barriers/files/trading/reports/instrument/.gitkeep +1 -0
  172. workspace_templates/modules/information-barriers/files/trading/reports/macro/.gitkeep +1 -0
  173. workspace_templates/modules/information-barriers/files/trading/reports/news/.gitkeep +1 -0
  174. workspace_templates/modules/information-barriers/files/trading/reports/policy/.gitkeep +1 -0
  175. workspace_templates/modules/information-barriers/files/trading/reports/portfolio/.gitkeep +1 -0
  176. workspace_templates/modules/information-barriers/files/trading/reports/postmortem/.gitkeep +1 -0
  177. workspace_templates/modules/information-barriers/files/trading/reports/risk/.gitkeep +1 -0
  178. workspace_templates/modules/information-barriers/files/trading/reports/technical/.gitkeep +1 -0
  179. workspace_templates/modules/information-barriers/files/trading/reports/valuation/.gitkeep +1 -0
  180. workspace_templates/modules/information-barriers/files/trading/research/.gitkeep +1 -0
  181. workspace_templates/modules/information-barriers/module.json +19 -0
  182. workspace_templates/modules/paper-trading/files/.tradingcodex/mcp/adapters/paper-trading.py +4 -0
  183. workspace_templates/modules/paper-trading/module.json +16 -0
  184. workspace_templates/modules/postmortem/files/.tradingcodex/workflows/postmortem.yaml +12 -0
  185. workspace_templates/modules/postmortem/module.json +16 -0
  186. workspace_templates/modules/repo-skills/files/.agents/skills/approve-order/SKILL.md +38 -0
  187. workspace_templates/modules/repo-skills/files/.agents/skills/approve-order/agents/openai.yaml +6 -0
  188. workspace_templates/modules/repo-skills/files/.agents/skills/collect-evidence/SKILL.md +46 -0
  189. workspace_templates/modules/repo-skills/files/.agents/skills/collect-evidence/agents/openai.yaml +6 -0
  190. workspace_templates/modules/repo-skills/files/.agents/skills/create-order-intent/SKILL.md +46 -0
  191. workspace_templates/modules/repo-skills/files/.agents/skills/create-order-intent/agents/openai.yaml +6 -0
  192. workspace_templates/modules/repo-skills/files/.agents/skills/execute-paper-order/SKILL.md +35 -0
  193. workspace_templates/modules/repo-skills/files/.agents/skills/execute-paper-order/agents/openai.yaml +6 -0
  194. workspace_templates/modules/repo-skills/files/.agents/skills/external-data-source-gate/SKILL.md +76 -0
  195. workspace_templates/modules/repo-skills/files/.agents/skills/fundamental-analysis/SKILL.md +46 -0
  196. workspace_templates/modules/repo-skills/files/.agents/skills/fundamental-analysis/agents/openai.yaml +6 -0
  197. workspace_templates/modules/repo-skills/files/.agents/skills/head-manager-interview/SKILL.md +81 -0
  198. workspace_templates/modules/repo-skills/files/.agents/skills/head-manager-interview/agents/openai.yaml +6 -0
  199. workspace_templates/modules/repo-skills/files/.agents/skills/head-manager-interview/references/investor-profile-reference.md +50 -0
  200. workspace_templates/modules/repo-skills/files/.agents/skills/instrument-analysis/SKILL.md +40 -0
  201. workspace_templates/modules/repo-skills/files/.agents/skills/instrument-analysis/agents/openai.yaml +6 -0
  202. workspace_templates/modules/repo-skills/files/.agents/skills/investment-workflow-map/SKILL.md +100 -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/macro-analysis/SKILL.md +40 -0
  205. workspace_templates/modules/repo-skills/files/.agents/skills/macro-analysis/agents/openai.yaml +6 -0
  206. workspace_templates/modules/repo-skills/files/.agents/skills/manage-subagents/SKILL.md +119 -0
  207. workspace_templates/modules/repo-skills/files/.agents/skills/news-analysis/SKILL.md +43 -0
  208. workspace_templates/modules/repo-skills/files/.agents/skills/news-analysis/agents/openai.yaml +6 -0
  209. workspace_templates/modules/repo-skills/files/.agents/skills/orchestrate-workflow/SKILL.md +290 -0
  210. workspace_templates/modules/repo-skills/files/.agents/skills/orchestrate-workflow/agents/openai.yaml +6 -0
  211. workspace_templates/modules/repo-skills/files/.agents/skills/policy-review/SKILL.md +43 -0
  212. workspace_templates/modules/repo-skills/files/.agents/skills/policy-review/agents/openai.yaml +6 -0
  213. workspace_templates/modules/repo-skills/files/.agents/skills/portfolio-review/SKILL.md +44 -0
  214. workspace_templates/modules/repo-skills/files/.agents/skills/portfolio-review/agents/openai.yaml +6 -0
  215. workspace_templates/modules/repo-skills/files/.agents/skills/postmortem/SKILL.md +31 -0
  216. workspace_templates/modules/repo-skills/files/.agents/skills/review-risk/SKILL.md +45 -0
  217. workspace_templates/modules/repo-skills/files/.agents/skills/review-risk/agents/openai.yaml +6 -0
  218. workspace_templates/modules/repo-skills/files/.agents/skills/scenario-quality-gates/SKILL.md +126 -0
  219. workspace_templates/modules/repo-skills/files/.agents/skills/synthesize-decision/SKILL.md +45 -0
  220. workspace_templates/modules/repo-skills/files/.agents/skills/synthesize-decision/agents/openai.yaml +6 -0
  221. workspace_templates/modules/repo-skills/files/.agents/skills/technical-analysis/SKILL.md +43 -0
  222. workspace_templates/modules/repo-skills/files/.agents/skills/technical-analysis/agents/openai.yaml +6 -0
  223. workspace_templates/modules/repo-skills/files/.agents/skills/valuation-review/SKILL.md +47 -0
  224. workspace_templates/modules/repo-skills/files/.agents/skills/valuation-review/agents/openai.yaml +6 -0
  225. workspace_templates/modules/repo-skills/files/.tradingcodex/mainagent/head-manager-interview.md +97 -0
  226. workspace_templates/modules/repo-skills/module.json +36 -0
  227. workspace_templates/modules/stub-execution/files/.tradingcodex/mcp/adapters/stub-execution.py +4 -0
  228. workspace_templates/modules/stub-execution/module.json +15 -0
  229. workspace_templates/modules/tradingcodex-mcp/files/.tradingcodex/mcp/adapters/live-adapter.contract.md +25 -0
  230. workspace_templates/modules/tradingcodex-mcp/files/.tradingcodex/mcp/enforcer/README.md +5 -0
  231. workspace_templates/modules/tradingcodex-mcp/files/.tradingcodex/mcp/gateway/README.md +8 -0
  232. workspace_templates/modules/tradingcodex-mcp/files/.tradingcodex/mcp/server.py +27 -0
  233. workspace_templates/modules/tradingcodex-mcp/files/.tradingcodex/mcp/smoke-call.py +18 -0
  234. workspace_templates/modules/tradingcodex-mcp/module.json +24 -0
apps/__init__.py ADDED
@@ -0,0 +1 @@
1
+
apps/audit/__init__.py ADDED
@@ -0,0 +1 @@
1
+
apps/audit/admin.py ADDED
@@ -0,0 +1,11 @@
1
+ from django.contrib import admin
2
+
3
+ from apps.audit.models import AuditEvent
4
+
5
+
6
+ @admin.register(AuditEvent)
7
+ class AuditEventAdmin(admin.ModelAdmin):
8
+ list_display = ("created_at", "actor_principal", "source", "action", "decision", "resource")
9
+ list_filter = ("source", "decision", "action")
10
+ search_fields = ("actor_principal", "action", "resource", "request_hash", "result_hash")
11
+ readonly_fields = ("created_at", "workspace_context", "request_hash", "result_hash")
apps/audit/apps.py ADDED
@@ -0,0 +1,8 @@
1
+ from django.apps import AppConfig
2
+
3
+
4
+ class AuditConfig(AppConfig):
5
+ default_auto_field = "django.db.models.BigAutoField"
6
+ name = "apps.audit"
7
+ label = "audit"
8
+ verbose_name = "Audit Ledger"
@@ -0,0 +1,35 @@
1
+ # Generated by Django 5.2.5 on 2026-06-08 09:49
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ initial = True
9
+
10
+ dependencies = [
11
+ ]
12
+
13
+ operations = [
14
+ migrations.CreateModel(
15
+ name='AuditEvent',
16
+ fields=[
17
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
18
+ ('created_at', models.DateTimeField(auto_now_add=True)),
19
+ ('actor_principal', models.CharField(default='system', max_length=128)),
20
+ ('source', models.CharField(default='service', max_length=32)),
21
+ ('action', models.CharField(max_length=160)),
22
+ ('resource', models.CharField(blank=True, max_length=255)),
23
+ ('decision', models.CharField(default='recorded', max_length=32)),
24
+ ('request_hash', models.CharField(blank=True, max_length=64)),
25
+ ('result_hash', models.CharField(blank=True, max_length=64)),
26
+ ('workspace_context', models.JSONField(blank=True, default=dict)),
27
+ ('payload', models.JSONField(blank=True, default=dict)),
28
+ ],
29
+ options={
30
+ 'verbose_name': 'Audit event',
31
+ 'verbose_name_plural': 'Audit events',
32
+ 'ordering': ['-created_at', '-id'],
33
+ },
34
+ ),
35
+ ]
File without changes
apps/audit/models.py ADDED
@@ -0,0 +1,22 @@
1
+ from django.db import models
2
+
3
+
4
+ class AuditEvent(models.Model):
5
+ created_at = models.DateTimeField(auto_now_add=True)
6
+ actor_principal = models.CharField(max_length=128, default="system")
7
+ source = models.CharField(max_length=32, default="service")
8
+ action = models.CharField(max_length=160)
9
+ resource = models.CharField(max_length=255, blank=True)
10
+ decision = models.CharField(max_length=32, default="recorded")
11
+ request_hash = models.CharField(max_length=64, blank=True)
12
+ result_hash = models.CharField(max_length=64, blank=True)
13
+ workspace_context = models.JSONField(default=dict, blank=True)
14
+ payload = models.JSONField(default=dict, blank=True)
15
+
16
+ class Meta:
17
+ ordering = ["-created_at", "-id"]
18
+ verbose_name = "Audit event"
19
+ verbose_name_plural = "Audit events"
20
+
21
+ def __str__(self) -> str:
22
+ return f"{self.created_at:%Y-%m-%d %H:%M:%S} {self.action}"
@@ -0,0 +1 @@
1
+
apps/harness/admin.py ADDED
@@ -0,0 +1,52 @@
1
+ from django.contrib import admin
2
+
3
+ from apps.harness.models import RoleSkillAssignment, SkillProposal, WorkspaceContext
4
+ from apps.harness.services import (
5
+ apply_skill_proposals,
6
+ approve_skill_proposals,
7
+ reject_skill_proposals,
8
+ set_role_skill_assignments_enabled,
9
+ )
10
+
11
+
12
+ @admin.register(WorkspaceContext)
13
+ class WorkspaceContextAdmin(admin.ModelAdmin):
14
+ list_display = ("project_name", "path_hash", "git_branch", "last_seen_at")
15
+ search_fields = ("project_name", "path", "path_hash", "git_remote", "git_branch")
16
+ readonly_fields = ("path_hash", "created_at", "last_seen_at")
17
+
18
+
19
+ @admin.register(RoleSkillAssignment)
20
+ class RoleSkillAssignmentAdmin(admin.ModelAdmin):
21
+ list_display = ("role", "skill", "enabled", "source")
22
+ list_filter = ("role", "enabled", "source")
23
+ search_fields = ("role", "skill")
24
+ actions = ["enable_assignments", "disable_assignments"]
25
+
26
+ @admin.action(description="Enable selected role skill assignments")
27
+ def enable_assignments(self, request, queryset):
28
+ set_role_skill_assignments_enabled(queryset, True, str(request.user or "admin"))
29
+
30
+ @admin.action(description="Disable selected role skill assignments")
31
+ def disable_assignments(self, request, queryset):
32
+ set_role_skill_assignments_enabled(queryset, False, str(request.user or "admin"))
33
+
34
+
35
+ @admin.register(SkillProposal)
36
+ class SkillProposalAdmin(admin.ModelAdmin):
37
+ list_display = ("proposal_id", "type", "target", "skill", "status", "execution_sensitive", "created_at")
38
+ list_filter = ("type", "status", "execution_sensitive", "target")
39
+ search_fields = ("proposal_id", "target", "skill", "approved_by")
40
+ actions = ["approve_proposals", "apply_proposals", "reject_proposals"]
41
+
42
+ @admin.action(description="Approve selected skill proposals")
43
+ def approve_proposals(self, request, queryset):
44
+ approve_skill_proposals(queryset, str(request.user or "admin"))
45
+
46
+ @admin.action(description="Apply selected approved skill proposals")
47
+ def apply_proposals(self, request, queryset):
48
+ apply_skill_proposals(queryset, str(request.user or "admin"))
49
+
50
+ @admin.action(description="Reject selected skill proposals")
51
+ def reject_proposals(self, request, queryset):
52
+ reject_skill_proposals(queryset, str(request.user or "admin"))
apps/harness/apps.py ADDED
@@ -0,0 +1,8 @@
1
+ from django.apps import AppConfig
2
+
3
+
4
+ class HarnessConfig(AppConfig):
5
+ default_auto_field = "django.db.models.BigAutoField"
6
+ name = "apps.harness"
7
+ label = "harness"
8
+ verbose_name = "Harness Operations"
@@ -0,0 +1,68 @@
1
+ # Generated by Django 5.2.5 on 2026-06-08 09:49
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ initial = True
9
+
10
+ dependencies = [
11
+ ]
12
+
13
+ operations = [
14
+ migrations.CreateModel(
15
+ name='SkillProposal',
16
+ fields=[
17
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
18
+ ('proposal_id', models.CharField(max_length=220, unique=True)),
19
+ ('type', models.CharField(max_length=32)),
20
+ ('target', models.CharField(max_length=128)),
21
+ ('skill', models.CharField(max_length=160)),
22
+ ('status', models.CharField(default='proposed', max_length=32)),
23
+ ('approved_by', models.CharField(blank=True, max_length=128)),
24
+ ('execution_sensitive', models.BooleanField(default=False)),
25
+ ('created_at', models.DateTimeField(auto_now_add=True)),
26
+ ('applied_at', models.DateTimeField(blank=True, null=True)),
27
+ ],
28
+ options={
29
+ 'verbose_name': 'Skill proposal',
30
+ 'verbose_name_plural': 'Skill proposals',
31
+ 'ordering': ['-created_at', '-id'],
32
+ },
33
+ ),
34
+ migrations.CreateModel(
35
+ name='WorkspaceContext',
36
+ fields=[
37
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
38
+ ('path_hash', models.CharField(max_length=64, unique=True)),
39
+ ('project_name', models.CharField(max_length=180)),
40
+ ('path', models.CharField(max_length=1024)),
41
+ ('git_remote', models.CharField(blank=True, max_length=512)),
42
+ ('git_branch', models.CharField(blank=True, max_length=180)),
43
+ ('metadata', models.JSONField(blank=True, default=dict)),
44
+ ('created_at', models.DateTimeField(auto_now_add=True)),
45
+ ('last_seen_at', models.DateTimeField(auto_now=True)),
46
+ ],
47
+ options={
48
+ 'verbose_name': 'Workspace context',
49
+ 'verbose_name_plural': 'Workspace contexts',
50
+ 'ordering': ['project_name', 'id'],
51
+ },
52
+ ),
53
+ migrations.CreateModel(
54
+ name='RoleSkillAssignment',
55
+ fields=[
56
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
57
+ ('role', models.CharField(max_length=128)),
58
+ ('skill', models.CharField(max_length=160)),
59
+ ('enabled', models.BooleanField(default=True)),
60
+ ('source', models.CharField(default='bootstrap', max_length=64)),
61
+ ],
62
+ options={
63
+ 'verbose_name': 'Role skill assignment',
64
+ 'verbose_name_plural': 'Role skill assignments',
65
+ 'unique_together': {('role', 'skill')},
66
+ },
67
+ ),
68
+ ]
File without changes
apps/harness/models.py ADDED
@@ -0,0 +1,55 @@
1
+ from django.db import models
2
+
3
+
4
+ class WorkspaceContext(models.Model):
5
+ path_hash = models.CharField(max_length=64, unique=True)
6
+ project_name = models.CharField(max_length=180)
7
+ path = models.CharField(max_length=1024)
8
+ git_remote = models.CharField(max_length=512, blank=True)
9
+ git_branch = models.CharField(max_length=180, blank=True)
10
+ metadata = models.JSONField(default=dict, blank=True)
11
+ created_at = models.DateTimeField(auto_now_add=True)
12
+ last_seen_at = models.DateTimeField(auto_now=True)
13
+
14
+ class Meta:
15
+ ordering = ["project_name", "id"]
16
+ verbose_name = "Workspace context"
17
+ verbose_name_plural = "Workspace contexts"
18
+
19
+ def __str__(self) -> str:
20
+ return f"{self.project_name} {self.path_hash[:12]}"
21
+
22
+
23
+ class RoleSkillAssignment(models.Model):
24
+ role = models.CharField(max_length=128)
25
+ skill = models.CharField(max_length=160)
26
+ enabled = models.BooleanField(default=True)
27
+ source = models.CharField(max_length=64, default="bootstrap")
28
+
29
+ class Meta:
30
+ unique_together = [("role", "skill")]
31
+ verbose_name = "Role skill assignment"
32
+ verbose_name_plural = "Role skill assignments"
33
+
34
+ def __str__(self) -> str:
35
+ return f"{self.role}: {self.skill}"
36
+
37
+
38
+ class SkillProposal(models.Model):
39
+ proposal_id = models.CharField(max_length=220, unique=True)
40
+ type = models.CharField(max_length=32)
41
+ target = models.CharField(max_length=128)
42
+ skill = models.CharField(max_length=160)
43
+ status = models.CharField(max_length=32, default="proposed")
44
+ approved_by = models.CharField(max_length=128, blank=True)
45
+ execution_sensitive = models.BooleanField(default=False)
46
+ created_at = models.DateTimeField(auto_now_add=True)
47
+ applied_at = models.DateTimeField(null=True, blank=True)
48
+
49
+ class Meta:
50
+ ordering = ["-created_at", "-id"]
51
+ verbose_name = "Skill proposal"
52
+ verbose_name_plural = "Skill proposals"
53
+
54
+ def __str__(self) -> str:
55
+ return self.proposal_id
@@ -0,0 +1,49 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from django.db.models import QuerySet
6
+ from django.utils import timezone
7
+
8
+ from apps.harness.models import RoleSkillAssignment, SkillProposal
9
+
10
+
11
+ def set_role_skill_assignments_enabled(queryset: QuerySet[RoleSkillAssignment], enabled: bool, actor: str = "admin") -> int:
12
+ count = queryset.update(enabled=enabled)
13
+ _audit("role_skill_assignment.enabled" if enabled else "role_skill_assignment.disabled", {"count": count}, actor)
14
+ return count
15
+
16
+
17
+ def approve_skill_proposals(queryset: QuerySet[SkillProposal], actor: str = "admin") -> int:
18
+ count = queryset.update(status="approved", approved_by=actor)
19
+ _audit("skill_proposal.approved", {"count": count}, actor)
20
+ return count
21
+
22
+
23
+ def apply_skill_proposals(queryset: QuerySet[SkillProposal], actor: str = "admin") -> int:
24
+ applied = 0
25
+ for proposal in queryset.filter(status__in=["approved", "proposed"]):
26
+ RoleSkillAssignment.objects.update_or_create(
27
+ role=proposal.target,
28
+ skill=proposal.skill,
29
+ defaults={"enabled": True, "source": f"proposal:{proposal.proposal_id}"},
30
+ )
31
+ proposal.status = "applied"
32
+ proposal.approved_by = proposal.approved_by or actor
33
+ proposal.applied_at = timezone.now()
34
+ proposal.save(update_fields=["status", "approved_by", "applied_at"])
35
+ applied += 1
36
+ _audit("skill_proposal.applied", {"count": applied}, actor)
37
+ return applied
38
+
39
+
40
+ def reject_skill_proposals(queryset: QuerySet[SkillProposal], actor: str = "admin") -> int:
41
+ count = queryset.update(status="rejected")
42
+ _audit("skill_proposal.rejected", {"count": count}, actor)
43
+ return count
44
+
45
+
46
+ def _audit(action: str, payload: dict[str, Any], actor: str) -> None:
47
+ from tradingcodex_service.domain import write_audit_event_if_available
48
+
49
+ write_audit_event_if_available(None, actor, "admin", {"type": action, "payload": payload})
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,111 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from django import template
6
+ from django.urls import NoReverseMatch, reverse
7
+ from django.utils import timezone
8
+
9
+ from tradingcodex_service.domain import tradingcodex_db_path
10
+
11
+
12
+ register = template.Library()
13
+
14
+
15
+ def _count(model: Any, **filters: Any) -> int:
16
+ try:
17
+ return model.objects.filter(**filters).count() if filters else model.objects.count()
18
+ except Exception:
19
+ return 0
20
+
21
+
22
+ def _admin_url(name: str) -> str:
23
+ try:
24
+ return reverse(f"admin:{name}_changelist")
25
+ except NoReverseMatch:
26
+ return "#"
27
+
28
+
29
+ @register.simple_tag
30
+ def tc_admin_overview() -> dict[str, Any]:
31
+ from apps.audit.models import AuditEvent
32
+ from apps.harness.models import SkillProposal, WorkspaceContext
33
+ from apps.integrations.models import AdapterDefinition
34
+ from apps.mcp.models import McpToolCall, McpToolDefinition
35
+ from apps.orders.models import ApprovalReceipt, ExecutionResult, OrderIntent
36
+ from apps.policy.models import PolicyDecision, RestrictedSymbol
37
+ from apps.portfolio.models import PortfolioSnapshot
38
+ from apps.research.models import ResearchArtifact, SourceSnapshot
39
+
40
+ latest_snapshot = PortfolioSnapshot.objects.order_by("-created_at", "-id").first()
41
+ portfolio_payload = latest_snapshot.payload if latest_snapshot and isinstance(latest_snapshot.payload, dict) else {}
42
+ positions = portfolio_payload.get("positions") if isinstance(portfolio_payload.get("positions"), dict) else {}
43
+ cash_krw = portfolio_payload.get("cash_krw")
44
+ if cash_krw is None:
45
+ cash_krw = 0
46
+
47
+ recent_calls = McpToolCall.objects.order_by("-created_at", "-id")[:6]
48
+ recent_audit = AuditEvent.objects.order_by("-created_at", "-id")[:6]
49
+
50
+ return {
51
+ "generated_at": timezone.now(),
52
+ "db_path": str(tradingcodex_db_path()),
53
+ "workspace_count": _count(WorkspaceContext),
54
+ "research_count": _count(ResearchArtifact),
55
+ "source_snapshot_count": _count(SourceSnapshot),
56
+ "pending_skill_proposals": _count(SkillProposal, status="proposed"),
57
+ "draft_orders": _count(OrderIntent),
58
+ "valid_approvals": _count(ApprovalReceipt, valid=True),
59
+ "executions": _count(ExecutionResult),
60
+ "policy_denies": _count(PolicyDecision, decision="deny"),
61
+ "restricted_symbols": _count(RestrictedSymbol, active=True),
62
+ "mcp_tools_enabled": _count(McpToolDefinition, enabled=True),
63
+ "mcp_tools_total": _count(McpToolDefinition),
64
+ "mcp_errors": _count(McpToolCall, status="error"),
65
+ "adapters_enabled": _count(AdapterDefinition, enabled=True),
66
+ "live_adapters_enabled": _count(AdapterDefinition, enabled=True, live=True),
67
+ "cash_krw": cash_krw,
68
+ "positions_count": len(positions),
69
+ "latest_snapshot": latest_snapshot,
70
+ "recent_calls": recent_calls,
71
+ "recent_audit": recent_audit,
72
+ "quick_links": [
73
+ {"label": "Research Memory", "url": _admin_url("research_researchartifact"), "kind": "Research"},
74
+ {"label": "Order Intents", "url": _admin_url("orders_orderintent"), "kind": "Orders"},
75
+ {"label": "Approvals", "url": _admin_url("orders_approvalreceipt"), "kind": "Risk"},
76
+ {"label": "Executions", "url": _admin_url("orders_executionresult"), "kind": "Execution"},
77
+ {"label": "Paper Portfolio", "url": _admin_url("portfolio_portfoliosnapshot"), "kind": "Portfolio"},
78
+ {"label": "MCP Calls", "url": _admin_url("mcp_mcptoolcall"), "kind": "MCP"},
79
+ {"label": "Audit Events", "url": _admin_url("audit_auditevent"), "kind": "Audit"},
80
+ {"label": "Workspace Contexts", "url": _admin_url("harness_workspacecontext"), "kind": "Harness"},
81
+ ],
82
+ }
83
+
84
+
85
+ @register.filter
86
+ def tc_app_purpose(app_label: str) -> str:
87
+ return {
88
+ "auth": "Admin users, groups, and staff access.",
89
+ "harness": "Workspace provenance, role skills, and skill proposals.",
90
+ "research": "DB-canonical markdown research, source snapshots, and evidence packs.",
91
+ "orders": "Order intents, approval receipts, and paper/stub execution results.",
92
+ "portfolio": "Central paper portfolio snapshots, cash, and positions.",
93
+ "policy": "Principals, capability allowlists, restricted list, and policy decisions.",
94
+ "mcp": "Tool registry and MCP call ledger.",
95
+ "audit": "Append-only operational and policy event history.",
96
+ "integrations": "Read-only data and execution adapter definitions.",
97
+ "universes": "Enabled investment universe plugins and defaults.",
98
+ "workflows": "Workflow runs, handoffs, readiness labels, and artifacts.",
99
+ }.get(app_label, "Operational records and configuration.")
100
+
101
+
102
+ @register.filter
103
+ def tc_status_class(value: Any) -> str:
104
+ text = str(value).lower()
105
+ if text in {"ok", "allow", "accepted", "approved", "enabled", "filled", "valid", "true"}:
106
+ return "tc-status-good"
107
+ if text in {"deny", "denied", "rejected", "error", "blocked", "disabled", "false"}:
108
+ return "tc-status-bad"
109
+ if text in {"proposed", "pending", "recorded", "stubbed", "research-only"}:
110
+ return "tc-status-warn"
111
+ return "tc-status-neutral"
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,24 @@
1
+ from django.contrib import admin
2
+
3
+ from apps.integrations.models import AdapterDefinition
4
+ from apps.integrations.services import disable_adapters, disable_live_adapters, enable_non_live_adapters
5
+
6
+
7
+ @admin.register(AdapterDefinition)
8
+ class AdapterDefinitionAdmin(admin.ModelAdmin):
9
+ list_display = ("adapter_id", "kind", "enabled", "live")
10
+ list_filter = ("enabled", "live", "kind")
11
+ search_fields = ("adapter_id", "kind")
12
+ actions = ["enable_non_live_adapters", "disable_adapters", "disable_live_adapters"]
13
+
14
+ @admin.action(description="Enable selected non-live adapters")
15
+ def enable_non_live_adapters(self, request, queryset):
16
+ enable_non_live_adapters(queryset, str(request.user or "admin"))
17
+
18
+ @admin.action(description="Disable selected adapters")
19
+ def disable_adapters(self, request, queryset):
20
+ disable_adapters(queryset, str(request.user or "admin"))
21
+
22
+ @admin.action(description="Disable all selected live adapters")
23
+ def disable_live_adapters(self, request, queryset):
24
+ disable_live_adapters(queryset, str(request.user or "admin"))
@@ -0,0 +1,8 @@
1
+ from django.apps import AppConfig
2
+
3
+
4
+ class IntegrationsConfig(AppConfig):
5
+ default_auto_field = "django.db.models.BigAutoField"
6
+ name = "apps.integrations"
7
+ label = "integrations"
8
+ verbose_name = "Integrations"
@@ -0,0 +1,29 @@
1
+ # Generated by Django 5.2.5 on 2026-06-08 09:49
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ initial = True
9
+
10
+ dependencies = [
11
+ ]
12
+
13
+ operations = [
14
+ migrations.CreateModel(
15
+ name='AdapterDefinition',
16
+ fields=[
17
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
18
+ ('adapter_id', models.CharField(max_length=120, unique=True)),
19
+ ('kind', models.CharField(default='execution', max_length=64)),
20
+ ('enabled', models.BooleanField(default=False)),
21
+ ('live', models.BooleanField(default=False)),
22
+ ('config', models.JSONField(blank=True, default=dict)),
23
+ ],
24
+ options={
25
+ 'verbose_name': 'Adapter definition',
26
+ 'verbose_name_plural': 'Adapter definitions',
27
+ },
28
+ ),
29
+ ]
File without changes
@@ -0,0 +1,16 @@
1
+ from django.db import models
2
+
3
+
4
+ class AdapterDefinition(models.Model):
5
+ adapter_id = models.CharField(max_length=120, unique=True)
6
+ kind = models.CharField(max_length=64, default="execution")
7
+ enabled = models.BooleanField(default=False)
8
+ live = models.BooleanField(default=False)
9
+ config = models.JSONField(default=dict, blank=True)
10
+
11
+ class Meta:
12
+ verbose_name = "Adapter definition"
13
+ verbose_name_plural = "Adapter definitions"
14
+
15
+ def __str__(self) -> str:
16
+ return self.adapter_id
@@ -0,0 +1,31 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from django.db.models import QuerySet
6
+
7
+ from apps.integrations.models import AdapterDefinition
8
+
9
+
10
+ def enable_non_live_adapters(queryset: QuerySet[AdapterDefinition], actor: str = "admin") -> int:
11
+ count = queryset.filter(live=False).update(enabled=True)
12
+ _audit("adapter.enabled_non_live", {"count": count}, actor)
13
+ return count
14
+
15
+
16
+ def disable_adapters(queryset: QuerySet[AdapterDefinition], actor: str = "admin") -> int:
17
+ count = queryset.update(enabled=False)
18
+ _audit("adapter.disabled", {"count": count}, actor)
19
+ return count
20
+
21
+
22
+ def disable_live_adapters(queryset: QuerySet[AdapterDefinition], actor: str = "admin") -> int:
23
+ count = queryset.filter(live=True).update(enabled=False)
24
+ _audit("adapter.live_disabled", {"count": count}, actor)
25
+ return count
26
+
27
+
28
+ def _audit(action: str, payload: dict[str, Any], actor: str) -> None:
29
+ from tradingcodex_service.domain import write_audit_event_if_available
30
+
31
+ write_audit_event_if_available(None, actor, "admin", {"type": action, "payload": payload})
apps/mcp/__init__.py ADDED
@@ -0,0 +1 @@
1
+
apps/mcp/admin.py ADDED
@@ -0,0 +1,33 @@
1
+ from django.contrib import admin
2
+
3
+ from apps.mcp.models import McpToolCall, McpToolDefinition
4
+ from apps.mcp.services import set_mcp_tools_enabled, sync_builtin_mcp_registry
5
+
6
+
7
+ @admin.register(McpToolDefinition)
8
+ class McpToolDefinitionAdmin(admin.ModelAdmin):
9
+ list_display = ("name", "category", "risk_level", "requires_approval", "audit_required", "experimental", "enabled", "updated_at")
10
+ list_filter = ("enabled", "category", "risk_level", "requires_approval", "audit_required", "experimental")
11
+ search_fields = ("name", "description", "capability_required")
12
+ readonly_fields = ("updated_at",)
13
+ actions = ["enable_tools", "disable_tools", "sync_builtin_tools"]
14
+
15
+ @admin.action(description="Enable selected MCP tools")
16
+ def enable_tools(self, request, queryset):
17
+ set_mcp_tools_enabled(queryset, True, str(request.user or "admin"))
18
+
19
+ @admin.action(description="Disable selected MCP tools")
20
+ def disable_tools(self, request, queryset):
21
+ set_mcp_tools_enabled(queryset, False, str(request.user or "admin"))
22
+
23
+ @admin.action(description="Sync built-in MCP tool registry")
24
+ def sync_builtin_tools(self, request, queryset):
25
+ sync_builtin_mcp_registry(str(request.user or "admin"))
26
+
27
+
28
+ @admin.register(McpToolCall)
29
+ class McpToolCallAdmin(admin.ModelAdmin):
30
+ list_display = ("created_at", "tool_name", "principal_id", "status", "duration_ms")
31
+ list_filter = ("tool_name", "status", "principal_id")
32
+ search_fields = ("tool_name", "principal_id", "request_hash", "result_hash", "error")
33
+ readonly_fields = ("created_at", "tool_name", "principal_id", "status", "request", "response", "workspace_context", "request_hash", "result_hash", "error", "duration_ms")
apps/mcp/apps.py ADDED
@@ -0,0 +1,8 @@
1
+ from django.apps import AppConfig
2
+
3
+
4
+ class McpConfig(AppConfig):
5
+ default_auto_field = "django.db.models.BigAutoField"
6
+ name = "apps.mcp"
7
+ label = "mcp"
8
+ verbose_name = "MCP Gateway"