Skip to main content

Terminal-native billable ledger for solo developers

Project description

TTD

Terminal-native billable ledger for solo developers who invoice by the hour.

Install

PyPI distribution: ttd-ledger. CLI command: ttd.

uv tool install ttd-ledger
ttd --help

One-off: uvx ttd-ledger.

Quick start (development)

just setup
prek run --all-files
uv run ttd

Development

Command Purpose
just check Ruff lint/format check + ty (fast gate before PR or agent handoff)
just setup Install dependencies (uv sync) and git hooks (uv run prek install)
uv sync Install dependencies only
prek install Install git hooks only
prek run --all-files Run all checks (same as CI)
uv run ttd CLI (Rich tables; health check by default)
just db-seed Seed local DB with demo clients, projects, and entries
just release-smoke Build wheel/sdist and verify ttd from the artifact
just release Full checks + smoke, then trigger GitHub Release workflow
uv run ttd-api Litestar API (scaffold)
uv run ttd-tui Textual TUI (scaffold)

Period export

Close a billing period to CSV (default), XLSX, or Numbers. Format is inferred from --output; omit it to print CSV to stdout.

# CSV to stdout
ttd export --from 2026-05-01 --to 2026-05-31

# CSV, XLSX, or Numbers file
ttd export --from 5/1 --to 5/31 --output period.csv
ttd export --from 5/1 --to 5/31 --client Acme --output period.xlsx
ttd export --from 5/1 --to 5/31 --output period.numbers

# Optional export-time round-up (minutes); set on client or project
ttd client add Acme --rate 150 --rounding-minutes 15
ttd project update --client Acme --name Website --rounding-minutes 30

Detail rows roll up duration entries by project, day, and note; interval entries stay one row each. A summary section (same file or Summary sheet) totals billable hours and hourly dollars by project and client. See docs/design/data-layer.md for column schemas.

Configuration

Persistent settings live in layered TOML files plus optional TTD_* env overrides. Inspect effective values and source layers with ttd config show; set local or global keys with ttd config set.

ttd config show
ttd config init
ttd config set data_dir ~/.local/share/ttd
ttd config set --global clock_format 24h
ttd config get db_filename

Global file: ~/.config/ttd/ttd.toml. Local override: nearest ttd.toml walking up from cwd. Precedence: env → local → global → defaults. See docs/design/data-layer.md.

Release (maintainers)

One-time setup

  1. PyPI project — Register ttd-ledger (name must match project.name in pyproject.toml).

  2. Trusted publishing — On that project: PublishingAdd a new pending publisherGitHub:

    Field Value
    Owner syn54x
    Repository ttd
    Workflow name release.yml
    Environment pypi
  3. GitHub environment — Repo SettingsEnvironments → create pypi (no secrets required for OIDC).

  4. GitHub PagesSettingsPagesSource: GitHub Actions.

Pre-release check

just release-smoke

Builds the wheel/sdist and runs ttd --help from the artifact (same layout CI publishes).

Publish

  1. Complete one-time setup above.

  2. Merge to main with conventional commits since the last tag.

  3. From a clean, pushed main:

    just release
    

    Runs CI checks, release-smoke, then triggers the Release workflow (cz bump, PyPI publish, GitHub Release, docs deploy).

    Watch progress: gh run watch --workflow release.yml

Failed publish recovery

If PyPI rejects the upload (for example filename reuse after a deleted version), main may already have the bump commit and tag while PyPI has nothing:

  1. Bump to a new version (PyPI never reuses deleted filenames).

  2. Update CHANGELOG.md for that version.

  3. Delete stray or failed tags (git push origin :refs/tags/v0.x.y).

  4. Push main, tag the recovery version, push the tag.

  5. Re-run the workflow with publish only (skips cz bump):

    gh workflow run release.yml --ref main -f publish_only=true
    gh run watch --workflow release.yml
    

Also delete accidental non-semver tags (e.g. list) — they break git describe and commitizen.

Smoke test after publish

uvx ttd-ledger --help
uv tool install ttd-ledger
ttd

Roadmap

Milestone sequencing and v1 scope: docs/roadmap.md. Product direction: STRATEGY.md.

Architecture

  • ttd.core — async domain services and SQLite (ferro-orm)
  • ttd.cli — cyclopts CLI adapter
  • ttd.api — Litestar API adapter (scaffold)
  • ttd.tui — Textual TUI adapter (scaffold)

Domain logic lives only in ttd.core. Surfaces are thin adapters.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ttd_ledger-0.2.1.tar.gz (35.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ttd_ledger-0.2.1-py3-none-any.whl (55.7 kB view details)

Uploaded Python 3

File details

Details for the file ttd_ledger-0.2.1.tar.gz.

File metadata

  • Download URL: ttd_ledger-0.2.1.tar.gz
  • Upload date:
  • Size: 35.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for ttd_ledger-0.2.1.tar.gz
Algorithm Hash digest
SHA256 ea7cf1b638a2c293a5e00f886351cd1164c3b5fd4e7862307769cf868a9ad530
MD5 f739b643e0c0d49365c136dc3f9e8b11
BLAKE2b-256 b95ce2b761fac9fa8d623e1380b0bc6f0273e553a5efde36dc2d4b458a69525d

See more details on using hashes here.

Provenance

The following attestation bundles were made for ttd_ledger-0.2.1.tar.gz:

Publisher: release.yml on syn54x/ttd

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ttd_ledger-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: ttd_ledger-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 55.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for ttd_ledger-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 5cd7fe6d9b41743b8dd3e7f57903036fa251366acc6117276686a5f2998f2df5
MD5 d6f56515cebad00a658be37fa59fd282
BLAKE2b-256 c3986551f271356886747bd4678193fb77fb00be5d824b078128c1f2679dc295

See more details on using hashes here.

Provenance

The following attestation bundles were made for ttd_ledger-0.2.1-py3-none-any.whl:

Publisher: release.yml on syn54x/ttd

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page