Skip to content

feat(witan): free-text search for witan projects and witan tasks - #362

Merged
blarghmatey merged 5 commits into
mainfrom
witan-cli-list-search
Sep 18, 2026
Merged

blarghmatey merged 5 commits into
mainfrom
witan-cli-list-search

Conversation

@blarghmatey

Copy link
Copy Markdown
Member

What are the relevant tickets?

N/A

Description (What does it do?)

Finding a project or task from the CLI meant paging through the whole list, even though the server already exposes BM25 search as workflow_project_search and task_search. This adds an optional positional query to both listing commands, e.g. witan projects gravitino or witan tasks 'grafana dashboard'. Results come back in relevance order, and the existing flags (--status, --repo, --all-repos, --project, --assignee, --ready, --limit) still apply.

It also fixes witan tasks --ready --status X, which ignored --status because task_ready takes no status (so --ready --status open also listed blocked tasks whose blockers had closed). Both the search and listing paths now filter the same way.

Releases witan-council 0.36.0, so this publishes on merge.

Implementation details
  • projects calls workflow_project_search instead of workflow_project_list when a query is given. Both take the same repo/status arguments.
  • tasks filters the search hits on the fields they carry (status, project_slug), hiding closed tasks unless --status is passed, the same as the plain listing. --ready and --assignee are checked against task_ready/task_list, because readiness and @me only resolve on the server.
  • The first version checked every hit against task_list, and it came back empty for witan tasks --all-repos 'grafana dashboard' against the deployed server while task_search had 20 hits. With no repo in scope, task_list reads list_all_tasks, which ends in limit 50 (read.gq), so any match older than the 50 most recently updated tasks was dropped. test_tasks_query_finds_tasks_older_than_the_recent_window covers this.
  • Search rows don't include blocked_by, so search output leaves it out instead of printing it blank, in both the table and --output-format json|yaml|toml (which dumps the row dicts, not the columns). The status column still shows blocked.
  • task_ready truncates server-side, so when --status or a query filters its result client-side the CLI asks it for every ready task first.
  • The projects and tasks docstrings moved to the indented numpydoc form cyclopts parses. The one-line name: desc form showed only continuation lines in --help. docs/reference/cli.md is regenerated.

How can this be tested?

  • uv run --isolated --package witan-council --group test pytest mcp/servers/witan on the rebased head: 1199 passed, 1 skipped. New tests in tests/test_cli.py cover ranking with closed-task elision, --status closed, the no-match message, a match older than 51 newer tasks under --all-repos, --ready --status open with and without a query, JSON search output without blocked_by, and project search.
  • ./bin/gen_docs.py --check, just check-versions, just check-core-floor, and uv lock --check pass.
  • Run against the deployed server: witan tasks --all-repos 'grafana dashboard' returns the open StarRocks and in-progress ClickHouse observability tasks with closed matches hidden. witan projects omnigraph returns 4 active projects. witan tasks --ready omnigraph returns ready tasks. witan projects gravitino prints "No projects matching 'gravitino'"; workflow_project_search with repo="" and status=None returns 0 rows for that query, so that's correct.

Additional Context

  • The server caps each search at 20 hits before --ready, --assignee or --project filter them, so a narrow filter can miss a lower-ranked match.
  • --assignee combined with a query and --all-repos is still subject to the 50-row cap, tracked in tk-witan-tasks-all-repos-and-status-listings-are-si-faf47c (comment added with this case).
  • Follow-ups filed under wp-witan-service-quality-and-maintenance-f5ad70: tk-witan-projects-has-no-way-to-list-or-search-ever-60471c (--status '' is rejected by the server, so there's no way to ask for every status), tk-most-witan-cli-help-output-drops-parameter-descr-155897 (the docstring format in the rest of the CLI), and tk-structured-cli-output-carries-rich-escaped-title-16403a (a query containing [ shows up Rich-escaped in the JSON/YAML/TOML title).

🤖 Generated with Claude Code

https://claude.ai/code/session_01SFRYTsWVvNq32z75QjgjzC

blarghmatey and others added 4 commits September 18, 2026 11:52
Finding a project or task from the CLI meant paging through the full list,
because the BM25 search tools the server already exposes had no CLI entry
point. Both commands now take an optional positional query, e.g.
`witan tasks 'grafana dashboard'`, and rank results by relevance.

Task hits are filtered on the fields search rows carry (status, project)
rather than intersected with `task_list`: with no repo in scope that list is
the 50 most recently updated tasks, so the intersection dropped every older
match. `--ready` and `--assignee` still intersect with the server's answer,
because readiness and `@me` only resolve server-side.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SFRYTsWVvNq32z75QjgjzC
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SFRYTsWVvNq32z75QjgjzC
Search rows don't carry blocked_by. Dropping it from the table columns only
hid it in txt mode: render_table dumps the row dicts for json/yaml/toml, so
every search result reported an empty blocked_by, including blocked tasks.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SFRYTsWVvNq32z75QjgjzC
task_ready takes no status, so `--ready --status open` also listed blocked
tasks whose blockers had closed and in_progress tasks with lapsed leases,
while the new search path did honour --status. Both paths now filter the same
way. task_ready truncates server-side, so it fetches every ready task before
the filter runs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SFRYTsWVvNq32z75QjgjzC
Copilot AI balanced review requested due to automatic review settings September 18, 2026 16:47

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Both new searches fail in guarded local-fallback mode because their tools are absent from the read allowlist.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Adds relevance-ranked free-text search to project/task CLI listings and fixes ready-task status filtering.

Changes:

  • Adds optional search queries while preserving listing filters.
  • Adds CLI coverage and regenerated reference documentation.
  • Releases witan-council 0.36.0.
File summaries
File Description
mcp/servers/witan/witan/cli/tasks.py Adds task search and status-aware readiness filtering.
mcp/servers/witan/witan/cli/projects.py Adds project search.
mcp/servers/witan/tests/test_cli.py Tests search, filtering, ranking, and output.
docs/reference/cli.md Documents new query arguments.
mcp/servers/witan/CHANGELOG.md Records the release changes.
mcp/servers/witan/pyproject.toml Bumps the package to 0.36.0.
uv.lock Updates the locked workspace version.
Review details
  • Files reviewed: 6/7 changed files
  • Comments generated: 2
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread mcp/servers/witan/witan/cli/projects.py
Comment thread mcp/servers/witan/witan/cli/tasks.py
task_search and workflow_project_search were missing from READ_TOOLS, so when
a deployment is configured and nothing routed the invocation to it, the guard
refused them as writes and `witan tasks QUERY` / `witan projects QUERY`
exited instead of reading the fallback store. Both tools only read.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SFRYTsWVvNq32z75QjgjzC
@blarghmatey
blarghmatey merged commit 426f4e7 into main Sep 18, 2026
17 checks passed
@blarghmatey
blarghmatey deleted the witan-cli-list-search branch September 18, 2026 18:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants