> Source: https://wexa.ai/docs/context/code-sync

# Code sync

Code sync keeps the code graph in step with a connected repository. It needs a project-scoped credential holding `fabric:codesync.write`. The flow is:

1. Sign in with the editor extension or the launcher ([Launcher and editor extension](/docs/sdks-and-apis/launcher-and-editor-extension)). The token is scoped to one organization, department and project.
2. Check the scope: `curl -sS -H "Authorization: Bearer $FABRIC_API_KEY" https://fabric.wexa.ai/v1/codesync/names`
3. Register the repository with `POST /v1/codesync/connector`, then `POST /v1/codesync/bootstrap` with `{"repo_url":"https://github.com/acme/widgets","repo_name":"acme/widgets","ttl_seconds":3600}`.
4. Catch up with `POST /v1/codesync/ingest-async`, then poll `GET /v1/codesync/ingest-status/{job_id}`. The daemon then sends `POST /v1/codesync/ingest-event` as you work.
5. Read the graph with [`search-code`](/docs/context/search-code) and [`fetch-code`](/docs/context/fetch-code).

## Limits

| Behavior | Detail |
|---|---|
| Grant | `fabric:codesync.write` for all credentialled routes except `names`; project-scoped token required. |
| Scope | Organization and project are overwritten from the token before forwarding. |
| Request size | Bodies over the cap are refused, not truncated. |
| No ingestion target | `502` `unconfigured`. |
| Status polling | Counts against project and organization quota. |
| Webhook auth | HMAC-SHA256 signature, not a credential. |

**More details**

### The flow in words

1. **Sign in.** A browser authorization grants the client a token scoped to one organization, department and project. That scope decides where the code lands.
2. **Register the checkout.** The client ensures the project's repository connection exists and picks up the addresses it needs. A launcher on a cloud machine can get a short-lived token instead of storing a long-lived one.
3. **Catch up.** The first pass is a bulk ingestion of the existing tree, submitted as a job because it can take a while. The response carries a job identifier and a separate call reports its status. See [ingestion](/docs/context/ingestion).
4. **Keep up.** The daemon sends incremental events as you work, so the graph tracks the working tree rather than the last full pass.
5. **Read.** Agents search and fetch the code graph, which lives beside the rest of the project's [context graph](/docs/context/context-graph) under the same isolation and governance.

**Code sync** keeps the code graph in step with a connected repository, so a codebase becomes context a question can be asked of instead of a folder an agent is handed one file at a time.

You need a project-scoped credential holding the `fabric:codesync.write` grant, which the sign-in flow gives the client. A token with the grant but no project is refused with `"code sync requires a project-scoped token (re-consent with a project selected)"`.

### How it works

The flow is the one the Wexa MCP server's clients use, so an editor can do it without a separate credential.

Three pieces cooperate, and they are usually installed together:

- **The daemon does the work.** `fabric-sync` runs locally, watches the git working tree and pushes what changed to the gateway. It is the only piece that touches your code.
- **The editor extension drives it.** The VS Code extension, which ships as Codegraph, is where you sign in and see whether sync is running and whether anything failed. It activates on a git working tree or an existing sync configuration, writes the configuration file the other clients read, and starts and supervises the daemon.
- **The launcher connects an assistant.** `fabric-connect` registers the checkout, starts or reuses the daemon, queues a catch-up pass, then proxies a stdio connection to the gateway for an editor agent or desktop client.

Every request is pinned to its token's scope. The organization and project on the payload are overwritten from the token before the request is forwarded, so a client cannot ingest into a project it was not granted whatever it sends. The check happens at the edge, where the caller is. See [scope and server-bound arguments](/docs/get-started/core-ideas#know-what-scope-a-call-carries).

### Check which scope your credential resolves to

`GET /v1/codesync/names` needs no grant. It tells a client which organization, department, project and user its credential resolves to before it sends data anywhere. Names come back alongside ids where the platform can resolve them, so treat them as present when available.

**Read the resolved scope**

**REST API**

```bash
curl -sS -H "Authorization: Bearer $FABRIC_API_KEY" \
  https://fabric.wexa.ai/v1/codesync/names
```

**TypeScript SDK**

```ts
import { Fabric } from '@wexa-fabric/sdk'

const fabric = new Fabric()
const scope = await fabric.names()
```

**Python SDK**

```python
from wexa import Fabric

fabric = Fabric()
scope = fabric.names()
```

