@agentshouse/skills 0.1.0-cdf317eaa8570 → 0.1.0-ce192f978a032

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 (54) hide show
  1. package/README.md +4 -4
  2. package/agent-instructions.json +4 -5
  3. package/dist/index.d.ts +1 -2
  4. package/dist/index.js +5 -12
  5. package/guide/{routines → agent-functions}/work-on-ticket.md +6 -8
  6. package/guide/apps/build.md +2 -1
  7. package/guide/apps/chat.md +32 -8
  8. package/guide/apps/client.md +1 -1
  9. package/guide/apps/content-safety.md +4 -4
  10. package/guide/apps/data.md +10 -6
  11. package/guide/apps/example-function.md +66 -0
  12. package/guide/apps/example-tasks-2.md +0 -2
  13. package/guide/apps/example-tasks.md +2 -34
  14. package/guide/apps/functions.md +13 -0
  15. package/guide/apps/local-first.md +10 -9
  16. package/guide/apps/local-query-results.md +13 -4
  17. package/guide/apps/local-query.md +20 -12
  18. package/guide/apps/page.md +3 -2
  19. package/guide/apps/room-drafts.md +21 -14
  20. package/guide/apps/runtime-api.md +17 -10
  21. package/guide/apps/runtime-conversations.md +28 -0
  22. package/guide/apps/runtime-files.md +8 -6
  23. package/guide/apps/runtime-refusals.md +10 -5
  24. package/guide/apps/runtime.md +1 -1
  25. package/guide/apps/search.md +21 -0
  26. package/guide/apps/start.md +5 -3
  27. package/guide/apps/verify.md +4 -5
  28. package/guide/index.md +5 -5
  29. package/guide/owner-rules.md +9 -8
  30. package/guide/reference/access-level.md +9 -0
  31. package/guide/reference/agent-function.md +15 -0
  32. package/guide/reference/app-manifest.md +1 -1
  33. package/guide/reference/schema.md +22 -11
  34. package/guide/reference/triggers.md +10 -4
  35. package/guide/sites/build.md +7 -6
  36. package/guide/sites/entry-data-contract.md +1 -1
  37. package/guide/sites/runtime.md +1 -1
  38. package/guide/skills/build-app.md +1 -1
  39. package/guide/skills/house-onboarding.md +8 -12
  40. package/guide/skills/prototype-app.md +6 -6
  41. package/guide/skills/wizard.md +7 -1
  42. package/owner-rules-earlier.json +5 -1
  43. package/package.json +1 -1
  44. package/set/code-review/SKILL.md +1 -1
  45. package/set/codebase-design/DESIGN-IT-TWICE.md +1 -1
  46. package/set/grilling/SKILL.md +1 -1
  47. package/set/implement-spec/SKILL.md +4 -2
  48. package/set/improve-codebase-architecture/SKILL.md +1 -1
  49. package/set/research/SKILL.md +1 -1
  50. package/set/wayfinder/SKILL.md +1 -1
  51. package/upstream.json +2 -2
  52. package/guide/apps/local-search.md +0 -35
  53. package/guide/reference/read-level.md +0 -9
  54. package/guide/reference/routine.md +0 -14
@@ -4,9 +4,10 @@ What App code reaches through the runtime's client: its surfaces, its reach, obs
4
4
 
5
5
  App code reaches the MD Runtime through the remote client. The surfaces are Rooms, Query,
6
6
  Search, Observe, Types, Room Draft, Save, History, Resolve, binary files, Call,
7
- Reached, Log, the reported persistence answer, reauthorization, conversation, the chat
7
+ Reached, the reported persistence answer, reauthorization, conversation, the chat
8
8
  draft, and Presentation State. Sync Status, readiness, the Service Mode, the storage-loss
9
- statement, the deployment facts and the signed-in member are observations only.
9
+ statement, the deployment facts, the signed-in member and the count of authority changes
10
+ are observations only.
10
11
 
11
12
  The host attaches each port with its reach, and every member and observation answers
12
13
  within it: a Room outside it answers as one the replica does not hold, Rooms lists only
@@ -20,7 +21,9 @@ unsubscribe, and `close()` ends it. Closing the port ends every handle and rejec
20
21
  pending call and observation; a reconnected client observes again.
21
22
 
22
23
  `observe('agents')` answers every Agent a new conversation can go to, each `{ identity,
23
- name }`, with a conversation yet or not. Each conversation the Provider lists is held
24
+ name }`, a retired one left out: online every Agent of the User, with a conversation yet or
25
+ not, each with its `cli` and `environment` `{ identity, name, state }`, `state` `online` or
26
+ `offline`; offline every Agent a conversation names. Each conversation the Provider lists is held
24
27
  complete in the browser. `conversation.list()` and `observe('conversations')` answer each
25
28
  with its Agent's identity and name, its name, created and finished times, last outcome,
26
29
  live `state` (`asking` while a question waits, `working` while a turn runs, else `idle`)
@@ -29,14 +32,18 @@ limit, total: true })` holds its latest `limit` messages, at most 1,000, oldest
29
32
  `total` their count, and `next` while older ones exist, which `after` takes, there or in
30
33
  `conversation.read(id, { limit, after })`, for the window before; its chat draft; and,
31
34
  only in memory, what the Provider streams whether or not anything views it: the running
