SuperAPI AI Directory

create-skill

Agents & models

View repository

Updated 10-16 10:07

About this skill

Create Skill

Author a Skill package the execution factory can register and an agent can follow. No platform code is involved: the agent already has get_skill_content, search_capabilities, get_kn_detail, query_metric, execute_tool and execute_action; the Skill's job is to say which capabilities to use and how.

Works with the openbkn skill

create-skill writes the files; the openbkn skill runs openbkn skill register, openbkn skill set-status, openbkn sandbox run, openbkn function create once they exist. create-bkn models the network itself — a Skill assumes the network, its metrics and its actions already exist.

Package layout

{skill_dir}/
├── SKILL.md                 # required; frontmatter name + description (+ metadata.uses)
└── references/              # optional: report format, business rules, IO contract
    └── report-spec.md

The execution factory parses only frontmatter name, description and metadata (free-form, stored as-is). The body is prose the agent reads — the "capability dependencies" table below is a convention, not a schema.

Workflow

  1. Fix the scope — one knowledge network (bkn_scope). List the user questions that trigger this skill and the parameters the agent must obtain from the user.
  2. Pick capabilities by name — metrics and action types from get_kn_detail / get_object_types, functions and MCP tools from search_capabilities. Use the registered names verbatim; the agent searches by name.
  3. Declare them twice — machine-readable in frontmatter metadata.uses[] (type, name, purpose, confirm), and for the agent in the body table (name | type | purpose | how to call | how to read the result | confirmation).
  4. Write the steps — numbered, one platform call per step, with parameter mapping between steps. Say which step ends early on a good result and which step must ask the user first.
  5. Mark confirmations — any action with side effects gets confirm: true and the sentence "do not execute without an explicit yes". The platform does not gate this; the skill does.
  6. Add references/report-spec.md — the output shape, including the "依据" line naming the capabilities used so the user can check the trace.
  7. Register, publish, mount — see Delivery. A skill is only visible to an agent inside networks it is mounted on.
  8. Verify end-to-end — one managed interaction should show get_skill_content → query_metric → execute_tool → execute_action under the same interaction_id, and bkn_finish_interaction should return evidence_status: complete.

Template: assets/templates/SKILL.md.template · assets/templates/report-spec.md.template. Worked example (verified on a 0.1.5 deploy): references/examples/demand-deliverability-assessment/.

Writing rules

  • Names are lookup keys. A misspelled name means the agent cannot find the capability.
  • Only mounted capabilities. Tell the agent to report "not mounted" rather than fall back to a same-named capability in another network or the platform catalog.
  • Text fields locate with match. Fields carrying a full-text index (condition_operations contains match) may reject == at the resource layer; say so in the step that locates rows.
  • Finding skills: search_capabilities with a query ranks functions first; pass types: ["skill"] when the goal is the skill itself.
  • No secrets, no URLs. A skill names capabilities; the platform carries credentials and the managed turn.

Functions (bkn-osdk)

A function is Python that runs in the platform sandbox and is registered as a tool. The sandbox ships bkn_osdk and injects BKN_BASE_URL, BKN_TOKEN, BKN_CONVERSATION_ID, BKN_INTERACTION_ID and BKN_PARENT_OPERATION_ID, so the code configures nothing:

from bkn_osdk import kn

def handler(event):
    rows = kn.query_object_instance(event["kn_id"], "order", limit=500,
                                    filters=[{"field": "status", "op": "==", "value": "paid"}],
                                    properties=["order_no", "amount"], response_format="json")
    return {"count": len(rows.get("datas") or [])}

Hard rules, all verified against a live sandbox:

  1. The entry point must be handler(event); event is the tool's input object.
  2. No from __future__ import ... — the sandbox prepends a wrapper and the import becomes a SyntaxError.
  3. Tool parameter type is one of string / number / boolean / array / object; integer is rejected with 400.
  4. Reads made through bkn-osdk inside the function land on the caller's interaction as children of the execute_tool operation — no extra wiring.

Skeleton: assets/templates/function.py.template. Full example (BOM level-1 kitting check): references/examples/functions/l1_kitting_check.py. Details of kn.query_metric / kn.run_sql and the generated ontology layer: the bkn-osdk README under python/.

Calling another function

A function may call another function mounted on the same network through the platform:

from bkn_osdk import kn

def handler(event):
    answer = kn.execute_tool(event["kn_id"], event["box_id"], event["tool_id"],
                             {"kn_id": event["kn_id"], "product": event["product"], "qty": 50})
    body = answer.get("body", answer)           # the callee's raw response
    if body.get("exit_code") not in (0, None):  # HTTP 200 does not mean the callee succeeded
        return {"ok": False, "reason": body.get("stderr", "")[-300:]}
    return {"ok": True, **(body.get("result") or {})}
  • kn.execute_tool carries the sandbox's managed turn, so the callee's sandbox gets the same caller credential and the trace shows the callee under this function's execute_tool operation, with the callee's own reads below it.
  • Needs a sandbox bkn-osdk that has kn.execute_tool (bkn-sdk #100 or later). On an older SDK the only route is bkn_osdk.call("/api/agent-retrieval/v1/kn/execute_tool", ...), and the request body must carry a bkn_context built from BKN_CONVERSATION_ID, BKN_INTERACTION_ID and BKN_PARENT_OPERATION_ID; without it the callee's sandbox is given no credential at all.
  • The callee's own mounting and permissions apply. There is no depth or cycle guard — do not write functions that call each other.

Example: references/examples/functions/call_l1_check.py.

Code → tool (openbkn CLI 0.1.5+)

openbkn sandbox run ./fn.py --event '{"kn_id":"<kn>","product":"P1","qty":50}' --pass-token
openbkn toolbox create --name my_functions --type function     # name: letters, digits, _, CJK
openbkn function create ./fn.py --toolbox <box-id> --name fn \
    --description "..." \
    --inputs '[{"name":"kn_id","type":"string","required":true}]' \
    --outputs '[{"name":"kitting_ok","type":"boolean"}]'
openbkn function enable <tool-id> --toolbox <box-id>          # tools start disabled
openbkn toolbox publish <box-id>

Mount the tool on the network (binding one twice is a no-op):

openbkn bkn capability attach <kn> --box <box-id> --tool <tool-id>

Delivery

openbkn skill register ./{skill_dir}          # -> skill_id, status unpublish
openbkn skill set-status <skill_id> published
openbkn bkn capability attach <kn> --skill <skill_id>

Validation checklist

  • Frontmatter has name, description, metadata.bkn_scope, metadata.uses[]
  • Every name in uses[] also appears in the body table, spelled identically
  • Every capability is mounted on bkn_scope (check with search_capabilities / get_kn_detail)
  • Each action with side effects has confirm: true and a "do not execute without an explicit yes" step
  • Steps map outputs of one call to inputs of the next explicitly
  • references/report-spec.md ends with the capabilities used, for trace cross-checking
  • Function code: handler(event), no __future__ import, parameter types from the allowed set