npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@exellix/ai-skills

v5.8.0

Published

Foundational skill execution layer for exellix ecosystem using @x12i/ai-gateway with FlexMD 2.0 support and Catalox as the catalog store

Readme

@exellix/ai-skills

Foundational skill execution layer for the exellix ecosystem: templates live in the Catalox native catalog ai-skills, execution uses @x12i/ai-gateway, and responses support FlexMD 2.0 structured text.

🚀 Env-Ready: Provider keys can be loaded from .env automatically. catalox is required at construction time (see Quick Start).

Documentation

| Topic | Doc | |--------|-----| | Flex-MD vs gateway parsing, integration tests | docs/FLEX_MD_AND_TESTING.md | | Catalox integration & env notes | docs/CATALOX_PEER_GUIDE.md · Environment (Firebase & Catalox v4) | | Activix integration best practices | .docs/activix-integration-best-practices-checklist.md | | Per-package log level (AI_SKILLS_LOGS_LEVEL) | Logging below and @x12i/logxer on npm | | Gateway templates (v4), invoke() vs invokeChat(), templateRendering | docs/GATEWAY_TEMPLATE_PROTOCOL_V4.md | | This package: workingMemory, templateRenderOptions, client templateRendering | docs/AI_SKILLS_GATEWAY_TEMPLATES.md | | Invoke execution metadata (provider, modelUsed, effectiveModelConfig, …) | docs/AI_GATEWAY_INVOKE_EXECUTION_METADATA.md | | Graph execution context (graphId, nodeId, identity mapping) | docs/GRAPH_EXECUTION_SUPPORT.md | | Gateway invoke preflight (analyzeSkillRequest, FuncX ≥ 4.0.1) | docs/SKILL_REQUEST_ANALYSIS.md | | External follow-ups (Activix persistence vs gateway envelope) | docs/AI_GATEWAY_FEATURE_REQUESTS.md |

