AGENT SKILL

automation

暂无简介

License 许可
GPL-3.0
所属仓库
ZMGID/kivio
最近更新
2026-11-12
Stars
★ 585
Forks
42

03 SKILL.md 正文

Kivio automations

Kivio automations are directed graphs: one trigger, then actions and logic, stored as JSON.

Not for scheduled tasks. When the user wants something done on a schedule in this conversation (定时任务, 提醒, "每天早上帮我…"), call schedule action=create instead. Build an automation only when the user explicitly asks for an automation/workflow.

Do this: activate this skill, automation action=list once, then automation action=upsert with a complete graph in one call.

Do not: glob the repo, invent node type names, or dry_run to discover the schema. dry_run is only for a finished candidate. This skill is the schema — automation action=upsert's tool description is short on purpose. Validation errors also return allowedNodeTypes + schemaHint.

Chat exposes one native automation tool with seven actions. It is an on-demand tool: when it is not in your tool list, read tool://automation for its schema and run it with write to tool://automation (content = JSON arguments, e.g. {"action":"list"}), or call automation directly by name. After creating a graph, tell the user to open #chat/automations/{id}.

Tools

  1. automation action=list — ids, names, enabled, trigger type. Call this first to avoid duplicates.
  2. automation action=get — full graph for one id.
  3. automation action=upsert — create or replace the whole graph in one call. Omit id to create. Omit node position to auto-layout. dry_run: true only after you already have a complete graph. Error-severity issues reject the save and return allowedNodeTypes + schemaHint; fix those and resubmit the whole graph.
  4. automation action=set_enabled — start/stop schedule and hotkey registration (separate from upsert).
  5. automation action=run — blocking. Optional input (string or { text, json }) becomes {{output}} / {{json.input.*}} for later nodes. Default wait 600s (max 1800). Timeout is not a failure: the run continues; poll with automation action=runs.
  6. automation action=runs — recent summaries, or one run's per-node details when run_id is set.
  7. automation action=delete — permanent. Goes through normal approval.

Do not call these tools from inside an action.agent step. Workflow agents never receive automation tools.

After creating or changing a graph, tell the user to open #chat/automations/{id} (Extensions → Automations) to inspect the canvas.

Graph contract (schema v1)

{
  "schemaVersion": 1,
  "id": "",
  "name": "Daily briefing",
  "enabled": false,
  "nodes": [],
  "edges": [],
  "viewport": { "x": 0, "y": 0, "zoom": 1 }
}
  • Exactly one trigger recommended (trigger.manual | trigger.schedule | trigger.hotkey).
  • Main-flow edges: { "id", "source", "target" }. Tree only — no cycles.
  • Agent slot edges (not part of the main flow): source is the slot node, target is action.agent, sourceHandle: "slot", targetHandle: "runtime" | "context" | "tool" | "skill".
  • Node ids unique. Positions optional (auto-layout when every node is at {x:0,y:0}).
  • enabled: false until the user asks to arm schedule/hotkey. Manual and agent runs still work.

Interpolation

Downstream templates:

  • {{output}} — previous node's text. After automation action=run with a string input, this is that string at the trigger.
  • {{json.path}} — walk the previous JSON. Agent-run input is nested at json.input.
  • {{json.input.topic}} — a field from automation action=run { "input": { "json": { "topic": "..." } } }.

No $json expressions, no $('Node') cross-references.

Node types and data

Every node: { "id", "type", "position"?, "data": { "label": "..." } }. Extra fields live under data.

Triggers

trigger.manual — editor / agent test runs only.

trigger.schedule

"data": {
  "label": "Schedule",
  "schedule": { "kind": "daily", "hour": 9, "minute": 0, "intervalMinutes": 60 }
}

kind: daily | weekdays | interval. For interval, intervalMinutes ≥ 1. hour 0–23, minute 0–59.

trigger.hotkey

"data": { "label": "Hotkey", "hotkey": { "accelerator": "CommandOrControl+Shift+B" } }

Modifiers: CommandOrControl, Control, Alt, Shift, Super.

Actions

action.agent — unattended model step. Put prompt/runtime/tools/skills on slot nodes, not inline.

action.notify — { "notify": { "body": "{{output}}" } }

action.http — { "http": { "method": "GET", "url": "https://…", "headers": "", "body": "" } }
method: GET|POST|PUT|PATCH|DELETE. URL required.

action.set — { "set": { "fields": [{ "key": "text", "value": "{{output}}" }] } }

