[ANN] Perth.jl — project schedules you can compute on, with a browser UI attached

Hi everyone

I plan a lot of work in spreadsheets, and I kept hitting the same wall: the schedule was a picture, not data. Asking “if this slips two days, what else moves?” meant redrawing it by hand.

Perth.jl is a critical-path engine with a browser UI on top, the part I care about is that the model and the scheduling live in Julia and the browser is one view of it, not the source of truth.

using Perth                 *# re-exports Date, Day, Week, Month, today*

p = *create_project*("Service Times & Queueing Study")

*# Phases are WBS summaries: their dates, duration and progress roll up*
*# from their children on every save.*
data     = *add_task!*(p, "1. Data preparation")
analysis = *add_task!*(p, "2. Analysis")
extract = *add_task!*(p, "Extract records from the case system";
                    duration = 3, parent = data.id, assignee = "Bruno")
clean = *add_task!*(p, "Clean and validate the dataset";
                  duration = 4, parent = data.id, assignee = "Bruno",
                  dependencies = \[extract.id\])
*# "id+1" is finish-to-start with a day of lag; "SS:"/"FF:" prefixes give*
*# start-to-start and finish-to-finish, with or without lag.*
fit = *add_task!*(p, "Fit service-time distributions";
                duration = 4, parent = analysis.id, assignee = "Ana",
                dependencies = \["$(clean.id)+1"\])
report = *add_task!*(p, "Write the report";
                   duration = 5, parent = analysis.id, assignee = "Ana",
                   dependencies = \["SS:$(fit.id)+1"\])
*add_task!*(p, "Review analysis and code";
          duration = 3, parent = analysis.id, assignee = "Dante",
          dependencies = \["FF:$(report.id)"\],
          deadline = *today*() + *Week*(4))
*schedule!*(p)      *# forward + backward CPM pass*
p                 *# Unicode Gantt in the REPL, SVG in Pluto and Jupyter*

The deadline is the piece I find most useful day to day. It never moves the task, it caps the late finish, so missing it turns the slack of that task and of everything feeding it negative, by exactly the number of days you are late:

*slack*(p)          *# id, name, early_start, early_finish, slack_days, critical*

*deadline_slip*(p)  *# only the commitments you are actually missing*

Plain CPM tells you a task is critical; it can’t tell you that you broke a promise.

Perth.run() opens a localhost page with the timeline, and it keeps up: edit from the REPL and the page reloads on its own; edit in the browser and project(p.id) gives you back what you just did.

A few things that fell out of writing it in Julia:

  • tasks(p), tasktable(p), slack(p) and workload(p) return Tables.jl rows, so DataFrames and CSV need no glue.

  • Business-day calendars are a BusinessDays.jl package extension: set_calendar!(p, "Brazil") and the whole engine skips weekends and holidays. Same pattern for Makie — ganttplot(p) gives a publication figure — and QRCoders.

  • A Project renders as a Unicode Gantt in the REPL and as inline SVG drawn by Julia, not by the app.

  • Projects are plain JSON on disk, with an optional .perth.jl mirror that is readable Julia source — that is the one I actually commit next to a repo.

Beyond the above there are baselines (set_baseline! slippage), pinned dates, milestones, per-person workload and overallocation reports, costs and an S-curve, and iCalendar export. A tour that exercises all of it is in examples/queue_study.jl.

There is also a kanban board, Perth.kanban(), and both apps take share = true, which puts them on the local network: everyone opens the same page, each machine shows up as a labelled cursor, edits appear live. Cards can be linked to Gantt tasks with kanban_from_project!(p) — moving a card to done sets the task’s progress to 100 on every connected browser. An access key is optional and can be set or changed with the server already running.

What it is not: a multi-tenant server. It is a LAN tool for a room of people who already trust each other. No login, concurrent edits to one project resolve as last-write-wins, and you should not put the port on the internet.

] add Perth

Repo: GitHub - dantebertuzzi/Perth.jl: 📊 Gantt + 🗂️ Kanban project management in Julia. One REPL command opens a local web UI in your browser — while the REPL stays free to drive the same projects in code. 🌐 Real-time sharing over your LAN. · GitHub

Feedback welcome, especially on the scheduling semantics, which are the part I would most like to get right before 1.0.

I love this idea.

You might be interested in ProjectManagement.jl
which I build quiet a while ago to help me with high level project planning,
in particular PERT charts.
It does things like critical path identification and total time distribution estimation.

In traditional project planning one would normally do.

  • Work break bown structucture (list everything that needs to be done)
  • PERT charts (capture dependancies, and thus what can be done in parallel what the critical path is)
  • Gantt charts: assign tasks to people and time.

(PERT charts intrinsically assume that you are not bound by number of people / equiptment when identifying critical tasks)