The other routes have no SDK method; clients call them over REST.

### Register a repository

Two calls prepare a project. Both are idempotent, and the client makes them for you at sign-in.

- `POST /v1/codesync/connector` finds or provisions the codebase connector for the token's project and triggers a connector synchronisation, so the codebase ontology exists before the first ingest. Call it once at the start of a session. If the connector authority is unreachable it fails loudly rather than half-succeeding.
- `POST /v1/codesync/bootstrap` binds a repository, by URL and name, to the project's connector and returns the binding the GitHub webhook later looks up. A push for a repository never bootstrapped is refused, and the refusal says so.

```bash
curl -sS -X POST https://fabric.wexa.ai/v1/codesync/bootstrap \
  -H "Authorization: Bearer $FABRIC_API_KEY" -H "Content-Type: application/json" \
  -d '{"repo_url":"https://github.com/acme/widgets","repo_name":"acme/widgets","ttl_seconds":3600}'
```

### Send changes to the graph

Choose by what you have. The first three are alternatives, not stages.

| You have | Use |
|---|---|
| one file-save event, want it visible immediately | `POST /v1/codesync/ingest-event` |
| a batch of files from one scan | `POST /v1/codesync/bulk-ingest` |
| a whole repository, first extraction | `POST /v1/codesync/ingest-async`, then poll `GET /v1/codesync/ingest-status/{job_id}` |
| commits landing on a branch you do not watch locally | the GitHub receiver, after `bootstrap` |

The two synchronous routes forward a client-shaped body and return the ingestion target's JSON verbatim with its status code. A body over the size cap is refused rather than truncated. With no ingestion target configured they answer `502` `unconfigured` rather than pretending to have accepted the data.

`ingest-async` queues the work and returns a `job_id` at once. The editor extension uses it for a full extraction. The queued payload carries the token's organization and project whatever the client sent.

Poll the status route on an interval, not in a tight loop. It counts against the project and organization quota windows like any other call.

### Read the graph directly

`GET /v1/codesync/bolt-credentials` returns connection details for clients that query the project's graph rather than going through the gateway. These are credentials, so do not log the response and do not cache it where a second project could read it.

### Receive GitHub pushes

`POST /v1/codesync/webhook/github` takes no bearer token. It is authenticated by an HMAC-SHA256 signature over the raw body in `X-Hub-Signature-256`, and is covered with the other inbound callbacks on [Webhooks](/docs/automation/webhooks).

- A `ping` answers `200`.
- A wrong or missing signature answers `401`.
- Any other non-push event answers `200` and names the event as ignored.
- A push for a repository never bootstrapped answers `404` `repo_not_bound`.

For a bound repository the receiver collects the added, modified and removed paths across the commits and stamps the repository node with the branch and head commit. It deletes the removed paths, so the graph never drifts worse than stale. The exact responses are in the [reference](/docs/context/code-sync-api).

### Search and read the code

The **code graph** is the representation of a repository's code: its files, its symbols and the calls between them. Two tools read it, and both are available in every deployment regardless of which services are configured:

- [`search-code`](/docs/context/search-code) finds code by text, symbol or identifier and returns the matching lines with their file paths.
- [`fetch-code`](/docs/context/fetch-code) reads a span of a file, or one symbol, once you know where to look.

Search first and fetch second, so an agent spends its context on the few spans that matter rather than whole files. Structural questions, such as what calls this or what it imports, are traversals that [`query-context`](/docs/context/query-context) answers against the same graph.

### What this is not

**It is not a connector.** A repository connection differs from one in four ways:

- It cannot be provisioned. A repository is not in the set [`provision-connector`](/docs/connectors/provision-connector) can provision. See [connectors](/docs/connectors/overview).
- The client establishes it, over the code-sync surface, as part of signing in, with no provisioning step first.
- It mints no skills. Provisioning a connector creates one skill per action it supports, and a repository has no actions for an agent to call.
- Its output is a graph, not a capability: a connector gives an agent things it can do, a repository connection gives it code it can read.

The two overlap only in that both end with something queryable in the project. They are governed by different grants and named differently on purpose.

**It is not the [knowledge base](/docs/context/knowledge-base).** The code graph is structure, found by searching text and traversing relationships rather than by similarity to a question. Design documents about the code are prose and belong in the knowledge base.

**It is not the [data catalog](/docs/context/create-ontology).** The catalog describes data assets outside Wexa; the code graph holds a representation of the code itself.
