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

Publish as model

A published Core appears in ScaiGrid's model catalogue and is callable through POST /v1/inference/chat exactly like any other backend. This is how you let arbitrary ScaiGrid clients chat with the agent without knowing they're talking to a ScaiCore program.

This page is about the ScaiGrid wrapper's publish surface. For how the program itself answers — its DSL, its flows, its tool calls — see /docs/scaicore.

What publish does#

When you call POST /cores/{id}/publish, the wrapper:

  1. Creates a BackendModel row with provider_type=scaicore and connection_config.core_id set.
  2. Creates a FrontendModel row with slug scaicore/{tenant_slug}/{core_slug}, the Core's name, description (pulled from metadata.description or source.identity.persona), the Core's avatar, and capabilities = {tool_use: true, streaming: false}.
  3. Wires the front-end model to the back-end with a ModelBackend link.
  4. Writes published, published_model_id, published_backend_id, published_slug into the Core's metadata so unpublish can find it again.
  5. Optionally adds the new model slug to any model groups you list — with scope validation: non-super-admins cannot add to global groups or to partner / tenant groups they don't belong to.

The Core stays running (or whatever state it was in). Publication is metadata-only — the Core itself doesn't restart.

Publish#

bash
1
2
3
4
curl -X POST "$SCAIGRID_HOST/v1/modules/scaicore/cores/$CORE_ID/publish" \
  -H "Authorization: Bearer $SCAIGRID_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "group_ids": ["mg_internal_chat", "mg_qa"] }'
python
1
2
3
4
5
6
core = httpx.post(
    f"{os.environ['SCAIGRID_HOST']}/v1/modules/scaicore/cores/{core_id}/publish",
    headers={"Authorization": f"Bearer {os.environ['SCAIGRID_API_KEY']}"},
    json={"group_ids": ["mg_internal_chat", "mg_qa"]},
).json()["data"]
print(core["metadata"]["published_slug"])
javascript
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const res = await fetch(`${process.env.SCAIGRID_HOST}/v1/modules/scaicore/cores/${coreId}/publish`, {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.SCAIGRID_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ group_ids: ["mg_internal_chat", "mg_qa"] }),
});
const { data: core } = await res.json();
console.log(core.metadata.published_slug);

group_ids is optional. If omitted (or if the caller lacks models:manage), the new model exists in the catalogue but is not added to any group — clients with group-restricted access will not see it.

If the Core is already published, the call returns a 400 VALIDATION_ERROR ("Core is already published as a model"). Use sync to update an existing publication.

Call the published model#

The slug is your standard ScaiGrid model id:

bash
1
2
3
4
5
6
7
curl -X POST "$SCAIGRID_HOST/v1/inference/chat" \
  -H "Authorization: Bearer $SCAIGRID_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "scaicore/acme/approval-agent",
    "messages": [{"role": "user", "content": "Please review this expense."}]
  }'

Routing, accounting, audit, and rate-limiting all work the same as for any other model. The dispatcher resolves the scaicore provider and forwards the request into the Core through its HostEnvironment.

Sync after edits#

If you change the Core's name, description, persona, or avatar after publishing, the FrontendModel row goes stale. The publishing service exposes a sync() method that re-reads the Core and rewrites the FrontendModel's display_name, description, system_prompt_template, avatar_url, and metadata_. Today this is called internally on edit paths; there is no separate HTTP endpoint for it.

Unpublish#

bash
1
2
curl -X POST "$SCAIGRID_HOST/v1/modules/scaicore/cores/$CORE_ID/unpublish" \
  -H "Authorization: Bearer $SCAIGRID_API_KEY"

Unpublish removes the slug from every model group it was added to, deletes the FrontendModel (which cascades the ModelBackend link), deletes the BackendModel, and clears the published_* keys from the Core's metadata. The Core itself is untouched.

If the Core was never published, you get a 400 VALIDATION_ERROR ("Core is not published").

Scope rules for group_ids#

The wrapper validates each requested group against the caller's scope:

Caller Allowed groups
Super admin Any (global, partner, tenant).
Partner admin partner scoped to your partner; tenant scoped to your tenants.
Tenant admin tenant scoped to your tenant.

Groups outside your scope are silently dropped from the request — the publish still succeeds, but the model is not added to those groups. There is no error for "you tried to add to a group you can't see." If you need the explicit feedback, list groups via the standard /v1/models/groups endpoints first.

What you can't do (yet)#

  • Stream from a published Core. Capabilities are set with streaming: false. The Core's response is materialised then returned; long-running flows that yield tokens incrementally are not exposed through /v1/inference/chat streaming today.
  • Direct OpenAI-compat dispatch. Published Cores work through the native /v1/inference/chat endpoint. The /oai/v1/ compat layer routes through the same dispatcher, so it will work, but the wrapper is built around the native API as primary (see ScaiGrid's API hierarchy notes).

Common gotchas#

  • No groups, no visibility. Publishing without group_ids leaves the model out of every group. Clients with group-restricted scopes won't see it. If you want public visibility for the tenant, add the slug to your tenant's default model group.
  • Slug collisions. Slug is scaicore/{tenant_slug}/{core_slug} — already-unique-by-design, no collision possible unless you somehow forge a tenant slug. If you do hit a collision, the underlying DB write will fail with a uniqueness error.
  • Re-publish requires unpublish. Calling publish on an already-published Core errors out. Unpublish first, then publish again. Edits to the published row use sync(), not republish.
Updated 2026-05-18 15:01:29 View source (.md) rev 11