Vertesia Tool Server Resource
Step-by-step guide for creating tool server resources. Each resource follows the same workflow:
- Create files in the appropriate
src/modules/app/resources/<type>/<collection>/directory - Export from the collection's
index.ts - Register the collection in
src/modules/app/resources/<type>/index.ts(only when adding a new collection)
For full code templates of every resource type, see REFERENCE.md.
Conventions
- All imports use
.jsextensions:import { x } from "./foo.js" - Use
satisfiesfor type validation ({} satisfies Tool<T>,{} satisfies InCodeTypeSpec, …) - Icons are SVG strings exported as default from
.tsfiles - Import hooks (
?skill,?skills,?prompt,?template,?templates,?raw) only work in Rollup-compiled tool-server code, not in UI code - Snake_case for resource names (
my_tool,my_type); PascalCase for TypeScript exports (MyTool,MyType) - User-owned resources live in
src/modules/app/resources/<type>/ - See
src/modules/examples/resources/<type>/for working starter code when the examples module is available
Resource types
Tool
Three files in src/modules/app/resources/tools/<collection>/<tool-name>/:
| File | Purpose |
|------|---------|
| schema.ts | TypeScript interface + JSONSchema (satisfies JSONSchema) |
| <impl>.ts | The run function — uses ToolExecutionPayload<P>, returns ToolResultContent |
| index.ts | Tool<P> definition (satisfies Tool<ParamsT>) |
Then export from src/modules/app/resources/tools/<collection>/index.ts as a ToolCollection.
→ Code in REFERENCE.md § Tool.
Skill
Files in src/modules/app/resources/skills/<collection>/<skill-name>/:
| File | Required | Purpose |
|------|----------|---------|
| SKILL.md | yes | YAML frontmatter + instructions for the agent |
| properties.ts | no | Runtime gating (isEnabled) |
| *.tsx | no | Widgets (compiled to dist/widgets/) |
| *.py, *.js | no | Scripts (copied to dist/scripts/) |
Skills are auto-discovered: the collection imports ./all?skills — no per-skill imports needed.
→ Code in REFERENCE.md § Skill.
Interaction
Two flavors:
- Template-based —
prompt.hbs+prompt_schema.ts+result_schema.ts+index.ts(InteractionSpecimporting the prompt via?prompt). - Code-based —
index.tsonly, withprompts: [{ role, content, content_type }, …]inline. Use this for agents/conversations.
Then export from src/modules/app/resources/interactions/<collection>/index.ts as an InteractionCollection.
→ Code in REFERENCE.md § Interaction (template-based) and § Interaction (code-based).
Content Type
One file per type in src/modules/app/resources/types/<collection>/<type-name>.ts (InCodeTypeSpec), then a ContentTypesCollection in types/<collection>/index.ts.
Key fields: name (snake_case), object_schema (JSON Schema with additionalProperties: false), table_layout (columns for the UI), is_chunkable, strict_mode.
→ Code in REFERENCE.md § Content Type.
Rendering Template
Folder per template in src/modules/app/resources/templates/<collection>/<template-name>/:
TEMPLATE.mdwith YAML frontmatter (description,type: 'document' | 'presentation', optionaltitle,tags)- Asset files (SVG, LaTeX, PNG) — auto-discovered, copied to
dist/templates/
Templates are auto-discovered: the collection imports ./all?templates.
→ Code in REFERENCE.md § Rendering Template.
Collection registration
Once a collection is exported from src/modules/app/resources/<type>/<collection>/index.ts, add it to the array in src/modules/app/resources/<type>/index.ts:
// src/modules/app/resources/tools/index.ts
import { MyTools } from "./my-collection/index.js";
export const tools = [MyTools];
src/tool-server/app-server-modules.ts is generated from active modules and config.ts imports from it, so no further server wiring is needed.
Each collection needs an SVG icon.svg.ts (default string export). Code in REFERENCE.md § Collection registration & icons.
Verification
After creating a resource:
pnpm build:serverpnpm start- Check the admin UI at
http://localhost:3000/— your resource should appear. - Or hit the API:
curl http://localhost:3000/api/tools(or/skills,/interactions,/types,/templates).