Skip to content

feat(witan): bundle omnigraph binary, zero-config setup, and task query fixes#4

Merged
blarghmatey merged 5 commits into
mainfrom
feat/witan-omnigraph-bundling-and-task-fixes
Jun 23, 2026
Merged

feat(witan): bundle omnigraph binary, zero-config setup, and task query fixes#4
blarghmatey merged 5 commits into
mainfrom
feat/witan-omnigraph-bundling-and-task-fixes

Conversation

@blarghmatey

@blarghmatey blarghmatey commented Jun 22, 2026

Copy link
Copy Markdown
Member

What are the relevant tickets?

N/A

Description (What does it do?)

Two logical groups of changes to the `witan` and `witan-code` MCP servers, plus a follow-up addressing reviewer feedback.

1. Task tracking fixes

  • `update_task` mutation now preserves the `repo` field on updates (was silently dropped, causing tasks to lose their repo scope after any edit)
  • Task list queries now return `repo` in result rows so callers can distinguish repo-scoped tasks from globally-created ones
  • `task_list` merges repo-scoped and unscoped (`repo=null`) tasks — tasks created without git context (e.g. via a globally-configured MCP server) are now visible in any repo session
  • `WITAN_REPO` empty string now explicitly disables auto-detection rather than falling through to git-remote discovery; documents the global-MCP-server use case where the server CWD is not the session repo
  • CLI: `witan tasks` shows a helpful hint when no tasks are found in the current repo instead of a bare "No tasks." — suggests `--all-repos`

2. omnigraph binary bundling and zero-config first-run setup

Eliminates the manual `install.sh` step. After this change, `uvx --from git+https://github.com/mitodl/agent-kit#subdirectory=mcp/servers/witan witan serve` works on a fresh machine with no prior setup.

Binary distribution — `hatch_build.py` (new, both packages)

  • Custom hatchling build hook downloads the platform omnigraph binary (`linux-x86_64` or `macos-arm64`) from ModernRelay/omnigraph GitHub releases during `pip install` / `uvx` wheel build
  • Binary lands at `witan/_bin/omnigraph` (or `witan_code/_bin/omnigraph`) inside the installed package via `force-include`
  • `OmnigraphClient._find_binary()` checks the bundled path first, then falls back to PATH
  • `witan_code/store.py`'s private `_binary()` was a `shutil.which()`-only copy that missed the bundled location — fixed to delegate to `OmnigraphClient._find_binary()`
  • `.gitignore`: `*/_bin/` (hook output) and `__cluster/` (cluster state)

Auto-init — `server.py`

  • `_ensure_graph()` runs at module import time: calls `omnigraph init --schema` + `omnigraph schema apply` if the local store is missing; no-op for remote (`http`/`s3`) URIs
  • Mirrors the lazy init that `witan-code/store.py` already did for per-repo code stores

CLI hygiene — both `graph.py` files

  • `--quiet` added to `mutate`, `load`, and `repair` invocations: suppresses the RFC-011 resolved-write-target diagnostic from stderr so only real errors reach the `_RETRYABLE`/`_NEEDS_REPAIR` detection path

omnigraph config migration (RFC-008)

  • Delete `omnigraph.yaml`: deprecated since omnigraph v0.7.0, was emitting deprecation warnings on every CLI invocation; `omnigraph config migrate` is not yet implemented in the binary
  • Add `cluster.yaml`: team-owned replacement covering schema/query declarations; passes `omnigraph cluster validate` (56 resources, 109 dependency edges)
  • Add `config/operator-config.example.yaml`: documents the personal `~/.omnigraph/config.yaml` `--profile witan` shorthand that replaces the old `cli:`/`aliases:` keys

Renovate — `renovate.json` (new)

  • Extends the org preset (`local>mitodl/.github:renovate-config`) with a `customManagers` regex entry that tracks `_OMNIGRAPH_VERSION` in both `hatch_build.py` files against `ModernRelay/omnigraph` GitHub releases

