Integration 101: Your First Module in 15 Minutes
Objective
Create a minimal Istari Digital Platform module using a shell script — no Python framework, no build tools. The module:
- Accepts an input text file
- Copies it to the output with a timestamp header
- Can be executed through the Istari Digital Platform
By completing this tutorial, you'll learn:
- How to structure a platform module
- How to define function inputs and outputs using the file contract
- How to test, deploy, and run your module
- How to set up and configure the Istari Digital Agent to execute jobs
Namespace: Throughout this tutorial, replace
<namespace>with your own unique namespace (e.g. your name or team:alice,teamx). This keeps your module key unique when multiple developers share the same platform control plane.
For example: module key@alice:integration-101, function key@alice:copy, tool keyalice-tool.
Prerequisites
- Access to an Istari Digital Platform environment (e.g.
dev.istari.app) - Docker and Docker Compose installed
- The Istari Digital CLI for Linux (amd64) — obtain it from Artifactory.
- The Istari Digital Agent installer for Linux (amd64) — a
.debpackage or tarball from the same source
Key Concepts
Modules
A module is a package containing one or more functions that the Istari Digital Agent can execute. Modules are language-agnostic but must follow a file-based contract for communication.
Your module can be anything executable: a shell script, a Python script, a compiled binary. In this tutorial we use a simple bash script.
Functions
Functions define:
- Inputs: Models (files) and parameters
- Outputs: Files or directories generated by the function
- Execution: How the function runs (command, environment)
File Contract
The Agent runs your module functions by executing a command (run_command in the manifest). It passes three paths:
- input file (
input_file.json) — JSON with model file paths and parameters - output file (
output_file.json) — your module writes a JSON array of output file metadata here - temp dir — Temporary directory for intermediate files
Step 1: Start the Docker Environment
1.1 Create the Dockerfile
FROM ubuntu:24.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
zip \
unzip \
ca-certificates \
jq \
nano
WORKDIR /workspace
CMD ["sleep", "infinity"]
1.2 Create docker-compose.yml
services:
istari-tutorial:
build: .
image: istari-tutorial:24.04
platform: linux/amd64
container_name: istari-tutorial
volumes:
- .:/workspace
- ./downloads:/downloads:ro
working_dir: /workspace
stdin_open: true
tty: true
Note:
platform: linux/amd64is required because the Istari Digital CLI and Agent are only available for amd64. On Apple Silicon Macs this runs under Docker emulation.
1.3 Place downloads
mkdir -p downloads
# Copy the CLI tarball and Agent .deb here, e.g.:
# cp /path/to/stari_ubuntu_24_04-amd64-v<VERSION>.tar.gz downloads/
# cp /path/to/istari-agent_<VERSION>_amd64.deb downloads/
In this tutorial we are using
- stari_ubuntu_24_04-amd64-v0.21.1.tar
- istari-agent_10.1.2_amd64
1.4 Start the container and open a shell
docker compose up -d --build
docker compose exec istari-tutorial bash
You are now in a bash shell inside Ubuntu 24.04 (amd64). The project root is mounted at /workspace, and downloads/ is at /downloads (read-only).
All remaining steps are run inside this container.
Editing files: The Dockerfile includes
nano, so you can edit files directly inside the container (e.g.nano module_manifest.json). You can also use your preferred editor on the host — because/workspaceis a mounted volume, any changes you make on the host are immediately visible inside the container.
Step 2: Install and Initialize the CLI
2.1 Install the CLI
Extract and set up the CLI from /downloads:
cd /tmp
tar -xzf /downloads/stari_ubuntu_24_04-amd64-v0.21.1.tar
./stari_ubuntu_24_04-amd64/stari_ubuntu_24_04-amd64 setup
The setup installs the Istari Digital CLI in your path; accept the prompt:
Istari Digital CLI Setup
==================================================
⚠ The 'stari' CLI is not currently on your PATH.
You're running it from: /tmp/stari_ubuntu_24_04-amd64/stari_ubuntu_24_04-amd64
Would you like to add 'stari' to your PATH now? [y/n] (y): y
Update your PATH and check stari CLI:
source ~/.bashrc
stari --version
2.2 Generate credentials and create a .env file
- Access the Istari Digital Platform (e.g.
dev.istari.app). - Go to Developer Settings → generate an API Key and copy the Registry URL.
- Go to Admin Settings → generate an Agent PAT (shown only once; store it securely).
Note: To access Developer Settings and Admin Settings, click on your name at the bottom of the left sidebar.
Create a .env file in your project root (on the host) with these values:
REGISTRY_URL=<registry-url>
API_KEY=<your-api-key>
AGENT_PAT=<your-agent-pat>
Inside the container, load the variables:
cd /workspace
source /workspace/.env
2.3 Initialize the CLI
stari client init "$REGISTRY_URL" "$API_KEY" --yes
stari client ping
You should see a successful connection.
Successfully connected
Successfully connected to Istari Digital at <registry_url>.
2.4 Patch the config file
Workaround: The CLI does not write a
defaultsection to the config file, but the Agent requires it. Without this step the Agent will fail withKeyError: 'default'on startup.
echo "default: {}" >> /root/.config/istari_digital/istari_digital_config.yaml
Step 3: Create the Module
No scaffolding needed. Create the module directory with just two files: a manifest and a shell script.
mkdir -p /workspace/my-module
cd /workspace/my-module
3.1 Create the shell script
Create copy.sh:
#!/usr/bin/env bash
# Istari module: copies input file to output with a timestamp header.
# Usage: copy.sh --input-file <path> --output-file <path> --temp-dir <path>
set -e
# Parse arguments
while [[ $# -gt 0 ]]; do
case "$1" in
--input-file) INPUT_FILE="$2"; shift 2 ;;
--output-file) OUTPUT_FILE="$2"; shift 2 ;;
--temp-dir) TEMP_DIR="$2"; shift 2 ;;
*) shift ;;
esac
done
# Read the input file path from the input JSON
FILE_PATH=$(jq -r '.input_file.value' "$INPUT_FILE")
# Copy with timestamp header
OUTPUT_PATH="${TEMP_DIR}/copied_file.txt"
echo "# Processed at $(date -Iseconds)" > "$OUTPUT_PATH"
echo "" >> "$OUTPUT_PATH"
cat "$FILE_PATH" >> "$OUTPUT_PATH"
# Write the output JSON
echo '[{"name": "copied_file", "type": "file", "path": "'"${OUTPUT_PATH}"'"}]' > "$OUTPUT_FILE"
Make it executable:
chmod +x copy.sh
3.2 Create the manifest
Create module_manifest.json (replace <namespace>):
{
"module_key": "@<namespace>:agent-101",
"module_version": "1.0.0",
"module_checksum": "placeholder",
"module_type": "function",
"module_display_name": "101 Tutorial",
"tool_key": "<namespace>-tool",
"tool_versions": ["1.0.0"],
"operating_systems": ["Ubuntu 24.04"],
"agent_version": ">=9.0.0",
"internal": false,
"authors": [
{
"name": "Your Name",
"email": "you@example.com"
}
],
"functions": {
"@<namespace>:copy": [
{
"entrypoint": "copy.sh",
"run_command": "bash {entrypoint} --input-file {input_file} --output-file {output_file} --temp-dir {temp_dir}",
"operating_systems": ["Ubuntu 24.04"],
"tool_versions": ["1.0.0"],
"function_schema": {
"inputs": {
"input_file": {
"type": "user_model",
"validation_types": ["@extension:txt"],
"optional": false,
"display_name": "Input File"
}
},
"outputs": [
{
"name": "copied_file",
"type": "file",
"required": true,
"upload_as": "artifact",
"display_name": "Copied File"
}
]
}
}
]
}
}
Key points:
module_key:@<namespace>:agent-101— unique per developer on the control plane.tool_key:<namespace>-tool— shown in the Platform UI when granting tool access.- The function key
@<namespace>:copymust use the same namespace asmodule_key. run_commandcallsbash {entrypoint} ...— the Agent resolves{entrypoint}to the path ofcopy.sh.- The shell script parses
--input-file,--output-file,--temp-dirlike any CLI tool. - We are using a simple shell script but the same approach works with any executable, including a compiled binary.
Validate the manifest
stari module lint module_manifest.json
Step 4: Test Locally
cd /workspace/my-module
mkdir -p test_run
echo "Hello, Istari!" > test_run/input.txt
Create test_run/input.json:
{
"input_file": {
"type": "user_model",
"value": "test_run/input.txt"
}
}
Run the script:
bash copy.sh \
--input-file test_run/input.json \
--output-file test_run/output.json \
--temp-dir test_run
Check the results:
cat test_run/output.json
cat test_run/copied_file.txt
You should see the copied file with a timestamp header.
Step 5: Package and Publish
5.1 Package
cd /workspace/my-module
zip -r /workspace/my-module.zip . -x "test_run/*"
5.2 Publish to the Platform Registry
stari client publish module_manifest.json
5.3 Provide access
The user who publishes the module has access by default. To give access to other users:
- Open Admin Settings (click your name at the bottom of the left nav bar).
- Select User → select a user → open the ellipsis menu (⋯).
- Select Manage Tool Access.
- Check the tool that matches your
tool_key(e.g.alice-tool).
Step 6: Set Up the Agent
The Agent runs on the machine (or container) and polls the Platform for jobs. When a job is available, the Agent executes your module locally. Both the Agent and the module must be installed on the same machine.
6.1 Install the Agent
dpkg -i /downloads/istari-agent_10.1.2_amd64.deb
The Agent is installed to /opt/local/istari_agent/.
6.2 Initialize the Agent
Use the variables from your .env file (loaded in Step 2.2):
source /workspace/.env
stari agent init "$REGISTRY_URL" "$AGENT_PAT"
Enable headless mode: Open the config file and add istari_digital_agent_headless_mode: true under the agent: section. This is required when running the Agent without a graphical display (e.g. in Docker or over SSH).
echo " istari_digital_agent_headless_mode: true" >> /root/.config/istari_digital/istari_digital_config.yaml
6.3 Install the Module on the Agent
mkdir -p /opt/local/istari_agent/istari_modules/my-module
cp /workspace/my-module.zip /opt/local/istari_agent/istari_modules/my-module/
unzip -o /opt/local/istari_agent/istari_modules/my-module/my-module.zip -d /opt/local/istari_agent/istari_modules/my-module
6.4 Start the Agent
/opt/local/istari_agent/istari_agent_<VERSION>
Your Agent version may vary.
Expected result (successful start): You should see Agent logs with basic information:
- MainThread - INFO - Agent initialized
- MainThread - INFO - Istari agent version 10.1.2
- MainThread - INFO - Configuration: istari_digital_agent_poll_interval=15
...
- MainThread - INFO - Agent ID: 063d23f7-49aa-4386-9f58-260d2ed7cb58
- registration_thread - INFO - Got display name 'trusty-oin-4579' from server
- MainThread - INFO - No compatible jobs
- MainThread - INFO - Checking for available jobs
The Agent is polling; leave it running.
Step 7: Run the Function via the Platform
In the Platform UI:
- Upload a
.txtfile. - Select the file and choose Create Job.
- In the Select a tool/function dropdown, select the tool and function you created.
- Execute the job.
This starts a Job that you can monitor in the Jobs section.
Check the Agent logs in the terminal where the Agent is running.
You should see entries like:
Found available job 6b1d8333-d0c8-4d9b-992e-975724a5e8c6
CLAIMING JOB STATE: job 6b1d8333...
EXECUTING JOB STATE: job 6b1d8333...
Running process 6b1d8333... in cwd /opt/local/istari_agent/istari_modules/my-module with command: ['bash', '/opt/local/istari_agent/istari_modules/my-module/copy.sh', '--input-file', '...input.json', '--output-file', '...output.json', '--temp-dir', '...out']
Process 6b1d8333... completed succesfully
Return code for job 6b1d8333...: 0
Job 6b1d8333... completed successfully
EXECUTION SUCCESS STATE: job 6b1d8333...
Check results
In the Platform UI:
- Go to the Files tab.
- Find your file and view the artifact generated by the job.
Cleaning Up
When you are done, exit the container and stop it:
exit
docker compose down
Summary: What You've Achieved
By completing this tutorial, you've built and deployed your first Platform module with a @<namespace>:copy function that:
- Accepts a text file as input,
- Adds a timestamp header to the content,
- Returns the processed file as an artifact,
- Runs as a job on the Istari Digital Platform.
Key Skills You've Learned
- Module Structure: How to create a module with just a script and a manifest.
- Function Design: Defining inputs, outputs, and execution logic.
- Local Testing: Validating your function before deployment.
- Deployment Workflow: Packaging, publishing, and granting access to your module.
- Agent Integration: Setting up and running the Agent to execute jobs.
Troubleshooting
DisplayNameError: Bad display name ""
The Agent tries to start a system-tray icon, which requires a graphical display. In Docker or over SSH (headless), there is no display and the Agent crashes.
Fix: Enable headless mode in your Agent config. Add the following under agent: in istari_digital_config.yaml:
agent:
istari_digital_agent_headless_mode: true
KeyError: 'default'
The CLI doesn't write a default section but the Agent expects it.
Fix: echo "default: {}" >> /root/.config/istari_digital/istari_digital_config.yaml
Module version 1.0.0 already exists
HTTP response body: {"detail":"Malformed Manifest: \"Module version 1.0.0 already exists.\""}
The registry rejects a publish if that exact version has already been uploaded. Module versions are immutable once published.
Fix: Bump module_version in module_manifest.json (e.g. 1.0.0 → 1.0.1) and publish again.