About uipath-functions
A skill for building deterministic UiPath Coded Functions in Python, JavaScript, or TypeScript. It covers typed inputs and outputs, local testing, packaging, publishing, and deployment, without LLM reasoning or agent loops.
Key features
- 01Scaffold Python and JS/TS functions
- 02Define typed input and output schemas
- 03Run and test functions locally
- 04Pack, publish, and push projects
- 05Call UiPath APIs from functions
- 06Configure resource bindings
Use cases
- 01Implement custom business rules
- 02Transform data with typed contracts
- 03Test a function before publishing
- 04Invoke platform APIs from function code
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ uipath/ skills --skill uipath-functionsAfter installing, type/uipath-functionsin Claude Code to confirm it loaded.
Bundled files
References and scripts installed along with SKILL.md.
assets/solutions/metadata.jsonreferences/js/authoring-guide.mdbindings-guide.mdcalling-uipath-apis-guide.mdcoded-app-wiring-guide.mddeployment-guide.mdhttp-semantics-guide.mdjob-mode-guide.mdlocal-dev-guide.mdreferences/python/bindings-reference.mdworkflow-guide.mdDetails
From the project READMEUiPath Coded Functions
Atomic, deterministic units of business logic — no LLM reasoning, no agent loop — written in Python or TypeScript/JavaScript and shipped as first-class UiPath artifacts. One uip function CLI drives both languages. A Coded Function takes typed input, executes deterministic code, and returns typed output; use one when generic activities don't cover the required logic (custom-auth API calls, domain rules, ERP queries via Integration Service, data transforms).
When to Use This Skill
- Scaffold, author, or modify a coded function in either language (
uip function new <NAME> -l py|ts|js) - Declare typed contracts — Pydantic Input/Output (Python) or
defineSchema<T>()/ JSON Schema literals (JS/TS) - Test locally:
uip function run(both languages),uip function serve+ curl (JS/TS HTTP endpoints) - Error handling: returned error fields (Python),
FunctionError/status codes and job fault semantics (JS/TS) - Call UiPath platform APIs from inside a function (Python SDK;
@uipath/uipath-typescriptwithctxtokens) - Wire a Coded App frontend to a JS/TS function backend (tokens, CORS, timeout budget, local dev loop)
- Pack, publish, invoke in production; register in a solution; derive
bindings.jsonresource bindings from SDK calls - Debug deployed failures: cold-start hangs, errorCode 4801/4804/1623, missing tokens, entrypoint errors
Do NOT use this skill for:
- LLM/agentic projects (
agent.json, LangGraph, LlamaIndex, OpenAI Agents, agent loop) →uipath-agents - The Coded App frontend itself (React/Vite app code, PKCE setup, app deploy) →
uipath-coded-apps
Language Split
Detect an existing project by its signals before doing anything; for a new project the language follows the caller's stack.
| Python | JS/TS | |
|---|---|---|
| Scaffold | uip function new <NAME> -l py (-l py required) | uip function new <NAME> -l ts / -l js (ts is the CLI default) |
| Project signals | pyproject.toml + uipath.json functions map | package.json + uipath.json functions map |
| Contracts | Pydantic BaseModel / @dataclass Input/Output | defineSchema<T>() (TS) / JSON Schema literal (JS) |
| Entrypoints | "main": "main.py:<fn>", generated by uip function init | functions/<FILE>.ts:default, auto-synced; no init |
| Calling mode | run-as-job (Maestro, agents, Orchestrator API) | one declared mode: HTTP endpoint or run-as-job — never both |
| Local dev | uip function run | uip function serve (HTTP on :7070) / uip function run (one-shot job) |
| References | references/python/ | references/js/ |
Job-startable functions are invoked from Maestro BPMN/Flow (Service Task), coded agents (as a tool or step), other functions, the Orchestrator API (POST /Jobs/StartJobs), or schedules/triggers. A JS/TS HTTP-mode function is instead called synchronously through its Orchestrator HTTP trigger (references/js/http-semantics-guide.md).
Critical Rules
Both languages
- No LLM calls inside a Coded Function. LLM reasoning breaks the deterministic contract — that project is an agent →
uipath-agents. - The
functionsmap inuipath.jsonidentifies the project as a Coded Function — it is the marker every tool reads. - Cloud-backed work needs auth:
uip login --organization "<ORG>" --tenant "<TENANT>" --output json.
Python
UiPath()must never be instantiated at module level — lazy singleton inside a getter.- Errors are returned, not raised: populate
error_type/error_messageoutput fields; never let exceptions bubble out of the entrypoint. uip function initmust run beforepackorpush— it generatesentry-points.jsonandproject.uiprojand createsbindings.jsonas an empty skeleton when the file is absent; re-run after any schema or entrypoint change. It never derives bindings from code (Rule 7).- Typed I/O is mandatory — Pydantic
BaseModel,pydantic.dataclasses.dataclass, stdlib@dataclass, or a thin typed class; apply@traced(name=..., run_type="uipath")to the entrypoint for LLM Ops Traces. pyproject.tomlneedsauthors(elsepackrejects:Project authors cannot be empty) and no[build-system]section.uip function new -l pyproduces a function scaffold —uipath.jsonwith afunctionsmap, nolanggraph.json— regardless of any agent framework package (uipath-langchain,uipath-llamaindex,uipath-openai-agents) installed in the venv.- Bindings are derived from
uipathSDK calls — never left empty, never guessed.initleaves"resources": []. Everysdk().assets/queues/processes/buckets/context_grounding/connections/mcp/taskscall needs a matchingbindings.jsonentry, produced by the sync workflow in references/python/bindings-reference.md. Without it the project packs and publishes cleanly, surfaces no resource for mapping at deploy time, and fails at runtime.uip function pushresolves the entries against the Resource Catalog exactly asuip codedagent pushdoes.
JS/TS
- Throw
FunctionError, never plainError. A plain throw is always a generic 500 (JsCodedFunction.HandlerError) that leaks the raw stack;FunctionError(message, status)carries an author-controlled status (passerrorCodein options to set the job error code). Argument order is(message, status). See error handling. - Contracts are schema-first.
defineSchema<T>()over interfaces (TS, lowered at build time) or a bare JSON Schema literal (JS). Do not use zod/arktype/valibot for new functions — they break static contract extraction and add a runtime dependency. No$ref,any,bigint, or tuples; the schema literal must be static. - One default-exported
defineFunctionper file, directly underfunctions/. Helper modules are_-prefixed (functions/_helpers.ts).method+pathtogether or neither — the pair selects the function's single calling mode: HTTP endpoint or plain run-as-job, never both. Logic needed on both surfaces gets two thin functions sharing a_-helper. - Intra-project imports carry the
.tsextension (./_helpers.ts). Extensionless imports resolve in local dev but hang the whole runtime at production cold start, with no logs. - Runtime deps go in
dependencies, public npm only; the SDK stays indevDependencies. Production runsnpm install --omit=devat cold start — a runtime import fromdevDependenciesor a private registry crashes/hangs the function. Regenerate the lockfile after any dependency change; a stalepackage-lock.jsonfails every route with errorCode 4801. - Finish in <20 s — the gateway times out at 25 s and returns a
303to a polling URL without CORS: a browser caller loses the result permanently, and recovering it server-side via the redirect is undocumented. UseAbortSignal.timeout(...)on every external call; move longer work to a run-as-job function. - Deployed POST with empty input still needs
body: '{}'— the gateway rejects an empty body with400 errorCode 4804(local serve does not, so the bug only appears in production). - Two tokens, two identities.
ctx.user.accessToken= the caller's token (delegated, caller's folder permissions);ctx.robot.accessToken= the function's own robot identity (S2S, privileged reads).ctx.robotis always null under local serve (ctx.useronly when no Bearer token is sent) — fall back toprocess.env["UIPATH_ACCESS_TOKEN"]. - Read platform coordinates from
ctx.platform(baseUrl,orgId,tenantId,folderKey), never from input fields — caller-controlled URLs are a redirect risk. Env vars (UIPATH_BASE_URL,UIPATH_ORG_ID,UIPATH_TENANT_ID) are the local-only fallback. - Only the SDK
logger.*reaches Orchestrator job logs.console.*prints locally and is not forwarded. - No
Buffer. UseUint8Array,TextEncoder,TextDecoder. - After
uip function publish, manually update the Function Release in Orchestrator (Automations → Processes) — triggers only sync to the new version once the release is updated. uip function runis a one-shot job execution, not an HTTP call. To exercise the HTTP surface locally, curl/fetch against theserveserver — no CLI subcommand invokes a route for you.
Quick Start
Python
uip function new <NAME> -l py # scaffold a Python function project
# author: Pydantic Input/Output + @traced entrypoint, lazy UiPath() singleton, errors returned not raised
uip function init # generate entry-points.json / project.uiproj; bindings.json starts empty
# sync bindings.json from the SDK resource calls — references/python/bindings-reference.md
uip function run <ENTRYPOINT> '{"document_id": "42"}'
uip function pack && uip function publish
Full workflow (schema, template, uipath.json registration, pyproject.toml, SDK capabilities, attachments, packOptions): references/python/workflow-guide.md.
JS/TS
uip function new <NAME> -l ts # or -l js; --empty for no sample
# author: one default-exported defineFunction per functions/ file — method+path for HTTP, neither for run-as-job
uip function serve # HTTP on :7070, hot reload; test with curl
uip function run --function <NAME> --input '{}' # one-shot local job execution
uip function pack && uip function publish # then update the Function Release in Orchestrator
// functions/invoice.ts
import { defineFunction, defineSchema, FunctionError } from "@uipath/coded-functions-js-sdk";
interface Input {
invoiceId: string;
/** @default 0 */
amount?: number;
}
interface Output {
approved: boolean;
}
export default defineFunction({
name: "approve-invoice",
method: "POST",
path: "/invoice", // omit method+path entirely for a run-as-job function
input: defineSchema<Input>(),
output: defineSchema<Output>(),
handler: async (input, ctx) => {
if (!ctx.user?.accessToken) throw new FunctionError("Unauthorized", 401);
return { approved: input.amount! < 10_000 }; // success data only — errors are thrown
},
});
Authoring detail, local dev, HTTP semantics, deployment, bindings, Coded App wiring: references/js/ (navigation below).
CLI Reference
uip function new <NAME> -l py|ts|js [--empty] # scaffold (TypeScript default; --empty is JS/TS only)
uip function init # Python only — entry-points.json, project.uiproj, empty bindings.json skeleton
uip function serve [--port 7070] [--runtime node|deno] # JS/TS only — local HTTP server, hot reload
uip function run # both languages — one-shot local execution
uip function pack [--nolock] # build the .nupkg
uip function publish [--feed-id <FEED_ID>] # upload package to a process feed
uip function push --project-id <PROJECT_ID> [--ignore-resources] # sync sources to Studio Web and import bindings.json resources
uip function runtime-install # JS/TS — one-time runtime pre-install (otherwise downloaded on first serve/run)
The retired plural spelling (
functions) is not available — always write the singularuip function.
Reference Navigation
| I need to… | Read |
|---|---|
| Python: full workflow — scaffold, schema, template, registration, dependencies, init, SDK calls, attachments, pack | python/workflow-guide.md |
Python: derive and sync bindings.json from SDK resource calls — per-resource schema, SubType, entrypoint binding, what push does | python/bindings-reference.md |
| JS/TS: write handlers, contracts, ctx, errors, logging | js/authoring-guide.md |
| JS/TS: run and test locally (serve, run, env, tokens) | js/local-dev-guide.md |
| JS/TS: routing, status codes, deployed limits | js/http-semantics-guide.md |
| JS/TS: run-as-job mode, fault semantics | js/job-mode-guide.md |
| JS/TS: pack, publish, invoke in prod, solutions, cold start | js/deployment-guide.md |
| JS/TS: bindings — entry-points.json, bindings_v2.json, overrides | js/bindings-guide.md |
| JS/TS: call UiPath APIs from a function (uipath-typescript, IS) | js/calling-uipath-apis-guide.md |
| JS/TS: wire a Coded App frontend to a function backend | js/coded-app-wiring-guide.md |
Anti-patterns
Python
- Instantiating
UiPath()at module level — always a lazy singleton inside a getter (Python Rule 1). - Raising exceptions from the entrypoint — populate the error output fields and return (Python Rule 2).
- Skipping
uip function initafter a schema change — staleentry-points.jsonships wrong contracts (Python Rule 3). - Shipping
bindings.jsonwith"resources": []while the code calls SDK resources —initonly creates the skeleton; derive the entries (Python Rule 7).
JS/TS
throw new Error("…")— generic 500, raw stack leaked, no author-controlled status — JS Rule 1.- Returning an
errors[]array inside a 200. Output schemas carry success data only; a function throws one error at a time. - zod/arktype contracts on new functions — break static extraction, drag a runtime dependency — JS Rule 2.
- Extensionless relative imports — work locally, hang production cold start — JS Rule 4.
- Runtime dependency in
devDependenciesor on a private registry — skipped or unfetchable at cold start — JS Rule 5. - Adding
server.proxyto the Coded App's Vite config to reach the function — it breaks the app's OAuth callback; fetchhttp://localhost:7070/<PATH>directly (serve sends CORS*). - Accepting
baseUrl/orgId/tenantIdas function input — redirect risk; usectx.platform— JS Rule 9. - Calling the portal domain from a browser — no CORS there; browsers must call the
api.<HOST>subdomain. console.logfor production diagnostics — never reaches job logs — JS Rule 10.- Building the invoke URL from the trigger's own Id — 404 errorCode 1623; the URL takes the folder Key GUID + package id + slug.
- Expecting a caller to recover a result after 25 s — keep HTTP functions under 20 s, move longer work to a run-as-job function — JS Rule 6.