Skip to main content
At the end of this page you will have a page live at https://<org-slug>-<project-slug>.ravi.page/<route>, and you will know how to choose who can open it, protect it with a password, read comments on it and roll it back. You need a Console login and a default project first: see Log in to the Console.
This page describes ravi.bot@next. In @latest (3.260927.5), ravi pages ship is a dry-run unless you pass --execute, and it creates a separate host named after --title instead of using the project host. Install @next with bun add -g ravi.bot@next, or switch an existing install with ravi update --next.

How Pages is organized

  • A project has one default host: <org-slug>-<project-slug>.ravi.page, for example acme-website.ravi.page.
  • A page is a route on that host. / is the project home; /report and /docs are other pages.
  • --title is the page title. It never creates a host.
  • Do not create one host per page. The host name ravi and names starting with ravi- are reserved and cannot be created.

Publish your first page

1

List the routes already published

Shipping to a route that is already published replaces that page. ravi pages list --project website --json shows the host itself; the default one has isDefault: true.
2

Ship the page

Without --json, the output lists the host, then the route, its visibility and the URL, then a Comments line (see comments):
If the project has no host yet, ship creates <org-slug>-<project-slug> and gives it this ship’s --visibility as its default.
3

Open the URL

The page is private by default: open it while signed in to the Console with an account that can read the project. To open it to everyone, see Visibility.

What ship takes

Pass --title and exactly one content source: Defaults: --route /, --visibility private, --entrypoint index.html. --project overrides the saved project scope. --json returns { url, site, slug, route, visibility, artifactId, uses?, warnings? }. ship publishes immediately. --execute is accepted and ignored. If a ship fails, read the error before retrying; do not probe by shipping again.
--dir uploads every file in the folder except .git and .DS_Store. That includes .env files and node_modules. Ship a clean build folder. Symlinks are refused. The Console accepts up to 1,000 files, 100 MB in total and 50 MB per file.
A positional argument is not the project. ravi pages ship website --title ... creates or reuses a legacy extra host called website.ravi.page. Pass the project with --project website.

Visibility

For private pages, the visitor’s active organization in the Console must be the page’s organization. People in several organizations may need to switch organization in the Console first.

Host default and route policy

Two settings decide what a visitor gets:
  • The host default, set when the host was created: the Default visibility field, --visibility on ravi projects create --default-page-site, or the --visibility of the first ship when that ship created the host.
  • The route policy, set by every ship (--visibility, default private).
If the route is not public, the route policy applies. If the route is public, the host default applies. So a page is public only when both the route and the host default are public.
A public route on a private host stays private. The ship output and ravi pages published still show public, because they report the route policy, not what visitors get. A project created with the preselected private default hits this on its first public page.
Change visibility without uploading anything:
  • The first argument is the host slug (<org-slug>-<project-slug>), as shown by ravi pages list.
  • Without --route, only the host default changes. Routes shipped with the default private stay private.
  • With --route, only that route changes. The output shows the effective Visibility and the host Default.
  • Switching to public is a dry-run without --execute: it prints the plan (host or route, current and target) and exits 3. Lowering visibility applies immediately.
To make a page public on a private host, run both: ravi pages visibility <host> public --execute and either ship with --visibility public or set the route with --route. There is no unpublish command. To take a page down, lower it: ravi pages visibility acme-website private --route /hello.

Password

Visitors without a session get a password form. --route defaults to /. For automation, pipe the password from a protected file with --stdin:
Never put the password in a command argument, an environment variable, a log or a JSON payload. The CLI has no flag for it, and its output never contains it. remove requires a replacement --visibility, so removing a password never makes a page public by accident.

Share a page with one person

To show a private page to one person, share it with their email. Do not make the route public or add a password for that.
  • The person signs in to the Console with that email (verified) and sees only what was shared: the route, or with --site every private route of the host. It is not membership: no operator bar, no voice Page Chat and no live Bases data. They can use the text chat of the routes shared with them, from the floating guest link.
  • --expires takes 30d, 12h, 2w or an ISO date, up to 365 days. Sharing again updates the expiry and reason. unshare --grant <id> removes one grant by the id pages access lists.
  • Anyone who can publish to the project can share: an organization owner, admin or developer, or a project admin or developer.
To bring someone into the organization instead, create an invite. Ravi does not email it: the command prints a link that works once, for that email only, for 7 days.
Roles are viewer (default), developer, admin, billing and owner. Only an owner or admin invites, and only an owner invites an owner. When a page answers that you have no access, ask its managers:
The answer carries an approval link. Anyone can forward it; opening it changes nothing, and only the page’s managers can approve. When your agent runs these commands, it acts for whoever wrote the message: you on your own turns, and otherwise that person through their ravi link (to share or invite, both of you must have the role; a request is made in their name). A person without a link gets ACTOR_NOT_LINKED, and Ravi starts their link itself: on WhatsApp the agent asks them to message it in private, where Ravi sends the approval link. To let a narrower agent use them, grant mutate:pages.access:*, read:pages.access:*, mutate:invites:*, read:invites:* or mutate:access.requests:create as needed.

