kortext 2.2.3 → 3.0.0

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 (208) hide show
  1. package/AGENTS.md +0 -4
  2. package/CHANGELOG.md +81 -0
  3. package/LICENSE +21 -0
  4. package/README.md +145 -55
  5. package/USER-GUIDE.md +505 -0
  6. package/bin/kortext.js +23 -0
  7. package/bin/kortext.ts +377 -0
  8. package/dist/bin/kortext.js +346 -0
  9. package/dist/bin/kortext.js.map +1 -0
  10. package/dist/mcp/index.js +4 -0
  11. package/dist/mcp/index.js.map +1 -0
  12. package/dist/mcp/server.js +553 -0
  13. package/dist/mcp/server.js.map +1 -0
  14. package/dist/mcp/sse.js +38 -0
  15. package/dist/mcp/sse.js.map +1 -0
  16. package/dist/mcp/stdio.js +44 -0
  17. package/dist/mcp/stdio.js.map +1 -0
  18. package/dist/server/cli/cleanup.js +73 -0
  19. package/dist/server/cli/cleanup.js.map +1 -0
  20. package/dist/server/cli/commands.js +73 -0
  21. package/dist/server/cli/commands.js.map +1 -0
  22. package/dist/server/cli/doctor.js +118 -0
  23. package/dist/server/cli/doctor.js.map +1 -0
  24. package/dist/server/cli/executor-factory.js +39 -0
  25. package/dist/server/cli/executor-factory.js.map +1 -0
  26. package/dist/server/cli/init.js +121 -0
  27. package/dist/server/cli/init.js.map +1 -0
  28. package/dist/server/cli/logs.js +28 -0
  29. package/dist/server/cli/logs.js.map +1 -0
  30. package/dist/server/cli/serve.js +72 -0
  31. package/dist/server/cli/serve.js.map +1 -0
  32. package/dist/server/config/env.js +12 -0
  33. package/dist/server/config/env.js.map +1 -0
  34. package/dist/server/db/client.js +32 -0
  35. package/dist/server/db/client.js.map +1 -0
  36. package/dist/server/db/json.js +21 -0
  37. package/dist/server/db/json.js.map +1 -0
  38. package/dist/server/db/migrate.js +70 -0
  39. package/dist/server/db/migrate.js.map +1 -0
  40. package/dist/server/db/migrations/001_init.sql +243 -0
  41. package/dist/server/db/repositories/audit-log.js +58 -0
  42. package/dist/server/db/repositories/audit-log.js.map +1 -0
  43. package/dist/server/db/repositories/backlog.js +96 -0
  44. package/dist/server/db/repositories/backlog.js.map +1 -0
  45. package/dist/server/db/repositories/contexts.js +54 -0
  46. package/dist/server/db/repositories/contexts.js.map +1 -0
  47. package/dist/server/db/repositories/decisions.js +71 -0
  48. package/dist/server/db/repositories/decisions.js.map +1 -0
  49. package/dist/server/db/repositories/handovers.js +53 -0
  50. package/dist/server/db/repositories/handovers.js.map +1 -0
  51. package/dist/server/db/repositories/index.js +30 -0
  52. package/dist/server/db/repositories/index.js.map +1 -0
  53. package/dist/server/db/repositories/locks.js +59 -0
  54. package/dist/server/db/repositories/locks.js.map +1 -0
  55. package/dist/server/db/repositories/notifications.js +63 -0
  56. package/dist/server/db/repositories/notifications.js.map +1 -0
  57. package/dist/server/db/repositories/pending-questions.js +63 -0
  58. package/dist/server/db/repositories/pending-questions.js.map +1 -0
  59. package/dist/server/db/repositories/runs.js +138 -0
  60. package/dist/server/db/repositories/runs.js.map +1 -0
  61. package/dist/server/db/repositories/runtime-artifacts.js +39 -0
  62. package/dist/server/db/repositories/runtime-artifacts.js.map +1 -0
  63. package/dist/server/db/repositories/secrets.js +65 -0
  64. package/dist/server/db/repositories/secrets.js.map +1 -0
  65. package/dist/server/db/repositories/sessions.js +48 -0
  66. package/dist/server/db/repositories/sessions.js.map +1 -0
  67. package/dist/server/db/schemas.js +308 -0
  68. package/dist/server/db/schemas.js.map +1 -0
  69. package/dist/server/engine/consistency.js +25 -0
  70. package/dist/server/engine/consistency.js.map +1 -0
  71. package/dist/server/engine/dag.js +86 -0
  72. package/dist/server/engine/dag.js.map +1 -0
  73. package/dist/server/engine/executor.js +2 -0
  74. package/dist/server/engine/executor.js.map +1 -0
  75. package/dist/server/engine/executors/claude-cli-executor.js +83 -0
  76. package/dist/server/engine/executors/claude-cli-executor.js.map +1 -0
  77. package/dist/server/engine/executors/cli-spawn.js +127 -0
  78. package/dist/server/engine/executors/cli-spawn.js.map +1 -0
  79. package/dist/server/engine/executors/codex-cli-executor.js +69 -0
  80. package/dist/server/engine/executors/codex-cli-executor.js.map +1 -0
  81. package/dist/server/engine/executors/gemini-cli-executor.js +69 -0
  82. package/dist/server/engine/executors/gemini-cli-executor.js.map +1 -0
  83. package/dist/server/engine/executors/mock-executor.js +52 -0
  84. package/dist/server/engine/executors/mock-executor.js.map +1 -0
  85. package/dist/server/engine/executors/persona-routed-executor.js +17 -0
  86. package/dist/server/engine/executors/persona-routed-executor.js.map +1 -0
  87. package/dist/server/engine/gate-enforcer.js +75 -0
  88. package/dist/server/engine/gate-enforcer.js.map +1 -0
  89. package/dist/server/engine/git-commit.js +42 -0
  90. package/dist/server/engine/git-commit.js.map +1 -0
  91. package/dist/server/engine/handover.js +120 -0
  92. package/dist/server/engine/handover.js.map +1 -0
  93. package/dist/server/engine/item-lifecycle.js +74 -0
  94. package/dist/server/engine/item-lifecycle.js.map +1 -0
  95. package/dist/server/engine/persona-registry.js +108 -0
  96. package/dist/server/engine/persona-registry.js.map +1 -0
  97. package/dist/server/engine/worker-pool.js +324 -0
  98. package/dist/server/engine/worker-pool.js.map +1 -0
  99. package/dist/server/engine/workflow-loader.js +55 -0
  100. package/dist/server/engine/workflow-loader.js.map +1 -0
  101. package/dist/server/engine/workflow-parser.js +158 -0
  102. package/dist/server/engine/workflow-parser.js.map +1 -0
  103. package/dist/server/engine/worktree.js +176 -0
  104. package/dist/server/engine/worktree.js.map +1 -0
  105. package/dist/server/index.js +99 -0
  106. package/dist/server/index.js.map +1 -0
  107. package/dist/server/notifications/dispatcher.js +60 -0
  108. package/dist/server/notifications/dispatcher.js.map +1 -0
  109. package/dist/server/notifications/slack.js +37 -0
  110. package/dist/server/notifications/slack.js.map +1 -0
  111. package/dist/server/notifications/telegram.js +33 -0
  112. package/dist/server/notifications/telegram.js.map +1 -0
  113. package/dist/server/orchestrator/approval-queue.js +83 -0
  114. package/dist/server/orchestrator/approval-queue.js.map +1 -0
  115. package/dist/server/orchestrator/blueprint-watcher.js +94 -0
  116. package/dist/server/orchestrator/blueprint-watcher.js.map +1 -0
  117. package/dist/server/orchestrator/orchestrator.js +283 -0
  118. package/dist/server/orchestrator/orchestrator.js.map +1 -0
  119. package/dist/server/orchestrator/pipeline-chainer.js +96 -0
  120. package/dist/server/orchestrator/pipeline-chainer.js.map +1 -0
  121. package/dist/server/orchestrator/resume.js +36 -0
  122. package/dist/server/orchestrator/resume.js.map +1 -0
  123. package/dist/server/routes/approvals.js +52 -0
  124. package/dist/server/routes/approvals.js.map +1 -0
  125. package/dist/server/routes/backlog.js +44 -0
  126. package/dist/server/routes/backlog.js.map +1 -0
  127. package/dist/server/routes/db-info.js +21 -0
  128. package/dist/server/routes/db-info.js.map +1 -0
  129. package/dist/server/routes/docs.js +70 -0
  130. package/dist/server/routes/docs.js.map +1 -0
  131. package/dist/server/routes/doctor.js +19 -0
  132. package/dist/server/routes/doctor.js.map +1 -0
  133. package/dist/server/routes/handovers.js +25 -0
  134. package/dist/server/routes/handovers.js.map +1 -0
  135. package/dist/server/routes/health.js +11 -0
  136. package/dist/server/routes/health.js.map +1 -0
  137. package/dist/server/routes/personas.js +96 -0
  138. package/dist/server/routes/personas.js.map +1 -0
  139. package/dist/server/routes/runs.js +41 -0
  140. package/dist/server/routes/runs.js.map +1 -0
  141. package/dist/server/routes/workflows.js +38 -0
  142. package/dist/server/routes/workflows.js.map +1 -0
  143. package/dist/server/safety/harmful-output-filter.js +40 -0
  144. package/dist/server/safety/harmful-output-filter.js.map +1 -0
  145. package/dist/server/safety/secret-scanner.js +169 -0
  146. package/dist/server/safety/secret-scanner.js.map +1 -0
  147. package/dist/server/services/markdown-sync.js +101 -0
  148. package/dist/server/services/markdown-sync.js.map +1 -0
  149. package/dist/web/assets/index-B80d5ZPZ.js +75 -0
  150. package/dist/web/assets/index-B80d5ZPZ.js.map +1 -0
  151. package/dist/web/assets/index-Bge5Gzqv.css +1 -0
  152. package/dist/web/index.html +13 -0
  153. package/docs/architecture.md +413 -0
  154. package/package.json +83 -11
  155. package/scripts/copy-migrations.mjs +29 -0
  156. package/workspace/.locks/workspace_handover.md.lock +3 -0
  157. package/hooks/audit-logger.sh +0 -25
  158. package/hooks/auto-locker.sh +0 -74
  159. package/hooks/auto-unlocker.sh +0 -17
  160. package/hooks/backlog-sync-guard.sh +0 -12
  161. package/hooks/branch-guard.sh +0 -32
  162. package/hooks/commit-msg-guard.sh +0 -43
  163. package/hooks/git-pre-commit.sh +0 -76
  164. package/hooks/git-pre-push.sh +0 -17
  165. package/hooks/handover-guard.sh +0 -33
  166. package/hooks/kortext-init.sh +0 -194
  167. package/hooks/kortext-lib.sh +0 -151
  168. package/hooks/lint-guard.sh +0 -50
  169. package/hooks/secret-scanner.sh +0 -89
  170. package/hooks/size-guard.sh +0 -48
  171. package/hooks/snapshot-guard.sh +0 -39
  172. package/hooks/write-guard.sh +0 -77
  173. package/scripts/kortext-backlog-add.py +0 -123
  174. package/scripts/kortext-backlog-health.py +0 -112
  175. package/scripts/kortext-backlog-sync.py +0 -117
  176. package/scripts/kortext-bulk-plan.py +0 -63
  177. package/scripts/kortext-cli.py +0 -376
  178. package/scripts/kortext-consistency-check.py +0 -74
  179. package/scripts/kortext-context-check.py +0 -146
  180. package/scripts/kortext-handover.py +0 -107
  181. package/scripts/kortext-item-check.py +0 -61
  182. package/scripts/kortext-item-start.py +0 -70
  183. package/scripts/kortext-item-transition.py +0 -78
  184. package/scripts/kortext-lock.py +0 -174
  185. package/scripts/kortext-session-start.py +0 -127
  186. package/scripts/lock_kortext.sh +0 -34
  187. package/settings/.claude-settings.template.json +0 -48
  188. package/settings/CHANGELOG.md +0 -176
  189. package/settings/INTEGRATION-MAP.md +0 -276
  190. package/settings/README.md +0 -255
  191. package/settings/USER-GUIDE.md +0 -502
  192. package/settings/VERSION +0 -1
  193. package/settings/config.md +0 -8
  194. package/settings/runtime-adapters.md +0 -104
  195. package/skills/backend-developer/.gitkeep +0 -0
  196. package/skills/compliance-expert/.gitkeep +0 -0
  197. package/skills/copywriter/.gitkeep +0 -0
  198. package/skills/db-admin/.gitkeep +0 -0
  199. package/skills/delivery-manager/.gitkeep +0 -0
  200. package/skills/designer/.gitkeep +0 -0
  201. package/skills/devops-engineer/.gitkeep +0 -0
  202. package/skills/engineering-manager/.gitkeep +0 -0
  203. package/skills/frontend-developer/.gitkeep +0 -0
  204. package/skills/growth-expert/.gitkeep +0 -0
  205. package/skills/operation-manager/.gitkeep +0 -0
  206. package/skills/product-manager/.gitkeep +0 -0
  207. package/skills/qa-engineer/.gitkeep +0 -0
  208. package/skills/security-engineer/.gitkeep +0 -0
