@agentshouse/skills 0.1.0-c221fe4e31976 → 0.1.0-c2653a0a4ef70

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.
@@ -2,16 +2,16 @@
2
2
 
3
3
  How an App reads and writes its Rooms on the device, offline too.
4
4
 
5
- - The runtime holds every bound Room on the device and streams in every change from any device, App or agent. `query` and `observe` answer from the device and never wait on the network; `search` asks House ([Search rules](apps/search)).
5
+ - The runtime holds every bound Room on the device and streams in every change from any device, App or agent, but a Search-level Room, which an App shows only as the rows [`queryHouse`](apps/query-house) asks for, never offline. `query` and `observe` answer from the device and never wait on the network; `search` asks House ([Search rules](apps/search)).
6
6
  - Draw from `observe` at once, with no request of your own; an observation hears each later change by itself, so never poll, refetch or subscribe. An answer is `{ pending }` while a Room it reads has not reached this device or been prepared on it: draw the page without those documents; keep the empty state for a complete answer. `rooms` answers once the runtime knows the Rooms the page reaches. Offer binding a Room when it is empty while the sync status's `providerUnreachable` is false and `observe('connection-refusal')` answers `null`; any other empty list says only that nothing can be listed yet.
7
7
  - Show no loading state: draw the last state the device holds. A wait shows only after an act the User pressed whose answer comes from outside the stream, such as `bridge.callExternal`, until it arrives.
8
8
  - Write optimistically: write a Room Draft, then `save`. The change shows in every query at once as a Pending Change and reaches House when it can. `save` refuses at once, with its `code`, a change that is `stale`, `changed-underneath` or against the schema: say so and keep the form. After `changed-underneath`, draw the joined Room Draft and its `marks` ([Room Drafts](apps/room-drafts)).
9
9
  - Show what the runtime reports: `observe('queue', room)` lists changes House has not confirmed yet, and `observe('sync-status')`'s `attentionRequired` lists each change House refused, returned as a Room Draft with why, to save again or discard.
10
- - Keep what the User types in the Room Draft (`roomDraft.write`) as they type; it survives a new release replacing the page, a reload and another tab. Draw a form again only when its page changes, never on a streamed change.
10
+ - Keep what the User types in the Room Draft (`roomDraft.write`) as they type; it survives a new release, a reload and another tab. Draw a form again only when its page changes, never on a streamed change.
11
11
  - A document has one Room Draft, shared by every tab and App, and `save` takes all of it. A write replaces every part and names the revision it read, so write onto the parts it holds; one from an older revision answers `stale` with the current Room Draft: show that one. A field part names as its `base` the value the page showed, `{ value }`, or `null` when the document has no such field.
12
12
  - Save a change the User does not type, such as a checkbox, with `saveParts(room, [{ path, parts }])`: it writes no Room Draft, so the one another tab holds stays.
