> ## Documentation Index
> Fetch the complete documentation index at: https://docs.caylex.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Search Skills by Tag

> Find every skill carrying a given tag across all of your projects — or a specific set of them — in a single call, plus the parallel search for global skills across navigators.

[Skills](/platform/projects) can carry **tags** in their `SKILL.md` frontmatter (`tags: [finance, onboarding]`). Tags are a great way to group related skills — but skills live inside individual projects, so answering "which skills across my workspace are tagged `finance`?" would normally mean listing every project's skills and filtering client-side.

The `GET /skills` endpoint does this in one call: it searches **across projects** in your tenant and returns every skill that carries the tag, along with each match's project and file manifest.

<Note>
  Looking for **global skills** — the ones attached to a [Navigator](/platform/navigators) in the Navigator Library rather than to a single project? Those live under a parallel endpoint, `GET /navigator-global-skills`. Jump to [Search global skills by tag](#search-global-skills-by-tag).
</Note>

## Endpoint used

| Method & path           | Purpose                                                                                   |
| ----------------------- | ----------------------------------------------------------------------------------------- |
| `GET /skills?tag={tag}` | Return every skill tagged `{tag}` in your tenant, optionally scoped to a set of projects. |

### Query parameters

| Parameter | Required | Default | Description                                                                                                                                                                                          |
| --------- | -------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `tag`     | yes      | —       | The exact tag to match.                                                                                                                                                                              |
| `project` | no       | `all`   | Scope of the search. Pass `all` for every project in your tenant, or **repeat** the parameter to restrict to a set — each value is a project **name** or **UUID** (`project=Support&project=6f1c…`). |
| `page`    | no       | `1`     | Page number (1-based).                                                                                                                                                                               |
| `size`    | no       | `50`    | Items per page (max `200`).                                                                                                                                                                          |

<Note>
  Tags live on the **skill bundle** (from its `SKILL.md` frontmatter), not on individual bundled files. Matching is an exact, case-sensitive comparison against the tags as they were uploaded.
</Note>

<Note>
  Project scoping accepts either the project **name** (exact, case-sensitive — URL-encode spaces, so `Support Team` becomes `Support%20Team`) or its **UUID**. Passing a name or UUID that doesn't exist in your tenant returns `404`.
</Note>

## Response shape

The endpoint returns a **plain JSON array** (not the cursor-paginated envelope used by some other list endpoints). Each item is a matched skill with its project and current-revision file manifest — the `SKILL.md` body is omitted to keep the response compact:

```json theme={null}
[
  {
    "id": "b3f1…",
    "project_id": "6f1c…",
    "project_name": "Support Team",
    "slug": "refund-policy",
    "name": "Refund Policy",
    "description": "How to evaluate and process refund requests.",
    "tags": ["finance", "support"],
    "file_count": 2,
    "total_size_bytes": 8123,
    "revision": 3,
    "original_uploader": { "id": "…", "email": "you@acme.com" },
    "last_uploaded_by": { "id": "…", "email": "you@acme.com" },
    "created_at": "2026-06-01T12:00:00Z",
    "last_uploaded_at": "2026-06-20T09:30:00Z",
    "files": [
      { "path": "examples.md", "size_bytes": 4096, "content_type": "text/markdown", "kind": "reference" },
      { "path": "scripts/calc.py", "size_bytes": 4027, "content_type": "text/x-python", "kind": "script" }
    ]
  }
]
```

<Tip>
  Need the full `SKILL.md` body or a bundled file's contents? Use the per-skill detail endpoint (`GET /projects/{project_id}/skills/{skill_id}`) or a file endpoint with the `id`/`path` values returned here.
</Tip>

## The procedure

<Steps>
  <Step title="Pick your scope">
    Search your whole workspace with `project=all` (the default), or narrow to specific projects by repeating `project=` with names or UUIDs.
  </Step>

  <Step title="Call the endpoint">
    `GET /skills?tag={tag}` with your platform access token. The result is every matching skill across the requested scope.
  </Step>

  <Step title="Use the results">
    Each item tells you which `project_name`/`project_id` the skill lives in and lists its files. Follow up with the per-skill endpoints if you need the `SKILL.md` body or file contents.
  </Step>
</Steps>

## Full example

Find every skill tagged `finance` across the workspace and print where each one lives. The `project` tab shows how to scope the same search to specific projects.

<Tabs>
  <Tab title="Python">
    ```python search_skills.py theme={null}
    import os

    import requests

    BASE_URL = "https://api.caylex.ai/api/v1"
    HEADERS = {"Authorization": f"Bearer {os.environ['CAYLEX_PLATFORM_TOKEN']}"}


    def search_skills(tag: str, projects: list[str] | None = None) -> list[dict]:
        # `project` defaults to "all"; pass a list of names/UUIDs to scope it.
        params = [("tag", tag)]
        params += [("project", p) for p in (projects or ["all"])]
        resp = requests.get(f"{BASE_URL}/skills", headers=HEADERS, params=params)
        resp.raise_for_status()
        return resp.json()


    def main() -> None:
        # Whole workspace:
        skills = search_skills("finance")

        # Or scope to a set of projects (names or UUIDs):
        # skills = search_skills("finance", projects=["Support Team", "Billing"])

        for skill in skills:
            files = ", ".join(f["path"] for f in skill["files"]) or "(no bundled files)"
            print(f"[{skill['project_name']}] {skill['name']} — {files}")


    if __name__ == "__main__":
        main()
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript searchSkills.ts theme={null}
    const BASE_URL = "https://api.caylex.ai/api/v1";
    const headers = { Authorization: `Bearer ${process.env.CAYLEX_PLATFORM_TOKEN}` };

    interface SkillSearchItem {
      project_name: string;
      name: string;
      files: { path: string }[];
    }

    async function searchSkills(
      tag: string,
      projects: string[] = ["all"],
    ): Promise<SkillSearchItem[]> {
      const params = new URLSearchParams({ tag });
      for (const p of projects) params.append("project", p); // repeatable
      const res = await fetch(`${BASE_URL}/skills?${params}`, { headers });
      if (!res.ok) throw new Error(`Search failed: HTTP ${res.status}`);
      return res.json();
    }

    async function main() {
      // Whole workspace, or pass e.g. ["Support Team", "Billing"] to scope it.
      const skills = await searchSkills("finance");
      for (const skill of skills) {
        const files = skill.files.map((f) => f.path).join(", ") || "(no bundled files)";
        console.log(`[${skill.project_name}] ${skill.name} — ${files}`);
      }
    }

    main();
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    BASE="https://api.caylex.ai/api/v1"
    AUTH="Authorization: Bearer $CAYLEX_PLATFORM_TOKEN"

    # Every skill tagged "finance" across the whole workspace
    curl -G "$BASE/skills" -H "$AUTH" --data-urlencode "tag=finance"

    # Scope to a set of projects (names or UUIDs; repeat --data-urlencode)
    curl -G "$BASE/skills" -H "$AUTH" \
      --data-urlencode "tag=finance" \
      --data-urlencode "project=Support Team" \
      --data-urlencode "project=6f1c0b3e-1e2a-4c9d-8f0a-2b7c5d9e1234"
    ```
  </Tab>
</Tabs>

## Search global skills by tag

**Global skills** are attached to a [Navigator](/platform/navigators) in the Navigator Library instead of to a single project. A navigator's global skills are shared with every project that navigator is connected to, so they don't belong to any one project — which means the project-scoped `GET /skills` search above intentionally **excludes** them.

To search global skills, use the parallel `GET /navigator-global-skills` endpoint. It works just like `GET /skills`, but the scope is a set of **navigators** instead of projects, and each result carries the owning navigator instead of a project.

### Endpoint used

| Method & path                            | Purpose                                                                                            |
| ---------------------------------------- | -------------------------------------------------------------------------------------------------- |
| `GET /navigator-global-skills?tag={tag}` | Return every global skill tagged `{tag}` in your tenant, optionally scoped to a set of navigators. |

### Query parameters

| Parameter   | Required | Default | Description                                                                                                                                                                                                                 |
| ----------- | -------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `tag`       | yes      | —       | The exact tag to match.                                                                                                                                                                                                     |
| `navigator` | no       | `all`   | Scope of the search. Pass `all` for every navigator in your tenant, or **repeat** the parameter to restrict to a set — each value is a navigator **name**, **api name**, or **UUID** (`navigator=Support&navigator=6f1c…`). |
| `page`      | no       | `1`     | Page number (1-based).                                                                                                                                                                                                      |
| `size`      | no       | `50`    | Items per page (max `200`).                                                                                                                                                                                                 |

<Note>
  Tag matching is identical to the project search: an exact, case-sensitive comparison against the skill's `SKILL.md` frontmatter tags. Passing a navigator name/UUID that doesn't exist in your tenant returns `404`.
</Note>

### Response shape

Same plain JSON array as the project search, but each item identifies the owning **navigator** (`navigator_identity_id` + `navigator_name`) and sets `source` to `"global"`:

```json theme={null}
[
  {
    "id": "a1d2…",
    "navigator_identity_id": "9c4e…",
    "navigator_name": "Support Navigator",
    "source": "global",
    "slug": "refund-policy",
    "name": "Refund Policy",
    "description": "How to evaluate and process refund requests.",
    "tags": ["finance", "support"],
    "file_count": 2,
    "total_size_bytes": 8123,
    "revision": 3,
    "original_uploader": { "id": "…", "email": "you@acme.com" },
    "last_uploaded_by": { "id": "…", "email": "you@acme.com" },
    "created_at": "2026-06-01T12:00:00Z",
    "last_uploaded_at": "2026-06-20T09:30:00Z",
    "files": [
      { "path": "examples.md", "size_bytes": 4096, "content_type": "text/markdown", "kind": "reference" },
      { "path": "scripts/calc.py", "size_bytes": 4027, "content_type": "text/x-python", "kind": "script" }
    ]
  }
]
```

<Tip>
  Need the full `SKILL.md` body or a bundled file's contents for a global skill? Use the per-navigator detail endpoints (`GET /navigator-global-skills/{navigator_id}/skills/{skill_id}` and its file routes) with the `navigator_identity_id`/`id`/`path` values returned here.
</Tip>

### Example

Find every global skill tagged `finance` across all navigators, and print which navigator owns each one. The `navigator` tab shows how to scope the same search to specific navigators.

<Tabs>
  <Tab title="Python">
    ```python search_global_skills.py theme={null}
    import os

    import requests

    BASE_URL = "https://api.caylex.ai/api/v1"
    HEADERS = {"Authorization": f"Bearer {os.environ['CAYLEX_PLATFORM_TOKEN']}"}


    def search_global_skills(tag: str, navigators: list[str] | None = None) -> list[dict]:
        # `navigator` defaults to "all"; pass a list of names/UUIDs to scope it.
        params = [("tag", tag)]
        params += [("navigator", n) for n in (navigators or ["all"])]
        resp = requests.get(f"{BASE_URL}/navigator-global-skills", headers=HEADERS, params=params)
        resp.raise_for_status()
        return resp.json()


    def main() -> None:
        # Every navigator:
        skills = search_global_skills("finance")

        # Or scope to a set of navigators (names or UUIDs):
        # skills = search_global_skills("finance", navigators=["Support Navigator"])

        for skill in skills:
            files = ", ".join(f["path"] for f in skill["files"]) or "(no bundled files)"
            print(f"[{skill['navigator_name']}] {skill['name']} — {files}")


    if __name__ == "__main__":
        main()
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript searchGlobalSkills.ts theme={null}
    const BASE_URL = "https://api.caylex.ai/api/v1";
    const headers = { Authorization: `Bearer ${process.env.CAYLEX_PLATFORM_TOKEN}` };

    interface NavigatorSkillSearchItem {
      navigator_name: string;
      name: string;
      files: { path: string }[];
    }

    async function searchGlobalSkills(
      tag: string,
      navigators: string[] = ["all"],
    ): Promise<NavigatorSkillSearchItem[]> {
      const params = new URLSearchParams({ tag });
      for (const n of navigators) params.append("navigator", n); // repeatable
      const res = await fetch(`${BASE_URL}/navigator-global-skills?${params}`, { headers });
      if (!res.ok) throw new Error(`Search failed: HTTP ${res.status}`);
      return res.json();
    }

    async function main() {
      // Every navigator, or pass e.g. ["Support Navigator"] to scope it.
      const skills = await searchGlobalSkills("finance");
      for (const skill of skills) {
        const files = skill.files.map((f) => f.path).join(", ") || "(no bundled files)";
        console.log(`[${skill.navigator_name}] ${skill.name} — ${files}`);
      }
    }

    main();
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    BASE="https://api.caylex.ai/api/v1"
    AUTH="Authorization: Bearer $CAYLEX_PLATFORM_TOKEN"

    # Every global skill tagged "finance" across all navigators
    curl -G "$BASE/navigator-global-skills" -H "$AUTH" --data-urlencode "tag=finance"

    # Scope to a set of navigators (names or UUIDs; repeat --data-urlencode)
    curl -G "$BASE/navigator-global-skills" -H "$AUTH" \
      --data-urlencode "tag=finance" \
      --data-urlencode "navigator=Support Navigator" \
      --data-urlencode "navigator=6f1c0b3e-1e2a-4c9d-8f0a-2b7c5d9e1234"
    ```
  </Tab>
</Tabs>

## Next steps

<CardGroup cols={2}>
  <Card title="Sync skills from your repo" icon="rotate" href="/cookbooks/sync-skills">
    Keep a folder of `SKILL.md` files in version control and push changes to a Caylex project from CI.
  </Card>

  <Card title="Platform Authentication" icon="key" href="/auth/platform-authentication">
    Create and manage the platform access token these recipes use.
  </Card>
</CardGroup>
