data

SkillDev tools

Guides your agent in writing data fetching, API calls, server/client components, and SWR hooks.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the data skill

About this capability

Use when implementing data fetching, API calls, server/client components, or SWR hooks

What this skill tells your AI

The instructions your AI receives, as published by trycompai/comp in .agents/skills/data/SKILL.md and read by ahel’s review.

Source Cursor rule: .cursor/rules/data.mdc. Original Cursor alwaysApply: false.

Data Fetching

Core Pattern: Server → Client → SWR

1. Server Page Fetches Data

// app/(app)/[orgId]/tasks/page.tsx
export default async function TasksPage({ params }: { params: Promise<{ orgId: string }> }) {
  const { orgId } = await params; // From URL, NOT session
  const tasks = await getTasks(orgId);
  return <TaskListClient organizationId={orgId} initialTasks={tasks} />;
}

2. Client Component Receives Initial Data

// components/TaskListClient.tsx
'use client';

export function TaskListClient({ organizationId, initialTasks }: Props) {
  const { tasks, createTask, updateTask } = useTasks({
    organizationId,
    initialData: initialTasks,
  });
  // Initial render is instant - no loading state
}

3. SWR Hook with fallbackData

// hooks/useTasks.ts
export function useTasks({ organizationId, initialData }: UseTasksOptions) {
  const { data, mutate } = useSWR(
    ['/v1/tasks', organizationId], // Include orgId for cache isolation
    async ([endpoint, orgId]) => {
      const response = await apiClient.get(endpoint, orgId);
      return response.data?.tasks ?? [];
    },
    { fallbackData: initialData }
  );

  const createTask = async (input: CreateTaskInput) => {
    await apiClient.post('/v1/tasks', input, organizationId);
    mutate(); // Revalidate
  };

  const updateTask = async ({ taskId, input }: { taskId: string; input: UpdateTaskInput }) => {
    await apiClient.put(`/v1/tasks/${taskId}`, input, organizationId);
    mutate(); // Revalidate
  };

  return { tasks: data ?? [], createTask, updateTask, mutate };
}

API Client

Use apiClient from @/lib/api-client:

import { apiClient } from '@/lib/api-client';

await apiClient.get<ResponseType>('/v1/endpoint', organizationId);
await apiClient.post<ResponseType>('/v1/endpoint', body, organizationId);
await apiClient.put<ResponseType>('/v1/endpoint', body, organizationId);
await apiClient.delete('/v1/endpoint', organizationId);

Server vs Client Components

Layouts = server. Interactive logic in separate client components.

// layout.tsx (server)
export default function Layout({ children }) {
  return (
    <PageLayout>
      <PageHeader title="Title" />
      <ClientTabs /> {/* Client component */}
      {children}
    </PageLayout>
  );
}

// components/ClientTabs.tsx
'use client';
export function ClientTabs() {
  const router = useRouter();
  // Interactive logic here
}

State Management

No nuqs - use React state or Next.js patterns:

// ✅ React state for UI
const [isOpen, setIsOpen] = useState(false);

// ✅ Next.js for URL state
const router = useRouter();
const searchParams = useSearchParams();

// ❌ No nuqs
import { useQueryState } from 'nuqs';

Rules

// ✅ Always
const { orgId } = await params;                    // From URL params
const { data } = useSWR(key, f, { fallbackData }); // With initial data
await apiClient.get('/v1/endpoint', orgId);        // Use apiClient
useSWR(['/v1/tasks', orgId], fetcher);            // Include orgId in key

// ❌ Never
const orgId = session?.activeOrganizationId;       // From session
const { data } = useSWR('/api/data');              // No initial data
await fetch('/api/endpoint');                      // Direct fetch

File Structure

app/(app)/[orgId]/tasks/
├── page.tsx                 # Server - fetches data
├── components/
│   └── TaskListClient.tsx   # Client - receives initialData
├── hooks/
│   └── useTasks.ts          # SWR hook with mutations
└── data/
    └── queries.ts           # Server-side queries

Signals

GitHub stars
2k
Forks
412
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
data-trycompai
Source
github.com/trycompai/comp