Skip to content

rcli network driver + example-app brand alignment (#FF6900)#570

Draft
sanchitmonga22 wants to merge 3 commits into
mainfrom
feat/example-apps-brand-alignment
Draft

rcli network driver + example-app brand alignment (#FF6900)#570
sanchitmonga22 wants to merge 3 commits into
mainfrom
feat/example-apps-brand-alignment

Conversation

@sanchitmonga22

@sanchitmonga22 sanchitmonga22 commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

rcli control-plane network driver + example-app brand alignment

Combines two SDK-repo changes into one PR.

Part 1 — rcli control-plane network driver (sdk/runanywhere-cli)

Turns rcli into a control-plane client that can point at any backend (including localhost) for integration testing and manual debugging.

  • Global --base-url / --api-key / --environment flags (+ RUNANYWHERE_* env vars), threaded into the SDK config with zero regression when absent.
  • rcli auth login — real handshake (API key → JWT, device register, model-assignments fetch).
  • rcli telemetry emit --modality <m> and rcli telemetry blast — model-free telemetry through the real network transport with a 12-modality result table.
  • Proven end-to-end against a locally-run backend: login registers a device with real hardware facts; blast lands all 12 modalities as verified rows; a bad key exits non-zero. Existing commands unchanged (10/10 CLI tests).

Part 2 — align the 5 example apps to the brand + design guideline

Every example app had drifted from the brand: their UI accents were the legacy #FF5500 (Flutter/RN were plain blue) while their logos were already the correct #FF6900. This finishes the migration.

  • examples/DESIGN_GUIDELINE.md — canonical brand doc (primary = the logo's #FF6900, gradient →#FB2C36, full palette light+dark, per-platform mapping, the white-on-orange contrast caveat).
  • iOS (AppColors + AccentColor + Keyboard/Activity extensions), Android (Color.kt tonal ramp on the brand hue + dead template swatches removed), Flutter (mislabeled-blue primary → brand, seed pinned), Web (CSS tokens + loading SVG + theme-color), React Native (two competing theme systems consolidated onto one anchored to #FF6900; legacy barrel deleted; migrated screens now get dark mode).
  • Each app's AGENTS.md gains a Design System section pointing at the guideline (CLAUDE.md symlinks intact); parent AGENTS.md references it.
  • Removed the dead rac_telemetry_manager_parse_response declaration + stale export.

Grep-proven: zero legacy accent literals remain; #FF6900 present in all five apps.

Summary by CodeRabbit

  • New Features

    • Added CLI support for control-plane environments, authentication, device registration, and model assignments.
    • Added telemetry commands for sending events by modality or across all supported modalities, with JSON and human-readable results.
    • Improved theme-aware styling across the React Native app, including light and dark modes.
  • Style

    • Standardized example app branding around the RunAnywhere orange and updated palettes across Android, iOS, Flutter, React Native, and web.
  • Documentation

    • Added comprehensive cross-platform design guidelines and theme configuration guidance.

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1ab52bc7-33a7-4097-a2a5-4cc1aea49680

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR adds shared design guidance and aligns Android, Flutter, iOS, React Native, and web examples with the #FF6900 brand palette. It also adds validated control-plane connectivity, authentication, telemetry commands, device callbacks, and related CLI build and API updates.

Changes

Example app design system alignment

Layer / File(s) Summary
Design guideline and native platform palette updates
AGENTS.md, examples/DESIGN_GUIDELINE.md, examples/android/..., examples/flutter/..., examples/ios/...
Adds shared design rules and updates native example brand colors, palette constants, and theme guidance.
React Native theme-system migration
examples/react-native/RunAnywhereAI/...
Introduces cached theme-aware styles and migrates screens and components from static tokens to dynamic useTheme() styling.
Web branding and CSS token updates
examples/web/RunAnywhereAI/...
Updates web design documentation, logo gradients, browser metadata, component accents, and CSS theme variables.

Control-plane CLI workflows

Layer / File(s) Summary
Connection configuration and SDK bootstrap
sdk/runanywhere-cli/src/app.cpp, sdk/runanywhere-cli/src/bootstrap.*, sdk/runanywhere-cli/src/commands/commands.h
Adds environment, base URL, and API-key options; validates connections; initializes SDK state; and registers device callbacks.
Control-plane transport and login handshake
sdk/runanywhere-cli/src/net/control_plane.*
Adds device metadata callbacks, HTTP POST handling, authentication, phase-two SDK initialization, and login result structures.
Authentication command
sdk/runanywhere-cli/src/commands/cmd_auth.cpp
Adds rcli auth login with device-registration validation and JSON or human-readable output.
Telemetry emission workflows
sdk/runanywhere-cli/src/commands/cmd_telemetry.cpp, sdk/runanywhere-cli/README.md, sdk/runanywhere-commons/...
Adds telemetry emit and telemetry blast, tracks and flushes modality events, reports backend accounting, and removes the obsolete telemetry response parser API/export.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant Bootstrap
  participant ControlPlane
  participant SDK
  participant Backend
  CLI->>Bootstrap: Parse and validate connection options
  Bootstrap->>SDK: Initialize SDK state
  Bootstrap->>ControlPlane: Register device callbacks
  CLI->>ControlPlane: Run auth login or telemetry command
  ControlPlane->>Backend: Authenticate and exchange API key
  ControlPlane->>SDK: Initialize phase two
  SDK->>Backend: Post device or telemetry data
  Backend-->>CLI: Return registration and telemetry accounting
Loading

Possibly related PRs

Suggested labels: documentation, enhancement, core

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description does not follow the required template and omits the checklist, testing, labels, and screenshots sections. Rewrite the PR body using the repository template, including Description, Type of Change, Testing, Labels, Checklist, and Screenshots sections.
Docstring Coverage ⚠️ Warning Docstring coverage is 12.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the two main changes: rcli network driver work and example-app brand alignment.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/example-apps-brand-alignment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sanchitmonga22 sanchitmonga22 changed the title Align example apps to brand #FF6900 + design guideline rcli network driver + example-app brand alignment (#FF6900) Jul 19, 2026
@sanchitmonga22

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

Please do a detailed review of this PR. It combines two changes:

  1. rcli control-plane network driver (sdk/runanywhere-cli) — new connection flags, auth login, and telemetry emit/blast commands driving the real network layer; plus removal of the dead rac_telemetry_manager_parse_response declaration.
  2. Example-app brand alignment — retargeting all 5 example apps (iOS/Android/Flutter/RN/Web) from the legacy #FF5500/blue to the brand #FF6900, a new examples/DESIGN_GUIDELINE.md, and the React Native dual-theme-system consolidation.

Areas worth close attention: the RN theme migration (legacy barrel deletion + 11 file migration), the Android tonal-ramp regeneration, the Flutter ColorScheme seed/copyWith, and the rcli connection-flag threading + auth handshake.

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown

@sanchitmonga22: Starting a detailed end-to-end review of #570, with extra scrutiny on the rcli connection/auth transport, telemetry commands, React Native theme migration, Android palette ramp, and Flutter ColorScheme setup.

✅ Action performed

Full review finished.

sanchitmonga22 and others added 2 commits July 19, 2026 10:20
…lemetry

Turns rcli into a control-plane client that can point at any backend for
integration testing and manual debugging:
- Global --base-url / --api-key / --environment flags (+ RUNANYWHERE_* env
  vars), threaded into the SDK config with zero regression when absent.
- rcli auth login — real handshake (API key -> JWT, device register,
  model-assignments fetch).
- rcli telemetry emit --modality <m> and rcli telemetry blast — model-free
  telemetry through the real network transport, with a 12-modality result table.

Verified end-to-end against a locally-run backend: login registers a device
with real hardware facts; blast lands all 12 modalities as verified rows; a
bad key exits non-zero. Existing commands unchanged (10/10 CLI tests).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U4scoVoLn3Z3NxaiK3LC5M
Every example app had drifted from the brand: UI accents were the legacy
#FF5500 (Flutter/RN were plain blue) while the logos were already the correct
#FF6900. This finishes the migration.

- examples/DESIGN_GUIDELINE.md: canonical brand doc (primary = the logo's
  #FF6900, gradient ->#FB2C36, full palette light+dark, per-platform mapping,
  the white-on-orange contrast caveat).
- iOS (AppColors + AccentColor + Keyboard/Activity extensions), Android
  (Color.kt tonal ramp on the brand hue; dead template swatches removed),
  Flutter (mislabeled-blue primary -> brand, seed pinned), Web (CSS tokens +
  loading SVG + theme-color), React Native (two competing theme systems
  consolidated onto one anchored to #FF6900; legacy barrel deleted; migrated
  screens now get dark mode).
- Each app's AGENTS.md gains a Design System section pointing at the guideline
  (CLAUDE.md symlinks intact); parent AGENTS.md references it.
- Removed the dead rac_telemetry_manager_parse_response declaration + export.

Grep-proven: zero legacy accent literals remain; #FF6900 present in all five.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U4scoVoLn3Z3NxaiK3LC5M
@sanchitmonga22
sanchitmonga22 force-pushed the feat/example-apps-brand-alignment branch from f5271dd to c14f46b Compare July 19, 2026 17:21
@sanchitmonga22

Copy link
Copy Markdown
Contributor Author

Force-pushed a cleanup (squashed to 2 commits: rcli driver + example-app brand alignment). @coderabbitai full review — please review the updated commits.

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown

@sanchitmonga22: Starting a fresh detailed review of the updated, squashed commits in #570. I’ll re-check the rcli connection/auth/telemetry flow and each platform’s brand/theme migration, with particular scrutiny on the RN consolidation, Android tonal palette, and Flutter ColorScheme configuration.

✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🧹 Nitpick comments (4)
examples/web/RunAnywhereAI/src/styles/components.css (2)

474-474: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use the existing design-system token.

This rgba value exactly matches the --color-primary-light token defined in design-system.css. Using the token maintains a single source of truth for brand colors.

♻️ Proposed fix
-  box-shadow: 0 2px 8px rgba(255,105,0,0.12);
+  box-shadow: 0 2px 8px var(--color-primary-light);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/web/RunAnywhereAI/src/styles/components.css` at line 474, Replace
the hardcoded rgba box-shadow color at the affected style declaration with the
existing --color-primary-light design-system token from design-system.css,
preserving the current shadow dimensions and opacity behavior.

2387-2388: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider using color-mix to reference the primary brand token.

Instead of hardcoding the RGB values (255, 105, 0) of the brand color across component files, consider using color-mix with var(--color-primary) to derive the transparent values. This prevents the RGB values from falling out of sync if the primary brand hex changes in the future.

For example: color-mix(in srgb, var(--color-primary) 40%, transparent).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/web/RunAnywhereAI/src/styles/components.css` around lines 2387 -
2388, Update the box-shadow colors in the animation containing the 0%, 50%, and
100% keyframes to use color-mix with var(--color-primary) instead of hardcoded
RGB values, preserving the existing 40% opacity effect and transparent final
state.
sdk/runanywhere-cli/src/net/control_plane.cpp (1)

230-240: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

platform_name() duplicates desktop_platform() in bootstrap.cpp.

Both functions implement the identical #if defined(__APPLE__)/__linux__/_WIN32 chain returning "macos"/"linux"/"windows"/"desktop" (bootstrap.cpp Lines 143-153). Since control_plane.h is now a public header, bootstrap.cpp could reuse net::platform_name() instead of maintaining a second copy that can silently drift.

♻️ Proposed consolidation
 // bootstrap.cpp
-const char *desktop_platform() {
-#if defined(__APPLE__)
-  return "macos";
-#elif defined(__linux__)
-  return "linux";
-#elif defined(_WIN32)
-  return "windows";
-#else
-  return "desktop";
-#endif
-}
+// use net::platform_name() instead (see net/control_plane.h)
-  sdk_config.platform = desktop_platform();
+  sdk_config.platform = net::platform_name();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdk/runanywhere-cli/src/net/control_plane.cpp` around lines 230 - 240, Remove
the duplicate platform detection logic from desktop_platform() in bootstrap.cpp
and reuse net::platform_name() from control_plane.h instead. Preserve the
existing platform string results and ensure bootstrap.cpp references the shared
function rather than maintaining its own preprocessor chain.
sdk/runanywhere-cli/src/commands/cmd_auth.cpp (1)

63-78: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

JSON token_expires_at loses the raw epoch value.

For --json (machine-readable) output, format_epoch_seconds returns an ISO-8601 string, so scripted consumers must re-parse a date string instead of reading a Unix timestamp directly. Consider emitting both the raw epoch integer and the formatted string in JSON mode.

♻️ Proposed fix
             .field("device_uuid", summary.persistent_device_id)
-            .field("token_expires_at", format_epoch_seconds(summary.token_expires_at))
+            .field("token_expires_at", static_cast<int64_t>(summary.token_expires_at))
+            .field("token_expires_at_iso", format_epoch_seconds(summary.token_expires_at))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdk/runanywhere-cli/src/commands/cmd_auth.cpp` around lines 63 - 78, Update
the JSON output in the options.json branch to preserve the raw Unix timestamp
alongside the existing formatted token_expires_at value. Add a distinct field
using summary.token_expires_at directly, while keeping token_expires_at as the
ISO-8601 string and leaving non-JSON output unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@examples/flutter/RunAnywhereAI/lib/app/runanywhere_ai_app.dart`:
- Around line 219-234: Update the light and dark ThemeData color schemes so the
custom primary override does not retain an incompatible seed-derived onPrimary
value: either remove copyWith(primary: AppColors.brandOrange) or explicitly set
onPrimary to a contrasting color alongside the custom primary. Apply the same
correction wherever AppColors.brandOrange is assigned as primary.

In `@examples/react-native/RunAnywhereAI/src/screens/ChatScreen.tsx`:
- Around line 791-793: Update the active LoRA pill color expression near
loraAdapterCount so its text and icon meet AA contrast in light mode against
colors.primary; use the existing darker ink color rather than colors.onPrimary,
while preserving the inactive colors.primary state.

In `@examples/web/RunAnywhereAI/src/main.ts`:
- Around line 636-637: Replace the hardcoded colors in the SVG gradient stops
near the gradient definition with existing design-system CSS custom-property
tokens, using the appropriate primary and gradient-end variables (such as
--color-primary and --bubble-user-end). If no suitable end-color token exists,
add one in the relevant CSS and reference it from the SVG instead of embedding
hex values in the view.

In `@sdk/runanywhere-cli/src/bootstrap.cpp`:
- Around line 168-182: Update initialize_sdk_metadata so a non-RAC_SUCCESS
result from rac_state_initialize is propagated as failure instead of only
warning and continuing to rac_sdk_init. Ensure bootstrap() handles that returned
failure and does not report successful initialization, while preserving the
existing result description for diagnostics.

In `@sdk/runanywhere-cli/src/commands/cmd_telemetry.cpp`:
- Around line 210-246: Move the telemetry orchestration out of
run_telemetry_session, emit, and blast into a single higher-level commons/net
entry point that owns login, manager setup, tracking, flush, destruction,
endpoint accounting, and callback handling. Update these command functions to
only parse options, invoke that helper, and render the returned result, removing
CLI-side modality, endpoint, UUID, and response-accounting logic. Preserve
existing success and failure behavior.
- Around line 100-116: Update extract_bool_field to skip optional whitespace
between the colon and the boolean value before comparing against “true”.
Preserve the existing false result when the key is absent or the value is not
true, and leave extract_int_field unchanged.
- Around line 356-380: In the telemetry summary loop around kModalities, remove
the hardcoded endpoint reconstruction and locate the matching EndpointStats
entry by its modality-specific endpoint suffix, using the actual endpoint keys
captured by the callback. Preserve the existing row status, counters, and all_ok
aggregation once the matching stats are found, while retaining the "NO POST"
fallback when no endpoint matches.

In `@sdk/runanywhere-cli/src/net/control_plane.cpp`:
- Around line 62-117: Move hostname, device-model, OS-version, and chip-name
retrieval behind the rac_platform_adapter_t interface, adding adapter
capabilities modeled on get_memory_info and implementing them in the desktop
adapter. Update device_get_info and the query helpers to consume
adapter-provided values, removing direct calls to std::getenv, uname, and
sysctlbyname from the network module while preserving existing fallback
behavior.
- Around line 392-399: Update the authentication response handling around
rac_auth_handle_authenticate_response so RAC_ERROR_SECURE_STORAGE_FAILED no
longer proceeds silently: surface a clear warning to the user while preserving
the existing successful flow and distinct rejection handling for other
non-success results.

---

Nitpick comments:
In `@examples/web/RunAnywhereAI/src/styles/components.css`:
- Line 474: Replace the hardcoded rgba box-shadow color at the affected style
declaration with the existing --color-primary-light design-system token from
design-system.css, preserving the current shadow dimensions and opacity
behavior.
- Around line 2387-2388: Update the box-shadow colors in the animation
containing the 0%, 50%, and 100% keyframes to use color-mix with
var(--color-primary) instead of hardcoded RGB values, preserving the existing
40% opacity effect and transparent final state.

In `@sdk/runanywhere-cli/src/commands/cmd_auth.cpp`:
- Around line 63-78: Update the JSON output in the options.json branch to
preserve the raw Unix timestamp alongside the existing formatted
token_expires_at value. Add a distinct field using summary.token_expires_at
directly, while keeping token_expires_at as the ISO-8601 string and leaving
non-JSON output unchanged.

In `@sdk/runanywhere-cli/src/net/control_plane.cpp`:
- Around line 230-240: Remove the duplicate platform detection logic from
desktop_platform() in bootstrap.cpp and reuse net::platform_name() from
control_plane.h instead. Preserve the existing platform string results and
ensure bootstrap.cpp references the shared function rather than maintaining its
own preprocessor chain.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e7bc59ca-823b-4592-a5d3-2dc70fc2ba44

📥 Commits

Reviewing files that changed from the base of the PR and between 541842a and f5271dd.

📒 Files selected for processing (53)
  • AGENTS.md
  • examples/DESIGN_GUIDELINE.md
  • examples/android/RunAnywhereAI/AGENTS.md
  • examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/ui/screens/benchmark/BenchmarkShareCard.kt
  • examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/ui/theme/Color.kt
  • examples/android/RunAnywhereAI/app/src/main/res/values/colors.xml
  • examples/flutter/RunAnywhereAI/AGENTS.md
  • examples/flutter/RunAnywhereAI/lib/app/content_view.dart
  • examples/flutter/RunAnywhereAI/lib/app/runanywhere_ai_app.dart
  • examples/flutter/RunAnywhereAI/lib/core/design_system/app_colors.dart
  • examples/ios/RunAnywhereAI/AGENTS.md
  • examples/ios/RunAnywhereAI/RunAnywhereAI/Assets.xcassets/AccentColor.colorset/Contents.json
  • examples/ios/RunAnywhereAI/RunAnywhereAI/Core/DesignSystem/AppColors.swift
  • examples/ios/RunAnywhereAI/RunAnywhereAI/Features/VoiceKeyboard/FlowActivationView.swift
  • examples/ios/RunAnywhereAI/RunAnywhereActivityExtension/RunAnywhereActivityExtensionLiveActivity.swift
  • examples/ios/RunAnywhereAI/RunAnywhereKeyboard/KeyboardView.swift
  • examples/react-native/RunAnywhereAI/AGENTS.md
  • examples/react-native/RunAnywhereAI/App.tsx
  • examples/react-native/RunAnywhereAI/src/components/chat/LoRASheet.tsx
  • examples/react-native/RunAnywhereAI/src/components/chat/ToolCallIndicator.tsx
  • examples/react-native/RunAnywhereAI/src/components/chat/TypingIndicator.tsx
  • examples/react-native/RunAnywhereAI/src/components/common/LoadingOverlay.tsx
  • examples/react-native/RunAnywhereAI/src/components/common/ModelStatusBanner.tsx
  • examples/react-native/RunAnywhereAI/src/navigation/BottomTabs.tsx
  • examples/react-native/RunAnywhereAI/src/screens/ChatAnalyticsScreen.tsx
  • examples/react-native/RunAnywhereAI/src/screens/ChatScreen.tsx
  • examples/react-native/RunAnywhereAI/src/screens/StorageScreen.tsx
  • examples/react-native/RunAnywhereAI/src/screens/VLMScreen.tsx
  • examples/react-native/RunAnywhereAI/src/theme/colors.ts
  • examples/react-native/RunAnywhereAI/src/theme/index.ts
  • examples/react-native/RunAnywhereAI/src/theme/spacing.ts
  • examples/react-native/RunAnywhereAI/src/theme/system/colors.ts
  • examples/react-native/RunAnywhereAI/src/theme/system/index.ts
  • examples/react-native/RunAnywhereAI/src/theme/system/themedStyles.ts
  • examples/react-native/RunAnywhereAI/src/theme/typography.ts
  • examples/react-native/RunAnywhereAI/src/utils/modelDisplay.ts
  • examples/web/RunAnywhereAI/AGENTS.md
  • examples/web/RunAnywhereAI/index.html
  • examples/web/RunAnywhereAI/src/main.ts
  • examples/web/RunAnywhereAI/src/styles/components.css
  • examples/web/RunAnywhereAI/src/styles/design-system.css
  • sdk/runanywhere-cli/CMakeLists.txt
  • sdk/runanywhere-cli/README.md
  • sdk/runanywhere-cli/src/app.cpp
  • sdk/runanywhere-cli/src/bootstrap.cpp
  • sdk/runanywhere-cli/src/bootstrap.h
  • sdk/runanywhere-cli/src/commands/cmd_auth.cpp
  • sdk/runanywhere-cli/src/commands/cmd_telemetry.cpp
  • sdk/runanywhere-cli/src/commands/commands.h
  • sdk/runanywhere-cli/src/net/control_plane.cpp
  • sdk/runanywhere-cli/src/net/control_plane.h
  • sdk/runanywhere-commons/exports/RACommons.exports
  • sdk/runanywhere-commons/include/rac/infrastructure/telemetry/rac_telemetry_manager.h
💤 Files with no reviewable changes (6)
  • examples/react-native/RunAnywhereAI/src/theme/colors.ts
  • examples/react-native/RunAnywhereAI/src/theme/spacing.ts
  • examples/react-native/RunAnywhereAI/src/theme/index.ts
  • sdk/runanywhere-commons/include/rac/infrastructure/telemetry/rac_telemetry_manager.h
  • examples/react-native/RunAnywhereAI/src/theme/typography.ts
  • sdk/runanywhere-commons/exports/RACommons.exports

Comment on lines 219 to +234
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: AppColors.primaryBlue,
seedColor: AppColors.brandOrange,
brightness: Brightness.light,
),
).copyWith(primary: AppColors.brandOrange),
useMaterial3: true,
appBarTheme: const AppBarTheme(centerTitle: true, elevation: 0),
navigationBarTheme: NavigationBarThemeData(
indicatorColor: AppColors.primaryBlue.withValues(alpha: 0.2),
indicatorColor: AppColors.primaryAccent.withValues(alpha: 0.2),
),
),
darkTheme: ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: AppColors.primaryBlue,
seedColor: AppColors.brandOrange,
brightness: Brightness.dark,
),
).copyWith(primary: AppColors.brandOrange),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

white text contrast ratio on #FF6900 WCAG AA pass

💡 Result:

White text on the color #FF6900 does not pass WCAG AA requirements [1]. To meet WCAG AA (Success Criterion 1.4.3), text must maintain a contrast ratio of at least 4.5:1 against its background, or 3:1 for large-scale text [2][3][4]. The combination of white (hex #FFFFFF) and the orange shade #FF6900 produces a contrast ratio of approximately 2.89:1 [1]. Because this ratio is below both the 4.5:1 threshold for normal text and the 3:1 threshold for large text, it fails to meet WCAG AA compliance [2][1][4]. For reference, #FF6900 provides better contrast when used with dark text; for example, using black text (#000000) on a #FF6900 background results in a ratio of approximately 7.27:1, which passes both WCAG AA and AAA requirements [1].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the relevant theme file around the reported lines.
sed -n '180,280p' examples/flutter/RunAnywhereAI/lib/app/runanywhere_ai_app.dart

# Look for any other overrides that might affect primary/onPrimary in this app.
rg -n "copyWith\\(primary:|onPrimary|ColorScheme.fromSeed|brandOrange|primaryAccent" examples/flutter/RunAnywhereAI/lib -g '*.dart'

Repository: RunanywhereAI/runanywhere-sdks

Length of output: 6166


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read the theme file with line numbers for exact context.
cat -n examples/flutter/RunAnywhereAI/lib/app/runanywhere_ai_app.dart | sed -n '200,260p'

# Check whether the same pattern appears elsewhere.
rg -n "copyWith\\(primary: AppColors\\.brandOrange|ColorScheme\\.fromSeed\\(|onPrimary" examples/flutter/RunAnywhereAI/lib -g '*.dart'

Repository: RunanywhereAI/runanywhere-sdks

Length of output: 2974


🏁 Script executed:

#!/bin/bash
set -euo pipefail
cat -n examples/flutter/RunAnywhereAI/lib/app/runanywhere_ai_app.dart | sed -n '200,260p'
rg -n "copyWith\\(primary: AppColors\\.brandOrange|ColorScheme\\.fromSeed\\(|onPrimary" examples/flutter/RunAnywhereAI/lib -g '*.dart'

Repository: RunanywhereAI/runanywhere-sdks

Length of output: 2974


Keep onPrimary aligned with the custom primary

ColorScheme.fromSeed(...) seeds a tonal palette, but copyWith(primary: AppColors.brandOrange) leaves onPrimary at the seed-derived value. White text on #FF6900 is only ~2.9:1, so primary-colored surfaces can miss WCAG AA. Either drop the override or set a contrasting onPrimary.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/flutter/RunAnywhereAI/lib/app/runanywhere_ai_app.dart` around lines
219 - 234, Update the light and dark ThemeData color schemes so the custom
primary override does not retain an incompatible seed-derived onPrimary value:
either remove copyWith(primary: AppColors.brandOrange) or explicitly set
onPrimary to a contrasting color alongside the custom primary. Apply the same
correction wherever AppColors.brandOrange is assigned as primary.

Comment on lines 791 to 793
color={
loraAdapterCount > 0
? Colors.textWhite
: Colors.primaryPurple
loraAdapterCount > 0 ? colors.onPrimary : colors.primary
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -nP -C2 'onPrimary' examples/react-native/RunAnywhereAI/src/theme/system/colors.ts

Repository: RunanywhereAI/runanywhere-sdks

Length of output: 967


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,260p' examples/react-native/RunAnywhereAI/src/theme/system/colors.ts
printf '\n--- contrast check ---\n'
python3 - <<'PY'
from math import isclose

# Replace with palette values from the file if needed after inspection.
# This script is ready to compute contrast once the hex values are known.
PY

Repository: RunanywhereAI/runanywhere-sdks

Length of output: 7311


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the relevant section around the active LoRA pill.
sed -n '760,820p' examples/react-native/RunAnywhereAI/src/screens/ChatScreen.tsx

printf '\n--- contrast ratio ---\n'
python3 - <<'PY'
def hex_to_rgb(h):
    h = h.lstrip('#')
    return tuple(int(h[i:i+2], 16)/255.0 for i in (0,2,4))

def rel_lum(rgb):
    def f(c):
        return c/12.92 if c <= 0.03928 else ((c+0.055)/1.055) ** 2.4
    r,g,b = (f(c) for c in rgb)
    return 0.2126*r + 0.7152*g + 0.0722*b

def contrast(a, b):
    la, lb = rel_lum(hex_to_rgb(a)), rel_lum(hex_to_rgb(b))
    hi, lo = max(la, lb), min(la, lb)
    return (hi + 0.05) / (lo + 0.05)

fg = "`#FFFBFF`"  # lightScheme.onPrimary
bg = "`#FF6900`"  # primary
print(f"contrast({fg}, {bg}) = {contrast(fg, bg):.2f}:1")
PY

Repository: RunanywhereAI/runanywhere-sdks

Length of output: 2329


Active LoRA pill needs a darker active color in light mode

examples/react-native/RunAnywhereAI/src/screens/ChatScreen.tsx:791-793 uses colors.onPrimary on colors.primary in light mode, which is #FFFBFF on #FF6900 (~2.82:1). That misses AA for the pill text/icon; switch the active state to a darker ink color or make the active label/icon larger/bolder.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/react-native/RunAnywhereAI/src/screens/ChatScreen.tsx` around lines
791 - 793, Update the active LoRA pill color expression near loraAdapterCount so
its text and icon meet AA contrast in light mode against colors.primary; use the
existing darker ink color rather than colors.onPrimary, while preserving the
inactive colors.primary state.

Comment on lines +636 to +637
<stop offset="0%" style="stop-color:#FF6900"/>
<stop offset="100%" style="stop-color:#FB2C36"/>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Do not hardcode brand hexes in views.

The SVG gradient uses hardcoded hex values (#FF6900 and #FB2C36). As per coding guidelines, you must use design-system CSS custom-property tokens and never hardcode brand hexes in views.

Consider using existing tokens like var(--color-primary) and var(--bubble-user-end), or adding a dedicated gradient-end token to the CSS instead of hardcoding the hexes here.

♻️ Proposed fix to use CSS tokens
-            <stop offset="0%" style="stop-color:`#FF6900`"/>
-            <stop offset="100%" style="stop-color:`#FB2C36`"/>
+            <stop offset="0%" style="stop-color:var(--color-primary)"/>
+            <stop offset="100%" style="stop-color:var(--bubble-user-end)"/>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<stop offset="0%" style="stop-color:#FF6900"/>
<stop offset="100%" style="stop-color:#FB2C36"/>
<stop offset="0%" style="stop-color:var(--color-primary)"/>
<stop offset="100%" style="stop-color:var(--bubble-user-end)"/>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/web/RunAnywhereAI/src/main.ts` around lines 636 - 637, Replace the
hardcoded colors in the SVG gradient stops near the gradient definition with
existing design-system CSS custom-property tokens, using the appropriate primary
and gradient-end variables (such as --color-primary and --bubble-user-end). If
no suitable end-color token exists, add one in the relevant CSS and reference it
from the SVG instead of embedding hex values in the view.

Source: Coding guidelines

Comment on lines +168 to +182
// Mirror rac_sdk_init_phase1_proto's step order: runtime state first (the
// auth / device-registration / telemetry paths read env + credentials from
// rac_state), then the copied SDK configuration + client info.
const rac_result_t state_rc = rac_state_initialize(
connection.environment, connection.api_key.c_str(),
connection.base_url.c_str(), device_id[0] != '\0' ? device_id : "");
if (state_rc != RAC_SUCCESS) {
out::status_line("warning: SDK state init failed: " +
out::describe_result(state_rc));
}

rac_sdk_config_t sdk_config = {};
sdk_config.environment = RAC_ENV_DEVELOPMENT;
sdk_config.api_key = "";
sdk_config.base_url = "";
sdk_config.environment = connection.environment;
sdk_config.api_key = connection.api_key.c_str();
sdk_config.base_url = connection.base_url.c_str();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Don't silently continue when rac_state_initialize fails.

initialize_sdk_metadata only warns (Line 174-177) when rac_state_initialize fails, then proceeds to call rac_sdk_init and returns normally; bootstrap() treats this as success. Every downstream control-plane read (rac_state_get_environment, rac_state_get_api_key, rac_state_get_base_url in control_plane.cpp) depends on this call having succeeded. If it fails, rcli auth login/rcli telemetry emit will read stale/default state and fail with a confusing, unrelated error (e.g. "development mode has no control plane") instead of surfacing the real root cause.

🛡️ Proposed fix: propagate the failure
-void initialize_sdk_metadata(const Connection &connection) {
+rac_result_t initialize_sdk_metadata(const Connection &connection) {
   char device_id[RAC_DEVICE_ID_BUFFER_MIN_SIZE] = {};
   ...
   const rac_result_t state_rc = rac_state_initialize(
       connection.environment, connection.api_key.c_str(),
       connection.base_url.c_str(), device_id[0] != '\0' ? device_id : "");
   if (state_rc != RAC_SUCCESS) {
-    out::status_line("warning: SDK state init failed: " +
-                     out::describe_result(state_rc));
+    out::error_line("SDK state init failed: " + out::describe_result(state_rc));
+    return state_rc;
   }
   ...
+  return RAC_SUCCESS;
 }

And in bootstrap():

-    initialize_sdk_metadata(connection);
+    rc = initialize_sdk_metadata(connection);
+    if (rc != RAC_SUCCESS) {
+      return rc;
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Mirror rac_sdk_init_phase1_proto's step order: runtime state first (the
// auth / device-registration / telemetry paths read env + credentials from
// rac_state), then the copied SDK configuration + client info.
const rac_result_t state_rc = rac_state_initialize(
connection.environment, connection.api_key.c_str(),
connection.base_url.c_str(), device_id[0] != '\0' ? device_id : "");
if (state_rc != RAC_SUCCESS) {
out::status_line("warning: SDK state init failed: " +
out::describe_result(state_rc));
}
rac_sdk_config_t sdk_config = {};
sdk_config.environment = RAC_ENV_DEVELOPMENT;
sdk_config.api_key = "";
sdk_config.base_url = "";
sdk_config.environment = connection.environment;
sdk_config.api_key = connection.api_key.c_str();
sdk_config.base_url = connection.base_url.c_str();
// Mirror rac_sdk_init_phase1_proto's step order: runtime state first (the
// auth / device-registration / telemetry paths read env + credentials from
// rac_state), then the copied SDK configuration + client info.
char device_id[RAC_DEVICE_ID_BUFFER_MIN_SIZE] = {};
const rac_result_t state_rc = rac_state_initialize(
connection.environment, connection.api_key.c_str(),
connection.base_url.c_str(), device_id[0] != '\0' ? device_id : "");
if (state_rc != RAC_SUCCESS) {
out::error_line("SDK state init failed: " + out::describe_result(state_rc));
return state_rc;
}
rac_sdk_config_t sdk_config = {};
sdk_config.environment = connection.environment;
sdk_config.api_key = connection.api_key.c_str();
sdk_config.base_url = connection.base_url.c_str();
return RAC_SUCCESS;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdk/runanywhere-cli/src/bootstrap.cpp` around lines 168 - 182, Update
initialize_sdk_metadata so a non-RAC_SUCCESS result from rac_state_initialize is
propagated as failure instead of only warning and continuing to rac_sdk_init.
Ensure bootstrap() handles that returned failure and does not report successful
initialization, while preserving the existing result description for
diagnostics.

Comment on lines +100 to +116
// Minimal field extraction from the backend's SDKTelemetryBatchResponse JSON
// ({"success":true,"events_received":N,"events_stored":N,"events_skipped":N,
// "storage_version":"V2"}). The CLI deliberately carries no JSON parser.
int extract_int_field(const std::string& json, const std::string& key) {
const std::string needle = "\"" + key + "\":";
const size_t pos = json.find(needle);
if (pos == std::string::npos) {
return -1;
}
return std::atoi(json.c_str() + pos + needle.size());
}

bool extract_bool_field(const std::string& json, const std::string& key) {
const std::string needle = "\"" + key + "\":";
const size_t pos = json.find(needle);
return pos != std::string::npos && json.compare(pos + needle.size(), 4, "true") == 0;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Manual JSON extraction is brittle to backend formatting changes.

extract_bool_field does a byte-exact comparison of 4 chars right after "key": (Line 115). This only works for compact JSON with no space after the colon (e.g. "success":true). If the backend ever emits pretty-printed or differently-spaced JSON (e.g. "success": true), every response is misclassified as success=false, causing emit/blast to report failures for successful telemetry deliveries. extract_int_field's atoi call is safe here since atoi skips leading whitespace, but extract_bool_field's raw compare is not.

🐛 Proposed fix — skip optional whitespace before comparing
 bool extract_bool_field(const std::string& json, const std::string& key) {
     const std::string needle = "\"" + key + "\":";
-    const size_t pos = json.find(needle);
-    return pos != std::string::npos && json.compare(pos + needle.size(), 4, "true") == 0;
+    size_t pos = json.find(needle);
+    if (pos == std::string::npos) {
+        return false;
+    }
+    pos += needle.size();
+    while (pos < json.size() && std::isspace(static_cast<unsigned char>(json[pos]))) {
+        ++pos;
+    }
+    return json.compare(pos, 4, "true") == 0;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Minimal field extraction from the backend's SDKTelemetryBatchResponse JSON
// ({"success":true,"events_received":N,"events_stored":N,"events_skipped":N,
// "storage_version":"V2"}). The CLI deliberately carries no JSON parser.
int extract_int_field(const std::string& json, const std::string& key) {
const std::string needle = "\"" + key + "\":";
const size_t pos = json.find(needle);
if (pos == std::string::npos) {
return -1;
}
return std::atoi(json.c_str() + pos + needle.size());
}
bool extract_bool_field(const std::string& json, const std::string& key) {
const std::string needle = "\"" + key + "\":";
const size_t pos = json.find(needle);
return pos != std::string::npos && json.compare(pos + needle.size(), 4, "true") == 0;
}
// Minimal field extraction from the backend's SDKTelemetryBatchResponse JSON
// ({"success":true,"events_received":N,"events_stored":N,"events_skipped":N,
// "storage_version":"V2"}). The CLI deliberately carries no JSON parser.
int extract_int_field(const std::string& json, const std::string& key) {
const std::string needle = "\"" + key + "\":";
const size_t pos = json.find(needle);
if (pos == std::string::npos) {
return -1;
}
return std::atoi(json.c_str() + pos + needle.size());
}
bool extract_bool_field(const std::string& json, const std::string& key) {
const std::string needle = "\"" + key + "\":";
size_t pos = json.find(needle);
if (pos == std::string::npos) {
return false;
}
pos += needle.size();
while (pos < json.size() && std::isspace(static_cast<unsigned char>(json[pos]))) {
+pos;
}
return json.compare(pos, 4, "true") == 0;
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdk/runanywhere-cli/src/commands/cmd_telemetry.cpp` around lines 100 - 116,
Update extract_bool_field to skip optional whitespace between the colon and the
boolean value before comparing against “true”. Preserve the existing false
result when the key is absent or the value is not true, and leave
extract_int_field unchanged.

Comment on lines +210 to +246
/**
* Login (JWT), create a manager wired to the real transport, run `track_fn`,
* flush, and account per-endpoint results. Returns false on login failure.
*/
template <typename TrackFn>
bool run_telemetry_session(const GlobalOptions& options, FlushReport* report, TrackFn&& track_fn) {
Bootstrapped env;
if (bootstrap(options, &env) != RAC_SUCCESS) {
return false;
}

// The V2 telemetry endpoints only accept a JWT, so emit implies login —
// one process performs the handshake and the flush (in-process token).
std::string error;
if (net::login(nullptr, &error) != RAC_SUCCESS) {
out::error_line(error);
return false;
}

const char* device_id = rac_state_get_device_id();
rac_telemetry_manager_t* manager = rac_telemetry_manager_create(
rac_state_get_environment(), device_id != nullptr ? device_id : "", net::platform_name(),
RCLI_VERSION);
if (manager == nullptr) {
out::error_line("telemetry manager creation failed");
return false;
}
rac_telemetry_manager_set_device_info(manager, net::device_model().c_str(),
net::os_version_string().c_str());
rac_telemetry_manager_set_http_callback(manager, telemetry_http_callback, &report->context);

report->tracked = track_fn(manager);
rac_telemetry_manager_flush(manager);
rac_telemetry_manager_set_http_callback(manager, nullptr, nullptr);
rac_telemetry_manager_destroy(manager);
return true;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift

Command file orchestrates many commons entry points, contrary to the cmd_*.cpp guideline.

run_telemetry_session (and the emit/blast functions that use it) chains rac_telemetry_manager_create, _set_device_info, _set_http_callback, repeated _track, _flush, _destroy, plus net::login and net::control_plane_post (via the callback) — well beyond "invoke exactly one commons entry point." Contrast with cmd_auth.cpp, which calls bootstrap() + a single net::login() and stays compliant. The modality table, endpoint-path knowledge, UUID generation, and manual response accounting are also CLI-side reimplementations of what looks like SDK-internal orchestration.

Consider exposing a single higher-level commons/net entry point (e.g. a "run telemetry session" helper) that owns manager lifecycle + flush + accounting, leaving this file to just parse flags and render the result — consistent with cmd_auth.cpp's shape.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdk/runanywhere-cli/src/commands/cmd_telemetry.cpp` around lines 210 - 246,
Move the telemetry orchestration out of run_telemetry_session, emit, and blast
into a single higher-level commons/net entry point that owns login, manager
setup, tracking, flush, destruction, endpoint accounting, and callback handling.
Update these command functions to only parse options, invoke that helper, and
render the returned result, removing CLI-side modality, endpoint, UUID, and
response-accounting logic. Preserve existing success and failure behavior.

Source: Coding guidelines

Comment on lines +356 to +380
bool all_ok = true;
std::vector<std::vector<std::string>> rows;
for (const ModalitySpec& spec : kModalities) {
const std::string endpoint = std::string("/api/v2/sdk/telemetry/") + spec.name;
const auto it = report.context.endpoints.find(endpoint);
std::string status = "NO POST";
int received = 0;
int stored = 0;
int skipped = 0;
bool row_ok = false;
if (it != report.context.endpoints.end()) {
const EndpointStats& stats = it->second;
received = stats.received;
stored = stats.stored;
skipped = stats.skipped;
row_ok = stats.failures == 0 && stats.received == count;
status = row_ok ? ("HTTP " + std::to_string(stats.last_status))
: (stats.last_error.empty()
? "HTTP " + std::to_string(stats.last_status)
: stats.last_error);
}
all_ok = all_ok && row_ok;
rows.push_back({spec.name, row_ok ? "ok" : "FAILED", status, std::to_string(received),
std::to_string(stored), std::to_string(skipped)});
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Hardcoded endpoint reconstruction duplicates SDK-internal path knowledge and can silently misreport results.

endpoint is rebuilt here as "/api/v2/sdk/telemetry/" + spec.name purely to look up stats in report.context.endpoints, even though that map is already keyed by the actual endpoint string received from commons via the callback's endpoint parameter (Line 139-143). If the real endpoint format ever diverges from this literal (API version bump, trailing segment, casing), every row silently falls into the "NO POST" / FAILED branch even though the POST succeeded — a false failure that's hard to notice since the command still exits non-zero "correctly" but for the wrong reason.

This also duplicates the endpoint-path pattern that commons already owns (per the file's own header comment: "one POST per modality to /api/v2/sdk/telemetry/{modality}"), which the cmd_*.cpp coding guideline flags: "Do not place ... SDK-internal path/framework knowledge in commands."

🐛 Proposed fix — match by suffix instead of reconstructing the full path
-        const std::string endpoint = std::string("/api/v2/sdk/telemetry/") + spec.name;
-        const auto it = report.context.endpoints.find(endpoint);
+        const auto it = std::find_if(
+            report.context.endpoints.begin(), report.context.endpoints.end(),
+            [&](const auto& kv) {
+                const std::string& ep = kv.first;
+                return ep.size() >= std::string(spec.name).size() + 1 &&
+                       ep.compare(ep.size() - std::string(spec.name).size(), std::string::npos,
+                                  spec.name) == 0;
+            });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
bool all_ok = true;
std::vector<std::vector<std::string>> rows;
for (const ModalitySpec& spec : kModalities) {
const std::string endpoint = std::string("/api/v2/sdk/telemetry/") + spec.name;
const auto it = report.context.endpoints.find(endpoint);
std::string status = "NO POST";
int received = 0;
int stored = 0;
int skipped = 0;
bool row_ok = false;
if (it != report.context.endpoints.end()) {
const EndpointStats& stats = it->second;
received = stats.received;
stored = stats.stored;
skipped = stats.skipped;
row_ok = stats.failures == 0 && stats.received == count;
status = row_ok ? ("HTTP " + std::to_string(stats.last_status))
: (stats.last_error.empty()
? "HTTP " + std::to_string(stats.last_status)
: stats.last_error);
}
all_ok = all_ok && row_ok;
rows.push_back({spec.name, row_ok ? "ok" : "FAILED", status, std::to_string(received),
std::to_string(stored), std::to_string(skipped)});
}
bool all_ok = true;
std::vector<std::vector<std::string>> rows;
for (const ModalitySpec& spec : kModalities) {
const auto it = std::find_if(
report.context.endpoints.begin(), report.context.endpoints.end(),
[&](const auto& kv) {
const std::string& ep = kv.first;
return ep.size() >= std::string(spec.name).size() + 1 &&
ep.compare(ep.size() - std::string(spec.name).size(), std::string::npos,
spec.name) == 0;
});
std::string status = "NO POST";
int received = 0;
int stored = 0;
int skipped = 0;
bool row_ok = false;
if (it != report.context.endpoints.end()) {
const EndpointStats& stats = it->second;
received = stats.received;
stored = stats.stored;
skipped = stats.skipped;
row_ok = stats.failures == 0 && stats.received == count;
status = row_ok ? ("HTTP " + std::to_string(stats.last_status))
: (stats.last_error.empty()
? "HTTP " + std::to_string(stats.last_status)
: stats.last_error);
}
all_ok = all_ok && row_ok;
rows.push_back({spec.name, row_ok ? "ok" : "FAILED", status, std::to_string(received),
std::to_string(stored), std::to_string(skipped)});
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdk/runanywhere-cli/src/commands/cmd_telemetry.cpp` around lines 356 - 380,
In the telemetry summary loop around kModalities, remove the hardcoded endpoint
reconstruction and locate the matching EndpointStats entry by its
modality-specific endpoint suffix, using the actual endpoint keys captured by
the callback. Preserve the existing row status, counters, and all_ok aggregation
once the matching stats are found, while retaining the "NO POST" fallback when
no endpoint matches.

Source: Coding guidelines

Comment on lines +62 to +117
std::string query_hostname() {
#if defined(_WIN32)
const char* name = std::getenv("COMPUTERNAME");
return name != nullptr ? name : "windows-host";
#else
struct utsname info{};
if (uname(&info) == 0 && info.nodename[0] != '\0') {
return info.nodename;
}
return "desktop-host";
#endif
}

std::string query_device_model() {
#if defined(__APPLE__)
char model[128] = {};
size_t size = sizeof(model);
if (sysctlbyname("hw.model", model, &size, nullptr, 0) == 0 && model[0] != '\0') {
return model;
}
return "Mac";
#elif defined(_WIN32)
return "Windows PC";
#else
struct utsname info{};
if (uname(&info) == 0 && info.machine[0] != '\0') {
return std::string(info.sysname[0] != '\0' ? info.sysname : "Linux") + " " + info.machine;
}
return "Linux PC";
#endif
}

std::string query_os_version() {
#if defined(_WIN32)
return {};
#else
struct utsname info{};
if (uname(&info) == 0 && info.release[0] != '\0') {
// Backend os_version column caps at 20 chars.
return std::string(info.release).substr(0, 20);
}
return {};
#endif
}

std::string query_chip_name() {
#if defined(__APPLE__)
char brand[256] = {};
size_t size = sizeof(brand);
if (sysctlbyname("machdep.cpu.brand_string", brand, &size, nullptr, 0) == 0 &&
brand[0] != '\0') {
return brand;
}
#endif
return {};
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift

Direct platform-API calls bypass the rac_platform_adapter_t IoC boundary.

query_hostname, query_device_model, query_os_version, and query_chip_name call uname, sysctlbyname, and std::getenv directly. This same function's caller (device_get_info, Line 165-170) already fetches comparable device metadata (memory) through rac_get_platform_adapter(), showing the adapter is the intended path for this class of data. Querying the OS directly here duplicates responsibility that belongs behind the adapter interface and bypasses the inversion-of-control boundary the SDK otherwise enforces.

Consider exposing hostname/device-model/OS-version/chip info as additional rac_platform_adapter_t capabilities (mirroring get_memory_info) so rcli's desktop adapter implementation supplies this data through the same IoC surface other consumers use, rather than rcli's own network module querying the OS.
As per coding guidelines, "C++ must access platform services only through the rac_platform_adapter_t inversion-of-control interface; it must not call platform APIs directly."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdk/runanywhere-cli/src/net/control_plane.cpp` around lines 62 - 117, Move
hostname, device-model, OS-version, and chip-name retrieval behind the
rac_platform_adapter_t interface, adding adapter capabilities modeled on
get_memory_info and implementing them in the desktop adapter. Update
device_get_info and the query helpers to consume adapter-provided values,
removing direct calls to std::getenv, uname, and sysctlbyname from the network
module while preserving existing fallback behavior.

Comment on lines +392 to +399
const int auth_rc = rac_auth_handle_authenticate_response(response.body.c_str());
if (auth_rc != RAC_SUCCESS && auth_rc != RAC_ERROR_SECURE_STORAGE_FAILED) {
if (error != nullptr) {
*error = "authentication response rejected: " + single_line_preview(response.body);
}
return RAC_ERROR_INVALID_RESPONSE;
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Secure-storage failure is swallowed silently.

When rac_auth_handle_authenticate_response returns RAC_ERROR_SECURE_STORAGE_FAILED, the code treats the login as successful and continues with no warning to the user (Line 393). The auth token may not have been persisted securely, but nothing surfaces that degradation.

🛡️ Proposed fix: surface the degradation
     const int auth_rc = rac_auth_handle_authenticate_response(response.body.c_str());
-    if (auth_rc != RAC_SUCCESS && auth_rc != RAC_ERROR_SECURE_STORAGE_FAILED) {
+    if (auth_rc == RAC_ERROR_SECURE_STORAGE_FAILED) {
+        out::status_line("warning: auth token could not be stored securely");
+    } else if (auth_rc != RAC_SUCCESS) {
         if (error != nullptr) {
             *error = "authentication response rejected: " + single_line_preview(response.body);
         }
         return RAC_ERROR_INVALID_RESPONSE;
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const int auth_rc = rac_auth_handle_authenticate_response(response.body.c_str());
if (auth_rc != RAC_SUCCESS && auth_rc != RAC_ERROR_SECURE_STORAGE_FAILED) {
if (error != nullptr) {
*error = "authentication response rejected: " + single_line_preview(response.body);
}
return RAC_ERROR_INVALID_RESPONSE;
}
}
const int auth_rc = rac_auth_handle_authenticate_response(response.body.c_str());
if (auth_rc == RAC_ERROR_SECURE_STORAGE_FAILED) {
out::status_line("warning: auth token could not be stored securely");
} else if (auth_rc != RAC_SUCCESS) {
if (error != nullptr) {
*error = "authentication response rejected: " + single_line_preview(response.body);
}
return RAC_ERROR_INVALID_RESPONSE;
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdk/runanywhere-cli/src/net/control_plane.cpp` around lines 392 - 399, Update
the authentication response handling around
rac_auth_handle_authenticate_response so RAC_ERROR_SECURE_STORAGE_FAILED no
longer proceeds silently: surface a clear warning to the user while preserving
the existing successful flow and distinct rejection handling for other
non-success results.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@sdk/runanywhere-cli/src/commands/cmd_telemetry.cpp`:
- Around line 139-141: Update the request body construction in the
control_plane_post call to use a zero length whenever json_body is null, while
preserving json_length when the pointer is valid. Ensure the fallback empty
string can never be constructed with a non-zero length.

In `@sdk/runanywhere-cli/src/net/control_plane.cpp`:
- Around line 404-421: Update login() to call rac_proto_buffer_free(&out_buffer)
after rac_sdk_init_phase2_proto completes and before both the failure return in
the parse/phase2_rc check and the successful return path. Ensure the
caller-owned buffer is released exactly once on every exit while preserving the
existing result and error handling.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f9ec4151-abd7-4128-a1d3-31eb01bb7555

📥 Commits

Reviewing files that changed from the base of the PR and between 541842a and c14f46b.

📒 Files selected for processing (53)
  • AGENTS.md
  • examples/DESIGN_GUIDELINE.md
  • examples/android/RunAnywhereAI/AGENTS.md
  • examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/ui/screens/benchmark/BenchmarkShareCard.kt
  • examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/ui/theme/Color.kt
  • examples/android/RunAnywhereAI/app/src/main/res/values/colors.xml
  • examples/flutter/RunAnywhereAI/AGENTS.md
  • examples/flutter/RunAnywhereAI/lib/app/content_view.dart
  • examples/flutter/RunAnywhereAI/lib/app/runanywhere_ai_app.dart
  • examples/flutter/RunAnywhereAI/lib/core/design_system/app_colors.dart
  • examples/ios/RunAnywhereAI/AGENTS.md
  • examples/ios/RunAnywhereAI/RunAnywhereAI/Assets.xcassets/AccentColor.colorset/Contents.json
  • examples/ios/RunAnywhereAI/RunAnywhereAI/Core/DesignSystem/AppColors.swift
  • examples/ios/RunAnywhereAI/RunAnywhereAI/Features/VoiceKeyboard/FlowActivationView.swift
  • examples/ios/RunAnywhereAI/RunAnywhereActivityExtension/RunAnywhereActivityExtensionLiveActivity.swift
  • examples/ios/RunAnywhereAI/RunAnywhereKeyboard/KeyboardView.swift
  • examples/react-native/RunAnywhereAI/AGENTS.md
  • examples/react-native/RunAnywhereAI/App.tsx
  • examples/react-native/RunAnywhereAI/src/components/chat/LoRASheet.tsx
  • examples/react-native/RunAnywhereAI/src/components/chat/ToolCallIndicator.tsx
  • examples/react-native/RunAnywhereAI/src/components/chat/TypingIndicator.tsx
  • examples/react-native/RunAnywhereAI/src/components/common/LoadingOverlay.tsx
  • examples/react-native/RunAnywhereAI/src/components/common/ModelStatusBanner.tsx
  • examples/react-native/RunAnywhereAI/src/navigation/BottomTabs.tsx
  • examples/react-native/RunAnywhereAI/src/screens/ChatAnalyticsScreen.tsx
  • examples/react-native/RunAnywhereAI/src/screens/ChatScreen.tsx
  • examples/react-native/RunAnywhereAI/src/screens/StorageScreen.tsx
  • examples/react-native/RunAnywhereAI/src/screens/VLMScreen.tsx
  • examples/react-native/RunAnywhereAI/src/theme/colors.ts
  • examples/react-native/RunAnywhereAI/src/theme/index.ts
  • examples/react-native/RunAnywhereAI/src/theme/spacing.ts
  • examples/react-native/RunAnywhereAI/src/theme/system/colors.ts
  • examples/react-native/RunAnywhereAI/src/theme/system/index.ts
  • examples/react-native/RunAnywhereAI/src/theme/system/themedStyles.ts
  • examples/react-native/RunAnywhereAI/src/theme/typography.ts
  • examples/react-native/RunAnywhereAI/src/utils/modelDisplay.ts
  • examples/web/RunAnywhereAI/AGENTS.md
  • examples/web/RunAnywhereAI/index.html
  • examples/web/RunAnywhereAI/src/main.ts
  • examples/web/RunAnywhereAI/src/styles/components.css
  • examples/web/RunAnywhereAI/src/styles/design-system.css
  • sdk/runanywhere-cli/CMakeLists.txt
  • sdk/runanywhere-cli/README.md
  • sdk/runanywhere-cli/src/app.cpp
  • sdk/runanywhere-cli/src/bootstrap.cpp
  • sdk/runanywhere-cli/src/bootstrap.h
  • sdk/runanywhere-cli/src/commands/cmd_auth.cpp
  • sdk/runanywhere-cli/src/commands/cmd_telemetry.cpp
  • sdk/runanywhere-cli/src/commands/commands.h
  • sdk/runanywhere-cli/src/net/control_plane.cpp
  • sdk/runanywhere-cli/src/net/control_plane.h
  • sdk/runanywhere-commons/exports/RACommons.exports
  • sdk/runanywhere-commons/include/rac/infrastructure/telemetry/rac_telemetry_manager.h
💤 Files with no reviewable changes (6)
  • examples/react-native/RunAnywhereAI/src/theme/colors.ts
  • sdk/runanywhere-commons/exports/RACommons.exports
  • examples/react-native/RunAnywhereAI/src/theme/spacing.ts
  • examples/react-native/RunAnywhereAI/src/theme/index.ts
  • examples/react-native/RunAnywhereAI/src/theme/typography.ts
  • sdk/runanywhere-commons/include/rac/infrastructure/telemetry/rac_telemetry_manager.h

Comment on lines +139 to +141
const net::HttpResult result = net::control_plane_post(
endpoint, std::string(json_body != nullptr ? json_body : "", json_length),
requires_auth == RAC_TRUE);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Guard the string length when json_body is null.

std::string(json_body != nullptr ? json_body : "", json_length) still passes json_length even when the pointer fell back to "". If commons ever hands a null body with a non-zero length, this reads past the empty literal (OOB). Zero the length in the null branch.

🛡️ Proposed fix
-    const net::HttpResult result = net::control_plane_post(
-        endpoint, std::string(json_body != nullptr ? json_body : "", json_length),
-        requires_auth == RAC_TRUE);
+    const net::HttpResult result = net::control_plane_post(
+        endpoint, json_body != nullptr ? std::string(json_body, json_length) : std::string(),
+        requires_auth == RAC_TRUE);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const net::HttpResult result = net::control_plane_post(
endpoint, std::string(json_body != nullptr ? json_body : "", json_length),
requires_auth == RAC_TRUE);
const net::HttpResult result = net::control_plane_post(
endpoint, json_body != nullptr ? std::string(json_body, json_length) : std::string(),
requires_auth == RAC_TRUE);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdk/runanywhere-cli/src/commands/cmd_telemetry.cpp` around lines 139 - 141,
Update the request body construction in the control_plane_post call to use a
zero length whenever json_body is null, while preserving json_length when the
pointer is valid. Ensure the fallback empty string can never be constructed with
a non-zero length.

Comment on lines +404 to +421
v1::SdkInitPhase2Request request;
const std::string request_bytes = proto::serialize(request);
rac_proto_buffer_t out_buffer;
rac_proto_buffer_init(&out_buffer);
const rac_result_t phase2_rc = rac_sdk_init_phase2_proto(
request_bytes.empty() ? nullptr
: reinterpret_cast<const uint8_t*>(request_bytes.data()),
request_bytes.size(), &out_buffer);
v1::SdkInitResult result;
std::string parse_error;
if (!proto::parse_proto_buffer(&out_buffer, &result, &parse_error) ||
phase2_rc != RAC_SUCCESS) {
if (error != nullptr) {
*error = "services init failed: " +
(parse_error.empty() ? out::describe_result(phase2_rc) : parse_error);
}
return phase2_rc != RAC_SUCCESS ? phase2_rc : RAC_ERROR_INVALID_RESPONSE;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm the proto buffer ownership/free contract in commons.
rg -nP '\brac_proto_buffer_(init|free|reset|destroy)\b' -g '*.h' -g '*.hpp' -g '*.c' -g '*.cpp'

Repository: RunanywhereAI/runanywhere-sdks

Length of output: 168


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the control plane implementation and the proto buffer API definitions/usages.
git ls-files 'sdk/runanywhere-cli/src/net/control_plane.cpp' \
             'sdk/runanywhere-commons/**' \
             'sdk/**' \
  | sed -n '1,200p'

echo '--- rac_sdk_init_phase2_proto usages ---'
rg -n "rac_sdk_init_phase2_proto|rac_proto_buffer_" sdk -g '*.h' -g '*.hpp' -g '*.c' -g '*.cpp'

echo '--- control_plane.cpp around the cited lines ---'
sed -n '360,460p' sdk/runanywhere-cli/src/net/control_plane.cpp

Repository: RunanywhereAI/runanywhere-sdks

Length of output: 50387


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- proto buffer API declaration ---'
sed -n '1,220p' sdk/runanywhere-swift/Sources/RunAnywhere/CRACommons/include/rac_error_proto.h

echo '--- proto buffer implementation ---'
fd -a 'rac_proto_buffer.cpp' sdk/runanywhere-commons sdk/runanywhere-swift | head -n 20

Repository: RunanywhereAI/runanywhere-sdks

Length of output: 3700


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- control_plane.cpp around login() ---'
sed -n '1,260p' sdk/runanywhere-cli/src/net/control_plane.cpp

echo '--- phase2 function implementation ---'
sed -n '560,640p' sdk/runanywhere-commons/src/lifecycle/sdk_init.cpp

Repository: RunanywhereAI/runanywhere-sdks

Length of output: 12090


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- control_plane.cpp around login() ---'
sed -n '360,450p' sdk/runanywhere-cli/src/net/control_plane.cpp

echo '--- phase2 function implementation ---'
sed -n '580,630p' sdk/runanywhere-commons/src/lifecycle/sdk_init.cpp

Repository: RunanywhereAI/runanywhere-sdks

Length of output: 6455


Free out_buffer before returning from login()

rac_proto_buffer_init(&out_buffer) creates caller-owned storage, and this path never calls rac_proto_buffer_free(&out_buffer) on either the success or failure exits after rac_sdk_init_phase2_proto, so login() leaks the proto buffer on every call. Free it before each return.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdk/runanywhere-cli/src/net/control_plane.cpp` around lines 404 - 421, Update
login() to call rac_proto_buffer_free(&out_buffer) after
rac_sdk_init_phase2_proto completes and before both the failure return in the
parse/phase2_rc check and the successful return path. Ensure the caller-owned
buffer is released exactly once on every exit while preserving the existing
result and error handling.

…iftPM CLI target

The RunAnywhereMLXCLI SwiftPM target lists rcli sources explicitly, but the
network-driver files were never added — so the callers compiled while the
definitions did not, failing swift-spm at link with undefined symbols
rcli::net::register_device_callbacks / commands::register_auth /
commands::register_telemetry. Add src/net/control_plane.cpp,
src/commands/cmd_auth.cpp, src/commands/cmd_telemetry.cpp (src/main.cpp stays
excluded — RunAnywhereMLXCLI provides its own Swift entry point). Verified:
'swift build --product RunAnywhereMLXCLI' links clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012nxQHeWG9c5SEwzp1tbqdc
@shubhammalhotra28 shubhammalhotra28 added the WIP Work in progress, not ready for review label Jul 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

WIP Work in progress, not ready for review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants