Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

8 Commits

Folders and files

Repository files navigation

Session Timebox

Running many Claude Code sessions across Terminal tabs makes it easy to lose track of which one is waiting on you, which one is mid-task, and what each is about. Session Timebox is a local board that reads your Claude Code sessions and Slack asks, lets you sort them into lanes, and lets you drag them onto a 24-hour calendar to time-box the next few days. It makes no model calls on its own; the only token use is the Slack refresh, and only when you click it.

Run it

Requirements: macOS, Python 3.9+, and Claude Code (its claude command is used to resume sessions in Terminal).

git clone https://github.com/dushyant-uipath/session-timebox.git ~/timebox
python3 ~/timebox/server.py

Open http://localhost:8765. Stop the server with Ctrl+C.

To keep it running after you close the terminal:

nohup python3 ~/timebox/server.py > ~/timebox/server.log 2>&1 &

To stop a background server:

pkill -f "timebox/server.py"

Options:

Flag Default What it does
--port 8765 Port the board listens on
--days 14 How far back to look for sessions
--allow-origin https://dushyant-uipath.github.io Extra web origin allowed to call the server, repeatable

Open it from GitHub Pages

https://dushyant-uipath.github.io/session-timebox/ serves the same page and reads data from the server on localhost:8765, so the server must be running. Chrome asks once for permission to reach your local network; allow it. A fork hosted elsewhere needs its origin passed with --allow-origin.

Link to the session that edits the board

Tweak this board in Claude at the top switches to a chosen Claude session, or resumes it if it's closed. Set the session once:

curl -X POST -d '{"ops":[{"path":["homeSession"],"value":"<session-id>"}]}' http://localhost:8765/api/op

Start it at login

Save this as ~/Library/LaunchAgents/com.session-timebox.plist, replacing YOUR_USER:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key><string>com.session-timebox</string>
  <key>ProgramArguments</key>
  <array>
    <string>/usr/bin/python3</string>
    <string>/Users/YOUR_USER/timebox/server.py</string>
  </array>
  <key>EnvironmentVariables</key>
  <dict><key>PATH</key><string>/Users/YOUR_USER/.local/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string></dict>
  <key>RunAtLoad</key><true/>
  <key>KeepAlive</key><true/>
  <key>StandardOutPath</key><string>/Users/YOUR_USER/timebox/server.log</string>
  <key>StandardErrorPath</key><string>/Users/YOUR_USER/timebox/server.log</string>
</dict>
</plist>

Then load it with launchctl load ~/Library/LaunchAgents/com.session-timebox.plist. The PATH entry must include the folder that holds claude (which claude prints it).

