The idea, in plain words
Until now, one environment basically ran one assistant. We're changing that so the same environment can run many assistants of the same kind (e.g. several Microsoft Teams bots) that stay completely walled off from each other.
A messaging endpoint is one named chat assistant — a specific bot identity bound to a chosen list of bundles. Several endpoints can live in one environment, and a question asked on one can only reach the flows that endpoint is allowed to see.
“Legal Assistant” on Teams
Bound to the Legal bundles only. Its Fast2Flow search index physically contains nothing but Legal flows.
“Draft an NDA between Acme and us by Friday.”
→ routed to the NDA flow. An accountant on the other bot literally cannot reach it.
“Accounting Assistant” on Teams
Same environment, same Teams provider type — but a different bot identity, bound to Accounting bundles only.
“Raise an expense claim for last week's travel.”
→ routed to the expenses flow. Legal flows are invisible here.
Three things make this work, and each is a deliberate design choice:
provider_id (the bot instance) is now distinct from provider_type (“teams”).
Hard isolation. An admit-gate rejects any request whose bundle isn't in the endpoint's allow-list — belt and braces with the scoped index.
Own front door. First-time users see that endpoint's welcome flow, not a generic fallback.
How a message flows
From an inbound chat message to a pre-filled card — and where each phase plugs in.
M1Messaging endpoints & scoped routing
The plumbing that makes multiple isolated assistants possible. This whole train is landed and dev-published.
Bot identity is now separate from bot type
provider_id identifies the specific instance; provider_type is the class.
Two Teams bots in one env are no longer rejected as duplicates.
A typed “MessagingEndpoint” entity + CLI to manage it
New entity holds the bot's id, display name, secret refs, linked bundles and welcome flow.
New gtc op messaging endpoint add / list / link-bundle / set-welcome-flow / remove verbs.
Each endpoint gets its own private search index
Fast2Flow scope switched from tenant:team to endpoint:id. The index for an
endpoint contains only its linked bundles' flows — Legal questions can't match Accounting flows.
Validation hardened at the trust boundary (PR #26 + #32).
Endpoint id flows through ingress + the hard admit-gate
The x-greentic-messaging-endpoint-id header is threaded through serving. The admit-gate
fail-closes any request whose resolved bundle isn't in that endpoint's allow-list (401/403, never 500).
First-time users see the endpoint's welcome menu
A user with no prior session on an endpoint bypasses Fast2Flow and is sent straight to that
endpoint's welcome_flow. Each assistant owns its own front door.
M2Utterance prefill
Once a message is routed to a flow, pre-fill that flow's card from what the user actually typed — so a lawyer who says “NDA with Acme by Friday” opens a card with counterparty and due-date already filled.
New “slot-extractor” component
Pulls structured values (dates, names, amounts, yes/no, choices) out of free text. Scaffold merged (new repo, PR #1). Real regex extraction for all 5 slot types is the next PR.
The original utterance now rides along on routing
Fast2Flow's Dispatch directive now echoes the user's original text, so downstream
nodes can read it without an extra session round-trip.
Adaptive Cards accept a “prefill” payload
Cards now take an explicit prefill with documented precedence — both as an
Input.value merge and a prefill.* binding namespace.
Flow-authoring pattern + docs + worked example
Document the canonical chain (Dispatch → slot-extractor → prefilled card), add the
slot_schema manifest field, and ship the Legal-NDA worked example.
+Bonus: deterministic entity extraction
While building M1.3, a stronger foundation for prefill landed ahead of schedule — a deterministic, multilingual extractor that doesn't need an LLM.
greentic-intent crate + index manifest v2 + intent-on-Dispatch
Deterministic multilingual entity extraction (PR #27), first-class utterances in the index with a cross-version reader (PR #28), and intent prefill wired into the routing host (PR #29).
Where we stand
✓ Already done
- Multiple bot identities per environment M1.1 · provider_id ≠ provider_type
- Typed endpoint entity + full CLI M1.2 · deploy-spec + operator verbs
- Per-endpoint private Fast2Flow index M1.3 · PR #26 + #32
- Endpoint id through ingress + hard admit-gate M1.4 · greentic-start
- First-contact welcome flow M1.5 · own front door per endpoint
- Utterance echoed on Dispatch M2.2 · PR #31
- Adaptive Card prefill payload M2.3 · PR #50
- Deterministic multilingual extractor bonus · PRs #27–#29
○ Still to do
- Real slot extraction (5 types: text, choice, number, date, yes/no) M2.1 PR 2 · chrono dates + i18n affirmatives
- Wire extractor output → card prefill (integration smoke) M2.1 PR 3
- Authoring pattern + docs + Legal-NDA example M2.4
- Register the new repo in REPO_MANIFEST.toml component-slot-extractor · tier 3 · 0.1→0.2
- Per-endpoint session isolation (via ctx attribute) open question #2 — decided, not yet built
- Telemetry:
gt.messaging_endpoint_idspan attr open question #5 — C5 annotate_span pattern
Quick reference
Glossary — the five words that matter
Environment — a deployment (e.g. “prod”). Hosts everything below.
Messaging endpoint — one named chat assistant = one bot identity + its allowed bundles + a welcome flow.
Bundle — a deployable unit of packs/flows. An endpoint links the bundles it's allowed to reach.
Fast2Flow — the router that matches a user's message to the right flow. Now scoped per endpoint.
Prefill / slot — values pulled from the user's text (a “slot” = one field) and dropped into a card.
Explicitly out of scope (for now)
• Cross-endpoint handoff (“let me ask Legal” from inside Accounting) — would need a new gateway node.
• Multi-turn slot filling — M2 is single-utterance, one-shot extraction.
• LLM-driven “which assistant should I use?” discovery — users reach an endpoint via its channel directly.
• Per-traffic-split endpoint differences — an endpoint's linked bundles apply env-wide.
• WebChat / DirectLine / WS endpoint resolution — a sibling follow-up.
Why two layers of isolation?
The scoped index (M1.3) means an endpoint's router physically cannot match a flow it isn't allowed to see. The admit-gate (M1.4) is a separate fail-closed check at the door: even if a request somehow names a bundle outside the endpoint's allow-list, it's refused before dispatch. Belt and braces — a single conceptual gate enforced at two independent points.