Features

  • Unified Skill Runner: Execute skills via metadata, not hardcoded handlers
  • FlexMD 2.0 Output: Always returns structured-text format with parsed payloads
  • Catalox-native templates: Instruction and prompt bodies are read from the Firestore native catalog ai-skills via @x12i/catalox; the gateway receives inline template text (not nx-content registry keys for skills)
  • Provision from disk: npm run catalox:provision-ai-skills merges .metadata/skills/*.instructions.md / *.prompt.md into that catalog and sets planned | draft | published status
  • Presentation API: Load pretty markdown for editors, save with lossless storage normalization (getSkillTemplatesForPresentation, updateSkillTemplatesFromPresentation, getSkillTemplateInputs); see Skill templates (Catalox)
  • Catalog audit fields (storage only): Catalox rows may store optional audit template text for editors; this package only executes runSkill (no built-in audit pass).
  • Gateway integration: @x12i/ai-gateway for LLM calls only; the built-in gateway has enableContentRegistry: false — skill templates are never loaded from nx-content / GitHub in this package
  • Activity tracking: With enableActivityTracking, the gateway persists activities via @x12i/activix; this SDK enriches rows with cost / costStatus and contract-shaped outer.output.parsed when applicable (see Cost and output contract)
  • Model Configuration: Per-request model selection and parameter control (temperature, maxTokens, etc.)
  • Full template pipeline (default): Uses gateway.invoke() with inline bodies; the gateway message builder renders tokens (downstream stack; e.g. Rendrix). runSkill populates workingMemory.input and can pass templateRenderOptions, templateTokens, or client-level templateRendering (see docs/AI_SKILLS_GATEWAY_TEMPLATES.md).
  • Execution engine catalog: Optional aiEngineId echoes the Catalox ai-engines row (ai-gateway only; provision with npm run catalox:provision-ai-engines) for discovery and identity — see Execution engines (aiEngineId).
  • Request analysis (implementation-phase): analyzeSkillRequest simulates the gateway packet and reviews it via FuncX — not chained into runSkill; see docs/SKILL_REQUEST_ANALYSIS.md.

Installation

npm install @exellix/ai-skills

This package depends on @x12i/ai-gateway, @x12i/catalox, @x12i/logxer, @x12i/env, @x12i/rendrix, and firebase-admin (for Firestore-backed Catalox). @x12i/catalox ≥ 4.0 expects Node 20+. Align firebase-admin / @x12i/catalox versions with your app if you share a Firebase app instance.

@x12i/ai-gateway ≥ 9.3.0 is recommended: invoke metadata includes routing fields (≥9.1.1), rejection metadata on failures (≥9.1.2), and normalized billing (costUsd, cost, costStatus: priced | unpriced) on success (≥9.3). See docs/AI_GATEWAY_INVOKE_EXECUTION_METADATA.md. Every runSkill call must include agentId, jobTypeId, and taskTypeId (Activix linkage — no package defaults).

CI: npm run test:ci runs npm run build and npm run test:unit (no live Firestore or real LLM). Full npm test still runs test:integration, which may append live catalog tests when env enables them.

Custom admin flows that call Catalox with createCatalog, bindCatalogToApp, or similar before an app binding exists should set superAdmin: true on CataloxContext (see defaultAiSkillsCataloxContext overrides and docs/CATALOX_PEER_GUIDE.md).

Publishing: the npm tarball is limited to dist/, README.md, and erc-manifest.json via the files field in package.json (avoids shipping tests, logs, or local scratch files).

Environment variables (Firebase & Catalox v4)

createCataloxFromEnv() in this package delegates credential resolution to @x12i/catalox/firebase (same precedence as upstream Catalox v4).

| Variable | Notes | |----------|--------| | FIREBASE_PROJECT_ID | Required for this package’s createCataloxFromEnv() wiring: set it in .env or the process environment. Project id is not inferred from GCLOUD_PROJECT, GOOGLE_CLOUD_PROJECT, or service-account JSON. | | GOOGLE_SERVICE_ACCOUNT_BASE64 | Recommended for CI and scripts: standard Google service account JSON, base64-encoded, passed to Admin cert(...). | | FIRESTORE_DATABASE_ID | Optional named Firestore database id; omit for the default database. |

Not supported in Catalox v4: an environment variable (or secret-token _path field) that points at a service-account JSON file on disk. Use GOOGLE_SERVICE_ACCOUNT_BASE64, Application Default Credentials (workload identity, GOOGLE_APPLICATION_CREDENTIALS, etc.), or load a key file in your application and pass cert(...) / Catalox’s serviceAccountPath bootstrap option (caller-supplied string only).

Provider keys for the default gateway (OPENAI_API_KEY, GROK_API_KEY, OPEN_ROUTER_KEY / OPENROUTER_API_KEY) are unchanged — see Troubleshooting below.

Quick Start

0) Prerequisites

  1. Node.js 20+ — matches @x12i/catalox engine requirements.
  2. Firebase / Firestore — set FIREBASE_PROJECT_ID (see above) and GOOGLE_SERVICE_ACCOUNT_BASE64. createCataloxFromEnv() uses @x12i/catalox/firebase under the hood. You can instead construct Catalox with createCatalox from @x12i/catalox / @x12i/catalox/embedder and your own Firestore instance.
  3. Provision the catalog (merges in-repo .metadata/skills into Catalox):
npm run catalox:provision-ai-skills
npm run catalox:provision-ai-engines
  1. At least one LLM provider key (OPENAI_API_KEY, GROK_API_KEY, or OPEN_ROUTER_KEY / OPENROUTER_API_KEY) for @x12i/ai-gateway.

1) Create the client

import { ExellixSkillsClient, RunSkillRequest, RunSkillResponse, createCataloxFromEnv } from "@exellix/ai-skills";

const catalox = createCataloxFromEnv();

const skills = new ExellixSkillsClient({
  catalox,
  enableActivityTracking: true,
});

You can also construct Catalox yourself (createCatalox from @x12i/catalox or @x12i/catalox/embedder with your firestore / firebaseApp) and pass options.catalox. An external gateway is optional; catalox is always required.

2) Run a skill

// Using the RunSkillRequest interface
const runSkillRequest: RunSkillRequest = {
  skillKey: "skills/professional-answer",
  input: "Question: What is the best way to migrate from X to Y?",
  variables: { orgName: "ACME", audience: "security team" },
  jobId: "job-123",
  taskId: "task-456",
  agentId: "agent-abc",
  jobTypeId: "your-job-type-id",
  taskTypeId: "your-task-type-id",
};

const res: RunSkillResponse = await skills.runSkill(runSkillRequest);

// Access FlexMD payloads
console.log(res.flexMd.payloads.shortAnswer);
console.log(res.flexMd.payloads.fullAnswer);

2b) Execution engines (aiEngineId)

runSkill always invokes @x12i/ai-gateway with inline Catalox template text; Rendrix runs inside the gateway. Optional aiEngineId must be omitted, blank, or ai-gateway — it is merged into gateway.invoke identity and matches the single row in the Catalox ai-engines catalog (provisioned for listing / UIs). Unknown values throw at resolve time.

2a) Run a skill with model configuration

// Override model and generation parameters per-request
const res = await skills.runSkill({
  skillKey: "skills/professional-answer",
  input: "Question: What is the best way to migrate from X to Y?",
  variables: { orgName: "ACME" },
  jobId: "job-123",
  taskId: "task-456",
  agentId: "agent-abc",
  jobTypeId: "your-job-type-id",
  taskTypeId: "your-task-type-id",
  modelConfig: {
    model: "gpt-4-turbo",
    temperature: 0.7,
    maxTokens: 2000,
    topP: 0.9
  }
});

2b) Optional: parser / template overrides

Per skill run you can pass templateRenderOptions (merged on gateway defaults) and templateTokens (highest-priority overlay). On the client, templateRendering sets defaults for every invoke. Details and examples: docs/AI_SKILLS_GATEWAY_TEMPLATES.md.

2c) Optional: identity propagation

identity is per-request runtime context from your application (trace ids, tenant, graph/node ids, etc.). It is not the SDK client’s constructor options, not env/config for this package, and not “package identity” from package.json—unless you explicitly copy such values into this object when you build the request.

identity vs runContext: The gateway invoke() API uses the property name identity (see @x12i/ai-gateway). Activix stores that same envelope on activity documents as BSON runContext. This SDK passes identity through to the gateway; you do not set runContext on runSkill inputs here. Responses expose the envelope as identity when the gateway returns it (and resolution may also consider metadata shapes that use runContext).

You can pass an identity object to runSkill() to propagate caller identity context downstream.

  • If you provide identity, the client forwards it as-is to the gateway.
  • The client will add identity.skillId from the executing request only if it is missing.
  • The RunSkillResponse includes identity only if downstream returns one. If downstream does not provide identity, it will be omitted (no fallback).
const res = await skills.runSkill({
  skillKey: "skills/professional-answer",
  input: "Question: ...",
  jobId: "job-123",
  taskId: "task-456",
  agentId: "agent-abc",
  jobTypeId: "your-job-type-id",
  taskTypeId: "your-task-type-id",
  skillId: "node-q0",
  identity: {
    traceId: "trace-123",
    userId: "user-456"
    // skillId is optional here; if omitted, it will be set from `skillId` above
  }
});

// Only present when downstream returned it:
console.log(res.identity);

// Token usage + cost (from gateway metadata); always on metadata.usage for every run.
// costUsd when priced; costStatus when usage exists but no price ("unpriced") or async pricing ("deferred").
console.log(res.metadata.usage, res.metadata.costUsd, res.metadata.costStatus, res.metadata.modelUsed);

// When `identity` is returned, the same snapshot is nested under `identity.aiSkillsLlm` for Activix-style
// chaining—forward the whole `identity` to the next `runSkill` so pipelines retain billing context.
console.log(res.identity?.aiSkillsLlm);

3) Max output tokens (maxTokens), modelConfig, and trace visibility

This SDK does not compute or default maxTokens. If you set runSkill({ modelConfig: { maxTokens: N } }), that object is forwarded verbatim on gateway.invoke({ modelConfig }) (same for temperature, model, provider-specific fields, etc.). If you omit modelConfig or omit maxTokens, the effective cap comes from @x12i/ai-gateway / the provider (see docs/AI_GATEWAY_FEATURE_REQUESTS.md for documenting defaults upstream).

Dynamic per call: compute limits in your orchestrator and pass a fresh modelConfig every invoke; nothing in this package caches values between calls.

| What you need | Where it appears | |---------------|------------------| | What you sent (modelConfig, timeoutMs) | Trace-only: debugTrace.invokeRequest when executionMode: "trace" or diagnostics.includeDebugTrace | | Requested / echoed cap | debugTrace.usage.maxTokensRequested (from your modelConfig.maxTokens when set; may align with gateway metadata when present) | | What ran (model id, token counts) | debugTrace.modelUsed, debugTrace.usage, routing ids |

const budget = estimateMaxOutputTokens(someContext); // your policy

const res = await skills.runSkill({
  skillKey: "skills/professional-answer",
  input: "Question: ...",
  jobId: "job-1",
  taskId: "task-1",
  modelConfig: {
    maxTokens: budget,
    temperature: 0.5,
    model: "gpt-4-turbo",
  },
  executionMode: "trace",
});

console.log(res.debugTrace?.invokeRequest?.modelConfig?.maxTokens);
console.log(res.debugTrace?.usage.maxTokensRequested);

On gateway failures with trace mode enabled, SkillExecutionTraceError carries diagnostics.trace with the same shapes where available; metadata attached on the thrown error is merged when present (see metadataFromInvokeError export).

Cost and output contract (Run Analysis)

Studio / graph Run Analysis expects activities and responses to explain billing and structured output. This package normalizes both on every successful runSkill and best-effort patches the persisted Activix row when metadata.activityId is present.

Cost reporting (metadata.costUsd / metadata.costStatus)

Gateway invoke() metadata (≥ 9.3) uses costUsd / cost when priced and costStatus: "priced" | "unpriced". This SDK never echoes gateway "priced" — priced runs expose costUsd only. When usage exists but no USD total is known, costStatus: "unpriced" is set (gateway explicit flag or SDK fallback).

| Gateway / router situation | Gateway metadata | On RunSkillResponse.metadata | Activix record (gateway completeRecord + SDK patch) | |----------------------------|-------------------|-------------------------------|------------------------------------------------------| | Priced (router, catalog, or ai-tools) | costUsd, cost, costStatus: "priced" | costUsd (no costStatus) | Top-level cost, costStatus: "priced", outer.metadata billing slice, outer.cost.usd | | Usage, no price | costStatus: "unpriced" | costStatus: "unpriced" | costStatus: "unpriced" + token usage on outer.metadata / response.metadata | | Legacy async pricing | costStatus: "deferred" (older gateways) | costStatus: "deferred" | same |

Gateway logSuccess writes billing on the activity row during invoke() when enableActivityTracking is on (default). patchActivixActivityAfterSkill then merges the same billing slice plus outputContract parsed fields so Run Analysis and Activix queries stay aligned with RunSkillResponse.metadata.

metadata.usage is always populated (zeros when the gateway omits token fields). The same billing slice is mirrored on identity.aiSkillsLlm when the gateway returns identity, and on debugTrace in trace mode.

Output contract (outputContract)

outputContract is per invoke, not a global list for all skills. Pass the field names your graph node or skill expects on parsed / outer.output.parsed — typically from graph inputs.outputContract (via @exellix/ai-tasks / graph-engine).

Supported shapes: string[], { fields: string[] }, { keys: string[] }, or { required: string[] }.

After FlexMD / gateway parsing (and local parseFlexMd fallback), the SDK fills missing contract keys from:

  1. flexMd.payloads
  2. Markdown section headings (### Short AnswershortAnswer)

Examples (illustrative — use the contract for that skill/node):

// professional-answer–style skill
await skills.runSkill({
  skillKey: "skills/professional-answer",
  outputContract: ["shortAnswer", "fullAnswer", "assumptions", "unknowns", "evidence"],
  // ...jobId, taskId, agentId, jobTypeId, taskTypeId, input, ...
});

// professional-decision–style skill
await skills.runSkill({
  skillKey: "skills/professional-decision",
  outputContract: ["decision", "score", "rationale", "risks"],
  // ...
});

This package does not auto-map skillKey to a catalog contract; upstream must pass outputContract when structured fields are required. Catalog payload names are documented in docs/metadata.md (requiredPayloads per skill).

Exports (for orchestrators and tests): normalizeSkillBillingFromGatewayMetadata, enrichParsedForOutputContract, patchActivixActivityAfterSkill, types SkillCostStatus, OutputContract.

Built-in skills (catalog)

Authoritative rows are defined in code as AI_SKILLS_CATALOG_ITEMS and written to Catalox by npm run catalox:provision-ai-skills. Typical runnable keys:

  • skills/professional-answer — structured professional answer (FlexMD payloads)
  • skills/professional-decision — structured decision output
  • Additional catalog rows exist for other packaged skills; use listCatalogSkills() (all statuses), listPublishedSkills() (published only), or Catalox listCatalogItems for the live list.

runSkill takes skillKey like skills/professional-answer. Bodies are not resolved as nx-content registry keys for execution; they are loaded from Catalox and sent to the gateway as inline template strings.

Skill templates (Catalox)

Provisioning (disk → Firestore)

Keep canonical markdown under .metadata/skills/<id>.instructions.md and .metadata/skills/<id>.prompt.md, then run:

npm run catalox:provision-ai-skills

That merges file contents into the native catalog ai-skills, sets instructionsText / promptText, and computes status: planned | draft | published (runnable when both bodies exist and status is draft or published).

Presentation layer (read / edit)

Low-level helpers live under @exellix/ai-skills exports from ./catalox (e.g. normalizeForStorage, toPresentationMarkdown, extractTemplateTokensFromTexts).

On ExellixSkillsClient:

| Method | Purpose | |--------|---------| | getSkillTemplatesForPresentation(skillKey, { includeAudit? }) | Catalox read → markdown formatted for editors | | updateSkillTemplatesFromPresentation(skillKey, patch, options?) | Editor markdown → lossless storage normalization → Catalox upsert (requires write Catalox context) | | getSkillTemplateInputs(skillKey) | Union of {{token}} placeholders from raw stored bodies; treats input as the primary payload token | | listCatalogSkills(options?) | Lists every catalog row (all status values); forwards Catalox query options (e.g. limit) | | upsertSkillCatalogItem(input, options?) | Create/update full row (metadata + optional markdown); optional ifNotExists for strict create | | softDeleteSkillCatalogItem(skillKey) | Clears bodies and audit fields and sets planned (no hard delete) |

Write access: updates use batchUpsertNativeCatalogItems; use a Catalox context with permission to write the catalog (e.g. provision-style god mode or an app binding with write). This package does not create credentials.

Skill key usage

await skills.runSkill({
  skillKey: "skills/professional-answer",
  input: "Your question here...",
});

Catalox item ids are the short key (e.g. professional-answer); the client accepts either skills/professional-answer or the short id where helpers normalize.

Troubleshooting

options.catalox is required

Pass catalox into new ExellixSkillsClient({ catalox, ... }). Use createCataloxFromEnv() from this package, createCataloxFromEnv() from @x12i/catalox/firebase, or createCatalox({ firestore, firebaseApp }) from @x12i/catalox / @x12i/catalox/embedder.

❌ Skill is planned or “incomplete templates”

Run npm run catalox:provision-ai-skills (or write bodies via updateSkillTemplatesFromPresentation) so instructionsText and promptText are non-empty and status is draft or published.

❌ Provider / env validation

At least one of OPENAI_API_KEY, GROK_API_KEY, OPEN_ROUTER_KEY, OPENROUTER_API_KEY is required when the client builds the default gateway. Firebase / Catalox variables are summarized above.

Logging (ai-skills / @x12i/logxer)

This package uses @x12i/logxer with a stable env prefix AI_SKILLS.

| Item | Detail | |------|--------| | Canonical env var | AI_SKILLS_LOGS_LEVEL | | Fallback | AI_SKILLS_LOG_LEVEL is used only if AI_SKILLS_LOGS_LEVEL is unset | | Default (both unset) | warn — not silent; you will see warnings and errors | | Silence this package | Set AI_SKILLS_LOGS_LEVEL=off (or none / silent) | | More detail | info, debug, or verbose (case-insensitive; see @x12i/logxer docs) |

Cross-cutting sinks (console, file, JSON, unified app config) are configured by the host app, not per this prefix — see the @x12i/logxer README.

.env: with default autoLoadDotenv, the client loads .env from the current working directory using loadDotenv from @x12i/env.

# Examples
export AI_SKILLS_LOGS_LEVEL=info
export AI_SKILLS_LOGS_LEVEL=debug
export AI_SKILLS_LOGS_LEVEL=off

ExellixSkillsClient passes packageName into the logger (default "AI-SKILLS"); that label appears in log metadata alongside the [AI-SKILLS] message prefix.

Testing (integration + templates)

This repo is ESM ("type": "module"). Use the npm scripts below (they run via tsx for .ts entrypoints).

Default test gate (npm test): npm run build then npm run test:integration (may append live catalog tests when env enables them). npm run test:ci runs npm run build and npm run test:unit (mocked gateway / no Firestore / no LLM).

npm test                       # build + integration harness (see run.ts)
npm run test:ci                # build + deterministic unit slice (CI-safe)
npm run test:unit              # same unit slice as test:ci (without build)
npm run test:integration       # full integration harness (run.ts)
npm run catalox:provision-ai-skills   # merge .metadata/skills → Firestore (before live tests)
npm run catalox:provision-ai-engines  # merge in-repo engine rows → native `ai-engines` (before engine catalog live test)
npm run live:professional-answer      # smoke: professional-answer via Catalox + default gateway LLM
npm run test:real              # extra real LLM scenarios; needs .env + valid Firebase credentials

Live tests (opt-in, test/run.ts)

Some cases use real Catalox (Firestore-backed catalog) and the same integration slice can invoke real LLM calls when provider keys are set. They are off by default so CI does not require a provisioned Firebase project.

Set AI_SKILLS_LIVE_TESTS=1 (or true / yes / on) before npm run test:integration to append the live cases registered in test/run.ts:

  • Catalox ai-skills list — read-only Firestore list sanity check.
  • Catalox ai-engines list — verifies npm run catalox:provision-ai-engines wrote the ai-gateway row (read-only).
  • Skill template presentation — read-only Catalox + presentation helpers.

Why not in @x12i/catalox: only this package’s test harness reads AI_SKILLS_LIVE_TESTS; Catalox does not gate downstream CI.

Optionally run npm run test:real before a major release (broader LLM + client scenarios; needs Firebase + provider keys in .env).

Flex-MD log noise (extractJsonFromFlexMd / require(...) is not a function): that path lives in @x12i/ai-gateway, not in this package’s parseFlexMd. See docs/FLEX_MD_AND_TESTING.md for the split of responsibilities and acceptance notes.

Model Configuration

You can control which model is used and how it generates responses on a per-request basis using the modelConfig field.

Model Configuration Options

interface ModelConfig {
  /** Model identifier (e.g., "gpt-4-turbo", "claude-3-opus", "gpt-3.5-turbo") */
  model?: string;
  
  /** Model ID (alternative to model name, for provider-specific model IDs) */
  modelId?: string;
  
  /** Provider name (e.g., "openai", "anthropic") */
  provider?: string;
  
  /** Temperature for generation (0.0 to 2.0) - controls randomness */
  temperature?: number;
  
  /** Maximum tokens to generate */
  maxTokens?: number;
  
  /** Top-p (nucleus) sampling parameter (0.0 to 1.0) */
  topP?: number;
  
  /** Frequency penalty (-2.0 to 2.0) */
  frequencyPenalty?: number;
  
  /** Presence penalty (-2.0 to 2.0) */
  presencePenalty?: number;
  
  /** Stop sequences (array of strings) */
  stop?: string[];
  
  /** Additional provider-specific parameters */
  [key: string]: any;
}

