agent4.io

io.agent4Published by agent4.ioOfficial publisherv1.4.0Updated Oct 24, 2026

Build and run grounded business agents over MCP: agents, knowledge bases, skills, Storylines.

VerifiedStreamable HTTPWeb executableProductivity & WorkflowKnowledge & MemoryAI & ML

Overview

AI-generated overview

Manage an agent4.io tenant over MCP: create and configure agents, skills, knowledge bases, shares and page playbooks, and inspect usage and end users.

What you can do
List, create and partially update agents, including their tool whitelists and model settings, and list the tools and connected MCP servers available to them. Manage skills and knowledge bases: create and edit them, add text documents, search chunks, build and patch a structured index. Create and configure shares and integration entry points, set PWA branding and bind a custom domain. Run dry-run checks on skill triggers, planner escalation and plan previews, and rewrite or diagnose prompt fields. Read tenant info, usage statistics, end-user rosters and session metadata, and manage page playbooks with their stats. Search agent4.io's own product documentation.
When to use it
Useful when you build or operate agents on agent4.io and want to configure them conversationally instead of through the console: authoring personas and tasks, wiring tools and knowledge, publishing chat entry points, and checking usage or trigger behaviour before going live.
Requirements
Remote endpoint at api.agent4.io over streamable HTTP. Requires an agent4.io tenant and an API key sent in the X-API-Key header, created in the console under Settings, Security.
Before you install
The API key grants access to the whole tenant, so keep it out of shared logs. Many tools write or replace data: agent, skill and knowledge-base updates, list fields such as tools, skills and knowledge_bases are full-list replacements, and shares, branding and custom-domain bindings change what end users see. Custom-domain binding requires the client to set up DNS first. Usage and end-user tools return metadata only, not conversation content.

Installation

In SourceWeft

  1. Open agent4.io in the dashboard and add it to a workspace.
  2. Connect X-API-Key credentials. They are stored privately and never shown on public pages.
  3. Enable the server for the chats that should use its tools.

Web executable via Streamable HTTP. Remote servers run from the web runtime once configured in a workspace.

Use with an agent

Paste this prompt into Claude Code, Codex, Cursor or another agent — or into SourceWeft chat. The agent reads this server's install guide, shows you its publisher, endpoint and sign-in, and adds it to your client once you agree. Keys never go into a command.

Read https://sourceweft.com/mcp/io.agent4%2Fagent4-tenant/install.md and connect the MCP server it describes to my client. Before changing any config, show me its publisher, endpoint and sign-in method and wait for my OK. Never put an API key in a command or in a file I would commit; ask me where it should come from.

Read the install guide the agent follows

Other MCP clients

Add this to your client's mcpServers config.

{
  "mcpServers": {
    "agent4-io": {
      "type": "http",
      "url": "https://api.agent4.io/v1/mcp",
      "headers": {
        "X-API-Key": "<YOUR_API_KEY>"
      }
    }
  }
}

Tools

50

list_agents

List all agents in this tenant (name + published state).

Takes no parameters.

get_agent

Get one agent's full configuration (soul/task/tools/skills/knowledge_bases/model/params).

Parametersnamerequired

create_agent

Create an agent. `name` is lower-cased on save — it is a key, not a display name. soul = persona/identity; task = duties and boundaries; tools = tool-name whitelist (check list_tools first; the system tools time/geo/weather **and `compute_chart`** are **auto-enabled by default**, no need to list them — but note that passing `tools` at all replaces that default list, so include them yourself if you pass any); knowledge_bases = attached knowledge base names (once attached, retrieval is injected automatically every turn). `ask_forms` (**on by default**) lets the agent reply with a tappable single/multi-choice form instead of a paragraph of questions — the natural move when it needs two or three facts before it can answer. `compute_chart`, on by default too, is what lets it draw a chart; it computes shares / growth / running totals / projections in code from numbers already in the material, so the model never does the arithmetic. Pass `ask_forms=False` for an agent that should only ever answer in prose. alias = the **public human-readable slug** — strongly recommended: it becomes the memorable URL segment for this agent (`{public_base}/t/<tenant>/<alias>`), the link you hand to people. Use a URL-safe lowercase-hyphen name (`booking`, `suchka-venue`); it is normalised automatically. Collisions / invalid names are reported in alias_result.