How the board works

  • Sessions come from ~/.claude/projects/*/*.jsonl (sessions_digest.py). Subagent and temp sessions are skipped.
  • Live status comes from ~/.claude/sessions/<pid>.json, which Claude Code writes for each running process: busy, idle, or shell (background command running).
  • Cards show the session title, or your own name for it. Click a card to see your last message and Claude's last reply.
  • Lanes start as Critical & blocking, Iterative bug fixing, Map of work, and Others. New sessions land in Others, and a card stays in whichever lane you drag it to. Dragging changes only the board; it never sends anything to the session.
  • Status badges: Running when Claude Code reports the process busy, Needs you when Claude's last reply ends with a question, otherwise Idle.
  • Go to terminal switches Terminal.app to the tab running that session, matched by its tty. A session that isn't running opens in a new tab with claude --resume. The first click asks macOS for permission to control Terminal.

To-dos and lanes

  • Type in + Add to-do at the top of a lane and press Enter to add a card of your own.
  • Double-click a to-do title to rename it, and click the card to add a note.
  • Double-click any card title to rename it. auto name on a renamed session or Slack card goes back to the generated headline.
  • Drag a card onto another card to place it above or below; each lane keeps its own order. Cards you haven't placed yet show at the top, by status.
  • Double-click a lane name to rename it, and press Enter to save or Escape to cancel.
  • Drag a lane by its header to reorder lanes.
  • + Add lane creates a lane. Click a lane's × twice to delete it; its to-dos move to Others.
  • Others and Done can be renamed but not deleted, because cards without a lane land in them.

Done and removing cards

  • Drag any card to Done, or click the × on the card, to mark it done and stop tracking it.
  • Done keeps cards for 24 hours with a Restore button, then hides them for good.
  • A refresh keeps done cards in Done, and a Slack refresh skips them because they match by message timestamp.
  • A done session comes back, tagged "new activity", only if you send it new messages after marking it done.

Subtasks

  • Session cards list the agent-team members working under that session, read from <session>/subagents/*.jsonl and their .meta.json, with each agent's latest assigned task.
  • A pulsing dot marks an agent active in the last 5 minutes.
  • Type in + subtask on any card to add your own; tick it off or double-click to rename it.
  • Drag any subtask onto the calendar on its own.
  • The × on a subtask deletes your own subtasks and stops tracking agent subtasks.

Time boxes

  • Drag a card or subtask onto a day and time to create a 1-hour block, snapped to 15 minutes.
  • Drag a block to move it, including to another day. Drag its bottom edge to resize it.
  • Remove a block with its ×, by selecting it and pressing Delete, or by dragging it off the calendar. Each removal shows an Undo button for 5 seconds.
  • Double-click empty time for a custom block, and type its title.
  • Double-click a block to jump to its session or Slack thread.
  • Drag the divider between the board and the calendar to resize the calendar. Use the Days buttons for 3, 5, or 7 days and the Zoom buttons for taller hours.
  • Export .ics downloads every block from today on, for import into Google Calendar.

Outlook meetings

The calendar shows your Outlook meetings next to your time boxes, read-only, from Outlook's published ICS link. No tokens or sign-in are involved.

  1. In Outlook on the web: Settings → Calendar → Shared calendars → Publish a calendar → pick your calendar and "Can view all details" → Publish, then copy the ICS link.
  2. Save it where the server reads it, readable only by you:
    printf '%s' 'PASTE_ICS_LINK' > ~/timebox/calendar.url
    chmod 600 ~/timebox/calendar.url
  3. Install the two parsing libraries once, then restart the server:
    python3 -m pip install --user icalendar recurring-ical-events

The server downloads the feed every 10 minutes in the background (calendar_worker in server.py), expands recurring meetings for the next 8 days, and caches them in calendar.json so the board loads instantly after a restart. Outlook refreshes the published copy on its own schedule, so a just-booked meeting can take a while to appear.

  • Accepted meetings are solid, tentative ones dashed; overlapping meetings sit side by side.
  • All-day events show under the day name.
  • A time box that overlaps a meeting shifts right so both stay readable.
  • Hover a meeting and click × to hide it and its repeats (for example a recurring hold); Undo is offered for 5 seconds.

Anyone with the ICS link can read your calendar; calendar.url and calendar.json are in .gitignore.

Slack

Click Slack synced … · ↻ Refresh in the header to refresh on demand. The server starts a background session (claude --bg, Sonnet, named slack-refresh-<time>) in ~/timebox with the prompt in slack_refresh.md. It re-checks the items already listed, searches mentions, DM asks, and your own "I'll check / get back" messages since the last sync (8 days on the first run), opens each thread to drop resolved ones, and posts the result to POST /api/slack. The button shows "Syncing Slack…" until then, and the session is stopped and removed afterwards. Refresh sessions never appear on the board.

One-time setup: ~/timebox must be a trusted folder (run claude there once and accept), because claude --bg refuses untrusted folders. Optionally save your Slack user ID so refreshes skip looking it up:

curl -X POST -d '{"ops":[{"path":["slackUser"],"value":"U0XXXXXXX"}]}' http://localhost:8765/api/op

Each refresh uses tokens (a background Sonnet session searching and reading threads); nothing runs unless you click. Cards from your own promises get a You promised tag.

The board reads Slack items from slack.json, which any Claude session can also write directly in this format:

{
  "synced_at": 1791016079,
  "items": [
    {
      "id": "1790957704.631429",
      "who": "Sender name",
      "where": "#channel or DM",
      "headline": "Five words or fewer",
      "summary": "One sentence on what it is about.",
      "ask": "What they want from you",
      "kind": "ask | commitment",
      "category": "critical_blocking | bug_fixing | map_of_work | other",
      "url": "https://...slack.com/archives/...",
      "ts": "1790957704"
    }
  ]
}

Your data

The server listens on 127.0.0.1 only and answers requests from localhost and the origins passed with --allow-origin; other web pages get 403. Runtime files hold your board, Slack asks, and calendar, and .gitignore keeps them out of the repository:

File Contents
timebox.db SQLite: lanes, card order and names, to-dos, subtasks, placements, done cards, and time boxes
slack.json Slack asks
calendar.url Your private Outlook ICS link
calendar.json Cached meetings for the next 8 days
server.log Server output

The page sends each change as a small update (POST /api/op, applied in one SQLite transaction by apply_ops in server.py), so two open tabs don't overwrite each other. A state.json from an older version is imported into timebox.db on first start.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages