Every school has a cupboard of stuff that walks off — laptops, chargers, lab kit, sports gear. The tracking is usually a shared spreadsheet that nobody trusts by October: no history, no idea who has what, and "overdue" is whatever someone remembers. I wanted the smallest honest tool that fixes that, and a CLI is the smallest honest tool.
The problem
The desk has three jobs — hand something out, take it back, and answer "what's out and who's late." A spreadsheet does all three badly because it has no notion of an event: you overwrite a cell and the past is gone. The fix is to store actions, not a current state, so the answer to every question is just a query.
Store what happened, not what is — the rest is a query.
How it works
Four subcommands over a SQLAlchemy model of users, items, loans and categories. Each item gets a UUID token you can scan or copy; each loan carries a due date (7 days by default) and records who performed it. "Overdue" is derived by comparing the due date to now — never stored, so it's always right:
# register a laptop, loan it for two weeks, then see what a student has out lenddesk add-item "ThinkPad X260" laptops --performed-by S-1042 lenddesk loan-item <token> S-2210 --days 14 --performed-by S-1042 lenddesk status --school-id S-2210
The status view is the one people actually live in — active loans, sorted by due date, with a blunt overdue flag:
Item Token Borrower School ID Due Overdue ------------------------------------------------------------------------------- ThinkPad X260 8f3a1c… Mia Holm S-2210 2026-04-22 YES Casio FX-991 b20e77… Jonas Berg S-1188 2026-05-03
What I'd do differently
- UTC everywhere in storage was the right instinct, but the CLI prints bare dates — a late-evening loan can look a day off to whoever reads it. Display-local, store-UTC should have been there from line one.
- Errors currently
sys.exit(1)straight from the command handlers; pushing that up to one boundary would make the core reusable behind a web UI later. - Categories are created on demand by name, which is friendly until someone types "laptops" and "Laptops" and splits the shelf in two.
Roadmap
It's a deliberate prototype — the CLI proves the data model. The token is already a UUID so a phone can scan it, which makes the natural next step a thin web front end over the same core/ actions, not a rewrite.
Thanks for reading. Found a bug or have a sharper idea? get in touch — or run ls above to see the rest.