create-walle 0.9.21 → 0.9.23

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 (500) hide show
  1. package/README.md +27 -5
  2. package/package.json +2 -2
  3. package/template/CLAUDE.md +2 -2
  4. package/template/LICENSE +1 -1
  5. package/template/bin/ctm-dev-cleanup.js +24 -3
  6. package/template/bin/ctm-launch.sh +13 -0
  7. package/template/bin/dev.sh +156 -18
  8. package/template/bin/node-bin.sh +84 -0
  9. package/template/bin/pin-node.sh +51 -0
  10. package/template/claude-task-manager/api-prompts.js +1203 -182
  11. package/template/claude-task-manager/api-reviews.js +109 -15
  12. package/template/claude-task-manager/approval-agent.js +1360 -280
  13. package/template/claude-task-manager/bin/restart-ctm.sh +64 -23
  14. package/template/claude-task-manager/bin/storage-migration-supervisor.js +338 -0
  15. package/template/claude-task-manager/db.js +4417 -295
  16. package/template/claude-task-manager/docs/app-update-refresh-protocol.md +69 -0
  17. package/template/claude-task-manager/docs/approval-ai-refinement.md +138 -0
  18. package/template/claude-task-manager/docs/approval-rescue-loop.md +74 -0
  19. package/template/claude-task-manager/docs/codex-operational-warning-health.md +107 -0
  20. package/template/claude-task-manager/docs/codex-resume-state-guard-design.md +17 -12
  21. package/template/claude-task-manager/docs/codex-terminal-render-controller-handoff.md +311 -0
  22. package/template/claude-task-manager/docs/coding-agent-hooks-architecture.md +418 -0
  23. package/template/claude-task-manager/docs/conversation-import-freshness.md +20 -0
  24. package/template/claude-task-manager/docs/google-workspace-auth-health.md +77 -0
  25. package/template/claude-task-manager/docs/image-paste-ux.md +13 -0
  26. package/template/claude-task-manager/docs/ipad-web-preview.md +88 -0
  27. package/template/claude-task-manager/docs/main-loop-offload-architecture.md +66 -0
  28. package/template/claude-task-manager/docs/microsoft-dev-tunnel-phone-access-design.md +274 -519
  29. package/template/claude-task-manager/docs/mobile-live-streaming.md +27 -5
  30. package/template/claude-task-manager/docs/mobile-remote-submission-lifecycle.md +69 -0
  31. package/template/claude-task-manager/docs/phone-access-design.md +53 -15
  32. package/template/claude-task-manager/docs/phone-passkey-identity.md +122 -0
  33. package/template/claude-task-manager/docs/phone-setup.md +3 -0
  34. package/template/claude-task-manager/docs/prompt-editing-tree-design.md +25 -1
  35. package/template/claude-task-manager/docs/remote-desktop-access-design.md +268 -0
  36. package/template/claude-task-manager/docs/restart-lifecycle-architecture.md +95 -0
  37. package/template/claude-task-manager/docs/runtime-work-control-plane.md +53 -0
  38. package/template/claude-task-manager/docs/session-interactive-wait-surfaces.md +38 -0
  39. package/template/claude-task-manager/docs/session-needs-you-dismissal.md +84 -0
  40. package/template/claude-task-manager/docs/session-render-state-management-design.md +91 -3
  41. package/template/claude-task-manager/docs/session-standup-command-center-design.md +25 -1
  42. package/template/claude-task-manager/docs/session-title-authority.md +32 -0
  43. package/template/claude-task-manager/docs/session-workspace-binding.md +33 -0
  44. package/template/claude-task-manager/docs/skill-intent-resolution-design.md +72 -0
  45. package/template/claude-task-manager/docs/walle-mcp-supervisor-health.md +86 -0
  46. package/template/claude-task-manager/docs/walle-relay-phone-access-design.md +24 -15
  47. package/template/claude-task-manager/docs/walle-session-history-hydration.md +114 -0
  48. package/template/claude-task-manager/docs/walle-session-input-queue.md +104 -0
  49. package/template/claude-task-manager/docs/walle-session-model-catalog.md +90 -0
  50. package/template/claude-task-manager/docs/walle-session-model-preferences.md +15 -6
  51. package/template/claude-task-manager/git-utils.js +897 -27
  52. package/template/claude-task-manager/lib/agent-capabilities.js +33 -0
  53. package/template/claude-task-manager/lib/agent-cli-cache.js +37 -7
  54. package/template/claude-task-manager/lib/agent-hooks-installer.js +26 -2
  55. package/template/claude-task-manager/lib/agent-presets.js +17 -1
  56. package/template/claude-task-manager/lib/all-sessions-query.js +108 -0
  57. package/template/claude-task-manager/lib/approval-ai-refinement.js +488 -0
  58. package/template/claude-task-manager/lib/approval-self-adapt.js +168 -0
  59. package/template/claude-task-manager/lib/async-semaphore.js +44 -0
  60. package/template/claude-task-manager/lib/auth-context.js +5 -0
  61. package/template/claude-task-manager/lib/auth-rate-limit.js +47 -4
  62. package/template/claude-task-manager/lib/auth-rules.js +29 -2
  63. package/template/claude-task-manager/lib/auto-approval-verifier.js +129 -16
  64. package/template/claude-task-manager/lib/background-llm.js +144 -17
  65. package/template/claude-task-manager/lib/branch-inventory.js +212 -0
  66. package/template/claude-task-manager/lib/claude-desktop-sessions.js +15 -3
  67. package/template/claude-task-manager/lib/coalesce-sync-frames.js +151 -0
  68. package/template/claude-task-manager/lib/codex-launch-health.js +762 -0
  69. package/template/claude-task-manager/lib/codex-transcript-pager.js +51 -0
  70. package/template/claude-task-manager/lib/codex-zst.js +124 -0
  71. package/template/claude-task-manager/lib/coding-agent-models.js +233 -30
  72. package/template/claude-task-manager/lib/connection-health.js +232 -0
  73. package/template/claude-task-manager/lib/conversation-blob-parser.js +42 -0
  74. package/template/claude-task-manager/lib/conversation-tail-merge.js +89 -26
  75. package/template/claude-task-manager/lib/ctm-session-context-api.js +39 -10
  76. package/template/claude-task-manager/lib/cursor-conversation-store.js +354 -0
  77. package/template/claude-task-manager/lib/db-owner-worker-client.js +315 -0
  78. package/template/claude-task-manager/lib/document-review.js +141 -6
  79. package/template/claude-task-manager/lib/escalation-review.js +152 -0
  80. package/template/claude-task-manager/lib/graceful-shutdown.js +159 -0
  81. package/template/claude-task-manager/lib/headless-term-service.js +678 -0
  82. package/template/claude-task-manager/lib/heavy-worker-fallback.js +38 -0
  83. package/template/claude-task-manager/lib/jsonl-conversation-parser.js +542 -0
  84. package/template/claude-task-manager/lib/jsonl-range-reader.js +112 -0
  85. package/template/claude-task-manager/lib/main-db-census.js +216 -0
  86. package/template/claude-task-manager/lib/message-pagination.js +106 -4
  87. package/template/claude-task-manager/lib/microsoft-dev-tunnel-setup.js +750 -26
  88. package/template/claude-task-manager/lib/mobile-auth-api.js +274 -7
  89. package/template/claude-task-manager/lib/mobile-auth-store.js +592 -10
  90. package/template/claude-task-manager/lib/mobile-notification-dispatcher.js +15 -0
  91. package/template/claude-task-manager/lib/model-overview-brain-fallback.js +311 -0
  92. package/template/claude-task-manager/lib/model-overview-cache.js +141 -0
  93. package/template/claude-task-manager/lib/models-health-routing-notice.js +126 -0
  94. package/template/claude-task-manager/lib/node-pin-guard.js +93 -0
  95. package/template/claude-task-manager/lib/perf-tracker.js +242 -6
  96. package/template/claude-task-manager/lib/permission-match.js +76 -0
  97. package/template/claude-task-manager/lib/permission-sync.js +133 -20
  98. package/template/claude-task-manager/lib/process-title.js +35 -0
  99. package/template/claude-task-manager/lib/prompt-executions-query.js +25 -0
  100. package/template/claude-task-manager/lib/prompt-index-disk-cache.js +44 -0
  101. package/template/claude-task-manager/lib/prompt-intent.js +132 -0
  102. package/template/claude-task-manager/lib/provider-user-context.js +34 -0
  103. package/template/claude-task-manager/lib/read-pool-client.js +313 -0
  104. package/template/claude-task-manager/lib/readpool-breaker.js +31 -0
  105. package/template/claude-task-manager/lib/recent-sessions-breaker.js +12 -0
  106. package/template/claude-task-manager/lib/remote-feedback-client.js +72 -0
  107. package/template/claude-task-manager/lib/remote-relay-protocol.js +37 -4
  108. package/template/claude-task-manager/lib/remote-relay-store.js +159 -0
  109. package/template/claude-task-manager/lib/remote-submission-observer.js +278 -0
  110. package/template/claude-task-manager/lib/restart-guard.js +109 -0
  111. package/template/claude-task-manager/lib/restore-interruption-detector.js +439 -0
  112. package/template/claude-task-manager/lib/restore-policy.js +13 -0
  113. package/template/claude-task-manager/lib/restore-resume-batch.js +74 -0
  114. package/template/claude-task-manager/lib/restore-runtime.js +68 -0
  115. package/template/claude-task-manager/lib/restore-storm.js +34 -0
  116. package/template/claude-task-manager/lib/resume-cwd.js +36 -0
  117. package/template/claude-task-manager/lib/resume-preflight.js +313 -0
  118. package/template/claude-task-manager/lib/runtime-work-registry.js +444 -0
  119. package/template/claude-task-manager/lib/sanitize-openai-auth.js +31 -0
  120. package/template/claude-task-manager/lib/scheduler.js +21 -1
  121. package/template/claude-task-manager/lib/scrollback-snapshot-store.js +159 -0
  122. package/template/claude-task-manager/lib/serial-task-queue.js +64 -0
  123. package/template/claude-task-manager/lib/server-listeners.js +239 -0
  124. package/template/claude-task-manager/lib/session-capture.js +42 -7
  125. package/template/claude-task-manager/lib/session-content-backfill.js +131 -0
  126. package/template/claude-task-manager/lib/session-history.js +388 -43
  127. package/template/claude-task-manager/lib/session-host-manager.js +287 -0
  128. package/template/claude-task-manager/lib/session-image-refs.js +209 -0
  129. package/template/claude-task-manager/lib/session-jobs.js +399 -59
  130. package/template/claude-task-manager/lib/session-prompt-index.js +137 -0
  131. package/template/claude-task-manager/lib/session-restore.js +53 -0
  132. package/template/claude-task-manager/lib/session-standup.js +123 -23
  133. package/template/claude-task-manager/lib/session-state-bus.js +14 -0
  134. package/template/claude-task-manager/lib/session-stream.js +64 -16
  135. package/template/claude-task-manager/lib/session-timeline-summary.js +260 -0
  136. package/template/claude-task-manager/lib/session-token-usage.js +494 -0
  137. package/template/claude-task-manager/lib/session-workspace-binding.js +356 -0
  138. package/template/claude-task-manager/lib/setup-network-config.js +9 -0
  139. package/template/claude-task-manager/lib/size-cap.js +45 -0
  140. package/template/claude-task-manager/lib/size-cap.test.js +62 -0
  141. package/template/claude-task-manager/lib/skill-autocomplete.js +180 -1
  142. package/template/claude-task-manager/lib/skill-intent-resolver.js +304 -0
  143. package/template/claude-task-manager/lib/sqlite-driver.js +19 -3
  144. package/template/claude-task-manager/lib/standup-attention.js +7 -3
  145. package/template/claude-task-manager/lib/status-authority.js +39 -0
  146. package/template/claude-task-manager/lib/status-hooks.js +4 -0
  147. package/template/claude-task-manager/lib/storage-migration.js +235 -0
  148. package/template/claude-task-manager/lib/structured-capture.js +298 -0
  149. package/template/claude-task-manager/lib/sync-io-census.js +163 -0
  150. package/template/claude-task-manager/lib/tailscale-setup.js +6 -0
  151. package/template/claude-task-manager/lib/terminal-activity-evidence.js +33 -0
  152. package/template/claude-task-manager/lib/terminal-choice.js +364 -0
  153. package/template/claude-task-manager/lib/terminal-control-sanitize.js +17 -0
  154. package/template/claude-task-manager/lib/terminal-fingerprint.js +48 -0
  155. package/template/claude-task-manager/lib/terminal-output-flush.js +84 -0
  156. package/template/claude-task-manager/lib/timeline-order.js +122 -0
  157. package/template/claude-task-manager/lib/transcript-store.js +348 -43
  158. package/template/claude-task-manager/lib/transport-security.js +84 -1
  159. package/template/claude-task-manager/lib/wait-state.js +184 -0
  160. package/template/claude-task-manager/lib/walle-client.js +47 -5
  161. package/template/claude-task-manager/lib/walle-ctm-history.js +564 -4
  162. package/template/claude-task-manager/lib/walle-external-actions.js +135 -16
  163. package/template/claude-task-manager/lib/walle-history-hydration.js +46 -0
  164. package/template/claude-task-manager/lib/walle-native-health.js +403 -0
  165. package/template/claude-task-manager/lib/walle-repair.js +701 -0
  166. package/template/claude-task-manager/lib/walle-session-cache.js +109 -0
  167. package/template/claude-task-manager/lib/walle-session-context.js +57 -21
  168. package/template/claude-task-manager/lib/walle-session-model-catalog.js +34 -0
  169. package/template/claude-task-manager/lib/walle-supervisor.js +539 -63
  170. package/template/claude-task-manager/lib/walle-transcript.js +52 -0
  171. package/template/claude-task-manager/lib/worktree-active-sync.js +11 -7
  172. package/template/claude-task-manager/lib/worktree-cwd.js +32 -1
  173. package/template/claude-task-manager/package.json +1 -1
  174. package/template/claude-task-manager/prompt-harvest.js +89 -66
  175. package/template/claude-task-manager/providers/claude-code.js +51 -3
  176. package/template/claude-task-manager/providers/cursor.js +140 -45
  177. package/template/claude-task-manager/public/css/reviews.css +551 -61
  178. package/template/claude-task-manager/public/css/setup.css +191 -0
  179. package/template/claude-task-manager/public/css/walle-session.css +865 -10
  180. package/template/claude-task-manager/public/css/walle.css +154 -0
  181. package/template/claude-task-manager/public/designs/ai-providers-consolidation-v2.html +830 -0
  182. package/template/claude-task-manager/public/index.html +18516 -2058
  183. package/template/claude-task-manager/public/ipad.html +363 -0
  184. package/template/claude-task-manager/public/js/document-review-links.js +301 -0
  185. package/template/claude-task-manager/public/js/image-normalize.js +69 -36
  186. package/template/claude-task-manager/public/js/message-renderer.js +1265 -77
  187. package/template/claude-task-manager/public/js/prompts.js +66 -29
  188. package/template/claude-task-manager/public/js/reviews.js +901 -133
  189. package/template/claude-task-manager/public/js/session-activity-utils.js +11 -1
  190. package/template/claude-task-manager/public/js/session-search-utils.js +94 -10
  191. package/template/claude-task-manager/public/js/session-status-precedence.js +23 -5
  192. package/template/claude-task-manager/public/js/setup.js +1273 -176
  193. package/template/claude-task-manager/public/js/stream-view.js +691 -73
  194. package/template/claude-task-manager/public/js/terminal-reconciler.js +210 -0
  195. package/template/claude-task-manager/public/js/walle-session.js +2455 -158
  196. package/template/claude-task-manager/public/js/walle.js +455 -28
  197. package/template/claude-task-manager/public/m/app.css +2909 -262
  198. package/template/claude-task-manager/public/m/app.js +6601 -398
  199. package/template/claude-task-manager/public/m/claim.html +224 -17
  200. package/template/claude-task-manager/public/m/index.html +117 -21
  201. package/template/claude-task-manager/public/m/sw.js +3 -1
  202. package/template/claude-task-manager/public/manifest.json +2 -2
  203. package/template/claude-task-manager/public/prompts.html +30 -14
  204. package/template/claude-task-manager/queue-engine.js +507 -28
  205. package/template/claude-task-manager/scripts/repair-claude-session-images.js +27 -8
  206. package/template/claude-task-manager/server.js +14341 -2197
  207. package/template/claude-task-manager/session-integrity.js +160 -18
  208. package/template/claude-task-manager/session-search-ranking.js +1 -0
  209. package/template/claude-task-manager/session-utils.js +25 -5
  210. package/template/claude-task-manager/workers/approval-blocklist.js +96 -6
  211. package/template/claude-task-manager/workers/approval-widget-validator.js +14 -8
  212. package/template/claude-task-manager/workers/conversation-import-worker.js +11 -50
  213. package/template/claude-task-manager/workers/db-owner-worker.js +386 -0
  214. package/template/claude-task-manager/workers/harvest-worker.js +9 -55
  215. package/template/claude-task-manager/workers/headless-term-worker.js +9 -530
  216. package/template/claude-task-manager/workers/read-pool-worker.js +387 -0
  217. package/template/claude-task-manager/workers/scrollback-worker.js +11 -72
  218. package/template/claude-task-manager/workers/session-host-process.js +146 -0
  219. package/template/claude-task-manager/workers/session-integrity-worker.js +10 -54
  220. package/template/claude-task-manager/workers/state-detectors/base.js +18 -1
  221. package/template/claude-task-manager/workers/state-detectors/claude-code.js +182 -9
  222. package/template/claude-task-manager/workers/state-detectors/codex.js +150 -2
  223. package/template/claude-task-manager/workers/state-detectors/cursor.js +127 -0
  224. package/template/claude-task-manager/workers/state-detectors/gemini.js +21 -0
  225. package/template/claude-task-manager/workers/state-detectors/index.js +29 -0
  226. package/template/claude-task-manager/workers/state-detectors/opencode.js +103 -0
  227. package/template/docs/design/markdown-review-pane.md +206 -0
  228. package/template/docs/designs/2026-05-17-portkey-gateway-provider-ux.md +129 -38
  229. package/template/docs/designs/2026-05-20-mobile-worktree-finish-command.md +27 -0
  230. package/template/docs/designs/2026-05-22-ai-configuration-consolidation.md +248 -0
  231. package/template/docs/designs/ai-configuration-consolidation-mock.html +812 -0
  232. package/template/docs/private-memory-and-pii-policy.md +69 -0
  233. package/template/package.json +2 -1
  234. package/template/scripts/check-private-data.js +201 -0
  235. package/template/shared/sqlite-owner-guard.js +30 -0
  236. package/template/shared/sqlite-owner-write-queue.js +225 -0
  237. package/template/shared/sqlite-storage-policy.js +111 -0
  238. package/template/shared/sqlite-write-lock.js +428 -0
  239. package/template/wall-e/agent-runners/claude-code.js +5 -0
  240. package/template/wall-e/agent.js +166 -22
  241. package/template/wall-e/api-walle.js +524 -70
  242. package/template/wall-e/auth/provider-flows.js +11 -1
  243. package/template/wall-e/bin/walle-mcp-stdio.js +341 -17
  244. package/template/wall-e/brain.js +1614 -141
  245. package/template/wall-e/chat/attachment-blocks.js +96 -0
  246. package/template/wall-e/chat/attachments.js +2 -1
  247. package/template/wall-e/chat/capability-resolver.js +7 -7
  248. package/template/wall-e/chat/context-messages.js +28 -0
  249. package/template/wall-e/chat/conversation-frame.js +630 -0
  250. package/template/wall-e/chat/provider-messages.js +125 -0
  251. package/template/wall-e/chat.js +1002 -233
  252. package/template/wall-e/coding/acceptance-contract.js +170 -0
  253. package/template/wall-e/coding/acp-adapter.js +1 -1
  254. package/template/wall-e/coding/agent-catalog.js +3 -0
  255. package/template/wall-e/coding/artifact-store.js +93 -0
  256. package/template/wall-e/coding/capability-router.js +120 -0
  257. package/template/wall-e/coding/coding-run-controller.js +423 -0
  258. package/template/wall-e/coding/compaction-service.js +157 -12
  259. package/template/wall-e/coding/frontend-verification.js +258 -0
  260. package/template/wall-e/coding/lifecycle-hooks.js +75 -0
  261. package/template/wall-e/coding/local-preview-contract.js +157 -0
  262. package/template/wall-e/coding/permission-service.js +57 -13
  263. package/template/wall-e/coding/prompt-bundle.js +19 -1
  264. package/template/wall-e/coding/prompt-section-registry.js +227 -0
  265. package/template/wall-e/coding/provider-compat.js +15 -0
  266. package/template/wall-e/coding/runtime-events.js +224 -0
  267. package/template/wall-e/coding/runtime-mode.js +3 -0
  268. package/template/wall-e/coding/side-git-snapshot.js +160 -4
  269. package/template/wall-e/coding/snapshot-service.js +143 -1
  270. package/template/wall-e/coding/stream-processor.js +388 -34
  271. package/template/wall-e/coding/task-tool.js +141 -4
  272. package/template/wall-e/coding/tool-execution-controller.js +365 -0
  273. package/template/wall-e/coding/tool-registry.js +43 -5
  274. package/template/wall-e/coding/user-hooks.js +217 -0
  275. package/template/wall-e/coding-orchestrator.js +1330 -221
  276. package/template/wall-e/coding-prompts.js +20 -4
  277. package/template/wall-e/context/context-builder.js +15 -2
  278. package/template/wall-e/decision/confidence.js +1 -1
  279. package/template/wall-e/docs/coding-acceptance-contract.md +41 -0
  280. package/template/wall-e/docs/external-action-controller.md +26 -6
  281. package/template/wall-e/docs/telemetry-lifecycle.md +8 -2
  282. package/template/wall-e/embeddings.js +591 -53
  283. package/template/wall-e/external-action-controller.js +12 -0
  284. package/template/wall-e/http/auth.js +1 -0
  285. package/template/wall-e/http/chat-api.js +46 -11
  286. package/template/wall-e/http/model-admin.js +836 -34
  287. package/template/wall-e/lib/boot-profile.js +88 -0
  288. package/template/wall-e/lib/event-loop-monitor.js +93 -0
  289. package/template/wall-e/lib/service-health.js +194 -0
  290. package/template/wall-e/llm/anthropic.js +130 -5
  291. package/template/wall-e/llm/client.js +266 -63
  292. package/template/wall-e/llm/default-fallback.js +382 -0
  293. package/template/wall-e/llm/health.js +19 -0
  294. package/template/wall-e/llm/message-guard.js +78 -0
  295. package/template/wall-e/llm/model-catalog.js +252 -1
  296. package/template/wall-e/llm/openai.js +26 -4
  297. package/template/wall-e/llm/portkey-sync.js +654 -0
  298. package/template/wall-e/llm/provider-error.js +30 -2
  299. package/template/wall-e/llm/registry.js +5 -1
  300. package/template/wall-e/llm/request-compat.js +67 -0
  301. package/template/wall-e/loops/backfill.js +79 -23
  302. package/template/wall-e/loops/brain-optimize.js +67 -0
  303. package/template/wall-e/loops/ingest.js +25 -10
  304. package/template/wall-e/loops/question-digest.js +160 -0
  305. package/template/wall-e/loops/reflect.js +6 -4
  306. package/template/wall-e/loops/think.js +39 -12
  307. package/template/wall-e/mcp-server.js +318 -36
  308. package/template/wall-e/memory/ctm-context-client.js +52 -14
  309. package/template/wall-e/memory/ctm-operational-context.js +237 -0
  310. package/template/wall-e/memory/ctm-prompt-executions-client.js +128 -0
  311. package/template/wall-e/memory/ctm-session-context.js +111 -63
  312. package/template/wall-e/prompts/coding/deepseek.txt +3 -0
  313. package/template/wall-e/prompts/coding/gemini.txt +6 -0
  314. package/template/wall-e/prompts/coding/gpt.txt +6 -0
  315. package/template/wall-e/prompts/coding/local.txt +7 -0
  316. package/template/wall-e/runtime/decision-hooks.js +115 -0
  317. package/template/wall-e/runtime/devbox-gateway.js +82 -8
  318. package/template/wall-e/runtime/prompt-manifest.js +86 -0
  319. package/template/wall-e/runtime/tool-executor.js +269 -0
  320. package/template/wall-e/runtime/tool-result-envelope.js +138 -0
  321. package/template/wall-e/runtime/transcript-projection.js +60 -0
  322. package/template/wall-e/runtime/walle-runtime.js +224 -0
  323. package/template/wall-e/scripts/db-optimize/migrate.js +162 -0
  324. package/template/wall-e/scripts/db-optimize/recall-eval.js +117 -0
  325. package/template/wall-e/server.js +15 -0
  326. package/template/wall-e/session-files.js +9 -0
  327. package/template/wall-e/skills/_bundled/google-calendar/run.js +1 -1
  328. package/template/wall-e/skills/_bundled/gws-workspace/run.js +1 -1
  329. package/template/wall-e/skills/_bundled/slack-mentions/run.js +76 -6
  330. package/template/wall-e/skills/claude-code-reader.js +7 -3
  331. package/template/wall-e/skills/script-skill-runner.js +10 -0
  332. package/template/wall-e/skills/skill-planner.js +38 -0
  333. package/template/wall-e/tools/builtin-middleware.js +19 -9
  334. package/template/wall-e/tools/local-tools.js +1428 -16
  335. package/template/wall-e/tools/permission-checker.js +73 -5
  336. package/template/wall-e/tools/question-manager.js +117 -7
  337. package/template/wall-e/training/harvester.js +12 -28
  338. package/template/wall-e/training/replay.js +25 -80
  339. package/template/website/index.html +10 -10
  340. package/template/wall-e/eval/ab-test.js +0 -203
  341. package/template/wall-e/eval/agent-runner.js +0 -772
  342. package/template/wall-e/eval/agent-scorer.js +0 -461
  343. package/template/wall-e/eval/aggregator.js +0 -414
  344. package/template/wall-e/eval/allowed-test-commands.js +0 -34
  345. package/template/wall-e/eval/benchmark-generator.js +0 -113
  346. package/template/wall-e/eval/benchmarks/chat-eval.json +0 -1662
  347. package/template/wall-e/eval/benchmarks/chat.json +0 -82
  348. package/template/wall-e/eval/benchmarks/coding-agent-real.json +0 -1
  349. package/template/wall-e/eval/benchmarks/coding-agent.json +0 -1581
  350. package/template/wall-e/eval/benchmarks/coding.json +0 -122
  351. package/template/wall-e/eval/benchmarks/memory-retrieval.json +0 -234
  352. package/template/wall-e/eval/benchmarks/reasoning.json +0 -82
  353. package/template/wall-e/eval/benchmarks/swebench-lite-30.json +0 -212
  354. package/template/wall-e/eval/benchmarks.js +0 -669
  355. package/template/wall-e/eval/cc-replay.js +0 -719
  356. package/template/wall-e/eval/chat-eval.js +0 -525
  357. package/template/wall-e/eval/check-keys.js +0 -15
  358. package/template/wall-e/eval/check-providers.js +0 -42
  359. package/template/wall-e/eval/codex-cli-baseline.js +0 -669
  360. package/template/wall-e/eval/coding-agent-real.js +0 -570
  361. package/template/wall-e/eval/context-compactor.js +0 -251
  362. package/template/wall-e/eval/debug-agent003.js +0 -68
  363. package/template/wall-e/eval/diagnostics.js +0 -216
  364. package/template/wall-e/eval/eval-orchestrator.js +0 -642
  365. package/template/wall-e/eval/evaluate.js +0 -202
  366. package/template/wall-e/eval/evaluator.js +0 -373
  367. package/template/wall-e/eval/exporter.js +0 -212
  368. package/template/wall-e/eval/fixtures/express-basic/package.json +0 -9
  369. package/template/wall-e/eval/fixtures/express-basic/server.js +0 -115
  370. package/template/wall-e/eval/fixtures/express-basic/test.js +0 -83
  371. package/template/wall-e/eval/fixtures/express-buggy/package.json +0 -9
  372. package/template/wall-e/eval/fixtures/express-buggy/server.js +0 -113
  373. package/template/wall-e/eval/fixtures/express-buggy/test.js +0 -83
  374. package/template/wall-e/eval/fixtures/express-buggy-items/package.json +0 -9
  375. package/template/wall-e/eval/fixtures/express-buggy-items/server.js +0 -112
  376. package/template/wall-e/eval/fixtures/express-buggy-items/test.js +0 -83
  377. package/template/wall-e/eval/fixtures/express-buggy-search/package.json +0 -9
  378. package/template/wall-e/eval/fixtures/express-buggy-search/server.js +0 -121
  379. package/template/wall-e/eval/fixtures/express-buggy-search/test.js +0 -83
  380. package/template/wall-e/eval/fixtures/express-rename-data/data.js +0 -34
  381. package/template/wall-e/eval/fixtures/express-rename-data/package.json +0 -9
  382. package/template/wall-e/eval/fixtures/express-rename-data/server.js +0 -97
  383. package/template/wall-e/eval/fixtures/express-rename-data/test.js +0 -88
  384. package/template/wall-e/eval/fixtures/express-xss/package.json +0 -12
  385. package/template/wall-e/eval/fixtures/express-xss/server.js +0 -90
  386. package/template/wall-e/eval/fixtures/express-xss/test.js +0 -67
  387. package/template/wall-e/eval/fixtures/express-xss/views/profile.ejs +0 -9
  388. package/template/wall-e/eval/fixtures/fullstack-app/config/default.js +0 -9
  389. package/template/wall-e/eval/fixtures/fullstack-app/config/test.js +0 -13
  390. package/template/wall-e/eval/fixtures/fullstack-app/package.json +0 -11
  391. package/template/wall-e/eval/fixtures/fullstack-app/public/css/style.css +0 -137
  392. package/template/wall-e/eval/fixtures/fullstack-app/public/index.html +0 -46
  393. package/template/wall-e/eval/fixtures/fullstack-app/public/js/app.js +0 -121
  394. package/template/wall-e/eval/fixtures/fullstack-app/public/js/auth.js +0 -71
  395. package/template/wall-e/eval/fixtures/fullstack-app/public/js/items.js +0 -80
  396. package/template/wall-e/eval/fixtures/fullstack-app/public/js/users.js +0 -46
  397. package/template/wall-e/eval/fixtures/fullstack-app/public/login.html +0 -45
  398. package/template/wall-e/eval/fixtures/fullstack-app/public/register.html +0 -38
  399. package/template/wall-e/eval/fixtures/fullstack-app/scripts/migrate.js +0 -23
  400. package/template/wall-e/eval/fixtures/fullstack-app/scripts/seed.js +0 -46
  401. package/template/wall-e/eval/fixtures/fullstack-app/server/db.js +0 -99
  402. package/template/wall-e/eval/fixtures/fullstack-app/server/index.js +0 -94
  403. package/template/wall-e/eval/fixtures/fullstack-app/server/middleware/auth.js +0 -19
  404. package/template/wall-e/eval/fixtures/fullstack-app/server/middleware/logger.js +0 -19
  405. package/template/wall-e/eval/fixtures/fullstack-app/server/router.js +0 -50
  406. package/template/wall-e/eval/fixtures/fullstack-app/server/routes/auth.js +0 -69
  407. package/template/wall-e/eval/fixtures/fullstack-app/server/routes/health.js +0 -23
  408. package/template/wall-e/eval/fixtures/fullstack-app/server/routes/items.js +0 -88
  409. package/template/wall-e/eval/fixtures/fullstack-app/server/routes/users.js +0 -75
  410. package/template/wall-e/eval/fixtures/fullstack-app/server/test.js +0 -198
  411. package/template/wall-e/eval/fixtures/fullstack-app/server/utils/response.js +0 -34
  412. package/template/wall-e/eval/fixtures/fullstack-app/server/utils/validate.js +0 -26
  413. package/template/wall-e/eval/fixtures/fullstack-app/server.js +0 -8
  414. package/template/wall-e/eval/fixtures/fullstack-app/test.js +0 -12
  415. package/template/wall-e/eval/fixtures/monorepo-basic/package.json +0 -8
  416. package/template/wall-e/eval/fixtures/monorepo-basic/packages/api/data.js +0 -58
  417. package/template/wall-e/eval/fixtures/monorepo-basic/packages/api/middleware.js +0 -46
  418. package/template/wall-e/eval/fixtures/monorepo-basic/packages/api/package.json +0 -8
  419. package/template/wall-e/eval/fixtures/monorepo-basic/packages/api/routes.js +0 -64
  420. package/template/wall-e/eval/fixtures/monorepo-basic/packages/api/server.js +0 -56
  421. package/template/wall-e/eval/fixtures/monorepo-basic/packages/api/test.js +0 -116
  422. package/template/wall-e/eval/fixtures/monorepo-basic/packages/cli/commands.js +0 -61
  423. package/template/wall-e/eval/fixtures/monorepo-basic/packages/cli/index.js +0 -62
  424. package/template/wall-e/eval/fixtures/monorepo-basic/packages/cli/output.js +0 -43
  425. package/template/wall-e/eval/fixtures/monorepo-basic/packages/cli/package.json +0 -11
  426. package/template/wall-e/eval/fixtures/monorepo-basic/packages/cli/test.js +0 -44
  427. package/template/wall-e/eval/fixtures/monorepo-basic/packages/shared/formatters.js +0 -43
  428. package/template/wall-e/eval/fixtures/monorepo-basic/packages/shared/index.js +0 -12
  429. package/template/wall-e/eval/fixtures/monorepo-basic/packages/shared/package.json +0 -5
  430. package/template/wall-e/eval/fixtures/monorepo-basic/packages/shared/test.js +0 -55
  431. package/template/wall-e/eval/fixtures/monorepo-basic/packages/shared/validators.js +0 -29
  432. package/template/wall-e/eval/fixtures/monorepo-basic/test.js +0 -46
  433. package/template/wall-e/eval/fixtures/node-cli/index.js +0 -78
  434. package/template/wall-e/eval/fixtures/node-cli/package.json +0 -10
  435. package/template/wall-e/eval/fixtures/node-cli/test.js +0 -57
  436. package/template/wall-e/eval/fixtures/node-typed/package.json +0 -8
  437. package/template/wall-e/eval/fixtures/node-typed/src/handlers.js +0 -31
  438. package/template/wall-e/eval/fixtures/node-typed/src/utils.js +0 -33
  439. package/template/wall-e/eval/fixtures/node-typed/test.js +0 -36
  440. package/template/wall-e/eval/fixtures/python-flask/app.py +0 -14
  441. package/template/wall-e/eval/fixtures/python-flask/requirements.txt +0 -2
  442. package/template/wall-e/eval/fixtures/python-flask/test_app.py +0 -25
  443. package/template/wall-e/eval/fixtures/wall-e-subset/brain.js +0 -105
  444. package/template/wall-e/eval/fixtures/wall-e-subset/eval/aggregator.js +0 -101
  445. package/template/wall-e/eval/fixtures/wall-e-subset/eval/benchmarks/chat.json +0 -20
  446. package/template/wall-e/eval/fixtures/wall-e-subset/eval/benchmarks/coding.json +0 -32
  447. package/template/wall-e/eval/fixtures/wall-e-subset/eval/benchmarks.js +0 -64
  448. package/template/wall-e/eval/fixtures/wall-e-subset/eval/fixtures/simple-project/package.json +0 -6
  449. package/template/wall-e/eval/fixtures/wall-e-subset/eval/fixtures/simple-project/server.js +0 -31
  450. package/template/wall-e/eval/fixtures/wall-e-subset/eval/fixtures/simple-project/test.js +0 -18
  451. package/template/wall-e/eval/fixtures/wall-e-subset/eval/fixtures/simple-project/utils.js +0 -34
  452. package/template/wall-e/eval/fixtures/wall-e-subset/eval/runner.js +0 -104
  453. package/template/wall-e/eval/fixtures/wall-e-subset/eval/scorer.js +0 -73
  454. package/template/wall-e/eval/fixtures/wall-e-subset/eval/test.js +0 -134
  455. package/template/wall-e/eval/fixtures/wall-e-subset/llm/client.js +0 -99
  456. package/template/wall-e/eval/fixtures/wall-e-subset/llm/providers.js +0 -63
  457. package/template/wall-e/eval/fixtures/wall-e-subset/llm/test.js +0 -70
  458. package/template/wall-e/eval/fixtures/wall-e-subset/package.json +0 -10
  459. package/template/wall-e/eval/fixtures/wall-e-subset/test.js +0 -86
  460. package/template/wall-e/eval/harvester.js +0 -685
  461. package/template/wall-e/eval/head-to-head.js +0 -388
  462. package/template/wall-e/eval/humaneval-adapter.js +0 -321
  463. package/template/wall-e/eval/list-models.js +0 -31
  464. package/template/wall-e/eval/livecodebench-adapter.js +0 -291
  465. package/template/wall-e/eval/mail-integration.js +0 -443
  466. package/template/wall-e/eval/manifest.js +0 -186
  467. package/template/wall-e/eval/meta-harness/adapters/coding-agent.js +0 -57
  468. package/template/wall-e/eval/meta-harness/bootstrap-snapshot.js +0 -149
  469. package/template/wall-e/eval/meta-harness/candidate-store.js +0 -117
  470. package/template/wall-e/eval/meta-harness/cli.js +0 -86
  471. package/template/wall-e/eval/meta-harness/domain-spec.js +0 -154
  472. package/template/wall-e/eval/meta-harness/domains/coding-agent.domain.json +0 -84
  473. package/template/wall-e/eval/meta-harness/examples/env-bootstrap-candidate.js +0 -29
  474. package/template/wall-e/eval/meta-harness/experience-store.js +0 -174
  475. package/template/wall-e/eval/meta-harness/frontier.js +0 -96
  476. package/template/wall-e/eval/meta-harness/harness-interface.js +0 -90
  477. package/template/wall-e/eval/meta-harness/leakage-guard.js +0 -80
  478. package/template/wall-e/eval/meta-harness/optimizer.js +0 -207
  479. package/template/wall-e/eval/meta-harness/proposer-runner.js +0 -110
  480. package/template/wall-e/eval/meta-harness/reporting.js +0 -58
  481. package/template/wall-e/eval/meta-harness/telemetry.js +0 -27
  482. package/template/wall-e/eval/meta-harness/validation.js +0 -81
  483. package/template/wall-e/eval/promoter.js +0 -228
  484. package/template/wall-e/eval/provider-normalizer.js +0 -33
  485. package/template/wall-e/eval/replay.js +0 -395
  486. package/template/wall-e/eval/run-agent-benchmarks.js +0 -386
  487. package/template/wall-e/eval/run-codex-cli-baseline.js +0 -177
  488. package/template/wall-e/eval/run-coding-agent-real.js +0 -187
  489. package/template/wall-e/eval/run-eval.js +0 -435
  490. package/template/wall-e/eval/run-model-comparison.js +0 -142
  491. package/template/wall-e/eval/session-evaluator.js +0 -187
  492. package/template/wall-e/eval/session-miner.js +0 -207
  493. package/template/wall-e/eval/session-retrieval-benchmark.js +0 -150
  494. package/template/wall-e/eval/session-transcripts.js +0 -509
  495. package/template/wall-e/eval/shadow.js +0 -161
  496. package/template/wall-e/eval/swebench-adapter.js +0 -345
  497. package/template/wall-e/eval/swebench-docker.js +0 -192
  498. package/template/wall-e/eval/train.py +0 -320
  499. package/template/wall-e/eval/trainer.js +0 -232
  500. package/template/wall-e/eval/weekly-eval-loop.js +0 -241
