Official Convilyn Author SDK for TypeScript / JavaScript — build and host
the tool servers that power the Convilyn AI platform's workflows. The
counterpart to the consumer SDK
@convilyn/sdk: where the
consumer SDK calls Convilyn with a ck_ key, the Author SDK lets you extend
the platform — authoring the tool servers that the gateway calls back into,
secured by HMAC. The wire shapes match Convilyn's gateway and authoring APIs
exactly.
Convilyn Author helps builders turn tools, services, and repeated processes into reusable workflow building blocks. It is part of the CoreNovus vision for practical AI workflows across cloud services, local machines, AI PCs, edge devices, and future IoT environments.
Public mirror of Convilyn's monorepo (the source of truth). Contributions are welcome and land in the shipped package — see CONTRIBUTING.md (fork → PR → upstreamed, authorship preserved).
Status: feature-complete surface (0.x). Ships the tool-server foundation, the
ToolServer+ JSON-RPC/mcpruntime, theconvilyn-authorCLI, confirmation-token signing, and theConvilynClientplatform client + local test harness. Only what is documented here is exported and covered by SemVer; while0.x, minor versions may still adjust the surface.
Workflow authoring lives in the Convilyn chat Builder (web console) — the canonical authoring surface. This is the tool-server SDK: build, register, verify and operate the MCP tool servers the platform's workflows call. The
WorkflowSpecDSL andsubmitWorkflowwere removed in 0.10.0 (the platform's developer submission endpoint is parked); edge integrators export a Builder-built workflow's grounded contract via the consumer SDK (userWorkflows.groundedContract(...)).
npm install @convilyn/sdk-authorNode 18+ (uses node:crypto). Ships ESM + CJS + type declarations. Runtime
dependencies are minimal — commander (CLI) and zod-to-json-schema — plus
zod as a peer dependency.
The gateway signs every call it makes to your tool server; verify the signature
to reject forged requests (use this if you run your own HTTP framework — the
SDK's built-in runtime, serve, does it for you).
import { verifySignature, InvalidSignatureError } from '@convilyn/sdk-author'
try {
// `verifySignature` reads the `x-convilyn-signature` / `-timestamp` headers.
verifySignature(
process.env.CONVILYN_HMAC_SECRET!,
rawBodyBytes,
req.headers as Record<string, string | undefined>,
)
// ...handle the verified request
} catch (err) {
if (err instanceof InvalidSignatureError) {
// err.reason ∈ missing_secret | missing_header | invalid_timestamp |
// timestamp_out_of_range | signature_mismatch
res.writeHead(401).end()
}
}signRequest(secret, body, unixSeconds) produces the matching
{ signature, timestamp } pair — for tests, or for calling a developer-hosted
server directly.
import { ConvilynManifest, InMemoryDataStore, ToolResult, SDKConfig } from '@convilyn/sdk-author'
const manifest = new ConvilynManifest(
{ name: 'weather', version: '1.0.0', description: 'Weather tools' },
{
tools: [
{
name: 'get_weather',
description: 'Get current weather',
inputSchema: { type: 'object', properties: { location: { type: 'string' } } },
idempotent: true,
},
],
}
)
await manifest.save('convilyn.manifest.json')
const store = new InMemoryDataStore()
const refId = await store.store({ large: 'payload' }) // → "td_<12-hex>"
const result = ToolResult.ok({ refId, summary: 'Weather for Taipei' })
const config = SDKConfig.fromEnv() // reads CONVILYN_* env varsTools return { ref_id, summary } (build with ToolResult.ok(...) /
ToolResult.fail(...)) so the agent's context stays small and fetches the full
data by ref_id later.
defineTool declares a tool from a Zod schema — the single
source of truth for the manifest input_schema, the handler's argument types,
and runtime validation of inbound calls. ToolServer registers tools and
serve runs the JSON-RPC /mcp runtime (/health, /manifest, and an
HMAC-verified POST /mcp), interchangeable with the Python / Go author SDKs
behind the same gateway. zod is a peerDependency — install it alongside the
SDK and import { z } from 'zod' yourself.
import { defineTool, ToolServer, ToolResult, serve } from '@convilyn/sdk-author'
import { z } from 'zod'
const echo = defineTool({
name: 'echo',
description: 'Echo the input text back.',
input: z.object({ text: z.string().min(1) }),
idempotent: true,
handler: (args) => ToolResult.ok({ echoed: args.text }, `Echoed ${args.text.length} chars`),
})
const server = new ToolServer({ name: 'echo-server', version: '1.0.0', description: 'demo' })
server.register(echo)
// Run it (CONVILYN_HMAC_SECRET / CONVILYN_PORT come from the env via SDKConfig):
serve(server, { port: 8080 })The package ships a convilyn-author binary:
npx convilyn-author init my-server # scaffold a TS project
cd my-server && npm install && npm run build
npx convilyn-author dev # run the JSON-RPC /mcp server (serve)
npx convilyn-author synth # write convilyn.manifest.json
npx convilyn-author test # local compliance checks (runComplianceChecks)
npx convilyn-author push --endpoint-url https://my-server.example.com # register your deployed tool serversynth / dev / test load a built JS module (default server.js,
override with --file dist/server.js) that exports a ToolServer as its default
or a named server export.
push registers your deployed tool server with the Developer Portal
(wrapping ConvilynClient.submitServer): set a cvl_ key in
CONVILYN_API_KEY, then push --endpoint-url <https://...> (the HTTPS URL where
you host the server) with --file (built server, default server.js). The
managed deploy --hosted provisions your server in the Convilyn-Hosted Author
Runtime (no infrastructure of your own): deploy --hosted [--region us-east-1]
hands over the manifest, then logs <runtimeId> tails the runtime logs and
rollback <runtimeId> flips back to the previous version. Without --hosted,
deploy errors and points at push --endpoint-url (BYO). Both commands speak
the same Developer Portal wire contract as ConvilynClient.
ConvilynClient is a fetch-based client for the Developer Portal
(/api/v1/developers/*) — the platform's third-party author/publish surface,
mirroring the Python convilyn-author SDK. You build and test your own tool
server locally (ToolServer, runComplianceChecks), then integrate it by
registering through the portal. Authenticate with a cvl_ developer key as a
Bearer token (CONVILYN_API_KEY); the base URL is
${CONVILYN_PLATFORM_URL}/api/v1.
The SDK does not call the first-party console surfaces (
/user_workflows/*,/mcp/tools/catalog) — those are JWT/session endpoints owned by the web UI, not an author-publishing API. Validate your server locally withrunComplianceChecksbefore submitting.
import { ConvilynClient, ToolServer } from '@convilyn/sdk-author'
// 1) Register once (no auth) → mint + capture a cvl_ key. Save it; shown once.
const client = new ConvilynClient()
const { api_key } = await client.register({ email: 'dev@example.com', name: 'Dev' })
// …or pass an existing cvl_ key: new ConvilynClient({ apiKey: myCvlKey })
// …or set it in the environment: export CONVILYN_API_KEY=cvl_your_key
// 2) Submit your own tool server for verification.
const server = await client.submitServer({
manifest: myToolServer.manifest().toWire(),
endpoint_url: 'https://my-server.example.com',
})
await client.testServer(server.server_id) // sandbox test
await client.serverStatus(server.server_id) // → verified / active / rejectedAlso available: listServers / deactivateServer, and the hosted-runtime
surface deployHostedRuntime / rollbackHostedRuntime / getHostedRuntimeLogs.
A non-2xx response throws
ConvilynApiError (with .status and .body); an authed call with no key throws
ConvilynAuthorError before any network call.
For tools that require a human confirmation handshake, the SDK signs and verifies confirmation tokens byte-for-byte compatibly with the gateway and the Python / Go author SDKs:
import { mintConfirmationToken, verifyConfirmationToken, CONFIRMATION_TTL_SECONDS } from '@convilyn/sdk-author'
const secret = process.env.CONVILYN_TOOL_CONFIRMATION_SECRET!
const expiresAtUnix = Math.floor(Date.now() / 1000) + CONFIRMATION_TTL_SECONDS
const token = mintConfirmationToken({ toolName: 'submit_order', arguments: args, expiresAtUnix, secret })
// On the confirming re-call, with `confirmation_token` present in arguments:
verifyConfirmationToken({ toolName: 'submit_order', arguments: argsWithToken, token, secret })
// throws ConfirmationInvalidError on a malformed / expired / mismatched tokenThe argument digest strips volatile presigned-URL params, so a re-presigned URL still matches the originally-confirmed arguments.
invokeTool drives a ToolServer in-process (no HTTP), returning the same wire
envelope the gateway would receive — ideal for unit tests:
import { invokeTool } from '@convilyn/sdk-author'
const wire = await invokeTool(server, 'echo', { text: 'hi' })
expect(wire.status).toBe('ok')
expect(wire.data).toEqual({ echoed: 'hi' })| Secret (env) | Used for |
|---|---|
CONVILYN_API_KEY |
cvl_ developer key — Bearer auth to the Developer Portal (ConvilynClient) |
CONVILYN_HMAC_SECRET |
Verifying inbound POST /mcp calls from the gateway (serve / verifySignature) |
CONVILYN_TOOL_CONFIRMATION_SECRET |
Minting / verifying confirmation tokens |
npx convilyn-author init my-server scaffolds a complete TypeScript
tool-server project (server.ts, build config, .env.example) — the fastest
way to see the tool server, manifest, and compliance checks working together.
This package follows Semantic Versioning. The SemVer
contract is exactly the set of names exported from the package root; anything
not exported there is internal and may change in any release. The package.json
exports map blocks deep imports, and a packaging test pins the public surface.
While the package is 0.x (pre-1.0), minor versions may still contain breaking
changes as the surface stabilises toward 1.0.
Apache-2.0 — see LICENSE.
