Publish and install through the API¶
The concept behind publications is explained in Sharing and reuse.
A key holding the management capability does everything an administrator does in the console
with a bundle: publish, install, sync, and detach a copied member
(Manage organisations through the API shows how to switch
that capability on). The routes here come in the same two shapes: a path with no organisation in
it is your own organisation, and a path naming one (/organisations/{id}/...) is an organisation
below you.
For a bundle kept as files in a repository, the artific command calls these routes for you:
Release a bundle with the artific command.
Publishing¶
POST /publications creates the offer — a name, who may see it (visibility), and whether it is
listed right away:
curl -s -X POST "$CORE_URL/publications" \
-H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
-d '{"name": "starter-bundle", "visibility": "subtree", "status": "listed"}'
PATCH /publications/{pid} changes the description, and only the description: the name and the
visibility stay as they were, and a body naming either is refused. On an app that is already
listed in the marketplace the new text shows as pending_description on your own reads, and goes
live when Artific next lists a version of the app after its review.
POST /publications/{pid}/versions publishes a version — from rows of your own library, or as a
manifest handed over whole:
curl -s -X POST "$CORE_URL/publications/pub_4Kd9.../versions" \
-H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
-d '{"members": [{"kind": "prompt", "id": "prm_9Fb2..."}]}'
GET /publications, GET /publications/{pid} and the covers beside them answer exactly what the
console shows of your own offer; GET /publications/{pid}/entitlements shows who is entitled to
it. POST .../submit asks Artific to review a catalogue publication; the review itself stays
Artific's, as does the review queue of GET /catalogue.
Installing¶
GET /available-publications shows what your organisation may install; POST /subscriptions
installs one:
curl -s -X POST "$CORE_URL/subscriptions" \
-H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
-d '{"publication_id": "pub_4Kd9..."}'
A required parameter with no value leaves the subscription at needs_configuration rather than
refusing it; PATCH /subscriptions/{sid} supplies the value afterwards, and PATCH .../secrets
a credential on its own. A bundle that signs people in through an OAuth application this
deployment has not configured waits at needs_configuration too, with last_error reading
unconfigured_client:<name> (the preview lists the name under clients.unconfigured); ask your
operator to configure it, then send PATCH /subscriptions/{sid} with the body {} to re-check
and start the install. GET /subscriptions, GET .../{sid} and POST .../preview (what
installing would mean, writing nothing) work the same way the console's do.
Syncing and forking¶
POST /subscriptions/{sid}/sync asks directly for the sync a new version, a new config or a
new credential would otherwise cause on its own:
curl -s -X POST "$CORE_URL/subscriptions/sub_1Ac7.../sync" \
-H "Authorization: Bearer $CORE_KEY"
When the subscription is not linked, diverged or stale, this answers 409 with a fixed
code (sync_not_now:<status>) rather than a sentence. POST .../members/{member}/fork detaches
one member from the publication so your organisation may change it; the name is the member's own
in the manifest, never its id. DELETE /subscriptions/{sid} unsubscribes.
Prompts in a bundle¶
A prompt member's definition is the body of POST /prompts/{id}/versions: template,
input_schema, role and install_values, plus the prompt's own metadata. A labels field is
accepted and ignored; the copy arrives without labels.
Publishing from rows ({"kind": "prompt", "id": "prm_..."} in members) takes the prompt's latest
published version, never a draft, and turns its install values into parameters of the bundle, with
your own value as the installer's default.
What an installed prompt copy carries¶
- Name. The subscription's
prefixfollowed by the member's name. - Metadata. The publisher's. Every sync that writes the copy (a new publication version, or a
changed
config) replaces the copy'smetadataas a whole with the member's; a member without metadata leaves{}. While the copy is linked you cannot change it yourself: a new version of a linked copy is409. - Labels. None. Labels never travel: the copy arrives unclassified, and no sync writes its labels.
- Versions. A sequence of its own. Each sync that writes the copy adds its next version (1, 2, 3), whichever publication version produced it.
A sealed prompt copy¶
When the publisher withholds the content, the seal hides the template and the variables of each
version installed under it, and nothing else. GET /prompts/{id} and the version routes answer
such a version with:
| Field | Value |
|---|---|
sealed |
true |
template |
null |
input_schema |
empty: {"type": "object", "properties": {}, "required": [], "additionalProperties": false} |
install_values |
{} |
role, version, state |
as installed |
The prompt's name, metadata and origin stay readable too. A turn renders the version
unchanged, so a sealed prompt can be run but not read. A sealed copy cannot be detached, and
POST /prompts/{id}/copy refuses it with 403.
Scripts in a bundle¶
A script can be a member of a bundle like a prompt or a connector.
Whoever installs it gets a copy in their own library, offered to their models as
script__<prefix><name>.
What a script member holds¶
A script member's definition is the body of POST /scripts without the name and the labels: a
copy arrives unclassified, as every copy does. The script's files do not travel inside the
manifest. Each entry of files names a file by path, size_bytes and sha256, and the bytes
are held beside the publication, by digest:
curl -s -X PUT "$CORE_URL/publications/pub_4Kd9.../files/$(sha256sum template.pptx | cut -d' ' -f1)" \
-H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/octet-stream" \
--data-binary @template.pptx
The route checks that the bytes have the digest in the path (422 on sha256 otherwise), and
holding the same file again writes nothing. GET on the same path answers whether the publication
holds it already; 404 means you still have to upload it. The limits:
- one file at most 32 MiB; a larger upload is
413; - a version's script files and carried packages together at most 128 MiB; past that the version is
422onmembers; - all files of one publication together at most 1 GiB; past that an upload or a publish is
409.
Your operator can change them.
You rarely upload by hand:
- Publishing from rows (
{"kind": "script", "id": "scr_..."}inmembers) takes the script's latest version and copies its files onto the publication itself. - Publishing a manifest needs every file uploaded first. An entry whose digest the publication
does not hold is
422onmembers.<i>.definition.files.<j>.sha256.
A toolset, an alias or an agent in the same bundle names the script as
{"$member": "house_deck", "kind": "script"}, which becomes the subscriber's own copy. A published
version's files are readable again at
GET /publications/{pid}/versions/{v}/members/script/{member}/files/{path}.
Packages in a bundle¶
What happens to a package a script names depends on who approved it:
- A library in the image, or a package your operator approved for the deployment, travels by name only. The subscriber is on the same deployment, so its copy finds the same approval.
- A package only your organisation approved travels with the bundle: the member names it with
its file (
ecosystem,name,version,filename,size_bytes,sha256), and the file is held beside the publication like the script's own files. Publishing from rows copies it for you.
The subscriber sees these packages before installing: the preview's packages lists each one
with its ecosystem, name, version, file and digest, even when the bundle withholds its content.
Installing is the approval. The package is installed for that copied script alone, shown with
approval: bundle on the copy's versions, and never added to the subscriber's own list of approved
packages. Their administrators still decide what their own scripts may use.
A later version in which a script brings a package it did not bring before (a new name, a new
version, or other bytes) waits for the subscriber, as changed terms do: the subscription goes to
needs_acceptance and the copy keeps running what it ran. Preview that version first, with the
subscription's own prefix and config so the report matches your install, then accept:
curl -s -X POST "$CORE_URL/subscriptions/preview" \
-H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
-d '{"publication_id": "pub_4Kd9...", "follow": "pinned", "pinned_version": 4,
"prefix": "acme-", "config": {"company": "Acme"}}'
curl -s -X PATCH "$CORE_URL/subscriptions/sub_1Ac7..." \
-H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
-d '{"accept_terms_version": 4}'
A version that drops a package, or brings only ones already accepted, installs like any other.
Installing a script¶
A bundle with a script needs tooling and computer in the subscriber's organisation. When the
organisation is not permitted computer, the subscription is refused 422: no key there could run
the script.
- Linked. While the copy follows the publication, it is the publication's to change: a new
version or a delete of the copy is
409, naming the publication. Each new publication version that changes what the script runs becomes a new version of the copy. - Forked.
POST .../members/{member}/forkdetaches the copy, when the terms allow it. From then on it is an ordinary script of yours and follows no new versions. - Sealed. When the publisher withholds the content, the copy can be run but not read: its reads
answer the name, the description and the parameters, with
entrypointasnullandfilesempty, and its file route answers404. A sealed copy cannot be forked or published again. In a turn it runs on a computer of its own, separate from the computer the model's shell tools use, so nothing in the turn can read its files; that second computer is billed as sandbox time like the first.
For an organisation below you¶
Every route above also exists under /organisations/{id}/..., for an organisation you reach with
management:
curl -s -X POST "$CORE_URL/organisations/ten_9Fb2.../subscriptions" \
-H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
-d '{"publication_id": "pub_4Kd9..."}'
This is a management operation over that organisation's library — the same kind of thing creating a key there is — not a way to read its prompts, skills or knowledge directly: that stays a key you register inside it (Work inside a child).
The marketplace¶
GET /marketplace shows what Artific has approved for the whole deployment — a different path
from the console's GET /catalogue, because every route here shares one path space and that path
already exists. The review queue itself (?status=submitted in the console) is not there: that
stays Artific's alone.