Guide
Manage context with facts and skills
Save business definitions as organization facts and reusable instructions as shared Markdown skills. Create, read, replace, and delete sample context through the SDK.
Workflow
- 1Create an organization-scoped API key with Write access to All Facts and All Skills. Set PERMUTE_API_KEY and PERMUTE_WORKSPACE_ID to an existing workspace in that organization.
- 2Use facts for definitions, aliases, formulas, and baselines. Use organizationSkills for company-wide instructions and skills on a workspace client for workspace instructions (shared skills only).
- 3Read back the saved context. Fact updates replace every editable field, so resend fields you want to keep. Skill updates create or replace a complete Markdown file of at most 2,000 words.
- 4Run the example to verify each replacement. It uses unique names and paths, then deletes its sample context in finally; remove the cleanup block when adapting it to save real business context.
Complete example
import { PermuteClient } from '@permute/sdk';
const orgClient = new PermuteClient({
apiKey: process.env.PERMUTE_API_KEY!,
baseUrl: process.env.PERMUTE_API_BASE_URL, // Optional; defaults to the public API.
});
const client = orgClient.withWorkspace(process.env.PERMUTE_WORKSPACE_ID!);
const sample = crypto.randomUUID();
const path = 'examples/' + sample + '/revenue.md'; // SDK encodes nested paths.
const definition = {
name: 'Sample net revenue ' + sample,
definition: 'Revenue after returns, excluding tax.',
formula: 'gross_revenue - returns',
formulaType: 'math' as const,
};
let factId: string | undefined;
try {
// Facts belong to the organization, regardless of the selected workspace.
const fact = await orgClient.facts.create(definition);
factId = fact.id;
await orgClient.organizationSkills.update(path, {
content: '# Revenue policy\nUse the net revenue fact when reporting revenue.',
});
await client.skills.update(path, {
content: '# Revenue reporting\nGroup net revenue by customer for this workspace.',
});
const facts = await orgClient.facts.list();
const skills = await client.skills.list();
if (!facts.items.some((item) => item.id === factId) ||
!skills.items.some((item) => item.file === path)) {
throw new Error('Saved context is missing from the catalog');
}
console.log(await orgClient.organizationSkills.get(path));
// Resend the complete fact, preserving its definition and formula type.
await orgClient.facts.update(factId, {
...definition,
formula: 'gross_revenue - returns - discounts',
});
const content = '# Revenue reporting\nGroup net revenue by customer and month.';
await client.skills.update(path, { content });
const savedFact = await orgClient.facts.get(factId);
const savedSkill = await client.skills.get(path);
if (savedFact.formula !== 'gross_revenue - returns - discounts' ||
savedSkill.content !== content) {
throw new Error('Context replacement did not match');
}
console.log('Verified fact and skill:', savedFact.id, path);
} finally {
// Delete only the unique sample records created by this example.
await Promise.all([
...(factId ? [orgClient.facts.delete(factId)] : []),
orgClient.organizationSkills.delete(path),
client.skills.delete(path),
]);
}