Repository navigation
v0.30.0
Chap's job blocks read a released Chap as well as master. Chap v2.5.1, the newest release,
answers a job's status as a bare word ("SUCCESS") where master answers with the whole job, so
chap.dataset.import, chap.backtest.run and chap.prediction.run stayed running forever against
it. They now read both shapes: PENDING, RECEIVED, STARTED and RETRY wait, SUCCESS ends,
and FAILURE, REVOKED and REJECTED fail. A status word outside those keeps the step waiting and
is logged once per job; an answer with no usable status fails as chap.job.unreadable.
follow_for bounds a Chap job. The three job blocks take follow_for, 6h by default. A job
still unsettled past it fails as chap.job.not_settled, transient, naming the job and its last
status; a shorter step deadline still ends the wait first. follow_for is not sent to Chap.
Docs. "Following a job" on the Chap blocks page, the install and Chap examples pages run as
written, and the shelf documents' run lines name the shelves where they are.
Requires dirigent 0.30.0.
The dirigent 0.30.0 notes follow.
Released 2026-11-01. Every package in the workspace moves to 0.30.0 together, and so do
dirigent-dhis2, dirigent-contrib, dirigent-fhir and dirigent-integration.
The FHIR pack gains a search that feeds a fan-out, FHIRPath, validation, CQL and measures.
dirigent-fhir's main adds fhir.search's emit: pages | resources for a following for_each,
transform.fhirpath, map.fhirpath and filter.fhirpath on the verb frames, fhir.validate
(structural, on the engine's R4 models), and fhir.cql and fhir.measure (a CQL library, and a
measure answered as a MeasureReport), released with this version. application/fhirpath and
text/cql join the program media types in dirigent_common.programs, and a field publishing
either refuses a ${...} at apply (document.step_reference_in_fhirpath,
document.step_reference_in_cql) and when the step starts (reference.in_fhirpath,
reference.in_cql), as a template does: a value reaches the expression as a variable, and the
library as a parameter.
FHIRPath and CQL are highlighted where they are written. The web UI's program editor tokenises application/fhirpath and text/cql fields in the house inks, both palettes, with a %name or $this in the ink a jq $name wears.
Every instance serves MCP over HTTP at /mcp. An agent connects to the instance itself with
its own API token, claude mcp add --transport http dirigent https://<instance>/mcp --header "Authorization: Bearer …", and nothing is installed beside it. Each request acts as the token it
presents, a viewer token is offered only the tools that read, and every tool is a call to the
instance's own API, so the API decides what a role may do. A request without a token that resolves
is answered 401, and one a page on another origin caused is answered 403
(server.mcp_cross_origin). The session cookie does not authenticate there. mcp_enabled
(default on) turns it off, and mcp_max_body, mcp_session_idle and mcp_max_sessions bound it.
The stdio command uvx dirigent-mcp is unchanged, and both offer a new whoami tool.
dirigent-mcp --transport http serves MCP in front of a remote instance. It listens on
127.0.0.1:3334 and answers only a loopback Host, takes each caller's own bearer token and
forwards it to DG_URL, never DG_TOKEN, and refuses another origin's page. An address other
machines can reach needs --allow-remote.
More MCP tools, and resources to write a document against. list_connections,
get_connection and check_connection (secrets redacted; checking is admin only), list_schemas
and get_schema, list_alert_rules and get_alert_rule, get_source with an endpoint's full URL
and how a caller authenticates, and rotate_source_token, marked destructive. get_run answers
how a source's input arrived (via) and stored_bytes. Every tool's readOnlyHint,
destructiveHint, idempotentHint and openWorldHint now say what its call does. The resources
dirigent://schema/document, dirigent://blocks and dirigent://blocks/{block_id} serve the
format and the catalogue. GET /api/v1/alert-rules/{code} reads one rule, and the client's
alerts.rule() and blocks.document_schema() call it and GET /schema/document.
dirigent-fhir is on PyPI, and dg init --pack dirigent-fhir adds it. The FHIR pack, a fhir
connection kind and the fhir.read, fhir.search, fhir.create, fhir.update and
fhir.transaction blocks for one FHIR R4 server, is published at 0.29.0 and pinned at the
runtime's version like dirigent-dhis2 and dirigent-contrib, in the flag and the form. It moves
with each release from now on, and the integration make test covers it.
A polled source keeps a cadence shorter than the poll tick. A worker used to look for due
sources only every source_poll_tick (5s), so a sensor source with poll: 1s ran every five
seconds and "poked again at once after a success" waited out the tick. A worker now sleeps until
the earliest polled source falls due, at most source_poll_tick and never less than 50
milliseconds. source_poll_tick is now the longest a worker goes without looking.
dg source list, show and inputs render at a terminal. They wrote NDJSON whatever the
terminal, -o console included. A source now reads as one line: its state, its step, the
pipeline, what it listens to, and what it has taken, with a warning level when it last failed. An
input reads as what came of it, its run or its refusal and reason. In a pipe they write the same
source and source.input records as before.
A pipeline.run step says which step of its child failed. A child run that failed on a step
used to surface as run … failed: no reason was recorded. A run's snapshot now carries its first
failed step and that step's error, step 'load' failed: … (run.step_failed), so the parent's
step reads run … failed: step 'load' failed: ….
Refusals that name what uses a thing agree with how many there are. Removing a connection or a
schema something still names reads … while it is named by pipeline nightly or … by pipelines a, b, in the API and in the browser, instead of while pipeline nightly name it. schema.in_use
carries the clause as a new users param beside pipelines and count. A header secret with a
control character reads no HTTP header can carry … and one was found in api_key.
An endpoint source says where it is called and how. The pipeline page, the editor's step
panel and the triggers screen's panel show an endpoint's methods and full URL with a copy button,
and how a caller authenticates: a bearer token, an HMAC signature, or public. New token (New secret on a signed source) asks first, then shows the new credential once with a curl line that
calls the endpoint with it. The triggers screen used to replace a token without asking.
A run says how it started, and whether its reply reached anybody. The run page reads by admin, from the sample, by admin, with an input given, or by a call to ask. A reply's box says sent
or not sent, and its panel says sent to the caller or recorded, not sent. The Run… dialog on
a pipeline with a source says it starts from the source's sample and that nobody receives the reply.
AttemptOut gains via, how a source's input arrived (request, poll, hold, hand, or
sample for a hand run that gave no input).
A step that runs no block says what it is. The editor's canvas and step panel name a reply
reply, as the run graph does, rather than no block, and the pipeline page draws no Blocks panel
for a pipeline whose steps run none.
The navigation rail resizes again. Drag its right edge between 152px and 320px, or focus the
edge and use the arrow keys, Home and End; the width is remembered in each browser, and a
double-click on the edge gives back the 168px it opens at. Cmd/Ctrl+B and Show navigation still
hide and show it whole.
dirigent-contrib moves with each release. It relocks at the tagged commit and takes the same
version as dirigent-dhis2 and dirigent-integration, and the integration make test that is run
before a release is called done covers it.