@agentshouse/kit 0.1.0-alpha.25 → 0.1.0-alpha.27

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 (117) hide show
  1. package/README.md +172 -158
  2. package/bin/connect-linux.sh +15 -4
  3. package/bin/kit.js +48 -46
  4. package/bootstrap.json +3 -3
  5. package/package.json +1 -1
  6. package/src/adapter-mcp.js +23 -1
  7. package/src/bridge.js +4 -0
  8. package/src/configuration.js +13 -209
  9. package/src/connector-login.js +3 -84
  10. package/src/contract.js +4 -0
  11. package/src/delivery.js +4 -7
  12. package/src/directory.js +6 -26
  13. package/src/google/calendar.js +39 -45
  14. package/src/google/drive.js +61 -186
  15. package/src/google/entries.js +346 -0
  16. package/src/google/gateway.js +3 -6
  17. package/src/google/gmail.js +33 -23
  18. package/src/google/oauth.js +106 -66
  19. package/src/google/source.js +21 -23
  20. package/src/house.js +43 -5
  21. package/src/how-we-work.md +25 -0
  22. package/src/kit-work-stream.js +1 -1
  23. package/src/launcher.js +11 -4
  24. package/src/mcp.js +5 -0
  25. package/src/setup.js +8 -14
  26. package/src/skill-set/ask-matt/PHASE-BOUNDARIES.md +55 -0
  27. package/src/skill-set/ask-matt/SKILL.md +91 -0
  28. package/src/skill-set/ask-matt/agents/openai.yaml +4 -0
  29. package/src/skill-set/code-review/LICENSE +21 -0
  30. package/src/skill-set/code-review/SKILL.md +89 -0
  31. package/src/skill-set/code-review/agents/openai.yaml +3 -0
  32. package/src/skill-set/codebase-design/DEEPENING.md +37 -0
  33. package/src/skill-set/codebase-design/DESIGN-IT-TWICE.md +44 -0
  34. package/src/skill-set/codebase-design/LICENSE +21 -0
  35. package/src/skill-set/codebase-design/SKILL.md +116 -0
  36. package/src/skill-set/codebase-design/agents/openai.yaml +3 -0
  37. package/src/skill-set/diagnosing-bugs/LICENSE +21 -0
  38. package/src/skill-set/diagnosing-bugs/SKILL.md +140 -0
  39. package/src/skill-set/diagnosing-bugs/agents/openai.yaml +3 -0
  40. package/src/skill-set/diagnosing-bugs/scripts/hitl-loop.template.sh +44 -0
  41. package/src/skill-set/domain-modeling/ADR-FORMAT.md +47 -0
  42. package/src/skill-set/domain-modeling/CONTEXT-FORMAT.md +60 -0
  43. package/src/skill-set/domain-modeling/LICENSE +21 -0
  44. package/src/skill-set/domain-modeling/SKILL.md +76 -0
  45. package/src/skill-set/domain-modeling/agents/openai.yaml +3 -0
  46. package/src/skill-set/grill-me/LICENSE +21 -0
  47. package/src/skill-set/grill-me/SKILL.md +8 -0
  48. package/src/skill-set/grill-me/agents/openai.yaml +4 -0
  49. package/src/skill-set/grill-with-docs/LICENSE +21 -0
  50. package/src/skill-set/grill-with-docs/SKILL.md +8 -0
  51. package/src/skill-set/grill-with-docs/agents/openai.yaml +4 -0
  52. package/src/skill-set/grilling/LICENSE +21 -0
  53. package/src/{starter-set → skill-set}/grilling/SKILL.md +1 -1
  54. package/src/skill-set/handoff/LICENSE +21 -0
  55. package/src/skill-set/handoff/SKILL.md +17 -0
  56. package/src/skill-set/handoff/agents/openai.yaml +4 -0
  57. package/src/skill-set/implement/LICENSE +21 -0
  58. package/src/skill-set/implement/SKILL.md +16 -0
  59. package/src/skill-set/implement/agents/openai.yaml +4 -0
  60. package/src/skill-set/improve-codebase-architecture/HTML-REPORT.md +123 -0
  61. package/src/skill-set/improve-codebase-architecture/LICENSE +21 -0
  62. package/src/skill-set/improve-codebase-architecture/SKILL.md +72 -0
  63. package/src/skill-set/improve-codebase-architecture/agents/openai.yaml +4 -0
  64. package/src/skill-set/prototype/LICENSE +21 -0
  65. package/src/skill-set/prototype/LOGIC.md +67 -0
  66. package/src/skill-set/prototype/SKILL.md +28 -0
  67. package/src/skill-set/prototype/UI.md +112 -0
  68. package/src/skill-set/prototype/agents/openai.yaml +3 -0
  69. package/src/skill-set/research/LICENSE +21 -0
  70. package/src/skill-set/research/SKILL.md +14 -0
  71. package/src/skill-set/research/agents/openai.yaml +3 -0
  72. package/src/skill-set/resolving-merge-conflicts/LICENSE +21 -0
  73. package/src/skill-set/resolving-merge-conflicts/SKILL.md +16 -0
  74. package/src/skill-set/resolving-merge-conflicts/agents/openai.yaml +3 -0
  75. package/src/skill-set/tdd/LICENSE +21 -0
  76. package/src/skill-set/tdd/SKILL.md +40 -0
  77. package/src/skill-set/tdd/agents/openai.yaml +3 -0
  78. package/src/skill-set/tdd/mocking.md +59 -0
  79. package/src/skill-set/tdd/tests.md +77 -0
  80. package/src/skill-set/teach/GLOSSARY-FORMAT.md +35 -0
  81. package/src/skill-set/teach/LEARNING-RECORD-FORMAT.md +46 -0
  82. package/src/skill-set/teach/LICENSE +21 -0
  83. package/src/skill-set/teach/MISSION-FORMAT.md +31 -0
  84. package/src/skill-set/teach/RESOURCES-FORMAT.md +32 -0
  85. package/src/skill-set/teach/SKILL.md +141 -0
  86. package/src/skill-set/teach/agents/openai.yaml +4 -0
  87. package/src/skill-set/to-questionnaire/LICENSE +21 -0
  88. package/src/skill-set/to-questionnaire/SKILL.md +55 -0
  89. package/src/skill-set/to-questionnaire/agents/openai.yaml +4 -0
  90. package/src/skill-set/to-spec/LICENSE +21 -0
  91. package/src/skill-set/to-spec/SKILL.md +76 -0
  92. package/src/skill-set/to-spec/agents/openai.yaml +4 -0
  93. package/src/skill-set/to-tickets/LICENSE +21 -0
  94. package/src/skill-set/to-tickets/SKILL.md +106 -0
  95. package/src/skill-set/to-tickets/agents/openai.yaml +4 -0
  96. package/src/skill-set/wait-what/LICENSE +21 -0
  97. package/src/skill-set/wait-what/SKILL.md +8 -0
  98. package/src/skill-set/wait-what/agents/openai.yaml +4 -0
  99. package/src/skill-set/wayfinder/LICENSE +21 -0
  100. package/src/skill-set/wayfinder/SKILL.md +129 -0
  101. package/src/skill-set/wayfinder/agents/openai.yaml +4 -0
  102. package/src/skill-set/writing-for-agents/LICENSE +21 -0
  103. package/src/skill-set/writing-for-agents/SKILL-MECHANICS.md +22 -0
  104. package/src/skill-set/writing-for-agents/SKILL.md +83 -0
  105. package/src/skill-set/writing-for-agents/agents/openai.yaml +3 -0
  106. package/src/skill-set.js +85 -0
  107. package/src/source.js +51 -26
  108. package/src/state.js +19 -1
  109. package/src/tasks.js +72 -0
  110. package/src/worker.js +46 -68
  111. package/src/working-copy.js +1 -15
  112. package/src/google/declared.js +0 -146
  113. package/src/google/id.js +0 -1
  114. package/src/instance/google.js +0 -1
  115. package/src/starter-set.js +0 -17
  116. /package/src/{starter-set/grilling → skill-set/ask-matt}/LICENSE +0 -0
  117. /package/src/{starter-set → skill-set}/grilling/agents/openai.yaml +0 -0
