Concepts, value, and typical clone scenarios — less code.
Concepts, value, and typical clone scenarios — less code.
Preparing Ring Platform content
Preparing Ring Platform content
Preparing Ring Platform content
Use Founder / Developer tabs in the docs sidebar to filter this page. This article is the SSOT for Conversation.type (channel) vs metadata.kind (subtype) and inbox hygiene for tool chats.
Ring messaging combines REST conversations with Tunnel Protocol fan-out so members chat in context of opportunities, entities, and store deals without refreshing the page.
| Layer | Where |
|---|---|
| REST | app/api/conversations/** |
| Realtime | Tunnel channels conversation:{id} — see Tunnel Protocol |
| UI | features/chat, features/messages |
| Types | features/chat/types/index.ts |
| API reference | Messaging API |
Ring does not invent a new top-level conversation type for every feature. Two layers stay separate:
| Field | Meaning | Example |
|---|---|---|
Conversation.type | Channel / domain routing — where the thread lives in the messaging system | direct, entity, opportunity, product, group |
metadata.kind | Optional subtype within that channel | generative_gallery |
metadata.hiddenFromInbox | Inbox contract — hide from Messages list | true for tool editors |
Verified channel enum (TypeScript + create zod in app/api/conversations/route.ts):
direct | entity | opportunity | product | group
Do not add type: 'generative'. Generative Gallery reuses type: 'product' plus kind: 'generative_gallery' and hiddenFromInbox: true. Extending the channel enum for one feature breaks product lookup helpers and invents parallel plumbing.
Same product channel, different visibility:
| Use | type | Metadata highlights | Messages inbox |
|---|---|---|---|
| Store product agent (DAGI) | product | real productId, no tool kind | Visible |
| Generative Gallery tool chat | product | kind: 'generative_gallery', hiddenFromInbox: true, productId/subject = genmedia:… | Hidden |
Conversation metadata.kind is not the same namespace as message metadata.kind (e.g. payment_request, env_request, task, poll, rsvp, dao_jar, share_card, gallery_upload, ghost_write_result, game_request).
Interactive types share one lifecycle kit (features/chat/lib/interactive-kind.ts + bubble registry + notify helper): server-action create → dual-gate widget (type OR metadata.kind) → updateMessage / tunnel message:update → typed notify. Domain owns money for dao_jar via public-pools: native treasury chip-in (contributeToPool) and card/PayPal (public_pool_contribution → desk-oracle FX). Chat owns the snapshot — always refreshOpenDaoJarMessages after totals change. share_card reuses MESSAGE_RECEIVED + data.kind. Tier A interactive UX is remediated (2026-07-21); see Public Pools & DAO Jars.
Peer games add game_request (allowlisted in interactive-kind.ts): session SSOT in PeerGameService.createInvite, Tunnel game:invite / games:incoming (incl. terminal clear), and IncomingGameBanner on Messages + /games. Titles: tic-tac-toe · chess · checkers. Direct conversations only. See Peer Games.
Structured work inside a thread: Ring Tasks (type: 'task' + /tasks tree).
Instant conversation shortens the path from match → trust → deal. Members stay inside your Ring instead of dropping to email or third-party chat. Tool editors (image generation history) stay out of the main inbox so operators are not flooded with system threads.
Depends-on: live message and jar updates publish on conversation tunnel channels.
Same-workflow: dao_jar money, dual-currency contribute, and jar refresh after chip-in.
See-also: product-channel tool chats stay hidden from the Messages inbox.
See-also: product agent chats share type product but stay inbox-visible.
Use Founder / Developer tabs in the docs sidebar to filter this page. This article is the SSOT for Conversation.type (channel) vs metadata.kind (subtype) and inbox hygiene for tool chats.
Ring messaging combines REST conversations with Tunnel Protocol fan-out so members chat in context of opportunities, entities, and store deals without refreshing the page.
| Layer | Where |
|---|---|
| REST | app/api/conversations/** |
| Realtime | Tunnel channels conversation:{id} — see Tunnel Protocol |
| UI | features/chat, features/messages |
| Types | features/chat/types/index.ts |
| API reference | Messaging API |
Ring does not invent a new top-level conversation type for every feature. Two layers stay separate:
| Field | Meaning | Example |
|---|---|---|
Conversation.type | Channel / domain routing — where the thread lives in the messaging system | direct, entity, opportunity, product, group |
metadata.kind | Optional subtype within that channel | generative_gallery |
metadata.hiddenFromInbox | Inbox contract — hide from Messages list | true for tool editors |
Verified channel enum (TypeScript + create zod in app/api/conversations/route.ts):
direct | entity | opportunity | product | group
Do not add type: 'generative'. Generative Gallery reuses type: 'product' plus kind: 'generative_gallery' and hiddenFromInbox: true. Extending the channel enum for one feature breaks product lookup helpers and invents parallel plumbing.
Same product channel, different visibility:
| Use | type | Metadata highlights | Messages inbox |
|---|---|---|---|
| Store product agent (DAGI) | product | real productId, no tool kind | Visible |
| Generative Gallery tool chat | product | kind: 'generative_gallery', hiddenFromInbox: true, productId/subject = genmedia:… | Hidden |
Conversation metadata.kind is not the same namespace as message metadata.kind (e.g. payment_request, env_request, task, poll, rsvp, dao_jar, share_card, gallery_upload, ghost_write_result, game_request).
Interactive types share one lifecycle kit (features/chat/lib/interactive-kind.ts + bubble registry + notify helper): server-action create → dual-gate widget (type OR metadata.kind) → updateMessage / tunnel message:update → typed notify. Domain owns money for dao_jar via public-pools: native treasury chip-in (contributeToPool) and card/PayPal (public_pool_contribution → desk-oracle FX). Chat owns the snapshot — always refreshOpenDaoJarMessages after totals change. share_card reuses MESSAGE_RECEIVED + data.kind. Tier A interactive UX is remediated (2026-07-21); see Public Pools & DAO Jars.
Peer games add game_request (allowlisted in interactive-kind.ts): session SSOT in PeerGameService.createInvite, Tunnel game:invite / games:incoming (incl. terminal clear), and IncomingGameBanner on Messages + /games. Titles: tic-tac-toe · chess · checkers. Direct conversations only. See Peer Games.
Structured work inside a thread: Ring Tasks (type: 'task' + /tasks tree).
Instant conversation shortens the path from match → trust → deal. Members stay inside your Ring instead of dropping to email or third-party chat. Tool editors (image generation history) stay out of the main inbox so operators are not flooded with system threads.
Depends-on: live message and jar updates publish on conversation tunnel channels.
Same-workflow: dao_jar money, dual-currency contribute, and jar refresh after chip-in.
See-also: product-channel tool chats stay hidden from the Messages inbox.
See-also: product agent chats share type product but stay inbox-visible.
Use Founder / Developer tabs in the docs sidebar to filter this page. This article is the SSOT for Conversation.type (channel) vs metadata.kind (subtype) and inbox hygiene for tool chats.
Ring messaging combines REST conversations with Tunnel Protocol fan-out so members chat in context of opportunities, entities, and store deals without refreshing the page.
| Layer | Where |
|---|---|
| REST | app/api/conversations/** |
| Realtime | Tunnel channels conversation:{id} — see Tunnel Protocol |
| UI | features/chat, features/messages |
| Types | features/chat/types/index.ts |
| API reference | Messaging API |
Ring does not invent a new top-level conversation type for every feature. Two layers stay separate:
| Field | Meaning | Example |
|---|---|---|
Conversation.type | Channel / domain routing — where the thread lives in the messaging system | direct, entity, opportunity, product, group |
metadata.kind | Optional subtype within that channel | generative_gallery |
metadata.hiddenFromInbox | Inbox contract — hide from Messages list | true for tool editors |
Verified channel enum (TypeScript + create zod in app/api/conversations/route.ts):
direct | entity | opportunity | product | group
Do not add type: 'generative'. Generative Gallery reuses type: 'product' plus kind: 'generative_gallery' and hiddenFromInbox: true. Extending the channel enum for one feature breaks product lookup helpers and invents parallel plumbing.
Same product channel, different visibility:
| Use | type | Metadata highlights | Messages inbox |
|---|---|---|---|
| Store product agent (DAGI) | product | real productId, no tool kind | Visible |
| Generative Gallery tool chat | product | kind: 'generative_gallery', hiddenFromInbox: true, productId/subject = genmedia:… | Hidden |
Conversation metadata.kind is not the same namespace as message metadata.kind (e.g. payment_request, env_request, task, poll, rsvp, dao_jar, share_card, gallery_upload, ghost_write_result, game_request).
Interactive types share one lifecycle kit (features/chat/lib/interactive-kind.ts + bubble registry + notify helper): server-action create → dual-gate widget (type OR metadata.kind) → updateMessage / tunnel message:update → typed notify. Domain owns money for dao_jar via public-pools: native treasury chip-in (contributeToPool) and card/PayPal (public_pool_contribution → desk-oracle FX). Chat owns the snapshot — always refreshOpenDaoJarMessages after totals change. share_card reuses MESSAGE_RECEIVED + data.kind. Tier A interactive UX is remediated (2026-07-21); see Public Pools & DAO Jars.
Peer games add game_request (allowlisted in interactive-kind.ts): session SSOT in PeerGameService.createInvite, Tunnel game:invite / games:incoming (incl. terminal clear), and IncomingGameBanner on Messages + /games. Titles: tic-tac-toe · chess · checkers. Direct conversations only. See Peer Games.
Structured work inside a thread: Ring Tasks (type: 'task' + /tasks tree).
Instant conversation shortens the path from match → trust → deal. Members stay inside your Ring instead of dropping to email or third-party chat. Tool editors (image generation history) stay out of the main inbox so operators are not flooded with system threads.
Depends-on: live message and jar updates publish on conversation tunnel channels.
Same-workflow: dao_jar money, dual-currency contribute, and jar refresh after chip-in.
See-also: product-channel tool chats stay hidden from the Messages inbox.
See-also: product agent chats share type product but stay inbox-visible.
Integrator contracts for conversations and typing.
/api/mcp/v1/messaging/conversations| Agent tooling |
After writes, publish on Tunnel channel conversation:{id} via publishToChannel — clients subscribe with useTunnelChannel (not raw useTunnel().subscribe() in effects).
Create body type must be one of: direct | entity | opportunity | product | group (z.enum in app/api/conversations/route.ts). Optional metadata includes productId, groupName, kind, hiddenFromInbox, and domain ids (entityId, opportunityId, …).
ConversationService.getConversations skips rows where isHiddenToolConversation is true (features/chat/services/conversation-service.ts):
metadata.hiddenFromInbox === true (preferred long-term gate)metadata.kind === 'generative_gallery'productId or subject starts with genmedia: or imggen:| Path | Responsibility |
|---|---|
features/chat/types/index.ts | Conversation, CreateConversationRequest, filters |
features/chat/services/conversation-service.ts | CRUD + isHiddenToolConversation |
features/chat/, features/messages/ | Chat UI |
features/generative-media/service.ts | Creates hidden product + generative_gallery chats |
features/store/services/product-agent-service.ts | Creates visible product agent chats |
lib/tunnel/ | Hub, publisher, transports |
hooks/use-tunnel-channel.ts | Stable channel subscribe |
/api/tunnel/ws primary/api/tunnel/poll)Full endpoint samples: Messaging API. Architecture: Real-time.
Next-step: 1:1 audio/video in direct chats.
Integrator contracts for conversations and typing.
/api/mcp/v1/messaging/conversations| Agent tooling |
After writes, publish on Tunnel channel conversation:{id} via publishToChannel — clients subscribe with useTunnelChannel (not raw useTunnel().subscribe() in effects).
Create body type must be one of: direct | entity | opportunity | product | group (z.enum in app/api/conversations/route.ts). Optional metadata includes productId, groupName, kind, hiddenFromInbox, and domain ids (entityId, opportunityId, …).
ConversationService.getConversations skips rows where isHiddenToolConversation is true (features/chat/services/conversation-service.ts):
metadata.hiddenFromInbox === true (preferred long-term gate)metadata.kind === 'generative_gallery'productId or subject starts with genmedia: or imggen:| Path | Responsibility |
|---|---|
features/chat/types/index.ts | Conversation, CreateConversationRequest, filters |
features/chat/services/conversation-service.ts | CRUD + isHiddenToolConversation |
features/chat/, features/messages/ | Chat UI |
features/generative-media/service.ts | Creates hidden product + generative_gallery chats |
features/store/services/product-agent-service.ts | Creates visible product agent chats |
lib/tunnel/ | Hub, publisher, transports |
hooks/use-tunnel-channel.ts | Stable channel subscribe |
/api/tunnel/ws primary/api/tunnel/poll)Full endpoint samples: Messaging API. Architecture: Real-time.
Next-step: 1:1 audio/video in direct chats.
Integrator contracts for conversations and typing.
/api/mcp/v1/messaging/conversations| Agent tooling |
After writes, publish on Tunnel channel conversation:{id} via publishToChannel — clients subscribe with useTunnelChannel (not raw useTunnel().subscribe() in effects).
Create body type must be one of: direct | entity | opportunity | product | group (z.enum in app/api/conversations/route.ts). Optional metadata includes productId, groupName, kind, hiddenFromInbox, and domain ids (entityId, opportunityId, …).
ConversationService.getConversations skips rows where isHiddenToolConversation is true (features/chat/services/conversation-service.ts):
metadata.hiddenFromInbox === true (preferred long-term gate)metadata.kind === 'generative_gallery'productId or subject starts with genmedia: or imggen:| Path | Responsibility |
|---|---|
features/chat/types/index.ts | Conversation, CreateConversationRequest, filters |
features/chat/services/conversation-service.ts | CRUD + isHiddenToolConversation |
features/chat/, features/messages/ | Chat UI |
features/generative-media/service.ts | Creates hidden product + generative_gallery chats |
features/store/services/product-agent-service.ts | Creates visible product agent chats |
lib/tunnel/ | Hub, publisher, transports |
hooks/use-tunnel-channel.ts | Stable channel subscribe |
/api/tunnel/ws primary/api/tunnel/poll)Full endpoint samples: Messaging API. Architecture: Real-time.
Next-step: 1:1 audio/video in direct chats.