Parametersnamerequiredsoultaskaliasmodeltoolsskillsask_formspublishedknowledge_bases

update_agent

Update **part** of an agent — fields you don't pass stay as they are. ⚠️ List-field semantics, don't mix them up: `tools=[...]` / `skills=[...]` / `knowledge_bases=[...]` are **full-list replacement** — items you didn't read first get pushed out. To "add one / remove one", use `add_tools` / `remove_tools` (and add_/remove_skills, add_/remove_knowledge_bases): incremental, idempotent, leaves the rest untouched. After the call, **read the response** to verify the final list — don't announce "enabled" just because the call succeeded. Also: tools can ride on a skill (the tools field of create_skill/update_skill) — once the skill is attached to an agent, its bound tools join the chat-time whitelist automatically, but they **do not appear in the agent's own tools list**. `auto_suggest=True` makes the agent propose 1–3 clickable follow-up questions after every turn (rendered above the composer; clicking one sends it). `suggest_prompt` is optional steering for those questions ("always move toward booking a demo") — leave it empty and they are written from the conversation alone. Costs one extra short LLM call per turn.

Parametersnamerequiredsoultaskmodeltoolsskillsgreetingadd_toolsask_formspublishedreasoningadd_skills+9 more

list_tools

List tool names assignable to agents, with their descriptions (incl. the tenant's connected MCP tools).

Takes no parameters.

list_mcp_servers

List the MCP servers connected in this tenant's tool library (read-only; secret fields omitted).

Takes no parameters.

create_share

Create a **share / integration entry point** for an agent — this is how end users actually reach it. **`published=True` only means "visible", not "reachable"**: for end users to talk to the agent you must create a share. The response carries a directly openable chat link (`{public_base}/s/<token>`) and the website embed URL (`{public_base}/embed/<token>`). For a website widget, paste one line before </body>: `<script src="{public_base}/embed.js" data-token="<token>"></script>`. label names this entry point ("website widget", "support link"). Telegram/WhatsApp and other channels are connected separately on the agent's Integration page in the console. **No website?** Hand the returned `chat_url` or `qr_url` (QR code) straight to the tenant: print it on business cards / flyers / in-store; scanning opens a full-page chat, no login, returning visitors are remembered per browser. **For links you give to humans, prefer `pretty_url`** (when present in the response): `{public_base}/t/<tenant alias>/<agent alias>` — memorable, printable, survives token rotation. No pretty_url = aliases not fully set — **fix that proactively**: agent alias via `create_agent`'s alias param or `PUT /agents/{name}/alias`; tenant alias in console → Settings. The `/s/<token>` link still works, but it is the machine/embed form, not one to read out to a person.

Parameterslabelagent_namerequired

list_shares

List an agent's shares (token / label / disabled / chat link / embed URL / appearance config). When the top-level `pretty_url` is non-empty it is the preferred link to give humans (see create_share).

Parametersagent_namerequired

configure_share

Configure this share — its name and its **appearance** — fields you don't pass stay as they are (server-side partial merge). - `label`: the name at the top of the chat page, and the browser tab's title. **Renaming a share is this call**; you never need to create a replacement and delete the old one. That would mint a new token, so the link already embedded in the client's site would stop working — the visible name and the address are not the same thing. - `theme_color`: the brand colour, `#RGB` or `#RRGGBB`. **This one colour is all you give** — its foregrounds are derived on save. - `highlight_color`: **only if the brand actually has a second colour.** Most don't; leave it out and nothing changes anywhere. When set, it is used where something should be visible without competing with the primary action: the second series in a chart, and citation markers. Buttons, the current storyline step and user bubbles stay on `theme_color` — two colours fighting over the same element is how a two-colour palette goes wrong. Foregrounds are derived from it the same way. Text/foreground colours are derived server-side to WCAG contrast and stored (a light brand colour automatically gets dark text instead of white) — **do not compute a palette yourself and do not try to set text colours**; they would be overridden. - `logo_url`: absolute URL. The header scales by height, any aspect ratio fits; **the collapsed launcher bubble is square**, so only near-square images (aspect 0.74–1.35) are used on the bubble — a wide wordmark falls back to the platform icon there. Want your mark in both places? Provide a square variant too. - `input_mode`: `text` (text box, default) or `voice` (opens in push-to-talk). Requires the platform's voice backend. - `launcher`: hover tooltip text for the bubble. `theme`: `light` / `dark` / empty = follow the visitor. - `custom_

Parameterslabelthemetokenrequiredlauncherlogo_urlagent_namerequiredcustom_cssinput_modetheme_colorhighlight_color

set_pwa_branding

Configure a specific **agent's** PWA branding and install experience (applies to that agent's `/s/` standalone chat pages — what gets installed to the home screen is one agent's entry page, so each agent is its own app). - `agent`: the agent name whose install branding to configure (required). - `icon_source_url`: public URL of one master image (PNG/JPG/WebP ≥192×192, ideally a square logo). The server derives the full set: browser-tab favicon(48) + install icons 192/512 + Android maskable(512). Non-square images are centre-cropped. Once set, "Add to Home Screen" installs this agent's own icon. - `install_prompt`: prompt style — `banner` (a dismissible slim bar inside the chat page, default), `card` (a card shown on first visit; more visible, more intrusive), `off` (no prompt). Android/Chrome uses the system install dialog; iOS automatically switches to a "Share → Add to Home Screen" illustrated guide. Icon/prompt params optional, settable independently. Returns the final config (icon URLs + install_prompt). Full walkthrough in the Cookbook's configure-branding.

Parametersagentrequiredinstall_prompticon_source_url

set_custom_domain

Bind the client's own domain to this tenant's chat pages: `https://chat.client.com/` serves the tenant's branded page (or a specific agent's chat), the address bar keeps the client's domain, and the TLS certificate is issued automatically. **Have the client configure DNS first**: add a CNAME at their DNS provider pointing to the `cname_target` in the response (`endpoint.agent4.io`). Key points: - **Subdomains only** (`chat.client.com`). An apex domain (`client.com`) cannot carry a CNAME — have the client use a subdomain, or a DNS provider with CNAME flattening (Cloudflare etc.). - **Cloudflare users must set the record to DNS only (grey cloud)**. With the proxy on (orange cloud) the name resolves to Cloudflare's addresses, verification fails, and `last_error` says so. - Verification is **asynchronous**: checked once immediately on binding; if DNS hasn't propagated it stays `pending` and is re-checked every 10 minutes (calling this tool again also re-triggers). `status` = `active` means live; the certificate is issued on first visit. - **One** domain per tenant; changing the domain re-runs verification, changing only `agent_alias` does not. - Requires a plan that includes custom domains (403 = upgrade needed). `agent_alias` empty → the domain lands on the tenant's branded page (listing available agents); set to an agent's public alias → lands directly on that agent's chat page.

