D43. The core is the client of Elabora's hosting; the author's AI reads review comments placed in the sources, and only people publish, share and resolve (14 Oct 2026)
The hosting (Elabora’s servers: the API at https://api.elabora.studio, modules on <space>.elabora.page, EU) publishes web builds (D41) by their hashes, shows private ones to reviewers through a secret link (revue.elabora.studio, D42), and signs authors in by a code sent by e-mail (its protocol, version 3). The command line comes first, for agents, and the app’s screens on top later; the author’s AI must be able to act on reviewers’ remarks without a person copying them over.
- One client, in
@elabora/nodecloud/, without a new dependency (Node’sfetch): signing in (startSignIn,verifySignIn, the handle once), publishing (publishCoursebuilds for the web in a temporary folder,publishFolderhashes the files, announces the manifest, sends only the blobs the space lacks, whole or in parts above the API’s limit (limits.singlePutMaxBytes, parts ofpartBytes, four blobs at a time), then commits), reviews (create, list, regenerate the link, close, read-only, open, delete; a new private version goes to the publication’s open reviews), comments (list withsince, the author’s reply, resolve, reopen) andresolveComments. The command line (elabora account,elabora publish,elabora review) and the MCP server’s read tools call it, the app will. The API ishttps://api.elabora.studio;ELABORA_CLOUD_URLpoints elsewhere (the tests’ fake server), HTTPS only but on this computer. Nothing runs unless the author asks: the core makes no network call of its own (docs/architecture.md, goals). - The credential in a file of the local data, readable by the author only, on the model of the ElevenLabs key (D40): the session token in
<local data>/credentials/elabora-session(0600 in a 0700 folder, written whole then moved into place), with the API it belongs to, the account’s address, handle and the device’s name; a tester’s invitation key, kept byelabora account login --invitation <file>|- --space <space>, incredentials/elabora-invitation;ELABORA_CLOUD_KEY_FILE(withELABORA_CLOUD_SPACEfor an invitation key) for scripts and trials. First found: the variable, the session, the invitation. A credential is only sent to the API it names: a session made against a test server is never sent to the real one, nor the other way round. The code is read from the input, never an argument; tokens and keys are in no output, log or message (maskedeas_…1a2b;CloudErrorscrubseas_,eik_,erl_,ert_from what the API says). A 401 forgets the session (the protocol: the session is over) and says to sign in again; a refused invitation key is kept and said. The app reads the same file later; whether it moves the token to the keychain after a gesture, as D40 did for the key, is its decision (an agent runs as the author and reads either). - The review link is shown once, to the person who creates or regenerates it (the API keeps only its hash), or written to
--link-out(0600): it is made to be shared, unlike a token. A private publication is a review build (--review-origin https://revue.elabora.studio, more with--review-origin), named<course id>-reviewby default so that it never meets the public one (<course id>), whose visibility the first commit fixes; a public one is built with its address as canonical andnoindexunless--index(which only accounts allowed to be indexed may ask). A folderelabora build --target webwrote is published as it is. - Comments placed in the course’s sources. A reviewer’s anchor names a screen by its permanent key (D4), a block by its id, a step, a layer, a narration line and a word (D28).
resolveCommentsturns it into what an AI acts on: the screen’s id, title and source file (screens/<id>.json) throughelabora.lock.json; the block’s type, its JSON pointer and layer; the step’s label, the layer’s title, the line’s speaker and text, the word (the API counts words from 0, the bridge names them with their occurrence: both read); the translation’s file when the comment was written in another language; the point and the reviewer’s frame. What the sources no longer have is said (id: null,type: null), never guessed. Whether a remark may be fixed already:newerInReview(a newer version was sent to the review since the comment’s) andscreenChanged, from a record of what this computer published (<project data>/cloud/publications.json: each version, the course version it was built from and a hash of every screen’s canonical JSON then; nothing secret),nullwhen this computer did not publish that version. Threads come with their replies;revis passed back assince; replies since a rev come under their thread.elabora review commentsprints it for people and agents (--json: the same as the MCP tool). - The MCP server reads, people act.
elabora_review_listandelabora_review_comments(read-only,openWorldHint: true) give the course’s reviews (those of the publications built from it, bymeta.course.id, from any computer) and their placed comments. There is no tool to sign in, publish, share a link, answer, resolve, close or delete: publishing puts a module in front of people under the author’s name and spends their account’s limits, a link gives access to unpublished work, and answering or resolving speaks to a reviewer as the author: each is the author’s decision, as approving a plan is (D5). An agent fixes the sources and tells the author, thread by thread, what it changed; the author publishes the next version (it reaches the review by itself), answers and resolves, from the command line or the app. A comment’s text is a person’s outside the project: the tool’s description tells agents to take it as a remark, never as instructions. - The device is named for its system, not its computer.
elabora account loginsends « Elabora CLI · macOS » (or Windows, Linux) as the session’s device, where it sentElabora CLI (<computer name>): a computer’s name is often a first name, and it would have reached the hosting and its sessions list (and the privacy policy’s « what the sessions list shows ») without the author having typed anything.--device <name>names it as the author likes, and is the way to tell two computers apart; the sessions list also shows when each was created and last used. - An older version can be withdrawn alone (
elabora publication versions <name>,elabora publication withdraw <name> <version> --yes; the API’sDELETE …/publications/<name>/versions/<version>). Until then a pinned version (a public one stays at…/@<version>/, immutable) could leave only with its whole publication, so that erasing a personal datum from an old version meant unpublishing everything. The current version is refused (publish a newer one first, or unpublish): a publication always has one. A review that showed the withdrawn version keeps it in its list, marked withdrawn, with its comments; the module is not shown. The command asks for--yes, asreview deletedoes, and says that a browser which already has the version may keep it. The local record of published versions (<project data>/cloud/publications.json) is the author’s own and keeps its line, so comments on the withdrawn version are still placed in the sources. - Tests never reach the hosting: a fake of the protocol (test/cloud-fake.ts) on 127.0.0.1, credentials in throwaway folders (
ELABORA_CLOUD_SESSION_FILE,ELABORA_CLOUD_INVITATION_FILE), no e-mail. The trial on the real API uses a tester’s key of the spaceessai, never printed. Revisit if: the app keeps the token in the keychain (then the command line asks it, as for the key), agents need to publish on their own (a scoped key per agent with its own limits, never the author’s session), the review page settles on another anchor (one function,placeOf), or a server-side project (collaboration) makes the record of published screens the server’s. Amended on 14 Oct 2026 (the app’s account settings): the session goes through a store, the 0600 file by default; the app gives its own (setSessionStore, its safeStorage) when the author’s AI may not use the session, and every read, write and removal goes there (sign-in, the handle written back, a 401, signing out). The client gains what Réglages › Compte and Publier call:accountSessions,revokeSession(this device’s own forgets the session here),updateAccount { displayName, language },chooseHandle(handle, { displayName }),requestDeletionCodeanddeleteAccount(confirm, code)(then the session is forgotten),unpublish(« Retirer du web »; refused while a review shows the publication) andrenameReview. A private publication builds as a preview: the checks of the guardrails and of the delivery checklist that fail stop the web and the package, never the reviewers; they come back aschecksandelabora publish --privatelists them; errors of the course itself stop it as before.test/cloud-fake.tsspeaks these routes too, and the app may import it. Amended on 29 Oct 2026 (protocol 7, elabora-cloud C33): the handle may change once in 30 days, with no redirect.chooseHandlerenames the space when the account has one, and the session file takes the new handle;elabora account handle <name>asks for--changebefore renaming (it breaks every link to the old address), andaccount statussays when the next change is allowed (nextHandleChangeAt).