package/README.md CHANGED
@@ -4,12 +4,15 @@ 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
12
  On Linux `amd64` or `arm64`, run the published, versioned bootstrap once:
10
13
 
11
14
  ```sh
12
- bash <(curl -fsSL https://github.com/agentshouse/kit/releases/download/v0.1.0-alpha.25/connect-linux.sh)
15
+ bash <(curl -fsSL https://github.com/agentshouse/kit/releases/download/v0.1.0-alpha.27/connect-linux.sh)
13
16
  ```
14
17
 
15
18
  The bootstrap first establishes Docker Engine from what it observes on the
@@ -40,13 +43,18 @@ and starts the container with Docker's `unless-stopped` lifecycle. Pass
40
43
  `--workspace /absolute/path` for one other workspace root or `--manual` for
41
44
  the existing URL and one-time-code login route. `--house <origin>` selects
42
45
  another House and is retained in Kit home. A repeated invocation reuses the
43
- same container, credential and Environment.
46
+ same container, credential and Environment. Every invocation that is not a
47
+ forwarded command also sets `skills` in Kit's configuration: `--no-skills`
48
+ declines [the Skill set](#the-skill-set) and an invocation without it accepts
49
+ the set again.
44
50
 
45
51
  Running a newer release's bootstrap the same way is the only update. When the
46
52
  installed container runs another image, the bootstrap pulls this release's
47
53
  image and asks the running resident Kit to drain with `kit resident drain`. The
48
- resident stops acquiring Runs, resumptions, setup and agent CLI work, while the
49
- Sessions it supervises keep their renewal, owner stops, answers and reports.
54
+ resident stops acquiring Runs, resumptions, setup, agent CLI work, Google
55
+ sign-ins and scheduled Google captures, while the Sessions it supervises keep
56
+ their renewal, owner stops, answers and reports and a capture already running
57
+ finishes.
50
58
  While any Agent Session is still running or unreported, including one whose Run
51
59
  was being acquired when the drain began, the bootstrap names it and leaves the
52
60
  container as it is; rerun it once they end. Once nothing remains,
@@ -135,21 +143,17 @@ anything reaches House.
135
143
 
136
144
  ## Building the package
137
145
 
138
- The repository checkout is the development source. Build the package
139
- that can be published by supplying House's dedicated installed-application
140
- Google OAuth client, its id and its client secret:
146
+ The repository checkout is the development source. Build the package that can
147
+ be published:
141
148
 
142
149
  ```sh
143
- HOUSE_KIT_GOOGLE_OAUTH_CLIENT_ID=kit-client.apps.googleusercontent.com \
144
- HOUSE_KIT_GOOGLE_OAUTH_CLIENT_SECRET=GOCSPX-kit-installed-app \
145
150
  npm run build
146
151
  ```
147
152
 
148
- The command writes the publishable package to `dist/package`. Both values are
149
- public instance content fixed into that package at build time: Google issues an
150
- installed application's client secret without treating it as confidential, and
151
- still requires it in every token request. The installed Kit does not read either
152
- from its runtime environment and never requests them from House.
153
+ The command writes the publishable package to `dist/package`. It reads no
154
+ environment and ships no provider OAuth client: each Google account signs in
155
+ with the User's own client, as [the Google preset](#the-google-preset)
156
+ describes.
153
157
 
154
158
  Runtime dependencies stay minimal and exactly pinned in `package.json` and
155
159
  `package-lock.json`: House's own `@agentshouse/mdmodel`, `yaml`, which reads
@@ -227,7 +231,8 @@ never printed by Kit.
227
231
  "settings": "/home/ada/.claude/settings.json"
228
232
  }
