| name | coding-versori-sdk |
| description | Use this skill whenever the user wants to create, debug, or modify data integration workflows using the versori-run SDK. Also covers deploying projects, viewing or tailing workflow logs, diagnosing failed executions, and managing connections, systems, activations, issues, or notification channels via the `versori` CLI. Also use when the user mentions Versori, `versori-run`, or `@versori/run`. Also use when the user mentions ETL pipelines, API integrations, webhook handlers, scheduled cron workflows, durable workflows, data transformation, file processing, or real-time streaming. Also use in any workspace whose `package.json` or `deno.json` depends on `@versori/run`, or where a `.versori` file is present (synced Versori project), including generic Plan-mode "Build" / "implement the plan" prompts and `[Previous conversation summary]` resumes where the prompt itself does not mention Versori. When any of these triggers match, load this skill and read SKILL.md before other work. |
Versori Integration Skill
Expert-level data integration code using the versori-run SDK.
Read this skill fully before other work
If you are reading this, a trigger matched โ read this entire SKILL.md, not just the section that looked relevant, before exploration, clarifying questions, or code changes.
Project markers โ check every turn in the active directory:
package.json or deno.json lists @versori/run as a dependency
- a
.versori file is present (directory synced from the Versori platform)
If either marker is present, this skill is mandatory even when the user's prompt is generic ("continue", "implement the plan", "fix the bug") or resumes from [Previous conversation summary].
Also applies when the task involves: integration workflow code; versori CLI operations (deploy, logs, KV, issues, notifications, connections, systems, activations, variables); or keywords such as Versori, ETL, webhooks, cron, or data transformation.
Resume / Plan-mode: a prior agent's decision that this skill did not apply does not carry through summaries or generic implement-the-plan prompts โ re-read this file fresh from the top.
Retrieval sources
The most up-to-date information can always be found in the official documentation. Prefer reading the official documentation over relying on existing Versori knowledge.
Core Principles
TypeScript only. Do not generate code in any other language. If asked, explain that versori-run requires TypeScript.
Scope validation. Decline requests unrelated to data integration (ETL, API integrations, database sync, data transformation, file processing, webhooks, real-time streaming). Politely explain what you specialise in.
Code Quality & Testing:
- Pragmatic DRY: Create reusable code when possible, but do not force DRY (Don't Repeat Yourself) if it makes the code harder to read or overly abstracted.
- Extract Pure Logic: Extract data transformations, payload mappers, and complex logic into pure functions in
src/services/.
- Test Pure Functions: Pure functions must have Deno tests written for them (e.g.,
src/services/mapper.test.ts). Run them using deno test before deploying.
- Avoid Mocks: In unit tests, avoid creating mocks. Prefer not testing a function at all if it requires a lot of mocks (e.g., heavily context-dependent SDK tasks). Focus testing effort entirely on pure, mock-free logic.
Runtime Environment
Versori projects execute on Deno, running TypeScript directly โ no build step is required.
package.json is still used: Deno reads it via deno install to resolve npm dependencies
- Standard imports (
from '@versori/run') work as-is โ no npm: prefix needed
The runtime is Deno 2.3.
Avoid Node-only APIs (require(), __dirname, __filename). Use Deno-compatible alternatives or standard web APIs where possible.
Required Project Files
Every generated project MUST include these files:
src/index.ts (entry point โ ALWAYS required)
import { durable } from '@versori/run';
import { myWorkflow } from './workflows/my-workflow';
async function main(): Promise<void> {
const mi = await durable.DurableInterpreter.newInstance();
mi.register(myWorkflow);
await mi.start();
}
main().then().catch((err) => console.error('Failed to run main()', err));
package.json
{
"name": "integration-name",
"version": "1.0.0",
"type": "module",
"module": "dist/index.js",
"dependencies": {
"@versori/run": "^0.8.0"
}
}
tsconfig.json
{
"compilerOptions": {
"module": "ES2022",
"esModuleInterop": true,
"target": "ES2024",
"moduleResolution": "node",
"sourceMap": true,
"outDir": "dist"
},
"lib": ["es2015"]
}
For larger integrations, split workflows into src/workflows/ and shared utilities into src/services/.
File Organization
- One workflow per file in
src/workflows/
- Shared utilities (transformations, validation) in
src/services/
- Type definitions in
src/types/
src/index.ts imports all workflows and registers them with the interpreter
- Extract reusable functions into services rather than duplicating across workflows
Critical Rules
Connection Names
- After research, review the System & Authentication section for any systems that need user-specific configuration (e.g., shop domain, subdomain, instance URL). Ask the user for these values before proceeding. Then run
versori projects systems bootstrap --file <path> --project <id> --system-overrides '<json>' (passing confirmed user-specific values via the overrides flag) to create systems, and run versori projects systems list --project <id> --environment <env> to verify what was created
- Before creating a connection, run
versori connections list to see existing connection names. Connection names must be unique โ do not reuse a name that already exists.
- After verifying systems, create connections for each system. Default to real credentials โ never pass literal secrets in commands. Instead, generate a
.env.example file and have the user fill in a .env file. Follow this workflow:
- Inspect auth types: After running
versori projects systems list, look at each system's AuthSchemeConfigs.Type to determine required credentials.
- Map auth types to env vars using these conventions (see
references/cli-usage.md for the full mapping table):
api-key โ <SYSTEM>_API_KEY
basic-auth โ <SYSTEM>_USERNAME, <SYSTEM>_PASSWORD
oauth2 (authorization_code grant) โ create via Versori UI, not CLI; the CLI cannot complete the browser redirect
oauth2 (client_credentials grant) โ <SYSTEM>_CLIENT_ID, <SYSTEM>_CLIENT_SECRET (read grant type and token URL from systems list -o yaml output)
none โ use --bypass automatically, no credentials needed
Where <SYSTEM> is the system name uppercased with hyphens replaced by underscores (e.g. system my-shop โ MY_SHOP_API_KEY).
- Generate
.env.example: Create a .env.example file listing every required variable with empty values and a comment per system:
# shopify credentials (api-key)
SHOPIFY_API_KEY=
# erp credentials (basic-auth)
ERP_USERNAME=
ERP_PASSWORD=
- Ask the user to copy
.env.example to .env and fill in the actual secret values: "I've generated .env.example with the required variables. Copy it to .env and fill in your credentials, then let me know when you're ready. Or if you'd prefer to skip credentials for now, I can create bypass connections instead."
- Create connections using single-quoted
'$VARIABLE' references so the CLI resolves them from .env at runtime:
versori connections create --project <id> --environment production \
--name shopify --template-id <tid> --api-key '$SHOPIFY_API_KEY'
versori connections create --project <id> --environment production \
--name erp --template-id <tid> --username '$ERP_USERNAME' --password '$ERP_PASSWORD'
Use --env-file <path> to specify a custom .env file location (defaults to .env in the current directory). Never read or display the .env file โ it contains secrets. The CLI resolves variables at runtime; you only need to know the file path, not its contents.
- If the user chooses bypass: use
--bypass and suffix the connection name with random characters to avoid name conflicts. This is a fallback for when credentials aren't available yet.
--bypass is mutually exclusive with credential flags. Never combine --bypass with --api-key, --username/--password, or --client-id/--client-secret. When --bypass is passed, all credential flags are silently ignored and the connection is created with no authentication. Use --bypass only when the auth scheme type is none or the user explicitly wants to skip credentials entirely.
- Always run
versori projects systems list before generating workflow code if a project ID is known.
- If a required system is still missing after bootstrap, stop and tell the user which systems are missing before writing any code. Ask for the name of their org, then give them the direct link
https://ai.versori.com/integrations/<project-id>?org=<org> to add the missing systems. Proceed once they confirm.
Effective Base URLs (the /api strip)
The Versori runtime strips a trailing /api segment from every system's
configured base URL before concatenating it with your fetch() path. This is a
platform-wide behaviour, not a template bug, and it is why templateBaseUrl
in versori projects systems list -o yaml often looks "shorter" than the URL
you see in the API docs or in the versori projects systems bootstrap summary
output.
Practical consequence: if a system's REST endpoints live at
https://host/api/foo, the path you pass to fetch() must include the
/api/ segment yourself.
Known examples:
- Slack:
fetch('/api/chat.postMessage', ...) โ not /chat.postMessage.
- Any template whose documented base ends in
/api/.
Before writing fetch() paths for a new system:
- Run
versori projects systems list -o yaml and read templateBaseUrl.
- Compare it to the API's documented base URL.
- If the documented base ends in
/api/ and templateBaseUrl does not,
every fetch() path you write for that system must start with /api/.
The connection Parameter Takes the System Name
http('id', { connection: 'X' }, ...) resolves X against the project's
systems, not its connections. Despite the parameter name, X must equal
the system name from versori projects systems list. Versori looks up which
connection is currently active for that system at runtime.
โ
Correct โ system name, regardless of which connection is active:
http('post', { connection: 'slack' }, ...)
โ Wrong โ these will all fail to resolve at runtime:
http('post', { connection: 'slack-prsum' }, ...) // connection name
http('post', { connection: 'slack-feedback' }, ...) // connection name
http('post', { connection: '01K7KZNV109PF1Z5ESFR27D19B' }, ...) // system id
This indirection is deliberate: you can swap the underlying connection โ
rotate credentials, migrate from bypass to OAuth, move between environments โ
without editing any workflow code.
Configuration & Variables
Versori has three distinct mechanisms for non-code configuration. Do not
conflate them:
| Mechanism | Scope | When it resolves | Set via | Read from workflow via |
|---|
.env file ($FOO refs) | Local CLI only | CLI-time | .env in project dir | Not accessible at runtime |
| Activation variable | Per-activation | Runtime | Versori UI โ Project โ Activations โ Variables | ctx.activation.getVariable('foo') |
| KV store | Project / org / execution | Runtime | ctx.openKv(...).set(...) | ctx.openKv(...).get(...) |
Rules:
-
.env values are not available at runtime. They exist solely so
versori connections create can inject secrets via $VARIABLE references.
Never call Deno.env.get(...) / process.env.X in workflow code expecting
to pick up a .env value โ it will be undefined in the deployed runtime.
-
Anything that might vary per tenant, per environment, or per deploy
should be an activation variable. Hard-code a sensible fallback for
local development, but read the activation variable first. Example:
const channel =
(ctx.activation.getVariable('slackChannelId') as string | undefined) ??
'#general';
-
Use KV for workflow-produced state (cursors, dedupe keys, batch
progress), not for configuration.
-
Document every activation variable your workflow reads in a
comment at the top of the file, including expected type and default. This
is the contract between the code and whoever configures the project.
-
Activation variables take effect immediately โ no redeploy needed.
Mention this when an operator asks "do I need to redeploy to change X?".
-
Declare the schema before setting any value. Activation variables live in
the project's DynamicVariablesSchema. Both versori projects users activate --variable and versori projects users set-variable pre-flight against the
schema and refuse keys that aren't declared โ there is no auto-declare on
first use. The required ordering for any new variable is:
versori projects variables add --project <id> --name <key> --type <type>
- then either
--variable <key>=<value> on activate, or
versori projects users set-variable --name <key> --value <value> on an
existing activation.
Key-Value store access (versori kv)
The versori kv commands inspect and manage a project's KV store from the CLI.
KV holds live workflow state โ cursors, dedupe keys, batch progress โ so the
group is split into a read tier and a mutation tier, and you must treat them very
differently.
Read tier โ safe to run for diagnosis (use freely):
versori kv stores list โ list the org's KV stores.
versori kv list โ enumerate entries under a prefix (capped page; use
-o json / -o yaml for full nested values). Supports server-side
--created-after / --created-before / --metadata key=value filters.
KV "search" is prefix descent plus these filters โ there is no value or
key-substring search (pipe -o json to jq for that). Pagination is
cursor-based, ordered newest-first by internal ID (not by key): to page,
pass the previous response's opaque nextCursor to --after (never a key โ
a key triggers a misleading 500). An empty nextCursor means end-of-results,
not a hidden page โ cross-check totals with kv count, don't invent key-based
paging.
versori kv count โ total entries matching a prefix. Use this to answer "how
many items?" โ list only returns a capped page, so a full count needs
count. The count API is prefix-only (no created/metadata filter).
versori kv get โ fetch one entry by key.
Mutation tier โ NEVER run unless the user explicitly asks for that specific
change:
versori kv set โ write a value at a key.
versori kv delete โ remove a single key.
versori kv wipe โ cascade-delete every entry under a prefix (bulk; the most
destructive).
Rules for the mutation tier:
- Explicit request only. Do not
set / delete / wipe as a side-effect of
debugging, to "fix up" or "clean" state, or because it seems helpful. Only when
the user names the mutation.
- Never guess the target. Confirm the store/scope and key/prefix before any
mutation.
wipe refuses an empty prefix and only proceeds with --confirm
(without it, it prints a dry-run count).
- Non-interactive safety.
set / delete require --yes in non-TTY shells;
the CLI refuses otherwise.
- Value encoding matches the SDK.
kv set JSON-encodes values the same way
ctx.openKv().set() does, and the read commands unwrap that encoding by default
(--raw-values shows the literal stored bytes). So a value written with
kv set is readable by workflow code and vice-versa.
Addressing: every kv command targets a store either by raw ID (--store <id> plus
--prefix / --key) or by friendly scope (--scope organization|workspace|project|user|execution with --project / --environment /
--external-id / etc.), which derives the store + key prefix the same way the
runtime SDK does. See references/cli-usage.md for full flags.
Per-activation :project: scoping (common gotcha). ctx.openKv(':project:') is per activation โ its data lives under each user's activation, not at the project root. From the CLI always reach it with --scope project --activation-id <activationId>, never --external-id on --scope project (that flag is ignored for project scope and silently returns 0). Cross-check any zero count with kv list โฆ --limit 3 before concluding the store is empty โ see the per-activation scoping table in references/cli-usage.md (KV store).
CLI Commands
Use the versori CLI for any operation that touches the Versori platform: listing / creating / syncing / starring projects, switching contexts, bootstrapping systems, creating or listing connections, uploading or listing project assets, deploying, viewing or tailing workflow logs, diagnosing failed executions, managing notification channels and their project links, managing activations, end-users, or project / activation variables, and listing or saving project files.
Before running any versori command, read references/cli-usage.md first. It is the authoritative source for command names, required and optional flags, defaults, output formats, and pre-flight checks for this CLI. Do not run versori --help to discover commands and do not guess flag names โ load the reference and use the documented invocation. Only fall back to versori <command> --help if the reference is genuinely silent on a command you need.
Before running any project-scoped versori command, switch to the intended local project directory when local files or .versori defaults matter. Do not run from an unrelated synced directory and rely on --project to compensate: --project changes the remote project ID, but commands such as deploy, save, sync, logs, assets, systems, variables, activations, and notification project links may still read local files or .versori from the current/target directory. If operating on a different project, cd there first (or pass the command's explicit --directory/-d and use that directory consistently), then run the CLI command.
Two-step versori projects sync. sync is dry-run by default โ invoking it without --confirm only prints the create / update / delete diff, it does not touch local files or rewrite .versori. Always run it once without --confirm first, show the user the diff (especially any deletions), and only re-run with --confirm once they confirm โ or when the diff is clearly safe (no deletions, expected file changes only). Never invoke versori projects sync --confirm as a first step; the dry-run pass is the safety net.
Run versori commands outside any sandbox. If your environment wraps shell commands in a network-restricted sandbox (Claude Code sandbox, agent sandboxes, etc.), versori calls will fail with a 403 because the CLI authenticates against the Versori API. Run these commands unsandboxed โ e.g. in Claude Code use the "run without sandbox" option. The CLI is safe to run directly; it only talks to the configured Versori API and the user's local project directory.
Always confirm before deploying or bootstrapping unless the user explicitly says "deploy", "ship it", or "go ahead".
Always dry-run before syncing โ sync deletes local files not present in the platform. It defaults to dry-run (no --confirm); run the dry-run first, show the user the diff, then re-run with --confirm once they're happy.
Always ensure a .gitignore exists โ After syncing a project or setting up a new project directory, check if a .gitignore file exists. If it doesn't, create one with the recommended content from references/cli-usage.md before installing dependencies or deploying. This prevents node_modules/, dist/, and other local artifacts from being pushed to the platform.
Always verify code locally before deploying โ Before running a deploy command, you MUST ensure the code is valid by running deno install followed by deno check src/index.ts (or deno lint). Fix any type errors or linting issues before attempting to deploy. If deno is not available skip local validation.
Write tests for pure functions โ Whenever you extract logic into pure functions (e.g., data transformations, payload mappers) in src/services/, you should write Deno tests for them (e.g., src/services/mapper.test.ts) and run them using deno test to verify their correctness before deploying.
Versioning & Deploying
A version is an immutable snapshot of the project's files. Deploying makes one version live on an environment. Read references/cli-usage.md (the versions create / versions deploy / deploy entries) for full flags before running any of these.
Save a version automatically whenever a significant feature or self-contained unit of work is complete. After you finish a big feature, a meaningful refactor, or a working increment โ and have validated it locally (deno check / deno test) โ default to creating a version with versori projects versions create. This is a cheap, non-deploying checkpoint (it uploads files and records a snapshot; it does not make anything live). Do it proactively without waiting to be asked. The only times you skip it:
- the user is about to deploy this same work now (the deploy creates the version โ see below), or
- the user has said they don't want a version / checkpoint.
Make every new version visible to the user. After you create one, state clearly that you've saved a new checkpoint โ include its name and ID, and say explicitly that it is not yet live (nothing has been deployed). The user should never have to guess whether a new version now exists. Example: "Saved a new version (<name>, 01KSโฆ) โ this is a checkpoint only, not deployed. Say the word and I'll deploy it."
Always pass --name and --description. Both are required in practice โ if either is omitted the CLI drops into an interactive editor, which hangs a non-interactive agent. Put a concise summary of what changed in --description so the version list reads like a changelog. Pick any sensible short --name; don't over-think it (no required naming scheme):
versori projects versions create \
--name "<short-name>" \
--description "New POST /orders webhook that upserts Shopify orders into Snowflake; adds retry on 5xx."
Deploy when the user asks for it or implies it โ saving never deploys on its own. Creating a version is a non-live checkpoint; making it live on an environment is a separate, deliberate step that you take only on the user's intent:
- Explicit โ "deploy", "ship it", "push to production", "release it", "go live", "go ahead". Just deploy.
- Implied โ "make it live", "get it running on the env", "I want to test it on staging/production", "publish the new webhook", "can you put this up so I can hit the URL". Treat these as deploy requests.
- Ambiguous or implied-only โ confirm the target environment before deploying (e.g. "Deploy the latest version to
production?"). When the intent is explicit, deploy without asking.
When you do deploy, don't create a redundant version. versori projects deploy always uploads the current files and creates a brand-new version, then makes it live. So:
- If you have not already created a version for this exact code, run
versori projects deploy (it creates the version for you โ pass --version and a --description of what changed).
- If you just created a version with
versions create and the local files have not changed since, deploy that existing snapshot with versori projects versions deploy --version-id <id> --environment <env> instead of projects deploy. This avoids a duplicate version and is faster (no re-upload). Capture the --version-id from the versions create output (or versori projects versions list).
- If the local files have changed since the version was created, create a fresh version (or use
projects deploy) โ never deploy a stale snapshot.
After any deploy, tell the user which version is now live on which environment, then diagnose and fix runtime errors from logs exactly as before (see the logs-diagnosis flow in references/cli-usage.md).
Project Selection
Before writing any code or running CLI commands that require a project ID, determine the active project:
- Check for
.versori file โ if a .versori file exists in the current directory, the user is already inside a synced project. Read the project_id from it and use that โ no need to ask about project selection.
- No
.versori file โ ask the user whether they want to use an existing project or create a new one:
- Existing project: run
versori projects list to show available projects, let the user pick one, then continue (sync it down if needed).
- New project: run
versori projects create --name <name> to create a fresh project and use the returned ID.
- Sync project: run
versori projects sync --project <project-id> (dry-run, the default) to preview what will be written, show the user the diff, then re-run with --confirm to actually pull in the project context locally before moving on with the next tasks.
When a .versori file is present, most CLI commands (deploy, save, sync, systems, assets, etc.) automatically read the project ID from it, so the --project flag can be omitted.
Reference Projects (Starred)
Organisations can mark projects as starred reference projects โ the blessed
examples for that org. Before generating a new project or suggesting substantive
changes to an existing one, gather these references so the code you write
follows the org's established patterns.
Do this once per conversation, at the start of a project-create or
project-edit flow. Do not re-fetch on every command. Hold the result in your
conversation context and consult it while writing code.
Flow:
- Run
versori context show -o json.
- If
disableReferences is true, skip this whole section โ the user has
opted out for this context (typically for debugging or internal CLI work).
- Run
versori projects list --starred -o json.
- If the result is an empty list, skip โ the org has no starred references.
- Take the first 3 starred projects (up to 5 if they look small or closely
related to the task). Keep the cap โ full project file trees can be large,
and we don't want to blow the context window.
- For each chosen project, run
versori projects files --project <id> -o json
to read its files โ that's the actual code you'll mimic. (projects details
only returns metadata, not file contents.)
- Treat the returned files as blessed reference patterns from this
organisation. When generating new workflow code, prefer the structure,
naming conventions, error-handling style, retry/backoff idioms, and KV usage
observed in the references over generic defaults. If the references disagree
with something documented elsewhere in this skill, the references win โ they
represent what the org actually wants.
If the user explicitly says they don't want references consulted this time
("skip references", "ignore starred projects", etc.), honour that and skip
without setting disable_references โ the config flag is for persistent opt-
out, in-conversation requests are one-shot.
Context the User May Provide
- API documentation for systems being integrated
- Error logs from failing workflows
- Existing service files and code
- Integration variables schema
- Existing project systems with auth configured
- Research documents from a previous research phase
- Implicit: the organisation's starred reference projects (fetched per the "Reference Projects" section above)
For unknown systems, research APIs and create a research document before generating code. If no information can be found, ask the user for API docs. For well-known APIs (e.g. Shopify, Stripe), ask the user whether they'd like you to carry out research first or proceed directly with code generation.
Error Handling
- Syntax / SDK errors: Fix and explain changes made
- Connection / auth errors: Inform the user to check credentials โ do not modify code
- Do not regenerate unaffected files
Logging & Issues (write code a human can debug from logs alone)
Read references/sdk-guide.md (the Logging and Creating Issues sections) before writing observability code. The default bar is high: a human or agent should be able to diagnose a failure from the logs alone, without asking the workflow to be re-run with extra logging added. Build this in from the start โ do not ship a workflow that logs only "failed" and then wait for a follow-up prompt to add detail.
Debugging: when deploy fails, the environment is down, executions restart silently, or logs are unhelpful, run versori projects issues list before reading source โ especially open critical issues (OOM Killed, Environment failed to deploy). Diagnosis flows and CLI examples: references/cli-usage.md (Issues & resource limits โ Platform critical issues). If no platform issue explains it, follow Diagnosing a workflow failure from logs there; cross-check issues again if logs are empty or only info.
Writing issues: issues come from ctx.createIssue(), auto-submit when a thrown error reaches a workflow-level .catch() (high/low), or platform lifecycle events. ctx.log.error does not create an issue โ use createIssue only for static-connection infrastructure failures a human can fix; handle data-level and dynamic-connection errors in-task and do not throw to .catch(). Severity rules (critical vs high, etc.): references/sdk-guide.md (Escalating to a human). Issues are always inspectable in the UI and via versori projects issues list/get.
Email alerts: an issue with no linked notification channel is silently dropped for email โ ctx.createIssue() succeeds but no alert is sent. When workflows can raise issues that should page someone, ensure an email channel exists and is linked to the environment (versori notifications channels create, versori notifications project link). Ask the user for the recipient email (--email is required). Full CLI steps: references/cli-usage.md (Notification channels (email alerts)).
Log semantically and richly around every external call โ by default, not on request:
- Before each outbound call: log the method, the resolved path, and the request payload (full if small; a summarised shape โ keys, counts, ids โ if large).
- After each call: log the response status and body (or a summary for large bodies).
- On a caught error: log the proximate cause and the specific input that triggered it (the offending record/id), so the failure is reproducible from the log line.
- Never log secrets (credentials, tokens, API keys, or bodies containing them). See the never-log-secrets rule in the SDK guide.
Add performance/memory logging whenever the workflow may hold a lot of data in memory โ proactively, without being asked. Environments have a fixed memory limit and the platform will OOM-kill a container that exceeds it (surfacing a critical OOM Killed issue โ see references/cli-usage.md, Platform critical issues). Whenever you write code that could accumulate unbounded or large data in memory, build in size-aware logging and prefer a streaming/batched shape over loading everything at once:
- Buffering a full API response, reading an entire file, or
Promise.all-ing a large fan-out: log the count and an approximate size (e.g. record count, byte length) before and after, so an OOM is diagnosable from the logs instead of a silent restart.
- Accumulating results across a paginated loop or an unbounded array: log the running size each page, and stream/flush in batches (write to KV, emit downstream, or
for await per page) rather than collecting the whole set in one array.
- Call it out to the user when you spot an unbounded-memory pattern, and say what you did (streamed / batched / capped) โ this is the code-level counterpart to bumping the memory limit.
Research Phase
Before writing workflow code, research the APIs being integrated. Use any available search or
web fetch tools to find up-to-date API documentation, endpoints, request/response schemas,
authentication requirements, and integration patterns (rate limits, pagination, error codes).
Capture findings in a structured research document (versori-research/research.md).
Skip research only when the user provides complete API documentation or you are fully confident
in the endpoint details for well-known APIs.
Do not search for general programming questions, SDK usage, or logic patterns.
After the research document is complete, review the System & Authentication section to identify any systems whose base URL or configuration depends on user-specific values (e.g., a Shopify shop domain, Salesforce instance URL, Zendesk subdomain, or any tenant-specific identifier). If any system requires such input, ask the user for the required values before proceeding. Do not guess or use placeholder values. Do not modify the research document with these values โ they will be passed via the --system-overrides flag.
After confirming any required values, run versori projects systems bootstrap --file versori-research/research.md --project <id> --system-overrides '{"Shopify": {"base_url": "https://my-store.myshopify.com/admin/api/2024-01"}}' to create the required systems in the project from the research file, then verify with versori projects systems list --project <id> --environment <env>. Next, create connections for each system using versori connections create with real credentials (or --bypass if the user prefers to skip credentials) before proceeding to code generation. Omit --system-overrides if no systems require user-specific configuration.
After bootstrapping, upload the research document as a project asset using versori projects assets upload --file versori-research/research.md --project <id> so it is available as context for Versori AI agents.
See references/research-docs.md for the required document structure, inclusions, and exclusions.
SDK Reference
Before writing any workflow code, read references/sdk-guide.md for the full Versori Run SDK guide covering core concepts (workflows, triggers, tasks, interpreters), usage patterns (scheduled workflows, webhooks, HTTP tasks, error handling, durable workflows, KV storage), context API, type signatures, and best practices for code generation.
Plan-mode: keep implement-the-plan re-triggering this skill
"Implement the plan", Plan-mode Build, and similar domain-neutral prompts can arrive with no Versori keywords. To make sure the next agent turn re-triggers this skill, when you author a plan for a project that uses @versori/run, embed this line at the very top of the plan file (under the title, before any todo list):
Required reading: before executing any task below, load skills/coding-versori-sdk/SKILL.md. This plan implements code on top of @versori/run and depends on its conventions.