Skip to main content

Code Style Philosophy

Autonome enforces strict code style to maintain consistency and quality across the codebase:
  • Zero tech debt: Do things right from the start, no workarounds
  • Adaptive refactoring: Clean up sloppy code whenever you encounter it
  • No bandaid fixes: Fix issues at their source, not with patches
  • Complete implementations: Build for scale (>1000 users), not quick hacks
From AGENTS.md: “Early development, no users. No backwards compatibility concerns. Do things RIGHT: clean, organized, zero tech debt. Never create compatibility shims.”

Biome Configuration

Autonome uses Biome for linting and formatting instead of ESLint + Prettier:
  • Faster than ESLint (10-100x speedup)
  • Single tool for both linting and formatting
  • Zero config required (sensible defaults)
  • Native to the JavaScript ecosystem

Configuration File

Biome is configured in biome.json:
{
  "$schema": "https://biomejs.dev/schemas/2.2.4/schema.json",
  "formatter": {
    "enabled": true,
    "indentStyle": "tab"
  },
  "javascript": {
    "formatter": {
      "quoteStyle": "double"
    }
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true
    }
  },
  "assist": {
    "actions": {
      "source": {
        "organizeImports": "on"
      }
    }
  }
}

Running Biome

# Check for issues (lint + format)
bun run check

# Format code
bun run format

# Lint code
bun run lint

# Auto-fix issues
bun run check --write
Run bun run check before committing to catch style violations early.

Core Style Rules

1. Indentation: Tabs

Always use tabs for indentation, never spaces:
// Good ✅
function calculatePnl(position: Position) {
	const { side, quantity, averagePrice, currentPrice } = position;
	if (side === "BUY") {
		return (currentPrice - averagePrice) * quantity;
	}
	return (averagePrice - currentPrice) * quantity;
}

// Bad ❌ (spaces)
function calculatePnl(position: Position) {
  const { side, quantity, averagePrice, currentPrice } = position;
  if (side === "BUY") {
    return (currentPrice - averagePrice) * quantity;
  }
  return (averagePrice - currentPrice) * quantity;
}
Why tabs?
  • Accessibility: Users can configure tab width to their preference
  • Smaller file sizes
  • Easier to navigate with keyboard

2. Quotes: Double

Always use double quotes for strings:
// Good ✅
const message = "Hello, world!";
const symbol = "BTC-USD";
import { Button } from "@/components/ui/button";

// Bad ❌
const message = 'Hello, world!';
const symbol = 'BTC-USD';
import { Button } from '@/components/ui/button';
Exception: Use backticks for template literals:
const greeting = `Hello, ${name}!`;
const query = `
	SELECT * FROM "Orders"
	WHERE "status" = 'OPEN'
`;

3. Import Organization

Biome automatically organizes imports:
// Correct order (automatic):
// 1. External packages
import { useState } from "react";
import { useQuery } from "@tanstack/react-query";
import * as Sentry from "@sentry/react";

// 2. Internal absolute imports
import { orpc } from "@/server/orpc/client";
import { Button } from "@/components/ui/button";
import { calculatePnl } from "@/core/shared/trading/calculations";

// 3. Relative imports
import { PositionCard } from "./PositionCard";
import { usePositions } from "../hooks/usePositions";

// 4. Type imports (grouped separately)
import type { Position } from "@/db/schema";
import type { ReactNode } from "react";

4. Semicolons

Biome enforces semicolons at the end of statements:
// Good ✅
const x = 5;
return calculatePnl(position);

// Bad ❌
const x = 5
return calculatePnl(position)

TypeScript Conventions

Type Annotations

Use explicit types for function parameters and return values:
// Good ✅
function calculatePnl(position: Position): number {
	const pnl = (position.currentPrice - position.averagePrice) * position.quantity;
	return pnl;
}

// Acceptable (return type inferred)
function getSymbol(position: Position) {
	return position.symbol; // string inferred
}

// Bad ❌ (no parameter types)
function calculatePnl(position) {
	return position.currentPrice - position.averagePrice;
}

Type vs Interface

Prefer type over interface for most cases:
// Good ✅
type Position = {
	id: string;
	side: "BUY" | "SELL";
	quantity: string;
	averagePrice: string;
};

// Use interface for extending
interface ExtendedPosition extends Position {
	exitPlan?: ExitPlan;
}

Avoid any

Never use any - use unknown or proper types:
// Good ✅
function parseJson(data: string): unknown {
	return JSON.parse(data);
}

const result = parseJson(jsonString);
if (typeof result === "object" && result !== null) {
	// Safe to use
}

// Bad ❌
function parseJson(data: string): any {
	return JSON.parse(data);
}

React Component Patterns

Component Structure

import type { ReactNode } from "react";
import { cn } from "@/lib/utils";
import { cva, type VariantProps } from "class-variance-authority";