3. Review feedback (commit 6becdf8)

  • `list_unscoped_tasks` query (new, no limit cap): replaces `list_all_tasks` in `_unblock_dependents`, both `task_ready` branches, and the unscoped-merge paths in `task_list` — the old `limit 50` silently dropped unscoped tasks on busy graphs; `list_all_tasks` (limit 50) is kept only for the display-capped `task_list` else-branch
  • `urlopen(timeout=30)`: replaced `urlretrieve` in both `hatch_build.py` files to prevent indefinite hang during `pip install` / `uvx` on a slow or unreachable network
  • `expanduser()` on `Path(graph_uri)` in `_ensure_graph()` so a literal `` in `WITAN_GRAPH_URI` doesn't create a directory named ``
  • `check=True` on `schema apply` subprocess call so init failures surface as exceptions rather than silently continuing
  • JSONC in `_load_json()`: VS Code `settings.json` allows `//` comments and trailing commas; `_load_json()` now strips them before parsing; returns `None` on parse failure so all callers skip writing rather than overwriting the file (prevents data loss on Copilot and Kilo Code installs)
  • `WITAN_REPO` in `context.py`: `_detect_repo()` now checks `WITAN_REPO` first, matching the server-side behaviour; empty string suppresses detection entirely
  • Unscoped tasks in `inject_context()`: the hook now fetches `list_unscoped_tasks` unconditionally and merges them with repo-scoped tasks, so global work items appear in the prompt context even when a repo is detected
  • Pi extensions: added `cwd: ctx?.cwd` to `spawnSync` in both `configs/pi/extensions/workflow-context.ts` and the bundled `witan/extensions/pi/workflow-context.ts` so `inject-context` detects the correct repo in Pi sessions

How can this be tested?

Task fixes:

  1. Create a task with a repo scope, then update any field via the MCP `task_update` tool — verify the `repo` field is preserved in the response
  2. Create a task without git context (e.g. empty `WITAN_REPO=`), then open a repo session and run `witan tasks` — the unscoped task should appear alongside repo-scoped ones
  3. Set `WITAN_REPO=` (empty) in the MCP server config — verify auto-detection is suppressed and no git subprocess is spawned

Binary bundling / zero-config setup:

  1. In a fresh virtualenv with no `omnigraph` on PATH: `pip install git+https://github.com/mitodl/agent-kit#subdirectory=mcp/servers/witan\` — confirm the build hook message appears and `~/.local/share/witan/graph.omni` does not yet exist
  2. Run `witan tasks` — the graph should be auto-initialised and the command should succeed (returning "No tasks" rather than an error)
  3. Confirm the bundled binary is used: `python -c "from witan.graph import OmnigraphClient; print(OmnigraphClient._find_binary())"` should return a path ending in `witan/_bin/omnigraph`

Cluster config:

cd mcp/servers/witan
omnigraph cluster validate  # should print: cluster config valid: 56 resource(s), 109 dependency edge(s)

Review feedback fixes:

  • Create >50 tasks (mix of scoped and unscoped); verify `witan tasks` and `task_ready` return unscoped tasks past position 50
  • Install to VS Code with comments in `settings.json`; run `witan setup --agent kilo` — should skip writing rather than clobbering the file
  • Set `WITAN_REPO=` in env and run `witan inject-context` — should return empty output without spawning git

Additional Context

The `install.sh` scripts are intentionally kept as an escape hatch for users who want `omnigraph` on their system PATH for direct CLI use, but they are no longer required for the MCP server to function.

On unsupported platforms (anything other than `linux-x86_64` and `macos-arm64`) the build hook logs a warning and skips — the server falls back to PATH lookup as before.

blarghmatey and others added 2 commits June 22, 2026 12:41
- update_task mutation now preserves the repo field (was silently dropped
  on updates, causing tasks to lose their repo scope)
- task list queries return repo in result rows so callers can distinguish
  repo-scoped tasks from globally-created ones
- task_list merges repo-scoped and unscoped (repo=null) tasks so tasks
  created without git context remain visible in any repo session
- empty WITAN_REPO env var now explicitly disables auto-detection rather
  than falling through to git-remote discovery; documents the global-MCP
  server use case where server CWD is not the session repo
- CLI: witan tasks shows a hint when no tasks are found in the current
  repo instead of a bare 'No tasks.' — suggests --all-repos

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eliminates the manual install.sh step for new users. After this change,
`uvx --from git+...#subdirectory=mcp/servers/witan witan serve` works
on a fresh machine with no prior setup.

Binary distribution
- Add hatch_build.py to witan and witan-code: custom hatchling build hook
  that downloads the platform omnigraph binary (linux-x86_64 or
  macos-arm64) from GitHub releases during pip install / uvx wheel build
  and places it at witan/_bin/omnigraph (or witan_code/_bin/omnigraph)
- Update both pyproject.toml files: register the hook and add _bin/ to
  force-include so the bundled binary lands in site-packages
- OmnigraphClient._find_binary() now checks the bundled path first before
  falling back to PATH; witan_code/store.py's private _binary() was a
  shutil.which()-only copy that missed the bundled location -- fixed to
  delegate to OmnigraphClient._find_binary()
- .gitignore: add */_bin/ (hook output) and __cluster/ (cluster state)

Auto-init
- server.py: _ensure_graph() runs at module import time and calls
  `omnigraph init --schema` + `omnigraph schema apply` if the local store
  does not yet exist; no-ops for remote (http/s3) URIs. Mirrors the lazy
  init that witan-code/store.py already did for per-repo code stores.

