Skip to content

Attach a repository to a tenant (idempotent).

PUT
/tenants/{tenant_id}/repositories/{repository_id}
curl --request PUT \
--url https://shiftagent.example.com/tenants/example/repositories/example \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "is_default": true }'

Idempotent attach: 201 on first attachment, 200 when the attachment already existed (body fields merged — provided → replaced, omitted → unchanged, null → cleared).

  • is_default: true also sets tenant.default_repository_id (and clears the flag from any previous default — one default at a time).
  • branch_override reads a different branch of the same repository for this tenant only.

The body is optional; a bare PUT attaches with defaults. This is cold-path step 2: attach the registry repository as the tenant default right after the tenant upsert returns 201.

tenant_id
required
string
/^tnt_[A-Za-z0-9]+$/

Internal tenant ID.

repository_id
required
string
/^rep_[A-Za-z0-9]+$/

Internal repository ID.

Media type application/json

Optional body for attachTenantRepository. Merge semantics: provided → replaced, omitted → unchanged, null → cleared.

object
is_default

Make this the tenant default (sets tenant.default_repository_id; clears the previous default’s flag).

boolean
branch_override

Read this branch for the tenant; null clears.

string | null
Examples
Example attach_default

Cold-path attach as tenant default

{
"is_default": true
}

Attachment already existed — fields merged.

Media type application/json

A repository attached to a tenant. Addressed by the composite path /tenants/{tenant_id}/repositories/{repository_id} — no separate ID. Embeds the repository for convenience.

object
object
required
string
Allowed value: repository_attachment
tenant_id
required
string
/^tnt_[A-Za-z0-9]+$/
repository_id
required
string
/^rep_[A-Za-z0-9]+$/
is_default
required

Whether this is the tenant default (⇔ tenant.default_repository_id). At most one per tenant.

boolean
branch_override
required

Branch read for this tenant instead of the registry branch.

string | null
repository
required

The attached repository, embedded.

object
object
required
string
Allowed value: repository
id
required
string
/^rep_[A-Za-z0-9]+$/
name
required

Unique across the registry.

string
<= 255 characters
repo_url
required

Git remote URL.

string format: uri
branch
required

Branch scanned for skills (tenant attachments may override).

string
default: main
provider
required

Git hosting flavor (drives auth mechanics).

string
default: generic
Allowed values: github gitlab bitbucket azure_devops generic
credential_id
required

Vault credential used to access the repository. Secret material is never readable — pre-authenticated at registration.

string | null
/^crd_[A-Za-z0-9]+$/
sync
required

Skill-discovery sync state of a repository.

object
state
required

pending — not yet scanned (or invalidated by an update); syncing — scan in flight; ready — skill catalog current; error — last scan failed (see error).

string
Allowed values: pending syncing ready error
last_synced_at
required

Completion time of the last successful scan.

string | null format: date-time
error
required

Human-readable failure reason when state is error.

string | null
skill_count
required

Number of skills currently cataloged.

integer
metadata
required

Free-form string key–value map for host/adapter bookkeeping (e.g. a host-side reference ID). Max 50 keys; values max 500 chars. Replaced wholesale when provided in updates.

object
<= 50 properties
key
additional properties
string
<= 500 characters
created_at
required

RFC 3339 / ISO 8601 timestamp, UTC.

string format: date-time
updated_at
required

RFC 3339 / ISO 8601 timestamp, UTC.

string format: date-time
created_at
required

RFC 3339 / ISO 8601 timestamp, UTC.

string format: date-time
updated_at
required

RFC 3339 / ISO 8601 timestamp, UTC.

string format: date-time
Example
{
"object": "repository_attachment",
"repository": {
"object": "repository",
"branch": "main",
"provider": "github",
"sync": {
"state": "pending"
}
}
}

Repository attached to the tenant.

Media type application/json

A repository attached to a tenant. Addressed by the composite path /tenants/{tenant_id}/repositories/{repository_id} — no separate ID. Embeds the repository for convenience.

object
object
required
string
Allowed value: repository_attachment
tenant_id
required
string
/^tnt_[A-Za-z0-9]+$/
repository_id
required
string
/^rep_[A-Za-z0-9]+$/
is_default
required

Whether this is the tenant default (⇔ tenant.default_repository_id). At most one per tenant.

boolean
branch_override
required

Branch read for this tenant instead of the registry branch.

string | null
repository
required

The attached repository, embedded.

object
object
required
string
Allowed value: repository
id
required
string
/^rep_[A-Za-z0-9]+$/
name
required

Unique across the registry.

string
<= 255 characters
repo_url
required

Git remote URL.

string format: uri
branch
required

Branch scanned for skills (tenant attachments may override).

string
default: main
provider
required

Git hosting flavor (drives auth mechanics).

string
default: generic
Allowed values: github gitlab bitbucket azure_devops generic
credential_id
required

Vault credential used to access the repository. Secret material is never readable — pre-authenticated at registration.

string | null
/^crd_[A-Za-z0-9]+$/
sync
required

Skill-discovery sync state of a repository.

object
state
required

pending — not yet scanned (or invalidated by an update); syncing — scan in flight; ready — skill catalog current; error — last scan failed (see error).

string
Allowed values: pending syncing ready error
last_synced_at
required

Completion time of the last successful scan.

string | null format: date-time
error
required

Human-readable failure reason when state is error.

string | null
skill_count
required

Number of skills currently cataloged.

integer
metadata
required

Free-form string key–value map for host/adapter bookkeeping (e.g. a host-side reference ID). Max 50 keys; values max 500 chars. Replaced wholesale when provided in updates.

object
<= 50 properties
key
additional properties
string
<= 500 characters
created_at
required

RFC 3339 / ISO 8601 timestamp, UTC.

string format: date-time
updated_at
required

RFC 3339 / ISO 8601 timestamp, UTC.

string format: date-time
created_at
required

RFC 3339 / ISO 8601 timestamp, UTC.

string format: date-time
updated_at
required

RFC 3339 / ISO 8601 timestamp, UTC.

string format: date-time
Examples
Example attached_default

Attached as tenant default

{
"object": "repository_attachment",
"tenant_id": "tnt_01hzx8acme001",
"repository_id": "rep_01hzx8fieldops",
"is_default": true,
"branch_override": null,
"repository": {
"object": "repository",
"id": "rep_01hzx8fieldops",
"name": "field-ops",
"repo_url": "https://git.example.com/agent-skills/field-ops.git",
"branch": "main",
"provider": "generic",
"credential_id": "crd_01hzx8gitmain",
"sync": {
"state": "ready",
"last_synced_at": "2026-07-02T09:33:00Z",
"error": null
},
"skill_count": 5,
"metadata": {},
"created_at": "2026-07-02T09:31:00Z",
"updated_at": "2026-07-02T09:33:00Z"
},
"created_at": "2026-07-02T09:34:00Z",
"updated_at": "2026-07-02T09:34:00Z"
}

Missing or invalid credentials — no bearer token, an unknown/revoked sk_int_ key, or an expired platform JWT.

Media type application/problem+json

RFC 9457 problem+json error envelope. type is a URI under https://shiftagent.example.com/problems/{slug} (deployment host substituted); see the API-level problem registry for every slug.

object
type
required

Problem type URI (registry slug).

string format: uri-reference
title
required

Short, human-readable summary of the problem type.

string
status
required

HTTP status code.

integer format: int32
detail

Human-readable explanation specific to this occurrence.

string
instance

URI reference identifying this occurrence.

string format: uri-reference
request_id

Correlation ID for support and log lookup.

string
conflicting_resource_id

On name-conflict, external-id-conflict, and resource-in-use: the ID of the existing/depended-on resource — fetch it and continue (replay recovery).

string
errors

On validation-error, field-level details.

Array<object>
object
pointer
required

JSON pointer to the offending field.

string
message
required

What failed.

string
Examples
Example unauthorized

Missing or invalid bearer token

{
"type": "https://shiftagent.example.com/problems/insufficient-scope",
"title": "Unauthorized",
"status": 401,
"detail": "Provide a valid sk_int_ service key or platform JWT.",
"request_id": "req_01hzx8auth001"
}

Not found — the resource does not exist, was deprovisioned, or lies outside the integration key’s subtree (indistinguishable by design).

Media type application/problem+json

RFC 9457 problem+json error envelope. type is a URI under https://shiftagent.example.com/problems/{slug} (deployment host substituted); see the API-level problem registry for every slug.

object
type
required

Problem type URI (registry slug).

string format: uri-reference
title
required

Short, human-readable summary of the problem type.

string
status
required

HTTP status code.

integer format: int32
detail

Human-readable explanation specific to this occurrence.

string
instance

URI reference identifying this occurrence.

string format: uri-reference
request_id

Correlation ID for support and log lookup.

string
conflicting_resource_id

On name-conflict, external-id-conflict, and resource-in-use: the ID of the existing/depended-on resource — fetch it and continue (replay recovery).

string
errors

On validation-error, field-level details.

Array<object>
object
pointer
required

JSON pointer to the offending field.

string
message
required

What failed.

string
Examples
Example not_found

Unknown resource

{
"type": "https://shiftagent.example.com/problems/not-found",
"title": "Not found",
"status": 404,
"detail": "No tenant with external_id acme:tenant:999999.",
"request_id": "req_01hzx8nf001"
}

Unprocessable — validation-error (schema/semantic validation failed; errors[] lists JSON-pointer details) or role-required (user has multiple roles and no role_id was given).

Media type application/problem+json

RFC 9457 problem+json error envelope. type is a URI under https://shiftagent.example.com/problems/{slug} (deployment host substituted); see the API-level problem registry for every slug.

object
type
required

Problem type URI (registry slug).

string format: uri-reference
title
required

Short, human-readable summary of the problem type.

string
status
required

HTTP status code.

integer format: int32
detail

Human-readable explanation specific to this occurrence.

string
instance

URI reference identifying this occurrence.

string format: uri-reference
request_id

Correlation ID for support and log lookup.

string
conflicting_resource_id

On name-conflict, external-id-conflict, and resource-in-use: the ID of the existing/depended-on resource — fetch it and continue (replay recovery).

string
errors

On validation-error, field-level details.

Array<object>
object
pointer
required

JSON pointer to the offending field.

string
message
required

What failed.

string
Examples

Field-level validation failure

{
"type": "https://shiftagent.example.com/problems/validation-error",
"title": "Validation error",
"status": 422,
"detail": "One or more fields failed validation.",
"errors": [
{
"pointer": "/skill_access/skill_ids/0",
"message": "skl_01hzx8unknown does not belong to the effective repository."
}
],
"request_id": "req_01hzx8val001"
}