Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
59 changes: 59 additions & 0 deletions .agents/skills/deus-code-style/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
name: deus-code-style
description: "Deus Machine internal code style and conventions. Use when writing, reviewing, or modifying code in this project. Covers Tailwind v4, component patterns, animations, and performance. Triggers on: writing code, styling, components, CSS, tailwind, shadcn, animation, performance, database query, polling, rendering, zustand, react query."
---

# Deus Code Style

Internal conventions for writing code in the Deus Machine codebase.

## Quick Reference

| Topic | Guide | When to use |
|---|---|---|
| [Tailwind & Styling](tailwind.md) | Tailwind v4 gotchas, global CSS rules, color system | Writing any CSS or styling |
| [Components](components.md) | Shadcn, file locations, architecture patterns | Creating or modifying UI components |
| [Animations](animations.md) | Easing defaults, CSS vs Framer Motion, performance | Adding motion or transitions |
| [Performance](performance.md) | DB rules, polling, rendering, git subprocess | Backend queries, frontend lists, data fetching |

## Core Conventions

### ts-pattern for Discriminated Unions

Use `ts-pattern` instead of switch/case or if/else chains on `.type`, `.status`, `.state` fields:

```tsx
import { match, P } from "ts-pattern";

return match(block)
.with({ type: "text" }, (b) => <TextBlock block={b} />)
.with({ type: "tool_use" }, (b) => <ToolUseBlock block={b} />)
.exhaustive(); // catches missing cases at compile time
```

- `.exhaustive()` — all cases must be handled
- `.otherwise()` — intentional fallback for open-ended matching

### State Management Split

- **Zustand** — UI state only (modals, selections, layout, sidebar)
- **TanStack Query v5** — Server state (workspaces, sessions, repos, messages, settings)

Feature hooks: `src/features/{feature}/api/{feature}.queries.ts` and `.service.ts`. Never put server data in Zustand.

### File Organization

```
src/features/{feature}/ui/ # Feature-scoped components (default)
src/shared/components/ # Cross-feature reusable compositions
src/components/ui/ # Shadcn base primitives (edit freely)
src/platform/ # Platform abstraction (Electron IPC, socket)
```
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

Default to feature-scoped. Only promote to `shared/` when a second feature needs it.

### Git Diff Semantics

- Branch resolution always prefers **remote** (`origin/{branch}`) over local — never change to local-first
- Diffs use git CLI against **working directory** (committed + staged + unstaged) — `diff_tree_to_tree` would miss uncommitted changes
- All git calls use `spawn()` with timeouts (5s short ops, 15s diffs)
32 changes: 32 additions & 0 deletions .agents/skills/deus-code-style/animations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Animations

## Project Defaults

- **Default easing:** `ease-out-quart` — `cubic-bezier(.165, .84, .44, 1)`
- **Default duration:** 200-300ms. Never exceed 1s.
- **Hover transitions:** `200ms ease` for color/background/opacity. Disable on touch with `@media (hover: hover) and (pointer: fine)`.
- **Don't use built-in CSS easings** (`ease-out`, `ease-in`) except `ease` for hover and `linear` for constant-speed. Always custom cubic-bezier.

## CSS vs Framer Motion

**CSS/Tailwind** for:
- Hover/focus transitions
- Infinite loops (spinners, shimmers)
- Tooltip/popover enter/exit
- Simple opacity/transform keyframes

