Case study · Majordomus // Tech demo · case study Technical

Case study: AI-assisted delivery under a supervisory control layer

Published 2026-09-14 · 18 min read

One person directed an AI coding agent that built this bilingual site on 14 September 2026 under Majordomus 0.6.0. From the ledger, Git and GitHub records, this case study shows how the supervisory layer was configured and used, what it caught, what it cost and what it does not check.

Supervised tasks
6
Checkpoints
7
Handovers
4
Decisions
4
Findings
8
Commits
11
Pipeline runs
8
Releases
6
First commit to first verified release
51.0 min 37 s 14 September 2026, 09:54:05 → 10:45:42 UTC · from Majordomus initialisation: 19.0 min 19 s

Snapshot of the records through · Majordomus 0.6.0 · data/case_study.json

The task lifecycle

Select a step to see its registered command, why it exists and a real recorded example. Every step has its own address, so a link opens it directly.

  1. 1 Start with a scope
  2. 2 Check
  3. 3 Watch for drift
  4. 4 Checkpoint
  5. 5 Record decisions
  6. 6 Hand over
  7. 7 Finish with verification
  8. 8 Read the ledger

1 / 8 Start with a scope

Command
majordomus start "<task>" --scope <paths>
What it does
Opens the checkout's single active task with a title, a profile and the paths the work may touch.
Why
A scope turns what the agent was asked to change into a list a tool can compare with the working tree.
Recorded example
Task started: Ship Catharsis as a Service: Zola EN/CS site, CI/CD to GitHub Pages, live verification, automatic releases
Profile implementation; scope of 26 paths.

2 / 8 Check

Command
majordomus check
What it does
Reports, without writing anything, whether the task is consistent with the policy, its scope and the recorded state.
Why
Problems show up on the machine, before a push or a pipeline run.
Recorded example
A scope of "." was caught before the first push
The restarted task declared its scope as ".", which Majordomus does not read as the whole repository, so majordomus check reported every changed file as out of scope. The task was restarted with explicit top-level paths before the first push.

3 / 8 Watch for drift

Command
majordomus watch
What it does
Reports drift between the recorded task, its scope, the policy and the generated instruction files.
Why
Moving or adding files changes what a task touches, often without anyone deciding it.
Recorded example
Scope drift after files were moved; task restarted
The first task claimed 20 paths but not the root files that were moved into artwork/ and static/. The handover records that majordomus watch reported the drift; the task was finished as partial and restarted before the first push.

4 / 8 Checkpoint

Command
majordomus checkpoint < note.md
What it does
Records a short progress note of at most 40 lines, or derives one from Git.
Why
Progress lives in a file instead of in the agent's conversation.
Recorded example
Checkpoint: Ship Catharsis as a Service: Zola EN/CS site, CI/CD to GitHub Pages, live verification, automatic releases
Authored progress note (at most 40 lines by policy); the body stays in the checkout's local state.

5 / 8 Record decisions

Command
majordomus decision add "<decision>" --why "<rationale>"
What it does
Appends a dated decision with its rationale, the rejected alternatives and the evidence.
Why
The next worker can see why something is the way it is, and a person can promote the decision to an ADR.
Recorded example
Structured data is built as Tera data and serialised with json_encode
Why: Hand-written JSON-LD inside HTML templates gets HTML-escaped and breaks on quotes; building the graph as template maps keeps escaping correct by construction. Rejected: hand-written JSON-LD strings; a client-side script injecting JSON-LD. Evidence: templates/partials/structured-data.html; scripts/validate-html.py parses every JSON-LD block.

6 / 8 Hand over

Command
majordomus handover < body.md
What it does
Writes a continuation record with Objective, Current State and Next Action; branch, commit and changed files come from Git.
Why
Any outcome other than completed has to say what comes next, so a restart depends on recorded facts.
Recorded example
Handover written: current state and next action
Current state: Phase A validated locally: validate.sh 7/7, Playwright 37/37. Not yet committed or deployed. New top-level paths (requirements-dev.txt, Rust workspace, data/, schemas/) fall outside this task scope. Next action: Restart the task with a scope covering all planned paths, commit and deploy Phase A, then implement Phase B and Phase C.

7 / 8 Finish with verification

Command
majordomus finish --outcome completed --verify-command "npm run smoke"
What it does
Evaluates the finish contract. Completed requires a verification command that exits 0, recorded with its exit code and duration.
Why
Done means the live site passed a check, not that code was written.
Recorded example
Task finished as completed: Ship Catharsis as a Service: Zola EN/CS site, CI/CD to GitHub Pages, live verification, automatic releases
Finish contract: 7 pass, 4 skipped; verification command scripts/smoke-production.sh https://korczis.github.io/catharsis-as-a-service/ exited 0 in 7 s.

8 / 8 Read the ledger

Command
majordomus history
What it does
Prints the append-only ledger of starts, checkpoints, decisions, handovers and finishes.
Why
Every claim on this page can be traced to one of its lines.
Recorded example
Majordomus layer initialised; provider instruction files generated
The policy was projected into 3 instruction files (AGENTS.md, CLAUDE.md, GEMINI.md) that point every agent at .ai/README.md.

Timeline

