chitty 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. chitty-0.1.0/.github/workflows/release.yml +83 -0
  2. chitty-0.1.0/.gitignore +4 -0
  3. chitty-0.1.0/AGENTS.md +32 -0
  4. chitty-0.1.0/CLAUDE.md +1 -0
  5. chitty-0.1.0/LICENSE +21 -0
  6. chitty-0.1.0/Makefile +22 -0
  7. chitty-0.1.0/PKG-INFO +79 -0
  8. chitty-0.1.0/PLAN.md +397 -0
  9. chitty-0.1.0/README.md +54 -0
  10. chitty-0.1.0/chitty/human/HUMAN-1--decide-whether-check-should-detect-depends-on-cycles.md +9 -0
  11. chitty-0.1.0/chitty/human/HUMAN-2--publish-chitty-to-pypi.md +13 -0
  12. chitty-0.1.0/chitty/tasks/TASK-1--reject-setext-headings-in-task-bodies.md +16 -0
  13. chitty-0.1.0/chitty.toml +9 -0
  14. chitty-0.1.0/package-lock.json +28 -0
  15. chitty-0.1.0/package.json +7 -0
  16. chitty-0.1.0/pyproject.toml +70 -0
  17. chitty-0.1.0/src/chitty/__init__.py +0 -0
  18. chitty-0.1.0/src/chitty/check.py +67 -0
  19. chitty-0.1.0/src/chitty/cli.py +355 -0
  20. chitty-0.1.0/src/chitty/config.py +140 -0
  21. chitty-0.1.0/src/chitty/errors.py +2 -0
  22. chitty-0.1.0/src/chitty/git.py +29 -0
  23. chitty-0.1.0/src/chitty/guide.md +14 -0
  24. chitty-0.1.0/src/chitty/ids.py +73 -0
  25. chitty-0.1.0/src/chitty/mcp.py +178 -0
  26. chitty-0.1.0/src/chitty/model.py +576 -0
  27. chitty-0.1.0/src/chitty/store.py +449 -0
  28. chitty-0.1.0/tests/__init__.py +0 -0
  29. chitty-0.1.0/tests/support.py +39 -0
  30. chitty-0.1.0/tests/test_autocommit.py +66 -0
  31. chitty-0.1.0/tests/test_check.py +50 -0
  32. chitty-0.1.0/tests/test_cli.py +297 -0
  33. chitty-0.1.0/tests/test_config.py +58 -0
  34. chitty-0.1.0/tests/test_formatters.py +88 -0
  35. chitty-0.1.0/tests/test_ids.py +50 -0
  36. chitty-0.1.0/tests/test_mcp.py +48 -0
  37. chitty-0.1.0/tests/test_model.py +281 -0
  38. chitty-0.1.0/tests/test_store.py +110 -0
  39. chitty-0.1.0/uv.lock +970 -0
