{"_id":"@ecology91/tasks-axi","name":"@ecology91/tasks-axi","dist-tags":{"latest":"0.2.5"},"versions":{"0.2.5":{"name":"@ecology91/tasks-axi","version":"0.2.5","packageManager":"pnpm@11.1.1","description":"GitLab-compatible AXI task/backlog CLI — token-efficient TOON output, pluggable backends, byte-exact markdown round-trip, idempotent mutations","type":"module","repository":{"type":"git","url":"git+https://gitlab.home.arpa/workflow/tasks-axi.git"},"homepage":"https://www.npmjs.com/package/@ecology91/tasks-axi","bugs":{"url":"https://gitlab.home.arpa/workflow/tasks-axi/-/issues"},"keywords":["tasks","backlog","cli","agent","axi","gitlab","merge-request","toon","beads"],"bin":{"tasks-axi":"dist/bin/tasks-axi.js"},"publishConfig":{"access":"public"},"scripts":{"build":"tsc","build:skill":"tsx scripts/build-skill.ts","test":"vitest run","test:watch":"vitest","lint":"eslint .","dev":"tsx bin/tasks-axi.ts","prepack":"npm run build"},"license":"MIT","engines":{"node":">=20"},"dependencies":{"@toon-format/toon":"^2.1.0","axi-sdk-js":"^0.1.10"},"devDependencies":{"@eslint/js":"^10.0.1","@types/node":"^22.0.0","eslint":"^10.1.0","globals":"^17.4.0","prettier":"^3.8.1","tsx":"^4.0.0","typescript":"^5.7.0","typescript-eslint":"^8.58.0","vitest":"^3.0.0","yaml":"^2.9.0"},"gitHead":"e02ca39de961c8c3e1e38c402700e5b1fa891c60","_id":"@ecology91/tasks-axi@0.2.5","_nodeVersion":"24.15.0","_npmVersion":"12.0.2","dist":{"integrity":"sha512-hA8e2gnLmh6JZKcIrXKZrVL56HKQBf2uD/lhXZR4s63j4KYsbpSdOu5zWurYspYTZ2OCAJfr4mD72awCdaa4xg==","shasum":"9b0949804ed9683b0ccea2d5e8d2c3bcc8ded522","tarball":"https://registry.npmjs.org/@ecology91/tasks-axi/-/tasks-axi-0.2.5.tgz","fileCount":34,"unpackedSize":274610,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCICNjmmm4YuPId44sHtJqSt1BO7qqORRyhwLKOchdHUluAiBowS55rxHncZS5B+LjSBo96k32SJ73qvxTg2zYsF+klQ=="}]},"_npmUser":{"name":"ecology91","email":"ecology91@proton.me"},"directories":{},"maintainers":[{"name":"ecology91","email":"ecology91@proton.me"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/tasks-axi_0.2.5_1786180334071_0.523063159531242"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-08T09:12:13.914Z","0.2.5":"2026-08-08T09:12:14.214Z","modified":"2026-08-08T09:12:14.491Z"},"maintainers":[{"name":"ecology91","email":"ecology91@proton.me"}],"description":"GitLab-compatible AXI task/backlog CLI — token-efficient TOON output, pluggable backends, byte-exact markdown round-trip, idempotent mutations","homepage":"https://www.npmjs.com/package/@ecology91/tasks-axi","keywords":["tasks","backlog","cli","agent","axi","gitlab","merge-request","toon","beads"],"repository":{"type":"git","url":"git+https://gitlab.home.arpa/workflow/tasks-axi.git"},"bugs":{"url":"https://gitlab.home.arpa/workflow/tasks-axi/-/issues"},"license":"MIT","readme":"<h1 align=\"center\">tasks-axi</h1>\n\n<p align=\"center\">\n  <a href=\"https://www.npmjs.com/package/@ecology91/tasks-axi\"><img alt=\"npm\" src=\"https://img.shields.io/npm/v/%40ecology91%2Ftasks-axi?style=flat-square\" /></a>\n  <img alt=\"GitLab merge request support\" src=\"https://img.shields.io/badge/GitLab-MR%20links-fc6d26?style=flat-square\" />\n  <a href=\"https://img.shields.io/badge/platform-macOS%20%7C%20Linux%20%7C%20Windows-blue?style=flat-square\"><img alt=\"Platform\" src=\"https://img.shields.io/badge/platform-macOS%20%7C%20Linux%20%7C%20Windows-blue?style=flat-square\" /></a>\n</p>\n\nTask and backlog manager for agents — designed with [AXI](https://github.com/kunchenguid/axi) (Agent eXperience Interface).\n\ntasks-axi makes a tiny structured change to a human-readable backlog at near-zero output-token cost.\nIt edits a hand-editable `backlog.md` in place with a byte-exact round-trip, so the markdown stays the source of truth while long task bodies never bloat a `list`.\nIt borrows the dependency-graph and ready-query model from [beads](https://github.com/gastownhall/beads), adds structured dispatch holds, and keeps the house style from its `*-axi` siblings - token-efficient TOON output, contextual next-step suggestions, idempotent mutations, and structured errors.\n\n## Why\n\nEvery backlog mutation today regenerates markdown through the model, which is expensive output tokens and risks dropped, duplicated, or reordered items.\ntasks-axi reduces that to the length of one short command plus a compact confirmation read back as cheap input.\nThe long status line that the model used to rewrite on every status change is now a `body`.\nNote writes are inspect-then-update: read the current body with `show <id> --full`, then replace it deliberately with `update --body` or `update --body-file`.\nPass `--archive-body` with a body replacement when the superseded body should be moved to cold history in `note-archive.md`.\n\n## Quick Start\n\nInstall the GitLab-compatible ecology91 package globally, then install its tasks-axi skill in the [Agent Skills](https://agentskills.io) format with [`npx skills`](https://github.com/vercel-labs/skills):\n\n```sh\nnpm install -g @ecology91/tasks-axi\nnpx skills add \"$(npm root -g)/@ecology91/tasks-axi\" --skill tasks-axi -g\n```\n\nThe installed skill invokes the globally installed `tasks-axi` command directly. Node 20+ is required.\nInstalling the skill does not enable session hooks; those remain an explicit opt-in below.\n\nJust ask for anything that touches the backlog - filing or dispatching work, completing a task, finding dispatchable or held work - and the agent loads the skill on its own when it recognizes the task.\n\n`-g` installs the skill for all projects; drop it to install for the current project only.\n\n## Other Ways to Install\n\nThe skill is the recommended path, but it is not the only one. To run the GitLab-compatible CLI without a global install, tell your agent:\n\n```\nExecute `npx -y @ecology91/tasks-axi` to manage the backlog.\n```\n\n### Original upstream package (without GitLab MR support)\n\nThe original unscoped package remains available for upstream-compatible use.\nIt does not include this distribution's GitLab merge-request support, so do not use it for GitLab MR links.\nTell your agent:\n\n```\nExecute `npx -y tasks-axi` to manage the backlog.\n```\n\n### Session hook\n\nWant the current backlog fed into every agent session as ambient context instead of loading on demand?\nAfter installing this checkout's CLI globally, opt into the hook:\n\n```sh\ntasks-axi setup hooks\n```\n\nThis installs a `SessionStart` hook for **Claude Code**, **Codex**, and **OpenCode** that surfaces the live backlog at the start of each session.\n**Restart your agent session after running this** so the new hook takes effect.\n\n## Usage\n\nRun with no arguments for a content-first dashboard of the current backlog:\n\n```\n$ tasks-axi\nbin: ~/.local/bin/tasks-axi\ndescription: Agent ergonomic task & backlog manager for the current workspace...\nin_flight[1]{id,title,kind,repo}:\n  homemux-h7,PERSISTENT SECONDMATE - owns HomeMux end to end,secondmate,homemux\nsummary:\n  queued: 14\n  ready: 13\nqueued[10]{id,title,kind,blocked_by}:\n  firstmate-lease-adopt,adopt the durable lease,ship,treehouse-lease-t4\n  ...\ndone: 10 retained\nhelp[2]:\n  - Run `tasks-axi list --state queued` for all 14 queued tasks\n  - Run `tasks-axi ready` to see only unblocked work\n```\n\nThe common mutations are one short, low-token command:\n\n```sh\n# add a task (the id is the caller-supplied join key; --mint generates one)\ntasks-axi add lavish-foo-q9 \"fix summary toggle\" --kind ship --repo lavish-axi --priority 2 --start\n\n# move through the workflow\ntasks-axi start firstmate-lease-adopt\ntasks-axi done sm-idle-handoff-q8 --pr https://github.com/owner/repo/pull/42\ntasks-axi done gitlab-delivery-q9 --pr https://gitlab.example.com/group/project/-/merge_requests/42\ntasks-axi reopen some-task\n\n# dependencies, holds, and the ready queue\ntasks-axi block firstmate-lease-adopt --by treehouse-lease-t4\ntasks-axi hold firstmate-lease-adopt --reason \"captain decision pending\" --kind captain\ntasks-axi unhold firstmate-lease-adopt\ntasks-axi ready\ntasks-axi ready --include-held\n\n# edit the body and title: inspect current notes, then replace the body or title deliberately\ntasks-axi show nm-release-validation --full\ntasks-axi update nm-release-validation --body \"rewritten notes\"\ntasks-axi update nm-release-validation --body-file notes.md --archive-body\ntasks-axi update nm-release-validation --title \"clearer title\"\n\n# read the full notes on demand (truncated by default)\ntasks-axi show homemux-h7 --full\n\n# maintenance\ntasks-axi prune --keep 10        # archives the surplus, never deletes\ntasks-axi render                 # normalize the markdown in place\ntasks-axi mv hibit-cert-cleanup --to ../homemux/data/backlog.md\n# move a linked blocker/dependent set together\ntasks-axi mv blocker-b1 dependent-d2 --to ../homemux/data/backlog.md\n```\n\nOutput is [TOON](https://toonformat.dev)-encoded and token-efficient.\nThe long task body is truncated by default — the whole point is that `list` stays cheap; use `--full` only when you need the complete notes.\n`update --body` and `update --body-file` replace the body wholesale, so agents should inspect the current body first and write back the curated current state rather than appending a journal entry.\n`--archive-body` preserves the replaced body in `note-archive.md` using the same dated markdown archive block style as done pruning.\nEvery write leads with a terse `ok:` line confirming the write result, including the resulting task state when the command changes one (e.g. `ok: start lavish-share -> In flight`, `ok: done grok-harness-g7 -> Done (pr <url>)`, `ok: render -> normalized 3`), followed by state-aware next-step hints that never suggest an action the command just performed.\nMutations are idempotent and report what changed (`already: true` on a no-op), so re-running one is safe.\nRunning `done` again on an already Done task can still backfill a new `--pr`, `--report`, or `--note` without changing the original close date.\n`hold <id> --reason \"<text>\"` records an intentional pause without turning it into prose, and `unhold <id>` clears it.\nThe reason must be single-line text without parentheses because parentheses are reserved for canonical markdown tags.\nActive holds are excluded from `ready`; a hold with `--until YYYY-MM-DD` becomes inactive on and after that date, so the task can surface as ready again if nothing else blocks it.\nUse `ready --include-held` to show dispatchable ready work and a separate `held` group with the hold reason, kind, and until date.\nUse `list --state held` or `list --fields held,hold_reason,hold_kind,hold_until` when you need to scan active hold state directly.\nPass `--json` to any mutation for a machine-readable result object (`{ \"ok\": true, \"action\": …, \"task\": { … } }` or operation-specific result fields) instead of TOON, so an agent can confirm a write deterministically without a follow-up read.\nFor `mv`, a single task returns `id`, while a multi-task move returns first-occurrence-ordered, deduplicated `ids`, plus `from` and `to`.\n\nRun `tasks-axi --help` for the command list, or `tasks-axi <command> --help` for per-command usage.\n\nTyped PR links accept an HTTP(S) URL ending in `/pull/<number>` or a strict\nHTTPS GitLab URL ending in `/-/merge_requests/<positive-iid>` (including nested\ngroups). GitLab links must not contain credentials, query strings, or fragments;\nthese GitLab rules also apply to `public-followup` `pr_url` deliverables, which\nretain their existing HTTPS requirement.\n\n## Durable public follow-ups\n\nA promised public final is a first-class `kind=public-followup` obligation, not a worker task or a `blocked-by` edge.\nCreate and mutate it only through the dedicated namespace:\n\n```sh\ntasks-axi public-followup add public-final-ab \\\n  --request-context-file request.json \\\n  --purpose promised-final \\\n  --expected-final-file expected.json \\\n  --expires-at 2026-10-01T00:00:00Z \\\n  --json\n\ntasks-axi public-followup bind-work public-final-ab --relation-file relation.json --json\ntasks-axi public-followup supersede-work public-final-ab --relation rel-code --successor-file successor.json --json\ntasks-axi public-followup work-event public-final-ab --event-file event.json --json\ntasks-axi public-followup list --work-ref secondmate:demo/work-code-q1 --json\ntasks-axi public-followup ready --json\ntasks-axi public-followup begin-delivery public-final-ab --payload-hash <sha256> --json\ntasks-axi public-followup record-error public-final-ab --error-file error.json --json\ntasks-axi public-followup record-delivery public-final-ab --receipt-file receipt.json --json\n```\n\nThe request context file contains the relay-issued request id, platform, opaque `ctx1` binding, bounded public-safe summary, received time, follow-up expiry, and reservation expiry.\nThe expected-final file defines its typed outcome, stable project, required deliverable names, and `all-required` or `any-required` completion policy.\nRelation files contain a stable `relation_id`, `{home_id, task_id}` work reference, `fulfills` or `contributes` role, required flag, and generation.\nCompletion event files use schema version 1 and bind an event id, obligation id, relation id, generation, source home, work id, typed outcome, safe deliverables, bounded public-safe outcome, and a `successor` field that is null unless the outcome supersedes the relation.\nA posted receipt file records `state=posted`, request id, platform, attempt and chunk counts, posted time, and optional retention time.\nIts attempt count must exactly match the currently recorded delivery attempt, including late receipts that reconcile that same attempt from `unknown` or `partial`.\nAn error file records the current attempt count, a safe delivery state, validated error code, occurrence time, optional retry time, and optional chunk counts.\nIts attempt count must exactly match the currently recorded delivery attempt, and stale or future-attempt errors fail without mutation.\nExpected-final types permit only their matching safe deliverables: `pr_url`, `report_path`, `commit_sha`, or `error_code`.\nRun `tasks-axi public-followup --help` for the exact file-backed command surface and state names.\n\nEach mutation is idempotent and returns the monotonic obligation `revision`, changed fields, and complete typed payload under `--json`.\nDuplicate accepted event ids are no-ops, while conflicting ids, stale generations, source mismatches, malformed typed data, and changed immutable intake fields fail closed.\nOne work item can relate to several obligations, and one obligation can require work from several homes.\nThese cross-home relations are separate from same-backlog dispatch dependencies.\nExisting same-backlog `blocked-by` edges remain delivery gates for `ready` and `begin-delivery`.\n\n`tasks-axi ready` excludes public obligations from its ordinary `ready` worker group and exposes delivery-ready obligations only in `ready_public_followups`.\nUse `tasks-axi public-followup ready` when handling public delivery.\nGeneric `start`, `done`, `reopen`, active removal, content or kind changes, and dispatch holds cannot bypass the public-followup state machine.\nOnly `record-delivery` with a validated terminal `posted` receipt or `waive --approved-by captain` can atomically move an obligation to Done.\nNormal Done pruning then preserves the complete typed receipt or waiver in `done-archive.md`.\n\nThe Markdown backend stores version 1 typed data in a reserved base64url canonical-JSON HTML comment immediately below the task bullet.\nThe bounded public-safe title and `(kind: public-followup)` remain visible, but callers other than tasks-axi must not parse or rewrite the reserved comment.\nGeneric title and body updates are refused because changing the immutable public promise requires a successor obligation.\nThe typed schema permits public-safe identifiers, summaries, deliverables, receipt counters, timestamps, and validated error codes.\nIt rejects unknown fields so raw request text, parent context, author or channel ids, signed URLs, and raw platform responses cannot silently enter machine-readable output.\n\n## The markdown backend\n\n`backlog.md` stays the hand-editable source of truth.\ntasks-axi parses it leniently into a model, mutates the targeted item, and re-renders **in place** with a byte-exact round-trip on a file nobody has changed — `render(parse(src)) === src`.\nTargeted task mutations re-render only the affected task; every other line, including free-form (no-id) notes, is preserved verbatim.\nAn item's body includes every following indented or blank line, so multi-paragraph notes and indented Markdown content move intact with the task.\nTrailing separator blanks remain with the item's raw source for byte-exact preservation without becoming part of its structured body.\nMaintenance commands are explicit exceptions: `render` normalizes every recognized task, `prune` trims the chosen section into the archive, and `mv` writes both source and destination backlogs.\n`mv <id> [<id>...] --to <path-or-dir>` moves one or more tasks as one atomic cross-file transaction.\nTo move a dependency-connected set, include every linked blocker and active dependent in the same command, unless the other endpoint already exists in the destination backlog.\nThe command refuses a move that would strand a dependency across the two files, while preserving intra-set `blocked-by` links and their reason strings.\nMoved tasks are re-rendered canonically, so their multi-paragraph bodies remain intact but a trailing blank separator before the next item or section is dropped.\n\nThe read-modify-write window is guarded by an advisory lockfile, an atomic write (temp file + rename), and a fresh re-read on every invocation, so a hand-edit and a CLI-edit cannot clobber each other.\nTask state is carried by the section header, not by the bullet style: `## In flight`, `## Queued`, and `## Done` decide whether a recognized item is in flight, queued, or done.\nIn flight parses both the legacy `- **id** - ...` form and firstmate's `- [ ] id - ...` checkbox form, while normalization renders both In flight and Queued items as `- [ ] id - ...` and Done items as `- [x] id - ...`.\nUntouched legacy lines are still preserved byte-for-byte; only mutated or explicitly normalized tasks are rewritten.\n\nIt gently formalizes the inline tags a backlog already uses as the canonical fields:\n\n- `(repo: X)` - the repo a task belongs to\n- `blocked-by: <id>` or `blocked-by: <id> - <reason>` - a dependency edge, optionally with preserved free-text rationale (also `parent:` / `discovered-from:`)\n- `(since <date>)` - when a task started; `(merged <date>)` / `(reported <date>)` when it closed\n- `(kind: X)` - task kind, when not already implied by a leading `SHIP` / `SCOUT` / `DOCS-ONLY` / `PERSISTENT SECONDMATE` word\n- `(priority: 0-4)` - optional priority, also accepted through `add` / `update --priority`\n- `(hold: <reason>)`, `(hold-kind: captain|external|load|parked|future)`, `(hold-until: YYYY-MM-DD)` - structured dispatch holds written by `hold`\n- Typed PR links use the PR/MR contract above; `data/<id>/report.md` paths and\n  other `http(s)` urls are also typed links\n\n`tasks-axi render` rewrites every id'd task into this canonical form; free-form lines are left untouched.\nBare dependency edges render immediately after the title, while reason-bearing dependency edges render after the parenthetical tags so the reason stays attached to the edge on the next parse.\nDependency reasons are preserved metadata only; readiness still keys off the blocker id.\nHold reasons are preserved metadata too, but active holds are a readiness gate until cleared or until their date gate expires.\nExisting prose markers like `HELD`, `PARKED`, `DEFERRED`, `CAPTAIN-DECISION`, and `do not dispatch` stay prose until you intentionally migrate them.\nMap them to structured holds by preserving the original prose as the reason and choosing `captain`, `parked`, `future`, `load`, or `external` only when the text supports that bucket.\nDo not bulk-rewrite live backlogs just to chase these tags; migrate only when touching the task or when a hold migration specifically targets them.\n`add --blocked-by` and `block --by` require the referenced task to exist, and `rm` refuses to remove a task that still blocks active work.\nSingle-task `mv` has the same protection; use multi-task `mv` to move its active dependents with it.\n\n## Configuration\n\nBackend and path are resolved in this order: `--backend` / `--file` flags passed after the command, then `TASKS_AXI_BACKEND` / `TASKS_AXI_FILE` env, then a project `.tasks.toml`, then `~/.tasks-axi/config.toml`, then the defaults.\nWithout an explicit path, tasks-axi uses `backlog.md` when present, then `data/backlog.md` when present, and otherwise targets `backlog.md` for future writes.\n\n```toml\n# .tasks.toml in the project root\nbackend = \"markdown\"\n\n[markdown]\npath = \"data/backlog.md\"\narchive = \"data/done-archive.md\"\ndone_keep = 10\n```\n\n`archive` is optional; when omitted, pruned tasks are appended to `done-archive.md` next to the active backlog.\nBody replacements with `--archive-body` append superseded bodies to `note-archive.md` next to the active backlog.\n\n## Backends\n\nP1 ships the **markdown** backend only, behind a narrow `Store` interface so additional backends slot in without touching the CLI layer.\n\n| Backend                | Status  |\n| ---------------------- | ------- |\n| markdown               | shipped |\n| sqlite                 | planned |\n| github / jira / linear | planned |\n\n## Development\n\nThe packaged CLI runs on Node 20+. Building from source requires Node 22.13+ because this repository pins pnpm 11.\n\n```sh\npnpm install --frozen-lockfile\npnpm build         # tsc -> dist/\npnpm test          # vitest\npnpm lint          # eslint\npnpm run build:skill -- --check   # fail if the generated skill is stale\n```\n\nThe installable skill is generated from the same description and help the CLI prints, so it can never drift.\n\n## Contributing\n\nContributions are welcome.\nHuman-authored changes targeting `main` go through the [`no-mistakes`](https://github.com/kunchenguid/no-mistakes) gate, which runs local review, test, documentation, and lint gates before opening a GitLab merge request; remote CI runs only when configured.\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for the full workflow and repo conventions.\n\n## License\n\n[MIT](LICENSE) © Kun Chen\n","readmeFilename":"README.md","_rev":"1-84c7f68d66545271ff73497f58476ebb"}