Every recorded event, oldest first: Majordomus tasks, checkpoints, handovers, decisions and finishes, the findings derived from them, commits, pipeline runs and releases. Open an event for its detail and links. Filters are kept in the address, so a filtered view can be bookmarked.

  1. Commit feat(poster): add Catharsis as a Service poster with print render

    No Pages pipeline run for this commit (it predates the workflow).

  2. Task Majordomus layer initialised; provider instruction files generated

    The policy was projected into 3 instruction files (AGENTS.md, CLAUDE.md, GEMINI.md) that point every agent at .ai/README.md.

  3. Task Task started: Ship Catharsis as a Service: Zola EN/CS site, CI/CD to GitHub Pages, live verification, automatic releases

    Profile implementation; scope of 20 paths.

  4. Handover Handover written: current state and next action

    Current state: Site sources, templates, styles, scripts and tests written; validation in progress. The first task scope omitted the pre-existing root files that were moved into artwork/ and static/ (index.html, bg.jpg, catharsis-as-a-service.png, catharsis-as-a-service.jpg, .nojekyll), so watch reports scope drift. Next action: Restart the task with a scope covering the whole repository and continue: validate, commit, CI, deploy, verify, release.

  5. Finding Scope drift after files were moved; task restarted

    The first task claimed 20 paths but not the root files that were moved into artwork/ and static/. The handover records that majordomus watch reported the drift; the task was finished as partial and restarted before the first push.

  6. Finish Task finished as partial: Ship Catharsis as a Service: Zola EN/CS site, CI/CD to GitHub Pages, live verification, automatic releases

    Finish contract: 5 pass, 6 skipped; no verification command recorded.

  7. Task Task started: Ship Catharsis as a Service: Zola EN/CS site, CI/CD to GitHub Pages, live verification, automatic releases

    Profile implementation; scope of 1 path declared as ".".

  8. Checkpoint Checkpoint: Ship Catharsis as a Service: Zola EN/CS site, CI/CD to GitHub Pages, live verification, automatic releases

    Authored progress note (at most 40 lines by policy); the body stays in the checkout's local state.

  9. Handover Handover written: current state and next action

    Current state: Site, CI/CD, rules and repo settings are done; validate passes and 30/30 local e2e pass. A scope of "." is not interpreted as the whole repository, so check reports every file out of scope. Next action: Restart with explicit top-level scope paths, then commit, push, watch the Pages pipeline and verify production.

  10. Finding A scope of "." was caught before the first push

    The restarted task declared its scope as ".", which Majordomus does not read as the whole repository, so majordomus check reported every changed file as out of scope. The task was restarted with explicit top-level paths before the first push.

  11. Finish Task finished as partial: Ship Catharsis as a Service: Zola EN/CS site, CI/CD to GitHub Pages, live verification, automatic releases

    Finish contract: 5 pass, 6 skipped; no verification command recorded.

  12. Task Task started: Ship Catharsis as a Service: Zola EN/CS site, CI/CD to GitHub Pages, live verification, automatic releases

    Profile implementation; scope of 26 paths.

  13. Commit feat(site): ship Catharsis as a Service as a bilingual Zola site with verified CI/CD

    Pages pipeline: run 34834554169 success.

  14. Pipeline Pages pipeline passed: feat(site): ship Catharsis as a Service as a bilingual Zola site with…
  15. Finding The first push to main went through the ruleset's admin bypass

    The checkpoint written after the first push records that the push used the admin bypass of the repository ruleset that requires CI. Deployment was still gated: in the Pages workflow the deploy job needs the CI jobs, and the release job needs production verification.

  16. Checkpoint Checkpoint: Ship Catharsis as a Service: Zola EN/CS site, CI/CD to GitHub Pages, live verification, automatic releases

    Authored progress note (at most 40 lines by policy); the body stays in the checkout's local state.

  17. Release Release v0.1.0 published

    Cut by the Release job of run 34834554169 after Deploy and Verify production passed for commit 9bc6897.

  18. Finish Task finished as completed: Ship Catharsis as a Service: Zola EN/CS site, CI/CD to GitHub Pages, live verification, automatic releases

    Finish contract: 7 pass, 4 skipped; verification command scripts/smoke-production.sh https://korczis.github.io/catharsis-as-a-service/ exited 0 in 7 s.

  19. Finding "Completed" was recorded only with a passing check of the live site

    Both tasks closed as completed ran the production smoke test against the live URL as their verification command (exit 0, 7 s). The 3 tasks closed as partial recorded no verification command and claimed no completion.

  20. Task Task started: HTML5 Boilerplate practices, link previews per locale/page, structured data and SEO hardening

    Profile implementation; scope of 23 paths.

  21. Decision Structured data is built as Tera data and serialised with json_encode

    Why: Hand-written JSON-LD inside HTML templates gets HTML-escaped and breaks on quotes; building the graph as template maps keeps escaping correct by construction. Rejected: hand-written JSON-LD strings; a client-side script injecting JSON-LD. Evidence: templates/partials/structured-data.html; scripts/validate-html.py parses every JSON-LD block.

  22. Decision Link previews are localized per language, and the sitemap lists every language edition

    Why: A shared link preview is often the only part of the work a reader sees; hreflang alternates in the sitemap and og:locale:alternate keep each edition discoverable in its own language. Rejected: one English preview card for all pages; hreflang only in HTML. Evidence: templates/sitemap.xml; tests/site.spec.js 'link previews are localized and reachable'.

  23. Decision Python validators are tested with pytest in a project venv

    Why: User preference is pytest for Python; a venv keeps the global interpreter untouched and CI reproducible. Rejected: stdlib unittest; installing pytest globally. Evidence: requirements-dev.txt pins pytest 9.1.1.

  24. Checkpoint Checkpoint: HTML5 Boilerplate practices, link previews per locale/page, structured data and SEO hardening

    Authored progress note (at most 40 lines by policy); the body stays in the checkout's local state.

  25. Handover Handover written: current state and next action

    Current state: Phase A validated locally: validate.sh 7/7, Playwright 37/37. Not yet committed or deployed. New top-level paths (requirements-dev.txt, Rust workspace, data/, schemas/) fall outside this task scope. Next action: Restart the task with a scope covering all planned paths, commit and deploy Phase A, then implement Phase B and Phase C.

  26. Finding The brief outgrew the claimed scope; a new task claimed it

    When the brief grew to a Rust workspace, data files and Python tooling, the handover recorded that the new top-level paths fell outside the task's scope. The task was finished as partial and a new one claimed 31 paths.

  27. Finish Task finished as partial: HTML5 Boilerplate practices, link previews per locale/page, structured data and SEO hardening

    Finish contract: 5 pass, 6 skipped; no verification command recorded.

  28. Task Task started: Evidence-based catharsis site: psychology essays, advice library, tags, illustrations, per-page previews, Majordomus method, Rust integration, command registry, tests and docs

    Profile implementation; scope of 31 paths.

  29. Commit feat(seo): add boilerplate practices, localized previews, structured data and guides

    Pages pipeline: run 34836842423 success.

  30. Pipeline Pages pipeline passed: feat(seo): add boilerplate practices, localized previews, structured …
  31. Release Release v0.2.0 published

    Cut by the Release job of run 34836842423 after Deploy and Verify production passed for commit 54a31a2.

  32. Checkpoint Checkpoint: Evidence-based catharsis site: psychology essays, advice library, tags, illustrations, per-page previews, Majordomus method, Rust integration, command registry, tests and docs

    Authored progress note (at most 40 lines by policy); the body stays in the checkout's local state.

  33. Checkpoint Checkpoint: Evidence-based catharsis site: psychology essays, advice library, tags, illustrations, per-page previews, Majordomus method, Rust integration, command registry, tests and docs

    Derived from Git, not authored: 65 files changed since the task started.

  34. Commit feat(content): add research library, graded advice, command registry and Rust content API

    Pages pipeline: run 34842607207 failure.

  35. Pipeline Pages pipeline failed: feat(content): add research library, graded advice, command registry …

    10 jobs in 1 min 29 s: 6 passed, failed: CI / References (Crossref), skipped: Deploy, Release, Verify production. The next green run was 34842946706 for commit 94d734c.

  36. Finding A Crossref title mismatch stopped a deployment

    Run 34842607207 failed in References (Crossref); Deploy, Release, Verify production were skipped. The next green run was 34842946706 for commit 94d734c (fix(references): match Crossref titles with or without subtitles), which published v0.3.0.

  37. Commit fix(references): match Crossref titles with or without subtitles

    Pages pipeline: run 34842946706 success.

  38. Pipeline Pages pipeline passed: fix(references): match Crossref titles with or without subtitles
  39. Release Release v0.3.0 published

    Cut by the Release job of run 34842946706 after Deploy and Verify production passed for commit 94d734c.

  40. Decision Evidence is tracked as a dated ledger: data/sources.toml appraises every registry reference (design, level A–E), data/claims.toml records each public claim (type, level, confidence, sources, where used, last_reviewed, review_due), and validators fail the build on stale or inconsistent entries

    Why: The site makes psychological and physiological claims to the public; bibliographic correctness (Crossref) does not show whether a claim is still supported, how strong it is, or when it was last checked. Rejected: Free-text evidence notes inside each page; a single combined references+appraisal file (mixes Crossref-verifiable facts with editorial judgement). Evidence: scripts/validate-claims.py, .github/workflows/evidence-freshness.yml.

  41. Checkpoint Checkpoint: Evidence-based catharsis site: psychology essays, advice library, tags, illustrations, per-page previews, Majordomus method, Rust integration, command registry, tests and docs

    Derived from Git, not authored: 144 files changed since the task started.

  42. Commit feat(evidence): add evidence ledger, methods page, glossary, status and evidence-gated landing

    Pages pipeline: run 34845982889 success.

  43. Pipeline Pages pipeline passed: feat(evidence): add evidence ledger, methods page, glossary, status a…
  44. Decision ADR-0001 proposed: Evidence ledger with dated review for every public claim

    Recorded as proposed. Accepting an architecture decision is left to a person.

  45. Finding ADR-0001 stayed proposed; acceptance was left to a person

    The agent recorded the evidence-ledger decision as a proposed ADR and did not accept it. The final handover lists accepting or amending it as the next action for a person.

  46. Release Release v0.4.0 published

    Cut by the Release job of run 34845982889 after Deploy and Verify production passed for commit 4cbb6fb.

  47. Commit feat(api): export the evidence ledger and glossary, extend the Rust client, document the system

    Pages pipeline: run 34846771284 success.

  48. Pipeline Pages pipeline passed: feat(api): export the evidence ledger and glossary, extend the Rust c…
  49. Release Release v0.5.0 published

    Cut by the Release job of run 34846771284 after Deploy and Verify production passed for commit f2890f4.

  50. Handover Handover written: current state and next action

    Current state: main at f2890f4 is deployed as release v0.5.0; Pages pipeline run 34846771284 passed all 10 jobs including production verification. Evidence freshness workflow run 34846806810 passed. Local: validate.sh PASS, pytest 40 passed, Playwright 72 passed, cargo fmt/clippy/test pass. Ledger: 58 appraised sources, 50 claims, 54 glossary terms. ADR-0001 (evidence ledger) is proposed and awaits a person's acceptance. Next action: Accept or amend ADR-0001. Review Czech glossary terminology flagged as non-standard (kolektivní efervescence, pojmenování afektu, afektivní informatika). Optional: per-page social preview images (currently localized per language).

  51. Finish Task finished as completed: Evidence-based catharsis site: psychology essays, advice library, tags, illustrations, per-page previews, Majordomus method, Rust integration, command registry, tests and docs

    Finish contract: 7 pass, 4 skipped; verification command scripts/smoke-production.sh https://korczis.github.io/catharsis-as-a-service/ exited 0 in 7 s.

  52. Task Task started: Extend the site: more research and advice, per-page social previews, search and glossary cross-linking, second artifact Closure as a Service

    Profile implementation; scope of 31 paths.

  53. Checkpoint Checkpoint: Extend the site: more research and advice, per-page social previews, search and glossary cross-linking, second artifact Closure as a Service

    Checkpoint of the task recorded in the ledger; no note file is retained for it.

  54. Commit feat(screens): preview concept screens in place with paging and swipe

    Pages pipeline: run 34860959250 failure.

  55. Pipeline Pages pipeline failed: feat(screens): preview concept screens in place with paging and swipe

    10 jobs in 8 min 1 s: 8 passed, failed: Verify production, skipped: Release. The next green run was 34863500153 for commit 2125f1e.

  56. Finding Production verification failed, so no release was cut

    Run 34860959250 failed in Verify production; Release was skipped. The next green run was 34863500153 for commit 2125f1e (feat(research): expand measuring-emotion with verified sources), which published v0.6.0.

  57. Commit fix(screens): give previews addresses and test modified clicks deterministically

    No Pages pipeline run for this commit (it predates the workflow).

  58. Commit feat(research): expand measuring-emotion with verified sources

    Pages pipeline: run 34863500153 success.

  59. Pipeline Pages pipeline passed: feat(research): expand measuring-emotion with verified sources
  60. Release Release v0.6.0 published

    Cut by the Release job of run 34863500153 after Deploy and Verify production passed for commit 2125f1e.

  61. Commit feat(figures): add data-driven curves and pipeline figure kinds

    No Pages pipeline run for this commit (it predates the workflow).

