AGENTS.md

 1# AGENTS.md
 2
 3## What this repo is
 4- Rust CLI app (`td`) for local task tracking aimed at agent workflows.
 5- Storage is Loro CRDT in central storage (`~/.local/share/td/projects/<name>/`). Directory bindings map working directories to projects.
 6- Entry flow is `src/main.rs``yatd::run()` (`src/lib.rs`) → `cmd::dispatch()` (`src/cmd/mod.rs`).
 7- We use jj for version control, not git. DO NOT use Conventional Commits. Do use imperative, Linux kernel-style commits. Always check `jj st` before starting. If there are changes in progress, run `jj new -m ...` to create a new working copy describing the pending work. If there are no changes in the working copy, run `jj desc -m ...` to describe the pending work. `jj diff --git` is more understandable.
 8- JSON mode is not for "agent consumers". It's for wiring things together, whether the wirer is human or LLM.
 9- Contributions are through pr.pico.sh. If you're asked to open a PR or contribute or review a PR or similar and you have the skill, read that. If you don't have the skill, somehow fetch the contents of `https://git.secluded.site/agent-skills/blob/main/skills/collaborating-through-pr-pico-sh/SKILL.md?raw=1`. It's markdown, but served as raw plain text, so curl or any other UA will do fine. If you're not contributing/reviewing yet, don't read it yet.
10
11## Essential commands
12- Format: `jj fix` (rustfmt via repo-level jj config)
13- Lint (warnings are errors): `cargo clippy --quiet -- -D warnings`
14- Verify after changes: `make verify` (formats, typechecks, lints, and tests in one pass)
15
16## Implementation details
17- Project resolution: most commands resolve the project via `db::resolve_project_name()` which checks `--project` flag, `TD_PROJECT` env var, or the directory binding in `~/.local/share/td/bindings.json`. Without a resolved project, commands fail with "no project selected". Only `project` and `skill` subcommands avoid this check.
18- DB schema is created in `src/db.rs` (`SCHEMA`):
19- Foreign keys are explicitly enabled on each connection (`PRAGMA foreign_keys = ON`).
20- Task IDs:
21  - top-level: generated short IDs (`td-xxxxxx`) via `db::gen_id()`
22  - subtasks: `<parent>.<n>` generated by counting existing children in `create`.
23
24## Command/module map
25- CLI definition and argument shapes: `src/cli.rs`
26- Dispatch wiring: `src/cmd/mod.rs`
27- Command implementations live in `src/cmd/*.rs` (one module per subcommand, including `skill`).
28- Shared DB/domain helpers and structs (`Task`, `TaskDetail`, loaders): `src/db.rs`
29
30## Testing approach
31- Integration-style CLI tests in `tests/cli_*.rs` using:
32  - `assert_cmd` for invoking `td`
33  - `tempfile::TempDir` for isolated workdirs
34  - `predicates` for stdout/stderr assertions
35- Typical pattern:
36  1. create temp dir
37  2. run `td project init`
38  3. invoke command under test
39  4. assert output and/or inspect central storage in `~/.local/share/td/projects/<name>/` directly
40- When adding/changing behavior, prefer extending these CLI tests rather than only unit tests.
41
42## Conventions and patterns to preserve
43- Error handling uses `anyhow::Result` throughout command functions.
44- Keep command functions shaped as `run(...) -> Result<()>` with argument parsing in `cli.rs` and routing in `cmd/mod.rs`.
45- JSON structs rely on serde naming alignment (notably `Task.task_type` renamed to `"type"`). Maintain compatibility for import/export and tests.
46
47## Gotchas
48- Running commands without a project binding (and without `--project` or `TD_PROJECT`) yields `no project selected`. Tests should set `current_dir` to directories with initialized bindings.
49- `Cargo.toml` uses `rusqlite` with `bundled` feature, so SQLite is vendored; build behavior differs from system-SQLite setups.
50
51## Contributions
52