New functionality must follow the red-green-refactor cycle: 1. Write failing tests first 2. Confirm they fail before implementing 3. Implement until tests pass 4. Run full suite to check for regressions
167 lines
5.5 KiB
Markdown
167 lines
5.5 KiB
Markdown
# Timesheets — Agent Guide
|
|
|
|
> **Read `README.md` first** for a full description of the project, its
|
|
> subcommands, config file format, and Joplin notebook structure.
|
|
|
|
## Package layout
|
|
|
|
```
|
|
timesheets/
|
|
├── 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, 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.)
|
|
```
|
|
|
|
Tests live in `tests/`, one file per source module:
|
|
|
|
```
|
|
tests/
|
|
├── test_utils.py
|
|
├── test_parser.py
|
|
├── test_projects.py
|
|
├── test_config.py
|
|
├── test_output.py
|
|
├── test_joplin.py
|
|
└── test_status.py
|
|
```
|
|
|
|
---
|
|
|
|
## Package manager — uv
|
|
|
|
All dependency management and script execution is done via [`uv`](https://docs.astral.sh/uv/).
|
|
Do **not** use `pip` or `python` directly.
|
|
|
|
| Task | Command |
|
|
|---|---|
|
|
| Install / sync dependencies | `uv sync` |
|
|
| Add a runtime dependency | `uv add <package>` |
|
|
| Add a dev-only dependency | `uv add --dev <package>` |
|
|
| Run the CLI | `uv run timesheets <args>` |
|
|
| Run any Python script | `uv run python <script>` |
|
|
|
|
---
|
|
|
|
## Testing
|
|
|
|
The test suite uses **pytest** with **pytest-cov** for coverage reporting.
|
|
|
|
```sh
|
|
# Run all tests
|
|
uv run pytest
|
|
|
|
# Run with coverage report
|
|
uv run pytest --cov
|
|
|
|
# Run a specific test file
|
|
uv run pytest tests/test_parser.py
|
|
|
|
# Run a specific test
|
|
uv run pytest tests/test_parser.py::TestParseTable::test_empty_input
|
|
```
|
|
|
|
### Rules for adding or changing functionality
|
|
|
|
1. **Use test-driven development (TDD) for new functionality.** The workflow is:
|
|
1. Write the tests first, based on the expected behaviour.
|
|
2. Confirm the new tests *fail* before writing any implementation:
|
|
```sh
|
|
uv run pytest tests/test_<module>.py
|
|
```
|
|
3. Implement the functionality until all tests pass.
|
|
4. Run the full suite to confirm nothing regressed:
|
|
```sh
|
|
uv run pytest --cov
|
|
```
|
|
Skipping the "confirm it fails" step defeats the purpose of TDD — a test
|
|
that never fails gives no confidence.
|
|
|
|
2. **Always update or add tests** when modifying existing behaviour. Tests live
|
|
in the `tests/` file that corresponds to the module being changed
|
|
(e.g. changes to `parser.py` → `tests/test_parser.py`).
|
|
|
|
3. **Do not reduce coverage.** Every new function or branch should have at
|
|
least one test covering the happy path. Edge cases and error paths should be
|
|
covered where the logic is non-trivial.
|
|
|
|
4. `cli.py` is intentionally excluded from unit tests — it is thin glue code.
|
|
All logic worth testing belongs in the other modules.
|
|
|
|
5. Joplin integration tests in `test_joplin.py` must mock `ClientApi` — do not
|
|
require a live Joplin instance.
|
|
|
|
# Behavioral Guidelines
|
|
|
|
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.
|