@agentshouse/kit 0.1.0-alpha.3 → 0.1.0-alpha.30

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 (142) hide show
  1. package/README.md +697 -260
  2. package/bin/connect-linux.sh +200 -25
  3. package/bin/kit.js +179 -157
  4. package/bootstrap.json +17 -0
  5. package/package.json +7 -2
  6. package/src/adapter-mcp.js +76 -12
  7. package/src/agents.js +63 -8
  8. package/src/binding.js +52 -0
  9. package/src/blocks.js +2 -26
  10. package/src/bridge.js +28 -14
  11. package/src/bytes.js +19 -8
  12. package/src/configuration.js +13 -209
  13. package/src/connector-login.js +3 -84
  14. package/src/contract.js +36 -11
  15. package/src/delivery.js +4 -7
  16. package/src/directory.js +6 -26
  17. package/src/draft.js +4 -82
  18. package/src/git-main.js +138 -0
  19. package/src/git.js +62 -0
  20. package/src/google/calendar.js +39 -45
  21. package/src/google/drive.js +61 -186
  22. package/src/google/entries.js +346 -0
  23. package/src/google/gateway.js +3 -6
  24. package/src/google/gmail.js +33 -23
  25. package/src/google/oauth.js +106 -66
  26. package/src/google/source.js +21 -23
  27. package/src/host.js +6 -2
  28. package/src/house-main.js +65 -8
  29. package/src/house.js +446 -127
  30. package/src/how-we-work.md +25 -0
  31. package/src/inbound.js +2 -18
  32. package/src/kit-work-stream.js +118 -0
  33. package/src/launcher.js +46 -10
  34. package/src/local-files.js +3 -11
  35. package/src/login.js +23 -11
  36. package/src/mcp.js +18 -0
  37. package/src/mount.js +13 -21
  38. package/src/original.js +4 -4
  39. package/src/pacing.js +41 -0
  40. package/src/plan.js +37 -45
  41. package/src/repository.js +3 -61
  42. package/src/session-bin/git +2 -0
  43. package/src/setup.js +14 -15
  44. package/src/skill-set/ask-matt/PHASE-BOUNDARIES.md +55 -0
  45. package/src/skill-set/ask-matt/SKILL.md +91 -0
  46. package/src/skill-set/ask-matt/agents/openai.yaml +4 -0
  47. package/src/skill-set/code-review/LICENSE +21 -0
  48. package/src/skill-set/code-review/SKILL.md +89 -0
  49. package/src/skill-set/code-review/agents/openai.yaml +3 -0
  50. package/src/skill-set/codebase-design/DEEPENING.md +37 -0
  51. package/src/skill-set/codebase-design/DESIGN-IT-TWICE.md +44 -0
  52. package/src/skill-set/codebase-design/LICENSE +21 -0
  53. package/src/skill-set/codebase-design/SKILL.md +116 -0
  54. package/src/skill-set/codebase-design/agents/openai.yaml +3 -0
  55. package/src/skill-set/diagnosing-bugs/LICENSE +21 -0
  56. package/src/skill-set/diagnosing-bugs/SKILL.md +140 -0
  57. package/src/skill-set/diagnosing-bugs/agents/openai.yaml +3 -0
  58. package/src/skill-set/diagnosing-bugs/scripts/hitl-loop.template.sh +44 -0
  59. package/src/skill-set/domain-modeling/ADR-FORMAT.md +47 -0
  60. package/src/skill-set/domain-modeling/CONTEXT-FORMAT.md +60 -0
  61. package/src/skill-set/domain-modeling/LICENSE +21 -0
  62. package/src/skill-set/domain-modeling/SKILL.md +76 -0
  63. package/src/skill-set/domain-modeling/agents/openai.yaml +3 -0
  64. package/src/skill-set/grill-me/LICENSE +21 -0
  65. package/src/skill-set/grill-me/SKILL.md +8 -0
  66. package/src/skill-set/grill-me/agents/openai.yaml +4 -0
  67. package/src/skill-set/grill-with-docs/LICENSE +21 -0
  68. package/src/skill-set/grill-with-docs/SKILL.md +8 -0
  69. package/src/skill-set/grill-with-docs/agents/openai.yaml +4 -0
  70. package/src/skill-set/grilling/LICENSE +21 -0
  71. package/src/{starter-set → skill-set}/grilling/SKILL.md +1 -1
  72. package/src/skill-set/handoff/LICENSE +21 -0
  73. package/src/skill-set/handoff/SKILL.md +17 -0
  74. package/src/skill-set/handoff/agents/openai.yaml +4 -0
  75. package/src/skill-set/implement/LICENSE +21 -0
  76. package/src/skill-set/implement/SKILL.md +16 -0
  77. package/src/skill-set/implement/agents/openai.yaml +4 -0
  78. package/src/skill-set/improve-codebase-architecture/HTML-REPORT.md +123 -0
  79. package/src/skill-set/improve-codebase-architecture/LICENSE +21 -0
  80. package/src/skill-set/improve-codebase-architecture/SKILL.md +72 -0
  81. package/src/skill-set/improve-codebase-architecture/agents/openai.yaml +4 -0
  82. package/src/skill-set/prototype/LICENSE +21 -0
  83. package/src/skill-set/prototype/LOGIC.md +67 -0
  84. package/src/skill-set/prototype/SKILL.md +28 -0
  85. package/src/skill-set/prototype/UI.md +112 -0
  86. package/src/skill-set/prototype/agents/openai.yaml +3 -0
  87. package/src/skill-set/research/LICENSE +21 -0
  88. package/src/skill-set/research/SKILL.md +14 -0
  89. package/src/skill-set/research/agents/openai.yaml +3 -0
  90. package/src/skill-set/resolving-merge-conflicts/LICENSE +21 -0
  91. package/src/skill-set/resolving-merge-conflicts/SKILL.md +16 -0
  92. package/src/skill-set/resolving-merge-conflicts/agents/openai.yaml +3 -0
  93. package/src/skill-set/tdd/LICENSE +21 -0
  94. package/src/skill-set/tdd/SKILL.md +40 -0
  95. package/src/skill-set/tdd/agents/openai.yaml +3 -0
  96. package/src/skill-set/tdd/mocking.md +59 -0
  97. package/src/skill-set/tdd/tests.md +77 -0
  98. package/src/skill-set/teach/GLOSSARY-FORMAT.md +35 -0
  99. package/src/skill-set/teach/LEARNING-RECORD-FORMAT.md +46 -0
  100. package/src/skill-set/teach/LICENSE +21 -0
  101. package/src/skill-set/teach/MISSION-FORMAT.md +31 -0
  102. package/src/skill-set/teach/RESOURCES-FORMAT.md +32 -0
  103. package/src/skill-set/teach/SKILL.md +141 -0
  104. package/src/skill-set/teach/agents/openai.yaml +4 -0
  105. package/src/skill-set/to-questionnaire/LICENSE +21 -0
  106. package/src/skill-set/to-questionnaire/SKILL.md +55 -0
  107. package/src/skill-set/to-questionnaire/agents/openai.yaml +4 -0
  108. package/src/skill-set/to-spec/LICENSE +21 -0
  109. package/src/skill-set/to-spec/SKILL.md +76 -0
  110. package/src/skill-set/to-spec/agents/openai.yaml +4 -0
  111. package/src/skill-set/to-tickets/LICENSE +21 -0
  112. package/src/skill-set/to-tickets/SKILL.md +106 -0
  113. package/src/skill-set/to-tickets/agents/openai.yaml +4 -0
  114. package/src/skill-set/wait-what/LICENSE +21 -0
  115. package/src/skill-set/wait-what/SKILL.md +8 -0
  116. package/src/skill-set/wait-what/agents/openai.yaml +4 -0
  117. package/src/skill-set/wayfinder/LICENSE +21 -0
  118. package/src/skill-set/wayfinder/SKILL.md +129 -0
  119. package/src/skill-set/wayfinder/agents/openai.yaml +4 -0
  120. package/src/skill-set/writing-for-agents/LICENSE +21 -0
  121. package/src/skill-set/writing-for-agents/SKILL-MECHANICS.md +22 -0
  122. package/src/skill-set/writing-for-agents/SKILL.md +83 -0
  123. package/src/skill-set/writing-for-agents/agents/openai.yaml +3 -0
  124. package/src/skill-set.js +85 -0
  125. package/src/source.js +93 -54
  126. package/src/state.js +19 -1
  127. package/src/sync-library.js +7 -11
  128. package/src/sync-state.js +16 -3
  129. package/src/sync.js +36 -21
  130. package/src/tasks.js +75 -0
  131. package/src/telegram-view.js +214 -0
  132. package/src/telegram.js +161 -66
  133. package/src/turn-frames.js +69 -0
  134. package/src/worker.js +674 -184
  135. package/src/working-copy.js +1221 -0
  136. package/src/workspace.js +40 -32
  137. package/src/google/declared.js +0 -146
  138. package/src/google/id.js +0 -1
  139. package/src/instance/google.js +0 -1
  140. package/src/starter-set.js +0 -17
  141. /package/src/{starter-set/grilling → skill-set/ask-matt}/LICENSE +0 -0
  142. /package/src/{starter-set → skill-set}/grilling/agents/openai.yaml +0 -0