Usage Examples

Basic Model Selection

const res = await skills.runSkill({
  skillKey: "skills/professional-answer",
  input: "Your question here",
  modelConfig: {
    model: "gpt-4-turbo"
  }
});

Full Model Configuration

const res = await skills.runSkill({
  skillKey: "skills/professional-answer",
  input: "Your question here",
  modelConfig: {
    model: "gpt-4-turbo",
    temperature: 0.7,
    maxTokens: 2000,
    topP: 0.9,
    frequencyPenalty: 0.5
  }
});

Provider Override

const res = await skills.runSkill({
  skillKey: "skills/professional-answer",
  input: "Your question here",
  modelConfig: {
    provider: "anthropic",
    model: "claude-3-opus",
    temperature: 0.3
  }
});

Dynamic maxTokens per invoke

function maxTokensForStep(step: "summary" | "detail") {
  return step === "summary" ? 800 : 4000;
}

const res = await skills.runSkill({
  skillKey: "skills/professional-answer",
  input: "Your question here",
  jobId: "job-1",
  taskId: "task-1",
  modelConfig: {
    maxTokens: maxTokensForStep("detail"),
    temperature: 0.5,
  },
});

Notes

  • modelConfig is optional. If omitted, gateway/router defaults apply for each field.
  • This package does not merge a global default modelConfig at construction time; only templateRendering has client-wide defaults for template rendering.
  • The gateway and provider enforce valid ranges (e.g. temperature).