@@ -1,9 +1,10 @@
1
- # Microsoft Dev Tunnel Phone Access Design
1
+ # Microsoft Dev Tunnel Client Access Design
2
2
 
3
- Status: Implementation update
4
- Date: 2026-05-19
3
+ Status: Design update
4
+ Date: 2026-05-30
5
5
  Owner: CTM / Wall-E
6
6
  Related docs:
7
+ - `claude-task-manager/docs/remote-desktop-access-design.md`
7
8
  - `claude-task-manager/docs/phone-access-design.md`
8
9
  - `claude-task-manager/docs/walle-relay-phone-access-design.md`
9
10
  - `claude-task-manager/docs/phone-setup.md`
@@ -12,315 +13,255 @@ External references:
12
13
  - Microsoft Dev Tunnels quickstart:
13
14
  `https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/get-started`
14
15
  - Microsoft Dev Tunnels security:
15
- `https://learn.microsoft.com/en-gb/azure/developer/dev-tunnels/security`
16
+ `https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/security`
16
17
  - Microsoft Dev Tunnels CLI reference:
17
18
  `https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/cli-commands`
18
- - VS Code Port Forwarding:
19
- `https://code.visualstudio.com/docs/debugtest/port-forwarding`
19
+ - Tailscale quickstart:
20
+ `https://tailscale.com/docs/how-to/quickstart`
21
+ - Tailscale access controls:
22
+ `https://tailscale.com/docs/features/access-control/acls`
20
23
 
