feat: make vk safe to drive from scripts and agents #32
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/agent-cli"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Makes vk safe and practical to drive from scripts and AI agents. The four parts from our discussion each have their own commit, plus two fixes found in live testing and a README section.
1. Errors, exit codes and
--jsoneverywhere (ee37bad)--json, errors come out on stderr as{"error": {"kind", "message"}}.--json/-jworks anywhere on the command line, or viaVK_JSON=1. Write commands print their result, sovk new --jsongives you the new task's id.check,timeline, andedit/commentwith no text) refuse to start without a terminal instead of hanging on an editor.--project fooused to take the first project whose title contained "foo". An exact title now wins, and an ambiguous partial match is an error that lists the candidates.2. Safe edits (
5b6fd82, fixa307f30)--expect-updated <time>on edit, done, fav, label, assign, relation and rm. If the task changed since you read it, the command fails with exit 5 and writes nothing. The editor flow andvk checkapply the same check against the version they opened.--dry-run/-non every write shows a field-by-field diff, or a summary for creates and deletes, without writing. It still resolves the task, project, label or user, so a dry run catches the same errors the real run would.-reads a description or comment from stdin.3.
vk contextandvk changes(12175f3, fix70cfdbe)vk context 42: the task's fields, description, checklist, relations and comments in one Markdown document (or JSON).updatedis shown verbatim, ready for--expect-updated.vk changes --since 12h [-p project]: tasks created, done or updated since then, newest first. It uses the server-sideupdatedfilter and re-checks every result locally. On a live instance with 667 tasks it matched a full scan exactly.4.
vk claim/vk unclaim/vk --mine(66aee26)--force. Repeating a claim or unclaim is a harmless no-op.VK_USER_ID, thenuser_idinvk.toml, then/user.Verification
clippy -D warningsandRUSTDOCFLAGS=-D warnings cargo docare clean. 102 tests pass (up from 68).contextandchanges.a307f30: create/update responses reportupdatedwith nanoseconds, but Vikunja stores whole seconds.🤖 Generated with Claude Code
vk was hard to drive from scripts and agents: failures were panics with exit code 101, list endpoints silently returned a partial result when a page failed, and JSON output existed on four commands only. Errors. Every command now returns a VkError with a kind, reported on stderr (as {"error": {"kind", "message"}} in JSON mode) with its own exit code: 2 usage, 3 not found, 4 auth, 5 conflict, 6 api, 7 network, 1 other. HTTP statuses from Vikunja map onto these kinds, and the server's message is kept. Paging stops on an error instead of treating it as the end of the list. JSON. --json / -j is accepted anywhere on the command line, or via VK_JSON=1. Commands that change something print the resulting object: the created or updated task (so `vk new` reports the new id), the new comment, project or label, or {"deleted": ...}. Interactive commands (check, timeline, edit and comment without text) refuse JSON mode and a missing terminal instead of hanging on an editor. sync prints its stats. Project names. `--project foo` used to take the first project whose title contained "foo", which could silently pick the wrong one. An exact title match now wins, a single partial match is still accepted, and several are an error listing the candidates. Labels and users resolve through the same not-found errors instead of unwrapping. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>vk already re-reads a task before writing it back, so omitted fields are no longer cleared. That only protects the milliseconds between vk's own read and write, though. An agent that reads a task, thinks, and writes minutes later still overwrites whatever a person changed in between. --expect-updated <time> on edit, done, fav, label, assign, relation and rm takes the task's `updated` value from an earlier read. If the task has changed since, the command fails with a conflict (exit 5) and writes nothing. Any RFC 3339 spelling of the same instant matches. The editor flow of `vk edit` and the `vk check` checklist apply the same check implicitly, against the version they opened, so a long editing session cannot save over changes made meanwhile. --dry-run / -n on every command that changes something reports what it would do without doing it: a field-by-field diff for task updates, or a summary of the create/delete/relate. It still resolves the task, project, label or user, so a dry run catches the same not-found errors the real run would. With --json the report is {"dry_run": true, "action", "task", "changes": {field: {from, to}}}. Task updates are split into pure functions (TaskEdit::apply, with_done, with_favorite) and one update_task call, which is what makes the dry run exact. Also: - `-` reads a description or comment from stdin, so long markdown doesn't have to go through shell quoting - users can be given by numeric id. API tokens are refused on Vikunja's user routes, so name lookups cannot work with them, and the error now says so Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>