229
233
  ],
230
- "host": null
234
+ "host": null,
235
+ "skills": true
231
236
  }
232
237
  ```
233
238
 
@@ -247,13 +252,19 @@ mode: `"intermittent"` for a laptop or other normally offline placement,
247
252
  any other value refuses as `kit_configuration_invalid`; `kit apply` sends the
248
253
  declared mode with the rest of the desired state. An
249
254
  instance declares one or more services, and under the `custom` preset each
250
- service owns the command that produces it.
255
+ service owns the command that produces it. The Kit reads only `custom` instances
256
+ and passes over any other entry of `instances`.
251
257
 
252
258
  `host` declares the Linux host this installation measures for
253
259
  [host capacity reporting](#host-capacity). `null` declares that this Kit reports
254
260
  no capacity; the section is required like the others, so a host is measured only
255
261
  where the Environment owner says so.
256
262
 
263
+ `skills` is this Environment's choice of [the Skill set](#the-skill-set):
264
+ `true` accepts it and `false` declines it. A configuration that omits it
265
+ accepts the set. The bootstrap writes it on every invocation that is not a
266
+ forwarded command.
267
+
257
268
  `clients` is the local Agent client catalogue and never leaves the installation.
258
269
  Each entry names one client whose lifecycle hook configuration this Kit
259
270
  reconciles: `kind` is `claude-code`, the one client this Kit installs a hook
@@ -348,119 +359,81 @@ refuses as `kit_hook_rejected` instead of leaving whatever was installed before.
348
359
 
349
360
  ## The Google preset
350
361
 
351
- The published Kit is built with one House-owned Google installed-application
352
- OAuth client. Its id and client secret are public build-time instance content,
353
- not House secrets and not values served by House at run time. Google refresh
354
- and access tokens remain in the installation's local credential store.
355
-
356
- Each Google instance represents one Google account, and one Kit installation
357
- may declare as many as the User has. Each instance owns its own local Google
358
- authorization, selectors, Source references, Room routes, checkpoints and
359
- health under `state/<instance>/`; the installation's one `kit login` covers
360
- them all, and no instance can read another's provider credential.
362
+ House holds this Environment's Google Sources, and its owner sets them in the
363
+ App. Each entry names an account name the owner chooses, one service -
364
+ `gmail`, `calendar` or `drive` - the Rooms it goes to, and what its first
365
+ capture takes: `{ "new": true }` for new activity only, `{ "days": n }`,
366
+ `{ "items": n }` or `{ "all": true }`. Neither the configuration file nor any
367
+ command on this computer declares one.
368
+
369
+ Each service captures a fixed corpus under its own read-only scope: Gmail every
370
+ message but Spam and Trash, Calendar the account's primary calendar, and Drive
371
+ the files the account owns.
372
+
373
+ The resident reads the list from `/kit/sources/desired` each time its Kit
374
+ control stream connects and each time House signals `sources` on it, then
375
+ reconciles:
376
+
377
+ - a new entry gets its local state and is captured once its account is signed
378
+ in for its service;
379
+ - a changed entry's Rooms take effect on its next capture;
380
+ - an entry House no longer lists stops, and its checkpoint, health, gaps,
381
+ dropped items and unsaved originals are deleted;
382
+ - an account left with no entry has each of its grants revoked at Google's
383
+ revocation endpoint and its credentials, its OAuth client included, deleted.
384
+ Google's revocation ends every grant the Google user gave the client's
385
+ project, so when another listed account is signed in to the same Google user,
386
+ the Kit deletes the local credentials and revokes nothing.
387
+
388
+ It then reports every entry to `/kit/sources/report`, and reports an entry
389
+ again after each sign-in and each capture: `signed_out` while its
390
+ account holds no grant for its service, `failed` with its cause code when its
391
+ last capture failed, and `ready` otherwise, each with the account's signed-in
392
+ email once the Kit knows it.
393
+
394
+ The Kit ships no Google OAuth client. Each account signs in with the User's
395
+ own: an OAuth client of type Desktop app in the User's Google Cloud project,
396
+ with the service's API enabled there. An entry whose account holds no grant for
397
+ its service opens a login renewal for integration `google`, instance the
398
+ account name and service the entry's service, and presents its ceremony on
399
+ House's owner-authenticated page, so the owner's browser never has to reach
400
+ this Environment. When the account has no client yet, the page first collects
401
+ the client id and secret. It then links to Google's consent for that service's
402
+ scope only; Google sends the browser to a `http://127.0.0.1:<port>/` address
403
+ that nothing answers, and the owner pastes that whole address into the page.
404
+ The Kit accepts it only when it carries the state its own consent issued,
405
+ exchanges the code with its PKCE verifier and the account's client, and stores
406
+ the grant beside the client in `state/google/credentials/<account>.json`. The
407
+ collected values pass through House's live relay only; neither they nor any
408
+ token enter a report, a log or anything House stores. Adding a
409
+ service to a signed-in account asks only for that service's consent, and each
410
+ service keeps its own grant. An address that answers another consent, or a code
411
+ Google refuses to exchange, stores nothing; a declined consent or a ceremony
412
+ that outlives its ten-minute bound cancels the sign-in, and the Kit tries again
413
+ at the next reconciliation.
414
+
415
+ The resident captures each signed-in entry every 15 minutes, with no command.
416
+ An occurrence never overlaps its entry's previous one, and one missed while the
417
+ resident was stopped is not replayed: the next resumes from the checkpoint. The
418
+ first capture fixes the initial choice's boundary, so `new` captures nothing
419
+ that existed then and everything that arrives after.
361
420
 