package/README.md CHANGED
@@ -4,61 +4,184 @@ House Kit is a public package repository. Product development is planned and
4
4
  coordinated in the [Agents House repository](https://github.com/trof3039/agents.house);
5
5
  this repository contains only the package source and its operator documentation.
6
6
 
7
+ The Skill set Kit installs is Matt Pocock's
8
+ [`mattpocock/skills`](https://github.com/mattpocock/skills); thank you, Matt.
9
+
7
10
  ## Connect a Linux computer
8
11
 
9
- On Linux `amd64` or `arm64` with a working Docker Engine, run the published,
10
- versioned bootstrap once:
12
+ On Linux `amd64` or `arm64`, run the published, versioned bootstrap once:
11
13
 
12
14
  ```sh
13
- bash <(curl -fsSL https://github.com/agentshouse/kit/releases/download/v0.1.0-alpha.3/connect-linux.sh)
15
+ bash <(curl -fsSL https://github.com/agentshouse/kit/releases/download/v0.1.0-alpha.30/connect-linux.sh)
14
16
  ```
15
17
 
18
+ The bootstrap first establishes Docker Engine from what it observes on the
19
+ computer. A Docker Engine that already answers is used as it is, on any
20
+ distribution. On Ubuntu 22.04, 24.04 or 26.04 LTS it follows Docker's
21
+ [apt repository recipe](https://docs.docker.com/engine/install/ubuntu/) for
22
+ whatever is missing: it installs `docker-ce`, `docker-ce-cli`,
23
+ `containerd.io`, `docker-buildx-plugin` and `docker-compose-plugin` from
24
+ `download.docker.com`, starts the `docker` service when it is stopped and adds
25
+ the account to the `docker` group. Every such step runs through `sudo`, which
26
+ asks for the password as it ordinarily does. A new group membership applies
27
+ from the account's next sign-in, so the invocation that grants it reaches
28
+ Docker Engine through `sudo` for the rest of its own run; a later invocation
29
+ from a session older than the membership is refused until the account signs
30
+ out and back in. The bootstrap refuses an Ubuntu computer whose installed
31
+ `docker.io`, `docker-compose`, `docker-compose-v2`, `docker-doc`,
32
+ `docker-buildx`, `podman-docker`, `containerd` or `runc` package conflicts with
33
+ that recipe rather than removing it. Any other distribution needs a working
34
+ Docker Engine supplied by its owner, and without one the bootstrap stops with
35
+ that missing prerequisite. A step that fails names its cause and changes
36
+ nothing further; running the same bootstrap again continues from the state it
37
+ left, including after a restart.
38
+
16
39
  The release asset pins one immutable multi-architecture image digest. It creates
17
40
  owner-protected `~/.house-kit` and `~/AgentsHouse`, mounts those as the complete
18
41
  Kit home and `/agents/house`, enrolls through House Login in the host browser,
19
42
  and starts the container with Docker's `unless-stopped` lifecycle. Pass
20
43
  `--workspace /absolute/path` for one other workspace root or `--manual` for
21
44
  the existing URL and one-time-code login route. `--house <origin>` selects
22
- another House and is retained in Kit home. A repeated invocation reuses the
23
- same container, credential and Environment; a different installed image is
24
- left for the explicit update journey.
45
+ another House and is retained in Kit home. A local loopback House,
46
+ `http://127.0.0.1:<port>` or `http://localhost:<port>`, runs the resident
47
+ container on the host network, as the one-shot login, credential check and
48
+ apply containers always run, so the resident reaches the House the host serves;
49
+ an HTTPS House leaves it on Docker's own network. A repeated invocation reuses the
50
+ same container, credential and Environment. Every invocation that is not a
51
+ forwarded command also sets `skills` in Kit's configuration: `--no-skills`
52
+ declines [the Skill set](#the-skill-set) and an invocation without it accepts
53
+ the set again.
54
+
55
+ Running a newer release's bootstrap the same way is the only update. When the
56
+ installed container runs another image, the bootstrap pulls this release's
57
+ image and asks the running resident Kit to drain with `kit resident drain`. The
58
+ resident stops acquiring Runs, resumptions, setup, agent CLI work, Google
59
+ sign-ins and scheduled Google captures, while the Sessions it supervises keep
60
+ their renewal, owner stops, answers and reports and a capture already running
61
+ finishes.
62
+ While any Agent Session is still running or unreported, including one whose Run
63
+ was being acquired when the drain began, the bootstrap names it and leaves the
64
+ container as it is; rerun it once they end. Once nothing remains,
65
+ the resident stops renewing, releases its exact lease and stays quiescent, and
66
+ the bootstrap replaces the container with one on this release's image over the
67
+ same Kit home and workspace. The credential, Environment, Kit-home state and
68
+ everything under the workspace are kept; anything installed elsewhere in the old
69
+ container is not. A stopped container is replaced without a drain.
70
+
71
+ If House refuses the installed Kit with `kit_upgrade_required`, including in
72
+ its answer to a command the resident serves, the resident calls House no more,
73
+ neither to release nor to report. It keeps supervising
74
+ every running Session locally and never stops one to make progress. A Session
75
+ that ends keeps its exact binding, stop observation and outcome in Kit home,
76
+ and the drain answers ready once no supervised process runs. The updated Kit
77
+ waits for the old lease to expire, acquires the next one and reports each held
78
+ Session before it acquires any work, restoring no process and inventing no
79
+ outcome.
80
+
81
+ The versioned `bootstrap.json` is the machine-readable command source for this
82
+ release. It is exported from the npm package as `@agentshouse/kit/bootstrap`
83
+ (JSON import) and published byte-for-byte beside `connect-linux.sh` in the
84
+ GitHub release. Its schema version is `1`, its `version` is the Kit package
85
+ version, and `hosts` contains only bootstrap scripts published in that release.
86
+ The package exports only the `./bootstrap` subpath; `./package.json` and source
87
+ subpaths are not exported. For this release, only `hosts.linux` exists. In this
88
+ schema example, `<version>` stands for the package's version:
89
+
90
+ ```json
91
+ {
92
+ "schemaVersion": 1,
93
+ "version": "<version>",
94
+ "hosts": {
95
+ "linux": {
96
+ "command": "bash <(curl -fsSL https://github.com/agentshouse/kit/releases/download/v<version>/connect-linux.sh)",
97
+ "asset": {
98
+ "name": "connect-linux.sh",
99
+ "url": "https://github.com/agentshouse/kit/releases/download/v<version>/connect-linux.sh"
100
+ },
101
+ "workspace": { "argument": "--workspace", "quoting": "posix" }
102
+ }
103
+ }
104
+ }
105
+ ```
106
+
107
+ `command` is complete for the default workspace. To show a selected absolute
108
+ workspace, append the declared `workspace.argument` and the path as one POSIX
109
+ shell-quoted argument. For example, `/home/user/My Agents' House` becomes
110
+ `--workspace '/home/user/My Agents'\'' House'`. Quote the entire path before
111
+ adding it to a copyable shell command; never interpolate it as shell syntax.
112
+ The bootstrap validates an absolute workspace root and encodes it as one Docker
113
+ `--mount` CSV source field, including commas and double quotes in the name.
114
+ The package manifest contains no image digest: the release workflow
115
+ fills the immutable image digest into the published script after the package
116
+ has been built.
25
117
 
26
118
  The bootstrap does not install native Kit on an ordinary computer. The native
27
119
  package remains for managed Nodes and an explicitly selected eligible Kit host.
28
120
 
121
+ The same bootstrap is the host's entry point for the existing `kit` commands:
122
+ append `kit` and the command to the connect command above, as in
123
+ `bash <(curl -fsSL …/connect-linux.sh) kit apply` or
124
+ `bash <(curl -fsSL …/connect-linux.sh) kit telegram connect`. It forwards the
125
+ command and its arguments unchanged into the installed container through the
126
+ host's Docker client and ends with the command's own output and exit status.
127
+ Standard input stays attached and a terminal stays a terminal, so a hidden
128
+ prompt such as the Telegram bot token is read inside the container and never
129
+ becomes an argument or printed output. With the output redirected, the
130
+ command's output and errors stay separate and the terminal stops echoing typed
131
+ input until the command ends. A running container runs the command beside its
132
+ resident Kit; a stopped one runs it in a one-off container over the same Kit
133
+ home and workspace and stays stopped. `kit login` takes the bootstrap's own
134
+ login route, a one-off container on the host network so the host browser can
135
+ return to its loopback listener, or `--manual` for the URL and one-time code.
136
+ Forwarding installs no host-native Kit and gives the container no Docker socket
137
+ or further mount; it refuses when no Kit is installed or the installed one
138
+ differs from this bootstrap's.
139
+
140
+ The owner's working copy push is forwarded the same way: run
141
+ `bash <(curl -fsSL …/connect-linux.sh) house git push [commit] --owner` from a
142
+ directory beneath the workspace root, such as a Room copy under
143
+ `working-copies/rooms/`. The bootstrap runs the container's `house` in the
144
+ matching directory beneath `/agents/house`, through the resident's lease when
145
+ the container runs, and refuses a directory outside the workspace before
146
+ anything reaches House.
147
+
29
148
  ## Building the package
30
149
 
31
- The repository checkout is the development source. Build the package
32
- that can be published by supplying House's dedicated installed-application
33
- Google OAuth client, its id and its client secret:
150
+ The repository checkout is the development source. Build the package that can
151
+ be published:
34
152
 
35
153
  ```sh
36
- HOUSE_KIT_GOOGLE_OAUTH_CLIENT_ID=kit-client.apps.googleusercontent.com \
37
- HOUSE_KIT_GOOGLE_OAUTH_CLIENT_SECRET=GOCSPX-kit-installed-app \
38
154
  npm run build
39
155
  ```
40
156
 
41
- The command writes the publishable package to `dist/package`. Both values are
42
- public instance content fixed into that package at build time: Google issues an
43
- installed application's client secret without treating it as confidential, and
44
- still requires it in every token request. The installed Kit does not read either
45
- from its runtime environment and never requests them from House.
157
+ The command writes the publishable package to `dist/package`. It reads no
158
+ environment and ships no provider OAuth client: each Google account signs in
159
+ with the User's own client, as [the Google preset](#the-google-preset)
160
+ describes.
46
161
 
47
162
  Runtime dependencies stay minimal and exactly pinned in `package.json` and
48
163
  `package-lock.json`: House's own `@agentshouse/mdmodel`, `yaml`, which reads
49
164
  House's text answers, and the Agent Client Protocol SDK
50
165
  `@agentclientprotocol/sdk` with its peer `zod`, which is this Kit's one protocol
51
- client for the compiled adapter contracts. The SDK's approval
166
+ client for the compiled adapter contracts, and `ws` for the authenticated Kit
167
+ control stream. The SDK's approval
52
168
  receipt is [`docs/agents/acp-sdk-dependency-approval.json`](docs/agents/acp-sdk-dependency-approval.json),
53
169
  which the User wrote once this adoption's proof had passed. The adapter
54
170
  packages themselves are Environment prerequisites, not Kit dependencies, and
55
171
  carry no record.
56
172
 
57
- The bootstrap invokes bare `kit login`. The first login names its new
173
+ The bootstrap invokes bare `kit login`, which connects to `https://agents.house`;
174
+ `--house <origin>` names another House. Login records the House in Kit home
175
+ beside the credential. Every House-bound command talks to that recorded House,
176
+ and every command but login refuses `--house` as an unknown argument. The first login names its new
58
177
  Environment after the host computer and stores its Environment id in Kit home;
59
- an explicit later login reconnects that retained id. `--environment <uuid>`
60
- selects a different retained Environment for explicit recovery. A malformed
61
- id or an answer naming a different Environment is refused before installation.
178
+ the panel renames it. An explicit later login reconnects that retained id, and
179
+ `--environment <uuid>` reconnects the Environment it names instead, whether or
180
+ not Kit home records one, and Kit home then records that id. Reconnecting issues the next credential for the same Environment
181
+ and ends the previous one, including one `envs/revoke` ended; House refuses an
182
+ Environment it no longer holds with its cause and never creates a replacement.
183
+ A malformed id or an answer naming a different Environment is refused before
184
+ installation.
62
185
 
63
186
  Use `--manual` when the browser cannot reach the Kit's loopback listener. The
64
187
  command stores the issued Kit User credential in `$HOUSE_KIT_HOME/credential`
@@ -112,7 +235,8 @@ never printed by Kit.
112
235
  "settings": "/home/ada/.claude/settings.json"
113
236
  }
114
237
  ],
115
- "host": null
238
+ "host": null,
239
+ "skills": true
116
240
  }
117
241
  ```
118
242
 
@@ -132,13 +256,19 @@ mode: `"intermittent"` for a laptop or other normally offline placement,
132
256
  any other value refuses as `kit_configuration_invalid`; `kit apply` sends the
133
257
  declared mode with the rest of the desired state. An
134
258
  instance declares one or more services, and under the `custom` preset each
135
- service owns the command that produces it.
259
+ service owns the command that produces it. The Kit reads only `custom` instances
260
+ and passes over any other entry of `instances`.
136
261
 
137
262
  `host` declares the Linux host this installation measures for
138
263
  [host capacity reporting](#host-capacity). `null` declares that this Kit reports
139
264
  no capacity; the section is required like the others, so a host is measured only
140
265
  where the Environment owner says so.
141
266
 
267
+ `skills` is this Environment's choice of [the Skill set](#the-skill-set):
268
+ `true` accepts it and `false` declines it. A configuration that omits it
269
+ accepts the set. The bootstrap writes it on every invocation that is not a
270
+ forwarded command.
271
+
142
272
  `clients` is the local Agent client catalogue and never leaves the installation.
143
273
  Each entry names one client whose lifecycle hook configuration this Kit
144
274
  reconciles: `kind` is `claude-code`, the one client this Kit installs a hook
@@ -165,7 +295,7 @@ and the batch it produces, and the lease has to outlive both.
165
295
  Apply the declared source state to House:
166
296
 
167
297
  ```sh
168
- kit apply --house https://agents.house
298
+ kit apply
169
299
  ```
170
300
 
171
301
  Only the state House declares - instances, services, `source_ref`, and Room
@@ -233,119 +363,81 @@ refuses as `kit_hook_rejected` instead of leaving whatever was installed before.
233
363
 
234
364
  ## The Google preset
235
365
 
236
- The published Kit is built with one House-owned Google installed-application
237
- OAuth client. Its id and client secret are public build-time instance content,
238
- not House secrets and not values served by House at run time. Google refresh
239
- and access tokens remain in the installation's local credential store.
366
+ House holds this Environment's Google Sources, and its owner sets them in the
367
+ App. Each entry names an account name the owner chooses, one service -
368
+ `gmail`, `calendar` or `drive` - the Rooms it goes to, and what its first
369
+ capture takes: `{ "new": true }` for new activity only, `{ "days": n }`,
370
+ `{ "items": n }` or `{ "all": true }`. Neither the configuration file nor any
371
+ command on this computer declares one.
372
+
373
+ Each service captures a fixed corpus under its own read-only scope: Gmail every
374
+ message but Spam and Trash, Calendar the account's primary calendar, and Drive
375
+ the files the account owns.
376
+
377
+ The resident reads the list from `/kit/sources/desired` each time its Kit
378
+ control stream connects and each time House signals `sources` on it, then
379
+ reconciles:
380
+
381
+ - a new entry gets its local state and is captured once its account is signed
382
+ in for its service;
383
+ - a changed entry's Rooms take effect on its next capture;
384
+ - an entry House no longer lists stops, and its checkpoint, health, gaps,
385
+ dropped items and unsaved originals are deleted;
386
+ - an account left with no entry has each of its grants revoked at Google's
387
+ revocation endpoint and its credentials, its OAuth client included, deleted.
388
+ Google's revocation ends every grant the Google user gave the client's
389
+ project, so when another listed account is signed in to the same Google user,
390
+ the Kit deletes the local credentials and revokes nothing.
391
+
392
+ It then reports every entry to `/kit/sources/report`, and reports an entry
393
+ again after each sign-in and each capture: `signed_out` while its
394
+ account holds no grant for its service, `failed` with its cause code when its
395
+ last capture failed, and `ready` otherwise, each with the account's signed-in
396
+ email once the Kit knows it.
397
+
398
+ The Kit ships no Google OAuth client. Each account signs in with the User's
399
+ own: an OAuth client of type Desktop app in the User's Google Cloud project,
400
+ with the service's API enabled there. An entry whose account holds no grant for
401
+ its service opens a login renewal for integration `google`, instance the
402
+ account name and service the entry's service, and presents its ceremony on
403
+ House's owner-authenticated page, so the owner's browser never has to reach
404
+ this Environment. When the account has no client yet, the page first collects
405
+ the client id and secret. It then links to Google's consent for that service's
406
+ scope only; Google sends the browser to a `http://127.0.0.1:<port>/` address
407
+ that nothing answers, and the owner pastes that whole address into the page.
408
+ The Kit accepts it only when it carries the state its own consent issued,
409
+ exchanges the code with its PKCE verifier and the account's client, and stores
410
+ the grant beside the client in `state/google/credentials/<account>.json`. The
411
+ collected values pass through House's live relay only; neither they nor any
412
+ token enter a report, a log or anything House stores. Adding a
413
+ service to a signed-in account asks only for that service's consent, and each
414
+ service keeps its own grant. An address that answers another consent, or a code
415
+ Google refuses to exchange, stores nothing; a declined consent or a ceremony
416
+ that outlives its ten-minute bound cancels the sign-in, and the Kit tries again
417
+ at the next reconciliation.
418
+
419
+ The resident captures each signed-in entry every 15 minutes, with no command.
420
+ An occurrence never overlaps its entry's previous one, and one missed while the
421
+ resident was stopped is not replayed: the next resumes from the checkpoint. The
422
+ first capture fixes the initial choice's boundary, so `new` captures nothing
423
+ that existed then and everything that arrives after.
240
424
 
241
- Each Google instance represents one Google account, and one Kit installation
242
- may declare as many as the User has. Each instance owns its own local Google
243
- authorization, selectors, Source references, Room routes, checkpoints and
244
- health under `state/<instance>/`; the installation's one `kit login` covers
245
- them all, and no instance can read another's provider credential.
246
-
247
- ```json
248
- {
249
- "availability": "intermittent",
250
- "execution_authority": "refuse",
251
- "migrators": [],
252
- "instances": [
253
- {
254
- "id": "google-account",
255
- "preset": "google",
256
- "scopes": ["https://www.googleapis.com/auth/contacts.readonly"],
257
- "services": [
258
- {
259
- "service": "gmail",
260
- "source_ref": "src_google_mail",
261
- "rooms": ["work-room"],
262
- "backfill": { "days": 30 },
263
- "selection": { "labels": ["INBOX"] }
264
- },
265
- {
266
- "service": "calendar",
267
- "source_ref": "src_google_calendar",
268
- "rooms": ["work-room"],
269
- "backfill": { "all": true },
270
- "selection": { "calendars": ["primary"] }
271
- },
272
- {
273
- "service": "drive",
274
- "source_ref": "src_google_drive",
275
- "rooms": ["work-room"],
276
- "backfill": { "count": 500 },
277
- "selection": { "files": ["file-id"], "folders": ["folder-id"] }
278
- }
279
- ]
280
- }
281
- ],
282
- "clients": [],
283
- "host": null
284
- }
425
+ ```sh
426
+ kit source capture work # one occurrence of every entry of the account now
427
+ kit source capture work gmail # one occurrence of one entry now
428
+ kit source status work
285
429
  ```
286
430
 
287
- Google authorization is incremental. Enabling Gmail requests only Gmail's
288
- read-only scope; Calendar and Drive request their own read-only scopes only
289
- when enabled. Each service scope set has its own local provider grant, so a
290
- later authorization never widens or replaces a sibling service's grant.
291
- Additional Google API scopes are declared once on the preset instance and
292
- remain local; a declared service names only scopes that instance already
293
- holds. Drive requires at least one explicit file or folder selection and never
294
- defaults to the whole account.
431
+ `kit source capture` and `kit source status` take the account name where a
432
+ custom connector takes its instance; a name House lists as an account is read
433
+ as the account. While the resident runs, it performs the requested occurrence
434
+ itself, after any occurrence of that entry already running.
295
435
 
296
- A Google API outside the three curated services may use the closed declared
297
- service schema. The declaration is data only: no script or executable transform
298
- is loaded. Its host must be a Google API domain and it runs under scopes the
299
- instance already holds.
300
-
301
- ```json
302
- {
303
- "service": "people",
304
- "source_ref": "src_google_people",
305
- "rooms": ["work-room"],
306
- "backfill": { "all": true },
307
- "declaration": {
308
- "host": "people.googleapis.com",
309
- "path": "/v1/people/me/connections",
310
- "query": { "personFields": "names,emailAddresses,metadata" },
311
- "page_size": "pageSize",
312
- "scopes": ["https://www.googleapis.com/auth/contacts.readonly"],
313
- "page_token": {
314
- "request": "pageToken",
315
- "response": "nextPageToken",
316
- "checkpoint_request": "syncToken",
317
- "checkpoint_response": "nextSyncToken"
318
- },
319
- "items": "connections",
320
- "fields": {
321
- "native_id": "resourceName",
322
- "native_version": "etag",
323
- "provider_modified_at": "metadata.sources.0.updateTime",
324
- "observed_at": "metadata.sources.0.updateTime",
325
- "body": ["names.0.displayName", "emailAddresses.0.value"],
326
- "container": "metadata.sources.0.type"
327
- }
328
- }
329
- }
330
- ```
331
-
332
- A Google instance signs in only through [Environment setup](#environment-setup),
333
- on House's owner-authenticated page, so the owner's browser never has to reach
334
- this Environment. For each enabled service whose scopes the instance does not
335
- hold yet, the page links to Google's consent for exactly that service's scopes.
336
- Google then sends the browser to a `http://127.0.0.1:<port>/` address that
337
- nothing answers: the owner copies that whole address from the address bar and
338
- pastes it into the page. The Kit accepts it only when it carries the state its
339
- own consent issued, exchanges the code with its PKCE verifier and the built
340
- client, and stores the grant locally. An address that answers another consent,
341
- or a code Google refuses to exchange, fails the login and stores nothing; a
342
- declined consent cancels it. Grants already completed for earlier services stay.
343
-
344
- `kit source sign-in <instance>` signs in a custom connector instance through
345
- its own command, described below. It skips an instance whose local
346
- authorization is already valid and answers `ready`, `skipped`, or
347
- `needs_attention`. A Google instance refuses it as `kit_connector_login_guided`
348
- and names House setup.
436
+ A failed occurrence records its cause. A Google 403 for an API disabled in the
437
+ client's project fails as `api_disabled`, and `kit source status` names the API
438
+ to enable; a revoked scope (`google_scope_revoked`), an expired or revoked grant
439
+ (`google_authority_revoked`) and a provider failure
440
+ (`google_provider_unavailable`) keep their own codes.
349
441
 
350
442
  ## Environment setup
351
443
 
@@ -354,11 +446,13 @@ its owner asks it to renew what the Environment holds. The Kit acts on the
354
446
  request it acquires, never on its own:
355
447
 
356
448
  ```sh
357
- kit setup --house https://agents.house
449
+ kit setup
358
450
  ```
359
451
 
360
452
  `kit worker run` performs the same step at the start of a pass, before it
361
- hands out any work, so a managed Environment needs no terminal. The walk first
453
+ hands out any work, so a managed Environment needs no terminal; the resident
454
+ Kit performs it each time its control stream connects and on each `runs`
455
+ signal, which House also sends for every setup request. The walk first
362
456
  prepares the absolute `/agents/house` base, then visits every declared agent
363
457
  CLI and then every connector instance, in configuration order:
364
458
 
@@ -462,15 +556,54 @@ An object whose content changes without its native version changing keeps its
462
556
  key and is refused by House as a delivery-key conflict rather than silently
463
557
  overwriting the earlier Record.
464
558
 
465
- The same command owns its module authorization. `kit source sign-in` and the
466
- setup walk's status check send one JSON line
559
+ The same command owns its module authorization. `kit source sign-in <instance>`
560
+ skips an instance whose local authorization is already valid and answers
561
+ `ready`, `skipped`, or `needs_attention`. It and the setup walk's status check
562
+ send one JSON line
467
563
  with `action: "authorization"` and `mode: "status"` or `mode: "login"`; the
468
564
  command returns exactly one JSON object such as `{ "authorized": true }`.
469
565
 
566
+ ## The Kit control stream
567
+
568
+ The resident Kit holds one `/kit/stream` WebSocket for its Environment,
569
+ authenticated with its Environment control lease and the Kit contract header,
570
+ for as long as it holds that lease; `kit worker run` holds one for the length
571
+ of its pass to receive its owner's commands, and `kit telegram serve` holds one
572
+ while it serves the gateway under a lease of its own. The Kit sends no
573
+ subscribe frame and accepts every frame House sends. What it writes there is
574
+ the live view of the turns it runs, as draft and plan frames the
575
+ [Worker runtime](#the-worker-runtime) describes, and a `gap` frame when the
576
+ [Telegram gateway](#the-telegram-gateway) needs a turn's whole view again.
577
+
578
+ Each time the socket connects, the resident acquires everything a signal could
579
+ have named, because a signal House sent while the socket was down is lost: its
580
+ Runs and resumptions with their setup and conversation files, the owner's
581
+ pending commands, the agent CLI list, the saved working copy choice and its
582
+ Google Sources. After that it acquires only what House names. A
583
+ `work_available` frame for `agents`, `working_copy` or `sources` acquires that
584
+ subject alone. `runs` takes a resumption or else a waiting Run, readying the
585
+ agent CLIs, a requested setup and conversation files first. `commands` hands
586
+ the supervised Session its stops, interrupts and answers and takes a
587
+ resumption the same way, without acquiring a Run. An `entries` frame, a change
588
+ in a Room the lease admits, delivers the working copies. A pass that took a Run
589
+ acquires again once that Run ends, and a pass that found nothing waits for the
590
+ next signal. A Run outcome House did not take is reported again every 30
591
+ seconds until House answers. The Kit has no idle acquisition cycle, no command
592
+ poll and no Session heartbeat: a Session is observed when its process starts
593
+ and when its supervisor sees it stop.
594
+
595
+ A socket that closes or never opens reconnects after a delay drawn between half
596
+ and all of one second, doubled for each consecutive failure up to 30 seconds.
597
+ An `authority_changed` close reconnects after a delay drawn between 0 and 2
598
+ seconds, with no error backoff. A `replaced` close, which means a newer
599
+ connection holds the Environment, ends the resident with `kit_stream_replaced`,
600
+ and an upgrade House refuses with `kit_upgrade_required` stops every House call
601
+ as [above](#connect-a-linux-computer) describes; neither is retried.
602
+
470
603
  ## The Worker runtime
471
604
 
472
605
  ```sh
473
- kit worker run --house https://agents.house
606
+ kit worker run
474
607
  ```
475
608
 
476
609
  Worker-runtime readiness validates the tmux this Kit declares support for,
@@ -538,27 +671,12 @@ inside `/agents/house` is somebody else's default or an owner's own workspace,
538
671
  never this Agent's. Every path that is not this exact equality, one deeper
539
672
  inside `/agents/house` included, must
540
673
  already exist in this Environment as a directory the installation can enter;
541
- Kit never creates or seeds it.
542
-
543
- When the Agent's own default directory is absent, Kit builds the starter set in
544
- a temporary directory beneath the base and renames it into place as one atomic
545
- step, so a partly seeded directory is never visible at the default path. Two
546
- concurrent first launches race that rename; the loser discards its temporary
547
- directory and uses the directory the winner put there, so the pair still leaves
548
- one complete directory and nothing partial. A present default directory -
549
- including one whose starter files the owner edited or removed - launches
550
- exactly as it is, and a deleted default directory is recreated with a fresh
551
- starter set on its next launch.
552
-
553
- The starter set is `AGENTS.md` with the single line ``The agents.house `house`
554
- CLI is available: run `house --help`.``, `CLAUDE.md` as a relative symbolic link to it, `.agents/skills/grilling/`
555
- vendored from [`mattpocock/skills`](https://github.com/mattpocock/skills)
556
- `skills/productivity/grilling` at a pinned commit with its MIT license and a
557
- provenance header naming that commit, and `.claude/skills` as a relative
558
- symbolic link to `.agents/skills`. Once seeded the files belong to the owner:
559
- Kit never syncs, refreshes, or restores them, and refreshing the vendored skill
560
- for new Agents is an ordinary Kit release that never touches an already seeded
561
- directory.
674
+ Kit never creates it.
675
+
676
+ When the Agent's own default directory is absent, Kit creates it empty; two
677
+ concurrent first launches create the same directory. A present default
678
+ directory launches exactly as it is, and a deleted one is created empty again
679
+ on its next launch. Kit writes no file into any working directory.
562
680
 
563
681
  A relative, missing, inaccessible, or non-directory working directory refuses
564
682
  with `kit_launch_directory_unavailable` before any provider process starts. Kit falls back to no other location - not the
@@ -566,6 +684,52 @@ base, not `$HOUSE_KIT_HOME`, and not its own current directory - and neither
566
684
  connecting an installation nor launching a session moves, copies, overwrites,
567
685
  or removes anything a working directory holds.
568
686
 
687
+ ## The Skill set
688
+
689
+ The Skill set is every skill the `mattpocock/skills` plugin manifest names at
690
+ one pinned commit but `setup-matt-pocock-skills`, `triage` and `wizard`. Each
691
+ is vendored under `src/skill-set/<name>/` with every file it ships, the
692
+ upstream MIT `LICENSE` and a provenance header in `SKILL.md` naming the commit
693
+ and upstream path. Nothing else is edited but two lines: a
694
+ `disable-model-invocation: true` frontmatter line in `SKILL.md` and an
695
+ `allow_implicit_invocation: false` line in `agents/openai.yaml` are removed, so
696
+ an agent reaches every skill without being told its name.
697
+
698
+ Kit installs the Skill set once for the Environment, for every Agent whatever
699
+ its working directory, under the home it launches agent CLIs with: each skill
700
+ as the directory `$HOME/.agents/skills/<name>`, which Codex and Grok Build
701
+ read, and a relative symbolic link `$HOME/.claude/skills/<name>` to it, which
702
+ Claude Code reads; when `$HOME/.claude/skills` already resolves to
703
+ `$HOME/.agents/skills`, Claude Code reads the directory there and Kit makes no
704
+ link. In a container that home is Kit home, so the set survives
705
+ container recreation; on a native host it is the host user's home.
706
+
707
+ `$HOUSE_KIT_HOME/state/skill-set.json` records the names Kit installed and the
708
+ Kit version that installed them, and Kit owns exactly those names: the
709
+ directory and the link of each. At start and on every resident pass, when
710
+ the set is accepted and the record names another version or none, Kit deletes
711
+ every recorded name, installs the current Skill set and rewrites the record. A
712
+ name whose directory or link exists without being recorded is the owner's: Kit
713
+ leaves it untouched and installs nothing under it. Kit never compares, merges
714
+ or restores a file, so an edit to an installed skill is lost at the next
715
+ release and a copy under another name is kept. When `skills` is `false`, Kit
716
+ deletes every recorded name and the record and installs nothing.
717
+
718
+ After Kit first installs the Skill set, the first Session it launches whose
719
+ Profile ceiling lets it write the owner's How-we-work document
720
+ `/private/library/how-we-work.md` creates it, when it is absent, with the text
721
+ Kit ships in `src/how-we-work.md`, over the Session's own bridge before its
722
+ first prompt is built. Kit then notes in `$HOUSE_KIT_HOME/state/how-we-work`,
723
+ apart from the record, that the document exists, and a present document is
724
+ noted the same way without being touched. Nothing ever creates it again: a
725
+ release, a declined Skill set and a later acceptance leave the note, so an
726
+ owner's edit stands and a deleted document stays deleted. A Session whose
727
+ ceiling cannot write the document launches without it and leaves it for the
728
+ next one; any other refused creation refuses the attempt as
729
+ `kit_how_we_work_unwritable` with House's answer before a prompt is sent. A
730
+ Skill set Kit cannot install or remove refuses the pass as
731
+ `kit_skill_set_unavailable` and names the path.
732
+
569
733
  ## The declared agent CLIs
570
734
 
571
735
  The Environment owner installs no adapter binary by hand. `kit agents update`
@@ -575,6 +739,17 @@ minimum's major - under
575
739
  `$HOUSE_KIT_HOME/agents/<kind>/releases/<release>/`, never touching what the
576
740
  owner installed globally, and an acquired route's command is that installed
577
741
  executable rather than a path anyone writes into `kit.json`.
742
+ The resident Kit also listens for an `agents` availability pointer on its
743
+ control stream. It reads the whole wanted list from House over HTTPS, removes
744
+ Kit-owned CLI directories that are no longer wanted, installs newly wanted
745
+ kinds, and reports its held state immediately, including while another Agent
746
+ run remains active. A newly wanted kind that needs provider authorization uses
747
+ the existing guided House login ceremony; Kit reports readiness again when it
748
+ ends. A reconnect reads the list again, so a pointer missed during a stream
749
+ outage changes no authority.
750
+ Removal waits for an active worker pass or any unresolved live WorkerSession
751
+ binding to stop using a CLI directory; the Kit keeps reporting that kind until
752
+ it removes the directory.
578
753
 
579
754
  Every candidate release is proved before it serves: the Kit installs it beside
580
755
  the current release, runs the contract's own conformance check - the protocol's
@@ -669,11 +844,24 @@ prompt's stop reason through the contract's own table to one of four turn
669
844
  outcomes: completed, interrupted, refused by the provider, or exhausted. A stop
670
845
  reason the contract does not name, including a vendor-specific one a different
671
846
  contract names, fails the turn as `kit_adapter_contract_mismatch` rather than
672
- being guessed. It sends the request
673
- as the first prompt block, followed by current House guidance fetched through
674
- the Run connection. Missing or unreadable guidance refuses the turn; the
675
- launcher does not copy the private Routine instruction into the acquisition
676
- request. It forwards only adapter-classified User-visible assistant
847
+ being guessed. After committing the Run, and again on every resumption, the
848
+ Kit reads what the Session was started for from House's
849
+ `/kit/runs/<run>/request` with the Session credential: the Routine Request with
850
+ its input, references, requester and the pinned revision's instruction, or the
851
+ sealed conversation turn. It sends that as the first prompt block, followed by
852
+ current House guidance fetched through the Run connection, so the Agent calls
853
+ nothing to learn it. An unreadable request or guidance refuses the turn.
854
+ A session opened with `session/new` gets one more text block ahead of those,
855
+ the same for every adapter kind: the line
856
+ `The agents.house house CLI is available: run house --help.`, the base
857
+ instructions of the Execution attempt plan House acquired, and the current text
858
+ of the owner's How-we-work document `/private/library/how-we-work.md`, which the
859
+ launcher reads with the `shell` tool over the Session's own bridge, following
860
+ House's cursor to the whole text. An absent document, one the Session's ceiling
861
+ cannot read, and empty base instructions add nothing. Any other failed read
862
+ refuses the attempt as `kit_how_we_work_unreadable` with the bridge's cause
863
+ before a prompt is sent. A session reloaded with `session/load` already holds
864
+ the block and gets none. It forwards only adapter-classified User-visible assistant
677
865
  text back over the local channel, and leaves reasoning, tool traces, and
678
866
  terminal output where they are. The supervised process's own House calls travel
679
867
  that same channel through the `house` CLI. The Kit holds the WorkerRunToken, replaces it in place when
@@ -686,37 +874,55 @@ what it has seen so far, and seals the turn itself. No Agent is asked to report
686
874
  text a deterministic observer already sees, and no agent-facing tool admits final
687
875
  text.
688
876
 
689
- While the adapter generates, the Kit posts the whole User-visible assistant text
690
- of the turn so far to `sessions/<session>/drafts` as an ephemeral draft. Only
877
+ While the adapter generates, the supervisor writes the whole User-visible
878
+ assistant text of the turn so far as `draft` frames on the Environment's
879
+ [control stream](#the-kit-control-stream); it calls no draft route. Only
691
880
  adapter-classified assistant message text enters that stream; reasoning, tool
692
- calls, plans, and terminal output never do. The Kit maps the structure it can
693
- read in that text - paragraphs, headings, fenced code, ordered and unordered
694
- lists, pipe tables, and `$$` formulas - into House's admitted blocks, and leaves
695
- anything it did not parse as the paragraph it observed. It invents no structure
696
- and renders nothing.
697
-
698
- The Kit coalesces and paces that stream rather than mirroring every chunk. It
699
- sends the first observed view at once, then at most one view every 500
700
- milliseconds, and one more the moment the adapter completes a message; one call
701
- is in flight at a time, so a newer view replaces the view it overtook and the
702
- view observed last is the view House sees last. A view whose text exceeds
703
- House's 4096-byte bound is not sent. A draft persists nowhere - not in this
704
- Kit's local state, not as House history - is never retried, and can neither
705
- delay nor prove turn completion: a refused, lost, or overtaken draft changes no
706
- Run, WorkerSession, or delivery state. Ending the stream waits for no draft the
707
- transport is still holding, so a slow or unanswered draft call cannot delay the
708
- seal or the Run behind it.
881
+ calls, and terminal output never do. The Kit maps the structure it can read in
882
+ that text - paragraphs, headings, fenced code, ordered and unordered lists, pipe
883
+ tables, and `$$` formulas - into House's blocks, and leaves anything it did not
884
+ parse as the paragraph it observed. It invents no structure, renders nothing,
885
+ and holds back or refuses no draft for its length: a frame carries every block
886
+ of the text however long it is.
887
+
888
+ A frame names the turn it belongs to, as House answered the Session's `started`
889
+ observation with the turn's `conversation_id` and `turn_id`, together with the
890
+ Execution attempt as `attempt_id`. It carries a `sequence` that grows by one
891
+ with each paced view of the turn, and replaces the turn's view from the block
892
+ index `from` onward with the `blocks` it carries, so a frame for text that only
893
+ grew carries the blocks from the first one that changed, and a view that
894
+ changed no block is a frame that replaces nothing. The launcher numbers the
895
+ views, so a Kit that restarts mid-turn continues the turn's sequence. The Kit
896
+ coalesces and paces that stream rather than mirroring every chunk: it writes
897
+ the first observed view at once and then at most one view in each
898
+ 500-millisecond pacing window, the latest one, even when the adapter completes
899
+ a message inside a window. A frame written while the socket is down is lost,
900
+ so the first frame after each reconnect, and after any frame the socket could not carry, replaces the view
901
+ from block 0. A Session House names no conversation turn for gets no frames. A
902
+ draft persists nowhere - not in this Kit's local state, not as House history -
903
+ is never retried, and can neither delay nor prove turn completion.
904
+
905
+ A `plan` session update is one snapshot of the agent's steps. The Kit writes
906
+ each snapshot as a `plan` frame paced by the same rule, carrying every step's
907
+ `label`, `priority` and `status` exactly as the adapter gave them, its own
908
+ `sequence`, and the step index `from` it replaces the plan onward. The act that
909
+ ends the turn carries the last snapshot the Kit saw as its final `plan`: the
910
+ seal, the observed stop, the Run outcome and an `interrupted` interrupt outcome
911
+ each name the provider turn and every step's `label` and `status`, however many
912
+ steps and however long their text, and a turn that never planned carries none.
913
+ There is no per-snapshot plan route.
709
914
 
710
915
  When the adapter completes the turn, the Kit seals it with one
711
- `sessions/<session>/assistant-messages` call carrying the same blocks and a
712
- UUIDv7 `operation_id`. The exact request - that identity and those blocks - is
713
- written into the WorkerSession binding before the call leaves, so a recovered
714
- call returns the outcome House recorded and never seals a turn twice, and
715
- House's answer names the turn it closed and the delivery it queued. An answer
716
- the Kit never received leaves the Run unsettled with the request retained: the
717
- next `kit worker run` replays exactly that operation and those blocks before
718
- settling anything, rather than reporting a failure it cannot prove. A refusal
719
- House did decide is the Run's reported failure.
916
+ `sessions/<session>/assistant-messages` call carrying the same blocks, the final
917
+ plan, and a UUIDv7 `operation_id`. The exact request - that identity, those
918
+ blocks and that plan - is written into the WorkerSession binding before the
919
+ call leaves, so a recovered call returns the outcome House recorded and never
920
+ seals a turn twice, and House's answer names the turn it closed and the
921
+ delivery it queued. An answer the Kit never received leaves the Run unsettled
922
+ with the request retained: the next `kit worker run` replays exactly that
923
+ operation, those blocks and that plan before settling anything, rather than
924
+ reporting a failure it cannot prove. A refusal House did decide is the Run's
925
+ reported failure.
720
926
 
721
927
  That seal is the one durable record of the turn, and only a seal House accepted
722
928
  completes a turn: the Kit reports whole-turn completion to House after the seal
@@ -736,7 +942,9 @@ nonzero exit status. The CLI holds
736
942
  no credential: it calls over its Session's bridge, which attaches the Session
737
943
  credential and refuses a caller without that Session's nonce as
738
944
  `kit_bridge_unauthorized`. House network calls use only the selected
739
- `2026-07-28` profile.
945
+ `2026-07-28` profile. `house git push` is the one local verb House does not list;
946
+ [working copies](#working-copies) describe it, and `house --help` and
947
+ `house git push --help` explain it.
740
948
 
741
949
  Two verbs name files on the Session's own computer: `upload_attachment` takes
742
950
  one `path`, and `append_record` takes `attachments` as local paths. The CLI
@@ -819,8 +1027,8 @@ receiving a complete byte stream, validating any reported size, and writing the
819
1027
  file. A lost acknowledgement preserves the completed local file for House's
820
1028
  idempotent admission and later cleanup. Failed files remain pending; House's
821
1029
  all-files-ready gate keeps their turn unprocessed.
822
- The provider receives absolute local paths beside the owning messages, both in
823
- its initial prompt and in `session_get_request`. The cache persists across
1030
+ The provider receives absolute local paths beside the owning messages in its
1031
+ first prompt. The cache persists across
824
1032
  turns; only House-authorized terminal Run cleanup removes its Run directory.
825
1033
 
826
1034
  The accepted attachment's retained original is separate from that cache. The Kit
@@ -833,8 +1041,9 @@ A save that fails leaves one note in `state/conversation-originals/` naming the
833
1041
  attachment, its Run, the local file and the descriptor it declared. Each
834
1042
  later `kit worker run` retries it from that file without materializing or
835
1043
  acknowledging anything again, and reports `source_unavailable` when
836
- the file is gone or changed rather than saving different bytes. While a
837
- WorkerSession stays supervised the same retry runs at the heartbeat interval. The note leaves once
1044
+ the file is gone or changed rather than saving different bytes. When a
1045
+ supervised WorkerSession ends, the same retry runs once more before its Run is
1046
+ reported. The note leaves once
838
1047
  House records the save, once House answers that the Run is over, or when House
839
1048
  authorizes that Run's cache cleanup; House accepts no save for a Run that has
840
1049
  settled, so an unsaved original keeps its failed outcome from then on. The owner
@@ -845,8 +1054,8 @@ outcome it handled, and exits non-zero while any of them is unsaved.
845
1054
  One `kit worker run` then takes one House-authorized resumption, or otherwise
846
1055
  acquires one waiting Run, and supervises exactly that WorkerSession. A resumed
847
1056
  conversation loads its retained native provider session through ACP
848
- `session/load`, receives the current input from House through
849
- `session_get_request`, and executes one turn. Historical output replayed during
1057
+ `session/load`, receives the current input House answers for the Run in its
1058
+ first prompt, and executes one turn. Historical output replayed during
850
1059
  loading is not emitted as new assistant output. Missing or rejected provider
851
1060
  continuation never starts a replacement provider conversation in the same Run.
852
1061
 
@@ -913,7 +1122,12 @@ content, no prompt, and no resolved secret, and Session authority is always
913
1122
  reissued by House rather than recovered from disk. It is evidence for
914
1123
  reconciliation, never permission to resume or recreate work, and nothing keeps
915
1124
  it once House has answered for the Run: a settled terminal state, a confirmed
916
- owner stop, and a retained Provider continuation each drop it.
1125
+ owner stop, and a retained Provider continuation each drop it. When the
1126
+ supervised process ends, the binding first records what the Kit observed: the
1127
+ sealed final text, whether the turn completed, the capacity or provider refusal,
1128
+ the execution failure and whether a Provider continuation is retained. The Kit
1129
+ then reports that stop, and a restarted Kit reports the same recorded stop
1130
+ instead of treating the session as lost.
917
1131
 
918
1132
  A restarted `kit worker run` reconciles the records it kept before it acquires
919
1133
  anything new. It reports every retained settlement note first, because those
@@ -937,7 +1151,7 @@ A restore of House's database starts a new log epoch. Until this Environment
937
1151
  has reported in it, House refuses every act that touches a Run, acquisition and
938
1152
  lease release included, as `epoch_report_required` naming the epoch. The first
939
1153
  such refusal ends whatever the pass was doing. One raised inside a supervised
940
- Run's bridge, while it admits or settles a question, streams a draft, or
1154
+ Run's bridge, while it admits or settles a question, reports an interrupt, or
941
1155
  replaces Session authority for a forwarded call, never becomes an answer to the
942
1156
  Agent: it ends the bridge and the pass at once. The Kit then reports, under the
943
1157
  lease it holds and at `POST /kit/sessions/report`, every Run it holds a spawn
@@ -965,7 +1179,10 @@ written into the durable binding. Reconciliation must obtain current House
965
1179
  authority before the live process can make further calls.
966
1180
 
967
1181
  An owner stop requested through House reaches this Kit as a durable command,
968
- both at startup and while a Session is supervised. The Kit destroys the exact
1182
+ both at startup and while a Session is supervised: House signals `commands` on
1183
+ the Kit control stream and the supervisor acquires the pending stops,
1184
+ interrupts and answers at once, so a stop reaches the process within a second.
1185
+ The Kit destroys the exact
969
1186
  tmux session, confirms that it is gone, and reports the stopped Session. It
970
1187
  reports no continuation for a Run stopped by its owner and never reopens the
971
1188
  local channel for that Session.
@@ -1004,8 +1221,8 @@ into the evidence each spec writes under `tmp/delivery-evidence/`.
1004
1221
  ## Capturing
1005
1222
 
1006
1223
  ```sh
1007
- kit source capture acme --house https://agents.house # every declared service
1008
- kit source capture acme notes --house https://agents.house # one service
1224
+ kit source capture acme # every declared service
1225
+ kit source capture acme notes # one service
1009
1226
  ```
1010
1227
 
1011
1228
  Each run reads the checkpoint, acquires one bounded page, submits one batch,
@@ -1019,8 +1236,8 @@ on the door's own deduplication. When House stops a batch early, its answer
1019
1236
  settles only the prefix it reached, and the unsettled tail is reoffered with the
1020
1237
  rest. The loop repeats while the connector still returns items and no Room
1021
1238
  destination is blocked, and every run ends by writing the service's health into
1022
- this installation's own state. House holds no preset, service, route, checkpoint
1023
- or health of yours.
1239
+ this installation's own state. House holds no custom connector's service, route,
1240
+ checkpoint or health, and no Google entry's checkpoint or health.
1024
1241
 
1025
1242
  A Capture item that declares a `file` attachment answers one Record per Room
1026
1243
  destination: Rooms of one owner share that owner's Record, and a Room of another
@@ -1038,8 +1255,8 @@ Room and Record and exits non-zero while any stays unsaved; acquisition health
1038
1255
  stays about acquisition, so a failed save never changes it.
1039
1256
 
1040
1257
  ```sh
1041
- kit source retry-files acme --house https://agents.house # every declared service
1042
- kit source retry-files acme notes --house https://agents.house # one service
1258
+ kit source retry-files acme # every declared service
1259
+ kit source retry-files acme notes # one service
1043
1260
  ```
1044
1261
 
1045
1262
  `retry-files` saves only the references still outstanding. It runs no connector,
@@ -1062,10 +1279,27 @@ retained references still waiting to be saved.
1062
1279
  Every command that changes or reads installation state takes this
1063
1280
  installation's exclusive Environment control lease for the length of its run
1064
1281
  and renews it before it expires, so two Kit commands never work against the
1065
- same installation at once. A command that ends, or is interrupted once its work
1066
- has stopped, releases that exact lease so the next command acquires at once; a
1067
- refused command leaves it to expire. A `kit login` credential is presented only to take
1068
- that lease.
1282
+ same installation at once. A command that ends, is refused, or is interrupted
1283
+ once its work has stopped releases that exact lease so the next command acquires
1284
+ at once. A `kit login` credential is presented only to take that lease.
1285
+
1286
+ While `kit resident` holds that lease, a command runs through it instead: the
1287
+ command presents no credential, the resident confirms its current lease with
1288
+ House and sends the command's House requests under it, an interrupted command
1289
+ cancels its request there, and the lease stays held when the command ends. The
1290
+ resident serves one such command at a time and refuses another with
1291
+ `environment_control_lease_active`, so two commands still never work at once.
1292
+ A resident whose lease House refuses answers the command with that refusal; the
1293
+ command never acquires a lease of its own while a resident serves it. While an
1294
+ update drains, `state/update-drain` refuses every such command, `kit login` and
1295
+ `kit worker run` with `kit_update_draining` before it enrolls, acquires or
1296
+ delegates anything. A command already served keeps the resident's lease until
1297
+ it ends, while the resident refuses its acquisition of new work and its
1298
+ Telegram updates with `kit_update_draining`, which ends a served
1299
+ `kit telegram serve` once each of its activities reports the deliveries and
1300
+ files it already acquired; until it ends, the drain answers that it waits for
1301
+ that command and the bootstrap leaves the container as it is. The bootstrap
1302
+ removes the file when it replaces the container.
1069
1303
 
1070
1304
  Interrupting the command cancels the running connector without advancing the
1071
1305
  checkpoint.
@@ -1078,8 +1312,7 @@ Git credential:
1078
1312
  ```sh
1079
1313
  kit repository capture /srv/acme \
1080
1314
  --room work-room \
1081
- --source-handle acme-repository \
1082
- --house https://agents.house
1315
+ --source-handle acme-repository
1083
1316
  ```
1084
1317
 
1085
1318
  The command runs ordinary `git pull` in the checkout with the local User's Git
@@ -1104,25 +1337,186 @@ interrupted run is never resumed: the next run opens a new manifest and House
1104
1337
  answers with what is still needed. The command reports the Publication
1105
1338
  reference, the paths delivered, the items refused and the ending.
1106
1339
 
1340
+ ## Working copies
1341
+
1342
+ The Environment owner chooses in House which Rooms this Environment keeps
1343
+ locally, and whether it keeps `/private`. An Environment whose owner never chose
1344
+ copies nothing, and a Room joined later stays uncopied until the owner selects
1345
+ it. The resident Kit reads the saved choice through
1346
+ `POST /kit/working-copy/selection` whenever its control stream connects or
1347
+ reconnects and whenever House points it there after a save;
1348
+ `kit worker run` reads it once before its pass.
1349
+
1350
+ Each selected Room becomes one ordinary Git repository at
1351
+ `/agents/house/working-copies/rooms/<room_ref>`, and `/private` one at
1352
+ `/agents/house/working-copies/private`. The Room reference names the location,
1353
+ so a Room handle change moves nothing. Every Agent launched afterwards receives
1354
+ the House path and local repository of each active copy in its context, one
1355
+ line each, such as `/rooms/work: /agents/house/working-copies/rooms/r_1x.q`.
1356
+
1357
+ A Room repository holds the Room's complete readable content: `ROOM.md`,
1358
+ `library/`, `capture/` with its provenance sidecars, and `collaboration/`. The
1359
+ `/private` repository holds its Library, collaboration, each Room's private
1360
+ `AGENTS.md`, the `agents/` cards and `house/`. Attached settings and attachment
1361
+ bytes are not copied. The branch `main` starts at the commit House served, which
1362
+ tracks exactly the files House declares writable under the Environment's
1363
+ current grant. Every other file is read-only House content: the generated
1364
+ `.gitignore` names and explains it, so Git never tracks it, and the matching
1365
+ `.ignore` keeps it visible to ripgrep and other native search. Neither file
1366
+ grants anything, and House refuses a change to a read-only path however it is
1367
+ committed.
1368
+
1369
+ Local edits, staging and commits change nothing in House until a commit is
1370
+ pushed. `refs/house/received` records the House content last received; each
1371
+ commit Kit wrote there, and each commit it acknowledged for a push, is a House
1372
+ state. The House revision of every file content Kit received, keyed by path,
1373
+ Git blob and the House state that received it, stays in Kit home under
1374
+ `state/working-copies/`, outside the repository. A local commit is a local tree, never a House revision.
1375
+
1376
+ The resident Kit keeps every active copy current. Whenever its control stream
1377
+ carries a Room change, and whenever it reads the saved choice, one
1378
+ `POST /kit/door/discover` tells it where each
1379
+ copied Room stands, and for a Room that moved on it reads the changes after the
1380
+ copy's recorded position through `POST /kit/door/enumerate`. A changed, new or
1381
+ removed authored file becomes a commit on `refs/house/received`, its House
1382
+ revision kept in Kit home; changed, new or removed read-only content, such as
1383
+ Capture with its provenance sidecar or a House projection, is written into or
1384
+ removed from the ignored local tree, with each directory a removal leaves empty,
1385
+ and `.gitignore` and `.ignore` follow it.
1386
+ Delivery never touches the branch, the index or a tracked file, and a push
1387
+ waiting for its outcome or its local integration keeps its record. A push takes
1388
+ each file's revision from the newest House state in its own base's history that
1389
+ received that content, so a local commit keeps the base it was made on even when
1390
+ House returns to the same text under a newer revision. A file new to the copy is tracked when a write scope
1391
+ House declares for the Room covers it more closely than a declared protected
1392
+ path, and a local file already sitting where new read-only content arrives
1393
+ stays yours: Kit neither overwrites nor later removes it. When the write scopes
1394
+ or protected paths House declares for the Room change, Kit reads the Room again
1395
+ as a reselection does. A position older than House
1396
+ retains, or from before House's database was restored, makes Kit read the Room
1397
+ again as a reselection does; while House's replica has not reached the position
1398
+ the copy waits, and the resident delivers again 30 seconds later. A Room House
1399
+ no longer answers under its
1400
+ recorded handle makes Kit read the saved choice again, which follows a handle
1401
+ change or marks the copy inactive, and a Room that lost sync is named on
1402
+ standard error as `operation_denied` and keeps what it holds. `kit worker run`
1403
+ delivers once, after reading the saved choice.
1404
+
1405
+ `house git push [commit]`, run anywhere inside a copy or one of its linked
1406
+ worktrees, submits one commit, `HEAD` by default, resolved once. Kit compares
1407
+ that commit's tree with the newest House state in its history, so every linked
1408
+ worktree keeps its own base, and sends the difference as one ordinary House edit:
1409
+ a changed field, section or preamble against its own prior value, any other
1410
+ change as the whole file against its exact revision, a new file as a create and
1411
+ a committed deletion as a removal. Staged and unstaged work, and files absent
1412
+ only from the working tree, are never sent. Native `git push` reaches no House
1413
+ remote. Inside an Agent Session the push goes through that Session's bridge,
1414
+ under its own authority and provenance; outside one it needs
1415
+ `house git push [commit] --owner`, which the resident Kit carries out under its
1416
+ control lease when a resident runs, and which otherwise acquires and releases
1417
+ its own. A Session refuses `--owner`, and a missing bridge is never replaced by
1418
+ owner authority.
1419
+
1420
+ A Session's edit too large for one MCP request of 4 MiB goes through House's
1421
+ `prepare_edit_upload` Command on that Session's bridge, naming every changed
1422
+ path, the byte count and the SHA-256 of the bytes to upload under the push's
1423
+ operation. Those bytes are the serialized changes, padded with trailing spaces
1424
+ to one byte over 4 MiB when only the request around them passed the bound,
1425
+ because House takes no smaller upload. Kit sends them to the upload address
1426
+ House returns and then calls `edit` with the paths and the returned upload
1427
+ instead of the changes, so House applies them as the same one edit. The upload
1428
+ is recorded in Kit home before the edit is sent, so a push whose answer was lost
1429
+ resends that same edit; when House no longer holds the uploaded bytes and has
1430
+ not applied the edit, the push uploads them again once under the same operation.
1431
+ A change set beyond House's batch bounds is refused whole and never split.
1432
+
1433
+ Inside an Agent Session `git` is Kit's shim in front of the installed Git, and
1434
+ every command runs exactly as that Git runs it. In a copy or one of its linked
1435
+ worktrees the shim compares that worktree's index before and after each
1436
+ command. When `git mv` succeeds, Git's own dry run of the same command names
1437
+ which path went where, and the shim hands each move to the resident Kit, which
1438
+ keeps every moved document's successive paths in Kit home. A staged move
1439
+ belongs to its worktree's index: a command there that takes its path out of the
1440
+ index or brings it in anew, such as `git reset`, `git restore --staged`,
1441
+ `git rm`, `git stash` or `git switch`, takes it back, and so does removing the
1442
+ worktree. A `git commit` whose commit carries the move ties it to that commit.
1443
+ A tied move counts for every pushed commit whose history holds one of its
1444
+ commits, whatever the index does meanwhile. `git commit --amend` and
1445
+ `git rebase`, Kit's own rebase onto House's result included, also tie it to
1446
+ their result when the rewritten branch still carries it, so aborting the rebase
1447
+ or resetting back to the original commit keeps it as well. A `git reset` that
1448
+ leaves every commit of the move behind without touching its latest path in the
1449
+ index returns it to that worktree's index, where the next commit ties it again.
1450
+ Any other rewrite, such as a cherry-pick, leaves the move tied to its earlier
1451
+ commits. A push sends House's rename of the same document from the path its
1452
+ House base holds to the latest of its counted paths the pushed commit holds,
1453
+ when the commit no longer has the first and the base did not have the second;
1454
+ a moved file whose content also changed follows as a
1455
+ whole-file replacement at its destination. House keeps the document's identity
1456
+ and rewrites the links and references that name it; Kit reads those rewrites
1457
+ through `POST /kit/door/enumerate` and records them in the acknowledgment.
1458
+ Anything else records no move and the push sends an ordinary removal and
1459
+ creation, which House refuses while another document still refers to the
1460
+ removed one: a failed `git mv`, one undone or never committed through the
1461
+ shim, and a move made with Git outside the shim such as in the owner's own
1462
+ shell. An accepted push drops the moves its commit's history holds.
1463
+
1464
+ House decides before any local Git step. A refusal changes nothing in House;
1465
+ after `edit_conflict` Kit records the current content House names for the
1466
+ refused paths in `refs/house/received`, reading by revision any content the
1467
+ refusal does not carry, so the agent merges or rebases onto it with native Git,
1468
+ commits, and pushes again. After acceptance Kit records House's result for the
1469
+ pushed paths, the contents an owner push receives or each accepted revision
1470
+ read by name, in a commit that covers the pushed one and in
1471
+ `refs/house/received`; a read-only path House regenerates, such as the Wiki
1472
+ index, stays out of Git. The copy's recorded position goes back to where it
1473
+ stood when the push was sent, so the next delivery brings again anything House
1474
+ changed after the push's result, including what delivery received while the
1475
+ push awaited its answer. Kit then
1476
+ fast-forwards a clean branch still at the pushed commit, or rebases only its
1477
+ later commits. A result not yet readable, uncommitted tracked changes,
1478
+ a moved branch or a rebase conflict leave the branch as it was, with no stash or
1479
+ reset, and the push answers that House accepted it while local integration is
1480
+ pending; the next `house git push` finishes that integration without another
1481
+ House edit. A push whose answer was lost is recorded in Kit home before it is
1482
+ sent, and the next push by the same Session, or by the owner for an owner push,
1483
+ resends it under its original operation. Another caller cannot
1484
+ recover it: while the pushing Session lives it is refused as
1485
+ `kit_working_copy_push_pending`, and once that Session has ended Kit reads House
1486
+ again and drops it. When a retained push's operation has expired, Kit reads the
1487
+ Room again: if House holds the pushed content the push finishes as accepted,
1488
+ otherwise it is dropped and the next push submits it as a new operation.
1489
+
1490
+ Deselecting a Room, or losing read access to it, marks its copy inactive:
1491
+ launches omit it, delivery stops, a new push is refused as
1492
+ `kit_working_copy_inactive`, and nothing local is deleted; a push already sent still settles and integrates. Selecting it again reads the Room
1493
+ again, advances `refs/house/received`, and replaces only the read-only content
1494
+ Kit wrote, never the branch, the index or a tracked file. A Room the owner may
1495
+ read without sync is refused as `operation_denied` and stays uncopied, while its
1496
+ ordinary remote reads are unaffected. Kit names each refused copy on its
1497
+ standard error.
1498
+
1107
1499
  ## Explicit synchronization
1108
1500
 
1109
- Beside the reconciling Working Copy, Kit has one explicit synchronization mode.
1501
+ Beside [working copies](#working-copies), Kit has one explicit synchronization mode.
1110
1502
  It selects prefixes over the User root, materializes them into a named local
1111
1503
  directory, enumerates whole content and removals after the recorded positions,
1112
1504
  and submits a resolved exact-base change set the caller prepared. Kit does no
1113
1505
  local reconciliation. The mode shares no Working Copy manifest, never infers a
1114
- removal from a locally absent file, and writes authored mutations only for the
1115
- two Libraries and `ROOM.md`.
1506
+ removal from a locally absent file, and writes authored mutations only within
1507
+ House's declared write scopes: a selected Room's Library and, where granted,
1508
+ `ROOM.md`. `/private` selects the Private Room by its Room reference, records an independent Room
1509
+ position, and keeps its `agents/` cards and Room-specific private `AGENTS.md`
1510
+ beside `library/**`.
1116
1511
 
1117
1512
  ```sh
1118
1513
  kit sync bootstrap ./replica \
1119
- --house https://agents.house \
1120
1514
  --prefix /rooms/work/library \
1121
1515
  --prefix /rooms/work/capture \
1122
1516
  --prefix /private/library
1123
- kit sync pull ./replica --house https://agents.house
1124
- kit sync submit ./replica --house https://agents.house --changes ./changes.json
1125
- kit sync rebootstrap ./replica --house https://agents.house
1517
+ kit sync pull ./replica
1518
+ kit sync submit ./replica --changes ./changes.json
1519
+ kit sync rebootstrap ./replica
1126
1520
  ```
1127
1521
 
1128
1522
  `bootstrap` writes `ROOM.md`, Library text, House-derived projections, and
@@ -1135,10 +1529,12 @@ a Room the User can only read answers `bootstrap`, `pull`, and `rebootstrap`
1135
1529
  with `operation_denied`. Generated `_provenance` files delivered beside authored
1136
1530
  Library paths are House metadata, not authored Library documents. `pull` presents
1137
1531
  each recorded position with its log epoch, applies each enumerated path's whole
1138
- content or removal, and advances those positions. A position older than House's
1532
+ content or removal, and advances those positions. A removal, pulled or accepted
1533
+ from `submit`, also removes each directory it leaves empty up to the authority,
1534
+ so a later file can take that path; a directory still holding a file, such as a
1535
+ local draft, stays. A position older than House's
1139
1536
  declared retention, or one of a log epoch before House's database was restored,
1140
- is reported as `position_expired` with rematerialization as the remedy; only
1141
- `rebootstrap` rebuilds the directory.
1537
+ is reported as `position_expired`; only `rebootstrap` rebuilds the directory.
1142
1538
 
1143
1539
  `submit` sends field, section, and preamble operations with that value's prior
1144
1540
  content as base, and whole-file, rename, and removal operations with the file
@@ -1179,23 +1575,20 @@ for a batch that reaches it.
1179
1575
 
1180
1576
  ## Attachments
1181
1577
 
1182
- Upload one local file as an attachment to a Room or to your private tree. Name
1578
+ Upload one local file as an attachment to a Room or to your Private Room. Name
1183
1579
  the place explicitly. Kit sends the descriptor and the selected bytes; it does
1184
1580
  not scan a directory, convert a URL, or attach sibling files, credentials, or
1185
1581
  absolute paths.
1186
1582
 
1187
1583
  ```sh
1188
1584
  kit attachment upload ./notes.bin \
1189
- --house https://agents.house \
1190
1585
  --room room:work \
1191
1586
  --media-type application/pdf
1192
1587
 
1193
1588
  kit attachment upload ./notes.bin \
1194
- --house https://agents.house \
1195
1589
  --private
1196
1590
 
1197
1591
  kit attachment get \
1198
- --house https://agents.house \
1199
1592
  --attachment at_1x.q \
1200
1593
  --room room:work \
1201
1594
  --output ./notes.bin
@@ -1241,7 +1634,7 @@ Any missing prerequisite refuses the create before House ever presents the
1241
1634
  workspace as constrained, naming the exact missing piece.
1242
1635
 
1243
1636
  ```sh
1244
- kit workspace host --house https://agents.house
1637
+ kit workspace host
1245
1638
  ```
1246
1639
 
1247
1640
  The command acquires this host's workspace work under its Environment control
@@ -1273,6 +1666,13 @@ House authorizes: a managed workspace House no longer authorizes to run is
1273
1666
  stopped, and a container this Kit did not create is never adopted, started or
1274
1667
  removed.
1275
1668
 
1669
+ A pass House does not answer, such as one during a House restart, ends that
1670
+ pass only, and the host tries again on the next one; a pass House refuses ends
1671
+ the host. Without `--passes` the host serves until SIGINT or SIGTERM. It
1672
+ asks House to release its control lease when it ends, after its passes, a
1673
+ refusal, SIGINT or SIGTERM; once House has released it, a restarted host is
1674
+ admitted at once.
1675
+
1276
1676
  Ceilings are shared ceilings. The ceilings configured across one host may exceed
1277
1677
  that host, nothing is reserved for any workspace, and no workspace is promised
1278
1678
  its maximum while another one runs.
@@ -1296,7 +1696,7 @@ image from the original the Session stored.
1296
1696
  Bind the bot to this Environment:
1297
1697
 
1298
1698
  ```sh
1299
- kit telegram connect --house https://agents.house
1699
+ kit telegram connect
1300
1700
  ```
1301
1701
 
1302
1702
  The command asks for the token on a hidden terminal prompt, or reads one line
@@ -1315,12 +1715,12 @@ proven owner's Telegram user id.
1315
1715
  Run the gateway:
1316
1716
 
1317
1717
  ```sh
1318
- kit telegram serve --house https://agents.house
1718
+ kit telegram serve
1319
1719
  ```
1320
1720
 
1321
1721
  The command holds one Environment control lease for the whole run and performs
1322
1722
  three activities inside it, each paced on its own so none of them blocks
1323
- another:
1723
+ another, beside the live drafts described below:
1324
1724
 
1325
1725
  - **ingress** reads updates from the stored offset, normalizes each one into the
1326
1726
  update House accepts, submits it, and advances the stored offset only after
@@ -1341,15 +1741,39 @@ another:
1341
1741
  original, and reported the same way; a pull that fails reports
1342
1742
  `transfer_failed` and an ambiguous upload answer reports `delivery_unknown`.
1343
1743
  Only an image ever becomes a file item, because House offers every other file
1344
- as a `conversation_file_link` message this queue delivers like any other. Live drafts ride that same queue as their own item and are
1345
- never reported back, because a draft has no settlement: House has already
1346
- coalesced each conversation to its latest view, and the gateway sends the
1347
- drafts of a pass after its durable deliveries with the Bot API's native
1348
- `sendRichMessageDraft` on the bound forum topic thread, under the same bot-wide
1349
- `retry_after` gate. The gateway coalesces nothing again and holds no draft for
1350
- a later pass: a draft taken in a pass that gate closed is dropped, and the next
1351
- view House coalesces takes its place. Pacing lives here because this is where
1352
- the Bot API is called.
1744
+ as a `conversation_file_link` message this queue delivers like any other. The
1745
+ queue carries no draft: an answer holding a draft item is refused as
1746
+ `kit_telegram_response_invalid`. House caps no message, so the gateway alone
1747
+ fits one to Telegram's rich message limits, 32,768 characters and 500 blocks:
1748
+ a rich message past them is sent as consecutive messages in order, split
1749
+ between blocks and inside a block only when that block alone exceeds them,
1750
+ and reported once, `delivered` with the first message's id when every part
1751
+ was delivered and otherwise with the answer of the first part that was not.
1752
+ Each answer also names the `threads` the bot's topics carry, a
1753
+ `conversation_id` with its `chat_id` and `topic_id`, which is where live
1754
+ drafts go.
1755
+
1756
+ Live drafts come from the control stream, not from House's queue. Run on its
1757
+ own, the command holds the Environment's [control stream](#the-kit-control-stream)
1758
+ for its lease; served by `kit resident`, it receives the draft and plan frames
1759
+ the resident's socket receives, through the resident, and never opens a second
1760
+ socket. The gateway Environment's socket carries every conversation bound to a
1761
+ topic of the bot, with no subscribe frame. The gateway keeps the latest view of
1762
+ each such conversation's turn: a frame that starts at block 0 replaces a view,
1763
+ the next frame in sequence applies from its `from`, and a frame after a gap in
1764
+ the sequence, or one for a turn it holds no view of, is applied nowhere and
1765
+ answered with one `gap` frame naming the conversation and turn, so House sends
1766
+ the whole view again. It renders each view as one Telegram draft per turn with
1767
+ `sendRichMessageDraft` on the bound topic, the live plan above the assistant
1768
+ text, under one draft id derived from the turn, because Telegram shows one bot
1769
+ draft per topic and a second id would replace the first. A view past the rich
1770
+ message limits is shortened inside that one draft, never split into a second.
1771
+ A live plan is part of the draft and never a sent message; the frozen plan
1772
+ House queues at the turn's end is the turn's one plan message. Drafts coalesce
1773
+ to the latest view, one Bot API call at a time, and are never reported back:
1774
+ the same bot-wide `retry_after` gate drops a draft while it is closed, and a
1775
+ draft answered with `retry_after` closes it. A closed gate drops a preview,
1776
+ never a durable delivery.
1353
1777
 
1354
1778
  Each serve run first asks House to settle the attempts an earlier run abandoned,
1355
1779
  so a restarted gateway never leaves a delivery attempted forever. A Telegram
@@ -1357,11 +1781,14 @@ so a restarted gateway never leaves a delivery attempted forever. A Telegram
1357
1781
  the delay Telegram supplied has passed. `--passes <count>` bounds each activity
1358
1782
  to that many passes and is what tests and one-shot runs use; without it the
1359
1783
  command is resident and stops on SIGINT or SIGTERM, printing what it settled.
1784
+ Each refused pass is printed as it happens, naming its activity, item and
1785
+ refusal code, so a gateway refused on every pass says so while it runs; the
1786
+ summary printed when it stops still lists each of them.
1360
1787
 
1361
1788
  Release the bot:
1362
1789
 
1363
1790
  ```sh
1364
- kit telegram disconnect --house https://agents.house
1791
+ kit telegram disconnect
1365
1792
  ```
1366
1793
 
1367
1794
  The command writes a local disconnect marker first, deletes the webhook, removes
@@ -1386,11 +1813,22 @@ $HOUSE_KIT_HOME/
1386
1813
  state/repositories/<repository identity>.json
1387
1814
  state/sync/<replica identity>.json
1388
1815
  state/sync/<replica identity>.pending.json
1816
+ state/working-copies/rooms/<room ref>.json
1817
+ state/working-copies/private.json
1389
1818
  state/attachments/<upload identity>.json
1390
1819
  state/conversation-originals/<attachment identity>.json
1391
1820
  state/sessions/<tmux session>.json
1821
+ state/update-drain
1822
+ state/skill-set.json
1823
+ state/how-we-work
1392
1824
  state/continuations/<run identity>.json
1393
- state/<instance>/credentials/google.json
1825
+ state/google/entries/<source>.json
1826
+ state/google/credentials/<account>.json
1827
+ state/google/checkpoints/<source>.json
1828
+ state/google/health/<source>.json
1829
+ state/google/gaps/<source>.json
1830
+ state/google/dropped/<source>.json
1831
+ state/google/originals/<source>.json
1394
1832
  state/<instance>/checkpoints/<service>.json
1395
1833
  state/<instance>/health/<service>.json
1396
1834
  state/<instance>/gaps/<service>.json
@@ -1400,15 +1838,18 @@ $HOUSE_KIT_HOME/
1400
1838
 
1401
1839
  Every file is written atomically and readable only by its owner. A file the Kit
1402
1840
  cannot read is refused rather than treated as a service that never captured.
1403
- Disabling a service or an instance leaves its state in place, so re-enabling
1404
- resumes from the stored cursor instead of importing again.
1841
+ A Google entry's state is keyed by its Source reference and lives only while
1842
+ House lists the entry. Disabling a custom service or instance leaves its state
1843
+ in place, so re-enabling resumes from the stored cursor instead of importing
1844
+ again.
1405
1845
 
1406
1846
  ```sh
1407
- kit source reset acme --house https://agents.house # every service
1408
- kit source reset acme notes --house https://agents.house # one service
1847
+ kit source reset acme # every service
1848
+ kit source reset acme notes # one service
1409
1849
  ```
1410
1850
 
1411
- Reset is the only deletion of captured state. It removes the named checkpoints
1851
+ Reset serves custom connectors, and is the only deletion of their captured
1852
+ state. It removes the named checkpoints
1412
1853
  and their outstanding retained references so the next capture restarts exactly at
1413
1854
  the configured backfill boundary. It takes the same
1414
1855
  Environment control lease a capture takes, so it cannot delete a checkpoint a
@@ -1442,7 +1883,7 @@ refused rather than read as no limit. A ceiling is a shared ceiling, never a
1442
1883
  reservation, and House infers no supported Agent count from any of these values.
1443
1884
 
1444
1885
  ```sh
1445
- kit host report --house https://agents.house
1886
+ kit host report
1446
1887
  ```
1447
1888
 
1448
1889
  The command reads `/proc/stat` twice a second apart, reads `/proc/meminfo`, and
@@ -1464,7 +1905,7 @@ Description=Report measured host capacity to House
1464
1905
  [Service]
1465
1906
  Type=oneshot
1466
1907
  User=house-kit
1467
- ExecStart=/usr/bin/kit host report --house https://agents.house
1908
+ ExecStart=/usr/bin/kit host report
1468
1909
  ```
1469
1910
 
1470
1911
  ```
@@ -1513,11 +1954,10 @@ manifest, URLs, or attachments.
1513
1954
 
1514
1955
  ```sh
1515
1956
  kit migrate emit my-import --package /home/ada/exports/project
1516
- kit migrate mount /home/ada/exports/project --house https://agents.house \
1517
- --subtree /rooms/work/library/project
1957
+ kit migrate mount /home/ada/exports/project --subtree /rooms/work/library/project
1518
1958
  # Or emit and mount in one maintained mount session:
1519
1959
  kit migrate run my-import --package /home/ada/exports/another-project \
1520
- --house https://agents.house --subtree /private/library/another-project
1960
+ --subtree /private/library/another-project
1521
1961
  ```
1522
1962
 
1523
1963
  Emission refuses an existing output directory. The module reads one JSON line
@@ -1583,7 +2023,7 @@ prepared model definitions survive a later content-mount refusal or unmount.
1583
2023
 
1584
2024
  The atomic text mount includes a report with pending transfer rows. Kit then
1585
2025
  uploads each downloaded file once as an attachment to the mount's Room or
1586
- private tree, independently retrieves and compares the saved bytes, and only
2026
+ Private Room, independently retrieves and compares the saved bytes, and only
1587
2027
  after that proof succeeds rewrites every link to it, in every referring
1588
2028
  document, to its attachment reference, such as `at_1x.q`. The reference is an
1589
2029
  identity House resolves, not an HTTP download URL. A link's query and fragment
@@ -1604,8 +2044,8 @@ leaves the pending mounted report plus the local outcomes. Re-migration is
1604
2044
  explicit unmount followed by mount.
1605
2045
 
1606
2046
  ```sh
1607
- kit migrate unmount /rooms/work/library/project --house https://agents.house
1608
- kit migrate unmount /rooms/work/library/project --house https://agents.house \
2047
+ kit migrate unmount /rooms/work/library/project
2048
+ kit migrate unmount /rooms/work/library/project \
1609
2049
  --confirm /rooms/work/library/project
1610
2050
  ```
1611
2051
 
@@ -1629,10 +2069,7 @@ workspaces.
1629
2069
  ```sh
1630
2070
  docker compose -f test/compose.yaml build kit
1631
2071
  docker compose -f test/compose.yaml run --rm kit npm test
1632
- docker compose -f test/compose.yaml run --rm \
1633
- -e HOUSE_KIT_GOOGLE_OAUTH_CLIENT_ID=kit-client.apps.googleusercontent.com \
1634
- -e HOUSE_KIT_GOOGLE_OAUTH_CLIENT_SECRET=GOCSPX-kit-installed-app \
1635
- kit npm run build
2072
+ docker compose -f test/compose.yaml run --rm kit npm run build
1636
2073
  ```
1637
2074
 
1638
2075
  `test/pair/run.sh` boots real Core, Auth and PostgreSQL and runs the installed