Testing Locally

Test your Trik before publishing to ensure it works correctly.

Quick Start: Three Ways to Test

You don’t need to publish your trik to test it. Three options:

  1. Local playground (recommended) — Add your trik’s path to the playground’s .trikhub/config.json and run the interactive chat. See Using the Local Playground below.

  2. Scaffold a test agent — Run trik create-agent ts (or py) to generate a minimal agent project. Add your local trik path to its .trikhub/config.json.

  3. Run standalone — Your trik is a LangGraph codebase. Import and invoke it directly in a test script without any gateway.

Build First

Compile your TypeScript to JavaScript:

npm run build # or npx tsc

Ensure your entry.module path points to the compiled output:

{ "entry": { "module": "./dist/index.js", "export": "agent" } }

The dist/ directory must exist with valid JavaScript before the gateway can load your trik.

Manual Testing

The local playground provides an interactive chat environment with full gateway integration. This is the best way to test your trik end-to-end.

  1. Navigate to the playground:
cd examples/js/local-playground npm install
  1. Add your trik to .trikhub/config.json:
{ "triks": [ { "id": "yourname/my-trik", "path": "/absolute/path/to/your/trik" } ] }
  1. Set any required config values:
trik config set yourname/my-trik ANTHROPIC_API_KEY sk-ant-...
  1. Run the playground:
npm run dev
  1. Test your trik in conversation:
You: Search for articles about machine learning Assistant: [Hands off to article-search agent] Article Search: I found 3 articles about machine learning... You: Show me the first one Article Search: [Displays article content] You: /back Assistant: [Returns to main agent]

For tool-mode triks, the tools appear directly on the main agent — no handoff happens:

You: Compute the SHA-256 hash of "hello world" Assistant: The SHA-256 hash of "hello world" is b94d27b9934d3e08...

Unit Testing

Conversational Mode

Import your agent and call processMessage() directly:

// agent.test.ts import { describe, it, expect } from 'vitest'; import { agent } from './src/index'; // Mock context const mockContext = { sessionId: 'test-session-1', config: { get: (key: string) => { if (key === 'ANTHROPIC_API_KEY') return process.env.ANTHROPIC_API_KEY; return undefined; }, has: (key: string) => key === 'ANTHROPIC_API_KEY', keys: () => ['ANTHROPIC_API_KEY'], }, storage: { get: async () => null, set: async () => {}, delete: async () => false, list: async () => [], getMany: async () => new Map(), setMany: async () => {}, }, }; describe('article-search agent', () => { it('responds to a search query', async () => { const response = await agent.processMessage!( 'Find articles about AI', mockContext ); expect(response.message).toBeTruthy(); expect(response.message.length).toBeGreaterThan(0); // The agent should not transfer back on a valid query expect(response.transferBack).toBe(false); }); it('transfers back for out-of-domain requests', async () => { const response = await agent.processMessage!( 'What is the weather like today?', mockContext ); expect(response.transferBack).toBe(true); }); });

Run tests:

npx vitest

Tool Mode

Import your agent and call executeTool() directly:

// tools.test.ts import { describe, it, expect } from 'vitest'; import { agent } from './src/index'; const mockContext = { sessionId: 'test-session-1', config: { get: () => undefined, has: () => false, keys: () => [], }, storage: { get: async () => null, set: async () => {}, delete: async () => false, list: async () => [], getMany: async () => new Map(), setMany: async () => {}, }, }; describe('hash-utils tools', () => { it('computes a SHA-256 hash', async () => { const result = await agent.executeTool!( 'computeHash', { text: 'hello world', algorithm: 'sha256' }, mockContext ); expect(result.output.hash).toBe( 'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9' ); expect(result.output.algorithm).toBe('sha256'); expect(result.output.inputLength).toBe(11); }); it('throws for unknown tool', async () => { await expect( agent.executeTool!('nonexistent', {}, mockContext) ).rejects.toThrow('Unknown tool "nonexistent"'); }); });

Integration Testing

Using the Gateway

For integration tests, use the gateway’s routeMessage() to test the full routing lifecycle:

