@agentshouse/skills 0.1.0-ca3affce380c3 → 0.1.0-ca6f30223cbaf

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.
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "lines": [
3
3
  "From House:",
4
- "Work with House through the `house` CLI: run `house --help`, and `house open_guide` opens `index`, the root page of House's guides and formats.",
5
- "To give the User a file, upload it with `house upload` and link it; for an App, a Site or a website, follow the Guide from `index` with `house open_guide`. Never start a server.",
4
+ "Work with House through the `house` CLI: run `house --help`, and `house run_command '{\"command\":\"guide/open\"}'` opens `index`, the root page of House's guides and formats.",
5
+ "To give the User a file, upload it with `house upload` and link it; for an App, a Site or a website, follow the Guide from `index` with `guide/open`. Never start a server.",
6
6
  "Optional per-Room instructions: `/rooms/private/rooms/<handle>/AGENTS.md`.",
7
- "For another Agent's help, `send_agent_function_request` naming one of the Room's Agent function cards under `house/agent-functions/`, or the Agent and what you ask, as its Trust level there allows; its mail comes back into this conversation."
7
+ "For another Agent's help, `agent-functions/send` naming one of the Room's Agent function cards under `house/agent-functions/`, or the Agent and what you ask, as its Trust level there allows; its mail comes back into this conversation."
8
8
  ]
9
9
  }
@@ -2,7 +2,7 @@
2
2
 
3
3
  How to build an App over your User's Rooms and publish it, one page per step.
4
4
 
5
- An App is a web page over your User's Rooms, for your User and whom they share it with (`create_share`). House serves the built files and gives the page the App runtime, which holds every bound Room in the browser and syncs it with House. There is no server, backend or House API of yours to call.
5
+ An App is a web page over your User's Rooms, for your User and whom they share it with (`shares/create`). House serves the built files and gives the page the App runtime, which holds every bound Room in the browser and syncs it with House. There is no server, backend or House API of yours to call.
6
6
 
7
7
  - [Start an App](apps/start)