Parametersdomainrequiredagent_alias

list_skills

List this tenant's skills.

Takes no parameters.

get_skill

Get one skill's full content (including the complete instructions text).

Parametersnamerequired

create_skill

Create a skill. description = "when to use" (goes into the system prompt, keep it short); instructions = the detailed guide (fetched on demand via load_skill). The paradigm (important): instructions are visible only AFTER the model calls load_skill — if calling some tool is **mandatory** ("user gives a phone number → must call save_contact"), the trigger must be written into description, otherwise models often answer directly without loading the skill and the rule never takes effect. Also never promise return values a tool doesn't produce (ticket numbers / IDs) — the model will fabricate them. The returned warnings field flags both patterns.

Parametersnamerequiredtoolsdescriptioninstructions

update_skill

Update part of a skill — fields you don't pass stay as they are (server-side PATCH merge, no GET+PUT round-trip). ⚠️ `tools=[...]` is **full-list replacement**; to add/remove one use `add_tools`/`remove_tools` (incremental, idempotent). Tools bound to a skill take effect automatically at chat time on any agent the skill is attached to — no need to also add them to the agent's tools.

Parametersnamerequiredtoolsadd_toolsdescriptioninstructionsremove_tools

test_skill_trigger

Reality-check whether your prompts actually trigger tool calls (dry-run) — run this after writing/changing a skill instead of counting corpses in production. Replays your messages N times against the **production** system-prompt assembly, tool schemas and this tenant's actual model routing, capturing only the model's tool-call decision: **tool side effects are NOT executed**, no session is stored. Tokens count toward the tenant quota (messages≤5, samples≤5, at most 25 calls per invocation — pick test messages carefully). Two modes for the skill's two battlefields: - loaded=false (default): first turn, skill not loaded — tests whether the trigger in description works; - loaded=true: simulates post-load_skill — tests the quality of instructions (incl. few-shot examples). Returns per-message hit counts plus claimed_without_call (the model said "noted" WITHOUT calling the tool — the worst failure, fix first). Cover edge cases in your test messages: numbers with spaces, buried in long questions, corrections, email-only. The loop: create_skill → check warnings (static lint) → test_skill_trigger (dynamic reality check) → adjust description / add examples → re-test until the hit rate holds.

Parametersagentrequiredskillloadedsamplesmessagesrequiredexpect_tool

list_knowledge_bases

List this tenant's knowledge bases (with doc/chunk counts and relevance cutoff).

Takes no parameters.

get_knowledge_base

Get one knowledge base's configuration (including the full instructions text shown to the model).

Parametersnamerequired

create_knowledge_base

Create a knowledge base. **Write `description` — it is what routes questions to this base.** Before each answer the platform reads every attached base's `description` and decides which ones this question needs; a base whose description is vague or blank gets searched when it should not, or missed when it should. One line, in the words a visitor would use, naming the subject **and the boundary**: "Country-by-country medical device registration requirements — not company or pricing information." It is also the line shown in the console list, but that is the lesser job. **Write `instructions` at creation time — do not leave it blank.** It is injected next to this KB's excerpts whenever they are retrieved. It does NOT affect recall (recall is vector search + max_distance); it governs how the model USES what was retrieved. Derive it from the expected usage, one line each: - Scope: what it covers / does not, and what to do when out of scope ("Covers residential mortgages only; for car or personal loans, say so and hand off"). - Authority: where it ranks ("Current company policy; overrides industry norms"). - Usage rules specific to this content ("Any quoted rate must state its effective date"). The generic "answer from the excerpts; say when not covered" is built into the platform — never repeat it here. Blank is acceptable only for generic reference material with no special rules. Worked examples: search_agent4_docs("knowledge base instructions examples"). max_distance is the relevance cutoff (blank = global default 0.6); tighten for regulatory content, and calibrate against real queries rather than guessing. top_k is how many passages this base contributes per turn (1-10, blank = 3). Set it from the **shape of the documents**, not from how important the base feels: if a typical document is five passages long, three of them is a third of a record, and the model answers f

Parametersnamerequiredtop_kdescriptioninstructionsmax_distance

update_knowledge_base

Update part of a knowledge base — fields you don't pass stay as they are (server-side PATCH merge).

Parametersnamerequiredtop_kdescriptioninstructionsmax_distance

add_knowledge_text

Add a **text** document to a knowledge base (chunking + embedding happen synchronously; returns the real chunk count). For **local files** (pdf/docx…) see `add_knowledge_file`.

Parameterstitlerequiredcontentrequiredkb_namerequired

add_knowledge_file

Add a local file's content to a knowledge base (txt/md/html/pdf/docx). **This MCP runs on the platform server and cannot read paths on YOUR machine.** For text files, read the content yourself and call `add_knowledge_text`; for binaries (pdf/docx), upload via the console, or curl `/knowledge-bases/{name}/documents/upload`. **To ingest a whole folder, zip it and send that one endpoint** — subdirectories are walked, md/txt/pdf/html/docx are ingested one by one, and document names use the in-archive relative path (`2025/rates.pdf` vs `2026/rates.pdf` therefore never collide). Images, `.DS_Store` etc. inside the zip are ignored; if the archive contains an encrypted, corrupt or abnormally high-compression file, **the whole archive is rejected** naming the offending entry.

Parameterspathrequiredtitlekb_namerequired

search_knowledge_base

Search this knowledge base; returns matching chunks with distances. Uses **exactly the same retrieval path as real conversations** — use it to validate the cutoff and chunking: an empty result means this question will be judged "not covered" and the agent will answer "not in the knowledge base".

Parametersqueryrequiredkb_namerequired

build_knowledge_index