32
- `turn` with its parts and its context in use and window, which the message accepted under
33
- the turn's id replaces, the open questions, the process state, and the CLI's commands and
34
- options, none stored or searchable. `chatDraft.write` and `chatDraft.discard` keep what
35
- the App Creator composes, and `chatDraft.prepend(conversation, draft)` puts a returned
36
- message ahead of it as it stands. Sending it is a Provider Action that needs the Provider
37
- reachable and is never queued. A new conversation's chat draft is keyed `new:<Agent
35
+ `turn` with its Session content parts, which the message accepted under the turn's id
36
+ replaces, the session's `state` with its context, limits, cost and what still runs, the open
37
+ questions, the process state, the CLI's commands and options, and `deliveryWaiting`, the
38
+ messages that wait in the Agent's queue, none stored or searchable. A saved message's
39
+ `content` holds its turn's parts, tokens and state, and one its owner took out of the queue
40
+ carries `removed: true`. `chatDraft.write` and `chatDraft.discard` keep what
41
+ the App Creator composes, `chatDraft.prepend(conversation, draft)` puts a returned
42
+ message ahead of it as it stands and `chatDraft.append(conversation, draft)` a text after it.
43
+ Sending it is a Provider Action that needs the Provider reachable and is never queued.
44
+ A new conversation's chat draft is keyed `new:<Agent
38
45
  identity>`: no conversation list removes it, a retired Agent's goes, and the first answer
39
46
  to `conversation.create({ agent_id, operation_id })` moves it to the created conversation,
40
47
  where `conversation.send(conversation)` sends it; a replay of that create moves nothing.
41
48
 
42
- Next: [Presentation State, binary files and the network](apps/runtime-files)
49
+ Next: [Conversation acts and the Chat's device state](apps/runtime-conversations)
@@ -0,0 +1,28 @@
1
+ # Conversation acts and the Chat's device state
2
+
3
+ The conversation acts beyond sending, and what the browser keeps for the Chat.
4
+
5
+ Each act takes the operation id its caller makes once and hands again on a retry, so
6
+ House runs it once. `conversation.takeOut(conversation, message, operation)` takes a
7
+ message that waits in the Agent's queue out. `conversation.decide(request, 'approve' |
8
+ 'decline', operation)` decides a waiting request, its `{ request, room, message? }` as the
9
+ conversation shows it. `conversation.rename(conversation, name, operation)` renames a
10
+ conversation, `conversation.option(conversation, option, value, operation)` sets a session
11
+ option and `conversation.retry(conversation, message, operation)` sends a refused message
12
+ again. A release that declares no conversations is refused each with `action-undeclared`
13
+ naming its act.
14
+
15
+ `conversation.pin(figures)` keeps the Chat's pinned figures, which every conversation's
16
+ `pins` shows, `conversation.openTurn(conversation, turn)` each chat's last opened turn,
17
+ which its row's `opened` shows beside `answered`, the turn its Agent answered last, and
18
+ `conversation.dismissSuggestion(conversation, suggestion)` each chat's suggested next
19
+ prompt the User dismissed, which that conversation's `dismissedSuggestion` shows, on this
20
+ browser for House and every App alike; none of it is sent to House. Without conversations
21
+ they read none and keep nothing.
22
+
23
+ `conversation.pageMetadata(appName, address)` answers the Page metadata block a message
24
+ carries after the User's text: the App's name, the page's address and, while the page
25
+ holds at most ten Local Queries open, each one's definition on its own line, never its
26
+ results.
27
+
28
+ Next: [Presentation State, binary files and the network](apps/runtime-files)
@@ -29,22 +29,24 @@ or remove one as a Document, its bytes following.
29
29
  - `<room-media room path width height alt>` draws an image, video or audio file of the
30
30
  Room. It reserves the box `width` and `height` set, in the file's own pixels, or a 16:9
31
31
  one, before any byte; asks for the file only as it nears the view; draws a file the
32
- browser keeps from its bytes, offline too, and reads and keeps an image; plays a video
33
- or audio file from the Provider's address loading only its metadata; asks again when a
34
- shown file's address lapses; asks again while the file cannot be shown yet, such as
32
+ browser keeps from its bytes, offline too, and reads and keeps an image; shows a video's
33
+ first frame with a play mark and plays it only in House's full-screen viewer, which a
34
+ press on it opens, and plays an audio file, loading only either's metadata from the
35
+ Provider's address; asks again when a shown file's address lapses; asks again while the
36
+ file cannot be shown yet, such as
35
37
  while the Room does not hold it or House did not answer, until House refuses it for
36
38
  good; and shows its children where the file cannot be read.
37
39
  - `binaryFile.read(room, path, revision?)` answers `{ kind: 'binary', stream, byteLength,
38
40
  mediaType }`, the bytes a `ReadableStream` of parts of at most a mebibyte, which the
39
41
  browser keeps for later reads, offline too.
40
42
 
41
- Rooms, Query, Search, Observe, Types, Room Draft, Save, and Reached never touch the
42
- network; History, a binary file's attach and download, a file shown or read that the
43
+ Rooms, Query, Observe, Types, Room Draft, Save, and Reached never touch the network;
44
+ Search, History, a binary file's attach and download, a file shown or read that the
43
45
  browser does not keep, and Call go to the Provider through the Adapter.
44
46
  Call takes the Action names the Adapter declares, any other answering `undeclared`. A Call
45
47
  result whose effect the Provider places in a Room carries `at`, that Room and Room
46
48
  Version: `reached(room, roomVersion)` answers whether the Room's confirmed state has
47
- reached it, refreshing the Room until it has, and `reached(room, roomVersion, path)`
49
+ reached it, which the Room's next changes bring, and `reached(room, roomVersion, path)`
48
50
  whether the held copy of that document was written later. A History revision names its
49
51
  author, `{ kind: 'user', id }` or `{ kind: 'inbox', id, name }`; History of a Path no
50
52
  document holds answers the removed document's revisions, newest first, with `deleted:
@@ -2,11 +2,12 @@
2
2
 
3
3
  How the MD Runtime API refuses and fails, and how App code reads the deployment facts and who uses it.
4
4
 
5
- Every refusal and failure carries `code` and `retryable`: each Call and History answer
6
- other than its result, a refused Save or Room Draft write, a returned Room Draft's reason,
7
- a Room's refusal, the Connection Refusal and every error a member rejects with, beside its
8
- message, a Provider refusal with the Provider's own `retryable`. Every code and value is
9
- open: handle one you do not know by its `code` and `retryable`. Only a tag telling which
5
+ A refusal or failure carries `code` and `retryable`: each Call and History answer other
6
+ than its result, a refused Save, a returned Room Draft's reason, a Room's refusal and every
7
+ error a member rejects with, beside its message, a Provider refusal with the Provider's own
8
+ `retryable`. The Connection Refusal carries a `code` and no `retryable`, and a Room Draft
9
+ write from an older revision answers `{ outcome: 'stale', current }`. Every code and value
10
+ is open: handle one you do not know by its `code`. Only a tag telling which
10
11
  fields a value carries, such as `kind`, is closed: keep a branch for one you do not know.
11
12
  A model with no usable types answers `types: null`.
12
13
 
@@ -17,3 +18,7 @@ learns it: the User the Provider signed in, `{ kind: 'user', id, name }` like a
17
18
  until the Provider first names one, and where it names none. It is kept
18
19
  with the Local Replicas, answers offline once known, and every port hears the next member
19
20
  named; signing out answers `null`, then ends the observation with the authorization.
21
+ `observe('authority-changes')` answers how many times House told the runtime that what its
22
+ User may see changed, a Room's members, a Share or an offer among them, and hears each next
23
+ one, never a reconnection, so a view that read such a fact through Call reads it again when
24
+ the count moves.
@@ -7,7 +7,7 @@ change it, build, and push. They are documentation, not enforcement.
7
7
 
8
8
  - [The MD Runtime API](apps/runtime-api)
9
9
  - [Local Query rules](apps/local-query)
10
- - [Local Search rules](apps/local-search)
10
+ - [Search rules](apps/search)
11
11
  - [Room Draft, Save, and outcome rules](apps/room-drafts)
12
12
  - [Content safety and launch promises](apps/content-safety)
13
13
  - [App code takes the client its host hands it and never constructs a Runtime](apps/client)
@@ -0,0 +1,21 @@
1
+ # Search rules
2
+
3
+ How `search` finds Documents by words through House, and how a page finds them offline.
4
+
5
+ `search({ text, rooms })` asks House's search, the one Agents use, once and online: there
6
+ is no observed search and the device keeps no full-text index. `rooms` names Room locators
7
+ and defaults to every Room the page binds; the search never leaves those Rooms, and finds
8
+ words in every Document there.
9
+
10
+ - **Results.** `{ kind: 'found', documents }`, ranked by House, at most 20 hits. A hit names
11
+ its `room` and `path`, and a text hit its first `line` and a short `snippet` of it. Read a
12
+ hit's Document with `query` naming its `paths`.
13
+ - **Offline.** Without a connection `search` answers `{ kind: 'offline' }`, and where no
14
+ House search is reached, `{ kind: 'undeclared' }`. Find Documents then with a
15
+ [Local Query](apps/local-query): by Path, name, field values and `text`, a phrase its text
16
+ contains. That filter ranks nothing.
17
+ - **Refusals.** House's refusal answers as `kind: 'rejected'` with its `code`, and a lost
18
+ answer as `transport-uncertainty`: say the search failed and keep what the page shows.
19
+ - **Conversations.** `search` finds no message. Inside one conversation
20
+ `conversation.read(conversation, { text })` answers its messages that contain a phrase,
21
+ in windows as any read of it.
@@ -2,9 +2,11 @@
2
2
 
