Files
workspace/AGENTS.md

4.9 KiB

AGENTS.md - Agent Coding Guidelines

Monorepo: data engineering projects + WhatsApp CRM apps.


Project Structure

workspace/
├── apps/
│   ├── go-crm/            # Go CRM, Chi router (primary)
│   ├── whatsapp-crm/      # Next.js CRM, Kanban board
│   ├── whatsapp-sync/     # WhatsApp message sync
│   ├── whatsapp-reader/   # WhatsApp message reader
│   └── timesfm-forecast/  # Time series forecast (Python/uv)
├── data/                  # SQLite files
│   ├── go-crm.db
│   └── whatsapp.db
├── data-engineering/      # Udacity DE portfolio
└── skills/                # dbt reference templates

Build / Lint / Test Commands

go-crm (primary)

cd apps/go-crm

go run main.go                    # dev
go build -o go-crm main.go        # build binary
./go-crm                          # run binary

go mod download                   # deps
go mod tidy                       # clean go.mod/go.sum

# DB: /workspace/data/go-crm.db

whatsapp-crm (Next.js)

cd apps/whatsapp-crm

npm run dev          # dev server 0.0.0.0:3000
npm run build        # production build
npm run start        # production server

npm run lint         # ESLint

npm run test         # all Jest tests
npm run test:watch  # watch mode
npm run test:coverage  # coverage

npm run test -- tests/kanban.test.ts
npm run test -- --testPathPattern=kanban

whatsapp-sync

cd apps/whatsapp-sync

npm run start        # node src/index.js
npm run dev         # node --watch src/index.js
npm run sync        # node src/sync.js
npm run test        # Jest
npm run test:watch
npm run test:coverage

whatsapp-reader

cd apps/whatsapp-reader

node index.js       # main script
node sync.js        # sync script
# no test script

timesfm-forecast

cd apps/timesfm-forecast

uv venv && source .venv/bin/activate  # create + activate venv
uv pip install -e .                    # install package
timesfm-app                            # run Streamlit app

Code Style Guidelines

TypeScript

  • strict: true in tsconfig.json
  • Explicit types for params + return values
  • interface for objects, type for unions/aliases
interface Contact {
  id: number
  name: string
  stage: Stage
}

function getContactById(id: number): Contact | null

Imports

  • Path alias @/* (tsconfig.json)
  • Order: external → internal → relative
  • Group: React imports → other imports → types → components
import { useState, useMemo } from 'react'
import { Stage, STAGES, Contact } from '@/lib/types'
import { ContactCard } from '@/components/ContactCard'

Naming

  • Components: PascalCase (KanbanBoard, ContactCard)
  • Files: PascalCase (.tsx), camelCase (.ts)
  • Interfaces/Types: PascalCase
  • Constants: UPPER_SNAKE_CASE
  • Hooks: camelCase + use prefix
  • Booleans: is/has/should prefix

Error Handling

  • Zod for input validation + react-hook-form
  • Wrap async in try/catch
  • Return proper HTTP status codes
export async function POST(request: Request) {
  try {
    const body = await request.json()
    const validated = CreateContactInput.parse(body)
  } catch (error) {
    if (error instanceof ZodError) {
      return Response.json({ error: error.errors }, { status: 400 })
    }
    return Response.json({ error: 'Internal server error' }, { status: 500 })
  }
}

Component Structure

  • 'use client' directive for client-side
  • Destructure props, explicit typing
  • Keep components focused, small
  • Extract reusable logic to custom hooks
'use client'

interface Props {
  contacts: Contact[]
  onContactClick: (contact: Contact) => void
}

export default function ComponentName({ contacts, onContactClick }: Props) {
  const [state, setState] = useState(false)

  return <div>{/* JSX */}</div>
}

Database (sql.js)

  • Zod schemas for table definitions
  • Validate data before insert/update
  • Use transactions for multi-step ops

Testing

  • Test files: tests/*.test.ts or *.test.tsx
  • @testing-library/react for component tests
  • @testing-library/user-event for interactions
  • AAA pattern: Arrange, Act, Assert
test('should update contact stage', async () => {
  const user = userEvent.setup()
  render(<KanbanBoard {...props} />)

  await user.click(screen.getByText('Move to Next Stage'))
  expect(onStageChange).toHaveBeenCalledWith(1, 'DECIDINDO')
})

CSS / Styling

  • CSS modules or global CSS
  • BEM-like: block-element--modifier
  • Co-locate styles when possible

Git

  • Meaningful commit messages
  • Branch naming: feature/description or fix/description
  • Run npm run lint + npm run test before commit

Important Notes

  • whatsapp-crm: Next.js 14 App Router
  • Database: sql.js (WebAssembly SQLite), runs in browser
  • Auth: WhatsApp Web.js QR code scanning
  • STAGES constant: Kanban pipeline (defined in src/lib/types.ts)