lastlight 0.1.8 → 0.2.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 (478) hide show
  1. package/README.md +265 -118
  2. package/agent-context/rules.md +62 -9
  3. package/agent-context/security.md +69 -0
  4. package/config/default.yaml +89 -0
  5. package/deploy/.env.production.example +20 -2
  6. package/deploy/entrypoint.sh +16 -17
  7. package/deploy/native/README.md +160 -0
  8. package/deploy/native/install.sh +110 -0
  9. package/deploy/native/lastlight.env.example +95 -0
  10. package/deploy/native/lastlight.service +50 -0
  11. package/deploy/sandbox-entrypoint.sh +59 -42
  12. package/dist/admin/auth.d.ts +1 -1
  13. package/dist/admin/auth.js +3 -1
  14. package/dist/admin/auth.js.map +1 -1
  15. package/dist/admin/chat-session-reader.d.ts +11 -14
  16. package/dist/admin/chat-session-reader.js +27 -51
  17. package/dist/admin/chat-session-reader.js.map +1 -1
  18. package/dist/admin/docker.d.ts +37 -0
  19. package/dist/admin/docker.js +86 -1
  20. package/dist/admin/docker.js.map +1 -1
  21. package/dist/admin/index.js +38 -3
  22. package/dist/admin/index.js.map +1 -1
  23. package/dist/admin/log-search.test.d.ts +1 -0
  24. package/dist/admin/log-search.test.js +78 -0
  25. package/dist/admin/log-search.test.js.map +1 -0
  26. package/dist/admin/routes.d.ts +52 -3
  27. package/dist/admin/routes.js +780 -63
  28. package/dist/admin/routes.js.map +1 -1
  29. package/dist/admin/routes.test.js +680 -14
  30. package/dist/admin/routes.test.js.map +1 -1
  31. package/dist/admin/server-logs.test.d.ts +1 -0
  32. package/dist/admin/server-logs.test.js +58 -0
  33. package/dist/admin/server-logs.test.js.map +1 -0
  34. package/dist/admin/sessions.d.ts +26 -39
  35. package/dist/admin/sessions.js +86 -310
  36. package/dist/admin/sessions.js.map +1 -1
  37. package/dist/admin/sessions.test.d.ts +1 -0
  38. package/dist/admin/sessions.test.js +78 -0
  39. package/dist/admin/sessions.test.js.map +1 -0
  40. package/dist/admin/version.d.ts +15 -0
  41. package/dist/admin/version.js +73 -0
  42. package/dist/admin/version.js.map +1 -0
  43. package/dist/admin/version.test.d.ts +1 -0
  44. package/dist/admin/version.test.js +71 -0
  45. package/dist/admin/version.test.js.map +1 -0
  46. package/dist/cli-config.d.ts +55 -0
  47. package/dist/cli-config.js +119 -0
  48. package/dist/cli-config.js.map +1 -0
  49. package/dist/cli-config.test.d.ts +1 -0
  50. package/dist/cli-config.test.js +92 -0
  51. package/dist/cli-config.test.js.map +1 -0
  52. package/dist/cli-format.d.ts +19 -0
  53. package/dist/cli-format.js +107 -0
  54. package/dist/cli-format.js.map +1 -0
  55. package/dist/cli-server.d.ts +73 -0
  56. package/dist/cli-server.js +347 -0
  57. package/dist/cli-server.js.map +1 -0
  58. package/dist/cli-server.test.d.ts +1 -0
  59. package/dist/cli-server.test.js +38 -0
  60. package/dist/cli-server.test.js.map +1 -0
  61. package/dist/cli-timeline.d.ts +35 -0
  62. package/dist/cli-timeline.js +373 -0
  63. package/dist/cli-timeline.js.map +1 -0
  64. package/dist/cli-timeline.test.d.ts +1 -0
  65. package/dist/cli-timeline.test.js +104 -0
  66. package/dist/cli-timeline.test.js.map +1 -0
  67. package/dist/cli.d.ts +0 -19
  68. package/dist/cli.js +910 -194
  69. package/dist/cli.js.map +1 -1
  70. package/dist/config-overlay.test.d.ts +1 -0
  71. package/dist/config-overlay.test.js +112 -0
  72. package/dist/config-overlay.test.js.map +1 -0
  73. package/dist/config-resolve.d.ts +28 -0
  74. package/dist/config-resolve.js +47 -0
  75. package/dist/config-resolve.js.map +1 -0
  76. package/dist/config-resolve.test.d.ts +1 -0
  77. package/dist/config-resolve.test.js +68 -0
  78. package/dist/config-resolve.test.js.map +1 -0
  79. package/dist/config.d.ts +62 -49
  80. package/dist/config.js +452 -76
  81. package/dist/config.js.map +1 -1
  82. package/dist/config.test.js +201 -32
  83. package/dist/config.test.js.map +1 -1
  84. package/dist/connectors/github-webhook.js +83 -5
  85. package/dist/connectors/github-webhook.js.map +1 -1
  86. package/dist/connectors/github-webhook.test.d.ts +1 -0
  87. package/dist/connectors/github-webhook.test.js +156 -0
  88. package/dist/connectors/github-webhook.test.js.map +1 -0
  89. package/dist/connectors/messaging/session-manager.d.ts +18 -0
  90. package/dist/connectors/messaging/session-manager.js +83 -2
  91. package/dist/connectors/messaging/session-manager.js.map +1 -1
  92. package/dist/connectors/messaging/session-manager.test.d.ts +1 -0
  93. package/dist/connectors/messaging/session-manager.test.js +144 -0
  94. package/dist/connectors/messaging/session-manager.test.js.map +1 -0
  95. package/dist/connectors/slack/connector.d.ts +9 -0
  96. package/dist/connectors/slack/connector.js +15 -0
  97. package/dist/connectors/slack/connector.js.map +1 -1
  98. package/dist/connectors/slack/mrkdwn.js +81 -0
  99. package/dist/connectors/slack/mrkdwn.js.map +1 -1
  100. package/dist/connectors/slack/mrkdwn.test.js +49 -0
  101. package/dist/connectors/slack/mrkdwn.test.js.map +1 -1
  102. package/dist/connectors/types.d.ts +1 -1
  103. package/dist/cron/fanout.d.ts +33 -0
  104. package/dist/cron/fanout.js +55 -0
  105. package/dist/cron/fanout.js.map +1 -0
  106. package/dist/cron/fanout.test.d.ts +1 -0
  107. package/dist/cron/fanout.test.js +73 -0
  108. package/dist/cron/fanout.test.js.map +1 -0
  109. package/dist/cron/jobs.d.ts +5 -0
  110. package/dist/cron/jobs.js +10 -3
  111. package/dist/cron/jobs.js.map +1 -1
  112. package/dist/cron/scheduler.d.ts +12 -0
  113. package/dist/cron/scheduler.js +27 -1
  114. package/dist/cron/scheduler.js.map +1 -1
  115. package/dist/engine/agent-executor.d.ts +158 -0
  116. package/dist/engine/agent-executor.js +1140 -0
  117. package/dist/engine/agent-executor.js.map +1 -0
  118. package/dist/engine/agent-executor.test.d.ts +1 -0
  119. package/dist/engine/agent-executor.test.js +395 -0
  120. package/dist/engine/agent-executor.test.js.map +1 -0
  121. package/dist/engine/chat-runner.d.ts +123 -0
  122. package/dist/engine/chat-runner.js +379 -0
  123. package/dist/engine/chat-runner.js.map +1 -0
  124. package/dist/engine/chat-runner.test.d.ts +1 -0
  125. package/dist/engine/chat-runner.test.js +104 -0
  126. package/dist/engine/chat-runner.test.js.map +1 -0
  127. package/dist/engine/chat-skills.d.ts +45 -0
  128. package/dist/engine/chat-skills.js +184 -0
  129. package/dist/engine/chat-skills.js.map +1 -0
  130. package/dist/engine/chat-skills.test.d.ts +1 -0
  131. package/dist/engine/chat-skills.test.js +20 -0
  132. package/dist/engine/chat-skills.test.js.map +1 -0
  133. package/dist/engine/chat.d.ts +20 -23
  134. package/dist/engine/chat.js +251 -155
  135. package/dist/engine/chat.js.map +1 -1
  136. package/dist/engine/chat.test.d.ts +1 -0
  137. package/dist/engine/chat.test.js +42 -0
  138. package/dist/engine/chat.test.js.map +1 -0
  139. package/dist/engine/classifier.d.ts +35 -2
  140. package/dist/engine/classifier.js +170 -31
  141. package/dist/engine/classifier.js.map +1 -1
  142. package/dist/engine/classifier.test.d.ts +1 -0
  143. package/dist/engine/classifier.test.js +115 -0
  144. package/dist/engine/classifier.test.js.map +1 -0
  145. package/dist/engine/dispatcher.d.ts +60 -0
  146. package/dist/engine/dispatcher.js +601 -0
  147. package/dist/engine/dispatcher.js.map +1 -0
  148. package/dist/engine/dispatcher.test.d.ts +1 -0
  149. package/dist/engine/dispatcher.test.js +511 -0
  150. package/dist/engine/dispatcher.test.js.map +1 -0
  151. package/dist/engine/event-shim.d.ts +117 -0
  152. package/dist/engine/event-shim.js +435 -0
  153. package/dist/engine/event-shim.js.map +1 -0
  154. package/dist/engine/event-shim.test.d.ts +1 -0
  155. package/dist/engine/event-shim.test.js +194 -0
  156. package/dist/engine/event-shim.test.js.map +1 -0
  157. package/dist/engine/git-auth.d.ts +13 -17
  158. package/dist/engine/git-auth.js +99 -42
  159. package/dist/engine/git-auth.js.map +1 -1
  160. package/dist/engine/git-auth.test.d.ts +1 -0
  161. package/dist/engine/git-auth.test.js +117 -0
  162. package/dist/engine/git-auth.test.js.map +1 -0
  163. package/dist/engine/github-app-client.d.ts +7 -0
  164. package/dist/engine/github-app-client.js +16 -0
  165. package/dist/engine/github-app-client.js.map +1 -0
  166. package/dist/engine/github-app-client.test.d.ts +1 -0
  167. package/dist/engine/github-app-client.test.js +44 -0
  168. package/dist/engine/github-app-client.test.js.map +1 -0
  169. package/dist/engine/github-tools.d.ts +12 -0
  170. package/dist/engine/github-tools.js +261 -0
  171. package/dist/engine/github-tools.js.map +1 -0
  172. package/dist/engine/github.d.ts +1027 -43
  173. package/dist/engine/github.js +153 -14
  174. package/dist/engine/github.js.map +1 -1
  175. package/dist/engine/llm.d.ts +47 -0
  176. package/dist/engine/llm.js +221 -0
  177. package/dist/engine/llm.js.map +1 -0
  178. package/dist/engine/llm.test.d.ts +1 -0
  179. package/dist/engine/llm.test.js +189 -0
  180. package/dist/engine/llm.test.js.map +1 -0
  181. package/dist/engine/profiles.d.ts +249 -0
  182. package/dist/engine/profiles.js +42 -0
  183. package/dist/engine/profiles.js.map +1 -0
  184. package/dist/engine/router.d.ts +12 -6
  185. package/dist/engine/router.js +339 -81
  186. package/dist/engine/router.js.map +1 -1
  187. package/dist/engine/router.test.js +428 -78
  188. package/dist/engine/router.test.js.map +1 -1
  189. package/dist/engine/screen.d.ts +41 -0
  190. package/dist/engine/screen.js +93 -0
  191. package/dist/engine/screen.js.map +1 -0
  192. package/dist/engine/screen.test.d.ts +1 -0
  193. package/dist/engine/screen.test.js +82 -0
  194. package/dist/engine/screen.test.js.map +1 -0
  195. package/dist/index.js +423 -437
  196. package/dist/index.js.map +1 -1
  197. package/dist/managed-repos.d.ts +7 -9
  198. package/dist/managed-repos.js +12 -15
  199. package/dist/managed-repos.js.map +1 -1
  200. package/dist/managed-repos.test.js +24 -19
  201. package/dist/managed-repos.test.js.map +1 -1
  202. package/dist/notify/index.d.ts +15 -0
  203. package/dist/notify/index.js +6 -0
  204. package/dist/notify/index.js.map +1 -0
  205. package/dist/notify/model.d.ts +57 -0
  206. package/dist/notify/model.js +89 -0
  207. package/dist/notify/model.js.map +1 -0
  208. package/dist/notify/model.test.d.ts +1 -0
  209. package/dist/notify/model.test.js +109 -0
  210. package/dist/notify/model.test.js.map +1 -0
  211. package/dist/notify/notifier.d.ts +17 -0
  212. package/dist/notify/notifier.js +87 -0
  213. package/dist/notify/notifier.js.map +1 -0
  214. package/dist/notify/notifier.test.d.ts +1 -0
  215. package/dist/notify/notifier.test.js +100 -0
  216. package/dist/notify/notifier.test.js.map +1 -0
  217. package/dist/notify/render.d.ts +21 -0
  218. package/dist/notify/render.js +59 -0
  219. package/dist/notify/render.js.map +1 -0
  220. package/dist/notify/render.test.d.ts +1 -0
  221. package/dist/notify/render.test.js +65 -0
  222. package/dist/notify/render.test.js.map +1 -0
  223. package/dist/notify/transports/github.d.ts +26 -0
  224. package/dist/notify/transports/github.js +26 -0
  225. package/dist/notify/transports/github.js.map +1 -0
  226. package/dist/notify/transports/slack.d.ts +26 -0
  227. package/dist/notify/transports/slack.js +28 -0
  228. package/dist/notify/transports/slack.js.map +1 -0
  229. package/dist/notify/transports.test.d.ts +1 -0
  230. package/dist/notify/transports.test.js +71 -0
  231. package/dist/notify/transports.test.js.map +1 -0
  232. package/dist/notify/types.d.ts +95 -0
  233. package/dist/notify/types.js +16 -0
  234. package/dist/notify/types.js.map +1 -0
  235. package/dist/sandbox/docker-compose.test.d.ts +1 -0
  236. package/dist/sandbox/docker-compose.test.js +128 -0
  237. package/dist/sandbox/docker-compose.test.js.map +1 -0
  238. package/dist/sandbox/docker.d.ts +97 -9
  239. package/dist/sandbox/docker.js +192 -41
  240. package/dist/sandbox/docker.js.map +1 -1
  241. package/dist/sandbox/docker.test.d.ts +1 -0
  242. package/dist/sandbox/docker.test.js +137 -0
  243. package/dist/sandbox/docker.test.js.map +1 -0
  244. package/dist/sandbox/egress-allowlist.d.ts +69 -0
  245. package/dist/sandbox/egress-allowlist.js +164 -0
  246. package/dist/sandbox/egress-allowlist.js.map +1 -0
  247. package/dist/sandbox/egress-allowlist.test.d.ts +1 -0
  248. package/dist/sandbox/egress-allowlist.test.js +65 -0
  249. package/dist/sandbox/egress-allowlist.test.js.map +1 -0
  250. package/dist/sandbox/egress-firewall-config.d.ts +127 -0
  251. package/dist/sandbox/egress-firewall-config.js +434 -0
  252. package/dist/sandbox/egress-firewall-config.js.map +1 -0
  253. package/dist/sandbox/egress-firewall-config.test.d.ts +1 -0
  254. package/dist/sandbox/egress-firewall-config.test.js +244 -0
  255. package/dist/sandbox/egress-firewall-config.test.js.map +1 -0
  256. package/dist/sandbox/images.d.ts +23 -0
  257. package/dist/sandbox/images.js +55 -0
  258. package/dist/sandbox/images.js.map +1 -0
  259. package/dist/sandbox/index.d.ts +82 -3
  260. package/dist/sandbox/index.js +223 -93
  261. package/dist/sandbox/index.js.map +1 -1
  262. package/dist/sandbox/index.test.d.ts +1 -0
  263. package/dist/sandbox/index.test.js +157 -0
  264. package/dist/sandbox/index.test.js.map +1 -0
  265. package/dist/session-log.d.ts +63 -0
  266. package/dist/session-log.js +290 -0
  267. package/dist/session-log.js.map +1 -0
  268. package/dist/session-log.test.d.ts +1 -0
  269. package/dist/session-log.test.js +85 -0
  270. package/dist/session-log.test.js.map +1 -0
  271. package/dist/setup.d.ts +31 -12
  272. package/dist/setup.js +516 -174
  273. package/dist/setup.js.map +1 -1
  274. package/dist/setup.test.js +138 -6
  275. package/dist/setup.test.js.map +1 -1
  276. package/dist/state/approval-store.d.ts +86 -0
  277. package/dist/state/approval-store.js +140 -0
  278. package/dist/state/approval-store.js.map +1 -0
  279. package/dist/state/build-assets.d.ts +50 -0
  280. package/dist/state/build-assets.js +154 -0
  281. package/dist/state/build-assets.js.map +1 -0
  282. package/dist/state/build-assets.test.d.ts +1 -0
  283. package/dist/state/build-assets.test.js +106 -0
  284. package/dist/state/build-assets.test.js.map +1 -0
  285. package/dist/state/db.d.ts +65 -333
  286. package/dist/state/db.js +112 -835
  287. package/dist/state/db.js.map +1 -1
  288. package/dist/state/db.test.js +127 -91
  289. package/dist/state/db.test.js.map +1 -1
  290. package/dist/state/execution-store.d.ts +257 -0
  291. package/dist/state/execution-store.js +527 -0
  292. package/dist/state/execution-store.js.map +1 -0
  293. package/dist/state/migrate.d.ts +15 -0
  294. package/dist/state/migrate.js +175 -0
  295. package/dist/state/migrate.js.map +1 -0
  296. package/dist/state/workflow-run-store.d.ts +195 -0
  297. package/dist/state/workflow-run-store.js +363 -0
  298. package/dist/state/workflow-run-store.js.map +1 -0
  299. package/dist/state/workflow-run-store.test.d.ts +1 -0
  300. package/dist/state/workflow-run-store.test.js +264 -0
  301. package/dist/state/workflow-run-store.test.js.map +1 -0
  302. package/dist/telemetry/index.d.ts +38 -0
  303. package/dist/telemetry/index.js +253 -0
  304. package/dist/telemetry/index.js.map +1 -0
  305. package/dist/telemetry/index.test.d.ts +1 -0
  306. package/dist/telemetry/index.test.js +73 -0
  307. package/dist/telemetry/index.test.js.map +1 -0
  308. package/dist/telemetry/pi-events.d.ts +12 -0
  309. package/dist/telemetry/pi-events.js +134 -0
  310. package/dist/telemetry/pi-events.js.map +1 -0
  311. package/dist/telemetry/pi-events.test.d.ts +1 -0
  312. package/dist/telemetry/pi-events.test.js +69 -0
  313. package/dist/telemetry/pi-events.test.js.map +1 -0
  314. package/dist/workflows/dag.d.ts +13 -1
  315. package/dist/workflows/dag.js +7 -3
  316. package/dist/workflows/dag.js.map +1 -1
  317. package/dist/workflows/dag.test.js +22 -0
  318. package/dist/workflows/dag.test.js.map +1 -1
  319. package/dist/workflows/golden-build.test.d.ts +1 -0
  320. package/dist/workflows/golden-build.test.js +45 -0
  321. package/dist/workflows/golden-build.test.js.map +1 -0
  322. package/dist/workflows/loader-overlay.test.d.ts +1 -0
  323. package/dist/workflows/loader-overlay.test.js +101 -0
  324. package/dist/workflows/loader-overlay.test.js.map +1 -0
  325. package/dist/workflows/loader.d.ts +36 -11
  326. package/dist/workflows/loader.js +311 -87
  327. package/dist/workflows/loader.js.map +1 -1
  328. package/dist/workflows/loader.test.js +114 -10
  329. package/dist/workflows/loader.test.js.map +1 -1
  330. package/dist/workflows/loop-eval.js +2 -0
  331. package/dist/workflows/loop-eval.js.map +1 -1
  332. package/dist/workflows/loop-eval.test.js +14 -0
  333. package/dist/workflows/loop-eval.test.js.map +1 -1
  334. package/dist/workflows/phase-executor.d.ts +145 -0
  335. package/dist/workflows/phase-executor.js +691 -0
  336. package/dist/workflows/phase-executor.js.map +1 -0
  337. package/dist/workflows/phase-executor.test.d.ts +1 -0
  338. package/dist/workflows/phase-executor.test.js +434 -0
  339. package/dist/workflows/phase-executor.test.js.map +1 -0
  340. package/dist/workflows/phase-ref.d.ts +44 -0
  341. package/dist/workflows/phase-ref.js +78 -0
  342. package/dist/workflows/phase-ref.js.map +1 -0
  343. package/dist/workflows/phase-ref.test.d.ts +1 -0
  344. package/dist/workflows/phase-ref.test.js +24 -0
  345. package/dist/workflows/phase-ref.test.js.map +1 -0
  346. package/dist/workflows/resume.d.ts +5 -11
  347. package/dist/workflows/resume.js +88 -7
  348. package/dist/workflows/resume.js.map +1 -1
  349. package/dist/workflows/runner.d.ts +34 -27
  350. package/dist/workflows/runner.js +252 -930
  351. package/dist/workflows/runner.js.map +1 -1
  352. package/dist/workflows/runner.test.js +346 -35
  353. package/dist/workflows/runner.test.js.map +1 -1
  354. package/dist/workflows/schema.d.ts +52 -10
  355. package/dist/workflows/schema.js +147 -7
  356. package/dist/workflows/schema.js.map +1 -1
  357. package/dist/workflows/simple.d.ts +67 -3
  358. package/dist/workflows/simple.js +248 -87
  359. package/dist/workflows/simple.js.map +1 -1
  360. package/dist/workflows/simple.test.d.ts +1 -0
  361. package/dist/workflows/simple.test.js +107 -0
  362. package/dist/workflows/simple.test.js.map +1 -0
  363. package/dist/workflows/templates.d.ts +29 -0
  364. package/dist/workflows/templates.js +42 -4
  365. package/dist/workflows/templates.js.map +1 -1
  366. package/dist/workflows/templates.test.js +103 -0
  367. package/dist/workflows/templates.test.js.map +1 -1
  368. package/dist/workflows/triggers.d.ts +21 -0
  369. package/dist/workflows/triggers.js +44 -0
  370. package/dist/workflows/triggers.js.map +1 -0
  371. package/dist/workflows/verdict.d.ts +19 -0
  372. package/dist/workflows/verdict.js +30 -0
  373. package/dist/workflows/verdict.js.map +1 -0
  374. package/dist/workflows/verdict.test.d.ts +1 -0
  375. package/dist/workflows/verdict.test.js +44 -0
  376. package/dist/workflows/verdict.test.js.map +1 -0
  377. package/dist/worktree/manager.d.ts +1 -1
  378. package/dist/worktree/manager.js +14 -14
  379. package/dist/worktree/manager.js.map +1 -1
  380. package/dist/worktree/manager.test.d.ts +1 -0
  381. package/dist/worktree/manager.test.js +87 -0
  382. package/dist/worktree/manager.test.js.map +1 -0
  383. package/docker-compose.yml +206 -5
  384. package/package.json +19 -7
  385. package/sandbox.Dockerfile +97 -18
  386. package/skills/README.md +40 -0
  387. package/skills/browser-qa/SKILL.md +193 -0
  388. package/skills/browser-qa/scripts/agent-browser.mjs +380 -0
  389. package/skills/building/SKILL.md +95 -0
  390. package/skills/chat/SKILL.md +30 -11
  391. package/skills/code-review/SKILL.md +59 -0
  392. package/skills/debug-production/SKILL.md +108 -0
  393. package/skills/demo/SKILL.md +194 -0
  394. package/skills/demo/scripts/compose-demo.sh +205 -0
  395. package/skills/issue-answer/SKILL.md +90 -0
  396. package/skills/issue-comment/SKILL.md +38 -24
  397. package/skills/issue-triage/SKILL.md +103 -37
  398. package/skills/issue-triage/references/AGENT-BRIEF.md +61 -0
  399. package/skills/pr-comment/SKILL.md +64 -0
  400. package/skills/pr-review/SKILL.md +65 -49
  401. package/skills/qa-test/SKILL.md +97 -0
  402. package/skills/repo-health/SKILL.md +48 -45
  403. package/skills/security-feedback/SKILL.md +173 -0
  404. package/skills/security-feedback/references/templates.md +77 -0
  405. package/skills/security-review/SKILL.md +213 -0
  406. package/skills/security-review/references/issue-format.md +302 -0
  407. package/skills/verify/SKILL.md +118 -0
  408. package/workflows/answer.yaml +37 -0
  409. package/workflows/build.yaml +32 -22
  410. package/workflows/cron-security.yaml +6 -0
  411. package/workflows/demo.yaml +55 -0
  412. package/workflows/explore.yaml +9 -0
  413. package/workflows/pr-comment.yaml +16 -0
  414. package/workflows/pr-fix.yaml +3 -0
  415. package/workflows/pr-review.yaml +4 -1
  416. package/workflows/prompts/answer.md +67 -0
  417. package/workflows/prompts/architect.md +24 -7
  418. package/workflows/prompts/demo.md +100 -0
  419. package/workflows/prompts/executor.md +29 -20
  420. package/workflows/prompts/explore-ask.md +51 -22
  421. package/workflows/prompts/explore-publish.md +2 -2
  422. package/workflows/prompts/explore-read.md +24 -10
  423. package/workflows/prompts/explore-synthesize.md +15 -8
  424. package/workflows/prompts/fix.md +9 -10
  425. package/workflows/prompts/guardrails.md +26 -8
  426. package/workflows/prompts/pr-fix.md +6 -7
  427. package/workflows/prompts/pr.md +11 -10
  428. package/workflows/prompts/qa-browser.md +95 -0
  429. package/workflows/prompts/qa-synth.md +44 -0
  430. package/workflows/prompts/qa-test.md +60 -0
  431. package/workflows/prompts/re-reviewer.md +8 -9
  432. package/workflows/prompts/reviewer.md +10 -9
  433. package/workflows/prompts/verify-browser.md +93 -0
  434. package/workflows/prompts/verify-synth.md +44 -0
  435. package/workflows/prompts/verify.md +63 -0
  436. package/workflows/qa-test.yaml +87 -0
  437. package/workflows/security-feedback.yaml +25 -0
  438. package/workflows/security-review.yaml +29 -0
  439. package/workflows/verify.yaml +85 -0
  440. package/deploy/mcp-config.tmpl.json +0 -14
  441. package/dist/cron/rate-limits.d.ts +0 -26
  442. package/dist/cron/rate-limits.js +0 -193
  443. package/dist/cron/rate-limits.js.map +0 -1
  444. package/dist/engine/executor.d.ts +0 -75
  445. package/dist/engine/executor.js +0 -292
  446. package/dist/engine/executor.js.map +0 -1
  447. package/mcp-github-app/package.json +0 -18
  448. package/mcp-github-app/src/auth.js +0 -66
  449. package/mcp-github-app/src/github.js +0 -371
  450. package/mcp-github-app/src/index.js +0 -534
  451. package/skills/devops/webhook-subscriptions/SKILL.md +0 -180
  452. package/skills/github/DESCRIPTION.md +0 -3
  453. package/skills/github/codebase-inspection/SKILL.md +0 -115
  454. package/skills/github/github-auth/SKILL.md +0 -54
  455. package/skills/github/github-auth/scripts/gh-env.sh +0 -66
  456. package/skills/github/github-code-review/SKILL.md +0 -480
  457. package/skills/github/github-code-review/references/review-output-template.md +0 -74
  458. package/skills/github/github-issues/SKILL.md +0 -369
  459. package/skills/github/github-issues/templates/bug-report.md +0 -35
  460. package/skills/github/github-issues/templates/feature-request.md +0 -31
  461. package/skills/github/github-pr-workflow/SKILL.md +0 -395
  462. package/skills/github/github-pr-workflow/references/ci-troubleshooting.md +0 -183
  463. package/skills/github/github-pr-workflow/references/conventional-commits.md +0 -71
  464. package/skills/github/github-pr-workflow/templates/pr-body-bugfix.md +0 -35
  465. package/skills/github/github-pr-workflow/templates/pr-body-feature.md +0 -33
  466. package/skills/github/github-repo-management/SKILL.md +0 -515
  467. package/skills/github/github-repo-management/references/github-api-cheatsheet.md +0 -161
  468. package/skills/github-orchestrator/SKILL.md +0 -103
  469. package/skills/mcp/DESCRIPTION.md +0 -3
  470. package/skills/mcp/mcporter/SKILL.md +0 -122
  471. package/skills/mcp/native-mcp/SKILL.md +0 -356
  472. package/skills/software-development/architect/SKILL.md +0 -154
  473. package/skills/software-development/assure-guardrails/SKILL.md +0 -239
  474. package/skills/software-development/plan/SKILL.md +0 -64
  475. package/skills/software-development/requesting-code-review/SKILL.md +0 -291
  476. package/skills/software-development/subagent-driven-development/SKILL.md +0 -433
  477. package/skills/software-development/systematic-debugging/SKILL.md +0 -366
  478. package/skills/software-development/test-driven-development/SKILL.md +0 -342