3
3
  How to get an App's repository, build it and publish every change.
4
4
 
5
- - An App with an `a_` reference already exists, even with no release yet, as every App your User makes in the panel does. Clone its `.git` address, `<origin>/app/<app_ref>.git` or its `source_url` in `list_apps`, with `git clone -c 'credential.helper=!kit git-credential' -c user.name=<agent-git-name> -c user.email=<agent-git-email> <address>`, so Git signs in as you and can commit, in every later step too. Run `npm ci --ignore-scripts`, then publish with `npm run publish`, never with `--name`.
5
+ - An App with an `a_` reference already exists, even with no release yet, as every App your User makes in the panel does. Clone its `.git` address, `<origin>/app/<app_ref>.git` or its `source_url` in `apps/list`, with `git clone -c user.name=<agent-git-name> -c user.email=<agent-git-email> <address>`, so Git commits as you in every later step too. Run `npm ci --ignore-scripts`, then publish with `npm run publish`, never with `--name`.
6
+ - Git signs in as you with a credential your User makes for you on `<origin>/connections`, given as its password.
7
+ - When the Kit runs you, add `-c 'credential.helper=!kit git-credential'` to the clone instead, so the Kit signs Git in.
6
8
  - Only when no App exists yet, clone `<origin>/app/new.git` the same way: it gives mdui, a minimal App in plain TypeScript with its test and `npm run publish`. Run `npm ci --ignore-scripts`, then `npm run publish -- --name "<display name>"`, which creates the App and prints its address and its `.git` address. Then `git remote set-url origin <that .git address>`; every later `npm run publish` goes there, without `--name`.
7
9
  - Use any framework and build tool. `npm run build` leaves the whole release in `dist/`: the entry HTML, every file it loads, `app.json` and `schema.yaml`. The entry names files by relative paths (Vite: `base: './'`), carries no inline script and loads nothing from outside the release, so bundle fonts and libraries. A release holds at most <release-files> files and <release-size>.
8
10
  - Your User sees a change only once it is published, so an ask to change an App is an ask to publish it: end every change with a commit and `npm run publish`, which builds, pushes `main` and the build, and prints `published` or the reason House refused. A `git push` of `main` alone publishes nothing and says so. A refused push changes nothing and the previous release keeps running.
9
- - Without Git, zip the project folder after the build, without `node_modules` and `.env`, `upload` the ZIP to a Room and publish it with `publish_app_zip`.
10
- - Every page registers `bridge.cooperate` in its entry script before its first draw, as mdui's `main.ts` does, even a page that reads no Room: only then does a page your User has open take each release by itself, with no reload. A page that registers none keeps the release it opened on until it is opened again. A page that draws everything at once and has nothing to type or select registers `bridge.cooperate({ checkpoint() {}, persist() {}, capture: () => scrollY, restore(top) { scrollTo(0, Number(top)); }, ready: () => true, settle() {} })` after `const bridge = houseBridge()`, which keeps its scroll position. Every other page keeps its User's task through the release as [the example](apps/example-tasks) does: `checkpoint` waits until the page has drawn, `persist` until its Room Draft writes are done, failing while a field it shows was refused its last write so the release waits, `capture` answers the focused field with its cursor and selection, the scroll position and whatever else it holds outside the address, and `restore` puts them back once the page has drawn again; `node_modules/@agentshouse/app-bridge/docs/families.md` describes each member.
11
+ - Without Git, zip the project folder after the build, without `node_modules` and `.env`, `upload` the ZIP to a Room and publish it with `apps/publish-zip`.
12
+ - A page whose first draw is not yet the place it opened on, as one that draws its Room's documents once `observe` answers, registers `bridge.cooperate({ placed })` in its entry script before its first draw, where `placed` resolves once that place shows what it holds, as [the example](apps/example-tasks) does: House keeps its preparation surface over the page until then, and shows a page that registers none at its first draw. An open page keeps the release it loaded and runs the next one at its next load, so it needs no update code; `node_modules/@agentshouse/app-bridge/docs/families.md` describes each bridge member.
@@ -6,12 +6,11 @@ Before `npm run publish`:
6
6
 
7
7
  - `npm test` passes against the newest `@agentshouse/app-bridge` and `@agentshouse/mdruntime` (`npm install --ignore-scripts <name>@latest`), since every page gets House's newest runtime. Keep mdui's test: it runs the built page on `createMemoryAdapter` from `@agentshouse/mdruntime/memory` and `createHouseBridgeTestHost` from `@agentshouse/app-bridge/test-host`, with no House.
8
8
  - Every slot type is in `schema.yaml` exactly as in the bound Room's `settings/schema.yaml`.
9
- - The entry script registers `bridge.cooperate` before its first draw.
10
9
  - The page works 360 pixels wide, offline, and reloaded at a deep address.
11
10
 
12
11
  After it:
13
12
 
14
- - `list_apps` names the App's `published_release`, whose `revision` is the `main` commit it was built from; a clone, a fetch and `git ls-remote` see `main` alone.
15
- - Bind the Room once with `set_app_bindings`.
16
- - See it yourself: sign your own browser in with `create_sign_in_code`, then open the App's url.
17
- - Give your User its address. An open page that registers `bridge.cooperate` takes each release by itself; nothing asks them to update.
13
+ - `apps/list` names the App's `published_release`, whose `revision` is the `main` commit it was built from; a clone, a fetch and `git ls-remote` see `main` alone.
14
+ - Bind the Room once with `apps/bindings/set`.
15
+ - See it yourself: sign your own browser in with `sign-in-codes/create`, then open the App's url.
16
+ - Give your User its address. An open page keeps the release it loaded, and its next load made online runs the release you published; nothing asks them to update.
package/guide/index.md CHANGED
@@ -1,12 +1,12 @@
1
1
  # House
2
2
 
3
- Where House's guides and formats start: `open_guide` opens a page by its `path` or finds pages by `words`.
3
+ Where House's guides and formats start: `guide/open` opens a page by its `path` or finds pages by `words`.
4
4
 
5
5
  House keeps Markdown files in Rooms, which your User shares with other people and their agents.
6
6
 
7
- While your User's My Room, which `list_rooms` marks, holds no `wayfinding-map`, open [House Onboarding](skills/house-onboarding) first.
7
+ While your User owns no Room but the Private Room, as `rooms_list` shows, open [House Onboarding](skills/house-onboarding) first.
8
8
 
9
- - `apps/`, building an App over your User's Rooms: [Build an App](apps/build).
10
- - `reference/`, the formats House reads: [Read level](reference/read-level), [App manifest](reference/app-manifest), [Routine](reference/routine), [Schema](reference/schema) and [Triggers](reference/triggers).
11
- - `routines/`, the Routines House writes into every Private Room: [Work on ticket](routines/work-on-ticket).
9
+ - `apps/`, building an App over your User's Rooms: [Build an App](apps/build), and the functions House runs for it when a Trigger fires: [App functions](apps/functions).
10
+ - `reference/`, the formats House reads: [Access level](reference/access-level), [App manifest](reference/app-manifest), [Schema](reference/schema) and [Triggers](reference/triggers).
11
+ - `agent-functions/`, the Agent function an Agent takes a plan's tickets by, written for the plan's Room and naming that Agent as [Agent function](reference/agent-function) says: [Work on ticket](agent-functions/work-on-ticket).
12
12
  - `skills/`, House's Skills: [Prototype an App](skills/prototype-app).
