Skip to content

Listing skills

GET /skills

The skills a key can reach — the discovery counterpart of GET /prompts. On-prem only.

Two shapes, depending on the scope you ask for. Pass exactly one of project_id or organization_id.

ParameterNotes
project_idthe effective skill set for one project
organization_idthe promotion ladder, plus every project you can reach

Both key transports work here, as on the read endpoints.

Listing vs. resolving

GET /skills?project_id=… and GET /skills/resolve return the same resolved set for a project — listing is resolve at format=index, wrapped with the project's name and flow mode. Use resolve when you want bodies; use this when you want an inventory, or when you want the organisation view.

Project scope

bash
curl -s "$IM_URL/skills?project_id=8112d9c4-8334-43dd-a3c0-436b5cf1f475" \
  -H "X-API-Key: $IM_KEY"
json
{
  "project_id": "8112d9c4-8334-43dd-a3c0-436b5cf1f475",
  "project_name": "sample",
  "flow_mode": "ai_assisted",
  "total": 2,
  "skills": [
    { "name": "sonar-clean-code",
      "version": { "sha": "aacea0c4cd13", "version_label": "v1.0" },
      "resolution": { "tier": "organization", "shadowed": [], "pinned": false } },
    { "name": "test",
      "version": { "sha": "a28b804cda57", "version_label": "v1.0" },
      "resolution": { "tier": "project", "shadowed": [], "pinned": false } }
  ]
}

Skills are tiered — project, organisation and global — and this returns the effective set after resolution, including which tier won and what it shadowed. That is the same resolution the runtime performs, so what you list is what a consumer would actually get. See Resolution & pins.

flow_modestring

The project's publishing flowreview_required, direct_publish or ai_assisted. Tells you what a publish into this project will do before you attempt one.

Organisation scope — the promotion ladder

A skill is promoted one tier at a time: project → organisation → global. Organisation scope reports that ladder rather than flattening it, because "available to every project in this org" and "lives in one project" are different facts about a skill, and a picker has to tell them apart.

bash
curl -s "$IM_URL/skills?organization_id=d7fb6107-1188-4f7c-97e2-978403f3e3be" \
  -H "X-API-Key: $IM_KEY"
json
{
  "organization_id": "d7fb6107-1188-4f7c-97e2-978403f3e3be",
  "organization_skills": [
    {
      "name": "helper",
      "version": { "sha": "aacea0c4cd13" },
      "resolution": { "tier": "organization" },
      "promoted_from": { "scope": "project", "scope_id": "831172bf-bf48-4720-b1dd-df9b891cca48" }
    }
  ],
  "installed_skills": [
    {
      "name": "helper",
      "version": { "sha": "f10c3b7e21a4" },
      "resolution": { "tier": "global" },
      "promoted_from": { "scope": "organization", "scope_id": "d7fb6107-1188-4f7c-97e2-978403f3e3be" }
    }
  ],
  "projects": [
    {
      "project_id": "8112d9c4-8334-43dd-a3c0-436b5cf1f475",
      "project_name": "sample",
      "flow_mode": "ai_assisted",
      "skills": [ "…" ]
    }
  ]
}
organization_skillsarray

Skills promoted to this organisation, and therefore available to every project in it. Each carries resolution.tier: "organization".

installed_skillsarray

Global-tier skills installed at organisation level, with resolution.tier: "global".

Listed separately because they cannot be found by organisation id at all — a global skill is stored with no owning organisation, and is reachable only through its install record.

promoted_fromobject

The origin scope of a promoted skill: { "scope", "scope_id" }. Answers "where did this come from?" — a project id for an organisation skill, an organisation id for a global one.

Origin only. The source skill id and version sha are withheld, since a caller reading an organisation listing is not necessarily a member of the project a skill was promoted from.

Absent on a skill that was created at its tier rather than promoted into it.

Project-tier skills are not repeated at the top level

They belong to one project, and appear in that project's resolved set under projects[] — which is where shadowing applies.

The example above is the ordinary case rather than a contrived one: the same name, helper, appears at two tiers, because promotion copies a skill upward and leaves the original in place. So read resolution.tier rather than inferring the tier from the bucket it arrived in.

Two consequences worth designing for:

  • A global skill nobody installed is not listed. Listing it would advertise a skill no project can reach.
  • Delisting is a kill-switch. A delisted global stops resolving even for existing installs, and disappears from this listing at the same moment.

Scope is exclusive

Both parameters, or neither, is a 422.

That is deliberate rather than lenient: silently preferring one would let you believe you had asked an organisation-wide question and quietly receive a single project.

No limit here

GET /prompts accepts and validates a limit. GET /skills does not — a limit in the query string is ignored rather than rejected, because a project's resolved skill set is bounded by resolution, not by pagination.

Who can list what

Listing requires project membership — being on the project, not merely in its organisation. Super Admins count as members of every project in their organisation.

Organisation scope is filtered by the same rule: you get the projects you can actually open, so an organisation you belong to but whose projects you were never added to returns 200 with an empty projects list, not a 403. "Nothing here" stays distinguishable from "you may not look".

Errors

StatusMeaning
401key missing, invalid or revoked
403not a member of that project, or that organisation
422both scope parameters, or neither

Next

Copyright © 2026 elsai foundry.