Custom-host integration: This guide documents a low-level, direct-manifest lazy loader for Jetski/Cortex and similar hosts. For Codex or Claude Code, the recommended path is AAS Core, which provides neutral, deterministic catalog retrieval and validates exact agent-selected IDs through a bounded, read-only MCP server.
This guide shows how to integrate the agentic-awesome-skills repository with an agent based on Jetski/Cortex + Gemini (or similar frameworks) without exceeding the model context window.
The common error seen in Jetski/Cortex is:
TrajectoryChatConverter: could not convert a single message before hitting truncation
The issue is not with the skills themselves, but with how they are loaded.
Never do:
skills/*/SKILL.md directories at startup;SKILL.md content into a single system prompt;With 2,715+ skills, this approach fills the context window before user messages are even added, causing truncation.
Core principles:
skills_index.json to know which skills exist without loading full text.data/skills_index.json as an exact mirror of the canonical manifest.SKILL.md only for skills actually invoked in a conversation (for example, when @skill-id appears).SKILLS_ROOT before reading SKILL.md.schemas/skills-index.v1.schema.json.The recommended flow is:
skills_index.json (and data/skills_index.json if your host expects compatibility reads) and build an id -> meta map.@skill-id references from user/system messages.SkillMeta objects using the bootstrap map.SKILL.md files only for these IDs (up to a configurable maximum).skills_index.jsonThe file skills_index.json is an array of objects, for example:
data/skills_index.jsonis the compatibility mirror and should stay in sync with the canonical root manifest.
{
"id": "brainstorming",
"path": "skills/brainstorming",
"category": "planning",
"name": "brainstorming",
"description": "Use before any creative or constructive work.",
"risk": "safe",
"source": "official",
"date_added": "2026-02-27"
}
Key fields:
id: identifier used in @id mentions (for example, @brainstorming).path: directory containing SKILL.md (for example, skills/brainstorming/).To resolve the path to a skill definition:
fullPath = path.join(SKILLS_ROOT, meta.path, "SKILL.md").Note:
SKILLS_ROOTis the root directory where you installed the repository (for example,~/.agent/skills).
The parser should validate against:
Full example in:
docs/integrations/jetski-gemini-loader/.
type SkillMeta = {
id: string;
path: string;
name: string;
description?: string;
category?: string;
risk?: string;
};
function loadSkillIndex(indexPath: string): Map<string, SkillMeta> {
const raw = fs.readFileSync(indexPath, "utf8");
const arr = JSON.parse(raw) as SkillMeta[];
const map = new Map<string, SkillMeta>();
for (const meta of arr) {
map.set(meta.id, meta);
}
return map;
}
@skill-idconst SKILL_ID_REGEX = /@([a-zA-Z0-9-_./]+)/g;
function resolveSkillsFromMessages(
messages: { role: string; content: string }[],
index: Map<string, SkillMeta>,
maxSkills: number
): SkillMeta[] {
const found = new Set<string>();
for (const msg of messages) {
let match: RegExpExecArray | null;
while ((match = SKILL_ID_REGEX.exec(msg.content)) !== null) {
const id = match[1];
if (index.has(id)) {
found.add(id);
}
}
}
const metas: SkillMeta[] = [];
for (const id of found) {
const meta = index.get(id);
if (meta) metas.push(meta);
if (metas.length >= maxSkills) break;
}
return metas;
}
SKILL.md filesasync function loadSkillBodies(
skillsRoot: string,
metas: SkillMeta[]
): Promise<string[]> {
const bodies: string[] = [];
for (const meta of metas) {
const fullPath = path.join(skillsRoot, meta.path, "SKILL.md");
const text = await fs.promises.readFile(fullPath, "utf8");
bodies.push(text);
}
return bodies;
}
Pseudocode for the pre-processing phase before TrajectoryChatConverter:
async function buildModelMessages(
baseSystemMessages: { role: "system"; content: string }[],
trajectory: { role: "user" | "assistant" | "system"; content: string }[],
skillIndex: Map<string, SkillMeta>,
skillsRoot: string,
maxSkillsPerTurn: number,
overflowBehavior: "truncate" | "error" = "truncate"
): Promise<{ role: string; content: string }[]> {
const referencedSkills = resolveSkillsFromMessages(
trajectory,
skillIndex,
Number.MAX_SAFE_INTEGER
);
if (
overflowBehavior === "error" &&
referencedSkills.length > maxSkillsPerTurn
) {
throw new Error(
`Too many skills requested in a single turn. Reduce @skill-id usage to ${maxSkillsPerTurn} or fewer.`
);
}
const selectedMetas = resolveSkillsFromMessages(
trajectory,
skillIndex,
maxSkillsPerTurn
);
const skillBodies = await loadSkillBodies(skillsRoot, selectedMetas);
const skillMessages = skillBodies.map((body) => ({
role: "system" as const,
content: body,
}));
return [...baseSystemMessages, ...skillMessages, ...trajectory];
}
Tip: Add token estimation to trim or summarize
SKILL.mdfiles when the context window approaches its limit. This repository’s reference loader also supports an explicit fallback:overflowBehavior: "error".
To avoid unclear errors for the user, set:
Strategies when the threshold is exceeded:
“Too many skills were requested in a single turn. Reduce the number of
@skill-idreferences in your message or split them into multiple turns.”
@skill-id → no SKILL.md loaded → prompt remains small → no error.@skill-id references → only related SKILL.md files are loaded → no overflow.@skill-id references → maxSkillsPerTurn or token guardrails trigger → no silent overflow.For additional control:
skills/.disabled/ to exclude them in certain environments;docs/users/bundles.md to load only focused groups.If the host keeps reopening the same corrupted trajectory after a truncation error:
%TEMP%;Complete guide:
To prevent recurrence:
overflowBehavior: "error" when you prefer explicit failure;skillsRoot.SKILL.md files into a single prompt.skills_index.json as the canonical lightweight manifest.@skill-id.Following this pattern, Jetski/Cortex + Gemini can use the full agentic-awesome-skills library safely, at scale, and within modern model context-window limits.