@slopus/happy-terminal 0.3.0-beta.13

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 (248) hide show
  1. package/LICENSE +21 -0
  2. package/LICENSE-CODEX +203 -0
  3. package/LICENSE-GROK-BUILD +204 -0
  4. package/LICENSE-HAPPY +21 -0
  5. package/README.md +60 -0
  6. package/THIRD-PARTY-NOTICES.md +34 -0
  7. package/dist/HappyTerminalUserError.d.ts +12 -0
  8. package/dist/app/AppTranscriptEntry.d.ts +33 -0
  9. package/dist/app/AppendOnlyStreamingRender.d.ts +12 -0
  10. package/dist/app/CodexFileDiff.d.ts +20 -0
  11. package/dist/app/CodexMcpToolCall.d.ts +25 -0
  12. package/dist/app/CodingAssistantAgentBackend.d.ts +81 -0
  13. package/dist/app/CodingAssistantApp.d.ts +128 -0
  14. package/dist/app/CompletedTurn.d.ts +11 -0
  15. package/dist/app/FileMentionAutocomplete.d.ts +30 -0
  16. package/dist/app/HappyTerminalProcessTerminal.d.ts +7 -0
  17. package/dist/app/NoticeChild.d.ts +4 -0
  18. package/dist/app/SecretMenuController.d.ts +31 -0
  19. package/dist/app/SelectionList.d.ts +24 -0
  20. package/dist/app/SessionDraftSync.d.ts +51 -0
  21. package/dist/app/StartupStatusApp.d.ts +34 -0
  22. package/dist/app/StartupStatusCardModel.d.ts +22 -0
  23. package/dist/app/TemporaryFullscreenController.d.ts +9 -0
  24. package/dist/app/TerminalColorLevel.d.ts +1 -0
  25. package/dist/app/TerminalOutputTrace.d.ts +12 -0
  26. package/dist/app/TerminalTheme.d.ts +11 -0
  27. package/dist/app/TranscriptEntryRenderCache.d.ts +10 -0
  28. package/dist/app/applyWorkflowRunUpdate.d.ts +2 -0
  29. package/dist/app/blendComposerBackground.d.ts +2 -0
  30. package/dist/app/boundedJsonStringify.d.ts +1 -0
  31. package/dist/app/calculateCacheHitPercent.d.ts +2 -0
  32. package/dist/app/codexDiffAnsi.d.ts +17 -0
  33. package/dist/app/compactCompletedTurnEntries.d.ts +2 -0
  34. package/dist/app/containsMarkdownTable.d.ts +1 -0
  35. package/dist/app/createAgentMarkdownTheme.d.ts +3 -0
  36. package/dist/app/createBackgroundTerminalViewer.d.ts +16 -0
  37. package/dist/app/createCompletedTurn.d.ts +6 -0
  38. package/dist/app/createEditorTheme.d.ts +3 -0
  39. package/dist/app/createFileMentionAutocompleteItems.d.ts +3 -0
  40. package/dist/app/createSecretInputPanel.d.ts +12 -0
  41. package/dist/app/createSelectionPanel.d.ts +14 -0
  42. package/dist/app/createSerialTaskQueue.d.ts +1 -0
  43. package/dist/app/createSessionPicker.d.ts +17 -0
  44. package/dist/app/createSlashCommands.d.ts +7 -0
  45. package/dist/app/createStopOnceHandler.d.ts +1 -0
  46. package/dist/app/createSubagentMonitor.d.ts +17 -0
  47. package/dist/app/createTerminalInputBurstHandler.d.ts +5 -0
  48. package/dist/app/createWorkflowMonitor.d.ts +15 -0
  49. package/dist/app/defaultTerminalTheme.d.ts +1 -0
  50. package/dist/app/describeModelChoice.d.ts +4 -0
  51. package/dist/app/describeProviderSignIn.d.ts +2 -0
  52. package/dist/app/describeReasoningLevel.d.ts +4 -0
  53. package/dist/app/detectCodexDiffLanguage.d.ts +1 -0
  54. package/dist/app/encodeModelChoice.d.ts +1 -0
  55. package/dist/app/endsAfterOpeningCodeFence.d.ts +1 -0
  56. package/dist/app/findFileMentionContext.d.ts +9 -0
  57. package/dist/app/findFileMentionPrefix.d.ts +5 -0
  58. package/dist/app/formatActivityElapsedTime.d.ts +1 -0
  59. package/dist/app/formatCodexMcpToolResult.d.ts +3 -0
  60. package/dist/app/formatCompactTokens.d.ts +1 -0
  61. package/dist/app/formatFileMention.d.ts +1 -0
  62. package/dist/app/formatProviderError.d.ts +6 -0
  63. package/dist/app/formatRelativeTime.d.ts +2 -0
  64. package/dist/app/formatResetDuration.d.ts +1 -0
  65. package/dist/app/formatSessionPickerEntry.d.ts +14 -0
  66. package/dist/app/formatSessionTokenStatus.d.ts +6 -0
  67. package/dist/app/formatSessionUsageSummary.d.ts +3 -0
  68. package/dist/app/formatStartupStatusUsageRemaining.d.ts +2 -0
  69. package/dist/app/formatStartupStatusUsageRows.d.ts +2 -0
  70. package/dist/app/formatSubagentToolCall.d.ts +10 -0
  71. package/dist/app/formatToolPermissionNotice.d.ts +3 -0
  72. package/dist/app/formatToolResultForDisplay.d.ts +2 -0
  73. package/dist/app/formatTurnUsageSummary.d.ts +2 -0
  74. package/dist/app/formatWorkUsageSummary.d.ts +14 -0
  75. package/dist/app/highlightAgentCode.d.ts +1 -0
  76. package/dist/app/highlightCodexDiffLine.d.ts +2 -0
  77. package/dist/app/highlightShellCommand.d.ts +1 -0
  78. package/dist/app/humanizeGoalStatus.d.ts +2 -0
  79. package/dist/app/humanizeMcpName.d.ts +1 -0
  80. package/dist/app/humanizePermissionMode.d.ts +2 -0
  81. package/dist/app/humanizePermissionReviewLevel.d.ts +2 -0
  82. package/dist/app/humanizeProviderId.d.ts +1 -0
  83. package/dist/app/humanizeReasoningLevel.d.ts +1 -0
  84. package/dist/app/humanizeSubagentStatus.d.ts +2 -0
  85. package/dist/app/humanizeToolName.d.ts +1 -0
  86. package/dist/app/humanizeWorkflowStatus.d.ts +2 -0
  87. package/dist/app/installResumeInstructions.d.ts +26 -0
  88. package/dist/app/installTerminalCrashCleanup.d.ts +26 -0
  89. package/dist/app/isLightTerminalBackground.d.ts +2 -0
  90. package/dist/app/layoutCodexFileDiff.d.ts +13 -0
  91. package/dist/app/looksLikeAuthenticationFailure.d.ts +5 -0
  92. package/dist/app/nearestXtermColorIndex.d.ts +2 -0
  93. package/dist/app/parseCodexMcpToolInvocation.d.ts +2 -0
  94. package/dist/app/parseSessionCommand.d.ts +6 -0
  95. package/dist/app/providerErrorResetAt.d.ts +2 -0
  96. package/dist/app/providerQuotaToStartupStatusUsage.d.ts +3 -0
  97. package/dist/app/readClipboardImage.d.ts +9 -0
  98. package/dist/app/renderActivityWave.d.ts +3 -0
  99. package/dist/app/renderAgentMarkdown.d.ts +8 -0
  100. package/dist/app/renderBackgroundTerminalCompletion.d.ts +1 -0
  101. package/dist/app/renderBackgroundTerminalInteraction.d.ts +2 -0
  102. package/dist/app/renderBackgroundTerminalSummary.d.ts +1 -0
  103. package/dist/app/renderChildRows.d.ts +13 -0
  104. package/dist/app/renderCodexDiffLine.d.ts +3 -0
  105. package/dist/app/renderCodexFileDiff.d.ts +7 -0
  106. package/dist/app/renderCodexMcpToolCall.d.ts +2 -0
  107. package/dist/app/renderCompletedTurnStats.d.ts +2 -0
  108. package/dist/app/renderExecCommand.d.ts +11 -0
  109. package/dist/app/renderExploration.d.ts +9 -0
  110. package/dist/app/renderFullscreenComponent.d.ts +8 -0
  111. package/dist/app/renderHappyTerminalBanner.d.ts +6 -0
  112. package/dist/app/renderHappyTerminalVersion.d.ts +1 -0
  113. package/dist/app/renderNoticeWithChildren.d.ts +7 -0
  114. package/dist/app/renderPendingSteeringMessages.d.ts +1 -0
  115. package/dist/app/renderStartupStatusCard.d.ts +7 -0
  116. package/dist/app/renderSubagentSummary.d.ts +6 -0
  117. package/dist/app/renderTurnCompletionSeparator.d.ts +1 -0
  118. package/dist/app/renderWorkflowSummary.d.ts +1 -0
  119. package/dist/app/resolveInputBackground.d.ts +3 -0
  120. package/dist/app/resolveStartupProviderQuota.d.ts +3 -0
  121. package/dist/app/resolveStartupSessionId.d.ts +18 -0
  122. package/dist/app/resolveTerminalColorLevel.d.ts +2 -0
  123. package/dist/app/resolveTerminalStyle.d.ts +1 -0
  124. package/dist/app/resolveTerminalTheme.d.ts +5 -0
  125. package/dist/app/runApp.d.ts +27 -0
  126. package/dist/app/runClipboardCommand.d.ts +8 -0
  127. package/dist/app/sanitizeTerminalText.d.ts +1 -0
  128. package/dist/app/shortenHomePath.d.ts +2 -0
  129. package/dist/app/sortSubagentsForDisplay.d.ts +2 -0
  130. package/dist/app/subagentElapsedMs.d.ts +2 -0
  131. package/dist/app/subagentLogMessageText.d.ts +2 -0
  132. package/dist/app/surfaceThemedLine.d.ts +3 -0
  133. package/dist/app/truncatePathToWidth.d.ts +1 -0
  134. package/dist/app/truncateTextForDisplay.d.ts +5 -0
  135. package/dist/app/truncateUtf8BytesForDisplay.d.ts +1 -0
  136. package/dist/app/upsertSubagentSummary.d.ts +2 -0
  137. package/dist/app/workflowDisplay.d.ts +2 -0
  138. package/dist/client/HappyAgentEventHub.d.ts +25 -0
  139. package/dist/client/RemoteAgent.d.ts +74 -0
  140. package/dist/client/RemoteAgentRunError.d.ts +4 -0
  141. package/dist/client/RemoteTerminalAttachment.d.ts +19 -0
  142. package/dist/client/RemoteTerminalClientReplica.d.ts +14 -0
  143. package/dist/client/ensureLocalProtocolServer.d.ts +10 -0
  144. package/dist/client/fetchProviderQuotas.d.ts +10 -0
  145. package/dist/client/index.d.ts +8 -0
  146. package/dist/client/loadAgentCatalog.d.ts +32 -0
  147. package/dist/config/createProjectConfigSecurityNotice.d.ts +10 -0
  148. package/dist/config/defaultConfig.d.ts +2 -0
  149. package/dist/config/getDefaultGlobalConfigPath.d.ts +1 -0
  150. package/dist/config/getDefaultLocalConfigPath.d.ts +1 -0
  151. package/dist/config/getDefaultRuntimeConfigPath.d.ts +1 -0
  152. package/dist/config/getHappyConfigDirectory.d.ts +1 -0
  153. package/dist/config/getHappyTerminalHome.d.ts +1 -0
  154. package/dist/config/index.d.ts +15 -0
  155. package/dist/config/loadConfig.d.ts +2 -0
  156. package/dist/config/mergeConfigValues.d.ts +2 -0
  157. package/dist/config/parseConfigToml.d.ts +7 -0
  158. package/dist/config/readConfigFile.d.ts +2 -0
  159. package/dist/config/readProjectConfigFile.d.ts +2 -0
  160. package/dist/config/resolveConfigPaths.d.ts +2 -0
  161. package/dist/config/runtimeConfigLock.d.ts +1 -0
  162. package/dist/config/types.d.ts +74 -0
  163. package/dist/config/updateRuntimeConfig.d.ts +2 -0
  164. package/dist/config/updateRuntimePreferences.d.ts +2 -0
  165. package/dist/config/withoutProjectMachineSettings.d.ts +7 -0
  166. package/dist/config/writeRuntimeConfig.d.ts +3 -0
  167. package/dist/config/writeRuntimeConfigDefaults.d.ts +2 -0
  168. package/dist/daemon/createUnixSocketFetch.d.ts +2 -0
  169. package/dist/daemon/daemonPid.d.ts +11 -0
  170. package/dist/daemon/ensureHappyAgentBinary.d.ts +15 -0
  171. package/dist/daemon/ensureLocalProtocolServer.d.ts +24 -0
  172. package/dist/daemon/getHappyDaemonPaths.d.ts +16 -0
  173. package/dist/daemon/happyAgentBinaryConfig.d.ts +15 -0
  174. package/dist/daemon/index.d.ts +5 -0
  175. package/dist/daemon/runDaemonCommand.d.ts +4 -0
  176. package/dist/debug/DebugLog.d.ts +11 -0
  177. package/dist/debug/closeNodeInspector.d.ts +1 -0
  178. package/dist/debug/createDebugJsonReplacer.d.ts +1 -0
  179. package/dist/debug/createRequestDebugDirectory.d.ts +1 -0
  180. package/dist/debug/getDebugRootDirectory.d.ts +1 -0
  181. package/dist/debug/getNodeInspectorUrl.d.ts +1 -0
  182. package/dist/debug/index.d.ts +8 -0
  183. package/dist/debug/openNodeInspector.d.ts +1 -0
  184. package/dist/debug/registerHappyTerminalDebugRoot.d.ts +5 -0
  185. package/dist/docs/DESIGN.md +2191 -0
  186. package/dist/docs/README.md +93 -0
  187. package/dist/docs/agents-and-collaboration.md +365 -0
  188. package/dist/docs/architecture.md +468 -0
  189. package/dist/docs/extending.md +561 -0
  190. package/dist/docs/happy.md +386 -0
  191. package/dist/docs/permissions-and-sandbox.md +342 -0
  192. package/dist/docs/workspaces.md +281 -0
  193. package/dist/errorToMessage.d.ts +1 -0
  194. package/dist/formatCliFailure.d.ts +10 -0
  195. package/dist/index.d.ts +3 -0
  196. package/dist/index.js +17151 -0
  197. package/dist/main.js +18946 -0
  198. package/dist/observability/daemonContext.d.ts +16 -0
  199. package/dist/observability/index.d.ts +1 -0
  200. package/dist/processes/BoundedOutputBuffer.d.ts +20 -0
  201. package/dist/processes/NativeProcessManager.d.ts +66 -0
  202. package/dist/processes/ProcessGroupReaper.d.ts +32 -0
  203. package/dist/processes/index.d.ts +7 -0
  204. package/dist/processes/isProcessRunning.d.ts +1 -0
  205. package/dist/processes/isTargetProcessAlive.d.ts +1 -0
  206. package/dist/processes/killProcessTree.d.ts +2 -0
  207. package/dist/processes/resolveSystemShell.d.ts +1 -0
  208. package/dist/processes/startProcessTransport.d.ts +33 -0
  209. package/dist/processes/types.d.ts +41 -0
  210. package/dist/processes/waitForProcessExit.d.ts +2 -0
  211. package/dist/protocol/AppletProtocol.d.ts +101 -0
  212. package/dist/protocol/Attachment.d.ts +96 -0
  213. package/dist/protocol/ClientProtocolTypes.d.ts +481 -0
  214. package/dist/protocol/DocumentProtocol.d.ts +109 -0
  215. package/dist/protocol/EventId.d.ts +1 -0
  216. package/dist/protocol/FolderProtocol.d.ts +236 -0
  217. package/dist/protocol/FolderSharingProtocol.d.ts +97 -0
  218. package/dist/protocol/GitHubPluginProtocol.d.ts +43 -0
  219. package/dist/protocol/GlobalSecurityProtocol.d.ts +7 -0
  220. package/dist/protocol/HappyCloudProtocol.d.ts +178 -0
  221. package/dist/protocol/InstallationProtocol.d.ts +80 -0
  222. package/dist/protocol/OnboardingProtocol.d.ts +47 -0
  223. package/dist/protocol/P2pCredentialProtocol.d.ts +273 -0
  224. package/dist/protocol/P2pIdentityProtocol.d.ts +8 -0
  225. package/dist/protocol/P2pPairingProtocol.d.ts +68 -0
  226. package/dist/protocol/P2pProtocol.d.ts +185 -0
  227. package/dist/protocol/PluginWireTypes.d.ts +81 -0
  228. package/dist/protocol/ProfileProtocol.d.ts +127 -0
  229. package/dist/protocol/ProjectFileProtocol.d.ts +63 -0
  230. package/dist/protocol/ProjectProtocol.d.ts +646 -0
  231. package/dist/protocol/ProtocolVersion.d.ts +8 -0
  232. package/dist/protocol/ServiceNotice.d.ts +175 -0
  233. package/dist/protocol/SessionProtocol.d.ts +1156 -0
  234. package/dist/protocol/SharingProtocol.d.ts +159 -0
  235. package/dist/protocol/SlotProtocol.d.ts +270 -0
  236. package/dist/protocol/TimelineProtocol.d.ts +88 -0
  237. package/dist/protocol/WorkletProtocol.d.ts +159 -0
  238. package/dist/protocol/createEventIdFactory.d.ts +7 -0
  239. package/dist/protocol/index.d.ts +34 -0
  240. package/dist/readPackageVersion.d.ts +1 -0
  241. package/dist/readPackageVersion.js +16 -0
  242. package/dist/reportCliFailure.d.ts +2 -0
  243. package/dist/runHappyTerminal.d.ts +6 -0
  244. package/dist/terminal/index.d.ts +2 -0
  245. package/dist/terminal/types.d.ts +39 -0
  246. package/dist/types.d.ts +6 -0
  247. package/dist/writeStderrSync.d.ts +5 -0
  248. package/package.json +97 -0
