Skip to content

feat(mcp): ship compact cross-agent surface and reliable hooks#290

Open
zzet wants to merge 25 commits into
mainfrom
feat/mcp-facade-v1
Open

feat(mcp): ship compact cross-agent surface and reliable hooks#290
zzet wants to merge 25 commits into
mainfrom
feat/mcp-facade-v1

Conversation

@zzet

@zzet zzet commented Jul 11, 2026

Copy link
Copy Markdown
Owner

Summary

  • publish a static 21-tool public MCP surface for every named client, with lean agent-neutral instructions and no dependency on deferred promotion
  • collapse implementation-era choices behind selector-driven read / edit, operation-dispatched domain tools, and stable operation schemas returned on demand by capabilities
  • make Gortex directly callable in Codex 0.142+ (mcp__gortex and non-prefixed gortex namespaces), required at startup, and tolerant of bounded daemon cold start
  • keep the same compact names and request objects available through gortex call only for harnesses that have no MCP transport by design
  • preserve explicit compatibility surfaces, user-owned configuration, mutation guards, policy gates, and wire-format behavior during migration
  • specify the contract, effects, rollout, acceptance gates, host responsibilities, and compatibility mapping in docs/mcp-facade-v1.md

Public contract and schema

  • initialize -> tools/list returns the same 21 public tools for canonical clients, supported aliases, and unknown non-empty client names; empty/pre-initialize sessions retain the server default
  • wire-format selection remains independent of tool-surface selection, so unknown clients stay JSON-safe
  • read({target:{file:"..."}}) and symbol/file edit calls infer their operation from the selector
  • change({operation:"impact", target:{symbol:"..."}}) and target.symbols now use the same selector family as read and relations; compatibility source.symbols still lowers correctly, while an explicit target wins
  • capabilities projects every available operation into the stable public envelope instead of exposing captured handler fields such as ids; fixed server arguments stay hidden
  • an exhaustive contract test covers more than 100 available operations and proves every returned request_shape validates against both its operation schema and the static facade schema
  • the canonical registry covers 178/178 compatibility handlers and drives routing, introspection, policy, effect, and dispatch parity

Host and agent integration

  • Codex 0.142+ receives features.code_mode.direct_only_tool_namespaces = ["mcp__gortex", "gortex"], required = true, and startup_timeout_sec = 90
  • Codex configuration merging is additive and idempotent: custom namespaces, feature fields, MCP environment, command arguments, tool timeout, and unrelated servers survive; known older Codex releases do not receive unsupported fields
  • MCP-capable instructions and hooks treat a missing callable Gortex handle as an integration failure: stop indexed-code operations and report it; never start a daemon or silently switch to Bash
  • Pi and the separately labeled CLI skill retain the exact Bash-only mirror for harnesses with no MCP transport by design
  • Claude Code, Cursor, Kiro, Hermes, Cline, Kilo Code, Antigravity, Codex, and other generated integrations use public names without mentioning the internal surface version
  • exact v0.60.0 migration fingerprints are versioned in code and have an explicit removal gate: no earlier than v0.63.0, after the supported direct-upgrade floor and release-note conditions in docs/versioning.md

Impact safety and explore quality

  • reach records are copy-on-write and become usable only after generation, all distance tiers, and an explicit completion marker are published
  • lookup, eager maintenance, unrelated metadata writers, and watcher topology replacement are coordinated so a partial reach record cannot produce a false-safe LOW / 0 affected result
  • watcher single-file and storm updates invalidate reach data before waiting impact readers resume
  • repeated identical change.impact calls remain stable; the reported first-correct/later-zero race has dedicated regression and race coverage
  • natural-language explore keeps the best generic data-leaf match but demotes repeated same-name leaves behind callable/type targets; literal symbol lookup ordering is unchanged
  • the public explore regression first proves the raw top six are crowded by client variables, then proves the public response restores the relevant callable
  • explore follow-up guidance now names only public read / search operations

Codex hook and issue coverage

Prior story / failure Coverage in this PR
#207 SessionStart Migrates managed hooks, preserves `startup
#209 Bash PreToolUse Splits multi-keyword alternations and provides opt-in deny / conservative rewrite postures; hard deny requires a workspace-scoped graph-confirmed match.
#211 Bash PostToolUse Uses the daemon AF_UNIX MCP connection first; the optional HTTP endpoint remains compatibility-only.
#212 hooks-only refresh gortex init --hooks-only migrates stale managed matchers and posture commands without duplicating hooks or touching MCP/instruction surfaces.
#213 source-read enrichment Covers cat, head, tail, and bounded non-mutating sed -n / awk NR...print shapes.
#215 file-list enrichment Covers conservative line-oriented fd, ls, tree -fi, and git ls-files; ambiguous or execution-capable forms stay no-ops.
#218 MCP read shaping Matches the always-present public read, including selector-default calls; advisory remains default, deny/rewrite opt-in.
#230 documented closeout Documents supported postures, output replacement, and intentional lifecycle gaps separately.
#259 invalid CLI shape Bash-only guidance renders gortex call <public-tool>; MCP guidance never recommends a transport fallback.
openai/codex#21503 deferred discovery Gortex namespaces are forced direct where Codex supports it; raw tools/list or settings-screen discovery alone is no longer considered success.