21
24
  ## Summary
22
25
 
23
- Microsoft Dev Tunnel is a quick fallback transport for reaching CTM from a
24
- phone without buying a domain, installing a VPN, or configuring Cloudflare.
25
- It exposes local CTM through a `*.devtunnels.ms` URL using an outbound host
26
- connection to Microsoft's Azure-hosted tunnel service.
27
-
28
- This is a tunnel, not Walle Remote. It should not replace the Walle Relay
29
- product direction. It should sit in `Setup -> Access` as a practical fallback:
26
+ Microsoft Dev Tunnel is the default direct browser transport for secure CTM
27
+ access from another browser client, including phone and desktop. CTM supports
28
+ two explicit tunnel access modes:
29
+
30
+ 1. **CTM-authenticated** - recommended for phones. Microsoft Dev Tunnels allows
31
+ anonymous `connect` to the CTM port, and CTM remains the application auth
32
+ gate with pairing, client-device token, origin checks, route scopes, passkey
33
+ step-up, audit, and revocation.
34
+ 2. **Private Microsoft gate** - requires Microsoft/GitHub Dev Tunnel browser
35
+ auth before the request reaches CTM. This is useful when the user wants a
36
+ provider gate in front of CTM, but it can fail on mobile browsers before CTM
37
+ can display its pairing UI.
38
+
39
+ > **Invariant (2026-05-30): CTM-authenticated is the default; private is an
40
+ > explicit opt-in.** Dev Tunnels "private" mode enforces auth by redirecting the
41
+ > *initial request* to an interactive Microsoft/GitHub login page. The phone
42
+ > client is a PWA that reaches CTM via `fetch()` + a `WebSocket` on the same
43
+ > tunnel origin, and programmatic XHR/fetch/WebSocket cannot follow that
44
+ > cross-origin redirect — so forcing private silently bricks remote access
45
+ > ("can't connect / times out"). A brief earlier experiment that made private the
46
+ > default was reverted for this reason. Private is therefore honored only as a
47
+ > deliberate opt-in (an explicit UI selection, `CTM_MS_TUNNEL_ACCESS_MODE=private`,
48
+ > or `options.allowPrivateAccess`); a private value coming only from persisted
49
+ > state is treated as stale and migrated back to CTM-authenticated so the phone
50
+ > keeps working across headless restarts. If you want a true edge sign-in that is
51
+ > compatible with the PWA/WebSocket, use Cloudflare Access (GitHub/Google SSO via
52
+ > a JWT/cookie) or Tailscale (device identity) instead — both are already wired.
53
+
54
+ The CTM-authenticated flow exposes the local CTM host through a
55
+ Microsoft-managed tunnel like this:
30
56
 
