Setup guide · Your AI Work Tracker

Track your work with Claude.
No spreadsheets. No setup hell.

The page you came to steal from — and you should. Three layers working as one system: a task list your AI keeps honest, a tiny website (just a shell and a data file) hosted free, and a capture backend for thoughts that arrive mid-meeting. You talk about your day in plain conversation; it stays organized, prioritized, password-locked, and open from any browser. By the bottom of this page, you own one.

? How this works

Three layers, one conversation. Your task list is where the truth lives. The website — a shell plus a data file — is where you look at it. The capture backend (optional, Step 6) is how you talk to it from a meeting. The website part really is this simple:

📄
index.html
The display shell. Never changes. Shows your tracker in the browser.
+
🗂
data.json
Your session data. Claude rewrites this each time you check in.
→
🌐
GitHub Pages
Free hosting. Your tracker is a live website you can open anytime.
Your new routine, so you can picture it: you sit down, open a chat, paste a short prompt, and tell me — well, your version of me — what kind of day it was. Your AI reads the current data file, asks you the two or three questions worth asking, and hands back an updated one. You upload it. Your site matches your life again. Five minutes. No app to open, no subscription to cancel later, nothing to remember except talk to the thing. You've kept harder habits by accident.

✦ What makes it think, not just list 2026 update

A plain to-do list tells you what exists. This one tells you what to do — because your AI reads every item through a few lenses at once, and lets priority fall out instead of guessing it. You don't set any of this up; it's just how the check-in thinks now.