What this case study is (and is not)

This page documents one delivery: the site you are reading, built on 14 September 2026 by an AI coding agent (Claude Code) that one person directed, with Majordomus 0.6.0 as the supervisory control layer between the agent and the repository. It is written as a tech demo. Every number on it is computed from records the delivery left behind: the Majordomus ledger, the decision log and handovers of the working checkout, the Git history, and GitHub’s records of pipeline runs and releases. The timeline renders those records one by one, and each event links to the commit, run, release or file it came from.

What the page is not matters as much:

  • Not a controlled comparison. There was one session, one person and one agent, and no comparable session without supervision. No speed-up factor follows from these records, and none is claimed here. Measured durations are reported; estimates of time saved, with their assumptions labelled, are left to the time accounting article.
  • Not a general claim about Majordomus. It shows how one repository configured it, which commands ran, what they recorded and what they refused. Another configuration behaves differently.
  • Not a record of everything. The ledger stores accepted operations. A command that Majordomus refused leaves no entry, so friction is visible here only where a handover, a checkpoint or a commit mentions it.
  • Not a transcript. Prompts, checkpoint bodies and local paths stay in the checkout. The published snapshot is curated, and docs/CASE-STUDY.md describes what it contains and why.

The method note covers the first release in detail, including the kinds of instructions that drove the work. This page covers the supervision layer itself: how it was set up, how each part was used and where it stopped helping.