31
57
  ```text
32
- iPhone browser
33
- -> private devtunnels.ms browser URL
34
- -> Microsoft/GitHub Dev Tunnels login gate
58
+ remote browser
59
+ -> private devtunnels.ms URL
60
+ -> Dev Tunnels connect-only forwarding
35
61
  -> Azure Dev Tunnels service
36
- -> devtunnel host process on Mac
62
+ -> devtunnel host process on the Mac
37
63
  -> local CTM on 127.0.0.1:3456
38
- -> CTM mobile device claim + optional passkey step-up
64
+ -> CTM client-device auth, scopes, step-up, audit, and revocation
39
65
  ```
40
66
 
41
- The design goal is to make the flow feel like "sign in on the Mac, start
42
- tunnel, pair phone" rather than "copy terminal commands and hope the URL
43
- works."
67
+ Anonymous tunnel `connect` is not the same as anonymous CTM access. It only
68
+ lets a browser reach CTM; the CTM app must still reject unpaired devices and
69
+ unauthorized routes. The setup UI must name the selected mode clearly and show
70
+ what is protecting the connection.
71
+
72
+ This doc covers the transport. The access-control architecture is shared with
73
+ mobile and desktop remote access in `remote-desktop-access-design.md`.
44
74
 
45
75
  ## Product Positioning
