Skip to content

docs: add contributor docs, agent rules, templates and CI - #6

Open
KomalSrinivasan wants to merge 7 commits into
mainfrom
chore/repo-setup
Open

KomalSrinivasan wants to merge 7 commits into
mainfrom
chore/repo-setup

Conversation

@KomalSrinivasan

@KomalSrinivasan KomalSrinivasan commented Nov 10, 2026 •

Copy link
Copy Markdown
Collaborator

Gives this repo the same contributor docs, rules and tooling as drift-ui/ui.

Stacked on #2. CI runs the Jest suite that #2 adds, so merge #2 first. After that, this diff only has the two commits below.

What's in it

  • README.md: the component table, install steps, local development and the repo layout. The install URL points at native.drift-ui.dev, and the README says to build the registry locally until that site exists.
  • CONTRIBUTING.md: setup with a simulator or Expo Go, a seven-step checklist for porting a component, component guidelines, and the commit conventions. Porting starts in drift-ui/ui: a component with a lib file gets its registry:lib item there first, as #146 does for key-value-editor.
  • AGENTS.md and CLAUDE.md: the same issue-to-pull-request workflow as drift-ui/ui, written for React Native. This replaces the AGENTS.md from the Expo template but keeps its warning to check the versioned Expo docs. It also adds a work-on-issue skill.
  • .github:
    • The pull request template has a "Differences from the web component" section and checkboxes for iOS, Android and dark mode.
    • The bug template asks for platform and device.
    • The component request template only covers components that already exist in drift-ui.
    • CI runs format, typecheck, lint, test and the registry build.
  • Tooling: Prettier with the same settings as drift-ui/ui, including Tailwind class sorting. ESLint runs through expo lint and is pinned to 9, because eslint-plugin-react fails to load on ESLint 10.

Formatting the repo rewrote the React Native Reusables files to our style (double quotes, no semicolons). drift-ui/ui does the same with its shadcn files.

Renovate is left out because #1 already adds it.

Checklist

  • bun run format:check, bun run typecheck, bun run lint, bun run test and bun run registry:build pass

Summary by cubic

Sets up this repo's contributor docs, agent rules, GitHub templates, CI and formatting tooling to match drift-ui/ui, and ports key-value-editor as the first registry component.

Docs and templates

  • README, CONTRIBUTING, AGENTS.md, CLAUDE.md and a work-on-issue skill cover setup, the porting checklist and the issue-to-pull-request workflow.
  • New PR, bug and component request templates ask for differences from the web component and iOS/Android/dark-mode checks.
  • CI runs format, typecheck, lint, test and the registry build, including the Jest suite added here.

Tooling and first component

  • Prettier matches drift-ui/ui (no semicolons, double quotes, Tailwind class sorting), which reformatted existing files; ESLint is pinned to 9 because eslint-plugin-react fails to load on 10.
  • Jest with jest-expo and React Native Testing Library is added, with test suites for the registry components.
  • key-value-editor keeps the web component's API and shared logic, and detects pasted .env text in onChangeText since React Native has no paste event; a newline or a paste that replaces a selected key counts as a paste.

Written for commit a11f313. Summary will update on new commits.

View guided diff Turn on auto-fix

Same API as the web component. Shared logic comes from the
@drift-ui/key-value-editor-utils lib item, primitives and theme
variables from React Native Reusables. Pasted .env text is detected in
onChangeText since React Native has no paste event; the key field is
multiline so newlines survive the paste.

Adds jest-expo with React Native Testing Library.

Refs drift-ui/ui#132
Same Prettier settings as drift-ui/ui (no semicolons, double quotes,
Tailwind class sorting) and ESLint through expo lint. ESLint is pinned
to 9 because eslint-plugin-react does not load on 10. Adds lint, format
and format:check scripts.
Mirrors drift-ui/ui: contributor guide with the steps to port a
component, the agent workflow in AGENTS.md with a work-on-issue skill,
bug and component request templates, a pull request template with iOS,
Android and dark mode checks, and CI running format, typecheck, lint,
test and registry build.
@socket-security

socket-security Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai 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.

11 issues found across 35 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name=".github/pull_request_template.md">

<violation number="1" location=".github/pull_request_template.md:15">
P2: This checklist omits `bun run format:check` and `bun run registry:build`, both required by CI, so PRs can satisfy the listed checks and still fail CI. Add both commands here.</violation>
</file>

<file name="CONTRIBUTING.md">