@@ -3,8 +3,7 @@
3
3
  What a Room is for and where work goes, the skills' output included.
4
4
 
5
5
  A Room is where information people share is kept; it is not the place for
6
- private information. Work goes into the Room it belongs to, or My Room, which
7
- `list_rooms` marks, when none is named.
6
+ private information. Work goes into the Room it belongs to.
8
7
 
9
8
  Every House answer carries the `url` of what it names; send the User that link.
10
9
 
@@ -23,12 +22,14 @@ The skills are already set up; never run `setup-matt-pocock-skills`.
23
22
  - Rejected requests (triage): `out-of-scope/<concept>.md`
24
23
  - Implementation notes (implement-spec): `projects/<name>/notes/`
25
24
  - PR bodies (pr): `projects/<name>/prs/<branch>.md`
26
- - Wayfinding map: one `wayfinding-map` document, `projects/<name>/map.md`,
27
- and its tickets, `wayfinding-ticket` documents in order as
28
- `projects/<name>/map/NN-<slug>.md`: a ticket carries its `title`, its
29
- `map` (the map's path), its `kind` (its type) and `blocked_by` (its
30
- blockers); a claim sets `status: in-progress` and the
31
- `assignee`, and a resolution writes the Answer and sets `done`, or
25
+ - Wayfinding map: one `wayfinding-map` document, `projects/<name>/map.md`
26
+ with `type: wayfinding-map` in its frontmatter, and its tickets,
27
+ `wayfinding-ticket` documents in order as `projects/<name>/map/NN-<slug>.md`
28
+ with `type: wayfinding-ticket`, since House knows a map or a ticket only by
29
+ its `type`: a ticket carries its `name` as its `#` line, its
30
+ `map` (a link to the map), its `kind` (its type) and `blocked_by` (its
31
+ blockers); a claim sets its `status` to `in-progress` and its
32
+ `assignee`, and a resolution writes its Answer and sets `done`, or
32
33
  `out-of-scope`
33
34
  - Research: `research/<slug>.md`
34
35
  - Architecture reports (improve-codebase-architecture): `architecture/<slug>.html`
@@ -0,0 +1,9 @@
1
+ # Access level
2
+
3
+ How much of a Room a grant or a Share lets its holder do with its text, and where.
4
+
5
+ Access level, `level` on a Room grant or a Share’s Room item, each level including the one before it: `search`, the Search level, reaches the Room through `search`, `shell` and `inspect` alone, each reply at most <mcp-read-size> of the Room’s text, with no copy anywhere; `open`, the Open level, also opens the Room in browser Apps while the browser is online, and acts as `search` everywhere else; `keep`, the Keep level, also copies the Room to the devices that keep it, offline included, and is the one `export` needs. Apps need `open` or `keep`.
6
+
7
+ ```json
8
+ { "room_ref": "r_ab12.1", "level": "open", "operations": ["write"] }
9
+ ```
@@ -0,0 +1,15 @@
1
+ # Agent function
2
+
3
+ How an Agent function document in the Private Room is written, one for each Room it serves.
4
+
5
+ Agent function, `/rooms/private/rooms/<room-handle>/agent-functions/<name>.md`, serving the Room `<room-handle>` names: `description`; `input`, a text saying what to send, empty if nothing; `agent`, the identifier of the one of your User's current Agents it starts; and `afk`, `true` for a run nobody watches, off when absent, under which Kit answers every question and permission prompt of the conversation a request starts by itself, for that conversation's life. The body is the instruction, which never leaves the Private Room. Writing it needs your User's write in that Room. House writes its card, the description, input, Agent and `answer`, at `/rooms/<room-handle>/house/agent-functions/<name>.md`, where every member reads it, and refuses a name a card there already holds as `name_taken`. An Agent function a second Room needs is a copy under that Room's handle. While its document is not written in this form, every request for it is refused `agent_function_unreadable`. Anyone who writes that Room asks it with `agent-functions/send` naming the card, or names the `agent` with their own words, as the Standing answer there allows: the card's `answer`, or the Agent's for own words. `at_once`, the default, starts it; `ask_me` waits for the owner's approval; `off` refuses it, `agent_function_not_admitted` or `own_text_not_admitted`. Only the owner sets an answer, on the Room's House page; no field of this document holds one. The owner, their agents and their Private Room's Triggers start at once under every answer, a Trigger of another Room asks as its writers do, and `inspect` on a Room root names the Agents you may ask there with their answers. An Agent function request's input is text the Agent reads, and House checks no shape. Mail your conversation sends with `agent-functions/mail/send` and a request it sent reaches the conversation that request started at once where that Agent's own-words answer there is `at_once`; otherwise `agent-functions/mail/send` answers `waiting: true` and the mail waits for that Agent's owner, and a declined one comes back to you as House's message saying so. That conversation's mail always comes back to yours. A request's run is the first turn of the conversation it starts: during that turn the Agent names the document it wrote in the request's Room as the request's result with `agent-functions/result/set`, and the turn's end finishes the request. The conversation stays active until it is Done, which `conversations/mark-done` sets at the end of a turn and which nothing undoes, so mail reaches it after its run.
6
+
7
+ A Trigger's `message` action puts its `text`, a link to what matched and its files into the active conversation, one not Done, its Agent function started from that Room for what the Event is about: the chat of a customer's `chat-message`, the matched document or item, or the Trigger for a `cron` clock. Its Event shows `continued` with that `request`; with none, it starts the Agent function as a `agent_function` action does, `requested`. A conversation waiting for approval refuses it, `refused` with `conversation_waiting`. The Agent reads a customer's message as a customer's words, one from a Trigger of its owner's Private Room as the owner's instruction, and any other as what matched, never an instruction. A `agent_function` action starts a new request on every Event. A `done` action marks Done every active conversation a request of its Trigger's Room started for the Event's document, whoever owns its Agent, but one waiting for approval, which stays for its owner to approve or decline; its Event shows `marked` with their number, `conversations`, 0 when there are none, as on a `cron` clock, whose Event names no document.
8
+
9
+ ```markdown
10
+ - **Description**: Summarize a thread in five bullets.
11
+ - **Input**: The thread to summarize, as a ref or pasted text.
12
+ - **Agent**: 019a0000-0000-7000-8000-000000000001
13
+
14
+ Read the thread and write five bullets under summaries/.
15
+ ```
@@ -2,7 +2,7 @@
2
2
 
3
3
  What an App's `app.json` declares.
4
4
 
