Platform
ScaiWave ScaiGrid ScaiCore ScaiBot ScaiDrive ScaiKey Models Tools & Services
Solutions
Organisations Developers Internet Service Providers Managed Service Providers AI-in-a-Box
Resources
Support Documentation Blog Downloads
Company
About Research Careers Investment Opportunities Contact
Log in

Quickstart

In five minutes you'll have a published skill bound to a workspace and resolvable from the runtime. We'll use a trivial "summarise" skill so you can focus on the surface, not the content.

You need:

  • A ScaiGrid API key with scaiskills:publish and scaiskills:bind (any tenant admin has both).
  • tar and curl (or the language equivalents below).
bash
1
2
3
export SCAIGRID_HOST="https://scaigrid.scailabs.ai"
export SCAIGRID_API_KEY="sgk_..."
export WORKSPACE_ID="ten_..."   # your tenant / workspace id

1. Register the skill identity#

Register the slug first — it owns all future versions.

bash
1
2
3
4
5
6
7
8
curl -X POST "$SCAIGRID_HOST/v1/modules/scaiskills/skills" \
  -H "Authorization: Bearer $SCAIGRID_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "slug": "summarise",
    "visibility": "private",
    "description": "Summarise a passage in three sentences."
  }'
python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import httpx, os
res = httpx.post(
    f"{os.environ['SCAIGRID_HOST']}/v1/modules/scaiskills/skills",
    headers={"Authorization": f"Bearer {os.environ['SCAIGRID_API_KEY']}"},
    json={
        "slug": "summarise",
        "visibility": "private",
        "description": "Summarise a passage in three sentences.",
    },
).json()
print(res["data"]["id"])
javascript
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
const res = await fetch(`${process.env.SCAIGRID_HOST}/v1/modules/scaiskills/skills`, {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.SCAIGRID_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    slug: "summarise",
    visibility: "private",
    description: "Summarise a passage in three sentences.",
  }),
});
console.log((await res.json()).data.id);

Save the returned skill.id and the slug summarise.

2. Build a bundle#

A bundle is a .tar.gz with a SKILL.md at the root. The YAML frontmatter is the manifest; everything below the closing --- is the body the LLM eventually reads.

bash
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
mkdir -p summarise/references
cat > summarise/SKILL.md <<'EOF'
---
name: summarise
version: 0.1.0
description: Summarise a passage in three sentences.
triggers:
  - summarise
  - tl;dr
permissions: []
secrets: []
EOF
echo "When the user asks for a summary, produce exactly three sentences." >> summarise/SKILL.md

tar -czf summarise-0.1.0.tar.gz -C summarise SKILL.md references

3. Publish the version#

bash
1
2
3
curl -X POST "$SCAIGRID_HOST/v1/modules/scaiskills/skills/summarise/versions" \
  -H "Authorization: Bearer $SCAIGRID_API_KEY" \
  -F "bundle=@summarise-0.1.0.tar.gz"

The response carries the content_hash (SHA-256), the storage_uri, and status: "published". Re-uploading the same bytes will dedup on hash.

4. Bind the skill to a scope#

Pin to the exact version for now. @latest and ^0.1 are also valid in the version field. Use the skill.id you saved in step 1.

bash
1
2
3
4
5
6
7
8
9
curl -X POST "$SCAIGRID_HOST/v1/modules/scaiskills/bindings" \
  -H "Authorization: Bearer $SCAIGRID_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"skill_id\": \"$SKILL_ID\",
    \"version\": \"0.1.0\",
    \"scope_type\": \"workspace\",
    \"scope_id\": \"$WORKSPACE_ID\"
  }"

Because the manifest declared no permissions and no secrets, pending_grants is false and the binding is active immediately.

5. Resolve the scope#

This is what the runtime calls per turn.

bash
1
2
3
4
5
6
7
curl -X POST "$SCAIGRID_HOST/v1/modules/scaiskills/resolve" \
  -H "Authorization: Bearer $SCAIGRID_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"scope_type\": \"workspace\",
    \"workspace_id\": \"$WORKSPACE_ID\"
  }"

You get back the lightweight manifest list — slug, version, description, triggers — and a cache_ttl_ms of 60 000. The full body is fetched only when the model decides to call skills.view on the slug.

What just happened#

  • POST /skills wrote a mod_scaiskills_skills row owned by your workspace.
  • POST /skills/{slug}/versions validated the bundle, deduped against existing content hashes, stored at s3://.../scaiskills/{skill_id}/{content_hash}.tar.gz, and persisted the parsed manifest on the version row.
  • POST /bindings resolved 0.1.0 to a concrete published version, walked its requires.skills (none here), built an empty lockfile, and flipped pending_grants to false.
  • POST /resolve looked up active, non-pending bindings for the workspace, deduped by skill_id with user > channel > workspace precedence, and returned the lightweight manifests. Result is now cached in Redis for 60 seconds.

Next#

Updated 2026-05-18 15:01:32 View source (.md) rev 12