<violation number="1" location="CONTRIBUTING.md:27">
P2: This setup lists Expo Go on a phone but only explains the simulator/emulator shortcuts, leaving phone contributors without the launch step. Tell them to scan the QR code in Expo Go.</violation>
</file>

<file name="registry/default/ui/icon.tsx">

<violation number="1" location="registry/default/ui/icon.tsx:18">
P2: The interop leaves `text-*` colors in `style` instead of mapping them to Lucide’s `color` prop, so icon strokes do not reliably follow utility classes or the button text context. Add `color: "color"` to `nativeStyleToProp`.</violation>
</file>

<file name="README.md">

<violation number="1" location="README.md:50">
P3: This directory description incorrectly includes the locally maintained `utils.ts` helper. Clarify that `utils.ts` is local so contributors know this file can be edited here.</violation>
</file>

<file name="AGENTS.md">

<violation number="1" location="AGENTS.md:55">
P3: This asks agents to read a lib file even when the web component has none, although CONTRIBUTING makes that file optional. Change this to “its lib file, if present” so components without shared logic do not send agents searching for nonexistent source.</violation>
</file>

<file name="registry/default/lib/key-value-editor-utils.ts">

<violation number="1" location="registry/default/lib/key-value-editor-utils.ts:35">
P2: `readQuoted` removes the backslash before every character, so quoted values containing unsupported escapes lose data. Consume the backslash only for the documented `\"` and `\\` escapes.</violation>
</file>

<file name="registry/default/hooks/use-controllable-state.ts">

<violation number="1" location="registry/default/hooks/use-controllable-state.ts:14">
P2: When `T` is a function, React invokes `defaultValue` as a lazy initializer and later invokes function-valued state updates as updater functions, rather than storing those functions. Wrap function values when initializing and updating React state.</violation>

<violation number="2" location="registry/default/hooks/use-controllable-state.ts:22">
P2: The updater runs against the render-captured `currentValue`, so two functional updates in one batched event both emit the same next value and uncontrolled state loses an increment. Resolve each updater against the latest pending value so queued updates compose.</violation>
</file>

<file name="registry/default/ui/key-value-editor.tsx">

<violation number="1" location="registry/default/ui/key-value-editor.tsx:89">
P2: Replacing a row with a `.env` block that starts with the same key drops that entry: stripping `row.key` turns `HOST=1` into `=1`, which the parser discards. Parse the complete text before treating the existing key as an insertion prefix.</violation>

<violation number="2" location="registry/default/ui/key-value-editor.tsx:94">
P2: Pasting before existing rows focuses the final pre-existing row because `next.at(-1)` selects the overall tail. Track and focus the last row inserted by the paste instead.</violation>
</file>

<file name="tailwind.config.js">

<violation number="1" location="tailwind.config.js:11">
P2: The preview cannot reach this dark palette: `app.json` forces `userInterfaceStyle: "light"` and no code sets a dark scheme. Enable automatic appearance and wire NativeWind's class-mode scheme.</violation>
</file>

Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.

View guided diff | Turn on auto-fix | Re-trigger cubic


## Checklist

- [ ] `bun run typecheck`, `bun run lint` and `bun run test` pass

@cubic-dev-ai cubic-dev-ai Bot Nov 10, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: This checklist omits bun run format:check and bun run registry:build, both required by CI, so PRs can satisfy the listed checks and still fail CI. Add both commands here.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At .github/pull_request_template.md, line 15:

<comment>This checklist omits `bun run format:check` and `bun run registry:build`, both required by CI, so PRs can satisfy the listed checks and still fail CI. Add both commands here.</comment>

<file context>
@@ -0,0 +1,20 @@
+
+## Checklist
+
+- [ ] `bun run typecheck`, `bun run lint` and `bun run test` pass
+- [ ] Tests cover what a user does: typing, pressing, submitting
+- [ ] New components are added to `registry.json` and the README table, each at its alphabetical position
</file context>
Suggested change
- [ ] `bun run typecheck`, `bun run lint` and `bun run test` pass
- [ ] `bun run format:check`, `bun run typecheck`, `bun run lint`, `bun run test` and `bun run registry:build` pass
Fix with cubic