Additional hook reliability:

  • local privacy-safe hook-effectiveness.jsonl records event, emitted-context flag, daemon reachability, capped alternation count, and latency, including no-op events
  • UserPromptSubmit can re-surface task-relevant graph context in long sessions
  • Codex apply_patch PostToolUse runs change detection and derives affected-symbol tests, guards, and contracts
  • GORTEX_CODEX_HOOK_MODE=enrich|deny|rewrite|suppress keeps advisory behavior as default and provides opt-in enforcement/rewrite/output replacement
  • suppress uses Codex's supported PostToolUse result replacement fields

Intentional Codex lifecycle gaps remain explicit: there is no separate PreCompact / PostCompact hook because SessionStart(source="compact") restores orientation, and no Stop continuation policy.

Validation

  • full tracked functional package suite passed (with the load-sensitive cold-index benchmark run separately)
  • go test ./internal/mcp -count=1 passed, including facade/schema/explore integration
  • reach, impact, and watcher regression suites passed under -race with repeated reach/impact runs
  • isolated TestColdIndexNoWallClockRegression passed in 4.99s
  • generated agent-render goldens regenerated and verified
  • go vet passed over tracked packages
  • golangci-lint v2.11.4: 0 issues
  • git diff --check

Addresses #241 and its referenced #206 implementation stories. Also covers the #259 follow-up.

@zzet zzet force-pushed the feat/mcp-facade-v1 branch from 1db66cb to eb3af3e Compare July 12, 2026 08:41
@zzet zzet changed the title feat(mcp): introduce facade-v1 tool surface for Codex feat(mcp): ship compact cross-agent surface and reliable hooks Jul 12, 2026
// Keep this roster closed and agent-neutral. The bare names are the exact
// public CLI/MCP names; Pi adds only its collision-avoidance prefix at the
// registration boundary.
const PUBLIC_TOOLS: ToolDescriptor[] = [

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

TODO: validate if it makes sense to keep the dynamic list for preset instead of hardcoded.

Comment thread cmd/gortex/testdata/agent-render/claude-code.txt
}

// ---------------------------------------------------------------------------
// On-demand tool discovery (mirrors MCP tools_search + promotion)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

TODO: validate if it makes sense to keep the tools discovery logic.

// Keep this roster closed and agent-neutral. The bare names are the exact
// public CLI/MCP names; Pi adds only its collision-avoidance prefix at the
// registration boundary.
const PUBLIC_TOOLS: ToolDescriptor[] = [

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

TODO: validate if it makes sense to keep the dynamic list for preset instead of hardcoded.
Duplicate of #290 (comment) comment.

}

// ---------------------------------------------------------------------------
// On-demand tool discovery (mirrors MCP tools_search + promotion)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

TODO: validate if it makes sense to keep the tools discovery logic.
Duplicate of #290 (comment) comment

@zzet

zzet commented Jul 13, 2026

Copy link
Copy Markdown
Owner Author

Optimization and language-outlier update (2026-07-13)

Shipped on this branch:

  • 66c6586 preserves text/vector rank provenance for concept exploration, bounds the expensive graph rerank to 2x the fetch width, skips FTS-equivalent expansion, and adds dual-channel/scope regression coverage.
  • cd65faf changes the compact answer draft to an explicit top-3 + best caller + best callee policy. Structural rows require discriminative multi-segment parent/child names, exclude metadata- and path-detected tests, rank shared parent/child terms first, and include exact IDs only for graph-only rows. Unqualified clear/convert/get/set/write no longer become exact anchors; qualified/path anchors remain exact.

Validation:

  • go test ./internal/query ./internal/mcp -count=1
  • go test -race ./internal/mcp/... ./internal/query/...
  • full contract-selected race suite passed for cmd/gortex, agents, config, SQLite graph, indexer, local provider, MCP, and query packages.
  • Gortex change tests report all changed symbols covered; guards are clean. Contract remains WARN solely because the explore path has a high static blast radius.

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.

1 participant