Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.svantic.com/llms.txt

Use this file to discover all available pages before exploring further.

Generate Tools from TypeScript Source Code

You have existing TypeScript functions and you want to turn them into agent capabilities without rewriting anything. Forge scans your source files, reads the exported function signatures and JSDoc comments, and generates tool specs and runnable capability code automatically. This walkthrough uses a billing module as the running example.

Prerequisites

  • TypeScript source files with exported functions
  • JSDoc comments on the functions you want to expose (recommended but not strictly required)
  • The Svantic CLI installed (npm install -g @svantic/cli)

Step 1: Write Your Functions

Forge works best with exported functions that have JSDoc annotations. Here is a typical billing module:
// src/billing.ts

/**
 * Charge a customer's payment method.
 * @param customer_id - The unique customer identifier.
 * @param amount_cents - Amount to charge in cents.
 * @param currency - ISO 4217 currency code (default: "usd").
 * @returns The charge object with id, status, and amount.
 */
export async function charge(
  customer_id: string,
  amount_cents: number,
  currency: string = 'usd',
): Promise<{ id: string; status: string; amount: number }> {
  // your implementation
}

/**
 * Refund a previous charge, fully or partially.
 * @param charge_id - The ID of the charge to refund.
 * @param amount_cents - Amount to refund in cents. Omit for a full refund.
 */
export async function refund(
  charge_id: string,
  amount_cents?: number,
): Promise<{ id: string; status: string }> {
  // your implementation
}

/**
 * List all charges for a customer within a date range.
 * @param customer_id - The customer to query.
 * @param from_date - Start of range (ISO 8601).
 * @param to_date - End of range (ISO 8601).
 */
export async function list_charges(
  customer_id: string,
  from_date: string,
  to_date: string,
): Promise<Array<{ id: string; amount: number; status: string; created_at: string }>> {
  // your implementation
}

// Not exported -- Forge ignores this
function validate_amount(cents: number): boolean {
  return cents > 0;
}

Step 2: Scan the File

svantic forge tool --scan src/billing.ts
Output:
Scanned src/billing.ts — found 3 exported functions:

  charge          (customer_id, amount_cents, currency?)
  refund          (charge_id, amount_cents?)
  list_charges    (customer_id, from_date, to_date)

Run with --pick to select specific functions, or omit to generate all.

Step 3: Generate Tools

Generate all functions:
svantic forge tool --scan src/billing.ts --out ./tools/
Or pick specific ones:
svantic forge tool --scan src/billing.ts --pick charge,refund --out ./tools/
This produces:
FileContents
billing.tool-spec.yamlThe intermediate Tool Spec YAML
billing.capabilities.tsCapability wrappers that call your original functions

Step 4: Review the Generated Code

The generated capabilities delegate to your original functions:
import { define_tool } from '@svantic/sdk/forge';
import { charge as charge_impl } from '../src/billing';

export const charge = define_tool({
  name: 'charge',
  description: 'Charge a customer\'s payment method.',
  parameters: {
    type: 'object',
    properties: {
      customer_id: { type: 'string', description: 'The unique customer identifier' },
      amount_cents: { type: 'number', description: 'Amount to charge in cents' },
      currency: { type: 'string', description: 'ISO 4217 currency code (default: "usd")' },
    },
    required: ['customer_id', 'amount_cents'],
  },
  execute: async (params) => {
    return await charge_impl(
      params.customer_id,
      params.amount_cents,
      params.currency,
    );
  },
});

How JSDoc Becomes LLM Descriptions

Forge maps your JSDoc annotations directly to tool and parameter descriptions:
JSDoc ElementMaps To
Function-level commentdescription field on the tool
@param name - textdescription on the matching parameter property
@returns textAppended to the tool description as “Returns: …”
@default valuedefault field on the parameter
@exampleIgnored (not included in tool spec)
If a function has no JSDoc, Forge generates a description from the function name (charge becomes "Invoke the charge function"). This works but produces weaker LLM tool selection — add real descriptions whenever possible.

Type Mapping

Forge infers JSON Schema types from your TypeScript signatures:
TypeScript TypeJSON Schema Type
string{ type: 'string' }
number{ type: 'number' }
boolean{ type: 'boolean' }
string[], Array<string>{ type: 'array', items: { type: 'string' } }
{ key: string } (inline object){ type: 'object', properties: { key: { type: 'string' } } }
Named interface/type aliasResolved and inlined as { type: 'object', properties: {...} }
T | undefined, T?Property is omitted from required
Literal union 'a' | 'b'{ type: 'string', enum: ['a', 'b'] }
Record<string, T>{ type: 'object', additionalProperties: { type: ... } }
unknown, any{ type: 'string', description: 'JSON-encoded value' }
Complex or deeply nested generics may not resolve cleanly. In those cases, Forge emits a warning and falls back to { type: 'string' }. Simplify the signature or add a @param override.

Programmatic Usage

import { scan_file, list_functions } from '@svantic/sdk/forge';

const functions = await list_functions('./src/billing.ts');
console.log(functions);
// [
//   { name: 'charge', params: ['customer_id', 'amount_cents', 'currency?'] },
//   { name: 'refund', params: ['charge_id', 'amount_cents?'] },
//   { name: 'list_charges', params: ['customer_id', 'from_date', 'to_date'] },
// ]

const result = await scan_file({
  file_path: './src/billing.ts',
  pick: ['charge', 'refund'],
  output_dir: './tools/',
});

console.log(result.tool_spec);    // Parsed YAML object
console.log(result.capabilities); // Array of generated tool definitions

Scanning Multiple Files

Pass multiple --scan flags or use a glob:
svantic forge tool --scan src/billing.ts --scan src/inventory.ts --out ./tools/

svantic forge tool --scan "src/**/*.ts" --out ./tools/
Each file produces its own .tool-spec.yaml and .capabilities.ts pair. Combine them later with svantic forge agent (see Composing Agents).

Handling Classes

Forge scans exported class methods as well as standalone functions. Each public method becomes a separate tool, prefixed with the class name:
export class Billing {
  /** Charge a customer. */
  async charge(customer_id: string, amount: number) { /* ... */ }

  /** Refund a charge. */
  async refund(charge_id: string) { /* ... */ }
}
Generated tool names: billing_charge, billing_refund. Private and protected methods are skipped. Static methods are included.

Updating After Code Changes

Re-run the scan command after modifying your source files. Forge regenerates the Tool Spec and capabilities, overwriting previous output. Any manual edits in *.custom.ts files in the output directory are preserved.