# Project pack: Homepage @ 44bf8c1

Facts about **Homepage** for an AI following the [BespokeAI handover guide](https://handoff.bespokeai.software/guide/v1.md). This pack is pinned to one version and never changes after publication.

> Homepage is a start page for your browser or a wall tablet. It gathers the links your household uses into tidy, labelled tiles, with the weather, the date, a search box and live numbers from your home apps, such as tonight's meal from Mealie or how many photos are in Immich. You set it up by editing a few simple text files, so an AI can write them for you. It runs on your own computer and keeps your app passwords out of the browser.

## Version and source
- Repository: https://github.com/gethomepage/homepage
- Pinned commit: `44bf8c196232592049d99275f7c58718d167e9e4`. Use exactly this version.
- Get it: `git clone https://github.com/gethomepage/homepage homepage && cd homepage && git checkout 44bf8c196232592049d99275f7c58718d167e9e4`
- Or download a zip: https://github.com/gethomepage/homepage/archive/44bf8c196232592049d99275f7c58718d167e9e4.zip
- Official docs: https://gethomepage.dev
- Licence: **GPL-3.0-only**. Free to use and change. If you give a changed copy to other people, you must share your source code under the same licence. Running it for yourself or your household has no extra obligations.

## Running it
- Easiest:

  ```sh
  docker run -d --name homepage -p 3000:3000 -e HOMEPAGE_ALLOWED_HOSTS=localhost:3000 -v /path/to/config:/app/config --restart unless-stopped ghcr.io/gethomepage/homepage:latest
  # then open http://localhost:3000; example config files appear in /path/to/config on first start.
  # Add the address you'll use (e.g. 192.168.1.20:3000) to HOMEPAGE_ALLOWED_HOSTS.
  ```

- Needs: Docker (AMD64 or ARM64, so a Raspberry Pi works), For development, Node.js 22 and pnpm
- Develop: `pnpm install && pnpm dev   # http://localhost:3000; copy src/skeleton to config/ first`
- Test: `pnpm test`
- Check/lint: `pnpm lint`
- Build: `pnpm build`
- Stack: javascript, yaml, css (Next.js 16, React 19, Tailwind CSS, next-i18next, NextAuth, Vitest). Difficulty for a non-developer with an AI: **easy**. Everything you see is defined in a handful of YAML files (services, bookmarks, widgets, settings), with custom.css and custom.js for looks. No database. A new service widget is a small, well-documented folder in src/widgets/ with many examples to copy.

## Customisation points (settings → extend → code)
- **services-and-bookmarks** [settings]: Groups of tiles with names, icons and links, plus plain bookmark lists. Sort them by room, person or purpose. → `services.yaml and bookmarks.yaml in the config folder (examples in src/skeleton/; docs/configs/services.md, docs/configs/bookmarks.md)`
- **look-and-layout** [settings]: Name the page, pick a background photo and colour, arrange groups in columns or tabs. → `settings.yaml (src/skeleton/settings.yaml; docs/configs/settings.md) → title, background, theme, colour, layout, tabs, card style, language`
- **info-widgets** [settings]: The top bar with "Good morning", the clock, today's weather and a search box. → `widgets.yaml (docs/widgets/info/, src/components/widgets/) → greeting, date and time, weather, search, resources`
- **custom-css-js** [settings]: Bigger text for a wall tablet, hide elements, or small tweaks without rebuilding. → `custom.css and custom.js in the config folder (docs/configs/custom-css-js.md)`
- **service-widgets** [extend]: Live numbers from your apps, a shared calendar, or any JSON API through the custom API widget. → `widget section of a service in services.yaml (docs/widgets/services/, e.g. homeassistant.md, mealie.md, immich.md, calendar.md, customapi.md, iframe.md)`
- **docker-discovery** [extend]: Tiles appear automatically for containers that carry homepage labels. → `docker.yaml and container labels (docs/configs/docker.md, src/utils/config/docker.js)`
- **mcp** [extend]: Let an AI assistant such as Claude read your setup and, if you allow it, add tiles for you. → `/api/mcp endpoint (docs/configs/mcp.md, src/utils/mcp/homepage-mcp.js)`
- **new-widget** [code]: A widget for an app that isn't supported yet. → `src/widgets/<name>/ (widget.js + component.jsx), registered in src/widgets/widgets.js and src/widgets/components.js; text in public/locales/en/common.json; guide in docs/widgets/authoring/`

## Must keep working
- The config folder. Copy it before experimenting; one YAML indentation mistake can blank the page.
- API keys stay on the server. Widgets must keep fetching through Homepage's proxy, never from the browser directly.
- HOMEPAGE_ALLOWED_HOSTS and login settings. Don't set allowed hosts to * on anything reachable from the internet.
- Existing widget names and options, so other people's config files keep working.

## Staying updatable
Nearly everything is configuration, so most people never need a fork. Homepage's contributing guide says it generally does not accept AI-generated pull requests, and any AI help must be stated clearly in the PR. Keep AI-written widgets in your own copy unless you have reviewed and understood them yourself.

## Data, costs and safety
- Personal data: **no**. Stored in: YAML files plus custom.css and custom.js in the config folder (/app/config in Docker). No database. The config folder holds API keys for your other apps, so treat it as private. Back it up or keep it in a private Git repository; restoring is just copying the files back. Use HOMEPAGE_VAR_ or HOMEPAGE_FILE_ variables to keep keys out of the YAML.
- Service: Your other self-hosted apps (Home Assistant, Mealie, Immich, Paperless and 150+ more) (optional, free): Service widgets show live numbers from these apps using API keys you put in the config.
- Service: Weather providers (Open-Meteo, OpenWeatherMap, WeatherAPI) (optional, free (Open-Meteo needs no key)): Weather in the top bar.
- Service: OIDC sign-in provider (Authentik, Authelia, Keycloak…) (optional, free (self-hosted) or varies): Optional login in front of the page instead of a simple password.
- Setting `HOMEPAGE_ALLOWED_HOSTS`: The addresses you open Homepage at, comma-separated (e.g. 192.168.1.20:3000). Needed for anything other than localhost.
- Setting `PUID`: Run as this user ID instead of root (PGID for the group). Make sure the config folder belongs to that user.
- Setting `HOMEPAGE_AUTH_ENABLED`: Set to true to require a login. Needs HOMEPAGE_AUTH_SECRET, HOMEPAGE_EXTERNAL_URL and a password or OIDC settings.
- Setting `HOMEPAGE_AUTH_SECRET` (**secret**: the person enters it themselves, never in chat): Random string of 32+ characters for signing login cookies (openssl rand -base64 32).
- Setting `HOMEPAGE_EXTERNAL_URL`: The full address people use to open Homepage, needed when login is enabled.
- Setting `HOMEPAGE_AUTH_PASSWORD` (**secret**: the person enters it themselves, never in chat): Password for the simple login. Never paste it into an AI chat.
- Setting `HOMEPAGE_MCP_ENABLED`: Turns on the optional AI assistant (MCP) endpoint at /api/mcp. Off by default.
- Setting `HOMEPAGE_MCP_TOKEN` (**secret**: the person enters it themselves, never in chat): Token (32+ characters) for AI assistants using the MCP endpoint. It can read every API key in your config.
- Setting `HOMEPAGE_MCP_ALLOW_WRITE`: Lets the MCP endpoint change your config files. Leave off unless you need it.
- Homepage has no login unless you turn one on. Keep it on your home network, or put it behind a reverse proxy with HTTPS and HOMEPAGE_AUTH_ENABLED.
- The config folder holds API keys for your other apps. Never paste it, or HOMEPAGE_* secrets, into an AI chat; share it with keys removed.
- Mounting the Docker socket gives Homepage a lot of power over your server. Use it read-only, or a socket proxy, or leave it out.
- The optional MCP endpoint can read every key in your config and, with writes on, change custom.js. Only enable it with a long token and on a trusted network.

---

# Customising Homepage

Homepage is configured, not programmed. Almost every change is an edit to a YAML file in your config folder,
and Homepage picks it up when you reload the page. Only write code for a widget that doesn't exist yet.

## Level 1: Settings (no code)
All files live in your config folder (`/app/config` in Docker). Homepage creates examples from `src/skeleton/` on first start.

- **`services.yaml`:** groups of tiles, each with a name, icon, link and description.
- **`bookmarks.yaml`:** simple lists of links with short abbreviations.
- **`widgets.yaml`:** the top bar: greeting, date and time, weather (Open-Meteo needs no key), search, server resources.
- **`settings.yaml`:** title, background image and blur, theme and colour, layout (columns, tabs, collapsible groups), card style, language, link targets. See `docs/configs/settings.md`.
- **`custom.css` / `custom.js`:** bigger text for a wall tablet, hidden elements and other small tweaks (`docs/configs/custom-css-js.md`).
- **Secrets:** write `{{HOMEPAGE_VAR_MEALIE_KEY}}` in YAML and set the value as an environment variable, so keys stay out of the files.

## Level 2: Extend (no fork)
- **Service widgets:** add a `widget:` block under a service for live numbers from Home Assistant, Mealie, Immich, Paperless, Photoprism and 150+ others (`docs/widgets/services/`).
- **Calendar widget:** show iCal feeds, such as a family Google calendar or bin collection dates (`docs/widgets/services/calendar.md`).
- **Custom API widget:** show fields from any JSON API (`docs/widgets/services/customapi.md`), or embed a page with the iframe widget.
- **Docker labels:** containers labelled `homepage.group`, `homepage.name` and so on appear automatically (`docs/configs/docker.md`).
- **MCP endpoint:** let an AI assistant read your setup and, if you allow writes, add services for you (`docs/configs/mcp.md`). Off by default.

## Level 3: Code

| Change | Where |
|---|---|
| New service widget | `src/widgets/<name>/widget.js` (API mapping) and `component.jsx` (display); register in `src/widgets/widgets.js` and `src/widgets/components.js` |
| Widget docs | `docs/widgets/services/<name>.md`; authoring guide in `docs/widgets/authoring/` |
| Wording | `public/locales/en/common.json` (other languages come from Crowdin) |
| New info widget | `src/components/widgets/` |
| Page layout | `src/pages/index.jsx`, `src/components/services/`, `src/components/bookmarks/` |
| Loading config | `src/utils/config/` |

## Running locally
- **Just use it:** the Docker command in `bespoke.yaml`, then open http://localhost:3000.
- **Develop:**
  1. Install Node.js 22 and pnpm.
  2. Run `pnpm install`.
  3. Copy `src/skeleton` to `config/`.
  4. Run `pnpm dev` and open http://localhost:3000.
- **Check:** `pnpm lint` and `pnpm test`.

## Pitfalls
- YAML is fussy about spaces. A broken file shows an error on the page; the logs say which line.
- "Host validation failed": add the exact address you use to `HOMEPAGE_ALLOWED_HOSTS`.
- Widgets need the app's address as Homepage's container sees it, which may differ from the address in your browser.
- Homepage generally does not accept AI-generated pull requests. Keep your own widgets in your copy unless you understand them fully.

---
Machine-readable: [bespoke.yaml](https://handoff.bespokeai.software/p/homepage/44bf8c1/bespoke.yaml) · Agent skill: [SKILL.md](https://handoff.bespokeai.software/p/homepage/44bf8c1/SKILL.md)
