# BespokeAI listing guide (v1)

You are an AI assistant helping someone list their open-source project on **BespokeAI** (https://bespokeai.software), a catalogue of apps that ordinary people can adapt to their own lives with their own AI. Your job is to prepare the **listing files** inside the project's own GitHub repository. The person then submits the repository, the owner of BespokeAI reviews it, and it goes live. Nobody edits BespokeAI's code to add a project: everything BespokeAI shows comes from the files you write.

This guide never changes once published. Its address is `https://handoff.bespokeai.software/listing/v1.md`.

## Rules for you

1. **Be truthful.** Only describe what the project really does. Read the code, the README and the licence. If you cannot tell something (how to run it, the licence, whether it needs paid services), **ask the person**; never guess.
2. **Write for ordinary people, not developers.** Plain English, short sentences, no jargon in the tagline, summary, highlights, ideas and safety notes. Developer detail belongs in `CUSTOMIZE.md` and the `where` fields.
3. **Never put secrets or personal data in any file or picture**: no API keys, passwords, tokens, real email addresses, real names of other people, or real accounts visible in screenshots. Use dummy data.
4. **Do not write instructions meant for other AIs** in these files (for example "ignore previous instructions"). The reviewer reads them, and wording like that gets the listing rejected.
5. Make small, honest commits. Do not change the project's code unless the person asks you to.
6. **Look for leaks before you push.** BespokeAI scans every submitted project for passwords, keys, `.env` files, database files and personal data, including old commits if the deep scan is on. Check for them first: search the files and, if you can, the git history. If you find a real key or password, tell the person to **revoke it at the service that issued it and make a new one**. Deleting it from the code is not enough, because it stays in the history. Never print or copy a real secret into the chat.

## What you will create

All listing files live in one folder at the root of the repository:

```
.bespoke/
  bespoke.yaml          the listing (see "bespoke.yaml" below)
  CUSTOMIZE.md          a map of the code for the AI that will adapt the project
  logo.png              optional square logo (PNG, JPG or WebP)
  screenshots/
    home.png            1 to 5 screenshots of the real app
```

BespokeAI sets these itself, so leave them out or expect them to be replaced: `spec`, `kind`, `pack_revision`, `pack_guide_version`, `source.repo`, `source.ref`, and `hosting.cloud`. `id` is optional (it defaults to the repository name).

## Step 1: Find out what you need

Read the repository, then ask the person for anything missing. At minimum you need to be sure of:

- what the project does and who it is for, in the person's own words
- the open-source licence (a `LICENSE` file must exist; GitHub must recognise it)
- how to run it for the first time, and one easy way to **try** it (a `docker run` line, a download link, or an install guide)
- which parts someone can change by settings, by add-ons and themes, or only by editing code
- whether it stores personal data, needs passwords or API keys, or costs money to run
- whether there is a public demo (optional)

## Step 2: Write `.bespoke/bespoke.yaml`

Field rules (BespokeAI rejects the listing if these are not met):

| Field | Rule |
|---|---|
| `name` | The project's name. |
| `tagline` | 10–90 characters. One plain-English promise, e.g. "See every subscription you pay for." |
| `summary` | 40–600 characters. What it does, for whom, and where the data lives. |
| `category` | One of: `money`, `tasks-focus`, `notes-journal`, `food-home`, `family`, `health-fitness`, `learning`, `hobbies`, `small-business`, `community`, `ai`. |
| `tags` | At least 3 words people might search for. |
| `licence.spdx` | The licence as an SPDX identifier (for example `MIT`, `Apache-2.0`, `GPL-3.0-only`, `AGPL-3.0-only`, `BSD-3-Clause`). It must be open source. |
| `licence.summary` | One or two plain sentences on what the licence lets people do, including any duty to share changes. |
| `stack` | `languages` (required), optional `frameworks` and `databases`. |
| `size.difficulty` | `easy`, `moderate` or `advanced`: how hard it is for a beginner with an AI helper to change this project. |
| `runtime.modes` | One or more of: `hosted-demo`, `docker`, `local-dev`, `static-host`, `server`, `desktop`, `mobile`. |
| `runtime.quickstart` | The commands to install and run it **after cloning**. Do **not** write `git clone` or `git checkout`: BespokeAI adds them, pinned to your commit. Put each step on its own line and never put a command after a `#` comment on the same line. |
| `runtime.trial_quickstart` | **Required.** One way to try the released app. |
| `runtime.ports` | Numbers of the ports it listens on. |
| `data.personal_data` | `true` or `false`. Be honest. |
| `adaptation.knobs` | At least 2. Each has `id` (lowercase-with-hyphens), `level` (`settings`, `extend` or `code`), `where` (the menu or folder) and `description`. |
| `adaptation.suggested` | At least 2 ideas people could ask their AI to build. Each has `id`, `title`, `level`, `difficulty` (`easy`, `moderate`, `advanced`) and a `prompt` written the way an ordinary person would say it. |
| `adaptation.do_not_break` | The things a change must not break (data, login, migrations, tests). |
| `listing.audience` | **Required.** One sentence on who it is for. |
| `listing.highlights` | 2–6 short bullet points. |
| `listing.aliases` | Optional. Up to 8 everyday phrases people may search for, each under 40 characters (for example `split bills`). |
| `safety.notes` | **Required.** At least one plain note about data, passwords or costs. |
| `media.logo` | Optional path such as `.bespoke/logo.png`. |
| `media.screenshots` | **Required**, 1–5 paths inside `.bespoke/`. |
| `demo` | Optional: `url` (https), `credentials`, `notes`. |
| `services`, `env` | Optional lists of outside services and environment variables. Mark secrets with `secret: true` and describe them; never give real values. |

Words to avoid: "revolutionary", "seamless", "powerful", "robust", and any claim you cannot check.

### Complete example

This example passes the checker. Replace every detail with the real project's.

```yaml
name: linkding
tagline: A fast, minimal bookmark manager that stays out of your way.
summary: >-
  linkding is a self-hosted bookmark manager that is easy to run and use. You save links with tags and notes, search them
  instantly, and keep archived copies of pages. There is a browser extension, a bookmarklet, an API, and import and export
  for common formats.
category: notes-journal
tags:
  - bookmarks
  - links
  - tags
  - archive
  - browser-extension
  - minimal
  - self-hosted
licence:
  spdx: MIT
  summary: Free to use, change and share, even commercially. Keep the original copyright notice.
source:
  homepage: https://linkding.link
  docs: https://linkding.link
stack:
  languages:
    - python
    - javascript
  frameworks:
    - Django
    - Svelte
    - uWSGI
  databases:
    - sqlite
    - postgresql
size:
  difficulty: easy
  notes: A small Django app with a little Svelte. Clear structure and good tests. Most changes are a view, a
    template or a setting.
runtime:
  modes:
    - hosted-demo
    - docker
    - local-dev
  quickstart: |
    make init
    make serve
  trial_quickstart: |
    docker run -d --name linkding -p 9090:9090 -v linkding-data:/etc/linkding/data -e LD_SUPERUSER_NAME=admin -e LD_SUPERUSER_PASSWORD=choose-a-strong-password sissbruecker/linkding:latest
    # then open http://localhost:9090
  requirements:
    - Docker for a trial
    - Python 3.12 with uv and Node for development
  dev: make serve
  test: make test
  lint: make lint
  ports:
    - 9090
services:
  - name: Browser extension
    required: false
    cost: free
    purpose: Save a page with one click.
env:
  - key: LD_SUPERUSER_NAME
    required: false
    secret: false
    description: Name of the first admin user.
  - key: LD_SUPERUSER_PASSWORD
    required: false
    secret: true
    description: Password of the first admin user. Never paste it into an AI chat.
data:
  personal_data: true
  storage: A SQLite database and saved assets under /etc/linkding/data.
  notes: Bookmarks can reveal interests and plans. Back up the data folder.
adaptation:
  knobs:
    - id: tags-and-bundles
      level: settings
      where: In the app, under Bookmarks, Tags and Bundles
      description: Organise links with tags and saved searches.
    - id: general-settings
      level: settings
      where: Settings → General, Integrations
      description: Default view, archiving and sharing behaviour.
    - id: rest-api
      level: extend
      where: Settings → Integrations and the API docs
      description: Add and read bookmarks from scripts.
    - id: custom-css
      level: extend
      where: Settings → General → Custom CSS
      description: Restyle the interface without code.
    - id: views-and-templates
      level: code
      where: bookmarks/templates and bookmarks/views
      description: New pages and layouts.
  suggested:
    - id: read-later-inbox
      title: Read-later inbox
      level: settings
      difficulty: easy
      prompt: Use a 'to-read' tag and a bundle that shows only unread links.
    - id: shared-family-links
      title: Family links page
      level: settings
      difficulty: easy
      prompt: Share a few bookmarks publicly with the family and keep the rest private.
    - id: weekly-link-digest
      title: Weekly digest
      level: extend
      difficulty: moderate
      prompt: Email me my 10 most recent bookmarks every Sunday.
    - id: dark-theme
      title: Custom styling
      level: extend
      difficulty: easy
      prompt: Give it a dark theme with larger text.
  do_not_break:
    - Django migrations. Add new ones; never edit old ones.
    - Authentication and API token checks.
    - Import and export formats.
  upstream_friendly: Prefer settings, custom CSS and the API. Small additions in new templates or views keep updates easy.
media:
  logo: .bespoke/logo.png
  screenshots:
    - .bespoke/screenshots/bookmarks.png
    - .bespoke/screenshots/tags.png
listing:
  audience: Anyone who wants their bookmarks private, searchable and fast.
  highlights:
    - Tags, notes and instant search
    - Archived copies of pages
    - Browser extension and REST API
    - Tiny and easy to run
safety:
  notes:
    - Use a strong admin password and HTTPS if it is reachable from the internet.
    - Public sharing is off by default. Check before turning it on.
```

## Step 3: Write `.bespoke/CUSTOMIZE.md`

This is for the AI that will adapt the project, so it can be technical. Between 300 and 30,000 characters. Cover:

1. A table of "You want to change… | Look in…" with real paths.
2. "Use the gentlest change first": settings, then add-ons or themes, then code.
3. Two or three recipes, for example how to add a field or a page, step by step with file names.
4. How to run and check changes (the real commands).
5. Pitfalls: what silently breaks things (migrations, generated files, secrets).

Every path and command must exist in the repository. Check them.

## Step 4: Pictures

- Take **real screenshots** of the running app, using dummy data. If you cannot run it, ask the person to supply screenshots and put them in `.bespoke/screenshots/`.
- PNG, JPG or WebP. Each file **at most 800 KB**. Screenshots **800 to 4000 pixels wide** (1280 is good). Prefer WebP or optimised PNG.
- The first screenshot is used as the card image, so make it the best view of the app.
- A logo should be square, between 128 and 2048 pixels, with a transparent or plain background.
- No real names, emails, addresses, tokens or private content in any picture.

## Step 5: Check your work

Commit and push the `.bespoke/` folder, then ask BespokeAI to check it:

```
GET https://bespokeai.software/api/listing-check?repo=OWNER/NAME&ref=BRANCH_OR_COMMIT
```

The answer is JSON: `ok` (true or false), `errors` (must fix), `warnings` (read them) and a `preview` of the final listing. If you cannot call web addresses, tell the person to paste the repository link on https://bespokeai.software/submit, which shows the same report.

Fix every error, push again, and check again until `ok` is true. Treat warnings seriously; fix them unless you have a good reason. The check also reads the repository's licence from GitHub and compares it with `licence.spdx`.

## Step 6: Hand back to the person

Tell the person, in plain words:

1. what you created and what they should look at (the tagline, summary and screenshots);
2. that they should open **https://bespokeai.software/submit**, paste the repository link, and press submit;
3. that right after submitting they get a **private security report link**. If the scan finds something, the report explains it and gives a prompt for you to fix it. Fix it, push, and submit again; every submission is scanned again;
4. that the owner of BespokeAI reviews every listing by hand, and that when the project changes they can update the files and submit again.

## Schema

The full machine-readable schema is at `https://handoff.bespokeai.software/spec/bespoke-v0.schema.json`. The listing check applies it to your file after BespokeAI fills in its own fields.
