Who is working where, which shifts nobody has picked up, and how coverage looks
per site. Built on AgentUI and edited entirely as
local files with @agentuiai/cli.
This is the tool that usually exists as a shared spreadsheet one person keeps in their head — the one that breaks the week they take holiday.
npm install -g @agentuiai/cli
agentui auth login
agentui project create --name "Shift Coverage"
cd shift-coverageOne command creates the project on the platform and scaffolds the local folder,
AGENTS.md included. Copy entities/, pages/, components/ and functions/
from this repo, then:
agentui validate
agentui project push --dry-run
agentui project push
agentui build && agentui deployKeep the board fresh with an hourly scan:
agentui automation trigger set schedule "0 * * * *"
agentui functions invoke coverageScan
agentui functions logs coverageScanentities/Site.schema.json code, timezone, minimum staffing
entities/Employee.schema.json site, role, weekly hour cap
entities/Shift.schema.json date, hours, role needed, assignment, status
pages/Coverage.jsx coverage per site, grouped server-side
pages/OpenShifts.jsx the gaps, with one-click assignment
components/ CoverageBar, ShiftRow
functions/coverageScan.js Deno function, recomputes is_uncovered hourly
Coverage is counted by the platform, not the browser. Coverage.jsx runs
two grouped Shift.aggregate() calls and subtracts. Listing shifts and counting
in JavaScript would cap at 300 rows and quietly under-report a chain with more
than a few sites.
is_uncovered is stored, not computed at read time. "Nobody assigned, or
the assigned person no-showed" is a condition across two columns, which grouped
aggregate filters cannot express. The hourly scan writes it down; the dashboard
reads it back.
Dates and instants are different fields. shift_on is format: "date" and
holds YYYY-MM-DD — a shift belongs to a calendar day at its own site, not to
an instant. starts_at and ends_at are format: "date-time" and hold ISO
instants, which is what you need when sites sit in different timezones.
OpenShifts.jsx assigns the first available person with the right role. It does
not check weekly_hour_cap, and a real roster must — that check belongs in a
serverless function where it can read the whole week's shifts without the
300-row cap biting. It is left out so the assignment flow stays readable.
agentui --json project list
agentui --json project push --dry-run
agentui --json functions invoke coverageScanEvery subcommand takes --json and prints machine-parseable JSON on stdout,
structured errors included.
- CLI docs: https://www.agentui.ai/en/agentui-cli/
- Flat command reference for agents: https://www.agentui.ai/agentui-cli.md
- Package: https://www.npmjs.com/package/@agentuiai/cli (MIT, Node 22+)
- Companion examples: https://github.com/nesbtesh/agentui-example-inventory · https://github.com/nesbtesh/agentui-example-purchase-orders
MIT.