362
- ```json
363
- {
364
- "availability": "intermittent",
365
- "execution_authority": "refuse",
366
- "migrators": [],
367
- "instances": [
368
- {
369
- "id": "google-account",
370
- "preset": "google",
371
- "scopes": ["https://www.googleapis.com/auth/contacts.readonly"],
372
- "services": [
373
- {
374
- "service": "gmail",
375
- "source_ref": "src_google_mail",
376
- "rooms": ["work-room"],
377
- "backfill": { "days": 30 },
378
- "selection": { "labels": ["INBOX"] }
379
- },
380
- {
381
- "service": "calendar",
382
- "source_ref": "src_google_calendar",
383
- "rooms": ["work-room"],
384
- "backfill": { "all": true },
385
- "selection": { "calendars": ["primary"] }
386
- },
387
- {
388
- "service": "drive",
389
- "source_ref": "src_google_drive",
390
- "rooms": ["work-room"],
391
- "backfill": { "count": 500 },
392
- "selection": { "files": ["file-id"], "folders": ["folder-id"] }
393
- }
394
- ]
395
- }
396
- ],
397
- "clients": [],
398
- "host": null
399
- }
421
+ ```sh
422
+ kit source capture work # one occurrence of every entry of the account now
423
+ kit source capture work gmail # one occurrence of one entry now
424
+ kit source status work
400
425
  ```
401
426
 
402
- Google authorization is incremental. Enabling Gmail requests only Gmail's
403
- read-only scope; Calendar and Drive request their own read-only scopes only
404
- when enabled. Each service scope set has its own local provider grant, so a
405
- later authorization never widens or replaces a sibling service's grant.
406
- Additional Google API scopes are declared once on the preset instance and
407
- remain local; a declared service names only scopes that instance already
408
- holds. Drive requires at least one explicit file or folder selection and never
409
- defaults to the whole account.
410
-
411
- A Google API outside the three curated services may use the closed declared
412
- service schema. The declaration is data only: no script or executable transform
413
- is loaded. Its host must be a Google API domain and it runs under scopes the
414
- instance already holds.
415
-
416
- ```json
417
- {
418
- "service": "people",
419
- "source_ref": "src_google_people",
420
- "rooms": ["work-room"],
421
- "backfill": { "all": true },
422
- "declaration": {
423
- "host": "people.googleapis.com",
424
- "path": "/v1/people/me/connections",
425
- "query": { "personFields": "names,emailAddresses,metadata" },
426
- "page_size": "pageSize",
427
- "scopes": ["https://www.googleapis.com/auth/contacts.readonly"],
428
- "page_token": {
429
- "request": "pageToken",
430
- "response": "nextPageToken",
431
- "checkpoint_request": "syncToken",
432
- "checkpoint_response": "nextSyncToken"
433
- },
434
- "items": "connections",
435
- "fields": {
436
- "native_id": "resourceName",
437
- "native_version": "etag",
438
- "provider_modified_at": "metadata.sources.0.updateTime",
439
- "observed_at": "metadata.sources.0.updateTime",
440
- "body": ["names.0.displayName", "emailAddresses.0.value"],
441
- "container": "metadata.sources.0.type"
442
- }
443
- }
444
- }
445
- ```
427
+ `kit source capture` and `kit source status` take the account name where a
428
+ custom connector takes its instance; a name House lists as an account is read
429
+ as the account. While the resident runs, it performs the requested occurrence
430
+ itself, after any occurrence of that entry already running.
446
431
 
447
- A Google instance signs in only through [Environment setup](#environment-setup),
448
- on House's owner-authenticated page, so the owner's browser never has to reach
449
- this Environment. For each enabled service whose scopes the instance does not
450
- hold yet, the page links to Google's consent for exactly that service's scopes.
451
- Google then sends the browser to a `http://127.0.0.1:<port>/` address that
452
- nothing answers: the owner copies that whole address from the address bar and
453
- pastes it into the page. The Kit accepts it only when it carries the state its
454
- own consent issued, exchanges the code with its PKCE verifier and the built
455
- client, and stores the grant locally. An address that answers another consent,
456
- or a code Google refuses to exchange, fails the login and stores nothing; a
457
- declined consent cancels it. Grants already completed for earlier services stay.
458
-
459
- `kit source sign-in <instance>` signs in a custom connector instance through
460
- its own command, described below. It skips an instance whose local
461
- authorization is already valid and answers `ready`, `skipped`, or
462
- `needs_attention`. A Google instance refuses it as `kit_connector_login_guided`
463
- and names House setup.
432
+ A failed occurrence records its cause. A Google 403 for an API disabled in the
433
+ client's project fails as `api_disabled`, and `kit source status` names the API
434
+ to enable; a revoked scope (`google_scope_revoked`), an expired or revoked grant
435
+ (`google_authority_revoked`) and a provider failure
436
+ (`google_provider_unavailable`) keep their own codes.
464
437
 