46
76
 
47
- Access methods should be presented in this order:
77
+ Direct browser access methods should be presented in this order:
48
78
 
49
- 1. **Walle Remote** - recommended product path, E2E typed relay.
50
- 2. **Microsoft Dev Tunnel** - quick browser fallback, no DNS or VPN.
51
- 3. **Tailscale** - private network fallback.
52
- 4. **Cloudflare Access** - advanced custom-domain fallback.
79
+ 1. **Microsoft Dev Tunnel** - default. CTM-authenticated phone-friendly browser
80
+ tunnel by default, with an optional private Microsoft/GitHub-gated mode.
81
+ 2. **Tailscale** - private-network alternative when both devices are in the
82
+ user's tailnet or the Mac is shared into a tailnet.
83
+ 3. **Walle Remote** - typed mobile relay for request/response control when a
84
+ full browser UI is not required.
53
85
 
54
- Microsoft Dev Tunnel is best when:
86
+ Cloudflare Tunnel is out of scope for the CTM remote-desktop plan and should
87
+ not be shown in the main remote-access setup flow.
55
88
 
56
- - the user wants phone access today;
57
- - Walle Relay is not deployed yet;
58
- - the user does not want to install Tailscale on the phone;
59
- - the user does not own or want to configure a domain;
60
- - the user is comfortable signing into Microsoft or GitHub on the Mac to manage
61
- the tunnel.
89
+ Microsoft Dev Tunnel is best when:
62
90
 
63
- Microsoft's CLI documentation marks Dev Tunnels as preview/no-SLA. Treat this
64
- as a convenience fallback, not the primary remote-access product contract.
91
+ - the user wants full CTM browser access from another computer or phone;
92
+ - the user wants CTM's own pairing flow to load on the remote browser without
93
+ first completing Microsoft/GitHub browser auth;
94
+ - the user does not want a VPN or domain;
95
+ - CTM still owns app-level permissions, pairing, passkey step-up, and audit.
65
96
 
66
- It is not best when:
97
+ Tailscale is best when:
67
98
 
68
- - the user requires relay-blind E2E payload privacy;
69
- - long-running production availability is required;
70
- - company policy blocks Microsoft Dev Tunnels domains;
71
- - the user cannot sign into the same Microsoft/GitHub identity on the phone;
72
- - company policy blocks Microsoft Dev Tunnels domains or browser sign-in.
99
+ - both machines can be authenticated into the same tailnet;
100
+ - the user wants direct private-network access instead of a hosted tunnel;
101
+ - ACLs/grants can restrict CTM to the intended devices and port.
73
102
 
74
103
  ## Design Principles
75
104
 
76
- 1. **Keep the tunnel private.** Microsoft Dev Tunnels are private by default.
77
- CTM must not create anonymous `connect` access automatically. The phone
78
- signs into Microsoft/GitHub before Dev Tunnels forwards anything to CTM.
79
- 2. **Use CTM auth after the Microsoft gate.** Microsoft/GitHub login decides
80
- whether the phone can reach the tunnel. CTM device pairing, scopes, audit,
81
- and revocation decide what that browser is allowed to do after it reaches
82
- CTM.
83
- 3. **Use a stable tunnel origin.** CTM device cookies and WebAuthn passkeys are
84
- origin-scoped. Temporary tunnel URLs create confusing re-pairing failures.
85
- 4. **Make Microsoft gate failures diagnosable.** If Microsoft returns 401 or an
86
- auth redirect, the phone request has not reached CTM. In private mode that
87
- is expected until the phone signs in with the same tunnel identity.
88
- 5. **Separate tunnel readiness from phone pairing.** A running tunnel only
89
- means the network path exists. The phone still needs CTM pairing and local
90
- Mac approval.
91
- 6. **Make stop/revoke obvious.** The user should see both controls:
92
- `Stop Tunnel` for network exposure and `Revoke Phone` for CTM device access.
93
-
94
- ## Recommended Flow
105
+ 1. **Name the transport gate explicitly.** CTM-authenticated mode lets the
106
+ browser reach CTM directly and relies on CTM app auth. Private Microsoft
107
+ gate mode requires Microsoft/GitHub tunnel auth before CTM loads.
108
+ 2. **No anonymous CTM access.** CTM-authenticated mode may create a narrow
109
+ anonymous Dev Tunnel `connect` rule, but CTM must still require pairing,
110
+ device token, origin checks, route/WS authorization, passkey step-up, audit,
111
+ and revocation before exposing app data or controls.
112
+ 3. **One client-device architecture.** Phone and desktop use the same device
113
+ identity, pairing, passkey step-up, scopes, audit log, origin binding, and
114
+ revocation model. The only difference is the UI surface: `/m/` for mobile,
115
+ `/` for desktop.
116
+ 4. **Full desktop means full CTM UI.** A trusted desktop client opens the same
117
+ dashboard as local use: sessions, terminal, conversation view, prompts,
118
+ queue, reviews, models, setup, and raw terminal input where permitted.
119
+ 5. **No temporary desktop mode.** Do not create a separate reduced desktop
120
+ product. Use normal CTM with remote auth and policy gates.
121
+ 6. **Stable origin required.** CTM cookies and passkeys are origin-scoped.
122
+ Reuse a persistent tunnel ID and URL instead of temporary URLs.
123
+ 7. **Make access failures precise.** Distinguish Microsoft/GitHub auth,
124
+ tunnel process, CTM origin, CTM device token, route scope, and passkey
125
+ step-up failures.
126
+ 8. **Revocation must close live access.** Revoking a CTM client device closes
127
+ existing WebSockets and invalidates future HTTP/WS access.
128
+
129
+ ## Recommended Setup Flow
95
130
 
96
131
  ### Desktop First-Time Setup
97
132
 
98
133
  1. User opens `Setup -> Access`.
99
134
  2. User selects `Microsoft Dev Tunnel`.
100
- 3. CTM shows a four-step setup rail:
135
+ 3. CTM shows one setup rail:
101
136
 
102
137
  ```text
103
- 1 Install 2 Sign in 3 Start tunnel 4 Pair phone
138
+ 1 Install 2 Sign in 3 Start tunnel 4 Pair browser
104
139
  ```
105
140
 
106
- 4. CTM checks for `devtunnel` CLI.
107
- 5. If missing, user sees install choices:
108
- - `brew install --cask devtunnel`
109
- - Microsoft install script / download link
110
- - `Refresh`
141
+ 4. CTM checks for the `devtunnel` CLI.
142
+ 5. If missing, CTM offers install instructions and a refresh action.
111
143
  6. CTM checks signed-in status with `devtunnel user show`.
112
- 7. If signed out, user chooses:
113
- - `Sign in with Microsoft`
114
- - `Sign in with GitHub`
115
- - `Use device code`
144
+ 7. If signed out, CTM offers Microsoft, GitHub, and device-code sign-in.
116
145
  8. CTM creates or reuses a persistent CTM tunnel ID.
117
146
  9. CTM creates or verifies port `3456` with protocol `http`.
118
- 10. CTM resets port access to the Dev Tunnels default so stale anonymous access
119
- is removed.
147
+ 10. User chooses the access mode:
148
+ - CTM-authenticated: create or verify anonymous `connect` access for this
149
+ tunnel port and rely on CTM app auth after forwarding.
150
+ - Private Microsoft gate: verify no anonymous `connect` access exists, and
151
+ offer `Reset to private` if stale anonymous access is detected.
120
152
  11. CTM starts `devtunnel host <tunnel-id>` as a managed child process.
121
153
  12. CTM parses the `https://...devtunnels.ms` URL from stdout.