Comment thread CONTRIBUTING.md
bun start
```

Press `i` for iOS or `a` for Android. `App.tsx` is the preview screen.

@cubic-dev-ai cubic-dev-ai Bot Nov 10, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: This setup lists Expo Go on a phone but only explains the simulator/emulator shortcuts, leaving phone contributors without the launch step. Tell them to scan the QR code in Expo Go.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At CONTRIBUTING.md, line 27:

<comment>This setup lists Expo Go on a phone but only explains the simulator/emulator shortcuts, leaving phone contributors without the launch step. Tell them to scan the QR code in Expo Go.</comment>

<file context>
@@ -0,0 +1,101 @@
+bun start
+```
+
+Press `i` for iOS or `a` for Android. `App.tsx` is the preview screen.
+
+## Porting a component
</file context>
Suggested change
Press `i` for iOS or `a` for Android. `App.tsx` is the preview screen.
For a simulator or emulator, press `i` for iOS or `a` for Android; for Expo Go, scan the QR code with the app. `App.tsx` is the preview screen.
Fix with cubic

cssInterop(IconImpl, {
className: {
target: "style",
nativeStyleToProp: {

@cubic-dev-ai cubic-dev-ai Bot Nov 10, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: The interop leaves text-* colors in style instead of mapping them to Lucide’s color prop, so icon strokes do not reliably follow utility classes or the button text context. Add color: "color" to nativeStyleToProp.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At registry/default/ui/icon.tsx, line 18:

<comment>The interop leaves `text-*` colors in `style` instead of mapping them to Lucide’s `color` prop, so icon strokes do not reliably follow utility classes or the button text context. Add `color: "color"` to `nativeStyleToProp`.</comment>

<file context>
@@ -0,0 +1,62 @@
+cssInterop(IconImpl, {
+  className: {
+    target: "style",
+    nativeStyleToProp: {
+      height: "size",
+      width: "size",
</file context>
Fix with cubic

Comment on lines +35 to +38
if (quote === '"' && character === "\\" && index + 1 < text.length) {
value += text[++index]
continue
}

@cubic-dev-ai cubic-dev-ai Bot Nov 10, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: readQuoted removes the backslash before every character, so quoted values containing unsupported escapes lose data. Consume the backslash only for the documented \" and \\ escapes.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At registry/default/lib/key-value-editor-utils.ts, line 35:

<comment>`readQuoted` removes the backslash before every character, so quoted values containing unsupported escapes lose data. Consume the backslash only for the documented `\"` and `\\` escapes.</comment>

<file context>
@@ -0,0 +1,79 @@
+  for (let index = 1; index < text.length; index++) {
+    const character = text[index]
+    if (character === quote) return value
+    if (quote === '"' && character === "\\" && index + 1 < text.length) {
+      value += text[++index]
+      continue
</file context>
Suggested change
if (quote === '"' && character === "\\" && index + 1 < text.length) {
value += text[++index]
continue
}
if (
quote === '"' &&
character === "\\" &&
(text[index + 1] === quote || text[index + 1] === "\\")
) {
Fix with cubic

defaultValue: T
onChange?: (value: T) => void
}) {
const [uncontrolledValue, setUncontrolledValue] = React.useState(defaultValue)

@cubic-dev-ai cubic-dev-ai Bot Nov 10, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: When T is a function, React invokes defaultValue as a lazy initializer and later invokes function-valued state updates as updater functions, rather than storing those functions. Wrap function values when initializing and updating React state.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At registry/default/hooks/use-controllable-state.ts, line 14:

<comment>When `T` is a function, React invokes `defaultValue` as a lazy initializer and later invokes function-valued state updates as updater functions, rather than storing those functions. Wrap function values when initializing and updating React state.</comment>

<file context>
@@ -0,0 +1,32 @@
+  defaultValue: T
+  onChange?: (value: T) => void
+}) {
+  const [uncontrolledValue, setUncontrolledValue] = React.useState(defaultValue)
+  const isControlled = value !== undefined
+  const currentValue = isControlled ? value : uncontrolledValue
</file context>
Fix with cubic

function changeKey(index: number, text: string) {
const row = rows[index]
if (text.length - row.key.length > 1) {
const pasted = text.startsWith(row.key)

@cubic-dev-ai cubic-dev-ai Bot Nov 10, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Replacing a row with a .env block that starts with the same key drops that entry: stripping row.key turns HOST=1 into =1, which the parser discards. Parse the complete text before treating the existing key as an insertion prefix.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At registry/default/ui/key-value-editor.tsx, line 89:

<comment>Replacing a row with a `.env` block that starts with the same key drops that entry: stripping `row.key` turns `HOST=1` into `=1`, which the parser discards. Parse the complete text before treating the existing key as an insertion prefix.</comment>

<file context>
@@ -0,0 +1,195 @@
+  function changeKey(index: number, text: string) {
+    const row = rows[index]
+    if (text.length - row.key.length > 1) {
+      const pasted = text.startsWith(row.key)
+        ? text.slice(row.key.length)
+        : text
</file context>
Fix with cubic

Comment thread global.css Resolved
Comment thread tailwind.config.js

/** @type {import('tailwindcss').Config} */
module.exports = {
darkMode: "class",

@cubic-dev-ai cubic-dev-ai Bot Nov 10, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: The preview cannot reach this dark palette: app.json forces userInterfaceStyle: "light" and no code sets a dark scheme. Enable automatic appearance and wire NativeWind's class-mode scheme.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At tailwind.config.js, line 11:

<comment>The preview cannot reach this dark palette: `app.json` forces `userInterfaceStyle: "light"` and no code sets a dark scheme. Enable automatic appearance and wire NativeWind's class-mode scheme.</comment>

<file context>
@@ -1,7 +1,39 @@
+
 /** @type {import('tailwindcss').Config} */
 module.exports = {
+  darkMode: "class",
   content: ["./App.tsx", "./registry/**/*.{ts,tsx}"],
   presets: [require("nativewind/preset")],
</file context>
Fix with cubic

Comment thread README.md
```text
registry.json item manifest read by `shadcn build`
registry/default/ui/*.tsx component source, plus React Native Reusables primitives
registry/default/lib/*.ts installed from @drift-ui, never edited here

@cubic-dev-ai cubic-dev-ai Bot Nov 10, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: This directory description incorrectly includes the locally maintained utils.ts helper. Clarify that utils.ts is local so contributors know this file can be edited here.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At README.md, line 50:

<comment>This directory description incorrectly includes the locally maintained `utils.ts` helper. Clarify that `utils.ts` is local so contributors know this file can be edited here.</comment>

<file context>
@@ -1,33 +1,63 @@
+```text
+registry.json                  item manifest read by `shadcn build`
+registry/default/ui/*.tsx      component source, plus React Native Reusables primitives
+registry/default/lib/*.ts      installed from @drift-ui, never edited here
+registry/default/hooks/*.ts    installed from @drift-ui, never edited here
+App.tsx                        preview screen
</file context>
Suggested change
registry/default/lib/*.ts installed from @drift-ui, never edited here
registry/default/lib/*.ts shared logic from @drift-ui; utils.ts is local
Fix with cubic

Comment thread AGENTS.md
gh issue view <n> --comments
```

Read the web component in drift-ui/ui too: its source, its lib file and its tests. If the issue is ambiguous, ask in the conversation before writing code. Do not guess an API.

@cubic-dev-ai cubic-dev-ai Bot Nov 10, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: This asks agents to read a lib file even when the web component has none, although CONTRIBUTING makes that file optional. Change this to “its lib file, if present” so components without shared logic do not send agents searching for nonexistent source.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At AGENTS.md, line 55:

<comment>This asks agents to read a lib file even when the web component has none, although CONTRIBUTING makes that file optional. Change this to “its lib file, if present” so components without shared logic do not send agents searching for nonexistent source.</comment>

<file context>
@@ -1,41 +1,126 @@
+gh issue view <n> --comments
+```
+
+Read the web component in drift-ui/ui too: its source, its lib file and its tests. If the issue is ambiguous, ask in the conversation before writing code. Do not guess an API.
+
+### 3. Claim it and branch
</file context>
Suggested change
Read the web component in drift-ui/ui too: its source, its lib file and its tests. If the issue is ambiguous, ask in the conversation before writing code. Do not guess an API.
Read the web component in drift-ui/ui too: its source, its lib file if present, and its tests. If the issue is ambiguous, ask in the conversation before writing code. Do not guess an API.
Fix with cubic

…tive-foreground

A multiline paste over a selected key could shrink the text, so the
length check missed it. A newline now counts as a paste too, and a paste
that replaced the selected key drops the old key. The theme gains
--destructive-foreground, which tailwind.config.js already maps.
# Conflicts:
#	registry/default/ui/key-value-editor.tsx

@localhostd3veloper localhostd3veloper 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.

CI passes, and format, typecheck, lint, tests and the registry build pass locally.

One change: line 9 of AGENTS.md lists me as lead maintainer and leaves out syedfahadjunaid. We list the two of us as equals, the way the ui AGENTS.md does: Maintainers: [@localhostd3veloper](https://github.com/localhostd3veloper) and [@syedfahadjunaid](https://github.com/syedfahadjunaid). Keep the sentence about you running the pilot.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants