Greentic · Phase M

One environment, many messaging assistants

How we let a single deployment environment host several independent chat assistants — each tied to its own set of bundles, its own welcome menu, and its own private knowledge — so they can never reach into each other's flows.

Status as of 1 June 2026  ·  Phase M1 complete  ·  Phase M2 3 of 4 landed  ·  plain-language explainer

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.

“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:

Identity ≠ type. 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.

ENVIRONMENT · e.g. “prod” Inbound message Teams / Slack… Identify instance → provider_id Admit gate bundle ∈ endpoint's allow-list? teams-legal Legal bundles only teams-accounting Accounting bundles Scoped Fast2Flow one index per endpoint + welcome flow Slot extract + AC prefill Card opens pre-filled M1.4 M1.4 M1.2 M1.3/5 M2.1–2.3
Green tags = shipped · amber tag = partly shipped. The admit-gate is the hard wall; the scoped index is the second layer of the same isolation.

M1Messaging endpoints & scoped routing

The plumbing that makes multiple isolated assistants possible. This whole train is landed and dev-published.

Shipped Partly shipped Not started
M1.1

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.

greentic-types · greentic-runner-host
Done
M1.2

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.

greentic-deploy-spec · greentic-deployer · greentic-operator
Done
M1.3

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).

greentic-fast2flow
Done
M1.4

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).

greentic-runner · greentic-runner-host · greentic-start
Done
M1.5

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.

greentic-runner · greentic-start
Done

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.

M2.1

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.

component-slot-extractor
Scaffold
M2.2

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.

greentic-fast2flow · PR #31
Done
M2.3

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.

component-adaptive-card · PR #50
Done
M2.4

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.

greentic-docs · greentic-examples
Not started

+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.

intent

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).

greentic-fast2flow · PRs #27 #28 #29
Done

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_id span 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.