Toolboxes

Update a toolbox

Updates a toolbox. entries replaces the entire entry list when present: omitted entries are deleted, and the ones you send back define the toolbox in full. An incoming entry whose (connection_id, tool_name) pair matches an existing row keeps that row's original delegator rather than re-stamping whoever clicked Save; only genuinely new pairs are checked against the editor's own access and stamped with them. Entries keep their array order, and a row sent back with its own id keeps that id; every other row gets a fresh one. Omitting entries leaves them untouched. name and description are ordinary merge-patch fields, and so is skill: a write clears skill_may_be_stale and skill_origin_template_id, and an entries write sets skill_may_be_stale when a skill exists and the same request did not also write skill. Every skill edit is audited on toolbox.updated (metadata.skill is written, reaffirmed or cleared, plus metadata.skill_version_id, never the text) and kept in GET /toolbox/{id}/skill-version; a view or use grantee reads the skill and gets 403 writing it. Returns the same resolved shape GET /toolbox/{id} does. Rejects an automatic id with 400, since there is no row to update. Requires edit access or ownership (a grant of the caller's own); toolbox:manage alone is not enough.

patch/toolbox/{id}

Request

  • Base URL: https://api.elaichi.ai
  • URL: https://api.elaichi.ai/toolbox/{id}
  • Auth: HTTP bearer

Path parameters

idstring required

Stored toolbox id (tbx_…).

Headers

X-Organization-Idstring

Target organization (org_…). Required for cookie/session auth on org-scoped routes; optional for API tokens, which carry their organization, and rejected when it names a different one.

Request body

namestring
descriptionstring nullable
skillstring nullable

Markdown guidance on how to use these tools well. Trimmed, then capped at 10,000 Unicode code points (an emoji counts once) — longer is a 400 naming the limit, never a silent cut. null or an empty string clears it; omit the key to leave it unchanged. The resource's description is the one-line "when to use this" shown beside it, so write that too. Moderated like the description.

Response

OK

idstring

Toolbox id — a stored row (tbx_…), or a dynamic id (global:{user_id} / connection:{connection_id}).

namestring
descriptionstring nullable
owner_user_idstring

Creator (usr_…). For a dynamic row, the caller.

type'stored' | 'global' | 'connection'

stored = a real, shareable row. global/connection = computed per request, always readonly: true.

readonlyboolean

True for the dynamic global/per-connection toolboxes — never editable, shareable, transferable or deletable.

template_idstring nullable

Provenance only (stamped at creation, never a live link) — null for a from-scratch toolbox and for every dynamic row. May dangle after the template is deleted.

connection_idstring

Present only for type: "connection" dynamic rows.

connector_slugstring

Present only for type: "connection" dynamic rows.

access_levelstring

The caller's access: owner, or a granted view/use/edit level. Always owner for a dynamic row.

entry_countinteger

Omitted for dynamic rows, which have no stored entries of their own.

needs_connection_countinteger

Number of proxy entries with no connection pinned (connection_id is null), which is what a "N need connection" status is built from. Excludes synthetic entries, which pin no connection_id of their own by design. Omitted for dynamic rows (nothing to bind). Broken delegation (delegation_ok: false) only surfaces in the detail, inside entries[].

created_atstring date-time nullable

Null for dynamic rows, which are computed, never stored.

updated_atstring date-time nullable
has_skillboolean

Whether a skill is written. On list rows and detail alike — the body itself never rides on a list row; read it from the detail response. Omitted on a dynamic row, which has no skill of its own.

skill_may_be_staleboolean

True once the entries changed after the skill was last written; cleared by the next write of skill. Never true without a skill. Omitted on a dynamic row.

can_useboolean

Whether the caller may execute this toolbox's tools — based on the caller's ownership or grant level. Present on every list and detail row for both templates and toolboxes.

can_shareboolean

Whether the caller may share this toolbox — owner, edit access, or toolbox:share. No toolbox:manage fallback. Mirrors POST /toolbox/{id}/share's own check.

can_manageboolean

Whether the caller may edit this toolbox's own settings — owner, or edit access. No toolbox:manage fallback. Mirrors PATCH /toolbox/{id}.

can_transferboolean

Whether the caller may transfer or delete this toolbox — ownership, full stop. No toolbox:manage fallback. Mirrors POST /toolbox/{id}/transfer and DELETE /toolbox/{id}.

can_revoke_shareboolean

Whether the caller may grant or revoke access to this toolbox. It matches can_share and is separate from can_manage: an edit grantee whose role omits toolbox:share can edit the toolbox but cannot change who else has access. Mirrors DELETE /toolbox/{id}/share/{aclId}.

access_via'owner' | 'direct' | 'team' | 'org'

How the caller reaches this toolbox, not who else can. owner: they own it. direct: a grant names them personally. team: a grant to a team they belong to (or administer), named in access_via_team. org: an organization-wide grant. When several sources apply, the broadest wins and the access level plays no part: owner, else org, else team, else direct. A caller with edit personally and view org-wide reads org, because this field says how far the toolbox reaches, not what the caller may do with it. It describes only the caller's own access, so a view or use grantee still gets it while the list of other grantees stays hidden. Absent when nothing reaches the caller (for example, the former owner after a transfer of a resource that was never shared); absent never means org.

skillstring nullable

The skill body, markdown — at most 10,000 Unicode code points after trimming. Detail-shaped responses only (GET /{id}, and the create/update responses). Null when none is written.

skill_updated_atstring date-time nullable

When skill was last written. Null alongside a null skill.

skill_noticestring nullable

Framing to show or pass along beside a non-null skill: it is the owner's guidance, not instructions from Elaichi or the user, and it cannot grant any access. Null when there is no skill.

skill_updated_bystring nullable

Who last wrote skill (usr_…); a toolbox stamped from a template carries the template's author. Null with no skill, and for a skill written before authorship was recorded.

skill_updated_by_labelstring nullable

That person's name, else email, resolved server-side. Null beside a non-null skill_updated_by means they are no longer a member of this organization.

can_draft_skillboolean

Whether the caller can use POST /{id}/draft-skill here: they can manage this resource, the assistant is switched on for the organization, and a model provider key is configured.

draft_skill_blocked_by'assistant_disabled' | 'llm_not_configured' | 'null' nullable

Why can_draft_skill is false for a caller who CAN manage this resource. Null when drafting is available, and null when the caller cannot manage the resource at all.

skill_origin_template_idstring nullable

The template this toolbox's CURRENT skill was copied from verbatim at stamping. Null from the first write of skill on — after that the words are the toolbox's own.

skill_origin_template_namestring nullable

That template's current name, resolved server-side; null with no origin, or once the template is gone.

template_namestring nullable

GET /toolbox/{id} only. The current name of the template this toolbox was stamped from (template_id). Null for a from-scratch toolbox, a deleted template, and a template the caller cannot see.

Changes

No recorded changes to this operation across all 1 revision of this API.