How to work with Rahhal's Marsam
Operating rules for humans contributing code and AI agents generating it. Following these keeps the platform coherent — and turns "I need a component" from a fork in the road into a clear, documented path.
Hard rules
Non-negotiable. These are the same rules baked into CLAUDE.md at the repo root.
Compose first
Reach for @rahhal/ui before writing your own button. If a wrapper recurs across two or more apps, promote it back into the package.
Tokens come from @rahhal/themes
Never redefine brand colors in an app's Tailwind config. Edit packages/themes/src/themes/{light,dark}.ts and rebuild — never edit the generated CSS / JSON by hand.
Bilingual + RTL by default
EN and AR ship together. Use Tailwind logical utilities (ms-*, me-*, ps-*, pe-*, start-*, end-*) so RTL flips automatically. Locale resolution lives in @rahhal/i18n.
Auth via @rahhal/auth only
Phone OTP is the only sign-in method (standalone OR iOS → web handover). Never import @supabase/supabase-js directly. Never parse the URL fragment manually.
Document deliberately
Shared packages get TSDoc on every export, file headers, and a thorough README. Inline comments only when the why is non-obvious.
No AI attribution in git
Don't add Co-Authored-By Claude (or any AI mention) to commits or PRs. Keep authorship clean.
Need a component that isn't here?
The default answer is not "build it locally and forget" — it's "plan it for the design system from the start." Follow this flow whether you're a human or an agent.
- 1
Search. Confirm it's really missing — filter the catalog at / and grep packages/ui/src. A new variant of an existing component usually belongs as a variant, not a new component.
- 2
Scope. Will more than one mini-app reasonably use this? If yes, plan it for @rahhal/ui from the start. If it's truly one-app-only, keep it app-local — but add a comment with the intended promotion trigger.
- 3
Design the public API. Sketch the props in TypeScript first. Mirror existing conventions: forwardRef, asChild where slot composition makes sense, logical utilities for spacing, design-token classes for color.
- 4
Implement under packages/ui/src/<component>.tsx. Add file-level TSDoc. Export from index.ts. Add a subpath in package.json. The package ships source TSX, not bundled output.
- 5
Add a catalog entry AND a meta row. apps/design-system/src/catalog/entries/<slug>.tsx for the React preview and apps/design-system/src/spec/components-meta.ts for the .md endpoint. Both are required.
- 6
Open one PR. Component + catalog entry + meta + i18n strings should land together. Reviewers can verify the docs match the code in a single pass.
The catalog is the public contract. If a component isn't in the catalog, it doesn't exist for the rest of the platform — and that's how features fragment. Build it here, once, well-documented.
For AI agents
Use this when generating UI for any Rahhal mini-app.
- Fetch /skill.md first — it lists every catalog page and the cross-platform conventions.
- Match by token name, not hex. bg-primary is portable across light/dark/RTL; #C2562B is not.
- Read the relevant /components/<slug>.md before generating. It documents props, variants, and gotchas.
- Honor RTL. Use logical utilities (ms-*, me-*, etc.) and rtl:rotate-180 on directional icons.
- Propose new components fully. When something is missing, deliver source + catalog entry + meta row + i18n strings in one change — don't leave the catalog out of sync.
For humans
Code-review checklist when shipping platform changes.
- Catalog updated? New / renamed components have a catalog/entries/<slug>.tsx AND a row in spec/components-meta.ts.
- Themes built? Token edits are followed by pnpm --filter @rahhal/themes build so generated CSS / JSON match.
- RTL tested? Flip the locale switcher to AR; logical utilities should mirror the layout without manual flipping.
- i18n strings in both locales? New copy lands in both en.json and ar.json.
- TSDoc on shared exports? Every public symbol in packages/* gets a one-line summary, params, and an example for components / hooks.