5
- App manifest, `app.json` at an App’s root: `entry`, its HTML page, and `room_slots`, each with a `name`, `access` `read` or `write`, and `types` from the `schema.yaml` beside it, written like a Room schema; `set_app_bindings` fills a slot with Rooms. Where needed it adds `external_origins`, the https origins its page may reach; `conversations: true` to read your User’s conversations; `local_search: true` to call `search`; `inboxes: true` to show and answer customer chats, naming `inbox-chat` and `inbox-message` in `room_slots`; `house_model`, the House model types it shows, which it reads from your User’s Private Room under `house/` without binding that Room; `house_acts`, the House acts it calls by their act names, such as `rooms/rename`, never one only a person takes or one that changes what an App reaches; and `theme_colour`, `#rrggbb`. A User who does not own the App is asked once to allow the House model types and House acts it declares, and again only for those a later release adds; a declined one reads nothing and is refused. [Build an App](apps/build) shows how its page works.
5
+ App manifest, `app.json` at an App’s root: `entry`, its HTML page, and `room_slots`, each with a `name`, `access` `read` or `write`, and `types` from the `schema.yaml` beside it, written like a Room schema; `apps/bindings/set` fills a slot with Rooms. Where needed it adds `external_origins`, the https origins its page may reach; `conversations: true` to read your User’s conversations; `inboxes: true` to show customer chats, naming `chat` and `chat-message` in `room_slots`, and answer them through `chats/reply`, since only House writes a chat's documents; `house_acts`, the House acts it calls by their act names, such as `rooms/list` for your User’s Rooms or `rooms/rename`, never one only a person takes or one that changes what an App reaches, except that a Self-hosted Building's App may declare its administrators' acts, `building/people/list`, `building/people/add`, `building/people/remove`, `building/administrators/name`, `building/administrators/take`, `building/factor/require`, `building/factor/stop-requiring` and `building/factor/reset`, which its page calls in an administrator's browser once it has asked them to confirm each; `functions`, each a `name` and the `entry` file a Trigger runs on House's servers ([App functions](apps/functions)); and `theme_colour`, `#rrggbb`. A User who does not own the App is asked nothing when it opens and once to allow each House act it declares, at the App’s first call of that act, which waits on the answer; a declined one is refused. Nobody is asked about an act they have no right to use, and it is refused them unasked, the App's owner included: the administrators' acts `not_building_administrator` to anyone who is no administrator, and `rooms/create`, the acts that change another member's access, `rooms/access/entries/set`, `rooms/access/schema-roles/set` and `rooms/access/revoke`, and the owner acts the Private Room never admits, `rooms/archive`, `rooms/unarchive`, `rooms/public/set`, `rooms/rename`, `rooms/space/set`, `rooms/delete` and `rooms/ownership/cancel`, `operation_denied` to anyone who manages no Room but their Private Room. [Build an App](apps/build) shows how its page works.
6
6
 
7
7
  ```json
8
8
  {
@@ -2,27 +2,38 @@
2
2
 
3
3
  How a Room's `settings/schema.yaml` declares its document types.
4
4
 
5
- Schema, `/rooms/<room>/settings/schema.yaml`: one JSON Schema in YAML. Each top-level key is an MD type holding the schema of its frontmatter; `$defs` holds shapes reused through `$ref: '#/$defs/<name>'`. An object setting neither `additionalProperties` nor `unevaluatedProperties` refuses other keys. House adds `reference` on a string at any depth, naming the types, or `attachment`, its value links to, and `cross_room: true` beside it, letting that be another Room's document of those types; a link or reference written as its `/rooms/<room>/` path is stored relative to the document; `sections`, a type's `##` headings, each `{ kind: text }` or `{ kind: list, items }`; and `member_document: true` on one type, whose documents name their member with `member`, a User Identifier from `list_members`. On a type, `create_roles` lists the Schema Roles that may create its documents and `delete_roles` those that may delete them, and changing a document's `type` needs both; on a field of a type's own `properties`, `change_roles` lists those that may change it, `initial_roles` those that may set it on a new document, and `transitions` the `{from, to, roles}` changes it may make, `null` standing for absent; `owner` and `member` are built in, `[]` allows nobody, and only someone who manages the Room's access changes them. `edit` creates or replaces the whole text, and may rewrite the documents a change breaks in the same call. A Room may use a Shared schema instead, which `use_shared_schema` chooses: its `settings/schema.yaml` is then a read-only copy of it.
5
+ Schema, `/rooms/<room>/settings/schema.yaml`: one JSON Schema in YAML. Each top-level key is an MD type holding the schema of its documents' values; `$defs` holds shapes reused through `$ref: '#/$defs/<name>'`. An object setting neither `additionalProperties` nor `unevaluatedProperties` refuses other keys. House adds `reference` on a string at any depth, naming the types, or `attachment`, its value links to, and `cross_room: true` beside it, letting that be another Room's document of those types; a link or reference written as its `/rooms/<room>/` path is stored relative to the document; `title` on a field, the label a document shows for it, its key when it has none; `contentMediaType: text/markdown` on a string, Markdown text under its own heading; and `member_document: true` on one type, whose documents name their member with `member`, a User Identifier from `rooms/members/list`. On a type, `create_roles` lists the Schema Roles that may create its documents and `delete_roles` those that may delete them, and changing a document's `type` needs both; on a field of a type's own `properties`, `change_roles` lists those that may change it, `initial_roles` those that may set it on a new document, and `transitions` the `{from, to, roles}` changes it may make, `null` standing for absent; `owner` and `member` are built in, `[]` allows nobody, and only someone who manages the Room's access changes them. `files_batch` creates or replaces the whole text, and may rewrite the documents a change breaks in the same call.
6
+
7
+ A Room in a Space shows its Space's schema at that path and keeps none of its own: its owner and a member who can write in the Space change it there, a rule keyword only someone who manages the Space, in an edit holding that change alone, checked against every document of every Room of the Space; a change that would break any document is refused naming it, so change that document in its own edit first. A Room taken out of its Space keeps the last version as its own.
8
+
9
+ A typed document keeps only `type`, `member`, `submitted` and House's other keys in its frontmatter and writes its values in its body: `name` as its `#` line; under it each short value as one `- **Label**: value` line, yes or no as `- [x] Label` or `- [ ] Label`, a reference as a link, a group of short values as an indented list under its label and a list of plain values as indented bullets; a Markdown text, or a value holding a line break, under its own `##` heading, one level deeper per level of nesting; rows of short values as a table whose column headings are labels; any other list as one heading per item, named by the item's `name`; and a value of no single JSON type as one fenced `json` block under its heading. Values come in any order and in any spelling GitHub Markdown reads alike. The list directly under the `#` line is the value list; a heading naming no field, the text around the values and everything after a `---` line is free text. A refusal names the line: `repeated-value` for a value written twice, `unknown-label` for a value line naming no field, `malformed-value` for a value its type's form does not read. Changing a `title` relabels every document of the type.
6
10
 
7
11
  ```yaml
8
12
  person:
9
13
  member_document: true
10
14
  properties:
11
- role: { type: string }
15
+ name: { type: string }
16
+ role: { type: string, title: Role }
12
17
  task:
13
18
  properties:
14
- title: { type: string }
15
- status: { enum: [open, done] }
16
- owner: { type: string, reference: person }
17
- required: [title]
18
- sections:
19
- Notes: { kind: text }
19
+ name: { type: string }
20
+ status: { enum: [open, done], title: Status }
21
+ owner: { type: string, reference: person, title: Owner }
22
+ notes: { type: string, contentMediaType: text/markdown, title: Notes }
23
+ required: [name]
20
24
  ```
21
25
 
22
26
  ```markdown
23
27
  ---
24
- type: person
25
- member: <User Identifier from list_members>
26
- role: Designer
28
+ type: task
27
29
  ---
30
+
31
+ # Ship the release
32
+
33
+ - **Status**: open
34
+ - **Owner**: [Ada](../people/ada.md)
35
+
36
+ ## Notes
37
+
38
+ What is left before Friday.
28
39
  ```
@@ -1,9 +1,15 @@
1
1
  # Triggers
2
2
 
3
- How a Trigger's `condition` and `actions` are written for `create_trigger` and `edit_trigger`.
3
+ How a Trigger's `condition` and `actions` are written for `triggers/create` and `triggers/edit`; House writes a Room's Triggers as read-only `house-trigger` documents at `house/triggers/<trigger>.md`.
4
4
 