122
- 13. CTM updates the phone origin allowlist for that exact URL.
123
- 14. CTM enables `Pair Phone`.
124
- 15. User clicks `Pair Phone`.
125
- 16. CTM creates a normal CTM device claim using the Dev Tunnel origin.
126
- 17. CTM shows QR, link, account reminder, and local approval expectation.
127
-
128
- ### Phone First-Time Pairing
129
-
130
- 1. User scans the QR.
131
- 2. iPhone opens the `https://<tunnel>-3456.<region>.devtunnels.ms/m/claim?...`
132
- URL.
133
- 3. Microsoft may show:
134
- - anti-phishing interstitial;
135
- - Microsoft/GitHub sign-in;
136
- - access denied if the phone signs into the wrong account.
137
- 4. After the private gate passes, Microsoft forwards the browser to CTM.
138
- 5. CTM mobile claim page says:
139
-
140
- ```text
141
- Microsoft tunnel connected
142
- This phone still needs CTM pairing.
143
- ```
144
-
145
- 6. CTM issues a device token for this phone. Passkey registration is used for
146
- high-risk step-up, not as the primary proof that the phone can reach CTM.
147
- 7. Mac shows:
148
-
149
- ```text
150
- Pair this phone?
151
- Account: user@example.com or GitHub username
152
- Device: iPhone / Safari
153
- Origin: https://<tunnel>-3456.<region>.devtunnels.ms
154
- Scopes: Read, Respond
155
- ```
156
-
157
- 9. User approves on Mac.
158
- 10. Phone lands on `/m/`.
154
+ 13. CTM updates the origin allowlist for that exact URL.
155
+ 14. CTM enables:
156
+ - `Pair Desktop Browser`
157
+ - `Pair Phone`
158
+ - `Copy Desktop URL`
159
+ - `Copy Mobile URL`
160
+
161
+ ### Remote Browser Pairing
162
+
163
+ 1. User opens the desktop or mobile URL:
164
+ - desktop: `https://<tunnel>-3456.<region>.devtunnels.ms/`
165
+ - mobile: `https://<tunnel>-3456.<region>.devtunnels.ms/m/`
166
+ 2. In CTM-authenticated mode, the browser should reach CTM directly. In private
167
+ Microsoft gate mode, Microsoft may show anti-phishing and Microsoft/GitHub
168
+ sign-in before CTM receives the request.
169
+ 3. After the request reaches CTM, CTM shows a pairing gate if the browser has
170
+ no CTM client-device token.
171
+ 4. CTM creates a pending pairing request for the current origin and surface.
172
+ 5. The Mac setup page shows the pending request with device hint, origin,
173
+ requested surface, scopes, and short code.
174
+ 6. Local user approves or rejects.
175
+ 7. Approval creates a CTM client-device token and registers or verifies a
176
+ passkey for high-risk step-up.
177
+ 8. The browser lands on `/` for desktop or `/m/` for mobile.
159
178
 
160
179
  ### Returning Use
161
180
 
162
- 1. User opens saved CTM mobile URL.
163
- 2. If the tunnel is running and Microsoft browser session is still valid,
164
- phone goes straight to CTM.
165
- 3. If Microsoft auth expired, phone signs into Microsoft/GitHub again.
166
- 4. CTM device cookie and passkey remain valid only if the tunnel origin is the
167
- same.
181
+ 1. User opens the saved URL.
182
+ 2. CTM-authenticated mode forwards to CTM directly; private Microsoft gate mode
183
+ first gates network access with Microsoft/GitHub tunnel auth.
184
+ 3. CTM client-device token gates app access in both modes.
185
+ 4. If the tunnel origin is stable, CTM cookies and passkeys remain valid.
186
+ 5. If CTM token is missing or expired, CTM shows the pairing gate again.
168
187
 
169
188
  ### Stop and Resume
170
189
 
171
190
  1. User clicks `Stop Tunnel`.
172
191
  2. CTM stops the `devtunnel host` process.
173
- 3. Phone shows `Mac offline` or cannot reach the tunnel URL.
174
- 4. CTM keeps the paired phone record, but the network path is closed.
175
- 5. User clicks `Start Tunnel` later.
192
+ 3. Remote browsers can no longer reach CTM.
193
+ 4. CTM keeps paired client-device records.
194
+ 5. User clicks `Start Tunnel`.
176
195
  6. CTM reuses the same persistent tunnel ID and origin.
177
- 7. Phone access resumes without re-pairing.
178
-
179
- ## Sleep and Idle Availability
180
-
181
- Microsoft Dev Tunnel only forwards to CTM while the Mac can run the local CTM
182
- server and the `devtunnel host` process. If macOS puts the laptop to sleep, the
183
- phone cannot reconnect until the Mac wakes. Unlocking the laptop often appears
184
- to "fix" phone access because it wakes the machine and gives the tunnel process
185
- a chance to reconnect.
186
-
187
- CTM should make this contract explicit rather than pretending the tunnel is an
188
- always-on hosted service.
189
-
190
- ### Availability Modes
191
-
192
- Default mode:
196
+ 7. Existing remote browsers resume without re-pairing unless their CTM token or
197
+ passkey state expired.
193
198
 
194
- - CTM restores a desired-running tunnel at startup.
195
- - CTM watches for long event-loop gaps that imply sleep/wake.
196
- - After wake, CTM verifies the managed tunnel process and restarts it if it is
197
- missing, stale, or running with an incompatible host-header mode.
198
- - CTM prefers `--host-header unchanged --origin-header unchanged`, but older
199
- Dev Tunnels CLI builds can crash on those flags. When that happens, CTM
200
- retries with the default header rewrite mode and relies on forwarded-host
201
- recovery in the request/auth layer.
202
- - The phone app reconnects when Safari returns to the foreground.
199
+ ### Expiration And Renewal
203
200
 
204
- Keep-awake mode:
201
+ The `devtunnel` CLI accepts a maximum tunnel/access expiration of 30 days. CTM
202
+ therefore cannot create a never-expiring Microsoft tunnel; it should make the
203
+ remote URL stable by reusing the same tunnel ID and proactively renewing the
204
+ service-side expiration.
205
205
 
206
- - User explicitly enables `Keep Mac awake for phone access`.
207
- - CTM starts a scoped macOS `caffeinate` process while the Microsoft tunnel is
208
- desired-running.
209
- - The assertion prevents idle system sleep but does not intentionally keep the
210
- display awake.
211
- - The UI shows the active assertion, warns about battery drain, and offers a
212
- one-click disable action.
213
- - CTM stops the assertion when the user disables the mode or stops the tunnel.
206
+ CTM policy:
214
207
 
215
- CTM must not silently prevent sleep forever. The user owns the tradeoff between
216
- availability and battery/thermal behavior.
208
+ - create persistent tunnels with `--expiration 30d`;
209
+ - renew the tunnel in place with `devtunnel update <tunnel-id> --expiration 30d`;
210
+ - mark renewal due after 25 days, leaving a buffer before the 30-day service
211
+ limit;
212
+ - for CTM-authenticated mode, recreate the port-level anonymous `connect` access
213
+ rule on the same 25-day cadence because the CLI exposes `access create` and
214
+ `access delete`, but not `access update`;
215
+ - keep renewal checks cheap in the normal watchdog path by reading local renewal
216
+ timestamps first and only calling the CLI when renewal is due, manual setup is
217
+ run, or access repair is requested.
217
218
 
218
- ### Recovery Watchdog
219
+ Renewal does not bypass Microsoft/GitHub account requirements for managing the
220
+ tunnel. If the local `devtunnel` credential expires, CTM should surface a
221
+ sign-in-required state and resume renewal after the user signs in again.
219
222
 
220
- The watchdog should run only when Microsoft tunnel state says
221
- `desired_running: true`.
223
+ ## Tailscale Alternative
222
224
 
223
- On each watchdog tick:
225
+ Tailscale is not anonymous. For the normal case, both sides must be signed into
226
+ the same tailnet. Other secure variants are also possible, such as sharing the
227
+ Mac into another authenticated tailnet user or using managed/auth-key device
228
+ enrollment, but they are still authenticated tailnet flows.
224
229
 
225
- 1. Inspect the saved managed tunnel state.
226
- 2. Verify the saved PID still belongs to `devtunnel host <tunnel-id>`.
227
- 3. Confirm the host-header mode is one CTM can authenticate: preferred
228
- passthrough flags, or a recorded default-header fallback.
229
- 4. If the process is missing or invalid, call the same restore path used at CTM
230
- startup.
231
- 5. If restore succeeds, re-apply the tunnel origin to the in-memory allowed
232
- origins.
233
- 6. Persist `last_watchdog_check_at`, `last_watchdog_recovered_at`, and
234
- `watchdog_error` for diagnostics.
230
+ CTM should treat Tailscale as a transport, not as the only auth layer:
235
231
 
236
- The watchdog should also detect sleep/wake by measuring timer drift. If a tick
237
- arrives much later than expected, CTM should run an immediate recovery check
238
- instead of waiting for a normal polling interval.
232
+ - bind only to loopback and approved private/Tailscale interfaces;
233
+ - rely on Tailscale ACLs/grants to restrict network reachability;
234
+ - still require CTM client-device pairing for `/` and `/m/`;
235
+ - still enforce CTM route/WS scopes and passkey step-up.
239
236
 
240
- ### Phone Foreground Reconnect
237
+ ## Access Policy
241
238
 
242
- iOS can suspend Safari timers and WebSockets while the phone is idle or in the
243
- background. The mobile app should reconnect on:
239
+ ### Trusted Desktop Client
244
240
 
245
- - `online`
246
- - `focus`
247
- - `pageshow`
248
- - `visibilitychange` when the document becomes visible
241
+ A paired trusted desktop client can:
249
242
 
250
- Foreground recovery should:
243
+ - load the full `/` CTM dashboard;
244
+ - open session tabs;
245
+ - view terminal and conversation history;
246
+ - send raw terminal input to sessions where CTM policy allows it;
247
+ - send Wall-E/coding messages;
248
+ - create sessions and prompts;
249
+ - use queue, review, model, and setup pages subject to scopes and step-up.
251
250
 
252
- 1. close any stale WebSocket;
253
- 2. open a fresh WebSocket;
254
- 3. refresh session data immediately;
255
- 4. keep the user's draft text;
256
- 5. show a clear connection state if CTM is unreachable.
251
+ Protected operations still require additional gates:
257
252
 
258
- This does not replace the Mac-side watchdog. It handles the phone-side stale
259
- browser case after the tunnel is already reachable again.
253
+ - route/WS authorization from `auth-rules`;
254
+ - passkey step-up for high-risk remote actions;
255
+ - local-only restrictions for hooks, telemetry ingest, OAuth callbacks, and
256
+ other machine-local endpoints;
257
+ - audit events for auth, remote input, model changes, terminal control, and
258
+ revocation.
260
259
 
261
- ### User-Facing States
260
+ ### Mobile Client
262
261
 