CLI hygiene
- Add --quiet to mutate, load, and repair invocations: suppresses the
  RFC-011 resolved-write-target diagnostic from stderr so only real errors
  reach the error-detection path in _run()

omnigraph config migration (RFC-008)
- Delete omnigraph.yaml: deprecated since omnigraph v0.7.0; was emitting
  deprecation warnings and omnigraph config migrate is not yet implemented
- Add cluster.yaml: team-owned replacement covering schema/query
  declarations; passes `omnigraph cluster validate` (56 resources, 109
  dependency edges)
- Add config/operator-config.example.yaml: documents the personal
  ~/.omnigraph/config.yaml profile (replaces the old cli:/aliases: keys)

Renovate
- Add renovate.json extending the org preset with a customManagers regex
  entry that tracks _OMNIGRAPH_VERSION in both hatch_build.py files
  against ModernRelay/omnigraph GitHub releases

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request introduces automated bundling of the omnigraph binary during package installation via custom Hatchling build hooks, and updates the witan and witan-code servers to utilize this bundled binary. It also adds automatic local graph initialization on startup, updates CLI display and scoping for repositories, and refactors task querying to merge unscoped tasks with repo-scoped tasks. Feedback on these changes highlights a potential bug where unscoped tasks could be silently omitted due to a hardcoded limit of 50 in the list_all_tasks query. Additionally, it is recommended to add a network timeout to the binary download process and ensure that schema application failures are not silently ignored by adding check=True to the subprocess execution.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread mcp/servers/witan/witan/server.py Outdated
Comment thread mcp/servers/witan/witan/server.py Outdated
Comment thread mcp/servers/witan-code/hatch_build.py Outdated
Comment thread mcp/servers/witan/hatch_build.py Outdated
Comment thread mcp/servers/witan/witan/server.py
blarghmatey and others added 2 commits June 22, 2026 12:58
…on-checkpoint, setup CLI commands

- context.py: ports workflow-context-inject.sh and workflow-session-checkpoint.sh
  logic into Python, eliminating the checkout-relative QUERIES_DIR dependency
- cli.py: adds inject-context (UserPromptSubmit hook), session-checkpoint (Stop
  hook), and setup commands; hooks are now one-liners calling witan CLI directly
- witan/skills/: bundles agent-memory, project-tracker, workflow, task SKILL.md
  files in the wheel for install-time distribution
- witan/hooks/: bundles thin wrappers (2-line scripts) in the wheel; copied to
  ~/.claude/hooks/ by witan setup
- witan setup: installs omnigraph to PATH, skills to ~/.claude/skills/, hooks to
  ~/.claude/hooks/, and merges MCP+hook registrations into ~/.claude/settings.json
  in a single command — replaces the previous 6-step manual setup

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- setup.py: per-agent install registry with install_claude, install_pi,
  install_copilot, install_opencode, install_kilo and auto-detection helpers
- cli.py: witan setup --agent <name|all> with full per-agent dispatch;
  removes inline setup logic (now delegated to setup.py module)
- workflow-context.ts: rewrite to call `witan inject-context` instead of
  calling omnigraph directly with a checkout-relative QUERIES_DIR — same
  problem that was fixed for the Claude hook; now checkout-independent
- extensions/pi/: bundle workflow-context.ts and codegraph.ts in the wheel
  so `witan setup --agent pi` copies them without needing a checkout

Config targets per agent:
  claude   ~/.claude/settings.json (mcpServers + hooks)
  pi       ~/.pi/agent/mcp.json + ~/.pi/agent/extensions/ + skills
  copilot  ~/.config/Code/User/mcp.json (servers + type:stdio)
  opencode ~/.config/opencode/config.json (mcp key)
  kilo     ~/.config/Code/User/settings.json (kilocode.mcpServers)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR upgrades the witan / witan-code MCP servers to work “out of the box” by bundling the omnigraph binary at build time, adding auto-initialization and per-agent setup helpers, and fixing task repo-scoping behavior so tasks don’t silently lose (or hide) their repo context.

Changes:

  • Bundle omnigraph into wheels via a custom Hatch build hook; update binary resolution and quiet noisy write subcommands.
  • Add zero-config first-run behavior (graph auto-init) plus new CLI/setup + hook/extension plumbing for workflow context injection and session checkpointing.
  • Fix task repo field preservation + repo visibility in queries and merge repo-scoped + unscoped tasks in repo sessions.

Reviewed changes

