Token导航 LogoToken导航TokenDH.com
研究检索敏感数据clawhub未标认证来源可访问clear审计提醒

zion-baas-skill锡安巴斯技能

Agent Skill

zion-baas-skill 用于查找、检索和筛选相关信息,适合在 OpenClaw 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

4,775

周安装

197

GitHub Stars

公开资料未说明

下载量

1,560
OpenClaw

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

MIT-0

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:zion-baas-skill(锡安巴斯技能)
来源仓库:https://github.com/timqin-m/zion-baas-skill
安装命令:
openclaw skills install zion-baas-skill
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 OpenClaw 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

ClawHubOpenClaw
openclaw skills install zion-baas-skill

简介

zion-baas-skill 提供 Zion.app 的无头 BaaS 应用集成支持,用于后端功能接入。

  • 适用于需要调用 Zion 后端服务(如 GraphQL API)的场景。
  • 通过 clawhub 安装并使用 openclaw skills install zion-baas-skill 命令部署。
  • 需配置相应身份验证凭证与 API 访问权限。
  • 建议参考原始仓库文档了解具体集成方式与安全边界。

SKILL.md

name
zion-baas
description
Instructions and authentication code for building headless BaaS applications with Zion.app (functorz.com). Use when integrating Zion backend features like GraphQL, actionflows, AI agents, binary assets, and payments.

Zion.app Headless BaaS Skill

Overview

This skill outlines how to build frontend applications utilizing Zion.app as a headless Backend-as-a-Service (BaaS). Zion exposes all backend interactions (database, actionflows, third-party APIs, and AI agents) through a single, unified GraphQL API.

  • HTTP URL: https://zion-app.functorz.com/zero/{projectExId}/api/graphql-v2
  • WebSocket URL: wss://zion-app.functorz.com/zero/{projectExId}/api/graphql-subscription

Token Acquisition & Authentication (CRITICAL)

To interact with authenticated endpoints, you must obtain a JWT token by logging in or registering. Unauthenticated requests are assigned an anonymous user role. The JWT can be obtained in two ways. One is via username + password login. The other one is by querying the Meta API & fetching runtime backend token. The token return in FETCH_DATA_VISUALIZER is the runtime backend token.

1. Username Registration & Login

You should ask user for username and password.

mutation AuthenticateWithUsername($username: String!, $password: String!, $register: Boolean!) {
  authenticateWithUsername(username: $username, password: $password, register: $register) {
    account { id, permissionRoles }
    jwt { token }
  }
}

*Note: Both mutations return FZ_Account which is a subset of the full account type. It contains only email, id, permissionRoles, phoneNumber, profileImageUrl, roles, and username.*

Developer Authentication with Zion.app (Meta API)

If you need to interact directly with the Zion platform (Meta API) to fetch project schemas, list projects, or authenticate as an admin to the runtime backend, follow these steps:

1. Acquire Developer JWT Token

There are two ways to acquire a developer token: via OAuth Flow or via Email/Password login.

Option A: OAuth Flow

