Initial spec: AGENTS.md build spec + archived original notes

This commit is contained in:
2026-10-11 17:24:04 +11:00
commit 5d793298a6
3 changed files with 255 additions and 0 deletions

187
AGENTS.md Normal file
View File

@@ -0,0 +1,187 @@
# Outbound Voice (demo)
> Build spec for Paperclip. **Status: last project.** Do not start until the Hub,
> the phone app, and Artemis work. Follow the phases in section 11 in order.
---
## 1. Purpose and outcome
A **demonstration of technology**. Show that the system can hold an artificial voice
conversation: MiniMax supplies the voice, an LLM supplies the words.
Sam sets a phone number, a topic, and a tone, then presses **Call now**.
**Outcome (the single success statement):**
> Sam enters a number, a topic, and a tone, presses Call now, and listens to a
> short, natural conversation driven by the LLM in a MiniMax voice.
## 2. Scope
**In scope**
- Set the target number, the topic, the tone, and the goal.
- Start a call on demand ("Call now").
- Speech to text the other person; the LLM decides the reply; MiniMax text to speech speaks.
- Keep the conversation on topic and in tone.
- End the call gracefully.
- Store and show the transcript.
**Out of scope**
- Inbound calls.
- Production or unattended use.
- Anything safety-critical.
- WhatsApp, unless it turns out to be simple. Decide in Phase 2.
## 3. Users and roles
- **Sam only.** This is an operator tool.
## 4. Functional requirements
| ID | Requirement |
|---|---|
| FR-1 | Set a target: phone number, topic, tone, and goal. **Choose the channel:** a phone call, WhatsApp, or Sam's Aussie Broadband service. |
| FR-2 | Start a call on demand ("Call now"). |
| FR-3 | Loop: STT the callee → LLM plans the reply → MiniMax TTS speaks it. |
| FR-4 | Keep the reply on topic and in the chosen tone. |
| FR-5 | Detect the end and close the call gracefully. |
| FR-6 | Store the transcript: each turn, who spoke, and the time. |
| FR-7 | Show a live transcript during the call. |
| FR-8 | A hard time limit per call. The demo never runs away. |
| FR-9 | Log the call: number, topic, tone, duration, result. |
## 5. Screens and UX flow
**Screen: control page**
1. Fields: target number, topic, tone, goal.
2. A **Call now** button.
3. A live transcript panel (speaker, text, time).
4. A **Hang up** button.
5. Call history with transcripts.
**Main flow**
```
Fill the form → Call now → watch the transcript → Hang up (or auto-end) → read the log
```
## 6. Look and feel
Reuse the Family Home Lab design system.
- Source: `/home/sam/Docker/Containers/family-home-lab/DESIGN.md`
- Tokens: `/home/sam/Docker/Containers/family-home-lab/portal/static/tokens.css`
- Copy `tokens.css` into this project.
Canvas `#f6f5f4`, one action blue `#0075de`, Inter, 8px grid, pill CTAs. Dark mode.
## 7. Data model
SQLite inside the service. Suggested:
| Table | Holds |
|---|---|
| `calls` | number, topic, tone, goal, started-at, ended-at, duration, result |
| `turns` | call id, speaker (`ai` or `human`), text, created-at |
| `recordings` | optional audio paths |
Retention: keep transcripts for a bounded period. Recordings only if Sam asks.
## 8. Integrations
| System | Use |
|---|---|
| **MiniMax** | Text to speech, and speech to text. Keys already in `environment.d`. |
| **OmniRoute** | The LLM that plans each reply. |
| **Telephony** | **To be decided** — see section 13. |
| **Hub** | Optional. `/ask` is not required. A `/notify` on call end is optional. |
## 9. Technology (locked)
| Item | Value |
|---|---|
| Backend | **Go** |
| UI | **HTMX** + server-rendered HTML |
| Database | **SQLite** |
| Voice | **MiniMax** T2A and STT |
| LLM | **OmniRoute** |
| Telephony | **Choose per call:** phone call, WhatsApp, or Aussie Broadband. Providers decided in Phase 2. |
| Host | `.13`, Docker |
| Container | **This project's own.** |
| Port | Allocate one (suggest **8794**). |
| URL | `voice.lab.audasmedia.com.au` via Caddy on `.35` |
| Auth | **Separate session login.** |
## 10. Rules and constraints
1. **It is a demo.** Keep calls short, and set a hard time limit.
2. **Never call a real person without Sam's explicit action.** No bulk, no cold lists.
3. Consider whether to disclose that the caller is an AI. Decide in section 13.
4. Models go through **OmniRoute**, except MiniMax voice.
5. Secrets come from `environment.d`.
6. Own folder, own container, own port.
7. This project writes its own docs.
## 11. Build order
**Phase 1 — Skeleton and control page**
Go service, SQLite, session login, the form, Docker, Caddy route.
*DoD:* the page runs on `.13` and the form saves.
**Phase 2 — Telephony (the risk phase)**
Prove that a call can be placed and that audio flows both ways. Decide the provider
here.
*DoD:* a real call connects and the app receives the other person's audio. **If this
fails, stop and report.**
**Phase 3 — The conversation loop**
STT → LLM → MiniMax TTS, turn by turn.
*DoD:* a short real conversation happens, with the LLM replying in a MiniMax voice.
**Phase 4 — Topic and tone**
Prompt the LLM from the form's topic, tone, and goal.
*DoD:* two different tones produce clearly different conversations.
**Phase 5 — Transcript**
Store and display each turn live.
*DoD:* the transcript is complete after a call.
**Phase 6 — Graceful end**
Detect the end, hang up, enforce the time limit.
*DoD:* the call ends cleanly at the limit.
**Phase 7 — Documentation**
*DoD:* project-docs run; docs updated.
## 12. Acceptance criteria
- Sam enters a number, topic, and tone, and presses Call now.
- A real call connects, and the LLM holds a short on-topic conversation.
- The tone setting measurably changes the conversation.
- The transcript is stored and readable.
- The call ends cleanly at the time limit.
- It runs in its own container on its own port.
## 13. Decisions and remaining questions
Resolved:
1. It is a **demo**, not production.
2. **Last project.** Do not start early.
3. MiniMax voice, OmniRoute for the LLM.
Resolved:
1. **Channel is chosen per call:** a phone call, WhatsApp, or Sam's Aussie Broadband
service.
Remaining:
1. **Telephony providers.** Three channels to prove in Phase 2:
- **Phone call** — a SIP/cloud provider (for example Twilio), or the Kotlin app
places the call and routes audio.
- **WhatsApp** — no public API. Options: WhatsApp Business Cloud API, or screen
control through `artemis_control`.
- **Aussie Broadband — mobile.** Confirmed as a mobile service. Confirm whether
it exposes an API, SIP, or only a SIM.
**Phase 2 proves at least one channel end to end.**
2. Which channel is the default?
3. One-way (speak a message) or two-way (hold a conversation)? The demo implies two-way.
4. Do we disclose that the caller is an AI? Recommend yes.
5. Which number does it call from, and who pays for it?