5
- A Room's Triggers are its read-only `house-trigger` documents, one at `house/triggers/<trigger>.md` for each, which House writes as the Trigger's acts left it.
5
+ `condition`: When it fires: `on`, a `query` in the [Local Query](apps/local-query) language, at most one of `types`, `pathPrefix` or `paths` (one document, followed when it moves) and a `where`, naming a member by their member document's path, then the change tests. A task becoming ready: `{on: "documents", query: {types: ["task"], where: {"/status": "review"}}}`, firing as it starts to match, a new one only with `new_documents: true`. A field moving: `changes: {field: "/status", from: ["open"], to: ["done"]}`, or `from: "new"`, `to: "deleted"`; any edit `"text"`. `by: {"/door": "browser", "/user": "<User id>"}` tests who changed it and how; `moved_between_rooms: true` only a move between Rooms. Items: `{on: "items", query: {where: {"/address": "<address>", "/json/ref": "refs/heads/main"}}}`, also `/source`, `/delivery`, `/headers/<name>`. A clock is `{on: "clock", cron: "0 9 * * 1", time_zone: "Europe/Berlin"}`, or a day before each task is due: `{on: "clock", query: {types: ["task"], where: …}, date: "/due", days: -1, at: "09:00", time_zone: "Europe/Berlin"}`. In your Private Room alone, a notification to you: `{on: "notifications", query: {where: {"/kind": "share-offer"}}}` over its `house-notification` document; such a Trigger holds no `notify` action. A refusal names the test and what it takes.
6
6
 
7
- `condition`: When it fires, e.g. `{on: "documents", scope: {type: "task"}, mode: "starts_matching", new_documents: false, match: {all: [{path: "/fields/status", eq: "review"}, {path: "/members/assignee", eq: "<User id>"}]}}`; for a new document in a folder, `{on: "documents", scope: {folder: "/answers"}, mode: "starts_matching", new_documents: true, match: {all: []}}`; for any edit of one document, typed or plain, `{on: "documents", scope: {document: "/notes/plan.md"}, mode: "field_changes", field: "/text"}`; on documents, `moved_between_rooms: true` fires only on a document moved in from or out to another Room, `false` only on any other change; for arriving items, `{on: "items", address: "<push address>", match: {path: "/json/ref", eq: "refs/heads/main"}}`. A clock is `{on: "clock", cron: "0 9 * * 1", time_zone: "Europe/Berlin"}`, or a day before each task is due: `{on: "clock", scope: {type: "task"}, date: "/fields/due", days: -1, at: "09:00", time_zone: "Europe/Berlin", match: <test>}`.
7
+ A message into a conversation the Room's [Agent function request](reference/agent-function) started: `{on: "messages", query: {where: {"/sender": "requester"}}}`, testing `/sender`, `/agent_function` and `/path`, the request's document, never its words.
8
8
 
9
- `actions`: What it does; a `notify` action names whom it reaches, e.g. `{kind: "notify", title: "Ready to test", text: "A task waits.", to: {users: ["<User id>"], fields: ["/members/assignee"], roles: ["owner"]}}`, Users by id, the member a field of the matched document names, and every holder of a Schema Role; a `routine` action names a Routine Access.
9
+ `actions`: a `notify` action names whom it reaches, e.g. `{kind: "notify", title: "Ready", text: "A task waits.", to: {users: ["<User id>"], fields: ["/members/assignee"], roles: ["owner"]}}`, Users by id, the member a field of the matched document names, and every holder of a Schema Role; a `function` action names an App and one function its latest release declares, e.g. `{kind: "function", app: "a_…", function: "assign lead"}`, which you may add only for an App you hold with this Room in a write slot of your bindings; [App functions](apps/functions) says how House runs it. `triggers/fired/list` shows each run `ran` with its `release`, or `failed` (`function_failed`, its `error`), never run again, or `function_not_started` while House tries, `final` after its last try.
10
+
11
+ In your Private Room alone, a `function` action naming no `app` runs one of your Environment functions ([wizard](skills/wizard)), e.g. `{kind: "function", function: "nightly backup"}`; elsewhere, or for one you do not hold, it is refused `not_found`. Kit runs its script with no terminal, the Event as JSON in the file `HOUSE_INPUT` names, one Event at a time. `triggers/fired/list` shows each run `ran` or `failed` (`function_failed`, its `error`), never run again, with its `run`, `exit_code` and `output`; a Kit not connected at its turn reads `no_target` with `environment_offline`, never run later.
12
+
13
+ A Trigger acts on at most <trigger-events-per-hour> Events in each UTC hour, across its versions, skipped and failed ones not counted; `triggers/fired/list` shows the first past the number `missed: "skipped"` with `code: "cap_reached"`, which starts nothing, and none later that hour; the Trigger shows as failing. A Trigger whose own actions make what it fires on stops there, so narrow its condition.
14
+
15
+ `{kind: "agent_function", card: "<name>", payload: "<input>"}` starts an [Agent function](reference/agent-function) and `{kind: "message", card: "<name>", text: "<text>"}` messages it; no such card is refused `not_found`, a retired one `agent_function_retired`, and one whose document misses its type's form fails `agent_function_unreadable` for good. `{kind: "done"}` marks Done each active conversation the Room's Agent function requests started for the Event's document, `marked` with their number.
@@ -4,15 +4,16 @@ How to build a Site, an App at a public address anyone opens without signing in.
4
4
 
5
5
  Build it as [Build an App](apps/build) says, with what follows. Anything private is an App.
6
6
 
7
- - A Site starts with `create_site`: `name` is its address name, and the answer's `source_url` is its App's `.git` address to clone the same way.
8
- - A Site shows the Rooms it published, as `published` names them: creating it publishes its bound Rooms, a release keeps the published data, and later Room edits stay private until `publish_site_data`. A publication whose `state` is `preparing` replaces the shown one once its screenshot is taken; `list_sites` names each Site's newest publication and its `state`, and `publish_site_data` with nothing changed since answers that publication. `unpublish_site` stops serving a Site and keeps it; `republish_site` or `publish_site_data` serves it again.
9
- - Bind a Site's Rooms with `set_site_bindings`.
7
+ - A Site starts with `sites/create`: `name` is its address name, and the answer's `source_url` is its App's `.git` address to clone the same way. With `app_ref` it gives one of your User's Apps that address instead of making a new App: that App keeps its holders, each still opens it at its App address, and each release reaches them and the Site's visitors together. An App has one Site at most.
8
+ - `sites/delete` ends the address and keeps the App; `apps/delete` deletes the App and its Site.
9
+ - A Site shows the Rooms it published, as `published` names them: creating it publishes its bound Rooms, a release keeps the published data, and later Room edits stay private until `sites/publish`. A publication whose `state` is `preparing` replaces the shown one once its screenshot is taken; `sites/list` names each Site's newest publication and its `state`, and `sites/publish` with nothing changed since answers that publication. `sites/unpublish` stops serving a Site and keeps it; `sites/republish` or `sites/publish` serves it again.
10
+ - Bind a Site's Rooms with `sites/bindings/set`.
10
11
  - A Site is public: anyone opens it, nobody signs in, and every visitor reads its bound Rooms, which must be your User's own and never the Private Room.
11
12
  - Everything it shows lives as documents in its Room; put its demo data there, never in code.