The setup

The agent and the person. The agent read the repository, ran commands, edited files, committed and pushed. In the first phases the person sent about fifteen messages: requests, art direction, long structured briefs and short directives such as “deploy”, “release automatically” and “use Majordomus and enforce it”. Implementation choices were the agent’s. Later in the day, further agents and a second session worked on the same checkout in parallel; the section on continuity describes how.

The repository. A Zola 0.23.6 site in English and Czech, styled with Tailwind CSS and enhanced with Alpine.js and Flowbite; Python validators, a Playwright suite and pytest; a small Rust workspace that reads the site’s JSON API; and GitHub Actions workflows that deploy to GitHub Pages and cut releases. The about page describes the site, and the status page shows the build that is running.

The Majordomus layer. Majordomus keeps its state in a directory named .ai/, which has two halves:

  • .ai/repo/ is tracked in Git and shared by every checkout. Its manifest registers the sections. The policy sets context budgets, the checkpoint interval of the default profile, the requirements of the finish contract (scope respected, verification ran, state updated, no open blockers, note present), the sections a handover must have (Objective, Current State, Next Action) and two enforcement entries that bind commands to Git hooks. Four execution profiles exist (implementation, debugging, deep work, routine), and every task here ran under implementation. Rules live under .ai/repo/rules/: a pinned, read-only vendored baseline and six project rules. Architecture decisions live under .ai/repo/adrs/.
  • .ai/local/ is ignored by Git. It holds the active task, the append-only ledger, checkpoints, handovers, the decision log and open questions. Nothing in it may be published by a generator, which is why this page ships a curated export instead of the directory.

From the policy, Majordomus generated three instruction files, AGENTS.md, CLAUDE.md and GEMINI.md. Each one points an agent at .ai/README.md and its discovery protocol. The first ledger event, at 10:26:23 UTC, is that projection.

Hooks and CI. Running npm ci points Git at the repository’s .githooks/ directory. The CI workflow repeats the Majordomus health check in a job of its own, so a clone without hooks is still checked. The wiring table lists every enforcement point.

The task lifecycle in practice

