Build Reclaim.ai
KINDAreplaces $12/mosaves $144/yrback to the verdict
A scheduling assistant whose core is a constraint solver over your calendar: fit tasks and recurring habits into free time, respect deadlines and working hours, and rearrange when a meeting lands on top of something without producing a different plan every time it runs.
Before step 1
Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.
- installfree
Why Runs the server, the solver and the sync workers.
Get it nodejs.org, or nvm install 22. open ↗
Verify
node --version prints v22 or higher - installfree locally
Why Placements, solves and busy time with correct interval queries.
Get it Docker or your package manager. open ↗
Verify
psql connects and a range overlap query returns correctly - accountfree
Why Phase 3 writes real events into a real calendar, and the failure modes only appear against a live account with existing meetings.
Get it A test calendar with a month of realistic meetings, including recurring series with exceptions and some declined invitations.
Verify
Events can be created and the tool's own events are identifiable by stored id - have readyfree
Why Solver behaviour is entirely determined by how fragmented a real calendar is, and a test calendar with three meetings will make any solver look excellent.
Get it Use your actual calendar, or reconstruct a genuinely busy week including back-to-back meetings and a day with almost no free time.
Verify
A week exists with at least fifteen meetings and one nearly full day - decidefree
Why Declined, tentative, all-day and out-of-office events each need an answer before the solver exists, and changing the answer later silently changes every plan.
Get it Write down whether each status blocks time, and what working hours actually mean for you including whether evenings count.
Verify
A written note gives a rule for every status your calendar produces
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, due_at, min_chunk_minutes, max_chunk_minutes, priority, completed_at) - habits(id, title, cadence, duration_minutes, window_start, window_end, days_json, priority) - placements(id, source_kind, source_id, calendar_event_id, starts_at, ends_at, solve_id, pinned, user_moved) - solves(id, at, reason, placements_changed, inputs_hash) · so you can explain why the plan changed - busy(id, calendar_id, starts_at, ends_at, external_event_id, is_ours) · the calendar as the solver sees it - working_hours(day_of_week, start_local, end_local, zone) - A placement records whether the user moved it, because a block someone dragged somewhere is a decision the solver must respect rather than undo.
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.
| Variable | Needed | Example | Where the value comes from |
|---|---|---|---|
DATABASE_URLsecret | required | postgres://localhost:5432/schedule | Placements, tasks and a copy of your calendar's busy time. |
CALENDAR_CLIENT_IDsecret | required | a provider client id | Calendar access. Request the narrowest scope that allows creating and updating your own events. |
USER_TIMEZONE | required | Europe/London | Working hours and habit windows are local. Everything stored is in UTC. |
MIN_CHUNK_MINUTES | required | 45 | The smallest useful block. Below this a placement is an interruption rather than work. |
SOLVE_STABILITY_BIAS | required | high | How strongly to prefer keeping existing placements over a marginally better plan. |
TOUCH_FOREIGN_EVENTS | required | never | Present as a constant so the answer is visible in configuration. There is no other value. |
The build, in order
Knowing when you are actually free
A correct picture of free time, including the awkward cases.
The series minus its cancellations. Assuming the series is the common bug.
Files
src/recurrence.tssrc/recurrence.test.tsDeclined, tentative, all-day, out of office. Each needs an explicit answer.
Files
src/busy.tsNot the server's, and not a fixed offset.
Files
src/hours.ts
done when · tick each as it passeswatch out- Treating a declined invitation or an all-day event as busy time removes most of the week from consideration, and treating tentative events as free schedules work on top of meetings people are probably attending. Decide the rule for each status explicitly, and expand recurrence with exceptions rather than assuming the series.
Placing work into the gaps
Tasks and habits get placed sensibly and the same inputs give the same plan.
Same inputs, same plan, asserted in the suite. This is what makes it usable.
Files
src/solve.tssrc/solve.test.tsTwenty minutes of deep work is not useful. The minimum exists for a reason.
Files
src/chunk.tsSilently dropping a task before its deadline is the worst possible behaviour.
Files
src/report.ts
done when · tick each as it passeswatch out- A solver that finds a slightly better arrangement each run will move your Tuesday afternoon every time it executes, and a plan that changes constantly is one nobody can work to. Prefer keeping existing placements over marginal improvements, and make identical inputs produce an identical plan.
Writing to a calendar you did not create
Placed blocks appear in your real calendar and nothing else is ever touched.
Never by title or colour. A rename must not orphan a block.
Files
src/calendar.tsIn the write path, with a test that attempts it and expects a refusal.
Files
src/calendar.tstests/foreign-events.test.tsSync tokens expire. A resync that duplicates a week is very visible.
Files
src/sync.ts
done when · tick each as it passeswatch out- Identifying your own events by title or colour means a user renaming a block makes it invisible to the tool, which then creates a duplicate, or worse, a coincidence of naming makes the tool delete a real meeting. Store the created event identifier and treat anything not in that set as untouchable.
When a meeting lands on your work
A new meeting moves the affected block and nothing else.
The displaced block and its dependents. Not the week.
Files
src/resolve.tsSomeone dragging a block has expressed a preference. Undoing it is insulting.
Files
src/placements.tsA block that started is history, whether or not the work happened.
Files
src/resolve.ts
done when · tick each as it passeswatch out- Re-solving the whole week when one meeting appears rearranges work the user has already mentally committed to, and doing that a few times teaches them to ignore the calendar entirely. Move the displaced block and its dependents, leave everything else, and treat a block the user dragged as pinned.
Explaining the plan, and living with itproduct builder
You can ask why something is where it is, and see whether the plan matched reality.
Deadline, priority, habit window. So the plan can be questioned.
Files
src/reasons.tsWhat moved and why. Silent rearrangement is what erodes trust.
Files
src/diff.tsContinuing to schedule fiction makes the whole calendar untrustworthy.
Files
src/adherence.ts
done when · tick each as it passeswatch out- A scheduler that keeps placing a habit you never do produces a calendar full of fiction, and the user stops trusting every other block as well. Detect a habit or task type that is consistently not completed, surface it, and offer to reduce or remove it rather than continuing to place it.
That is the whole plan for Reclaim.ai. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- Multi-person meeting scheduling.
- Integrations with external task tools.
- Machine-learned duration estimation.
- Team-wide scheduling policies.
- team coordination
- smart rescheduling polish
- scheduling links
- calendar edge cases
- uptime
- Buffer time around meetings, which most people need more than more work blocks
- Travel time between events with locations, once the busy model is trustworthy
- Focus mode integration, so a placed block actually protects itself
Need the files? The project pack on the verdict page hands your agent the whole brief · more tasks & calendar.