12
13
  - A visitor's edits stay in their browser and never reach House: write them with `save` as an App does.
13
- - To receive messages from visitors, name an Intake Room with `set_site_intake_room` and send each with `runtime.call('submit', { content })`, online only.
14
- - `describe_site` sets the title and description search engines show.
15
- - With `google_analytics_id` set by `describe_site`, House measures a visitor only after they accept. While `bridge.onStatus` reports `analytics.measures`, ask them on the Site unless `analytics.choice` holds their answer, report it with `bridge.analyticsConsent('accept')` or `bridge.analyticsConsent('decline')`, and keep a way on every page to decline later, which reloads the page unmeasured.
14
+ - To receive messages from visitors, name an Intake Room with `sites/intake-room/set` and send each with `runtime.call('sites/submissions/create', { content })`, online only. `content` is one Markdown document the Intake Room's `settings/schema.yaml` accepts, and House adds its `site` and `submitted` fields. The call answers `{ kind: 'action', result: { submitted: true } }` once House stored it. Anything else stored nothing: `{ kind: 'rejected', code }` says why, such as `bot_check_failed` for a browser that failed the bot check, as automated test browsers do, `site_intake_room_absent`, `invalid_documents` with the `path`, `rule` and `field` it broke, `submission_reserved_key`, `submission_too_large`, `limit_reached` or `cap_reached`. So thank the visitor only for `submitted`, and otherwise show that nothing was sent.
15
+ - `sites/describe` sets the title and description search engines show.
16
+ - With `google_analytics_id` set by `sites/describe`, House measures a visitor only after they accept. While `bridge.onStatus` reports `analytics.measures`, ask them on the Site unless `analytics.choice` holds their answer, report it with `bridge.analyticsConsent('accept')` or `bridge.analyticsConsent('decline')`, and keep a way on every page to decline later, which reloads the page unmeasured.
16
17
  - See it yourself: open its url, which needs no sign-in.
17
18
 
18
19
  House serves each route as HTML by the [Entry Data Contract](sites/entry-data-contract), and [The App runtime on a Site](sites/runtime) says what the runtime does differently there.
@@ -2,7 +2,7 @@
2
2
 
3
3
  How a Site App's `entry_data` has House serve each route as HTML from Rooms.
4
4
 
5
- Entry Data Contract, `entry_data` in a Site App’s `app.json`: House serves each route as HTML from your Rooms before the App starts, running none of your code. Each of `routes` has a `path` (`/`, `/posts/:slug`), optional `query` (functional `?name` parameters with defaults), `queries` (Local Query objects with `types` and a `pathPrefix` at each scope, no `rooms`; `{"$param": "slug"}` takes an argument, `"as": "integer"` converts it; `boundQuery` from `@agentshouse/mdruntime/entry` fills the same query in your page), `interaction` (the queries its first interaction needs), `title`, `description` and `body`. A body node is text, `{text: v}`, `{markdown: v}` of a document, `{tag, attrs, children}`, `{each: v, as, children}` or `{if: v, then, else}`; a value `v` is a literal, `{param}`, `{at, pointer}` into a query result or `each` item, `{join: [v]}`, `{count: v}` or `{stem: v}`. An `img`, a document's images among them, loads lazily in the box its `width` and `height` name, 16:9 without them. `styles` lists release CSS files. A route that fails starts the App as usual, and the Site document names why.
5
+ Entry Data Contract, `entry_data` in a Site App’s `app.json`: House serves each route as HTML from your Rooms before the App starts, running none of your code. Each of `routes` has a `path` (`/`, `/posts/:slug`), optional `query` (functional `?name` parameters with defaults), `queries` (Local Query objects with `types` and a `pathPrefix` at each scope, no `rooms` or `fileIds`; `{"$param": "slug"}` takes an argument, `"as": "integer"` converts it; `boundQuery` from `@agentshouse/mdruntime/entry` fills the same query in your page), `interaction` (the queries its first interaction needs), `title`, `description` and `body`. A body node is text, `{text: v}`, `{markdown: v}` of a document, `{tag, attrs, children}`, `{each: v, as, children}` or `{if: v, then, else}`; a value `v` is a literal, `{param}`, `{at, pointer}` into a query result or `each` item, `{join: [v]}`, `{count: v}` or `{stem: v}`. An `img`, a document's images among them, loads lazily in the box its `width` and `height` name, 16:9 without them. `styles` lists release CSS files. A route that fails starts the App as usual, and the Site document names why.
6
6
 