**Framer Motion** for:
- Mount/unmount transitions (`AnimatePresence` + `initial`/`animate`/`exit`)
- Layout animations (items shifting after reorder)
- Staggered lists (`staggerChildren`)
- Height auto (CSS can't animate to `auto`)

## Rules

- Animate only `transform` and `opacity` — never width, height, top, left, margin, padding
- `will-change` only for: transform, opacity, clipPath, filter
- No blur above 20px
- Co-locate animation config with the component, not in global.css
- Never define `@keyframes` in global.css for a single component — use Framer Motion inline
- Reuse: `{ duration: 0.2, ease: [0.165, 0.84, 0.44, 1] }` (ease-out-quart)
- Always wrap conditional renders in `AnimatePresence` when exit animations are needed
51 changes: 51 additions & 0 deletions .agents/skills/deus-code-style/components.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Components

## Shadcn — You Own the Code

Files in `src/components/ui/` are starter code you're meant to customize. Editing them directly is the intended workflow.

### Edit `components/ui/*` directly when:
- Changing default styles, adding project-wide variants, fixing a11y, adjusting animations

### Create feature components when:
- Adding app-specific behavior, combining shadcn primitives into domain patterns, adding business logic

### Shadcn Rules

1. **Theme first** — try CSS variables in `global.css` before editing components. If you're overriding the same className everywhere, edit the component once.
2. **Keep standard props** — preserve `className`, `variant`, `size`, `asChild`. Don't embed domain logic in `ui/*`.
3. **Refresh from upstream** with `bunx shadcn@canary add <component> --overwrite`, then reapply customizations.

## Component Architecture

### Encapsulate Self-Contained Concerns

If a piece of UI involves data derivation + rendering + state, make it a component. Don't scatter utilities across the parent.

```tsx
// Bad — parent wires up avatar logic manually
function Item({ repo }) {
const owner = getRepoOwner(repo.name);
const url = getGitHubAvatarUrl(owner);
return <Avatar><AvatarImage src={url} />...</Avatar>;
}

// Good — component owns its concern
function Item({ repo }) {
return <RepoAvatar repoName={repo.name} />;
}
```

### Extract vs Keep Inline

**Extract when:** combines data + rendering, has own state/hooks, reusable, 10+ lines distracting from parent.

**Keep inline when:** pure layout div, one-liner, only makes sense in this parent.

### Where Components Live

| Location | What goes here |
|---|---|
| `src/features/{feature}/ui/` | Default. Feature-scoped components. |
| `src/shared/components/` | Cross-feature reusable compositions (only when 2+ features need it) |
| `src/components/ui/` | Shadcn base primitives only |
52 changes: 52 additions & 0 deletions .agents/skills/deus-code-style/performance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Performance

The app manages tens of repos, hundreds of workspaces, and multiple concurrent agent sessions. Naive patterns compound at this scale.

## Database

- **Index every query pattern** — all indexes in `shared/schema.ts`. Add one for any new query.
- **No N+1** — never subquery per row. Use `sessions.last_user_message_at` directly. Batch or denormalize.
- **Paginate unbounded collections** — messages, file lists. Default 50-100 items.
- **Auto-update triggers** for `updated_at` columns.
- **Column deprecation** — rename with `DEPRECATED_` prefix, never drop.
- **PRAGMA optimize** on startup and graceful shutdown.

## Polling Discipline

- **WebSocket push over polling** — all data resources use WS subscriptions. Never poll data that has a subscription.
- **Budget:** <5 HTTP req/sec steady state. Only pollers: git diffs on working sessions (2-5s).
- **Gate polling on state** — don't poll idle workspaces.

| Frequency | What |
|---|---|
| 2-5s | Git diff hooks (only when session status = "working") |
| 30s+ / on-demand | Settings, repos, config, PR status |
| Never poll | Workspaces, stats, sessions, messages (WS push) |

## Frontend Rendering

- **Virtualize unbounded lists** — anything >30 items uses `@tanstack/react-virtual` (sidebar, messages, file tree)
- **Zustand selector discipline** — never destructure entire store. Always individual selectors:
```tsx
// Bad: const { x, y } = useStore();
// Good: const x = useStore((s) => s.x);
```
Use `useShallow` for structurally-equal objects/arrays.
- **Memoize list items** — `React.memo()` on components in `.map()` loops
- **Batch queries** — use bulk endpoints (e.g. `useBulkDiffStats`), not per-item hooks

## Git + Subprocess

- Treat git calls as expensive — deduplicate aggressively
- Use bulk endpoints (one call per repo interval), not per-item hooks
- Cache diff results with short TTL (5-10s)
- Cap concurrent git subprocesses to prevent CPU spikes

## Read-Layer Priority

When optimizing, tackle in this order:
1. `GET /workspaces/by-repo` (heaviest — joins repos + workspaces + sessions)
2. `GET /stats` (consolidated count query)
3. `GET /sessions/:id`
4. `GET /sessions/:id/messages` (paginated, cursor-based)
5. On-demand reads (repos, settings, config, PR status)
71 changes: 71 additions & 0 deletions .agents/skills/deus-code-style/tailwind.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Tailwind & Styling

## Tailwind CSS v4 — Key Differences

v4 is NOT v3. These are the traps:

- **No JavaScript config.** All config lives in `src/global.css` using `@theme` directive. Never create `tailwind.config.js`.
- **No `@layer`** — `@layer base/components/utilities` is not supported in v4.
- **No `@apply`** — use vanilla CSS instead.
- **No `@theme inline`** — put everything in the main `@theme` block.
Comment on lines +7 to +10

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Tailwind CSS v4 documentation: is tailwind.config.jsoptional or unsupported, and is@apply removed or still supported?

💡 Result:

In Tailwind CSS v4, the tailwind.config.js file is optional. Configuration has shifted to a CSS-first approach using the @theme directive directly in your CSS file where Tailwind is imported, eliminating the need for a separate JS config file in most cases. However, tailwind.config.js is still supported for backward compatibility via the @config directive if needed for advanced customizations like specific content paths or plugins. The @apply directive is still fully supported in Tailwind CSS v4. It allows inlining utility classes into custom CSS, with examples provided in the official documentation. In certain contexts like Vue/Svelte components or CSS modules, use @reference to access utilities. Note that Tailwind's creator recommends avoiding @apply when possible in favor of utility classes, but it remains available and functional.

Citations:


🏁 Script executed:

# Examine the full content of the tailwind.md file to verify the !important contradiction at lines 52 and 60
cat -n .agents/skills/deus-code-style/tailwind.md | head -65 | tail -20

Repository: zvadaadam/deus-machine

Length of output: 1155


🌐 Web query:

Tailwind CSS v4 @layer directive: is it supported, deprecated, or removed?

💡 Result:

In Tailwind CSS v4, the @layer directive is supported as the standard native CSS cascade layers at-rule. Tailwind v4 uses native CSS cascade layers (generated output includes @layer theme, base, components, utilities;) instead of hijacking it like in v3 for special behavior such as automatic variant generation on custom styles in @layer utilities/components. You can still use @layer base, @layer components, @layer utilities in your CSS to organize custom styles into the appropriate cascade layer for correct specificity ordering. However, styles defined in @layer (utilities/components) no longer automatically receive variant support (hover:, md:, etc.). For variant-compatible custom utilities, use the new @utility directive instead. The @layer directive itself is neither deprecated nor removed; its Tailwind-specific "magic" from v3 has been replaced by native CSS behavior and new directives like @utility.

Citations:


Lines 7–10 contain inaccurate Tailwind v4 constraints that will mislead contributors.

According to official Tailwind v4 documentation:

  • tailwind.config.js is optional, not forbidden. The config file is still supported via @config directive for backward compatibility and advanced customization needs; CSS-first approach is preferred but not absolute.
  • @apply is still fully supported in v4 (not removed). The framework's creator recommends avoiding it when possible, but it remains available and functional.
  • @layer is still supported and works as native CSS cascade layers. Behavior changed from v3 (custom styles no longer auto-receive variants), but use @utility directive for variant-compatible custom utilities instead.

Additionally, there's a contradiction between line 52 ("Never use !important") and the DevTools debugging snippet on line 60, which uses !important. Clarify whether the absolute rule applies everywhere or if there are specific exceptions (like DevTools snippets).

Suggested fix: Replace absolute prohibitions with pragmatic guidance: "Prefer CSS-first config; use tailwind.config.js only when CSS cannot express the need. Avoid @apply in favor of utility classes; use @layer for organizing styles with awareness of v4 behavior changes."

🧰 Tools
🪛 LanguageTool

[style] ~10-~10: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...apply** — use vanilla CSS instead. - **No @theme inline`** — put everything in t...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/deus-code-style/tailwind.md around lines 7 - 10, Update the
guidance in the Tailwind v4 doc block to remove absolute prohibitions and
reflect current behavior: change the bullets referencing "No JavaScript config",
"No `@layer`", "No `@apply`", and "`@theme inline`" to pragmatic guidance that
`tailwind.config.js` is optional (use `@config` when needed), `@apply` remains
supported but should be used sparingly, `@layer` is supported with v4 behavior
changes (use `@utility` for variant-compatible utilities), and prefer a single
`@theme` block but allow exceptions; also reconcile the “Never use `!important`”
rule with the DevTools debugging snippet by adding an exception or clarifying
when `!important` is acceptable for debugging.

- **No `tailwindcss-animate`** — animations are built-in.
- **Vite plugin:** `@tailwindcss/vite` (not `@tailwindcss/postcss`).

### Color System: OKLCH

All colors use OKLCH, not HSL/RGB. Semantic colors in `:root` and `.dark`:

```css
@theme {
--color-background: var(--background);
--color-primary: var(--primary);
--font-family-sans: "Helvetica Neue", -apple-system, ...;
}
```

For semi-transparent: `color-mix(in oklch, var(--primary) 25%, transparent)`.

## What Goes Where

### Global CSS (`src/global.css`) — ONLY:

1. `@theme` block (design tokens)
2. `@keyframes` (GPU-accelerated animations shared across components)
3. Global element styles (`html`, `body`, `#root`, scrollbars)
4. Complex effects Tailwind can't do (vibrancy, backdrop filters, markdown content styling)
5. `@media (prefers-reduced-motion)`, `@media (hover: hover)`

### Never add to global CSS:

Simple utilities that Tailwind already handles — spacing, shadows, typography, layout, colors. If Tailwind does it in 2-3 classes, don't make a custom utility.

### Component variants (`src/components/ui/*`):

Repeated patterns: size variations (`size="sm"`), style variations (`variant="outline"`), state variations (`data-state="active"`).

### Inline Tailwind:

Layout, one-off adjustments, responsive, state variants — the usual.

## Specificity & Overrides

- Never use `!important` — if you need it, the specificity architecture is wrong
- `cn()` / twMerge only merges classes with **identical modifiers**. `has-[>svg]:px-3` and `has-[&>svg]:px-1` coexist instead of overriding. Always match the exact modifier string from the base component.
- When debugging spacing, always read the base component source (`components/ui/*.tsx`) to see what CVA defaults you're inheriting

## Debugging Layout Issues

Before touching CSS:

1. Outline everything: `* { outline: 1px solid rgba(255,0,0,0.3) !important; }` in DevTools
2. Trace the full component tree (parent + element + children across files)
3. Check parent/grandparent for `p-*`, `gap-*`, flex alignment
4. Check compound spacing (parent padding + child margin + flex gap)
5. Read the shadcn base component source for hidden defaults

## General Rules

- All colors via CSS variables/tokens, never hardcoded (`bg-blue-500`, `#3b82f6`)
- Consistent 16px default padding (dense product)
- Use container queries (`@container`) over media queries for reusable components
- Prefer logical properties (`margin-inline`, `padding-block`) for future-proofing
File renamed without changes.
File renamed without changes.
File renamed without changes.
56 changes: 0 additions & 56 deletions .agents/skills/remotion-best-practices/SKILL.md

This file was deleted.

Loading
Loading