Majordomus allows one active task per checkout. The lifecycle diagram above walks through each step with its registered command and a real recorded example; this section tells the same story in order.

Start with a scope. majordomus start opens a task with a title, a profile and the paths it may touch. The first task started at 10:26:23 UTC and claimed 20 paths. Six tasks were started in the recorded period, with scopes from one path to 31.

Work, then check. majordomus check is read-only: it reports whether the active task is consistent with the policy, its scope and the recorded state. majordomus watch reports drift between the task, its scope, the policy and the generated instruction files. Between them they caught two scope problems before the first push (see what supervision caught).

Checkpoint. majordomus checkpoint records a short progress note, capped at 40 lines by the policy. Seven checkpoints were recorded. The agent wrote four of them; the checkpoint at 10:43:27, for example, was written right after the first push, while the pipeline was running. Two were derived from Git without any authored text and state only how many files had changed since the task started: 65 at 12:16:46 and 144 at 12:52:41. The last one belongs to the task that was still active at the end of the snapshot.

Record decisions. majordomus decision appends a dated entry with the rationale, the rejected alternatives and the evidence. Four decisions were recorded; they are listed under decisions and ADRs below.

Hand over. majordomus handover writes a continuation record with the three sections the policy requires. Four handovers were written. Three of them came one or two seconds before a task was finished as partial, which is the pattern the finish contract asks for: an outcome other than completed needs a note that says what comes next.

Finish with a verification command. majordomus finish evaluates the finish contract. An outcome of completed requires a verification command that ran and exited zero, and the ledger stores the command, its exit code and its duration. For this repository the agent chose the production smoke test, the script behind npm run smoke, run against the live URL. The first completed task closed at 10:47:25 UTC, less than two minutes after release v0.1.0 was published, and its verification command exited 0 after 7 seconds. Its contract recorded seven requirements as pass, four as skipped and none as failed; requirements that did not apply to the outcome or the configuration are recorded as skipped. The second completed task closed the same way at 13:08:34, after release v0.5.0.

Read it back. majordomus history prints the ledger. The snapshot behind this page was exported from its JSON output.

Enforcement wiring

A rule that nothing runs is a suggestion. Majordomus reconciles the enforcement entries of its policy: majordomus doctor fails when a declared command is missing, is not executable, is not invoked by the hook the policy names, or is invoked in a way that swallows its exit code. The vendored rule behind this is enforcement-wiring, and the doctor enforces it.

  • Pre-commit. .githooks/pre-commit refuses to run when Majordomus is not installed and then runs majordomus doctor. A commit therefore requires a healthy, wired layer.
  • Pre-push. .githooks/pre-push runs majordomus finish --check, which evaluates the active task’s finish contract without closing the task. A push that carries work outside the claimed scope is refused before it leaves the machine.
  • Commit messages. .githooks/commit-msg runs scripts/lint-commits.sh. Conventional Commits are enforced because release versions are computed from them.
  • The CI supervision job. The Majordomus supervision job in ci.yml installs Majordomus at the pinned version 0.6.0 (the installer verifies the SHA-256 of the release), points Git at the hooks and runs majordomus doctor. It passed in every Pages run in the snapshot.
  • Deployment gates. pages.yml runs CI, then Deploy, then Verify production, then Release. Deploy asserts that the Pages URL equals the base URL in the Zola configuration. Verify production waits until the live site serves the pushed commit, then runs the smoke test and the browser suite against it with npm run test:production. Release runs only after Verify production has passed.
  • Repository rulesets. Three rulesets protect the repository on GitHub: main requires CI, the history of main cannot be rewritten or deleted, and v* tags cannot be moved or deleted. The CI requirement allows an admin bypass, and the first push used it.

Only the two hooks are Majordomus enforcement in the strict sense. The rest are conventional safeguards of the same repository, and this account does not separate their effects from those of Majordomus.

Rules next to the code

Rules are Markdown documents with front matter: an id, a version, a class (blocking or advisory) and optional dependencies written as exact id@version references. The effective set is additive, the vendored Majordomus baseline plus the project’s own rules, and there is no override mechanism. majordomus rules list prints the set with each rule’s class and the commands that enforce it.

The six project rules, each linked to its file:

  • verified-deployment: nothing is reported as deployed until the verify job of the Pages workflow has passed against the live URL that GitHub returns.
  • zola-source-of-truth: Zola generates all public HTML; content lives in Markdown, interface strings in translation dictionaries, and templates are shared by both languages.
  • release-on-verified-main: Conventional Commits are mandatory, and every verified push to main produces a release whose version is derived from the commits.
  • evidence-ledger: every public claim is recorded with its sources, evidence level, confidence and a review date that has not passed.
  • no-neuro-overreach: no sentence may claim that a signal, a model or a brain region reveals what a person feels.
  • medical-claims: findings are stated at group level with their limits, nobody is assessed individually, and every research note and advice entry carries the clinical disclaimer.

All six are blocking, and their dependencies are explicit: evidence-ledger depends on verified-deployment, no-neuro-overreach on evidence-ledger, and medical-claims on both. None of them has an x-majordomus block, and the rule listing reports them as having no validator. That is deliberate and written in each file: Majordomus resolves them, lists them and loads them into an agent’s context, while the project’s validators, CI jobs and review enforce them. The distinction matters when reading this case study. When a prohibited phrase or an expired claim fails the build, the project’s content validator or ledger validator caught it, not Majordomus.