7
7
  ```json
8
8
  {
@@ -1,6 +1,6 @@
1
1
  # The App runtime on a Site
2
2
 
3
- What the App runtime does differently on a Site's page.
3
+ What the App runtime does differently on a Site's page. Everything else is as in an App, [Local first](apps/local-first) included: House serves a Site's first screen as HTML from its [Entry Data Contract](sites/entry-data-contract) before the App starts, so a Site's page draws no loading state either.
4
4
 
5
5
  A History revision or a Document's `change` written by a Site gives its `author` as `{ kind: 'site', id, name }`. `observe('member')` answers `null` on a Site, and a Document's `change` is `null` there, since the Provider delivers no time.
6
6
 
@@ -20,6 +20,6 @@ Claim the build ticket. Starting from the User's decision, run `grill-with-docs`
20
20
  Publish into the App the prototype made, never a new one, so its address and bindings stay:
21
21
 
22
22
  - where you run Git, from a clone of its `.git` address, with `npm run publish` and never `--name`, as [Start an App](apps/start) says;
23
- - otherwise zip the project folder after its build, `dist/` included and `.env` and `node_modules/` left out, `upload` the ZIP to the Room and publish it with `publish_app_zip`, naming the App by the reference in the map's Notes.
23
+ - otherwise zip the project folder after its build, `dist/` included and `.env` and `node_modules/` left out, `upload` the ZIP to the Room and publish it with `apps/publish-zip`, naming the App by the reference in the map's Notes.
24
24
 
25
25
  Resolve the build ticket with the App's address and give the User the address.
@@ -1,29 +1,25 @@
1
1
  ---
2
2
  name: house-onboarding
3
- description: Find out what a new User wants from House and keep their plan as a Wayfinding map and tickets in My Room; run it while My Room holds no `wayfinding-map`.
3
+ description: Find out what a new User wants from House and keep their plan as a Wayfinding map and tickets in a Room you make for it; run it while your User owns no Room but the Private Room.
4
4
  ---
5
5
 
6
6
  # House Onboarding
7
7
 
8
- Onboard your User: find out what they want and keep the plan as a map and tickets in My Room.
8
+ Onboard your User: find out what they want and keep the plan as a map and tickets in a Room of its own.
9
9
 
10
10
  Run `wayfinder` to chart the map; this page adds only what is House's. `wayfinder` is also a Command of its name for a client that has not installed it, and the Owner rules, `/rooms/private/owner-rules.md`, say how a map and its tickets are written.
11
11
 
12
12
  ## Open
13
13
 
14
- - When `list_rooms` lists a Room your User does not own and its access is not `public`, they were invited to it: first tell them which Room it is, who invited them and what they may do there. `list_members` names its owner, and `list_rooms` their access.
14
+ - When `rooms_list` lists a Room your User does not own and its access is not `public`, they were invited to it: first tell them which Room it is, who invited them and what they may do there. `rooms/members/list` names its owner, and `rooms_list` their access.
15
15
  - Then ask what they want.
16
16
 
17
17
  ## Keep the plan
18
18
 
19
- - Keep the map as one `wayfinding-map` and its tickets as `wayfinding-ticket` documents in My Room, which `list_rooms` marks with `my_room: true`. Chart the map even when the way looks clear: My Room's map is how House knows onboarding ran.
19
+ - Make the plan's App and Room with one `templates/use` of the `plan` Template, at the address `templates/list` answers for it, each named for what your User wants: the App shows the map and its tickets.
20
+ - Keep the map as one `wayfinding-map` and its tickets as `wayfinding-ticket` documents in that Room, each declaring `type: wayfinding-map` or `type: wayfinding-ticket` in its frontmatter: a field named for the type makes no map. Chart the map even when the way looks clear.
20
21
  - Keep decisions about the account, billing, runtime or credentials in the Private Room, `/rooms/private`.
21
22
  - Make the App for your User's goal a ticket.
22
-
23
- ## My App
24
-
25
- My App, `<origin>/app/my`, is your User's own App, and House's default My App shows the map and its tickets.
26
-
27
- - When you can build and test code, build My App as [Build an App](apps/build) says and publish it into the App `list_apps` names `My App`. Keep its slot `rooms`, which holds your User's Rooms, so its binding stays.
28
- - Otherwise leave House's default.
29
- - When you cannot hand House a file, give your User the App's ZIP to upload to My App in the panel.
23
+ - Write the pair that starts an Agent on a ticket a person sets `status: in-progress` with it as its assignee: for yourself when you run as one of your User's Agents, and for another of them when your User asks, each named by the id `agents/list` answers for it.
24
+ - The pair's Agent function is the text of [Work on ticket](agent-functions/work-on-ticket) with a `- **Agent**: <agent id>` line added to its values, written to `/rooms/private/rooms/<room-handle>/agent-functions/work-on-ticket.md` for the plan's Room, or to `work-on-ticket-<n>.md`, `<n>` the next free number from 2, when that name is taken.
25
+ - Its Trigger is made by `triggers/create` in the plan's Room, described "Start <agent name> on a ticket a person sets in progress for it", with the one action `{"kind": "agent_function", "card": "<that file's name without .md>"}` and the condition `{"on": "documents", "query": {"types": ["wayfinding-ticket"], "where": {"/assignee/agent": "<agent id>"}}, "changes": {"field": "/status", "to": ["in-progress"]}, "by": {"/door": "browser"}}`, the id `agents/list` answers for that Agent.
@@ -11,29 +11,29 @@ Keep everything where the Owner rules, `/rooms/private/owner-rules.md`, say. Eac
11
11
 
12
12
  ## 1. Open the map
13
13
 
14
- In the Room the User names, or My Room when they name none, which `list_rooms` marks, chart a map as `wayfinder` does, but skip its grilling: the way is set here.
14
+ In the Room the work belongs to, the one the User names or else one you make with `rooms/create`, chart a map as `wayfinder` does, but skip its grilling: the way is set here.
15
15
 
16
16
  - **Destination:** the App the User asked for, built and published.
17
17
  - **Notes:** this map's tickets do the work they name; the App's address and `a_` reference once the prototype is published.
18
18
  - **Tickets**, each blocked by the one before:
19
- 1. Prototype, `kind: task`: build a prototype and publish it as the App's first release.
20
- 2. Design decision, `kind: grilling`: the User's decision on the prototype's design.
19
+ 1. Prototype, `kind: task`: three design variants in one prototype, published as the App's first release.
20
+ 2. Design decision, `kind: grilling`: the variant the User picks, with their edits.
21
21
  3. Build, `kind: task`: run [`build-app`](skills/build-app).
22
22
 
23
23
  ## 2. Publish the prototype
24
24
 
25
- Claim the first ticket. Build the prototype as [Build an App](apps/build) says: its pages, their look and their flow, just enough for the User to judge the design.
25
+ Claim the first ticket. Build three variants as [Build an App](apps/build) says, each a distinct visual direction (type, colour, layout, tone), not three shades of one. Each draws every main page with real-looking content, and a switcher on the page moves between them. Build only pages, their look and their flow: no tests, no data model, no reviews. Before publishing, look at each variant at phone and desktop width and redo any that looks generic or broken.
26
26
 
27
27
  Publish it as a new App, which creates it:
28
28
 
29
29
  - where you run Git, with `npm run publish -- --name "<display name>"`;
30
- - otherwise zip the project folder after its build, `dist/` included and `.env` and `node_modules/` left out, `upload` the ZIP to the Room and publish it with `publish_app_zip`, naming the display name and no App.
30
+ - otherwise zip the project folder after its build, `dist/` included and `.env` and `node_modules/` left out, `upload` the ZIP to the Room and publish it with `apps/publish-zip`, naming the display name and no App.
31
31
 
32
32
  Write the App's address and reference into the map's Notes, resolve the ticket with them, and give the User the address.
33
33
 
34
34
  ## 3. Record the User's decision
35
35
 
36
- Claim the second ticket and ask the User to open the prototype and decide on its design: keep it, or what to change. A change they ask for before deciding is a new prototype release in the same App: `npm run publish` without `--name`, or `publish_app_zip` naming the App. Resolve the ticket with their decision in their words; never decide for them.
36
+ Claim the second ticket and ask the User to open the prototype and pick one variant, naming any edits or pieces to take from the others. Publish the chosen variant with those edits, without the switcher, as the next release of the same App: `npm run publish` without `--name`, or `apps/publish-zip` naming the App. Repeat with each round of edits until the User keeps it. Resolve the ticket with their decision in their words; never decide for them.
37
37
 
38
38
  ## 4. Build
39
39
 
@@ -9,7 +9,13 @@ Write one bash script for the steps only the User can do: it says what to open a
9
9
 
10
10
  ## As a Web Wizard
11
11
 
12
- Create it with `create_web_wizard`, for the Environment you work through or another of the User's that they name (`list_environments`). Give the User the link it answers: they read the whole script there, and nothing runs until they press Run. Its output and what they type never reach you. When they say they are done, read the document at the path it answered, which says how it ended, and go on only once its state is finished with exit code 0.
12
+ Create it with `wizards/create`, for the Environment you work through or another of the User's that they name (`environments/list`). Give the User the link it answers: they read the whole script there, and nothing runs until they press Run. Its output and what they type never reach you. When they say they are done, read the document at the path it answered, which says how it ended, and go on only once its state is finished with exit code 0.
13
+
14
+ ## As a function
15
+
16
+ For a script the User may want to keep, propose a name when you create the Web Wizard. Only the User keeps a script: they tick Keep as a function on its page, may change the name, and press Keep, which runs nothing and makes the script one of their Environment functions. The document then reads kept with the function's name; keeping under a name they already use replaces that function's script. `inspect` on the Environment lists its functions, and `environments/functions/delete` deletes one. On a function's page the User can also press Run now, which runs it in a terminal they type into, so a kept script may ask them for a password there; nothing of that run reaches you.
17
+
18
+ `environments/functions/run` runs a function on its Environment, whose Kit must be connected, and answers when the run ends. Your input reaches the script as JSON in the file `HOUSE_INPUT` names. The run has no terminal, so a script that asks for typing fails at once; such a step stays a Web Wizard. The answer's ending is exited with its exit_code, timed_out at the run's time limit, not_started with its cause, or interrupted when House lost the run; output is the end of what the script printed, cut when its start was dropped.
13
19
 
14
20
  ## As a script they run
15
21