From 5d793298a60f72091e2108aee56452abd49e1da2 Mon Sep 17 00:00:00 2001 From: Sam Rolfe Date: Sun, 11 Oct 2026 17:24:04 +1100 Subject: [PATCH] Initial spec: AGENTS.md build spec + archived original notes --- .gitignore | 36 +++++++++ AGENTS.md | 187 ++++++++++++++++++++++++++++++++++++++++++++++ ORIGINAL_NOTES.md | 32 ++++++++ 3 files changed, 255 insertions(+) create mode 100644 .gitignore create mode 100644 AGENTS.md create mode 100644 ORIGINAL_NOTES.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..23c0a75 --- /dev/null +++ b/.gitignore @@ -0,0 +1,36 @@ +# Secrets +.env +.env.* +*.local +*.keystore + +# Go +bin/ +*.exe +*.test +*.out + +# Python +__pycache__/ +*.pyc +.venv/ +venv/ + +# Node / web +node_modules/ +dist/ +*.visual-check.* + +# Android / Kotlin +.gradle/ +build/ +local.properties +*.apk + +# OS / editors +.DS_Store +*.swp + + +# Pi agent generated memory (local state, not source) +.pi/memory-vault/ diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..aec15e9 --- /dev/null +++ b/AGENTS.md @@ -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? diff --git a/ORIGINAL_NOTES.md b/ORIGINAL_NOTES.md new file mode 100644 index 0000000..4de6b80 --- /dev/null +++ b/ORIGINAL_NOTES.md @@ -0,0 +1,32 @@ +# Voice Outbound — Original Notes (archived) + +> Historical pre-planning notes. **Superseded by `AGENTS.md`.** Do not build from this. + + +> Kept for provenance. Replaces the earlier `PLAN.md`. Do not build from this. + +``` +Purpose +- Test whether the system can hold a voice conversation — an artificial one. +- MiniMax supplies the voice. An LLM supplies the words. +- The system calls out and holds a short, natural conversation. + +Why it is separate +- Not Artemis (screen control). Not the phone app (a Hub way in). + +Sam's description +- Create conversations with MiniMax voices, controlled via an LLM that interprets + and creates voices and responds. +- Assign a phone number, a conversation topic, a tone, etc. in the description. +- "Call now". +- It is a demonstration of tech. + +Original open questions +- Real phone calls, or WhatsApp voice notes/calls? +- One-way or two-way? +- A Hub destination, or fully standalone? +- Which LLM, and through OmniRoute? +- How is a transcript stored? + +Provenance: this folder was split out of `voice_artemis_minimax` on 2026-10-10. +```