- Athas is a desktop code editor built with Tauri, React, TypeScript, and Rust.
- Frontend feature code lives under
src/features/. - Shared frontend code lives under
src/components,src/hooks, andsrc/utils. - Extension-specific code lives under
src/extensions/. - Rust feature logic should prefer
crates/[feature]; keepsrc-taurifocused on app wiring and integration.
- Always use Bun for repo scripts and package management.
- Required environment: Bun
1.3.2, Node.js22+, and Rust. - Install dependencies with
bun install. - Start the app with
bun dev. - Use
bun smoke alphaorbun smoke prodfor quick local smoke tests of packaged app launches. - Run full checks with
bun check. - Run tests with
bunx vp test run. - Run TypeScript checks with
bun typecheck. - Run Rust checks with
bun check:rustwhen touching Rust code. - When touching release flow, validate locally with
bun scripts/release.ts <bump> --dry-runbefore anything else, then runbun release:check.
- Never change
AGENTS.mdunless the user explicitly asks. - Do not prefix unused variables with an underscore; delete them instead.
- Do not use emojis in commit messages, logs, or documentation.
- When adding a broadly useful user-facing action, add or update its command-palette entry; do not mirror low-level or context-only controls.
- Validate the relevant checks after making changes instead of stopping at code edits.
- Default to working directly on
main. - If a branch is needed, branch from
main. - Keep branch names short and descriptive.
- Keep releases and release tags on
main.
- Keep commits focused. One logical change per commit.
- Commit titles should be short, direct, and describe the outcome of the change.
- Start commit messages with an uppercase letter.
- Every commit must include a short wrapped body in plain language.
- Wrap commit body lines before the commitlint line-length limit instead of leaving warnings behind.
- Commit bodies should explain what changed and why without headings, boilerplate, or filler.
- When useful, end the commit message with a separate
Fixes ...orCloses ...line. - Avoid prefixes, filler, hype, and changelog-style noise in commit messages.
- Never leave commitlint or message-format warnings unresolved.
- Before creating a commit, run the checks that match the change.
- When editing commit text that includes code, multiline content, or shell-sensitive characters, prefer a file-based edit over inline shell text.
- Follow existing code style and keep changes aligned with nearby code.
- Use kebab-case for file and folder names by default.
- React component files, hook files, and utility files should use descriptive kebab-case names such as
settings-dialog.tsx,use-keymaps.ts, ortheme-loader.ts. - Import React hooks directly and call them by name, such as
useEffect(...), instead of qualifying hooks through the React namespace. - Avoid new vague filenames such as
helpers.ts,misc.ts, orutils.tswhen the file can be named after what it actually does. - Avoid unnecessary comments in UI components; prefer self-explanatory code.
- Avoid unnecessary
cn(...)calls; use it only for conditional or merged class names. - Use Tailwind utilities for normal component styling.
- Keep app-wide CSS in
src/styles/for base reset, fonts, scrollbars, theme tokens, shared syntax tokens, and platform/window overrides only. - Keep feature CSS next to the feature and import it from the owning component entrypoint; use it only for generated markup, third-party DOM, editor layers, or selectors Tailwind cannot express clearly.
- Prefer
src/uiprimitives and CVA variants for reusable UI styling instead of feature-specific wrapper classes or new global CSS selectors. - Do not add exported Tailwind class string constants such as
*_CLASS_NAME; use CVA variants or UI primitives for reusable styling. - Use CSS variables for theme colors; do not hardcode hex values in UI code.
- Keep font size, font family, theme colors, keymaps, and shortcuts in their existing system-level homes instead of redefining them ad hoc in feature components.
- Never use hardcoded font-size utilities such as
text-[11px]in UI code; use the shared UI font-size classes such asui-text-sm,ui-text-base, and related system primitives instead. - Interactive elements must remain accessible, including accessible names for icon-only controls and usable keyboard/focus behavior.
- Treat
src/uiprimitives andsrc/styles/theme.cssas the source of truth for reusable visual behavior. - Do not create
src/ui/testsor add tests for UI primitives that only assert rendering, class names, data slots, variants, or upstream Base UI/Shadcn behavior. Test product behavior in the owning feature instead unless the user explicitly requests a primitive-level regression test. - Before creating UI markup or a new component, search
src/uiand at least two comparable feature surfaces for an existing primitive or composition. - Feature components may control placement, responsive layout, and domain content. They must not redefine a shared primitive's height, radius, border, background, typography, or interaction states with local utility classes.
- When a primitive is missing a needed visual behavior, add a named semantic prop or CVA variant to the primitive and migrate every current consumer that represents the same pattern.
- Do not create pass-through wrappers, exported Tailwind class constants, or feature-local copies of shared controls. Keep a wrapper only when it owns behavior or a stable composition reused by multiple consumers.
- If the same visual utility sequence appears in two feature consumers, move that contract into a shared primitive before finishing the change.
- New app-wide visual concepts require semantic variables in
src/styles/theme.css, derived from the existing theme colors when possible. Do not add feature-local color mixes or hardcoded light/dark values. - Prefer spacing and surface contrast over borders. Borders should communicate a real boundary and should be owned by the primitive rather than added independently by consumers.
- Keep
classNameescape hatches focused on layout and placement. Repeated visual overrides are evidence that the primitive API needs a semantic variant. - When touching a shared primitive, audit all import sites and remove confirmed dead or redundant code in that primitive's module.
- Before finishing UI work, verify light and dark themes plus hover, active, focus-visible, disabled, overflow, and resized states in the real Tauri app when practical.
- Three registries, three sets of rules.
src/ui/icons.tsxowns UI icons: one outline drawing per product concept, tinted withcurrentColor.src/ui/brand-marks.tsxowns third-party marks, which keep their own artwork and stay out of the stroke system. Icon themes undersrc/extensions/icon-themes/own file-type art, which the user can replace. src/ui/icons.tsxis the only module allowed to importnucleo-ui-outline-18. Add a new icon by exporting it there, never by reaching into the library from a feature.- One concept, one name, one drawing. Two exports must never wrap the same Nucleo drawing, and an export's name must describe what it draws. Import icons under their own name;
import { XIcon as Close }splits one concept back into two vocabularies. - Icons carry no stroke decisions at the call site. Stroke lives in
src/styles/icons.css, pinned to real pixels withvector-effect: non-scaling-strokeso it does not drift when the UI font size scales the 18px drawing grid. Choose weight with theopticalprop only:sm(1.25px) up to 20px,md(1.5px) to 28px,lg(2px) above that. A numericsizepicks the tier on its own. - Pin a concept in
src/ui/icon-concepts.tswhen it shows up in more than one feature and more than one glyph would be defensible. Two concepts must never resolve to the same icon. - Use line chevrons for disclosure, expansion, submenu, and directional navigation controls. Reserve triangular play icons for actions that actually start or resume something.
- Prefer sizing icons by inheritance (the default
1em) so they track the UI font size. Reach for an explicitsizeonly when the icon is not sitting next to text. src/features/settings/tests/ui-icon-contract.test.tsenforces the structural half of these rules. Run it after touching the icon layer.
- New React Zustand stores should use the shared
createSelectorshelper. - Keep store actions grouped under an
actionsobject.
- Group feature-specific code under
src/features/[feature]/. - Keep
src/uifor reusable UI primitives,src/hooksfor shared hooks, andsrc/utilsfor genuinely shared helpers with no feature-specific behavior. - Do not add feature logic to
src/root shared folders just because it is convenient. - Keep settings-related concerns such as fonts, themes, and UI preferences under
src/features/settings/. - Keep keymaps and shortcut logic under
src/features/keymaps/. - Keep extension and theme implementation under
src/extensions/. - Prefer subfolders such as
components,hooks,services,stores,types,utils, andtestsinstead of leaving feature logic in the feature root. - If a feature contains a distinct subfeature, give it a dedicated nested folder and keep its components, hooks, and helpers close to that subfeature instead of scattering them across the whole feature.
- If a file is only used by one subfeature, keep it inside that subfeature folder instead of promoting it to the feature root.
- Do not put feature-specific code in global shared folders unless it is genuinely shared across features.
- Keep feature tests under
src/features/[feature]/tests/when practical. - New user-facing documentation belongs in the
wwwrepo underwww/docs/, not in this repo.
- Validate release changes locally before publishing anything.
- Do not use real release tags to debug release automation.
- Keep Windows MSI versioning numeric-only via
tauri.bundle.windows.wix.version. - Release automation is triggered by pushing
v*tags. - Use
bun scripts/release.ts <bump> --dry-runbefore running a real release command.