Unreleased documentation. These pages follow the main branch and can change before the next release. For supported guidance, use v0.26.1.
If you are evaluating Registry Casework as the inbox
for a team that reviews changes to a registry the
Base Registry Engine (BReg) holds, start with one
change request and one review.
You will generate a registry project and a Casework project that fit each other, connect them, run
both on your machine, submit a change request to the registry, approve and apply it from the Casework
inbox as Staff, and read the applied change back from the registry.
Everything you keep goes into one directory, tutorial-work.
Install both products
Section titled “Install both products”Install breg, bregctl, and mint, then casework and caseworkctl.
Registry Mint issues the local access tokens this
tutorial uses, standing in for the identity provider a deployment would have; both installers
ship it, and either copy serves:
curl -fsSL https://github.com/registrystack/registry-stack/releases/latest/download/breg-install.sh | bashbregctl --versionmint --versioncurl -fsSL https://github.com/registrystack/registry-stack/releases/latest/download/casework-install.sh | bashcaseworkctl --versionEach installer checks its binaries against the release SHA256SUMS before anything reaches
~/.local/bin, and installs them together or not at all.
Keep that directory on your PATH.
The two commands must print the same version, because caseworkctl dev drives bregctl and
refuses one from another release.
The URL takes the latest release, and a deployment pins a version instead.
The command pipes a script from GitHub into bash; | less in place of | bash reads it first.
Verify the release as described in OpenSSF and release trust,
then rerun the installers with BREG_ASSET_DIR and CASEWORK_ASSET_DIR pointing at the verified
directory.
Create the two projects
Section titled “Create the two projects”Open a terminal in a directory of your choice and generate both projects.
Keep this terminal in the same directory for the rest of the tutorial; every path starts with
tutorial-work/.
mkdir -p tutorial-workbregctl init tutorial-work/registry --template professional-licencescaseworkctl init tutorial-work/casework --template professional-reviewbregctl init reports 12 artifacts written, then 0 errors, 10 findings and three next steps.
The findings name profiles that may list every row; they are the starter’s declared authority,
reviewed in Create and query your first registry, and nothing in this tutorial
depends on them.
caseworkctl init reports init succeeded., lists the files it created, and names
caseworkctl source add as what to run next.
What the two projects declare
Section titled “What the two projects declare”The professional-licences starter is a registry of professional licences, with a
professional-license entity and a scope-correction change request that proposes a correction to
one licence and applies it only after a review stage named review.
Its dev-clients.yaml declares the reader, editor, and reviewer clients the local session
registers with Mint.
The professional-review template is a Casework deployment over that registry: one source,
professional-register, using the breg adapter; one request kind, the scope-correction entity,
routed to the corrections queue; and the staff, supervisor, and administrator profiles.
Its dev-clients.yaml declares one client per profile and a corrections-team serving the queue.
The two fit because the Casework template names the entity the registry starter declares. A registry that declared no change request would give Casework nothing to present.
Connect the registry to Casework
Section titled “Connect the registry to Casework”Casework needs a description of the registry it presents, and the registry needs an event
destination and a reader profile for Casework.
caseworkctl source add derives both from the registry project, and previews before it writes:
caseworkctl source add tutorial-work/registry --project tutorial-work/casework --source-id professional-registerThe report begins source add succeeded. with status: preview at its end, and its
bregAuthoringChanges line lists the six places it will change in the registry project:
bregAuthoringChanges: [{"file":"registry.yaml","operation":"ensure_exact","path":"/entities/scope-correction/events/casework-lifecycle-v1"},{"file":"registry.yaml","operation":"ensure_exact","path":"/accessProfiles/casework-reader"},{"file":"dev-clients.yaml","operation":"ensure_exact","path":"/clients/casework-reader"},{"file":"dev-clients.yaml","operation":"ensure_exact","path":"/clients/administrator"},{"file":"dev-clients.yaml","operation":"ensure_exact","path":"/clients/supervisor"},{"file":"dev-clients.yaml","operation":"ensure_exact","path":"/clients/staff"}]The rest of the report is omitted here: bregAuthoringPatch carries the exact declarations those
six paths receive, and candidateRuntimeBinding the event destination a deployment would configure.
In registry.yaml, a lifecycle event on scope-correction tells Casework when a request changes,
and a casework-reader access profile lets Casework read requests and nothing else.
In dev-clients.yaml, a casework-reader client is the credential the local Casework session
reads the registry with, and administrator, supervisor, and staff are the Casework project’s
own people, registered with the registry’s Mint so one token serves both products. Staff and
Supervisor are explicitly admitted to BReg because they review and apply its requests;
Administrator remains a Casework-only caller.
Read the preview, then write it:
caseworkctl source add tutorial-work/registry --project tutorial-work/casework --source-id professional-register --applyThe command rewrites registry.yaml and dev-clients.yaml in tutorial-work/registry with the
declarations the preview listed.
On a project of your own, commit or copy the two files first, so the diff shows exactly what Casework
asked for.
The report now ends status: applied, and next names the two steps a deployment takes from here:
provisioning the webhook secret the runtime binding references, and running caseworkctl doctor.
The local sessions do both for you.
The command wrote tutorial-work/casework/sources/professional-register.json, the source
description Casework serves from, and professional-register.breg-runtime.yaml beside it, the
runtime binding a deployment would hand to the registry.
Start the registry
Section titled “Start the registry”Both runtimes store their records in Docker volumes on your machine, and the private keys they
generate live in tutorial-work/registry/.breg/dev/ and tutorial-work/casework/.casework/dev/,
owner-only directories that stay out of version control.
Nothing here is configured for anyone else’s data.
Start the registry:
bregctl dev tutorial-work/registryThe first start downloads the pinned PostgreSQL image, so it takes longer than the later ones.
The command returns once the registry answers, with status ready in its report.
dev started PostgreSQL in a container, started Mint, registered the seven clients from
dev-clients.yaml under a fresh key each, built the registry package, and started breg.
The report names the registry address, the token endpoint, the audience, and one credential directory per client, as absolute paths under your directory:
bregctl dev succeeded. status ready project <your-directory>/tutorial-work/registry breg url http://127.0.0.1:8090 token endpoint http://127.0.0.1:8091/token audience urn:breg:dev:<identifier>The remaining lines, the package revision, the state and runtime files, the webhook receiver, and
the seven client blocks, are omitted here.
The four clients source add wrote are among the seven: casework-reader, administrator,
supervisor, and staff.
The services keep running after the command returns, so this one terminal is enough.
Start Casework
Section titled “Start Casework”Start the Casework project beside the running registry:
caseworkctl dev tutorial-work/casework --source-project tutorial-work/registry--source-project names the registry project whose local session stands in for the deployed
registry.
The command returns once Casework answers, with status: ready in its report.
dev started a second PostgreSQL container, read the registry session’s state, borrowed its Mint as
the token issuer, exported the casework-reader credential and the three human clients from the
registry session, wrote an operator file binding the source to the registry’s address, migrated the
database, started casework, and seeded the directory from
dev-clients.yaml.
The report names the Casework address, the token endpoint it shares with the registry, the audience, and the credential paths, as absolute paths under your directory:
dev succeeded.audience: urn:breg:dev:<identifier>caseworkUrl: http://127.0.0.1:8092sources: {"professional-register":{"bregUrl":"http://127.0.0.1:8090","project":"<your-directory>/tutorial-work/registry"}}stateFile: <your-directory>/tutorial-work/casework/.casework/dev/state.jsonstatus: readytokenEndpoint: http://127.0.0.1:8091/tokenThe clients, directory, journal, operatorConfig, and project lines between them are
omitted here.
The audience and the token endpoint are the registry session’s: a Staff token minted there is
valid at both products, which is what lets Casework carry your authority to the registry.
Use the two addresses from the reports. These assignments use the default ports or the
CASEWORKCTL_DEV_CASEWORK_PORT override; if you started the registry with --mint-port, replace
the token endpoint:
casework_url="http://127.0.0.1:${CASEWORKCTL_DEV_CASEWORK_PORT:-8092}"token_endpoint="http://127.0.0.1:8091/token"credentials=tutorial-work/casework/.casework/dev/credentialsKeep this terminal open so the values remain available to the later commands.
Submit a change request
Section titled “Submit a change request”The registry starter ships two examples: first-record creates a licence, and reviewed-change
drafts and submits a scope-correction against it.
Run the first, as the registry’s own editor client:
bregctl examples run first-record tutorial-work/registryThe report begins bregctl examples run succeeded. and names the attempt and the record it
created, then shows the create and get results as JSON.
The licence MY-FIRST-001 holds one licensed activity, example-assessment, and the condition
Supervized community practice.
The identifiers vary per run; the rest of the report is omitted here.
Submit the correction:
bregctl examples run reviewed-change tutorial-work/registry --step submitThe report names a second attempt and, under Example progress retained, the request it created.
Its draft result shows the proposed values, two licensed activities and an empty condition, and
its submit result reads "operation": "submit_request".
The request now waits in the registry’s review stage.
The registry is what holds the request; Casework learns of it through the lifecycle event source add declared and through reconciliation, which the local session runs every five seconds.
Open the inbox as Staff
Section titled “Open the inbox as Staff”Ask Mint for a token as the staff client and write it into a file curl can send as an
authorization header:
umask 077mint token --url "$token_endpoint" \ --client-id "$(cat "$credentials/staff/client-id")" \ --key "$credentials/staff/assertion-key.jwk" \ | sed 's/^/Authorization: Bearer /' > tutorial-work/staff.headerSuccess prints nothing.
mint token signs a request with the client’s private key and posts it to the token endpoint, the
way an application would; the token carries the casework:staff scope Casework’s staff profile
requires and the starter:reviewer scope the registry’s reviewer profile requires, and lasts five
minutes.
tutorial-work/staff.header holds a bearer token that acts as Staff at both products until it
expires.
umask 077 makes it readable only by your user.
Keep it out of version control, screenshots, and support messages.
List the work items the Staff client’s team serves, polling until the request arrives, because Casework learns of it through the registry’s event and its own reconciliation rather than at the moment you submitted:
for _ in $(seq 1 30); do curl --silent --show-error \ --header @tutorial-work/staff.header \ --header 'Registry-Casework-Profile: staff' \ --header 'Registry-Source-Profile: reviewer' \ --output tutorial-work/inbox.json --write-out 'HTTP %{http_code}\n' \ "$casework_url/v1/work-items?view=my_teams&queue=corrections&limit=25" python3 -c 'import json, sys; items = json.load(open("tutorial-work/inbox.json")).get("items", []); sys.exit(0 if any(item["occurrenceKind"] == "review" for item in items) else 1)' && break sleep 2doneHTTP 200Each poll prints one status line; the first poll is enough when the event has already arrived. If the loop runs for its full minute, the item never came: see Troubleshooting.
Every Casework request carries Registry-Casework-Profile, the profile the caller acts under.
A request touching a registry source also carries Registry-Source-Profile, the
source profile the caller acts under at the
registry: Casework reads the registry as you, under that profile, so what you see is what
the registry lets a reviewer see.
Read the inbox:
python3 -m json.tool tutorial-work/inbox.json{ "items": [ { "itemId": "5a7c9171-4eee-4fdc-ae0c-6c99b88ef496", "subject": { "sourceId": "professional-register", "kind": "scope-correction", "id": "3610928e-39c5-4085-94fd-a34109011922" }, "occurrenceKind": "review", "stage": "review", "binding": { "sourceRevision": "2", "version": "1", "integrity": "sha256:3d36e5d90957f52d675844dd16bfd2f0d41156df43a233ba5fe11ee2d9068b6f", "generation": "sha256:1bd6b87fce7b9f214402b9297862ac581765734df7d53f4b19e7b39a007adc50" }, "bindingReference": "sha256:183223f7c0702240c70b00b7b951d188e8c05685fb4de07857a2706bb18ef8f2", "state": "open", "queueId": "corrections", "revision": 1, "firstObservedAt": "2026-09-12T12:42:14.890712Z", "passiveDueAt": "2026-09-14T12:42:14.890712Z", "updatedAt": "2026-09-12T12:42:14.890712Z", "routing": { "policyDigest": "sha256:d44d1f8398aaceab1cbbaee94e78130403f7cd7e634227dae8efe36c12f2b67c" }, "actions": [ { "operation": "claim", "href": "/v1/work-items/5a7c9171-4eee-4fdc-ae0c-6c99b88ef496/claim", "ifMatch": "\"1\"" } ] } ], "status": "complete", "servedQueues": [ "corrections" ]}Identifiers, digests, and timestamps vary per run.
subject is the registry’s request: its id is the request identifier the submit step reported.
occurrenceKind is review and stage is review, because the registry’s scope-correction
declares one review stage of that name and the request is waiting in it.
binding pins the registry revision and the request’s effect digest this item was observed at, so
a decision you make names exactly what you looked at.
passiveDueAt is the first-review-response target the Casework template declares, 48 hours after
the item was observed.
actions offers claim with the ifMatch value that version of the item answers to.
Approve the review
Section titled “Approve the review”A claim makes you the holder, so two people do not review the same request twice. Renew the Staff token before you act, so time spent reading the inbox cannot turn this request into an authentication refusal:
mint token --url "$token_endpoint" \ --client-id "$(cat "$credentials/staff/client-id")" \ --key "$credentials/staff/assertion-key.jwk" \ | sed 's/^/Authorization: Bearer /' > tutorial-work/staff.headerTake the identifier and the offered ifMatch value of the review item from the inbox rather than
typing them:
item_id=$(python3 -c 'import json; items = json.load(open("tutorial-work/inbox.json"))["items"]; print(next(item["itemId"] for item in items if item["occurrenceKind"] == "review"))')claim_match=$(python3 -c 'import json; items = json.load(open("tutorial-work/inbox.json"))["items"]; actions = next(item["actions"] for item in items if item["occurrenceKind"] == "review"); print(next(action["ifMatch"] for action in actions if action["operation"] == "claim"))')Claim it:
curl --silent --show-error \ --header @tutorial-work/staff.header \ --header 'Registry-Casework-Profile: staff' \ --header 'Registry-Source-Profile: reviewer' \ --header "If-Match: $claim_match" \ --header 'Idempotency-Key: tutorial-claim-review' \ --header 'Content-Type: application/json' \ --data '{}' \ --output tutorial-work/claimed.json --write-out 'HTTP %{http_code}\n' \ "$casework_url/v1/work-items/$item_id/claim"HTTP 200A write carries Idempotency-Key so a retry after a lost response returns the first result instead
of acting twice.
Read the part of the response that changed:
python3 -c 'import json; item = json.load(open("tutorial-work/claimed.json"))["item"]; print(json.dumps({key: item[key] for key in ("state", "revision", "holder", "actions")}, indent=2))'{ "state": "claimed", "revision": 2, "holder": { "issuer": "http://127.0.0.1:8091", "subject": "professional-review-staff" }, "actions": [ { "operation": "release", "href": "/v1/work-items/5a7c9171-4eee-4fdc-ae0c-6c99b88ef496/release", "ifMatch": "\"2\"" }, { "operation": "delegate", "href": "/v1/work-items/5a7c9171-4eee-4fdc-ae0c-6c99b88ef496/delegate", "ifMatch": "\"2\"" }, { "operation": "approve", "href": "/v1/work-items/5a7c9171-4eee-4fdc-ae0c-6c99b88ef496/decisions", "ifMatch": "\"2\"" }, { "operation": "reject", "href": "/v1/work-items/5a7c9171-4eee-4fdc-ae0c-6c99b88ef496/decisions", "ifMatch": "\"2\"" }, { "operation": "request_correction", "href": "/v1/work-items/5a7c9171-4eee-4fdc-ae0c-6c99b88ef496/decisions", "ifMatch": "\"2\"" } ]}The holder is the issuer and subject Mint put in the token, the registry’s Mint and the
registry_principal claim the staff client declares, and the revision moved to 2.
actions now offers the three decisions the registry’s review stage admits, beside release and
delegate, each carrying the new ifMatch.
Build the approval from the claim response, because a decision names the binding you had in front of you and the registry profile you decide under:
python3 -c 'import json; item = json.load(open("tutorial-work/claimed.json"))["item"]; json.dump({"displayedBinding": item["binding"], "sourceProfileId": "reviewer", "operation": "approve"}, open("tutorial-work/approve.json", "w"), indent=2)'approve_match=$(python3 -c 'import json; actions = json.load(open("tutorial-work/claimed.json"))["item"]["actions"]; print(next(action["ifMatch"] for action in actions if action["operation"] == "approve"))')Approve:
curl --silent --show-error \ --header @tutorial-work/staff.header \ --header 'Registry-Casework-Profile: staff' \ --header 'Registry-Source-Profile: reviewer' \ --header "If-Match: $approve_match" \ --header 'Idempotency-Key: tutorial-approve' \ --header 'Content-Type: application/json' \ --data @tutorial-work/approve.json \ --output tutorial-work/approved.json --write-out 'HTTP %{http_code}\n' \ "$casework_url/v1/work-items/$item_id/decisions"HTTP 200A decision without If-Match is refused with 428 and code precondition.required, because
Casework will not forward a decision made on an unknown version of the item.
Read the attempt the decision created:
python3 -c 'import json; attempt = json.load(open("tutorial-work/approved.json"))["attempt"]; print(json.dumps({key: attempt[key] for key in ("state", "operation", "receipt")}, indent=2))'{ "state": "completed", "operation": "approve", "receipt": { "sourceRevision": "3", "resultingState": "approved", "binding": { "sourceRevision": "3", "version": "1", "integrity": "sha256:3d36e5d90957f52d675844dd16bfd2f0d41156df43a233ba5fe11ee2d9068b6f", "generation": "sha256:1bd6b87fce7b9f214402b9297862ac581765734df7d53f4b19e7b39a007adc50" }, "actorReference": "hmac-sha256:016f12c016e49957aa570b4b6de8ca157b189803a9328fad15301397cd0d82f6", "metadata": { "nativeReceipt": "{\"actorReference\":\"hmac-sha256:016f12c016e49957aa570b4b6de8ca157b189803a9328fad15301397cd0d82f6\",\"id\":\"3610928e-39c5-4085-94fd-a34109011922\",\"request\":{\"application\":null,\"bregState\":\"approved\",\"effectDigest\":\"sha256:3d36e5d90957f52d675844dd16bfd2f0d41156df43a233ba5fe11ee2d9068b6f\",\"proposal\":{\"applicationDisposition\":\"queue\",\"reviewMode\":\"staged\"},\"proposalVersion\":1},\"revision\":3,\"snapshot\":\"breg1_945a9384-6249-42d8-92ae-5017b55c0d63\"}", "traceId": "01a095a46ed9087e47b3b8c15dd23dee" } }}Casework did not approve anything itself: the attempt carried
your decision to the registry under the reviewer profile, and the receipt is the registry’s
answer.
"resultingState": "approved" and "bregState":"approved" inside nativeReceipt are the
registry saying the request passed its review stage at its revision 3.
The item in the same response reads "state": "synchronizing" with no actions, because the
review occurrence is finished and Casework is catching up with what the registry did next.
"applicationDisposition":"queue" in the receipt is why there is a next step: this change request
declares that an approved change is applied by a second explicit decision, not on approval.
Apply the change
Section titled “Apply the change”The registry queued the approved change for application, and Casework presents that as a second
work item on the same request.
Renew the token, then poll the inbox for an item whose occurrenceKind is application:
mint token --url "$token_endpoint" \ --client-id "$(cat "$credentials/staff/client-id")" \ --key "$credentials/staff/assertion-key.jwk" \ | sed 's/^/Authorization: Bearer /' > tutorial-work/staff.headerfor _ in $(seq 1 30); do curl --silent --show-error \ --header @tutorial-work/staff.header \ --header 'Registry-Casework-Profile: staff' \ --header 'Registry-Source-Profile: reviewer' \ --output tutorial-work/inbox.json --write-out 'HTTP %{http_code}\n' \ "$casework_url/v1/work-items?view=my_teams&queue=corrections&limit=25" python3 -c 'import json, sys; items = json.load(open("tutorial-work/inbox.json")).get("items", []); sys.exit(0 if any(item["occurrenceKind"] == "application" for item in items) else 1)' && break sleep 2doneHTTP 200A poll in the seconds after the approval may print HTTP 409, because the review item is still
synchronizing; the loop reads again.
Read the new item’s identity:
python3 -c 'import json; items = json.load(open("tutorial-work/inbox.json"))["items"]; item = next(item for item in items if item["occurrenceKind"] == "application"); print(json.dumps({key: item[key] for key in ("occurrenceKind", "binding", "state", "revision", "actions")}, indent=2))'{ "occurrenceKind": "application", "binding": { "sourceRevision": "3", "version": "1", "integrity": "sha256:3d36e5d90957f52d675844dd16bfd2f0d41156df43a233ba5fe11ee2d9068b6f", "generation": "sha256:1bd6b87fce7b9f214402b9297862ac581765734df7d53f4b19e7b39a007adc50" }, "state": "open", "revision": 1, "actions": [ { "operation": "claim", "href": "/v1/work-items/7d1358c3-0859-415b-a7ad-adbcc4f56191/claim", "ifMatch": "\"1\"" } ]}It is a different item, with its own identifier and revision 1, bound to the registry revision the approval produced. Claim it the same way:
item_id=$(python3 -c 'import json; items = json.load(open("tutorial-work/inbox.json"))["items"]; print(next(item["itemId"] for item in items if item["occurrenceKind"] == "application"))')claim_match=$(python3 -c 'import json; items = json.load(open("tutorial-work/inbox.json"))["items"]; actions = next(item["actions"] for item in items if item["occurrenceKind"] == "application"); print(next(action["ifMatch"] for action in actions if action["operation"] == "claim"))')curl --silent --show-error \ --header @tutorial-work/staff.header \ --header 'Registry-Casework-Profile: staff' \ --header 'Registry-Source-Profile: reviewer' \ --header "If-Match: $claim_match" \ --header 'Idempotency-Key: tutorial-claim-application' \ --header 'Content-Type: application/json' \ --data '{}' \ --output tutorial-work/claimed.json --write-out 'HTTP %{http_code}\n' \ "$casework_url/v1/work-items/$item_id/claim"HTTP 200The claim response offers apply beside release and delegate.
Build the application from it and send it:
python3 -c 'import json; item = json.load(open("tutorial-work/claimed.json"))["item"]; json.dump({"displayedBinding": item["binding"], "sourceProfileId": "reviewer", "operation": "apply"}, open("tutorial-work/apply.json", "w"), indent=2)'apply_match=$(python3 -c 'import json; actions = json.load(open("tutorial-work/claimed.json"))["item"]["actions"]; print(next(action["ifMatch"] for action in actions if action["operation"] == "apply"))')curl --silent --show-error \ --header @tutorial-work/staff.header \ --header 'Registry-Casework-Profile: staff' \ --header 'Registry-Source-Profile: reviewer' \ --header "If-Match: $apply_match" \ --header 'Idempotency-Key: tutorial-apply' \ --header 'Content-Type: application/json' \ --data @tutorial-work/apply.json \ --output tutorial-work/applied.json --write-out 'HTTP %{http_code}\n' \ "$casework_url/v1/work-items/$item_id/decisions"HTTP 200Read the receipt:
python3 -c 'import json; receipt = json.load(open("tutorial-work/applied.json"))["attempt"]["receipt"]; print(json.dumps({key: receipt[key] for key in ("sourceRevision", "resultingState")}, indent=2)); print(json.loads(receipt["metadata"]["nativeReceipt"])["request"]["application"])'{ "sourceRevision": "4", "resultingState": "applied"}{'applicationId': '646bb184-848d-4222-a20e-8d7e1f8fec31', 'appliedAt': '2026-09-12T12:43:19.267466Z', 'effectDigest': 'sha256:3d36e5d90957f52d675844dd16bfd2f0d41156df43a233ba5fe11ee2d9068b6f', 'proposalVersion': 1}"resultingState": "applied" is the registry reporting that it wrote the correction into the
licence; applicationId and appliedAt are its record of that write.
The effectDigest is the one the inbox item’s binding.integrity carried from the start: what was
applied is what you were shown.
Verify the registry
Section titled “Verify the registry”Casework’s receipts are the registry’s answers, and the registry holds the record.
Ask it, through the retained example attempt, as the reviewer client:
bregctl examples run reviewed-change tutorial-work/registry --step inspectThe inspect result carries the request as the registry holds it.
Among its lines, with identifiers and timestamps that vary per run:
"bregState": "applied", "decisions": [ { "decidedAt": "2026-09-12T12:42:56.622404Z", "kind": "approve", "reasonPresent": false, "stageId": "review" } ], "resultLinks": [ { "targetEntityId": "professional-license", "targetRecordId": "f372d369-4823-4c93-beea-7975135d4235", "targetRevision": 2 } ]The request is applied, its one decision was an approve in stage review, and resultLinks
names the licence revision the application wrote: revision 2 of the record first-record created.
The report’s closing next command offers --step approve, which no longer applies to a request
the registry has applied; the rest of the report is omitted here.
Read the licence’s history:
bregctl examples run reviewed-change tutorial-work/registry --step historyThe history result lists two revisions of the licence, newest first.
Revision 2 is a patch carrying "example-assessment" and "example-practical-services" under
licensedActivities and an empty authorizationConditions; revision 1 is the create with the
original single activity and condition.
Each carries an actorReference, the registry’s opaque handle for who acted, and a
requestReference: the correction is in the registry’s own history as an ordinary revision made
through review, and nothing about Casework is in it.
Stop both sessions
Section titled “Stop both sessions”Stop Casework first, then the registry, because Casework reconciles against the registry while it runs:
caseworkctl dev stop tutorial-work/caseworkbregctl dev stop tutorial-work/registryEach report’s status reads stopped.
The containers and their volumes stay, with the licence, the request, the work items, and the
attempts, and the two start commands from Start the registry and
Start Casework, in that order, bring the same runtimes back.
Stopping with --remove deletes a session’s container and its volume.
For Casework, the work items and attempts go with them; for the registry, the licence and the
request.
Nothing here restores them.
caseworkctl dev stop tutorial-work/casework --removebregctl dev stop tutorial-work/registry --removeEither way, keep tutorial-work/: the two projects inside it are what the configuration guides
edit, and tutorial-work/casework/sources/ holds the connection source add wrote.
What you built
Section titled “What you built”You generated a registry project and a Casework project that fit each other, connected them with one command, ran both as services sharing one token issuer, submitted a change request to the registry, approved and applied it from the Casework inbox as Staff, and read the applied revision from the registry’s own history. The registry decided what you were allowed to see and do; Casework coordinated who held the work and carried your decisions.
Troubleshooting
Section titled “Troubleshooting”Renew an expired token
Section titled “Renew an expired token”A local token lasts five minutes.
Run the mint token command for the staff client again; it replaces the header file.
If it fails, the registry session is stopped: start it again with the command from
Start the registry, then start Casework, then renew.
Other problems
Section titled “Other problems”| Symptom | Next move |
|---|---|
bregctl, caseworkctl, or mint is not found | Add the installer’s directory, ~/.local/bin unless you changed it, to PATH in this terminal. |
caseworkctl dev refuses over a reported version | The bregctl, casework, or mint it resolved comes from another release than caseworkctl. The refusal names both versions. Install both products from the same release, or put the matching build first on PATH. |
caseworkctl dev refuses a project that declares a source | It was started without --source-project. A source binding needs a running registry session; pass --source-project tutorial-work/registry after bregctl dev reports ready. |
bregctl dev refuses a port | Something else listens on 8090, 8091, or 55432. Pass --breg-port, --mint-port, or --database-port on the first start; later starts keep the ports you chose. With --mint-port, change the token_endpoint assignment in Start Casework. |
caseworkctl dev refuses a port | Something else listens on 8092 or 55433. Set CASEWORKCTL_DEV_CASEWORK_PORT or CASEWORKCTL_DEV_DATABASE_PORT, or pass --casework-port or --database-port, on the first start; the casework_url assignment picks the first up. The session borrows the registry’s Mint, so its own Mint port is unused. |
Either dev command fails before it reports ready | Read the refusal: it names the check that failed. Otherwise check that Docker is running. bregctl dev events tutorial-work/registry and caseworkctl dev events tutorial-work/casework show the retained journals; do not share the credential files beside them. |
| The inbox loop runs its full minute with no item | Check that the submit step reported "operation": "submit_request", and that the registry session is still running: bregctl dev tutorial-work/registry reuses a running session and reports status ready. Then read the Casework journal with caseworkctl dev events tutorial-work/casework for the source reconciliation it logged. |
An inbox read returns 400 with code source-profile.required | A source-backed inbox is read under a registry profile. Send Registry-Source-Profile: reviewer. |
A request returns 401 with code authentication.refused | The token expired, or the header file is stale. Mint it again, as Renew an expired token describes. |
A request returns 400 with code request.invalid | Another required or structured input is missing or malformed. Every request carries Registry-Casework-Profile, and every write also carries Idempotency-Key; source-backed reads name a source profile as described above. |
A decision returns 428 with code precondition.required | The If-Match header is missing. Take the ifMatch value from the actions entry for the operation you want in the claim response. |
A claim or decision returns 412 with code precondition.failed | The item moved. Re-read it, take the ifMatch value from the actions entry for the operation you want, and send it again. |
An inbox read or a claim returns 409 | The item is synchronizing with the registry, or another caller holds it. Read the inbox again a few seconds later; its actions array shows what remains open to you. |
A decision returns 422 with code request.source-rejected | The registry refused the promoted action body. Fix the decision request before trying again; re-reading the inbox does not fix this refusal. |
A decision returns 502 with code source.bad-gateway | The registry answered outside its registered contract. Check that the registry session is ready; if it is, inspect the Casework journal for the invalid response class. |
| You opened a fresh terminal | Run the casework_url, token_endpoint, and credentials assignments from Start Casework again. The header file and tutorial-work directory are still there. |
- Connect a Base Registry Engine source for what
source addwrote and how a deployment binds the same source. - Review changes before updating a registry to change the registry’s review stage the inbox presented.
- How Casework works for the model behind claims, attempts, and receipts.
- Deploy Registry Casework for the runtime binding and reconciliation interval a deployment declares.
- Registry Casework API reference for where Casework’s authority ends and the source’s begins.