From 5febf69a57bab5d553ae50f36b9e99add1116a3a Mon Sep 17 00:00:00 2001 From: dvcdsys Date: Mon, 7 Sep 2026 14:15:21 +0200 Subject: [PATCH 1/2] feat(plugin): add Codex marketplace --- .agents/plugins/marketplace.json | 20 + .github/workflows/ci-plugin.yml | 12 + README.md | 78 ++ doc/CODEX_PLUGIN.md | 65 ++ plugins/cix-openai/.codex-plugin/plugin.json | 37 + plugins/cix-openai/README.md | 52 ++ .../agents/cix-workspace-investigator.md | 136 ++++ .../cix-openai/skills/cix-workspace/SKILL.md | 721 ++++++++++++++++++ .../skills/cix-workspace/agents/openai.yaml | 6 + plugins/cix-openai/skills/cix/SKILL.md | 314 ++++++++ .../cix-openai/skills/cix/agents/openai.yaml | 6 + plugins/cix/scripts/sync-skills.sh | 71 +- plugins/cix/skills/cix-workspace/SKILL.md | 2 +- plugins/cix/skills/cix/SKILL.md | 17 +- skills/README.md | 15 +- skills/cix-workspace/SKILL.md | 2 +- 16 files changed, 1541 insertions(+), 13 deletions(-) create mode 100644 .agents/plugins/marketplace.json create mode 100644 doc/CODEX_PLUGIN.md create mode 100644 plugins/cix-openai/.codex-plugin/plugin.json create mode 100644 plugins/cix-openai/README.md create mode 100644 plugins/cix-openai/agents/cix-workspace-investigator.md create mode 100644 plugins/cix-openai/skills/cix-workspace/SKILL.md create mode 100644 plugins/cix-openai/skills/cix-workspace/agents/openai.yaml create mode 100644 plugins/cix-openai/skills/cix/SKILL.md create mode 100644 plugins/cix-openai/skills/cix/agents/openai.yaml diff --git a/.agents/plugins/marketplace.json b/.agents/plugins/marketplace.json new file mode 100644 index 00000000..509b99c3 --- /dev/null +++ b/.agents/plugins/marketplace.json @@ -0,0 +1,20 @@ +{ + "name": "code-index", + "interface": { + "displayName": "Code Index" + }, + "plugins": [ + { + "name": "cix-openai", + "source": { + "source": "local", + "path": "./plugins/cix-openai" + }, + "policy": { + "installation": "AVAILABLE", + "authentication": "ON_INSTALL" + }, + "category": "Developer Tools" + } + ] +} diff --git a/.github/workflows/ci-plugin.yml b/.github/workflows/ci-plugin.yml index d9e6e570..cd563e2e 100644 --- a/.github/workflows/ci-plugin.yml +++ b/.github/workflows/ci-plugin.yml @@ -11,6 +11,7 @@ on: - 'plugins/**' - 'skills/**' - '.claude-plugin/**' + - '.agents/plugins/**' - '.github/workflows/ci-plugin.yml' pull_request: branches: [main, develop] @@ -18,6 +19,7 @@ on: - 'plugins/**' - 'skills/**' - '.claude-plugin/**' + - '.agents/plugins/**' - '.github/workflows/ci-plugin.yml' # Minimum permissions required by the workflow (CodeQL workflow-permissions advisory). @@ -66,6 +68,16 @@ jobs: jq . plugins/cix/.claude-plugin/plugin.json jq . plugins/cix/hooks/hooks.json jq . plugins/cix-cowork/.claude-plugin/plugin.json + jq . .agents/plugins/marketplace.json + jq . plugins/cix-openai/.codex-plugin/plugin.json + + - name: Validate Codex plugin invariants + run: | + test ! -e plugins/cix-openai/.mcp.json + test "$(jq -r '.name' plugins/cix-openai/.codex-plugin/plugin.json)" = "cix-openai" + test "$(jq -r '.plugins[0].name' .agents/plugins/marketplace.json)" = "cix-openai" + test "$(jq -r '.plugins[0].source.path' .agents/plugins/marketplace.json)" = "./plugins/cix-openai" + test "$(jq -r '.mcpServers // empty' plugins/cix-openai/.codex-plugin/plugin.json)" = "" - name: Check plugin skills are in sync with canonical sources run: | diff --git a/README.md b/README.md index 4fbb42c3..e127f731 100644 --- a/README.md +++ b/README.md @@ -204,6 +204,82 @@ is required — vectors aren't comparable across providers. `cix` is designed to be called by AI agents (Claude, GPT, Cursor, custom agents) as a shell tool — they run `cix search` instead of Grep/Glob and get ranked snippets rather than raw file dumps. +### Codex / ChatGPT desktop (CLI-first, no MCP) + +The Codex plugin reuses the same `cix` and `cix-workspace` skill instructions +as the Claude Code plugin. The skill does not contain the search engine and does +not connect through MCP: it teaches Codex to run the locally installed `cix` +command-line client. + +#### 1. Install and connect the `cix` client + +First complete the [Quick Start](#quick-start): run a cix server, create an API +key in the dashboard, and install the client. If the server is already running, +the minimum client setup is: + +```bash +curl -fsSL https://raw.githubusercontent.com/dvcdsys/code-index/main/install.sh | bash +cix config set server.local.url http://localhost:21847 +cix config set server.local.key cix_ +cix status +``` + +Use the real server URL instead of `http://localhost:21847` when cix runs on +another machine. The URL and API key stay in the user's cix configuration; they +are not stored in the Codex plugin. + +#### 2. Add the marketplace and install the plugin + +Run this once in a terminal: + +```bash +codex plugin marketplace add dvcdsys/code-index +``` + +Then open Codex CLI or the Codex area in the ChatGPT desktop app: + +1. Open `/plugins`. +2. Select the **Code Index** marketplace. +3. Install **cix — Code Search**. +4. Start a new conversation so Codex loads the newly installed skills. + +The marketplace downloads the plugin and its skill files. It does not install +the cix server or CLI, which is why step 1 is required. + +#### 3. Index a repository and verify the skill + +From the repository you want Codex to work with: + +```bash +cd /path/to/repository +cix status +cix init # only when the project has not been indexed yet +``` + +Ask Codex a normal code-navigation question, or invoke the skill explicitly: + +```text +$cix Explain how authentication requests are validated in this project. +``` + +`$cix` may also activate automatically for semantic code discovery, symbol +navigation, definitions, and references. For research spanning several indexed +repositories, invoke the manual-only workspace skill: + +```text +$cix-workspace Find where the API contract is produced and consumed. +``` + +To receive plugin updates later, run: + +```bash +codex plugin marketplace upgrade code-index +``` + +Then update or reinstall **cix — Code Search** from `/plugins` and start a new +conversation. Full setup, behavior, and compatibility notes: +[`doc/CODEX_PLUGIN.md`](doc/CODEX_PLUGIN.md). + **Claude Code (plugin, recommended).** Bundles the `cix` + `cix-workspace` skills, the `cix-workspace-investigator` sub-agent, CLI auto-install hooks, and a grep-nudge: ```bash @@ -302,6 +378,7 @@ docker compose down -v # stop AND wipe data + models (destructive) | [`doc/WEBHOOKS.md`](doc/WEBHOOKS.md) | GitHub webhook lifecycle, modes, HMAC validation | | [`doc/POLLING.md`](doc/POLLING.md) | Git polling sync, for repos where a webhook is not an option | | [`doc/COWORK_MCP.md`](doc/COWORK_MCP.md) | Using cix from Claude Desktop / Cowork over MCP (`cix mcp install`, multi-server) | +| [`doc/CODEX_PLUGIN.md`](doc/CODEX_PLUGIN.md) | CLI-first Codex/ChatGPT desktop plugin and marketplace setup | | [`doc/UPDATES.md`](doc/UPDATES.md) | Release-poll banner + stable vs develop install channels | | [`doc/CONFIG_REFERENCE.md`](doc/CONFIG_REFERENCE.md) | Complete env-var reference | | [`doc/RELEASES.md`](doc/RELEASES.md) | Cutting CLI + server + app releases, CVE scans, make targets | @@ -317,6 +394,7 @@ docker compose down -v # stop AND wipe data + models (destructive) | [`CONTRIBUTING.md`](CONTRIBUTING.md) | Contributor workflow | | [`plugins/cix/README.md`](plugins/cix/README.md) | Claude Code plugin reference | | [`plugins/cix-cowork/README.md`](plugins/cix-cowork/README.md) | Cowork skills plugin (MCP-based) reference | +| [`plugins/cix-openai/README.md`](plugins/cix-openai/README.md) | Codex plugin package (same CLI skills, OpenAI manifest) | --- diff --git a/doc/CODEX_PLUGIN.md b/doc/CODEX_PLUGIN.md new file mode 100644 index 00000000..cb111237 --- /dev/null +++ b/doc/CODEX_PLUGIN.md @@ -0,0 +1,65 @@ +# Using cix from Codex + +The `cix-openai` plugin is the Codex/ChatGPT plugin-format counterpart to the +Claude Code marketplace integration. It reuses the Claude Code `cix` and +`cix-workspace` skill bodies byte-for-byte, while adding the Codex manifest, +marketplace entry, and UI invocation policy. It is deliberately **CLI-first**: +the skills call the installed `cix` client through the terminal. The plugin does +not configure MCP, ship a background service, or depend on Claude hooks. + +## Install the cix client + +Deploy or connect to a self-hosted cix server, then install the client: + +```bash +curl -fsSL https://raw.githubusercontent.com/dvcdsys/code-index/main/install.sh | bash +cix config set server.main.url +cix config set server.main.key +cix status +``` + +You can copy the complete connect command from the dashboard's API-key dialog +instead of entering the URL and key separately. + +## Add the marketplace + +```bash +codex plugin marketplace add dvcdsys/code-index +``` + +Open `/plugins` in Codex, select **Code Index**, install **cix — Code Search**, +and begin a new conversation. + +For development against a local checkout: + +```bash +codex plugin marketplace add /absolute/path/to/code-index +``` + +Codex discovers the catalog at `.agents/plugins/marketplace.json` and the +plugin manifest at `plugins/cix-openai/.codex-plugin/plugin.json`. + +## Behavior + +The plugin includes two skills: + +- `$cix` is available for automatic selection and loads the same single-repo + guidance as the Claude Code plugin. +- `$cix-workspace` is explicit-only and loads the same cross-repository flow + plus investigator guidance as the Claude Code plugin. + +`plugins/cix/scripts/sync-skills.sh` owns the mirrors and CI checks the generated +Codex projections for drift. Skill bodies remain byte-identical; only the +frontmatter is adapted for Codex. + +The package contains no MCP configuration. That keeps local repository access, +server selection, and credentials in the existing `cix` CLI configuration at +`~/.cix/config.yaml`. + +## ChatGPT compatibility boundary + +The manifest and skills use the shared OpenAI plugin format. Full execution +requires a surface with local terminal access and the `cix` binary installed, +which includes Codex in the ChatGPT desktop app and Codex CLI. A web-only +ChatGPT session cannot call a local CLI; supporting it would require a remote +HTTP tool connection, which this CLI-first plugin intentionally does not add. diff --git a/plugins/cix-openai/.codex-plugin/plugin.json b/plugins/cix-openai/.codex-plugin/plugin.json new file mode 100644 index 00000000..0f37b47a --- /dev/null +++ b/plugins/cix-openai/.codex-plugin/plugin.json @@ -0,0 +1,37 @@ +{ + "name": "cix-openai", + "version": "0.1.0", + "description": "Semantic code search and cross-repository navigation for Codex, powered by the local cix CLI.", + "author": { + "name": "dvcdsys", + "url": "https://github.com/dvcdsys" + }, + "homepage": "https://codeindex.app", + "repository": "https://github.com/dvcdsys/code-index", + "license": "MIT", + "keywords": [ + "code-search", + "semantic-search", + "navigation", + "indexing", + "workspace" + ], + "skills": "./skills/", + "interface": { + "displayName": "cix — Code Search", + "shortDescription": "Semantic code search through the cix CLI", + "longDescription": "Teach Codex when and how to use the local cix command-line client for semantic search, symbol navigation, and cross-repository workspace research.", + "developerName": "dvcdsys", + "category": "Developer Tools", + "capabilities": [ + "Read" + ], + "websiteURL": "https://codeindex.app", + "defaultPrompt": [ + "Use cix to find how authentication works in this repository.", + "Trace this symbol from its definition to every caller.", + "Use a cix workspace to map this change across repositories." + ], + "brandColor": "#6D5EF5" + } +} diff --git a/plugins/cix-openai/README.md b/plugins/cix-openai/README.md new file mode 100644 index 00000000..550f93ec --- /dev/null +++ b/plugins/cix-openai/README.md @@ -0,0 +1,52 @@ +# cix for Codex + +Native Codex packaging for the same `cix` and `cix-workspace` skills shipped by +the Claude Code plugin. The skill bodies are synchronized byte-for-byte; only +the Codex manifest and UI metadata are product-specific. This plugin contains +no MCP server, hooks, or auto-installer: Codex calls the same installed `cix` +executable a developer uses in a terminal. + +## Prerequisites + +Install the client and connect it to a self-hosted cix server: + +```bash +curl -fsSL https://raw.githubusercontent.com/dvcdsys/code-index/main/install.sh | bash +cix config set server.main.url +cix config set server.main.key +cix status +``` + +The ready-made connect command in the cix dashboard can replace the two +`cix config` commands. + +## Install from this marketplace + +Register the repository as a Codex marketplace: + +```bash +codex plugin marketplace add dvcdsys/code-index +``` + +Then start Codex, open `/plugins`, choose the **Code Index** marketplace, and +install **cix — Code Search**. Start a new conversation so the skills are +available. + +For local development, register the repository checkout instead: + +```bash +codex plugin marketplace add /absolute/path/to/code-index +``` + +## Skills + +- `cix` activates automatically for open-ended code discovery and symbol + navigation. It uses the same workflow body as the Claude Code skill. +- `cix-workspace` is explicit-only. Invoke `$cix-workspace` for the same + cross-repository workflow and investigator fan-out available in Claude Code. + +Both skills use the CLI directly. They do not require or configure MCP. + +Run `plugins/cix/scripts/sync-skills.sh` after changing either canonical Claude +Code skill. CI runs the same script with `--check` so the shared bodies cannot +silently drift while Codex keeps its native frontmatter. diff --git a/plugins/cix-openai/agents/cix-workspace-investigator.md b/plugins/cix-openai/agents/cix-workspace-investigator.md new file mode 100644 index 00000000..9d408db0 --- /dev/null +++ b/plugins/cix-openai/agents/cix-workspace-investigator.md @@ -0,0 +1,136 @@ +--- +name: cix-workspace-investigator +description: "Read-only deep-dive of ONE repository inside a workspace fan-out task. Receives the user task + project_path + seed chunks (with the main agent's commentary on what to trust and what to question) + an explicit deliverable. Returns whatever the main agent asked for, in the format they asked for. Use only when the main session is running the cix-workspace skill workflow and has identified one or more cross-project repos to investigate in parallel. Do not use for: single-repo questions (use cix search directly), tasks not framed by the cix-workspace skill, anything that requires editing or running code." +tools: Bash, Read, Grep +model: inherit +--- + +# `cix-workspace-investigator` + +You investigate ONE repository as part of a larger cross-project workspace task. +The main agent has full context about the user's goal; you only see what they +passed to you in this single prompt. + +## Where your assigned project lives — read this FIRST + +The `project_path` (or `project_name`) the main agent passed you comes in one +of two shapes. Behave very differently depending on which: + +- **Local working tree** — looks like `/Users/.../some-repo` or `~/code/foo`. + The repo exists on this machine. `Read`, `Grep`, `ls`, `cat` all work + against its files. You can still pass `-n ` to cix for + precision, but plain `cd && cix search …` also works. + +- **Remote-only cix project** — looks like `github.com//@` + (the form `cix list` shows for GitHub-attached projects). **The repo is + NOT on disk.** `find`, `ls -R`, `locate`, `Grep`, and `Read` will return + nothing useful — there's nothing to read locally. The cix server has the + files, chunks, and symbols; you reach them only through the `cix` CLI. + +**If the main agent gave you a server alias, use it on EVERY cix call.** +The `cix` CLI can have several named servers configured, and a workspace +(plus all its repos) lives on exactly one of them. The main agent will +tell you which — e.g. "this project is on server `corporate`". When it +does, add the global `--server ` flag to *every* `cix` command +below, alongside `-n `. Without it, cix talks to the +*default* server, where your assigned project doesn't exist, and every +call comes back empty (which looks like "nothing found" but is really +"wrong server"). If no alias was given, you're on the default server — +don't invent one. + +**How to tell which shape your project is:** run `cix list` once (on the +right server), then `grep` for the exact identifier the main agent gave +you. + +```bash +cix list --server | grep -F "" +# (drop --server if the main agent didn't name one — default server) +``` + +- A line starting with `[✓] /` → local working tree. +- A line starting with `[✓] github.com/` → remote-only. +- No match → tell the main agent the project isn't indexed and stop. + +If the project is remote-only, **do not** waste calls on `find`, `ls -R`, +`Grep`, or `Read`. They will silently return empty and look like you're +making progress when you're not. Treat the cix CLI as your only window into +the code. + +## Your tools + +You have a read-only toolkit for code investigation inside the assigned project: + +> **Server flag.** If the main agent named a server (`--server `), +> append it to *every* command in this list, e.g. +> `cix search "" -n --server `. The examples +> below omit it for brevity; add it whenever you were given an alias. + +- **`cix search "" -n `** — semantic / hybrid lookups + *inside the assigned project*. **Always pass `-n `** (the + identifier from `cix list`); without it, cix searches whatever project + matches the current working directory — i.e. the main session's project, + not yours. +- **`cix def -n `** — go-to-definition, scoped to + the assigned project. Same `-n` rule. +- **`cix refs -n `** — find every usage, scoped. +- **`cix symbols -n `** — symbol search, scoped. +- **`cix summary -n `** — overview of languages, top dirs, + key symbols. Good first call to orient inside a remote-only project. +- **Read** — open specific files. **Local projects only.** For remote-only + projects this returns nothing useful; rely on `cix search` chunk snippets + instead, and raise `--limit` if you need more context around a hit. +- **Grep** — exact literal strings inside a **local** project. Not for + semantic search, not for remote-only projects. +- **Bash** — for running the `cix` CLI itself. Do **not** use it to navigate + the filesystem hunting for the project (`find /`, `locate`, `ls -R ~`); + remote-only projects aren't there. Never mutate state. + +The cix index already covers this project — you don't need to (and can't) +re-index. + +## Hard rules — non-negotiable + +1. **Stay inside the assigned project — and on the assigned server.** + Every `cix` invocation MUST carry `-n `, plus + `--server ` if the main agent named one. Without `-n`, cix + searches the cwd's project (the main session's repo, not yours); + without the right `--server`, it queries the wrong backend and returns + empty. Don't read or query other workspace repos. If a finding requires + looking elsewhere, surface it as an uncertainty for the main agent to + fan out further. +2. **Never hunt the filesystem for a remote-only project.** No + `find /`, no `locate`, no `ls -R ~`, no recursive Grep across `/`. + If `cix list` shows the project as `github.com/…@…`, the files do + not exist on this machine — the cix server is the only source. Pretending + to search will burn tool calls and return nothing. +3. **Read-only.** No `Write`, no `Edit`, no `git` mutations, no shell side + effects. If you see a bug, describe it — don't fix it. +4. **No recursion.** Don't spawn further sub-agents. You are one level of + fan-out; the main agent handles synthesis. +5. **Follow the main agent's instructions exactly.** Output format, depth, + word budget, and what to look for are the main agent's call — not yours. + If they ask for three bullets, give three bullets. If they ask for a + five-step trace, give that. Don't volunteer extra structure. +6. **Report what you can't do.** If a file is missing, if `cix` returns + empty for a term that should exist, if a seed chunk doesn't match what + the main agent suggested, if the project is remote-only and chunks alone + don't carry enough context — say so explicitly. Don't fabricate findings + to fill a template, and don't quietly fall back to grep against the + wrong tree. + +## Output contract + +Return exactly what the main agent asked for, in exactly the format they +asked for. The main agent already knows how to parse the response they +requested. Don't add a preamble, don't add a meta-summary unless asked, +don't restate the task back at them. + +If the request is ambiguous, pick the most-likely interpretation, execute it, +and flag the ambiguity in one short line at the end. + +## What you are NOT + +You are not a generic code-explorer. You are not a planner. You are not a +reviewer. You are a focused, read-only investigator for one repo, working +under explicit per-call instructions from a main agent that already knows +the workspace and the user. diff --git a/plugins/cix-openai/skills/cix-workspace/SKILL.md b/plugins/cix-openai/skills/cix-workspace/SKILL.md new file mode 100644 index 00000000..41a09642 --- /dev/null +++ b/plugins/cix-openai/skills/cix-workspace/SKILL.md @@ -0,0 +1,721 @@ +--- +name: cix-workspace +description: Cross-project research workflow for cix workspaces. Load the `cix-workspace` skill explicitly when a request spans multiple repos and you want the full workflow guidance (which repos? what code? what changes?) plus the trust rules for interpreting workspace search responses. Bundles the cix-workspace-investigator sub-agent for parallel per-repo fan-out. Do not auto-trigger. +--- + +# `cix workspace` — Cross-Project Research Workflow + +You usually work inside one repo — your **primary project** — the +directory the user opened you in. Most tasks are fully contained there +and `cix search` / `cix definitions` / `cix references` are the right +tools. + +But some tasks are not contained. A request like "wire feature X +through the platform" can touch a half-dozen repos in different +languages, layers, and shapes — a service, a shared library, the +infra manifests, an API spec. Reading the primary repo alone gives +you 1/N of the picture. Worse, you don't know which N repos are +actually involved until you look. + +`cix workspace` is the tool for that. It searches every repo in a +named workspace at once and tells you: + +1. **Which repos are actually relevant to this request.** +2. **Which code in those repos is the entry point.** +3. **What changes need to land in each, and in what order.** + +Those three questions are the *goal* of using this skill. Don't jump +to implementation before you can answer all three with evidence. + +> **Prerequisite: a populated workspace.** This skill assumes the +> workspace already exists and its repos are indexed. If it doesn't, +> create and populate one first (owner/admin): `cix ws create ""`, +> then `cix ws "" add ` for each already-indexed repo — or +> clone new GitHub repos in via the dashboard. `cix ws` lists what's +> available; the main `cix` skill has the full management verb reference. + + +## First: which server hosts the workspace? + +The `cix` CLI can be configured with **several named servers** (a local +box, a remote corporate backend, …). Each server hosts its **own** set of +workspaces and projects — a workspace named `platform` on one server is +unrelated to anything on another. Every `cix` command targets the +**default** server unless you pass the global `--server ` flag (or +set `CIX_SERVER`). + +```bash +cix config show # lists configured servers; * marks the default +``` + +**A workspace and all its repos live on exactly one server.** So before +you run the workflow, decide which server you're on, then be **consistent**: +pass the *same* `--server ` to *every* command in the flow — +`cix ws`, workspace search, per-project drill-down, and the sub-agent +fan-out. Mixing servers mid-workflow (orient on server A, drill down on +the default) silently returns empty or wrong-repo results, because the +project simply doesn't exist on the other server. + +**Agent rule:** use the default server (no flag) unless the user names a +specific server, or the primary project's workspace isn't on the default. +Never guess an alias — run `cix config show` to see the configured names. +Once you know the alias, thread it through the whole workflow. The +examples below omit `--server` for readability; add it to **every** command +when the target workspace is on a non-default server. + + +## When to reach for workspace search + +| Signal in the user's request | What to do | +|---|---| +| Names a product / acronym you don't fully recognize from primary repo | Workspace search the acronym, see where it lives | +| "Add X to the Y flow", "wire Z into A" | Workspace search Y or Z — likely cross-cutting | +| "Across services", "between repos", "end-to-end" | Workspace search the feature | +| Talks about an event / topic / contract / API endpoint | Workspace search the event name | +| References infra / deployment alongside code | Workspace search — infra repo is probably in the workspace too | +| "How do I change X in production / staging" | Workspace search BUT look past top-1 — the answer is usually a manifests/config/contract repo even when a code repo ranks higher (rule 7 below) | +| Plain bugfix entirely inside one file | **Don't** workspace search. `cix search` is enough | +| User points at a specific symbol / file path | **Don't.** `cix definitions ` or just Read the path | + +If you're not sure, run `cix ws` once to see whether the primary +project is even part of a workspace. If it isn't, this skill doesn't +apply. + + +## The workflow + +The goal-driven loop. Don't shortcut it. Each step is fast. + +### Step 0 — orient + +```bash +cix config show # which servers exist? which is default? +cix ws # list workspaces on the (default) server +cix ws # describe — confirm repos are indexed (✓ count) +``` + +If `cix ws` doesn't list the workspace your task is about, it may live on +a different server — re-run with `--server ` (the alias from +`cix config show`) and keep that flag on every later command. Lock in the +server here, before searching. + +If the workspace shows `stale_fts_repos` in any search response later, +trust the dense ranking less — see the troubleshooting section. + +### Step 1 — answer "which repos?" + +Run workspace search with a **short, term-rich query**, not the full +user sentence: + +```bash +# GOOD — short, term-rich (a product acronym + an action verb) +cix ws platform search "rate-limit middleware" + +# BAD — full sentence dilutes BM25 with stopwords ("add", "to", "a") +cix ws platform search "Add a rate limit to every API endpoint" +``` + +Why short: the hybrid algorithm fuses BM25 (literal token match) with +dense (semantic). BM25 carries the project-gating signal — repos that +share zero vocabulary with the query drop out. Common words ("add", +"flow", "for") match everywhere and dilute that signal. + +Read the response: + +- **`projects[]` is the answer to Q1.** Sorted by `project_score` + (candidacy). Each entry has `bm25_score` (literal-token overlap) + and `dense_score` (semantic similarity). +- Projects below the per-query relative threshold are already + filtered out — you only see the survivors. +- Top entry's `project_score` is your reference. Entries at 60-100% + of top are core relevant. Entries at 40-60% are secondary. Below + 40% would have been dropped server-side. + +**Always include the primary project** even if workspace search ranks +it low — the user's task is rooted there. The workspace's other +repos are dependencies / consumers / providers / counter-parties. + +### Step 2 — answer "what code is relevant?" + +**Now switch from workspace search to per-project search.** Workspace +search is a *scoping* tool: it tells you which repos are in play and shows +a teaser of chunks, but that teaser is capped (round-robin, ~5 chunks per +repo) and is NOT where you read the code. Once you know the target repos, +drill into each one with single-project search (`cix search -n +`) or a `cix-workspace-investigator` sub-agent — that is +where the real, file-grouped depth comes from. Don't try to answer the +task from the workspace chunk panel alone. + +For each repo from step 1, look at the chunks panel. The chunk list +is interleaved by rank across surviving projects so each repo's top +hit appears early. Use these chunks as **starting points** for a +deeper read, not as the full answer. + +For repos other than the primary, you have two options: + +**A. Quick scan (≤ 2 repos to investigate):** use single-project +search directly via the CLI, scoped with `-n` to the project. Pass the +`project_path` from the workspace-search `projects[]` panel verbatim: + +```bash +# Search inside one specific project (-n = exact project ID from cix list / +# the workspace projects[] panel). --server keeps it on the same backend +# the workspace lives on — REQUIRED when that's not the default server. +cix search "rate limit middleware handler" -n --min-score 0 +cix search "rate limit middleware handler" -n --server corporate --min-score 0 +``` + +The per-project default `min_score` is `0.2` — light floor that +keeps abstract NL queries non-empty. For drill-down on a natural- +language question ("how does X work end-to-end"), pass `--min-score 0` +explicitly to be safe. For strict code-symbol matching, pass `0.4+`. + +Workspace repos are **external** (server-cloned), so once search points you at +a file you can read the actual source — not just the capped chunk teaser — +straight from the server's checkout: + +```bash +cix tree internal/api -n # browse the tree (one level) +cix file internal/api/handler.go -n # whole file +cix file internal/api/handler.go --lines 80:140 -n +``` + +> Prefer the CLI over a raw `curl … /api/v1/projects/{hash}/search`: the +> CLI resolves the right server (and its key) from your config, so you +> can't accidentally point `$CIX_URL`/`$CIX_KEY` at a *different* server +> than the workspace. If you do hand-roll curl, make sure the URL + key +> belong to the server that hosts this workspace. + +**B. Fan-out to sub-agents (≥ 3 repos, or you need a thorough read):** +spawn one `cix-workspace-investigator` sub-agent per relevant repo, in +parallel. See the dedicated [Sub-agent fan-out pattern](#sub-agent-fan-out-pattern) +section below for the four-part prompt template, including how to pass +seed chunks with your interpretive commentary. + +Run them concurrently (one message, multiple Agent tool calls). When +they report back, you have N independent reads to synthesize, not N +sequential rabbit-holes. + +### Step 3 — answer "what changes?" + +This is your job, not a sub-agent's. Sub-agents report findings; you +write the plan. + +For each relevant repo: + +- What needs to change (specific file:line, or a new file). +- Why (which step of the data flow this implements). +- Order constraints (e.g. "shared-models migration must deploy + before backend reads new field"). +- Tests that prove it works. + +Confirm with the user before any of this lands. The plan is the +deliverable of this skill; the implementation is a separate step. + +### Throughout — ask, don't guess + +Trigger a clarifying question when: + +- Top-2 projects are at near-equal `project_score` and have different + labels — the request might fit either repo, ask which. +- `bm25_score` is 0 across all projects → either the FTS index is + stale (see troubleshooting) OR the user's term doesn't exist + literally in any repo. Ask the user for the term that *would* + appear in code ("we call it `Order` in code, not `Trade`"). +- A sub-agent reports it can't find a clear entry point — surface + that uncertainty back to the user, don't paper over it. +- The implementation plan needs a deploy-order assumption — confirm + who owns each repo and what their cycle looks like. + +Don't ask if the answer is obvious from the chunks. The bar is "I +have two plausible interpretations and the wrong one costs the user +real time." + + +## Reading the projects panel — what the numbers mean + +``` +project-a@main 0.500 5 hits bm25 0.421 dense 0.556 +project-b@main 0.412 5 hits bm25 0.318 dense 0.498 +project-c@main 0.288 3 hits bm25 0.155 dense 0.362 +``` + +- `project_score` (first column): the α-blended candidacy in [0, 1]. + Top = strongest signal across both retrieval modes. +- `bm25_score` and `dense_score`: the raw per-mode signals. The + algorithm normalizes these per query before blending — useful for + diagnosis, not for sorting. +- If `bm25_score` >> `dense_score` for a project: it's relevant + because of literal token overlap (product name appears in code). + Trust the surface area but verify semantic relevance manually. +- If `dense_score` >> `bm25_score`: it's relevant because of + semantic similarity (handler shape matches the query intent) but + the literal term isn't there. Common when the user's term is a + product nickname not used in code. +- If both are near zero: you're seeing the project because nothing + else cleared the gate either. Treat with skepticism. + + +## Trust rules — making sense of the response + +These ten rules were derived from a calibration eval (113 synthetic +queries + 5 real engineering tasks against a mixed-domain workspace). +Apply them before acting on workspace-search output. Numbers below +are empirical, not vibes. + +### Rule 1 — `chunk.score >= 0.4` is the trust threshold + +Chunks with `score < 0.4` are noise about 75% of the time +(rank-inversion and weak-signal FPs from the relative project gate). +Skim them only when the higher-scored chunks don't answer the +question. With the default `min_score=0.4` you usually won't see them +at all; if you passed `min_score=0` (intentional broad sweep), apply +this rule yourself. + +### Rule 2 — `chunk.score == 0` is a BM25-only hit, not low confidence + +The chunk's project matched the literal query tokens via FTS5 but the +embedding side didn't surface it. These are valuable when the query +carries project-specific identifiers (CamelCase symbols, file names, +acronyms). Discount them when the query is a generic English word +(`error`, `data`, `config`) — common-word BM25 hits are noise. + +### Rule 3 — Top-1 of `projects[]` is correct ~70% of the time in real tasks + +The synthetic eval measured 91% on single-target queries; real +engineering tasks hit ~70% because real queries often span layers +(see rule 7). When the top-1 project doesn't match your task's +intent, **scan ranks 2–5 before reformulating** — the right repo is +usually there. The `projects[]` panel is the answer to "where do +the words live", not "where should the change happen". + +### Rule 4 — Drop down to single-project search for depth + +When `projects[]` shows the target at rank 1 with a clear lead +(`project_score` ≥ 1.5× the next), switch to per-project search: +`cix search -n ""` (add `--server ` when the +workspace is on a non-default server). You get file-grouped, deeper +results without the cross-project round-robin cap of 5 chunks per repo. +`-n` takes the exact `project_path` from `projects[]` (e.g. +`github.com/owner/repo@branch`) — that is the correct, working way to +target one project; don't use `-p` (a filesystem path) for a remote repo. + +### Rule 5 — `min_score=0` for intentional cross-project sweeps + +Default workspace `min_score` is `0.4`. For queries that should +legitimately span many repos ("authentication", "configuration +loading", "Kafka consumers"), pass `min_score=0` explicitly. +Expect `projects[]` to list 5–8 entries — that's the feature, not a +bug. Ignore rule 1 in this mode: many real positives sit below 0.4 +in genuine cross-cutting queries. + +### Rule 6 — Add a 3rd disambiguating token, carefully + +If two query words are each domain-overloaded (e.g. "client SDK" +could be the generated API client, the shared library, or a model +type), add a third word. **Prefer meta-tokens** (`endpoint`, +`route`, `handler`, `manifest`, `migration`, `config file`) over +tech-stack guesses (`grpc`, `kafka`, `terraform`) — wrong stack +guesses actively rotate the ranking away from the right answer. If +unsure of the stack, run the query without a disambiguator first, +read the top-1 project's language/path patterns, then refine. + +### Rule 7 — "Change X in production" → manifests repo, not code repo + +For tasks framed as deploying / configuring / overriding a feature, +the answer usually lives in a manifests / config / contract repo +(K8s overlays, Helm charts, OpenAPI specs, environment-specific +yaml). Workspace search ranks by token frequency, so the code repo +typically wins. Look at `projects[]` for repos with **manifests, +config, platform, deploy, contract, openapi, infra** in their +names — those are often the right targets even at rank 3–5. + +### Rule 8 — When top-1 doesn't fit, scan first, reformulate second + +If you think top-1 is wrong: + +1. First, scan ranks 2–5. The right project is there ~80% of the + time when the layer mismatch caused rule 3 to fail. +2. Only after scanning, reformulate. Reformulating before scanning + wastes a round-trip and risks the new query introducing fresh + layer confusion. + +### Rule 9 — For per-project NL drill-down, pass `min_score=0` explicitly + +When dropping from workspace to per-project search with a natural- +language query (e.g. "how does X work"), pass `min_score=0` to be +safe. The per-project default `min_score=0.2` is lighter than it +used to be (`0.4`) and usually fine, but abstract semantic queries +can score in the 0.2–0.3 range that the default still rejects. + +### Rule 10 — Words ≠ change location (the intent-vs-tokens watchword) + +Workspace search ranks projects by *where the words live*. Your +task is usually about *where the change should happen*. These +coincide ~70% of the time, not 91%. When in doubt: read the +chunks in ranks 2–5 before committing to a target repo. + +### Quick example — when rules 7 and 10 save you + +> User: "Change the database timeout for the staging environment of +> the order service." + +Workspace search ranks the **order-service code repo** at #1 (it's +where the word "database" appears most). But the change needs to +land in the **environment-platform manifests repo** at rank #4. If +you stopped at top-1 you'd edit the wrong file. Rules 7 and 10 +remind you to scan further. + + +## Primary project nuance + +You are typically `cd`'d into a single repo. That's the *primary +project*. The user's task is framed *from* that repo — they're +extending it, integrating with something it depends on, or wiring up +something that consumes it. + +Patterns: + +- **The change centers on primary, others are consumers/providers.** + Most common. Primary gets the bulk of the implementation; the + other repos get small adapter changes (new field consumption, new + webhook subscriber, new client method). +- **The change is in another repo, primary just calls it.** Less + common but real. Primary's role is the integration test or the + feature-flag flip; the heavy lifting is elsewhere. +- **The change is genuinely distributed.** Migrations, schema changes + rolling through many services, protocol bumps. Each repo gets a + coordinated change with deploy-order constraints. + +Workspace search tells you which pattern you're in. Don't assume. + + +## Sub-agent fan-out pattern + +When you have 3+ relevant repos, fan out. Sub-agents run with isolated +context — the main session stays clean (no per-repo code chunks bloating +it) and the investigations run in parallel. + +Use the dedicated **`cix-workspace-investigator`** sub-agent, which ships +with this skill. It's a thin, read-only shell around `cix search` / `cix +def` / `cix refs` / `Read` / `Grep` with three hard rules baked in: +stay inside the assigned project, no edits, no recursion. The +methodology — what to look for, what to report, in what format — is +**your** call, per spawn. The sub-agent follows your instructions; it +doesn't second-guess them. + +### The four parts of a good per-spawn prompt + +You'll write one prompt per repo. A good one has four parts: + +#### 1. The user's task, verbatim + +Sub-agents have zero prior context. Paste the original user request even +if it feels redundant — your interpretation might be wrong, and the +user's wording is the ground truth the sub-agent should reason from. + +#### 2. The project identifier you're assigning + +Pass it in the exact form `cix list` shows. Two shapes are possible: + +- **Local working tree:** `/Users/.../some-repo`. The repo exists on disk; + the sub-agent can use `Read`/`Grep` on top of cix. +- **Remote-only:** `github.com//@`. The repo is *not* on + disk — it's a GitHub-attached project indexed only by the cix server. + The sub-agent must rely entirely on `cix search/def/refs` (passing + `-n `) and the chunks they return. + +Workspace search output gives you the identifier as `project_path` on each +entry in `projects[]`. Paste that string verbatim into the sub-agent prompt, +and tell the sub-agent explicitly which shape it is so it doesn't waste +calls grepping a tree that isn't there. One repo per spawn. + +**Pass the server alias too.** If the workspace is on a non-default server, +the sub-agent's `cix search -n ` calls must carry the *same* +`--server ` — otherwise they hit the default server, where the +project doesn't exist, and come back empty. State it plainly in the prompt: +"This project lives on server `corporate`; add `--server corporate` to every +`cix` call." If you're on the default server, say so (or omit it) so the +sub-agent doesn't invent a flag. + +#### 3. Seed chunks **with your commentary** + +This is the part most often done badly. Don't just paste raw chunk +pointers and hope the sub-agent figures out what matters. You saw the +workspace search response; you have hunches about which chunks are real +entry points and which are noise; pass that down. + +For each chunk you cite, add one short line of interpretation. For +the response as a whole, flag suspicious signals: + +- Which chunk looks like the most likely entry point and why +- Which chunks look like test fixtures / dead code / wrong-layer the + sub-agent should de-prioritize +- Numeric signals that need a second opinion: `score=0` (BM25-only + literal — verify the token isn't a false friend), `score < 0.4` (low + confidence, possible rank-inversion), `bm25_score` high + `dense_score` + near zero (literal-only match — concept may not actually live here) +- Whether you suspect this repo is wrong-layer (rule 7) — tell the + sub-agent to confirm relevance before diving into the chunks + +**Example "good chunk block":** + +``` +Seed chunks from workspace search: +- `internal/gateway/server.go:412-418` (score 0.55) — looks like the + HTTP handler entry point for the rate-limit feature; confirm it + invokes the limiter middleware rather than just returning 429. +- `internal/gateway/middleware.go:89-93` (score 0.49) — middleware + registration site. Verify whether rate-limit is wired here or + elsewhere. +- `tests/integration/rate_limit_test.go` (score 0.41) — integration + test. Useful for understanding the expected shape, but not where + the change lands. Skim only. +- `pkg/shared/util.go:1-30` (score 0) — BM25-only hit, "limit" + appears in a comment. Almost certainly noise; skip unless you need + shared utilities. + +Panel-level notes: +- Server: this project is on `corporate` — pass `--server corporate` on + every cix call (it does NOT exist on the default server). +- Workspace ranked this project #1 with a clear lead (project_score + 1.000 vs next 0.860). High confidence this is the right repo. +- bm25_score=8.5, dense_score=0.54 — strong on both signals, not a + wrong-layer concern. +``` + +#### 4. Explicit deliverable + +Tell the sub-agent **exactly** what to return and in what shape. Each +task has different needs: + +- "Confirm whether this repo is in scope. Yes / no / partial + one + sentence why." +- "Find the entry point for the rate-limit middleware. Report + file:line of the entry and a five-step trace through the call + graph." +- "List every file that would need to change to add a new audit-log + event type. No code, just file path + one-line per-file reason." + +Vague deliverables (`"investigate this repo"`) → vague answers. + +### Anti-patterns to avoid + +- **"Investigate this repo for rate-limit"** — no deliverable. The + sub-agent guesses scope and you can't verify the result. +- **Three paragraphs of context with nested questions** — sub-agent + answers the wrong question. Pick one deliverable per spawn. +- **"Read all the auth code"** — unbounded. Either fails or returns a + wall of text. +- **Pasting raw chunks without interpretation** — you saw the + response, you have hunches about what matters. Sub-agent doesn't. + Skipping commentary throws away the most valuable thing you can pass + down. + +### Mechanics + +Run all sub-agents in **one message with multiple Agent calls** so they +execute in parallel. Wait for completion. Synthesize their reports +yourself — sub-agents don't see each other's work; you do. Surface +inconsistencies (e.g. two repos disagree on which event format is +canonical) back to the user. + +**Model inheritance.** `cix-workspace-investigator` declares `model: +inherit` in its frontmatter, so each spawn runs on the same model as the +main session. You don't need to pass `model:` on Agent calls. If you do +pass it, you'll override inheritance — only do that intentionally (e.g. +forcing a smaller/faster model for a trivially-bounded look-up). + + +## Worked example — why this skill exists + +A representative failure mode that motivated the hybrid algorithm: + +**The naïve approach:** running workspace search with a full natural- +language sentence ("Add feature X to product Y"). The pre-hybrid +implementation was pure-dense — it returned the N nearest vectors +regardless of how far away "nearest" actually was. Every repo in the +workspace surfaced, including repos that contained **zero literal +mentions** of either the feature name or the product code. Confidently +reporting all of them as "relevant" wasted time on completely +unrelated repos. + +**The structural failure:** + +1. Pure-dense fan-out cannot tell "no signal" apart from "weak + signal" — a vector search always returns the K nearest vectors. +2. Long natural-language queries dilute the few tokens that carry + the actual gating signal. +3. Without a sparse-retrieval channel, an acronym or unique + identifier query has nothing to lock onto. + +**What this skill teaches instead:** + +1. Query with **just the high-precision term** first — the product + acronym, the feature name, the unique symbol. Everything else + is noise. +2. Verify that projects with `bm25_score = 0` aren't masquerading + as relevant. After the hybrid landed, repos with no literal + matches AND only marginal dense similarity drop out automatically + via the project gate. +3. Confirm with the user before treating "this repo surfaced in + search" as "this repo is in scope for the change". + +**The lesson encoded in this skill:** + +- Step 1: query the term, not the sentence. +- Step 1: trust the project gate; if a repo dropped out, it dropped + out for a reason. +- Step 2: read the surface area from `projects[]` first, then read + the chunks as starting points. +- Step 3: never assume "in search results" == "in scope". Verify. + + +## Troubleshooting + +### `bm25_score` is 0.000 on every project + +The workspace was indexed before the FTS5 mirror existed and the +sparse half of the hybrid is empty. Hybrid degrades to pure-dense +fan-out — the same algorithm that produces the false-positive +failure mode described in the worked example above. + +The response includes `stale_fts_repos` listing the affected +project_paths. Fix: reindex each project (dashboard → project card → +reindex button, or `POST /api/v1/projects/{hash}/reindex`). +After reindex, BM25 populates incrementally per-file as chunks are +written. + +Until reindex completes, **don't trust the project gating** — the +algorithm is producing the old failure mode. Verify project relevance +by literal grep on the term. + +### `status: "empty"` despite obviously-relevant repos in the workspace + +Either: + +- The query terms don't appear literally in any repo AND the dense + similarity is below threshold for everything (project-gate dropped + everyone). Re-phrase with the term the code actually uses, or + lower `min_score`. +- Every workspace repo is still indexing. Check `pending_repos` in + the response. + +### `status: "partial_failure"` + +At least one repo errored out (`failed_repos` array names them). +Common cause: a missing or corrupt vector collection. The remaining +repos still returned results. Surface to the user; don't silently +treat as complete. + +### Top-2 projects are at near-equal candidacy + +The algorithm isn't confident which repo is more relevant. Possible +causes: + +- The feature genuinely lives in both. Ask the user which they + intended as primary scope. +- The query is too broad — both repos match generic vocabulary. + Re-query with a more specific term. +- One repo is a fork or duplicate. Confirm with `cix ws ` + describe. + +### One project absolutely dominates everything else + +Could be legit (the user's task is mostly contained in one repo and +that repo is just very dense with relevant content). Or could be a +single repo accidentally matching the user's stopwords across many +files. Spot-check: is the project's `bm25_score` driven by the +high-IDF term (the product name) or by common words? + +### Top-1 is wrong-layer (rule 7 / rule 10 in action) + +The top-1 project contains the words but isn't where the change +should land. Classic example: "deploy X to staging" → workspace +ranks the code repo for X at #1, but the staging overlay lives in +a manifests repo at rank #4. Or: "add API endpoint Y" → ranks the +backend implementation at #1, but the OpenAPI contract repo at #3 +must be updated first. + +**Fix:** scan ranks 2–5 explicitly. Look for projects whose names +hint at a different layer (`*-platform`, `*-manifests`, +`*-contracts`, `*-config`, `*-infra`, `openapi*`). If you see one, +that's probably your real target. + +### Disambiguator backfired — the query lost its grip + +You added a 3rd word to discriminate between two overloaded terms, +and the response is *worse* — top projects all have mediocre scores +and the right repo isn't among them anymore. This usually happens +when the added token belongs to a different stack than your target +(e.g. you guessed a transport / framework / library that the canonical +repo doesn't use), so the extra token rotates the ranking toward +unrelated repos. + +**Fix:** strip the guessed-stack token. Try a meta-token instead +(`endpoint`, `route`, `handler`, `manifest`, `migration`). Or: run +the 2-word query as-is, scan the top-1 project's path patterns and +language to see what stack it actually uses, then refine. + + +## Quick command reference + +```bash +# Servers (run first if more than one backend is configured) +cix config show # list servers; * marks the default +cix ws --server corporate # any command takes the global --server +# (CIX_SERVER=corporate also selects it; --server wins over the env var) + +# List workspaces +cix ws +cix ws list --json + +# Describe one workspace (always do this before searching) +cix ws platform +cix ws platform describe --json + +# List repos attached to a workspace +cix ws platform list +cix ws platform repos --verbose + +# Search a workspace +cix ws platform search "rate-limit middleware" +cix ws platform search "JWT validation" --top-projects 8 --top-chunks 30 +cix ws platform search "audit logging" --json +``` + +Flags: + +- `--top-projects N` — surface up to N projects in the panel + (default 10, max 50). Increase for very broad explorations. +- `--top-chunks K` — return up to K chunks total (default 20, max + 200). Round-robin interleaved across surviving projects. +- `--min-score F` — drop dense hits below cosine F before scoring. + **Default 0.4** (symmetric with per-project search default). + Pass `0` explicitly for intentional cross-project sweeps that + need long-tail recall — broad concepts like "authentication" or + "Kafka consumers" that legitimately live in many repos. Higher + values (0.5+) for queries you want laser-focused. +- `--json` — raw machine-readable response. + + +## TL;DR + +When the user's task plausibly spans more than one repo: + +0. `cix config show` → if more than one server, decide which one hosts + the workspace and thread the **same** `--server ` through every + command below (default server → no flag needed). +1. `cix ws` → find the workspace, then `cix ws ` describe it. +2. Workspace search with a **short, term-rich** query. +3. Read `projects[]` → that's your scope (Q1 answered). +4. For each repo in scope, either single-project search (`cix search + -n `) or spawn a `cix-workspace-investigator` sub-agent + — in parallel, with seed chunks, the server alias, AND your + interpretive commentary on what to trust. +5. Synthesize the sub-agent reports → plan changes per repo, with + order constraints (Q2 + Q3 answered). +6. Ask the user to confirm the scope and plan before implementing. + +If `bm25_score` is 0 across the board, the FTS index is stale — +fix it before trusting the result. diff --git a/plugins/cix-openai/skills/cix-workspace/agents/openai.yaml b/plugins/cix-openai/skills/cix-workspace/agents/openai.yaml new file mode 100644 index 00000000..c17d05dd --- /dev/null +++ b/plugins/cix-openai/skills/cix-workspace/agents/openai.yaml @@ -0,0 +1,6 @@ +interface: + display_name: "cix Workspace Research" + short_description: "Map changes across indexed repositories" + default_prompt: "Use $cix-workspace to map this task across repositories." +policy: + allow_implicit_invocation: false diff --git a/plugins/cix-openai/skills/cix/SKILL.md b/plugins/cix-openai/skills/cix/SKILL.md new file mode 100644 index 00000000..f207edad --- /dev/null +++ b/plugins/cix-openai/skills/cix/SKILL.md @@ -0,0 +1,314 @@ +--- +name: cix +description: Semantic code search and navigation via the cix index. Use this when finding code by meaning rather than exact strings — cross-file lookups, symbol navigation, "where is X used", "how does Y work", "find authentication middleware", or exploring an unfamiliar codebase. Covers search, definitions, references, symbol search, file lookup, and indexing. +--- + +# Code Index (`cix`) — Semantic Code Search & Navigation + +You have access to `cix`, a semantic code index that understands the +codebase via embeddings + AST parsing. The right reflex is **"cix when +you don't have a pointer; grep when you do."** + +**Always invoke `cix` through the harness's shell or terminal execution +tool — do not call human-facing cix slash commands from inside a turn.** +An agent driving its own work should run `cix search …` / `cix def …` / +`cix refs …` directly so the output flows through the normal tool-result +pipeline and stays machine-parseable. The `cix` executable must be +available in the environment; if it is missing, follow the installation +instructions for the current integration rather than substituting MCP. + +## When to use which + +**Reach for `cix` first when:** +- The starting point is open-ended ("how does indexing work?", "find the + authentication middleware", "where is the main entry point?") +- You need cross-file navigation (definitions / references / callers) +- You're searching by *meaning*, not by an exact string + (`"JWT validation"` should find `verifyToken` even without that phrase) +- You're exploring an unfamiliar package or codebase + +**Skip `cix`, use Read / Grep / Glob directly when:** +- A failing test or stack trace already names the file and function — + just `Read` it +- You're chasing an exact literal: a specific error message, a config + key, a commit-message phrase, an import path +- You're inside dependencies (`node_modules`, `vendor`, `.venv`) — they + aren't indexed +- You're editing a non-code file (Dockerfile, yaml, lockfile) + +If `cix` returns nothing relevant after one well-formed query, fall +back to grep — don't loop on cix. + + +## Pick the cheapest tool that answers the question + +When you already know a symbol's **name**, reach for `cix def` / `cix refs` +before `cix search`. They return **metadata only** (file, line, signature, +call sites) — no source bodies — so they cost roughly an order of magnitude +fewer tokens. Measured on one real symbol in this codebase: + +| Command | Returns | Output size | +|---|---|---| +| `cix def ` | definition location + signature | ~250 B | +| `cix refs ` | every call site (file:line) | ~1 KB | +| `cix search ""` | matching code **with full source bodies** | ~7 KB | + +So `cix search` is ~28× the bytes of `cix def` and ~6× `cix refs` for the +same target. Rule of thumb: + +- Know the name, want "where is it defined / who calls it" → `cix def` / + `cix refs`. Cheap, precise, no source noise. +- Don't know the name, searching by *meaning* → `cix search`. +- Only escalate to `cix search` for a *known* symbol when you actually need + to read the surrounding implementation, not merely locate it. + + +## Commands Reference + +### Semantic Search — find code by meaning +```bash +cix search "authentication middleware" +cix search "database connection retry logic" +cix search "error handling in payment flow" --limit 20 +cix search "config parsing" --in ./internal/config/ +cix search "API routes" --lang go +cix search "main entry point" --exclude bench/fixtures --exclude legacy +``` + +**Flags:** +- `--in ` — restrict to file or directory (can repeat) +- `--exclude ` — drop a directory or substring from results (can repeat) +- `--lang ` — filter by language (can repeat) +- `--limit ` — max **files** returned (CLI default: 10) — output is + grouped per file with all matches inside, so 10 files ≈ many snippets. + **For agent use, prefer `--limit 5`**: five files is enough for most + lookups and keeps the result compact. This is a usage recommendation, + not a change to the CLI default — bump it back up when you genuinely + need broader exploration. +- `--min-score ` — minimum relevance 0.0–1.0 (default: **0.4**) + +### Go to Definition — find where a symbol is defined +```bash +cix definitions HandleRequest +cix def AuthMiddleware --kind function +cix def Config --file ./internal/config.go +``` +Aliases: `definitions`, `def`, `goto`. Flags: `--kind`, `--file`, `--limit`. + +### Find References — find where a symbol is used +```bash +cix references HandleRequest +cix refs AuthMiddleware --limit 50 +cix usages UserService --file ./internal/api/ +``` +Aliases: `references`, `refs`, `usages`. Flags: `--file`, `--limit`. + +### Symbol Search — find symbols by name +```bash +cix symbols handleRequest +cix symbols User --kind class +cix symbols Auth --kind function --kind method +``` +Flags: `--kind` (function/class/method/type, repeatable), `--limit`. + +### File Search — find files by path pattern +```bash +cix files "config" +cix files "middleware" --limit 20 +``` + +### Read Files & List Directories — EXTERNAL repos only +```bash +cix file internal/httpapi/server.go -n github.com/owner/repo@main # whole file +cix file README.md --lines 1:40 -n github.com/owner/repo@main # line range +cix file main.go --lines 120 -n github.com/owner/repo@main # single line +cix tree -n github.com/owner/repo@main # repo root, one level +cix tree internal/httpapi -n github.com/owner/repo@main # a subdir +``` + +These read from the server's checkout of an **external (GitHub-backed)** repo — +the way to inspect actual file contents and the file tree of a repo you do +**not** have locally (workspace / external projects). + +**Use them only for OTHER repos, not the project you're in.** For the current / +local project, the files are already on disk — use the native `Read`, `Grep`, +and `ls`/`cat` tools, which are faster and don't round-trip the server. `cix +file`/`cix tree` on a local project return an error telling you exactly that. +`--lines N:M` is 1-based inclusive (`N`, `N:`, `:M` also work). Big files / +directories are capped and marked truncated. + +### Project Overview +```bash +cix summary # languages, top dirs, key symbols +cix status # indexing status + file watcher status +cix list # all indexed projects +``` + +### Indexing +```bash +cix init [path] # register + index + start watcher +cix reindex # incremental +cix reindex --full # full reindex +cix cancel # cancel an in-flight indexing run +cix watch # start file-change auto-reindex daemon +cix watch stop # stop daemon +``` + +The watcher auto-reindexes on file change — manual `reindex` is rarely +needed. `cix status` shows whether the watcher is running and the +last-sync timestamp. + +### Servers — talk to more than one cix backend + +`cix` can be configured with several **named servers** (e.g. a local +box and a remote corporate server). One is the **default**; every +command targets the default unless you pass `--server `. + +```bash +cix config show # lists servers; * marks the default +cix --server corporate search "rate limiter" # run any command against a named server +cix search "rate limiter" --server corporate # --server is global; either position works +``` + +Servers are managed through `cix config` (persisted in +`~/.cix/config.yaml`): + +```bash +cix config set server.corporate.url https://cix.corp.internal +cix config set server.corporate.key +cix config set default_server corporate # change which server is the default +cix config unset server.corporate # remove a server +cix config unset server.corporate.key # clear just its key +``` + +The legacy single-server keys still work and operate on the **default** +server, so existing setups keep working unchanged: +`cix config set api.url ` / `cix config set api.key `. The +`--api-url` / `--api-key` flags override the selected server's URL/key +for a single invocation. + +**Agent rule:** use the default server (no flag) unless the user names a +specific server. Only add `--server ` when the task explicitly +targets that named backend; never guess an alias — run `cix config show` +to see the configured names if unsure. + +### Workspaces — cross-repo search + management + +A **workspace** groups several indexed repos into one corpus for +cross-project search. List / describe / search: + +```bash +cix ws # list workspaces +cix ws "" # describe (repos + status) +cix ws "" search "" # hybrid cross-repo search +``` + +Management (owner/admin): + +```bash +cix ws create "" [--description "…"] # create +cix ws "" add # link an indexed project (local or external) +cix ws "" remove # unlink +cix ws "" rename "" # rename +cix ws "" update [--name ""] [--description "…"] +cix ws "" delete [-y] # delete (prompts; -y skips) +``` + +`add`/`remove` take a project's absolute path, host_path +(`github.com/owner/repo@main`), or 16-hex `path_hash` (see `cix list`); no +arg defaults to the current directory. `add` links an **already-indexed** +project — it does not clone (to clone a new GitHub repo into a workspace, +use the dashboard). `delete` drops the workspace + its links, not the +projects. + +For the full cross-project *research* workflow — which repos to trust, how +to read the hybrid bm25/dense scores — use the dedicated **`cix-workspace`** +skill through the explicit skill-invocation syntax supported by the current +harness. + + +## Search quality — what scores mean + +Default `--min-score 0.4` is calibrated for the production embedding +model (CodeRankEmbed-Q8 with path-aware preamble). Rough landscape: + +| Score | Meaning | +|----------|---------------------------------------------------------| +| 0.65+ | Exact / very strong match — almost certainly relevant | +| 0.50–0.65| Strong match — usually relevant | +| 0.40–0.50| Weaker match — sometimes useful, sometimes not | +| <0.40 | Noise — filtered out by default | + +**If a query returns nothing**, lower the floor explicitly: +`--min-score 0.2` for very specific or long-tail queries. Don't drop +below 0.2 — results below that are noise. + + +## Writing better queries — leverage path-aware embedding + +Each chunk is embedded with its file path, language, and symbol name in +the preamble. This means **mentioning a file/dir/symbol you already +know about boosts ranking**: + +```bash +# Generic +cix search "validation" +# Better — pins the search to the auth area +cix search "validation in auth middleware" +# Even better when you know the symbol +cix search "ValidateToken" --kind function +``` + +Natural-language queries that name the *kind of thing* and *where it +lives* outperform single-word queries. + + +## Usage Patterns + +### Exploring unfamiliar code (`cix`'s strongest case) +```bash +cix summary # project structure, top dirs +cix search "main entry point server" # find where it starts +cix search "database connection setup" # find DB wiring +cix search "request handler" --in ./api # narrow to API +``` + +### Tracing a symbol end-to-end +```bash +cix def HandleRequest # where is it defined? +cix refs HandleRequest # who calls it? +cix search "HandleRequest error handling" # how are errors handled? +``` + +### Chasing a known target (often grep is enough) +```bash +# Stack trace says "internal/auth/middleware.go:42 — invalid token" +# → just Read that file. No cix needed. + +# Config key "max_concurrent_requests" used somewhere? +# → grep is more precise. +``` + +### Narrowing scope +```bash +cix search "middleware" --in ./api/ +cix search "config" --in ./cmd/ --exclude legacy +cix refs Config --file ./internal/server.go +``` + + +## Tips + +- Search queries are natural language, not regex. Write what you'd ask + a colleague. +- Output groups by file: each result line is a file with all relevant + matches inside, ordered top-to-bottom by line number. The + `[best 0.NN]` is the score of the top hit in that file. +- `cix def` is a faster path than `cix symbols` when you already know + the exact name. +- `--exclude` complements `--in` — use it to drop noisy dirs (`bench/`, + `legacy/`, vendored code) inline without touching `.cixignore`. +- The watcher keeps the index fresh. If results feel stale, check + `cix status` first — `Watcher: ✗ not running` is the usual cause. +- Don't loop. If a query returns nothing useful after one well-phrased + attempt + one `--min-score 0.2` retry, drop to grep. diff --git a/plugins/cix-openai/skills/cix/agents/openai.yaml b/plugins/cix-openai/skills/cix/agents/openai.yaml new file mode 100644 index 00000000..fcb4a80a --- /dev/null +++ b/plugins/cix-openai/skills/cix/agents/openai.yaml @@ -0,0 +1,6 @@ +interface: + display_name: "cix Code Search" + short_description: "Semantic code navigation with the cix CLI" + default_prompt: "Use $cix to find the implementation behind this behavior." +policy: + allow_implicit_invocation: true diff --git a/plugins/cix/scripts/sync-skills.sh b/plugins/cix/scripts/sync-skills.sh index 1a520d61..fc3ac900 100755 --- a/plugins/cix/scripts/sync-skills.sh +++ b/plugins/cix/scripts/sync-skills.sh @@ -1,6 +1,7 @@ #!/usr/bin/env bash -# sync-skills.sh — keep plugin-bundled skill files byte-identical with -# the canonical sources under skills/. +# sync-skills.sh — keep Claude Code plugin bundles byte-identical with their +# canonical sources, and keep Codex skill bodies synchronized with native +# Codex frontmatter. # # Fix #19 acceptance: the plugin ships byte-identical copies of files # that have a single source of truth elsewhere in the repo. Without @@ -15,6 +16,13 @@ # # skills/cix-workspace/agents/cix-workspace-investigator.md # → plugins/cix/agents/cix-workspace-investigator.md +# → plugins/cix-openai/agents/cix-workspace-investigator.md +# +# plugins/cix/skills/cix/SKILL.md (body + name/description) +# → plugins/cix-openai/skills/cix/SKILL.md (Codex frontmatter) +# +# skills/cix-workspace/SKILL.md (body + name/description) +# → plugins/cix-openai/skills/cix-workspace/SKILL.md (Codex frontmatter) # # Out of scope: skills/cix/SKILL.md vs plugins/cix/skills/cix/SKILL.md — # those are INTENTIONALLY different. The plugin version carries extra @@ -37,10 +45,21 @@ REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)" SRC=( "skills/cix-workspace/SKILL.md" "skills/cix-workspace/agents/cix-workspace-investigator.md" + "skills/cix-workspace/agents/cix-workspace-investigator.md" ) DST=( "plugins/cix/skills/cix-workspace/SKILL.md" "plugins/cix/agents/cix-workspace-investigator.md" + "plugins/cix-openai/agents/cix-workspace-investigator.md" +) + +CODEX_SRC=( + "plugins/cix/skills/cix/SKILL.md" + "skills/cix-workspace/SKILL.md" +) +CODEX_DST=( + "plugins/cix-openai/skills/cix/SKILL.md" + "plugins/cix-openai/skills/cix-workspace/SKILL.md" ) MODE="copy" @@ -86,6 +105,54 @@ for i in "${!SRC[@]}"; do fi done +# Codex requires only name and description in SKILL.md frontmatter. Preserve +# the canonical body verbatim while dropping Claude-only routing/tool fields; +# Codex invocation policy and UI metadata live in agents/openai.yaml. +render_codex_skill() { + awk ' + BEGIN { fence = 0; skill_name = ""; skill_description = "" } + /^---$/ { + fence++ + if (fence == 2) { + print "---" + print "name: " skill_name + print "description: " skill_description + print "---" + } + next + } + fence == 1 { + if ($0 ~ /^name: /) { + skill_name = substr($0, 7) + } else if ($0 ~ /^description: /) { + skill_description = substr($0, 14) + } + next + } + fence >= 2 { print } + ' "$1" +} + +for i in "${!CODEX_SRC[@]}"; do + src="$REPO_ROOT/${CODEX_SRC[$i]}" + dst="$REPO_ROOT/${CODEX_DST[$i]}" + tmp="$(mktemp "${TMPDIR:-/tmp}/cix-codex-skill.XXXXXX")" + render_codex_skill "$src" >"$tmp" + + if [[ "$MODE" == "check" ]]; then + if ! diff -q "$tmp" "$dst" >/dev/null 2>&1; then + echo "drift: ${CODEX_SRC[$i]} != ${CODEX_DST[$i]} (Codex projection)" >&2 + drift=1 + fi + elif ! cmp -s "$tmp" "$dst"; then + mkdir -p "$(dirname "$dst")" + cp "$tmp" "$dst" + echo "synced: ${CODEX_SRC[$i]} → ${CODEX_DST[$i]} (Codex projection)" + fi + + rm -f "$tmp" +done + if [[ "$MODE" == "check" && $drift -ne 0 ]]; then echo "" >&2 echo "Run plugins/cix/scripts/sync-skills.sh (no args) to fix." >&2 diff --git a/plugins/cix/skills/cix-workspace/SKILL.md b/plugins/cix/skills/cix-workspace/SKILL.md index 0a06bfc7..ad280484 100644 --- a/plugins/cix/skills/cix-workspace/SKILL.md +++ b/plugins/cix/skills/cix-workspace/SKILL.md @@ -1,6 +1,6 @@ --- name: cix-workspace -description: Cross-project research workflow for cix workspaces. Manual-invocation skill — load explicitly via `/cix-workspace ` when a request spans multiple repos and you want the full workflow guidance (which repos? what code? what changes?) plus the trust rules for interpreting workspace search responses. Bundles the cix-workspace-investigator sub-agent for parallel per-repo fan-out. Do not auto-trigger. +description: Cross-project research workflow for cix workspaces. Load the `cix-workspace` skill explicitly when a request spans multiple repos and you want the full workflow guidance (which repos? what code? what changes?) plus the trust rules for interpreting workspace search responses. Bundles the cix-workspace-investigator sub-agent for parallel per-repo fan-out. Do not auto-trigger. user-invocable: true allowed-tools: Bash(cix *), Agent --- diff --git a/plugins/cix/skills/cix/SKILL.md b/plugins/cix/skills/cix/SKILL.md index c354d105..1c78808a 100644 --- a/plugins/cix/skills/cix/SKILL.md +++ b/plugins/cix/skills/cix/SKILL.md @@ -26,13 +26,13 @@ You have access to `cix`, a semantic code index that understands the codebase via embeddings + AST parsing. The right reflex is **"cix when you don't have a pointer; grep when you do."** -**Always invoke `cix` through the Bash tool — do not call the -`/cix:search`, `/cix:def`, … slash commands from inside a turn.** Those -shortcuts exist for humans typing in the UI; an agent driving its own -work should run `cix search …` / `cix def …` / `cix refs …` as Bash so -the output flows through the normal tool-result pipeline and stays -machine-parseable. The `cix` CLI is bundled — the plugin auto-installs -it on first use if your system doesn't have it. +**Always invoke `cix` through the harness's shell or terminal execution +tool — do not call human-facing cix slash commands from inside a turn.** +An agent driving its own work should run `cix search …` / `cix def …` / +`cix refs …` directly so the output flows through the normal tool-result +pipeline and stays machine-parseable. The `cix` executable must be +available in the environment; if it is missing, follow the installation +instructions for the current integration rather than substituting MCP. ## When to use which @@ -242,7 +242,8 @@ projects. For the full cross-project *research* workflow — which repos to trust, how to read the hybrid bm25/dense scores — use the dedicated **`cix-workspace`** -skill (`/cix-workspace `). +skill through the explicit skill-invocation syntax supported by the current +harness. --- diff --git a/skills/README.md b/skills/README.md index 0bf9efa8..3d3ab80e 100644 --- a/skills/README.md +++ b/skills/README.md @@ -1,5 +1,9 @@ # Skills +The canonical CLI skills are packaged for both Claude Code and Codex. The Codex +copies under `plugins/cix-openai/` reuse the canonical bodies with native Codex +frontmatter, generated by `plugins/cix/scripts/sync-skills.sh`. + ## cix — Semantic Code Search Teaches an AI agent when to reach for `cix` (semantic, cross-file, @@ -8,6 +12,15 @@ non-code files). ### Install +With the Codex marketplace: + +```bash +codex plugin marketplace add dvcdsys/code-index +# Open /plugins, select Code Index, and install cix — Code Search. +``` + +Or for Claude Code manually: + ```bash cp -r skills/cix ~/.claude/skills/cix ``` @@ -97,4 +110,4 @@ cross-cutting prompts. The workspace flow is heavier than single-repo `cix search` (multi-repo fan-out, sub-agent spawns) and only pays off when you've made the call that cross-project research is what you actually need. Pair it with `/cix` for the single-repo navigation -guidance. \ No newline at end of file +guidance. diff --git a/skills/cix-workspace/SKILL.md b/skills/cix-workspace/SKILL.md index 0a06bfc7..ad280484 100644 --- a/skills/cix-workspace/SKILL.md +++ b/skills/cix-workspace/SKILL.md @@ -1,6 +1,6 @@ --- name: cix-workspace -description: Cross-project research workflow for cix workspaces. Manual-invocation skill — load explicitly via `/cix-workspace ` when a request spans multiple repos and you want the full workflow guidance (which repos? what code? what changes?) plus the trust rules for interpreting workspace search responses. Bundles the cix-workspace-investigator sub-agent for parallel per-repo fan-out. Do not auto-trigger. +description: Cross-project research workflow for cix workspaces. Load the `cix-workspace` skill explicitly when a request spans multiple repos and you want the full workflow guidance (which repos? what code? what changes?) plus the trust rules for interpreting workspace search responses. Bundles the cix-workspace-investigator sub-agent for parallel per-repo fan-out. Do not auto-trigger. user-invocable: true allowed-tools: Bash(cix *), Agent --- From fecb57eac0ccbdfbcaef2ed69488cd067de7b4c2 Mon Sep 17 00:00:00 2001 From: dvcdsys Date: Tue, 8 Sep 2026 13:06:02 +0200 Subject: [PATCH 2/2] fix(server): update x/crypto for SSH DoS advisories --- server/go.mod | 2 +- server/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/server/go.mod b/server/go.mod index 7ea63f43..6baf29cb 100644 --- a/server/go.mod +++ b/server/go.mod @@ -12,7 +12,7 @@ require ( github.com/oapi-codegen/runtime v1.6.0 github.com/philippgille/chromem-go v0.7.0 github.com/tetratelabs/wazero v1.12.0 - golang.org/x/crypto v0.55.0 + golang.org/x/crypto v0.56.0 golang.org/x/sync v0.22.0 golang.org/x/time v0.15.0 modernc.org/sqlite v1.54.0 diff --git a/server/go.sum b/server/go.sum index c9dad587..d0c8c2c2 100644 --- a/server/go.sum +++ b/server/go.sum @@ -181,8 +181,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M= -golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis= +golang.org/x/crypto v0.56.0 h1:GUh5Ii4J5jtcseSMiRqr1jXCNHoxjeV9Fmekc2oLy6Y= +golang.org/x/crypto v0.56.0/go.mod h1:OMW5y6CY9l38uPLmxU6l6pwcXp1obtLo3e6gT7gQR2I= golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM= golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=