Majordomus enforcement lives in the vendored baseline. Four of its rules did visible work in this delivery. Scope-integrity treats work outside the claimed paths as not belonging to the task; check, finish and watch enforce it. Verification-integrity requires a completed outcome to have a verification command that exited zero, with its exit code and duration recorded; finish enforces it. Note-integrity requires every outcome to carry a note with the sections that outcome needs; finish enforces it too. Enforcement-wiring, described above, is enforced by the doctor.

Decisions and ADRs

Two mechanisms separate a working decision from a durable one.

The decision log is local, append-only and cheap to write. majordomus decision records what was decided, why, what was rejected and where the evidence is. Four entries were recorded:

  1. Structured data is built as Tera data and serialised with json_encode. Hand-written JSON-LD inside templates is HTML-escaped and breaks on quotes. Rejected: hand-written JSON-LD strings, and a script that injects them in the browser.
  2. Link previews are localized per language, and the sitemap lists every language edition. Rejected: one English preview card for every page, and language alternates only in the HTML.
  3. Python validators are tested with pytest in a project virtual environment. Rejected: the standard library’s unittest, and a global pytest installation.
  4. Evidence is tracked as a dated ledger of appraised sources and graded claims, with validators that fail the build on stale or inconsistent entries. Rejected: free-text evidence notes on each page, and a single file that mixes bibliographic facts with editorial judgement.

The first three were recorded within one second of each other (11:08:30 to 11:08:31 UTC), shortly before a handover. Decisions were written down when a task was about to close, not continuously while it ran.

The architecture decision record is tracked and durable. The fourth decision was written up as ADR-0001 with its context, the decision, the rejected alternatives and the consequences, and the ledger records it as proposed at 12:55:12. The agent did not accept it, because acceptance is a person’s act. The last handover of that task names accepting or amending ADR-0001 as the next action, and majordomus adr list still shows it as proposed. The decision itself is visible on this site: the evidence page and the methods page render grades from the ledger it describes.

What supervision caught

The findings on this page are generated from the records, not written by hand. The export script declares what to look for and publishes a finding only when the ledger, a handover, a checkpoint or the pipeline data confirms it. Each card links to its evidence in the timeline. In order:

  • Scope drift after a file move. The first task claimed 20 paths but not the root files that were moved into the artwork and static directories. The handover records that majordomus watch reported the drift. The task was finished as partial 2 minutes 53 seconds after it started and restarted with a scope that named those files.
  • A scope of “.” before the first push. The restarted task declared a single dot as its scope. Majordomus does not read that as the whole repository, so majordomus check reported every changed file as out of scope. The task was restarted at 10:39:39 with 26 explicit paths. The first push came about three minutes later, and its pipeline passed all seven jobs.
  • A brief that outgrew its scope. When the work expanded to a Rust workspace, data files and Python tooling, the handover recorded that the new top-level paths fell outside the claimed scope. A new task claimed 31 paths.
  • A ruleset bypass. The checkpoint written after the first push records that the push went through the admin bypass of the ruleset that requires CI on main. Deployment itself stayed gated by the job dependencies of the workflow. This was recorded, not prevented.
  • Completion only with a live check. Both tasks closed as completed ran the production smoke test as their verification command, and both exited 0. The three partial tasks claimed no completion.
  • A failed reference check stopped a deployment. CI caught this one, not Majordomus. Run 34842607207 failed in the References (Crossref) job, and Deploy, Verify production and Release were skipped. A fix to title matching (commit 94d734c) followed, and the next run published v0.3.0 at 12:24:28, seven minutes after the failing run had started.
  • A failed production verification. Also CI. Run 34860959250 deployed and then failed in Verify production, when one of 84 browser tests timed out against the live site; Release was skipped. Because live verification needs a deployment, the unverified build stayed online until the next run. A follow-up commit made that test deterministic, and the next run, for a later commit that included it, passed and published v0.6.0.
  • An ADR left to a person. Described under decisions and ADRs above.

Three events mentioned in other accounts of this delivery are not among the findings, because the records do not confirm them: a pre-commit health check that flagged the README for not linking the agent bootstrap, a finish command refused until a handover existed, and a rule dependency the resolver rejected until it was written as an id@version reference. Refusals are not written to the ledger, and none of the three appears in a handover, a checkpoint or a commit. They may have happened; this page does not count them.

Continuity across restarts and parallel workers

Restarting a task was cheap in recorded time. Between a handover, the partial finish and the next start, the ledger never shows more than two seconds. Six tasks were started and three of them were restarts. What made restarts cheap is that the state lived in files rather than in the agent’s conversation. A handover carries the objective, the current state and the next action, together with fields computed from Git (branch, commit, clean or dirty tree, changed files) that an author may not write. The policy also has the session hooks write a briefing when an episode starts, a derived checkpoint when the conversation is compacted, and a continuation record when an episode ends while a task is still active.

Later in the day the delivery tested a harder case: several workers on one checkout at the same time. At the end of the snapshot one task is active. It started at 14:54:07 UTC and claims 31 paths, which is the whole working tree. Content agents, a second Claude session and the main session worked inside it at once, each told which files it owned. This page was written by one of those workers, which was told not to start, checkpoint, hand over or finish tasks and not to edit files that other workers held.

That arrangement exposes a limit. Majordomus scopes work per task and per checkout. Inside one checkout, parallel workers share the active task, and Majordomus cannot tell which worker changed which file. Coordination came from explicit path ownership in each worker’s instructions, and from Git. The vendored baseline states the Majordomus answer as principles: one worker, one scope, with a scope claimed by another worktree treated as a boundary, and parallel work isolated from each other. This delivery did not apply them inside one checkout.

Evidence of delivery

