My Custom Widget
This is a custom front component for Twenty.
);
};
export default defineFrontComponent({
universalIdentifier: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
name: 'my-widget',
description: 'A custom widget component',
component: MyWidget,
});
```
Key points:
- Front components are React components that render in isolated contexts within Twenty.
- The `component` field references your React component.
- Components are built and synced automatically during `yarn twenty dev`.
You can create new front components in two ways:
- **Scaffolded**: Run `yarn twenty add` and choose the option to add a new front component.
- **Manual**: Create a new `.tsx` file and use `defineFrontComponent()`, following the same pattern.
### Skills
Skills define reusable instructions and capabilities that AI agents can use within your workspace. Use `defineSkill()` to define skills with built-in validation:
```typescript
// src/skills/example-skill.ts
import { defineSkill } from 'twenty-sdk';
export default defineSkill({
universalIdentifier: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
name: 'sales-outreach',
label: 'Sales Outreach',
description: 'Guides the AI agent through a structured sales outreach process',
icon: 'IconBrain',
content: `You are a sales outreach assistant. When reaching out to a prospect:
1. Research the company and recent news
2. Identify the prospect's role and likely pain points
3. Draft a personalized message referencing specific details
4. Keep the tone professional but conversational`,
});
```
Key points:
- `name` is a unique identifier string for the skill (kebab-case recommended).
- `label` is the human-readable display name shown in the UI.
- `content` contains the skill instructions — this is the text the AI agent uses.
- `icon` (optional) sets the icon displayed in the UI.
- `description` (optional) provides additional context about the skill's purpose.
You can create new skills in two ways:
- **Scaffolded**: Run `yarn twenty add` and choose the option to add a new skill.
- **Manual**: Create a new file and use `defineSkill()`, following the same pattern.
### Typed API clients (`twenty-client-sdk`)
The `twenty-client-sdk` package provides two typed GraphQL clients for interacting with the Twenty API from your logic functions and front components:
| Client | Import | Endpoint | Generated? |
|--------|--------|----------|------------|
| `CoreApiClient` | `twenty-client-sdk/core` | `/graphql` — workspace data (records, objects) | Yes, at dev/build time |
| `MetadataApiClient` | `twenty-client-sdk/metadata` | `/metadata` — workspace config, file uploads | No, ships pre-built |
#### CoreApiClient
`CoreApiClient` is the main client for querying and mutating workspace data. It is **generated from your workspace schema** during `yarn twenty dev` or `yarn twenty build`, so it's fully typed to match your objects and fields.
```typescript
import { CoreApiClient } from 'twenty-client-sdk/core';
const client = new CoreApiClient();
// Query records
const { companies } = await client.query({
companies: {
edges: {
node: {
id: true,
name: true,
domainName: true,
},
},
},
});
// Create a record
const { createCompany } = await client.mutation({
createCompany: {
__args: {
data: {
name: 'Acme Corp',
},
},
id: true,
name: true,
},
});
```
The client uses a selection-set syntax: pass `true` to include a field, use `__args` for arguments, and nest objects for relations. You get full autocompletion and type checking based on your workspace schema.