@awesomate/hosting-mcp
Version:
Awesomate MCP server — lets Claude manage your Awesomate WordPress hosting, plan, limits, n8n automations, and build Node/static apps + databases
114 lines (91 loc) • 5.64 kB
Markdown
# People, places and topics — the entity layer
The platform builds one identity per person, place and topic across all of
the tenant's media (face clusters from photos/video, text names from posts,
books and transcripts). That is what lets `/v1/answer` handle "everything
about X", "who appears most often with X" and "what connects X and Y" with
citations. The user curates it — naming, merging, hiding, and deciding alias
suggestions — through `awesomate_knowledge_people` or the hub's
Knowledge → People page. The hub stores none of this; every call is a live
read of platform metadata (ids, counts, titles, locators — never photos,
never document text).
## Probe first
`list`, `aliases` and `resolve` check `GET /api/knowledge/entities` before
anything else. `available: false` means the platform has not enabled the
layer for this tenant yet. Say so plainly ("people and connections aren't
switched on for your knowledge base yet — nothing to do on your side"), do
not retry, and carry on with sources/ask. When it IS available the result
carries `counts` (named, unnamed, aliases pending, places, topics),
`last_resolution_at` and `resolution_job`.
## What a person looks like
```
{ person_id, handle, display_name | null, status: named|unknown|hidden,
face_count, text_mentions, docs, aliases }
```
- `display_name: null` + `status: 'unknown'` is an **unnamed face cluster**.
`handle` (e.g. `unknownBB0007`) is an opaque per-tenant label — it is NOT a
name, and nothing about it tells you who the person is.
- `get {personId}` adds `aliases[]` (text forms already linked), `co_mentions[]`
(`{entity_id, kind, label, shared_docs}`) and `docs[]` — the witness
sources, rendered for the user as `[n] title — (locator)` with the kind.
- Photos of a cluster exist only on the hub page. You cannot see them; the
user can. When they want to identify someone, send them there.
## Naming a person — the rules
1. **Only a name the user gives.** Never infer identity from a handle, from
co-mentions, from an alias suggestion's confidence, or from your own
knowledge of who "probably" appears in this content.
2. **Confirm the cluster before the name lands.** Show the counts and the
witness sources from `get` and ask "is this the person you mean?" — two
unnamed clusters can both be "the guy in the blue shirt". If the user is
working from photos, they confirm on the hub page and give you the
`handle` or `person_id`.
3. **`rename {personId, displayName}`**, then read `person.display_name` and
`relabelled` back. The platform propagates the name into facets and
queues a resolution; the agent answers with it after the next reindex.
4. A rename on an already-named person replaces the name everywhere. Same
confirmation.
## Merging duplicates
Two entries for one real person (a face cluster and a text-only person, or
two clusters the face pipeline split). `merge {personId, intoPersonId}` moves
every face and alias of `personId` onto `intoPersonId` and hides the source.
Before calling: name both entries to the user with their counts, say which
one survives, and get an explicit yes — reversal is a support request. Read
`faces_moved` / `aliases_moved` back afterwards. Never merge into a hidden
person; never merge a person into themselves (the tool refuses).
## Hiding
`hide {personId}` removes a person from answers (their sources stay
indexed); `unhide` brings them back. Reversible, so a confirmation sentence
is enough. Hidden people are listed with `status: 'hidden'`.
## Alias suggestions
`aliases` lists pending suggestions: a text form the content uses
(`alias`, normalised as `alias_norm`) that the platform thinks refers to a
known entity (`suggested_entity_id`, `suggested_label`, `confidence`), with
`sample_docs` as evidence and `mention_count`. **Identity is the pair
`(kind, alias_norm)` — there is no alias id.** Present alias → suggested
match → confidence → a sample title or two, then act ONLY on the user's
word:
- `decide {kind, aliasNorm, decision: 'accept', entityId}` — link it to the
suggested (or another known) entity.
- `decide {…, decision: 'accept', createPersonName}` — the alias is a real
person nobody has a cluster for yet; creates them (person kind only).
- `decide {…, decision: 'reject'}` — stays plain text, not suggested again.
Mentions re-link on the next resolution, so counts move after a short delay.
## Re-running resolution
`resolve` re-scans the content for people/places/topics, applies the user's
names and decisions (which are never undone by a re-run), and refreshes the
connections. It runs in the background and **counts toward the ingestion
allowance** — ask first. `202 queued` starts one; `200 running` means one is
already in flight and nothing new was started. A `resolution_job` that has
been `running` for over an hour is stuck — say so and offer
`awesomate_support`.
## Answering "who appears with X"
Once people are named, `awesomate_knowledge_ask` handles relationship
questions ("who appears most often with Dale?", "what connects Dale and
Fiji?") with citations to the witnessing photos/posts. Pass names exactly as
the user says them. If the answer names nobody, check `list` — the people
involved may still be unnamed clusters, which the platform never names in an
answer.
## What never happens here
- No guessing identities, no "this is probably …".
- No photos through these tools; no document text either.
- No rename / merge / decide / resolve without the user's explicit approval.
- No retry loop on `available: false` — it is a state, not an error.