263
- | State | Meaning | User copy |
264
- | --- | --- | --- |
265
- | Tunnel running, keep-awake off | Phone works while Mac stays awake | `Available while this Mac is awake.` |
266
- | Tunnel running, keep-awake on | CTM is preventing idle sleep | `Keeping this Mac awake for phone access.` |
267
- | Wake recovery running | CTM detected sleep/wake or stale tunnel | `Recovering the Microsoft tunnel...` |
268
- | Recovery failed | CTM could not restore the tunnel | `Tunnel recovery failed. Start the tunnel again.` |
269
- | Phone resumed stale | Safari came back before WebSocket recovered | `Reconnecting to CTM...` |
270
-
271
- ### Security and Resource Notes
272
-
273
- - Keep-awake mode is explicit and reversible.
274
- - CTM uses `spawn('caffeinate', args)` with fixed argv, not shell strings.
275
- - No tunnel tokens, Microsoft credentials, or phone pairing secrets are written
276
- into power assertion state.
277
- - Stopping the Microsoft tunnel should also stop the keep-awake assertion.
278
- - If CTM exits, `caffeinate -w <ctm-pid>` should end with it.
279
- - Battery users should see a warning before enabling keep-awake mode.
280
-
281
- ## Critical Origin Decision
282
-
283
- Do not use a temporary tunnel as the normal phone setup path.
284
-
285
- Temporary hosting is easy:
286
-
287
- ```bash
288
- devtunnel host -p 3456
289
- ```
290
-
291
- But it creates a new tunnel URL when the host process changes. That breaks
292
- mobile UX because:
293
-
294
- - CTM allowed origins need to change;
295
- - CTM cookies are scoped to the old origin;
296
- - WebAuthn/passkey credentials are scoped to the old RP ID;
297
- - saved home-screen PWA icons point to the old URL;
298
- - users experience this as "my paired phone stopped working."
299
-
300
- Recommended CTM behavior:
301
-
302
- ```bash
303
- devtunnel create ctm-<stable-random-id> --expiration 30d
304
- devtunnel port create ctm-<stable-random-id> -p 3456 --protocol http
305
- devtunnel host ctm-<stable-random-id> --host-header unchanged --origin-header unchanged
306
- ```
307
-
308
- The tunnel ID should be random and non-sensitive. Do not include usernames,
309
- company names, project names, repo names, or machine names.
310
-
311
- If that host command exits immediately with the Dev Tunnels
312
- `same key ... host` CLI error, CTM retries:
313
-
314
- ```bash
315
- devtunnel host ctm-<stable-random-id>
316
- ```
317
-
318
- This fallback is acceptable because CTM treats forwarded public tunnel headers
319
- as the source of truth for origin and WebAuthn recovery when Dev Tunnels rewrites
320
- `Host` or `Origin` to localhost.
321
-
322
- Show the expiry date in the UI. Renew or recreate before expiry if Microsoft
323
- allows it; otherwise tell the user exactly when re-pairing may be needed.
262
+ A paired mobile client uses the same auth stack, but the `/m/` UI remains
263
+ optimized for phone-sized interaction. Mobile may hide or reshape some controls,
264
+ but that is a UX choice, not a separate auth architecture.
324
265
 
325
266
  ## Desktop UX
326
267
 
@@ -335,22 +276,22 @@ Microsoft Dev Tunnel
335
276
  Badge:
336
277
 
337
278
  ```text
338
- Quick fallback
279
+ Default secure browser access
339
280
  ```
340
281
 
341
282
  Body:
342
283
 
343
284
  ```text
344
- Use a private Microsoft-hosted browser tunnel to open CTM from your phone. No
345
- DNS or VPN; the phone signs into the same Microsoft/GitHub tunnel account.
285
+ Open CTM from another computer or phone through a private Microsoft Dev Tunnel.
286
+ The remote browser signs into Microsoft/GitHub before CTM loads, then CTM
287
+ pairs and authorizes the browser.
346
288
  ```
347
289
 
348
290
  Security note:
349
291
 
350
292
  ```text
351
- This is a tunnel fallback, not Walle Remote. Keep anonymous access off. CTM
352
- pairing, device permissions, and passkey step-up still apply after the private
353
- Microsoft gate.
293
+ No anonymous tunnel access. CTM still controls device pairing, permissions,
294
+ passkey step-up, audit, and revocation.
354
295
  ```
355
296
 
356
297
  Primary button by state:
@@ -359,9 +300,11 @@ Primary button by state:
359
300
  | --- | --- |
360
301
  | CLI missing | `Install CLI` |
361
302
  | Signed out | `Sign in` |
362
- | Ready | `Start Tunnel` |
363
- | Running | `Pair Phone` |
364
- | Paired | `Open Phone URL` |
303
+ | Private tunnel ready | `Start Tunnel` |
304
+ | Running | `Pair Browser` |
305
+ | Paired desktop | `Open Desktop URL` |
306
+ | Paired phone | `Open Phone URL` |
307
+ | Anonymous access detected | `Reset to Private` |
365
308
  | Error | `Retry` |
366
309
 
367
310
  Secondary buttons:
@@ -369,195 +312,8 @@ Secondary buttons:
369
312
  - `Stop Tunnel`
370
313
  - `Refresh`
371
314
  - `Diagnostics`
372
- - `Copy URL`
373
-
374
- ### Setup Panel Layout
375
-
376
- Use one operational panel with a horizontal stepper on desktop and a vertical
377
- stepper on narrow screens.
378
-
379
- ```text
380
- Microsoft Dev Tunnel CTM protected
381
- No DNS or VPN. Phone opens the browser URL, then pairs with CTM.
382
-
383
- 1 Install ----- 2 Sign in ----- 3 Start tunnel ----- 4 Pair phone
384
-
385
- [Current step content]
386
-
387
- Connection
388
- Account: user@example.com
389
- Tunnel: ctm-a8f39c
390
- Phone URL: https://ctm-a8f39c-3456.usw2.devtunnels.ms/m/
391
- Status: Running
392
-
393
- [Pair Phone] [Copy URL] [Stop Tunnel]
394
- ```
395
-
396
- Do not bury Cloudflare-style details in form fields. This setup should mostly
397
- be buttons plus status.
398
-
399
- ### Step: Install
400
-
401
- State copy:
402
-
403
- ```text
404
- Install Microsoft's devtunnel CLI once on this Mac.
405
- ```
406
-
407
- Actions:
408
-
409
- - `Copy Homebrew command`
410
- - `Open Microsoft install docs`
411
- - `Refresh`
412
-
413
- Detected state:
414
-
415
- ```text
416
- devtunnel 1.x detected
417
- ```
418
-
419
- ### Step: Sign In
420
-
421
- State copy:
422
-
423
- ```text
424
- Sign into the account your phone will also use.
425
- ```
426
-
427
- Controls:
428
-
429
- - segmented control: `Microsoft` / `GitHub`
430
- - `Sign in`
431
- - `Use device code`
432
-
433
- Signed-in state:
434
-
435
- ```text
436
- Signed in as user@example.com
437
- This account manages the tunnel on this Mac only.
438
- ```
439
-
440
- ### Step: Start Tunnel
441
-
442
- Default settings:
443
-
444
- - Access: `Private Microsoft/GitHub account access`
445
- - Tunnel kind: `Persistent`
446
- - Port: `3456`
447
- - Protocol: `http`
448
- - Expiration: `30 days` if supported
449
-
450
- Primary CTA:
451
-
452
- ```text
453
- Start Tunnel
454
- ```
455
-
456
- Running state:
457
-
458
- ```text
459
- Tunnel running
460
- Phone access requires the same Microsoft/GitHub account plus CTM pairing.
461
- ```
462
-
463
- Do not offer broad tunnel-level public mode. CTM should reset stale anonymous
464
- rules back to Microsoft Dev Tunnels defaults rather than creating new anonymous
465
- rules.
466
-
467
- ### Step: Pair Phone
468
-
469
- Show only after the tunnel is running, the tunnel access is private, and CTM has
470
- an exact allowed origin.
471
-
472
- Content:
473
-
474
- ```text
475
- Scan with iPhone. First sign into the tunnel account below if Microsoft asks.
476
-
477
- Use this account:
478
- user@example.com
479
-
480
- Then CTM pairs this browser and records its device permissions.
481
- ```
482
-
483
- QR payload:
484
-
485
- ```text
486
- https://<tunnel>-3456.<region>.devtunnels.ms/m/claim?claim=...&secret=...
487
- ```
488
-
489
- Below QR:
490
-
491
- - `Copy Link`
492
- - `Expires in 09:59`
493
- - `Cancel Claim`
494
-
495
- Device list:
496
-
497
- ```text
498
- User's iPhone
499
- Last used 2m ago
500
- Scopes: Read, Respond
501
- [Revoke]
502
- ```
503
-
504
- ## Phone UX
505
-
506
- ### Before CTM Loads
507
-
508
- The user may see Microsoft-owned screens before CTM can render anything. The
509
- desktop QR panel must set that expectation.
510
-
511
- Expected Microsoft screens:
512
-
513
- - anti-phishing interstitial;
514
- - Microsoft/GitHub sign-in;
515
- - access denied if wrong account.
516
-
517
- CTM should not try to style or bypass these screens.
518
-
519
- ### CTM Claim Page
520
-
521
- After Microsoft forwards to CTM, show a compact confirmation:
522
-
523
- ```text
524
- Microsoft tunnel connected
525
-
526
- Finish pairing this phone with CTM.
527
-
528
- Tunnel account: user@example.com
529
- Mac: User's MacBook
530
- Access: Read, Respond
531
-
532
- [Pair this phone]
533
- ```
534
-
535
- If the user is on an unexpected origin:
536
-
537
- ```text
538
- This link no longer matches the active Microsoft tunnel.
539
- Generate a new pairing code on your Mac.
540
- ```
541
-
542
- ### CTM Home
543
-
544
- Once paired, the phone home should include a transport pill:
545
-
546
- ```text
547
- Microsoft Tunnel
548
- Private
549
- ```
550
-
551
- Status examples:
552
-
553
- - `Connected`
554
- - `Microsoft sign-in required`
555
- - `Tunnel stopped`
556
- - `Mac offline`
557
- - `Tunnel expires in 3 days`
558
-
559
- The transport pill should not dominate the home screen. It is a status signal,
560
- not the task.
315
+ - `Copy Desktop URL`
316
+ - `Copy Mobile URL`
561
317
 
562
318
  ## Failure States
563
319
 
@@ -565,47 +321,38 @@ not the task.
565
321
  | --- | --- | --- |
566
322
  | CLI missing | `Microsoft devtunnel CLI is not installed.` | Install, then refresh |
567
323
  | Auth missing | `Sign into Microsoft or GitHub before starting a tunnel.` | Sign in / device code |
568
- | Microsoft sign-in required | `Microsoft is asking the phone to sign in before CTM can load.` | Sign in on the phone with the account shown on the Mac |
569
- | Anonymous access found | `This tunnel has public browser access enabled.` | CTM resets the port access to private before showing Ready |
324
+ | Provider sign-in required | `Sign into the private Microsoft tunnel before CTM can load.` | Complete provider sign-in |
325
+ | Anonymous access detected | `This tunnel allows anonymous browser access. Reset it to private before using CTM remote access.` | Reset to private |
570
326
  | Tunnel start failed | `Tunnel did not start.` | Retry, copy diagnostics |
571
- | Temporary URL changed | `This phone link belongs to an old tunnel.` | Reuse persistent tunnel or re-pair |
327
+ | Temporary URL changed | `This browser link belongs to an old tunnel.` | Reuse persistent tunnel or re-pair |
572
328
  | Origin not allowed | `CTM has not trusted this tunnel URL yet.` | Refresh setup, save origin |
329
+ | CTM device missing | `Pair this browser before using CTM remotely.` | Approve pairing on Mac |
573
330
  | Claim expired | `Pairing code expired.` | Generate a new code |
574
- | Microsoft service blocked | `This network blocks Microsoft Dev Tunnels.` | Use Walle Remote, Tailscale, or Cloudflare |
331
+ | Microsoft service blocked | `This network blocks Microsoft Dev Tunnels.` | Use Tailscale |
575
332
  | Tunnel stopped | `Microsoft tunnel is stopped.` | Start tunnel on Mac |
576
333
  | Tunnel expiring | `Tunnel expires soon.` | Renew or recreate before expiry |
577
334
 
578
335
  ## Security Posture
579
336
 
580
- ### Required
581
-
582
- - Microsoft/GitHub account required on the Mac for tunnel management.
583
- - The phone must pass the Microsoft/GitHub private tunnel gate before CTM sees
584
- the request.
585
- - CTM device claim is still required so CTM can name, scope, revoke, and audit
586
- the browser/device.
587
- - Local Mac approval required for first phone pairing.
588
- - CTM route authorization registry still applies.
589
- - High-risk CTM actions still require passkey step-up when the browser has a
590
- CTM passkey registered for this origin.
591
- - Anonymous access is disabled by default and should not be created by CTM.
592
- - No tunnel access tokens in QR codes.
593
- - No inspect URL shown in the primary UI.
594
-
595
- ### Important Caveat
596
-
597
- Microsoft Dev Tunnel does not provide Walle-style relay-blind payload privacy.
598
- For web forwarding, Microsoft terminates TLS at the tunnel service ingress and
599
- rewrites headers for development scenarios. Treat Microsoft as part of the
600
- trusted transport path.
601
-
602
- That is acceptable for a fallback tunnel if:
603
-
604
- - the Microsoft/GitHub private gate remains on;
605
- - CTM app-layer auth remains strong;
606
- - the user understands that Dev Tunnels is a Microsoft-hosted relay, not an E2E
607
- blind relay;
608
- - sensitive long-running remote access moves to Walle Remote once available.
337
+ Required:
338
+
339
+ - Microsoft/GitHub account required for Dev Tunnel management and remote
340
+ browser access.
341
+ - No anonymous CTM app access. CTM-authenticated mode may use a connect-only
342
+ anonymous Dev Tunnel rule, but CTM pairing, device token, route scopes, and
343
+ passkey step-up remain mandatory app gates.
344
+ - CTM client-device token required for app access.
345
+ - Local Mac approval required for first browser pairing.
346
+ - CTM route authorization registry applies to HTTP and WebSocket actions.
347
+ - High-risk remote actions require passkey step-up.
348
+ - No tunnel access tokens in QR codes or browser URLs.
349
+ - Revocation closes active WebSockets and blocks future HTTP/WS requests.
350
+ - Audit records include transport, origin, surface, device, scope, and action.
351
+
352
+ Microsoft Dev Tunnel does not provide relay-blind payload privacy. Microsoft is
353
+ part of the trusted transport path. That is acceptable for this product shape
354
+ because the user explicitly selected Microsoft as the default secure transport
355
+ and CTM still owns app-layer authorization.
609
356
 
610
357
  ## Implementation Notes
611
358
 
@@ -618,26 +365,28 @@ Store:
618
365
  - port;
619
366
  - protocol;
620
367
  - signed-in account display;
621
- - private access status and whether stale anonymous access was removed;
368
+ - private access status;
369
+ - anonymous-access drift status;
622
370
  - expiration timestamp if available;
623
371
  - managed process PID;
624
372
  - last stdout/stderr lines for diagnostics;
625
- - whether CTM allowed origin has been applied.
373
+ - exact CTM allowed origin;
374
+ - paired client-device IDs for desktop and mobile surfaces.
626
375
 
627
376
  Do not store Microsoft/GitHub passwords or login tokens. The `devtunnel` CLI
628
377
  uses the system credential store.
629
378
 
630
379
  ### Process Management
631
380
 
632
- CTM should manage `devtunnel host <tunnel-id>` as a child process, similar to
633
- the Cloudflare fallback process model:
381
+ CTM should manage `devtunnel host <tunnel-id>` as a child process:
634
382
 
635
383
  - start with fixed argv, not shell strings;
636
384
  - capture stdout and stderr;
637
385
  - parse the public URL;
638
386
  - detect exit;
639
387
  - expose `Stop Tunnel`;
640
- - do not restart CTM unless the local CTM bind/origin config requires it.
388
+ - restore desired-running tunnel state after CTM restart or Mac wake;
389
+ - do not restart CTM unless local bind/origin config requires it.
641
390
 
642
391
  ### Readiness
643
392
 
@@ -647,23 +396,13 @@ the Cloudflare fallback process model:
647
396
  - user signed in;
648
397
  - persistent tunnel exists;
649
398
  - port `3456` configured;
650
- - stale anonymous browser `connect` access is absent;
399
+ - tunnel access is private;
400
+ - no anonymous connect access is detected;
651
401
  - host process running;
652
402
  - CTM allowed origin includes the tunnel URL;
653
- - CTM device claim can be generated for that origin.
403
+ - CTM client-device pairing can be generated for that origin.
654
404
 
655
- Do not show QR before these checks pass.
656
-
657
- ## Accessibility and Responsive Design
658
-
659
- - Stepper labels must be text, not color-only state.
660
- - All buttons must be at least 44px tall.
661
- - QR must have a copyable link and short-code fallback.
662
- - Status updates should use `aria-live="polite"`.
663
- - The account reminder must be visible near the QR on desktop and phone-sized
664
- setup screens.
665
- - Error copy should state whether the problem is Microsoft auth, tunnel
666
- process, CTM origin, or CTM pairing.
405
+ Do not show remote URLs before these checks pass.
667
406
 
668
407
  ## Test Plan
669
408
 
@@ -671,23 +410,38 @@ Manual happy path:
671
410
 
672
411
  1. Install `devtunnel`.
673
412
  2. Sign into Microsoft or GitHub.
674
- 3. Start persistent tunnel.
675
- 4. Confirm CTM shows a `devtunnels.ms` phone URL.
676
- 5. Scan QR on iPhone.
677
- 6. Complete CTM passkey pairing.
678
- 7. Send a low-risk session message.
679
- 8. Stop tunnel and confirm phone loses access.
680
- 9. Start tunnel again and confirm phone does not need re-pairing.
413
+ 3. Start persistent private tunnel.
414
+ 4. Confirm CTM shows both desktop and mobile URLs.
415
+ 5. Open desktop URL from another browser/computer.
416
+ 6. Complete Microsoft/GitHub tunnel auth if prompted.
417
+ 7. Approve CTM browser pairing on the Mac.
418
+ 8. Open a session and send a low-risk terminal/message action.
419
+ 9. Open mobile URL and confirm the same auth architecture with `/m/`.
420
+ 10. Stop tunnel and confirm remote clients lose access.
421
+ 11. Start tunnel again and confirm clients resume without re-pairing.
422
+ 12. Revoke the remote browser and confirm existing WebSocket closes.
681
423
 
682
424
  Negative cases:
683
425
 
426
+ - anonymous tunnel access detected;
684
427
  - expired claim;
685
428
  - tunnel host process crash;
686
429
  - tunnel URL changes;
687
430
  - CTM allowed origin missing;
688
- - stale anonymous access left by an older CTM build;
431
+ - provider sign-in appears before CTM;
432
+ - CTM device token missing;
689
433
  - high-risk action without CTM step-up.
690
434
 
435
+ Automated coverage should include:
436
+
437
+ - tunnel state normalization;
438
+ - anonymous-access drift detection;
439
+ - origin allowlist generation;
440
+ - pairing request lifecycle for desktop and mobile surfaces;
441
+ - HTTP route auth regression;
442
+ - WebSocket auth and revoke-close regression;
443
+ - audit event shape for remote desktop and mobile.
444
+
691
445
  ## MVP Cut Line
692
446
 
693
447
  MVP includes:
@@ -695,26 +449,27 @@ MVP includes:
695
449
  - setup card and stepper;
696
450
  - CLI detection;
697
451
  - sign-in status and account display;
698
- - persistent tunnel create/reuse;
699
- - private access reset/check so stale anonymous browser access is removed;
452
+ - persistent private tunnel create/reuse;
453
+ - anonymous-access drift detection and reset action;
700
454
  - managed `devtunnel host` process;
701
455
  - exact origin allowlist;
702
- - phone pairing QR;
456
+ - desktop and mobile pairing links;
457
+ - shared client-device auth for `/` and `/m/`;
703
458
  - stop tunnel;
704
459
  - diagnostics copy.
705
460
 
706
461
  MVP excludes:
707
462
 
708
- - anonymous browser access;
463
+ - Cloudflare Tunnel;
464
+ - anonymous tunnel access;
465
+ - separate temporary desktop mode;
709
466
  - team/tenant/org access controls;
710
- - tunnel access tokens for phone;
711
- - traffic inspection UI;
712
- - automatic public beta positioning as primary access.
467
+ - tunnel access tokens in browser URLs;
468
+ - traffic inspection UI.
713
469
 
714
470
  ## Recommendation
715
471
 
716
- Build Microsoft Dev Tunnel as a polished fallback because it removes most of
717
- the Cloudflare setup burden. Do not position it as the primary Walle Remote
718
- solution. The UI should be honest: it is fast and browser-only, but it is still
719
- a Microsoft-hosted private browser tunnel plus CTM device auth, not an E2E
720
- typed relay.
472
+ Use Microsoft Dev Tunnel as the default direct browser remote-access option.
473
+ Use Tailscale as the private-network alternative. Keep Walle Remote for typed
474
+ mobile relay workflows. Do not add Cloudflare Tunnel or a separate temporary
475
+ desktop mode to this plan.