Draft routing.md v1: topic map, overlap rule, never-route list
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
195
routing.md
Normal file
195
routing.md
Normal file
@@ -0,0 +1,195 @@
|
||||
# Routing Rules (`routing.md`)
|
||||
|
||||
**Purpose:** tell the running Hub how to choose a destination.
|
||||
**Owner:** Sam (human-edited).
|
||||
**Status:** v1 draft. First pass. Edit the tables; keep the three sections.
|
||||
**Related:** `hub_brief.md` (design), `docs/hub-api.md` (inbound API, section 5),
|
||||
`docs/ask-contract.md` (project interface).
|
||||
|
||||
This file is **not** `AGENTS.md`. `AGENTS.md` tells coding agents how to work.
|
||||
This file tells the Hub how to choose. Keep them separate.
|
||||
|
||||
---
|
||||
|
||||
## How the Hub uses this file
|
||||
|
||||
For each request, the Hub runs the checks in this order:
|
||||
|
||||
1. **Never-route check.** If the request is a control action (section 3), return
|
||||
`status: "refused"`. Stop. Do not ask an LLM.
|
||||
2. **Read capabilities.** Read the topic list from each project's
|
||||
`/capabilities` (`docs/ask-contract.md`).
|
||||
3. **Read this file.** Read the topic map (section 1) and the overlap rule
|
||||
(section 2).
|
||||
4. **Ask the LLM.** Give the LLM the question, the capability lists, and this
|
||||
file. The LLM returns one of four answers:
|
||||
- `route` — send to one project.
|
||||
- `fanout` — ask several projects, then merge.
|
||||
- `clarify` — ask the user one short question.
|
||||
- `no_match` — say it does not know.
|
||||
5. **Route.** Send the request. The action call holds no LLM (brief rule 4).
|
||||
|
||||
A project name in this file must match the `project` value in that project's
|
||||
`/capabilities` reply. A new project adds one row here and one `/capabilities`
|
||||
reply. Build the ability once.
|
||||
|
||||
**Fanout:** use it only when the question clearly needs two topics at once, for
|
||||
example "what do I have on today?" (school + email + calendar). Default to
|
||||
`route`, then `clarify` when unsure.
|
||||
|
||||
---
|
||||
|
||||
## 1. Topic to project map
|
||||
|
||||
The Hub uses these topics as the plain-language keys for routing. Keep the list
|
||||
short. Add a topic only when a project really answers it.
|
||||
|
||||
| Topic (what the user says) | Project | Kind | Status |
|
||||
|---|---|---|---|
|
||||
| email, inbox, mail, message, unread | `email_agent` | query `/ask` | placeholder — not built |
|
||||
| school, Compass, homework, timetable, class, NHS appointment | `compass_nhs` | query `/ask` | placeholder — not built |
|
||||
| screen time, internet use, time limits, what did the kids do online | `internet_control` | query `/ask` | placeholder — not built |
|
||||
| lights, lamp, switch, plug, timer, reminder, calendar event, device, thermostat | `home_assistant` | command (direct) | active service |
|
||||
| speak, say it out loud, house speakers, announce | `speakers` | command (direct) | active service |
|
||||
| search, look up, what is, who is, weather, news | `web_search` | command (direct) | placeholder — not built |
|
||||
| notify, notification, alert me, remind my phone | `apprise` | command (direct) | active service |
|
||||
| file a job, plan this, research this, slow task, work bench | `paperclip` | decision (approval) | active service |
|
||||
| phone screen, tap, open an app, type on the phone, scroll | `artemis` | command (direct, action only) | placeholder — not built |
|
||||
| visitor, front door, who is at the door | `front_door_cam` | peer intercom | placeholder — not built |
|
||||
| talk to the house voice, Hey Jervis | `jervis` | way in (voice only) | active service |
|
||||
| chat, per-person chat, dsh | `dsh` | peer (keeps its own chat) | active service |
|
||||
|
||||
**Not destinations.** These are ways in, not projects to route to. A request that
|
||||
names them still routes to the real destination.
|
||||
|
||||
| Name | Why it is not a destination |
|
||||
|---|---|
|
||||
| `phone_app` | Way in. Sends voice to the Hub. |
|
||||
| `console_portal` | Way in and dashboard. |
|
||||
| `admin_app` | Way in for restricted actions. Calls the internet control service directly. |
|
||||
|
||||
### Placeholder entries
|
||||
|
||||
Each project below is planned but **not built**. Keep the row and the placeholder
|
||||
so the file is ready. Replace the placeholder when the project declares its
|
||||
`/capabilities`.
|
||||
|
||||
| Project | Expected topics (placeholder) | First build step |
|
||||
|---|---|---|
|
||||
| `email_agent` | email, inbox, mail | brief build order step 5 |
|
||||
| `compass_nhs` | school, homework, timetable | brief build order step 5 |
|
||||
| `internet_control` | screen time, internet use, limits | brief build order step 6 |
|
||||
| `artemis` | phone screen control | brief build order step 7 |
|
||||
| `web_search` | search, weather, facts | pending |
|
||||
| `front_door_cam` | visitor | pending |
|
||||
|
||||
---
|
||||
|
||||
## 2. Preferred project when two overlap
|
||||
|
||||
Some topics fit two projects. The Hub uses this preference order. The left
|
||||
project wins. If the question still fits both, the Hub uses `clarify`.
|
||||
|
||||
| Overlap | Preferred | Other | Reason |
|
||||
|---|---|---|---|
|
||||
| "today" / "schedule" | `home_assistant` (calendar) | `compass_nhs` (timetable) | The calendar answers the whole day. School answers school only. |
|
||||
| "what do I have on" | `fanout` (`compass_nhs` + `email_agent` + `home_assistant`) | one project | Merge the three, then answer once. |
|
||||
| "message" | `email_agent` (email) | `dsh` (chat) | An email question is about the inbox, not the chat. A chat question stays in dsh. |
|
||||
| "reminder" | `home_assistant` | `apprise` | Home Assistant owns timers and reminders. Apprise only delivers. |
|
||||
| "appointment" | `compass_nhs` | `home_assistant` (calendar) | A health or school appointment is NHS or school data first. |
|
||||
| "what did the kids do" | `internet_control` | `email_agent` | Online use is the internet control service's data. |
|
||||
| "is the doorbell" / "visitor" | `front_door_cam` | `artemis` | The camera owns the visitor. Artemis only acts on the screen. |
|
||||
|
||||
Rules:
|
||||
|
||||
1. A **domain question** goes to the project that owns the data. Do not fanout
|
||||
for one topic.
|
||||
2. A **day summary** fans out. Merge to one short sentence.
|
||||
3. Two projects with equal claim, and the preference table does not decide, use
|
||||
`clarify`. Ask one short question. Example: "School or email?"
|
||||
4. Never fanout to more than three projects.
|
||||
5. A project that is down returns `status: "unavailable"` for that part. Do not
|
||||
fail the whole fanout.
|
||||
|
||||
---
|
||||
|
||||
## 3. Never-route list (control actions)
|
||||
|
||||
The Hub **never** routes a control action. It returns `status: "refused"` and
|
||||
points at the admin app. This list is the authority for that decision. Add every
|
||||
new control action here before you add the ability.
|
||||
|
||||
A control action is a **high-consequence change**. It changes parental controls,
|
||||
limits, or a child's access. Only the admin app does it, and it calls the
|
||||
internet control service **directly**. The Hub is not in that path
|
||||
(brief rules 8 and 11).
|
||||
|
||||
The Hub must refuse when the request means any of these:
|
||||
|
||||
| Control action | Refuse? |
|
||||
|---|---|
|
||||
| Cut the kids' internet. | **Refuse** |
|
||||
| Restore the kids' internet. | **Refuse** |
|
||||
| Change an internet time limit or daily allowance. | **Refuse** |
|
||||
| Change an internet schedule (bedtime, school hours). | **Refuse** |
|
||||
| Add, remove, or change a blocklist or content filter. | **Refuse** |
|
||||
| Change any parental control on any account or device. | **Refuse** |
|
||||
| Add, change, or remove a child profile or a device rule. | **Refuse** |
|
||||
| Pause, lock, or unlock a family device for a policy reason. | **Refuse** |
|
||||
| Any other state change on the internet control service. | **Refuse** |
|
||||
|
||||
The alternative reply is always the same:
|
||||
|
||||
> "Use the admin app to change internet limits."
|
||||
|
||||
`status: "refused"`, `route.kind: "refused"`,
|
||||
`route.reason: "high_consequence_control"`. See `docs/hub-api.md`, section 5.
|
||||
|
||||
### Not in the never-route list
|
||||
|
||||
These do **not** route as control. Keep them out of this list.
|
||||
|
||||
| Action | Path | Why |
|
||||
|---|---|---|
|
||||
| Turn on a lamp. | Hub → Home Assistant | Fast command. Low consequence. |
|
||||
| Set a timer or reminder. | Hub → Home Assistant | Fast command. Low consequence. |
|
||||
| Add a calendar event. | Hub → calendar project | Fast write. Approval not required. |
|
||||
| Speak on the house speakers. | Hub → speakers | Output only. |
|
||||
| File a Paperclip job. | Hub → approval → Paperclip | Slow decision. Needs a tap, but it does route through the Hub. |
|
||||
| Ask about screen time. | Hub → `internet_control` `/ask` | Read only. A query is allowed. |
|
||||
|
||||
**A spoken keycode is not the lock.** Voice may ask. Only the admin app confirms.
|
||||
|
||||
---
|
||||
|
||||
## 4. What the admin app may send to the Hub
|
||||
|
||||
The admin app is the only trusted door. It uses its own token
|
||||
(`HUB_TOKEN_ADMIN`). It may send the Hub:
|
||||
|
||||
1. **Queries and fast commands** — the same as any way in, through `POST /ask`.
|
||||
2. **A confirmation decision** — one yes or no for a Hub-owned approval, through
|
||||
`POST /approve`. In v1 this files a Paperclip job.
|
||||
|
||||
The admin app **must not** send a parental control change to the Hub. There is no
|
||||
Hub route for it. The admin app calls the **internet control service directly**,
|
||||
then shows the result. The Hub does not record, route, or run that change.
|
||||
|
||||
In one line: **the admin app may send the Hub a query, a fast command, or a
|
||||
Hub-owned approval decision — never a parental control change.**
|
||||
|
||||
---
|
||||
|
||||
## 5. Reply shape (short note)
|
||||
|
||||
The Hub returns the reply to the source and keeps it short (brief rule 6). The
|
||||
shape comes from `source` and `want` in `docs/hub-api.md`, section 9. This file
|
||||
does not change the reply shape.
|
||||
|
||||
---
|
||||
|
||||
## Change log
|
||||
|
||||
| Version | Date | Change |
|
||||
|---|---|---|
|
||||
| v1 | 2026-10-10 | First draft. Topic map, overlap rule, never-route list, admin app line. |
|
||||
Reference in New Issue
Block a user