Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 29 additions & 28 deletions .github/workflows/no-mistakes-required.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@ run-name: "PR #${{ github.event.pull_request.number }} body compliance - ${{ git

on:
pull_request:
types: [opened, edited, synchronize, reopened]
# The verdict is a pure function of pull_request.body, so a push carries no
# new body to judge but does move the head SHA. The pipeline pushes before
# it writes the deterministic Pipeline section, so a synchronize trigger
# pinned a FAILURE check run to the new head for a body the same run was
# about to fix. GitHub keeps that failure next to the later edited SUCCESS,
# and gh pr checks collapses same-named check runs by startedAt alone, so the
# CI monitor could park the run red forever (PR #773).
types: [opened, edited, reopened]
branches:
- main
# Never create a run for a release-please PR. The job-level author exemption
Expand All @@ -20,7 +27,7 @@ permissions:
# GitHub concurrency groups retain at most one pending run, replacing older
# pending runs even when cancel-in-progress is false. Give body-bearing events
# an immutable per-event group so first-time-fork approvals can never collapse
# opened/edited checks. Keep synchronize/reopened coalescing as before.
# opened/edited checks. Keep reopened coalescing as before.
concurrency:
group: no-mistakes-required-${{ github.event.pull_request.number }}-${{ (github.event.action == 'opened' || github.event.action == 'edited') && github.run_id || 'head-change' }}
cancel-in-progress: true
Expand All @@ -29,34 +36,28 @@ jobs:
check:
name: PR must be raised via no-mistakes
runs-on: ubuntu-latest
# Known automation accounts are exempt so automation keeps working:
# - github-actions[bot] opens PRs via GITHUB_TOKEN
# - dependabot[bot] opens dependency update PRs
# - release-please[bot] opens release PRs
# Other authors (human or bot) must raise PRs through `git push no-mistakes`.
#
# These stay job-level rather than moving to the action's `exempt-authors`
# input on purpose: an in-job exemption still requires the run to start, and
# a GITHUB_TOKEN PR's run is created in action_required and never starts.
# Keeping the condition here preserves the exact verdict shape this
# repository's gate already produces for those authors.
if: >-
github.event.pull_request.user.login != 'github-actions[bot]' &&
github.event.pull_request.user.login != 'dependabot[bot]' &&
github.event.pull_request.user.login != 'release-please[bot]'
steps:
- name: Verify no-mistakes signature in PR body
env:
PR_BODY: ${{ github.event.pull_request.body }}
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
set -eu
marker='Updates from [git push no-mistakes](https://github.com/kunchenguid/no-mistakes)'
if printf '%s' "${PR_BODY:-}" | grep -qF -- "$marker"; then
echo "Found no-mistakes signature in PR #${PR_NUMBER} body."
exit 0
fi
{
echo "::error::This PR was not raised through no-mistakes."
echo
echo "Contributions to this repository must be submitted via 'git push no-mistakes'."
echo "That pipeline runs the required review/test/lint/CI steps and writes a"
echo "deterministic '## Pipeline' section into the PR body containing:"
echo
echo " $marker"
echo
echo "See CONTRIBUTING.md for setup and the full workflow."
echo
echo "PR author: ${PR_AUTHOR}"
} >&2
exit 1
# The enforcement itself now lives in the shared composite action in the
# no-mistakes repository, so this repository no longer carries its own
# copy of the script to drift.
#
# Pinned to an immutable commit, never @main: main is editable by the very
# pull request this gate is judging. Bumping the pin is a separate,
# deliberate pull request.
- name: Verify no-mistakes signature and pipeline attestation in PR body
uses: kunchenguid/no-mistakes/.github/actions/require-no-mistakes@32d396ac0f29135daf7fcb9964aba9d5f4e796d6 # post-v1.57.1, untagged (action added in #819)
8 changes: 5 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ The CLI layer never knows which backend is active — it only talks to the `Stor
- `src/backends/markdown*.ts` — the only P1 backend.
- `src/public-followup.ts` - authoritative versioned schema, strict privacy-safe validation, canonical encoding, immutable-field checks, relation/event readiness, and terminal-state invariants for `kind=public-followup`; `src/commands/public-followup.ts` owns its dedicated CLI state machine.
- `src/commands/*` — one file per verb group; `src/view.ts` owns the read-side TOON projection; `src/confirm.ts` owns the write-side output (the `ok:` confirmation line, the `--json` payload, and `renderMutation`, which assembles both).
- Shared helpers copied from the family: `args.ts`, `body.ts`, `format.ts`, `fields.ts`, `toon.ts`, `suggestions.ts`, `skill.ts`.
- Shared helpers copied from the family: `args.ts`, `body.ts`, `format.ts`, `fields.ts`, `toon.ts`, `suggestions.ts`, `skill.ts` (minimal CLI-deferring stub generator).

## Markdown grammar invariants (the hard part — do not regress)

Expand Down Expand Up @@ -76,8 +76,8 @@ Any argv shape other than exactly one version flag falls through to `runAxiCli`,

## Build / test / ship

- `pnpm build` (tsc), `pnpm test` (vitest, `test/` mirrors `src/`), `pnpm lint` (eslint), `pnpm run build:skill -- --check` (the generated `skills/tasks-axi/SKILL.md` is built from `DESCRIPTION` + `TOP_HELP` and must not drift — CI runs the check).
- `skills/tasks-axi/SKILL.md` is generated — regenerate with `pnpm run build:skill` after changing the description or top-level help; never hand-edit it.
- `pnpm build` (tsc), `pnpm test` (vitest, `test/` mirrors `src/`), `pnpm lint` (eslint), `pnpm run build:skill -- --check` (CI fails if `skills/tasks-axi/SKILL.md` drifts from `src/skill.ts`).
- The shipped skill stays **minimal** and **defers to the CLI** for all actual guidance. Frontmatter (name/description/metadata) is the discovery surface; the body only says what tasks-axi is, when to reach for it, and pointers to `npx -y tasks-axi` (dashboard), `npx -y tasks-axi --help`, and `npx -y tasks-axi <command> --help`. tasks-axi CLI output is the single source of truth. Never re-duplicate CLI-owned commands, flags, or workflow steps into the skill - prefer a pointer. Never hand-edit `skills/tasks-axi/SKILL.md`; regenerate with `pnpm run build:skill`.
- This repo is no-mistakes-gated; ship through `/no-mistakes`.

### Release & packaging (mirrors the `*-axi` siblings)
Expand All @@ -89,6 +89,8 @@ Any argv shape other than exactly one version flag falls through to `runAxiCli`,
In a fresh clone, run `pnpm install --frozen-lockfile` before manual pack or publish.
Verify with `npm pack --dry-run` (no source/test cruft; bin is `dist/bin/tasks-axi.js` with its shebang preserved by tsc).
- **CI is a 3-OS matrix** (ubuntu/macos/windows) running install → build → lint → test → `build:skill --check`. The `Require no-mistakes` and `Guard generated files` checks gate every PR to `main`.
- **The `Require no-mistakes` gate is a thin caller of a shared composite action.** `.github/workflows/no-mistakes-required.yml` delegates enforcement to `kunchenguid/no-mistakes/.github/actions/require-no-mistakes`, pinned to an immutable commit SHA and never `@main` (main is editable by the very PR the gate judges). Enforcement logic and its tests live upstream in the no-mistakes repo - change enforcement there rather than hand-copying a script between siblings, and bump this repo's pin in a deliberate separate PR. This repo still owns its `on:`, `paths-ignore`, `concurrency`, `permissions`, job name, and author-exemption `if:`.
- The shared action binds the attestation to the PR's current head, so a PR whose body no-mistakes did not rewrite for that head goes red. That is the attestation contract, not a flake: push through `git push no-mistakes` so the body is refreshed. `on.pull_request.types` deliberately omits `synchronize` - the verdict is a pure function of the PR body, and a push-triggered run pins a failure to a head whose body the same pipeline run is about to fix.

## Follow-ups (out of P1 scope)

Expand Down
1 change: 0 additions & 1 deletion CLAUDE.md

This file was deleted.

2 changes: 2 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<!-- Points Claude at AGENTS.md via import; edit AGENTS.md, not this file. -->
@AGENTS.md
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ See the [no-mistakes quick start](https://kunchenguid.github.io/no-mistakes/star
- Run the full gate before pushing: `pnpm build && pnpm lint && pnpm test && pnpm run build:skill -- --check`.
- The CLI layer only talks to the `Store` interface; backends slot in behind it without touching command code.
- Do not hand-edit `CHANGELOG.md` or `.release-please-manifest.json` - release-please owns them.
- Do not hand-edit `skills/tasks-axi/SKILL.md` - it is generated from the CLI's own description and help by `pnpm run build:skill`. Regenerate and commit it after changing the description or top-level help; CI fails if it is stale.
- Do not hand-edit `skills/tasks-axi/SKILL.md` - it is generated from `src/skill.ts`. After changing the generator or shared description, run `pnpm run build:skill` and commit the result; CI fails if it is stale.

## Release and Packaging

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ pnpm lint # eslint
pnpm run build:skill -- --check # fail if the generated skill is stale
```

The installable skill is generated from the same description and help the CLI prints, so it can never drift.
The generated installable skill is intentionally minimal and points agents to the live CLI for all commands, flags, and workflows. CLI output remains the single source of truth.

## Contributing

Expand Down
4 changes: 2 additions & 2 deletions scripts/build-skill.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Generates skills/tasks-axi/SKILL.md from the shared CLI guidance so the
// installable skill never drifts from what `tasks-axi` prints.
// Generates skills/tasks-axi/SKILL.md as a minimal stub that defers to the
// live CLI for all actual guidance (see src/skill.ts).
//
// pnpm run build:skill # write the file
// pnpm run build:skill -- --check # fail (exit 1) if the committed file is stale
Expand Down
44 changes: 5 additions & 39 deletions skills/tasks-axi/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,48 +13,14 @@ metadata:

Agent ergonomic task & backlog manager for the current workspace. Prefer this over hand-editing backlog.md for task state, dependency, or hold changes.

You do not need tasks-axi installed globally - invoke it with `npx -y tasks-axi <command>`.
If tasks-axi output shows a follow-up command starting with `tasks-axi`, run it as `npx -y tasks-axi ...` instead.

tasks-axi operates on a hand-editable `backlog.md` in the current workspace (or the path set in `.tasks.toml`). It edits the file in place with a byte-exact round-trip, so the human-readable backlog stays the source of truth.

## When to use

Use tasks-axi whenever a task touches the backlog: filing or dispatching work, moving a task through queued -> in flight -> done, recording a PR url or report path on completion, tracking blocked-by dependencies, pausing dispatch with structured holds, finding dispatchable ready work or intentionally held work, or trimming the Done list.

## Workflow

1. Run `npx -y tasks-axi` with no arguments for a dashboard of the current backlog - in flight work, queued work with blockers, and suggested next commands.
2. Drill in verb-first: `list`, `show <id>`, `ready`, then mutate with `add`, `start`, `done`, `block`/`unblock`, `hold`/`unhold`, `update`.
3. The long notes never appear in `list`; run `show <id> --full` to read a task's complete body before replacing it.
4. `add` takes a caller-supplied id (the join key), e.g. `tasks-axi add fm-x "title" --kind ship --repo firstmate --start`; or pass `--mint` to generate a slug-xx id from the title.
5. `done <id> --pr <url>` (or `--report <path>`) closes a task, records the link, and prunes the Done list (archived, never deleted). Then `ready` shows work it unblocked.
6. `hold <id> --reason "<text>"` pauses dispatch without prose parsing; `ready` excludes active holds by default, and `ready --include-held` shows a separate held group.
Use `--until YYYY-MM-DD` for a date gate that becomes inactive on and after that date.
7. Human-readable responses include contextual next-step hints under `help:` when there is a useful follow-up - follow them.
8. `--json` mutation responses skip `help:` and return the deterministic result object instead.

## Commands

```
commands[19]:
(none)=dashboard, add, list, show, start, done, reopen, update, rm, block, unblock, hold, unhold, ready, public-followup, mv, prune, render, setup
```

Run `npx -y tasks-axi --help` for global flags, or `npx -y tasks-axi <command> --help` for per-command usage.
Get every command, flag, and workflow from the live CLI - it is the single source of truth:

## Tips
- `npx -y tasks-axi` - dashboard of the current backlog
- `npx -y tasks-axi --help` - global usage
- `npx -y tasks-axi <command> --help` - per-command usage

- Output is TOON-encoded and token-efficient; the long task body is truncated by default - the whole point is that `list` stays cheap.
Use `--full` only when you need the complete notes.
- Every write leads with an `ok:` line confirming the write result, including the resulting task state when the command changes one (e.g. `ok: start <id> -> In flight`, `ok: done <id> -> Done (pr <url>)`, `ok: render -> normalized <n>`), then state-aware next-step hints.
Mutations are idempotent and add `already: true` on a no-op; re-running is safe.
- Pass `--json` to any mutation (`add`, `start`, `done`, `reopen`, `update`, `rm`, `block`, `unblock`, `hold`, `unhold`, `mv`, `prune`, `render`) for a machine-readable result object (`{ "ok": true, "action": ..., "task": { ... } }` or operation-specific result fields) instead of TOON - confirm a write deterministically without a follow-up read.
- `block <id> --by <other>` and `unblock` manage the dependency graph; `hold <id> --reason "<text>" [--until YYYY-MM-DD]` and `unhold` manage structured dispatch pauses; `ready` lists only queued work with no unresolved blocker and no active hold.
- Filter `list` with `--state`, `--repo`, `--kind`, `--blocked`, `--limit`, and add columns with `--fields a,b,c`.
Use `list --state held` or `--fields held,hold_reason,hold_kind,hold_until` when scanning active hold state.
- Existing prose markers such as `HELD`, `PARKED`, `DEFERRED`, `CAPTAIN-DECISION`, and `do not dispatch` stay prose until intentionally migrated.
Preserve the original prose as the hold reason, then choose `captain`, `parked`, `future`, `load`, or `external` only when the text supports that bucket.
- Note writes are inspect-then-update: run `show <id> --full`, then replace the curated current body with `update <id> --body "<text>"` or `--body-file <path>`.
Add `--archive-body` to preserve the superseded body in `note-archive.md`; `--title "<text>"` replaces the title; `render` normalizes the file; `mv <id> [<id>...] --to <path>` moves one or more tasks to another backlog in one atomic transaction - pass a whole connected set (a blocker and its dependents) to move it together and preserve its `blocked-by` links and reason strings; moves that would strand an endpoint are refused.
- Free-form (no-id) backlog lines are preserved verbatim and are never modified.
You do not need tasks-axi installed globally. If the CLI prints a follow-up starting with `tasks-axi`, run it as `npx -y tasks-axi ...` instead.
Loading
Loading