@@ -0,0 +1,468 @@
1
+ # Happy Agent architecture
2
+
3
+ This document describes how Happy Agent is put together: the processes it runs, the
4
+ protocol between them, how inference and tools work, what is stored on disk, and
5
+ which package owns what. It is written for coding agents running inside Happy Agent and
6
+ for developers changing it.
7
+
8
+ It describes the behavior that is actually implemented. Where Happy Agent's stated
9
+ direction runs ahead of what ships today, that is called out explicitly in
10
+ [Where the product runs ahead of the code](#where-the-product-runs-ahead-of-the-code).
11
+
12
+ ## 1. The core idea
13
+
14
+ Happy Agent is one local harness that recreates several first-party coding agents on
15
+ top of a single runtime. GPT models receive Codex-shaped prompts and tools,
16
+ Claude models receive Claude Code-shaped prompts and tools, and Grok receives the
17
+ Grok Build prompt and tool contracts. Everything around inference — sessions,
18
+ permissions, sandboxing, persistence, subagents, MCP, the terminal — is shared.
19
+
20
+ Two consequences shape the whole system:
21
+
22
+ - **There is no Happy Agent account.** Happy Agent authenticates as the user's existing
23
+ installations do: it reads the credentials that Codex, Claude Code, and the
24
+ Grok CLI already manage on the machine, plus a Bedrock bearer token from the
25
+ environment when configured. The daemon only checks whether a credential is
26
+ present locally, and never asks a provider server which models exist.
27
+ - **Provider differences are confined to inference and the tool surface.** They
28
+ are not allowed to create a second security path, a second session model, or a
29
+ second persistence path. Every provider is routed through the same
30
+ `AgentContext`, `PermissionContext`, filesystem boundary, and shell sandbox.
31
+
32
+ Happy Terminal uses `@earendil-works/pi-tui` for terminal rendering. Happy Agent's
33
+ inference is implemented by the separately published, Node-only
34
+ `@slopus/happy-providers` library.
35
+
36
+ ## 2. Process architecture
37
+
38
+ Happy Agent is the long-lived headless daemon. Clients connect to it through the public API.
39
+ Happy Terminal is the official TUI client, available through the `happy` CLI, its own
40
+ `happy-terminal` and `rig` commands, Happy Desktop, or an embedded Node.js host. A standalone
41
+ Happy Terminal installation also locates and starts a compatible Happy Agent release.
42
+
43
+ ```text
44
+ happy / happy-terminal / rig / embedded host (Happy Terminal, one per window)
45
+ |
46
+ | HTTP + SSE over a unix socket, bearer token
47
+ v
48
+ happy-agent run (the daemon: sessions, agents, tools, SQLite)
49
+ |
50
+ +-- provider inference (happy-agent-base -> happy-providers -> vendor APIs)
51
+ +-- sandboxed shell, filesystem, Docker, MCP, background terminals
52
+ +-- sessions.sqlite
53
+ ```
54
+
55
+ ### The daemon
56
+
57
+ The daemon:
58
+
59
+ - creates its private runtime directory at `~/.happy/agent` (or beneath
60
+ `HAPPY_HOME_DIR`), holding `server.sock`, `token`, `daemon.pid`, `daemon.log`,
61
+ the SQLite stores, and `observation/agent.log`;
62
+ - listens on the unix socket only, with the socket `chmod`ed to `0600`, and
63
+ authorizes every request against the token file;
64
+ - serves the protocol HTTP routes and WebSocket terminals;
65
+ - streams events as `text/event-stream`;
66
+ - owns the SQLite database and the domain modules for sessions, projects, Git,
67
+ the model catalog, file search, MCP, Happy sync, and scheduling.
68
+
69
+ The daemon holds the agent loop, tool execution, and the sandbox. The terminal UI
70
+ holds no agent logic; if it dies, the session keeps running.
71
+
72
+ ### The terminal UI
73
+
74
+ The standalone Happy Terminal CLI parses the command line and picks a mode: interactive app, headless
75
+ `exec`, monitor, daemon control (`happy-terminal daemon start|stop|kill|status|reload`), or offline
76
+ installation inspection (`happy-terminal inspect [--json]`). The daemon itself is the
77
+ standalone `happy-agent` CLI. Development builds use this checkout, while published Happy Terminal
78
+ installations select and verify a compatible Happy Agent release. Graceful stop waits for
79
+ the daemon PID to exit; `kill` uses the persisted PID when a daemon cannot shut down cleanly.
80
+
81
+ Inspection is the exception to the daemon-starting path below. It reads installation, CLI version,
82
+ and protocol compatibility facts without starting or contacting the daemon. A clean or
83
+ upgradeable inspection exits 0; incompatible, damaged, busy, or unreadable data exits 2 after
84
+ printing the same complete human or JSON result.
85
+
86
+ Before doing anything else, an interactive or headless run finds a running
87
+ daemon, checks that its identity matches the current build, and spawns one when
88
+ it does not. When the running daemon is older than the current build, the CLI
89
+ asks before restarting it. The client talks HTTP over the unix socket.
90
+
91
+ The interactive interface is built on Pi TUI. Its layout rules are strict: the
92
+ logical transcript is append-only, live above-composer status is compact and
93
+ never pulls history downward, and a resize is a full-frame redraw rather than a
94
+ partial reflow.
95
+
96
+ ### The protocol between them
97
+
98
+ The protocol covers sessions, projects, the timeline, global security, project
99
+ files, and a version handshake. Its shape is deliberately two mechanisms:
100
+
101
+ - **Request/response** carries entities: sessions, projects, workspaces, models,
102
+ transcripts, usage, secrets, subagents, MCP status.
103
+ - **An event stream** carries light, ordered updates. Cursors are monotonic
104
+ UUIDv7 values, so events always sort. Three queues serve it: a live queue with
105
+ bounded replay for local clients, an in-memory queue, and a persistent queue
106
+ that writes durable entries and publishes only after the transaction commits.
107
+ A client that reconnects presents its last cursor and either resumes or is
108
+ told a gap occurred and it should re-fetch.
109
+
110
+ `@slopus/happy-agent-client` is the typed client for this protocol. It exposes
111
+ the documented request, SSE, and resource contracts over a caller-supplied
112
+ Fetch implementation, so Node, browser, and Unix-socket hosts share one API
113
+ surface without carrying daemon code.
114
+
115
+ ### Remote terminals
116
+
117
+ Separately from the agent protocol, Happy Agent can remote a real terminal. Both ends run
118
+ libghostty: the daemon holds the canonical emulator and the client holds a
119
+ replica, and the ordered terminal bytes themselves are the delta — there is no
120
+ diffing step. Snapshot first, deltas afterwards. Reconnection, packet loss, and
121
+ state recovery are part of the protocol rather than session-ending failures.
122
+
123
+ ## 3. Sessions
124
+
125
+ A session is one conversation with an agent, and it is the unit of durability.
126
+ The essentials:
127
+
128
+ - `InMemorySession` is the model. It runs turns, streams output, handles
129
+ permissions, aborts, rewinds, goals, subagents, and metadata.
130
+ - `SessionEventLog` is the per-session append-only event history, plus the
131
+ derived indexes a session needs to answer questions quickly (message identity,
132
+ permission reviews, shell command state, provider quotas, retention window).
133
+ - Two stores implement the same `SessionStore` interface:
134
+ `PersistentSessionStore` (the daemon's durable store, which also implements
135
+ `InMemorySessionPersistence`) and `InMemorySessionStore` (a private in-memory
136
+ SQLite database used by tests and the gym, so they exercise the real
137
+ persistence contract without leaving state behind).
138
+ - **Database first, memory second.** Every change writes through persistence and
139
+ only then updates in-memory state. This is not optional.
140
+
141
+ Because sessions live in the daemon and are persisted as they go, they survive a
142
+ closed terminal and a daemon restart. `happy-terminal resume`, `happy-terminal fork`,
143
+ `happy-terminal exec --resume`, and `--last` all reopen a stored session; headless runs are
144
+ ordinary persisted sessions.
145
+
146
+ Subagents are sessions too, with their transcripts saved and readable from the
147
+ parent.
148
+
149
+ ## 4. Inference
150
+
151
+ ### The layers
152
+
153
+ ```text
154
+ happy-agent-base the durable turn: inference, tools, compaction
155
+ |
156
+ happy-agent-modules reusable tools, hooks, and product capabilities
157
+ |
158
+ happy-providers the network: transports, framing, retries, errors, credentials
159
+ |
160
+ vendor APIs Codex, Claude Agent SDK, xAI Responses, Bedrock
161
+ ```
162
+
163
+ ### The turn
164
+
165
+ The agent loop runs one turn: build the provider prompt and message list, stream
166
+ inference, then execute every tool the model called — in parallel — and write all
167
+ tool results. Only after every tool call is closed may compaction run. Two
168
+ invariants hold throughout and are relied on by the provider layer:
169
+
170
+ - Nothing runs in parallel with an inference on the same session — not a second
171
+ inference, not a compaction.
172
+ - No tool call is ever left open across an inference boundary.
173
+
174
+ The conversation Happy Agent keeps is richer than what goes to the model.
175
+ `isExcludedFromModelContext` separates the durable transcript from the model
176
+ context, so Happy Agent can show a user things the provider never sees. Opaque provider
177
+ data — `vendor`, `responseItems`, `encryptedReasoning` — is persisted verbatim and
178
+ passed back unchanged, which is what makes reasoning and parallel tool calls
179
+ replay correctly.
180
+
181
+ ### Context and instructions
182
+
183
+ The system prompt is assembled per model family — Claude, Codex, Grok — and
184
+ extended by Happy Agent with the environment description, project instructions, and the
185
+ content of the project's `AGENTS.md` files. Happy Agent discovers those files,
186
+ fingerprints them, and re-delivers their content to the model when they change.
187
+
188
+ ### Compaction
189
+
190
+ Compaction is a message, not a side effect. Happy Agent decides _when_; the provider
191
+ decides _how_.
192
+
193
+ - The auto-compact threshold compares an estimate of the current context against
194
+ provider-reported usage, using the model's `autoCompactWindow` from the
195
+ catalog.
196
+ - Happy Agent refuses to compact a conversation with unanswered tool calls — in either
197
+ the summarized prefix or the retained tail — because that would hand the
198
+ provider a broken history.
199
+ - Compaction is requested from the provider session itself, which uses the
200
+ vendor's **native** compaction wherever one exists and the vendor's own
201
+ compaction prompt where it does not. Happy Agent never substitutes a generic summary.
202
+ - The result is a `CompactionMessage` in the transcript recording the IDs of the
203
+ messages it replaces, the provider-shaped replacement context, and before/after
204
+ statistics. The "after" size starts as a local estimate and is rewritten as
205
+ exact from the provider-reported usage of the first inference that follows.
206
+
207
+ `/compact` forces the same path immediately.
208
+
209
+ ## 5. Providers
210
+
211
+ `@slopus/happy-providers` is the only place that talks to a vendor.
212
+
213
+ ### The interface
214
+
215
+ ```text
216
+ BaseProvider -> .session(id, options) -> BaseSession -> .run(request) -> SessionStream
217
+ -> .compact(options)
218
+ -> .destroy()
219
+ ```
220
+
221
+ Happy Agent installs this package as a normal npm runtime dependency. The package is kept in the same
222
+ workspace for development, but it is built, versioned, tagged, and published independently rather
223
+ than compiled into the Happy Agent bundle.
224
+
225
+ Providers are **stateful**: a session is created once and used for many turns, so
226
+ connection reuse, prompt caching, sticky turn state, and native compaction are
227
+ possible. `run` is exclusive, and the caller supplies the complete durable
228
+ transcript on each turn while the session retains provider-native continuation
229
+ state.
230
+
231
+ Exported provider classes: `AnthropicProvider`, `CodexProvider`, `GrokProvider`, and
232
+ `ResponsesProvider`. `AnthropicProvider` selects its Claude Agent SDK or Bedrock Messages
233
+ implementation from the credential. Each provider follows the same fixed shape: a provider, a
234
+ session, credentials, native prompts, native tool definitions, and error parsing.
235
+
236
+ ### Fidelity
237
+
238
+ The package's entire purpose is that a Happy Agent request looks like the native
239
+ client's request, in this priority order: prompt-cache prefix stability, system
240
+ prompts, tool definitions, message ordering. The caller supplies prompt and tool
241
+ _content_; the package must reproduce the _envelope_ — field names and nesting,
242
+ ordering, cache-control placement, headers, framing. The native prompts and tool
243
+ definitions of each vendor are kept verbatim; they are internal and never
244
+ exported, kept so golden-trace tests can reproduce real requests and so a reader
245
+ can check what the native client actually does.
246
+
247
+ Caller history is immutable here. A provider may make an ephemeral projection
248
+ while serializing one request (dropping reasoning blocks a vendor would reject),
249
+ but it must never return a rewritten history.
250
+
251
+ ### Provider keys and configuration
252
+
253
+ Canonical provider keys are `codex` (OpenAI/GPT), `claude` (Anthropic),
254
+ `grok` (xAI), and `bedrock`. These are the `type` values in configuration and the
255
+ built-in instance IDs. SDK or transport names never leak into a provider key.
256
+
257
+ Configured provider entries are turned into executor provider definitions —
258
+ `codexExecution`, `claudeExecution`, `grokExecution`,
259
+ `configuredBedrockExecution` — and Happy Agent reports which configured providers lack
260
+ local credentials. Users can declare any number
261
+ of named instances (`[providers.work_codex]`) for separate accounts; a custom
262
+ instance must state its `type`, and the section suffix becomes the provider ID.
263
+
264
+ ### Model catalogs
265
+
266
+ Catalogs are hardcoded in Happy Agent: model ID, display name, thinking levels, default
267
+ thinking level, context window, and auto-compact window. The catalog a user sees
268
+ combines that curated list with configuration and local credential presence. The
269
+ daemon never
270
+ discovers or fetches models from a provider API — startup must not wait on the
271
+ network — and a provider that is disabled or unauthenticated stays in the catalog
272
+ as a disabled entry with no models and a human-readable reason.
273
+
274
+ ### Retries and errors
275
+
276
+ Retry semantics belong to the provider, never the outer loop. Everything
277
+ retryable is retried inside `happy-providers` and surfaced as `retrying` events; an
278
+ error that reaches the agent loop is terminal by definition and is displayed, not
279
+ replayed. Errors are parsed into a typed `SessionProviderError`
280
+ (`authentication`, `out_of_tokens`, `rate_limit`, `server_overloaded`,
281
+ `internal_server_error`, `unclassified`), and recorded real failure responses are
282
+ replayed through the real transport to keep the parsers honest.
283
+
284
+ ### Usage and accounts
285
+
286
+ `SessionCacheUsage` reports `input` (always uncached), `output`, `cacheRead`,
287
+ `cacheWrite`, and `totalTokens`, normalized so each prompt token is counted once.
288
+ Quota observation is best-effort, bounded, and cached, and surfaces through
289
+ `/usage` and the `get_provider_usage` tool.
290
+
291
+ Automatic routing across multiple accounts of the same vendor is a direction, not
292
+ a feature. Today the pieces that exist are multiple configured provider
293
+ instances, model/provider compatibility checks, and usage reporting; account
294
+ selection is still the user's or the caller's choice.
295
+
296
+ ## 6. Tools
297
+
298
+ ### Vendor tools versus common tools
299
+
300
+ - **Vendor tools** are the provider's own surface — native names, argument
301
+ schemas, and model guidance — one set each for Claude, Codex, and Grok. A
302
+ Bedrock provider picks the Claude or Codex surface based on the model ID
303
+ prefix.
304
+ - **Common tools** belong to Happy Agent itself and are identical for every model:
305
+ scheduling (`wait`, `wait_until`, `schedule_message`), agent-tree usage,
306
+ provider usage, plugin tools, and user-input cancellation. They are assembled
307
+ in exactly one place, so a model added later picks them up with no
308
+ per-provider work.
309
+ - Collaboration tools (subagents, workflows, messaging) are selected the same
310
+ way, in the vendor's shape.
311
+ - Optional universal tools are additive: the Gemini tools when `GEMINI_API_KEY`
312
+ is set, and image generation behind a vendor-shaped surface.
313
+
314
+ Both entry points are routed from the same place. A model's tools are never
315
+ assembled by branching on a provider key or a tool-name list elsewhere.
316
+
317
+ Different names, one implementation: Claude's `Bash` and Codex's `exec_command`
318
+ run the same sandboxed shell, and Claude's `Read`/`Write` and Codex's
319
+ `apply_patch` cross the same filesystem boundary.
320
+
321
+ ### Permissions
322
+
323
+ There is one permission model for every provider. The modes are **Read only**,
324
+ **Workspace write** (the default for new sessions), **Auto**, and
325
+ **Full access**; see [permissions-and-sandbox.md](permissions-and-sandbox.md).
326
+
327
+ Every tool definition owns its Auto behavior. `shouldReviewInAutoMode` is
328
+ required; `shouldRunInFullAccessInAutoMode` is defined only for reviewed actions
329
+ that genuinely must cross the sandbox; `requiresAutoOrFullAccess` marks tools such
330
+ as MCP whose external boundary Happy Agent cannot enforce locally. Review is automatic and
331
+ never becomes a question to the user: it ends in allow or deny, it covers only the
332
+ proposed action, and it never becomes a durable command policy. A denial that was
333
+ never actually made — a timeout, an unavailable reviewer — must tell the agent the
334
+ action is _unproven_ rather than unsafe, and a turn that keeps being refused has
335
+ to stop itself.
336
+
337
+ Escalation syntax is provider-shaped but requests the same runtime behavior:
338
+ Codex `exec_command` uses `sandbox_permissions: "require_escalated"` with a
339
+ `justification`, Claude `Bash` uses `dangerouslyDisableSandbox: true`, Grok
340
+ `run_terminal_command` uses `sandbox_permissions` with a `description`. In Auto,
341
+ an allowed escalation scopes only that one tool execution to full access and
342
+ restores Auto immediately afterwards. In Read only or Workspace write, the field
343
+ cannot bypass the selected mode.
344
+
345
+ Restricted shell commands use macOS Seatbelt or Linux Bubblewrap; managed network
346
+ access, when configured, goes through per-command HTTP CONNECT and SOCKS5 proxies
347
+ that are torn down with the command. Docker-backed sessions nest the same
348
+ Bubblewrap sandbox inside the container. Full details are in
349
+ [permissions-and-sandbox.md](permissions-and-sandbox.md).
350
+
351
+ ## 7. Persistence
352
+
353
+ Everything durable is one asynchronous SQLite database under `~/.happy/agent` by default.
354
+ `HAPPY_HOME_DIR` moves the `.happy` root.
355
+
356
+ ### Rules
357
+
358
+ One persistence layer owns every read and every mutation. No SQL — raw or
359
+ through the query builder — exists anywhere else. Reads are operations prefixed
360
+ with `query`. Every operation takes the transaction first and awaits one when it
361
+ needs it, which is a no-op inside an existing transaction, so each operation is
362
+ a complete consistency boundary that still composes. Each connection serializes
363
+ access through `asyncLock`; transaction-scoped work reuses its transaction
364
+ without reacquiring the lock. A database failure is fatal by policy: Happy Agent is
365
+ local, and continuing after one is not an option.
366
+
367
+ ### What is stored
368
+
369
+ The schema holds projects, project workspaces and avatar
370
+ assets, sessions, session events, session messages, session context messages,
371
+ session turns, queued runs, durable user inputs, durable waits, scheduled
372
+ messages, secret registrations and their environment variables,
373
+ project secret attachments, Happy sync sessions and outbox, and the durable
374
+ global-event stream with its cursor state. It also holds local Happy Cloud enrollment and consent
375
+ records plus caller-encrypted profile and bounded mobile-session ciphertext.
376
+
377
+ Secrets are stored as plaintext JSON in this database. The file is mode `0600`
378
+ and its directory `0700`, which is access control, not encryption: replaced values
379
+ may persist in SQLite pages and the WAL.
380
+
381
+ Non-database daemon state under `~/.happy/agent` includes runtime settings, Happy credentials,
382
+ logs, the socket, and the authentication token. Happy Terminal keeps its client-specific runtime
383
+ settings under `~/.happy/happy-terminal`. User
384
+ configuration is separate, in `~/Happy/Config/happy.toml` (macOS) or
385
+ `~/happy/config/happy.toml` (Linux), with repository settings in `happy.toml`.
386
+
387
+ ### Migrations
388
+
389
+ Happy Agent applies an ordered list of migration functions inside one immediate
390
+ transaction, advancing `PRAGMA user_version` after each one and stamping
391
+ `PRAGMA application_id`.
392
+
393
+ - **Migrations are immutable.** Once a migration exists, its contents and version
394
+ never change, because a released Happy Agent may already have applied it. Every
395
+ subsequent schema change is a new file.
396
+ - **Generations reset.** A database whose `application_id` does not match the
397
+ current Happy Agent generation is dropped and rebuilt from the initial migration, which
398
+ therefore contains the complete current schema with no backfill path. That is
399
+ the early-stage policy: discard the old schema rather than carry compatibility
400
+ code forward.
401
+ - A database from a _newer_ schema version than the running Happy Agent is an error, not
402
+ a downgrade.
403
+
404
+ ## 8. Package layout
405
+
406
+ `packages/` in a pnpm TypeScript workspace. Source lives in `sources/`, with
407
+ `sources/main.ts` for an executable and `sources/index.ts` for a library.
408
+
409
+ | Package | What it is |
410
+ | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
411
+ | `packages/happy-agent` | `@slopus/happy-agent` — the headless daemon executable and lifecycle used by every client. |
412
+ | `packages/happy-terminal` | `@slopus/happy-terminal` — the reusable TUI, standalone `happy-terminal` and `rig` commands, Happy Agent launcher, and Node.js embedding API. |
413
+ | `packages/happy-agent-base` | `@slopus/happy-agent-base` — the minimal durable agent loop, provider routing, persistence, and feature hooks. |
414
+ | `packages/happy-agent-modules` | `@slopus/happy-agent-modules` — reusable agent tools, hooks, and product capabilities composed by Happy Agent. |
415
+ | `packages/happy-providers` | `@slopus/happy-providers` — the separately published, Node-only vendor library: stateful sessions, transports, retries, error parsing, credentials, and native compaction. |
416
+ | `packages/happy-agent-client` | `@slopus/happy-agent-client` — the typed request and SSE client for the public Happy Agent API. |
417
+ | `packages/ghostty-wasm` | `@slopus/ghostty-wasm` — the Ghostty terminal emulator compiled to WebAssembly, usable from Node and the browser. |
418
+ | `packages/ghostty-web` | `@slopus/ghostty-web` — the client/server protocol for remoting a Ghostty-backed terminal: snapshot, VT replay, semantic-grid recovery, flow control, paged scrollback. |
419
+ | `packages/happy-plugins` | The typed API available to TypeScript plugins running inside Happy, plus the development runner. |
420
+ | `packages/gym` | Private host-side end-to-end harness: PTY integration, fixtures, and the Docker image definition. |
421
+ | `packages/gym-tests` | Private black-box terminal scenarios exercising Happy Terminal and Happy Agent together in fresh containers. |
422
+
423
+ Inside a package, code is organized by domain module (`git`, `fs`, `sandbox`,
424
+ `docker`, `secrets`, `session`, `server`, `persistence`, …). A module's top level
425
+ holds what a reader needs; secondary helpers go in `impl/` with entity-then-
426
+ operation names; tests live in a nearby `tests/` directory rather than beside the
427
+ source; every directory carries a `README.md`. `happy-providers` is the deliberate
428
+ exception to one-function-per-file: it keeps larger files so a whole network path
429
+ stays readable in one place.
430
+
431
+ ## 9. Testing
432
+
433
+ - Unit and integration tests run with Vitest next to the code they cover.
434
+ - Golden-trace tests in `happy-providers` compare reconstructed requests against
435
+ real captured vendor traffic; recorded-response tests replay real HTTP failures
436
+ through the real transport. Both are deterministic and need no credentials.
437
+ - Live tests are named `*.live.test.ts` and gated behind `HAPPY_TERMINAL_LIVE_TEST=1`.
438
+ - The **gym** (`pnpm test:gym`) runs the built CLI and daemon through a real PTY
439
+ in a fresh Docker container. Only inference is mocked; the filesystem, shell,
440
+ processes, daemon, tools, and terminal rendering are real, with `libghostty-vt`
441
+ providing user-visible screen and scroll state. Use it for anything spanning
442
+ terminal input or rendering, inference, tools, processes, filesystem effects,
443
+ interruption, or concurrency.
444
+
445
+ For a bug fix, add the smallest deterministic test that reproduces the failure at
446
+ the layer where the broken contract is observable, keep that test unchanged while
447
+ fixing production code, and only then add lower-level tests.
448
+
449
+ ## 10. Where the product runs ahead of the code
450
+
451
+ Some of Happy Agent's stated direction is ahead of what ships today. Where that gap
452
+ matters in practice, it is worth naming:
453
+
454
+ - **Kimi Code.** A `kimi` provider using Moonshot's Chat Completions API is
455
+ described in some product material, but there is no Kimi provider: the provider
456
+ `type` union is `codex | claude | grok | bedrock`. Treat Kimi as intent, not
457
+ current behavior.
458
+ - **Pi as a tool surface.** A Pi `bash` tool is sometimes described alongside the
459
+ Codex, Claude, and Grok surfaces. The implemented vendor tool surfaces are
460
+ Claude, Codex, and Grok; Pi appears as the TUI library
461
+ (`@earendil-works/pi-tui`), not as a provider or toolset.
462
+ - **Account routing** is not implemented. Multiple accounts can be configured as
463
+ separate provider instances and chosen explicitly; automatic round-robin,
464
+ weighted, or usage-aware routing between compatible accounts does not exist
465
+ yet.
466
+ - **`fork` on `BaseSession`** is part of the provider contract but is not yet
467
+ implemented, so there is currently no supported way to branch a provider
468
+ session — including the compact-on-a-fork flow that motivates it.