13
13
  - Offline, all of this works and saves wait; `bridge.onStatus` reports `offline`: say so quietly.
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
- - 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 `not_found` naming the `origin`: tell the person that the Room's owner or a manager enters the key under Connected on the Room's Settings page, since no App opens that page.
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 then and keep what the User types; what was saved before is sent then.
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 whose `room_ref` names a Room bound in a `write` slot carries that Room's Service key for the origin, unseen by the page; any other carries none. Through a Room holding no key for the origin it is refused `not_found` naming the `origin`: tell the person its owner or a manager enters the key under Connected in the Room's Settings, which no App opens.
16
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`. The whole client: [The App runtime](apps/runtime).
@@ -0,0 +1,31 @@
1
+ # House query rules
2
+
3
+ How `queryHouse` asks House for pages of rows of a Room the device never holds.
4
+
5
+ A Room your User holds at the Search level never reaches the device. `rooms` lists it with
6
+ `queriesOnly: true` and nothing held, a [Local Query](apps/local-query) naming it fails with
7
+ the code `queries-only`, and one naming no Room leaves it out; its writes, history, files and
8
+ `resolve` answer as for a Room the App does not bind.
9
+
10
+ - **Asking.** `queryHouse(query)` takes a Document query in the language of a Local Query
11
+ whose `rooms` names that one Room, and asks House once, online. Nothing observes it: no
12
+ `observe`, hook or `readAgain` asks it again, so ask again when the page needs the rows
13
+ again, such as when the person scrolls, opens it again or presses refresh. `call` reaches no
14
+ `rooms/query`.
15
+ - **A page.** `{ kind: 'rows', documents, next }`: at most 100 rows, read in Path order,
16
+ ascending or with `orderBy: [{ by: 'path', direction: 'desc', stringSort: 'lexical' }]`.
17
+ Pass `next` as `after` for the next page. A page may hold fewer rows than `limit`, or none,
18
+ and still name `next`: only an answer without `next` is the end.
19
+ - **Refusals.** House answers `{ kind: 'rejected', code, fields }` for a part that would read
20
+ the whole Room, such as another order, `groupBy`, `total`, `hop`, `backlinks`, `fileIds`,
21
+ `select: 'all'` or a `limit` of 0, as `invalid-query` with a `message` naming the part, and
22
+ for a query over 8,000 bytes as `query_too_large` with its `cap`: fix the query.
23
+ - **Offline.** Without a connection `queryHouse` answers `{ kind: 'offline' }` at once: show
24
+ nothing of that Room and say it needs a connection. A lost answer is
25
+ `transport-uncertainty`, which the page may ask again, and where no House query is reached,
26
+ `{ kind: 'undeclared' }`.
27
+ - **Other Rooms.** A Room the device holds answers `rejected` with the code
28
+ `held-on-device`: read it with a Local Query. A Room the App does not reach answers
29
+ `room-not-readable`.
30
+ - **Nothing kept.** The rows reach the page alone: the device keeps none of them, so they are
31
+ gone once the page closes, and asking again shows what the Room holds then.
@@ -3,7 +3,7 @@
3
3
  What App code reaches through the runtime's client: its surfaces, its reach, observations, Agents and conversations.
4
4
 
5
5
  App code reaches the MD Runtime through the remote client. The surfaces are Rooms, Query,
6
- Search, Observe, Types, Room Draft, Save, History, Resolve, binary files, Call,
6
+ Search, House query, Observe, Types, Room Draft, Save, History, Resolve, binary files, Call,
7
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
9
  statement, the deployment facts, the signed-in member and the count of authority changes
@@ -11,7 +11,8 @@ are observations only.
11
11
 
12
12
  The host attaches each port with its reach, and every member and observation answers
13
13
  within it: a Room outside it answers as one the replica does not hold, Rooms lists only
14
- the Rooms reached whole, a Room reached for single Documents shows only them and their
14
+ the Rooms reached whole and, after them with `queriesOnly: true`, those its User holds at the
15
+ Search level, which only `queryHouse` reads ([House query rules](apps/query-house)), a Room reached for single Documents shows only them and their
15
16
  models' Types, and without conversations the conversation members, chat draft and
16
17
  observation hold none. A changed reach reaches every open observation as its new value.
17
18
 
@@ -8,6 +8,7 @@ change it, build, and push. They are documentation, not enforcement.
8
8
  - [The MD Runtime API](apps/runtime-api)
9
9
  - [Local Query rules](apps/local-query)
10
10
  - [Search rules](apps/search)
11
+ - [House query rules](apps/query-house)
11
12
  - [Room Draft, Save, and outcome rules](apps/room-drafts)
12
13
  - [Content safety and launch promises](apps/content-safety)
13
14
  - [App code takes the client its host hands it and never constructs a Runtime](apps/client)
@@ -12,8 +12,10 @@ Build it as [Build an App](apps/build) says, with what follows. Anything private
12
12
  - Everything it shows lives as documents in its Room; put its demo data there, never in code.
13
13
  - A visitor's edits stay in their browser and never reach House: write them with `save` as an App does.
14
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
+ - A Site loads House's servers when it is bound to a Room that changes often, or when it writes once per visitor, such as a Submission sent on every visit: send one only when a visitor asks to.
16
+ - Code that holds a key, such as one opening a checkout, runs in one of the App's functions, which the page calls: [A Site's function calls](sites/functions).
15
17
  - `sites/describe` sets the title and description search engines show.
16
18
  - 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.
17
19
  - See it yourself: open its url, which needs no sign-in.
18
20
 
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.
21
+ Build its first screen as [A Site's first load](sites/first-load) says. House serves a route as HTML only where the [Entry Data Contract](sites/entry-data-contract) declares it, and [The App runtime on a Site](sites/runtime) says what the runtime does differently there.
@@ -1,12 +1,20 @@
1
1
  # Entry Data Contract
2
2
 
3
- How a Site App's `entry_data` has House serve each route as HTML from Rooms.
3
+ How a Site App's `entry_data` has House serve each route as HTML before the App starts.
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` 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.
5
+ Entry Data Contract, `entry_data` in a Site App’s `app.json`: House serves each route in its `routes` list as HTML before the App starts, running none of your code. A Site has an Entry Page only for a route you list; any other address starts the App as usual.
6
+
7
+ A static route, one with no `queries` and no parameter, names only its `path`. Its Entry Page is your release's own HTML for that path: the `entry` document for `/`, `about/index.html` for `/about`. Write the route's first screen into that HTML. The push reads it without running it: it keeps the body's text and its plain elements (headings, paragraphs, lists, tables, links, images and the like), drops scripts, `on…` attributes and every other element (`button`, `form`, `svg`, `picture` among them) with its content, resolves relative addresses, drops an image the release lacks, and takes the head's `<title>`, `<meta name="description">` and each release stylesheet it links for every screen (no `media` but `all` or `screen`, not `alternate`). A static route that declares `body`, `title`, `description` or `styles`, whose HTML the release lacks, that links more than 8 stylesheets, or whose body passes 2000 nodes, 24 levels or, with every other route, 64 kB, refuses the push.
8
+
9
+ A route that reads Rooms or takes a parameter declares its Entry Page: 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`, `styles` (release CSS files) 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}`.
10
+
11
+ On every Entry Page an `img` keeps the `loading` and `fetchpriority` it names and loads lazily where it names no `loading`; a document's images always load lazily. Each takes the box its `width` and `height` name, 16:9 without them, and an `img` whose `src` is relative (`images/hero.webp`) shows that file of your release. House puts each stylesheet into the page itself, its relative `url()`s pointing into your release, so the page draws in your fonts and styles from its first byte. A route that fails starts the App as usual, and the Site document names why.
6
12
 
7
13
  ```json
8
14
  {
9
15
  "routes": [
16
+ { "path": "/" },
17
+ { "path": "/about" },
10
18
  {
11
19
  "path": "/posts/:slug",
12
20
  "queries": {
@@ -18,6 +26,7 @@ Entry Data Contract, `entry_data` in a Site App’s `app.json`: House serves eac
18
26
  }
19
27
  },
20
28
  "title": { "at": "post", "pointer": "/documents/0/fields/title" },
29
+ "styles": ["assets/site.css"],
21
30
  "body": [{ "markdown": { "at": "post", "pointer": "/documents/0" } }]
22
31
  }
23
32
  ]
@@ -0,0 +1,15 @@
1
+ # A Site's first load
2
+
3
+ How to build a Site whose first screen reaches a visitor's phone within about a second, and how to see that it does.
4
+
5
+ A phone on a slow link pays for every byte before the first screen, so what the release puts first decides how soon it shows. Build every Site this way by default:
6
+
7
+ - **An Entry Page for every entry route.** House draws a route as HTML before the App starts only where the release declares it in `entry_data` ([Entry Data Contract](sites/entry-data-contract)); any other route shows once the App has run. A route with no queries and no parameter names only its `path`, and its Entry Page is the release's own HTML for that path: the entry document for `/`, and `about/index.html` in the release for `/about`. House reads that HTML and never runs it, keeping its text and plain elements and taking its title, description and stylesheets from its head, so prerender each such route's first screen into it at build, its main image a plain `img`, since a `picture`, an `svg` and a script are dropped. A route that reads Rooms or takes a parameter declares its queries and its body. An Entry Page draws in the Site's own fonts, styles and images, so nothing moves when the App takes over.
8
+ - **Images at the size the App draws them**, each with its `width` and `height`: a larger file costs bytes nobody sees, and the box stays still while it loads.
9
+ - **The first image at once**: the first screen's main image names `loading="eager"` and `fetchpriority="high"`, in the release's HTML and in the App, since an Entry image that names no `loading` loads lazily. Every image below the first screen loads lazily.
10
+ - **No entrance animation on the first screen**: draw it in its final place, since content that fades or slides in counts as shown only once it stops.
11
+ - **Heavy libraries after the first draw**, behind a poster: load a 3D scene, a map or a video player with `import()` once the first screen has drawn, and show a still image of it until it runs.
12
+ - **Built minified and split**: minification on, and each route and heavy part a chunk of its own loaded by `import()`, so the first screen loads only its own code.
13
+ - **At most two font families**, the Site's own, their files in the release.
14
+ - **The first view within the bound** the publish warns at. The first view is the entry document, its scripts and stylesheets and what they import statically, compressed as House stores them. A first view past the bound, or no Entry Page for `/`, never stops a publish: its answer and `sites/list` name each in `warnings` by its `code`, `first_view_heavy` with its `bytes` and `bound`, and `entry_page_missing`. Fix them before the next publish.
15
+ - **Read `first_load` in `sites/list` after each publish.** House loads the Site once more, cold, as a phone on a slow link, and answers `{ first_content_ms, largest_content_ms, at }` for the release or publication it serves: `null` before that figure, when that load failed or where the Building times no Site. A figure that grew points at what that release added.
@@ -0,0 +1,11 @@
1
+ # A Site's function calls
2
+
3
+ How a Site's page calls a function its App declares and gets its answer, so code that holds a key, such as one opening a checkout, runs on House's servers and never on the page.
4
+
5
+ - **The call.** `runtime.call('sites/functions/call', { function, input })`, online only, calls any function the App's latest release declares ([App functions](apps/functions)), with `input` any JSON up to <function-input-size>, `null` when left out. It answers `{ kind: 'action', result: { answer } }`, `answer` being the function's return value as JSON, `null` when it returns nothing. Offline it answers `transport-uncertainty` at once and sends nothing later, and a Site House does not serve answers it too.
6
+ - **Open to every visitor.** Anyone at the Site calls any declared function with any input, signed in or not, and no bot check stands before it: check `call.kind` and `call.input` in every function, and look up a price, total or order by its id rather than taking it from the input.
7
+ - **What a function receives.** `export default async (call, house) => {}` receives `{ kind: 'site', id, site, moment, input, rooms, intake_room }`. `kind` is `site`, which no Trigger's event carries, so a function written for a Trigger refuses a visitor; `id` is new for each call; `site` is the Site's address; `moment` is when the call started, which `Date` reads; `input` is the call's input, whole; `rooms` lists under each slot of the release the Room references the Site binds there; and `intake_room` is the Intake Room's reference or `null`.
8
+ - **Its Rooms.** A call reads and writes every Room the Site binds and its Intake Room, with the Site owner's authority and those Rooms' Service keys, and no other Room. It has no Room of its own, so each method names one: `query` one Room in `rooms`, `saveParts(room, parts)` its first argument, `call` and `callExternal` their `room_ref`, and `toMoment` and `toLocal` their `room_ref` ([Times](apps/function-times)). Its writes are the App's, by `App <App> (function <function>)`, and count against the owner's Write limit.
9
+ - **Refused before it runs.** `{ kind: 'rejected', code }` with `not_found` for a function the latest release does not declare, `function_input_too_large`, or `limit_reached` with `limit: 'site_function_calls'` and its `retry_at` once the Site's calls pass their rate, which Full House raises.
10
+ - **Refused after it was taken.** A call runs in its Site owner's run slots, which their Triggers' runs share, at most <function-owner-slots> at once on each server. `function_not_started` says it found no slot within <function-start-wait> and never ran: send it again. `function_failed` with `error` says it ran and failed: its thrown text, `time_cap_reached` at <function-time>, `memory_cap_reached`, `external_call_cap_reached`, `answer_not_json` for an answer JSON cannot hold, or `answer_too_large` past <function-answer-size>. `function_unanswered` says House lost the answer after it may have started, so it may have run: a function that charges or orders names what it writes by an id the page sends, so a second call finds it.
11
+ - **Nothing kept.** House keeps nothing of a call once it has answered but its figure among the App's function runs.
@@ -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. 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.
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, so a Site's page draws no loading state either. A route has an Entry Page, House's HTML of it before the App starts, only where the release declares one in its [Entry Data Contract](sites/entry-data-contract).
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
 
@@ -9,7 +9,7 @@ and its Pending Change shows in every query and across reloads until the browser
9
9
  cleared. It is never sent: `observe('queue', room)` shows it `local`, Sync Status never waits on
10
10
  it, and once the Room no longer lets it apply it leaves the queue and returns no Room Draft.
11
11
 
12
- A Site's page fills its [Entry Data Contract](sites/entry-data-contract)'s
12
+ Where House served a route's Entry Page, the page fills that route's
13
13
  `{"$param": name}` arguments with `boundQuery` from `@agentshouse/mdruntime/entry`, as
14
14
  House did for its HTML. While the Site prepares, a query a route's `interaction` names
15
15
  answers from the entry's result when the page observes that descriptor, and every other
@@ -11,9 +11,20 @@ Build the App a prototype made, once the User has decided on its design, and pub
11
11
 
12
12
  Read the map `prototype-app` opened for this App. Start only when its design-decision ticket is resolved with the User's decision. Until then do nothing else: tell the User their decision on the prototype's design is missing, give them the prototype's address, and stop. Without such a map there is no decision: say so and offer [`prototype-app`](skills/prototype-app).
13
13
 
14
+ ## Design
15
+
16
+ Claim the build ticket. Read [Design an App](apps/design) and each page it links, then draft from the User's decision:
17
+
18
+ - the App's types and fields, as its `schema.yaml` will declare them;
19
+ - each piece of work no page does, the function that does it and the Trigger that starts it;
20
+ - for each design on [Designs that load House](apps/design-load) the App comes near, how it keeps that load down;
21
+ - its top colours, light and dark, from the decided prototype, and its icon.
22
+
23
+ The draft is no document of its own: the grilling takes it in.
24
+
14
25
  ## Build
15
26
 
16
- Claim the build ticket. Starting from the User's decision, run `grill-with-docs`, then `to-spec`, then `implement`. Keep what they write where the Owner rules, `/rooms/private/owner-rules.md`, say. Each Skill named here is also a Command of its name, or the Guide page it links, for a client that has not installed it.
27
+ Run `grill-with-docs` on that draft, then `to-spec`, then `to-tickets`, then `implement` for each ticket in order. Keep what they write in the map's Room, where the Owner rules, `/rooms/private/owner-rules.md`, say, and name that Room in the App's README as the Room where the App is developed. Each Skill named here is also a Command of its name, or the Guide page it links, for a client that has not installed it.
17
28
 
18
29
  ## Publish into the same App
19
30
 
@@ -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 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.
14
+ In the Room where the App is developed ([Design an App](apps/design)), 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.
@@ -24,6 +24,8 @@ In the Room the work belongs to, the one the User names or else one you make wit
24
24
 
25
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
+ Write the App's first screen as static HTML in its entry document, which its script takes over once it runs, so the screen shows before any script has loaded; every release keeps it so.
28
+
27
29
  Publish it as a new App, which creates it:
28
30
 
29
31
  - where you run Git, with `npm run publish -- --name "<display name>"`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentshouse/skills",
3
- "version": "0.1.0-c221fe4e31976",
3
+ "version": "0.1.0-c2653a0a4ef70",
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",