// 1. Variants definition (if applicable)
const buttonVariants = cva(
	"inline-flex items-center justify-center rounded-md font-medium",
	{
		variants: {
			variant: {
				default: "bg-primary text-primary-foreground",
				destructive: "bg-destructive text-destructive-foreground",
				outline: "border border-input",
			},
			size: {
				default: "h-10 px-4",
				sm: "h-9 px-3",
				lg: "h-11 px-8",
			},
		},
		defaultVariants: {
			variant: "default",
			size: "default",
		},
	},
);

// 2. Props interface
interface ButtonProps
	extends React.ButtonHTMLAttributes<HTMLButtonElement>,
		VariantProps<typeof buttonVariants> {
	children: ReactNode;
}

// 3. Component definition
export function Button({ className, variant, size, ...props }: ButtonProps) {
	return (
		<button
			className={cn(buttonVariants({ variant, size, className }))}
			{...props}
		/>
	);
}

Hooks Conventions

Custom hooks must start with use:
// Good ✅
export function usePositions(modelId: string) {
	return useQuery(
		orpc.trading.getPositions.queryOptions({
			input: { modelId },
		}),
	);
}

// Bad ❌
export function getPositions(modelId: string) {
	// Not a hook name
}

Event Handlers

Prefix event handlers with handle:
function PositionCard({ position }: Props) {
	const handleClose = () => {
		// Close position logic
	};

	const handleEdit = () => {
		// Edit logic
	};

	return (
		<div>
			<Button onClick={handleClose}>Close</Button>
			<Button onClick={handleEdit}>Edit</Button>
		</div>
	);
}

Naming Conventions

Variables & Functions

camelCase for variables and functions:
const portfolioValue = 10000;
const currentPrice = 50.25;

function calculateUnrealizedPnl() {}
function getOpenPositions() {}

Constants

UPPER_SNAKE_CASE for constants:
const INITIAL_CAPITAL = 10000;
const MAX_POSITION_SIZE = 1000;
const API_BASE_URL = "https://api.example.com";

// Exception: Configuration objects use camelCase
const VARIANT_CONFIG = {
	Apex: { color: "#FF6B6B", label: "Apex" },
	Trendsurfer: { color: "#4ECDC4", label: "Trendsurfer" },
};

Types & Interfaces

PascalCase for types, interfaces, and enums:
type Position = {
	id: string;
	side: OrderSide;
};

interface PositionCardProps {
	position: Position;
	onClose: () => void;
}

enum OrderStatus {
	OPEN = "OPEN",
	CLOSED = "CLOSED",
	CANCELED = "CANCELED",
}

Files & Directories

kebab-case for file names (except components):
src/
├── core/
│   └── shared/
│       └── trading/
│           ├── calculations.ts        # kebab-case
│           └── fill-tracker.ts        # kebab-case
├── components/
│   └── ui/
│       ├── Button.tsx                 # PascalCase for components
│       └── PositionCard.tsx           # PascalCase for components
└── server/
    └── features/
        └── trading/
            └── trading-repository.ts  # kebab-case

Database Conventions

Quoted Identifiers

Always quote capitalized table and column names:
// Good ✅
const positions = await db
	.select()
	.from(schema.Orders)
	.where(eq(schema.Orders.status, "OPEN"));

// SQL: SELECT * FROM "Orders" WHERE "status" = 'OPEN'

// Bad ❌
const positions = await db
	.select()
	.from(Orders) // Unquoted - will fail in PostgreSQL
	.where(eq(Orders.status, "OPEN"));

Monetary Values

Store as TEXT, cast to NUMERIC for calculations:
// Schema definition
export const Orders = pgTable("Orders", {
	id: text("id").primaryKey(),
	averagePrice: text("averagePrice").notNull(),
	realizedPnl: text("realizedPnl"),
});

// SQL queries
const totalPnl = await db.execute(sql`
	SELECT SUM(CAST("realizedPnl" AS NUMERIC)) as total
	FROM "Orders"
	WHERE "status" = 'CLOSED'
`);

oRPC Patterns

Procedure Structure

import "@/polyfill"; // Always import at top
import { os } from "@orpc/server";
import { z } from "zod";
import * as Sentry from "@sentry/react";

export const getPositions = os
	.input(
		z.object({
			modelId: z.string().optional(),
			variant: z.enum(["Apex", "Trendsurfer", "Contrarian", "Sovereign"]).optional(),
		}),
	)
	.output(
		z.array(
			z.object({
				id: z.string(),
				side: z.enum(["BUY", "SELL"]),
				quantity: z.string(),
				averagePrice: z.string(),
			}),
		),
	)
	.handler(async ({ input }) =>
		Sentry.startSpan({ name: "getPositions" }, async () => {
			const { modelId, variant } = input;
			// Implementation
			return positions;
		}),
	);

Client Usage

import { useQuery } from "@tanstack/react-query";
import { orpc } from "@/server/orpc/client";

function Positions() {
	const { data: positions } = useQuery(
		orpc.trading.getPositions.queryOptions({
			input: { modelId: "model-123" },
		}),
	);

	return <div>{/* Render positions */}</div>;
}