8
8
  - [An App's data](apps/data)
@@ -10,9 +10,9 @@ images and other resources only from origins the Provider's policy allows. An ag
10
10
  never read the authorization, load code from a Room, call the Provider directly, or rebase
11
11
  a refused Change Batch.
12
12
 
13
- MD UI uses semantic HTML, is fully operable from a keyboard with visible focus and
14
- labelled controls, and lays out from a 360 pixel wide viewport to a desktop. Its strings
15
- are English only, dates and numbers follow the browser locale, and content is never
16
- translated. Light and dark themes come from CSS custom properties, defaulting to the
13
+ MD UI uses semantic HTML, is fully operable from a keyboard with labelled controls and
14
+ the browser's own focus mark, and lays out from a 360 pixel wide viewport to a desktop.
15
+ Its strings are English only, dates and numbers follow the browser locale, and content is
16
+ never translated. Light and dark themes come from CSS custom properties, defaulting to the
17
17
  browser's preference and respecting an App's override. What an agent adds carries none of
18
18
  these promises by itself. Data lives only in the App Creator's browser and the Provider.
@@ -5,10 +5,11 @@ How an App keeps what it shows as typed documents in the Rooms bound to it.
5
5
  - Design the Room schema first. Each thing the App shows is one Markdown document in a Room: its frontmatter `type` names its MD type, the rest of its frontmatter holds the fields, and long text goes in `##` sections. `schema.yaml` declares the types ([Schema](reference/schema)).
6
6
  - Keep each type in its own folder, such as `tasks/`, and read it by `pathPrefix`: a query naming `types` fails with `unknown-type` while no bound Room declares them.
7
7
  - Link types with `reference` fields instead of copying values; a query follows them with `hop` and `backlinks`.
8
- - `app.json` `room_slots` names the Rooms the App needs, each with `access` `read` or `write` and the `types` it uses ([App manifest](reference/app-manifest)). Bind Rooms with `set_app_bindings`; App code cannot bind and reaches only bound Rooms, so it opens `bridge.ceremony('/bind/<app_ref>?slot=<name>')`, the House page where your User binds Rooms, which returns to the App.
9
- - A bound Room must hold each slot type identically in its own `settings/schema.yaml`, beside any other types, or its binding warns the User who bound it and House tells the App's owner once for that release and slot. Write it with `edit` before binding; `create_room` makes a new Room.
8
+ - `app.json` `room_slots` names the Rooms the App needs, each with `access` `read` or `write` and the `types` it uses ([App manifest](reference/app-manifest)). Bind Rooms with `apps/bindings/set`; App code cannot bind and reaches only bound Rooms, so it opens `bridge.ceremony('/bind/<app_ref>?slot=<name>')`, the House page where your User binds Rooms, which returns to the App.
9
+ - A bound Room must hold each slot type identically in its own `settings/schema.yaml`, beside any other types, or its binding warns the User who bound it, and `apps/bindings/list` names that release and slot in its `mismatch` line, to the App's owner too. Write it with `files_batch` before binding; `rooms/create` makes a new Room.
10
+ - A slot may hold a Space instead (`apps/bindings/set` with `space_ref`): every Room of it your User holds, now and later. An App its owner puts into a Space (`apps/space/set`) uses that Space's schema instead of its own `schema.yaml`, and every member of the Space uses it, each slot holding the Space's Rooms.
10
11
  - Read an existing Room's `settings/schema.yaml` before inventing types. Two Apps over one schema are two interfaces over the same data, and your User's agents read and write those documents too.
11
- - House's own facts, such as your User's Rooms and the Space each is in, come from House acts: name each in `app.json` `house_acts` and call it with `runtime.call('<act>', input)`, such as `runtime.call('rooms/read', {})`. A call needs a connection, so offline show what the bound Rooms hold. A slot holding the Private Room brings its Triggers and none of the other documents House writes under its `house/`.
12
+ - House's own facts, such as your User's Rooms and the Space each is in, come from House acts: name each in `app.json` `house_acts` and call it with `runtime.call('<act>', input)`, such as `runtime.call('rooms/list', {})`. A call needs a connection, so offline show what the bound Rooms hold. A slot holding the Private Room brings its Triggers and none of the other documents House writes under its `house/`.
12
13
  - `shares/create` lets a person into Rooms and Apps: its answer's `added` is `true` when their _Who can add me_ setting admits your User, so they are in at once, and `false` when the Share waits for their Accept.
13
- - What no browser can do, such as acting when documents change or at a set time, is a Trigger (`create_trigger`) that notifies or runs one of the App's [functions](apps/functions) on House's servers; what it writes reaches the App at once.
14
+ - What no browser can do, such as acting when documents change or at a set time, is a Trigger (`triggers/create`) that notifies or runs one of the App's [functions](apps/functions) on House's servers; what it writes reaches the App at once.
14
15
  - A Trigger may also start an [Agent function](reference/agent-function) on an Agent of your User.
@@ -2,13 +2,12 @@
2
2
 
3
3
  How a function hands each new lead to the manager on shift with the fewest leads since their shift began, records its decision and calls the CRM.
4
4
 
5
- A CRM posts each new lead to the Room's push address (`create_push_address`) as `{"event": "lead.created", "card": {"id": 101}}`. The Room holds three types: `staff/<key>.md` with `manager_id`, the manager's id at the CRM; `shifts/<key>.md` with `staff`, the key, and `starts` and `ends` as ISO instants; and `decisions/<card>.md` with `card`, `staff` and `decided_at`. The App's `external_origins` lists the CRM's origin, the Room holds a Service key for it, and a Trigger runs the function for each lead:
5
+ A CRM posts each new lead to the Room's push address (`capture/push-addresses/create`) as `{"event": "lead.created", "card": {"id": 101}}`. The Room holds three types: `staff/<key>.md` with `manager_id`, the manager's id at the CRM; `shifts/<key>.md` with `staff`, the key, and `starts` and `ends` as ISO instants; and `decisions/<card>.md` with `card`, `staff` and `decided_at`. The App's `external_origins` lists the CRM's origin, the Room holds a Service key for it, and a Trigger runs the function for each lead:
6
6
 
7
7
  ```json
8
8
  {
9
9
  "on": "items",
10
- "address": "<push address>",
11
- "match": { "path": "/json/event", "eq": "lead.created" }
10
+ "query": { "where": { "/address": "<push address>", "/json/event": "lead.created" } }
12
11
  }
13
12
  ```
14
13
 
@@ -12,7 +12,7 @@ task:
12
12
  required: [title, done]
13
13
  ```
14
14
 
15
- `app.json`, then `set_app_bindings` with slot `tasks`:
15
+ `app.json`, then `apps/bindings/set` with slot `tasks`:
16
16
 
17
17
  ```json
18
18
  { "entry": "index.html", "room_slots": [{ "name": "tasks", "access": "write", "types": ["task"] }] }
@@ -5,9 +5,9 @@ How an App declares a function that House runs on its servers when a Trigger fir
5
5
  - **Declare.** `app.json` lists `functions`, each `{"name": "assign lead", "entry": "functions/assign.js"}` ([App manifest](reference/app-manifest)). The entry is one ES module whose default export is the function and which imports nothing, so your build bundles each function, with all it imports, into `dist/`, such as `esbuild src/assign.ts --bundle --format=esm --outfile=dist/functions/assign.js`. A publish is refused whole for an entry that is missing, imports, has no default export or is over <function-size>, for a name used twice, and for more than <release-functions> functions.
6
6
  - **Run.** A Trigger's `function` action names the App and one of its functions ([Triggers](reference/triggers)). House runs the App's latest release when the Event's turn comes, one Event of a Trigger after another, so a run reads what the run before it wrote. Runs share a fixed number of slots on House's servers, and a run waits, its action `waiting`, until one is free.
7
7
  - **The event.** `export default async (event, house) => {}` receives `kind`, the condition's `on`, with `room`, `trigger`, `id`, `moment` and what matched: `path` and `reference`, a document change's `transition`, an arriving item's `item` with its `headers` and raw `body` text, a dated document's `document`, a delivered notification's `notification`, the facts of its web document, or a message's `message`, its `sender` and its request's `agent_function`, never its words, with the document that request was started for as `path` and `reference`. `Date` reads `moment`. The return value is ignored, so write what you keep into the Room.
8
- - **The App API.** `house` is the page's App API over the Trigger's Room alone: `query(q)` ([Local Query](apps/local-query)), which reads only the documents of the `types`, folders (`folder`, `pathPrefix`) and `paths` it names and answers over them alone, so the rest of a large Room is never read: name the `types` or `pathPrefix` of its `hop` and `backlinks` too, and select its parts, since a query or `hop` or `backlinks` naming none, or selecting `backlinks` or `'all'`, is refused `invalid-query`, `saveParts(room, parts)`, `call(name, input)` for the Room acts, each by its House act name, such as `records/read` and `rooms/members`, and `callExternal(request)`. `query` and `callExternal` reject a refusal with its `code` for the function to catch, while `call` answers it as a result whose `kind` is `rejected` and `saveParts` as `outcome: 'refused'`, as on the page, so check what they answer. Its writes are the App's, by `App <App> (function <function>)`, fire Triggers, its own included, and count against the Room owner's Write limit.
8
+ - **The App API.** `house` is the page's App API over the Trigger's Room alone: `query(q)` ([Local Query](apps/local-query)), which reads only the documents of the `types`, folders (`folder`, `pathPrefix`) and `paths` it names and answers over them alone, so the rest of a large Room is never read: name the `types` or `pathPrefix` of its `hop` and `backlinks` too, and select its parts, since a query or `hop` or `backlinks` naming none, or selecting `backlinks` or `'all'`, is refused `invalid-query`, `saveParts(room, parts)`, `call(name, input)` for the Room acts, each by its House act name, such as `records/list` and `rooms/members/list`, and `callExternal(request)`. `query` and `callExternal` reject a refusal with its `code` for the function to catch, while `call` answers it as a result whose `kind` is `rejected` and `saveParts` as `outcome: 'refused'`, as on the page, so check what they answer. Its writes are the App's, by `App <App> (function <function>)`, fire Triggers, its own included, and count against the Room owner's Write limit.
9
9
  - **Reach.** A run holds no `fetch`, timer, file, `console` or `Intl`: keep times as ISO instants, or convert a local time by its UTC offset yourself. `callExternal` takes the request `bridge.callExternal` takes and is the one way out, to an origin the release's `external_origins` lists; naming its Room, `room_ref: event.room`, carries that Room's Service key, which the function never sees, or is refused `service_key_not_found` naming the `origin`. Its calls count against the Room owner's `external_calls` limit.
10
10
  - **Never repeated.** A run that started is never run again, even when it failed after a call reached the service. Send `event.id` as the service's idempotency key where it takes one, and name what you write by what the event carries, so a second delivery of the same thing finds it.
11
- - **Failure and limits.** A throw settles the run `failed` with `function_failed` and its text, which `list_trigger_events` shows and the panel shows the Room's owner, with no notification; the next Event still runs. A run ends `failed` at <function-time>, at <function-memory> or past <function-calls> external calls: `time_cap_reached`, `memory_cap_reached` or `external_call_cap_reached`.
11
+ - **Failure and limits.** A throw settles the run `failed` with `function_failed` and its text, which `triggers/fired/list` shows and the panel shows the Room's owner, with no notification; the next Event still runs. A run ends `failed` at <function-time>, at <function-memory> or past <function-calls> external calls: `time_cap_reached`, `memory_cap_reached` or `external_call_cap_reached`.
12
12
 
13
13
  Next: [Example: assign a lead](apps/example-function)
@@ -13,5 +13,5 @@ How an App reads and writes its Rooms on the device, offline too.
13
13
  - Offline, all of this works and saves wait; `bridge.onStatus` reports `offline`: say so quietly.
14
14
  - A Room your User holds at the Open level locks once the browser has been offline 2 minutes, and from the moment it opens until House confirms the access. While it is locked, `rooms` lists it `locked: true`, a query that does not name it leaves it out, one naming it answers `{ pending }` with `awaits: 'unlock'`, and every other read and write naming it, `save` included, answers the code `room-locked` and keeps nothing. Draw it locked until it unlocks and keep what the User types in the page; what was saved before stays and is sent then.
15
15
  - An outside service is reached only at the origins `app.json` lists in `external_origins`, directly or through `bridge.callExternal`, sent by House's server. A call that names a Room bound to the App in a `write` slot with `room_ref` carries that Room's Service key for the origin, which the page never sees; any other call carries no key. A call through a Room that holds no key for the origin is refused `service_key_not_found` naming the `origin`: tell the person that the Room's owner or a manager enters the key under Service keys in the Room's Info, since no App opens that page.
16
- - The page's own storage is a disposable cache, the Room the only durable home of the App's data; handle any code or value you do not know through `code` and `retryable`, which every refusal and failure carries.
16
+ - The page's own storage is a disposable cache, the Room the only durable home of the App's data; handle any code or value you do not know by its `code` ([Refusals](apps/runtime-refusals)).
17
17
  - React: `useObserve` and `useSave` from `@agentshouse/mdruntime/react`. react-admin and Refine: the data providers of `@agentshouse/mdruntime-families`. The whole client: [The App runtime](apps/runtime).
@@ -1,13 +1,7 @@
1
1
  # Local Query changes, order and results
2
2
 
3
- How a Local Query answers text it does not hold and each change, orders, groups and pages its result, and fails.
3
+ How a Local Query answers each change, orders, groups and pages its result, and fails.
4
4
 
5
- - **Held text.** The device holds every Document's type, fields and links, and the text of
6
- each one up to House's device text bound and of each larger one read on it. A Document whose
7
- text it does not hold answers `textHeld: false`, and no selected `markdown`, `sections` or
8
- `preamble`. A query that selects its text reads it from House while online and keeps it, so
9
- select `fields` alone for a list that shows no text; offline it answers the mark, and a Save
10
- that needs that text is refused `transport-uncertainty`.
11
5
  - **Change, file ID and revision.** `change` is `{ author, time }` of the Document's head revision
12
6
  as the Provider last delivered it: `author` is `{ kind: 'user' | 'inbox', id, name }`, or
13
7
  `null` for a write the Provider made itself, and `time` its ISO 8601 change time, or the
@@ -17,11 +11,20 @@ How a Local Query answers text it does not hold and each change, orders, groups
17
11
  one Path for another is the same file moved, and an unsent creation has neither until it
18
12
  is Accepted. `revision` is the Provider's head revision, `null` for an unsent creation or edit,
19
13
  and moves with an unsent move. A Room's last change is its Document with the latest `time`.
20
- - **Order and groups.** `orderBy` sorts by `room`, `path`, `type`, `folder` or `{ field }`: missing
14
+ - **Size and Created.** `size` is the bytes a row holds, a text's UTF-8 length or a file's
15
+ `byteLength`, and `created` the ISO 8601 time its file was created, or `null` where the
16
+ Provider names none; an unsent creation takes the time it was saved.
17
+ - **Order and groups.** `orderBy` sorts by `room`, `path`, `type`, `folder`, `size`, `created`,
18
+ `updated`, which is its change's `time`, or `{ field }`: missing
21
19
  and null first, last with `nulls: 'last'`, then numbers and booleans, then date-times as instants, then text by `locale` or
22
20
  code point with `stringSort: 'lexical'`, then lists item by item; ties end with Room, then Path.
23
- `groupBy` by `room`, `type`, `folder` or `{ field }` answers `{ groups: [{ key, count }] }`,
24
- counted over every match and ordered by `count` or a key. A sort or group takes only a
21
+ `groupBy` by `room`, `type`, `folder`, `subfolder` or `{ field }` answers `{ groups: [{ key, count }] }`,
22
+ counted over every match. `subfolder` is the child folder of `pathPrefix`, or of the Room's root,
23
+ that holds a row, `null` for a row directly in it, so one query totals every child folder. A
24
+ group's `select: { size: true }` adds `documents` and `files`, each `{ count, size }`,
25
+ `updated: true` its latest `updated`, and `greatest: { field }` that field's greatest value. A
26
+ group orders by `count`, `size`, `updated`, `greatest` or a key, each with `nulls`. Grouped by
27
+ `folder` or `subfolder` alone, a folder holding no match answers a count of 0. A sort or group takes only a
25
28
  single-value pointer. `limit`, at most 1,000 whatever a query names, bounds the Documents or the
26
29
  groups, and a result it cuts short names `next`: the same query with it as `after` reads the next
27
30
  window, in the same order, ties included. `total: true` adds `total`, every match's count. An
@@ -11,12 +11,13 @@ draw it as loading and observe the query to hear the complete answer. A query is
11
11
 
12
12
  - **Filter.** `rooms` names Room locators and defaults to every Room. `types` names MD
13
13
  Types, and `any` names untyped Markdown Documents. `pathPrefix` is a directory: `notes`
14
- keeps `notes/a.md` and not `notes2/a.md`; `folder` keeps only what lies directly in it.
14
+ keeps `notes/a.md` and not `notes2/a.md`; `outside` names directories whose contents stay
15
+ out, `['house']` leaving `house/` out; `folder` keeps only what lies directly in it.
15
16
  `paths` keeps only the Paths it names: read named Documents so, never from a list.
16
17
  `fileIds` keeps only the Documents of the `fileId`s it names, wherever they moved, on
17
18
  the device alone: an App function refuses it.
18
- `text` keeps the Documents whose held text contains that phrase, ignoring case, ranking
19
- nothing; a text the device does not hold never matches.
19
+ `text` keeps the Documents whose text contains that phrase, ignoring case, ranking
20
+ nothing.
20
21
  - **Fields.** Every frontmatter value is named by JSON Pointer: `/status`,
21
22
  `/shipping/city`, `~1` for a `/` and `~0` for a `~` in a key. A segment that meets a
22
23
  list applies to every item and a number names one item. `where` names pointers, ANDs
@@ -38,13 +39,13 @@ draw it as loading and observe the query to hear the complete answer. A query is
38
39
  `resolve(room, path, destination)` answers its `document`, the `deleted` one's last
39
40
  `revision`, or `unreadable` where the App does not bind it or it is locked.
40
41
  - **Parts.** A Document query must `select`: `'all'`, or `fields`, `sections`,
41
- `preamble`, `markdown`, `backlinks`, `change`, `fileId` and `revision`, where `fields` is `'all'`
42
+ `preamble`, `markdown`, `backlinks`, `change`, `fileId`, `revision`, `size` and `created`, where `fields` is `'all'`
42
43
  or a list of pointers and `sections` `'all'` or a list of names. Selected pointers
43
44
  return the frontmatter holding only them, nested as written. A backlink names the
44
45
  referring Path, MD Type and the pointer it came from as `field`. Room and Path always
45
46
  return; a Markdown Document also returns its MD Type, and at most its first 1,000
46
47
  backlinks: a query on the referring field reads the rest. A non-Markdown Document
47
- returns only Room, Path and a selected `fileId` and `revision`, a binary Path entry its `binaryFile`
48
+ returns only Room, Path and a selected `change`, `fileId`, `revision`, `size` and `created`, a binary Path entry its `binaryFile`
48
49
  record too, and a text file its text as a selected `markdown`. An unselected part is absent. Select only what a screen shows: a list
49
50
  that selects the Markdown hears every edit of it.
50
51
 
@@ -6,7 +6,7 @@ What an App's page draws and how it behaves in the browser.
6
6
  - The address bar is the shell's, not your page's: read your place from `bridge.address()` and `bridge.onAddress`, and move with `bridge.push` or `bridge.replace`, so Back, Forward, reload and a shared link keep it; a push to the address already shown replaces it, so a double click adds no history entry. After an act that ends what the page shows, and when a dialog closes, `bridge.replace` the next address; a replace with the address this page was opened from goes back to it, so Back returns to where the person came from. Keep the open item, tab, filter and search in the address. Addresses under `/render` and `/info` are House's.
7
7
  - Files: take one in with `binaryFile.attach` the moment it is chosen and keep the Path it answers, hand one out with `binaryFile.download`, and show an image or video in `<room-media>` naming its width and height, so nothing waits for media and nothing moves when it arrives; never read a file whole to show or download it ([files](apps/runtime-files)).
8
8
  - Mobile first: lay out from 360 pixels wide up, with no action behind hover alone.
9
- - Every control works from the keyboard, with visible focus and a label.
9
+ - Every control works from the keyboard and has a label; give it no focus style of your own and never remove the browser's focus mark.
10
10
  - An empty list says what it will hold and invites the first document.
11
11
  - Long names truncate with an ellipsis and show in full on hover.
12
12
  - The element is the link: a row, card or name opens its item; no "Open" buttons.
@@ -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
 
@@ -5,16 +5,15 @@ How `search` finds Documents by words through House, and how a page finds them o
5
5
  `search({ text, rooms })` asks House's search, the one Agents use, once and online: there
6
6
  is no observed search and the device keeps no full-text index. `rooms` names Room locators
7
7
  and defaults to every Room the page binds; the search never leaves those Rooms, and finds
8
- words in every Document there, a large one the device never read included.
8
+ words in every Document there.
9
9
 
10
10
  - **Results.** `{ kind: 'found', documents }`, ranked by House, at most 20 hits. A hit names
11
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`: a text the device does not hold arrives
13
- from House.
12
+ hit's Document with `query` naming its `paths`.
14
13
  - **Offline.** Without a connection `search` answers `{ kind: 'offline' }`, and where no
15
14
  House search is reached, `{ kind: 'undeclared' }`. Find Documents then with a
16
- [Local Query](apps/local-query): by Path, name, field values and `text`, a phrase its held
17
- text contains. That filter ranks nothing and never finds a text the device does not hold.
15
+ [Local Query](apps/local-query): by Path, name, field values and `text`, a phrase its text
16
+ contains. That filter ranks nothing.
18
17
  - **Refusals.** House's refusal answers as `kind: 'rejected'` with its `code`, and a lost
19
18
  answer as `transport-uncertainty`: say the search failed and keep what the page shows.
20
19
  - **Conversations.** `search` finds no message. Inside one conversation
@@ -2,11 +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 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`.
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
6
  - Git signs in as you with a credential your User makes for you on `<origin>/connections`, given as its password.
7
7
  - When the Kit runs you, add `-c 'credential.helper=!kit git-credential'` to the clone instead, so the Kit signs Git in.
8
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`.
9
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>.
10
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.
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 `publish_app_zip`.
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
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.
@@ -10,7 +10,7 @@ Before `npm run publish`:
10
10
 
11
11
  After it:
12
12
 
13
- - `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.
14
- - Bind the Room once with `set_app_bindings`.
15
- - See it yourself: sign your own browser in with `create_sign_in_code`, then open the App's url.
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
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
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
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 the panel writes for My Room for each Agent it makes, naming that Agent, written as [Agent function](reference/agent-function) says: [Work on ticket](agent-functions/work-on-ticket).
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
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  How an Agent function document in the Private Room is written, one for each Room it serves.
4
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; and `agent`, the identifier of the one of your User's current Agents it starts. 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 and Agent, at `/rooms/<room-handle>/house/agent-functions/<name>.md`, where every member reads it, and refuses a name a card there already holds as `agent_function_name_taken`. An Agent function a second Room needs is a copy under that Room's handle. Anyone who writes that Room asks it with `send_agent_function_request` naming the card, or names the `agent` with their own words, as the Agent's Trust level in that Room allows: under Any request, the default, either starts at once; under Agent functions only the card starts at once and own words are refused `own_text_not_admitted`; under Approve each either waits for the Agent's owner to approve it. Its owner sets the level on the Agent's House page; the owner, their own agents and their Private Room's Triggers start it at once at every level, a Trigger of any other Room asks as that Room's writers do, and `inspect` on a Room root names the Agents you may ask there with their levels. An Agent function request's input is text the Agent reads, and House checks no shape. Mail your conversation sends with `send_mail` and a request it sent reaches the conversation that request started at once under Any request; below it, `send_mail` 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 `set_request_result`, and the turn's end finishes the request. The conversation stays active until it is Done, which `mark_done` sets at the end of a turn and which nothing undoes, so mail reaches it after its run.
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 and Agent, at `/rooms/<room-handle>/house/agent-functions/<name>.md`, where every member reads it, and refuses a name a card there already holds as `agent_function_name_taken`. An Agent function a second Room needs is a copy under that Room's handle. Anyone who writes that Room asks it with `agent-functions/send` naming the card, or names the `agent` with their own words, as the Agent's Trust level in that Room allows: under Any request, the default, either starts at once; under Agent functions only the card starts at once and own words are refused `own_text_not_admitted`; under Approve each either waits for the Agent's owner to approve it. Its owner sets the level on the Agent's House page; the owner, their own agents and their Private Room's Triggers start it at once at every level, a Trigger of any other Room asks as that Room's writers do, and `inspect` on a Room root names the Agents you may ask there with their levels. 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 under Any request; below it, `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
6
 
7
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
8
 
@@ -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; `inboxes: true` to show and answer customer chats, naming `chat` and `chat-message` in `room_slots`; `house_acts`, the House acts it calls by their act names, such as `rooms/read` 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/read`, `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 once to allow the House acts it declares, and again only for those a later release adds; 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 `shares/create`, `rooms/create` and the `rooms/access/` acts `operation_denied` to anyone who manages no Room but their Private Room. [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,7 +2,9 @@
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 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 `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.
6
8
 
7
9
  ```yaml
8
10
  person:
@@ -22,7 +24,7 @@ task:
22
24
  ```markdown
23
25
  ---
24
26
  type: person
25
- member: <User Identifier from list_members>
27
+ member: <User Identifier from rooms/members/list>
26
28
  role: Designer
27
29
  ---
28
30
  ```
@@ -1,15 +1,15 @@
1
1
  # Triggers
2
2
 
3
- How a Trigger's `condition` and `actions` are written for `create_trigger` and `edit_trigger`; House writes a Room's Triggers as read-only `house-trigger` documents at `house/triggers/<trigger>.md`.
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
- `condition`: When it fires, e.g. `{on: "documents", scope: {type: "task"}, mode: "starts_matching", new_documents: false, match: {path: "/fields/status", eq: "review"}}`; for a folder's new document, `{on: "documents", scope: {folder: "/answers"}, mode: "starts_matching", new_documents: true, match: {all: []}}`; for any edit of a document, `{on: "documents", scope: {document: "/plan.md"}, mode: "field_changes", field: "/text"}`; `moved_between_rooms: true` fires only on a document moved between Rooms, `false` on any other change; for items, `{on: "items", address: "<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>}`. In your Private Room alone, a notification to you: `{on: "notifications", match: {path: "/fields/kind", eq: "share-offer"}}`, testing its `house-notification` document's `/fields/kind` and its value fields, `match` optional; such a Trigger holds no `notify` action. A `/fields/…` or `/members/…` path reads only what the document's own type declares: a document with no `type` has no fields, whatever its front matter holds, so give it a `type` naming one in `settings/schema.yaml` that declares the field.
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"`; a section `{section: "Notes"}`; 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
- A message into a conversation the Room's [Agent function request](reference/agent-function) started: `{on: "messages", match: {path: "/sender", eq: "requester"}}`, testing `/sender`, `/agent_function` and `/path`, the request's document, never its words.
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`: 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. `list_trigger_events` 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.
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
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 `environment_function_not_found`. Kit runs its script with no terminal, the Event as JSON in the file `HOUSE_INPUT` names, one Event at a time. `list_trigger_events` 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.
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 `environment_function_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
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; `list_trigger_events` 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.
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
14
 
15
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 `agent_function_not_found`, a retired one `agent_function_retired`. `{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('site/submission', { content })`, online only. `content` is one Markdown document the Intake Room's `settings/schema.yaml` accepts, and House adds its `site` and `received` 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.
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 `received` 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.
@@ -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`, 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: 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 `agent: "<agent id>"` added to its frontmatter, 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,7 +11,7 @@ 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.
@@ -27,13 +27,13 @@ Claim the first ticket. Build three variants as [Build an App](apps/build) says,
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 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 `publish_app_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.
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,13 +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
13
 
14
14
  ## As a function
15
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 `delete_function` 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.
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
17
 
18
- `run_function` 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.
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.
19
19
 
20
20
  ## As a script they run
21
21
 
@@ -6,5 +6,7 @@
6
6
  "29951ee394aad9979eecfed3e5dc32c2c86e2226b6a380db5dbd4f305f4d1156",
7
7
  "b99799a2fcddcb99e6ac14acc8d7a92a9f8f69b53f6b41edbc6f8e978256c71a",
8
8
  "d14166e300ce35455ca51ec4959c2bc77668e5cb7f890d2b89c4d2c1e02af6b5",
9
- "e612bbaa90e41d60b9bcd0367a074b9735b9239c287e56fa1becc8364562a422"
9
+ "e612bbaa90e41d60b9bcd0367a074b9735b9239c287e56fa1becc8364562a422",
10
+ "1148f2eec3f500c66c4678a8ce9ab215c095692f505af1934574da6072f4f1a4",
11
+ "42b31e675bfb35457a6cc94a54a58b180e4e646a83cb480701ee2e6259a84ee7"
10
12
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentshouse/skills",
3
- "version": "0.1.0-ca3affce380c3",
3
+ "version": "0.1.0-ca6f30223cbaf",
4
4
  "description": "The upstream Skills agents.house serves its agents, verbatim, and the texts it writes for them: the Guide, its own Skills among the pages, and the Agent instructions",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/upstream.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "repository": "https://github.com/mattpocock/skills",
3
- "commit": "a496f5513d4a4cf889bc48e189e579f4b0bdf6aa",
4
- "date": "2026-10-29",
3
+ "commit": "4ae2317ddb22b046e26455e4f9c9b3aaaf62212d",
4
+ "date": "2026-10-31",
5
5
  "skills": [
6
6
  "ask-matt",
7
7
  "code-review",