{
  "version": "2",
  "generatedAt": "2026-11-03T22:49:39.280Z",
  "listing": {
    "slug": "almarklein--timetagger",
    "name": "TimeTagger",
    "tagline": "Tag-based personal time tracker with a documented web API that mirrors the hosted timetagger.app.",
    "shortTagline": "Tag-based personal time tracker",
    "description": "TimeTagger is a lightweight time tracker for individuals and freelancers: an interactive timeline, tags instead of projects, targets, Pomodoro and PDF/CSV reports. The Python server runs from pip or Docker and is configured with TIMETAGGER_* environment variables. The Builder documents a records/settings/updates web API with API tokens, identical on self-hosted servers and the EUR 3 per month hosted edition.",
    "capabilities": [
      "adaptable",
      "operable"
    ],
    "vertical": "scheduling-staffing",
    "alternativeTo": [
      "Toggl Track",
      "Harvest"
    ],
    "shape": "business-app",
    "formFactor": "web-app",
    "executionModel": "deterministic",
    "provenance": "human-written",
    "codeStack": {
      "languages": [
        "Python"
      ],
      "frameworks": [
        "asgineer",
        "uvicorn",
        "itemdb",
        "PScript"
      ],
      "packageManager": "pip",
      "database": [
        "SQLite"
      ],
      "hostingTarget": [
        "docker",
        "pypi"
      ]
    },
    "modelStack": null,
    "repos": [
      {
        "url": "https://github.com/almarklein/timetagger",
        "owner": "almarklein",
        "name": "timetagger",
        "license": "GPL-3.0",
        "stars": 1779,
        "lastCommit": "2026-05-17"
      }
    ],
    "interface": {
      "kind": "api",
      "url": "https://timetagger.readthedocs.io/en/latest/webapi/",
      "official": true,
      "hosted": "both"
    },
    "operability": "official",
    "recommendedWrapper": null,
    "reach": [
      {
        "job": "Read time records for a date range",
        "reachable": true,
        "evidence": "webapi: GET records with range and tag filters"
      },
      {
        "job": "Create and edit records",
        "reachable": true,
        "evidence": "webapi: PUT records accepts new or edited record objects"
      },
      {
        "job": "Start and stop a running timer",
        "reachable": true,
        "evidence": "webapi: records can be filtered by running state; a running record is written with PUT"
      },
      {
        "job": "Delete a record",
        "reachable": true,
        "evidence": "webapi: prefix the description with HIDDEN, the convention clients honour"
      },
      {
        "job": "Read and change settings",
        "reachable": true,
        "evidence": "webapi: GET and PUT settings"
      },
      {
        "job": "Sync incrementally",
        "reachable": true,
        "evidence": "webapi: GET updates since a timestamp"
      },
      {
        "job": "Generate PDF or CSV reports",
        "reachable": false,
        "evidence": "webapi documents no report endpoint; reports are produced client-side from records"
      },
      {
        "job": "Set daily, weekly or monthly targets",
        "reachable": null,
        "evidence": "targets live in the client; not stated whether they are in the settings object"
      },
      {
        "job": "Pomodoro timer",
        "reachable": false,
        "evidence": "client-side feature"
      }
    ],
    "editions": [
      {
        "name": "Self-hosted",
        "price": null,
        "open": true,
        "distributions": [
          {
            "kind": "source",
            "url": "https://github.com/almarklein/timetagger"
          },
          {
            "kind": "installable",
            "url": "https://pypi.org/project/timetagger/",
            "command": "pip install -U timetagger && python -m timetagger"
          },
          {
            "kind": "container",
            "url": "https://github.com/almarklein/timetagger/pkgs/container/timetagger"
          }
        ]
      },
      {
        "name": "timetagger.app",
        "price": {
          "amount": 3,
          "currency": "EUR",
          "period": "month"
        },
        "open": false,
        "distributions": [
          {
            "kind": "hosted",
            "url": "https://timetagger.app"
          }
        ]
      }
    ],
    "skills": {
      "kind": "none",
      "paths": [],
      "install": null,
      "note": "No SKILL.md, Claude Code plugin, or skills install target in the repo."
    },
    "customization": {
      "summary": "Everything is an environment variable or CLI flag: TIMETAGGER_BIND, TIMETAGGER_DATADIR, TIMETAGGER_CREDENTIALS (bcrypt user:hash pairs) for multi-user, TIMETAGGER_PROXY_AUTH_ENABLED, TIMETAGGER_PROXY_AUTH_TRUSTED and TIMETAGGER_PROXY_AUTH_HEADER to sit behind Authelia or similar, TIMETAGGER_PATH_PREFIX and TIMETAGGER_APP_REDIRECT. deploy/docker-compose.yml is the Docker path. For custom auth (JWT, OAuth) the libapi docs show a short Python run script overriding authenticate() and api_handler_triage().",
      "envVars": [
        "TIMETAGGER_BIND",
        "TIMETAGGER_DATADIR",
        "TIMETAGGER_LOG_LEVEL",
        "TIMETAGGER_CREDENTIALS",
        "TIMETAGGER_PROXY_AUTH_ENABLED",
        "TIMETAGGER_PROXY_AUTH_TRUSTED",
        "TIMETAGGER_PROXY_AUTH_HEADER",
        "TIMETAGGER_PATH_PREFIX",
        "TIMETAGGER_APP_REDIRECT"
      ],
      "configFiles": [
        "deploy/docker-compose.yml",
        "deploy/docker-compose.nonroot.yml"
      ],
      "promptFiles": [],
      "effort": "config-only",
      "editCount": 11
    },
    "useWhen": [
      "I'm a freelancer who wants a fast timeline-style tracker on my own box, with tags instead of a project hierarchy",
      "I want my agent to log what I worked on and pull the week's records over a small token-authenticated API"
    ],
    "accounts": [
      "timetagger.app (hosted edition only)"
    ],
    "active": true,
    "lastActivity": "2026-05-17",
    "gotchas": [
      "GPL-3.0 plus a CLA granting the author rights to use contributions in the hosted service",
      "Built for individuals: no teams, clients or invoicing; multi-user means separate credential entries, not shared data",
      "Last push 2026-05-17, inside the window but the slowest cadence on this shortlist",
      "API tokens never expire; reports and exports are not reachable through API"
    ],
    "fit": {
      "adaptable": 2,
      "operable": 3
    },
    "evidence": {
      "formFactor": "README: web-based time tracker served by a Python server, runs locally or on a server",
      "executionModel": "no model SDK or AI feature",
      "operability": "timetagger.readthedocs.io/en/latest/webapi/ published by the Builder; same endpoints on timetagger.app",
      "effort": "timetagger.readthedocs.io/en/latest/libapi/ lists TIMETAGGER_* variables; README shows credential and proxy-auth examples",
      "editions": "README: pip and Docker self-host under GPL-3.0; timetagger.app account EUR 3 per month",
      "active": "shortlist pushedAt 2026-05-17"
    },
    "confidence": {
      "formFactor": 0.95,
      "executionModel": 0.95,
      "operability": 0.9,
      "effort": 0.9,
      "reach": 0.8,
      "editions": 0.9
    },
    "openQuestions": [
      "Are targets stored in the settings object and therefore reachable through PUT settings?",
      "Does the hosted edition expose API tokens on every plan?"
    ],
    "sources": [
      {
        "url": "https://github.com/almarklein/timetagger",
        "foundBy": "sourcing:scheduling-staffing:curated"
      },
      {
        "url": "https://timetagger.readthedocs.io/en/latest/libapi/",
        "foundBy": "sourcing:scheduling-staffing:curated"
      },
      {
        "url": "https://timetagger.readthedocs.io/en/latest/webapi/",
        "foundBy": "analysis:scheduling-staffing"
      }
    ],
    "research": {
      "stage": "verified",
      "verdict": "unverified",
      "reason": "Official web API covers the whole data model (records and settings); env-var surface is complete and documented; GPL and single-user focus cap adaptable at 2.",
      "disputed": []
    },
    "url": "apps/almarklein--timetagger.html",
    "coverage": "partial",
    "paid": true,
    "source": "research/verified/almarklein--timetagger.json"
  }
}