The operator bar and comments

When a project member opens a page from the Console (the project’s Pages list), a bar appears at the top of the page. Ordinary visitors never see it. Its labels are in Portuguese today. From the bar you can:
  • see and change the page visibility, and manage the route password;
  • Comentar: leave a comment on an item of the page;
  • Mais opções → Histórico de releases: list releases, see Mudanças (changed files and line diffs) and Restaurar an older release.
Comments stay in the Console. They do not reach your agent today. ravi pages ship prints a Comments line about a comment trigger, but the Console does not emit the event that trigger listens to, so it never fires. If people need to send feedback that wakes the agent, give them a form backed by a Base and a trigger, see Interactive pages with Bases.
An open comment from someone else that you have not read blocks your next ship of that route, and restores from the bar. The CLI shows:
The CLI cannot list or mark comments as read, and opening the bar does not mark them read either. Open the page from the Console, read the comment in the bar, then delete it with the trash icon (Apagar comentário). Deleting needs write access to the project. Or ship to a different route. Changing visibility is never blocked by comments.

Page Chat (voice agent)

Page Chat is a voice agent inside every page. A signed-in viewer taps Falar in the Pages bar and talks to an agent that operates the page for them. It acts as that viewer only: it cannot do anything the viewer could not do. Page Chat shows on a site only when the site setting is on and the organization feature console.pages.chat is on. Organizations that already existed when Page Chat launched have it on by default.
  • The first argument is the host slug, the site id or the hostname.
  • set changes only the flags you pass. --enabled true turns on metered voice usage for every signed-in viewer of the site, so without --execute it prints the plan and exits 3.
  • Voices: bossa (default, Brazilian Portuguese, feminine), tempo (Brazilian Portuguese, masculine), marin, quartz, ripple, vesper, willow, stone, gleam, meridian, beacon, delta, cinder. --language is a BCP 47 tag (default pt-BR). --name takes up to 60 characters and --instructions up to 2,000.
  • featureEnabled in the JSON is the organization feature; settings.enabled is the site.
The agent reads the page through an accessibility snapshot, so real labels, headings and aria-labels decide what it can find. A page can also register actions the agent may call:
Use the push form: it works on every page, and the runtime reads the list where Page Chat is on. Action names use letters, digits, _ and -, up to 64 characters. A write action runs only after the viewer confirms by voice.

Text chat

Every page also has a text chat with Ravi. In the Pages bar, the Fale com o Ravi field opens a chat panel docked on the right (a bottom sheet on narrow screens), with a dot when there are unread messages. To put the chat inside a page, add the tag where it should go; the chat fills its container:
Pages replaces the tag with the chat of the current route when it serves the page. Give the container a height, for example min-height: 70vh, or make a page that holds only the chat. Rooms. Each route has one shared room, where everyone who opens that page talks together, and each person has a private room on that route with the agent. Comments left with Comentar also show up in the shared room, pointing at the item they are about. The voice Page Chat is a mode of the same conversation: what is said becomes messages in the room. Who can talk. Members of the organization who can read the project, and guests the route or site was shared with. Nobody signed out. The agent knows who wrote each message. When the agent answers in a shared room:
  • when someone calls it with @ravi or @ followed by the assistant name (--name);
  • when someone clicks one of the buttons in its answers;
  • while only one person has written in the room, since it is still a one-to-one conversation;
  • to every message, when the site’s reply policy is always.
In a private room it always answers. Writes need a click. The agent acts as the person who asked, with that person’s access and nothing more. Reads run at once. Every change, such as adding or editing a row in a Base, shows up in the panel as a summary with a confirm button, and runs only when the person who asked clicks it. Publishing, visibility changes, invites and deletions are not available in the chat. What it can read. In a shared room the agent reads only the data the page itself uses (the host’s --uses) and the knowledge marked for page viewers. Answers can include blocks besides text: a widget from your organization’s Library, a Bases view, a chart, buttons and a card. A view travels by reference: each person’s browser loads the rows with that person’s own access, so two people in the same room can see different rows. Conversations as a Base. When your organization has Bases, the messages of shared rooms are also copied into a read-only Base of the project, conversas-pages (view Conversas, one row per message: text, who wrote it, member, guest or agent, text, voice or comment, page and time). Project members can read it like any other Base, so an agent can search or chart conversations with ravi bases. Private rooms are never copied, and a deleted message loses its text there too. The text chat uses the same organization feature, console.pages.chat, and each agent turn is metered for the organization. Its settings live next to the voice ones:
  • --text turns the text chat on or off; --enabled stays the voice switch. By default the text chat is on, the reply policy is mention, the model is the platform default and no Ravi agent is set.
  • --text true, --reply-policy always and --ravi-agent widen what the agent does, so without --execute they print the plan and exit 3. Turning things off, going back to mention, changing the model and the --clear-* flags apply at once.
  • --text-model takes an AI Gateway model id, <provider>/<model>.
  • ravi pages chat show lists the text chat, reply policy, text model and Ravi agent next to the voice settings (settings.text, settings.replyPolicy, settings.textModel, settings.raviAgent in the JSON).