@@ -0,0 +1 @@
1
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-ease:initial;--tw-content:""}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:"JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;--color-neutral-100:oklch(97% 0 0);--color-neutral-950:oklch(14.5% 0 0);--color-white:#fff;--spacing:.25rem;--container-sm:24rem;--container-md:28rem;--container-3xl:48rem;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-wider:.05em;--leading-snug:1.375;--radius-md:.375rem;--radius-lg:.5rem;--shadow-sm:0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a;--shadow-md:0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a;--ease-out:cubic-bezier(0, 0, .2, 1);--ease-in-out:cubic-bezier(.4, 0, .2, 1);--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:"JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;--color-success:var(--success)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.top-0\.5{top:calc(var(--spacing) * .5)}.top-1\.5{top:calc(var(--spacing) * 1.5)}.top-9{top:calc(var(--spacing) * 9)}.top-\[var\(--header-h\)\]{top:var(--header-h)}.right-0{right:calc(var(--spacing) * 0)}.right-0\.5{right:calc(var(--spacing) * .5)}.right-1\.5{right:calc(var(--spacing) * 1.5)}.right-4{right:calc(var(--spacing) * 4)}.bottom-12{bottom:calc(var(--spacing) * 12)}.bottom-\[var\(--footer-h\)\]{bottom:var(--footer-h)}.left-\[var\(--sidebar-w\)\]{left:var(--sidebar-w)}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.container{width:100%}@media(min-width:40rem){.container{max-width:40rem}}@media(min-width:48rem){.container{max-width:48rem}}@media(min-width:64rem){.container{max-width:64rem}}@media(min-width:80rem){.container{max-width:80rem}}@media(min-width:96rem){.container{max-width:96rem}}.mx-1{margin-inline:calc(var(--spacing) * 1)}.mx-2{margin-inline:calc(var(--spacing) * 2)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mb-0\.5{margin-bottom:calc(var(--spacing) * .5)}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.ml-1{margin-left:calc(var(--spacing) * 1)}.ml-4{margin-left:calc(var(--spacing) * 4)}.ml-auto{margin-left:auto}.line-clamp-1{-webkit-line-clamp:1;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-flex{display:inline-flex}.table{display:table}.h-3{height:calc(var(--spacing) * 3)}.h-3\.5{height:calc(var(--spacing) * 3.5)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-7{height:calc(var(--spacing) * 7)}.h-8{height:calc(var(--spacing) * 8)}.h-\[38px\]{height:38px}.h-\[280px\]{height:280px}.h-\[var\(--header-h\)\]{height:var(--header-h)}.h-full{height:100%}.h-screen{height:100vh}.max-h-\[360px\]{max-height:360px}.max-h-\[400px\]{max-height:400px}.min-h-0{min-height:calc(var(--spacing) * 0)}.min-h-\[60vh\]{min-height:60vh}.min-h-\[200px\]{min-height:200px}.w-3{width:calc(var(--spacing) * 3)}.w-3\.5{width:calc(var(--spacing) * 3.5)}.w-4{width:calc(var(--spacing) * 4)}.w-8{width:calc(var(--spacing) * 8)}.w-\[340px\]{width:340px}.w-\[360px\]{width:360px}.w-full{width:100%}.w-px{width:1px}.w-screen{width:100vw}.max-w-3xl{max-width:var(--container-3xl)}.max-w-md{max-width:var(--container-md)}.max-w-sm{max-width:var(--container-sm)}.min-w-0{min-width:calc(var(--spacing) * 0)}.flex-1{flex:1}.flex-shrink{flex-shrink:1}.flex-shrink-0{flex-shrink:0}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.cursor-pointer{cursor:pointer}.resize{resize:both}.resize-none{resize:none}.flex-col{flex-direction:column}.flex-row{flex-direction:row}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-5{gap:calc(var(--spacing) * 5)}:where(.space-y-1\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1.5) * calc(1 - var(--tw-space-y-reverse)))}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-border-subtle>:not(:last-child)){border-color:var(--border-subtle)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-r-0{border-right-style:var(--tw-border-style);border-right-width:0}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-l-2{border-left-style:var(--tw-border-style);border-left-width:2px}.border-accent,.border-accent\/30{border-color:var(--accent)}@supports (color:color-mix(in lab,red,red)){.border-accent\/30{border-color:color-mix(in oklab,var(--accent) 30%,transparent)}}.border-border-accent{border-color:var(--border-accent)}.border-border-default{border-color:var(--border-default)}.border-border-subtle{border-color:var(--border-subtle)}.border-danger\/30{border-color:var(--danger)}@supports (color:color-mix(in lab,red,red)){.border-danger\/30{border-color:color-mix(in oklab,var(--danger) 30%,transparent)}}.border-danger\/40{border-color:var(--danger)}@supports (color:color-mix(in lab,red,red)){.border-danger\/40{border-color:color-mix(in oklab,var(--danger) 40%,transparent)}}.border-info\/30{border-color:var(--info)}@supports (color:color-mix(in lab,red,red)){.border-info\/30{border-color:color-mix(in oklab,var(--info) 30%,transparent)}}.border-signal\/30{border-color:var(--signal)}@supports (color:color-mix(in lab,red,red)){.border-signal\/30{border-color:color-mix(in oklab,var(--signal) 30%,transparent)}}.border-transparent{border-color:#0000}.border-warning\/30{border-color:var(--warning)}@supports (color:color-mix(in lab,red,red)){.border-warning\/30{border-color:color-mix(in oklab,var(--warning) 30%,transparent)}}.bg-accent,.bg-accent\/8{background-color:var(--accent)}@supports (color:color-mix(in lab,red,red)){.bg-accent\/8{background-color:color-mix(in oklab,var(--accent) 8%,transparent)}}.bg-bg-0{background-color:var(--bg-0)}.bg-bg-1{background-color:var(--bg-1)}.bg-bg-2{background-color:var(--bg-2)}.bg-bg-3{background-color:var(--bg-3)}.bg-danger{background-color:var(--danger)}.bg-neutral-950{background-color:var(--color-neutral-950)}.bg-transparent{background-color:#0000}.bg-white\/10{background-color:#ffffff1a}@supports (color:color-mix(in lab,red,red)){.bg-white\/10{background-color:color-mix(in oklab,var(--color-white) 10%,transparent)}}.p-2{padding:calc(var(--spacing) * 2)}.p-6{padding:calc(var(--spacing) * 6)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-3\.5{padding-block:calc(var(--spacing) * 3.5)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-5{padding-block:calc(var(--spacing) * 5)}.py-6{padding-block:calc(var(--spacing) * 6)}.pl-5{padding-left:calc(var(--spacing) * 5)}.text-left{text-align:left}.text-right{text-align:right}.font-mono{font-family:JetBrains Mono,ui-monospace,SF Mono,Menlo,Consolas,monospace}.text-\[9px\]{font-size:9px}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[12px\]{font-size:12px}.text-\[13px\]{font-size:13px}.text-\[14px\]{font-size:14px}.text-\[20px\]{font-size:20px}.leading-\[1\.6\]{--tw-leading:1.6;line-height:1.6}.leading-\[1\.55\]{--tw-leading:1.55;line-height:1.55}.leading-\[1\.65\]{--tw-leading:1.65;line-height:1.65}.leading-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[0\.10em\]{--tw-tracking:.1em;letter-spacing:.1em}.tracking-\[0\.12em\]{--tw-tracking:.12em;letter-spacing:.12em}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.whitespace-nowrap{white-space:nowrap}.text-accent{color:var(--accent)}.text-accent-soft{color:var(--accent-soft)}.text-bg-0{color:var(--bg-0)}.text-danger{color:var(--danger)}.text-info{color:var(--info)}.text-neutral-100{color:var(--color-neutral-100)}.text-prime{color:var(--prime)}.text-signal{color:var(--signal)}.text-signal-soft{color:var(--signal-soft)}.text-success{color:var(--success)}.text-tx-1{color:var(--tx-1)}.text-tx-2{color:var(--tx-2)}.text-tx-3{color:var(--tx-3)}.text-tx-disabled{color:var(--tx-disabled)}.text-warning{color:var(--warning)}.text-white{color:var(--color-white)}.capitalize{text-transform:capitalize}.uppercase{text-transform:uppercase}.underline{text-decoration-line:underline}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.blur{--tw-blur:blur(8px);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.backdrop-filter{-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-200{--tw-duration:.2s;transition-duration:.2s}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.ease-out{--tw-ease:var(--ease-out);transition-timing-function:var(--ease-out)}.outline-none{--tw-outline-style:none;outline-style:none}.before\:absolute:before{content:var(--tw-content);position:absolute}.before\:top-2:before{content:var(--tw-content);top:calc(var(--spacing) * 2)}.before\:bottom-2:before{content:var(--tw-content);bottom:calc(var(--spacing) * 2)}.before\:left-0:before{content:var(--tw-content);left:calc(var(--spacing) * 0)}.before\:w-\[2px\]:before{content:var(--tw-content);width:2px}.before\:rounded-r:before{content:var(--tw-content);border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.before\:bg-accent:before{content:var(--tw-content);background-color:var(--accent)}@media(hover:hover){.hover\:border-accent\/40:hover{border-color:var(--accent)}@supports (color:color-mix(in lab,red,red)){.hover\:border-accent\/40:hover{border-color:color-mix(in oklab,var(--accent) 40%,transparent)}}.hover\:border-border-default:hover{border-color:var(--border-default)}.hover\:bg-accent-soft:hover{background-color:var(--accent-soft)}.hover\:bg-bg-2:hover{background-color:var(--bg-2)}.hover\:text-tx-1:hover{color:var(--tx-1)}}.focus\:bg-bg-0:focus{background-color:var(--bg-0)}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-40:disabled{opacity:.4}}:root{--bg-0:#0a0814;--bg-1:#14101f;--bg-2:#1e1830;--bg-3:#2a2240;--bg-overlay:#0a0814bf;--tx-1:#fafafc;--tx-2:#b5b0c2;--tx-3:#6b6577;--tx-disabled:#3f3b4f;--accent:#a855f7;--accent-soft:#c084fc;--accent-deep:#7c3aed;--accent-glow:#a855f740;--signal:#ec4899;--signal-soft:#f472b6;--signal-glow:#ec489933;--success:#10b981;--warning:#f59e0b;--danger:#ef4444;--info:#3b82f6;--border-subtle:#ffffff0d;--border-default:#ffffff1a;--border-accent:#a855f74d;--border-strong:#ffffff2e;--prime:#f59e0b;--sidebar-w:220px;--header-h:48px;--footer-h:32px}html,body,#root{height:100%}body{background:var(--bg-0);color:var(--tx-1);-webkit-font-smoothing:antialiased;margin:0;font-family:-apple-system,BlinkMacSystemFont,Inter,Segoe UI,Roboto,sans-serif;font-size:13px;line-height:1.5}.mono{font-family:var(--font-mono)}.dot{border-radius:50%;flex-shrink:0;width:6px;height:6px;display:inline-block}.dot-success{background:var(--success)}.dot-warning{background:var(--warning)}.dot-danger{background:var(--danger)}.dot-info{background:var(--info)}.dot-accent{background:var(--accent)}.dot-signal{background:var(--signal)}.dot-muted{background:var(--tx-3)}@keyframes signal-pulse{0%,to{opacity:1}50%{opacity:.5}}.dot-pulse{animation:1.6s ease-in-out infinite signal-pulse}@keyframes toast-in{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.animate-toast-in{animation:.22s ease-out toast-in}.prose-markdown h1{color:var(--tx-1);letter-spacing:-.01em;margin:.6em 0 .4em;font-size:22px;font-weight:600}.prose-markdown h2{color:var(--tx-1);margin:1.4em 0 .4em;font-size:17px;font-weight:600}.prose-markdown h3{color:var(--tx-2);text-transform:uppercase;letter-spacing:.06em;margin:1.2em 0 .4em;font-size:14px;font-weight:600}.prose-markdown h4{color:var(--tx-2);margin:1em 0 .3em;font-size:13px;font-weight:600}.prose-markdown p{color:var(--tx-2);margin:.6em 0}.prose-markdown ul,.prose-markdown ol{color:var(--tx-2);margin:.6em 0 .6em 1.4em}.prose-markdown li{margin:.25em 0}.prose-markdown a{color:var(--accent-soft);text-underline-offset:2px;text-decoration:underline}.prose-markdown a:hover{color:var(--accent)}.prose-markdown code{font-family:var(--font-mono);background:var(--bg-2);border:1px solid var(--border-subtle);color:var(--tx-1);border-radius:4px;padding:.08em .35em;font-size:.92em}.prose-markdown pre{background:var(--bg-2);border:1px solid var(--border-subtle);border-radius:6px;margin:.8em 0;padding:12px 14px;overflow-x:auto}.prose-markdown pre code{background:0 0;border:none;padding:0;font-size:12px;line-height:1.55}.prose-markdown blockquote{border-left:2px solid var(--accent);color:var(--tx-3);margin:.8em 0;padding-left:12px}.prose-markdown hr{border:0;border-top:1px solid var(--border-subtle);margin:1.4em 0}.prose-markdown table{border-collapse:collapse;width:100%;margin:.8em 0;font-size:12px}.prose-markdown th,.prose-markdown td{border:1px solid var(--border-subtle);text-align:left;padding:6px 10px}.prose-markdown th{background:var(--bg-2);color:var(--tx-1)}.prose-markdown img{border-radius:6px;max-width:100%}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@property --tw-content{syntax:"*";inherits:false;initial-value:""}
@@ -0,0 +1,13 @@
1
+ <!doctype html>
2
+ <html lang="tr" class="dark">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Kortext</title>
7
+ <script type="module" crossorigin src="/assets/index-B80d5ZPZ.js"></script>
8
+ <link rel="stylesheet" crossorigin href="/assets/index-Bge5Gzqv.css">
9
+ </head>
10
+ <body class="bg-neutral-950 text-neutral-100 antialiased">
11
+ <div id="root"></div>
12
+ </body>
13
+ </html>
@@ -0,0 +1,413 @@
1
+ # Kortext v3 — Architecture
2
+
3
+ This document describes the runtime architecture of Kortext v3. It is meant
4
+ for developers contributing to Kortext or integrating against it. For an
5
+ end-user walkthrough, see [USER-GUIDE.md](../USER-GUIDE.md).
6
+
7
+ ## Layers at a glance
8
+
9
+ ```mermaid
10
+ flowchart TB
11
+ subgraph Clients["Clients"]
12
+ Dashboard["React Dashboard<br/>Vite + TanStack Router"]
13
+ ClaudeCode["Claude Code / Cursor<br/>(MCP stdio)"]
14
+ SSE["Remote MCP client<br/>(SSE)"]
15
+ CLI["kortext CLI"]
16
+ end
17
+
18
+ subgraph Backend["Express 5 backend (one process)"]
19
+ REST["REST API<br/>/api/*"]
20
+ MCPSSE["MCP /mcp/sse + /mcp/messages"]
21
+ MCPStdio["MCP stdio entry"]
22
+ end
23
+
24
+ subgraph Core["Core runtime"]
25
+ Orchestrator["Orchestrator<br/>watcher · chainer · queue · dispatcher"]
26
+ Engine["Pipeline engine<br/>parser · DAG · worker pool · gate · safety"]
27
+ Executors["CLI executors<br/>Claude · Codex · Gemini · Mock"]
28
+ end
29
+
30
+ subgraph State["State"]
31
+ SQLite[("SQLite<br/>.kortext/kortext.db")]
32
+ Worktrees[(".kortext/worktrees/<br/>per-run git worktrees")]
33
+ Markdown[("agents/ workflows/ rules/<br/>workspace/references/")]
34
+ end
35
+
36
+ Dashboard --> REST
37
+ CLI --> Backend
38
+ SSE --> MCPSSE
39
+ ClaudeCode --> MCPStdio
40
+
41
+ REST --> Orchestrator
42
+ MCPSSE --> Orchestrator
43
+ MCPStdio --> Orchestrator
44
+
45
+ Orchestrator --> Engine
46
+ Engine --> Executors
47
+ Engine --> SQLite
48
+ Engine --> Worktrees
49
+ Orchestrator --> SQLite
50
+ Orchestrator --> Markdown
51
+ ```
52
+
53
+ Single Node process. The MCP stdio entry is a separate process (one per
54
+ host CLI) that shares the factory and dependencies but mounts its own
55
+ transport.
56
+
57
+ ## Data layer
58
+
59
+ ### Hybrid: markdown + SQLite
60
+
61
+ | What | Where | Why |
62
+ |---|---|---|
63
+ | Blueprint, ADRs, references | `workspace/references/*.md` | Human authoring; long-form |
64
+ | Personas | `agents/*.md` | Human-editable; hot-reloaded |
65
+ | Workflows | `workflows/*.md` | Human-readable DAGs |
66
+ | Rules | `rules/*.md` | Human-readable; loaded into prompts |
67
+ | Backlog | SQLite `backlog_items` | Frequent state changes; relational |
68
+ | Runs / steps | SQLite `runs`, `run_steps` | Time-series; queried by status |
69
+ | Approvals | SQLite `pending_questions` | First-class lifecycle |
70
+ | Audit | SQLite `audit_log` | Append-only; queried by actor/action |
71
+ | Generated artifacts | Disk + SQLite index | Disk for history, index for search |
72
+
73
+ Two principles:
74
+
75
+ - **Human sources are read-only to the engine.** Personas and workflows
76
+ are parsed in memory; the engine never writes them back.
77
+ - **Generated markdown gets an index row** in `runtime_artifacts` so the
78
+ dashboard can find it without scanning the filesystem.
79
+
80
+ ### SQLite schema (13 tables)
81
+
82
+ ```mermaid
83
+ erDiagram
84
+ backlog_items ||--o{ runs : "item_id"
85
+ backlog_items ||--o{ contexts : "item_id"
86
+ backlog_items }o--|| backlog_items : "parent_id"
87
+ sessions ||--o{ contexts : "session_id"
88
+ runs ||--o{ run_steps : "run_id"
89
+ runs ||--o{ runtime_artifacts : "run_id"
90
+ runs ||--o{ pending_questions : "run_id"
91
+ runs ||--o{ secrets_scan_results : "run_id"
92
+ handovers ||--o| backlog_items : "item_id"
93
+ decisions_index ||--o| backlog_items : "item_id"
94
+ notifications_sent }o--|| pending_questions : "question_id"
95
+ ```
96
+
97
+ Specifics worth knowing:
98
+
99
+ - **All timestamps are `INTEGER` Unix milliseconds.** Read with
100
+ `new Date(ms)` on the dashboard side.
101
+ - **All JSON columns are `TEXT`** plus json1 access. Helpers in
102
+ `server/db/json.ts` parse on read and serialize on write.
103
+ - **WAL mode is on.** Required because the dashboard polls every 3 seconds
104
+ while the engine writes step status concurrently.
105
+ - **Foreign keys are enforced.** `PRAGMA foreign_keys = ON` is set in
106
+ `server/db/client.ts`.
107
+ - **Migrations** live in `server/db/migrations/*.sql` and run on first DB
108
+ open. `npm run build:server` copies them into `dist/server/db/migrations/`
109
+ so installed packages can boot from scratch.
110
+
111
+ ## Engine
112
+
113
+ ```mermaid
114
+ flowchart LR
115
+ md["workflows/*.md"] --> parser["workflow-parser.ts"]
116
+ parser --> dag["dag.ts<br/>(Kahn-style)"]
117
+ dag --> pool["worker-pool.ts<br/>concurrency 3 (configurable)"]
118
+ pool --> exec["executor.ts<br/>(interface)"]
119
+ exec --> claude["claude-cli-executor"]
120
+ exec --> codex["codex-cli-executor"]
121
+ exec --> gemini["gemini-cli-executor"]
122
+ exec --> mock["mock-executor"]
123
+
124
+ pool --> wt["worktree.ts<br/>(per-run isolation)"]
125
+ pool --> gate["gate-enforcer.ts<br/>(pre + barrier)"]
126
+ pool --> safety["secret-scanner.ts<br/>harmful-output-filter.ts"]
127
+ ```
128
+
129
+ ### Workflow parsing
130
+
131
+ `workflow-parser.ts` reads YAML frontmatter (`id`, `nextWorkflowId`, `gates`)
132
+ and the `## Steps` section. Each `### step_name` block becomes a typed
133
+ step with `persona`, `inputs`, `outputs`, optional `gate`. The parser is
134
+ intentionally minimal — full YAML is not required.
135
+
136
+ ### DAG construction
137
+
138
+ `dag.ts` walks every step and matches each `inputs[]` entry against
139
+ **`outputs[]`** from earlier steps. A step depends on the step that
140
+ produces its inputs. Inputs that no step produces are flagged as
141
+ `externalInputs` — these get checked by the gate enforcer.
142
+
143
+ Kahn-style topological sort detects cycles. Cycle = workflow rejected at
144
+ load time, never reaches the runtime.
145
+
146
+ ### Worker pool
147
+
148
+ `worker-pool.ts` is a **pull-ready scheduler**, not a topological queue:
149
+
150
+ 1. Initial ready set = nodes with zero dependencies.
151
+ 2. Up to `concurrency` workers are spawned (default 3, configurable per run).
152
+ 3. Each worker pulls one ready step, executes it, marks it `succeeded` /
153
+ `failed`, and re-evaluates the ready set.
154
+ 4. On first `failed`, an `AbortController` cancels in-flight steps and the
155
+ remaining graph is marked `skipped`.
156
+ 5. Gates pause the pool via a `gateController.pauseAtGate` barrier; resume
157
+ re-enters the same pool with the gate decision in hand.
158
+
159
+ ### Gate enforcement
160
+
161
+ Two kinds of gate:
162
+
163
+ - **Pre-gate (`externalInputs`):** the workflow declares external inputs
164
+ (e.g. `blueprint.md`); the enforcer checks each one's frontmatter has
165
+ `status: approved` before the run starts.
166
+ - **Mid-run barrier (`gate: true`):** the worker pool halts after the step
167
+ completes, writes a row to `pending_questions`, and waits for an
168
+ `approval-queue` decision.
169
+
170
+ A rejected gate flips the run to `cancelled` with
171
+ `error_message: rejected: <reason>` and quarantines the worktree.
172
+
173
+ ### Per-run worktrees
174
+
175
+ `worktree.ts` calls `git worktree add .kortext/worktrees/run-<id>` on a
176
+ branch named `kortext/run-<id>`. The namespace prevents collisions with
177
+ your own branches.
178
+
179
+ On success the engine can merge into the source branch and remove the
180
+ worktree (off by default). On failure the worktree is moved to
181
+ `.kortext/worktrees/quarantine/run-<id>-<timestamp>/` and the branch is
182
+ preserved.
183
+
184
+ `kortext cleanup --quarantine-older-than=Nd --branches` removes quarantined
185
+ worktrees and the matching branches after they age out.
186
+
187
+ ### Output safety
188
+
189
+ After each successful step the engine runs:
190
+
191
+ - **Secret scanner** — four pattern groups (quoted assignment, env
192
+ assignment, service token, auth header) with allow-listed exceptions
193
+ (`process.env`, `YOUR_…`, `PLACEHOLDER`, `.env*`). Findings flip the step
194
+ to `failed` with a masked snippet recorded in `secrets_scan_results`.
195
+ - **Harmful-output filter** — configurable banned-phrase list. The v3.0
196
+ implementation is a placeholder; a content-policy pass lands in v3.1+.
197
+
198
+ ## Orchestrator
199
+
200
+ ```mermaid
201
+ sequenceDiagram
202
+ participant File as blueprint.md
203
+ participant W as BlueprintWatcher
204
+ participant O as Orchestrator
205
+ participant C as PipelineChainer
206
+ participant E as Engine
207
+ participant Q as ApprovalQueue
208
+ participant D as Dispatcher
209
+ participant N as Slack/Telegram
210
+
211
+ File->>W: status: draft → approved
212
+ W->>O: triggerWorkflow(analysis, blueprint)
213
+ O->>E: runWorkflow(graph, executor)
214
+ E-->>Q: gate barrier (step k)
215
+ Q-->>D: notify(question)
216
+ D->>N: post
217
+ Note over Q: waits...
218
+ Q->>E: decision: approve
219
+ E-->>O: workflow complete
220
+ O->>C: chain(nextWorkflowId)
221
+ C->>O: triggerWorkflow(planning)
222
+ ```
223
+
224
+ ### Pipeline chainer
225
+
226
+ `pipeline-chainer.ts` reads the completed workflow's `nextWorkflowId` and
227
+ triggers the next run with the same item context. Chain breaks if
228
+ `nextWorkflowId` is missing or the previous run is in a terminal-failed
229
+ state.
230
+
231
+ ### Approval queue
232
+
233
+ `approval-queue.ts` writes a `pending_questions` row, notifies, and exposes
234
+ three REST endpoints:
235
+
236
+ - `GET /api/questions` — list open
237
+ - `POST /api/questions/:id/answer` — resolve with `{ decision, reason? }`
238
+ - `POST /api/runs/:runId/approve` — sugar for resolving the most recent
239
+ open question on a run
240
+
241
+ The same surface is exposed via MCP (`list_pending_questions`,
242
+ `respond_to_question`).
243
+
244
+ ### Notification dispatcher
245
+
246
+ `notifications/dispatcher.ts` fans out to `slack.ts` and `telegram.ts`,
247
+ deduplicated by `(channel, kind, resource_id)` and recorded in
248
+ `notifications_sent`. Restarting the runtime never replays old events.
249
+
250
+ ### Resume semantics
251
+
252
+ `resume.ts` runs on server boot. Any row in `runs` with `status: running`
253
+ is reclassified to `cancelled` with `error_message: orphaned: server
254
+ restarted`. `orchestrator.retryRun(runId)` can pick orphaned runs up from
255
+ their last persisted gate (pre-completed gates are replayed in order).
256
+
257
+ ## MCP server
258
+
259
+ ```mermaid
260
+ flowchart LR
261
+ factory["createKortextMcpServer(deps)"] --> tools["15 tools<br/>(zod schemas)"]
262
+ factory --> stdio["mcp/stdio.ts<br/>(CLI entry)"]
263
+ factory --> sse["mcp/sse.ts<br/>(Express hook)"]
264
+ sse --> session1["new McpServer<br/>per GET /mcp/sse"]
265
+ sse --> session2["..."]
266
+ ```
267
+
268
+ Key decisions:
269
+
270
+ - **Factory + injectable deps.** Tests, stdio, and SSE all call the same
271
+ factory with mocked or real dependencies (db, orchestrator,
272
+ registries).
273
+ - **SSE per-session McpServer instance.** The MCP SDK ties handler state
274
+ to the transport; multiplexing one server across two transports leaks
275
+ state. `mcp/sse.ts` creates a fresh `McpServer` per `GET /mcp/sse`,
276
+ keys a `transports` map by `sessionId`, and cleans up on `onclose`.
277
+ - **Stdio console patch.** Stdout is the JSONRPC channel. `bin/kortext.ts
278
+ mcp` re-routes `console.log` → `console.error` at startup. New modules
279
+ must default to `console.error` for any logging.
280
+ - **Tool envelope = JSON text + structuredContent.** Every tool returns
281
+ `{ content: [{type:'text', text: JSON.stringify(...)}], structuredContent }`
282
+ so old clients see text frames and new clients get structured payloads.
283
+
284
+ The 15 tools:
285
+
286
+ | Group | Tools |
287
+ |---|---|
288
+ | Workflow | `list_workflows`, `list_personas`, `list_pipelines`, `get_pipeline`, `start_pipeline` |
289
+ | Backlog | `list_backlog`, `add_backlog_item`, `transition_item` |
290
+ | Approval | `list_pending_questions`, `respond_to_question` |
291
+ | Context | `get_context`, `handover`, `get_logs` |
292
+ | Blueprint | `read_blueprint`, `approve_blueprint` |
293
+ | Health | `get_runtime_status` |
294
+
295
+ ## Dashboard
296
+
297
+ ```mermaid
298
+ flowchart LR
299
+ subgraph Routes["TanStack Router (hash history)"]
300
+ D["/"]
301
+ B["/board"]
302
+ M["/memory"]
303
+ Rp["/reports"]
304
+ Rf["/references"]
305
+ S["/settings/*"]
306
+ end
307
+
308
+ subgraph Overlays["Global overlays"]
309
+ Bell["BellMenu"]
310
+ Toast["Toasts"]
311
+ Term["TerminalPanel"]
312
+ Time["TimelinePanel"]
313
+ end
314
+
315
+ subgraph Stores["Context fan-out"]
316
+ PQ["PendingQuestionsProvider<br/>poll 3s"]
317
+ Shell["shell-store"]
318
+ end
319
+
320
+ PQ --> Bell
321
+ PQ --> Toast
322
+ Shell --> Term
323
+ Shell --> Time
324
+ ```
325
+
326
+ Implementation notes:
327
+
328
+ - **Hash history** so the Express side never needs an SPA fallback. Static
329
+ `dist/web` serves the bundle from any subpath.
330
+ - **Tailwind v4 `@theme inline` + CSS variables.** Palette tokens are a
331
+ single source — both `var(--accent)` and `bg-accent` work.
332
+ - **API type mirror.** `src/lib/api-types.ts` hand-mirrors server response
333
+ shapes so the frontend bundle never picks up transitive
334
+ `better-sqlite3`.
335
+ - **Allow-listed `/api/docs/:scope`.** Five scopes
336
+ (`references | reports | memory | rules | workflows`). `path.resolve` +
337
+ prefix check blocks traversal.
338
+ - **Marked + DOMPurify.** Every markdown render is sanitized.
339
+ - **Single polling source.** `PendingQuestionsProvider` is the only thing
340
+ hitting `/api/questions`; the bell, toast emitter, and dashboard card
341
+ all subscribe.
342
+
343
+ ## CLI
344
+
345
+ ```
346
+ bin/kortext.js (dual-mode shim)
347
+ ├── dist/bin/kortext.js exists? → in-process import (fast)
348
+ └── otherwise → spawn `tsx bin/kortext.ts` (dev)
349
+
350
+ bin/kortext.ts
351
+ ├── --version / --help (top-level)
352
+ ├── init → server/cli/init.ts (pure: scaffold plan)
353
+ ├── serve → server/cli/serve.ts (pure: buildServeCommands)
354
+ ├── start → server/cli/commands.ts (orchestrator)
355
+ ├── approve → server/cli/commands.ts
356
+ ├── status → server/cli/commands.ts
357
+ ├── logs → server/cli/logs.ts (pure: query plan)
358
+ ├── cleanup → server/cli/cleanup.ts
359
+ ├── doctor → server/engine/consistency.ts
360
+ └── mcp → mcp/stdio.ts
361
+ ```
362
+
363
+ Command modules under `server/cli/` are **pure** — they never call
364
+ `console.*`. The bin layer formats data and owns stdout/stderr. This is
365
+ what makes the CLI unit-testable without spawning processes.
366
+
367
+ ## CI
368
+
369
+ ```mermaid
370
+ flowchart LR
371
+ push["push / PR to main"] --> co["checkout@v4"]
372
+ co --> sn["setup-node@v4<br/>Node 22 · npm cache"]
373
+ sn --> ci["npm ci"]
374
+ ci --> lint["npm run lint"]
375
+ lint --> tc["npm run typecheck"]
376
+ tc --> test["npm test (263)"]
377
+ test --> build["npm run build"]
378
+ build --> smoke["node dist/bin/kortext.js --version"]
379
+ ```
380
+
381
+ `cancel-in-progress: true` on the workflow concurrency group supersedes
382
+ older runs for the same ref. The compiled-CLI smoke is the gate that
383
+ caught the `packageRoot()` walk-up bug — installed users always see the
384
+ fast `dist/` path, so the version-reporting bug would have shipped
385
+ otherwise.
386
+
387
+ ## Where to look in the codebase
388
+
389
+ | Concern | File |
390
+ |---|---|
391
+ | Schema | `server/db/migrations/001_init.sql` |
392
+ | DB client | `server/db/client.ts` |
393
+ | Repositories | `server/db/repositories/*.ts` |
394
+ | Workflow parsing | `server/engine/workflow-parser.ts` |
395
+ | DAG construction | `server/engine/dag.ts` |
396
+ | Worker pool | `server/engine/worker-pool.ts` |
397
+ | Worktree manager | `server/engine/worktree.ts` |
398
+ | Gate enforcer | `server/engine/gate-enforcer.ts` |
399
+ | Output safety | `server/safety/secret-scanner.ts`, `server/safety/harmful-output-filter.ts` |
400
+ | Orchestrator | `server/orchestrator/orchestrator.ts` |
401
+ | Blueprint watcher | `server/orchestrator/blueprint-watcher.ts` |
402
+ | Pipeline chainer | `server/orchestrator/pipeline-chainer.ts` |
403
+ | Approval queue | `server/orchestrator/approval-queue.ts` |
404
+ | Notifications | `server/notifications/{dispatcher,slack,telegram}.ts` |
405
+ | MCP factory | `mcp/server.ts` |
406
+ | MCP stdio | `mcp/stdio.ts` |
407
+ | MCP SSE | `mcp/sse.ts` |
408
+ | CLI bin | `bin/kortext.ts`, `bin/kortext.js` |
409
+ | Dashboard | `src/router.tsx`, `src/routes/*`, `src/components/*` |
410
+
411
+ For day-to-day operations see [USER-GUIDE.md](../USER-GUIDE.md). Internal
412
+ project history (phase-by-phase roadmap, handover bootstrap, contributor
413
+ guidelines) lives under [docs/internal/](./internal/).
package/package.json CHANGED
@@ -1,29 +1,101 @@
1
1
  {
2
2
  "name": "kortext",
3
- "version": "2.2.3",
4
- "description": "AI Agent Framework for Operational Discipline and Automated Project Management",
5
- "main": "index.js",
3
+ "version": "3.0.0",
4
+ "description": "Autonomous AI agent runtime TypeScript + SQLite + React",
5
+ "type": "module",
6
+ "private": false,
6
7
  "bin": {
7
- "kortext": "scripts/kortext-cli.py"
8
+ "kortext": "./bin/kortext.js"
9
+ },
10
+ "files": [
11
+ "bin/",
12
+ "dist/",
13
+ "agents/",
14
+ "workflows/",
15
+ "rules/",
16
+ "workspace/",
17
+ "scripts/",
18
+ "AGENTS.md",
19
+ "CHANGELOG.md",
20
+ "USER-GUIDE.md",
21
+ "docs/architecture.md",
22
+ "LICENSE"
23
+ ],
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "git+https://github.com/erayendes/kortext.git"
27
+ },
28
+ "homepage": "https://github.com/erayendes/kortext#readme",
29
+ "bugs": {
30
+ "url": "https://github.com/erayendes/kortext/issues"
8
31
  },
9
32
  "scripts": {
10
- "test": "python3 scripts/kortext-consistency-check.py",
11
- "check": "python3 scripts/kortext-context-check.py",
12
- "health": "python3 scripts/kortext-backlog-health.py"
33
+ "dev": "concurrently -n server,web -c blue,magenta \"npm:dev:server\" \"npm:dev:web\"",
34
+ "dev:server": "tsx watch --clear-screen=false server/index.ts",
35
+ "dev:web": "vite",
36
+ "build": "npm run build:server && npm run build:web",
37
+ "build:server": "tsc -p tsconfig.build.json && node scripts/copy-migrations.mjs",
38
+ "build:web": "vite build",
39
+ "preview": "vite preview",
40
+ "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.server.json --noEmit",
41
+ "lint": "eslint .",
42
+ "format": "prettier --write .",
43
+ "format:check": "prettier --check .",
44
+ "test": "vitest run",
45
+ "test:watch": "vitest"
13
46
  },
14
47
  "keywords": [
15
48
  "ai",
16
49
  "agent",
17
50
  "framework",
18
51
  "automation",
19
- "project-management",
52
+ "claude",
53
+ "codex",
20
54
  "gemini",
21
- "claude"
55
+ "mcp",
56
+ "orchestration"
22
57
  ],
23
58
  "author": "Eray Endes",
24
59
  "license": "MIT",
25
60
  "engines": {
26
- "node": ">=14.0.0",
27
- "python": ">=3.10.0"
61
+ "node": ">=22.0.0"
62
+ },
63
+ "dependencies": {
64
+ "@modelcontextprotocol/sdk": "^1.0.4",
65
+ "@tanstack/react-router": "^1.170.7",
66
+ "better-sqlite3": "^12.10.0",
67
+ "dompurify": "^3.4.5",
68
+ "express": "^5.0.1",
69
+ "lucide-react": "^1.16.0",
70
+ "marked": "^18.0.4",
71
+ "zod": "^3.24.1"
72
+ },
73
+ "devDependencies": {
74
+ "@eslint/js": "^9.18.0",
75
+ "@tailwindcss/vite": "^4.0.0",
76
+ "@tanstack/router-devtools": "^1.167.0",
77
+ "@types/better-sqlite3": "^7.6.12",
78
+ "@types/express": "^5.0.0",
79
+ "@types/marked": "^5.0.2",
80
+ "@types/node": "^22.10.5",
81
+ "@types/react": "^19.0.2",
82
+ "@types/react-dom": "^19.0.2",
83
+ "@typescript-eslint/eslint-plugin": "^8.20.0",
84
+ "@typescript-eslint/parser": "^8.20.0",
85
+ "@vitejs/plugin-react": "^4.3.4",
86
+ "concurrently": "^9.1.2",
87
+ "eslint": "^9.18.0",
88
+ "eslint-config-prettier": "^10.0.1",
89
+ "eslint-plugin-react": "^7.37.4",
90
+ "eslint-plugin-react-hooks": "^5.1.0",
91
+ "globals": "^15.14.0",
92
+ "prettier": "^3.4.2",
93
+ "react": "^19.0.0",
94
+ "react-dom": "^19.0.0",
95
+ "tailwindcss": "^4.0.0",
96
+ "tsx": "^4.19.2",
97
+ "typescript": "^5.7.2",
98
+ "vite": "^7.0.0",
99
+ "vitest": "^3.0.0"
28
100
  }
29
101
  }
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env node
2
+ // Post-build step: tsc doesn't copy non-TS assets. The migration runner
3
+ // expects `server/db/migrations/*.sql` next to the compiled `migrate.js`,
4
+ // so we mirror them into `dist/server/db/migrations/` after tsc emits.
5
+
6
+ import { cpSync, mkdirSync, readdirSync, existsSync } from 'node:fs';
7
+ import { dirname, join, resolve } from 'node:path';
8
+ import { fileURLToPath } from 'node:url';
9
+
10
+ const here = dirname(fileURLToPath(import.meta.url));
11
+ const root = resolve(here, '..');
12
+ const src = join(root, 'server', 'db', 'migrations');
13
+ const dst = join(root, 'dist', 'server', 'db', 'migrations');
14
+
15
+ if (!existsSync(src)) {
16
+ console.error(`[copy-migrations] source missing: ${src}`);
17
+ process.exit(1);
18
+ }
19
+ if (!existsSync(join(root, 'dist'))) {
20
+ console.error('[copy-migrations] dist/ not found — did `tsc` run?');
21
+ process.exit(1);
22
+ }
23
+
24
+ mkdirSync(dst, { recursive: true });
25
+ const files = readdirSync(src).filter((f) => f.endsWith('.sql'));
26
+ for (const f of files) {
27
+ cpSync(join(src, f), join(dst, f));
28
+ }
29
+ console.error(`[copy-migrations] copied ${files.length} migration file(s) → ${dst}`);
@@ -0,0 +1,3 @@
1
+ agent: agent1
2
+ file: workspace/handover.md
3
+ time: 2026-05-17T22:12:37.416963
@@ -1,25 +0,0 @@
1
- #!/bin/bash
2
- # KORTEXT MANAGED HOOK — generated/edited by kortext framework
3
- # [KORTEXT] İşlem Günlüğü (Audit Logger)
4
-
5
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6
- # shellcheck source=kortext-lib.sh
7
- source "$SCRIPT_DIR/kortext-lib.sh"
8
-
9
- LOG_FILE="$KORTEXT_WORKSPACE_DIR/reports/audit.log"
10
- TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
11
-
12
- # Çevresel değişkenlerden bilgileri çek (Casing ve isim kullandığın AI arayüzüne göre değişebilir)
13
- ACTION_FILE="${KORTEXT_FILE_PATH:-${CLAUDE_FILE_PATH:-${GEMINI_FILE_PATH:-${OPENAI_FILE_PATH:-N/A}}}}"
14
- LAST_CMD="${KORTEXT_LAST_CMD:-${CLAUDE_LAST_COMMAND:-${GEMINI_LAST_ACTION:-${OPENAI_LAST_COMMAND:-N/A}}}}"
15
- AGENT_NAME="${KORTEXT_AGENT_NAME:-${CLAUDE_AGENT_NAME:-${GEMINI_AGENT_NAME:-${OPENAI_AGENT_NAME:-Agent}}}}"
16
-
17
- mkdir -p "$KORTEXT_WORKSPACE_DIR/reports"
18
-
19
- # Kayıt Satırı Oluştur
20
- LOG_ENTRY="[$TIMESTAMP] | AGENT: $AGENT_NAME | FILE: $ACTION_FILE | CMD: $LAST_CMD"
21
-
22
- # Dosyaya ekle
23
- echo "$LOG_ENTRY" >> "$LOG_FILE"
24
-
25
- exit 0