【免费下载链接】genoffice
Free, open-source AI Office suite: Docs, Sheets, Slides, PDF, Markdown and HTML editors with a built-in AI agent, plus a `genoffice` CLI and agent skill so Claude Code, Codex and Cursor can create and edit real .docx/.xlsx/.pptx files locally. Bring your own key. macOS, Windows & Linux.
genoffice 是 GenOffice 随应用一同安装的本地 CLI,也是本仓库 skills/genoffice/SKILL.md 这一 Agent 技能(skill)文件的核心主题。本文以该技能文档为主体,结合 packages/cli 的源码实现,完整讲解如何让 Claude Code、Codex、Cursor 等编码 Agent 在本地用 genoffice 创建 docx/xlsx/pptx、在格式间转换、读取既有文件结构并执行结构化编辑,以及如何通过统一的 JSON 输出契约、批次语义和「完成前检查」质量门来保证每次产出真实、可用、可验证。读完本文,你将掌握这套 CLI 的全部命令、JSON 协议、典型工作流与常见错误的机器可读处理方式。
genoffice 是什么:一个为 Agent 而生的本地 Office 引擎
genoffice 与 GenOffice 一起安装,是 GenOffice 的命令行入口。它让你(或一个编码 Agent)在不打开图形界面的情况下,用 GenOffice 自己的引擎在本地完成以下工作:
- 从简报(brief)构建演示文稿(pptx):经过可检查的大纲(outline)、逐页规格(page spec)与渲染管线;
- 从 CSV 或 JSON 数据构建带公式的电子表格(xlsx);
- 从 Markdown 或 HTML 构建 Word 文档(docx),或构建 PDF;
- 在
pdf、docx、xlsx、pptx、md、html、csv之间互相转换; - 读取既有文件(包括用户自己的 docx/xlsx/pptx 作为素材)的结构与文本,并施加结构化编辑;
- 把结果直接在 GenOffice 编辑器中打开。
从源码看,CLI 的命令注册位于 packages/cli/src/cli.ts,通过 defaultRegistry() 注册了 info、convert、create、slides、sheet、docs、render、guide、search、image、media、open、selection、capabilities、install、mcp、skill 共 17 个命令,每个命令都是独立的 CommandDef。
隐私边界:所有命令都以无头(headless)方式运行在应用自带的引擎上;只有 search、image、media 三个命令会把查询词或所引用的文件发送到 GenOffice 中配置的提供商(provider)。其余操作全部在本地完成。
安装与启动器定位
技能文档给出的第一步是运行 genoffice --version。如果命令找不到,GenOffice 会在每次启动时把启动器目录写入:
- macOS / Linux:
~/.genoffice/launcher - Windows:
%USERPROFILE%\.genoffice\launcher
读取该文件中的一行,然后在 bash 中用引号包裹运行 "<dir>/genoffice",或在 PowerShell / cmd 中用 "<dir>\genoffice.cmd" 代替下面的 genoffice。当该文件缺失时,各平台的默认位置为:
| 平台 | 默认 CLI 位置 |
|---|---|
| macOS | /Applications/GenOffice.app/Contents/Resources/cli |
| Windows | %LOCALAPPDATA%\Programs\GenOffice\resources\cli |
| Linux | /opt/GenOffice/resources/cli |
技能文档的元数据声明了版本约束:当前 bundled 版本 2.51.0,要求 CLI >=0.9.0(见 skills/genoffice/SKILL.md 头部 frontmatter)。
通用契约:--json、退出码与错误结构
技能文档反复强调一条铁律:当程序要读取输出时,永远加 --json。这是 Agent 与 CLI 之间稳定协作的基石,对应的类型定义就在 packages/cli/src/result.ts。
成功与部分成功的输出
一个 JSON 对象输出到 stdout:
{
"status": "ok" | "partial",
"command": "…",
"summary": "…",
"output_path": "…", // 可选
"warnings": [ … ], // 可选
"detail": { … } // 可选
}
status: "partial":表示一次带--best-effort/--stop-on-error的apply虽然写入了文件,但丢失了部分操作(丢失的 op 在detail.failures中)。
失败输出
{
"status": "error",
"code": 1,
"error": "op_rejected",
"message": "人类可读",
"suggestion": "一句话的下一步建议",
"detail": { … }
}
退出码(与 EXIT 常量一一对应,见 packages/cli/src/result.ts):
| 退出码 | 含义 |
|---|---|
0 | 成功 |
1 | 用法错误或操作被拒绝 |
2 | 文件不存在 / 输出已存在 / 文件正被 GenOffice 打开 |
3 | 转换失败 |
4 | 应用不可用 |
字段语义:
error是机器可读的原因字符串(对应下文「命令失败时」的表格),程序应该基于它分支;suggestion是下一步的一句话建议,当命令、选项、op 名、元素 id 或 sheet 名差一个拼写时,会包含did you mean "…"?;detail以字段形式携带事实(如failures[]中的index、op、error、reason、valid_range、available、supported、usage,以及sheets、options、commands);- 绝不要解析
message——它是给人看的。
ErrorReason 的完整枚举同样定义在 packages/cli/src/result.ts,包括 unknown_command、invalid_json、unknown_op、op_rejected、target_not_found、sheet_not_found、resource_limit、outside_allowed_roots 等 20 种。
其他通用行为
--ops -、--cells -、--spec -从 stdin 读取(--from不支持);--out默认取输入文件所在目录、换新扩展名(convert),或原地编辑(apply);- 未知选项一律拒绝(退出码 1);
mcp服务器默认运行在 stdio 上;mcp [--http <port> [--host <addr>] [--token <secret>]]则改为提供 Streamable HTTP 服务。
命令总览:一张表看懂 18 个命令
技能文档给出了完整命令表,这里完整继承并补充参数要点:
| 命令 | 作用 |
|---|---|
genoffice info <file> [--password <pw>] | 元数据与结构摘要:docx 的 blocks 和标题、pptx 的 slide、xlsx 的 sheet、pdf 的页 |
genoffice convert <file> --to <fmt> [--out <path>] [--force] | 格式转换:pdf→docx/pptx/xlsx、csv→xlsx、xls/xlsb/ods→xlsx、md→docx/html、docx→html/md、html→docx、xlsx→csv(--sheet),以及 docx/xlsx/pptx/md/html→pdf |
genoffice create --type pptx --ops <file> --out <path> | 从一组 slide ops 构建新演示文稿 |
genoffice create --type pptx --spec <dir|file> [--outline <file>] --out <path> | 从逐页规格文件(每页一个,按名称排序)或单个 deck spec 文件构建演示文稿:px 定位的文本、形状与图片(即下文「设计演示文稿」的分阶段管线) |
genoffice create --type xlsx --from <data.csv|table.json> [--header] [--decimal ,] --out <path> | 从 CSV 或二维数组 / {sheets:[{name,rows}]} 构建新工作簿;"=…" 单元格是公式;--header 冻结第 1 行并过滤范围 |
genoffice create --type docx --from <text.md|fragment.html> --out <path> | 从 Markdown 或受限 HTML 片段构建新 Word 文档 |
genoffice create --type pdf --from <document> --out <path> | 由 GenOffice 渲染器把任何 md/html/docx/xlsx/pptx 打印为 PDF |
genoffice slides read <pptx> [--slide n] [--full|--max-chars n] [--layouts] / genoffice slides apply <pptx> --ops <file> [--dry-run] | 查看 id、几何信息与文本预览(默认裁剪到 300 字符、以 …(+n chars) 结尾并带 truncated: true;--max-chars 调整上限,--full 输出全文、每个表格行与演讲者备注),然后用 ops 编辑 |
genoffice slides audit <pptx> [--slide n] / genoffice slides render <pptx> --out <dir> [--scale 2] | 几何审计(越界、文本溢出、重叠):issues[] 带 code、level、path(s_n/e_*),越界与溢出场景会返回可直接传给 slides apply 的 suggest setTransform op;后者每页输出一张 PNG 供查看 |
genoffice render <file> --out <dir> [--page n] [--scale 2] [--el e_12 [--pad px]] [--grid [--cols 4] [--tile 320]] | 对 docx/xlsx/pptx/md/html/pdf 的每一页输出一张 PNG:在报告文档或工作簿「完成」之前先看渲染效果;--el(pptx)额外写出裁剪到单个元素的一页(<stem>-NN-e_12.png,id 来自 slides read);--grid 把所有页拼到一张联系表(<stem>-grid.png,行优先,瓦片位置在 grid.tiles) |
genoffice slides check <outline.json|page.json> / genoffice slides replace <pptx> --slide n --spec <page.json> | 校验 deck 大纲(出错退出 1)或构建并审计一个页面文件、对照其大纲条目与 style.md 检查;用页面文件重建一个 slide,其余 slide 不动 |
genoffice sheet read <xlsx> [--sheet name] [--range A1:D20] [--cols A,C:E] [--max-rows n] [--where formula|error|empty|number|text] [--stats] [--formats] / genoffice sheet apply <xlsx> --ops <file>|--cells <file> / genoffice sheet check <xlsx> | 读取范围外加 features(冻结窗格、筛选、图表、表格、该 sheet 的规则数;范围中的合并单元格与链接;--formats 追加单元格格式、列宽、行高);用 --cols(只读这些列,列名在 columns 中)、--max-rows(rowsShown/rowsTotal 与带 --range 的 note)、--where(只读某一类单元格,输出 {ref, value, formula},无网格)或 --stats(计数、已用范围与 sheet 列表,无单元格)控制输出体积;用工作簿 DSL 或按单元格地址编辑;check 列出公式错误、指向缺失 sheet 的引用、损坏的 defined name、超出数据的图表范围、### 列(附 set_col_width 建议)、占位文本与既有规则 |
genoffice docs read <docx> [--range a-b] [--html] [--full|--max-chars n] [--comments] [--revisions] [--header-footer] [--sections] [--fields] [--notes] / genoffice docs apply <docx> --ops <file> [--dry-run] / genoffice docs check <docx> | 按索引读 blocks(预览裁剪到 200 字符、以 …(+n chars) 结尾并带 truncated: true;--max-chars 调整上限,--full 解除限制;另含评论线程、修订、页眉/页脚文本、每节的页面设置、带缓存结果的域、脚注/尾注),然后编辑 |
genoffice guide <slides|docs|sheets> [group|op|design|spec] [--json] [--index] [--fingerprint] | 每个域的操作参考(op reference),由 apply 校验所用的同一份定义生成(写 ops 前必读);按需输出一个分组或一个 op 的 JSON schema;slides design / slides spec 用于构建演示文稿 |
genoffice search <query> [--images] [--max n] | 通过 GenOffice 配置的提供商做网页 / 图片搜索;detail.results[] 为 {title,url,snippet} |
genoffice image <prompt> [--out f.png] [--aspect 16:9] [--ref a.png,b.png] [--model <name>] | 用配置的提供商生成图片并保存;detail.mime、output_path |
genoffice media <file|url> [--ask <question>] | 描述 / 提问图片、视频或音频文件;答案在 summary 与 detail.text 中 |
genoffice capabilities | 查看 GenOffice 中配置了哪些云功能(搜索、图片搜索、图片生成、媒体分析)以及应用是否安装;无网络调用 |
genoffice open <file> [--slide n [--el e_12]|--block n|--range [Sheet!]B2:D5|--page n] | 在 GenOffice 应用中打开文件(仅在用户要求在那里查看时);带目标时还会滚动并选中对应 slide 元素 / block / 范围 / 页(target_not_found / out_of_range 会带回合法 id 或范围) |
genoffice selection <file> --json | 查看用户在编辑器中选中了什么:{slide, elements[], types[]}、{blocks:[a,b], text, collapsed}、{sheet, range, values?} 或 {page, text?}——在编辑前用它解析「这个」/「这里」;文件未在标签页打开时报 file_not_open_in_gui |
genoffice skill list / genoffice skill install <agent|all> [--dir <path>] [--force] / genoffice skill path | 检测本机编码 Agent(Claude Code、Codex、Cursor、Gemini CLI、Copilot、OpenCode、Windsurf)及其已装技能版本;把本技能复制/更新到它们的技能目录,或打印 bundled 的 SKILL.md;未经此命令或「设置 → 集成」中的点击,不安装任何东西 |
guide 命令的实现值得注意:它从 executor 校验所依赖的同一份定义(pptx-ops 的 markdown、sheets 的 zod schema、docs 的 op registry 与工具 schema)生成目录,所以指南永远与 apply 实际接受的保持一致、不会漂移(见 packages/cli/src/commands/guide.ts);--fingerprint 输出目录指纹(对目录内容做 sha256 后取前 12 位,见 packages/cli/src/op-catalog.ts),任何 op 或字段变更都会反映在指纹上。
命令选择速查:「Which command」
面对不同任务,技能文档给出了清晰的路径选择表,这里完整保留:
| 任务 | 命令路径 | 不适用 |
|---|---|---|
| 从简报(哪怕极短)出演示文稿 | guide slides design → style.md + outline.json → 逐页 slides check → create --type pptx --spec → render --grid → slides audit | 编辑已存在的 deck(slides apply);夹具 deck(create --type pptx --ops) |
| 修改既有 deck 的文字、图片或某一页 | slides read → slides apply --ops → slides audit → render --page | 整包重设风格(applyTheme op,或走分阶段重建路径) |
| 从数据构建工作簿 | create --type xlsx --from data.csv|table.json → 用 sheet apply --ops 做格式/图表 → sheet check | 修既有文件里的单个单元格(sheet apply --cells) |
| 编辑既有工作簿的单元格、格式、图表、规则 | sheet read → guide sheets <op> → sheet apply --ops → sheet check | refresh_pivot、会话表格与形状(会被拒绝:需要编辑器) |
| 从文本构建 Word 文档 | create --type docx --from report.md|fragment.html → docs check → render | 真实网页(convert page.html --to docx) |
| 编辑既有 Word 文档 | docs read → docs apply --ops → docs check | 读取其文本(convert --to md 或 docs read --full) |
| 读取用户文件作为素材 | convert --to md/csv 或 <domain> read --full --json | 对 Office 文件 unzip/cat;render(是像素,不是文本) |
| 改变文件格式 | convert <file> --to <fmt> | 任何内容修改(先编辑、后转换) |
| 查看页面效果 | render(--page、--el、--grid) | 提取文本或 id(read) |
| 把用户指到某个位置,或基于其选中内容行动 | open <file> --slide/--el/--block/--range/--page → selection <file> --json | 读取内容(read);用户未打开的文件(selection 需要标签页) |
| 查询 op 字段 | guide <domain> [group|op] [--json] | 凭本文件猜:指南由校验器生成、永远最新 |
| 把本技能交给另一个 Agent(或新机器) | skill list → skill install <agent>(或 skill path 后复制文件) | 手写技能;install-cli(那是把 genoffice 放进 PATH) |
技能安装命令与「设置 → 集成」面板共享同一个台账(ledger,位于 userData/app-settings.json),因此 CLI 安装会显示为「已安装」而非「外部」,见 packages/cli/src/commands/skill.ts。
必须知道的领域行为(Behaviour to know)
Word(docs)
- 同一批(batch)内的 block 索引是活索引——
insert_content插入两个 block 后,后面的索引整体后移两位;目标匹配不到任何 block 会导致整批失败(退出码 1)。 findReplace够不到表格单元格(请对表格用replace_blocks);受限集合之外的 HTML 标签被静默剥离。convert docx→md输出 GFM:& < >转成实体、公式变成$…$、图片被丢弃并计入detail.skipped。create --from x.md会内嵌相对路径引用的本地图片。insert_image接受本地路径(相对于当前目录,其次相对于 ops 文件)、data: URL 或 http(s) URL(png/jpg/gif),默认追加到末尾(除非给了afterBlockIndex);edit_chart的目标是docs read中 kind 为chart的 blocks;set_header_footer写纯文本,支持{PAGE}/{NUMPAGES}标记,view: "first"开启「首页不同」。- 评论 id 来自
docs read --comments;add_comment把新线程锚定到某个 block 或其中一段精确text上(occurrence从多个匹配里选一个),不改动文档文本;对带回复的线程根节点做delete_comment需要withReplies: true。 - 修订 id(
r1、r2…)来自docs read --revisions,是位置性的,任何编辑后都要重新 read 再accept_changes/reject_changes。 insertField在本地计算 SEQ 编号、REF 文本、DATE 与 MERGEFIELD;PAGE / NUMPAGES / AUTHOR 类结果是占位符,由 Word 打开时重算(docs check把它们报为 info)——交接文件时要说明这一点。edit_note是单个注释内的findReplace({ id, find, replace, matchCase? },脚注与尾注 id 相同时才需要kind),保留注释的 id、引用标记与格式;findReplace本身从不触及注释文本。define_style只打补丁给定字段(既有样式保留其余部分);applyStyle接受docs read --styles中的段落样式 id,当样式是标题样式时会把 blocks 变成标题。set_watermark传text: null即移除水印;insert_picture/insert_text_box的长度可用2.54cm/1in/72pt/96px或磅值。set_page_setup修改纸张 / 方向 / 边距 / 分栏 / titlePg / 页码,作用于所有节或某一节(section: N或blockIndex),长度写作"2.54cm"/"1in"/"72pt";insert_section_break在某 block 后拆分节(拆分出的副本随后用set_page_setup section: N修改);docs read --sections列出各节及其 block 范围。- 原生表格支持结构 op:
insertTableRow/deleteTableRow/insertTableColumn/deleteTableColumn(0 基,position: "before"|"after",count)、mergeTableCells/splitTableCell(网格range/cell;切割已有合并单元格会被拒绝)、setTableCellFormat(填充、垂直对齐、边框、width用 twips 或"2.5cm")、setTableStyle(样式 id 来自docs read的tableStyles,外加 look 标志);用nodeType: "table"定位,docs read会显示每张表的rows、cols与merged单元格。
Excel(sheet)
- ops 按顺序执行,每个都看到前一个的结果:
insert_rows/delete_cols之后的 ops 寻址的是位移后的网格(位移后写入的公式按原样存储,位移前写入的公式像既有公式一样被平移);批次内早先新增或重命名的 sheet 用新名称寻址。 - 规则、链接、注释、筛选与视觉元素必须排在其所在 sheet 的任何行列操作之后;defined-name ops 不能与 sheet 或行列 ops 混在同一批。
- 除了单元格,
sheet apply --ops还能写图表(add_chart、edit_chart作用于xl/charts/chartN.xml)、图片与形状、Excel 表格、冻结窗格、隐藏行列、带勾选项的筛选、条件格式、数据验证、超链接、注释、页面设置、sheet 保护、defined name 与标签页顺序/可见性(genoffice guide sheets有全部字段)。 --cells的style与format_range.format是同一对象({bold, fillColor, numberFormat, …})。- 颜色是
#RRGGBB或跟随工作簿主题的槽位:"accent1"、"accent1+40%"(变浅)、"dk2-25%"(变深)或{theme, tint};fill: {pattern: "lightGray", fg, bg?}或fill: {gradient: {angle, stops: [{position, color}]}}写图案与渐变填充,--formats会以槽位、tint 与解析后的 rgb 回显。 sheet read分开返回原始值(0.25、序列日期)与公式;features提供 sheet 级信息(冻结窗格、筛选、图表、表格与规则数,以及范围内的合并单元格与链接);--formats追加样式单元格、列宽(px)与行高(pt)。convert --to csv返回显示文本(百分比、日期)、UTF-8 带 BOM、CRLF 行尾,默认活动 sheet(除非--sheet)。create --from x.csv:首行sep=;会被识别并移除;ISO 日期(2024-01-01、2024-01-02 09:30)变成带日期格式的真实日期;--decimal ,把1.234,5读成 1234.5。- 本地引擎无法求值的公式(FILTER、SORT、UNIQUE、LET…)会不带缓存值写入,由 Excel 打开时计算;溢出公式(spill)以动态数组存储,在 Excel 365 中会溢出;
formulas_not_cached警告会点名这些单元格。
PowerPoint(slides)
- 图片类 ops(
addPicture、replacePicture、addMedia、setImageFill、setBackground)在bytes中接受本地路径或 data URL;扩展名自动推断。 setText的 runs 默认继承元素第一个 run 的样式(除非显式设置某字段,如bold: false)。- 同一
apply批次内的 ops 按顺序执行,因此后面的 op 可以寻址前面 op 添加的 slide;原子模式下只要有一个 op 未应用就什么都不写;--best-effort(旧名--isolation per_op)与--stop-on-error会写入已应用的部分并返回status: "partial"。 - 新建元素得到新的
e_*id:再次定位它们之前要重新跑slides read。 convert pptx→pdf像应用的导出一样渲染:每 slide 一张位图,无文本层。- 每个 EMU 长度字段(
box、offset、dx/dy、wEmu/hEmu、colWidthsEmu、insets)也接受带单位的字符串:"2.54cm"、"1in"、"10mm"、"12pt"、"96px"。 slides read列出每页的animations[](seq、el、effect、kind、trigger、durationMs、delayMs、direction);addAnimation/removeAnimation/reorderAnimation编辑一条时间线项(presetXml可原样透传 PowerPoint 导出的效果);insertEquation从 LaTeX 加入排版公式(PowerPoint 会渲染它,预览显示线性文本)。
文本元素的样式来源是分层追溯的:effective(第一个 run 的字号/字体族/颜色/加粗/斜体与段落对齐)带 src 标明每个值来自何处——run、paragraph defRPr、shape lstStyle、layout placeholder、master placeholder、master titleStyle/bodyStyle、presentation defaultTextStyle、theme major/minor。setFont 写在 run 层并覆盖以上所有层;applyTheme 改变主题字体与颜色。带超链接的元素还带 link(url、slide 跳转或 PowerPoint action:nextslide / previousslide / firstslide / lastslide / lastslideviewed / endshow);setLink 与 setText 的 link 字段都能写这三类链接。
应用内转换(→pdf、docx→html、html→docx、create --type pdf、render)
每次调用启动一个隐藏的 GenOffice 进程,耗时 1–6 秒,超时上限 180 秒,可以安全并发。html→docx 走 html2docx,适合真实网页;含 <formula> 的受限 HTML 片段则走 create --type docx --from fragment.html。
云功能(search、image、media)
--images 返回 detail.images[] {title,imageUrl,sourceUrl,source,width,height};提供商可能返回少于 --max 的结果。image 以提供商的真实格式保存(output_path 会告诉你;请求 .png 可能回 .jpg,记在 detail.note);--aspect / --size 在本地校验。
四步工作流(Workflow)
技能文档定义了 Agent 操作的标准节奏:
- 用
genoffice info或genoffice <domain> read --json了解结构:block 索引(docx)、s_<n>/e_*id 与 EMU 几何(pptx)、sheet 名与单元格值(xlsx)。 - 用
genoffice guide <domain>查 op 字段(单个 op 的 schema 用guide <domain> <op> --json),然后自己写 ops JSON。 - 批次较大时先
genoffice <domain> apply --dry-run;被拒绝的 op 以op_rejected返回并附 executor 的 usage 行——修复该 op 后重发整个批次。默认是原子性的:被拒时文件未被触碰,detail.batch为{total, applied: 0, failed, skipped}。--best-effort应用所有能应用的 op,--stop-on-error按顺序应用到第一次拒绝为止;两者都会写文件并以status: "partial"(退出码 0)作答,丢失的 op 在detail.failures、计数在detail.batch——程序必须检查status,不能只看退出码。
批次的三种模式在 packages/cli/src/batch.ts 中实现:atomic、best_effort、stop_on_error;--isolation per_op 是 --best-effort 的前身、含义相同,且不能与 --stop-on-error 混用。
- 执行下面的「完成前检查」质量门,然后报告输出路径。
常见陷阱对照表(Pitfalls)
技能文档用一张表总结了最容易踩的坑,这里完整保留并补充源码佐证:
| 陷阱 | 规则 |
|---|---|
slides read/audit/render/replace --slide n 与 op 目标 { "slide": n } 是 0 基;render --page n 是 1 基;docx block 索引是 0 基 | s_0 就是 PNG 的第 1 页 |
--ops -、--cells -、--spec - 读 stdin(--from 不支持);其他任何值都必须是存在的文件 | 不存在的路径报 file_not_found,而不是空批次 |
结构性编辑会重编号:addElement 后新 e_* id、加 slide 后 s_*、insert_content/delete_blocks 后 docx block 索引 | 同一批内索引是活的(后面的 op 看到前面的结果);下一批之前重新 read |
EMU 字段(offset、box、dx/dy、wEmu/hEmu、colWidthsEmu、insets)接受整数或单位字符串 "2.54cm"、"1in"、"10mm"、"12pt"、"96px" | 不要自己乘以 914400;slides read 返回的就是 EMU 整数 |
CSV 导入:首行 sep=; 被识别并移除,ISO 日期变成真实日期,--decimal , 处理 1.234,5 | --header 冻结第 1 行并加筛选;不加则第 1 行是数据 |
| 本地引擎无法求值的公式(FILTER、SORT、UNIQUE、LET、LAMBDA…)不带缓存值写入 | formulas_not_cached 警告列出它们;sheet read 在 Excel 打开文件前显示公式且无值。不是错误 |
sheet apply 按文件中当前标签页名寻址 sheet,拼写与标签一致 | sheet_not_found 携带 detail.sheets 和 did you mean |
| 结构性 sheet ops(插/删行、列、sheet)会位移同批后续 ops 的地址;defined-name ops 不与 sheet 或行列 ops 混用 | 用位移后的坐标写后续 ops(或把结构 op 放最后);规则、链接、注释、筛选与视觉元素放在其 sheet 的行列 op 之后 |
GenOffice 在标签页中打开了文件 → apply 拒绝(退出码 2,file_open_in_gui) | 请用户关闭该标签页,或用 --out other.ext;仅当用户接受编辑器可能覆盖时才用 --force |
create/convert/image 从不覆盖(退出码 2,output_exists);apply --out 指向既有文件也拒绝 | 换一个名字,或用户要求替换时用 --force |
apply --best-effort / --stop-on-error(旧 --isolation per_op)返回 status: "partial" 且退出码 0;check/audit 带问题也退出 0 | 读 status、detail.batch、detail.failures / detail.issues;退出码 0 不代表「干净」 |
| deck spec 是 1280×720 画布上的 px;ops 是 EMU | 同一个文件里绝不混用两者 |
convert pptx→pdf 无文本层;convert docx→md 丢图片(detail.skipped) | 需要每个字时用 docs read --full |
docs findReplace 跳过表格单元格;insert_content 中未知 HTML 标签被静默剥离 | 对表格 block 用 replace_blocks;待在受限 HTML 集合内(guide docs) |
命令失败时怎么办(When a command fails)
按 error 分支、照 suggestion 行事,然后重发整个批次(原子 apply 什么都没写)。detail 以字段携带事实,绝不解析 message。错误对照表完整如下:
error | 下一步命令 |
|---|---|
unknown_command, unknown_option | 用 suggestion 里的 did you mean;detail.commands / detail.options 列出合法项;技能比应用旧时运行 genoffice <command> --help |
missing_argument, invalid_argument | 修正 message 点名的 flag;genoffice <command> --help 显示所有 flag |
invalid_json | 重新序列化 ops 文件;经 --ops - 管道时检查引号 |
unknown_op | detail.failures[].supported 与 did_you_mean;genoffice guide <domain> 查列表 |
op_rejected | detail.failures[].usage 是 executor 的 usage 行;genoffice guide <domain> <op> --json 查 schema;修复该 op |
target_not_found | detail.failures[].available 列出该 slide 上的 id / 匹配的 blocks;否则 genoffice <domain> read <file> --json 重新定位 |
out_of_range | detail.failures[].valid_range(或 detail.valid_range);read 显示当前计数 |
sheet_not_found | detail.sheets 有文件中实际的标签名;照抄使用 |
file_not_found | 检查路径(相对当前目录);对 --ops 而言 - 是 stdin |
output_exists | 换 --out,或用户要求替换时用 --force |
file_open_in_gui | 请用户关闭标签页,或用 --out 写入;--force 仅在同意时 |
file_not_open_in_gui | selection/open --el 需要文件在标签页中:先 genoffice open <file>,再请用户选中 |
outside_allowed_roots | 待在 GENOFFICE_ALLOWED_ROOTS 内;不要尝试其他位置 |
resource_limit | 包内部件过多/过大、压缩比不合理或条目路径逃逸归档;detail 点名条目与限额。不要重试,告诉用户 |
unsupported | detail.supported 列出该命令接受什么;从上表选另一条路线 |
conversion_failed, app_unavailable | 文件或应用的问题:重试一次;若 capabilities --json 显示应用缺失,告诉用户(PDF 与 →html/html→ 路线需要 GenOffice) |
成功结果仍可能携带 warnings[]({code, message, suggestion?}):formulas_not_cached、op_warning(sheets op 被调整过)、images_dropped(convert docx→md)、output_renamed(image 以提供商的真实扩展名保存)。读它们、报告重要的、不要重试。
「完成前」质量门:三行检查,每次必做
技能文档要求每个产物固定做三项检查:
| 产物 | 1. 检查 | 2. 查看 | 3. 报告 |
|---|---|---|---|
| Deck | slides audit deck.pptx --json → detail.issues 为空(否则应用 suggest ops) | render deck.pptx --out shots --grid --json,打开联系表 | .pptx 路径与任何你保留原样的内容 |
| 工作簿 | sheet check book.xlsx --json → 无 formula_error、missing_sheet_ref、number_overflow(应用 set_col_width 建议) | render book.xlsx --out shots --json,看 sheet 的 PNG | .xlsx 路径;如有未缓存公式要点名 |
| 文档 | docs check report.docx --json → 无你修得了的 broken_ref、placeholder_left、field_not_evaluated | render report.docx --out shots --json,看第 1 页和最后一页 | .docx 路径 |
注意:check/audit 无论有没有发现都会以退出码 0 结束,发现项在 detail.issues[] 里,带稳定的 code、path,且尽可能带一条可直接传给 apply 的 suggest op。除非用户要求看文件,否则不要运行 genoffice open。
读取用户的文件:素材输入的正确姿势
用户交给你的素材(要转成幻灯片的报告、要总结的工作簿)由你直接读取:md、txt、csv、pdf 与图片直接打开。Office 文件是打包的 XML,必须先经过 CLI:
- docx:
genoffice convert file.docx --to md --out file.md取全文(图片被丢弃),或genoffice docs read file.docx --full --json/--html取带索引的 blocks。 - xlsx:
genoffice convert file.xlsx --to csv --sheet <name> --out file.csv取整张 sheet 的显示文本,或genoffice sheet read file.xlsx --range A1:H200 --json取原始值(不加--range时停在 500 行并说truncated: true;先用--stats估量工作簿大小,用--cols/--max-rows翻页宽表/长表,用--where formula只看公式)。 - pptx:
genoffice slides read file.pptx --full --json取每页文本、表格与演讲者备注;需要看页面时genoffice slides render file.pptx --out shots。
数据与措辞取自这些素材;绝不要自己 cat 或 unzip Office 文件本身。技能文档里这句「never cat or unzip the Office file itself」与 packages/cli/src/commands/convert.ts 中「Office 文件是 zipped XML,先走 CLI」的实现思路一致——CLI 的引擎负责解包、解析与安全边界。
设计演示文稿:分阶段管线(Deck 从简报诞生)
只要用户要演示文稿(无论多短),不要手工摆放 ops:要走 GenOffice 应用自己用的分阶段管线。你是模型,genoffice 是引擎,每个阶段都是 CLI 在下一阶段开始前检查的一个文件。Ops(create --ops、slides apply)只用于编辑已存在的 deck。这条管线的完整描述同样存在于 packages/pipelines/src/slides/guides/design.md(由 genoffice guide slides design 输出)。
- 每会话跑一次
genoffice guide slides design,再跑genoffice guide slides spec。跑一次genoffice capabilities --json:它会告诉你 GenOffice 是否配置了搜索、图片搜索与图片生成;仅在已配置时才用它们获取事实与照片,否则规划无照片页面。 - 为 deck 建一个文件夹。先把样式表写进
deck/style.md(颜色、字体、布局变体、一句话风格)。然后写大纲deck/outline.json(核心钩子 + 每页一条:标题、类型、布局、带真实数字的简报、image_queries),并运行genoffice slides check deck/outline.json --json;修掉每个错误再继续。只有用户要求审阅大纲时才展示大纲。 - 一步一页:重读
deck/style.md与该页的大纲条目,确定它的照片,写deck/pages/NN.json(一个页面对象,回显条目的title、type、layout),运行genoffice slides check deck/pages/NN.json --json;它会在上一级找到outline.json与style.md,对照条目 N 与配色检查页面。修到detail.audit、detail.outline.findings与detail.style.offPalette都为空(与大纲不一致会退出 1),再做下一页。绝不要在一个文件里写多页,也不要一步写多页。 genoffice create --type pptx --spec deck/pages --outline deck/outline.json --out deck/deck.pptx --json(大纲页没有对应文件或页面与条目不一致时拒绝运行)。然后genoffice slides render deck/deck.pptx --out deck/shots --json看 PNG;genoffice slides audit deck/deck.pptx --json看几何发现。修页面在其文件中改,genoffice slides replace deck/deck.pptx --slide n --spec deck/pages/NN.json --json重建单页。最多两轮修复。- 报告路径。照片来自
genoffice search --images结果、genoffice image或用户给的本地文件;绝不用灰框代替照片。数字来自用户素材或genoffice search;数字为示意时要明说。
管线文件之间的关系:slides check、create --spec 与 slides replace 会在页面文件旁与上一级查找 outline.json 与 style.md,把每个页面(文件 NN.json 即条目 pages[N-1])对照其大纲条目与样式表颜色检查,并在 detail.notes 中说明哪个文件缺失。outline.json 的字段为 topic、core_hook(带张力、数字或反直觉对比的一句话)、pages[](每页 title、type(cover/content/data/closing)、layout(来自样式表库的该类型变体)、brief、image_queries)。检查器强制执行的规则包括:全 deck 要有 core hook;内容页不得连续重复同一布局变体且全 deck 至少用 3 个变体;按内容选变体(三个并列点→three_column_cards,一个关键数字→hero_big_number,对比→two_column_comparison 或 two_by_two_grid,序列→timeline_horizontal,指标→kpi_cards_row);禁止占位符(「XX%」、「lorem」),每个数字与名字都来自已有素材。
编辑既有演示文稿
单页重写、换标题、换图:用 ops 而非分阶段管线,并保持 deck 自己的设计。
genoffice slides read deck.pptx --slide n --full --json取元素 id 与当前文本;仅凭文字看不出页面样貌时genoffice slides render deck.pptx --slide n --out shots --json。- 在既有元素上用
setText(未指定样式的 runs 继承原字体、字号与颜色),新内容用addElement/addPicture,删减用deleteElement。用户想保留原文件时用--out写。 - 编辑后
genoffice slides audit deck.pptx --slide n --json:同一文本框里更长的句子会溢出,应用它返回的suggestops(放大或移动框),再渲染一次查看。 - 被编辑元素的 id 会变:第二轮 ops 前重新
slides read。slides replace --slide n --spec从 spec 重建页面,只用于分阶段管线建的 deck,不用于重设用户带来的 deck 的风格。
三个开箱即用的示例
用 ops 建 deck(既有 deck 的编辑或夹具;给人用的演示文稿走上面的分阶段路径):
[
{
"op": "addElement",
"target": { "slide": 0 },
"kind": "textbox",
"offset": { "x": 914400, "y": 685800, "cx": 7315200, "cy": 914400 },
"paragraphs": [{ "runs": [{ "text": "Q3 Review", "bold": true, "fontSize": 36 }] }]
},
{ "op": "addBlankSlide", "target": { "slide": 0 } },
{
"op": "addTable",
"target": { "slide": 1 },
"rows": 3,
"cols": 3,
"offset": { "x": 914400, "y": 1828800, "cx": 7315200, "cy": 2286000 }
}
]
genoffice create --type pptx --ops deck.json --out q3.pptx --json
带公式的工作簿,然后格式化表头:
echo '[["item","qty","price"],["Apple",2,1.5],["Total","=SUM(B2:B2)",""]]' > table.json
genoffice create --type xlsx --from table.json --out sales.xlsx
echo '[{"op":"format_range","range":"A1:C1","format":{"bold":true,"fillColor":"#FFFF00"}}]' | genoffice sheet apply sales.xlsx --ops - --json
从 Markdown 建 Word 文档,然后在 block 0 后插入一段:
genoffice create --type docx --from report.md --out report.docx
echo '[{"op":"insert_content","afterBlockIndex":0,"html":"<p>Executive summary.</p>"}]' | genoffice docs apply report.docx --ops -
路径规则(Path rules)
- 传绝对路径或相对当前目录的路径;genoffice 从不在
--out路径或被编辑文件之外写入。 create和convert在没有--force时拒绝覆盖已有输出。apply默认原地编辑(除非给--out);--out指向另一个既有文件也需要--force。- genoffice 拒绝改写 GenOffice 窗口当前打开的文件(退出码 2,消息「GenOffice has this file open」)。请用户关闭该标签页、用
--out写到别的路径,或仅在用户接受编辑器可能覆盖时传--force。 - 若环境中设置了
GENOFFICE_ALLOWED_ROOTS,genoffice 只在这些目录内读写(否则退出码 2);请待在范围内。每条执行的命令都会记录到~/.genoffice/cli-audit.jsonl(GENOFFICE_AUDIT_LOG可重定向或禁用)。GENOFFICE_USER_DATA把 genoffice 指向非默认的 GenOffice 配置(打开的文档注册表、AI 设置)。
审计日志的实现见 packages/cli/src/audit.ts:每行一个 JSON 记录(command、argv、status、code、output_path、ms、cwd,外加时间戳与 pid),让放开 Agent 操作的用户事后能看到它碰过什么;日志超过 2 MB 会滚动为 .1 文件,且审计写入失败绝不拖垮命令本身。
- 图片类 ops(
addPicture、setImageFill、addMedia)的bytes字段接受本地文件路径,genoffice 负责读取。
限制与边界(Limits)
- 转 PDF 的应用内路线:转 PDF 在 GenOffice 应用内运行(隐藏进程,每次数秒),需要已安装 GenOffice,或用
GENOFFICE_APP_BIN指向它;docx→html与html→docx同理。这意味着这几条转换路线在本仓库的 CLI 包之外依赖应用二进制(packages/cli/src/commands/convert.ts 的APP_ROUTES与NODE_ROUTES区分了「本进程内完成」与「交给应用无头导出」两类转换)。 - Excel 高级 op 的约束:
add_pivot在targetCell写入透视表单元格(该处无值或公式,且 sheet 须已存在于文件中),外加一个 Excel 会刷新的原生透视表;源公式从文件求值,所以要放在更早的批次里。add_sparkline每数据行写一个单元格内迷你图(每个 op 至多 200 行)。convert_to_values用工作簿引擎从文件计算的值替换公式(错误结果保留公式;单元格编辑放在更早的批次)。set_page_setup还接受printTitles、header/footer与rowBreaks/colBreaks。仍需要实时编辑器的 Excel op(refresh_pivot、对会话创建的表格与形状的编辑)会被拒绝并给出原因。add_conditional_format与set_data_validation是在 sheet 已有规则之上追加(set_data_validation对已有规则的范围会替换之,null移除之);clear_conditional_formats从零开始。 - 公式求值:写入后会用工作簿引擎求值公式,因此
sheet read与缓存值读取者能看到数字。
结语:把 SKILL.md 当作 Agent 的操作手册
这份技能文档的精髓是「模型负责思考,genoffice 负责执行」:模型决定要什么(结构、样式、内容),CLI 以可校验的 JSON ops 与规格文件为输入,以机器可读的 JSON 结果为输出,并在每一步(大纲、逐页规格、批次、质量门)都提供检查点。仓库侧的实现与之严格对应:result.ts 定义契约、batch.ts 定义三种批次语义、op-catalog.ts 保证指南与校验器不漂移、audit.ts 保证每次执行可追溯。对任何接入 Claude Code、Codex 或 Cursor 的 Agent 而言,genoffice skill install <agent> 是把它装进技能目录的正规入口,而本文覆盖的每一个命令、陷阱与错误处理分支,都可以从 skills/genoffice/SKILL.md 原文档与 packages/cli 源码继续深入核对。
【免费下载链接】genoffice
Free, open-source AI Office suite: Docs, Sheets, Slides, PDF, Markdown and HTML editors with a built-in AI agent, plus a `genoffice` CLI and agent skill so Claude Code, Codex and Cursor can create and edit real .docx/.xlsx/.pptx files locally. Bring your own key. macOS, Windows & Linux.
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



