summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-04-08 09:58:02 +0300
committerPaul Buetow <paul@buetow.org>2026-04-08 09:58:02 +0300
commit8e351c86502cea78f1f0b3aa19cde7ca702bacab (patch)
tree1340e27219255b0ebe49bdbe3b5c2fbd95df8810
parent9e8f558a1f6fcdb09a8a02dfcd2e3d8fc9ce613f (diff)
Rename task CLI from ask to do
- Move cmd/ask to cmd/do; mage BuildDo builds binary named do - Update askcli help text, errors, Fish completion (complete -c do, __do_*) - Task alias cache path: XDG cache hexai/do/task-aliases-v2.json - Refresh README and docs; go install path cmd/do@latest - Remove accidentally tracked cmd/ask build artifact; ignore cmd/do/do and cmd/do/ask Made-with: Cursor
-rw-r--r--.gitignore4
-rw-r--r--Magefile.go12
-rw-r--r--README.md6
-rwxr-xr-xcmd/ask/askbin4322459 -> 0 bytes
-rw-r--r--cmd/do/main.go (renamed from cmd/ask/main.go)0
-rw-r--r--cmd/do/main_test.go (renamed from cmd/ask/main_test.go)0
-rw-r--r--docs/buildandinstall.md6
-rw-r--r--docs/fish-completion.md22
-rw-r--r--docs/plan-ask-uuid-wrapper.md108
-rw-r--r--docs/usage.md84
-rw-r--r--integrationtests/do_scope_test.go (renamed from integrationtests/ask_scope_test.go)54
-rw-r--r--integrationtests/do_test.go (renamed from integrationtests/ask_test.go)156
-rw-r--r--internal/askcli/command_add.go8
-rw-r--r--internal/askcli/command_delete.go2
-rw-r--r--internal/askcli/command_dep.go8
-rw-r--r--internal/askcli/command_fish.go4
-rw-r--r--internal/askcli/command_info_add_test.go2
-rw-r--r--internal/askcli/command_write.go16
-rw-r--r--internal/askcli/completion.go92
-rw-r--r--internal/askcli/completion_test.go42
-rw-r--r--internal/askcli/dispatch.go50
-rw-r--r--internal/askcli/dispatch_test.go16
-rw-r--r--internal/askcli/formatter.go2
-rw-r--r--internal/askcli/task_alias_cache.go2
-rw-r--r--internal/askcli/taskexec.go6
-rw-r--r--internal/askcli/taskexec_test.go22
-rw-r--r--internal/taskproxy/run_test.go12
27 files changed, 369 insertions, 367 deletions
diff --git a/.gitignore b/.gitignore
index 90b1ee1..49978b8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,6 @@
-/ask
+/do
+/cmd/do/do
+/cmd/do/ask
/hexai
/hexai-lsp-server
/hexai-mcp-server
diff --git a/Magefile.go b/Magefile.go
index 65748fd..fb19689 100644
--- a/Magefile.go
+++ b/Magefile.go
@@ -25,15 +25,15 @@ var (
// Build builds binaries.
func Build() error {
- mg.Deps(BuildAsk, BuildHexaiLSP, BuildHexaiCLI, BuildHexaiTmuxAction, BuildHexaiTmuxEdit, BuildHexaiMCPServer)
+ mg.Deps(BuildDo, BuildHexaiLSP, BuildHexaiCLI, BuildHexaiTmuxAction, BuildHexaiTmuxEdit, BuildHexaiMCPServer)
printCoverage()
return nil
}
-// BuildAsk builds the Taskwarrior proxy wrapper.
-func BuildAsk() error {
+// BuildDo builds the Taskwarrior proxy wrapper.
+func BuildDo() error {
printCoverage()
- return sh.RunV("go", "build", "-o", "ask", "./cmd/ask")
+ return sh.RunV("go", "build", "-o", "do", "./cmd/do")
}
// BuildHexaiLSP builds the LSP server binary.
@@ -70,7 +70,7 @@ func BuildHexaiMCPServer() error {
func Dev() error {
printCoverage()
mg.Deps(Test, Vet, Lint)
- if err := sh.RunV("go", "build", "-race", "-o", "ask", "./cmd/ask"); err != nil {
+ if err := sh.RunV("go", "build", "-race", "-o", "do", "./cmd/do"); err != nil {
return err
}
if err := sh.RunV("go", "build", "-race", "-o", "hexai-lsp-server", "./cmd/hexai-lsp-server"); err != nil {
@@ -120,7 +120,7 @@ func Install() error {
return err
}
for _, name := range []string{
- "ask",
+ "do",
"hexai-lsp-server",
"hexai",
"hexai-tmux-action",
diff --git a/README.md b/README.md
index 510705f..9e46ed5 100644
--- a/README.md
+++ b/README.md
@@ -14,12 +14,12 @@ It has got improved capabilities for Go code understanding (for example, create
* Stand-alone command line tool for LLM interaction
- Includes `--tps-simulation` to preview how fast a model would feel by streaming placeholder text or piped stdin at a chosen token-per-second rate
* Task management CLI for agent-managed project work
- - Entrypoint: `ask`
+ - Entrypoint: `do`
- Auto-scopes to `project:<repo> +agent` (derived from git repo root)
- Never exposes numeric task IDs — uses UUIDs only
- Machine-friendly output: UUID-only tables, suppressed decorative text
- - Subcommands: `ask add`, `ask list`, `ask info`, `ask annotate`, `ask start`, `ask stop`, `ask done`, `ask priority`, `ask tag`, `ask dep`, `ask urgency`, `ask modify`, `ask denotate`, `ask delete`, `ask fish`, `ask help`
- - Fish completion generator: `ask fish`
+ - Subcommands: `do add`, `do list`, `do info`, `do annotate`, `do start`, `do stop`, `do done`, `do priority`, `do tag`, `do dep`, `do urgency`, `do modify`, `do denotate`, `do delete`, `do fish`, `do help`
+ - Fish completion generator: `do fish`
* Parallel completions and CLI responses from multiple providers/models for side-by-side comparison
* **MCP server for prompt/runbook management** (`hexai-mcp-server`) - **⚠️ DEPRECATED/EXPERIMENTAL**
- Create, update, delete, and retrieve prompts via MCP protocol
diff --git a/cmd/ask/ask b/cmd/ask/ask
deleted file mode 100755
index cffc885..0000000
--- a/cmd/ask/ask
+++ /dev/null
Binary files differ
diff --git a/cmd/ask/main.go b/cmd/do/main.go
index afab992..afab992 100644
--- a/cmd/ask/main.go
+++ b/cmd/do/main.go
diff --git a/cmd/ask/main_test.go b/cmd/do/main_test.go
index db6b436..db6b436 100644
--- a/cmd/ask/main_test.go
+++ b/cmd/do/main_test.go
diff --git a/docs/buildandinstall.md b/docs/buildandinstall.md
index a707faa..abca741 100644
--- a/docs/buildandinstall.md
+++ b/docs/buildandinstall.md
@@ -3,7 +3,7 @@
Hexai uses Mage for developer tasks. Install Mage, then run targets like build, dev, test, and install.
- Install Mage: `go install github.com/magefile/mage@latest`
-- Build binaries: `mage build` (produces `ask`, `hexai`, `hexai-lsp-server`, `hexai-tmux-action`, and `hexai-tmux-edit`)
+- Build binaries: `mage build` (produces `do`, `hexai`, `hexai-lsp-server`, `hexai-tmux-action`, and `hexai-tmux-edit`)
- Dev build (+ tests, vet, lint): `mage dev`
- Run tests: `mage test`
- Run tests with coverage: `go test ./... -cover`
@@ -11,7 +11,7 @@ Hexai uses Mage for developer tasks. Install Mage, then run targets like build,
- In restricted sandboxes/CI (no sockets), skip network-based tests:
- `HEXAI_TEST_SKIP_NET=1 go test ./... -cover`
- Install binaries to `GOPATH/bin`: `mage install`
-- Load Fish completions in the current shell: `~/go/bin/ask fish | source`
+- Load Fish completions in the current shell: `~/go/bin/do fish | source`
Note: `mage lint` uses `golangci-lint`. Install via `mage devinstall` if needed.
@@ -19,7 +19,7 @@ Note: `mage lint` uses `golangci-lint`. Install via `mage devinstall` if needed.
Either use the Mage method as mentioned above, or install directly with:
-- Taskwarrior proxy: `go install codeberg.org/snonux/hexai/cmd/ask@latest`
+- Taskwarrior proxy: `go install codeberg.org/snonux/hexai/cmd/do@latest`
- CLI: `go install codeberg.org/snonux/hexai/cmd/hexai@latest`
- LSP: `go install codeberg.org/snonux/hexai/cmd/hexai-lsp-server@latest`
- Action runner: `go install codeberg.org/snonux/hexai/cmd/hexai-tmux-action@latest`
diff --git a/docs/fish-completion.md b/docs/fish-completion.md
index d707b77..f55e4cf 100644
--- a/docs/fish-completion.md
+++ b/docs/fish-completion.md
@@ -1,34 +1,34 @@
# Fish Completion
-The `ask` task-management CLI embeds its Fish completion script in the binary and prints it with `ask fish`.
+The `do` task-management CLI embeds its Fish completion script in the binary and prints it with `do fish`.
-It completes the top-level `ask` subcommands and the nested `ask dep` operations.
-It also completes task selectors for UUID-taking commands by reading pending tasks through `ask complete-uuids`, which uses the local alias cache for stable short IDs.
+It completes the top-level `do` subcommands and the nested `do dep` operations.
+It also completes task selectors for UUID-taking commands by reading pending tasks through `do complete-uuids`, which uses the local alias cache for stable short IDs.
Fish suggests each task's alias ID first and also keeps the raw UUID available as a fallback selector.
-Selector suggestions stop once a command has consumed its selector argument, and `ask dep add` / `ask dep rm` suggest selectors for both task positions.
-When typing `ask add depends:...`, Fish also completes the comma-separated dependency selector list inside the `depends:` modifier.
+Selector suggestions stop once a command has consumed its selector argument, and `do dep add` / `do dep rm` suggest selectors for both task positions.
+When typing `do add depends:...`, Fish also completes the comma-separated dependency selector list inside the `depends:` modifier.
The script preserves the global `--json` flag.
Load it into the current Fish session:
```sh
-ask fish | source
+do fish | source
```
If you installed with `mage install` and `~/go/bin` is not on your `PATH` yet, use:
```sh
-~/go/bin/ask fish | source
+~/go/bin/do fish | source
```
To enable it automatically for new Fish sessions, add this to your Fish config or a file in `~/.config/fish/conf.d/`:
```fish
-set -l ask_bin ~/go/bin/ask
+set -l do_bin ~/go/bin/do
-if test -x $ask_bin
- $ask_bin fish | source
+if test -x $do_bin
+ $do_bin fish | source
end
```
-No external `ask.fish` file is required.
+No external `do.fish` file is required.
diff --git a/docs/plan-ask-uuid-wrapper.md b/docs/plan-ask-uuid-wrapper.md
index dcaf44c..31d719b 100644
--- a/docs/plan-ask-uuid-wrapper.md
+++ b/docs/plan-ask-uuid-wrapper.md
@@ -1,8 +1,8 @@
-# Plan: `ask` as UUID-only Taskwarrior Wrapper
+# Plan: `do` as UUID-only Taskwarrior Wrapper
## Goal
-Rewrite the `ask` command from a thin pass-through proxy into a **subcommand-based CLI** that wraps Taskwarrior. The wrapper never exposes numeric task IDs to the caller — only UUIDs. Output is minimal and machine-friendly for coding agents.
+Rewrite the `do` command from a thin pass-through proxy into a **subcommand-based CLI** that wraps Taskwarrior. The wrapper never exposes numeric task IDs to the caller — only UUIDs. Output is minimal and machine-friendly for coding agents.
The existing `project:<repo> +agent` auto-injection is preserved.
@@ -10,39 +10,39 @@ The existing `project:<repo> +agent` auto-injection is preserved.
| Subcommand | Example | Taskwarrior equivalent |
|---|---|---|
-| `ask add "Implement X"` | create task | `task project:P +agent add "Implement X"` |
-| `ask add priority:H +cli "Fix bug"` | create with priority & tag | same + `priority:H +cli` |
-| `ask list` | list pending tasks | `task project:P +agent status:pending export` → reformat |
-| `ask info <uuid>` | show one task | `task uuid:<uuid> export` → filtered fields |
-| `ask annotate <uuid> "note"` | add annotation | `task uuid:<uuid> annotate "note"` |
-| `ask start <uuid>` | start work | `task uuid:<uuid> start` |
-| `ask stop <uuid>` | stop work | `task uuid:<uuid> stop` |
-| `ask done <uuid>` | mark complete | `task uuid:<uuid> done` |
-| `ask priority <uuid> H` | set priority | `task uuid:<uuid> modify priority:H` |
-| `ask tag <uuid> +foo` | add tag | `task uuid:<uuid> modify +foo` |
-| `ask tag <uuid> -foo` | remove tag | `task uuid:<uuid> modify -foo` |
-| `ask dep add <uuid> <dep-uuid>` | add dependency | `task uuid:<uuid> modify depends:<dep-uuid>` |
-| `ask dep rm <uuid> <dep-uuid>` | remove dependency | `task uuid:<uuid> modify depends:-<dep-uuid>` |
-| `ask dep list <uuid>` | show dependencies | `task uuid:<uuid> export` → `depends` field |
-| `ask urgency` | list by urgency | `task project:P +agent export` → sort by urgency |
-| `ask modify <uuid> <args...>` | general modify | `task uuid:<uuid> modify <args...>` (priority, tags, depends, /old/new/) |
-| `ask denotate <uuid> "text"` | remove annotation | `task uuid:<uuid> denotate "text"` |
-| `ask delete <uuid>` | delete task | `task uuid:<uuid> delete` |
-| `ask export` | raw JSON dump | `task project:P +agent export` → pass through |
+| `do add "Implement X"` | create task | `task project:P +agent add "Implement X"` |
+| `do add priority:H +cli "Fix bug"` | create with priority & tag | same + `priority:H +cli` |
+| `do list` | list pending tasks | `task project:P +agent status:pending export` → reformat |
+| `do info <uuid>` | show one task | `task uuid:<uuid> export` → filtered fields |
+| `do annotate <uuid> "note"` | add annotation | `task uuid:<uuid> annotate "note"` |
+| `do start <uuid>` | start work | `task uuid:<uuid> start` |
+| `do stop <uuid>` | stop work | `task uuid:<uuid> stop` |
+| `do done <uuid>` | mark complete | `task uuid:<uuid> done` |
+| `do priority <uuid> H` | set priority | `task uuid:<uuid> modify priority:H` |
+| `do tag <uuid> +foo` | add tag | `task uuid:<uuid> modify +foo` |
+| `do tag <uuid> -foo` | remove tag | `task uuid:<uuid> modify -foo` |
+| `do dep add <uuid> <dep-uuid>` | add dependency | `task uuid:<uuid> modify depends:<dep-uuid>` |
+| `do dep rm <uuid> <dep-uuid>` | remove dependency | `task uuid:<uuid> modify depends:-<dep-uuid>` |
+| `do dep list <uuid>` | show dependencies | `task uuid:<uuid> export` → `depends` field |
+| `do urgency` | list by urgency | `task project:P +agent export` → sort by urgency |
+| `do modify <uuid> <args...>` | general modify | `task uuid:<uuid> modify <args...>` (priority, tags, depends, /old/new/) |
+| `do denotate <uuid> "text"` | remove annotation | `task uuid:<uuid> denotate "text"` |
+| `do delete <uuid>` | delete task | `task uuid:<uuid> delete` |
+| `do export` | raw JSON dump | `task project:P +agent export` → pass through |
### List filters, sort, and limit
-`ask list` accepts optional filters, sort, and limit arguments:
+`do list` accepts optional filters, sort, and limit arguments:
| Example | Taskwarrior equivalent |
|---|---|
-| `ask list` | `task project:P +agent status:pending export` (default sort: priority-, urgency-) |
-| `ask list +READY` | `task project:P +agent +READY export` |
-| `ask list +BLOCKED` | `task project:P +agent +BLOCKED export` |
-| `ask list +frontend` | `task project:P +agent +frontend export` |
-| `ask list started` | `task project:P +agent start.any: export` |
-| `ask list limit:3` | show only first 3 results |
-| `ask list +READY limit:1` | next ready task |
+| `do list` | `task project:P +agent status:pending export` (default sort: priority-, urgency-) |
+| `do list +READY` | `task project:P +agent +READY export` |
+| `do list +BLOCKED` | `task project:P +agent +BLOCKED export` |
+| `do list +frontend` | `task project:P +agent +frontend export` |
+| `do list started` | `task project:P +agent start.any: export` |
+| `do list limit:3` | show only first 3 results |
+| `do list +READY limit:1` | next ready task |
## Data Retrieval: `task export`
@@ -81,7 +81,7 @@ If an argument looks like a bare numeric ID where a UUID is expected, reject wit
## Package Layout
```
-cmd/ask/main.go — parse subcommand, dispatch to askcli
+cmd/do/main.go — parse subcommand, dispatch to askcli
internal/askcli/ — NEW package
├── dispatch.go — subcommand router (switch args[0])
├── taskexec.go — wraps Taskwarrior execution (binary lookup, repo detection, run)
@@ -108,45 +108,45 @@ Each `command_*.go` file gets a corresponding `command_*_test.go`.
## Changes to Existing Code
-- **`cmd/ask/main.go`** — stops calling `taskproxy.Runner.Run` directly; delegates to `askcli.Dispatch()`.
+- **`cmd/do/main.go`** — stops calling `taskproxy.Runner.Run` directly; delegates to `askcli.Dispatch()`.
- **`internal/taskproxy/`** — reused by `askcli/taskexec.go` for binary lookup (`findTaskBinary`) and repo root detection (`detectRepoRoot`). The `Runner.Run` pass-through method becomes unused and can be removed.
## Task Breakdown
1. Scaffold `internal/askcli/` — dispatch, taskexec, taskexport, formatter
-2. Implement `ask add` (UUID extraction from Taskwarrior stdout)
-3. Implement `ask list` (export → UUID-only table)
-4. Implement `ask info <uuid>` (export → filtered fields)
-5. Implement `ask annotate <uuid> "note"`
-6. Implement `ask start <uuid>` / `ask stop <uuid>`
-7. Implement `ask done <uuid>`
-8. Implement `ask priority <uuid> <P>`
-9. Implement `ask tag <uuid> +/-tag`
-10. Implement `ask dep add/rm/list`
-11. Implement `ask urgency`
-12. Implement `ask modify <uuid> <args...>` (general-purpose modify)
-13. Implement `ask denotate <uuid> "text"` (remove annotation)
-14. Implement `ask delete <uuid>`
-15. Implement `ask export` (raw JSON)
-16. Add filter/sort/limit support to `ask list` (+READY, +BLOCKED, +tag, started, limit:N)
-17. Wire `cmd/ask/main.go` to `askcli.Dispatch`, remove old pass-through
+2. Implement `do add` (UUID extraction from Taskwarrior stdout)
+3. Implement `do list` (export → UUID-only table)
+4. Implement `do info <uuid>` (export → filtered fields)
+5. Implement `do annotate <uuid> "note"`
+6. Implement `do start <uuid>` / `do stop <uuid>`
+7. Implement `do done <uuid>`
+8. Implement `do priority <uuid> <P>`
+9. Implement `do tag <uuid> +/-tag`
+10. Implement `do dep add/rm/list`
+11. Implement `do urgency`
+12. Implement `do modify <uuid> <args...>` (general-purpose modify)
+13. Implement `do denotate <uuid> "text"` (remove annotation)
+14. Implement `do delete <uuid>`
+15. Implement `do export` (raw JSON)
+16. Add filter/sort/limit support to `do list` (+READY, +BLOCKED, +tag, started, limit:N)
+17. Wire `cmd/do/main.go` to `askcli.Dispatch`, remove old pass-through
18. Update docs and README
-19. Create `agent-task-management` skill (replacement for `taskwarrior-task-management`) — uses only `ask` subcommands, no Taskwarrior references
-20. Update Pi coding agent: rename `taskwarrior-plan-mode` extension → `agent-plan-mode`, rewrite to use `ask` subcommands only
-21. Audit `agent-task-management` skill and `agent-plan-mode` extension: ensure zero Taskwarrior leakage — agents must see `ask` as the native task system, not a wrapper
+19. Create `agent-task-management` skill (replacement for `taskwarrior-task-management`) — uses only `do` subcommands, no Taskwarrior references
+20. Update Pi coding agent: rename `taskwarrior-plan-mode` extension → `agent-plan-mode`, rewrite to use `do` subcommands only
+21. Audit `agent-task-management` skill and `agent-plan-mode` extension: ensure zero Taskwarrior leakage — agents must see `do` as the native task system, not a wrapper
## Skill & Extension Migration
-After the `ask` CLI is complete and documented, three follow-up tasks abstract away the Taskwarrior implementation detail:
+After the `do` CLI is complete and documented, three follow-up tasks abstract away the Taskwarrior implementation detail:
### 19. `agent-task-management` skill
-Create a new skill at `~/.agents/skills/agent-task-management/` by copying the structure from `taskwarrior-task-management` (SKILL.md + references/00-context.md through 5-review-overview-tasks.md). Rewrite all content to use `ask` subcommands (`ask add`, `ask list`, `ask info`, `ask start`, `ask stop`, `ask done`, `ask annotate`, `ask denotate`, `ask modify`, `ask priority`, `ask tag`, `ask dep`, `ask urgency`, `ask delete`, `ask export`). Remove all mentions of Taskwarrior, raw `task` command, numeric IDs, and `_uuid` lookups.
+Create a new skill at `~/.agents/skills/agent-task-management/` by copying the structure from `taskwarrior-task-management` (SKILL.md + references/00-context.md through 5-review-overview-tasks.md). Rewrite all content to use `do` subcommands (`do add`, `do list`, `do info`, `do start`, `do stop`, `do done`, `do annotate`, `do denotate`, `do modify`, `do priority`, `do tag`, `do dep`, `do urgency`, `do delete`, `do export`). Remove all mentions of Taskwarrior, raw `task` command, numeric IDs, and `_uuid` lookups.
### 20. `agent-plan-mode` Pi extension
-Rename `~/git/hyperstack/pi/agent/extensions/taskwarrior-plan-mode/` → `agent-plan-mode/`. Update `index.ts`, `utils.ts`, `README.md` to use new `ask` subcommands instead of raw pass-through calls. Rename `TaskwarriorTask` type, update state keys, command names, descriptions, and UI messages.
+Rename `~/git/hyperstack/pi/agent/extensions/taskwarrior-plan-mode/` → `agent-plan-mode/`. Update `index.ts`, `utils.ts`, `README.md` to use new `do` subcommands instead of raw pass-through calls. Rename `TaskwarriorTask` type, update state keys, command names, descriptions, and UI messages.
### 21. Taskwarrior leakage audit
-Grep all files in the new skill and extension for `taskwarrior` (any casing), `task warrior`, raw `task ` command patterns, numeric task ID usage, `_uuid` lookups, and any hint that `ask` wraps another tool. **Agents must believe `ask` IS the task management system — not a proxy.** This prevents agents from attempting raw Taskwarrior commands or mentioning Taskwarrior in annotations/descriptions.
+Grep all files in the new skill and extension for `taskwarrior` (any casing), `task warrior`, raw `task ` command patterns, numeric task ID usage, `_uuid` lookups, and any hint that `do` wraps another tool. **Agents must believe `do` IS the task management system — not a proxy.** This prevents agents from attempting raw Taskwarrior commands or mentioning Taskwarrior in annotations/descriptions.
diff --git a/docs/usage.md b/docs/usage.md
index 0786a00..cc78300 100644
--- a/docs/usage.md
+++ b/docs/usage.md
@@ -125,77 +125,77 @@ cat SOMEFILE.txt | hexai --tps-simulation 20
## Task management
-`ask` is a task management CLI for the current git project. By default it auto-scopes to `project:<repo> +agent` so operations are confined to agent-managed project tasks.
+`do` is a task management CLI for the current git project. By default it auto-scopes to `project:<repo> +agent` so operations are confined to agent-managed project tasks.
-Use `ask na <subcommand...>` or `ask no-agent <subcommand...>` to run the same subcommands against project tasks without the `+agent` tag. Those prefixes keep the project scope but replace the default tag filter with `-agent`.
+Use `do na <subcommand...>` or `do no-agent <subcommand...>` to run the same subcommands against project tasks without the `+agent` tag. Those prefixes keep the project scope but replace the default tag filter with `-agent`.
-`ask` never exposes Taskwarrior numeric task IDs. Human-facing output uses stable local alias IDs where practical, while `ask info` shows both the alias ID and the UUID. Commands that accept a task selector support either the alias ID or the UUID.
+`do` never exposes Taskwarrior numeric task IDs. Human-facing output uses stable local alias IDs where practical, while `do info` shows both the alias ID and the UUID. Commands that accept a task selector support either the alias ID or the UUID.
-`ask` must be run inside a git repository so the project name can be derived from the repo root.
+`do` must be run inside a git repository so the project name can be derived from the repo root.
### Subcommands
| Subcommand | Description |
|---|---|
-| `ask add "description"` | Create a new task and print `created task <alias-id>` |
-| `ask add depends:<id\|uuid>,<id\|uuid> "description"` | Create task with inline dependencies |
-| `ask add priority:H "description"` | Create task with priority |
-| `ask add +tag "description"` | Create task with tag |
-| `ask na add "description"` | Create a project task without the `+agent` tag |
-| `ask list` | List pending tasks only (alias-ID table) |
-| `ask na list` | List pending project tasks without the `+agent` tag |
-| `ask all` | List all tasks including completed/deleted |
-| `ask list +READY` | List only ready tasks |
-| `ask list +BLOCKED` | List blocked tasks |
-| `ask list +tag` | Filter by tag |
-| `ask list started` | List started tasks |
-| `ask list limit:N` | Limit results |
-| `ask list sort:priority-,urgency-` | Sort by priority then urgency |
-| `ask info [id\|uuid]` | Show task details, or the current started task if no selector is provided |
-| `ask annotate <id\|uuid> "note"` | Add annotation |
-| `ask start <id\|uuid>` | Start working on a task |
-| `ask stop <id\|uuid>` | Stop work on a task |
-| `ask done <id\|uuid>` | Mark task complete |
-| `ask priority <id\|uuid> H\|M\|L` | Set priority |
-| `ask tag <id\|uuid> +tag` | Add tag |
-| `ask tag <id\|uuid> -tag` | Remove tag |
-| `ask dep add <id\|uuid> <dep-id\|dep-uuid>` | Add dependency |
-| `ask dep rm <id\|uuid> <dep-id\|dep-uuid>` | Remove dependency |
-| `ask dep list <id\|uuid>` | List dependencies |
-| `ask urgency` | List tasks by urgency |
-| `ask modify <id\|uuid> <args...>` | General-purpose modify |
-| `ask denotate <id\|uuid> "text"` | Remove annotation |
-| `ask delete <id\|uuid>` | Delete a task |
+| `do add "description"` | Create a new task and print `created task <alias-id>` |
+| `do add depends:<id\|uuid>,<id\|uuid> "description"` | Create task with inline dependencies |
+| `do add priority:H "description"` | Create task with priority |
+| `do add +tag "description"` | Create task with tag |
+| `do na add "description"` | Create a project task without the `+agent` tag |
+| `do list` | List pending tasks only (alias-ID table) |
+| `do na list` | List pending project tasks without the `+agent` tag |
+| `do all` | List all tasks including completed/deleted |
+| `do list +READY` | List only ready tasks |
+| `do list +BLOCKED` | List blocked tasks |
+| `do list +tag` | Filter by tag |
+| `do list started` | List started tasks |
+| `do list limit:N` | Limit results |
+| `do list sort:priority-,urgency-` | Sort by priority then urgency |
+| `do info [id\|uuid]` | Show task details, or the current started task if no selector is provided |
+| `do annotate <id\|uuid> "note"` | Add annotation |
+| `do start <id\|uuid>` | Start working on a task |
+| `do stop <id\|uuid>` | Stop work on a task |
+| `do done <id\|uuid>` | Mark task complete |
+| `do priority <id\|uuid> H\|M\|L` | Set priority |
+| `do tag <id\|uuid> +tag` | Add tag |
+| `do tag <id\|uuid> -tag` | Remove tag |
+| `do dep add <id\|uuid> <dep-id\|dep-uuid>` | Add dependency |
+| `do dep rm <id\|uuid> <dep-id\|dep-uuid>` | Remove dependency |
+| `do dep list <id\|uuid>` | List dependencies |
+| `do urgency` | List tasks by urgency |
+| `do modify <id\|uuid> <args...>` | General-purpose modify |
+| `do denotate <id\|uuid> "text"` | Remove annotation |
+| `do delete <id\|uuid>` | Delete a task |
### Examples
```sh
# Create a task
-ask add priority:H "Implement new feature"
+do add priority:H "Implement new feature"
# Create a non-agent task
-ask na add "Follow up manually"
+do na add "Follow up manually"
# Create a task with dependencies
-ask add +cli depends:0,1 "Implement dependent feature"
+do add +cli depends:0,1 "Implement dependent feature"
# List tasks
-ask list +READY limit:5
+do list +READY limit:5
# List non-agent tasks
-ask no-agent list
+do no-agent list
# Show alias and UUID for a task
-ask info 0
+do info 0
# Show a non-agent task
-ask na info 0
+do na info 0
# Start working
-ask start 0
+do start 0
# Done
-ask done 0
+do done 0
```
## Hexai Action (TUI)
diff --git a/integrationtests/ask_scope_test.go b/integrationtests/do_scope_test.go
index a328881..f24f5ca 100644
--- a/integrationtests/ask_scope_test.go
+++ b/integrationtests/do_scope_test.go
@@ -13,7 +13,7 @@ import (
"codeberg.org/snonux/hexai/internal/askcli"
)
-func scopedAskArgs(scopePrefix string, args ...string) []string {
+func scopedDoArgs(scopePrefix string, args ...string) []string {
if strings.TrimSpace(scopePrefix) == "" {
return append([]string(nil), args...)
}
@@ -22,28 +22,28 @@ func scopedAskArgs(scopePrefix string, args ...string) []string {
}
func createTaskInScope(ctx context.Context, scopePrefix, desc string) (taskInfo, error) {
- stdout, stderr, code := runAsk(ctx, scopedAskArgs(scopePrefix, "add", "+integrationtest", desc))
+ stdout, stderr, code := runDo(ctx, scopedDoArgs(scopePrefix, "add", "+integrationtest", desc))
if code != 0 {
return taskInfo{}, fmt.Errorf("create task failed (code %d): stdout=%s stderr=%s", code, stdout.String(), stderr.String())
}
id := extractTaskIDFromAddOutput(stdout.String())
if id == "" {
- return taskInfo{}, fmt.Errorf("could not extract task ID from ask add output: %s", stdout.String())
+ return taskInfo{}, fmt.Errorf("could not extract task ID from do add output: %s", stdout.String())
}
info, ok := getTaskInfoInScope(ctx, scopePrefix, id)
if !ok {
- return taskInfo{}, fmt.Errorf("could not resolve task ID %q after ask %s add", id, scopePrefix)
+ return taskInfo{}, fmt.Errorf("could not resolve task ID %q after do %s add", id, scopePrefix)
}
if info.UUID == "" {
- return taskInfo{}, fmt.Errorf("ask %s info %q did not return a UUID", scopePrefix, id)
+ return taskInfo{}, fmt.Errorf("do %s info %q did not return a UUID", scopePrefix, id)
}
return info, nil
}
func getTaskInfoInScope(ctx context.Context, scopePrefix, selector string) (taskInfo, bool) {
- stdout, _, code := runAsk(ctx, scopedAskArgs(scopePrefix, "info", selector))
+ stdout, _, code := runDo(ctx, scopedDoArgs(scopePrefix, "info", selector))
if code != 0 {
return taskInfo{}, false
}
@@ -143,28 +143,28 @@ func TestNoAgentListSeparatesScopedTasks(t *testing.T) {
}
defer deleteTask(ctx, noAgentInfo.UUID)
- stdout, stderr, code := runAsk(ctx, []string{"list"})
+ stdout, stderr, code := runDo(ctx, []string{"list"})
if code != 0 {
- t.Fatalf("ask list failed with code %d: stdout=%s stderr=%s", code, stdout.String(), stderr.String())
+ t.Fatalf("do list failed with code %d: stdout=%s stderr=%s", code, stdout.String(), stderr.String())
}
if !strings.Contains(stdout.String(), agentDesc) {
- t.Fatalf("ask list should contain agent task %q: %s", agentDesc, stdout.String())
+ t.Fatalf("do list should contain agent task %q: %s", agentDesc, stdout.String())
}
if strings.Contains(stdout.String(), noAgentDesc) {
- t.Fatalf("ask list should not contain no-agent task %q: %s", noAgentDesc, stdout.String())
+ t.Fatalf("do list should not contain no-agent task %q: %s", noAgentDesc, stdout.String())
}
for _, prefix := range []string{"na", "no-agent"} {
t.Run(prefix, func(t *testing.T) {
- scopedStdout, scopedStderr, scopedCode := runAsk(ctx, []string{prefix, "list"})
+ scopedStdout, scopedStderr, scopedCode := runDo(ctx, []string{prefix, "list"})
if scopedCode != 0 {
- t.Fatalf("ask %s list failed with code %d: stdout=%s stderr=%s", prefix, scopedCode, scopedStdout.String(), scopedStderr.String())
+ t.Fatalf("do %s list failed with code %d: stdout=%s stderr=%s", prefix, scopedCode, scopedStdout.String(), scopedStderr.String())
}
if !strings.Contains(scopedStdout.String(), noAgentDesc) {
- t.Fatalf("ask %s list should contain no-agent task %q: %s", prefix, noAgentDesc, scopedStdout.String())
+ t.Fatalf("do %s list should contain no-agent task %q: %s", prefix, noAgentDesc, scopedStdout.String())
}
if strings.Contains(scopedStdout.String(), agentDesc) {
- t.Fatalf("ask %s list should not contain agent task %q: %s", prefix, agentDesc, scopedStdout.String())
+ t.Fatalf("do %s list should not contain agent task %q: %s", prefix, agentDesc, scopedStdout.String())
}
})
}
@@ -182,9 +182,9 @@ func TestNoAgentSelectorCommandsUseScopedTasks(t *testing.T) {
}
defer deleteTask(ctx, info.UUID)
- _, stderr, code := runAsk(ctx, []string{"info", info.ID})
+ _, stderr, code := runDo(ctx, []string{"info", info.ID})
if code == 0 {
- t.Fatalf("ask info %s unexpectedly succeeded outside no-agent scope", info.ID)
+ t.Fatalf("do info %s unexpectedly succeeded outside no-agent scope", info.ID)
}
if !strings.Contains(stderr.String(), "current scope") {
t.Fatalf("stderr = %q, want current-scope guidance", stderr.String())
@@ -192,19 +192,19 @@ func TestNoAgentSelectorCommandsUseScopedTasks(t *testing.T) {
for _, prefix := range []string{"na", "no-agent"} {
t.Run(prefix, func(t *testing.T) {
- stdout, scopedStderr, scopedCode := runAsk(ctx, []string{prefix, "info", info.ID})
+ stdout, scopedStderr, scopedCode := runDo(ctx, []string{prefix, "info", info.ID})
if scopedCode != 0 {
- t.Fatalf("ask %s info failed with code %d: stdout=%s stderr=%s", prefix, scopedCode, stdout.String(), scopedStderr.String())
+ t.Fatalf("do %s info failed with code %d: stdout=%s stderr=%s", prefix, scopedCode, stdout.String(), scopedStderr.String())
}
if !strings.Contains(stdout.String(), "UUID: "+info.UUID) {
- t.Fatalf("ask %s info output missing UUID %q: %s", prefix, info.UUID, stdout.String())
+ t.Fatalf("do %s info output missing UUID %q: %s", prefix, info.UUID, stdout.String())
}
})
}
- stdout, stderr, code := runAsk(ctx, []string{"na", "done", info.ID})
+ stdout, stderr, code := runDo(ctx, []string{"na", "done", info.ID})
if code != 0 {
- t.Fatalf("ask na done failed with code %d: stdout=%s stderr=%s", code, stdout.String(), stderr.String())
+ t.Fatalf("do na done failed with code %d: stdout=%s stderr=%s", code, stdout.String(), stderr.String())
}
task, err := exportTaskByUUID(ctx, info.UUID)
@@ -234,9 +234,9 @@ func TestNoAgentCompleteUUIDsUsesScopedTasks(t *testing.T) {
}
defer deleteTask(ctx, noAgentInfo.UUID)
- defaultStdout, defaultStderr, defaultCode := runAsk(ctx, []string{"complete-uuids"})
+ defaultStdout, defaultStderr, defaultCode := runDo(ctx, []string{"complete-uuids"})
if defaultCode != 0 {
- t.Fatalf("ask complete-uuids failed with code %d: stdout=%s stderr=%s", defaultCode, defaultStdout.String(), defaultStderr.String())
+ t.Fatalf("do complete-uuids failed with code %d: stdout=%s stderr=%s", defaultCode, defaultStdout.String(), defaultStderr.String())
}
if !hasSelectorLine(defaultStdout.String(), agentAlias) || !hasSelectorLine(defaultStdout.String(), agentUUID) {
t.Fatalf("default complete-uuids should contain agent selectors: %s", defaultStdout.String())
@@ -247,15 +247,15 @@ func TestNoAgentCompleteUUIDsUsesScopedTasks(t *testing.T) {
for _, prefix := range []string{"na", "no-agent"} {
t.Run(prefix, func(t *testing.T) {
- stdout, stderr, code := runAsk(ctx, []string{prefix, "complete-uuids"})
+ stdout, stderr, code := runDo(ctx, []string{prefix, "complete-uuids"})
if code != 0 {
- t.Fatalf("ask %s complete-uuids failed with code %d: stdout=%s stderr=%s", prefix, code, stdout.String(), stderr.String())
+ t.Fatalf("do %s complete-uuids failed with code %d: stdout=%s stderr=%s", prefix, code, stdout.String(),