package/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
 
12
12
  An AI agent that maintains GitHub repositories: triaging issues, reviewing PRs, monitoring repo health, and building features through an Architect → Executor → Reviewer development cycle.
13
13
 
14
- Built on the [Claude Agent SDK](https://platform.claude.com/docs/en/agent-sdk/overview) with a lightweight TypeScript harness for webhook ingestion, cron scheduling, and process management.
14
+ Built on [agentic-pi](https://github.com/cliftonc/agentic-pi) (workflow phases) and [`@earendil-works/pi-ai`](https://www.npmjs.com/package/@earendil-works/pi-ai) (in-process chat) with a lightweight TypeScript harness for webhook ingestion, cron scheduling, and process management. Provider-agnostic — point `LASTLIGHT_MODEL` at any `provider/model` pi-ai supports (defaults to `anthropic/claude-sonnet-4-6`).
15
15
 
16
16
  ## Production Setup (Clean Server)
17
17
 
@@ -24,20 +24,27 @@ npx lastlight setup
24
24
  The setup wizard walks you through:
25
25
 
26
26
  1. **GitHub App** — enter your App ID, Installation ID, and PEM key path
27
- 2. **Anthropic API key** — for the Claude Agent SDK
28
- 3. **Webhook secret** — auto-generated if you don't have one
29
- 4. **Domain & TLS** — optional Caddy config for automatic HTTPS
30
- 5. **Slack** optional bot token and app token for Slack integration
31
- 6. **Admin dashboard** — optional password protection
32
-
33
- It writes `.env`, copies your PEM into the secrets directory, generates
34
- `docker-compose.yml` and (optionally) a `Caddyfile`, then offers to build
35
- and start the containers. When it's done you have a running instance ready
36
- to receive webhooks.
27
+ 2. **Domain & TLS** — optional Caddy config for automatic HTTPS
28
+ 3. **Managed repositories** — the `owner/repo` list the bot operates on
29
+ 4. **Provider API key** — `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, and/or `OPENROUTER_API_KEY`,
30
+ whichever your `LASTLIGHT_MODEL` points at
31
+ 5. **Webhook secret** — auto-generated if you don't have one
32
+ 6. **Slack** — optional bot token and app token for Slack integration
33
+ 7. **Admin dashboard** optional password protection
34
+
35
+ It scaffolds your private **deployment overlay** at `instance/` writing
36
+ `instance/config.yaml` (your managed repos), `instance/secrets/.env`, and copying
37
+ your PEM to `instance/secrets/app.pem` (mode 600) — then offers to build and start
38
+ the Docker stack. When it's done you have a running instance ready to receive
39
+ webhooks. Everything deployment-specific lives in `instance/`, which is mounted
40
+ read-only and never baked into the image; edit it and `docker compose restart agent`
41
+ to apply (no rebuild). See [Deployment overlay](#deployment-overlay) for the model.
37
42
 
38
43
  > **Requires:** Node.js 20+, Docker, and a GitHub App already created
39
44
  > (see [Create a GitHub App](#1-create-a-github-app) below).
40
45
 
46
+ For a Docker-free production install (systemd unit, gondolin sandbox), see [Native deploy](#native-systemd-deploy) below.
47
+
41
48
  ---
42
49
 
43
50
  ## Quick Start (Local Dev)
@@ -45,8 +52,10 @@ to receive webhooks.
45
52
  ### Prerequisites
46
53
 
47
54
  - Node.js 20+
48
- - [Claude Code CLI](https://claude.ai/install.sh) installed and logged in (`claude login`)
55
+ - Docker Desktop (or compatible) only needed for `LASTLIGHT_SANDBOX=docker`; gondolin runs without it on macOS/Linux
49
56
  - A GitHub App (see [Create a GitHub App](#1-create-a-github-app) below)
57
+ - An API key for whichever provider your chosen `LASTLIGHT_MODEL` uses
58
+ (`OPENAI_API_KEY` for openai/…, `ANTHROPIC_API_KEY` for anthropic/…, `OPENROUTER_API_KEY` for openrouter/…)
50
59
 
51
60
  ### Setup
52
61
 
@@ -72,21 +81,35 @@ GITHUB_APP_INSTALLATION_ID=789012
72
81
 
73
82
  # Webhook secret (required for webhook mode)
74
83
  WEBHOOK_SECRET=your-secret-here
84
+
85
+ # Model + provider — pick one matching your key
86
+ LASTLIGHT_MODEL=anthropic/claude-sonnet-4-6
87
+ ANTHROPIC_API_KEY=sk-ant-...
88
+ # OPENAI_API_KEY=sk-...
89
+ # OPENROUTER_API_KEY=sk-or-...
90
+
91
+ # Sandbox backend (default: gondolin; alternatives: docker, none)
92
+ # LASTLIGHT_SANDBOX=gondolin
75
93
  ```
76
94
 
77
95
  ### Run
78
96
 
79
- `npm run dev` runs the harness on your host but spawns each agent task in a real Docker sandbox container, exactly like production. It is explicitly safe with your personal config:
97
+ `npm run dev` runs the harness on your host. Sandbox mode is selected by `LASTLIGHT_SANDBOX`:
98
+
99
+ - **`gondolin`** (default) — agentic-pi spawns a per-phase QEMU micro-VM in-process. Uses HVF on macOS, KVM on Linux. No Docker needed.
100
+ - **`docker`** — agentic-pi runs inside a per-phase sibling Docker container (the `lastlight-sandbox:latest` image). Requires Docker. Useful for prod-like smoke testing.
101
+ - **`none`** — agent runs in-process on your host with no isolation. Dev only — never in production.
102
+
103
+ The dev script is explicitly safe with your personal config:
80
104
 
81
105
  | | Touched? |
82
106
  |---|---|
83
107
  | `~/.gitconfig` (your identity, credential helper) | ❌ skipped (`LASTLIGHT_LOCAL_DEV=1`) |
84
- | `~/.claude/.credentials.json` | read once on first run, never written |
85
- | `~/.claude/projects/...` (your session history) | direct fallback disabled |
86
- | `./data/sandbox-claude-home/` | ✅ project-local seed of your claude login; sandboxes refresh tokens here, isolated from host |
108
+ | `./data/agent-sessions/` | project-local; shim envelope jsonls for the dashboard live here |
109
+ | `./data/sandbox-data/` | project-local bind-mount when using `LASTLIGHT_SANDBOX=docker` |
87
110
  | `./data/lastlight.db`, `./data/sandboxes/`, `./data/logs/` | ✅ project-local state, gitignored |
88
111
 
89
- One-time setup build the sandbox image:
112
+ If you want the Docker sandbox mode locally, build the image once first:
90
113
 
91
114
  ```bash
92
115
  docker compose --profile build-only build sandbox
@@ -101,10 +124,9 @@ npm run dev:dashboard # dashboard only
101
124
  ```
102
125
 
103
126
  Both server scripts call `scripts/dev-local.sh`, which:
104
- - Verifies Docker is running and the sandbox image exists
105
- - Locates your host claude credentials — `~/.claude/.credentials.json` on Linux, or the macOS keychain entry `Claude Code-credentials` on macOS. Run `claude login` first if neither is present.
106
- - Re-seeds `./data/sandbox-claude-home/.credentials.json` from the host credentials on every start, so a fresh `claude login` is picked up automatically without wiping anything.
107
- - Sets `LASTLIGHT_LOCAL_DEV=1`, `SANDBOX_DATA_VOLUME=./data/sandbox-claude-home`, `STATE_DIR=./data`, `CLAUDE_HOME_DIR=./data/sandbox-claude-home`, and `ENABLE_DIRECT_FALLBACK=false`
127
+ - Verifies the sandbox image exists when `LASTLIGHT_SANDBOX=docker`
128
+ - Copies your `GITHUB_APP_PRIVATE_KEY_PATH` into `./data/sandbox-data/secrets/app.pem` (mode 600) so the sandbox can authenticate to GitHub
129
+ - Sets `LASTLIGHT_LOCAL_DEV=1`, `STATE_DIR=./data`, `LASTLIGHT_SESSIONS_DIR=./data/agent-sessions`
108
130
  - Starts the harness with `tsx watch src/index.ts`
109
131
 
110
132
  #### Triggering work via the CLI
@@ -129,53 +151,82 @@ The default for a single-issue/PR shorthand is the **cheap** action (triage or r
129
151
 
130
152
  ### Authentication
131
153
 
132
- Locally, the Agent SDK uses your Claude Code login (subscription). No API key needed — just make sure `claude login` works on your host. `npm run dev` copies the credentials into the project-local sandbox claude-home, so the sandbox is logged in without bind-mounting your real `~/.claude`.
133
-
134
- To use an API key instead, set `ANTHROPIC_API_KEY` in `.env`.
154
+ pi-ai picks credentials from `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, and/or `OPENROUTER_API_KEY` on the harness env. The harness forwards them into each sandbox container (or VM) so workflow runs can reach the API.
135
155
 
136
156
  ---
137
157
 
138
158
  ## Docker Deployment
139
159
 
140
- ### Build and Run
141
-
142
- ```bash
143
- docker-compose build agent
144
- docker-compose up -d agent
145
- ```
160
+ The docker-compose stack is useful when you want a single `docker compose up -d` deploy. For gondolin (and a smaller deployment surface area), prefer the [native systemd deploy](#native-systemd-deploy) instead.
146
161
 
147
- ### First-Time Auth
162
+ ### Build and Run
148
163
 
149
- The container needs Claude Code credentials. Log in interactively once:
164
+ Build both the harness image **and** the sandbox image. The sandbox image is what the harness spawns per phase when `LASTLIGHT_SANDBOX=docker`. The sandbox service is under the `build-only` profile so it is never started — it is only built.
150
165
 
151
166
  ```bash
152
- docker exec -it lastlight-agent-1 claude login
167
+ docker compose build agent
168
+ docker compose --profile build-only build sandbox
169
+ docker compose up -d agent
153
170
  ```
154
171
 
155
- Follow the URL in your browser to authenticate. The auth token persists in the Docker volumeit survives container restarts and rebuilds.
156
-
157
- ### Secrets
172
+ Set `LASTLIGHT_SANDBOX=docker` in your `.env`. (Inside the harness container, gondolin's QEMU path isn't available unless you do the nested-virt setup yourself the docker-sandbox path is the practical default for Docker deployments.)
173
+
174
+ ### Deployment overlay
175
+
176
+ Everything specific to your deployment — managed repos, model/route/approval
177
+ overrides, agent-context, secrets — lives in a single **`instance/`** folder
178
+ next to `docker-compose.yml`. It's mounted read-only at `/app/instance`
179
+ (`LASTLIGHT_OVERLAY_DIR=/app/instance`) and is **never committed to the public
180
+ repo or baked into the image**, so it's the natural home for a private config
181
+ repo.
182
+
183
+ ```text
184
+ instance/
185
+ config.yaml # overlay config — merged over the public config/default.yaml
186
+ agent-context/*.md # (optional) persona/rules overrides, merged by filename
187
+ workflows/*.yaml # (optional) add or replace workflows by logical name
188
+ skills/<name>/SKILL.md # (optional) skill overrides
189
+ secrets/ # host-only, gitignored: .env + GitHub App *.pem
190
+ .env
191
+ app.pem
192
+ ```
158
193
 
159
- Create a `secrets/` directory with your GitHub App credentials:
194
+ `npx lastlight setup` scaffolds this for you. To do it by hand (or to clone a
195
+ private overlay repo into place):
160
196
 
161
197
  ```bash
162
- mkdir -p secrets
163
- cp .env secrets/
164
- cp your-app.private-key.pem secrets/
198
+ mkdir -p instance/secrets
199
+ cp deploy/.env.production.example instance/secrets/.env # then fill it in
200
+ cp your-app.private-key.pem instance/secrets/app.pem
201
+ chmod 600 instance/secrets/.env instance/secrets/app.pem
202
+ # instance/config.yaml — at minimum your managed repos:
203
+ printf 'managedRepos:\n - your-org/repo-one\n' > instance/config.yaml
165
204
  ```
166
205
 
167
- The entrypoint symlinks these into the container at startup.
206
+ Both the `agent` and `caddy` services read `instance/secrets/.env` via
207
+ `env_file`, and the entrypoint also sources it inside the container — so **no
208
+ repo-root `.env` is needed**. Merge rules: maps (`models`, `variants`, `routes`,
209
+ `approval`) deep-merge over the public defaults; arrays (`managedRepos`,
210
+ `disabled.*`) replace; environment variables override both. Overlay files are
211
+ read at startup — edit and `docker compose restart agent` to apply, no rebuild.
212
+ The dashboard **Config** tab shows Default / Overlay / Merged (non-secret) config
213
+ (secret-looking keys are redacted, so a stray secret in `config.yaml` won't leak).
214
+
215
+ Startup is **fail-fast**: if `LASTLIGHT_OVERLAY_DIR` is set but the folder is
216
+ missing or empty (the common "forgot to populate `instance/`" case), or a cron
217
+ targets a missing workflow, or a phase's prompt/skill can't resolve, the harness
218
+ exits `78` with a clear message instead of booting a broken instance.
168
219
 
169
220
  ### Expose Webhooks
170
221
 
171
- To receive GitHub webhooks, the server needs to be publicly reachable. The included Caddy config handles HTTPS:
222
+ To receive GitHub webhooks, the server needs to be publicly reachable. The included Caddy config handles HTTPS — set `DOMAIN` in `instance/secrets/.env`:
172
223
 
173
224
  ```bash
174
- # Set your domain
175
- echo "DOMAIN=lastlight.example.com" >> .env
225
+ # In instance/secrets/.env:
226
+ # DOMAIN=lastlight.example.com
176
227
 
177
228
  # Start both agent and caddy
178
- docker-compose up -d
229
+ docker compose up -d
179
230
  ```
180
231
 
181
232
  Or use [ngrok](https://ngrok.com) / [Cloudflare Tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) for testing.
@@ -186,12 +237,14 @@ All persistent state lives in a single Docker volume (`agent-data`), mounted at
186
237
 
187
238
  ```
188
239
  data/
189
- lastlight.db # SQLite: execution log, rate limits
190
- claude-home/ # Claude auth + session JSONL logs
191
- projects/-app/*.jsonl # Full audit trail per agent session
192
- sandboxes/ # Cloned repos per task
240
+ lastlight.db # SQLite: executions, workflow_runs, approvals, messaging sessions
241
+ agent-sessions/ # Dashboard JSONL envelope store (written by event-shim.ts)
242
+ projects/-app/*.jsonl # Chat sessions (one per Slack thread)
243
+ projects/-home-agent-workspace/*.jsonl # Sandbox-mode workflow sessions
244
+ sandboxes/ # Cloned repos per task (gondolin or docker)
245
+ sandbox-data/ # Shared volume mounted into docker-mode sandboxes
193
246
  logs/ # Structured logs
194
- sessions/ # (reserved)
247
+ secrets/app.pem # GitHub App PEM (mode 600) for sandbox access
195
248
  ```
196
249
 
197
250
  Mount this volume or bind-mount the directory for monitoring tools to access session logs and the execution database.
@@ -213,6 +266,29 @@ npx tsx src/cli.ts triage owner/repo
213
266
 
214
267
  ---
215
268
 
269
+ ## Native (systemd) Deploy
270
+
271
+ For a Linux production host with KVM available (`/dev/kvm`), the native deploy runs the harness directly under systemd and uses gondolin for sandboxing — no Docker required.
272
+
273
+ See [deploy/native/README.md](deploy/native/README.md) for the full runbook. The short version:
274
+
275
+ ```bash
276
+ git clone https://github.com/cliftonc/lastlight.git /opt/lastlight
277
+ cd /opt/lastlight
278
+ # (optional) install -m 0600 -o root /path/to/app.pem /etc/lastlight/app.pem
279
+ sudo bash deploy/native/install.sh # scaffolds /etc/lastlight/lastlight.env
280
+ sudo $EDITOR /etc/lastlight/lastlight.env # fill in secrets
281
+ sudo bash deploy/native/install.sh # second run: starts the service
282
+ ```
283
+
284
+ Re-deploys: `git pull && sudo bash deploy/native/install.sh` (idempotent — rebuilds and restarts the service).
285
+
286
+ **Required:** the host kernel must expose `/dev/kvm` (bare-metal Linux or KVM-enabled VM). Hetzner Cloud, Cloud Run, Fly Machines (without `--vm-cpu-class shared`), and most managed container hosts do **not** expose nested virt — see `agentic-pi`'s `SPIKE-gondolin.md` for the full constraint matrix.
287
+
288
+ If KVM isn't available, fall back to the Docker deploy above with `LASTLIGHT_SANDBOX=docker`.
289
+
290
+ ---
291
+
216
292
  ## Setup Details
217
293
 
218
294
  ### 1. Create a GitHub App
@@ -227,8 +303,9 @@ npx tsx src/cli.ts triage owner/repo
227
303
  - **Issues**: Read & Write
228
304
  - **Pull Requests**: Read & Write
229
305
  - **Contents**: Read & Write
306
+ - **Checks**: Read & Write (post the `last-light/review` check; receive its "Re-run" requests)
230
307
  - **Metadata**: Read
231
- 4. Subscribe to **events**: `Issues`, `Pull request`, `Issue comment`
308
+ 4. Subscribe to **events**: `Issues`, `Pull request`, `Issue comment`, `Check run`, `Check suite` (the last two enable the GitHub "Re-run checks" buttons to re-trigger a review)
232
309
  5. Click **Create GitHub App**
233
310
  6. Click **Generate a private key** — save the `.pem` file into the project directory
234
311
  7. Note the **App ID** from the app settings page
@@ -237,43 +314,96 @@ npx tsx src/cli.ts triage owner/repo
237
314
 
238
315
  ### 2. Environment Variables
239
316
 
317
+ Legacy `OPENCODE_*` names are still read as fallbacks for the corresponding `LASTLIGHT_*` names, so existing `.env` files from the OpenCode era keep working.
318
+
240
319
  | Variable | Required | Description |
241
320
  |----------|----------|-------------|
242
321
  | `GITHUB_APP_ID` | Yes | GitHub App ID |
243
322
  | `GITHUB_APP_PRIVATE_KEY_PATH` | Yes | Path to `.pem` file |
244
323
  | `GITHUB_APP_INSTALLATION_ID` | Yes | Installation ID |
245
324
  | `WEBHOOK_SECRET` | Yes | GitHub webhook signature secret |
246
- | `ANTHROPIC_API_KEY` | No | Anthropic API key (uses Claude login if not set) |
247
- | `CLAUDE_MODEL` | No | Model to use (default: `claude-sonnet-4-6`) |
325
+ | `OPENAI_API_KEY` | One of | API key when using `openai/…` models |
326
+ | `ANTHROPIC_API_KEY` | One of | API key when using `anthropic/…` models |
327
+ | `OPENROUTER_API_KEY` | One of | API key when using `openrouter/…` models |
328
+ | `LASTLIGHT_OVERLAY_DIR` | No | Trusted deployment overlay directory (the docker-compose stack mounts `instance/` here as `/app/instance`). Startup loads `config/default.yaml`, optional `$LASTLIGHT_OVERLAY_DIR/config.yaml`, then env overrides; overlay assets under `workflows/`, `workflows/prompts/`, `skills/`, and `agent-context/` replace built-ins. Secrets live in `$LASTLIGHT_OVERLAY_DIR/secrets/`. Restart required after changes. See [Deployment overlay](#deployment-overlay). |
329
+ | `LASTLIGHT_MODEL` | No | Default model (default: `anthropic/claude-sonnet-4-6`). Legacy: `OPENCODE_MODEL`. |
330
+ | `LASTLIGHT_MODELS` | No | Per-task model overrides as JSON, e.g. `{"chat":"openai/gpt-5.1-mini","architect":"openai/gpt-5.5"}`. Legacy: `OPENCODE_MODELS`. |
331
+ | `LASTLIGHT_THINKING` | No | Reasoning-effort default (`off` \| `minimal` \| `low` \| `medium` \| `high` \| `xhigh`). pi-ai translates per-provider. Legacy: `OPENCODE_VARIANT`. |
332
+ | `LASTLIGHT_THINKINGS` | No | Per-task thinking-level overrides as JSON, e.g. `{"architect":"high","reviewer":"high","triage":"minimal"}`. Legacy: `OPENCODE_VARIANTS`. |
333
+ | `LASTLIGHT_SANDBOX` | No | Workflow sandbox backend: `gondolin` (default) \| `docker` \| `none`. |
334
+ | `LASTLIGHT_OTEL_ENABLED` | No | Enable OpenTelemetry export (default: `false`). Standard `OTEL_*` env vars alone do not enable telemetry. |
335
+ | `LASTLIGHT_OTEL_SERVICE_NAME` | No | OTEL service name (default: `lastlight`; falls back to `OTEL_SERVICE_NAME`). |
336
+ | `LASTLIGHT_OTEL_INCLUDE_CONTENT` | No | Include prompts/message/tool-result content in telemetry (default: `false`; sensitive, use carefully). |
337
+ | `LASTLIGHT_OTEL_FORWARD_TO_SANDBOX` | No | Forward sandbox telemetry to the backend (default: `true`). On the `docker` backend this routes through an in-network OTEL collector; on `gondolin`/`none` it forwards allowlisted `OTEL_*` env vars directly. |
338
+ | `LASTLIGHT_OTEL_STRICT` | No | Throw on OTEL initialization/export setup failure instead of warn-and-continue (default: `false`). |
339
+ | `LASTLIGHT_OTEL_COLLECTOR_HOSTS` | No | Comma-separated collector hostnames added to the strict sandbox egress allowlist. Used only by the `gondolin` backend (the `docker` backend reaches its collector internally and ignores this). |
340
+ | `OTEL_EXPORTER_OTLP_ENDPOINT`, `OTEL_EXPORTER_OTLP_*_ENDPOINT` | No | Standard OTLP HTTP collector endpoints. Used by the harness directly, and by the in-network collector as its re-export target on the `docker` backend. |
341
+ | `OTEL_EXPORTER_OTLP_HEADERS`, `OTEL_EXPORTER_OTLP_*_HEADERS` | No | Standard OTLP headers; secret/env-only and never shown in public config. |
342
+ | `OTEL_SERVICE_NAME`, `OTEL_RESOURCE_ATTRIBUTES` | No | Standard OTEL resource configuration. |
343
+ | `LASTLIGHT_SESSIONS_DIR` | No | Where the dashboard reads sessions (default: `$STATE_DIR/agent-sessions`). |
248
344
  | `PORT` / `WEBHOOK_PORT` | No | Webhook listener port (default: `8644`) |
249
345
  | `STATE_DIR` | No | Persistent state directory (default: `./data`) |
250
- | `MAX_TURNS` | No | Max agent turns per invocation (default: `200`) |
346
+ | `DB_PATH` | No | SQLite path (default: `$STATE_DIR/lastlight.db`) |
347
+ | `MAX_TURNS` | No | Reserved (kept for API stability) |
251
348
  | `BOT_LOGIN` | No | Bot login name for self-event filtering (default: `last-light[bot]`) |
252
- | `LASTLIGHT_LOCAL_DEV` | No | Set to `1` to skip `git config --global` writes from `git-auth.ts`. Use this on dev machines so the harness doesn't overwrite your personal `~/.gitconfig`. The installation token is still passed to sandboxes via the `GIT_TOKEN` env var. |
253
- | `SANDBOX_DATA_VOLUME` | No | Either a Docker named volume name (default: `lastlight_agent-data`, used in production) or a host path (starts with `/`, `./`, `../`, or `~`) to bind-mount as `/data` inside each sandbox. Local dev uses `./data/sandbox-claude-home`. |
254
- | `CLAUDE_HOME_DIR` | No | Directory the dashboard reads sessions from (default: `./data/claude-home`). Local dev points this at `./data/sandbox-claude-home` to match the bind-mounted sandbox volume. |
255
- | `ENABLE_DIRECT_FALLBACK` | No | If `true`, the harness falls back to in-process Agent SDK execution when the sandbox image is unavailable. Local dev sets this to `false` to keep all agent work isolated in containers. |
349
+ | `LASTLIGHT_LOCAL_DEV` | No | Set to `1` on dev machines to skip `git config --global` writes from `git-auth.ts`. The installation token still reaches sandboxes via `GIT_TOKEN`. |
350
+ | `SANDBOX_DATA_VOLUME` | No | Used only when `LASTLIGHT_SANDBOX=docker`. Either a Docker named volume (default: `lastlight_agent-data`) or a host path (`/`, `./`, `../`, `~`) to bind-mount as `/data` inside each sandbox. Local dev uses `./data/sandbox-data`. |
351
+
352
+ ### OpenTelemetry export
353
+
354
+ OpenTelemetry is disabled by default. Set `LASTLIGHT_OTEL_ENABLED=true` and configure standard OTEL exporter env vars such as `OTEL_EXPORTER_OTLP_ENDPOINT`, `OTEL_EXPORTER_OTLP_HEADERS`, and `OTEL_RESOURCE_ATTRIBUTES` to export harness spans/metrics for workflow runs, phases, agent executions, PI event streams, and chat turns.
355
+
356
+ By default Last Light exports metadata only: workflow/phase names, repo, sandbox backend, model, success/stop reason, timing, tokens, and cost. Prompt text, message content, tool arguments, and tool outputs are redacted unless `LASTLIGHT_OTEL_INCLUDE_CONTENT=true`; that opt-in can export sensitive data and should only be used with a trusted collector.
357
+
358
+ When `LASTLIGHT_OTEL_FORWARD_TO_SANDBOX=true` (default), `agentic-pi` workflow sandboxes emit their own telemetry too. How it reaches the backend depends on the sandbox backend:
359
+
360
+ - **`docker` (production):** sandboxes export OTLP to an **in-network OTEL collector** (a `otel-collector` compose service on the `sandbox-egress` network, reached by a fixed internal IP). That collector re-exports to your real backend over its own outbound network leg. This means the sandbox only ever dials one fixed internal endpoint — collectors on any port or scheme (e.g. `https://collector:4318`) work without special egress rules, and the backend endpoint and auth headers (`OTEL_EXPORTER_OTLP_HEADERS`) stay host-side and are **never** forwarded into the untrusted sandbox. The collector cannot be redirected by sandbox traffic, so it adds no SSRF/exfil surface.
361
+ - **`gondolin` / `none`:** `agentic-pi` runs in the harness process and already inherits the harness OTEL SDK. Allowlisted `OTEL_*` env vars are forwarded into the sandbox shell env directly; `gondolin` adds collector hosts (parsed from `OTEL_EXPORTER_OTLP_ENDPOINT`, signal-specific endpoint env vars, and `LASTLIGHT_OTEL_COLLECTOR_HOSTS`) to its egress allowlist. Private/internal metadata hosts remain blocked.
362
+
363
+ Set `LASTLIGHT_OTEL_FORWARD_TO_SANDBOX=false` to disable sandbox telemetry entirely and keep collector endpoints/headers in the harness only.
256
364
 
257
365
  ### 3. Managed Repositories
258
366
 
259
- Edit `agent-context/rules.md` to list repositories the bot manages:
367
+ The public `config/default.yaml` ships an **empty** `managedRepos` list — set
368
+ yours in the overlay (`instance/config.yaml`), which replaces the list wholesale:
260
369
 
261
- ```markdown
262
- ## Managed Repositories
263
- - your-org/repo-one
264
- - your-org/repo-two
370
+ ```yaml
371
+ managedRepos:
372
+ - your-org/repo-one
373
+ - your-org/repo-two
265
374
  ```
266
375
 
376
+ Webhooks for repos not in this list are filtered at the connector level; Slack/CLI
377
+ commands targeting unmanaged repos are rejected. Install the GitHub App on each.
378
+
267
379
  ### 4. Customize Behaviour
268
380
 
381
+ Put deployment-specific changes in your overlay (`instance/`) instead of editing
382
+ packaged files — that keeps your config out of the public repo and applies on a
383
+ restart (no rebuild). See [Deployment overlay](#deployment-overlay) for the full
384
+ model and layout.
385
+
386
+ ```text
387
+ instance/
388
+ config.yaml # non-secret config overrides only
389
+ workflows/*.yaml # add/replace workflows by logical `name`
390
+ workflows/prompts/*.md # prompt overrides/fallbacks
391
+ skills/<name>/SKILL.md # skill overrides/fallbacks
392
+ agent-context/*.md # merged by filename; overlay replaces built-ins
393
+ secrets/ # host-only, gitignored: .env + *.pem
394
+ ```
395
+
396
+ The dashboard Config tab shows Default / Overlay / Merged non-secret config.
397
+ Overlay files are read at startup only; `docker compose restart agent` after changes.
398
+
269
399
  | What | Where |
270
400
  |------|-------|
271
- | Bot personality & communication style | `agent-context/soul.md` |
272
- | Operational rules, review guidelines, triage rules | `agent-context/rules.md` |
273
- | Skill definitions | `skills/*/SKILL.md` |
274
- | Orchestrator phases (Architect/Executor/Reviewer) | `src/engine/orchestrator.ts` |
275
- | Event routing rules | `src/engine/router.ts` |
276
- | Cron job schedules | `src/cron/jobs.ts` |
401
+ | Managed repos, routes, models, variants, approvals, disables | overlay `instance/config.yaml` (over `config/default.yaml`) |
402
+ | Bot personality & communication style | `agent-context/soul.md` or overlay `instance/agent-context/` |
403
+ | Operational rules, review guidelines, triage rules | `agent-context/rules.md` or overlay `instance/agent-context/` |
404
+ | Skill definitions | `skills/*/SKILL.md` or overlay `instance/skills/` |
405
+ | Workflow phases (Architect/Executor/Reviewer/PR) | `workflows/*.yaml` + `workflows/prompts/` or overlay equivalents |
406
+ | Cron job schedules | `workflows/cron-*.yaml` or overlay workflows |
277
407
 
278
408
  ---
279
409
 
@@ -282,7 +412,7 @@ Edit `agent-context/rules.md` to list repositories the bot manages:
282
412
  ```
283
413
  ┌─────────────────────────────────────────┐
284
414
  │ Connector Layer │
285
- │ GitHub Webhook │ (future: Slack, etc.)
415
+ │ GitHub Webhook │ Slack Socket Mode
286
416
  │ ↓ │ ↓ │
287
417
  │ Event Normalizer (EventEnvelope) │
288
418
  └────────────────┬────────────────────────┘
@@ -291,10 +421,11 @@ Edit `agent-context/rules.md` to list repositories the bot manages:
291
421
  │ Core Engine │
292
422
  │ Event Router (deterministic) │
293
423
  │ ↓ │
294
- Agent Executor (Claude Agent SDK)
295
- │ - System prompt from agent-context/
296
- - MCP tools (GitHub App)
297
- │ - Skills (SKILL.md)
424
+ Workflow Runner (YAML phases)
425
+ │ - Sandbox: `agentic-pi run` per phase
426
+ in a gondolin VM or docker container
427
+ │ - Chat: in-process pi-ai loop
428
+ │ one session per messaging thread │
298
429
  │ ↓ │
299
430
  │ Sandboxes (git clone per task) │
300
431
  │ Cron Scheduler (health reports) │
@@ -308,9 +439,9 @@ Edit `agent-context/rules.md` to list repositories the bot manages:
308
439
  2. **Router** maps event type to skill deterministically (no LLM in the routing loop):
309
440
  - `issue.opened` → `issue-triage`
310
441
  - `pr.opened` → `pr-review`
311
- - `comment.created` with `@last-light` from maintainer → `github-orchestrator`
312
- 3. **Executor** spawns a Claude Agent SDK session with the skill prompt, MCP tools, and agent context
313
- 4. **Orchestrator** (for build requests) runs a multi-phase cycle:
442
+ - `comment.created` with `@last-light` from a maintainer → routed by intent classifier (build / explore / triage / review / action)
443
+ 3. **Workflow runner** loads the matching YAML, dispatches each phase to `executeAgent` (`src/engine/agent-executor.ts`, which invokes agentic-pi) or, for chat, `ChatRunner` (`src/engine/chat-runner.ts`, in-process pi-ai)
444
+ 4. **Build workflow** runs a multi-phase cycle:
314
445
  - Phase 1: **Architect** — read-only analysis, writes plan to `.lastlight/issue-N/architect-plan.md`
315
446
  - Phase 2: **Executor** — TDD implementation following the plan
316
447
  - Phase 3: **Reviewer** — independent verification (no shared context with executor)
@@ -343,15 +474,27 @@ lastlight/
343
474
  index.ts # Connector registry
344
475
  engine/
345
476
  router.ts # Deterministic event → skill routing
346
- executor.ts # Agent SDK query() wrapper
347
- orchestrator.ts # Architect Executor Reviewer cycle
348
- agents.ts # Subagent role definitions
477
+ agent-executor.ts # Workflow phase runner: invokes agentic-pi
478
+ # (gondolin / docker / none backends)
479
+ chat-runner.ts # In-process pi-ai chat loop; one session per
480
+ # Slack/Discord thread, rehydrated from DB
481
+ chat.ts # Chat skill (delegates to ChatRunner)
482
+ github-tools.ts # Read-only GitHub tools surfaced to chat
483
+ event-shim.ts # Translates agentic-pi events → Claude-SDK
484
+ # envelope jsonl for the dashboard reader
485
+ profiles.ts # ExecutorConfig / ExecutionResult types +
486
+ # GITHUB_PERMISSION_PROFILES + loadAgentContext
487
+ llm.ts # One-shot LLM helper for screen + classifier
488
+ screen.ts # Prompt-injection screener
489
+ classifier.ts # Intent classifier (build / explore / triage / …)
349
490
  git-auth.ts # GitHub App git credential setup
350
- worktree/
351
- manager.ts # Git worktree per-task isolation
491
+ github.ts # Harness-side Octokit client (comments, etc.)
492
+ workflows/ # YAML workflow runner (see src/workflows/CLAUDE.md)
493
+ sandbox/ # Per-task workspace + docker-sandbox lifecycle
352
494
  cron/
353
495
  scheduler.ts # Cron with overlap protection
354
- jobs.ts # Job definitions
496
+ jobs.ts # Cron job registry
497
+ admin/ # Dashboard API (Hono) + session readers
355
498
  state/
356
499
  db.ts # SQLite execution tracking
357
500
 
@@ -367,15 +510,24 @@ lastlight/
367
510
  github/ # GitHub API workflow skills
368
511
  software-development/ # Dev skills (architect, TDD, debugging)
369
512
 
370
- mcp-github-app/ # MCP server: 28+ GitHub tools via Octokit
371
- src/
372
- index.js # MCP server entry (clone_repo, refresh_git_auth, etc.)
373
- auth.js # GitHub App JWT + installation token
374
- github.js # Octokit wrapper with retry/backoff
513
+ workflows/ # YAML workflow definitions
514
+ build.yaml # Architect → Executor → Reviewer → PR
515
+ issue-triage.yaml
516
+ pr-review.yaml
517
+ repo-health.yaml
518
+ cron-*.yaml # Cron-kind triggers
519
+ prompts/ # Per-phase prompt templates
375
520
 
376
521
  deploy/
377
- entrypoint.sh # Docker entrypoint
378
- Dockerfile
522
+ entrypoint.sh # Docker entrypoint (harness container)
523
+ sandbox-entrypoint.sh # Sandbox container entrypoint (docker-sandbox mode)
524
+ native/ # Native (systemd) deploy artifacts
525
+ lastlight.service # systemd unit
526
+ install.sh # Idempotent provision + redeploy script
527
+ lastlight.env.example # Env template for /etc/lastlight/lastlight.env
528
+ README.md # Native-deploy operator runbook
529
+ Dockerfile # Harness image (test-only; prod uses native deploy)
530
+ sandbox.Dockerfile # Sandbox image for LASTLIGHT_SANDBOX=docker
379
531
  docker-compose.yml
380
532
  Caddyfile # Reverse proxy for HTTPS
381
533
  ```
@@ -390,36 +542,41 @@ npm run dev:server
390
542
  # Look for "Required environment variable not set" errors
391
543
  ```
392
544
 
393
- ### `npm run dev` says the sandbox image is missing
545
+ ### `npm run dev` says the sandbox image is missing (docker-sandbox mode)
394
546
 
395
547
  ```bash
396
548
  docker compose --profile build-only build sandbox
397
549
  ```
398
550
 
399
- ### `npm run dev` says claude is not logged in
551
+ ### Workflow run fails with `exit 127: sh: 1: agentic-pi: not found`
552
+
553
+ The sandbox image needs `agentic-pi` baked in. Rebuild it:
400
554
 
401
555
  ```bash
402
- claude login # then re-run npm run dev
556
+ docker compose --profile build-only build sandbox
403
557
  ```
404
558
 
405
- ### Agent exits with code 1
559
+ If you're on an old `lastlight-sandbox:latest`, this picks up the install step that the current `sandbox.Dockerfile` performs.
406
560
 
407
- ```bash
408
- # Check if Claude is logged in
409
- claude --version && claude -p "hello"
561
+ ### Workflow hangs forever with no output (gondolin mode on a host without KVM)
410
562
 
411
- # In Docker: check auth persisted
412
- docker exec lastlight-agent-1 claude -p "hello"
413
- # If it fails, re-login AS THE LASTLIGHT USER (not root!):
414
- docker exec -it --user lastlight lastlight-agent-1 claude login
415
- ```
563
+ Gondolin requires `/dev/kvm` on Linux or HVF on macOS. Inside a container with no nested virt, `VM.create()` succeeds but the first `vm.exec()` hangs. Symptoms: phase shows "running" indefinitely with no JSONL events after `sandbox_status`.
564
+
565
+ Either switch to `LASTLIGHT_SANDBOX=docker` (sibling containers via socket) or move the harness to a KVM-capable host. Full analysis: `agentic-pi/SPIKE-gondolin.md`.
566
+
567
+ ### Agent run fails with a quota / billing error
568
+
569
+ The runtime surfaces upstream errors as `error_api` with the verbatim provider message in the executions row:
416
570
 
417
- **IMPORTANT**: Always use `--user lastlight` when running `claude login` in Docker. Running as root causes:
418
- - Permission errors (`.credentials.json` owned by root, session logs unwritable)
419
- - Config corruption (cached feature flags wiped, MCP auth cache polluted with Claude.ai servers)
420
- - `bypassPermissions` mode may stop working with MCP servers attached
571
+ - OpenAI: "Quota exceeded. Check your plan and billing details." top up at https://platform.openai.com/account/billing
572
+ - Anthropic: "Credit balance is too low" top up at https://console.anthropic.com
421
573
 
422
- If you accidentally logged in as root, rebuild the container: `docker compose build agent && docker compose up -d agent`
574
+ ### Chat replies fail with `error_error`
575
+
576
+ Check the agent logs for the underlying error — common causes:
577
+
578
+ - **Wrong key for the chat model.** `LASTLIGHT_MODELS={"chat":"anthropic/…"}` but no `ANTHROPIC_API_KEY` set. Fix the override or add the key.
579
+ - **Model id typo.** Watch for `[config] Model: …` in startup logs to confirm what's actually loaded.
423
580
 
424
581
  ### Webhooks not arriving
425
582
 
@@ -431,15 +588,5 @@ curl http://localhost:8644/health
431
588
  curl -X POST http://localhost:8644/webhooks/github -d '{}'
432
589
 
433
590
  # Check Docker port mapping
434
- docker-compose ps
591
+ docker compose ps
435
592
  ```
436
-
437
- ### Credit balance / rate limit errors
438
-
439
- If you see "Credit balance is too low", either:
440
- - Top up at https://console.anthropic.com (API key mode)
441
- - Remove `ANTHROPIC_API_KEY` from `.env` to use your Claude subscription instead
442
-
443
- ### Permission denied on MCP tools
444
-
445
- The executor runs with `bypassPermissions` mode. In Docker, this requires running as a non-root user (the Dockerfile handles this automatically).