Build (or rebuild) the structured index for a knowledge base — the second leg beside vector search. Vector search answers "what does this passage say". It **cannot count, filter numerically or aggregate**, so "how many documents", "which ones are between 1000 and 2000 words", "how many per category" are not answered badly — they are structurally unanswerable. This builds a small per-KB table from whatever structured header the documents share, which the agent can then query with SQL via `query_knowledge_table`. Only worth it when the documents share a machine-readable header (a metadata table, YAML front matter, `Field: value` lines). **Prose gets declined, and that is the right answer** — a table of unique values makes statistics meaningless. `roles` names the fields that must be extracted **exactly** and never paraphrased. Use it when the answer has to quote something the model must not invent: - `identity` — what to call the item (book title, drug name, product name) - `link` — where to send the user - `image` — what to show the user - `code` — the unique identifier Which link is "the" link is a business fact the data does not state — only the customer knows. A declared role that cannot be found comes back in `roles.unresolved` **with candidate field names**: ask the user which one it is, do not guess. **Read `dropped` in the report and tell the user about it.** A column that was thrown out (coverage too low, two columns holding identical values) is invisible in later query results — the model simply works around it — so this report is the only place it is ever mentioned.

Parametersnamerequiredroles

get_knowledge_index

Show the structured index profile: per column coverage, type, numeric range, top values, warnings. **The warnings are the point.** On a real 4,500-document catalogue this surfaced three data problems nobody knew about: 1,058 documents with `page_count` 0, 505 with `reading_level` 0, 493 with `word_count` 0 — those are not zeros, they are missing values recorded as 0, and they silently poison every average, minimum and range filter built on them. Report the warnings to the user in their own terms ("493 of your books have no word count — they will all tie for shortest"). Nothing else in the platform will ever tell them.

Parametersnamerequired

patch_knowledge_index

Change the structured index schema from one sentence of plain language. Example requests: "also track the author so users can find other books by them", "I want to filter by illustrator", "drop the cover link". The model may only emit add/modify/remove/refused — it cannot rewrite the table, so it has no way to damage columns the user did not mention. **Data that is not in the documents comes back in `refused`, not as a new column.** Asked for a publication year that the corpus does not carry, it says so instead of inventing an empty column. Pass that refusal on to the user verbatim. Call with `apply=false` first and show the user what would change; batch several edits and apply once. Applying marks the index for rebuild — it does **not** re-embed anything, so it is cheap.

Parametersnamerequiredapplyrequestrequired

improve_prompt

Rewrite a field's text to work better as an AI system prompt; returns the improved text. field ∈ persona | task | greeting | storyline_task | storyline_opening | storyline_ai_trigger | storyline_ai_criteria | skill_description | skill_instructions | kb_description | kb_instructions — determines the rewrite target (a Task should read like commands, a KB description says "what's inside / when it's relevant", a skill description says "when to use" in one line, …). current = the current text (empty = draft from scratch); hint = the direction you want this time (empty = general polish); context = on-site context (which KB is being edited, values of sibling fields) — the more specific, the better the fit. Returns only the improved text, no explanation, no wrapper — the caller places it next to the original for a human to accept or reject.

Parametershintfieldrequiredcontextcurrent

diagnose_prompt

Read a field and return a list of **specific** improvement suggestions (string array). field: same values as improve_prompt. current = the text to diagnose (required — an empty text has nothing to diagnose). Typical flow: diagnose_prompt first, pick the suggestions you want, then fold them into improve_prompt's hint.

Parametersfieldrequiredcontextcurrentrequired

test_planner_trigger

Dry-run the Dynamic Planner's escalation judge: would these messages be offered a step-by-step plan? Use it after editing the agent's `task`, since the task text is the **business-domain gate** — a vague task lets out-of-domain requests through, a narrow one turns real customers away. messages: the user's turns in order; the LAST one is treated as the current turn and the rest as that user's earlier messages (same window the live judge sees). samples>1 re-runs the judge to show stability (it is a probabilistic call). expect: pass true/false to get `matched`. Nothing is stored — no session, no enrollment. Tokens count toward the tenant quota (kind=planner). Returns {triggered, samples, goals[], domain, matched}. Reads the judge only: whether the user then ACCEPTS the offer is a separate, user-controlled step.

Parametersagentrequiredexpectsamplesmessagesrequired