Copilot reviewed 27 out of 28 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
renovate.json Adds Renovate config with regex manager tracking pinned omnigraph version in build hooks.
mcp/servers/witan/witan/skills/workflow/SKILL.md New workflow session manager skill documentation.
mcp/servers/witan/witan/skills/task/SKILL.md New interactive task manager skill documentation.
mcp/servers/witan/witan/skills/project-tracker/SKILL.md New end-to-end project tracking skill documentation.
mcp/servers/witan/witan/skills/agent-memory/SKILL.md New guidance on shared agent memory usage via witan.
mcp/servers/witan/witan/setup.py Adds witan setup installers for multiple agent platforms (Claude, Pi, Copilot, etc.).
mcp/servers/witan/witan/server.py Auto-init local graph, preserve task repo on update, and merge unscoped+scoped tasks in list/ready paths.
mcp/servers/witan/witan/repo.py Makes WITAN_REPO="" explicitly disable repo auto-detection.
mcp/servers/witan/witan/hooks/workflow-session-checkpoint.sh New Stop hook wrapper calling witan session-checkpoint.
mcp/servers/witan/witan/hooks/workflow-context-inject.sh New UserPromptSubmit hook wrapper calling witan inject-context.
mcp/servers/witan/witan/graph.py Adds --quiet for writes; checks bundled omnigraph path before PATH; updates error message.
mcp/servers/witan/witan/extensions/pi/workflow-context.ts New Pi extension delegating context injection to witan inject-context.
mcp/servers/witan/witan/extensions/pi/codegraph.ts New Pi extension to run witan-code index in the background on session start and edits.
mcp/servers/witan/witan/context.py New Python implementation for hook commands (inject-context, session-checkpoint).
mcp/servers/witan/witan/cli.py Adds inject-context, session-checkpoint, and setup CLI commands; improves task/project listing output.
mcp/servers/witan/queries/read.gq Adds repo to task list query result rows.
mcp/servers/witan/queries/mutations.gq Adds repo to update_task mutation inputs/updates.
mcp/servers/witan/pyproject.toml Enables custom Hatch build hook and force-includes bundled assets (schema/queries/bin/skills/hooks/extensions).
mcp/servers/witan/omnigraph.yaml Removes deprecated omnigraph YAML config.
mcp/servers/witan/hatch_build.py New Hatch build hook to download and bundle the omnigraph binary.
mcp/servers/witan/config/operator-config.example.yaml Adds example operator config for omnigraph profile-based usage.
mcp/servers/witan/cluster.yaml Adds omnigraph cluster config replacing deprecated omnigraph.yaml usage.
mcp/servers/witan-code/witan_code/store.py Uses shared _find_binary() logic so bundled omnigraph is found.
mcp/servers/witan-code/witan_code/graph.py Adds --quiet for writes and checks bundled omnigraph before PATH.
mcp/servers/witan-code/pyproject.toml Enables custom Hatch build hook and force-includes bundled bin assets.
mcp/servers/witan-code/hatch_build.py New Hatch build hook to download and bundle the omnigraph binary.
configs/pi/extensions/workflow-context.ts Updates Pi extension to delegate to witan inject-context.
.gitignore Ignores _bin/ outputs and omnigraph cluster state directories.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread mcp/servers/witan/witan/setup.py Outdated
Comment thread mcp/servers/witan/witan/server.py Outdated
Comment thread mcp/servers/witan/witan/server.py Outdated
Comment thread mcp/servers/witan/witan/server.py
Comment thread mcp/servers/witan/witan/context.py
Comment thread mcp/servers/witan/witan/context.py Outdated
Comment thread mcp/servers/witan/witan/extensions/pi/workflow-context.ts
Comment thread configs/pi/extensions/workflow-context.ts Outdated
Comment thread mcp/servers/witan/hatch_build.py
Comment thread mcp/servers/witan-code/hatch_build.py
- Add list_unscoped_tasks query (no limit cap) to replace list_all_tasks in
  paths that scan for unscoped work; list_all_tasks limit-50 retained only
  for the display-capped task_list else-branch
- Replace urlretrieve with urlopen(timeout=30) in both hatch_build.py files
  to prevent indefinite hang during pip install / uvx build
- Add expanduser() to Path(graph_uri) in _ensure_graph() so a literal ~ in
  WITAN_GRAPH_URI doesn't create a dir named '~'
- Add check=True to schema apply subprocess call so init failures are visible
- Fix _load_json() in setup.py to handle JSONC (VS Code settings.json allows
  // comments and trailing commas); callers now skip writing rather than
  overwriting an unparseable file (prevents data loss)
- Fix _detect_repo() in context.py to honour WITAN_REPO env var first;
  empty string suppresses detection entirely, matching server.py behaviour
- Fix inject_context() to also fetch unscoped tasks (repo=None) and merge
  them with repo-scoped tasks so global work items appear in the hook output
- Add cwd: ctx?.cwd to spawnSync in both Pi workflow-context.ts extensions
  so inject-context detects the correct repo in the Pi session context

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@blarghmatey blarghmatey merged commit 88e1cfe into main Jun 23, 2026
4 checks passed
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.

3 participants