The lenses. Every item quietly answers three questions: whose move is it (you, or someone you're waiting on), how soon (today, this week, later), and what kind of work (make something, review, coordinate, reply, chase). So you can ask your list real questions — "what's actually on me today?", "everything I'm waiting on Sarah for" — instead of scrolling and hoping.
Priority you don't throw. It's two things crossed. Urgency is computed from due dates and what's blocking — you can't inflate it. Importance is a rare flag your AI only raises with a reason. Cross them and you get the four buckets that actually matter: do now, protect (matters but isn't due — the work a deadline-sort quietly buries), knock out, or let it wait.
The check-in drives. Instead of you narrating and it transcribing, it reads your list, opens with a five-line triage (overdue · due today · blocking · in your court · gone quiet), asks only what needs a decision, proposes your five for today, and writes the updates for you to confirm. Five minutes, and you did the thinking together.

And it grows views as your work gets busier — a "who owes me" list grouped by person, a per-project overview, a running log of the decisions you've made. That's the whole shift: you stop maintaining a list and start talking to something that already understands how your work flows.


0 Download the starter kit and set up your workspace Do this first

One ZIP, five folders and a VERSION stamp. Each folder goes to a different place — the steps below explain exactly where. Nothing gets installed in the traditional sense; things mostly get copied and pointed at.

⬇ Download Starter Kit (.zip)

Inside: vault-setup/ · github-pages/ · apps-script/ · skills/ · tools/ · VERSION (currently 2026-07-01.2)

One prerequisite: the Claude desktop app (Cowork mode). That's what lets Claude actually touch files on your computer instead of just talking about them wistfully. Grab it at claude.ai/download if you haven't — everything below assumes it's installed.

📁 vault-setup/ — your working folder

This is the folder Claude reads and writes every session. The recommended setup is an Obsidian vault — Obsidian is a free note-taking app (obsidian.md) that stores everything as plain text files in a folder you own. When you create a new vault, Obsidian creates the folder for you. You then copy the contents of vault-setup/ into it.

Install Obsidian and create a new vault

Download Obsidian from obsidian.md. Open it and create a new vault — give it a name like "Work" or your name. Obsidian creates a folder on your computer automatically.

Copy the contents of vault-setup/ into your vault

From the ZIP, open vault-setup/. Copy everything inside — TASKS.md, index.html, and data.json — directly into your vault folder. These are the files Claude will read and update each session.

Connect the vault to Cowork

In the Claude desktop app, open Cowork and create a new project. When it asks for a folder, point it at your Obsidian vault. Cowork will now be able to read and write files there directly — no copy-pasting needed.

Don't want Obsidian? Then don't have it — I'm a narrator, not a salesman. Create a new Cowork project directly and Cowork makes the folder for you; copy the vault-setup/ contents in there instead. You lose the pretty note-taking layer, the tracker doesn't notice or care. It works exactly the same.

📁 github-pages/ — your live tracker website

index.html and data.json — the same two files that are also in your vault. Upload these to a free GitHub Pages repo so you can open your tracker from any browser. Step 2 walks you through this.

📁 apps-script/ — Quick Capture backend legacy

Kept for reference only. The old capture backend was a Google Sheet + Apps Script — we retired it. The tracker now captures right in the browser (localStorage) with a "Copy for check-in" button: no Google account, no web app, nothing to host. You can skip this folder entirely — see the updated Step 6.

📁 skills/ — the pipeline reference

One file: work-tracker-pipeline-friend.skill — the full architecture reference for this system: the three layers (vault → Apps Script → GitHub Pages), the exact tagging conventions, and the logic that turns your task list into data.json. Drag it into your first Claude chat and say "install this skill" (see Skills for the full install steps) so Claude has this as a standing reference in every future session — not just this one.


1 What's in the tracker — the two files explained

You already have both from Step 0 — but you should know what you're holding before you deploy it. Meet the skeleton and the heartbeat.

📄 index.html — the permanent shell

The skeleton. Filters, program view, stat tiles, quick capture, the password gate — all of it, and none of your data. Upload it to GitHub Pages once and never touch it again. It's the part of the tracker that doesn't know anything about you; it just knows how to display whatever the data file hands it.

🗂 data.json — your session data

The heartbeat. Claude rewrites this file every session with your current work — programs, open items, priorities, what got finished. Push a new version to GitHub and your live tracker updates in about thirty seconds. And once you've set a password, this file travels in disguise: what actually gets uploaded is data.enc.json, its encrypted twin, while the readable original never leaves your computer.


2 Put them on a free website (GitHub Pages)

GitHub Pages: a free, permanent URL for your tracker, from the same place that hosts half the internet's code. No coding involved — you'll mostly be clicking buttons with reassuring names.

Create a free GitHub account

Go to github.com and sign up. Use your personal email — your account stays with you even if you change jobs.

Create a new repository

Click the + in the top right → New repository. Name it something like work-tracker. Set it to Public. Click Create repository.

Upload your two files

On the repository page, click Add file → Upload files. Drag in both index.html and data.json. Scroll down and click Commit changes.

Enable GitHub Pages

Go to Settings → Pages (left sidebar). Under "Source", select Deploy from a branch, choose main, folder / (root). Click Save.

Get your tracker URL

After ~30 seconds, refresh the Pages settings. Your URL will appear — something like yourusername.github.io/work-tracker. Open it. Your tracker is live.

Updating later: Every session you replace one file and one file only. Repository → click the data file → pencil icon (Edit) → paste the new content → Commit. Thirty seconds later the live site matches reality. That's the entire maintenance burden of this system. I've seen houseplants that need more.

🔒 Protect your tracker with a password Recommended

GitHub Pages sites are public — anyone with the URL can read them, and making the repo private just unpublishes the site on a free plan. The kit solves this with real encryption instead.

Pick a password — yours, not anyone else's

Anything you'll remember. It never leaves your machine except as the key that unlocks the page in your own browser. If you ever forget it, nothing is lost — the plain data.json still lives in your folder; you just re-encrypt with a new password.

Ask Claude to encrypt your data file

The kit's tools/encrypt_data.py turns data.json into data.enc.json (AES-256 encryption — the real thing, not a hidden-field trick). Say: "Encrypt my data.json into data.enc.json using encrypt_data.py with the password ______".

Upload data.enc.json — and never the plain data.json

From now on the repo holds index.html + data.enc.json only. If a plain data.json is ever in the repo, delete it — it would defeat the whole gate. The plain file stays on your computer as the working copy.

Open your site

You'll see a password box and nothing else. Enter your password once — your browser remembers it after that. Visitors without the password see an empty page. Bonus: your Apps Script URL is inside the encrypted file, so even your capture endpoint stays hidden.

Before a password is set, the shell quietly falls back to reading the plain data.json — so everything in the steps below works out of the box, and the gate simply switches on the first time a data.enc.json appears in your repo.

3 First session — let Claude interview you Do this first

Do not fill in data.json by hand — that's a job for the AI, and frankly it enjoys it. Paste the prompt below and let Claude interview you; you talk, it builds.

Important — don't attach the file to the chat. Give Claude the folder path instead. It can read files right where they live, which means it can also update them right where they live — no downloading, re-uploading, or "wait, which version is this" archaeology later.

📋 Copy this prompt — paste it to Claude at your very first session

I'm setting up a personal work tracker. My tracker folder is at:
[PASTE YOUR FOLDER PATH — e.g. C:\Users\yourname\Documents\Work Tracker\]

The files in that folder are:
- data.json — the one you update each session (Claude reads and rewrites this)
- index.html — the display shell, never needs to change
- tools/parse_tasks.py + tools/encrypt_data.py — the generator and the password-gate encryptor
- work-tracker-pipeline-friend.skill — the architecture reference for this whole system

Before we start, please check four things:
0. VERSION CHECK: open index.html and confirm its second line says "KIT_VERSION: 2026-07-01.2". Also check the VERSION file from the starter zip. Then, if you have web access, fetch https://shadiaalkhaledi-dot.github.io/AIworkflow/work-tracker-guide.html and confirm no newer KIT_VERSION is mentioned there. If my files are missing the stamp, show an older version, or the live guide lists a newer one, STOP and tell me — I need to re-download work-tracker-starter.zip from that page before we set anything up.
1. Do I have a Cowork folder selected that points to the folder above? If not, remind me to add it in the Claude desktop app (Cowork panel → select folder) before continuing.
2. Is there a work-tracker-pipeline-friend.skill file in this folder? If so, read it now (or tell me to attach it and say "install this skill" if you can't read .skill files directly) — it explains the tagging conventions and generator logic so you don't have to guess at them each session.
3. Does data.json have a real Apps Script URL in the "apiUrl" field, or does it still say "PASTE_YOUR_APPS_SCRIPT_URL_HERE"? If it's still a placeholder, remind me to set up Google Sheets + Apps Script (see Step 6 of the setup guide) and paste the URL before our first real session. We can still do the onboarding interview now, but Quick Capture won't work until that's set.

Now, interview me about my work so you can fill in data.json properly. Ask me one topic at a time:

1. What is my project or role — what am I responsible for?
2. What are the main workstreams or programs I'm tracking? (e.g. different building packages, client files, product areas)
3. Who are the key people I work with — names, roles, and what I need from them?
4. What are the open items currently on my plate — what's in progress, what's blocked, what am I waiting on?
5. What meetings or decisions happened recently that I should capture?
6. Are there any notes from Microsoft Copilot, Teams, or email that I want to pull in?

After the interview, write a complete data.json and save it to my tracker folder. Then tell me how to upload it to GitHub so my tracker site updates.
What happens next: Claude asks questions one at a time; you answer like a human — no formatting, no bullet points, no performance. Ten to fifteen minutes of normal conversation later, out comes a complete data.json. Save it, upload it, and your tracker is born already knowing your whole workload. Most trackers start empty and die empty. Not this one.

4 Every session after that — the check-in prompt

The daily ritual — and the whole reason this system stays alive while app-based trackers gather guilt. Paste this at the start of each session; Claude reads the current state, asks what changed, hands back the update.

📋 Copy this prompt — use it at the start of every work session

Work session check-in. My tracker folder is at:
[YOUR FOLDER PATH — e.g. C:\Users\yourname\Documents\Work Tracker\]

My live tracker site is at: [YOUR GITHUB PAGES URL]

If you have work-tracker-pipeline-friend.skill installed or available in this folder, use it as your reference for the tagging conventions (status/court/horizon/action/cat/disc) so things stay consistent as this grows.

Please read the current data.json and then ask me:
- What happened since last time?
- Anything new that's blocking me?
- Any items I can mark done?
- Any new items to add?
- Any meetings or decisions to capture?

After I fill you in, update data.json to reflect today's state — new items, completed items, updated notes, and a "what we sorted out today" summary. Set meta.generated to today's date.

Then, if I've set a site password: re-encrypt with tools/encrypt_data.py (data.json → data.enc.json) and give me data.enc.json to upload to GitHub — never the plain data.json. If I haven't set a password yet, give me data.json as before.
The rhythm: One check-in at the start of each day, or whenever you sit down to actually work. Five minutes, conversational, done. The site updates the moment you push the new file. Miss a day? Nothing breaks, nothing nags — the tracker just waits. It's the only productivity tool you'll ever own that doesn't guilt-trip.

5 Bringing in Copilot and email notes

Already drowning in Teams meetings and Copilot transcripts? Good news — that's not a problem, that's an input. Those notes feed straight into the tracker.

After a Copilot meeting summary

Copy the Copilot summary from Teams. Paste it into your check-in conversation with Claude and say: "Here's the Copilot summary from today's meeting — pull any action items or decisions into my tracker."

From email threads

Copy the relevant email thread or paste key lines. Say: "Add this to the relevant item in my tracker as a note." Claude will file it under the right item and program.

From a day of scattered notes

If you jot notes in Teams chat or a notepad during the day, paste them all at once during your check-in. Say: "Here's everything that happened today — sort it into my tracker." Claude knows where things belong.

Tip: The tracker page itself has a Quick Capture box (the gold one at the top) — thumb something in from your phone mid-meeting and it queues up for your next check-in. Five capture types: New item, Note, Blocker, Watch, and Subtask. Because the best time to record a thought is the four seconds before the next one deletes it.

6 Quick Capture — log things in real time Optional

The tracker's ears — for the thoughts that arrive mid-meeting, when opening a chat would be rude and a sticky note would be a lie. The capture panel is built right into your live page: it queues what you type in the browser and gives you a "Copy for check-in" button. Next check-in, you paste that and your AI folds it in.

Update — no backend anymore. The original version sent captures to a Google Sheet via Apps Script. We retired that: capture is now purely in-browser (localStorage), so there's no Google account, no web app, nothing to deploy. Each item also carries its own inline buttons — + subtask · flag blocking · add note — so you capture right on the thing you're looking at. The detailed Google steps below are kept only as legacy; you can ignore them.
Create a Google Sheet

Go to sheets.google.com → New blank sheet. Name it Work Tracker Captures. You don't need to add headers by hand — the Apps Script below creates a "Log" tab with the right columns automatically the first time anything is captured.

Open Apps Script

In the sheet, go to Extensions → Apps Script. A code editor will open. Delete everything in the editor and paste the script below. Click the save icon (or Ctrl+S).

Deploy as a web app

Click Deploy → New deployment. Select type Web app. Set "Execute as" to Me and "Who has access" to Anyone. Click Deploy. Copy the long URL it gives you — this is your Apps Script URL. Keep it handy for the next step.

Paste the URL into data.json — this is how the tracker finds your sheet

Open data.json in your Cowork folder. Find the first line: "apiUrl": "PASTE_YOUR_APPS_SCRIPT_URL_HERE". Replace the placeholder with your real URL. Save, then push the updated data.json to GitHub. The tracker now knows where to send captures — no other file needs to change.

Tell Claude to pull captures at check-in

At your next check-in, say: "Also check for any pending Quick Captures from my sheet." Claude reads the unsynced rows (via the apiUrl in data.json), folds them into your task list, then marks them synced so they don't get pulled twice.

📋 Apps Script code — paste this into Extensions → Apps Script

var LOG_HEADER = ['Timestamp', 'Type', 'Program', 'Package', 'ItemRef', 'Text', 'Synced'];

function getSheet() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName('Log');
  if (!sheet) {
    sheet = ss.insertSheet('Log');
    sheet.appendRow(LOG_HEADER);
    sheet.setFrozenRows(1);
  }
  return sheet;
}

function doPost(e) {
  var sheet = getSheet();
  var data = JSON.parse(e.postData.contents);

  if (data.action === 'edit') {
    return handleEdit(sheet, data);
  }

  sheet.appendRow([
    new Date(), data.type || '', data.program || '', data.pkg || '',
    data.itemRef || '', data.text || '', 'N'
  ]);
  return ContentService.createTextOutput(JSON.stringify({ok: true}))
    .setMimeType(ContentService.MimeType.JSON);
}

function handleEdit(sheet, data) {
  var row = Number(data.row);
  if (!row || row < 2 || row > sheet.getLastRow()) {
    return ContentService.createTextOutput(JSON.stringify({ok: false, error: 'Invalid row'}))
      .setMimeType(ContentService.MimeType.JSON);
  }
  sheet.getRange(row, 2, 1, 5).setValues([[
    data.type || '', data.program || '', data.pkg || '', data.itemRef || '', data.text || ''
  ]]);
  return ContentService.createTextOutput(JSON.stringify({ok: true}))
    .setMimeType(ContentService.MimeType.JSON);
}

function doGet(e) {
  var sheet = getSheet();
  var action = e.parameter.action || 'pending';

  if (action === 'markSynced') {
    var rows = JSON.parse(e.parameter.rows || '[]');
    rows.forEach(function(r){ sheet.getRange(r, 7).setValue('Y'); });
    return ContentService.createTextOutput(JSON.stringify({ok: true, marked: rows.length}))
      .setMimeType(ContentService.MimeType.JSON);
  }

  var values = sheet.getDataRange().getValues();
  var out = [];
  for (var i = 1; i < values.length; i++) {
    if (String(values[i][6]) === 'N') {
      out.push({row: i+1, ts: values[i][0], type: values[i][1],
        program: values[i][2], pkg: values[i][3], itemRef: values[i][4], text: values[i][5]});
    }
  }
  return ContentService.createTextOutput(JSON.stringify(out))
    .setMimeType(ContentService.MimeType.JSON);
}

function out(data) {
  return ContentService.createTextOutput(JSON.stringify(data))
    .setMimeType(ContentService.MimeType.JSON);
}
After pasting, authorize it: Google will ask you to approve the script's access to your own spreadsheet — click "Review permissions" → choose your account → "Allow". It looks alarming; it's Google asking whether your code may talk to your sheet. It may.

↓ Blank data.json starter template

The blank slate — every placeholder below gets replaced during your onboarding interview, so this is for reading, not typing. The // ← comments explain what lives where.

{
  "apiUrl": "[PASTE YOUR APPS SCRIPT URL HERE — or leave as-is until you set up Quick Capture]",

  "meta": {
    "title": "Work Tracker — [Your Name]",
    "lede": "[One sentence describing what you're tracking, e.g. 'Airport terminal fitout — Concourse B and Central PBS']",
    "sessionDate": "[e.g. Tuesday, July 1]",
    "sprintEnd": "[e.g. 2026-07-10]",
    "sprintEndLabel": "[e.g. Jul 10]"
  },

  "programs": [
    {
      "name": "[Program or workstream name, e.g. 'Project Alpha']",
      "color": "var(--teal)",
      "packages": [
        "[Sub-area or package, e.g. 'Design Development']",
        "[Another sub-area, e.g. 'Client Coordination']"
      ]
    },
    {
      "name": "[Second program, e.g. 'Project Beta']",
      "color": "var(--mauve)",
      "packages": [
        "[Sub-area]"
      ]
    }
  ],

  "items": [
    {
      "id": "i01",
      "title": "[Action item title — what needs to happen]",
      "status": "open",
      "program": "[Must match a program name above]",
      "pkg": "[Must match a package name above]",
      "court": "You",
      "delegate": "[Optional — name of who you've handed this off to. Omit the field entirely if nobody's been delegated to.]",
      "horizon": "sprint",
      "action": "chase",
      "cat": "coordination",
      "disc": ["AR"],
      "due": "2026-07-03",
      "isNew": true,
      "why": "[Why this matters or what's at stake]",
      "meta": "[Extra context — who raised it, what meeting it came from]"
    }
  ],

  "details": {
    "i01": {
      "next": "[The specific next action — what exactly do you do next]",
      "subtasks": [
        "[Sub-task 1]",
        "[Sub-task 2]"
      ],
      "updates": [
        "2026-07-01|[What happened on this date]"
      ]
    }
  },

  "voice": [
    {
      "h4": "[Topic or decision heading]",
      "p": "[What was decided or sorted out — written as a plain sentence]"
    }
  ],

  "completedThisWeek": [
    {
      "h3": "[Program name]",
      "accent": "var(--teal)",
      "h3color": "var(--teal)",
      "items": [
        {
          "h4": "[Completed item title]",
          "p": "[What was resolved and how]"
        }
      ]
    }
  ],

  "completedLastWeek": []
}

Field reference

FieldWhat it means
status"open", "blocking", "unverified", or "watch"
courtWho it's waiting on — "You", or a person's name
delegateOptional — if you've handed this off to someone, their name. Shows as "Delegated to: [name]" next to court on the card. Leave the field out entirely if nobody's been delegated to.
horizonUrgency — "today", "sprint" (before sprint end date), "week", or leave blank
actionWhat kind of task — "model", "review", "coordinate", "chase", "admin"
catCategory — "decisions", "meetings", "coordination", "documentation", "drawings", "rfi"
discDiscipline tags — "AR", "ST", "ME", "EL", "signage", "safety", "security", "owner"
isNewtrue = shows an N badge (new since last check-in). Set to false after first upload.
dueDue date in YYYY-MM-DD format — drives the stat tiles and urgency sort
Advanced — tag these fields directly in your task list: instead of letting Claude guess status/category/discipline/etc. each check-in, you can write them right into a task line as bracketed tags, e.g. [cat:: coordination] [disc:: AR] [action:: chase] [court:: You] [horizon:: today] [delegate:: Jordan]. Claude reads these mechanically instead of re-inferring them, which keeps your tracker consistent as it grows. See the example rows already in your TASKS.md. Not required — Claude can still triage without them — but the more you tag, the less guesswork there is.

🎨 Program colors

Pick a color for each program from this list. Paste the full token (including "var(--") into the "color" field.

var(--teal)
var(--sage)
var(--mauve)
var(--gold)
var(--terracotta)
var(--rose)