Skip to content

Script skills: build, approve and use Python scripts in skills

Admin

A script skill is a skill that ships its own Python script next to its instructions (SKILL.md). The assistant calls the script instead of doing the work itself: it reads your file locally, computes by fixed rules and stores the result as a file — for example a SEPA credit transfer file from a CSV payment list. The model only sees the short summary the script returns, not the data. How ordinary skills without a script work is described in Upload new skills via ZIP.

  • Desktop app on macOS or Windows. On Windows, script skills are tested on Windows 11 (x64); the app also offers them on ARM64 devices, but they are not tested there yet. Known limits are listed below in the section “Windows specifics”. On Linux they are not offered; the app then shows “Script skills are not yet released on this operating system.” The web edition does not have them.

  • Pro license or higher (Pro or Site). In Free the app shows an upgrade notice instead.

  • Administrator role for uploading, approving and rebuilding.

  • uv is installed (Astral’s Python package manager). CompanyWizard does not ship uv. If it is missing, the Skills page shows the install command:

    • macOS:

      curl -LsSf https://astral.sh/uv/install.sh | sh
    • Windows (PowerShell):

      powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
  • Internet access for the one-off environment build: github.com, objects.githubusercontent.com and release-assets.githubusercontent.com (Python interpreter) as well as pypi.org and files.pythonhosted.org (packages). If a firewall filters outbound traffic, allow these hosts.

The sample SEPA transfers from CSV is a complete script skill that uses only the Python standard library:

It contains the skill, the script and the payment list example.csv with one deliberately invalid IBAN.

  1. Upload — on the Skills page choose Upload Skills (.zip) and select sepa-transfers.zip. The skill appears in the catalog, but the script is not runnable yet.
  2. Open the skill — select sepa-transfers in the skill tree. Above the instructions, the Scripts area shows the script sepa_from_csv with the status Not approved, its Version (short form of the checksum), its Packages (here: none) and No network access.
  3. Approve — check the description, packages and network hosts, then Approve. Optionally tick In chat without confirmation; the confirmation dialog in chat is then skipped for this script.
  4. Wait for the environment — after approval CompanyWizard builds the Python environment: Environment: being built, then ready. Only then is the script offered.
  5. Use it in chat — put example.csv into a folder, attach that folder in chat as the working folder, enable the skill sepa-transfers in the session’s skill selection and write: “Create a SEPA file from example.csv, execution on 2026-11-02, ordering party Example Trading Ltd with IBAN DE02120300000000202051.”
  6. Confirm — a dialog shows the script, parameters, input files and network access. After you confirm, the script runs. The answer names two payments, the total and the warning about the invalid IBAN in line 4; the file sepa-2026-11-02.xml is in the working folder.

A script skill is a top-level folder in the ZIP:

my-skill/
SKILL.md instructions for the assistant: when and how to call the script
skill-scripts.yaml manifest: scripts, parameters, inputs and outputs, network
requirements.txt optional: packages with checksums
scripts/*.py the scripts

This is how it looks in the sample:

python: "3.12"
scripts:
- name: sepa_from_csv
description: "Creates a SEPA bulk credit transfer (pain.001.001.09) from a CSV payment list"
entry: scripts/sepa_from_csv.py
parameters:
properties:
execution_date:
type: string
pattern: "^[0-9]{4}-[0-9]{2}-[0-9]{2}$"
debtor_account:
type: string
pattern: "^[A-Z]{2}[0-9]{2}[A-Z0-9]{11,30}$"
debtor_name:
type: string
required: [execution_date, debtor_account, debtor_name]
inputs: { min: 1, max: 1, extensions: [".csv"], max_mb: 5 }
outputs: { extensions: [".xml"] }
timeout_seconds: 60
network: deny
FieldMeaning
pythonPython version that uv provides, e.g. "3.12".
name, descriptionName of the script and the description the assistant sees.
entryPath to the .py file, relative to the skill folder, without ...
parametersParameters of type string, integer, number or boolean, optionally with a pattern; required lists the mandatory ones. CompanyWizard checks them before the start.
inputsNumber (min, max), allowed extensions and size per file (max_mb, at most 200, which is also the default).
outputsExtensions of the files the script creates.
timeout_secondsTime limit, default 60, at most 3600.
networkdeny or allowlist:host1,host2 with plain host names.

A secrets field is rejected. The Skills page shows manifest errors right after the upload (“These skills ship scripts that cannot be approved yet:”) and in the Scripts area under “Problems with the script manifest”.

  • Start: like python scripts/<file>.py in a fresh working directory, without stdin and without further arguments — input() does not work. Your own modules in the script folder can be imported as usual.
  • Input: the environment variable CW_REQUEST points to a request.json with {"parameters": {…}, "inputs": ["in/…"]}. The input files are copies under in/.
  • Output: the script writes files to the folder in CW_OUTPUT_DIR.
  • Result: on stdout it prints exactly one JSON object: {"summary": "…", "warnings": […], "metrics": {…}, "files": […]}. Only summary is mandatory. This is everything the assistant sees of the run.
  • Limits: stdout may be at most 64 KiB, otherwise the result is rejected. summary is cut after 4000 characters, each warning after 500.
  • Errors: an exit code other than 0 counts as an error. What the script writes to stderr never reaches the assistant; it only goes to the app’s log. So report domain problems as warnings — the assistant passes them on to the user.
  • Environment variables: only PATH, HOME, LANG, LC_*, TZ, TMPDIR plus CW_REQUEST and CW_OUTPUT_DIR; on Windows also SystemRoot, SystemDrive, windir, PATHEXT, COMSPEC, LOCALAPPDATA, TEMP and TMP. CompanyWizard’s credentials never reach the script.

Without a requirements.txt only the standard library is available. If you need packages, generate the file with checksums:

uv pip compile requirements.in --generate-hashes -o requirements.txt
  • Every entry needs --hash=sha256:…. If a checksum is missing, the manifest is rejected.
  • No option lines such as --index-url, -e or -r; they are rejected too. What you see in the file is exactly what gets installed.
  • Wheels only. If a package exists only as a source distribution, the environment build fails with a note about the source package. Pick a version that has a wheel for your operating system.

Pack the skill folder so that it is the top level of the ZIP and upload it as above. The assistant itself can neither create nor change script skills — they only enter the system through a ZIP upload.

  • An approval covers exactly the checked version. CompanyWizard computes a checksum over all files of the skill (excluding __pycache__, __MACOSX, .DS_Store) and checks it before every start. If a file changes — a new upload, an edit —, the script shows “Changed since approval - approval pending” and only runs again after a new approval.
  • Same packages, same environment. Scripts with an identical requirements.txt and Python version share one environment.
  • Rebuild environment discards the environment and builds it afresh, for example after you installed uv or when the build failed. While a script is running in that environment, this is refused.
  • Revoke withdraws the approval; the script is no longer offered from then on.
  • The skill has to be active in the session’s skill selection. → Enable skills and use them in chat
  • Input files come from the attached working folder or as a kb: path from a knowledge area the user may read.
  • Result files land in the working folder, without a working folder in the desktop app’s output folder. An existing file is never overwritten. → Where does CompanyWizard save documents?
  • Before every run the confirmation dialog appears — unless the script is approved In chat without confirmation. That is only possible for scripts without network hosts. In Plan mode the app always asks.
  1. Open the agent, tab Tools. In the Skill scripts section, tick the approved scripts. This also switches on the tool run_skill_script; if you later untick it in the tool list, the scripts are switched off for this agent.
  2. In the same tab, set a working folder — a script reads input files only from this folder. For the SEPA sample, the CSV goes there.
  3. Optionally choose an Output folder for scripts. Empty means: the working folder. If the agent has a “Working folder” storage target (Scope tab), scripts write there — the target takes precedence over the output folder and is enough on its own for saving. Without a storage target and without either folder the agent cannot be saved (“Scripts need an output folder or a working folder for this agent.”). With a “Vault” storage target, scripts are not offered. → Chain agents
  4. Scripts with network hosts only run in the agent if Allow scripts with network access is ticked.
  5. Also enable the skill in the Skills tab so the agent knows the instructions from the SKILL.md.

Agents run without a confirmation dialog and may not use kb: inputs. If a script cannot run, the reason appears at the start of the run’s summary: ”⚠ Scripts could not be run: …”.

  • Original data. A script works with the original files, not with pseudonymized data — that is its purpose. If it may use the network, it can send this data to its approved hosts. The Skills page and the agent point this out (“This script receives original data (not pseudonymized) and may send it to these hosts.”). Approving the hosts is your trust decision.
  • Sandbox. Every run has its own working directory; the script may write only there. Network access exists only to the approved hosts.
  • Read restriction. On macOS and Windows the script reads only its working directory, its Python environment and fixed system paths. On macOS it can tell that a file exists elsewhere, how large and how old it is — but it cannot read or list it.
  • Environment build on Windows. On Windows, CompanyWizard builds the Python environment outside the sandbox, because uv cannot work inside it. The build only installs the packages from requirements.txt with their checksums and runs no code from the skill. Its network traffic goes through the app’s proxy, which steers and logs it but does not enforce it. On macOS the build also runs in the sandbox.
  • No virtual machine. As with the CLI tool, this is best-effort containment, not VM isolation. → Command-line tools (CLI) in the assistant — overview & limits
  • At most two scripts run at the same time; further ones wait.
  • No os.devnull. A script that uses subprocess.DEVNULL or open(os.devnull) fails on Windows with PermissionError. Redirect output to a file in the working directory instead, or capture it with subprocess.PIPE.
  • Network scripts on standard accounts. Scripts with network hosts have so far been tested only under a user account with administrator rights. Under a standard account such a script may fail because it cannot reach the app’s proxy. Scripts without network access are not affected.
MessageWhat to do
”uv is not installed. …”Install uv with the command shown, then Rebuild environment.
Environment: build failedRead the reason shown: often a package without a wheel, or a firewall blocking the hosts from the prerequisites. Fix it, then Rebuild environment.
”Changed since approval - approval pending”The skill has changed. Review the changes and Approve again.
”Script skills are not yet released on this operating system.”Script skills run on macOS and Windows, not on Linux.
A script that runs on macOS stops on WindowsLook for PermissionError in the app’s log: often the script uses subprocess.DEVNULL or open(os.devnull), see “Windows specifics”.
”The license has expired and is read-only. …”Approving, rebuilding and running work again after renewal; revoking works at any time.
The script stops, the assistant names only an exit codeThe error output (stderr) is in the app’s log. Better report domain problems as warnings.