API Reference

ExellixSkillsClient

Constructor options (essential)

import type { Catalox } from "@x12i/catalox";
import type { TemplateRenderOptions } from "@x12i/ai-gateway";

interface ExellixSkillsClientOptions {
  /** Required. Skill bodies are read from the native `ai-skills` catalog. */
  catalox: Catalox;
  /** Optional; defaults to catalog app id `ai-skills`. */
  cataloxAppId?: string;

  packageName?: string;
  enableActivityTracking?: boolean;
  /** Optional external gateway; skill templates still load from `catalox`. */
  gateway?: AIGateway;

  forceLocal?: boolean;
  forceCreateRootDirectory?: boolean;
  templateRendering?: TemplateRenderOptions;
  autoLoadDotenv?: boolean;
  testMode?: boolean;
  disableActivityTrackingInTests?: boolean;
}

The built-in AIGateway uses enableContentRegistry: false; GITHUB_* is not required for ExellixSkillsClient initialization.

Methods

  • runSkill<T>(input: RunSkillRequest): Promise<RunSkillResponse<T>> — loads templates from Catalox, invokes gateway with inline bodies. Optional outputContract enriches parsed and the Activix activity row (see Cost and output contract).
  • getSkillTemplatesForPresentation(skillKey, opts?) — editor-oriented markdown + metadata.
  • updateSkillTemplatesFromPresentation(skillKey, patch, opts?) — save edited markdown (lossless storage normalization); requires Catalox write context.
  • getSkillTemplateInputs(skillKey){{token}} discovery from stored bodies.
  • listPublishedSkills(options?) — Catalox rows with status === "published".
  • listCatalogSkills(options?) — all catalog rows (any status); optional Catalox list query options.
  • upsertSkillCatalogItem(input, options?) — create/update catalog metadata and template bodies; options.ifNotExists enforces create-only.
  • softDeleteSkillCatalogItem(skillKey) — clears template and audit text and sets planned.

Template bodies are loaded only through runSkill (and the same Catalox fetch used there): pass skillKey; there is no separate “peek at one section string” API.

Diagnostic methods (gateway)

  • testContentRegistryConnection(), discoverContentStructure(), diagnoseSkillContent, listAvailableContent, runContentRegistryDiagnostics — forwarded to AIGateway. With the default gateway, nx-content is disabled; these calls are mainly useful if you inject a custom gateway with its own content registry.

For {{token}} discovery on stored bodies without invoking the LLM, use getSkillTemplateInputs(skillKey) (Catalox read + parse).

FlexMD 2.0 Format

Primary skills are designed around structured markdown (headings and/or Flex-MD style markers). A common explicit shape is:

[[professional-answer]]

@payload:shortAnswer
Brief answer here...

@payload:fullAnswer
Detailed answer here...

@payload:assumptions
List of assumptions...

The gateway normalizes responses with its own Flex-MD extraction. When it does not return parsed fields, this SDK uses parseFlexMd (src/utils/flex-md-parser.ts), which prefers the flex-md package via ESM import() and falls back to parsing [[frame:...]] + @payload: blocks.

When you pass outputContract, the SDK also maps markdown ### Section headings to camelCase keys (e.g. ### Full AnswerfullAnswer) so professional-answer templates that use headings still populate parsed even without @payload: markers. See Cost and output contract.

Details and caveats: docs/FLEX_MD_AND_TESTING.md.

Requirements

  • Node.js 20+ (see package.json engines; aligns with @x12i/catalox)
  • @x12i/catalox ≥ 4 and Firebase access for the ai-skills native catalog (see createCataloxFromEnv and Environment (Firebase & Catalox v4))
  • @x12i/ai-gateway (see package.json for the supported range)
  • @x12i/activix (version aligned with @x12i/ai-gateway in package.json) when you rely on activity tracking
  • At least one LLM provider key when using the default constructed gateway
  • Optional: .metadata/skills on disk to feed npm run catalox:provision-ai-skills

Related runtime packages

Task and graph orchestration live in sibling packages, not in @exellix/ai-skills:

  • @exellix/ai-tasks — task orchestration and task-level runtime wiring
  • @exellix/graph-engine — graph execution and graph-level runtime wiring; forward each node’s inputs.outputContract on runSkill when Run Analysis or downstream validation require structured parsed fields
  • @exellix/exellix-runtime — root runtime composition (for example loading composed runtimeObjects for debug tooling)

Older scopes such as @woroces/*, worox, worex, and graph packages named worox-graph / worex-graphs are not used here; there are no intentional aliases or compatibility shims for those names in this repository.

License

ISC