@@ -0,0 +1,83 @@
1
+ name: Publish release to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v[0-9]+.[0-9]+.[0-9]+"
7
+ - "v[0-9]+.[0-9]+.[0-9]+rc[0-9]+"
8
+ - "v[0-9]+.[0-9]+.[0-9]+[ab][0-9]+"
9
+
10
+ permissions: {}
11
+
12
+ jobs:
13
+ build:
14
+ name: Build and verify distributions
15
+ runs-on: ubuntu-24.04
16
+ timeout-minutes: 15
17
+ permissions:
18
+ contents: read
19
+ steps:
20
+ - name: Check out repository
21
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
22
+ with:
23
+ persist-credentials: false
24
+
25
+ - name: Install uv
26
+ uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
27
+ with:
28
+ enable-cache: false
29
+
30
+ - name: Install Node
31
+ uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
32
+
33
+ - name: Install Python
34
+ run: uv python install 3.12
35
+
36
+ - name: Verify tag matches package version
37
+ shell: bash
38
+ run: test "v$(uv version --short)" = "${GITHUB_REF_NAME}"
39
+
40
+ - name: Install dependencies
41
+ run: make install
42
+
43
+ - name: Check project
44
+ run: make check
45
+
46
+ - name: Build distributions
47
+ run: make build
48
+
49
+ - name: Upload verified distributions
50
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
51
+ with:
52
+ name: distributions
53
+ path: dist/
54
+ if-no-files-found: error
55
+ retention-days: 7
56
+
57
+ publish:
58
+ name: Publish verified distributions
59
+ needs: build
60
+ runs-on: ubuntu-24.04
61
+ timeout-minutes: 10
62
+ environment:
63
+ name: pypi
64
+ permissions:
65
+ id-token: write
66
+ steps:
67
+ - name: Install uv
68
+ uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
69
+ with:
70
+ enable-cache: false
71
+ ignore-empty-workdir: true
72
+
73
+ - name: Download verified distributions
74
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
75
+ with:
76
+ name: distributions
77
+ path: dist/
78
+
79
+ - name: Generate PEP 740 attestations
80
+ uses: astral-sh/attest-action@f589a42a7efb6fe400b4f400de60b4bc90390027 # v0.0.6
81
+
82
+ - name: Publish to PyPI
83
+ run: uv publish
@@ -0,0 +1,4 @@
1
+ .envrc
2
+ __pycache__/
3
+ node_modules/
4
+ /dist/
chitty-0.1.0/AGENTS.md ADDED
@@ -0,0 +1,32 @@
1
+ # Agents
2
+
3
+ Chitty is a markdown-native task tracker. `PLAN.md` is the design; read it
4
+ before changing behaviour, and update it when a decision changes.
5
+
6
+ - `make install` once (Python deps including the `mcp` extra, and the pinned
7
+ prettier used by the round-trip tests).
8
+ - `make check` (ruff, pyright, unittest) before every commit. `make format`
9
+ to fix formatting.
10
+ - Tests use `unittest` and write real files in temp dirs; no filesystem
11
+ mocking. The formatter tests fail, never skip, if prettier or mdformat is
12
+ missing.
13
+ - `cli.py` and `mcp.py` stay thin: behaviour lives in `store.py` and
14
+ `model.py` so the two front ends cannot diverge.
15
+ - Releases: bump `version` in `pyproject.toml`, commit, then push a tag
16
+ `v<version>`. `.github/workflows/release.yml` checks, builds and publishes
17
+ to PyPI by trusted publishing (environment `pypi`).
18
+
19
+ ## Chitty
20
+
21
+ Tasks live in `chitty/`. Use the `chitty` CLI (or MCP tools); do not hand-edit
22
+ task files. `chitty --help` is the full command reference.
23
+
24
+ - Work on one task per session. Start with `chitty show <ID>`.
25
+ - Before writing code, write your approach with `chitty edit <ID> --plan` and
26
+ set `-s doing`. Wait for approval if the human asked for it.
27
+ - Tick acceptance criteria as you meet them: `chitty edit <ID> --check N`
28
+ (numbers are shown by `chitty show`).
29
+ - Record anything surprising with `--note`. Set `-s done` when every
30
+ criterion is ticked and the work is verified.
31
+ - Found unrelated work? `chitty add` it (`-c human` if it needs a person).
32
+ Don't do it in this session.
chitty-0.1.0/CLAUDE.md ADDED
@@ -0,0 +1 @@
1
+ AGENTS.md
chitty-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ed Singleton
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
chitty-0.1.0/Makefile ADDED
@@ -0,0 +1,22 @@
1
+ .PHONY: install check test format build
2
+
3
+ install: ## install Python and node dev dependencies
4
+ uv sync --all-extras
5
+ npm ci
6
+
7
+ check: ## lint, type-check and run the tests
8
+ uv run ruff format --check .
9
+ uv run ruff check --no-fix .
10
+ uv run pyright
11
+ uv run python -m unittest discover -s tests -t .
12
+
13
+ test: ## run the tests
14
+ uv run python -m unittest discover -s tests -t .
15
+
16
+ format: ## format and auto-fix Python code
17
+ uv run ruff check --exit-zero .
18
+ uv run ruff format .
19
+
20
+ build: ## build the sdist and wheel into dist/
21
+ rm -rf dist
22
+ uv build
chitty-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,79 @@
1
+ Metadata-Version: 2.5
2
+ Name: chitty
3
+ Version: 0.1.0
4
+ Summary: Markdown-native task tracker for repos worked on by humans and coding agents
5
+ Project-URL: Homepage, https://github.com/Singletoned/chitty
6
+ Project-URL: Issues, https://github.com/Singletoned/chitty/issues
7
+ Author-email: Ed Singleton <ed@singletoned.com>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Keywords: agents,cli,markdown,mcp,task-tracker
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Software Development :: Bug Tracking
18
+ Requires-Python: >=3.12
19
+ Requires-Dist: click
20
+ Requires-Dist: pydantic
21
+ Requires-Dist: pyyaml
22
+ Provides-Extra: mcp
23
+ Requires-Dist: mcp>=2; extra == 'mcp'
24
+ Description-Content-Type: text/markdown
25
+
26
+ # Chitty
27
+
28
+ Markdown-native task tracker for repos worked on by humans and coding agents.
29
+ Put in a chitty; an agent (or you) picks it up; the file is the record.
30
+
31
+ Each task is one markdown file with YAML frontmatter under
32
+ `chitty/<context>/`, e.g. `chitty/tasks/TASK-12--add-search.md`. The files are
33
+ the only state: no database, no index. The tool only ever changes the lines
34
+ it means to, so prettier and mdformat leave its output alone and diffs stay
35
+ small. See `PLAN.md` for the full design.
36
+
37
+ ## Install
38
+
39
+ Not yet on PyPI. From a checkout:
40
+
41
+ ```sh
42
+ uv tool install . # CLI
43
+ uv tool install '.[mcp]' # CLI plus `chitty mcp`
44
+ ```
45
+
46
+ ## Use
47
+
48
+ ```sh
49
+ chitty init # chitty.toml, chitty/tasks/, AGENTS.md block
50
+ chitty add "Add search" -d "Search titles and bodies." \
51
+ --ac "Matches title" --ac "Case-insensitive" -l cli
52
+ chitty list
53
+ chitty show 1 # bare numbers mean the default context
54
+ chitty edit 1 -s doing --plan "Use casefold()." --check 1
55
+ chitty edit 1 --note "Safari needs a polyfill."
56
+ chitty add "Rotate prod password" -c human -d "Needs a person."
57
+ chitty move 1 human # new ID there; references are rewritten
58
+ chitty archive HUMAN-1
59
+ chitty check # validate everything; non-zero on problems
60
+ ```
61
+
62
+ Every command takes `--json`. `chitty --help` and `chitty <command> --help`
63
+ are the reference.
64
+
65
+ Contexts are configured in `chitty.toml`. Contexts in other repos (for
66
+ posting tasks elsewhere) go in `~/.config/chitty/contexts.toml`:
67
+
68
+ ```toml
69
+ [contexts.notes]
70
+ repo = "~/notes"
71
+ ```
72
+
73
+ ## Develop
74
+
75
+ ```sh
76
+ make install # uv sync --all-extras; npm ci (pinned prettier)
77
+ make check # ruff, pyright, unittest
78
+ make format
79
+ ```
chitty-0.1.0/PLAN.md ADDED
@@ -0,0 +1,397 @@
1
+ # Chitty — plan
2
+
3
+ Markdown-native task tracker for repos worked on by humans and coding agents.
4
+ A clean-room reimplementation of the idea behind Backlog.md, in Python, with
5
+ a file format that ordinary markdown tooling leaves alone and a much smaller
6
+ surface area.
7
+
8
+ Put in a chitty; an agent (or you) picks it up; the file is the record.
9
+
10
+ ## Principles
11
+
12
+ - The files are the truth. No database, no index, no cache. A directory scan
13
+ is fast enough for thousands of tasks.
14
+ - One task, one file, one writer at a time. No locking, no cross-branch
15
+ scanning, no automatic conflict repair. If you want a task from another
16
+ branch, merge the branch. IDs are sequential; task creation is expected to
17
+ be centralised (one agent or human), so we assume parallel branches don't
18
+ collide. `check` reports it if they do.
19
+ - Simple first. Add complexity when real-world use shows it is needed, not
20
+ before.
21
+ - Plain markdown. Every file must survive a round trip through the supported
22
+ formatters (below) without changing meaning. No HTML comments, no sentinel
23
+ markers, no numbering inside checklist text.
24
+ - Loud errors. Malformed files are rejected with a path and a reason, never
25
+ silently repaired. `chitty check` is the compile step.
26
+ - The tool carries the rules, not a prompt. Validation and `--help` are the
27
+ documentation; the agent instructions are ~20 lines and static.
28
+ - Minimal diffs. The tool never touches a line it didn't change, and never
29
+ writes a file whose content would be unchanged.
30
+ - No migrations in v1. The format is versioned (`format = 1` in config) so
31
+ one can be written later if ever needed.
32
+
33
+ ## Non-goals
34
+
35
+ TUI. Web UI. Cross-branch task resolution. File locking. Format migrations.
36
+ Remote/HTTP contexts (sync a directory instead). Subtask IDs (`24.1`).
37
+ Milestones. Docs/decisions directories. Wizards. Shell completions (v1).
38
+ Configurable statuses (v1). Moving tasks between repos. ID collision
39
+ handling beyond reporting it.
40
+
41
+ ## Layout
42
+
43
+ ```
44
+ repo/
45
+ chitty.toml
46
+ chitty/
47
+ tasks/ default context
48
+ TASK-2--add-search.md
49
+ TASK-3--fix-login.md
50
+ archive/
51
+ TASK-1--bootstrap.md
52
+ human/ another context
53
+ HUMAN-1--rotate-prod-password.md
54
+ ```
55
+
56
+ `chitty/` is the backlog root; each context is a subdirectory. Archived
57
+ tasks move to `<context>/archive/`. Nothing else lives under `chitty/`.
58
+
59
+ A missing context directory is an empty context; it is created on first
60
+ write. `init` creates `chitty/tasks/` only; `chitty/human/` appears the first
61
+ time something is added to it. (Git doesn't track empty directories, so a
62
+ freshly cloned repo may have none of them.)
63
+
64
+ Root discovery (CLI and MCP alike): `CHITTY_ROOT` if set, otherwise walk up
65
+ from the current directory to the first directory containing `chitty.toml`.
66
+ Error if neither finds one.
67
+
68
+ ## IDs
69
+
70
+ `<PREFIX>-<n>`, e.g. `TASK-13`.
71
+
72
+ - `PREFIX` is the context's prefix: `[A-Z]+`, unique within a repo.
73
+ - `n` is a positive integer, unpadded: `max(n over existing files in the
74
+ context, including archive) + 1`.
75
+
76
+ Filename: `<ID>--<slug>.md`, or `<ID>.md` when the slug is empty. The slug
77
+ is derived from the title at creation (lowercase, `[a-z0-9-]`, collapsed
78
+ hyphens, max 60 chars; empty if the title has no ASCII alphanumerics) and is
79
+ **not** updated when the title changes — it is there so `ls` is readable,
80
+ nothing more. Slugs never contain `--`, so the ID is everything before the
81
+ first `--`. The ID is not repeated in frontmatter.
82
+
83
+ Collisions: task creation is expected to be centralised, so two branches
84
+ creating the same ID is assumed not to happen in practice. If it does,
85
+ `chitty check` reports the files involved; the human renames one and fixes
86
+ references by hand. No tooling beyond that until real use shows it's
87
+ needed. Likewise, moving the highest-numbered task out of a context lets
88
+ its number be reused; accepted.
89
+
90
+ Referencing: commands accept `TASK-13`, or bare `13` for the default
91
+ context. Stored references (`depends_on`, `moved_from`) are always the full
92
+ `PREFIX-n` form; shorthand is expanded before writing.
93
+
94
+ ## Task file
95
+
96
+ ```markdown
97
+ ---
98
+ title: Add search to the task list
99
+ status: todo
100
+ labels:
101
+ - search
102
+ - cli
103
+ priority: medium
104
+ owner: ed
105
+ depends_on:
106
+ - TASK-7
107
+ - HUMAN-1
108
+ created: 2026-10-23
109
+ ---
110
+
111
+ ## Description
112
+
113
+ Free markdown.
114
+
115
+ ## Acceptance Criteria
116
+
117
+ - [ ] `chitty list --search` matches title and body
118
+ - [x] Matching is case-insensitive
119
+
120
+ ## Plan
121
+
122
+ Free markdown, written by the agent before implementing.
123
+
124
+ ## Notes
125
+
126
+ Free markdown. Append-only by convention; not enforced.
127
+ ```
128
+
129
+ Frontmatter schema (strict: unknown keys are an error):
130
+
131
+ | key | type | required | notes |
132
+ |--------------|--------------------|----------|----------------------------------------------|
133
+ | `title` | string | yes | non-empty, single line |
134
+ | `status` | `todo\|doing\|done` | yes | fixed in v1 |
135
+ | `labels` | list[string] | no | absent ≡ `[]` |
136
+ | `priority` | `low\|medium\|high` | no | absent means unset |
137
+ | `owner` | string | no | free text; `human`, a name, an agent |
138
+ | `depends_on` | list[ID] | no | any context in the same repo |
139
+ | `created` | date | yes | ISO 8601 date, set once |
140
+ | `moved_from` | ID | no | set by `move`; the ID in the source context |
141
+
142
+ There is no `updated` field. Git records when a file changed; the field would
143
+ add a line to every diff and conflict on every merge.
144
+
145
+ YAML is loaded with every scalar as a string (no implicit typing), so
146
+ `owner: no` is the string `"no"` and `status: on` fails validation as an
147
+ unknown status rather than becoming `True`. Pydantic parses `created` from
148
+ the string. When the tool *writes* a free-text field (`title`, `owner`,
149
+ `labels`) it quotes anything YAML 1.1 or 1.2 would read as a non-string
150
+ (`"no"`, `"2026-10-23"`, `"1e3"`), because other tools reading the file
151
+ won't be as careful. `created` is a real date and is written unquoted.
152
+
153
+ Body rules:
154
+
155
+ - Sections are `##` headings. Recognised: `Description`, `Acceptance
156
+ Criteria`, `Plan`, `Notes`. Unrecognised `##` headings, any `#` heading,
157
+ and non-blank content before the first `##` are errors. Use `###` and below
158
+ inside a section for structure.
159
+ - The parser is fence-aware: `##` inside a fenced code block is not a heading.
160
+ - `Description` is required and non-empty.
161
+ - `Acceptance Criteria` contains only a flat task list. An item starts with
162
+ `- [ ]`, `- [x]` or `- [X]` at column 0 and may continue on following
163
+ indented lines (formatters wrap long items). Blank lines between items are
164
+ allowed. Nested lists, unindented prose, and anything else in the section
165
+ are errors. Each item is one criterion, addressed by 1-based position in
166
+ the CLI; no numbers are stored in the text. The tool writes `- [x]`.
167
+ - Everything else is free markdown.
168
+
169
+ ### Supported formatters
170
+
171
+ The round-trip guarantee is tested against, and only claimed for:
172
+
173
+ - `prettier` with default settings, and with `proseWrap: always`;
174
+ - `mdformat` with the `mdformat-gfm` and `mdformat-frontmatter` plugins
175
+ (plain CommonMark mdformat turns `---` into a heading and escapes `[ ]`).
176
+
177
+ Both are pinned to exact versions. If either is missing, the round-trip
178
+ tests fail loudly; they are never skipped.
179
+
180
+ "Survives" means the file still parses to the same task. Byte-for-byte
181
+ no-op is only claimed for ordinary content: `mdformat-frontmatter`
182
+ re-serialises YAML as 1.2 and drops the quotes the tool adds for 1.1
183
+ readers (`"no"` becomes `no`), and mdformat renumbers ordered lists in free
184
+ markdown.
185
+
186
+ ### Writing
187
+
188
+ Serialisation is a patch over the original text, not parse-then-dump:
189
+
190
+ - Frontmatter is split into one span per top-level key (the key's line plus
191
+ any indented lines under it). Changed keys have their span replaced, new
192
+ keys are appended in table order, removed keys have their span deleted.
193
+ Every other byte — comments, quoting, blank lines — is left alone.
194
+ Comment and blank lines belong to the key below them, so replacing a key
195
+ keeps the comment above it.
196
+ - The body is split the same way, one span per `##` section. Only sections
197
+ the command changed are rewritten; new sections are appended in the
198
+ canonical order above.
199
+ - Acceptance Criteria are patched per item, so formatter wrapping survives:
200
+ `--check`/`--uncheck` change only the bracket character, `--rm-ac`
201
+ deletes that item's lines, `--ac` appends one line.
202
+ - Lists are written block-style (one item per line). Flow style is accepted
203
+ on read and left alone if the key isn't being changed.
204
+ - If the resulting content equals the current content, the file is not
205
+ written.
206
+ - `--note TEXT` appends `TEXT` as a new paragraph (preceded by a blank line)
207
+ to `## Notes`, creating the section if absent. No date prefix; include one
208
+ in the text if you want it.
209
+ - All checklist indices in a single `edit` refer to the list as it was
210
+ before the command ran. `show` prints the numbers next to each criterion so
211
+ callers don't count.
212
+
213
+ ## Config
214
+
215
+ `chitty.toml` at repo root (required; `chitty init` writes it):
216
+
217
+ ```toml
218
+ format = 1
219
+ default_context = "tasks"
220
+ autocommit = false # if true, commit each write
221
+
222
+ [contexts.tasks]
223
+ prefix = "TASK"
224
+
225
+ [contexts.human]
226
+ prefix = "HUMAN"
227
+ ```
228
+
229
+ Context directory is `chitty/<name>/`. Not configurable.
230
+
231
+ User-level `~/.config/chitty/contexts.toml` (optional), for adding tasks to
232
+ other repos or to a personal backlog:
233
+
234
+ ```toml
235
+ [contexts.hypurrcube]
236
+ repo = "~/src/hypurrcube" # that repo's chitty.toml applies
237
+ context = "tasks" # optional; default is that repo's default_context
238
+
239
+ [contexts.improvements]
240
+ repo = "~/notes/improvements" # any directory with a chitty.toml
241
+ ```
242
+
243
+ Resolution of a context name: repo `chitty.toml` first, then user file.
244
+ A name present in both is an error (no silent shadowing). A name in neither
245
+ is an error naming both paths.
246
+
247
+ ## Dependencies
248
+
249
+ `depends_on` may reference any context in the same repo (`TASK-3` blocked on
250
+ `HUMAN-1` is the common case). Rules:
251
+
252
+ - A reference to an ID that doesn't exist in the repo is a `check` error.
253
+ - A reference to an archived task is fine; archived is not deleted.
254
+ - `move` gives the task a new ID in the target context and rewrites every
255
+ reference to the old ID across the repo, reporting which files it touched.
256
+ - User-level contexts are write targets only; nothing can depend on a task
257
+ in another repo. If you need to track it, write the foreign ID in your own
258
+ task's Notes.
259
+
260
+ ## CLI
261
+
262
+ All commands take `--json` on reads (and on writes, printing the resulting
263
+ task). Exit non-zero with a message on stderr for every error. No prompts,
264
+ no wizards; every command is fully specifiable by flags.
265
+
266
+ ```
267
+ chitty init [--prefix TASK] write chitty.toml, chitty/tasks/, AGENTS.md block
268
+ chitty add TITLE -d TEXT [-c CTX] [--ac TEXT]... [-l LABEL]... [-p PRIO]
269
+ [--owner X] [--depends-on ID]...
270
+ chitty list [-c CTX] [-s STATUS]... [-l LABEL]... [--owner X] [--search TEXT]
271
+ [--archived | --all]
272
+ chitty show ID
273
+ chitty edit ID [--title T] [-s STATUS] [--add-label L]... [--rm-label L]... [-p PRIO]
274
+ [--owner X] [--depends-on ID]... [--rm-depends-on ID]...
275
+ [-d TEXT | --description-file F]
276
+ [--ac TEXT]... [--rm-ac N]... [--check N]... [--uncheck N]...
277
+ [--plan TEXT | --plan-file F] [--note TEXT]
278
+ chitty move ID CTX CTX must be in this repo; new ID, sets moved_from
279
+ chitty archive ID | chitty restore ID
280
+ chitty check [-c CTX] [PATH]... validate; non-zero on any error
281
+ chitty path ID print the file path (for editors/agents)
282
+ chitty mcp stdio MCP server (needs the mcp extra)
283
+ ```
284
+
285
+ - `-c/--context` defaults to `default_context`. On `add`, a user-level
286
+ context name is accepted: the file is written into that repo's working
287
+ tree as an untracked file and nothing else happens there — no commit,
288
+ pull or push, and that repo's `autocommit` setting is ignored. Any
289
+ `--depends-on` is validated against the *target* repo. Post-and-forget.
290
+ On every other command, `-c` must name a context in this repo.
291
+ - `-d` is required on `add`, because Description is required.
292
+ - `ID` arguments accept `TASK-13`, or bare `13` for the default context.
293
+ - `list` shows non-archived tasks by default; `--archived` shows only
294
+ archived; `--all` shows both. Default output is one line per task:
295
+ `TASK-12 doing Add search to the task list [cli,search]`.
296
+ - `move` is within the current repo only. It gives the task the next number
297
+ in the target context and keeps the slug. There is no cross-repo move;
298
+ `add -c otherrepo` plus `archive` here is the explicit two-step version.
299
+
300
+ ## MCP
301
+
302
+ `chitty mcp` runs a stdio server. Tools mirror the CLI one-to-one with the
303
+ same names and argument names: `add`, `list`, `show`, `edit`, `move`,
304
+ `archive`, `restore`, `check`, `path`. They return the same JSON
305
+ the CLI prints with `--json`. One resource, `chitty://guide`, returning the
306
+ same text as the AGENTS.md block. Tool descriptions state the rules (one
307
+ task per session, write Plan before coding, tick criteria as you go).
308
+
309
+ The `mcp` package pulls in starlette, uvicorn, httpx and friends, so it is an
310
+ optional extra: `uv tool install 'chitty[mcp]'`. Agents with a shell can use
311
+ the CLI with `--json` and need none of it. `chitty mcp` without the extra
312
+ exits with an error saying so.
313
+
314
+ ## Agent instructions
315
+
316
+ `chitty init` appends this block to `AGENTS.md` (creating it if absent),
317
+ idempotently, keyed on the `## Chitty` heading:
318
+
319
+ ```markdown
320
+ ## Chitty
321
+
322
+ Tasks live in `chitty/`. Use the `chitty` CLI (or MCP tools); do not hand-edit
323
+ task files. `chitty --help` is the full command reference.
324
+
325
+ - Work on one task per session. Start with `chitty show <ID>`.
326
+ - Before writing code, write your approach with `chitty edit <ID> --plan` and
327
+ set `-s doing`. Wait for approval if the human asked for it.
328
+ - Tick acceptance criteria as you meet them: `chitty edit <ID> --check N`
329
+ (numbers are shown by `chitty show`).
330
+ - Record anything surprising with `--note`. Set `-s done` when every
331
+ criterion is ticked and the work is verified.
332
+ - Found unrelated work? `chitty add` it (`-c human` if it needs a person).
333
+ Don't do it in this session.
334
+ ```
335
+
336
+ That is the whole prompt. Statuses are fixed, so the block is always correct.
337
+
338
+ ## Stack
339
+
340
+ - Python ≥ 3.12, packaged with `uv`; installed as `uv tool install chitty`,
341
+ tried with `uvx chitty`.
342
+ - Runtime: `click`, `pydantic`, `pyyaml`. Frontmatter is split on `---` by
343
+ our own code; YAML is loaded with a loader that resolves every scalar as a
344
+ string. Optional extra `mcp`.
345
+ - Dev: `ruff`, `pyright` (strict for `src/`, standard for tests; with
346
+ `types-PyYAML`), `unittest` (stdlib;
347
+ tests write real files in a temp dir and drive the CLI through
348
+ `click.testing.CliRunner`; no filesystem mocking), `prettier` and `mdformat`
349
+ with the plugins above for the round-trip tests.
350
+ - `Makefile` following the mate conventions (`.PHONY` targets with `##`
351
+ descriptions): `make check` (ruff + pyright + tests), `make format`.
352
+ - Git via `subprocess.run(..., check=True)`. Only used when `autocommit` is
353
+ on: `git add -- <paths> && git commit --only -m "chitty: <verb> <ID> <title>" -- <paths>`,
354
+ with all affected paths listed (two for `move`/`archive`/`restore`, more
355
+ when `move` rewrites references), so nothing the user had staged is swept
356
+ in. Failure is a loud error.
357
+
358
+ ## Module layout
359
+
360
+ ```
361
+ src/chitty/
362
+ __init__.py
363
+ model.py Task, Frontmatter, Criterion — parse/validate/serialise ONE file
364
+ ids.py ID and filename parsing, slugs, next number, shorthand
365
+ config.py RepoConfig, UserContexts — load + validate TOML
366
+ store.py Context, find/list/read/write/move/archive
367
+ check.py cross-file validation: parse errors, duplicate IDs,
368
+ dangling or self depends_on
369
+ errors.py ChittyError, the base of every user-facing error
370
+ git.py optional autocommit
371
+ cli.py click commands; thin, calls store/model, prints
372
+ mcp.py tool definitions wrapping the same functions as cli.py
373
+ (mcp ≥ 2: MCPServer, not FastMCP)
374
+ guide.md the AGENTS.md block, as package data
375
+ ```
376
+
377
+ `cli.py` and `mcp.py` contain no logic; both call the same functions in
378
+ `store.py`/`model.py` so behaviour cannot diverge.
379
+
380
+ ## Build order
381
+
382
+ 1. `model.py` + `ids.py` + tests: parse, single-file validation, patch-style
383
+ serialisation, round-trip. Tests include: prettier (default and
384
+ `proseWrap: always`) and mdformat (with plugins) are no-ops on tool
385
+ output; a wrapped criterion is one criterion and ticking it doesn't
386
+ unwrap it.
387
+ 2. `config.py`, `store.py`: contexts, read/write/move/archive,
388
+ missing-directory-is-empty.
389
+ 3. `check.py`: duplicates and dangling references.
390
+ 4. `cli.py`: `init`, `add`, `list`, `show`, `edit`, `check`, `path`.
391
+ 5. `move`, `archive`/`restore`, user-level contexts.
392
+ 6. `autocommit`.
393
+ 7. `mcp.py` as the optional extra.
394
+ 8. Dogfood: track Chitty's own work in `chitty/` from step 4 onward.
395
+
396
+ Steps 1–4 are a usable tool. Estimate for the whole list: 3–5k lines
397
+ including tests.