---
name: business-profile
description: "Populate the business's operational data in the graph — identity, address, opening hours, FAQs, brand assets, and services. Conversational setup that reads existing data first and fills gaps."
---

# Business Profile Setup

Invoked by the admin agent directly.

Applies when the business owner wants to set up, complete, or update their business profile — or when a session-start check reveals missing operational data in the graph.

## When to Activate

- Admin asks to set up, edit, or complete their business profile
- Onboarding step 9 delegates here on first run **only when the operator picked `business-owner` mode**. Personal mode bootstraps a personal-profile `Person` directly inside step 9 and does NOT invoke this skill.
- Session-start graph check shows a `LocalBusiness` node with missing data (no hours, no services, empty description)
- A recorder cycle reports `no-admin-user` or `no-local-business` — the graph lacks the prerequisite node. (For personal-mode accounts, this signal should not fire because the personal-profile `Person` already satisfies the precondition — if it does fire, the personal-profile node is missing or its `role` is wrong.)
- Admin asks questions like "update my address", "add our opening hours", "change the phone number"

## First-run path (no LocalBusiness yet)

The `AdminUser` and the operator's personal-profile `Person` are written deterministically at PIN setup time, so this skill no longer creates the AdminUser. When onboarding step 9 invokes this skill in `business-owner` mode, or when the operator's graph has no `LocalBusiness`:

1. **LocalBusiness.** Ask the operator for the business name first — this is the only mandatory property. Confirm the name and the OWNS link to the AdminUser. The recorder writes the `LocalBusiness` node with `scope: "shared"` and the OWNS edge in its next turn.
2. **Capture the remaining domains** (address, hours, services, FAQs, brand assets) in conversation. After the operator confirms each batch, the recorder folds those properties onto the `LocalBusiness` and adds the related nodes (`OpeningHoursSpecification`, `Service`, `FAQPage`, `ImageObject`).

Adapt the order if the operator provides data in a different sequence — the invariant is: the `LocalBusiness` is named and confirmed before any related-node batch is discussed. Confirm each batch with the operator before moving on; the recorder reads the confirmation off the transcript.

## Constraints

- **Schema-first.** Before discussing a batch, load `memory/references/schema-base.md` via `plugin-read`. If `businessType` is known on the `LocalBusiness` node, also load the matching vertical schema. Confirm which schemas were loaded so the recorder uses the right property names.
- **Existence-first, then read.** Before any claim about whether a `LocalBusiness` exists, call `memory-node-exists { label: "LocalBusiness" }`. Only `exists === false` is the first-run signal — an empty `memory-search` result is not, because a freshly seeded `LocalBusiness` with no name/description yet has nothing to score against either ranker. When `exists === true`, then use `memory-search` to read the existing `LocalBusiness` node and its related entities before asking the operator anything. Do not re-ask for data that is already in the graph — reference it and confirm it is still correct. Only on `exists === false` skip the search and proceed with the first-run path above.
- **Confirm before recording.** Present each batch of data back to the operator and get explicit confirmation. The recorder writes off the confirmed transcript; unconfirmed prose is not a record.
- **Exact property names.** Use Schema.org camelCase property names exactly as defined in the loaded schema reference. No synonyms, no abbreviations.
- **No placeholders.** Never propose empty strings, "TBD", or "unknown" as property values — they degrade search quality via poor embeddings. If a value is unknown, skip it.
- **Conversational, not a form.** Adapt to what the operator provides. Accept partial input and infer where reasonable (e.g. "9-5 weekdays" means Mon-Fri 09:00-17:00). Allow skipping sections and returning later.

## Data Domains

Six categories of operational data, each mapping to graph nodes defined in `schema-base.md`:

| Domain | Node type | Relationship to LocalBusiness |
|--------|-----------|-------------------------------|
| Identity (name, description, telephone, email, url) | `LocalBusiness` properties | — (direct properties) |
| Address (streetAddress, addressLocality, addressRegion, postalCode, addressCountry) | `LocalBusiness` properties | — (flattened, Phase 0) |
| Opening hours (per day: dayOfWeek, opens, closes) | `OpeningHoursSpecification` | `HAS_HOURS` |
| Brand assets (logo, hero image — name, contentUrl, encodingFormat, purpose) | `ImageObject` | `HAS_BRAND_ASSET` |
| FAQs (question + answer pairs) | `FAQPage` → `Question` | `HAS_FAQ`, then `CONTAINS` |
| Services (name, description, offers/pricing) | `Service` | `OFFERS` (from LocalBusiness) |

## Recording Nodes

When the operator confirms a new related node (hours, FAQs, assets, services), make sure the conversation names the `LocalBusiness` it attaches to and the edge type — the recorder reads this off the transcript and writes the node with the right adjacency. For FAQ questions, that means the operator confirms the `FAQPage` first, then the individual `Question`s that hang off it via `CONTAINS`.

When the operator changes existing data (a phone number, an address), reference the existing node by name in conversation; the recorder finds it via search and folds the new properties in.
