toga-ai 1.0.482 → 1.0.484
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/knowledge/INDEX.md
CHANGED
|
@@ -19,7 +19,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
|
|
|
19
19
|
## 2.0 framework
|
|
20
20
|
|
|
21
21
|
- **_underscore** (_Underscore) _(framework core)_ — 40 doc(s) → [2.0/apps/_underscore/INDEX.md](2.0/apps/_underscore/INDEX.md)
|
|
22
|
-
- **worker2** (Worker) —
|
|
22
|
+
- **worker2** (Worker) — 37 doc(s) → [2.0/apps/worker2/INDEX.md](2.0/apps/worker2/INDEX.md)
|
|
23
23
|
- **api2** (API) — 20 doc(s) → [2.0/apps/api2/INDEX.md](2.0/apps/api2/INDEX.md)
|
|
24
24
|
- **dbchanges2** (Database Changes) _(framework core)_ — 3 doc(s) → [2.0/apps/dbchanges2/INDEX.md](2.0/apps/dbchanges2/INDEX.md)
|
|
25
25
|
- **toga2-supply** (TOGa Supply) — 3 doc(s) → [2.0/apps/toga2-supply/INDEX.md](2.0/apps/toga2-supply/INDEX.md)
|
|
@@ -39,7 +39,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
|
|
|
39
39
|
- **togatech** (TOGA Technology Website) — 4 doc(s) → [standalone/apps/togatech/INDEX.md](standalone/apps/togatech/INDEX.md)
|
|
40
40
|
- **websocket** (WebSocket Server) — 2 doc(s) → [standalone/apps/websocket/INDEX.md](standalone/apps/websocket/INDEX.md)
|
|
41
41
|
- **forward** (Forwarder) — 3 doc(s) → [standalone/apps/forward/INDEX.md](standalone/apps/forward/INDEX.md)
|
|
42
|
-
- **claude** (Claude Harness) —
|
|
42
|
+
- **claude** (Claude Harness) — 3 doc(s) → [standalone/apps/claude/INDEX.md](standalone/apps/claude/INDEX.md)
|
|
43
43
|
|
|
44
44
|
## Clients
|
|
45
45
|
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: session
|
|
3
|
+
slug: bdr-live-call-status-and-callback-bug
|
|
4
|
+
title: BDR funnel live call status + real summary email, and AI-BDR callback root cause
|
|
5
|
+
author: tcox
|
|
6
|
+
repos: [bdr, worker2]
|
|
7
|
+
framework: "2.0"
|
|
8
|
+
client: shared
|
|
9
|
+
status: active
|
|
10
|
+
created: 2026-07-30
|
|
11
|
+
updated: 2026-07-30
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Session: bdr-live-call-status-and-callback-bug
|
|
15
|
+
**Date:** 2026-07-30
|
|
16
|
+
**Project/Repo:** bdr (2.0), plus a read-only worker2 investigation
|
|
17
|
+
**Task:** Make the BDR funnel usable by anyone (remove the contact-reference gate), drive the Success screen from real call data instead of a timed simulation, send the call summary by real email, and then root-cause a production bug where a callback requested during an AI-BDR call never happens.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## What WORKED
|
|
22
|
+
|
|
23
|
+
- **Contact-reference gate removed.** Deleted the `hasLead` submit-block and the
|
|
24
|
+
`phone.missingContactNotice` copy key from `src/flow/screens/CallNow.tsx`,
|
|
25
|
+
`src/flow/screens/Schedule.tsx`, `src/content/schema.ts`, `src/content/default.ts`.
|
|
26
|
+
Evidence: grep for `hasLead|missingContactNotice` across the repo returns zero matches;
|
|
27
|
+
design-parity audit against `C:\WWW\BDR\mockup` confirmed the removal restored mockup
|
|
28
|
+
parity (the mockup never had the notice).
|
|
29
|
+
- **Vapi's own API confirmed as a working live call-status source.** `GET https://api.vapi.ai/call`
|
|
30
|
+
returned HTTP 200 with the org's calls. Verified field shape: `id, status, type, createdAt,
|
|
31
|
+
startedAt, endedAt, endedReason, summary, transcript, recordingUrl, customer, analysis,
|
|
32
|
+
messages, cost`. Status enum `queued|ringing|in-progress|forwarding|ended`. Timestamps are
|
|
33
|
+
ISO-8601 UTC with `Z`. **Key fact: `createdAt` = placed, `startedAt` = ANSWERED,
|
|
34
|
+
`endedAt` = hangup.** A real call showed `createdAt 18:53:08 / startedAt 18:53:18 /
|
|
35
|
+
endedAt 18:53:35, endedReason "voicemail"` — the 10s gap is ring time.
|
|
36
|
+
- **Fixed the worker dispatcher reply-prefix bug** in `src/server/workerDialer.ts`. The worker
|
|
37
|
+
wraps every reply as `[<requestId>] Successfully Executed (<n> seconds): <json>`, so the old
|
|
38
|
+
`response.json()` always threw: it logged "immediate dial not placed" on every SUCCESSFUL
|
|
39
|
+
dial and discarded the response body. Now strips the prefix before parsing and returns a
|
|
40
|
+
typed `DialResult` carrying `vapiCallId` / `attemptId`. Evidence: regression test asserts a
|
|
41
|
+
dispatcher-wrapped success reply no longer logs the false warning.
|
|
42
|
+
- **Live call lifecycle on the Success screen.** New `/api/call-status` route, `vapiCall.ts`
|
|
43
|
+
server reader, `useCallStatusViewModel` polling hook. Mapping: `queued`/`ringing` -> dialing
|
|
44
|
+
with NO talk timer; `in-progress`/`forwarding` with `startedAt` -> active, timer counted from
|
|
45
|
+
the ANSWER time with server-clock-offset correction; `ended` -> frozen true talk duration;
|
|
46
|
+
ended with no `startedAt` or a voicemail/no-answer/busy reason -> a distinct not-answered
|
|
47
|
+
state that shows no timer and suppresses the recap card. The old simulation is retained
|
|
48
|
+
verbatim as the fallback whenever status is unavailable.
|
|
49
|
+
- **Post-hangup summary grace.** Vapi writes `summary` asynchronously after hangup, so the
|
|
50
|
+
first ended poll is usually `summary: null`. Added a bounded 30s / 2s-cadence grace that
|
|
51
|
+
keeps polling after ended until the real summary lands, with the screen already showing the
|
|
52
|
+
ended state. Frozen duration provably unchanged across the window (tested).
|
|
53
|
+
- **Real email send of the call summary.** New `/api/share-summary` route + `src/server/mailer.ts`
|
|
54
|
+
(nodemailer) + shared `src/lib/summaryText.ts`, so the Copy button and the emailed body are
|
|
55
|
+
byte-identical by construction. The client may only supply recipient + campaign id + bounded
|
|
56
|
+
variant index + signed token; never body or subject text.
|
|
57
|
+
- **mailto fallback removed entirely** (developer decision mid-session). `src/lib/shareMailto.ts`
|
|
58
|
+
and its test deleted; Send now only ever reaches sent or failed-with-retry.
|
|
59
|
+
- **Security hardening after the CSO audit returned BLOCK** (it flagged an unauthenticated
|
|
60
|
+
arbitrary-recipient mailer). Applied: purpose-scoped HMAC tokens (`status` vs `share`), token
|
|
61
|
+
moved from the URL query string to an `x-status-token` header, a valid share token now
|
|
62
|
+
REQUIRED for every send, Content-Type and `sec-fetch-site` checks, strict recipient validation
|
|
63
|
+
(rejects angle-bracket display-name form, commas, all non-ASCII), SMTP `requireTLS` + TLS 1.2
|
|
64
|
+
+ timeouts, `Cache-Control: no-store, private` on every envelope, exact ACL error-code matching
|
|
65
|
+
that fails CLOSED on an unknown 403, upstream AbortSignal timeouts, rejection of future-dated
|
|
66
|
+
token issuance. The Vapi call id travels only inside signed claims, never as a client param.
|
|
67
|
+
- **Final verification:** `npx tsc --noEmit` clean, `npm run lint` clean, `npm test`
|
|
68
|
+
**306/306 passing across 20 files**.
|
|
69
|
+
- **Credentials located and wired** (locations only): 2.0 SMTP settings are hardcoded constants
|
|
70
|
+
in `_underscore/Email.php` (SES us-west-2, port 587, TLS); the Vapi bearer credential is a
|
|
71
|
+
hardcoded constant in `worker2/Worker/Ai/Bdr/Vapi.php`. BDR consumes both as server-only env
|
|
72
|
+
vars `TOGA_SMTP_HOST/PORT/USER/PASS`, `TOGA_EMAIL_FROM`, `TOGA_VAPI_TOKEN` in the gitignored
|
|
73
|
+
`.env.local` (documented in `.env.example`).
|
|
74
|
+
- **Two knowledge captures pushed:** `6ed04d3` (8 docs — live-call-status, the api2 v2 query
|
|
75
|
+
contract, and updates) and `968404e` (3 docs — the callback root cause, with `bala` added as
|
|
76
|
+
co-owner for handoff).
|
|
77
|
+
- **Callback bug root-caused with empirical proof.** Extracted worker2's `convertDateTime` and
|
|
78
|
+
executed it on PHP 8.1.10: 22 of 32 realistic phrasings return null.
|
|
79
|
+
|
|
80
|
+
## What did NOT work — DO NOT RETRY THESE
|
|
81
|
+
|
|
82
|
+
- **Reading `ContactAttempts` through api2 — HTTP 403 `EZ-1`, record-level block.** Re-verified
|
|
83
|
+
live on 2026-07-30 against `api.togahub.com` with the BDR client credential, on ALL variants:
|
|
84
|
+
nested `/contacts/{uuid}/contact-attempts`, flat `/contact-attempts`, both with and without an
|
|
85
|
+
explicit `fields=` list. Response is `data.contactAttempts: null`. The pending read-only ACL
|
|
86
|
+
grant has still NOT landed. Do not build anything against this resource until it does.
|
|
87
|
+
- **Selecting `Contacts.id`** — `/contacts/{uuid}?fields=id` returns 403 `EZ-2` with
|
|
88
|
+
`identifiers.fields: ["id"]`. The client has no field grant on `Contacts.id`. Filter on
|
|
89
|
+
`Contacts.uuid` instead (api2 does not ACL-check `where`/`join`, only `fields`).
|
|
90
|
+
- **Direct production database access from this laptop.** TCP 3306 to the
|
|
91
|
+
`*.client.database.togahub.com` writer host **times out** (VPN required). This machine also
|
|
92
|
+
has no mysql client, no PHP, and no Python (only the Windows Store stub). Do not plan work
|
|
93
|
+
that assumes direct SQL — hand the developer ready-to-run SQL with pre-flight reads instead.
|
|
94
|
+
- **Reading the api2 auth token from `data.token`** — wrong path, the response has no such key.
|
|
95
|
+
The access token is at **`data.tokens.access`**.
|
|
96
|
+
- **Sharing the raw Claude Code session transcript (`~/.claude/projects/c--WWW/<id>.jsonl`) for
|
|
97
|
+
handoff.** Verified it contains live credential VALUES in plaintext: SMTP password (5
|
|
98
|
+
occurrences), Vapi token (2), Toga client API secret (4), HubSpot access token (4). Use
|
|
99
|
+
`/session-save` + `/session-resume` and the knowledge docs for handoff instead.
|
|
100
|
+
- **(worker2, the production bug) `convertDateTime` parsing natural-language callback times.**
|
|
101
|
+
22/32 phrasings return null on PHP 8.1.10. The trigger is the PREPOSITION/FILLER WORD, not
|
|
102
|
+
spelled-out numbers as previously recorded: `"10 minutes"` parses but `"in 10 minutes"` does
|
|
103
|
+
not; `"tomorrow 3pm"` parses but `"tomorrow at 3pm"` does not — and that is the exact example
|
|
104
|
+
the code comment claims works.
|
|
105
|
+
|
|
106
|
+
## Not tried yet (candidates for next session)
|
|
107
|
+
|
|
108
|
+
- A **live end-to-end call test** of the new UI. Not possible yet: campaign 2's `dateEnd` lapsed
|
|
109
|
+
on 2026-07-28 and the re-activation SQL had not been run at save time.
|
|
110
|
+
- **Verifying a real SMTP send.** Credentials are wired but no successful delivery has been
|
|
111
|
+
observed; `TOGA_EMAIL_FROM=DevTeam@goagilant.com` may or may not be an SES-verified identity.
|
|
112
|
+
- **Running Q1-Q5 from `2.0/apps/worker2/features/callback-scheduling.md`** against `Client_True`
|
|
113
|
+
to confirm the callback root cause with production data. Q1 is decisive.
|
|
114
|
+
- **Fixing any of the worker2 callback defects** — this session was diagnosis only; no worker2
|
|
115
|
+
code was modified. bala is picking this up.
|
|
116
|
+
- **Adding the `TOGA_*` env vars to the Amplify console** so the deployed site gets live status
|
|
117
|
+
and email (local `.env.local` only affects dev).
|
|
118
|
+
- **Binding the email recipient to the contact's on-file address** — the stricter anti-abuse
|
|
119
|
+
option; currently a token holder can email an arbitrary recipient (accepted residual risk).
|
|
120
|
+
- **Splitting BDR knowledge out of `2.0/apps/ai-bdr/` into its own `2.0/apps/bdr/` folder with an
|
|
121
|
+
`architecture.md`.** Flagged twice; an elevated call that needs a deliberate decision.
|
|
122
|
+
|
|
123
|
+
## Current file state
|
|
124
|
+
|
|
125
|
+
All BDR changes are **uncommitted on branch `TRUE-80435`** (working tree only — nothing was
|
|
126
|
+
committed or pushed all session, per the git-workflow rule).
|
|
127
|
+
|
|
128
|
+
| File | Status | Notes |
|
|
129
|
+
|------|--------|-------|
|
|
130
|
+
| `bdr src/flow/screens/CallNow.tsx` | modified | gate + notice removed; submit enables on the digit rule alone |
|
|
131
|
+
| `bdr src/flow/screens/Schedule.tsx` | modified | same removal |
|
|
132
|
+
| `bdr src/flow/screens/Success.tsx` | modified | live stages via a kind-keyed lookup; simulation path preserved verbatim |
|
|
133
|
+
| `bdr src/flow/screens/CallSummary.tsx` | modified | async send with sending/sent/failed; real-summary rendering; no mailto |
|
|
134
|
+
| `bdr src/flow/useCallStatusViewModel.ts` | new | poll loop + pure reducer, cadence, caps, summary grace |
|
|
135
|
+
| `bdr src/flow/callStatusApi.ts` | new | client fetcher, sends the token in a header |
|
|
136
|
+
| `bdr src/flow/shareSummaryApi.ts` | new | maps send outcomes to sent/unavailable/failed |
|
|
137
|
+
| `bdr src/flow/leadActions.ts` | modified | returns a handle `{ok, uuid?, statusToken?, shareToken?}`; `simulated` flag |
|
|
138
|
+
| `bdr src/flow/useAgentFlow.ts` | modified | stores the call handle under the submitGen guard |
|
|
139
|
+
| `bdr src/flow/AgentFlowRoot.tsx` | modified | passes the handle to calling-mode Success only |
|
|
140
|
+
| `bdr src/server/vapiCall.ts` | new | reads `GET api.vapi.ai/call/{id}`; maps to the CallStatus union |
|
|
141
|
+
| `bdr src/server/callStatus.ts` | modified | ContactAttempts path retained as the (403) fallback |
|
|
142
|
+
| `bdr src/server/statusToken.ts` | new | purpose-scoped HMAC, TTL, skew, optional `vapiCallId` claim |
|
|
143
|
+
| `bdr src/server/mailer.ts` | new | nodemailer, requireTLS, timeouts, scrubbed logs |
|
|
144
|
+
| `bdr src/server/workerDialer.ts` | modified | **prefix bug fixed**; returns `DialResult` with `vapiCallId` |
|
|
145
|
+
| `bdr src/server/callbackService.ts` | modified | surfaces `vapiCallId` |
|
|
146
|
+
| `bdr src/server/toga.ts` | modified | added `togaApiGetEnvelope` (needed to read EZ-1/EZ-2 out of a 403) |
|
|
147
|
+
| `bdr src/lib/summaryText.ts` | new | single renderer shared by Copy and the email |
|
|
148
|
+
| `bdr src/lib/emailFormat.ts` | new | strict recipient validation |
|
|
149
|
+
| `bdr src/lib/callStatus.ts` | new | shared CallStatus union + header constant |
|
|
150
|
+
| `bdr src/app/api/call-status/route.ts` | new | token-gated, never 500s, `no-store` |
|
|
151
|
+
| `bdr src/app/api/share-summary/route.ts` | new | share-token required, server-built content only |
|
|
152
|
+
| `bdr src/app/api/call-now/route.ts` | modified | mints both tokens with the `vapiCallId` claim |
|
|
153
|
+
| `bdr src/lib/shareMailto.ts` | **deleted** | mailto fallback removed by developer decision |
|
|
154
|
+
| `bdr src/content/schema.ts` + `default.ts` | modified | live-stage + send-state copy; notice key removed |
|
|
155
|
+
| `bdr src/proxy.ts` | modified | matcher + limiters for the two new routes |
|
|
156
|
+
| `bdr .env.example` | modified | documents SMTP + `TOGA_VAPI_TOKEN` |
|
|
157
|
+
| `bdr .env.local` | modified | real values added locally (gitignored) |
|
|
158
|
+
| `bdr package.json` | modified | added `nodemailer` + `@types/nodemailer` |
|
|
159
|
+
| worker2 / _underscore / api2 | **unmodified** | read-only investigation only |
|
|
160
|
+
|
|
161
|
+
## Decisions made
|
|
162
|
+
|
|
163
|
+
- **Vapi's API is the live call-status source, not `ContactAttempts`.** Rationale: ContactAttempts
|
|
164
|
+
is 403-blocked AND structurally inferior — `dtStarted` is DIAL time, so it cannot distinguish
|
|
165
|
+
ringing from talking, and `dtStarted` is retroactively rewritten by the webhook. Vapi exposes
|
|
166
|
+
ringing vs answered vs ended plus a real summary. It stays the better source even after the
|
|
167
|
+
grant lands. Rejected: waiting for the ACL grant; continuing to simulate.
|
|
168
|
+
- **The backend contract is unchanged for anonymous submits** (developer decision). The funnel
|
|
169
|
+
loads and accepts a phone number for anyone, but calls still only fire for campaign-linked
|
|
170
|
+
contacts, matching the original BDR backend. Rejected: server-side anonymous contact creation
|
|
171
|
+
(would have required a DNC pre-check that the 403 blocks anyway).
|
|
172
|
+
- **The mailto fallback was removed entirely** (developer decision). Consequence, accepted: with
|
|
173
|
+
SMTP unconfigured the Send button can only reach the failed state.
|
|
174
|
+
- **Token purpose-scoping and header transport**, adopted in response to the CSO BLOCK verdict.
|
|
175
|
+
Rejected: leaving one token to serve both read and send, and leaving it in the query string
|
|
176
|
+
(a 30-minute bearer capability over a named individual's call summary would land in access logs).
|
|
177
|
+
- **Accepted residual risk:** a token holder can email the summary to any address they type
|
|
178
|
+
(preserves the share-with-a-colleague use case). The stricter alternative is on the not-tried list.
|
|
179
|
+
- **BDR knowledge stays filed under `2.0/apps/ai-bdr/`** rather than restructuring mid-capture.
|
|
180
|
+
|
|
181
|
+
## Blockers
|
|
182
|
+
|
|
183
|
+
- **`ContactAttempts` read-only ACL grant still pending** (403 EZ-1). Blocks only the fallback
|
|
184
|
+
path — the Vapi path works without it. Note for whoever files it: the `c_*` fields are granted
|
|
185
|
+
through `AclCustomFieldPermissions`, a DIFFERENT table from the standard fields.
|
|
186
|
+
- **Campaign 2 (`26.05 - AI BDR - Ryan Nitti`, id 2) `dateEnd` lapsed 2026-07-28**, so no calls
|
|
187
|
+
place at all until it is extended. SQL was handed to the developer; the production DB is not
|
|
188
|
+
reachable from this machine.
|
|
189
|
+
- **No live end-to-end verification yet** of the call UI or a real email delivery.
|
|
190
|
+
|
|
191
|
+
## Exact next step
|
|
192
|
+
|
|
193
|
+
> In `Client_True`, run the campaign-2 re-activation pre-flight reads first (confirm the dialable
|
|
194
|
+
> count on campaign 2 is 0 or 1 and that contact 248 has no open `ContactAttempts` row with
|
|
195
|
+
> `dtEnded IS NULL`), then flip all campaign-2 contacts except 248 to `isOkayToCall = 0` and
|
|
196
|
+
> extend `Campaigns.dateEnd`. Then restart `npm run dev` in `C:\WWW\BDR`, open the funnel from
|
|
197
|
+
> the `?hsContactId=` link, tap Call Now, and confirm the Success screen shows Ringing with no
|
|
198
|
+
> timer, the timer starting at 00:00 on answer, and Call ended with the real Vapi summary.
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
_Saved by /session-save on 2026-07-30_
|
|
@@ -4,3 +4,4 @@
|
|
|
4
4
|
|-----|---------|-------|
|
|
5
5
|
| [Harness Distribution — How a knowledge.js Fix Reaches Teammates](workflows/harness-distribution.md) | There are **two copies** of `knowledge.js` on a developer's machine, and the skills use only one of them. | claude/scripts/install.js, claude/knowledge.js |
|
|
6
6
|
| [Knowledge Base Publish / Push Pipeline](workflows/knowledge-publish-pipeline.md) | How `/capture` and `/session-save` get knowledge docs from your working tree into `agilantsolutions/claude` on `_main`. | claude/knowledge.js |
|
|
7
|
+
| [MCP Tool Usage — "Talos" Means the Internal Knowledge Base, and Run Your Own SELECTs](workflows/mcp-tool-usage.md) | Two MCP connections are available in every session, and **Claude is expected to reach for them on its own judgement — nobody should have to say the word "MCP".* | claude/.claude/skills/kickoff/SKILL.md, claude/.claude/skills/capture/SKILL.md |
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: MCP Tool Usage — "Talos" Means the Internal Knowledge Base, and Run Your Own SELECTs
|
|
3
|
+
framework: "standalone"
|
|
4
|
+
repo: claude
|
|
5
|
+
project: Claude Harness
|
|
6
|
+
client: shared
|
|
7
|
+
type: workflow
|
|
8
|
+
status: active
|
|
9
|
+
updated: 2026-07-30
|
|
10
|
+
owners: ["jcardinal"]
|
|
11
|
+
files:
|
|
12
|
+
- claude/.claude/skills/kickoff/SKILL.md
|
|
13
|
+
- claude/.claude/skills/capture/SKILL.md
|
|
14
|
+
related:
|
|
15
|
+
- standalone/apps/claude/workflows/harness-distribution.md
|
|
16
|
+
- standalone/apps/claude/workflows/knowledge-publish-pipeline.md
|
|
17
|
+
- 2.0/apps/talos/features/mcp-servers.md
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Summary
|
|
21
|
+
|
|
22
|
+
Two MCP connections are available in every session, and **Claude is expected to reach for them on
|
|
23
|
+
its own judgement — nobody should have to say the word "MCP".**
|
|
24
|
+
|
|
25
|
+
1. **`claude.ai Internal Knowledgebase`** — the AWS Bedrock knowledge base of cleaned meeting
|
|
26
|
+
transcripts. **This is what the team means when they say "Talos."**
|
|
27
|
+
2. **`toga-db`** — read-only MySQL access to every TOGA environment, production included.
|
|
28
|
+
|
|
29
|
+
**Critical rules:** When a teammate says **"ask Talos"**, **"use Talos"**, or **"check Talos"**,
|
|
30
|
+
that is an instruction to **search the Internal Knowledge Base MCP** — it is *not* a request to
|
|
31
|
+
open, read, or reverse-engineer the `talos` repo. Only treat "Talos" as the codebase when the
|
|
32
|
+
speaker explicitly frames it as the project ("the Talos repo", "Talos deployment", "the Talos
|
|
33
|
+
agent code"). **Never ask a developer to go run a SELECT** — Claude has read access and must run
|
|
34
|
+
its own. **Writes (INSERT/UPDATE/DELETE/DDL) are the developer's to execute** — the MCP is
|
|
35
|
+
read-only by design, so hand them the statement. Use both connections proactively as part of
|
|
36
|
+
normal research, unprompted.
|
|
37
|
+
|
|
38
|
+
## The word "Talos" is overloaded — resolve it by context
|
|
39
|
+
|
|
40
|
+
| A teammate says | They mean | What to do |
|
|
41
|
+
|---|---|---|
|
|
42
|
+
| "Ask Talos", "use Talos", "check Talos", "what does Talos say about…" | The **Internal Knowledge Base MCP** | `kb_search` — this is the default reading |
|
|
43
|
+
| "the Talos repo", "Talos deployment", "the Talos agent", "the LangGraph agent", "TOGa IQ" | The **`talos` codebase** (2.0, Python/FastAPI) | Open `2.0/apps/talos/` knowledge and the repo |
|
|
44
|
+
|
|
45
|
+
**Default to the MCP.** The overwhelming majority of spoken uses of "Talos" mean the knowledge
|
|
46
|
+
base. Reverse-engineering the `talos` project because someone said "ask Talos" is a real failure
|
|
47
|
+
mode — it burns a session answering the wrong question.
|
|
48
|
+
|
|
49
|
+
Note the collision in this knowledge base itself: `2.0/apps/talos/features/mcp-servers.md`
|
|
50
|
+
documents the MCP servers that the **talos project builds and hosts** (`clickup-mcp`,
|
|
51
|
+
`toga-db-mcp`). That doc is about *building* those servers. This doc is about *using* the
|
|
52
|
+
connections. They are different subjects.
|
|
53
|
+
|
|
54
|
+
> Aside: the team has not settled whether "Talos" is an engine, a chatbot, or the umbrella AI
|
|
55
|
+
> brand, nor whether it is written `Talos` or `TALOS` (see the 2026-07-16 *TOGA Tech Website
|
|
56
|
+
> Review* transcript). Ambiguity about what Talos *is* as a brand is expected; ambiguity about
|
|
57
|
+
> what "ask Talos" *means operationally* is not — it means the knowledge base.
|
|
58
|
+
|
|
59
|
+
## Internal Knowledge Base MCP ("Talos")
|
|
60
|
+
|
|
61
|
+
Cleaned, classified meeting transcripts loaded automatically within 5–10 minutes of a meeting
|
|
62
|
+
ending. This is the record of **what people actually said and decided** — the complement to this
|
|
63
|
+
knowledge base, which records **how the code works**.
|
|
64
|
+
|
|
65
|
+
- **Scope:** account-wide there are 40 knowledge bases across 7 categories; the harness API key
|
|
66
|
+
currently reaches **1 category, `development-team` (34 KBs)**. Other categories (sales, HR,
|
|
67
|
+
legal, contact-center, tech-support, operations) exist but are outside the key's grant.
|
|
68
|
+
- **Shape:** one KB per client bucket, documents at
|
|
69
|
+
`s3://togaiq/development-team/<client>/approved/YYYY-MM-DD - <Meeting Title>.txt`, each with an
|
|
70
|
+
`approved_at` date. Ranking blends semantic relevance with recency.
|
|
71
|
+
- **Client names differ from `registry.json`.** The KB uses `compass-group` (not
|
|
72
|
+
`compass-usa`/`compass-canada`), `health-and-hospitals` (not `nychh`), `nyc-doe` (not `nycdoe`),
|
|
73
|
+
and carries buckets with no registry entry at all — `northwell`, `endeavor-health`, `casl`,
|
|
74
|
+
`lenovo`, `adyen`, `speedcast`, `rumc`, `uma`, `craftex`, `dunn`, `interfaith-ministries`,
|
|
75
|
+
`ford-foundation`, `alpha-omega-plastics`, `american-campus-communities`, `ninja-rmm`, plus
|
|
76
|
+
non-client buckets `general`, `ai`, `power-bi`, `warehouse`, `toga-desk`, `toga-technology`.
|
|
77
|
+
Always pick the `client` value from the `available_clients` list the tool returns.
|
|
78
|
+
|
|
79
|
+
**When to reach for it without being asked:**
|
|
80
|
+
|
|
81
|
+
- A teammate relays something said in a meeting and the terminology is unfamiliar or ambiguous.
|
|
82
|
+
- A decision's *rationale* matters ("why did we do it this way?") — git history says what
|
|
83
|
+
changed, transcripts say why.
|
|
84
|
+
- Business-side vocabulary that has no code footprint (see the terminology gotcha below).
|
|
85
|
+
- Before concluding "there is no knowledge about X" — check here as well as the code KB.
|
|
86
|
+
|
|
87
|
+
**Treat transcripts as evidence, not specification.** They record what was said in a room,
|
|
88
|
+
including things later reversed. Cite the filename and `approved_at` date, prefer the most recent
|
|
89
|
+
when chunks conflict, and let the code knowledge base win on questions of how something is
|
|
90
|
+
actually built.
|
|
91
|
+
|
|
92
|
+
### Terminology that lives only in transcripts
|
|
93
|
+
|
|
94
|
+
These have no footprint in the code knowledge base, so a code-only search returns nothing:
|
|
95
|
+
|
|
96
|
+
- **TechHub** — what **TOGa Commerce** is called on the Compass side.
|
|
97
|
+
- **Mix** — the Compass-side equivalent platform. A request to update "TechHub and Mix" means
|
|
98
|
+
both teams make the same change.
|
|
99
|
+
- **TOGa Retail** — internal-only platform for store-associated transactions; not in `registry.json`.
|
|
100
|
+
- **Personas** — TOGa Supply's item-visibility mechanism (~39 of them; 1 = everyone, 4 = canteen,
|
|
101
|
+
12 = admin and sees everything, 33 = MacBook/Surface).
|
|
102
|
+
- **OptimumDesk / Star Tech** — the ticketing system Talos integrates with for Office Depot.
|
|
103
|
+
- **TOGA vs toga** — capital-A **TOGA** is the company; lowercase **toga** is the platform.
|
|
104
|
+
|
|
105
|
+
## Database MCP (`toga-db`)
|
|
106
|
+
|
|
107
|
+
Read-only MySQL across every environment. All 24 clusters were connected as of 2026-07-30.
|
|
108
|
+
|
|
109
|
+
**Run SELECTs yourself, unprompted.** Do not ask a developer to run a query and paste results
|
|
110
|
+
back — that wastes their time on something Claude can do directly. Query whenever it answers the
|
|
111
|
+
question faster or more reliably than reading code: confirming a schema, checking whether a row
|
|
112
|
+
exists, verifying a config value, sizing a table before proposing a migration, or grounding a
|
|
113
|
+
claim in real data instead of an assumption.
|
|
114
|
+
|
|
115
|
+
**Writes are the developer's job.** The MCP permits `SELECT`/`SHOW`/`DESCRIBE`/`EXPLAIN` only.
|
|
116
|
+
For any `INSERT`/`UPDATE`/`DELETE`/DDL, write the statement out, say which environment and schema
|
|
117
|
+
it targets, and hand it to the developer to execute.
|
|
118
|
+
|
|
119
|
+
**Environments** — pass any alias; the server resolves it:
|
|
120
|
+
|
|
121
|
+
| Group | Names | Naming scheme |
|
|
122
|
+
|---|---|---|
|
|
123
|
+
| V2 production | `prod` / `production` | `Core`, `Client_<id>`, `Archive_<id>`, `Logs_<id>` |
|
|
124
|
+
| V1 production | `legacy` / `v1` | `Core`, `TOGA_<id>`, `TOGaLogs_<id>` |
|
|
125
|
+
| Non-prod | `dev-sandbox`, `client-sandbox`, `client-{alpha,beta,gamma}`, `qa-{task,hotfix,alpha,beta,gamma}`, `qc-{task,hotfix,security,performance,alpha,beta,gamma}`, `stage`, `demo` | V2 naming |
|
|
126
|
+
|
|
127
|
+
**Production is four separate clusters** — `prod-core`, `prod-client`, `prod-archive`,
|
|
128
|
+
`prod-logs`. Every non-prod environment is a single all-in-one host holding all groups. This is
|
|
129
|
+
the same split that makes cross-database joins work locally and fail in production (see
|
|
130
|
+
`2.0/apps/dbchanges2/architecture.md`).
|
|
131
|
+
|
|
132
|
+
**`local` is not this MCP.** If someone means their own machine's database, use the `mysql` CLI
|
|
133
|
+
via shell, not `toga-db`.
|
|
134
|
+
|
|
135
|
+
**Resolving a client name to its databases:** `Core.Clients.clientIdentifier` is the exact suffix
|
|
136
|
+
used in `Client_<id>`, `Archive_<id>`, and `Logs_<id>`.
|
|
137
|
+
|
|
138
|
+
```sql
|
|
139
|
+
-- environment='prod', schema_name='Core'
|
|
140
|
+
SELECT name, clientIdentifier FROM Clients WHERE name LIKE '%<keyword>%';
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Gotcha — the client roster is wider than `registry.json`, and identifiers are not guessable
|
|
144
|
+
|
|
145
|
+
`Core.Clients` held **46 clients** on 2026-07-30 against 17 in `registry.json`. A client absent
|
|
146
|
+
from the registry is normal, not an error — the registry tracks clients whose *code knowledge* has
|
|
147
|
+
been captured, not the full book of business.
|
|
148
|
+
|
|
149
|
+
Identifiers do not follow from the display name, so **look them up, never construct them**:
|
|
150
|
+
|
|
151
|
+
| Display name | `clientIdentifier` | Trap |
|
|
152
|
+
|---|---|---|
|
|
153
|
+
| Compass Group | `Compass_Usa` | Carries an **underscore**, and "Compass Group" maps to the **USA** entity |
|
|
154
|
+
| CompassCanada | `Compass_Canada` | Underscore again |
|
|
155
|
+
| AIG | `Aig` | Title-case, not `AIG` |
|
|
156
|
+
| Staples | `Staples` | A **separate client** from AIG, despite the registry title "AIG (Staples Protection Plan)" |
|
|
157
|
+
| Growrks | `Growrk` | Display name is plural, identifier is not |
|
|
158
|
+
| NYC Health + Hospitals | `Nychh` | |
|
|
159
|
+
| Towfoundation | `Towfoundation` | |
|
|
160
|
+
| Wiss, Janney, Elstner Associates, Inc. | `Wje` | |
|
|
161
|
+
|
|
162
|
+
Schema names are **case-sensitive** — copy the exact value from `toga_list_schemas` or
|
|
163
|
+
`Core.Clients`. `Client_Aig` works; `Client_AIG` and `client_aig` do not.
|
|
164
|
+
|
|
165
|
+
## Applying this
|
|
166
|
+
|
|
167
|
+
- **Never make a teammate name the tool.** "Which environment is that in?" is a fair question;
|
|
168
|
+
"please run this SELECT and paste the output" is not.
|
|
169
|
+
- **Ask about environment only when it genuinely changes the answer** — and when the context makes
|
|
170
|
+
it obvious (a production incident, a client-specific bug), infer it and say which one was used.
|
|
171
|
+
- **State the source.** For a query: the environment and schema. For the knowledge base: the
|
|
172
|
+
filename and its date. That lets the developer judge the evidence.
|
|
173
|
+
- **Combine the three sources.** Code knowledge base → how it is built. Talos → what was decided
|
|
174
|
+
and why. Database → what is actually true right now.
|
|
175
|
+
|
|
176
|
+
## Change history
|
|
177
|
+
- 2026-07-30 — Created. Established that "ask/use Talos" means the Internal Knowledge Base MCP and not the `talos` repo; that Claude runs its own SELECTs unprompted while developers execute writes; and that both MCP connections are used proactively without being requested. Recorded the KB↔registry client-name divergence and the `Core.Clients` identifier traps (jcardinal)
|
package/package.json
CHANGED