1 The big picture
The Tasks & Projects OS is one screen with seven tabs. Each tab gives a different way to look at the same set of tasks and projects. Rules and automations run quietly in the background to keep everything tidy.
Task List
Spreadsheet view of every Urgent / High / Not Urgent task. Inline edit anything.
How it works ›Reading the colour codes
Throughout this doc:
User action = a person clicks something
Automation = the app does it for you
Rule = a logical "if this then that" in the code
AI = a Claude model is called
Slack = sends a DM
Data = reads from / writes to Airtable
2 Task lifecycle — start to finish
Every task that ends up in this system goes through some or all of these stages.
Created
Add Task modal, inline timeline, KPI auto-spawn, or Strategy → Projects push
Assigned
To a team member. Slack DM fires.
Scheduled
Auto-placed on My Day or pinned to a Kanban week
Worked on
Status auto-derives from due date
Completed
All collaborators get a Slack DM
Created By Email, project link cascades into priority/business/collaborators, and a status is derived from the due date. None of this needs the user to do anything manual — it just happens on save.flowchart LR A[Click + Add Task]:::user --> B[Fill modal]:::user B --> C[Submit]:::user C --> D[Cascade rules apply]:::auto D --> E[POST to Airtable]:::data E --> F[Slack DM fires
to assignee]:::slack E --> G[Stamp Created By]:::auto E --> H[Re-render UI]:::auto classDef user fill:#DBE5F5,stroke:#5A86CF,color:#1e3a8a classDef auto fill:#DDE8DF,stroke:#2C6E49,color:#14532d classDef data fill:#E5E8E1,stroke:#5A6660,color:#1C2422 classDef slack fill:#E1ECF4,stroke:#4A154B,color:#4A154B
What happens the moment you press "Add Task"
3 Tab: My Day
For: the daily user — Kevin, Mica, Erica each on their own filtered view. Default tab on open.
What you see
- Vertical timeline — your day from working start to end, with hour markers
- Calendar events in plum (pulled from Google Calendar via the gcal proxy)
- Routine blocks in amber (Run, Lunch, Get Ready — configurable per user)
- Tasks in their priority colour: Urgent (red), High (yellow), Project (blue), Not Urgent (green)
- Side panel on the right: today's other tasks not yet placed on the timeline
What you can do
- User Drag a task between time slots → due date stays today, just changes start time
- User Drag the bottom edge of a task → resize duration
- User Drag a task into the side panel → reschedules to next available day with capacity
- User Drag from side panel onto timeline → schedules at that time
- User Double-click an empty slot → inline-add a task at that time (15-minute default)
- User Click the Auto-Schedule button → run the planner across the next two weeks
Automations fired here
| When | What happens |
|---|---|
| Page loads (Kevin only) | Auto Overdue tasks pulled forward to today (skips hard-deadline + project beyond this week) |
| Inline-add a task | Auto Task assigned to whoever's day you're viewing (not the logged-in user). Pinned at the clicked time. Slack DM to assignee if not yourself. |
| Drag onto side panel | Rule Find the next workday (skip weekends) within capacity for that assignee → reschedule due date there |
| Click Auto-Schedule | Auto Run scheduler with the rules in section 9 |
The colour-coded blocks
When two blocks land in the same time slot the timeline splits the column horizontally so they sit side-by-side instead of hiding each other.
4 Tab: Task List
For: the spreadsheet view of operational work. Shows tasks with priority Urgent / High / Not Urgent. Project-priority tasks live on the Kanban tab, not here.
Columns
Data Task · Assignee · Due Date · Hard? · Time Estimate · Priority · Project · Status · Business · Recurring · Actions
What you can do
- User Click any cell to inline-edit. Saves on blur.
- User Click anywhere on a row (outside an edit cell) to open the drawer
- User Filter by any column header — assignee, due, priority, project, business, recurring, status, time estimate
- User Bulk select with checkboxes → reassign / reschedule / mark complete / delete in one go
- User Sort by clicking column headers (default: due date then priority)
Automations fired here
| Trigger | What happens |
|---|---|
| Change Status to Completed | Auto Stamps Completion Date. Slack DM to every collaborator (except you). If recurring → roll the due date by the cadence and flip back to Upcoming. |
| Change Due Date | Auto Status re-derives instantly (Overdue / Today / Upcoming). Patched back to Airtable. |
| Change Assignee | Slack DM to new assignee. Auto The actor (whoever clicked) and the previous assignee both become collaborators. |
| Pick a Project | Rule Priority flips to "Project". Business inherits from project. Project's collaborators merged in. The drawer's Priority + Business dropdowns update in real-time. |
| Any inline edit succeeds | Auto Team filter counts at the top + KPI tiles re-render to match |
5 Tab: Kanban
For: planning project work week-by-week. Only Project-priority tasks appear here.
Three view modes
| Mode | Shows | Drag drops to |
|---|---|---|
| 4 Weeks (default) | Rolling 4 weeks from this Monday | Monday of that week |
| 12 Weeks | Rolling 12 weeks (horizontal scroll) | Monday of that week |
| 12 Months | Calendar months from this month | 1st of that month (or today if same month) |
The Overdue column
If any open Project task has a due date before the visible window, a red-bordered Overdue column auto-appears at the front. Drop a card onto a week → moves it there. Disappears when nothing is overdue.
The "leave my plan alone" rule
6 Tab: Projects
For: seeing how the strategic projects are progressing.
What each card shows
- Project name + business
- KPI progress bar — current value vs target
- Linked tasks (active count + overdue)
- Owner
- Click to expand → details + auto-opens the KPI drill-down
The KPI drill-down
For projects with computed KPIs, the drill-down has different shapes depending on what the compute returns:
| KPI kind | Drill-down shows | Example |
|---|---|---|
| Revenue / cost | Three cards (Revenue / Costs / Cushion) + transaction tables, plus per-month pills | Operating Cushion, MRR |
| Task completion | Three cards (Completed / Outstanding / Total) + tables of those task names | Web App module completion % |
Compute logic is hand-written JS stored in each project's KPI Compute Code field on Airtable. The Leadership Dashboard runs the compute and writes the result back as JSON in KPI Detail JSON. Task OS just reads what's already been computed — no compute happens here.
7 Tab: Capacity
For: who has the most on their plate this week. Each team member shows allocated hours per day for the next 14 days.
Configurable daily cap (default 6 hours) per person via localStorage. Coloured red when over capacity, amber when 80–100%, green below.
8 Tab: Recurring
For: seeing every task with a cadence (Daily, Weekly, Fortnightly, Monthly, Quarterly, Bi-Annually, Annually). Grouped by person and frequency.
Task Completions log records each cycle for productivity reporting. This means deleting a recurring task is permanent — no phantom respawns.Full lifecycle is in section 12.
9 Tab: Contractor Tasks
For: Gary, Rob, and Roy — the maintenance team. Tabbed switcher between the three of them.
How it differs from regular tasks
| Aspect | Regular task | Contractor task |
|---|---|---|
| Due date | Required | None — just a Created Date |
| Status | Derived from due date | Always Upcoming until Completed |
| Sort order | By due date then priority | By Priority Level then oldest Created Date |
| Grouped by | Nothing in the grid | Property (gradient sage card per property) |
| Identified by | (any task) | Maintenance Ticket = TRUE on Airtable |
10 Automation: Status derivation
The Status field is derived from the due date for almost every task. It's not something you usually set manually.
flowchart TD
A[Task in scope]:::data --> B{Stored status
= Completed
or Approval?}:::rule
B -->|Yes| C[Keep stored status]:::auto
B -->|No| D{Maintenance ticket?}:::rule
D -->|Yes| E[Force Upcoming]:::auto
D -->|No| F{Has due date?}:::rule
F -->|No| G[Upcoming]:::auto
F -->|Yes| H{Due < today?}:::rule
H -->|Yes| I[Overdue]:::auto
H -->|No| J{Due = today?}:::rule
J -->|Yes| K[Today]:::auto
J -->|No| L[Upcoming]:::auto
classDef rule fill:#FEF3C7,stroke:#C6A15B,color:#92400e
classDef auto fill:#DDE8DF,stroke:#2C6E49,color:#14532d
classDef data fill:#E5E8E1,stroke:#5A6660,color:#1C2422
How deriveTaskStatus decides what status to show
When you change a due date inline, the new status is also patched back to Airtable so downstream consumers (other automations, the dashboard, exports) see the same value. The Sync popover surfaces drift here as a "stale statuses" count with a one-click "Reconcile all" button.
11 Automation: Auto-scheduler
The "Auto-Schedule" button on My Day re-arranges your tasks across the next ~14 days, respecting calendar events, routine blocks, and capacity.
flowchart TD
A[Click Auto-Schedule]:::user --> B[Fetch calendar + routines]:::data
B --> C[Compute free slots per day]:::auto
C --> D[Walk tasks priority-first]:::auto
D --> E{Hard deadline?}:::rule
E -->|Yes| F[Skip — never moved]:::auto
E -->|No| G{Project priority
past Sunday?}:::rule
G -->|Yes| H[Skip — Kanban-pinned]:::auto
G -->|No| I{Due > 14 days?}:::rule
I -->|Yes| J[Skip — far future]:::auto
I -->|No| K[Place in next free slot
within daily cap]:::auto
classDef user fill:#DBE5F5,stroke:#5A86CF,color:#1e3a8a
classDef rule fill:#FEF3C7,stroke:#C6A15B,color:#92400e
classDef auto fill:#DDE8DF,stroke:#2C6E49,color:#14532d
classDef data fill:#E5E8E1,stroke:#5A6660,color:#1C2422
Order of checks the scheduler runs against each task
The four exclusions, in plain English
- Hard deadline — never moves. If you flagged it immovable, the scheduler reserves capacity on its existing day and walks past.
- Project past this week — never pulled forward. If you put a Project task on Kanban Week 3, the scheduler respects that — you planned it deliberately.
- Far future (>14 days) — left alone. If you intentionally pushed something out, don't pull it back.
- Within the horizon, no flags — fair game. Scheduler places it in the next free slot that has capacity.
For Kevin specifically: on dashboard load, overdue tasks (excluding hard-deadline + project-future) get a one-shot pull-forward to today. Other team members keep their overdue counts visible for accountability.
12 Automation: Slack notifications
Four event types fire DMs via the slack-notify Cloudflare Worker.
| Trigger | Recipient | DM reads | Skipped when |
|---|---|---|---|
| Task assigned (created with assignee) | Assignee | "Creator assigned a task to you" | Self-assignment |
| Task reassigned | New assignee | "Actor reassigned to you" | Reassign to same person, or to actor |
| Task completed | Every collaborator (except completer) | "Completer completed a task you collaborate on" | No collaborators, or completer is the only one |
| Comment added | Every collaborator + assignee (except commenter) | "Author left a comment" + the comment quoted | No other collaborators |
flowchart LR A[Web app event]:::user --> B[POST to Cloudflare Worker]:::auto B --> C[Worker: lookup
email → Slack user ID]:::auto C --> D{Found?}:::rule D -->|No| E[Return 404 — log to console]:::auto D -->|Yes| F[chat.postMessage]:::slack F --> G[DM lands in Slack]:::slack classDef user fill:#DBE5F5,stroke:#5A86CF,color:#1e3a8a classDef rule fill:#FEF3C7,stroke:#C6A15B,color:#92400e classDef auto fill:#DDE8DF,stroke:#2C6E49,color:#14532d classDef slack fill:#E1ECF4,stroke:#4A154B,color:#4A154B
From button click to Slack DM in < 2 seconds
The fail-safes
- 📨 Resend Slack button on the drawer — manually re-fires the assignment DM. Uses the task's stored
Created By Emailas the actor name (falls back to current user, then "(unknown)"). - Sync popover diagnostic panel — "Send test DM" picks a member and sends a test ping. "Check all recipients" runs a lookup-only check across the whole TEAM with no DMs sent.
- Per-member
slackEmailoverride — for people whose Airtable email differs from Slack (Gary). Translation happens on the way to the worker. - Fire-and-forget — Slack failures never block the user's save. Errors log to browser console + Cloudflare Worker logs.
13 Automation: Collaborator cascades
Three sources contribute to a task's collaborator list. They merge additively, deduplicated by email.
| Source | Triggers when | Adds |
|---|---|---|
| Project inheritance | Task gets a project link | Every member listed on that project's Project Collaborators field |
| Creator-as-collaborator | Task is created and assignee ≠ creator | The creator (current user) |
| Reassigner-as-collaborator | An existing task's assignee changes (and actor ≠ new assignee, ≠ already on list) | The actor (whoever clicked the dropdown) |
The Sync popover's drift check verifies the collaborator list locally vs Airtable for every active task — surfaces anywhere a cascade silently dropped.
14 Automation: Recurring rolling
Recurring tasks use the single rolling record model. One Airtable record per recurring task — its due date advances on completion.
flowchart TD
A[Recurring task with cadence]:::data --> B[User marks Completed]:::user
B --> C[Log completion to Task Completions table]:::auto
C --> D[Roll due date forward by cadence]:::auto
D --> E[Flip status back to Upcoming]:::auto
E --> F[Same record continues to live]:::auto
classDef user fill:#DBE5F5,stroke:#5A86CF,color:#1e3a8a
classDef auto fill:#DDE8DF,stroke:#2C6E49,color:#14532d
classDef data fill:#E5E8E1,stroke:#5A6660,color:#1C2422
Option A: one record forever, with an immutable completion log
Why this model?
- Clean delete semantics — deleting a recurring task is permanent. No phantom respawn from auto-spawn logic.
- Permanent productivity record — every cycle's completion is logged to the
Task Completionstable, independent of the live task. - Natural capacity projection — each task = one row, makes capacity calculation simple.
15 Automation: KPI computation
Each Project record has two KPI fields wired:
| Field | Type | Purpose |
|---|---|---|
KPI Compute Code | multilineText | Hand-written JS function body. Receives ctx with transactions / costs / tasks / project / today + helpers. Returns a number or an object with value + detail. |
KPI Detail JSON | multilineText | Most recent compute result, written by the Leadership Dashboard. Capped at ~95KB — long transaction lists trim progressively. |
Where compute runs
Leadership Dashboard
Loads. Fetches transactions + tasks. Builds ctx. Runs every project's compute code in a sandbox.
Result PATCHed
Writes kpiCurrent + kpiDetailJson back to the Project record on Airtable.
Task OS reads
Projects tab and Strategic KPIs section parse the JSON and render. No compute on this side.
Three KPI shapes currently live:
- Operating Cushion (Real Estate) — Revenue minus Fixed Costs, rolling 31 days + monthly breakdown
- MRR (Operations Director) — Sum of Fixed Income transactions, monthly breakdown
- Task Completion % (Web App project) — Linked tasks completed / total × 100
16 Automation: Sync & health check
The green ✓ Saved pill in the top-right opens a popover with everything you need to know about save state and data integrity.
What it monitors
| Section | Tells you |
|---|---|
| Save state | Pending / OK / Failed counts for the current session |
| Drift detection (Check Sync button) | Tasks where local state ≠ Airtable. Compares name, status, priority, due date, description, collaborators, Created By Email. |
| Stale statuses | Tasks where derived status ≠ Airtable's stored status. One-click "Reconcile all" to backfill at 5 req/s. |
| Missing creators | Active tasks without a Created By Email. One-click "Backfill with my email" to stamp the current user. |
| Slack diagnostic | Test DM to a single member, or batch lookup of every team member with no DMs sent (lookup-only mode). |
| Recent saves | Last 50 field-level edits with status. Persists across reloads via localStorage. |
17 Where AI helps
AI calls are limited to deliberate, scoped use cases — never a global "do my work" loop.
| Where | Model | What it does | Lives in |
|---|---|---|---|
| Strategy → Projects push | AI Sonnet | Extracts discrete tasks from each Monthly Stepping Stone description | os/strategy/strategy.js |
| KPI compute generation | AI Sonnet (manual) | Drafts JS compute bodies. Stored in Airtable, runs sandboxed in dashboard. | Hand-written, not in-app wizard |
| Reconciliation suggestions | AI Sonnet | Suggests Chart of Accounts categories for unreconciled transactions | Reconciliation skill |
All AI calls go through claude-proxy.kevinbrittain.workers.dev — Cloudflare Worker that holds the Anthropic API key server-side.
18 The data model
flowchart LR
T[Tasks]:::data
P[Projects]:::data
B[Businesses]:::data
TM[Team Members]:::data
C[Task Completions]:::data
TX[Transactions]:::data
T -->|Assignee| TM
T -->|Collaborators| TM
T -->|Project link| P
T -->|Business link| B
T -->|Created By Email| TM
P -->|Project Collaborators| TM
P -->|Business| B
T -->|On complete, log| C
P -->|KPI compute reads| TX
classDef data fill:#E5E8E1,stroke:#5A6660,color:#1C2422
How tables relate. Everything written by the web app PATCHes to Airtable directly.
Identity flow
On dashboard load you pick your identity ("Who are you?" overlay). That sets currentUser = name + email + key. Stored in localStorage so it sticks across reloads. Used everywhere the app needs to know "who is doing this": new task creator, comment author, complete actor, Slack DM sender, etc.
19 Glossary
- Active task
- Any task whose status isn't Completed and whose
Some Dayflag isn't set. The default filter for almost every list in the app. - Assignee
- The single person responsible for completing a task. Stored as an Airtable singleCollaborator field. Changing this fires a Slack reassignment DM.
- Cadence
- The repeat interval on a recurring task: Daily, Weekly, Fortnightly, Monthly, Quarterly, Bi-Annually, Annually.
- Collaborator
- Anyone CC'd on a task — they get the completion + comment DMs. Auto-populated by the cascades in section 13. Distinct from Assignee.
- Created By Email
- Plain-text field stamped on every web-app-created task with the creator's email. Survives identity switching, app upgrades, localStorage clears. Not set on tasks created in Airtable's native UI.
- Hard deadline
- A task flag that immobilises it. The auto-scheduler will not move a hard-deadline task in either direction.
- KPI Compute Code
- Hand-written JavaScript function body stored on a Project record. Runs sandboxed in the Leadership Dashboard's KPI engine to compute the project's current KPI value.
- Maintenance Ticket
- Boolean flag on a task that marks it as a contractor job. Tasks with this flag appear on the Contractor Tasks tab and are sorted differently (priority + age, not due date).
- Option A (recurring)
- The single-rolling-record model for recurring tasks: one record per task, due date advances on completion, completions logged separately. Replaces older auto-spawn-on-complete logic.
- Pull-in horizon
- The 14-day window from today within which the auto-scheduler is allowed to move tasks forward. Past this, tasks are left alone.
- Sync drift
- A mismatch between local state and Airtable that the Sync popover surfaces. Most commonly stale statuses; rarely a real save failure.
- currentUser
- The identity selected at login. Used as the actor for Slack DMs, the value stamped into Created By Email, the collaborator added by reassign cascades, and the default assignee for inline-add.