| name | linear-cost-tuning |
| description | Optimize Linear API usage and manage costs effectively.
Use when reducing API calls, managing rate limits efficiently,
or optimizing integration costs.
Trigger with phrases like "linear cost", "reduce linear API calls",
"linear efficiency", "linear API usage", "optimize linear costs".
|
| allowed-tools | Read, Write, Edit, Grep |
| version | 1.0.0 |
| license | MIT |
| author | Jeremy Longshore <jeremy@intentsolutions.io> |
Linear Cost Tuning
Overview
Optimize Linear API usage to maximize efficiency and minimize costs.
Prerequisites
- Working Linear integration
- Monitoring in place
- Understanding of usage patterns
Cost Factors
API Request Costs
| Factor | Impact | Optimization Strategy |
|---|
| Request count | Direct rate limit | Batch operations |
| Query complexity | Complexity limit | Minimal field selection |
| Payload size | Bandwidth/latency | Pagination, filtering |
| Webhook volume | Processing costs | Event filtering |
Instructions
Step 1: Audit Current Usage
interface UsageStats {
requests: number;
complexity: number;
bytesTransferred: number;
period: { start: Date; end: Date };
}
class UsageTracker {
private stats: UsageStats = {
requests: 0,
complexity: 0,
bytesTransferred: 0,
period: { start: new Date(), end: new Date() },
};
recordRequest(complexity: number, bytes: number): void {
this.stats.requests++;
this.stats.complexity += complexity;
this.stats.bytesTransferred += bytes;
this.stats.period.end = new Date();
}
(): {
{ .... };
}
(): {
: ;
: ;
: ;
} {
hours =
(....() - ....()) /
( * * );
{
: .. / .(hours, ),
: .. / .(.., ),
: (.. / .(hours, )) * * ,
};
}
(): {
. = {
: ,
: ,
: ,
: { : (), : () },
};
}
}
usageTracker = ();
Step 2: Reduce Request Volume
Polling vs Webhooks:
setInterval(async () => {
const issues = await client.issues({ first: 100 });
await syncIssues(issues.nodes);
}, 60000);
app.post("/webhooks/linear", async (req, res) => {
const event = req.body;
await handleEvent(event);
res.sendStatus(200);
});
Conditional Fetching:
interface ETagCache {
data: any;
etag: string;
timestamp: Date;
}
const etagCache = new Map<string, ETagCache>();
async function fetchWithETag(key: string, fetcher: () => Promise<any>) {
const cached = etagCache.get(key);
if (cached && Date.now() - cached.timestamp.getTime() < 5 * 60 * 1000) {
return cached.data;
}
const data = await fetcher();
etagCache.set(key, {
data,
etag: JSON.stringify(data).slice(0, 50),
timestamp: new Date(),
});
return data;
}
Step 3: Optimize Query Complexity
Calculate Complexity:
const expensiveQuery = `
query {
issues(first: 50) {
nodes {
id
title
assignee { name }
labels { nodes { name } }
comments(first: 10) {
nodes { body user { name } }
}
}
}
}
`;
const cheapQuery = `
query {
issues(first: 50) {
nodes {
id
identifier
title
priority
}
}
}
`;
Step 4: Implement Request Coalescing
class RequestCoalescer {
private pending = new Map<string, Promise<any>>();
async execute<T>(key: string, fn: () => Promise<T>): Promise<T> {
const existing = this.pending.get(key);
if (existing) {
return existing;
}
const promise = fn().finally(() => {
this.pending.delete(key);
});
this.pending.set(key, promise);
return promise;
}
}
const coalescer = new RequestCoalescer();
const [teams1, teams2, teams3] = await Promise.all([
coalescer.execute("teams", () => client.teams()),
coalescer.execute("teams", () => client.()),
coalescer.(, client.()),
]);
Step 5: Webhook Event Filtering
async function shouldProcessEvent(event: any): boolean {
if (event.data?.actor?.isBot) return false;
if (event.type === "Issue" && event.action === "update") {
const importantFields = ["state", "priority", "assignee"];
const changedFields = Object.keys(event.updatedFrom || {});
if (!changedFields.some(f => importantFields.includes(f))) {
return false;
}
}
const allowedTeams = ["ENG", "PROD"];
if (event.data?.team?.key && !allowedTeams.includes(event.data.team.key)) {
return false;
}
;
}
Step 6: Lazy Loading Pattern
class LazyLinearClient {
private client: LinearClient;
private teamsCache: any[] | null = null;
private statesCache = new Map<string, any[]>();
constructor(apiKey: string) {
this.client = new LinearClient({ apiKey });
}
async getTeams() {
if (!this.teamsCache) {
const teams = await this.client.teams();
this.teamsCache = teams.nodes;
}
return this.teamsCache;
}
async getStatesForTeam(teamKey: string) {
if (!this.statesCache.has(teamKey)) {
const teams = await this..({
: { : { : teamKey } },
});
states = teams.[].();
..(teamKey, states.);
}
..(teamKey)!;
}
() {
. = ;
..();
}
}
Cost Reduction Checklist
Monitoring Dashboard
const metrics = {
totalRequests: counter("linear_requests_total"),
requestDuration: histogram("linear_request_duration_seconds"),
complexityCost: histogram("linear_complexity_cost"),
cacheHits: counter("linear_cache_hits_total"),
cacheMisses: counter("linear_cache_misses_total"),
webhooksReceived: counter("linear_webhooks_received_total"),
webhooksFiltered: counter("linear_webhooks_filtered_total"),
};
Resources
Next Steps
Learn production architecture with linear-reference-architecture.