AGENTS.md
What this repo is
- Rust CLI app (
td) for local task tracking aimed at agent workflows. - Storage is SQLite in a per-project
.td/tasks.dbdatabase. - Entry flow is
src/main.rs→yatd::run()(src/lib.rs) →cmd::dispatch()(src/cmd/mod.rs). - We use jj for version control, not git. DO NOT use Conventional Commits. Do use imperative, Linux kernel-style commits. Always check
jj stbefore starting. If there are changes in progress, runjj new -m ...to create a new working copy describing the pending work. If there are no changes in the working copy, runjj desc -m ...to describe the pending work. - JSON mode is not for "agent consumers". It's for wiring things together, whether the wirer is human or LLM.
- 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.
Essential commands
- Format:
jj fix(rustfmt via repo-level jj config) - Lint (warnings are errors):
cargo clippy --quiet -- -D warnings - Verify after changes:
make verify(formats, typechecks, lints, and tests in one pass)
Implementation details
- Initialization requirement: most commands call
require_root()and fail unless.td/exists somewhere in current dir ancestry (db::find_root). Onlyinitandskillavoid this path. - DB schema is created in
src/db.rs(SCHEMA): - Foreign keys are explicitly enabled on each connection (
PRAGMA foreign_keys = ON). - Task IDs:
- top-level: generated short IDs (
td-xxxxxx) viadb::gen_id() - subtasks:
<parent>.<n>generated by counting existing children increate.
- top-level: generated short IDs (
Command/module map
- CLI definition and argument shapes:
src/cli.rs - Dispatch wiring:
src/cmd/mod.rs - Command implementations live in
src/cmd/*.rs(one module per subcommand, includingskill). - Shared DB/domain helpers and structs (
Task,TaskDetail, loaders):src/db.rs
Testing approach
- Integration-style CLI tests in
tests/cli_*.rsusing:assert_cmdfor invokingtdtempfile::TempDirfor isolated workdirspredicatesfor stdout/stderr assertions
- Typical pattern:
- create temp dir
- run
td init - invoke command under test
- assert output and/or inspect
.td/tasks.dbdirectly withrusqlite
- When adding/changing behavior, prefer extending these CLI tests rather than only unit tests.
Conventions and patterns to preserve
- Error handling uses
anyhow::Resultthroughout command functions. - Keep command functions shaped as
run(...) -> Result<()>with argument parsing incli.rsand routing incmd/mod.rs. - JSON structs rely on serde naming alignment (notably
Task.task_typerenamed to"type"). Maintain compatibility for import/export and tests.
Gotchas
- Running most commands outside an initialized tree yields
not initialized. Run 'td init'due to upward root search; tests should setcurrent_dirto initialized temp dirs. Cargo.tomlusesrusqlitewithbundledfeature, so SQLite is vendored; build behavior differs from system-SQLite setups.