This document provides context and guidelines for AI coding assistants working with Valdi Widgets. Valdi Widgets is a library of UI components and patterns that depends on the Valdi framework. The anti-hallucination and component patterns below apply to all Valdi/TSX code in this repo.
Valdi Widgets provides reusable UI widgets, styles, and patterns for apps built with Valdi. Valdi is a cross-platform UI framework that compiles declarative TypeScript components to native views on iOS, Android, and macOS. Valdi is NOT React — it uses TSX/JSX syntax but compiles to native code.
valdi_modules/– Valdi modules (widgets, navigation, valdi_standalone_ui, navigation_internal, playground)WORKSPACE– Depends on Valdi viahttp_archive(e.g.beta-0.0.2)- Build: Bazel; tests:
bazel test //valdi_modules/widgets:test //valdi_modules/navigation:test //valdi_modules/valdi_standalone_ui:test //valdi_modules/navigation_internal:test //valdi_modules/playground:test - Docs:
AGENTS.md(this file),README.md
The rest of this guide describes Valdi patterns so AI assistants don’t suggest React or wrong APIs when editing TypeScript/TSX in valdi_modules/.
CRITICAL: Valdi uses TSX/JSX syntax but is fundamentally different from React. The most common AI error is suggesting React patterns that do not exist in Valdi.
// ❌ WRONG - useState does not exist in Valdi
const [count, setCount] = useState(0);
// ❌ WRONG - useEffect does not exist in Valdi
useEffect(() => { ... }, []);
// ❌ WRONG - useContext, useMemo, useCallback, useRef do not exist
const value = useContext(MyContext);
// ❌ WRONG - Functional components do not exist
function MyComponent(props) { return <view />; }
const MyComponent = () => <view />;// ❌ WRONG - markNeedsRender() does NOT exist
this.markNeedsRender();
// ❌ WRONG - scheduleRender() is DEPRECATED; use StatefulComponent + setState()
this.scheduleRender();
// ❌ WRONG - onMount/onUpdate/onUnmount do NOT exist
onMount() { } // Use onCreate()
onUnmount() { } // Use onDestroy()
// ❌ WRONG - this.props does NOT exist
this.props.title // Use this.viewModel.title
// ❌ WRONG - onRender() returns void, not JSX
onRender() { return <view />; } // JSX is a statement: <view />;import { StatefulComponent } from 'valdi_core/src/Component';
class MyComponent extends StatefulComponent<ViewModel, State> {
state = { count: 0 };
onCreate() { }
onViewModelUpdate(prev: ViewModel) { }
onDestroy() { }
handleClick = () => {
this.setState({ count: this.state.count + 1 });
};
onRender() {
<button title={`Count: ${this.state.count}`} onPress={this.handleClick} />;
}
}- State: Use
StatefulComponent+setState(), notuseState - Props: Use
this.viewModel, notthis.props - Lifecycle:
onCreate(),onViewModelUpdate(),onDestroy() - onRender(): Returns
void; JSX is written as a statement, notreturned - Components: Always
classextendingComponentorStatefulComponent, never functions - Timers: Use
this.setTimeoutDisposable()in components, not rawsetTimeout/setInterval
import { createProviderComponentWithKeyName } from 'valdi_core/src/provider/createProvider';
import { withProviders, ProvidersValuesViewModel } from 'valdi_core/src/provider/withProviders';
const MyServiceProvider = createProviderComponentWithKeyName<MyService>('MyServiceProvider');
// In child: viewModel extends ProvidersValuesViewModel<[MyService]>
const [myService] = this.viewModel.providersValues;
const ChildWithProvider = withProviders(MyServiceProvider)(ChildComponent);valdi_modules/widgets/– Core widget components (buttons, cells, inputs, etc.)valdi_modules/navigation/– Navigation APIsvaldi_modules/navigation_internal/– Internal navigation supportvaldi_modules/valdi_standalone_ui/– Standalone UI modulevaldi_modules/playground/– Example app and entry point
Valdi itself (compiler, runtime, core modules) is in the @valdi// external repository; see Valdi’s AGENTS.md and docs for full framework documentation.
# Run tests
bazel test //valdi_modules/widgets:test //valdi_modules/navigation:test //valdi_modules/valdi_standalone_ui:test //valdi_modules/navigation_internal:test
# Build macOS app
bazel build //valdi_modules/playground:app_macos- Bazel: Use
BUILD.bazelandbazel build/bazel test - Valdi deps: Reference
@valdi//src/valdi_modules/src/valdi/...in BUILD files - TypeScript: Follow Valdi component patterns; no React hooks or functional components
- Tests: Jasmine; live under
test/in each module
| What | React | Valdi |
|---|---|---|
| Component | Function/class | Class only |
| State | useState |
state + setState() |
| Props | this.props |
this.viewModel |
| Mount | useEffect |
onCreate() |
| Unmount | useEffect cleanup |
onDestroy() |
| Render | return <jsx> |
<jsx />; (void) |
- Valdi: https://github.com/Snapchat/Valdi
- Valdi Widgets README:
/README.md
npm install -g @snap/valdiValdi-specific skills for AI coding assistants (component patterns, Bazel conventions, etc.) are bundled in the CLI:
valdi skills install # all detected AI tools
valdi skills install --for=claude # Claude Code only
valdi skills install --category=client # module-development skills only
valdi skills list # see all available skills and install statusThis file is adapted from Valdi’s AGENTS.md for the Valdi Widgets repo. For the full Valdi framework guide, see Valdi AGENTS.md.