Everything in this section is linked, and the timeline can be filtered to show only commits, pipeline runs or releases.

  • Commits. Every commit subject is a Conventional Commit. The first, the poster, is dated 09:54:05 UTC, one second before the GitHub repository was created; the site followed at 10:42:45.
  • Pipeline runs. The first Pages run started at 10:43:02 and finished at 10:45:45, with seven jobs that all passed. Later runs grew to ten jobs as Python tests, a Rust job and the Crossref check joined CI. Two of the first seven runs failed, and both failures are shown with what followed them.
  • Releases. Release v0.1.0 was published at 10:45:42, after live verification: 51 minutes 37 seconds after the first commit and 19 minutes 19 seconds after Majordomus was initialised. Releases v0.2.0 to v0.5.0 followed by 13:07:10, each cut by the Release job of a run whose production verification had passed.
  • Completed tasks. Both completed tasks store their verification command, exit code 0 and duration in the ledger.

Two loops can be measured directly. From the site commit to the published v0.1.0 took 2 minutes 57 seconds. From the start of the run that failed on references to the published v0.3.0 took 7 minutes 9 seconds. The releases page and the runs of the Pages workflow are the primary records, and gh run list reads the same data.

What it cost and what it did not solve

Friction. Three of six tasks ended as partial and were restarted because of how their scope was declared. Two of those restarts happened within the first fourteen minutes of supervision. A scope has to be written as explicit top-level paths, and in this delivery a grown brief meant closing the task and opening a new one, which matches the baseline principle of claiming paths when a task starts instead of widening the scope silently. The records themselves cost attention: seven checkpoints, four handovers and four decisions between 10:26 and 13:08 UTC, plus the task that followed. And because the finish contract refuses a completed outcome without a passing verification command, a task could not be closed as completed before the pipeline had deployed and the live site answered.

What Majordomus did not check.

  • Whether content is true, well sourced or safely worded. The project’s validators and a reviewer own that.
  • Whether the verification command is adequate. The contract checks that the command ran and exited zero; choosing a live smoke test was the agent’s decision.
  • Whether tests are meaningful, or whether a failing test is flaky or real.
  • Which worker did what inside one checkout shared by parallel workers.
  • The six project rules, which it lists but does not enforce.

What the records cannot show. Refused commands are not in the ledger. The time a person spent reading, deciding and writing briefs is recorded nowhere. Durations depend on hardware, the network and the CI queue. And because conventional safeguards (local validation, browser tests, CI gates and rulesets) ran alongside Majordomus, their effects cannot be separated here.

What it did change, as far as the records show. Every claim of completion in this project is tied to a recorded command and its exit code. Scope mistakes surfaced locally, before any push, instead of as failed pipeline runs. And the state needed to resume work sat in files that a new worker could read, which is also what made this case study possible.

How to reproduce

The records are in the public repository, except .ai/local/, which never leaves a checkout. To inspect them in your own clone:

  1. Install Majordomus from majordomus.dev and run npm ci so that the hooks are active.
  2. Check the layer with majordomus doctor, list the effective rules with majordomus rules list and the architecture decisions with majordomus adr list.
  3. Read the pipeline history with gh run list and the task lifecycle in .ai/repo/workflows/task-lifecycle.md.
  4. In a checkout that has its own ledger, majordomus history prints it, and python3 scripts/export-case-study.py regenerates the snapshot behind this page. With the check option, the same script validates the committed snapshot without local state or network access, which is how CI treats it.

The snapshot format, what it includes and what it leaves out are documented in docs/CASE-STUDY.md. For how the rest of the site was engineered, read the engineering articles.

Majordomus features used

FeatureHow it was usedEvidence
Scoped tasksSix tasks were started with an explicit list of paths. Scope problems were resolved by finishing the task as partial and starting a new one with a corrected scope.Each task start in the ledger carries its declared scope; three restarts are recorded.
Finish contract with a verification commandTasks closed as completed ran the production smoke test against the live URL; partial outcomes carried a handover instead.Each finish in the ledger stores the contract results, the verification command, its exit code and its duration.
CheckpointsShort progress notes while a task ran, written by the agent or derived from Git.Seven checkpoints in the ledger; two derived from Git state only the number of changed files.
HandoversWritten before every restart and at the end of the main task, with Objective, Current State and Next Action.Four handovers in the ledger; the policy requires the three sections.
Decision logDecisions with their rationale, rejected alternatives and evidence, written down while the work was fresh.Four recorded decisions, each linked to the files that implement it.
Architecture decision recordsThe evidence-ledger decision was written up as ADR-0001 and left proposed for a person to accept.One ADR proposal in the ledger; the ADR file still has the status proposed.
Rules as versioned documentsA pinned vendored baseline plus six project rules, loaded into the agent's context and listed with their class and the commands that enforce them.Rule files under .ai/repo/rules; the rule listing shows that the project rules have no Majordomus validator.
Health check wired into Git and CIThe pre-commit hook and a CI job run the health check, which also reconciles the policy's enforcement entries with the hooks.The hook file and the Majordomus supervision job, which passed in every Pages run of the snapshot.
Provider instruction filesAGENTS.md, CLAUDE.md and GEMINI.md were generated from the policy, so every agent starts from the same bootstrap.The first ledger event records the projection into three target files.
Append-only ledgerEvery start, checkpoint, decision, handover and finish was recorded with its time and Git commit; this page is exported from it.The snapshot behind this page and the script that exports and checks it.

Enforcement wiring

Where each check runs, what it runs and what it stops. Only the two hook entries are declared in the Majordomus policy; the rest are conventional safeguards of the same repository.

