Manage skills
tuqui_skillSkills: the workspace's step-by-step procedures (agentskills.io format). action='get' loads one by name. When the user, an instruction, another skill or an AGENTS.md names a skill, get it by that name directly: it loads skills 'list' does not show, so never go looking for copies on disk. If it is not found here and no skill tool of your own client lists it, say so; do not load a similar one in its place or improvise its steps. Loading it also names the tools its allowed-tools uses that are still hidden, to load with the tool search (unavailable_tools says why the rest cannot be used), and files lists the files it ships. A get may carry content_in_conversation instead of content: that version is already earlier in this conversation. 'list' finds a skill you have no name for: pass query (the task, in the words the skills use) and models (the Odoo models it works on) to rank the whole catalogue (workspace, personal, shared and system skills). The skill that clearly fits comes back already loaded in loaded_skill: follow it, no get needed. 'file' reads one of a skill's files to READ it; to RUN a script, pass the skill to execute_code(skills=[...]) instead. Over MCP only: 'materialize' returns a short-lived URL, SHA-256 and ready command to put a skill's whole folder on disk without the bytes passing through the conversation; 'upload_url' returns one to upload ONE file into a workspace skill straight from disk (hash it with sha256sum first). 'save' creates or updates a skill: pass content_md (a whole SKILL.md), or name, description, content and optional metadata. The body REPLACES what the skill said: to add a rule, get it first and send the whole body back with the rule in it. files ({path: text}) are merged into the folder, one file per call if you like; delete_files removes. 'delete' removes a skill by name. 'share' hands access to someone else (to and level 'usar' or 'editar'; level='none' takes it away). Writes take scope: 'workspace' or 'user'.
Tool call template
Replace each placeholder with a value matching the input schema. Only required parameters are included; add optional parameters as needed.
{
"id": 1,
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"arguments": {
"action": "<action>"
},
"name": "tuqui_skill"
}
}Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| to | No | share, target='user': who to give it to — their EMAIL or name (a user id also works). They must already be a member of this workspace: sharing does not invite. target='group': the group's name. A list, so handing the same level to a team is one call. | |
| dest | No | materialize: parent directory the skill's folder goes under, so the files end up in <dest>/<skill name>/ (default 'skills'). The archive itself is flat — SKILL.md and any references/ or scripts/ at its root — and the returned command is what creates the named folder. | |
| name | No | Kebab-case skill identifier, as named to you or listed by 'list'. Every action but 'list' needs it; on save, content_md may carry it instead. | |
| path | No | file: path of the file relative to the skill folder, exactly as get lists it (e.g. 'references/fields-by-version.md'). upload_url: the path the file takes inside the skill folder, e.g. 'scripts/capturar-tour.mjs' — relative, '/'-separated, not hidden, at most 3 levels deep. | |
| files | No | The skill's extra files as {path: text} — 'references/table.md', 'scripts/report.py'. Paths are relative to the skill folder, use '/', and may not be hidden, absolute or deeper than 3 levels. MERGED into the folder: what you send is created or overwritten, everything else stays, so a skill of many files can be published a few at a time and one file re-sent on its own. Use delete_files to remove. Text only, and bounded per call — a folder bigger than that arrives across several calls, or as a .zip import. A binary file (an .xlsx template, a logo) cannot travel here: it is uploaded with action='upload_url' or comes in the .zip. | |
| level | No | share: 'usar' or 'editar' — the two levels of the picker, Spanish because the spec fixes them as the domain vocabulary of the model (compartir-unificado §10). 'none' takes the access away: it revokes the person's share, or closes the object back to the people invited. 'link' is a reach only the Library offers (anyone in the workspace with the URL). | |
| limit | No | list: how many skills to return. Default 30. The reply always states the total, and carries `next_offset` when there is more. | |
| query | No | list: what you are looking for, in the words the skills use (usually the user's language, not English). Ranks the catalogue by relevance to it, instead of returning it in its stored order. | |
| scope | No | save, delete and share: REQUIRED. Pass 'user' for a personal skill only visible to you until you share it, scoped to this workspace (any authenticated user). Pass 'workspace' for a shared skill visible to all workspace members: creating or deleting one is an admin's call, and updating one needs edit access on that skill. A personal skill somebody shared with you at 'editar' is updated by saving it under its name, with either scope. 'share' with scope='user' shares your own personal skill, which stays personal. Always pass scope as a top-level argument — never embed it inside content_md. | |
| action | Yes | REQUIRED. Read: 'get' loads a skill by name, 'list' discovers names, 'file' reads one of a skill's files. Over MCP: 'materialize' puts a skill's folder on disk, 'upload_url' uploads one file into a workspace skill from disk. Write: 'save' creates or updates, 'delete' removes, 'share' hands access to somebody else. | |
| models | No | list: the Odoo models the task works on (e.g. ['sale.order']). A skill that declares one of them ranks higher. | |
| offset | No | list: where to resume. Pass the `next_offset` of the previous reply. | |
| sha256 | No | upload_url: SHA-256 of the file's bytes, in hex — the output of `sha256sum <file> | cut -d' ' -f1`. Do NOT compute it yourself: read it from the command, or the check it exists for is worthless. The upload is refused unless what arrives matches it. | |
| target | No | share: who gets it. 'user' (default) gives it to people; 'group' to whoever is in a group; 'workspace' moves the reach, handing the level to every member at once. | |
| content | No | save: Markdown body (no frontmatter). REPLACES the whole body of an existing skill — it is not merged the way `files` are, so whatever you leave out is dropped. Updating a skill means reading it with action='get' and sending it back whole, not sending only the part that changed. Omit it to keep the stored body, e.g. on a save that only changes files. | |
| enabled | No | Hide the skill from the directory when false. Omit to leave an existing skill's flag as it is; a new skill is born enabled. | |
| trigger | No | Who may offer the skill: 'both' (default for a new skill) = the / picker and the model's catalogue; 'slash' = the person only; 'auto' = the model only; 'none' = neither — the agents that link it are what enable it. Omit to leave an existing skill's mode untouched. | |
| metadata | No | Frontmatter remainder (allowed-tools, version, author, ...). Omit it to keep what the skill already has. | |
| content_md | No | Full SKILL.md document with YAML frontmatter (---/--- delimiters); alternative to passing name/description/content/metadata separately. Replaces the stored document whole, same as `content`. Do NOT include 'scope' in the frontmatter — pass it as a separate argument. | |
| description | No | save: routing signal for the LLM. Required for create/update. | |
| delete_files | No | Paths to remove from the skill's folder, e.g. ['references/old.md']. The counterpart of `files` merging: this is how a file goes away. A path may not be in both. | |
| consent_token | No | The approval a person gave for THIS call in Tuqui. Bound to these arguments and valid once. | |
| expected_sha256 | No | Optional {path: hex} of the SHA-256 each file in `files` should have. Send it when you are copying files from a source you can hash: the save is refused if what arrived is not what you meant to send, which turns 'I published the right bytes' from a guess into a check. The response always carries the SHA-256 of every stored file either way. |