Let the chat ask your Ravi

--ravi-agent <installation-id>/<agent> lets the page’s agent ask an agent on one of your organization’s Ravi machines, for example to look something up that only that machine knows. The question travels as a Library request, the same way agents on two machines ask each other:
  1. Find the installation id with ravi agents directory --json (installation.id of the agent’s entry).
  2. On that machine, open the agent to requests: ravi agents requests finance on --execute.
  3. Point the site at it: ravi pages chat set acme-website --ravi-agent <installation-id>/finance --execute.
The request arrives as coming from the person who asked in the chat, never from you: the agent answers in its reply and does not act on its machine for them. The machine picks up requests every 30 seconds while one of its agents takes requests, and every 15 seconds for a while after one came in.

Releases and restore

Every publish creates a release of the whole host: the map of all its routes. Restoring a release brings every route on the host back to that state, not just one page. Restore from the operator bar (Restaurar). An unread comment on any route in that release blocks the restore. The project’s Pages screen in the Console lists the release history but has no restore button. To roll back a single page, ship its previous content to the same route again. ship also records each publish on a local artifact (art_*), so ravi artifacts release activate can re-activate a recorded release from the terminal. The artifactId that ship prints is the Console’s id, not the local one; see Artifacts for how to find it. The bar is the simpler path.

Let your agent publish

Your agent runs the same ravi pages ship through the daemon, using the daemon’s Console login. It publishes as you: your role, your name on the release, and your unread comments.
  1. Run ravi login as the same OS user as the daemon (same HOME or RAVI_STATE_DIR). No daemon restart is needed.
  2. Give the agent Pages permissions. An agent with the full-access profile (see Make yourself the owner) already has them. A narrower agent needs them in its capability list:
    --capabilities replaces the list, so repeat the capabilities the agent already has. execute:group:pages also works for shipping and listing, but not for ravi pages password. See Permissions.
  3. Ask the agent, for example: “Publish ./report as /report on the website project.”
The daemon gives a CLI call from an agent 30 seconds. A large --dir upload can time out on the agent’s side even though the publish finished; check ravi pages published before shipping again.

Let your agent read a page

When you send your agent a Page link, it reads it with ravi pages read instead of a browser. A browser would stop at the Console login on a private page; pages read goes through the Console with the daemon’s login and returns the page as Markdown, with its links and the host’s other routes.
  • The agent picks the format. The default Markdown is the page’s text without its styles, layout or images, and the output says so. --format html returns the entry file’s source, and --format zip --out <file> (or --format files --out <dir>) downloads every published file, so the agent can see the design or build a page in the same style.
  • Public routes are always readable. Private, protected_link and password routes are read only on your own turns (the terminal, your direct chat with the agent, routines you own) and only when your login can read the project. When someone else sends the agent a private link, the command exits 3 and the agent tells them it cannot open it.
  • The read is static: the published file, not run in a browser. A data page built with JavaScript shows little text, and the result says so.
  • Ravi blocks browser and fetch tools aimed at *.ravi.page links and points the agent to ravi pages read. Every read of a private route is recorded in the Console audit log.

Custom domains

ravi pages domains <host> <hostname> binds a domain you own to a host. Without --execute it prints the DNS to create and writes nothing. With --execute it moves the setup forward and exits with DOMAIN_SETUP_REQUIRED while DNS work is pending. The message names the step (ownership, DNS, certificate) and the exact records; run the same command again once DNS has propagated. ravi pages list shows each host’s custom domains. A pending one says why it does not serve yet, the DNS still missing and the command to check again; ravi pages published lists pending ones below the pages. Only ready domains appear in urls, so a hostname missing there does not serve the host, even when it answers 200 from another server. The root domain (example.com) serves the host directly when your DNS provider supports a CNAME at the root (CNAME flattening on Cloudflare, ALIAS or ANAME elsewhere). Plain A records are not supported. A subdomain that was never bound answers Cloudflare’s 522 error instead of a Pages 404.

Data pages

Pages that read and write a Base (--uses ravi.bases.*) work only for signed-in members of the organization, on private or protected_link routes. ship refuses them on a public route (exit 2) unless you pass --members-best-effort on purpose. --uses applies to the whole host. See Interactive pages with Bases.

Advanced and compatibility commands

Use ravi pages ship for new pages. ravi skills show pages prints the agent-facing guide with more examples.