Critical Rules from AGENTS.md

1. Package Manager: Bun Only

# Good ✅
bun install
bun add package-name
bun run dev

# Bad ❌
npm install
pnpm add package-name
yarn dev

2. Data Fetching: oRPC Only

// Good ✅
const { data } = useQuery(
	orpc.trading.getPositions.queryOptions({ input: {} }),
);

// Bad ❌
const response = await fetch("/api/positions");
const data = await response.json();

3. Environment Variables: T3Env

// Good ✅
import { env } from "@/env";

const apiKey = env.LIGHTER_API_KEY;
const dbUrl = env.DATABASE_URL;

// Bad ❌
const apiKey = process.env.LIGHTER_API_KEY;
const dbUrl = import.meta.env.DATABASE_URL;

4. No Workarounds

// Bad ❌ - Bandaid fix
function calculatePnl(position: any) {
	// @ts-ignore
	return position.currentPrice - position.entryPrice;
}

// Good ✅ - Proper fix
function calculatePnl(position: Position): number {
	if (!position.currentPrice || !position.averagePrice) {
		throw new Error("Missing price data");
	}
	return position.currentPrice - position.averagePrice;
}

5. Adaptive Refactoring

Before:
// Encountered sloppy code
function calc(p) {
	return p.cp - p.ep;
}
After:
// Refactored while working nearby
function calculatePnl(position: Position): number {
	const { currentPrice, averagePrice } = position;
	return currentPrice - averagePrice;
}

6. Edge Case Exhaustion

// Good ✅ - All edge cases handled
function calculateWinRate(trades: Trade[]): number {
	// Edge case: Empty array
	if (trades.length === 0) {
		return 0;
	}

	// Edge case: All trades are break-even
	const winningTrades = trades.filter((t) => t.pnl > 0);
	if (winningTrades.length === 0) {
		return 0;
	}

	// Normal case
	return winningTrades.length / trades.length;
}

Component Styling (Tailwind + CVA)

Using CVA for Variants

import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";

const badgeVariants = cva(
	"inline-flex items-center rounded-md px-2 py-1 text-xs font-semibold",
	{
		variants: {
			variant: {
				default: "bg-primary text-primary-foreground",
				success: "bg-green-500 text-white",
				error: "bg-red-500 text-white",
			},
		},
		defaultVariants: {
			variant: "default",
		},
	},
);

interface BadgeProps extends VariantProps<typeof badgeVariants> {
	children: React.ReactNode;
	className?: string;
}

export function Badge({ variant, className, children }: BadgeProps) {
	return (
		<span className={cn(badgeVariants({ variant }), className)}>
			{children}
		</span>
	);
}

Using cn() for Class Merging

import { cn } from "@/lib/utils";

// Merge classes with proper precedence
<div
	className={cn(
		"base-class p-4 bg-white",
		isActive && "bg-blue-500", // Conditional
		className, // User override
	)}
/>

VS Code Integration

Add to .vscode/settings.json:
{
  "editor.defaultFormatter": "biomejs.biome",
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "quickfix.biome": "explicit",
    "source.organizeImports.biome": "explicit"
  },
  "[typescript]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[typescriptreact]": {
    "editor.defaultFormatter": "biomejs.biome"
  }
}

Pre-Commit Checklist

Before committing code:
  • Run bun run check (no errors)
  • Run bun run test (all tests pass)
  • Verify no console.log statements (unless intentional)
  • Check for unused imports/variables
  • Ensure proper TypeScript types (no any)
  • Verify database queries use quoted identifiers
  • Confirm environment variables use env.ts
  • Test affected functionality manually

Common Mistakes

Mistake 1: Using spaces instead of tabs

// Wrong
function foo() {
  return "bar"; // 2 spaces
}

// Correct
function foo() {
	return "bar"; // 1 tab
}
Fix: Run bun run format --write

Mistake 2: Single quotes

// Wrong
const message = 'Hello';

// Correct
const message = "Hello";
Fix: Run bun run format --write

Mistake 3: Unquoted database identifiers

// Wrong
await db.select().from(Orders);

// Correct
await db.select().from(schema.Orders); // Uses quoted "Orders"

Mistake 4: Direct process.env access

// Wrong
const apiKey = process.env.LIGHTER_API_KEY;

// Correct
import { env } from "@/env";
const apiKey = env.LIGHTER_API_KEY;

Mistake 5: Not organizing imports

// Wrong
import { Button } from "./Button";
import { useState } from "react";
import { env } from "@/env";

// Correct (Biome auto-organizes)
import { useState } from "react";
import { env } from "@/env";
import { Button } from "./Button";
Fix: Run bun run check --write

Next Steps

  • Set up your editor: Configure VS Code with Biome extension
  • Practice: Follow these conventions in your daily work
  • Review: Read Testing for QA workflow
  • Contribute: See Contributing Guidelines for the full development process
Consistency is more important than personal preference. Follow the style guide even if you disagree with specific choices.