cometchat-flutter-v6-core — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited cometchat-flutter-v6-core (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Ground truth:cometchat_chat_uikit@6(6.1.0) +cometchat_sdk@^5.0.6. EveryCometChat*symbol here is incatalogs/flutter-v6.json— compiler-verified against the published package. Signatures marked [verified] were compiled because the docs were wrong, or (forinitFromSettings) deliberately silent (DOCS-BACKLOG.mdPART 4): trust this file for those, fetch the rest viareferences/docs-map.md. THIN map loaded every run; depth inreferences/*.
<!-- core is the companion the other flutter v6 skills read; it has no Companion block of its own. -->
"add chat to my Flutter app", "integrate CometChat in Flutter", "set up CometChat credentials", "show a conversations + messages screen". An unscoped "add chat" means a production-ready core surface — a CometChatConversations screen pushing a message screen, with threaded replies and search wired, in Scaffold/SafeArea, keyboard-safe, every screen popping back — NOT a two-widget demo, NOT the whole tab-based app (see the golden path). It grows on request → cometchat-flutter-v6-placement.
flutter pub add cometchat_chat_uikitPin the major in pubspec.yaml — cometchat_chat_uikit: ^6.1.0 (a bare any can resolve across majors). The Chat SDK (cometchat_sdk) comes transitively and is re-exported by the kit barrel — do NOT add it separately unless you import SDK-only paths. Voice/video calling = a settings flag + native config (cometchat_calls_sdk is already a transitive kit dependency — see below) → cometchat-flutter-v6-calls.
Platform minimums — Android minSdk = 26 in android/app/build.gradle.kts; iOS platform :ios, '15.1' in ios/Podfile. The `getting-started` page says 24 / 13.0 and both are too low (DOCS-BACKLOG D7). The kit's own AAR allows 21, but transitive deps set the real floor and this one is not optional: cometchat_chat_uikit depends on `cometchat_calls_sdk` unconditionally — it sits in the main dependencies: block — and that package pins minSdkVersion 26 / platform :ios, '15.1' (5.0.7). Gradle and CocoaPods take the maximum across the graph, so a lower value is a build error whether or not the app uses calling.
references/setup-credentials.md)pubspec.yaml + lockfile (deps and the kit major), lib/main.dart, state management, navigation, and how config is handled. Reuse an existing .cometchat/config.json or settings asset (skip re-setup). Signal table: references/setup-credentials.md.cometchat_chat_uikit v5 (or any non-v6 major); reconcile first, never mix majors (RULES.md). A v5 project that wants v6 → cometchat-flutter-v6-migration.cometchat-settings.json (§4) from those creds; the CLI is dashboard/API-only and never writes Dart (RULES.md §21). Never defer credentials to a "add them yourself" TODO. Exact commands + the app-picker flow: references/setup-credentials.md.flutter build fails — see the note in §Integration ordering); never echo the Auth Key. Prod → server-minted auth token, not the Auth Key.init then login both hit onSuccess. An auth error is almost always the wrong Region.initFromSettings() once at startup → login(UID) after init succeeds → only THEN render any CometChat* widget.
Init via `initFromSettings` — the file-based, telemetry-attributed path (`RULES.md` §5). It reads a cometchat-settings.json asset and persists integrationSource="ai-agent". Flutter's signature takes NO settings argument (unlike web, which passes a settings object) — the file IS the input:
// [verified vs 6.1.0] — INTENTIONALLY undocumented upstream (@nodoc, owner decision:
// DOCS-BACKLOG F4 WONTFIX). Prefer it over the docs' UIKitSettingsBuilder + init()
// path, which loses telemetry attribution. The shape below is the contract.
import 'package:cometchat_chat_uikit/cometchat_chat_uikit.dart';
await CometChatUIKit.initFromSettings(
onSuccess: (String message) => debugPrint('CometChat initialized'),
onError: (CometChatException e) => debugPrint('Init failed: ${e.message}'),
);cometchat-settings.json at the project root, registered in pubspec.yaml under flutter: assets::
{
"appId": "APP_ID",
"region": "REGION",
"credentials": { "authKey": "AUTH_KEY" },
"uiKit": { "subscribePresenceForAllUsers": true, "enableCalling": false },
"chatSDK": { "autoEstablishSocketConnection": true }
}Keys are read exactly as above.uiKit.enableCallingis the only way to turn calling on via this path (UIKitSettingsdefaults it to false) — leave itfalseuntil the user asks for calls.credentials.authKeyis dev-only; omit it for production and log in with a server-minted token. Make a fresh clone build. A file registered underflutter: assets:MUST exist at build time orflutter build bundlefails with "No file or variants found for asset: cometchat-settings.json." So do not gitignore the registered asset. Instead commit a placeholder `cometchat-settings.json` — same shape, with a placeholder/emptyauthKey(NEVER a real dev Auth Key) — and have each developer and CI overwrite it locally/at build time with real credentials. (Enforce "no real key committed" via a pre-commit check or CI, not.gitignore.) For production, CI generates the prod-flavoured file (no Auth Key) at build time (cometchat-flutter-v6-production).
// login AFTER init succeeds. CometChatUIKit.login already checks getLoggedInUser()
// internally and no-ops if that UID is signed in, so no host-side re-login guard is needed.
await CometChatUIKit.login(
uid,
onSuccess: (User user) => debugPrint('Logged in: ${user.name}'),
onError: (CometChatException e) => debugPrint('Login failed: ${e.message}'),
);Which UID?login()needs a user that ALREADY EXISTS — never invent one. ASK, or take one from Dashboard → Users; fresh apps seedcometchat-uid-1…. The only tentative suggestion iscometchat-uid-1, labelled "if this is a fresh app." Prod → `CometChatUIKit.loginWithAuthToken(authToken, …)` with a token minted server-side. Init-once, hot-restart, and gating the first frame:references/lifecycle.md.
Init/session: CometChatUIKit (initFromSettings · login · loginWithAuthToken · logout · loggedInUser), UIKitSettingsBuilder, CometChatSubscriptionType, CometChatException. Core surface: CometChatConversations, CometChatMessageHeader, CometChatMessageList, CometChatMessageComposer; wired affordances CometChatThreadedHeader, CometChatSearch. Grow set (added on request): CometChatUsers, CometChatGroups, CometChatGroupMembers, CometChatChangeScope, CometChatCallLogs. Incoming calls need NO widget — with calling on, the kit presents the overlay itself (-calls).
TWO BARRELS — a real compile trap.package:cometchat_chat_uikit/cometchat_chat_uikit.dartgives you the chat widgets and the re-exported Chat SDK (User,Group,Conversation,BaseMessage,TextMessage— no separate import). Every calls symbol (CometChatIncomingCall,CometChatOutgoingCall,CometChatCallButtons,CometChatCallLogs,CometChatCallBubble,CometChatCalls) lives ONLY inpackage:cometchat_chat_uikit/cometchat_calls_uikit.dart, and that barrel does NOT re-export the chat widgets — a calls screen imports both. Verified: usingCometChatIncomingCallwith only the chat import fails to compile. The v6 widget is `CometChatThreadedHeader` —CometChatThreadHeader(the React name) does NOT exist here. Never carry a name across families.
CometChatConversations: onItemTap(Conversation) (select → push the message screen) · hideSearch · searchReadOnly (set true so the field acts as a button) · onSearchTap (→ push CometChatSearch) · conversationsRequestBuilder (scope to user/group when the ask is DM-only or groups-only — reuse the builder, don't client-filter) · hideAppbar · appBarOptions · onBack.CometChatMessageHeader: user: / group: (pass the SAME target as the list) · showBackButton (default true) + onBack · hideVoiceCallButton / hideVideoCallButton (call buttons are built in — leave them unless calls are out of scope) · auxiliaryButtonView / trailingView (where a custom action goes — see search below).CometChatMessageList: user: / group: · parentMessageId (thread mode) · onThreadRepliesClick [verified] — the type is ThreadRepliesClick = void Function(BaseMessage message, BuildContext context, {CometChatMessageTemplate? template}); a one-argument closure does not compile (DOCS-BACKLOG F2).CometChatMessageComposer: user: / group: · parentMessageId (thread mode). A plain send needs nothing else.CometChatSearch [verified]: onConversationClicked / onMessageClicked (not the docs' onConversationItemClick / onMessageItemClick — DOCS-BACKLOG F3) · onBack · user: / group: / searchIn to scope it to one chat.Any OTHER widget or a rarer prop → fetch its.mdtwin viareferences/docs-map.md. Full catalog:cometchat-flutter-v6-components.
Setup → init/login → gate the first frame on both resolving (show a loader; never render a CometChat* widget before login succeeds) → then:
CometChatConversations inside Scaffold + SafeArea. Wire onItemTap → Navigator.push the message screen for that conversation's User/Group. Wire the global search the documented way: searchReadOnly: true + onSearchTap → push a CometChatSearch screen, whose onConversationClicked/onMessageClicked navigate to the hit and whose onBack pops. (Or set hideSearch: true — but never leave the field dead.)CometChatMessageHeader + Expanded(child: CometChatMessageList(...)) + CometChatMessageComposer, all carrying the SAME user:/group:. Expanded is what makes the list fill the screen; the header/composer keep their intrinsic height. Leave Scaffold.resizeToAvoidBottomInset at its default true so the composer rides above the keyboard. The header's showBackButton defaults to true — wire onBack to Navigator.pop.onThreadRepliesClick to push a screen with CometChatThreadedHeader(parentMessage:, loggedInUser:) — both required, and it has no `onBack`, so the screen's own AppBar provides back — plus a CometChatMessageList + CometChatMessageComposer that each take parentMessageId: parentMessage.id AND the same `user:`/`group:` as the parent chat. Passing `parentMessageId` without the user/group target makes thread replies silently never send.CometChatMessageHeader has no search prop (unlike React). Put the action in the header's auxiliaryButtonView/trailingView slot — custom UI goes IN the slot, never stacked on top — and push CometChatSearch(user: …/group: …) so it searches only that chat.// [verified vs 6.1.0] the message screen — the shape the whole surface hangs off.
import 'package:cometchat_chat_uikit/cometchat_chat_uikit.dart';
import 'package:flutter/material.dart';
class MessageScreen extends StatelessWidget {
final User? user;
final Group? group;
const MessageScreen({super.key, this.user, this.group});
@override
Widget build(BuildContext context) {
return Scaffold( // resizeToAvoidBottomInset defaults to true = keyboard-safe
body: SafeArea(
child: Column(
children: [
CometChatMessageHeader(user: user, group: group, onBack: () => Navigator.pop(context)),
Expanded( // REQUIRED — the list fills the remaining height
child: CometChatMessageList(
user: user,
group: group,
onThreadRepliesClick: (BaseMessage message, BuildContext context,
{CometChatMessageTemplate? template}) {
Navigator.push(context, MaterialPageRoute(
builder: (_) => ThreadScreen(parentMessage: message, user: user, group: group),
));
},
),
),
CometChatMessageComposer(user: user, group: group),
],
),
),
);
}
}
// The thread screen the callback pushes — part of the DEFAULT surface, not an extra.
// NOTE: the list AND composer each take parentMessageId *and* the same user:/group:
// as the parent chat. parentMessageId alone => replies silently never send.
class ThreadScreen extends StatelessWidget {
final BaseMessage parentMessage;
final User? user;
final Group? group;
const ThreadScreen({super.key, required this.parentMessage, this.user, this.group});
@override
Widget build(BuildContext context) {
return Scaffold(
// The thread screen's back affordance is the AppBar — CometChatThreadedHeader
// has NO onBack/onError param (the docs show one; it does not exist, DOCS-BACKLOG F5).
// A pushed route gets the back button automatically.
appBar: AppBar(title: const Text('Thread')),
body: SafeArea(
child: Column(
children: [
CometChatThreadedHeader( // note the 'ed' — see the map above
parentMessage: parentMessage, // NOT `message:` (DOCS-BACKLOG F1)
loggedInUser: CometChatUIKit.loggedInUser!, // required
),
Expanded(
child: CometChatMessageList(
user: user, group: group, parentMessageId: parentMessage.id,
),
),
CometChatMessageComposer(
user: user, group: group, parentMessageId: parentMessage.id,
),
],
),
),
);
}
}SIZE it the mobile way — `references/layout.md`. The kit's list widgets expand to fill their parent, so the failure mode here is an unbounded height error or a collapsed list, and the fix is always the same: give the list a bounded box (Expanded/Flexibleinside aColumn, or a sized parent) instead of letting content drive it. Never nest the surface in an unboundedSingleChildScrollView/ColumnwithoutExpanded. Match the data scope to the REQUEST. Real apps ship seeded groups, so a plainCometChatConversationslists both 1:1s and groups. A DM-only ask scopes the list to user conversations viaconversationsRequestBuilder; a groups-only app scopes to groups; a generic "add chat" keeps BOTH. Reuse the builder — never hand-roll a client-side filter, and don't add a Groups tab to a 1:1-only app. Prod auth: mint a per-user auth token server-side and callloginWithAuthToken— the Auth Key is dev-only (references/lifecycle.md).
Add each only when asked: Users / Groups / Calls tabs (CometChatUsers · CometChatGroups · CometChatCallLogs) · group details (CometChatGroupMembers + CometChatChangeScope) · calls (→ -calls; incoming calls = only navigatorKey: CallNavigationContext.navigatorKey on the root MaterialApp — never mount CometChatIncomingCall yourself, that doubles the kit's overlay) · features (→ -features). The full tab-based app is the union of these — recipe in -placement. A scoped-DOWN ask (chat tab, bottom sheet, embedded panel) → the matching -placement variant.
setup-credentials.md — detect signals · version_conflict · dashboard creds · the settings asset.lifecycle.md — init-once + hot restart · gating the first frame · prod auth-token · logout.layout.md — mobile sizing (bounded height · Expanded · SafeArea · keyboard).docs-map.md — intent → live doc page (component twins + the SDK-docs section) · DOCS-GAP protocol · the pages that are wrong.anti-patterns.md — v5 carry-overs · unbounded height · render-before-login · the two-barrel trap.troubleshooting.md — symptom → cause → fix.references/anti-patterns.md)UIKitSettings.extensions, no CometChatUIKitChatExtensions, no DataSource/ChatConfigurator/*ExtensionDecorator, no CometChatUIKit.getDataSource(). Dashboard-enabled extensions surface automatically with zero client code. Also gone: the v5 combined shells (CometChatConversationsWithMessages, CometChatUsersWithMessages, CometChatMessages, CometChatUI) — v6 has no shell widget; the host composes screens. Full map: cometchat-flutter-v6-migration.onThreadRepliesClick, and the search callbacks were wrong on the live pages (DOCS-BACKLOG.md PART 4 F1/F2/F3/F5) — all four are now corrected upstream (re-verified against cometchat/docs@2ebb1db, 2026-09-09), so the [verified] names now agree with the pages; keep them. initFromSettings is different: it is deliberately undocumented and stays that way (F4 WONTFIX), so this skill is its only reference.Run the app: init then login both hit onSuccess → the conversations screen renders full-size (no sliver, no unbounded-height exception) → tap a conversation → messages send/receive → "reply in thread" opens the thread screen and back returns → the search field pushes search, a result navigates, back pops → the composer stays visible with the keyboard open → every pushed screen pops back. Blank screen ⇒ rendered before login resolved, or wrong Region/App ID. No bounded height, no thread wiring, or a dead search field ⇒ under-delivery. Tab-based app ⇒ verify per -placement.
Build the feature; do not write tests or run a test framework unless asked (RULES.md) — the above is an advisory human pass.RULES.md §19)Don't end on a silent code dump. Briefly: (1) what I wired (3–5 bullets, NAME the files); (2) decisions & why, flagging dev-only AS dev-only (Auth Key → server token for prod; the <uid>); (3) what I did NOT touch (additive — routing/state/theme intact). Then offer THREE options as a selectable choice and WAIT for the pick:
-features / -calls.-customization.A capability not in this pack: say so honestly + link CometChat's docs.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.