Project Monitor

One nightly page: where every project stands, what is open, and which projects need you to proceed or to conclude

The Project Monitor answers one question at 4 a.m.: which projects need me today, and for what? Open it at /admin/monitor on the hub (publicly https://ai-platform.lettre.ai/admin/monitor; private projects are shown only on this Mac and the tailnet).

It is the single successor of three earlier approaches that tracked the same thing in parallel:

Before Problem Now
Projects-development register (projects-dev build, 05:40; scan every 2 h) Good facts, but the per-section audits were written without evidence of the actual work and read like generic goals; the 2-hourly scan collided with the catalog lock Its scan stays as the project universe and fact source; its audit, render and the 2-hourly scan are no longer scheduled
Morning Plan (projects-dev morning, 06:00) Superseded on 26 Sep 2026 but still running; noisy field diffs Retired; /admin/morning redirects to the Project Monitor
Work Monitor (worklog) Session-centred, not project-centred; the aggregator ran on openscience while mac-studio — where most agent work happens — did not report at all Its collector feeds the monitor; the hub host (mac-studio) is now the only aggregator

ai-projects (port 5065) keeps managing tasks for its publication projects; the monitor reads its open tasks.

The nightly chain

flowchart LR
  subgraph macs [Every Mac, 23:55]
    C1[collect: Claude Code + Cursor transcripts, plans, todos, file sweep]
  end
  C1 --> SN[(worklog snapshots via Syncthing)]
  subgraph hub [mac-studio, 02:30 · retry 03:30]
    C2[collect] --> AG[aggregate Work Monitor]
    AG --> SC[register scan]
    SC --> EV[evidence dossier per project]
    EV --> AS[Partitur project-monitor ×60, parallel]
    AS --> BR[Partitur project-monitor-briefing]
    BR --> RP[registry/monitor/DAY.json]
  end
  SN --> EV
  RP --> PG["/admin/monitor"]

One launchd job, com.ai-platform.project-monitor, runs ae-platform monitor nightly --if-missing at 02:30; the 03:30 slot runs again only when the 02:30 report is missing or incomplete. A full run takes about four minutes (60 assessments, 8 in parallel). Each step is recorded with its time and result and shown in the Pipeline section of the page; a failing step never stops the following ones (a failed scan falls back to the previous facts).

What the monitor reads

Every project gets a dossier. Each item has an id that the assessment must cite:

Id Source
S1… Agent sessions of the last 14 days from every Mac: the owner’s prompts, the agent’s last reports, plans, todos not completed, failed tool calls. A session counts for a project when most of its file work (writes ×3, paths in shell commands, files read) lies in the project folder; a session that mainly served another project is marked “context only”.
W1… Work items of the Work Monitor (owner-set status, notes and next steps win)
D1… Project documents: STATUS.md, ROADMAP.md, TODO.md/NEXT.md (open checkboxes), issues.yml (open issues), a confirmed PROJECT.yaml, otherwise the README
M1… Claude Code agent memories that mention the project
T Open ai-projects tasks
F File activity from one walk of the umbrella (24 h / 7 d / 30 d, newest code and doc files)

Projects are the register’s projects, the top-level LWgrammar, and every PDAI collection (pdai:<name>, code in pdai/collections/ and data on PDAI-1). The 60 liveliest projects are assessed; the rest are listed as Not assessed tonight when they showed any file activity in the last 90 days.

Attention classes

Class Meaning
Needs your decision Waits for an answer, approval, credentials, quota or material only you can supply
Ready to start Planned or requested, implementation has not begun
Stalled — resume Stopped half-way: open todos, unfinished plan, failed run, or a complaint not yet fixed, idle 2+ days
Ready to conclude Built; verify, render, publish or close
Running Progressing; nothing waits for you
Quiet No meaningful work and nothing open

The judgement is made by the Partitur flows/register/project_monitor.yaml in ai-agent-orchestrator (runtime gemini-3.8-flash, the default Gemini model since 20 Oct 2026); the morning summary and the five first things to do come from project_monitor_briefing.yaml. Python only gathers evidence and checks the answer: every open issue, next step or result that cites no evidence id present in the dossier is removed before display. Private projects (privat/, privatkanzlei, korrespondenz) never enter the briefing.

Recording: what changed for complete activity capture

  • Claude Code in VS Code Insiders is read in full: subagent transcripts, Agent, TodoWrite, ExitPlanMode (plan text), AskUserQuestion, failed tool results (Claude Code stores them, unlike Cursor), the agent’s report at the end of every turn, and the paths named in shell commands — most edits in these sessions run through Bash, so Write/Edit paths alone missed most projects.
  • mac-studio now records (it reported nothing before); mac-mini got the collector and audit daemon. mac-air still needs scripts/install-worklog.sh when it is online.
  • The aggregator runs only on the hub host, so two machines no longer write the same Work Monitor report.

Commands

ae-platform monitor nightly                 # the whole chain now
ae-platform monitor nightly --skip-collect  # reassess only, from existing snapshots and facts
ae-platform monitor nightly --only development/famulus-proof
ae-platform monitor dossier development/famulus-proof   # what the assessment sees
ae-platform monitor show                    # latest report as markdown
scripts/install-worklog.sh --hub            # hub host: audit daemon + Project Monitor job
scripts/install-worklog.sh                  # every other Mac: collector + audit daemon

Output: platform/registry/monitor/<day>.json, latest.json, latest.md; API /api/monitor/report?day=, /api/monitor/days. Logs: platform/logs/project-monitor.{out,err}.log.

Landing backends

A second nightly job controls whether the landing pages’ backends work, not only whether they answer. ae-platform landings nightly (launchd com.ai-platform.landing-health, 02:10, hub host only) builds its task list every night from three sources:

  • config/landings.yaml, the register of landing pages;
  • the live public pages on GitHub Pages, read for every https://lettre.ngrok.dev link they carry;
  • config/routes.yaml, which tells which machine serves a path and how the proxy rewrites it.

A link that appears on a landing page tomorrow is therefore checked tomorrow, with no list to maintain. Each backend function is probed twice, at its origin (openscience or mac-studio directly) and publicly through ngrok, and curl’s timings are kept (connect, first byte, total).

Backend Functions checked
edition viewer registered documents (an empty registry is the known Registered documents: 0 failure), document viewer, thumbnail, facsimile (a 404 “No smaller derivative” falls back to the master, as the viewer does), transcript XML, Bedeutung frame, dossiers page
Kármán archive archive summary, facsimile, transcript, Bedeutung frame, dossiers page
glider, notebook, mitanni /api/health with content (glider: searchable collections)
notebooks the notebook content behind every ?nb= link
newsletter manifest, and the subscribe form’s CORS preflight from famulus.lettre.ai
every openscience child start page, plus the edition functions above

The openscience host is read over SSH:

  • the editions supervisor and each child: running, waiting or restarting;
  • load, free disk and memory, and its own proxy;
  • every edition registry: how many registered document paths are missing on its disk;
  • code files changed after the supervisor started, which means a restart is needed because Syncthing delivered new code to an old process.

When a function fails on openscience, the same request goes to mac-studio. The finding then says whether the cause lies on openscience only or everywhere.

Findings. A finding names a cause, not each symptom.

  • One per edition when its pages are missing on openscience.
  • One for all collections whose Bedeutung is not prepared.
  • A child that is down absorbs the findings of its route.
  • slow: over the budget in config/landing_health.yaml.
  • slower than usual: more than twice the median of the last 14 nights and at least 0.5 s more. This needs 3 nights of history in registry/health/landing_health.duckdb.
  • fallback: a public request was answered by mac-studio instead of openscience.

Rules that keep the findings honest:

  • A failed function is asked once more, two seconds later and alone. A failure that does not repeat (a database lock held by a writer, a busy machine) is noted in the row, not reported.
  • A function over its budget is measured once more alone, and the faster answer counts. The batch runs eight requests at a time and can slow itself down.
  • Image and transcript checks follow the viewer’s own fallbacks: the next leaf when the first has no scan, the master when no smaller derivative exists, .png or .jpg.
  • A child stopped with editionsctl stop is intended, and so is a waiting child whose route no longer names openscience.

Routing decision (owner, 20 Oct 2026). openscience holds only the landing editions (scripts/build_pdai_collection_server.py). The routes whose data it lacks are served by mac-studio as primary, and their children on openscience are stopped. These are library, kirch, rock-art, phototechnology, architektur-antik, babylonian-astronomy, wissenschaftstheorie, waterclocks, pirckheimer, glider and lemma-search. The old routes file is kept in ~/Library/Application Support/ai-platform/backups/.

Mail. Open findings are mailed to the owner. The sender is the first one in config/landing_health.yaml whose password is in the Keychain: the Famulus News Gmail App Password, else the HU account of the Privatkanzlei mail service. A run that fails itself is mailed too.

Acknowledging. A known finding can be listed under known: with an id, a reason and an end date. It is then shown but not mailed until that date; an entry without an end date is ignored.

Where to see it. The task list with status and times is in the section Landing backends of /admin/monitor, in registry/health/latest.md and in /api/monitor/landing-health.

ae-platform landings nightly            # probe, assess, record, report, mail open findings
ae-platform landings nightly --no-mail  # the same without the mail
ae-platform landings nightly --only euler kepler   # a quick look at some landings (no history, no report)
ae-platform landings show               # latest task list and findings

Code: src/ai_platform/health/ (probe, catalog, host, assess, mailer, nightly), tests tests/test_landing_health.py. Logs: platform/logs/landing-health.{out,err}.log.

Limits

  • An agent’s closing report is a claim, not a verification. The assessment treats a later complaint or repeated request as evidence that the problem is still open, but it cannot run the project’s tests.
  • File activity counts generated data and sync arrivals as well as edits; it is a signal of life, not of progress.
  • A session that touched no project folder (questions, machine care, mail) appears under Sessions without a project.