integration-development
Guide for creating new OAuth-based integrations in the Orient codebase. Use when adding external service integrations (APIs like Linear, GitHub, Slack, Notion, etc.), implementing OAuth flows, or creating catalog-based integration manifests. Covers the full integration lifecycle from manifest definition to tool implementation.
Installation
Follow the repository instructions for this skill and your agent. Review the files and dependencies before adding it to your workflow.
View source ↗GuidesSkill instructions
Integration Development
This skill provides guidance for creating OAuth-based integrations in Orient.
Integration Architecture
Orient uses a catalog-based architecture for integrations:
packages/integrations/src/
├── catalog/ # Integration definitions
│ ├── linear/
│ │ ├── INTEGRATION.yaml # Manifest
│ │ ├── oauth-config.ts # OAuth configuration
│ │ ├── tools.ts # API client and tools
│ │ └── index.ts # Exports
│ └── github/
│ └── ...
├── types/
│ └── integration.ts # IntegrationManifest types
└── index.ts # Package exports
Quick Start
- Create directory:
packages/integrations/src/catalog/<integration-name>/ - Create
INTEGRATION.yamlmanifest - Create
oauth-config.tsfor OAuth flow - Create
tools.tsfor API client - Create
index.tsfor exports - Update package.json exports
File Templates
INTEGRATION.yaml
See references/manifest-template.md for the complete template.
Key fields:
-
name: lowercase identifier (e.g.,linear,github) -
title: display name -
description: 50+ character description -
version: semver (e.g.,1.0.0) -
oauth: authorization and token URLs, scopes -
requiredSecrets: CLIENT_ID, CLIENT_SECRET, etc. -
tools: available API operations -
status:stable,beta, orexperimental
oauth-config.ts
Required exports:
- Scope constants (e.g.,
LINEAR_SCOPES) - Default scopes array
- Config interface
-
getAuthUrl()- generate authorization URL -
exchangeCode()- exchange code for tokens -
getUserInfo()- fetch user profile -
getConfigFromEnv()- load config from environment
tools.ts
Required exports:
- Type definitions for API responses
- Client class with API methods
- Factory function (e.g.,
createLinearClient())
OAuth Flow Patterns
Standard OAuth 2.0
Most services use standard OAuth 2.0:
// 1. Generate auth URL with state
const authUrl = getAuthUrl(config, scopes, state);
// 2. User authorizes in browser, redirected with code
// 3. Exchange code for tokens
const tokens = await exchangeCode(config, code);
// 4. Use access token for API calls
const client = createClient(tokens.accessToken);
OAuth 2.0 with PKCE
Some services require PKCE (Proof Key for Code Exchange):
// 1. Generate code verifier and challenge
const codeVerifier = crypto.randomBytes(32).toString('base64url');
const codeChallenge = crypto.createHash('sha256').update(codeVerifier).digest('base64url');
// 2. Include challenge in auth URL
const authUrl = `${baseUrl}?code_challenge=${codeChallenge}&code_challenge_method=S256`;
// 3. Include verifier in token exchange
const tokens = await exchangeCode(config, code, codeVerifier);
API Client Patterns
GraphQL APIs (Linear, GitHub GraphQL)
private async query<T>(query: string, variables?: Record<string, unknown>): Promise<T> {
const response = await fetch(this.apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.accessToken}`,
},
body: JSON.stringify({ query, variables }),
});
const result = await response.json();
if (result.errors?.length > 0) {
throw new Error(`GraphQL error: ${result.errors[0].message}`);
}
return result.data;
}
REST APIs (GitHub REST, Slack)
private async request<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
const response = await fetch(`${this.apiUrl}${endpoint}`, {
...options,
headers: {
Authorization: `Bearer ${this.accessToken}`,
Accept: 'application/json',
'Content-Type': 'application/json',
...options.headers,
},
});
if (!response.ok) {
const error = await response.json().catch(() => ({ message: response.statusText }));
throw new Error(`API error: ${error.message}`);
}
return response.json();
}
Logging Pattern
Always use the service logger:
import { createServiceLogger } from '@orient/core';
const logger = createServiceLogger('integration-name');
async function someOperation() {
const op = logger.startOperation('operationName', { param1: value1 });
try {
const result = await doWork();
op.success('Operation completed', { resultCount: result.length });
return result;
} catch (error) {
op.failure(error instanceof Error ? error : String(error));
throw error;
}
}
Type Transformation
Transform API responses to camelCase:
// API returns snake_case
const apiResponse = {
created_at: '2024-01-15',
pull_request: { html_url: '...' },
};
// Transform to camelCase
const result = {
createdAt: apiResponse.created_at,
pullRequest: { htmlUrl: apiResponse.pull_request.html_url },
};
Required Secrets
Define all required secrets in the manifest:
requiredSecrets:
- name: SERVICE_CLIENT_ID
description: OAuth Client ID from developer settings
category: oauth
required: true
- name: SERVICE_CLIENT_SECRET
description: OAuth Client Secret
category: oauth
required: true
- name: SERVICE_WEBHOOK_SECRET
description: Webhook signing secret (optional)
category: webhook
required: false
Webhook Support
For integrations that support webhooks:
webhooks:
events:
- push
- pull_request
- issues
signatureHeader: X-Hub-Signature-256
signatureAlgorithm: hmac-sha256
Testing Integrations
- OAuth flow: Test with real credentials in development
- API calls: Mock API responses in unit tests
- Token refresh: Test expiration handling
- Error handling: Test API error responses
Common Pitfalls
- Missing scopes: Always request all needed scopes upfront
- Token expiration: Handle refresh tokens if provided
- Rate limiting: Implement backoff for API errors
- Pagination: Handle paginated API responses
- Error messages: Parse API error details for useful messages
References
-
references/manifest-template.md- Full INTEGRATION.yaml template -
references/oauth-providers.md- OAuth configuration for common providers
Examples
Read the usage examples in the source repository.
View source ↗Source history
- Indexed on
- 2026-01-20
- Index updated
- 2026-01-26
- Branch
- main
Index and sync dates describe this directory. View the source repository for code history.
GitHub ↗chat Comments (0)
Sign in to join the discussion and leave a comment.
No comments yet. Be the first to share your thoughts!