Skip to content
Agentmart
Submit a tool

akdagent-protocol

AKDAgent 协议 v1 完整规范(**现役通道 = 纯文件通道**,剪贴板已整体退役):`akdagent-{req,res,hb,boot}-<host>.json` 的**字段与语义**(请求 `v/seq/id/op/args` ↔ 响应…

Skill by Akunda123

IndexedMIT★ 29
Write a review

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/akunda123-akdagent-protocol

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

AKDAgent 协议 v1 完整规范(**现役通道 = 纯文件通道**,剪贴板已整体退役):`akdagent-{req,res,hb,boot}-<host>.json` 的**字段与语义**(请求 `v/seq/id/op/args` ↔ 响应 `v/id/seq/ok/ts/host/result|error`)、规则(心跳声明能力 + `canServe` 判据 / **id 去重(不是 seq)** / **应答后必须 `consumeReq`** / **客户端按 `id` 字符串匹配** / 超时语义)、**32 个 op 清单**、目录解析顺序与时序、边界(多宿主 `-sv`/`-ix` 不互抢、排障三件套)、写操作护栏规格(指纹与 STALE、体量护栏、事务语义 —— **规格已定、尚未实现**)、能力边界自述与"不抢用户焦点"纪律;用于开发与 Synthesizer V Studio / Instrument X 桥通信的客户端(MCP server / Electron / 脚本)。旧 SVCMD/SVRES(剪贴板)内容仅作历史参考

Use cases: backend, agent-building

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md and code. Checked Oct 25, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/akdagent-protocol

What's inside

Skill name
akdagent-protocol
Description
AKDAgent 协议 v1 完整规范(**现役通道 = 纯文件通道**,剪贴板已整体退役):`akdagent-{req,res,hb,boot}-<host>.json` 的**字段与语义**(请求 `v/seq/id/op/args` ↔ 响应 `v/id/seq/ok/ts/host/result|error`)、规则(心跳声明能力 + `canServe` 判据 / **id 去重(不是 seq)** / **应答后必须 `consumeReq`** / **客户端按 `id` 字符串匹配** / 超时语义)、**32 个 op 清单**、目录解析顺序与时序、边界(多宿主 `-sv`/`-ix` 不互抢、排障三件套)、写操作护栏规格(指纹与 STALE、体量护栏、事务语义 —— **规格已定、尚未实现**)、能力边界自述与"不抢用户焦点"纪律;用于开发与 Synthesizer V Studio / Instrument X 桥通信的客户端(MCP server / Electron / 脚本)。旧 SVCMD/SVRES(剪贴板)内容仅作历史参考
License
MIT
Instructions
317 lines in SKILL.md · view on GitHub

Agent Skills spec issues

  • files: referenced but missing: references/06-track-misc.md, references/svp-format.md

Files (1)

  • SKILL.md

SKILL.md (first lines)

# AKDAgent 桥协议 v1(**文件通道**)

> 📌 **传输方式(2026-09-12 起,唯一通道)**:**剪贴板已整体退役**,只有文件通道 ——
> 请求 `<dir>\akdagent-req-<host>.json`(客户端**原子替换**写入:写 `.tmp` 再 rename)· 响应 `akdagent-res-<host>.json`(桥写 `.tmp` 再改名,失败则先删再改)·
> 心跳 `akdagent-hb-<host>.json`(存活 + 宿主信息 + **`ops` 能力清单** + 实际 `dir`)· 启动结果 `akdagent-boot-<host>.json`(成功/致命错误,供外部排障)。
> **`<dir>` 解析顺序(两端同序)**:① `%USERPROFILE%\AKDAgent\ipc`(**存在且可写才用** —— Lua 不能 mkdir)② `os.tmpdir()`(= `%TEMP%`)。
> ⚠️ 客户端另有环境变量 `AKDAGENT_IPC_DIR` 可覆盖,**桥不读它** ⇒ 设了就必须让桥也落在同一目录。**"两端 `dir` 不一致"是这套通道最常见的故障**(心跳里会写实际 `dir`,先对一眼)。
> 桥只有 Lua 一种 ⇒ **`run_script` 执行的是 Lua**(冒号调用、索引 1 起),不再是 JS。
> 本文件后文凡提到 `SVCMD:`/`SVRES:`/剪贴板的,均**只作历史参考**;现役事实以 `sv/lua/AKDAgentBridge.lua`(现 **1.0.0**)与 `server/src/fileipc.ts` 为准。

通信双方:**Bridge**(宿主内常驻 Lua 脚本,执行方)与 **Client**(MCP server / Electron 客户端,请求方)。
另有旁路产物 `akdagent-log-<host>.txt`(桥的运行日志)与 `akdagent-diag-*`(诊断),排障时先看它们。

> 规范原文维护在 `knowledge/docs/PROTOCOL.md`(**与本技能同源,改协议要一起改**);通道客户端实现 `server/src/fileipc.ts` · 桥侧 `sv/lua/AKDAgentBridge.lua`。

## 🔢 索引基准(全仓总纲 —— 看到任何 `index` 先读这条)

| 层 | 基准 | 说明 |
|---|---|---|
| **JS 绑定**(SV 官方脚本 JS)| **0 起** | `getTrack(0)` / `notes[0]` / `getIndexInParent()` 全 0 起。**的 JS 桥(`SVAgentBridge.js`)已退役**(连同归档目录 `legacy/`,2026-09-19 已删)—— 现役是 Lua 桥 |
| **Lua 绑定**(SV 官方脚本 Lua;SV1/SV2 都有)| **1 起** | 官方 API 原文:`getIndexInParent()` — *"In Lua, this index starts from 1. In JavaScript, this index starts from 0."* **参数与返回值都是** 1 起;桥内用 `CFG.INDEX_BASE = 1` 换算 |
| **对外协议**(`akdagent-{req,res,hb,boot}-<host>.json` 文件通道、`mcp__sv__*` 工具、本技能)| **一律 0 起** | 换算只发生在**桥内部**(`CFG.INDEX_BASE = 1`)⇒ 客户端与文档都不用改 |
| **工程文件**(`.svp`/`.ixp` 的 `notes[]`/`groups[]`/`meter[].index`)| **0 起** | JSON 数组下标 |
| **小节号**(`getMeasureMarkAt(measureNumber)` / `addMeasureMark` / `removeMeasureMark`)| **1 起** | 另有 `getMeasureMarkAtBlick(b)` 是**按 blick** 取 —— 两者别混(曾因此静默算错拍号) |

**三条最容易踩的坑**
1. **`get_selected_notes` 返回的 `index` 是「本次选中结果数组内的序号」(0 起),不是「组内下标」。**
   要写 `write_pit` 的 `indices`(那是**组内下标**)必须另取 `Note#getIndexInParent` —— 而且 **Lua 侧要 +1 换算**。
2. **序号类参数的基准逐个确认**:`trackIndex` / `audioTrackIndex` **0 起**;`part` **1 起**(`tools.ts` 里 `part - 1` 即证);不要想当然。
3. **别用"试一下"确定基准**:Lua 绑定的错误**穿透 `pcall`**(直接弹脚本错误框),一次试探就打断用户 —— 已实测两次,故 Lua 桥里**不做任何探测**,基准写死 `CFG.INDEX_BASE`。

## 消息格式(文件通道)

**请求** `<dir>\akdagent-req-<host>.json`(单行 JSON,客户端原子替换写入):

```jsonc
{ "v": 1, "seq": 1789175384220009, "id": "fileipc-1789175384220009",
  "op": "get_selected_notes", "args": {} }
```

**响应** `<dir>\akdagent-res-<host>.json`(桥写 `.tmp` 后改名):

```jsonc
{ "v": 1, "id": "fileipc-1789175384220009", "seq": 1789175384220009, "ok": true,
  "ts": 1789175384, "host": "sv", "result": { … } }
{ "v": 1, "id": "…", "seq": …, "ok": false, "ts": …, "host": "sv", "error": "…" }
```

| 字段 | 出现处 | 说明 |
|---|---|---|
| `v` | 双向 | 协议版本,恒为 `1` |
| **`id`** | 双向 | 请求唯一 id(客户端生成 `fileipc-<seq>`)。**两端的一切匹配与去重都以它为准** |
| `seq` | 双向 | 客户端生成的**单调递增**序号(`Date.now()*1000+计数器`)。⚠️ **只作观测**:桥**不按它去重**(见「规则 2」),也**不要求响应 seq 数值相等** |
| `op` | 请求 | 操作名(见下表) |
| `args` | 请求 | 参数对象(可省略) |
| `ok` / `ts` / `host` | 响应 | 是否成功 / Unix 秒 / 应答宿主(`sv` \| `ix`) |
| `result` / `error` | 响应 | 成功结果 / 错误描述(二选一) |

> 🔑 **`id` 按字符串比较,别比 seq**(`server/src/fileipc.ts` 实测教训):Lua 曾把 16 位 `seq` 编成科学计数法(`1789175384220009 → 1.78917538422e+15`)丢精度 ⇒ 客户端**只按 `id` 判等**,数字比较只当冗余条件 —— 否则会把"对端数字序列化不精确"放大成"桥不响应"。
> 🔑 **宿主标识写在文件名里**:`-sv`(Synthesizer V,SV1/SV2 **共用**)/ `-ix`(Instrument X)⇒ 旧文档说的"SV1 与 SV2 互相抢答"**在文件通道下不复存在**(各读各的文件);但**同一宿主开两个实例**仍会互抢同一份文件名。

## 规则

1. **心跳声明能力(`canServe`)**:发之前先看 `akdagent-hb-<host>.json` —— ① 有心跳文件 ② `ts` 新鲜(**≤ 15s**)③ 该 op 在心跳的 `ops` 数组里**被明确声明**。三条都过才发;否则明确报"无心跳 / 心跳过期 Ns / 桥未声明 op 'x'(并附 `advertisedOps`)"。**桥自报能力是最可靠的判据**(旧的文件/剪贴板白名单已随剪贴板一起删除)。
2. **id 去重(主键是 `id`,不是 `seq`)**:桥内存里存 `done[id]`;**重复 id ⇒ 不重复执行,直接重发缓存响应**(客户端超时重试正是靠这条)。缓存被淘汰后再来同 id ⇒ 回 `ok:false, error:"duplicate request id (response evicted from cache)"`。
   ⚠️ **别用 `seq > lastSeq` 去重** —— 不同客户端的 seq 尺度可差 1000 倍,先到的大 seq 会把后到的小 seq 请求**永久静默忽略**(实测 `reqSeen` 卡住、心跳正常、只有 resend 日志)。桥里 `lastSeq` 仅作统计。
3. **应答后必须消费请求文件(`consumeReq`)**:桥应答(或重发缓存)后删掉 `req` 文件 —— **且只在"文件内容仍等于读到的快照"时删**(客户端是原子 rename 写入,避免误删新请求)。不消费的后果实测过:每拍重读同一请求 ⇒ **命中缓存 ⇒ 每拍重发响应**(日志每秒 2~3 条 `resent cached response`、持续 90 秒,而客户端其实只发了一次)。
4. **同一时刻只允许一个在途请求**:客户端必须串行化(`server` 侧已做互斥)⇒ **模型侧不要并发下发**,串行是设计不是卡。
5. **超时**:客户端默认 **10s**、轮询 **40ms**;桥侧轮询间隔 **300ms**(`POLL_MS`)。
   ⚠️ **超时是"模糊"的** —— 它只代表"我们不等了",**宿主可能仍在把那次写做完** ⇒ **别急着重试写**,先 `ping` / 重读目标确认状态;确要重试就**用同一个 id**(命中缓存会重发响应,不会重复执行)。
6. **执行方语义**:所有写操作执行前先 `newUndoRecord()`(`run_script` 缺则拒绝,`readonly:true` 跳过),保证宿主内可撤销。
   📌 它是**一个撤销恢复边界,不是自动回滚**(见下「指纹 / 守卫」§ 的事务语义)。

## 操作清单(v1 · **共 32 个 op**,以实现为准)

> 真源 = `sv/lua/AKDAgentBridge.lua` 的 `OPS.*`;**2026-09-19 逐条核对过**。
> 心跳的 `ops` 数组就是这张表(桥自报),`canServe` 拿它判"这个 op 现在能不能服务"。
> 关系:**32 个 op ↔ 53 个 MCP 工具**(其中 44 个是 SV/IX 工具,另 3 个是 ACE Studio 工具,见下条) —— 工具比 op 多,因为分离 / 音频分析 / 旋律生成 / 织体渲染等**完全在本地算**,不经桥。

### 读操作(13)

| op | 说明 | 返回要点 |
|---|---|---|
| `ping` | 检测桥是否在线 | `{pong, host, version, isSV2, ts, dir, ops}` |
| `selftest` | 桥自检(内部一批断言) | `{ok, …}` |
| `get_project_info` | 工程基本信息 | `{fileName, durationBlicks, numTracks, tracks:[{name,numGroups}], numGroupsInLibrary}` |
| `get_current_group` | 当前编辑组 | `{current, name, uuid, noteCount, timeOffsetBlicks, pitchOffset}` |
| `get_selected_notes` | 当前选中音符 | `{count, notes:[{index, pitch, onsetQuarter, durationQuarter, endQuarter, lyrics}]}`<br>⚠️ `index` 是**本次选中结果数组内的序号(0 起)**,不是组内下标<br>🆕 0.3.23 附加非协议字段 **`indexInParent`**(**组内下标,0 起**)—— 要写 `indices`(组内下标)的调用方用它,别用 `index` |
| `get_melody_notes` | **当前组全部音符**(`maxNotes` 可限) | `{current, groupName, timeOffsetBlicks, noteCount, notes:[{index, pitch, onsetBlicks, durationBlicks, endBlicks, onsetQuarter, onsetSeconds, lyrics}]}`<br>⚠️ `onsetBlicks` 是**组内相对**,绝对位置 = `timeOffsetBlicks + onsetBlicks` |
| `get_measure_info` | 小节 / 拍号信息 | `{…}` |
| `get_note_time` | 音符时间换算(blick↔秒/拍) | `{…}` |
| `get_layout` | **当前组布局报告**(只读) | `{overlapCount, gapCount, smallGapCount, overlaps/gaps/smallGaps(各前 5 条), policy, isMain, hostIsSv2}`<br>📌 口径:**重叠 = 违规必须报**;**缝隙 = 允许但要告知**;短缝 ≤ 1/16 拍单列(消缝须经用户同意) |
| `get_lyrics_attrs` | 歌词 + 音素属性(含手动音素、`phonemeAttrs`、`dur`、`muted`) | `{…}` |
| `get_phonemes` | **整组的实际发音音素串**(含 T2P 默认)—— 桥 0.3.23 新增,给音素替换用;`Note#getPhonemes()` 只给**手动写死过**的串 | `{ok, current, count, phonemes:[…]}`<br>⚠️ 宿主没有 `SV:getPhonemesForGroup` ⇒ `unsupported:true`,调用方退回首动串 |
| `get_computed_pitch` | 宿主**算出的音高曲线**(SV2 2.1.1+;SV1 无此接口) | `{values, numeric, nulls, firstFrame, lastFrame, notReady}`<br>⚠️ 全 `null` 先查前置条件(组是否挂上轨 / 语种与声库是否兼容),别先怪"渲染没算完" |
| `get_computed_attributes` | 宿主**算出的音符属性**(`accent` / `rapTone` / `rapIntonation` / `phonemes[]` 含实际生效语种) | `{count, notes, languages, accents, notReady, …}` |

### 写操作(16)

| op | args 要点 | 说明 |
|---|---|---|
| `transpose_selected_notes` | `{semitones}` | 选中音符整体移调(−12 = 降八度) |
| `set_selected_lyrics` | `{lyrics}` | 选中音符统一设词 |
| `apply_lyrics` | `{lyrics}` | 把一段词**按顺序**分配给选中音符(中文逐字 / 英文按词,`-` 保留) |
| `fill_track_lyrics` | `{lyrics, track?}` | 按**轨道/组**填词(track 可给名字或 0 起下标) |
| `set_note_languages` | `{…}` | 设音符语言(**⛔ 语言属于用户状态,默认不动**,见下文专节) |
| `set_note_rap_accents` | `{…}` | 写 `rapAccent`(1 阴平 · 2 阳平 · 3 上声 · 4 去声 · 5 轻声) |
| `set_note_phonemes` | `{…}` | 写**手动音素** |
| `set_note_phoneme_attrs` | `{…}` | 写**音素属性**(SV2 的 `leftOffset` 等;⚠️ 引擎消费但**不回显到 computed**) |
| `set_note_dur` | `{…}` | SV1 音素时长**比例**写入 |
| `write_chords` | `{chordSegs \| notes, pattern?, octaveShift?, groupName?, trackIndex?, instrument?, host?}` | **建 `NoteGroup` + 写音符**;`notes` 通道吃任意 `{pitch, onsetBlicks, durationBlicks, lyrics?, dynamic?, articulations?}`,`timeOffset=0`(位置由 onset 表达)、**同名组幂等替换**、回读 `layout`。<br>📌 织体 / 和声骨架都走它(`sv_write_chords`、`sv_write_texture`) |
| `create_harmony_group` | `{…}` | 建和声组(给主旋律配和声声部) |
| `write_pit` | `{plan?, params?, indices?, mode?, text?, egg?}` | 音高线写入:SV2 打点曲线 / SV1 写 12 属性;含重音计划与彩蛋词。⚠️ **仅 IX**:目标里含**同 onset 音符(和弦/齐奏)**且走 curve 路线时,结果会带 **`chordStarts`/`chordNotes`/`chordHint`** 如实警告(本工具按**单声部骨架**画曲线 ⇒ 同伴音被拉到骨架音高,真机 `yAtOnset` = 0 与 −4 ⇒ **和弦可能被压成同度**;IX 侧该处宿主实现是暴力移植、本身有 bug,见已知缺陷 `IX-005`)—— **只告知、不阻止**;要逐音精确控制就 `indices` 只给一个。⛔ **这条只在 IX**:SV1 走 attr 路线(无共享骨架)、SV2 的骨架是既定设计 ⇒ **都不提示**(IX 的参数编辑限制不许外溢到 SV)<br>🆕 **0.3.25 · 交界自检(只进回包、用户不可见)**:curve 路线下,若**目标的 ±1 邻音已有曲线而本次没重写它**,回包多给 **`junction`**(`{targets, neighbours, stale, unknown, items:[{index, neighbour, stale, unknown}]}`)与 **`junctionHint`**(一句话);`stale` = 靠曲线 `scriptData` 里的**指纹**判出的**旧快照**(该音 ±2 的几何 + 各自生效参数),无指纹的旧曲线记 `unknown`。**含义**:这些交界处可能出现**两条有间距的线** ⇒ 推荐**把相邻音符放进同一次调用**(`indices` 同时给)|
| `align_audio` | `{firstBeatSec, bpm?, anchor?, measure?, introBeats?, introSec?, shiftBeats?, audioTrackIndex?}` | 移动音频轨使第一拍落到锚点(`trackIndex`/`groupIndex`/`audioTrackIndex` **均 0 起**) |
| `apply_tempo` | `{input?, bpm?, segmentBeats?, clearExisting?, measureStart?, beatOffsetSec?}` | 逐段写 tempo mark |
| `playback` | `{action:"play"\|"pause"\|"stop"\|"toggle"\|"seek", position?}` | 播放控制;**返回执行后的实际状态** `{status}` |
| `run_script` | `{code, scope?, readonly?}` | **通用逃生舱**:宿主内跑一段 **Lua**(冒号调用、索引 1 起);⚠️ **必须含 `SV.getProject():newUndoRecord()`**(缺则拒绝;`readonly:true` 跳过) |
| `apply_ornaments` | `{ornament, indices?, interval?, dir?, len?, headLen?, steps?, df?, style?, manual?, dryRun?}` | **装饰音(拆音符路线)**:`graceFront` 前倚音 · `graceBack` 后倚音 · `spikeUp` 向上尖尖 · `mordent` 波音 · `turn` 回音 · `tailRun` 音尾音阶行进 —— 六个**真切音符**;`anticipate` 反向预备 · `slide` 滑音 —— 两个**只写音符属性**(**仅 SV1**)。<br>口径:**SV2 同样拆音符、不画曲线**;**第一段承接原歌词、其余段 `-`**;**新音符默认自动音高**(`manual:true` 才 `setPitchAutoMode(false)`);**默认 `dryRun`**。回包给每段的 `{onsetQuarter, durQuarter, pitch, lyric, dF0Left?, tF0Left?}` 计划与 `failed[]` 原因(时值不足**不硬切**) |
| `set_automation` | `{parameter, points:[{onsetQuarter, value}], dryRun?}` | **参数自动化**:`NoteGroup#getParameter` + `Automation#add`;参数名大小写不敏感(`tension`/`loudness`/`breathiness`/`voicing`/`gender`/`vibratoEnv`/`pitchDelta`/`vocalMode_*`)。写前按**硬编码取值域 clamp**(不回包范围时如实标注);回读**只用 `Automation#get(b)` 单点采样** —— `getPoints`/`getAllPoints`/`getLinear`/`getDefinition`/`remove(index)` 在**已知缺陷 `IX-001`(调用即冻桥)**上,一律不调。**默认 `dryRun`** |

From Akunda123/SVIXAGENT, MIT.

More from Akunda123/SVIXAGENT

Signals

Stars
29
Forks
5
Open issues
4
Last commit (this folder)
Oct 6, 2026 (24 days ago)
Last release
Oct 9, 2026 (21 days ago)

From GitHub (fetched Oct 24, 2026).

Details

License
MIT
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from Akunda123

Cite this page

akdagent-protocol skill. Agent Mart. https://agentmart.dev/skills/akunda123-akdagent-protocol (last updated 2026-10-24)