action.clipboard — { "clipboard": { "op": "copy", "text": "{{output}}" } } (copy | read)

action.file — { "file": { "op": "write", "path": "notes.md", "content": "{{output}}" } } (read | write; path required)

action.command — { "command": { "command": "echo hi", "cwd": "", "timeoutSeconds": 30, "continueOnFail": false } }

Logic

logic.if — { "if": { "op": "contains", "value": "ok" } }
op: contains | equals | notEmpty. Outgoing sourceHandle: "true" | "false".

logic.switch — { "switch": { "cases": [{ "id": "1", "op": "equals", "value": "a" }] } }
Outgoing handles: each case id, plus "default".

logic.delay — { "delay": { "seconds": 5 } } (integer ≥ 1)

Agent slots (plug into action.agent)

Slot node data.agent:

agent.runtime

"agent": {
  "runtimeKind": "builtin",
  "providerId": "",
  "model": "",
  "externalAgentId": null,
  "externalModel": null
}

runtimeKind: builtin | chat | external. External needs externalAgentId (claude, codex, cursor, …).

agent.context — { "agent": { "prompt": "Summarize {{output}} in 5 bullets." } }

agent.tool — { "agent": { "toolIds": ["web_search", "web_fetch"] } }
Empty = read-only tools + skill loader. Never include automation or memory tools.

agent.skill — { "agent": { "skillIds": ["<installed-skill-id>"] } }(只写当前已启用技能的 id)

Best practices

  1. automation action=list before create. Reuse an id with upsert to replace.
  2. dry_run: true first. Fix every severity: "error" (nodeId + message).
  3. Leave enabled: false until the user wants the schedule/hotkey live; then automation action=set_enabled.
  4. Only when the user explicitly wants an automation: trigger.schedule + action.agent + action.notify fits “every morning, do X and ping me”. A plain timed prompt is a scheduled task (schedule action=create).
  5. For “take this problem and run my workflow”, automation action=run with input; do not rebuild the graph each time.
  6. After save, tell the user the name, id, and to open the Automations page.

Example 1 — daily agent briefing

{
  "name": "Daily briefing",
  "enabled": false,
  "nodes": [
    { "id": "t", "type": "trigger.schedule", "data": { "label": "09:00", "schedule": { "kind": "daily", "hour": 9, "minute": 0, "intervalMinutes": 60 } } },
    { "id": "a", "type": "action.agent", "data": { "label": "Brief" } },
    { "id": "ctx", "type": "agent.context", "data": { "label": "Prompt", "agent": { "prompt": "Write a short morning briefing from {{output}}." } } },
    { "id": "rt", "type": "agent.runtime", "data": { "label": "Runtime", "agent": { "runtimeKind": "builtin" } } },
    { "id": "n", "type": "action.notify", "data": { "label": "Notify", "notify": { "body": "{{output}}" } } }
  ],
  "edges": [
    { "id": "e1", "source": "t", "target": "a" },
    { "id": "e2", "source": "a", "target": "n" },
    { "id": "er", "source": "rt", "target": "a", "sourceHandle": "slot", "targetHandle": "runtime" },
    { "id": "ec", "source": "ctx", "target": "a", "sourceHandle": "slot", "targetHandle": "context" }
  ]
}

Example 2 — run with input

Existing graph: manual trigger → agent (prompt uses {{output}}) → notify.

automation action=run id=<id> input="Draft a reply to this email: …"

The trigger text becomes that string; the agent prompt interpolates it.

Example 3 — HTTP then branch

{
  "name": "Health ping",
  "nodes": [
    { "id": "t", "type": "trigger.manual", "data": { "label": "Manual" } },
    { "id": "h", "type": "action.http", "data": { "label": "GET", "http": { "method": "GET", "url": "https://example.com/health", "headers": "", "body": "" } } },
    { "id": "i", "type": "logic.if", "data": { "label": "OK?", "if": { "op": "contains", "value": "ok" } } },
    { "id": "yes", "type": "action.notify", "data": { "label": "Up", "notify": { "body": "healthy: {{output}}" } } },
    { "id": "no", "type": "action.notify", "data": { "label": "Down", "notify": { "body": "unhealthy: {{output}}" } } }
  ],
  "edges": [
    { "id": "e1", "source": "t", "target": "h" },
    { "id": "e2", "source": "h", "target": "i" },
    { "id": "e3", "source": "i", "target": "yes", "sourceHandle": "true" },
    { "id": "e4", "source": "i", "target": "no", "sourceHandle": "false" }
  ]
}

04 同仓库更多 Skills