preview_plan

Generate a plan for a goal and return it for review **without persisting anything** — no temporary storyline, no enrollment, no user affected. Use it to inspect plan quality before trusting the feature in production, or to see how the agent's `task` constrains the steps. Returns {plan, backend, warnings}. `warnings` flags machine-detectable smells, notably checklist items that are the AGENT's own deliverable ("produce a summary") — those can never be ticked off, because ticking is judged from what the USER provides, so the step would stall forever.

Parametersgoalrequiredagentrequired

usage_stats

Usage statistics. group ∈ total | agent | user | space | day | model. Metadata only — token counts and event counts, never any conversation content. Use group="user" to see who uses the most, group="agent" for the busiest agent.

Parametersgroup

tenant_info

This tenant's basic info and quota (plus custom-domain binding status, if any).

Takes no parameters.

search_agent4_docs

Search agent4.io's own product docs — concepts (what a thing *is*) and cookbook recipes (which tool to *call*). Use when you're unsure how an agent4.io feature works, what a term means, or how to build something on the platform. Returns top passages with title, layer ("concept"|"ops"), url and a snippet. Public content; no tenant data involved.

Parameterskqueryrequired

list_end_users

List this tenant's **end users** (the people chatting with your agents) — roster only, never any conversation content. Each user carries: display name, login method (email / oauth:* / proxy), email (if any), space/session/document counts, last-24h token usage, and a `console_url` (click through for detail). q filters by name or external id; sort ∈ recent (default) | tokens24h (descending 24h usage). Pagination: pass the returned next_cursor back as cursor. Typical: list_end_users(sort="tokens24h") to find the most active / most expensive users.

Parametersqsortlimitcursor

get_end_user

Get one end user's detail: basic profile (name, contact email/phone, city, timezone) + their spaces. Never any conversation content. Carries a `console_url` to the user's detail page.

Parametersuidrequired

list_user_sessions

List one end user's **sessions** — metadata only: agent, title (AI summary), message count, tokens, timestamps. **Message bodies are not returned.** Transcripts are rendered in the console: each session carries a `console_url` that **deep-links straight to that conversation, auto-opened** (no digging through the detail page when there are many), plus `user_console_url` to the user's detail page as the general entry. Hand the link to the tenant — a human reads the original there. Pagination: pass next_cursor back as cursor.

Parametersuidrequiredlimitcursor

list_page_contexts

List all page playbooks of this tenant (with match rules, greeting mode, position).

Takes no parameters.

upsert_page_context

Create or fully replace a page playbook. `context` is the page background the **server** injects for the agent — write "who lands on this page, what they are deciding, what they usually worry about"; do NOT write facts like prices or quotas (those belong in a knowledge base, which also ranks higher in authority). `url_pattern` is a glob (`*/pricing`, `*/solutions/*`), matches the path only, ignores query strings and trailing slashes; without it the page must report the key explicitly. Resolution order: explicit key > url_pattern > default. `greeting_mode="generated"` produces the greeting and suggested questions on the fly in the visitor's language (recommended); `"static"` uses your fixed `greeting` / `questions`. **This is a full replace**: fields you don't pass fall back to defaults rather than staying as they are. To change one field, `list_page_contexts` first, merge, then send.

Parameterskeyrequiredlabelcontextgreetingpositionquestionsis_defaulturl_patterngreeting_mode

resolve_page_context

Given a URL (or key), show which playbook it resolves to — always verify after writing a match rule. Globs make it easy to write rules that "look right but never match" (one `*` short, one path level too many) — and in production the only symptom is visitors silently getting the default playbook, with no error anywhere.

Parameterskeyurl

page_context_stats

Open counts and suggested-question click counts per playbook — find copy nobody clicks.

Takes no parameters.

list_storylines

List this tenant's storylines (optionally filtered by agent). Includes state, version, default flag.

Parametersagent

get_storyline

Get one storyline's full definition (whole graph + profile_schema + top-level fields).

Parametersstoryline_idrequired

create_storyline

