Agent Skills: Valdi Framework Development Skill

This skill should be used when working on Valdi framework projects. Valdi is Snapchat's cross-platform UI framework that compiles TypeScript/TSX components into native views for iOS, Android, and macOS. It provides specialized knowledge for component architecture, Bazel build system, native bindings, TSX elements, and cross-platform development. Use this skill when implementing Valdi components, debugging build issues, or creating new Valdi projects.

UncategorizedID: jarrodmedrano/jarrod-claude-skills/valdi

Install this agent skill to your local

pnpm dlx add-skill https://github.com/jarrodmedrano/jarrod-claude-skills/tree/HEAD/.claude/skills/valdi

Skill Files

Browse the full folder contents for valdi.

Download Skill

Loading file tree…

.claude/skills/valdi/SKILL.md

Skill Metadata

Name
valdi
Description
This skill should be used when working on Valdi framework projects. Valdi is Snapchat's cross-platform UI framework that compiles TypeScript/TSX components into native views for iOS, Android, and macOS. It provides specialized knowledge for component architecture, Bazel build system, native bindings, TSX elements, and cross-platform development. Use this skill when implementing Valdi components, debugging build issues, or creating new Valdi projects.

Valdi Framework Development Skill

Specialized guidance for developing cross-platform applications with Valdi, Snapchat's native UI framework that compiles TypeScript/TSX to native iOS, Android, and macOS views.

Overview

Valdi is NOT a WebView-based framework. It compiles TypeScript components directly into native platform code, delivering native performance without JavaScript bridges. The framework has been used in Snap's production apps for over 8 years.

When to Use This Skill

Invoke this skill when:

  • Working on any Valdi framework project
  • Creating new Valdi components or modules
  • Configuring Bazel build files for Valdi
  • Implementing native bindings (CppModule, NativeModule)
  • Debugging cross-platform rendering issues
  • Setting up Valdi development environment
  • Understanding Valdi's TSX element system

Key Principles

1. Bazel is Mandatory

Valdi uses Bazel exclusively for builds. Never suggest alternative build systems.

Common commands:

# Install CLI globally
pnpm install -g @snap/valdi

# Setup development environment
valdi dev_setup

# Check environment health
valdi doctor

# Bootstrap new project
valdi bootstrap

# Install platform dependencies
valdi install ios
valdi install android

# Enable hot reload during development
valdi hotreload

# Sync project configuration
valdi projectsync

2. Component Architecture

Valdi components are class-based with lifecycle methods:

import { Component, ComponentContext } from 'valdi_core';

interface ViewModel {
  title: string;
  count: number;
}

class MyComponent extends Component<ViewModel, ComponentContext> {
  onCreate(): void {
    // Initialize component
    console.log('Component created');
  }

  onMount(): void {
    // Component mounted to view hierarchy
  }

  onUnmount(): void {
    // Cleanup before removal
  }

  onRender() {
    return (
      <view style={styles.container}>
        <label style={styles.title}>{this.viewModel.title}</label>
      </view>
    );
  }
}

3. Native TSX Elements

Valdi provides native UI elements (NOT HTML):

| Element | Purpose | |---------|---------| | <view> | Container view (like div) | | <layout> | Flexbox layout container | | <scroll> | Scrollable container | | <label> | Text display | | <image> | Image display | | <video> | Video player | | <slot> | Content projection |

Element attributes use native styling, not CSS:

const styles = {
  container: {
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: '#FFFFFF',
    padding: 16,
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    color: '#000000',
  },
};

4. Project Structure

Standard Valdi project layout:

my_project/
├── BUILD.bazel              # Main Bazel build file
├── package.json             # Node dependencies (use pnpm)
├── .eslintrc.js            # ESLint configuration
├── app_assets/             # Application assets
│   └── images/
├── src/
│   ├── android/            # Android-specific code
│   ├── cpp/                # C++ native modules
│   ├── ios/                # iOS-specific code
│   └── valdi/              # Valdi TypeScript/TSX
│       ├── _configs/       # Valdi configs
│       ├── tsconfig.json
│       ├── .terserrc.json
│       └── my_module/      # Your module
│           ├── BUILD.bazel
│           ├── tsconfig.json
│           ├── res/        # Module resources
│           └── src/
│               ├── index.ts
│               └── MyComponent.tsx
└── standalone_app/         # Standalone app config

5. Bazel Build Configuration

Application BUILD.bazel:

load("//bzl:valdi.bzl", "valdi_application", "valdi_exported_library")

valdi_application(
    name = "my_app",
    title = "My Valdi App",
    version = "1.0.0",
    ios_bundle_id = "com.example.myapp",
    ios_device_families = ["iphone"],
    android_theme = "Theme.MyApp.Launch",
    android_app_icon = "app_icon",
    root_component = "App@my_module/src/MyApp",
    assets = glob(["app_assets/**/*"]),
    deps = ["//path/to/src/valdi/my_module"],
)

valdi_exported_library(
    name = "my_app_export",
    ios_bundle_id = "com.example.myapp.lib",
    bundle_name = "MyApp",
    deps = ["//path/to/src/valdi/my_module"],
)

Module BUILD.bazel:

load("//bzl:valdi.bzl", "valdi_module")

valdi_module(
    name = "my_module",
    srcs = glob(["src/**/*.ts", "src/**/*.tsx"]) + ["tsconfig.json"],
    assets = glob(["res/**/*.{jpeg,jpg,png,svg,webp}"]),
    android = struct(
        class_path = "com.example.valdi.modules.my_module",
        native_deps = ["//path/to/android:native_module"],
        release = True,
    ),
    ios = struct(
        module_name = "SCCMyModule",
        native_deps = ["//path/to/ios:native_module"],
        release = True,
    ),
    native = struct(
        deps = ["//path/to/cpp:native_module_cpp"],
    ),
    deps = [
        "//src/valdi_modules/valdi_core",
        "//src/valdi_modules/valdi_tsx",
    ],
    visibility = ["//visibility:public"],
)

6. Native Bindings

Valdi supports type-safe bindings to native code:

CppModule.d.ts:

declare module 'CppModule' {
  export function performCalculation(value: number): number;
  export function getNativeString(): string;
}

NativeModule.d.ts:

declare module 'NativeModule' {
  export function showNativeAlert(message: string): void;
  export function getPlatformInfo(): { os: string; version: string };
}

Usage in component:

import * as CppModule from 'CppModule';
import * as NativeModule from 'NativeModule';

class MyComponent extends Component<ViewModel, ComponentContext> {
  onMount() {
    const result = CppModule.performCalculation(42);
    const platform = NativeModule.getPlatformInfo();
  }
}

7. Cross-Platform Best Practices

All changes must work across iOS, Android, and macOS:

  • Test on multiple platforms before committing
  • Platform-specific code goes in dedicated directories (src/ios/, src/android/)
  • Use Valdi's abstraction layer for platform differences
  • Check AGENTS.md in repository for platform-specific guidance

Performance is critical:

  • Valdi emphasizes rendering efficiency
  • Use view recycling through Valdi's pooling systems
  • Components render independently (no parent re-renders)
  • Viewport-aware rendering for efficient scrolling

8. Development Workflow

Initial setup:

# Install Valdi CLI
pnpm install -g @snap/valdi

# Setup development environment (takes 10-20 minutes first time)
valdi dev_setup

# Verify installation
valdi doctor

Creating a new project:

mkdir my_project && cd my_project
valdi bootstrap
valdi install ios  # or android

Development cycle:

# Start hot reload for live updates
valdi hotreload

# After changing dependencies or resources
valdi projectsync

Editor setup (VSCode/Cursor):

  1. Install shell commands from editor
  2. Install extensions from Valdi release:
    • valdi-vivaldi.vsix (device logs, language support)
    • valdi-debug.vsix (JavaScript debugger)
  3. Configure TypeScript workspace version

Common Pitfalls

