
Initial Release
Visual orchestration for InterSystems IRIS maintenance tasks
Every task a squad member. Every flow a coordinated attack.
IRIS maintenance jobs such as integrity checks, journal switches, purges and compaction are
usually scheduled one at a time in the Task Manager. Their order, their dependencies and “what
happens if one fails” are kept in someone’s head or in a runbook.
SentaiTask turns that tacit knowledge into a declared, validated, observable flow:
Like a sentai squad, each step has its own role, and the flow decides when they move together.
SentaiTask is an ObjectScript backend on top of the IRIS management API (/api/admin), plus a
canvas UI that IRIS serves itself. It does not reimplement the platform’s permissions: every
platform call is made with the operator’s own credential (Constitution III, Delegated
Authorization).
sentai.model): Flow, Step, Edge, Join, Run, StepRun and LogEntry, persistedALL_MUST_SUCCEED.sentai.registry.StepType): a closed, compiled catalog. No code is eversentai.validation.FlowValidator): a single gate shared by validate, dispatch/validate can never be run.sentai.dispatch.WaveDispatcher): creates the Run and one StepRun persentai.rest.Dispatcher): /csp/sentai/api/v1, with password + JWTfrontend/): SvelteKit + Svelte Flow, compiled to static files in a Node stageDockerfile and served by IRIS’s own web server at /csp/sentai/ throughsentai.web.StaticFiles, behind the IRIS password (no unauthenticated web app). No Node┌─────────────────────────────────────────────────────────────┐
│ Operator (curl / canvas UI) │
└─────────────────────────┬───────────────────────────────────┘
│ Bearer token from /api/admin/login
▼
┌─────────────────────────────────────────────────────────────┐
│ REST /csp/sentai/api/v1 (sentai.rest) │
│ flows · validate · dispatch · runs · events (SSE) · wqm │
└──────────┬──────────────────────────────┬───────────────────┘
│ │
▼ ▼
┌──────────────────────┐ ┌───────────────────────────────┐
│ FlowValidator │◀─────│ WaveDispatcher │
│ one gate for │ │ Run + StepRuns (1 tx) │
│ validate/dispatch/ │ │ waves → %SYSTEM.WorkMgr │
│ schedule │ │ (per WQM category) │
└──────────┬───────────┘ └──────────────┬────────────────┘
│ categories │ start / poll / pause
▼ ▼
┌─────────────────────────────────────────────────────────────┐
│ IRIS management API /api/admin (platform) │
│ wqm-categories · database-dir/integrity-check · │
│ async-result │
└─────────────────────────────────────────────────────────────┘
git clone https://github.com/musketeers-br/sentai-task.git
cd sentai-task
docker-compose up -d --build
The build compiles the canvas, loads the sentai-task module and registers the REST application
/csp/sentai/api/v1 on http://localhost:52773. When the container is up, open
http://localhost:52773/csp/sentai/
Sign in to the canvas with your IRIS user (_SYSTEM / SYS on this dev image). That sign-in
exchanges the password for short-lived API tokens, which stay in memory only; the password is
never stored.
What is public and what is not: the page itself (HTML, JS, CSS) is served without
authentication bysentai.web.StaticFiles, which only reads the canvas build and holds no
data. Its code lives in a small database,SENTAIWEB, and the app’s roleSentaiWebPageonly
lets the anonymous request enter the namespace (read on its default globals database). Every
flow and run goes through the REST API, which always requires a token.
In an IRIS instance with the IPM client:
USER>zpm "install sentai-task"
The Dark / Light switch in the top bar changes theme on every screen.


The API uses the same 60-second JWT as the IRIS management API:
TOKEN=$(curl -s -X POST -u _SYSTEM:SYS http://localhost:52773/api/admin/login | jq -r .access_token)
Two integrity checks run in parallel and fan in to a third:
curl -s -X POST http://localhost:52773/csp/sentai/api/v1/flows \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{
"schemaVersion": 1,
"name": "nightly-checks",
"defaultCategory": "Default",
"steps": [
{"id": "01", "type": "integrity-check", "taskName": "IC USER", "namespace": "USER", "wqmCategory": "Default"},
{"id": "02", "type": "integrity-check", "taskName": "IC IRISAPP", "namespace": "IRISAPP", "wqmCategory": "Default"},
{"id": "03", "type": "integrity-check", "taskName": "IC %SYS", "namespace": "%SYS", "wqmCategory": "Default"}
],
"edges": [ {"source": "01", "target": "03"}, {"source": "02", "target": "03"} ],
"joins": [ {"target": "03", "policy": "ALL_MUST_SUCCEED"} ]
}'
curl -s -X POST http://localhost:52773/csp/sentai/api/v1/flows//validate -H "Authorization: Bearer $TOKEN" # {"errors":[],"warnings":[]}curl -s -X POST http://localhost:52773/csp/sentai/api/v1/flows//dispatch -H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json" -d '{"confirmations": []}'202 {"guid": "", "state": "running", ...}
curl -N http://localhost:52773/csp/sentai/api/v1/runs//events -H "Authorization: Bearer $TOKEN"
event: step-state-changed ... event: run-terminal
Steps 01 and 02 start together. Step 03 stays queued until both complete.
A run dispatched like this keeps the 60-second token it was given. To let it run longer, sign in
separately for the run and add that sign-in’s refresh token to the body,
"runCredential": {"refreshToken": "…"}, while sending its access token in Authorization. The
run then renews its own credential and erases it when it ends. The canvas does this for you.
| Area | Endpoints |
|---|---|
| Flows | GET/POST /flows · GET/PUT /flows/{id} · POST /flows/{id}/validate · POST /flows/{id}/dispatch · POST /flows/{id}/schedule |
| Runs | GET /runs · GET /runs/{guid} · GET /runs/{guid}/events (SSE) · POST /runs/{guid}/cancel · POST /runs/{guid}/pause |
| Steps | POST /runs/{guid}/steps/{stepGuid}/cancel · …/pause · …/rerun |
| Catalog | GET /catalog/step-types · GET /catalog/tasks · GET /catalog/tasks/{id} · POST /catalog/tasks/{id}/suspend |
| WQM | GET /wqm/categories · GET/PUT /wqm/categories/{name} |
Validation errors come back as {"errors": [{"stepId", "code", "message"}], "warnings": [...]},
with codes such as CYCLE_DETECTED, STEP_TYPE_NOT_SUPPORTED_ON_TARGET and CATEGORY_NOT_FOUND.
SentaiTask v1 only promises what was proven on IRIS 2026.2 (spec 004-backend-hardening):
integrity-check runs. The other six step types (compact-globals,defragment-globals, switch-journal, purge-audit-records, purge-task-history, custom)GET /catalog/step-types with available: false, and saved flows that useSTEP_TYPE_NOT_SUPPORTED_ON_TARGET./schedule validates the flow and registers a native task,runCredential), with which the run renews its own credential until it ends —runCredential (e.g. plain curl) keeps the 60 sdatabaseDirectory and similar fields do not choose what the platform operates on.CATEGORY_NOT_FOUND. The default for new flows, SENTAI.DEFAULT, does not exist on a stockDefault.docker exec -it sentai-task-iris-1 iris session iris -U IRISAPP
IRISAPP>zpm "load /home/irisowner/dev"
IRISAPP>zpm "test sentai-task -only"
The suite (sentai.unittest.*, 115 methods) runs against a test double of the management API, so
it never starts real platform jobs through the admin API.
The canvas has unit tests and end-to-end acceptance tests (these need Node 20+ on your machine and
the container running):
cd frontend
npm ci
npm test # unit tests (vitest)
npx playwright install chromium
npm run test:e2e # acceptance tests against http://localhost:52773
The acceptance tests drive real runs, so they take about six minutes; screenshots and captures
land in https://github.com/musketeers-br/sentai-task/blob/master/specs/002-canvas-ui/evidence/.
sentai-task/
├── src/sentai/
│ ├── model/ # Flow, Step, Edge, Join, Run, StepRun, Category, LogEntry
│ ├── registry/ # StepType: closed catalog (destructive / pausable / available)
│ ├── validation/ # FlowValidator: the single gate
│ ├── dispatch/ # WaveDispatcher, AdminApiClient, ScheduledFlowTask
│ ├── wqm/ # CategoryService: WQM read/write passthrough
│ ├── catalog/ # TaskService: native Task Manager catalog
│ └── rest/ # Dispatcher: REST API + SSE
├── tests/sentai/unittest/ # %UnitTest suites + AdminApiDouble
├── frontend/ # Canvas UI: SvelteKit + Svelte Flow, built to static files
├── design/ # Canvas UI prototypes (spec 002)
├── specs/ # Spec-driven history: 001 contract spike → 004 hardening
├── scripts/sanitation/ # Reviewed cleanup of historical test residue
├── module.xml
└── docker-compose.yml
runCredential (runs > 60 s work)SentaiTask is developed with 💜 by the Musketeers Team:

This project is licensed under the MIT License.
When the flow validates clean, the squad suits up.