465
438
  ## Environment setup
466
439
 
@@ -577,8 +550,10 @@ An object whose content changes without its native version changing keeps its
577
550
  key and is refused by House as a delivery-key conflict rather than silently
578
551
  overwriting the earlier Record.
579
552
 
580
- The same command owns its module authorization. `kit source sign-in` and the
581
- setup walk's status check send one JSON line
553
+ The same command owns its module authorization. `kit source sign-in <instance>`
554
+ skips an instance whose local authorization is already valid and answers
555
+ `ready`, `skipped`, or `needs_attention`. It and the setup walk's status check
556
+ send one JSON line
582
557
  with `action: "authorization"` and `mode: "status"` or `mode: "login"`; the
583
558
  command returns exactly one JSON object such as `{ "authorized": true }`.
584
559
 
@@ -653,27 +628,12 @@ inside `/agents/house` is somebody else's default or an owner's own workspace,
653
628
  never this Agent's. Every path that is not this exact equality, one deeper
654
629
  inside `/agents/house` included, must
655
630
  already exist in this Environment as a directory the installation can enter;
656
- Kit never creates or seeds it.
657
-
658
- When the Agent's own default directory is absent, Kit builds the starter set in
659
- a temporary directory beneath the base and renames it into place as one atomic
660
- step, so a partly seeded directory is never visible at the default path. Two
661
- concurrent first launches race that rename; the loser discards its temporary
662
- directory and uses the directory the winner put there, so the pair still leaves
663
- one complete directory and nothing partial. A present default directory -
664
- including one whose starter files the owner edited or removed - launches
665
- exactly as it is, and a deleted default directory is recreated with a fresh
666
- starter set on its next launch.
667
-
668
- The starter set is `AGENTS.md` with the single line ``The agents.house `house`
669
- CLI is available: run `house --help`.``, `CLAUDE.md` as a relative symbolic link to it, `.agents/skills/grilling/`
670
- vendored from [`mattpocock/skills`](https://github.com/mattpocock/skills)
671
- `skills/productivity/grilling` at a pinned commit with its MIT license and a
672
- provenance header naming that commit, and `.claude/skills` as a relative
673
- symbolic link to `.agents/skills`. Once seeded the files belong to the owner:
674
- Kit never syncs, refreshes, or restores them, and refreshing the vendored skill
675
- for new Agents is an ordinary Kit release that never touches an already seeded
676
- directory.
631
+ Kit never creates it.
632
+
633
+ When the Agent's own default directory is absent, Kit creates it empty; two
634
+ concurrent first launches create the same directory. A present default
635
+ directory launches exactly as it is, and a deleted one is created empty again
636
+ on its next launch. Kit writes no file into any working directory.
677
637
 
678
638
  A relative, missing, inaccessible, or non-directory working directory refuses
679
639
  with `kit_launch_directory_unavailable` before any provider process starts. Kit falls back to no other location - not the
@@ -681,6 +641,52 @@ base, not `$HOUSE_KIT_HOME`, and not its own current directory - and neither
681
641
  connecting an installation nor launching a session moves, copies, overwrites,
682
642
  or removes anything a working directory holds.
683
643
 
644
+ ## The Skill set
645
+
646
+ The Skill set is every skill the `mattpocock/skills` plugin manifest names at
647
+ one pinned commit but `setup-matt-pocock-skills`, `triage` and `wizard`. Each
648
+ is vendored under `src/skill-set/<name>/` with every file it ships, the
649
+ upstream MIT `LICENSE` and a provenance header in `SKILL.md` naming the commit
650
+ and upstream path. Nothing else is edited but two lines: a
651
+ `disable-model-invocation: true` frontmatter line in `SKILL.md` and an
652
+ `allow_implicit_invocation: false` line in `agents/openai.yaml` are removed, so
653
+ an agent reaches every skill without being told its name.
654
+
655
+ Kit installs the Skill set once for the Environment, for every Agent whatever
656
+ its working directory, under the home it launches agent CLIs with: each skill
657
+ as the directory `$HOME/.agents/skills/<name>`, which Codex and Grok Build
658
+ read, and a relative symbolic link `$HOME/.claude/skills/<name>` to it, which
659
+ Claude Code reads; when `$HOME/.claude/skills` already resolves to
660
+ `$HOME/.agents/skills`, Claude Code reads the directory there and Kit makes no
661
+ link. In a container that home is Kit home, so the set survives
662
+ container recreation; on a native host it is the host user's home.
663
+
664
+ `$HOUSE_KIT_HOME/state/skill-set.json` records the names Kit installed and the
665
+ Kit version that installed them, and Kit owns exactly those names: the
666
+ directory and the link of each. At start and on every resident pass, when
667
+ the set is accepted and the record names another version or none, Kit deletes
668
+ every recorded name, installs the current Skill set and rewrites the record. A
669
+ name whose directory or link exists without being recorded is the owner's: Kit
670
+ leaves it untouched and installs nothing under it. Kit never compares, merges
671
+ or restores a file, so an edit to an installed skill is lost at the next
672
+ release and a copy under another name is kept. When `skills` is `false`, Kit
673
+ deletes every recorded name and the record and installs nothing.
674
+
675
+ After Kit first installs the Skill set, the first Session it launches whose
676
+ Profile ceiling lets it write the owner's How-we-work document
677
+ `/private/library/how-we-work.md` creates it, when it is absent, with the text
678
+ Kit ships in `src/how-we-work.md`, over the Session's own bridge before its
679
+ first prompt is built. Kit then notes in `$HOUSE_KIT_HOME/state/how-we-work`,
680
+ apart from the record, that the document exists, and a present document is
681
+ noted the same way without being touched. Nothing ever creates it again: a
682
+ release, a declined Skill set and a later acceptance leave the note, so an
683
+ owner's edit stands and a deleted document stays deleted. A Session whose
684
+ ceiling cannot write the document launches without it and leaves it for the
685
+ next one; any other refused creation refuses the attempt as
686
+ `kit_how_we_work_unwritable` with House's answer before a prompt is sent. A
687
+ Skill set Kit cannot install or remove refuses the pass as
688
+ `kit_skill_set_unavailable` and names the path.
689
+
684
690
  ## The declared agent CLIs
685
691
 
686
692
  The Environment owner installs no adapter binary by hand. `kit agents update`
@@ -1165,8 +1171,8 @@ on the door's own deduplication. When House stops a batch early, its answer
1165
1171
  settles only the prefix it reached, and the unsettled tail is reoffered with the
1166
1172
  rest. The loop repeats while the connector still returns items and no Room
1167
1173
  destination is blocked, and every run ends by writing the service's health into
1168
- this installation's own state. House holds no preset, service, route, checkpoint
1169
- or health of yours.
1174
+ this installation's own state. House holds no custom connector's service, route,
1175
+ checkpoint or health, and no Google entry's checkpoint or health.
1170
1176
 
1171
1177
  A Capture item that declares a `file` attachment answers one Record per Room
1172
1178
  destination: Rooms of one owner share that owner's Record, and a Room of another
@@ -1708,8 +1714,16 @@ $HOUSE_KIT_HOME/
1708
1714
  state/conversation-originals/<attachment identity>.json
1709
1715
  state/sessions/<tmux session>.json
1710
1716
  state/update-drain
1717
+ state/skill-set.json
1718
+ state/how-we-work
1711
1719
  state/continuations/<run identity>.json
1712
- state/<instance>/credentials/google.json
1720
+ state/google/entries/<source>.json
1721
+ state/google/credentials/<account>.json
1722
+ state/google/checkpoints/<source>.json
1723
+ state/google/health/<source>.json
1724
+ state/google/gaps/<source>.json
1725
+ state/google/dropped/<source>.json
1726
+ state/google/originals/<source>.json
1713
1727
  state/<instance>/checkpoints/<service>.json
1714
1728
  state/<instance>/health/<service>.json
1715
1729
  state/<instance>/gaps/<service>.json
@@ -1719,15 +1733,18 @@ $HOUSE_KIT_HOME/
1719
1733
 
1720
1734
  Every file is written atomically and readable only by its owner. A file the Kit
1721
1735
  cannot read is refused rather than treated as a service that never captured.
1722
- Disabling a service or an instance leaves its state in place, so re-enabling
1723
- resumes from the stored cursor instead of importing again.
1736
+ A Google entry's state is keyed by its Source reference and lives only while
1737
+ House lists the entry. Disabling a custom service or instance leaves its state
1738
+ in place, so re-enabling resumes from the stored cursor instead of importing
1739
+ again.
1724
1740
 
1725
1741
  ```sh
1726
1742
  kit source reset acme # every service
1727
1743
  kit source reset acme notes # one service
1728
1744
  ```
1729
1745
 
1730
- Reset is the only deletion of captured state. It removes the named checkpoints
1746
+ Reset serves custom connectors, and is the only deletion of their captured
1747
+ state. It removes the named checkpoints
1731
1748
  and their outstanding retained references so the next capture restarts exactly at
1732
1749
  the configured backfill boundary. It takes the same
1733
1750
  Environment control lease a capture takes, so it cannot delete a checkpoint a
@@ -1947,10 +1964,7 @@ workspaces.
1947
1964
  ```sh
1948
1965
  docker compose -f test/compose.yaml build kit
1949
1966
  docker compose -f test/compose.yaml run --rm kit npm test
1950
- docker compose -f test/compose.yaml run --rm \
1951
- -e HOUSE_KIT_GOOGLE_OAUTH_CLIENT_ID=kit-client.apps.googleusercontent.com \
1952
- -e HOUSE_KIT_GOOGLE_OAUTH_CLIENT_SECRET=GOCSPX-kit-installed-app \
1953
- kit npm run build
1967
+ docker compose -f test/compose.yaml run --rm kit npm run build
1954
1968
  ```
1955
1969
 
1956
1970
  `test/pair/run.sh` boots real Core, Auth and PostgreSQL and runs the installed
@@ -6,6 +6,7 @@ NAME='house-kit'
6
6
  HOUSE='https://agents.house'
7
7
  WORKSPACE="$HOME/AgentsHouse"
8
8
  MANUAL=0
9
+ SKILLS=true
9
10
  WORKSPACE_SELECTED=0
10
11
  HOUSE_SELECTED=0
11
12
  FORWARDING=0
@@ -160,6 +161,10 @@ while (($#)); do
160
161
  MANUAL=1
161
162
  shift
162
163
  ;;
164
+ --no-skills)
165
+ SKILLS=false
166
+ shift
167
+ ;;
163
168
  *) refuse "unknown argument $1" ;;
164
169
  esac
165
170
  done
@@ -208,6 +213,16 @@ if [[ -f "$KIT_HOME/house" ]]; then
208
213
  HOUSE="$BOUND_HOUSE"
209
214
  fi
210
215
  [[ "$HOUSE" == https://* || "$HOUSE" == http://127.0.0.1:* || "$HOUSE" == http://localhost:* ]] || refuse 'House origin must use HTTPS or local loopback HTTP'
216
+ if ((FORWARDING == 0)); then
217
+ if [[ ! -f "$KIT_HOME/kit.json" ]]; then
218
+ printf '{"availability":"intermittent","execution_authority":"allow","migrators":[],"instances":[],"clients":[],"host":null,"skills":%s}\n' "$SKILLS" > "$KIT_HOME/kit.json"
219
+ elif grep -Eq '"skills"[[:space:]]*:' "$KIT_HOME/kit.json"; then
220
+ sed -E -i "s/(\"skills\"[[:space:]]*:[[:space:]]*)(true|false)/\\1$SKILLS/" "$KIT_HOME/kit.json" || refuse 'kit.json could not be updated'
221
+ else
222
+ sed -E -i "1s/^([[:space:]]*)\\{/\\1{\"skills\":$SKILLS,/" "$KIT_HOME/kit.json" || refuse 'kit.json could not be updated'
223
+ fi
224
+ grep -Eq "\"skills\"[[:space:]]*:[[:space:]]*$SKILLS" "$KIT_HOME/kit.json" || refuse 'kit.json could not be updated'
225
+ fi
211
226
  DOCKER_RUN=(docker run --rm --network host --user "$(id -u):$(id -g)" --mount "$KIT_HOME_MOUNT" --mount "$WORKSPACE_MOUNT" --env HOME=/kit-home --env HOUSE_KIT_HOME=/kit-home --env HOUSE_KIT_CONTAINER=1 --env "HOUSE_KIT_HOSTNAME=$(hostname)" "$IMAGE")
212
227
 
213
228
  if docker container inspect "$NAME" >/dev/null 2>&1; then
@@ -271,10 +286,6 @@ fi
271
286
 
272
287
  docker pull --quiet --platform "linux/$ARCH" "$IMAGE" >/dev/null
273
288
 
274
- if [[ ! -f "$KIT_HOME/kit.json" ]]; then
275
- printf '{"availability":"intermittent","execution_authority":"allow","migrators":[],"instances":[],"clients":[],"host":null}\n' > "$KIT_HOME/kit.json"
276
- fi
277
-
278
289
  if [[ -f "$KIT_HOME/credential" ]]; then
279
290
  "${DOCKER_RUN[@]}" credential check
280
291
  else