What is this table?
The directory you opened — say archive/Acme/mdl/ —
is the table. table.yaml describes the
columns; form.yaml describes the row-edit form
schema; every other .yaml file in the directory
is one row. Copying the directory anywhere takes the whole
table (spec + form + every row) with it.
Editing cells
Click a cell to select it. Then:
- ↑ / ↓ / ← / →
- Move selection. Hold Shift to extend a range.
- Tab / Shift+Tab
- Move right / left, wrap to next / previous row.
- Enter / F2 / double-click / typing
- Enter edit mode. Typing replaces the cell value; the
others keep it.
- Enter in edit mode
- Commit and move down.
- Tab in edit mode
- Commit and move right.
- Esc
- Cancel the edit; restore the prior value.
- Delete / Backspace
- Clear every cell in the current selection.
- Ctrl+D / Ctrl+R
- Fill the top row down / left column right through the
selected range.
- Ctrl+C / Ctrl+V
- Copy / paste — interoperates with Excel and Google
Sheets via tab-separated values.
- Ctrl+Z
- Undo the last edit (one history per session).
Edits save automatically when you move to a different row.
A small left-edge swatch on the row indicates state:
blue = unsaved, amber = the
server flagged a validation error, orange =
someone else changed this row since you loaded it (you'll
get a prompt with Use mine / Reload).
Sorting
Click a column header to sort by that column. Click again to
toggle direction. Shift-click another header to
add a secondary sort key.
The schedule
Each milestone keeps three dates:
Plan (the baseline you agreed),
Forecast (what you now expect) and
Actual (what happened). The grid shows one cell
per milestone: the actual once there is one, otherwise
the forecast, tagged a or f so the
track reads even in print. Hover any milestone cell
to see all three dates, the variance in days, and why the cell is
coloured the way it is.
Milestones are linked in a network — each one follows others
and has a duration in calendar days. You only use the milestones
that apply to a package: a milestone with no dates is not
in that package's schedule, and the chain simply skips
over it to the next one you do use.
A date and a duration are two views of one fact.
Pin either and the schedule works out the other; pin neither and
the network's own duration fills in. So you can pin
one date anywhere — vendor data, on site — and everything
before it back-calculates into "when we must start" while
everything after it runs forward. Where a date can be reached
going forward, that wins.
Two consequences worth knowing:
- Entering an actual re-forecasts everything
downstream. That is the point — record what happened
and the rest of the chain moves with it.
- Forecast follows plan until you say otherwise.
An untouched package forecasts exactly to plan, so most cells
read on plan
at first. That is normal, not an error.
Where a milestone waits on several others, it takes the
latest of them. Nothing calculated is saved — only the
dates and durations you pin — so a correction anywhere reflows
the schedule immediately.
Entering dates
Type into a milestone cell and add a letter anywhere to say
which date you mean:
2027-02-24
- Sets whichever track the cell is showing.
2027-02-24 a · a 2027-02-24
- Actual — it happened on that date.
2027-03-10 f
- Forecast — what you now expect.
2027-01-06 p
- Plan — the baseline.
NA f · NA a
- Not applicable — this milestone will
not happen.
NA f forecasts that it is not
required; NA a confirms it was not.
Dates are always YYYY-MM-DD. Clearing a cell
removes your pin and lets the value derive again. To see or edit
the three tracks in their own columns — and the durations —
open Columns ▾ and switch them on, or
right-click the column header.
The CSV takes the same entries. Export,
edit a milestone column in a spreadsheet — 2027-03-01 f,
NA a — and re-import; each value goes to the track
its letter names (no letter means forecast).
In a CSV, a CAPITAL letter means the schedule worked
that one out — 2027-01-11 F, 2027-01-11 P
— and importing skips it, exactly as if the cell were blank. So
the file shows you the whole calculated schedule and is still safe
to send back: nothing you didn't type can be turned into a fixed
date. Lowercase is yours. To take one over, just type your date
in its place; to hand one back to the schedule, empty the cell.
(Capitals are a plain-text device only — on screen the same thing
is said by italic, and typing is not case-sensitive.)
When a milestone isn't needed
A baseline that included a site visit, and the site visit
turned out not to be necessary. Say so on a track:
NA f while it is still a forecast,
NA a once it is confirmed. Often you will enter the
actual for the next milestone in the same sitting.
This is deliberately not the same as removing the milestone,
and the difference is worth knowing:
- A milestone with no dates at all
- Was never part of this package. The chain skips over it
and closes the gap — everything after it moves earlier.
- A milestone marked NA
- Was part of this package and will not happen. The
baseline still records that it was planned, and
its duration is still reserved, so nothing
downstream jumps. If the work really did compress, re-forecast
the next milestone as usual.
An NA milestone is settled: it never goes overdue, it is never
counted behind plan, and it drops out of "what this package is
waiting on". It reads muted, because there is nothing to act on.
Any measure can take it, not just milestones — an allowance that
will not be drawn is NA too, and it is left out of
column totals rather than counted as zero.
Once a row is baselined (row menu → Set baseline)
its Plan dates lock, so a baseline can't drift when a duration is
edited later. Re-baselining is an explicit action.
What the colours mean
Two different questions, answered on two different channels,
so neither has to be guessed at.
A solid red cell needs action now. It means a
forecast date has passed with nothing recorded against it —
either it happened and needs an actual, or it slipped and needs
re-forecasting. Red is used for nothing else.
The text colour compares against the baseline:
- Orange
- Behind plan — later than the baseline. Orange, not red,
because it is often the best that can be done and there may
be nothing to act on.
- Blue
- Exactly on plan.
- Green
- Ahead of plan.
- Plain text
- No baseline set, so there is nothing to compare against.
- Muted
NA
- Not applicable — excused from the comparison entirely.
- Bold
- An actual — a fact, not an estimate.
- Italic
- Calculated from the chain rather than typed in. (In an
exported CSV this is a capital track letter instead, since
italics don't survive a spreadsheet.)
The dot beside the package name summarises the
whole row, always matching its worst cell:
red something is overdue ·
amber behind plan, or a required document is
missing · green on or ahead of plan ·
grey every milestone recorded. Hover it for the
reason.
Filtering
Type in the box under a column header to filter rows whose value
contains your text (case-insensitive). The same box understands a
small grammar — the ? beside a filter jumps here.
Text (every column):
a b | both terms (AND) |
a|b | either term (OR) |
!x | does not contain x |
^s · x$ | starts with · ends with |
* | anything (matches all) |
^$ | empty / blank cells (!^$ = non-empty) |
|x | leading |: OR this column into the results instead of narrowing — (all plain filters) OR (any |-column) |
Dates (date columns also accept):
> >= < <= = | compare to a date |
a..b | inclusive range |
| values | today · 2026-07-15 · 2026-07 (month) · 2026 (year) · 26Q2 (quarter) |
| weekday | mon…sun — that weekday: today if it is, else the next one |
| offsets | +N / -N with d w m q y (e.g. today+2w) |
| snap | /d /w /m /q /y — round to the period start (today/m) |
| windows | last N <unit> / next N <unit> (last 7 days, last2w, next 2 weeks) |
^$ | rows with no date (!^$ = has a date) |
Examples: >today · <=today+30d ·
last 7 days · 26Q2 · >=mon ·
today-7d..today
Customizing the columns
A table's columns, sort and filter defaults come from the
table.yaml in its directory; the row-edit form
comes from form.yaml. To customize, drop your own
table.yaml (and matching form.yaml)
into the directory:
<dir>/
table.yaml ← columns + sort/filter defaults
form.yaml ← per-row schema (JSON Schema)
<id>.yaml ... ← rows
Operator-supplied files override the embedded defaults.
Hide a column by omitting it from columns:;
add a column by appending one (and adding the matching
property in form.yaml's
schema.properties). Any directory with a
table.yaml becomes a table —
<dir>/table.html renders it.
Permissions
Whether a row is editable depends on the cascading
.zddc permissions for the directory. Rows
in Issued or Received archives
are read-only by design (WORM).
Header buttons
- ◐ Theme
- Cycle auto / light / dark.
- ? Help
- This panel. Press Esc to close.