Create a storyline draft. After creating, self-check with validate_storyline, then publish_storyline. user_visibility — what the end user sees of their own run: "invisible" (default, no UI), "named" (a banner with the storyline name only), "trail" (banner + read-only view where untaken branches and future steps are redacted grey blocks), "full" (banner with step x/y + full read-only map). `learner_visibility` is the deprecated old name (legacy values hidden/completed_only still accepted and mapped). concurrency — who the progress follows: "user" (default) = progress belongs to the person, all of that user's sessions share one run — fits curricula / onboarding / KYC; "session" = progress belongs to the case, each session gets its own run, a new conversation = a new application — fits licence applications / tickets / per-product flows. Case state goes to the blackboard (travels with the run); facts about the person go to profile dimensions (shared across runs). graph = {"nodes":[Node,...], "edges":[]} (edges are derived from exits, may be left empty). Node = { node_key: stable uuid (unchanged across edits; exits/funnels reference it), title, task (may interpolate {dimension}/{blackboard.key}), type: "task"(default) | "document_review"(visual pre-review of uploads) | "export"(structured report) | "parallel"(parallel branches / AND-join), review: {"checkpoints":[str]} — type=document_review: per-item visual checkpoints, export: {"sections":[str]} — type=export: report sections, parallel: {"branches":[{"key":str,"label":str,"to_node_key":str},...]} — type=parallel: declares required branches, each pointing at a sub-flow entry; the user may do them in any order, the engine tracks completion, and only when ALL are done does the node take its single join exit (put it at exits[0]). A branch sub-flow's last step just exits bac

Parameterskeyrequirednameentrygraphagent_namerequiredallow_exitis_defaultconcurrencydescriptionon_completedisplay_nameshow_profile+6 more

update_storyline

Update **part** of a storyline draft — fields you don't pass stay as they are (GET-then-merge on top of a full PUT underneath). concurrency: "user" = progress belongs to the person (shared across sessions); "session" = progress belongs to the case (one run per session). Changes affect only **future** enrolments; in-flight runs are not migrated. ⚠️ Especially `graph`: not passing it = keep the existing graph. (This tool once treated "no graph" as replace-with-empty — renaming a storyline wiped its whole flow. Semantics are now partial; to truly clear the graph, pass `{"nodes":[],"edges":[]}` explicitly.) graph/Node/Exit/RuleAst structures: see create_storyline. Pass expected_version for optimistic locking. Read the response to verify, then validate_storyline.

Parameterskeyrequirednameentrygraphagent_namerequiredallow_exitis_defaultconcurrencydescriptionon_completedisplay_nameshow_profile+8 more

validate_storyline

Validate the storyline graph (entry / dead ends / unreachable / dangling / cross-line targets / rule dimensions). Returns {ok, errors}. Must pass before publishing.

Parametersstoryline_idrequired

publish_storyline

Publish a storyline: validates first (blocking errors → 422), then freezes an immutable version and marks it published.

Parametersstoryline_idrequired

unpublish_storyline

Unpublish (archive): no more auto-enrolment; in-flight users silently degrade to the plain agent on their next turn (progress kept — re-publishing resumes it).

Parametersstoryline_idrequired

clone_storyline

Clone a storyline into a new draft (new key, unpublished, doesn't claim default, no chain pointer) for tweaking.

Parametersstoryline_idrequired

export_storyline

Export a portable storyline JSON (schema_version + definition; no tenant/version/id) for backup, migration or re-import.

Parametersstoryline_idrequired

import_storyline

Import an exported storyline JSON as a draft. **Artifacts like "generate a storyline from a novel / source material" land here.** payload = the structure returned by export_storyline (schema_version + graph + profile_schema + top-level fields). Version-aware: payloads newer than the system supports are rejected. Always creates new, never claims default, key collisions auto-rename. override_agent_name rebinds the imported line to an agent that exists in the target tenant.

Parameterspayloadrequiredoverride_agent_name

Version history

1
  1. v1.4.0LatestSep 16, 2026

Score

83% of the applicable checks met

How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.

  • Reached in the last 30 daysRequired25 pts
  • Auth declaredRequired10 pts
  • Tools listedRequired15 pts
  • DescriptionRequired15 pts
  • Logo10 pts
  • Documentation15 pts

    Declare a GitHub repository with a README, or serve resource_documentation in the OAuth protected-resource metadata.

  • LicenseNot applicable

    A hosted service is used under its provider's terms, so no license is expected here. This check is left out of the percentage.