diff --git a/AGENTS.md b/AGENTS.md index 94c239c..e4224d8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,24 +1,24 @@ # Timesheets — Agent Guide -## Project overview +> **Read `README.md` first** for a full description of the project, its +> subcommands, config file format, and Joplin notebook structure. -A Python CLI tool that parses markdown pipe-delimited timesheet tables and -exports them to CSV for import into Odoo (or similar tools). It also supports -a human-readable summary view and can fetch notes directly from Joplin. - -### Package layout +## Package layout ``` timesheets/ -├── pyproject.toml # package metadata, entry point, dev dependencies +├── pyproject.toml +├── README.md ├── AGENTS.md +├── timesheets.example.toml └── src/timesheets/ ├── cli.py # argument parsing, main() entry point ├── parser.py # markdown table parsing, aggregation, date filtering ├── projects.py # project_map.json loading and key resolution - ├── output.py # CSV writing and summary printing + ├── output.py # CSV writing, summary, stories, and status printing ├── config.py # TOML config file loading and key extraction ├── joplin.py # Joplin API integration (notebook traversal, note fetching) + ├── status.py # day/week status calculations └── utils.py # shared low-level helpers (duration parsing, formatting, etc.) ``` @@ -31,7 +31,8 @@ tests/ ├── test_projects.py ├── test_config.py ├── test_output.py -└── test_joplin.py +├── test_joplin.py +└── test_status.py ``` --- @@ -51,81 +52,6 @@ Do **not** use `pip` or `python` directly. --- -## CLI usage - -The CLI has two subcommands: `summary` and `csv`. Both accept the same arguments. - -```sh -# Human-readable summary for today (from Joplin) -uv run timesheets summary --joplin - -# Human-readable summary for a specific day -uv run timesheets summary 2026-05-22 --joplin -uv run timesheets summary yesterday --joplin -uv run timesheets summary 3 days ago --joplin - -# Export today's entries as CSV to stdout -uv run timesheets csv --joplin - -# Export to a file -uv run timesheets csv --joplin -o output.csv - -# Use a local markdown file instead of Joplin -uv run timesheets summary --input timesheet.md -uv run timesheets csv --input timesheet.md -o output.csv - -# Read from stdin -cat timesheet.md | uv run timesheets csv --input - - -# Specify a day (positional, accepts YYYY-MM-DD, MM-DD, or DD-MM; - or / separator) -uv run timesheets csv 2026-05-22 --input input.md -uv run timesheets csv 05-22 --input input.md - -# Use a specific project map file -uv run timesheets csv --input input.md --map /path/to/project_map.json - -# Fetch entries for a specific day from Joplin -uv run timesheets csv 2026-05-22 --joplin --token your_token -``` - -`project_map.json` is auto-discovered in the current working directory if -`--map` is not provided. - ---- - -## Config file - -Create `timesheets.toml` in your working directory (or pass `--config /path/to/file.toml`): - -```toml -[joplin] -token = "your_api_token_here" - -[projects] -map = "/path/to/project_map.json" -``` - -Priority order for each value: **CLI flag > config file > environment variable / default**. - ---- - -## Joplin notebook structure - -The `--joplin` flag expects the following notebook hierarchy in Joplin: - -``` -Work/ -└── Timesheets/ - └── YYYY/ - └── YYYY - WNN/ ← notebook per week - └── YYYY - WNN ← note with the same title as the notebook -``` - -The note body contains one markdown table per day, each preceded by a heading -of the form `# - YYYY-MM-DD`. - ---- - ## Testing The test suite uses **pytest** with **pytest-cov** for coverage reporting. @@ -165,3 +91,71 @@ uv run pytest tests/test_parser.py::TestParseTable::test_empty_input 5. Joplin integration tests in `test_joplin.py` must mock `ClientApi` — do not require a live Joplin instance. + +# Development Guidelines + +# CLAUDE.md + +Behavioral guidelines to reduce common LLM coding mistakes. Merge with project-specific instructions as needed. + +**Tradeoff:** These guidelines bias toward caution over speed. For trivial tasks, use judgment. + +## 1. Think Before Coding + +**Don't assume. Don't hide confusion. Surface tradeoffs.** + +Before implementing: +- State your assumptions explicitly. If uncertain, ask. +- If multiple interpretations exist, present them - don't pick silently. +- If a simpler approach exists, say so. Push back when warranted. +- If something is unclear, stop. Name what's confusing. Ask. + +## 2. Simplicity First + +**Minimum code that solves the problem. Nothing speculative.** + +- No features beyond what was asked. +- No abstractions for single-use code. +- No "flexibility" or "configurability" that wasn't requested. +- No error handling for impossible scenarios. +- If you write 200 lines and it could be 50, rewrite it. + +Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify. + +## 3. Surgical Changes + +**Touch only what you must. Clean up only your own mess.** + +When editing existing code: +- Don't "improve" adjacent code, comments, or formatting. +- Don't refactor things that aren't broken. +- Match existing style, even if you'd do it differently. +- If you notice unrelated dead code, mention it - don't delete it. + +When your changes create orphans: +- Remove imports/variables/functions that YOUR changes made unused. +- Don't remove pre-existing dead code unless asked. + +The test: Every changed line should trace directly to the user's request. + +## 4. Goal-Driven Execution + +**Define success criteria. Loop until verified.** + +Transform tasks into verifiable goals: +- "Add validation" → "Write tests for invalid inputs, then make them pass" +- "Fix the bug" → "Write a test that reproduces it, then make it pass" +- "Refactor X" → "Ensure tests pass before and after" + +For multi-step tasks, state a brief plan: +``` +1. [Step] → verify: [check] +2. [Step] → verify: [check] +3. [Step] → verify: [check] +``` + +Strong success criteria let you loop independently. Weak criteria ("make it work") require constant clarification. + +--- + +**These guidelines are working if:** fewer unnecessary changes in diffs, fewer rewrites due to overcomplication, and clarifying questions come before implementation rather than after mistakes. diff --git a/README.md b/README.md index e69de29..a8bfb04 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,114 @@ +# Timesheets + +A Python CLI tool that parses markdown pipe-delimited timesheet tables and +exports them to CSV for import into Odoo. It also supports a human-readable +summary view, a stories list, a work status dashboard, and can fetch notes +directly from Joplin. + +## Package layout + +``` +timesheets/ +├── pyproject.toml # package metadata, entry point, dev dependencies +├── timesheets.example.toml # example config file +└── src/timesheets/ + ├── cli.py # argument parsing, main() entry point + ├── parser.py # markdown table parsing, aggregation, date filtering + ├── projects.py # project_map.json loading and key resolution + ├── output.py # CSV writing, summary, stories, and status printing + ├── config.py # TOML config file loading and key extraction + ├── joplin.py # Joplin API integration (notebook traversal, note fetching) + ├── status.py # day/week status calculations + └── utils.py # shared low-level helpers (duration parsing, formatting, etc.) +``` + +## Installation + +```sh +cd timesheets +uv sync +``` + +## Subcommands + +| Command | Description | +|---|---| +| `summary` | Human-readable summary of time spent per project | +| `csv` | Export timesheet entries as CSV for Odoo import | +| `stories` | List stories worked on, grouped by project | +| `status` | Show hours remaining today and projected week total | + +All subcommands accept the same source and day arguments: + +```sh +# Source: Joplin (recommended) or a local file +uv run timesheets --joplin +uv run timesheets --input timesheet.md + +# Day: defaults to today, accepts YYYY-MM-DD, MM-DD, natural language +uv run timesheets 2026-05-22 --joplin +uv run timesheets yesterday --joplin +uv run timesheets 3 days ago --joplin +``` + +### summary + +```sh +uv run timesheets summary --joplin # today, full detail +uv run timesheets summary -w --joplin # full week +uv run timesheets summary -s --joplin # short: one line per project +uv run timesheets summary -w -s --joplin # weekly short: per-day project totals +uv run timesheets summary -w -ss --joplin # weekly totals only: one line per day +``` + +### csv + +```sh +uv run timesheets csv --joplin # stdout +uv run timesheets csv --joplin -o output.csv # write to file +``` + +### stories + +```sh +uv run timesheets stories --joplin # today +uv run timesheets stories -w --joplin # full week +``` + +### status + +```sh +uv run timesheets status --joplin +``` + +## Config file + +Copy `timesheets.example.toml` to `timesheets.toml` in the working directory +(or pass `--config /path/to/file.toml`): + +```toml +[joplin] +token = "your_api_token_here" + +[projects] +map = "/path/to/project_map.json" + +[work] +daily_hours = 8.0 +weekly_hours = 40.0 +``` + +Priority order: **CLI flag > config file > environment variable > default**. + +## Joplin notebook structure + +``` +Work/ +└── Timesheets/ + └── YYYY/ + └── YYYY - WNN ← note per week, one table per day +``` + +Each table is preceded by a heading of the form `# - YYYY-MM-DD`. +Open entries (start time present, end time absent) are used by the `status` +command to calculate expected end time. diff --git a/project_map.json b/project_map.json index 197f29e..243026d 100644 --- a/project_map.json +++ b/project_map.json @@ -15,6 +15,10 @@ "Project": "[Factry] Historian Product Development", "Task": "[Historian] Incoming requests" }, + "incoming": { + "Project": "[Factry] Historian Product Development", + "Task": "[Historian] Incoming requests" + }, "internal": { "Project": "[Factry] Internal" },