// integration.test.ts import { describe, it, expect } from 'vitest'; import { TrikGateway } from '@trikhub/gateway'; describe('gateway integration', () => { let gateway: TrikGateway; beforeAll(async () => { gateway = new TrikGateway(); await gateway.initialize(); await gateway.loadTrik('./'); }); it('loads the trik successfully', () => { const loaded = gateway.getLoadedTriks(); expect(loaded).toContain('yourname/my-trik'); }); it('generates handoff tools for conversational triks', () => { const tools = gateway.getHandoffTools(); expect(tools.length).toBeGreaterThan(0); expect(tools[0].name).toContain('talk_to_'); }); it('generates exposed tools for tool-mode triks', () => { const tools = gateway.getExposedTools(); expect(tools.length).toBeGreaterThan(0); }); });

Using the LangChain Adapter

For end-to-end testing with a real LLM:

import { describe, it, expect } from 'vitest'; import { ChatAnthropic } from '@langchain/anthropic'; import { createReactAgent } from '@langchain/langgraph/prebuilt'; import { enhance } from '@trikhub/gateway/langchain'; describe('end-to-end with enhance()', () => { it('handles handoff to conversational trik', async () => { const model = new ChatAnthropic({ model: 'claude-sonnet-4-6' }); const app = await enhance(null, { createAgent: (trikTools) => createReactAgent({ llm: model, tools: trikTools }), config: { configPath: './.trikhub/config.json' }, debug: true, }); const response = await app.processMessage('Find articles about AI'); expect(response.source).not.toBe('main'); // Should hand off expect(response.message).toBeTruthy(); }); });

Schema Validation

Test that tool-mode outputs match your declared schemas:

import Ajv from 'ajv'; import manifest from './manifest.json'; import { agent } from './src/index'; const ajv = new Ajv(); describe('schema validation', () => { it('computeHash output matches outputSchema', async () => { const result = await agent.executeTool!( 'computeHash', { text: 'test', algorithm: 'sha256' }, mockContext ); const validate = ajv.compile(manifest.tools.computeHash.outputSchema); const valid = validate(result.output); expect(valid).toBe(true); if (!valid) console.log(validate.errors); }); });

Testing Checklist

Before publishing, verify:

  • trik lint . passes with no errors
  • Conversational: handoff works (main agent routes to your trik)
  • Conversational: transfer-back fires when the user’s request is out of domain
  • Conversational: multi-turn conversation works within a session
  • Tool mode: each tool handler returns output matching outputSchema
  • Tool mode: outputTemplate renders correctly with actual output values
  • Error cases return appropriate responses (not unhandled exceptions)
  • Config values are accessed correctly via context.config.get()
  • No sensitive data leaks into agent-visible outputs
  • dist/ directory is built and up to date

Debugging Tips

Enable Debug Logging

When using the LangChain adapter, enable debug mode to see handoff routing:

const app = await enhance(null, { createAgent: (trikTools) => createReactAgent({ llm: model, tools: trikTools }), debug: true, // Logs handoff events verbose: true, // Also dumps full message history });

Debug output appears with [trikhub] prefix, verbose output with [trikhub:verbose].

Add Console Logging

In your agent’s tools or handlers, use logging for debugging:

// In a conversational tool const searchTool = tool(async ({ topic }) => { console.log('Searching for:', topic); const results = await searchDatabase(topic); console.log('Found results:', results.length); return JSON.stringify({ count: results.length, results }); }, { name: 'search', description: 'Search articles', schema: z.object({ topic: z.string() }) }); // In a tool-mode handler async computeHash(input: Record<string, unknown>, context: TrikContext) { console.log('computeHash called with:', input); const { text, algorithm } = input as { text: string; algorithm: string }; const hash = createHash(algorithm).update(text).digest('hex'); console.log('Hash result:', hash); return { hash, algorithm, inputLength: text.length }; }

Check Manifest Validity

If your trik fails to load, start by validating the manifest:

trik lint .

Common issues:

  • Missing handoffDescription for conversational mode
  • Missing outputTemplate for tool-mode tools
  • entry.module pointing to a file that doesn’t exist
  • schemaVersion not set to 2

Next: Publish your trik to the registry.