> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pnbr.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Publish a Brain as a page

> A Brain has a page that its readers open in a browser, and you checked that it shows the Content and nothing else.

Guide · access

> **Use when**
>
> A person wants a client or a prospect to read part of a project in a browser, with no account, from a web address.

> **Looking for something else?**
>
> Giving a client a login, an agent or a key (recipe [ship-a-brain](https://docs.pnbr.io/guides/ship-a-brain.md)). Limiting one key to part of a project (recipe [share-with-a-view](https://docs.pnbr.io/guides/share-with-a-view.md)).

## Outcome

A Brain has one published page. The page shows the Brain's Content in a browser
and nothing else. The person chose who opens it: anyone with the web address, or
only the people on a list. You have the web address from the page's `address`,
and you know the expiry time and whether visitors may download document originals.
Images and derived previews remain readable when downloads are off.

## Before you start

* Orient first (recipe [orient](https://docs.pnbr.io/guides/orient.md)). Only a signed-in person who manages access can
  publish a page. A key or a connected agent is refused with
  `human_session_required` (card rule [brain.12](https://docs.pnbr.io/concepts/brain.md#rule-brain-12)). If you have the `brain_page`
  tool, you act as that person and can publish. Without it, give the person the
  choices below and ask them to publish.
* The Brain must have a published View as its Content and must not be retired
  (card rule [brain.1](https://docs.pnbr.io/concepts/brain.md#rule-brain-1)). If the Content is wrong, fix the View first (recipe
  [share-with-a-view](https://docs.pnbr.io/guides/share-with-a-view.md)).
* Check the Content as a reader sees it (recipe [ship-a-brain](https://docs.pnbr.io/guides/ship-a-brain.md), steps 4 to 6).
  A page shows the same Content to everyone who opens it.
* Ask the person four things.
  1. Who opens the page: anyone with the web address, or only the people on a
     list. For a list, ask for the emails or domains. `*.example.com` admits the
     subdomains of `example.com`, and `example.com` admits only that domain.
  2. When the page ends, if it should end, and the sentence a visitor reads then.
  3. Whether visitors may download document originals. Images and derived previews
     remain readable when downloads are off (card rule [brain.18](https://docs.pnbr.io/concepts/brain.md#rule-brain-18)).
  4. The title, the introduction and the accent color.

## Steps

1. Publish the page.
   * CLI: `penumbra brains page publish <brain-id> --title "<title>" --access anyone`,
     or `--access listed --listed <email or domain>` for a list. It asks first;
     without a terminal it needs `--yes`. Expect the page, its `address:` line (the
     web address), `state: published` and a `revision`.
   * API: `PUT /v1/orgs/{org}/projects/{project}/brains/{brain-id}/app`, with an
     `Idempotency-Key`, a `title` and an `access_mode` of `public` or `verified`.
     Add `viewers` for a list. The answer carries `address`, the web address.
   * MCP: `brain_page` with `action: "publish"`, a `title` and `access`
     (`anyone` or `listed`, with `viewers` for a list). The project's approval
     floor may hold the call: give the person the approval link and do not repeat it.
   * Read the web address from `address` in the answer. Do not build it from the
     address name. `address` is `null` when the cell has no page host: tell the
     person that the page has no web address to give yet.
   * Expect `brain_app_already_published` if the Brain has a page already (card
     rule [brain.15](https://docs.pnbr.io/concepts/brain.md#rule-brain-15)). Expect `plan_brain_app_limit` if the plan has no page left
     (card rule [brain.19](https://docs.pnbr.io/concepts/brain.md#rule-brain-19)). Expect `brain_app_authority_unavailable` if the
     person holds nothing in the project to hand to a page.
2. Change the list or the page.
   * CLI: `penumbra brains page viewers set <brain-id> --add <entry> --remove <entry>`,
     and `penumbra brains page update <brain-id>` for the title, the introduction,
     the expiry or the downloads. Removing an entry ends the sessions it admitted.
   * API: `PUT …/app/viewers` with `add` and `remove`, and `PATCH …/app`.
   * MCP: `brain_page` with `action: "update"`. Change the list with
     `add_viewers` and `remove_viewers` in a call of its own.
3. Open the page as a reader. Ask the person to open the web address in a private
   window. Check the overview, the Graph, the Files and the Shapes.
   * For a list, ask for a code with an address that is on the list. Ask for one
     with an address that is not. Both show the same message, and only the first
     sends an email (card rule [brain.16](https://docs.pnbr.io/concepts/brain.md#rule-brain-16)).
4. Read who looked.
   * CLI: `penumbra brains page activity <brain-id>`.
   * API: `GET …/app/activity`. Expect each person's email, first and last visit
     and the pages they read (card rule [brain.20](https://docs.pnbr.io/concepts/brain.md#rule-brain-20)).

## Check

* `penumbra brains page show <brain-id>` (or `GET …/app`) says `state: published` and
  no `reason`, and its `address` is the web address you give the person. Before the
  first publish, the same read answers `state: unpublished` with `page: null` and the
  plan's `limit` and `used` (the CLI says `Not published. 1 of 3 pages on this plan.`).
* The page shows the Files and the entities of the View, and a File outside the
  View is not found (card rule [brain.18](https://docs.pnbr.io/concepts/brain.md#rule-brain-18)).
* The introduction, the expiry and the downloads are what the person chose.
* For a list, an address that is not on it gets no email.

## If it goes wrong

| You see | Read |
| - | - |
| Publish refused with `brain_view_unavailable` | card rule [brain.1](https://docs.pnbr.io/concepts/brain.md#rule-brain-1) |
| Publish refused with `brain_app_already_published` | card rule [brain.15](https://docs.pnbr.io/concepts/brain.md#rule-brain-15) |
| Publish refused with `plan_brain_app_limit` | card rule [brain.19](https://docs.pnbr.io/concepts/brain.md#rule-brain-19) |
| A request refused with `human_session_required` | card rule [brain.12](https://docs.pnbr.io/concepts/brain.md#rule-brain-12) |
| A list entry refused with `brain_app_viewer_value_invalid` | card rule [brain.16](https://docs.pnbr.io/concepts/brain.md#rule-brain-16) |
| The page says `broken` with a `reason` | card rule [brain.17](https://docs.pnbr.io/concepts/brain.md#rule-brain-17) |
| The page shows less than the person expects | problem [hidden-reads-as-missing](https://docs.pnbr.io/troubleshooting/hidden-reads-as-missing.md) |
| A visitor gets `brain_app_not_found` | card rule [brain.17](https://docs.pnbr.io/concepts/brain.md#rule-brain-17) |

## Worth offering

* Offer to set an expiry time with a message when the page is for a short
  conversation.
* Offer to unpublish the page when the conversation ends
  (`penumbra brains page unpublish <brain-id>`). The runtime refuses the next
  read; cached public content may remain visible for up to 30 seconds
  (card rule [brain.17](https://docs.pnbr.io/concepts/brain.md#rule-brain-17)). Pages for a list are not cached.
* Offer to check the page again after each new publish of the View.

## Report

Name the Brain, its View and what the View includes, in the person's words. Give
the web address from `address`, who opens the page, the expiry and whether downloads are on. Say
what you checked as a reader. Say what you could not check, such as a page for a
list when you cannot read the email. Say that the person decides when to
unpublish.

## Keep going

[Brain](https://docs.pnbr.io/concepts/brain.md) · [View](https://docs.pnbr.io/concepts/view.md) · [Give a client a Brain and check what it answers](https://docs.pnbr.io/guides/ship-a-brain.md) · [Share part of a project with a View](https://docs.pnbr.io/guides/share-with-a-view.md) · [Something outside the View reads as not found](https://docs.pnbr.io/troubleshooting/hidden-reads-as-missing.md)

Penumbra Grammar 0.6.26


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.