Build Motion

KINDAreplaces $19/mosaves $228/yrback to the verdict

0%0 of 20 items done

Saved on this device only. Tick prerequisites first, then work the phases in order · do not start one until the checks above it pass.

Tasks with duration, deadline and priority, availability read from your real calendar, a solver that places them into free time respecting working hours and deadlines, time blocks written back as calendar events, and a rescheduling pass that explains what moved and why when a meeting appears.

estimated effort multi-daythe files for this build are in the project pack

RuntimeTypeScript on Node 22CalendarCalDAV, or a provider API, behind one interfaceSolverA greedy placement with a deterministic tie-break, not a constraint libraryStoragePostgreSQLTimeA library with a full time zone database

Before step 1

Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.

  1. installfree

    Why Runs the solver and the service.

    Get it nodejs.org, or nvm install 22. open ↗

    Verify node --version prints v22 or higher

  2. free with an existing account

    Why Availability from a test calendar tells you nothing, and writing blocks into a real calendar is the whole product. Use one you actually live by.

    Get it Set up the connection with your provider's credentials or CalDAV. Create a dedicated calendar for scheduled blocks so they are visually separable and easy to clear.

    Verify Busy time reads correctly and a test event writes to the blocks calendar

  3. installfree

    Why Holds tasks, plans and the history of what moved.

    Get it Install locally or run it in Docker. open ↗

    Verify psql connects and reports 16 or higher

  4. have readyfree

    Why The solver is only interesting against real work, and honest durations are what reveal whether the plan is achievable. Optimistic estimates produce a plan that fits and a week that does not.

    Get it Write down what you actually intend to do for two weeks, with a duration you would defend and a real deadline.

    Verify At least twenty tasks with durations and deadlines are entered

  5. free

    Why Product phase only. Most people have a second calendar containing meetings that block time, and ignoring it produces a plan that collides with reality.

    Get it Connect it read-only. It constrains placement without receiving blocks.

    Verify Its events appear as busy time

Data model

Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.

- tasks(id, title, duration_minutes, deadline_at, priority, min_block_minutes, max_block_minutes, state, project_id)
- dependencies(task_id, depends_on_task_id) · a task cannot be scheduled before what it needs
- availability(id, weekday, start_local, end_local, kind) · kind is work, deep or personal, in a stated time zone
- busy(id, source, starts_at_utc, ends_at_utc, external_id) · pulled from real calendars, never invented
- blocks(id, task_id, starts_at_utc, ends_at_utc, external_event_id, generation) · what was written back
- schedule_runs(id, at, generation, tasks_considered, tasks_placed, tasks_unplaceable, reason_json)
- A generation number on every block is what lets a rebuild replace the previous plan cleanly instead of accumulating duplicates.

Environment variables

These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.

VariableNeededExampleWhere the value comes from
DATABASE_URLsecretrequiredpostgres://user:pass@localhost:5432/scheduleYour PostgreSQL connection string.
BLOCKS_CALENDAR_IDrequiredscheduled-workThe calendar that receives blocks. A dedicated one, so clearing it is safe.
EVENT_TAGrequiredautoplanThe property value marking events this application created. Nothing without it is ever modified.
WORKING_TIMEZONErequiredEurope/LondonThe zone working hours are expressed in. Not the server's zone.
MIN_BLOCK_MINUTESrequired30Default minimum block. Shorter blocks fit more easily and are less useful for real work.
AVAILABILITY_STALE_MINUTESrequired60How old calendar data may be before the solver refuses to write a plan.
PLAN_HORIZON_DAYSrequired14How far ahead to schedule. Longer plans are more fragile because more will change.

The build, in order

  1. Real availability

    The application knows exactly when you are free, from your actual calendar.

    1. Behind one interface so the provider can change. Store instants with the source and external identifier.

      Files src/calendar.ts

    2. Per weekday, local wall clock, with the zone stated explicitly rather than inherited from the server.

      Files src/availability.ts

    3. Convert working hours to instants per date. Test across a clock change.

      Files src/availability.test.ts

    done when · tick each as it passes
    watch out
    • Working hours are local wall clock and busy time is instants, so subtracting one from the other without converting produces free intervals that shift by an hour twice a year. Convert working hours to instants for the specific dates being scheduled, using the zone, rather than treating them as fixed offsets.
  2. A solver that explains itself

    Tasks are placed into free time, and every task that was not placed says why.

    1. Deadline first, then priority, with a deterministic tie-break so runs are reproducible.

      Files src/solve.ts

    2. Respect minimum and maximum block size. A task needing two hours of unbroken focus cannot be four half hours.

      Files src/solve.ts

    3. Unplaceable is an output, not an omission. This is the difference between a plan and a wish.

      Files src/solve.ts

    done when · tick each as it passes
    watch out
    • A solver that silently omits what it cannot fit produces a plan that looks achievable and is not, and you discover the missing work at the deadline. Every unplaced task must appear with a reason: not enough free time before the deadline, blocked by a dependency, or a minimum block size larger than any available gap.
  3. Writing blocks back

    The plan appears in your calendar, and rebuilding it does not leave debris.

    1. An identifier in a property you own. Nothing untagged is ever touched.

      Files src/write.ts

    2. Delete the previous generation's tagged events, then write the new one. Count before and after.

      Files src/write.ts

    3. A block whose event is gone is a signal the user rejected it, not an error to correct.

      Files src/sync.ts

    done when · tick each as it passes
    watch out
    • Identifying your own events by title or by time will eventually delete a real meeting, and that is an unrecoverable mistake in someone's calendar. Tag every event you create with an identifier you own, and refuse to delete anything without that tag, even during cleanup.
  4. Rescheduling when the day changes

    A meeting appearing at short notice reshuffles the plan, and you can see what moved.

    1. On a schedule or on a change notification. A stale plan is worse than no plan.

      Files src/watch.ts

    2. Keep placements that still fit. Only what the change displaced may move.

      Files src/solve.ts

    3. Moved, at risk, and newly unplaceable. This is what the user actually reads after a rerun.

      Files src/diff.ts

    done when · tick each as it passes
    watch out
    • A solver rerun that reshuffles everything because one meeting appeared makes the plan feel random and untrustworthy, even when each individual placement is optimal. Weight stability explicitly: keep blocks that still fit, and move only what the change forced.
  5. Being honest about the plan

    The application tells you when the plan is not achievable rather than presenting a full calendar.

    1. Total task duration against total free time for the horizon. One number, shown prominently.

      Files src/capacity.ts

    2. Scheduled against actually done. Report the ratio as information about your estimates.

      Files src/completion.ts

    3. An estimate that was optimistic is a fact about estimating, not a failing.

      Files src/report.ts

    done when · tick each as it passes
    watch out
    • A scheduler that always produces a full plan implies the work is achievable, and the honest failure mode is telling someone that it is not. If committed work exceeds available time, say so at the top rather than placing tasks past their deadlines and calling it a schedule.
what this build does not replace
after v1, if you want it

Need the files? The project pack on the verdict page hands your agent the whole brief · more tasks & calendar.