WhereCommandEffectFile
Git pre-commit hookmajordomus doctorRefuses a commit unless the layer is healthy and every declared enforcement is wired without a swallowed exit code..githooks/pre-commit
Git pre-push hookmajordomus finish --checkRefuses a push when the active task would not satisfy its finish contract, for example with files outside its scope..githooks/pre-push
Git commit-msg hookscripts/lint-commits.sh --fileRefuses a commit subject that is not a Conventional Commit, because release versions are computed from the subjects..githooks/commit-msg
CI job: Majordomus supervisionmajordomus doctorInstalls the pinned Majordomus 0.6.0 and repeats the health check on every push and pull request, so a clone without hooks is still checked..github/workflows/ci.yml
CI job: Conventional commitsscripts/lint-commits.sh <range>Lints every subject in the pushed range; nothing deploys when it fails..github/workflows/ci.yml
Pages workflow: Verify productionnpm run smokeDeploy needs CI; Verify production waits for the pushed commit on the live site and runs the smoke test and Playwright against it; Release needs Verify production..github/workflows/pages.yml
Majordomus policyverification.finish_requiresThe finish contract selects five requirements: scope respected, verification ran, state updated, no open blockers, note present..ai/repo/policy.yaml
GitHub rulesetsrepository settingsmain requires CI (with an admin bypass), main history cannot be rewritten or deleted, and v* release tags cannot be moved or deleted.release-on-verified-main rule

What supervision caught

Generated from the records: a finding is published only when the ledger, a handover, a checkpoint or pipeline data confirms it. Each card links to its evidence in the timeline.

The brief outgrew the claimed scope; a new task claimed it

When the brief grew to a Rust workspace, data files and Python tooling, the handover recorded that the new top-level paths fell outside the task's scope. The task was finished as partial and a new one claimed 31 paths.

Caught by: recorded, not enforced by a command

Evidence

The first push to main went through the ruleset's admin bypass

The checkpoint written after the first push records that the push used the admin bypass of the repository ruleset that requires CI. Deployment was still gated: in the Pages workflow the deploy job needs the CI jobs, and the release job needs production verification.

Caught by: recorded, not enforced by a command

Evidence

A Crossref title mismatch stopped a deployment

Run 34842607207 failed in References (Crossref); Deploy, Release, Verify production were skipped. The next green run was 34842946706 for commit 94d734c (fix(references): match Crossref titles with or without subtitles), which published v0.3.0.

Caught by: CI · References (Crossref)

Evidence

Limits

  • One session, one person, one agent. There is no control condition, so no speed-up factor can be derived.
  • The ledger stores accepted operations. A refused command leaves no ledger entry, so friction is undercounted.
  • Majordomus does not judge content: evidence grading, medical wording and test adequacy belong to the project's validators, CI and a reviewer.
  • The six project rules carry no x-majordomus block. Majordomus resolves and lists them but does not enforce them.
  • The worker chooses the verification command. The contract checks that it ran and exited 0, not that it was the right check.
  • Parallel workers in one checkout share one active task, so attribution between them comes from their instructions and from Git, not from Majordomus.
  • Live verification needs a deployment, so a failed verify job leaves an unverified build online until the next run.
  • The snapshot is curated: prompts, checkpoint bodies and local paths are not published, and a person's time spent reading and deciding is recorded nowhere.

Concept screens

Concept screens · illustrative data

  • Concept screen of the Majordomus cockpit Sessions view: a list of working sessions and the timeline of one session from start to updated documentation, with the context sources it loaded.

    Sessions Each session keeps its timeline, context sources, decisions and handover.

  • Concept screen of the Majordomus cockpit Rules view: a list of enforced repository rules with coverage, the detail of one rule, its validation status and where it is enforced.

    Rules Executable rules with their enforcement points: command line, CI, pre-commit hook.

  • Concept screen of the Majordomus cockpit Worktrees view: parallel branches with their status, a diff of changed files, commits ahead and a terminal.

    Worktrees Parallel branches in their own worktrees, each tied to an issue and a session.

  • Concept screen of the Majordomus cockpit Issues view: an issue list and the detail of one issue with its linked worktree, session, pull request, tests and documentation.

    Issues An issue connected to the work that implements and verifies it.

  • Concept screen of the Majordomus cockpit Tests view: pass and fail counts, a results trend, coverage, quality gates and live test output.

    Tests Test runs, failures and quality gates in one place, linked to issues and commits.

  • Concept screen of the Majordomus cockpit Documentation view: a document tree and an architecture decision record with context, decision and consequences.

    Documentation Documentation and architecture decisions next to the rules they implement.

  • Concept screen of the Majordomus cockpit Milestones view: three milestones with progress bars, a cumulative progress chart, a timeline and dependencies.

    Milestones Milestones with progress, schedule and dependencies derived from the issue plan.

  • Concept screen of the Majordomus cockpit Models view: AI model providers with usage, latency, cost breakdown and live requests.

    Models Which models were used for what, at what latency and cost.

Concept screens of a Majordomus cockpit: sessions, rules, worktrees, issues, tests, documentation, milestones and model usage. All names, numbers and dates in them are illustrative.

These screens are concepts of a Majordomus cockpit with illustrative data. They do not show this project; its real records are the timeline and the numbers above.

Sources and links

References

  1. Majordomus (2026). Majordomus: A lightweight supervisory control layer for AI-assisted work (version 0.6.0). https://majordomus.dev
  2. Sig Nihl (2026). catharsis-as-a-service: repository, Pages workflow runs and release history. GitHub. https://github.com/korczis/catharsis-as-a-service