Recipe: Scaffolding with @agentskit/templates
Generate a build-ready AgentsKit package skeleton — tool, skill, adapter, embedder, memory, browser-adapter, or flow — in a few lines of Node.
@agentskit/templates is the programmatic authoring toolkit for extension
packages. You can call its scaffolds directly from monorepo tasks, custom CLIs,
or migration scripts.
Note: This package is not what
agentskit inituses. The CLI has its own application starters. Use@agentskit/templateswhen you want to generate a build-ready tool/skill/adapter/memory/flow skeleton with AgentsKit contracts; complete its implementation stubs before publishing.
#Available shapes
ScaffoldType | What lands on disk |
|---|---|
tool | ToolDefinition skeleton + JSON Schema example. |
skill | SkillDefinition with system prompt + few-shot block. |
adapter | AdapterFactory skeleton + abort-signal wiring. |
memory-vector | VectorMemory HTTP-backed skeleton with typed errors. |
memory-chat | ChatMemory + real MemoryRecord via serializeMessages. |
flow | flow.yaml + named FlowRegistry export + smoke test. |
embedder | EmbedFn factory (OpenAI-compatible HTTP shape). |
browser-adapter | Browser-only AdapterFactory with contract tests. |
Every shape produces a build-ready package skeleton: package.json,
tsconfig.json, tsup.config.ts, src/index.ts (named exports),
tests/index.test.ts, README.md. Dependencies are minimal and
caret-pinned — every package gets @agentskit/core ^1.0.0; only flow
also adds @agentskit/runtime ^0.10.0. No wildcards; no unused deps.
#Quick start
import { scaffold } from '@agentskit/templates'
const created = await scaffold({
type: 'adapter',
name: 'my-llm',
dir: './packages',
description: 'Adapter for our internal inference proxy',
// overwrite: false by default — existing dirs fail safely
})
console.log(`Wrote ${created.length} files into ./packages/my-llm`)
// Paths are final destinations (never staging paths).#Name rules
Unscoped kebab-case only (my-llm). Scoped packages (@org/pkg) are
intentionally unsupported in this beta line.
#Safety defaults
- Config validated before any filesystem write
- Symlink destination roots rejected
- Sibling staging directory + atomic rename
- Collision fails unless
overwrite: true(backup + rollback)
#Programmatic factories
Per-type factories build a ToolDefinition /
SkillDefinition / AdapterFactory in memory (no disk):
import {
createToolTemplate,
createSkillTemplate,
createAdapterTemplate,
} from '@agentskit/templates'
const tool = createToolTemplate({
name: 'lookup',
description: 'Look up a customer by id',
schema: { type: 'object', properties: { id: { type: 'string' } }, required: ['id'] },
execute: async ({ id }) => fetchCustomer(String(id)),
})
const skill = createSkillTemplate({
name: 'researcher',
description: 'Methodical web researcher.',
systemPrompt: 'You are a methodical researcher…',
tools: ['web_search', 'fetch_url'],
metadata: { team: 'research' },
})
const adapter = createAdapterTemplate({
name: 'echo',
capabilities: { streaming: true, tools: false },
createSource: () => ({
stream: async function* () { yield { type: 'text', content: 'echo' }; yield { type: 'done' } },
abort: () => {},
}),
})Each factory runs the matching validate*Template pass, so misshapen
inputs throw at the call site instead of crashing the runtime later.
#Custom CLI integration
Wrap scaffold in your team's CLI to seed conventions:
#!/usr/bin/env node
import { scaffold, SCAFFOLD_TYPES } from '@agentskit/templates'
import { writeFile } from 'node:fs/promises'
import { join } from 'node:path'
const [type, name] = process.argv.slice(2)
if (!type || !name || !(SCAFFOLD_TYPES as readonly string[]).includes(type)) {
console.error(`Usage: my-team-cli <${SCAFFOLD_TYPES.join('|')}> <name>`)
process.exit(1)
}
const dir = join(process.cwd(), 'packages')
await scaffold({ type: type as typeof SCAFFOLD_TYPES[number], name, dir })
await writeFile(join(dir, name, '.eslintrc.cjs'), `module.exports = require('@myteam/eslint-config')\n`)
await writeFile(join(dir, name, '.prettierrc'), `"@myteam/prettier-config"\n`)
console.log(`Done. Run: pnpm --filter agentskit-${name} dev`)#Testing your generated code
The scaffolded tests use Vitest with the same conventions as the
core packages (vitest run, lint via tsc --noEmit). Wire them
into your monorepo's CI right away — every new scaffold ships with
its own contract test that typechecks + runs.
#Related
agentskit init— CLI app starters (separate system).@agentskit/templatespackage reference.
Explore nearby
- PeerRecipes
Copy-paste solutions grouped by theme. Every recipe end-to-end, runs as written.
- PeerCustom adapter
Wrap any LLM API as an AgentsKit adapter. Plug-and-play with the rest of the kit in 30 lines.
- PeerAdapter contract tests
Verify any adapter against the ADR 0001 invariants A1–A10 with the shared test harness.
Vue / Svelte / Solid / React Native / Angular
One package per framework. Same ChatReturn contract as @agentskit/react — pick the binding that matches your stack.
Recipe: Bail / Qwen routing
Use the bail (Alibaba DashScope) / qwen adapter alongside Western providers, with cost-aware routing for Asia-Pacific traffic.