* origin/main: (142 commits) Exempt Python dunders from dead-code analysis store_sqlite: normalize native separators in generated dir columns store_sqlite: space WAL auto-checkpoints at 8k pages for index-write bursts store_sqlite: three-phase seeded reindex benchmark Update internal/semantic/tstypes/fact_spool.go ci(deps): bump github/codeql-action/upload-sarif store_sqlite: guard the json transport against unmarshalable payloads resolver: scope page_load to the pass clock resolver: split commit_apply interior timings store_sqlite: bind resolved-conversion updates as one json_each relation resolver: attribute pass interior time and churn shapes tstypes: true up spool capacity hints and page-cap/deadline comments resolver: note razor marker removals; make retention counters mean what they log fix(indexer): use incremental contract cleanup on untrack fix(mcp): cache index health scans fix(agents): register the OpenCode MCP server at user scope feat(agents): install the Gortex sub-agents for Codex CLI style: gofmt the init wizard test test(agents): regenerate the render goldens for the widened fence fix(uninstall): remove Claude Code's per-community skills too ... # Conflicts: # docs/agents.md # internal/mcp/overlay_view.go
internal/daemon
Process-local daemon plumbing — Unix socket transport, MCP dispatch session state, runtime state paths, plus the iteration-1 multi-server roster and editor-overlay machinery.
Surface
| File | Role |
|---|---|
paths.go |
Default file paths (socket, PID, log) |
proto.go |
Wire types for the daemon's internal MCP protocol |
client.go |
Connect-and-talk client used by the proxy CLI |
servers.go |
~/.gortex/servers.toml loader + ServerClient (HTTP/unix) + WorkspaceRosterCache + RouteForCwd |
overlay.go |
OverlayManager — register / push / delete editor buffer overrides |
router.go |
Router — hybrid-read query router |
Multi-server routing
~/.gortex/servers.toml declares the set of Gortex servers reachable
from this daemon. The schema:
[[server]]
slug = "main"
url = "unix:///run/gortex/main.sock"
default = true
[[server]]
slug = "tuck"
url = "https://tuck.gortex.example/v1"
auth_token_env = "GORTEX_TOKEN_TUCK"
workspaces = ["tuck"]
url accepts http(s)://... (TCP) or unix:///path/to.sock
(Unix-domain socket). Auth tokens come from auth_token (literal,
discouraged) or auth_token_env (env-var name resolved per-call so
rotation lands without a daemon restart).
Router.RouteToolCall walks the priority chain on every MCP tool
invocation:
- Caller-supplied scope override (e.g.
workspace: "tuck"on the tool args). - Walking up from cwd to find a
.gortex.yaml::workspacedeclaration. - Workspace roster — pre-declared
workspaces = [...]lists inservers.toml, then the cachedGET /v1/workspaces/<ws>/reposroster from each configured server. - The
default = trueentry, if any.
Resolved server == LocalSlug → run in-process via LocalExecute.
Resolved server != LocalSlug → proxy via ServerClient.ProxyTool
(POST /v1/tools/<name> with bearer auth).
Editor overlays
OverlayManager holds per-session in-flight file overrides so MCP
clients can ask "what would find_usages look like with my unsaved
buffer?" The HTTP front door at /v1/overlay/sessions/... is wired
in internal/server. BaseSHA drift detection refuses to merge a
stale overlay so wrong-line-number errors don't surface as graph bugs.
Caveat: pre-workspace-slug stores
A graph store written by a daemon that predates the workspace-slug
schema carries empty WorkspaceID/ProjectID columns on its nodes.
The daemon's warmup path
(MultiIndexer.BackfillWorkspaceSlugs invoked from
cmd/gortex/daemon_state.go::warmupDaemonState) re-stamps them from
the per-repo .gortex.yaml. Without that pass, the matcher's
EffectiveWorkspace falls back to RepoPrefix and explicit
shared-workspace setups silently lose identity until every file is
touched.