Actiwitee
Self-hosted · Open source

Everywhere you code,
one contribution graph

Actiwitee merges GitHub, competitive programming, and local AI-coding sessions into a single heatmap and read-only API, built for portfolios that reflect how you actually work.

config.yaml

sources:

github: [personal, work]

leetcode: [saish_korgaonkar]

codeforces: [saish_k]

agent:

signals: [cursor, hermes-cli]

$ actiwitee collect

github:personal 459 contrib

leetcode 15 contrib

codeforces 6 contrib

codechef 141 contrib

→ store.json updated

$ curl /contributions

{

"total": 622,

"contributions": [

{ "date": "2026-07-25",

"level": 2, "localMinutes": 76 }

]

}

$ actiwitee agent --once

[agent] active: ai-cli, terminal

→ 76 min local today

→ heartbeat stored

Hermes cron · every 5m

Built for developers who code everywhere

Actiwitee is the self-hostable backend behind unified coding activity, from open source commits to contest submissions to late-night AI pair sessions.

Multi-source aggregation

Pull from GitHub (multi-account), LeetCode, Codeforces, CodeChef, and more. Weighted merge with percentile-based heatmap levels.

Local session tracking

A lightweight agent samples AI CLI, IDE, and terminal activity. Local minutes show up on the graph without inflating commit counts.

Portfolio-ready API

Serve a read-only JSON API from Cloudflare Workers + R2. Drop the heatmap into any site with one env var.

Config-driven

One YAML file for sources, weights, CORS, and agent signals. No database, just JSON on disk.

Full history

GitHub history back to account creation. Scrollable graph with rich per-day tooltips: contributions, local time, and source breakdown.

Automate with cron

Collect on a schedule, publish to R2, and run the agent every few minutes. Set it once and forget it.

Plug in your sources

Add handles and tokens in config.yaml. Run collect. Actiwitee normalizes dates, deduplicates, and merges into one timeline.

GitHub

Multi-account, private repos via PAT

LeetCode

Submission calendar sync

Codeforces

Contest & practice activity

CodeChef

Practice streaks

Local agent

Cursor, VS Code, Claude Code, Hermes, terminal

Demo

Sample data for development

Read-only JSON API

Three routes, no auth required. Host on Cloudflare Workers + R2 and call from any frontend with one env var.

Live example → codepulse.saish.xyz
GET/health

Liveness check and per-source freshness timestamps.

{ "ok": true, "sources": { "github:personal": "2026-07-25T..." } }
GET/contributions?year=2026

Lean heatmap rows, GitHub-compatible {date, count, level} shape.

{ "total": 622, "contributions": [{ "date": "2026-07-25", "count": 3, "level": 2 }] }
GET/activity

Full payload with scores, local minutes, and per-source breakdown per day.

{ "contributions": [{ "date": "...", "count": 3, "level": 2, "localMinutes": 76, "breakdown": { "github": 2, "local": 76 } }] }

Self-host in six steps

From zero to a live portfolio heatmap. Edit config.yaml, deploy the Worker, point your site at the API.

GitHub, CP platforms, and the API work on all OSes. Local agent + automation tabs are Mac or Windows specific.

Step 01

Install & try the demo

Clone, build, run with synthetic data. No tokens required.

terminal

git clone https://github.com/SaishKorgaonkar/actiwitee.git
cd actiwitee
npm install
npm run build
cd cli
node dist/cli.js collect --demo
node dist/cli.js serve   # http://localhost:4787

verify

curl localhost:4787/health
curl localhost:4787/activity | head
Step 02

Configure your sources

Scaffold config, add handles and tokens. Secrets go in .env only.

terminal

node dist/cli.js init
# edits config.yaml + .env

config.yaml (excerpt)

sources:
  github:
    - id: personal
      username: your-handle
      tokenEnv: ACTIWITEE_GITHUB_PERSONAL_TOKEN
      includePrivate: true
  leetcode: [{ username: your-lc-handle }]
  codeforces: [{ username: your-cf-handle }]

weights: { github: 1, leetcode: 3, codeforces: 3, local: 1 }
levels: { mode: percentile }

.env

ACTIWITEE_GITHUB_PERSONAL_TOKEN=ghp_...
ACTIWITEE_GITHUB_WORK_TOKEN=ghp_...
Step 03

Track local coding sessions

Sample IDE, terminal, and AI CLI activity. Local minutes stay separate from commit counts.

Mac/Linux: IDE focus, process, and session-log signals.

config.yaml (agent)

agent:
  interval: 180
  signals:
    - { id: cursor, type: app-focus, match: "Cursor", category: editor }
    - { id: claude-code, type: session-log, path: "~/.claude/projects", category: ai-cli }
    - { id: ollama, type: process, match: "ollama|llama-server", category: local-model }

terminal

node dist/cli.js agent          # continuous
node dist/cli.js agent --once   # single sample
Step 04

Deploy the read-only API

Publish activity.json to R2 and serve from a Worker.

publish locally

node dist/cli.js collect
node dist/cli.js show > data/activity.json
# upload to R2 (see cli/deploy/worker/README.md)

deploy worker

cd cli/deploy/worker
npm install
cp wrangler.toml.example wrangler.toml
npx wrangler login
npm run deploy
Step 05

Wire your portfolio

Point your site at the API. Same shape as GitHub-style heatmaps.

.env (portfolio)

NEXT_PUBLIC_ACTIWITEE_API_URL=https://activity.yourdomain.com

fetch

const res = await fetch(`${API_URL}/activity`)
const { contributions } = await res.json()
Step 06

Automate collection & publish

Pick Mac or Windows below. Agent every 5 min, publish every hour.

Cron installer for macOS/Linux. Machine must stay awake.

terminal

cd cli
export ACTIWITEE_R2_BUCKET=your-bucket
export ACTIWITEE_R2_KEY=actiwitee/activity.json

bash scripts/install-cron.sh

# every 5 min: agent  |  every hour: publish
# remove: bash scripts/install-cron.sh --uninstall

Ready to unify your coding activity?

Open source and self-hostable. Star the repo, follow the guide above, and wire the heatmap into your portfolio in an afternoon.