Tools, skills and connectors
Host versioned tools, skills and connectors with explicit permission and result contracts.
A backend can register a versioned package, grant another Q principal permission to use it, and revoke it without installing code on Q. This profile requires migration 20261009_040000_extensions, matching API/index/agent workers and EXTENSIONS_API_ENABLED=true. The flag defaults off. The locally qualified SDK 1.1.0 archives contain Python, TypeScript and Go clients; publication and hosted rollout are separate operator steps.
Registration and identity
Use server-side Q credentials. All routes derive the tenant and principal from authentication. API key principals are key:<api_key_id>; user JWT principals use their subject. A namespace wildcard or * satisfies the scope check but never bypasses ownership or grants.
Operation under /v1/extensions | Scope | Authorisation |
|---|---|---|
POST /validate, POST / | extensions:manage | Validate or publish for the authenticated principal |
GET /, GET /{id}, GET /{id}/versions/{version}, GET /{id}/events | extensions:read | Owner or an explicitly granted principal |
POST /{id}/lifecycle, POST /{id}/grants, GET /{id}/grants | extensions:manage | Owner only |
POST /{id}/syncs, POST /{id}/syncs/{batch}/retry | connectors:sync | Owner or sync grant, plus edit access to the configured Space |
GET /{id}/syncs, GET /{id}/syncs/{batch} | extensions:read | Owner or granted principal |
The exact collection URL is /v1/extensions (no trailing slash). Collections accept limit (1–100) and after; extension/batch cursors are UUIDs, event cursors are integers. New APIs enforce scopes regardless of the legacy AI scope compatibility flag. The capability registry and public OpenAPI are authoritative.
ExtensionManifest uses manifest_version: "1", kind, slug, name, description, version and exactly one of tool, skill or connector. Semantic versions are three numeric components without pre-release labels. Unknown fields are rejected. The version digest covers canonical JSON, including normalised defaults. Optional credentials declare names/descriptions with location: "developer_host"; they never contain tokens, passwords or secret values.
Publish {manifest, expected_revision: 0} to create a registration. Identity is the tenant, owner and slug. An upgrade must use a strictly higher version and the current expected_revision. Published versions and audit events are immutable. Grant and lifecycle changes increment the registration revision; refresh it before starting another operation. Conflicts return 409 extension_revision_conflict or extension_version_conflict. Exact registration and lifecycle retries are recognised at the immediately preceding revision. For an uncertain grant response, read the registration and grants before deciding whether another mutation is needed.
Grant {principal_id, permissions: ["use"], expected_revision} for tools/skills, or ["sync"] for connectors. An empty permission array revokes a grant. Only the owner can upgrade or change lifecycle state. States are active, revoked and terminal removed; revoked registrations may be reactivated. History remains available to authorised principals. Namespaced resources cannot be mutated through legacy skill/connector endpoints.
Tool packages
Tool packages define effect: read|write|execute, approval: none|required and bounded input/output JSON Schemas. Input is an object. Q's finite schema subset excludes remote references and executable extensions. Write and execute tools always require approval; a read tool may also require it. Run flags and automatic review cannot remove that requirement.
Start an existing durable agent run with:
{
"prompt": "Look up SKU Q-DEMO using the registered catalogue tool.",
"durable_temporal": true,
"registered_tools": [{"extension_id": "11111111-1111-4111-8111-111111111111", "version": "1.0.0", "revision": 1}]
}The caller needs ai:answer, extensions:use, the normal workspace/run permissions and an owner/use grant. Q resolves the schema from the registration and reserves external_ext_<uuid> tool names. At most 16 inline and registered tools can be admitted together.
Use durable tool polling and result submission. The same authenticated run principal polls and submits; granting extension use alone does not grant access to somebody else's run. Q rechecks active state, grants and the exact version/revision before dispatch, pending argument access, result acceptance and journal replay. Upgrading or changing grants invalidates existing pins with extension_binding_changed; refresh references for a new run. An inactive registration returns extension_inactive.
Developer code and provider credentials stay on your host. Persist remote effects and their outputs under Q's invocation_id, so a lost result response cannot repeat a write. Q cannot roll back an effect already performed on your host. Removal denies further handoff/results but is not a remote process kill. Execution, retries and provider rate limits on the host remain the host's responsibility. Return provider failures as an explicit schema-defined outcome; never submit secret exception text. Approval resolution follows mandatory approval semantics.
Skill packages
Skill packages contain instructions, a category and up to eight Markdown reference files. No scripts, imports, shell commands, dependency installation or filesystem paths are accepted as package operations. Instructions remain untrusted model input and do not add permissions to Q tools.
Q materialises an on-demand skill with slug extension-<uuid hex>. Activate it using existing skill resolution activation_context.include_slugs; owner/use grants are checked for discovery, resolution and export. Revocation/removal disables subsequent resolution. Published historical instructions remain readable by authorised package readers; revocation cannot erase text already used in a completed prompt. See the sample skill manifest.
Connector packages
Connectors declare one immutable target space_id, transport: developer_push, min_sync_interval_seconds (1–86,400, default 5) and max_batch_documents (1–32, default 16). The authenticated publisher needs Space edit access at registration and delivery. Q neither fetches an arbitrary provider URL nor accepts provider credentials.
Push batches with a saved UUID batch_id, current registration expected_revision, expected checkpoint, nonempty new next_checkpoint and changes. Each change carries a stable remote_id, increasing positive source_revision, a title, and either nonblank text or deleted: true. Source revisions are bounded to JavaScript-safe integers. Upserts accept at most 32,000 text characters; total batch JSON is bounded to 512 KiB. For larger/binary sources use existing ingestion.
Q maps remote IDs to connector-owned document UUIDs. Explicit access defaults to private to the package owner, with optional user IDs; tenant-wide visibility must be requested explicitly. Q supplies the tenant label. Space permissions still apply. Restricting a document's ACL updates retained indexed chunks immediately, before embedding. A source delete tombstones retained evidence immediately.
The checkpoint records accepted source data, not completed indexing. Q commits snapshots, ACL changes, checkpoint and an outbox together, then dispatches through the normal recoverable index pipeline. If the process or queue fails, retry the same saved batch unchanged or call its retry endpoint. A reused batch ID with changed content returns connector_batch_conflict. Old source revisions with changed content are rejected. Identical unchanged documents retain their original indexing receipt; they do not falsely become ready.
A sync receipt distinguishes queued, dispatched, indexed, failed, superseded and revoked. Per-document status includes source/index revision, safe failure code, publication lag and last indexed time when available. Inspect GET .../syncs/{batch} until indexed. dispatched means queued for work. Transient dispatch failures use connector_delivery_unavailable; retry after the supplied retry_after_seconds. A source checkpoint conflict requires reconciling with the most recently accepted receipt; never invent a new checkpoint to bypass it. New batches admitted too quickly return 429 connector_rate_limited; honour the manifest interval. Retries do not allocate another source revision.
Revoking/removing an installation erases stored source text, tombstones indexed evidence and fences publication by in-flight workers. Re-enabling it requires a higher source revision to restore each document. Revoking a writer grant stops future submissions; already accepted data remains governed by its document ACL. Grant/revision changes do not rewrite accepted source snapshots.
Current bounded profile: 1,000 registrations per tenant, 100 versions per registration, 100 grantees per registration, 10,000 accepted sync batches and 10,000 source IDs per connector. Historical rows and deletion fences are retained; an operator retention/migration policy is required before increasing these limits. Source content is stored as tenant data; do not put provider credentials into source documents or instructions.
Client and rollout qualification
Python: q.extensions.validate/register/list/get/version/lifecycle/grant/grants/events/sync/syncs/sync_status/retry_sync; wire models live in q_client.extension_types. TypeScript: the matching q.extensions methods with syncStatus and retrySync, and root-exported types. Go: ValidateExtension, RegisterExtension, ListExtensions, GetExtension, ExtensionVersion, SetExtensionLifecycle, SetExtensionGrant, ExtensionGrants, ExtensionEvents, SyncExtension, ExtensionSyncs, ExtensionSyncStatus, RetryExtensionSync, with generated Ext* types. Each uses the normal authenticated transport.
The executable host examples demonstrate polling and incremental delivery. Synthetic local qualification covers contracts, real PostgreSQL, restricted-role RLS, ACL changes, in-flight removal and installed SDK archives. The connector reader accepts both legacy uppercase values and lowercase database defaults, while retaining the existing writer format without rewriting records. Operators must grant the application role access to the six extension tables/event sequence, apply the migration, roll matching API/agent/index workers, then enable the profile for a limited cohort. Real provider credentials, remote side effects, load and incident recovery still need deployment-specific qualification. A populated extension registry intentionally blocks destructive downgrade; preserve history and use a forward migration.