Add /ask contract; clarify peers, query vs control, identity gap
This commit is contained in:
137
docs/ask-contract.md
Normal file
137
docs/ask-contract.md
Normal file
@@ -0,0 +1,137 @@
|
||||
# The `/ask` Contract
|
||||
|
||||
**Purpose:** one small, uniform interface between the Hub and every data project.
|
||||
**Applies to:** email agent, Compass/NHS, internet control. Not Artemis (action only).
|
||||
**Status:** agreed shape. Build both sides to this.
|
||||
|
||||
---
|
||||
|
||||
## Why
|
||||
|
||||
Each project is the expert on its own data. The Hub is the expert on routing and
|
||||
reply shape. The Hub must **never** learn a project's data model.
|
||||
|
||||
One contract keeps the Hub thin and lets every project be built and used alone.
|
||||
|
||||
## The rule
|
||||
|
||||
> A project answers questions about **its own** domain. It reads only. It never
|
||||
> changes state on `/ask`.
|
||||
|
||||
Writes (cut internet, add to calendar, book interview) go through the project's
|
||||
own interface, or through an approval flow. Never through `/ask`.
|
||||
|
||||
## Endpoint
|
||||
|
||||
Every data project exposes two endpoints on its own port:
|
||||
|
||||
```
|
||||
GET /health -> {"ok": true}
|
||||
POST /ask -> answer a question about this project's data
|
||||
```
|
||||
|
||||
### Request
|
||||
|
||||
```json
|
||||
{
|
||||
"question": "what does Harry have on today?",
|
||||
"asker": "sam",
|
||||
"person": "harry",
|
||||
"source": "esp32"
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Required | Meaning |
|
||||
|---|---|---|
|
||||
| `question` | yes | The words the user said. Plain text. |
|
||||
| `asker` | yes | Who asked. Used for permission. |
|
||||
| `person` | no | Who the question is about. Defaults to `asker`. |
|
||||
| `source` | no | Where it came from. `esp32`, `phone`, `chat`, `admin`. |
|
||||
|
||||
### Response
|
||||
|
||||
```json
|
||||
{
|
||||
"answer": "Harry has maths and a music lesson today.",
|
||||
"data": {},
|
||||
"expires": "2026-10-10T09:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Required | Meaning |
|
||||
|---|---|---|
|
||||
| `answer` | yes | One short sentence. Safe to speak aloud. |
|
||||
| `data` | no | Structured detail. The Hub may ignore it. |
|
||||
| `expires` | no | When the answer stops being true. |
|
||||
|
||||
### Cannot answer
|
||||
|
||||
```json
|
||||
{ "answer": null, "reason": "no data for that person" }
|
||||
```
|
||||
|
||||
Never guess. Never invent. Say `reason` instead.
|
||||
|
||||
## Rules for the project
|
||||
|
||||
1. **Read only.** `/ask` never writes anything.
|
||||
2. **Answer for one person at most.** Check `asker` may see `person`.
|
||||
3. **One short sentence.** No lists unless asked.
|
||||
4. **Fast.** Answer in under 3 seconds, or return `answer: null`.
|
||||
5. **No secrets in the answer.** No tokens, no internal paths.
|
||||
|
||||
## Rules for the Hub
|
||||
|
||||
1. **Forward the question.** Do not parse the project's data.
|
||||
2. **Set a timeout.** 3 seconds. If slow, say so and stop waiting.
|
||||
3. **Pass identity.** Always send `asker`. Never send another person's question
|
||||
without permission.
|
||||
4. **Reformat only.** The Hub chooses text, speech, or notification. It does not
|
||||
change the meaning.
|
||||
5. **One project down is not an outage.** Say "that service is not answering".
|
||||
|
||||
## Notify (project to Hub)
|
||||
|
||||
A project may tell the Hub something, so the Hub can speak or notify.
|
||||
|
||||
```
|
||||
POST /notify
|
||||
{
|
||||
"from": "email_agent",
|
||||
"level": "important",
|
||||
"message": "3 emails need a decision.",
|
||||
"person": "sam"
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Meaning |
|
||||
|---|---|
|
||||
| `from` | The project name. |
|
||||
| `level` | `info`, `important`, or `urgent`. |
|
||||
| `message` | One short sentence for the user. |
|
||||
| `person` | Who should hear it. |
|
||||
|
||||
## Approval (write actions)
|
||||
|
||||
A write action needs a human yes. This is one shared pattern, not one per project.
|
||||
|
||||
1. The project sends an approval request: what, who, why, and a one-time id.
|
||||
2. The admin app shows **"Did you ask for this?"**.
|
||||
3. On tap, the admin app calls the project to execute.
|
||||
4. The project executes once and returns the result.
|
||||
|
||||
Approval is required for: parental control changes, calendar writes from email or
|
||||
school, and any Paperclip job.
|
||||
|
||||
**A spoken keycode is not the lock.** Only the admin app confirms.
|
||||
|
||||
## Authentication
|
||||
|
||||
Service to service. One bearer token per project, stored in
|
||||
`~/.config/environment.d/10-secrets.conf`. The Hub sends the target project's
|
||||
token. No project trusts an unsigned request.
|
||||
|
||||
## Versioning
|
||||
|
||||
The contract is version 1. Add fields; do not remove or rename them. A breaking
|
||||
change needs a new path, for example `/ask/v2`.
|
||||
@@ -13,6 +13,7 @@ Read this index to inject the exact file you need. Do not search all files.
|
||||
| **Configuration & Env** | `docs/outline/02-config-and-env.md` | Lists services, ports, env vars, and secret paths. |
|
||||
| **Code Structure Map** | `docs/outline/03-code-map.md` | Shows the planned folder layout and entry points. |
|
||||
| **AI Agent Runbook** | `docs/outline/04-agent-runbook.md` | Gives steps to build, test, and restart Hub work. |
|
||||
| **Ask Contract** | `docs/ask-contract.md` | The interface between the Hub and every data project. |
|
||||
| **Design Brief** | `hub_brief.md` | The agreed design. This file is the source of truth. |
|
||||
| **Project Rules** | `AGENTS.md` | Mission, rules, build order, and project relations. |
|
||||
|
||||
|
||||
@@ -18,6 +18,17 @@ way in, the phone app, would repeat the same work. The Hub stops this repeat.
|
||||
4. **Route** — send the request to one destination.
|
||||
5. **Answer** — return a short reply in the right shape.
|
||||
|
||||
When the question is about another project's data, step 4 asks that project
|
||||
through the `/ask` contract. See `docs/ask-contract.md`.
|
||||
|
||||
## Three Directions
|
||||
|
||||
Nothing here is ownership. These are directions of talk.
|
||||
|
||||
1. The Hub asks a project.
|
||||
2. A project tells the Hub.
|
||||
3. n8n triggers the project.
|
||||
|
||||
## Ways In
|
||||
|
||||
- Phone app (Kotlin) — wake word, voice, controls.
|
||||
@@ -26,17 +37,32 @@ way in, the phone app, would repeat the same work. The Hub stops this repeat.
|
||||
- dsh chat — per-person chat.
|
||||
- Console portal — web dashboard.
|
||||
|
||||
## Destinations
|
||||
## Peers and Destinations
|
||||
|
||||
| Destination | Job |
|
||||
Every other project is a peer. Each has its own folder, repo, port, and
|
||||
interface. Each works without the Hub.
|
||||
|
||||
| Peer | Talk direction |
|
||||
|---|---|
|
||||
| Home Assistant | Lights, switches, timers, calendar. |
|
||||
| Speakers (Jervis) | Speak and announce. |
|
||||
| Internet control | Parental limits on kids' devices. |
|
||||
| Artemis | Operate the phone screen. |
|
||||
| Paperclip | Slow, multi-step, recorded work. |
|
||||
| Web search | Tavily search. |
|
||||
| Apprise / NTFY | Notifications and email. |
|
||||
| Email agent | Hub asks it. It tells the Hub. n8n scans it. |
|
||||
| Compass / NHS | Hub asks it. It tells the Hub. n8n scans it. |
|
||||
| Internet control | Hub asks it. Control goes through its own apps. |
|
||||
| Artemis | Hub calls it to act. Nothing comes back. |
|
||||
| Home Assistant | Hub calls it to act. |
|
||||
| Speakers (Jervis) | Hub calls it to speak. |
|
||||
| Paperclip | Hub files jobs. The answer returns. |
|
||||
| Web search | Hub calls it. |
|
||||
| Apprise / NTFY | Hub calls it to notify. |
|
||||
|
||||
## Query, Command, or Control
|
||||
|
||||
| Kind | Path | Confirm |
|
||||
|---|---|---|
|
||||
| Query | Hub asks a project (`/ask`) | No |
|
||||
| Command | Hub calls Home Assistant | No |
|
||||
| Control | Admin app calls internet control | Yes, on the phone |
|
||||
|
||||
A high-consequence control does not route through the Hub.
|
||||
|
||||
## Reply Shapes
|
||||
|
||||
@@ -57,3 +83,4 @@ The Hub asks one question: does this need a decision, or does it need to happen?
|
||||
- Not a central brain. No single personality or memory.
|
||||
- Not Paperclip. The Hub does not wait minutes for an answer.
|
||||
- Not a destination. The Hub does not turn off the internet itself.
|
||||
- Not an owner. The other projects are peers, not sub-projects.
|
||||
|
||||
Reference in New Issue
Block a user