1. Using Web/React Patterns

Problem: Treating Valdi like React or web development.

// WRONG - HTML elements don't exist
<div className="container">
  <span>Hello</span>
</div>

// CORRECT - Use Valdi native elements
<view style={styles.container}>
  <label>Hello</label>
</view>

2. CSS-Style Styling

Problem: Using CSS syntax for styles.

// WRONG - CSS syntax
const styles = {
  container: {
    'background-color': '#fff',
    'font-size': '16px',
  }
};

// CORRECT - Camel case, numeric values
const styles = {
  container: {
    backgroundColor: '#FFFFFF',
    fontSize: 16,
  }
};

3. Modifying Auto-Generated Code

Problem: Editing Djinni-generated native bindings directly.

Solution: Always modify source files, never generated code. Regenerate bindings after source changes.

4. Wrong Build System

Problem: Using npm/yarn scripts, webpack, or other bundlers.

Solution: Valdi uses Bazel exclusively. Use valdi CLI commands.

5. Missing Platform Testing

Problem: Only testing on one platform.

Solution: Always verify changes work on iOS, Android, and macOS where applicable.

ESLint Configuration

Standard Valdi ESLint setup:

// .eslintrc.js
module.exports = {
  parser: '@typescript-eslint/parser',
  parserOptions: {
    project: './tsconfig.json',
    ecmaVersion: 2020,
    sourceType: 'module',
    ecmaFeatures: {
      jsx: true,
    },
  },
  plugins: [
    '@typescript-eslint',
    'eslint-plugin-valdi',
    'rxjs',
    'import',
    'unused-imports',
  ],
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
  ],
  rules: {
    // Valdi-specific rules
  },
};

TypeScript Configuration

Standard tsconfig.json for Valdi modules:

{
  "extends": "../../_configs/tsconfig.json",
  "compilerOptions": {
    "jsx": "react",
    "jsxFactory": "Valdi.createElement",
    "strict": true,
    "moduleResolution": "node",
    "esModuleInterop": true
  },
  "include": ["src/**/*"]
}

Available Libraries

Valdi provides these core modules:

| Module | Purpose | |--------|---------| | valdi_core | Core component system, lifecycle | | valdi_tsx | TSX/JSX support | | valdi_protobuf | Protobuf serialization | | valdi_http | HTTP client | | valdi_storage | Persistent encrypted storage | | valdi_navigation | Navigation system | | valdi_rxjs | RxJS integration |

Debugging

Using Hermes Debugger:

  • Available for JavaScript debugging
  • Set breakpoints in VSCode with valdi-debug extension

Using Valdi Inspector:

  • Inspect UI hierarchy
  • View component state
  • Performance profiling

Quick Reference

CLI Commands

| Command | Purpose | |---------|---------| | valdi dev_setup | Setup development environment | | valdi doctor | Check environment health | | valdi bootstrap | Create new project | | valdi install [platform] | Install platform dependencies | | valdi hotreload | Enable live updates | | valdi projectsync | Sync project configuration |

Lifecycle Methods

| Method | When Called | |--------|-------------| | onCreate() | Component initialization | | onMount() | Added to view hierarchy | | onUnmount() | Before removal from hierarchy | | onRender() | Render component UI |

Native Elements

| Element | HTML Equivalent | |---------|-----------------| | <view> | <div> | | <layout> | Flexbox container | | <scroll> | Scrollable div | | <label> | <span> / <p> | | <image> | <img> | | <video> | <video> |

References

For more details:

  • references/component-patterns.md - Advanced component patterns
  • references/bazel-configuration.md - Detailed Bazel setup
  • references/native-bindings.md - Native code integration

Additional Resources

  • Valdi GitHub: https://github.com/Snapchat/Valdi
  • AGENTS.md in repository for AI coding guidelines
  • Discord community for support
  • Codelabs in docs/ for guided tutorials

Remember: Valdi compiles to native code - think native, not web. Use Bazel for builds, pnpm for Node dependencies, and test on all target platforms.