@@ -76,8 +76,10 @@ An assistant has two parts stored separately:
7676 user_file`), written via a dedicated endpoint. Creating an assistant does
7777 NOT set its system prompt — that's a second call.
7878
79- Assistant ` source ` is ` builtin ` (shipped with the app, limited edits) or
80- ` user ` (custom, fully editable). Custom IDs look like ` custom-<digits>-<hex> ` .
79+ Assistant ` source ` is ` builtin ` (shipped with the app, limited edits), ` user `
80+ (custom, fully editable), or ` generated ` (auto-materialized from an online ACP
81+ agent — identity fields locked, not deletable). Custom IDs look like
82+ ` custom-<digits>-<hex> ` .
8183
8284### List / inspect
8385
@@ -135,11 +137,13 @@ installed agent's id — not a friendly name like `"claude"`. Read the available
135137agents first and copy the id you want:
136138
137139``` bash
140+ # the LIST response is flat — each row carries agent_id + agent directly:
138141python3 scripts/aionui_api.py get /api/assistants
139- # look at the `engine` block of any existing assistant, e.g.
140- # "engine": {"agent_id": "2d23ff1c", "agent": {"type": "acp", "acp_backend": "claude"}}
141- # reuse that agent_id for a new assistant on the same engine:
142- python3 scripts/aionui_api.py put /api/assistants/< id> ' {"id":"<id>","agent_id":"2d23ff1c"}'
142+ # {"id": "...", "agent_id": "2d23ff1c", "agent": {"type": "acp", "acp_backend": "claude"}, ...}
143+ # (only the single-assistant detail read nests these under an `engine` block:
144+ # GET /api/assistants/<id>?locale=en -> "engine": {"agent_id": "...", "agent": {...}})
145+ # reuse an existing agent_id for a new assistant on the same engine:
146+ python3 scripts/aionui_api.py put /api/assistants/< id> ' {"agent_id":"2d23ff1c"}'
143147```
144148
145149> If you omit ` agent_id ` on create, the backend does NOT default to a CLI engine:
@@ -176,7 +180,6 @@ modes the backend accepts. The `value` is what `fixed` locks to:
176180
177181``` bash
178182python3 scripts/aionui_api.py put /api/assistants/< id> ' {
179- "id": "<id>",
180183 "defaults": {
181184 "model": {"mode": "fixed", "value": "gemini-2.5-pro"},
182185 "permission": {"mode": "fixed", "value": "plan"},
@@ -187,13 +190,14 @@ python3 scripts/aionui_api.py put /api/assistants/<id> '{
187190```
188191
189192> Verified end-to-end: the backend stores all four entries verbatim and returns
190- > them on the ` ?locale= ` detail read. A brand-new assistant has ` defaults: null `
191- > until you set them.
193+ > them on the ` ?locale= ` detail read. On read, ` defaults ` is always present with
194+ > all four entries — a brand-new assistant has each set to ` {"mode":"auto"} ` (no
195+ > ` value ` ), never ` null ` . Lock one by sending ` {"mode":"fixed","value":...} ` .
192196
193197### Update
194198
195- ` PUT /api/assistants/<id> ` with ` {"id": "<id>", ... fields to change} ` . Send only
196- the fields you want to change .
199+ ` PUT /api/assistants/<id> ` , sending only the fields you want to change. The ` id `
200+ comes from the URL path — a body ` id ` , if sent, is ignored .
197201
198202### Set the system prompt (rules)
199203
@@ -216,14 +220,20 @@ python3 scripts/aionui_api.py post /api/skills/assistant-rule/read '{"assistant_
216220For multi-line / long prompts, write the text to a temp file and build the JSON
217221body in Python rather than inlining a giant shell string.
218222
223+ > To wipe an assistant's rule across all locales, `DELETE
224+ > /api/skills/assistant-rule/<assistant-id >`. A parallel trio exists for
225+ > per-assistant ** skill** content (distinct from the shared registry):
226+ > ` POST /api/skills/assistant-skill/{read,write} ` (same body shape as the rule
227+ > endpoints) and ` DELETE /api/skills/assistant-skill/<assistant-id> ` .
228+
219229### Avatar
220230
221231The ` avatar ` field accepts an emoji (` "📋" ` ), an image URL, a ` data: ` URI, or an
222232absolute local path. A self-contained inline SVG ` data: ` URI is a good default —
223233no external dependency, renders offline:
224234
225235``` bash
226- python3 scripts/aionui_api.py put /api/assistants/< id> ' {"id":"<id>"," avatar":"data:image/svg+xml;base64,<...>"}'
236+ python3 scripts/aionui_api.py put /api/assistants/< id> ' {"avatar":"data:image/svg+xml;base64,<...>"}'
227237```
228238
229239> ` GET /api/assistants/<id>/avatar ` also serves the raw avatar binary (Content-Type
@@ -239,7 +249,8 @@ team picker without deleting it.
239249### Delete
240250
241251` DELETE /api/assistants/<id> ` — only ` source: user ` assistants can be deleted.
242- Builtins can only be disabled.
252+ ` builtin ` and ` generated ` assistants can only be disabled (check the ` deletable `
253+ flag on the detail read).
243254
244255### Bulk import
245256
@@ -257,8 +268,9 @@ A skill is a folder containing a `SKILL.md` (YAML frontmatter `name` +
257268` description ` , then instruction body). The ` description ` decides when the agent
258269auto-triggers the skill, so write it carefully.
259270
260- Three sources: ` builtin ` (` ~/.aionui/builtin-skills/ ` ), ` custom `
261- (` ~/.aionui/skills/ ` ), ` extension ` (external, symlinked).
271+ Four sources: ` builtin ` (` ~/.aionui/builtin-skills/ ` ), ` custom `
272+ (` ~/.aionui/skills/ ` ), ` cron ` (` ~/.aionui/cron/skills/ ` , per-scheduled-task
273+ skills), ` extension ` (external, symlinked).
262274
263275### List / inspect the registry
264276
@@ -270,18 +282,23 @@ python3 scripts/aionui_api.py post /api/skills/info '{"skill_path":"/abs/path/to
270282
271283### Import a skill into the registry
272284
273- Two ways to install a skill — pick by whether you want a copy or a live link:
285+ ` POST /api/skills/import ` copies the skill(s) into the user skills dir and
286+ registers them. The one endpoint handles all three source shapes: a single skill
287+ folder, a PARENT folder containing many skills, or a ` .zip ` package.
274288
275289``` bash
276- # copy the folder into the user skills dir and register it
277- python3 scripts/aionui_api.py post /api/skills/import ' {"skill_path":"/abs/path/to/skill-folder"}'
278-
279- # symlink instead of copy — good for a skill you keep editing in an external repo.
280- # import-symlink (NOT bare import) is also what accepts a PARENT folder of many
281- # skills, or a .zip package.
282- python3 scripts/aionui_api.py post /api/skills/import-symlink ' {"skill_path":"/abs/path/to/skill-or-parent-or-zip"}'
290+ python3 scripts/aionui_api.py post /api/skills/import ' {"skill_path":"/abs/path/to/skill-or-parent-or-zip"}'
291+ python3 scripts/aionui_api.py get /api/skills/import-limits # server-side max file/total byte caps
292+ python3 scripts/aionui_api.py get /api/skills/import-history # recent import records
283293```
284294
295+ > For external skills you keep editing in place (registered without copying), see
296+ > "Discover & manage skill sources" below (` external-paths ` ) — that's how a live,
297+ > non-copied source is wired in. There is no ` import-symlink ` endpoint; the
298+ > reverse operation, ` POST /api/skills/export-symlink `
299+ > (` {"skill_path":"...","target_dir":"..."} ` ), symlinks an already-installed skill
300+ > back out to an external directory.
301+
285302> Caution: importing (copy) from a path that is ALREADY inside the user skills
286303> dir can race with the copy step. When editing an installed skill, edit the
287304> files in place, then re-import from a separate staging copy — or just verify
@@ -292,12 +309,12 @@ python3 scripts/aionui_api.py post /api/skills/import-symlink '{"skill_path":"/a
292309For skills that live outside the standard dirs:
293310
294311``` bash
295- python3 scripts/aionui_api.py post /api/skills/scan ' {"path ":"/abs/dir"}' # find skills under a dir
312+ python3 scripts/aionui_api.py post /api/skills/scan ' {"folder_path ":"/abs/dir"}' # find skills under a dir
296313python3 scripts/aionui_api.py get /api/skills/detect-paths # candidate skill locations
297314python3 scripts/aionui_api.py get /api/skills/detect-external # external skill dirs
298315python3 scripts/aionui_api.py get /api/skills/external-paths # list registered external paths
299- python3 scripts/aionui_api.py post /api/skills/external-paths ' {"path":"/abs/dir"}' # add one
300- python3 scripts/aionui_api.py delete /api/skills/external-paths ' {"path":"/abs/dir"}' # remove one
316+ python3 scripts/aionui_api.py post /api/skills/external-paths ' {"name":"<label>"," path":"/abs/dir"}' # add one (both required)
317+ python3 scripts/aionui_api.py delete /api/skills/external-paths ' {"path":"/abs/dir"}' # remove one (path only)
301318```
302319
303320The ** skills market** is a separate, app-wide toggle:
@@ -308,7 +325,7 @@ The **skills market** is a separate, app-wide toggle:
308325Put the skill's ` name ` into the assistant's ` enabled_skills ` :
309326
310327``` bash
311- python3 scripts/aionui_api.py put /api/assistants/< id> ' {"id":"<id>"," enabled_skills":["skill-a","skill-b"]}'
328+ python3 scripts/aionui_api.py put /api/assistants/< id> ' {"enabled_skills":["skill-a","skill-b"]}'
312329```
313330
314331> ` enabled_skills ` is the full set — include every skill you want kept, not just
@@ -345,11 +362,13 @@ The `transport` object is one of:
345362| --- | --- | --- |
346363| ` stdio ` | ` command ` , ` args? ` (string[ ] ), ` env? ` (map) | local process servers (npx/uvx/binaries) |
347364| ` sse ` | ` url ` , ` headers? ` (map) | remote Server-Sent-Events servers (legacy) |
348- | ` http ` / ` streamable_http ` | ` url ` , ` headers? ` (map) | remote HTTP servers (Streamable HTTP) |
365+ | ` http ` | ` url ` , ` headers? ` (map) | remote HTTP servers (Streamable HTTP) |
349366
350367> ` headers ` is an optional string→string map for auth (e.g. `{"Authorization":
351- > "Bearer …"}` ). ` streamable_http` is accepted on create/update but always
352- > normalizes to ` http ` in responses — don't expect ` streamable_http ` echoed back.
368+ > "Bearer …"}` ). The REST API accepts exactly these three ` type` values —
369+ > ` stdio ` , ` sse ` , ` http ` . Use ` http ` for Streamable-HTTP servers; there is no
370+ > separate ` streamable_http ` transport type at this layer (sending it fails
371+ > deserialization).
353372
354373### Create
355374
@@ -378,14 +397,20 @@ python3 scripts/aionui_api.py post /api/mcp/servers '{
378397returns the server's tool list (or an error / ` needs_auth ` ). Good to run after
379398creating a remote server.
380399
381- ### Toggle / update / delete
400+ ### Fetch one / toggle / update / delete
382401
383402``` bash
403+ python3 scripts/aionui_api.py get /api/mcp/servers/< id> # one server by id
384404python3 scripts/aionui_api.py post /api/mcp/servers/< id> /toggle # enable <-> disable
385405python3 scripts/aionui_api.py put /api/mcp/servers/< id> ' {"description":"..."}'
386406python3 scripts/aionui_api.py delete /api/mcp/servers/< id>
387407```
388408
409+ > Two more list-level helpers exist: ` POST /api/mcp/servers/import `
410+ > (` {"servers":[…]} ` , bulk-restore a set at once) and ` GET /api/mcp/agent-configs `
411+ > (scans installed Agent CLIs and returns their existing MCP configs — a source
412+ > for one-click import).
413+
389414> Remote servers may need OAuth: ` /api/mcp/oauth/check-status ` ,
390415> ` /api/mcp/oauth/login ` , ` /api/mcp/oauth/logout ` (all ` post ` ), and
391416> ` GET /api/mcp/oauth/authenticated ` which lists the server URLs that already
@@ -440,19 +465,21 @@ which protocol it speaks and what models it has. Use this to fill `platform` and
440465
441466``` bash
442467python3 scripts/aionui_api.py post /api/providers/detect-protocol ' {
443- "platform": "custom",
444468 "base_url": "https://api.deepseek.com/v1",
445469 "api_key": "sk-..."
446470}'
447471# -> {"protocol":"openai","confidence":90,"models":[...]}
448472```
449473
450- Optional fields on this body: ` timeout ` (ms), ` preferred_protocol ` (try a given
451- protocol first), and ` test_all_keys ` (bool — probe every key when ` api_key `
452- holds several).
474+ Required on this body: just ` base_url ` + ` api_key ` (no ` platform ` — the backend
475+ detects it). Optional: ` timeout ` (ms), ` preferred_protocol ` (try a given protocol
476+ first — one of ` openai ` , ` anthropic ` , ` gemini ` , ` unknown ` ), and ` test_all_keys `
477+ (bool — probe every key when ` api_key ` holds several).
453478
454- ` fetch-models ` (` POST /api/providers/fetch-models ` , same body) returns just the
455- model list for a not-yet-saved endpoint.
479+ ` fetch-models ` (` POST /api/providers/fetch-models ` ) returns just the model list
480+ for a not-yet-saved endpoint. Its body differs from detect-protocol: ` platform ` ,
481+ ` base_url ` , ` api_key ` are all ** required** (plus optional ` bedrock_config ` ,
482+ ` try_fix ` ).
456483
457484### Test a provider connection
458485
@@ -519,11 +546,13 @@ Two stores, both verified:
519546- ` PUT /api/settings/client ` — batch-update that store.
520547
521548` PUT /api/settings/client ` is a ** partial merge** — send only the keys you want
522- to change. Read first, change one key, read back.
549+ to change (a key set to ` null ` deletes it). Its response carries no data, so
550+ always read the store back to confirm.
523551
524552``` bash
525553python3 scripts/aionui_api.py get /api/settings/client
526554python3 scripts/aionui_api.py put /api/settings/client ' {"ui.zoomFactor": 1.0}'
555+ python3 scripts/aionui_api.py get /api/settings/client # confirm — PUT returns no body
527556```
528557
529558> To set which model a given assistant uses, configure that assistant's
@@ -535,19 +564,20 @@ python3 scripts/aionui_api.py put /api/settings/client '{"ui.zoomFactor": 1.0}'
535564
536565` GET /api/agents/management ` lists the available engines (` aionrs ` , ` claude ` ,
537566` codex ` , …). There is ** no** bare ` GET /api/agents ` — that path 404s; always use
538- the ` /management ` sub-path. Each row carries ` id ` , ` enabled ` (toggled on),
539- ` installed ` (spawn command resolvable on ` $PATH ` ), ` team_capable ` (can run in a
540- team), ` backend ` , ` agent_type ` , and a ` status ` of ` online ` / ` offline ` /
541- ` missing ` . Check ` installed ` (and ` status ` ) before binding an assistant to that
567+ the ` /management ` sub-path. Each row is rich: alongside ` id ` , ` name ` , ` enabled `
568+ (toggled on), ` installed ` (spawn command resolvable on ` $PATH ` ), ` team_capable `
569+ (can run in a team), ` backend ` , ` agent_type ` , and a ` status ` of ` online ` /
570+ ` offline ` / ` missing ` , it also carries ` config_options ` , ` available_modes ` ,
571+ ` available_models ` (when the engine advertises them), plus ` last_check_* `
572+ diagnostics. Check ` installed ` (and ` status ` ) before binding an assistant to that
542573engine (via its ` agent_id ` — see * Picking the engine* above).
543574
544- > The management row does ** not** include the engine ` handshake ` (its
545- > ` agent_capabilities ` / ` auth_methods ` / ` config_options ` / ` available_modes ` /
546- > ` available_models ` / ` available_commands ` ) — those live on the fuller agent
547- > metadata returned by ` POST /api/agents/refresh ` , which re-scans custom agents
548- > and returns each agent's ` available ` + ` handshake ` . Use ` refresh ` when you need
549- > the modes/models an engine offers; use ` management ` for the at-a-glance
550- > enabled/installed/status list.
575+ > What the management row does ** not** carry is the rest of the engine
576+ > ` handshake ` — ` agent_capabilities ` , ` auth_methods ` , ` available_commands ` . For
577+ > those, ` POST /api/agents/refresh ` re-scans agents and returns each one's full
578+ > metadata (` available ` + ` handshake ` ). The at-a-glance modes/models are already
579+ > on the management row; reach for ` refresh ` when you need capabilities, auth
580+ > methods, or the command list.
551581
552582---
553583
@@ -623,8 +653,16 @@ python3 scripts/aionui_api.py get /api/cron/jobs/<id> # one
623653python3 scripts/aionui_api.py put /api/cron/jobs/< id> ' {"enabled": false}' # partial update (pause)
624654python3 scripts/aionui_api.py post /api/cron/jobs/< id> /run # run it once right now
625655python3 scripts/aionui_api.py delete /api/cron/jobs/< id> # remove it
656+ python3 scripts/aionui_api.py get /api/cron/jobs/< id> /conversations # conversations this job has spawned
657+ python3 scripts/aionui_api.py get /api/cron/jobs/< id> /skill # {"has_skill": bool}
658+ python3 scripts/aionui_api.py post /api/cron/jobs/< id> /skill ' {"content":"<SKILL.md body>"}' # attach/replace a per-job skill
659+ python3 scripts/aionui_api.py delete /api/cron/jobs/< id> /skill # remove the attached skill
626660```
627661
662+ > A job can carry its own inline ** skill** (a ` SKILL.md ` -style instruction body)
663+ > via ` .../skill ` — this is the ` cron ` skill source. Handy when a scheduled task
664+ > needs bespoke instructions that shouldn't live in the shared registry.
665+
628666` PUT ` is a partial update — send only what changes (` name ` , ` description ` ,
629667` enabled ` , ` schedule ` , ` message ` , ` execution_mode ` , ` agent_config ` ,
630668` conversation_title ` , ` max_retries ` ). Read the job back to confirm its
0 commit comments