Set up a local HTTP server to receive the OAuth callback. Open the Zion authentication endpoint (https://auth.functorz.com/login) in the browser and wait for the token parameter.

You can run the bundled authentication script:

cd ~/.openclaw/skills/zion_baas/scripts
npm run auth

Option B: Email/Password Login

You can directly login with an email and password using the Meta API:

cd ~/.openclaw/skills/zion_baas/scripts
npm run auth:email <email> <password>

2. Querying the Meta API & Fetching Runtime Backend Token

Use the developer JWT token as a Bearer token against the Meta API (https://zionbackend.functorz.com/api/graphql) to get the schema or data visualizer tokens. The data visualizer token grants administrative access to the project's runtime backend (zeroUrl).

You can run the bundled script to fetch the token. It requires the developer token to be present in .zion/credentials.yaml.

cd ~/.openclaw/skills/zion_baas/scripts
npm run fetch-token -- <projectExId>

You can also search for projects or fetch their schema via the Meta API using the bundled meta script:

cd ~/.openclaw/skills/zion_baas/scripts
# Search projects (returns project names and exIds)
npm run meta -- search-projects "optional search term"

# Fetch project schema (returns data models, actionflows, apis)
npm run meta -- fetch-schema <projectExId>

Credential Management & State Persistence

All credentials and project state MUST be persisted in the .zion directory at the root of the user's project in YAML format, typically in a file named .zion/credentials.yaml.

Required YAML Format

The credentials file must adhere to the following structure:

# .zion/credentials.yaml
developer_token:
  token: "<your_developer_jwt_token>" # Used to communicate with zionbackend.functorz.com
  expiry: "<timestamp_or_date_of_expiry>"

project:
  exId: "<project_ex_id>"
  name: "<project_name>"
  admin_token:
    token: "<runtime_backend_admin_token>"
    expiry: "<timestamp_or_date_of_expiry>"
  other_users:
    - user_id: "<user_id>"
      user_tags: 
        - "<notable_information_about_the_user_1>"
      token:
        token: "<user_jwt_token>"
        expiry: "<timestamp_or_date_of_expiry>"
  • developer_token: The JWT token acquired via the OAuth flow, used against the Meta API (zionbackend.functorz.com).
  • project: Contains the core project identifiers (exId, name), the admin_token (data visualizer token) for the runtime backend, and other_users.
  • other_users: A list of authenticated users (e.g., test accounts) containing their user_id, helpful user_tags to identify their purpose, and their token.
  • expiry: All stored tokens must include an associated expiry.

Executing GraphQL Queries & Subscriptions via CLI

You can use the bundled scripts to quickly test GraphQL queries, mutations, and subscriptions from the command line without writing frontend boilerplate. These scripts automatically read the correct token from your project's .zion/credentials.yaml.

1. Execute a Query or Mutation

Pass your GraphQL query or mutation as a string.

cd ~/.openclaw/skills/zion_baas/scripts
npm run gql -- <projectExId> <role> '<query_string>' '<optional_variables_json>'
  • <role>: Can be admin (uses data visualizer token), anonymous (no token), or a specific user_id (fetches token from other_users in .zion/credentials.yaml).

*Example:*

npm run gql -- myProjectEx123 admin 'query GetProject($id: Int!) { project(id: $id) { name } }' '{"id": 1}'

2. Listen to a Subscription

Pass your GraphQL subscription as a string.

cd ~/.openclaw/skills/zion_baas/scripts
npm run subscribe -- <projectExId> <role> '<query_string>' '<optional_variables_json>'

The script will establish a WebSocket connection and continuously print events as they arrive until you kill it (Ctrl+C).

Database & GraphQL Schema Rules

  • Use zion MCP server or webfetch/curl to introspect the schema before making assumptions.

The GraphQL schema is automatically generated directly from the PostgreSQL data model.

CRITICAL CATCH-ALL RULE: If you are ever in doubt about the exact structure, available fields, Enum values (like [Enum:ROUNDING_MODE]), or specific arguments for an endpoint, you must use the webfetch/curl tool to introspect the live GraphQL schema via the provided endpoint URL before making assumptions.

1. Naming Conventions & Root Operations

Each table generates corresponding root query, mutation, and subscription fields. For a table named [table]:

Queries

  • [table]: Fetch lists (supports where, order_by, distinct_on, limit, offset).
  • [table]_by_pk: Fetch single record by primary key (id).
  • [table]_aggregate: Aggregate queries (count, sum, avg, min, max).
  • [table]_group_by: Group records based on specified fields.
  • fz_[table]_by_[column]: Auto-generated spatial proximity search if the table contains a geo_point column.
  • Relay API: If configured, generates a cursor-based pagination query returning a Connection_[table] object.

Mutations

  • insert_[table], insert_[table]_one: Create records. Supports nested inserts and on_conflict (requires constraint and update_columns).
  • update_[table], update_[table]_by_pk: Modify records. Uses _set (replace) and _inc (increment numeric). where is required (!) for bulk updates. *(Note: Hasura JSONB update operators like _append/_delete_key are not supported).*
  • delete_[table], delete_[table]_by_pk: Remove records. where is required (!) for bulk deletes.
  • export_[table]: Trigger a data export task for the table.

Subscriptions

  • [table], [table]_by_pk, [table]_aggregate: Live queries mirroring their standard query counterparts.

2. Column Types and Data Mappings

Primitive Types

  • textString, integerInt, bigint, bigserialbigint, float8Float8, decimalDecimal, booleanBoolean, jsonbjsonb.
  • Time/Date: timestamptz, timetz, date, interval.
  • Geo: geo_pointgeography.

Composite (Media) Types

Media columns (image, file, video) are structurally 1:N relations but act as fields.

  • Single Media: Stored as [column]_id (e.g., cover_image_id) referencing system asset tables (FZ_Image, FZ_File, FZ_Video).
  • Media Lists: Types like image_list, video_list, file_list map to GraphQL Arrays and are stored as [column]_ids (e.g., gallery_images_ids).

System-Managed Columns

id, created_at, updated_at are read-only and automatically managed. They cannot be used in mutation inputs (_set, _inc, insert inputs).

3. Relationships

Relationships are defined by foreign keys and determine GraphQL nested fields:

  • 1:1 (One-to-One): Yields a single nested object (e.g., meta: post_meta).
  • 1:N (One-to-Many): Yields an array (e.g., post_tags: [post_tag]) and an aggregate object (e.g., post_tags_aggregate).

4. Filtering (where clauses)

Filters rely on [table]_bool_exp.

Logical Operators

  • _and: [bool_exp], _or: [bool_exp], _not: bool_exp

Relation Filters

Navigate relationships using the relationship field name directly. The value is a nested [related_table]_bool_exp object.

  • To-One Relationships (1:1, N:1): Filters the parent record based on the single related record's fields.

*(e.g., Find posts where the author's name is "John": author: { name: { _eq: ... } })*

  • To-Many Relationships (1:N, N:M): Uses EXISTS semantics. The parent record is returned if any related record in the array matches the nested condition.

*(e.g., Find posts that have at least one tag named "Tech": post_tags: { tag: { name: { _eq: ... } } })*

Comparison Predicates (Strict Pattern)

Zion uses a strict Operator-First Pattern. A predicate must start with the operator. If it's a generic operator, the operand wrapper type must match the *final evaluated type*, not necessarily the column type.

Structure:

{
  "_operator": {
    "operand_type": {
      "left_operand": { ... },
      "right_operand": { ... }
    }
  }
}
  • Operators:

* Comparison (Generic): _eq, _neq, _gt, _lt, _gte, _lte * Array (Generic): _in, _nin * Nullity (Generic, Unary): _is_null, _is_not_null * Text (String Pattern): _like, _nlike, _ilike, _nilike, _similar, _nsimilar * JSONB: _contains, _contained_in, _has_key, _has_keys_any, _has_keys_all * Boolean: _is_true, _is_false * Collection: _is_empty, _is_not_empty

  • Operand Definitions (left_operand / right_operand):

* Literal: {"literal": value} * Column: {"column": "field_name"} * Function: {"function_name": { ...args }}

  • Operand Types (Determined by Final Value): bigint_operand, text_operand, boolean_operand, timestamptz_operand, etc.

Example Predicate (Extract Month from Timestamp and check if = 12):

{
  "_eq": {
    "bigint_operand": {
      "left_operand": {
        "extract_timestamptz": { "time": { "column": "created_at" }, "unit": "MONTH" }
      },
      "right_operand": { "literal": "12" }
    }
  }
}

5. Aggregations, Window Functions, and Order By

Aggregation ([table]_aggregate)

Returns an aggregate query object containing two main fields:

  • nodes: An array of the actual table objects ([table!]!) containing the raw data rows that match the query's where, limit, offset, and order_by criteria.
  • aggregate: An object containing statistical calculations over the matched rows:

* count(columns: [Enum], distinct: Boolean): * If no columns are provided, it counts all rows (COUNT(*)). * If distinct: true and 1+ columns are provided, it counts unique values or unique combinations of the specified columns. * If distinct: false and multiple columns are provided, the system restricts the count to only evaluate the *first* column in the array. * sum, avg: Only available for numeric columns. * max, min: Available for comparable columns (numeric, time, text).

Window Functions

Advanced analytical operations like ROW_NUMBER, RANK, DENSE_RANK, NTH_VALUE are supported in specific formula and window frame inputs.

Sorting (order_by)

Supports sorting by:

  1. Direct columns: { title: asc }
  2. Related 1:1 records: { author: { name: desc } }
  3. Aggregates of N:1 records: { post_tags_aggregate: { count: desc } }
  4. Vector Search: Text columns may support similarity sorting if the TEXT_COLUMN_VECTOR_SORT extension is applied.

6. Formula Functions (Operands)

Functions are used inside operand wrappers by wrapping the uppercase function name around its arguments (e.g., {"EXTRACT_TIMESTAMPTZ": { "time": ..., "unit": ... }}).

Input Constraints & Semantics

  • [TYPE]: Indicates a required column or scalar operand of that exact type.
  • [TYPE?]: Indicates an optional operand (usually defaults to 0 or null).
  • [ANY]: Accepts any column or scalar operand of any type.
  • [NUMERIC]: Accepts BIGINT, INTEGER, DECIMAL, FLOAT8, or BIGSERIAL.
  • [COMPARABLE]: Accepts NUMERIC types, TEXT, DATE, TIMESTAMPTZ, TIMETZ, or INTERVAL.
  • [ANY[]]: Accepts an array operand of any type.
  • [Enum:NAME]: Requires an explicit Enum value matching the [NAME] definition (e.g., [Enum:DATE_UNIT] requires YEAR, MONTH, etc.).
  • Nested Functions: Arguments can often be the output of other functions, provided the output type matches the expected input type.

Manipulation

  • CONCAT(items: [TEXT[]])
  • SUBSTRING(source_text: [TEXT], start_index: [BIGINT], end_index: [BIGINT])
  • LEFT(source_text: [TEXT], length: [BIGINT])
  • RIGHT(source_text: [TEXT], length: [BIGINT])
  • LOWER(source_text: [TEXT])
  • UPPER(source_text: [TEXT])
  • TRIM(text: [TEXT])
  • TRIM_TRAILING_ZERO(source_text: [TEXT])
  • REPEAT(text: [TEXT], times: [BIGINT])
  • ENCODE_URL(text: [TEXT])
  • DECODE_URL(text: [TEXT])
  • ARRAY_CONCAT(first_array: [ANY[]], second_array: [ANY[]])
  • SLICE(array: [ANY[]], start_index: [BIGINT], length: [BIGINT])
  • UNIQUE(array: [ANY[]])
  • COALESCE(array: [ANY[]])

Search & Replace

  • REPLACE_OCCURRENCES(source_text: [TEXT], search_text: [TEXT], replace_text: [TEXT], max_replacements: [BIGINT])
  • REPLACE_AT_POSITION(source_text: [TEXT], start_index: [BIGINT], length: [BIGINT], replace_text: [TEXT])
  • POSITION(source_text: [TEXT], search_text: [TEXT])
  • CONTAINS(source_text: [TEXT], search_text: [TEXT])

Regex

  • REGEX_EXTRACT(text: [TEXT], regex: [TEXT])
  • REGEX_REPLACE(text: [TEXT], regex: [TEXT], replacement: [TEXT])
  • REGEX_EXTRACT_ALL(text: [TEXT], regex: [TEXT])
  • REGEX_MATCH(text: [TEXT], regex: [TEXT])

Formatting & Utils

  • TEXT_DECIMAL_FORMAT(number: [DECIMAL], fraction_digits: [BIGINT], rounding_mode: [Enum:ROUNDING_MODE], clear_trailing_zeros: [BOOLEAN])
  • NUMBER_FORMAT(number: [DECIMAL], fraction_digits: [BIGINT], format: [Enum:NUMBER_FORMAT])
  • STRING_LEN(source_text: [TEXT])
  • RANDOM_TEXT(min_length: [BIGINT], max_length: [BIGINT], include_numbers: [BOOLEAN], include_lower_case: [BOOLEAN], include_upper_case: [BOOLEAN])
  • UUID()
  • JOIN(array: [TEXT[]], separator: [TEXT])
  • SPLIT(source_text: [TEXT], delimiter: [TEXT])
  • ARRAY_LEN(array: [ANY[]])

Arithmetic

  • ADD(value0: [NUMERIC], value1: [NUMERIC])
  • SUBTRACT(minuend: [NUMERIC], subtrahend: [NUMERIC])
  • MULTIPLY(value0: [NUMERIC], value1: [NUMERIC])
  • DIVIDE(dividend: [DECIMAL], divisor: [DECIMAL])
  • MODULO(dividend: [NUMERIC], divisor: [NUMERIC])
  • ABS(number: [NUMERIC])
  • POW(base: [NUMERIC], exponent: [NUMERIC])
  • LOG(base: [DECIMAL], argument: [DECIMAL])

Rounding & Formats

  • ROUND_UP(number: [DECIMAL])
  • ROUND_DOWN(number: [DECIMAL])
  • DECIMAL_FORMAT(number: [DECIMAL], fraction_digits: [BIGINT], rounding_mode: [Enum:ROUNDING_MODE])

Generators

  • RANDOM_BIGINT(min_length: [BIGINT], max_length: [BIGINT])
  • SEQUENCE(start: [BIGINT], end: [BIGINT], step: [BIGINT])

Current Time

  • CURRENT_DATE()
  • CURRENT_TIMETZ()
  • CURRENT_TIMESTAMPTZ()

Constructors

  • MAKE_DATE(years: [BIGINT], months: [BIGINT], days: [BIGINT])
  • MAKE_TIMETZ(hours: [BIGINT?], minutes: [BIGINT?], seconds: [BIGINT?], milliseconds: [BIGINT?])
  • MAKE_TIMESTAMPTZ(years: [BIGINT], months: [BIGINT], days: [BIGINT], hours: [BIGINT?], minutes: [BIGINT?], seconds: [BIGINT?], milliseconds: [BIGINT?])
  • MAKE_INTERVAL(years: [BIGINT], months: [BIGINT], weeks: [BIGINT], days: [BIGINT], hours: [BIGINT], minutes: [BIGINT], seconds: [BIGINT], milliseconds: [BIGINT])
  • FROM_DATE_AND_TIMETZ(date: [DATE], timetz: [TIMETZ])

Extraction & Formatting

  • EXTRACT_DATE(time: [DATE], unit: [Enum:DATE_UNIT])
  • EXTRACT_TIMETZ(time: [TIMETZ], unit: [Enum:TIME_UNIT])
  • EXTRACT_TIMESTAMPTZ(time: [TIMESTAMPTZ], unit: [Enum:TIMESTAMP_UNIT])
  • DATE_FORMAT(time: [DATE], format: [TEXT], language: [Enum:LANGUAGE])
  • TIMETZ_FORMAT(time: [TIMETZ], format: [TEXT], language: [Enum:LANGUAGE])
  • TIMESTAMPTZ_FORMAT(time: [TIMESTAMPTZ], format: [TEXT], language: [Enum:LANGUAGE])
  • DURATION_FORMAT(duration: [DECIMAL], unit: [Enum:DURATION_UNIT], format: [TEXT])
  • RELATIVE_DATE(time: [DATE], language: [Enum:LANGUAGE], hide_suffix: [BOOLEAN])
  • RELATIVE_TIMESTAMPTZ(time: [TIMESTAMPTZ], language: [Enum:LANGUAGE], hide_suffix: [BOOLEAN])

Calculations & Deltas

  • DELTA_DATE(date: [DATE], increase: [BOOLEAN], years: [BIGINT?], months: [BIGINT?], days: [BIGINT?])
  • DELTA_TIMETZ(timetz: [TIMETZ], increase: [BOOLEAN], hours: [BIGINT?], minutes: [BIGINT?], seconds: [BIGINT?], milliseconds: [BIGINT?])
  • DELTA_TIMESTAMPTZ(timestamptz: [TIMESTAMPTZ], increase: [BOOLEAN], years: [BIGINT?], months: [BIGINT?], days: [BIGINT?], hours: [BIGINT?], minutes: [BIGINT?], seconds: [BIGINT?], milliseconds: [BIGINT?])
  • EXTRACT_DATE_DURATION(start_time: [DATE], end_time: [DATE], unit: [Enum:DATE_UNIT])
  • EXTRACT_TIMETZ_DURATION(start_time: [TIMETZ], end_time: [TIMETZ], unit: [Enum:TIME_UNIT])
  • EXTRACT_TIMESTAMPTZ_DURATION(start_time: [TIMESTAMPTZ], end_time: [TIMESTAMPTZ], unit: [Enum:TIMESTAMP_UNIT])

Conversions

  • FROM_TIMESTAMPTZ_TO_DATE(timestamptz: [TIMESTAMPTZ])
  • FROM_TIMESTAMPTZ_TO_TIMETZ(timestamptz: [TIMESTAMPTZ])

Geography

  • FROM_COORDINATES(latitude: [DECIMAL], longitude: [DECIMAL])
  • GEO_DISTANCE(point0: [GEO_POINT], point1: [GEO_POINT], unit: [Enum:GEO_DISTANCE_UNIT])
  • GEO_LONGITUDE(geo: [GEO_POINT])
  • GEO_LATITUDE(geo: [GEO_POINT])

Aggregates

  • SUM(array: [NUMERIC[]])
  • AVG(array: [NUMERIC[]])
  • MAX(value0: [COMPARABLE], value1: [COMPARABLE])
  • MIN(value0: [COMPARABLE], value1: [COMPARABLE])
  • GREATEST(array: [COMPARABLE[]])
  • LEAST(array: [COMPARABLE[]])

Element Access

  • ITEM(array: [ANY[]], index: [BIGINT])
  • FIRST_ITEM(array: [ANY[]])
  • LAST_ITEM(array: [ANY[]])
  • RANDOM_ITEM(array: [ANY[]])
  • ARRAY_POSITION(array: [ANY[]], item: [ANY])

JSONB

  • JSON_EXTRACT_BY_DOT_NOTATION_JSONPATH(json: [JSONB], path: [TEXT])

Casting

  • CAST_FROM_TEXT(value: [TEXT])
  • CAST_COLUMN_TO_TEXT(value: [ANY])
  • CAST_ARRAY_TO_TEXT(value: [ANY[]])
  • CAST_TO_BIGINT(value: [ANY])
  • CAST_TO_DECIMAL(value: [ANY])

Vector Search

  • EMBEDDING_VECTOR_DISTANCE(embedded_text_column: [Enum:EMBEDDING_COLUMN], text: [TEXT], distance_function: [Enum:VECTOR_DISTANCE])

System

  • NULL_VALUE()

Explicit Enum Definitions

When an argument requires an [Enum:NAME], you must use one of the following exact string values:

  • [Enum:DATE_UNIT]: YEAR, MONTH, DAY, WEEK
  • [Enum:DURATION_UNIT]: DAY, HOUR, MINUTE, SECOND, MILLISECOND
  • [Enum:EMBEDDING_COLUMN]: (Dynamically generated based on columns with TEXT_COLUMN_VECTOR_SORT extension)
  • [Enum:GEO_DISTANCE_UNIT]: METER, KILOMETER, MILE
  • [Enum:LANGUAGE]: EN, ZH
  • [Enum:NUMBER_FORMAT]: THOUSANDS_SEPARATOR, PERCENT
  • [Enum:ROUNDING_MODE]: HALF_EVEN, HALF_UP, HALF_DOWN, UP, DOWN, CEILING, FLOOR
  • [Enum:TIMESTAMP_UNIT]: YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, MILLISECOND, WEEK
  • [Enum:TIME_UNIT]: HOUR, MINUTE, SECOND, MILLISECOND
  • [Enum:VECTOR_DISTANCE]: EUCLIDEAN, COSINE

Actionflow Protocol

Overview

Although zion-app.functorz.com already support direct CRUD operations that can be initiated from the frontend, many backend operations are multi-step, can be long-running and sometimes have to be asynchronous. Therefore zion-app.functorz.com also supports actionflows for these scenarios. An actionflow is a directed acyclic graph made up of actionflow nodes. These nodes represent either operations (e.g. insert into databsae, invoke another actionflow) or control flow changes (condition and loop). Actionflows also have two special nodes, input and output, where the arguments and return values of the entire actionflow are defined.

Actionflows have two modes of operation, sync or async. A synchronous actionflow is executed within a single database transaction, and therefore when an unexpected error is encountered, will rollback all database changes. Synchronous actionflows have runtime limits to avoid hogging database connection. Asynchronous actionflows run each node inside a new database transaction, so they do not have rollback mechanism, but are more suited for long running tasks, like long http calls, especially those made to LLM APIs as they can take minutes. Within actionflows, all nodes of invoking AI agents built in zion-app.functorz.com natively can only be added inside async ones.

Actionflow invocation process

In order to invoke an actionflow, one needs to obtain its id, a list of arguments and optionally its version. They are found inside the project schema. Actionflow invocation differ based on their type.

Sync actionflows

Sync actionflows can be invoked via a regular GraphQL mutation. The results will be returned in the response of the same HTTP request. Request:

mutation someOperationName ($args: Json!) {
 fz_invoke_action_flow(actionFlowId: "d3ea4f95-5d34-46e1-b940-91c4028caff5", versionId: 3, args: $args)
}
{
  "args": {
    "yaml": "post_link:\
  url: \"https://zion-app.functorz.com\"\
",
    "img_id": 1020000000000111
  }
}

Within this query, $args corresponds to the arguments listed in the actionflow's input node. Response:

{
  "data": {
    "fz_invoke_action_flow": {
      "img": {
        "id": 1020000000000090,
        "url": "https://fz-zion-static.functorz.com/202510252359/a64a7eb4793728a1977d3ea9e7b7e4e8/project/2000000000521152/import/1110000000000001/image/636.jpg"
      },
      "url": "https://zion-app.functorz.com"
    }
  }
}

Async actionflows

Async actionflows are triggered via a GraphQL mutation but the results are not returned in the response of the same HTTP request. Instead, a fz_create_action_flow_task is returned, containing the id of the corresponding task, which is then used for subscribing to the result in a separate GraphQL subscription. Mutation request:

mutation mh49tgie($args: Json!) {
 fz_create_action_flow_task(actionFlowId: "2a9068c5-8ee3-4dad-b3a4-5f3a6d365a2f", versionId: 4, args: $args)
}
{
  "args": {
    "int": 123,
    "img_id": 1020000000000116,
    "some_text": "Dreamer",
    "datetime_with_timezone": "2025-10-23T20:13:00-07:00"
  }
}

Mutation response: { "data": { "fz_create_action_flow_task": 1150000000000148 } }

Subscription request:

subscription fz_listen_action_flow_result($taskId: Long!) {
  fz_listen_action_flow_result(taskId: $taskId) {
    __typename"
    output
    status
  }
}
{ "taskId" : 1150000000000148 }

Subscription response:

{
  "data": {
    "fz_listen_action_flow_result": {
      "__typename": "ActionFlowTaskResult",
      "output": {
        "img": {
          "id": 1020000000000089,
          "url": "https://fz-zion-static.functorz.com/202510262359/3a5f04371bf68d6c94bb890879101f0a/project/2000000000521152/import/1110000000000001/image/637.jpg"
        },
        "xyz": {
          "type": "Point",
          "coordinates": [
            131,
            22
          ]
        }
      },
      "status": "COMPLETED"
    }
  }
}

There might be multiple messages sent by the GraphQL subscription before the final result (inside "output") is returned, and each may contain different status values. The status field has the following transition rules:

switch (status) {
  case CREATED -> Set.of(PROCESSING);
  case PROCESSING -> Set.of(COMPLETED, FAILED);
  default -> Set.of();
};

AI Agent Protocol

Overview

Zion.app has an integrated AI agent builder, which supports multi-modal (text, video, image) inputs and outputs, prompt templating, context fetching (via database and third-party APIs), tool use (actionflows, third-party APIs and other AI agents) and structured output (JSON according corresponding JSONSchema). AI Agents' results are delivered differently by the GraphQL service depending on the configuration of its output, namely, whether it is streaming and whether it is structured. A structured output can not be streamed but plain text can be either streamed or not. A structured output must be accompanied by a JSONSchema that describes the JSON's type. In order to invoke an AI agent, the id and the input arguments must be obtained from the project schema. An AI agent built in Zion.app's agent builder can only be invoked via the GraphQL API asynchronously.

Invocation process for streaming output

An example AI Agent configuration whose output is a streaming plain text will be used to illustrate this process. Its configuration is:

{
    "id": "mgzzu8jp",
    "summary": "An example summary of what the agent does",
    "inputs": {
      "mgzzufo2": {
        "type": "VIDEO",
        "displayName": "the_video",
      },
      "mh4cjjcf": {
        "type": "TEXT",
        "displayName": "text",
      },
      "mh4cjkyv": {
        "type": "BIGINT",
        "displayName": "some_int",
      },
      "mh4cjoof": {
        "type": "array",
        "itemType": "IMAGE",
        "displayName": "images",
      }
    },
    "output": "Unstructured Text"
}
  1. A mutation is sent to start the AI agent, supplying the arguments as inputArgs and the id as zAIConfigId. The response value only contains the id of the corresponding conversation. The keys of inputArgs should be the same keys in the inputs object from the schema. Input parameters of Image / video or other binary assets types, or arrays of such types are handled slightly differently. Their key names wihtin the inputArgs object have _id suffix. e.g. the following configuration
{ 
  "inputs": {
    "mgzzufo2": {
      "type": "VIDEO",
      "displayName": "the_video",
    }
  }
}

Corresponds to:

{
  "inputArgs": {
    "mgzzufo2_id": 1030000000000002,
  }
}

Mutation request: Query:

    mutation ZAICreateConversation($inputArgs: Map_String_ObjectScalar!, $zaiConfigId: String!) {
     fz_zai_create_conversation(inputArgs: $inputArgs, zaiConfigId: $zaiConfigId)
    }

Variables:

    {
      "inputArgs": {
        "mgzzufo2_id": 1030000000000002,
        "mh4cjjcf": "Just some text",
        "mh4cjkyv": 23,
        "mh4cjoof_id": [
          1020000000000097,
          1020000000000111,
          1020000000000120
        ]
      },
      "zaiConfigId": "mgzzu8jp"
    }

Mutation response:

    {
      "data": {
        "fz_zai_create_conversation": 1480
      }
    }
  1. Using the obtained conversation id to subscribe to the result of the previous invocation of the AI Agent. Multiple messages may be received. The messages' status may transition from IN_PROGRESS to STREAMING to eventually COMPLETED. The last message always gives you COMPLETED status and its data field will contain the consolidated output from all the previous STEAMING messages' data field.

For models that have reasoning content output, it works similarly as the actual output. i.e. Partial reasoning content will be emitted first in multiple messages in the reasoningContent field, and then when everything is ready, the entirety of reasoningContent will be emitted again the COMPLETED message. Subscription request: Query:

    subscription ZaiListenConversationResult($conversationId: Long!) {
      fz_zai_listen_conversation_result(conversationId: $conversationId) {
        conversationId
        status
        reasoningContent
        images {
          id
          __typename
        }
        data
        __typename
      }
    }

Variables:

    {
      "conversationId": 1480
    }

Subscription response messages:

    {
      "data": {
        "fz_zai_listen_conversation_result": {
          "__typename": "ConversationResult",
          "conversationId": 1480,
          "data": null,
          "images": null,
          "reasoningContent": null,
          "status": "IN_PROGRESS"
        }
      }
    }
    {
      "data":{
        "fz_zai_listen_conversation_result": {
          "__typename": "ConversationResult",
          "conversationId": 1480,
          "data": "This collection features three images and a short video. Two photos show the famous Chinese comedian and actor, Zhao Benshan. A third",
          "images": null,
          "reasoningContent": null,
          "status": "STREAMING"
        }
      }
    }
    {
      "data":{
        "fz_zai_listen_conversation_result": {
          "__typename": "ConversationResult",
          "conversationId": 1480,
          "data": " image is an anime illustration of a young woman in a \"SHOHOKU\" basketball jersey, resembling the character Haruko Akagi from the series *Slam Dunk*.",
          "images": null,
          "reasoningContent": null,
          "status": "STREAMING"
        }
      }
    }
    {
      "data":{
        "fz_zai_listen_conversation_result": {
          "__typename": "ConversationResult",
          "conversationId": 1480,
          "data": "This collection features three images and a short video. Two photos show the famous Chinese comedian and actor, Zhao Benshan. A third image is an anime illustration of a young woman in a \"SHOHOKU\" basketball jersey, resembling the character Haruko Akagi from the series *Slam Dunk*.",
          "images": null,
          "reasoningContent": null,
          "status": "COMPLETED"
        }
      }
    }

Invocation process for non streaming plain text output

  1. The mutation step is identical to the one inside the invocation process for streaming output. I.e. send mutation fz_zai_create_conversation(inputArgs: $inputArgs, zaiConfigId: $zaiConfigId) to obtain the conversation id.
  1. There will be no messages in the STREAMING state. i.e. A message of IN_PROGRESS status will be sent by the server, followed directly by the COMPLETED message with the final result.

Invocation process for AI agents that use models with image output

Certain model support image output, like gemini-2.5-flash-image. Their invocation process is the same as the plain text ones. Except that in the COMPLETED message, the field images will be filled with content. The images Their output will be no different from plain-text only outputs, regardless of the streaming setting. Their COMPLETED message looks like:

{
  "data": {
    "fz_zai_listen_conversation_result": {
      "__typename": "ConversationResult",
      "conversationId": 1494,
      "data": "I merged the three images into one, combining elements from each to create a new, unique image.\
",
      "images": [
        {
          "__typename": "FZ_Image",
          "id": 1020000000000164
        }
      ],
      "reasoningContent": null,
      "status": "COMPLETED"
    }
  }
}

The ids for FZ_Image in images represent the ids in Zion's file / asset system. Refer to zion-binary-asset-upload-rules

Invocation process for structured output

AI agents with structured output cannot be streaming. They also always come with a JSONSchema in their configuration.

{
  "output": {
      "type": "object",
      "properties": {
        "httpLink": {
          "type": "string"
        },
        "reasoning": {
          "type": "string"
        }
      },
      "required": [
        "httpLink",
        "reasoning"
      ]
    }
}

There will be no messages from the GraphQL server that are in the "STREAMING" state. There will be one "COMPLETED" message where the data field is a JSON that satisfies the JSONSchema. e.g.

{
  "httplink": "https://www.google.com/calendar/event?eid=MTcxN2U3cHAzaDFtYTdxYzd0bGV0aHNvYmsgamlhbmd5YW9rYWlqb2huQG0",
  "explanation": "No existing events were found on 2025-10-24 in America/Los_Angeles, so there are no conflicts. Preference is mornings; scheduled 08:00–08:10 at Los Altos High school. With no adjacent events, transit checks to previous and next events are trivially satisfied."
}

Continuing conversation

After AI Agent returns result (status = COMPLETED), the conversation can be continued by calling fz_zai_send_ai_message. The subscription of fz_zai_listen_conversation_result on the same conversationId will continue to receive messages. e.g. mutation request:

  mutation continue($conversationId: Long!, $text: String) {
    fz_zai_send_ai_message(conversationId: $conversationId, text: $text)
  }

Variables:

  {
    "conversationId": 1480,
    "text": "make it about the sun"
  }

The response from the corresponding fz_zai_listen_conversation_result will then continue. Similar to what happens after one initiates a converation with an AI agent, going through the same IN_PROGRESS -> (STREAMING) -> COMPLETED status transition.

Stopping conversation

For converations still in "IN_PROGRESS" or "STREAMING" states, they can be stopped by calling fz_zai_stop_responding, which always returns true. When called on conversations with "COMPLETED" state, a 400 error will be thrown inside the errors field of the GraphQL response. e.g. mutation request:

  mutation continue($conversationId: Long!) {
    fz_zai_stop_responding(conversationId: $conversationId)
  }

Variables:

  {
    "conversationId": 1480
  }

Binary Asset Upload

All binary assets (images, videos, files) are stored on object storage services (e.g., S3). Their storage path is recorded in Zion's database. When referencing these assets in other tables, you must store only the asset's Zion ID, not its path or URL.

Upload Workflow

To upload a binary asset and obtain its Zion ID, you must follow a strict two-step process:

Step 1: Obtain a Presigned Upload URL

  1. Calculate the MD5 hash of the file (raw 128-bit hash), then Base64-encode it.
  2. Call the appropriate GraphQL mutation to request a presigned upload URL. Use the mutation that matches your asset type:

- imagePresignedUrl for images - videoPresignedUrl for videos - filePresignedUrl for other files

Provide: - The Base64-encoded MD5 hash - The file format/suffix (see MediaFormat below) - (Optional) Access control (see CannedAccessControlList below)

##### Example GraphQL Mutations

   mutation GetImageUploadUrl($md5: String!, $suffix: MediaFormat!, $acl: CannedAccessControlList) {
     imagePresignedUrl(imgMd5Base64: $md5, imageSuffix: $suffix, acl: $acl) {
       imageId
       uploadUrl
       uploadHeaders
     }
   }

   mutation GetVideoUploadUrl($md5: String!, $format: MediaFormat!, $acl: CannedAccessControlList) {
     videoPresignedUrl(videoMd5Base64: $md5, videoFormat: $format, acl: $acl) {
       videoId
       uploadUrl
       uploadHeaders
     }
   }

   mutation GetFileUploadUrl($md5: String!, $format: MediaFormat!, $name: String, $suffix: String, $sizeBytes: Int, $acl: CannedAccessControlList) {
     filePresignedUrl(
       md5Base64: $md5
       format: $format
       name: $name
       suffix: $suffix
       sizeBytes: $sizeBytes
       acl: $acl
     ) {
       fileId
       uploadHeaders
       uploadUrl
     }
   }

- CannedAccessControlList (recommended: PRIVATE): - AUTHENTICATE_READ, AWS_EXEC_READ, BUCKET_OWNER_FULL_CONTROL, BUCKET_OWNER_READ, DEFAULT, LOG_DELIVERY_WRITE, PRIVATE, PUBLIC_READ, PUBLIC_READ_WRITE - MediaFormat: - CSS, CSV, DOC, DOCX, GIF, HTML, ICO, JPEG, JPG, JSON, MOV, MP3, MP4, OTHER, PDF, PNG, PPT, PPTX, SVG, TXT, WAV, WEBP, XLS, XLSX, XML

Step 2: Upload the File and Use the Returned ID

  1. The mutation response includes:

- The asset's unique ID (imageId, videoId, or fileId) - A presigned uploadUrl - Any required uploadHeaders

  1. Upload the file:

- Perform an HTTP PUT request to the uploadUrl with the raw file data - Include any uploadHeaders from the mutation response

  1. Reference the asset:

- Use the returned ID as the value for the corresponding *_id field in your Zion data mutation (e.g., cover_image_id: returnedImageId)

Note: This two-step process is mandatory for all media uploads in Zion.app.

Third-Party APIs

A project built on Zion.app can have many third-party HTTP APIs imported. These are separated into two categories: query or mutation, roughly (though not always the case) corresponding to the semantics of HTTP GET vs POST. Each API is stored in the following data structure:

type ScalarType = 'string' | 'boolean' | 'number' | 'integer';
type TypeDefinition =
  | ScalarType
  | { [key: string]: TypeDefinition | TypeDefinition[] };

interface ThirdPartyApiConfig {
  id: string;
  name: string;
  operation: 'query' | 'mutation';
  inputs: { [key: string]: TypeDefinition };
  outputs: { [key: string]: TypeDefinition };
}

N.B. The value of the operation field within ThirdPartyApiConfig determines the root GraphQL field. i.e. query -> query operation_${id}, and mutation -> mutation operation_${id}.

Invocation process

Each input should be provided unless the user asks to remove it. e.g. Given TPA configuration as follows:

      {
        "id": "lzb3ownk",
        "inputs": {
          "body": {
            "summary": "string",
            "location": "string",
            "description": "string",
            "start": {
              "dateTime": "string",
              "timeZone": "string"
            },
            "end": {
              "dateTime": "string",
              "timeZone": "string"
            },
            "attendees": [
              "string"
            ]
          },
          "Authorization": "string"
        },
        "outputs": {
          "body": {
            "kind": "string",
            "etag": "string",
            "id": "string",
            "status": "string",
            "htmlLink": "string",
            "created": "string",
            "updated": "string",
            "summary": "string",
            "description": "string",
            "location": "string",
            "creator": {
              "email": "string",
              "self": "boolean"
            },
            "organizer": {
              "email": "string",
              "self": "boolean"
            },
            "start": {
              "dateTime": "string",
              "timeZone": "string"
            },
            "end": {
              "dateTime": "string",
              "timeZone": "string"
            },
            "iCalUID": "string",
            "sequence": "number",
            "reminders": {
              "useDefault": "boolean"
            },
            "eventType": "string"
          }
        },
        "operation": "mutation"
      }

The corresponding GraphQL query should be

mutation request_${nonce}($summary: String, $location: String, $description: String, $start_dateTime: String, $start_timeZone: String, $end_dateTime: String, $end_timeZone: String, $attendees:[String], $Authorization: String) {
  operation_lzb3ownk(fz_body: {}, arg1: $_1, arg2: $_2) {
    responseCode
    field_200_json {
      {subFieldSelections}
    }
 }
}

field_200_json is a fixed fields for all third-party API derived GraphQL operation. It means the response that's valid for all 2xx response codes.

The responseCode subfield should always be checked, in case 5xx or 4xx codes are returned, which means field_200_json would be empty.

适合场景

01

OpenClaw 用户查找和安装 Skill 时

02

用户想查找某类 Agent Skill 时

03

需要根据任务场景推荐可安装能力包时

04

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

补充不同宿主或平台的使用分布数据

能力 5

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

OpenClaw

92.35%
按下载量换算1,441

安全审计

VirusTotal

通过

ClawScan

通过

Static analysis

可疑

权限和风险

敏感数据

该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。来源安全扫描存在 warning/failed 结果,不能写成本站确认安全。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills