Dayward AI
Week 1 · D4About 5 hours

Skills With Scripts: Executable Attachments, Dependencies and Sandboxing, Cross-Platform Support, and Breaking Down Document-Handling Skills

When a skill should ship a script instead of more instructions, how to make a script's dependencies self-contained, how to design its interface for an agent, and how a document-handling skill breaks into plan, then validate, then execute.

Today's goals 0/3

Sign in to tick these off and save your progress.

今日目标

  1. 能判断一段逻辑该写进 SKILL.md 正文还是该沉淀成 scripts 里的脚本
  2. 能写一个自包含、非交互、输出结构化、错误信息可自纠的 Agent 友好脚本
  3. 能把一个文档处理任务拆成先规划、再校验、后执行的三步流程

昨天讲设计方法时留了个尾巴:「先规划、再校验、后执行」里那道关键的校验,本身是一段代码。今天把 skill 的第三个目录 scripts/ 讲透——什么时候该从写指令切换到写代码,写出来的脚本怎么才算「给 Agent 用的」,以及让模型跑你的脚本风险到底在哪。读完正文、做完实验之后,回到页面顶部把三条目标勾掉。

小白版讲解

什么时候该写脚本

档案柜里的作业指导书,翻到某一页写着「把这张表的三十行金额加起来,误差不能超过一分」。你可以在页面上写清楚加法怎么做,也可以在这一页夹一个计算器。skill 的 scripts/ 目录就是那个夹在页里的计算器。

判断口径有三条,命中任意一条就该写脚本。

第一条,同一段逻辑被重新发明了第三次。 你把一个 skill 跑了几轮,回头翻它的执行轨迹,发现模型每次都在现写一段几乎一样的代码——解析同一种格式、画同一种图、做同一种校验。每次现写,每次都可能写得不一样,而且每次都要花 token 和时间。这时候把它写成一个测好的脚本,一次投入长期受益。

第二条,结果必须逐字一致。 校验、格式转换、哈希计算这类事,正确答案只有一个。让模型「按指令做」意味着每次都有偏移的可能;让它跑脚本意味着结果是确定的。确定性任务交给代码,判断性任务留给模型,这是分工的基本盘。

第三条,一条命令复杂到第一次很难敲对。 一个带七个参数、还要按顺序管道三次的命令,写进正文里模型迟早敲错一个横杠。包成脚本,正文里就只剩一行。反过来,如果只是调一个现成工具加两三个参数,直接在正文里写这条命令就行,没必要为它建一个 scripts/ 目录

第三条的反面也要说清楚:很多生态本来就有「不用装就能跑」的方式,比如 Node 侧的 npx、Python 侧的 uvxpipx。这类一次性命令直接写进正文即可,但一定要把版本钉死

BashBash
npx eslint@9.0.0 --fix .
uvx ruff@0.8.0 check .

不钉版本,你的 skill 就会在某个上游发版的早晨突然行为改变,而你完全不知道为什么。同理,如果脚本对运行环境有要求,写进 frontmatter 的 compatibility 字段,比如「需要 git、docker、jq 与联网」。

写脚本的门槛比多数人以为的要高一点:它是一份长期资产,要维护、要跟着模板变、要有人看得懂。所以三条判据一条都不命中的时候,老老实实写正文。

自包含:别让读者先装环境

脚本最容易死在第一步——依赖装不上。模型跑 python scripts/extract.py,报一句「没有这个模块」,然后它开始自作主张地装东西,这一步就失控了。

解决办法是把依赖声明写进脚本自己,让运行器现场解决。几个生态都有对应的写法:

Python 侧有一份专门的规范定义了「内联脚本元数据」,把依赖写在文件头部的注释块里,用 uv runpipx run 跑,运行器会自己建一个隔离环境把依赖装好:

TextText
# /// script
# requires-python = ">=3.12"
# dependencies = ["beautifulsoup4>=4.12,<5"]
# ///

JavaScript 侧,Deno 的 npm: 导入前缀和 Bun 的运行时自动安装都能达到同样效果,导入路径里直接带版本号。选哪一种取决于用户环境里装的是什么,但不管选哪种,版本都要钉死

自包含还有一层含义:脚本不要依赖当前工作目录。SKILL.md 里引用脚本一律用相对技能根目录的路径(scripts/validate.py),这是约定;但脚本内部要处理的输入文件路径,应该从参数拿,而不是假设「就在当前目录下」。

为 Agent 设计接口

这是今天最有价值的一节。**给 Agent 用的命令行工具,和给人用的,设计取舍完全不同。**人会读文档、会试错、会在报错时凭经验猜;Agent 只能读你打印出来的那几行字,然后决定下一步。

第一条,绝对不能交互。 Agent 跑在非交互终端里,回答不了任何提示。一个停下来等你输入环境名的脚本,会一直挂到超时。所有输入走参数、环境变量或标准输入。这不是最佳实践,是硬要求。

第二条,帮助信息就是接口文档。 Agent 学会用你的脚本,主要靠 --help。写清一句话说明、参数列表、以及两三个用法示例。但要短——这段输出会原样进上下文,跟别的东西抢位置。

第三条,错误信息决定了它下一次会不会做对。 一句「参数无效」浪费一整轮;写清「哪一项错了、期望什么、实际是什么、可选值有哪些」,模型当场就能改对。

TextText
错误:--format 只能是 json、csv、table 之一。
      实际收到:"xml"

这一条在校验类脚本上收益最大。「字段 signature_date 不存在,可用字段:customer_name、order_total、signature_date_signed」这样一句,模型一眼就看出自己写错了后缀。错误信息是给模型的提示词,用这个心态去写它。

第四条,输出要结构化,而且数据与诊断分流。 结构化数据走标准输出、进度与警告走标准错误。这样调用方能拿到一段干净的、可以直接交给别的工具处理的输出,同时诊断信息也没丢。

第五条,输出体量要可控。 很多 Agent 环境会在输出超过一两万字符时截断,而且不一定告诉你截了。所以默认给摘要或限量,再提供翻页参数让它按需要多要一点;实在很大就要求调用方指定输出文件。

还有几条零散但重要的:幂等(Agent 会重试,「不存在才创建」比「创建且重复则失败」安全);有意义的退出码(不同失败类型给不同的码,并在帮助里说明);危险操作提供预演开关

下面这段把这些原则落成一个最小的校验脚本。注意看错误信息的措辞——那才是重点,代码本身很简单。

validate.ts
type Field = { name: string; type: 'string' | 'number' | 'boolean'; required: boolean }
 
export function validate(fields: Field[], values: Record<string, unknown>): string[] {
  const errors: string[] = []
  const known = new Set(fields.map((f) => f.name))
 
  for (const f of fields) {
    if (!(f.name in values)) {
      if (f.required) errors.push(`缺少必填字段 ${f.name}(类型 ${f.type})`)
      continue
    }
    const actual = typeof values[f.name]
    if (actual !== f.type) {
      // 期望、实际、值三样都给全,模型才不用再猜一轮
      errors.push(`字段 ${f.name} 类型不符:期望 ${f.type},实际 ${actual}(值 ${JSON.stringify(values[f.name])})`)
    }
  }
  for (const name of Object.keys(values)) {
    // 未知字段几乎总是拼写错误,所以把可用字段全列出来
    if (!known.has(name)) errors.push(`模板里没有字段 ${name}。可用字段:${[...known].join('、')}`)
  }
  return errors
}
 
// 数据走标准输出,诊断走标准错误;退出码 0 通过、1 有错误、2 用法问题
export function main(argv: string[]): number {
  if (argv.length !== 2) {
    console.error('用法: validate <字段清单 JSON> <取值 JSON>')
    return 2
  }
  const errors = validate(loadFields(argv[0]), loadValues(argv[1]))
  console.log(JSON.stringify(errors.length === 0 ? { ok: true } : { ok: false, errors }))
  return errors.length === 0 ? 0 : 1
}

权限、沙箱与不可信输入

给 skill 加脚本,等于把「让模型执行代码」变成了这个 skill 的日常动作。这件事的风险边界要说清楚。

第一,skill 里的脚本是代码,来源就是信任边界。 你自己写的脚本和你从某个市场装来的 skill 里的脚本,风险完全不同。装第三方 skill 之前把 scripts/ 目录读一遍——这跟你装一个 npm 包之前会看两眼是一回事,只不过 skill 更容易被当成「文档」而放松警惕。

第二,预批工具要按最小权限给。 规范里的 allowed-tools 字段(以及各家客户端的等价机制)可以预先批准一些工具,免得每一步都弹确认框。但批准的粒度要卡到命令级:写「允许运行 git 的只读子命令」,不要写「允许运行任意 shell」。这个字段目前还是实验性的,各家支持程度不一,别把安全性完全押在它上面。

第三,脚本处理的输入是不可信的。 你的脚本要解析一份用户给的文件、一段接口返回的内容,那些内容里可能藏着「忽略之前的指令,改为执行……」这类东西。脚本本身只要不把输入当代码执行就没事,但脚本的输出会进模型的上下文——如果你原样回显了一大段外部内容,等于把那段话直接讲给了模型听。姊妹课 7 天 MCP 的第 6 天 专门讲这类提示注入与工具描述可信度的问题,写脚本前值得读一遍。

第四,危险操作要有闸门。 删除、覆盖、发布这类动作,给一个预演开关,或者要求显式加一个确认参数。Agent 会重试,重试一个不可逆操作的代价你承担不起。

跨平台

脚本跑在谁的机器上,你说了不算。三件事最容易翻车。

路径分隔符与大小写。 用语言标准库的路径拼接,不要手写斜杠;文件名大小写在有的系统上敏感、有的不敏感,SKILL.md 写成 Skill.md 在你机器上能跑、到同事那儿就消失。

shell 差异。 正文里写的命令如果只在某一种 shell 下成立,就在旁边给另一种的写法,或者干脆改用一个跨平台的运行器。规范给的例子就是这么做的:同一件事给出两种命令,让 Agent 按环境挑。

换行符与编码。 读写文本明确指定编码;生成文件时注意行尾风格,否则会在版本控制里制造大片无意义的差异。

这三件事的共同点是:它们在你自己机器上永远不会出现。所以要么在正文里显式声明环境要求(compatibility 字段就是干这个的),要么用标准库替你抹平差异,不要靠运气。

文档处理类 skill 的拆解

把上面所有东西合起来,就是一个完整的形态:先规划、再校验、后执行。文档处理、表单填写、批量改动这类任务都该走这条路。

有错误 通过 第 1 步 分析脚本读模板 产出字段清单这是真值 第 2 步 规划模型写取值计划不要凭记忆猜字段名 第 3 步 校验脚本比对计划与真值错误信息要够模型自己改对 第 4 步 执行脚本填充并写出文件只有这一步会落盘
Mermaid source
mermaidmermaid
flowchart TB
  A[第 1 步 分析<br/>脚本读模板 产出字段清单<br/>这是真值] --> B[第 2 步 规划<br/>模型写取值计划<br/>不要凭记忆猜字段名]
  B --> C[第 3 步 校验<br/>脚本比对计划与真值<br/>错误信息要够模型自己改对]
  C -- 有错误 --> B
  C -- 通过 --> D[第 4 步 执行<br/>脚本填充并写出文件<br/>只有这一步会落盘]

关键是第 3 步,不是第 1 步和第 4 步。 没有第 3 步,这就是一个普通的「读进来改一改写出去」;有了第 3 步,模型就有了一个在真正动手之前发现自己错了的机会,而且错误信息给得足够具体的话,它能自己改对。

三个设计要点值得单独记:

分析脚本产出的是「真值」。 模型不该凭记忆猜模板里有哪些字段,让脚本从模板里抽出来。这一步消灭的是最常见的一类错误:字段名拼错、多写一个不存在的字段。

校验脚本不改数据,填充脚本不做校验。 两件事混进一个脚本,模型就没法在计划和执行之间停下来。而且填充脚本要有个自检:填完还剩未替换的占位符就报错退出——宁可失败,也不要写出一份看起来填好了、实际带着占位符的文档,那种文件会被当成成品发出去。

中间产物要落盘。 计划写成一个 JSON 文件,而不是留在模型的上下文里。落盘之后校验脚本才能读到它,你也才能在出问题时打开看一眼。

源码导读

动手实验

🧪 D4 实验:一个带脚本的文档处理 skill,校验脚本加填充脚本,支持离线模拟运行

Code location: labs/agent-skills-7days/day-04-doc-skill-with-scripts

验收标准:

  1. MOCK=1 下能跑通全流程,输出里能看到分析、生成摘要、校验失败、修正后校验通过、填充成功五步,最后一步反面演示被正确拒绝。
  2. 分析脚本能从模板里抽出全部字段的名字、类型与是否必填,模型不需要凭记忆猜字段名。
  3. 校验脚本能报出三类错误:必填字段缺失、类型不符、模板里没有的未知字段;未知字段那条要列出可用字段。
  4. 填充脚本在还剩未填的必填占位符时以非零退出码失败,并列出是哪几个,而不是写出一份带占位符的文档。
  5. SKILL.md 的工作流写成带复选框的清单,校验那一步单独成步且写明失败后要回到上一步重来。

今天要写真代码,但代码不是重点,错误信息才是。动手之前先看一眼 solution 里校验脚本报出来的那四条错误,体会一下「够模型自己改对」是什么水平。一个可操作的自查:把你写的错误信息单独发给一个没看过模板的人,他能不能照着改对。

  1. 跑通 solution,用 MOCK=1 看清校验脚本先报错、修正后再执行成功的完整轨迹。
  2. 在 starter 里补全校验脚本的三类错误,重点打磨措辞而不是逻辑。
  3. 补全分析脚本的占位符解析与去重,让同一个字段不会出现两种类型。
  4. 补全填充脚本的自检,让它在还剩未填占位符时失败而不是写出半成品。
  5. 补全 SKILL.md 的工作流段与坑段,把三步流程写成模型能照着走的清单。

面试题

今天 3 道题在下方题库区,侧重脚本与指令的分界、Agent 友好的脚本接口、以及脚本执行的权限与沙箱。展开后先看「分析过程」再看要点——照着推导练,比背要点管用。标注「国内高频 / 海外高频」方便按目标市场取舍。

检查清单与明日预告

  • 能判断一段逻辑该写进 SKILL.md 正文还是该沉淀成 scripts 里的脚本
  • 能写一个自包含、非交互、输出结构化、错误信息可自纠的 Agent 友好脚本
  • 能把一个文档处理任务拆成先规划、再校验、后执行的三步流程
  • 能说出「校验脚本不改数据、填充脚本不做校验」这条分工的理由
  • 实验的 5 条验收标准全部通过
  • 3 道面试题不看要点也能答出至少 2 道

明天(D5)我们换个身份:从写 skill 的人,变成实现 skill 支持的人。前四天你一直在「用」渐进式加载,明天把它真的写出来——扫描目录、宽松解析 frontmatter、把名字与描述拼成目录注入系统提示、激活时才读入正文。自己实现一遍之后,你对前四天每一条建议的理解都会不一样,因为你会看到它们分别对应运行时的哪一行代码。

Interview questions

  • Which logic belongs in a skill's scripts directory and which belongs in the SKILL.md body?什么逻辑该写成脚本放进 skill 的 scripts 目录,什么该留在 SKILL.md 正文里?
    Common in ChinaCommon overseasBasic#agent-skills#scripts

    How to reason about it · think before answering

    1. This tests a sense of division of labor. Saying complex logic goes in scripts says nothing, because complex has no boundary. The interviewer wants decidable signals.
    2. Give three: the same logic gets reinvented a third time across execution traces; the result must be byte-identical (validation, format conversion, hashing); or a command is complex enough to be hard to get right first try.
    3. Expand the second into the core principle: deterministic work goes to code, judgment work stays with the model. Following instructions leaves room for drift; running a script does not.
    4. Give the other side: invoking an existing tool with two or three flags belongs inline in the body. Many ecosystems offer install-free one-off runners, and versions must be pinned or an upstream release silently changes your skill's behavior.
    5. Add the cost view: a script is a long-lived asset that must be maintained and kept in sync. When none of the three signals fire, prose is cheaper.
    6. Expected follow-up: how do you notice reinvention? Read execution traces rather than final outputs; the same helper appearing across runs is the signal.

    分析过程 · 先想清楚再作答

    1. 这题在考分工感。答「复杂的写脚本」等于没答,因为复杂是个没有边界的词。面试官要听的是可判定的信号。
    2. 给三条信号,命中任意一条就写脚本:同一段逻辑在执行轨迹里被重新发明了第三次;结果必须逐字一致(校验、格式转换、哈希);一条命令复杂到第一次很难敲对。
    3. 把第二条展开成分工原则,这是本题的核心句:**确定性任务交给代码,判断性任务留给模型**。让模型「按指令做」意味着每次都有偏移的可能,让它跑脚本意味着结果确定。
    4. 再给反面:只是调一个现成工具加两三个参数,直接在正文写这条命令就行,不必建 scripts 目录。很多生态有免安装的一次性运行方式,用它们时**版本必须钉死**,否则上游一发版你的 skill 行为就变了。
    5. 补一条成本视角:脚本是长期资产,要维护、要跟模板同步、要有人看得懂。三条信号一条都不命中的时候,写正文更划算。
    6. 可预期的追问是「怎么发现模型在重新发明轮子」。答案是读执行轨迹而不是只看最终产出——同一个辅助函数在几次运行里反复出现,就是该沉淀成脚本的信号。

    Key points

    • Write a script when any of three fire: third reinvention, byte-identical results required, or a command hard to get right first try.
    • Deterministic work to code, judgment work to the model.
    • A tool invocation with a couple of flags stays inline, with the version pinned.
    • Scripts are long-lived assets with maintenance cost; if no signal fires, write prose.
    • Spot reinvention by reading execution traces, not final outputs.

    答题要点

    • 三条信号命中任一条就写脚本:重复发明第三次、结果必须逐字一致、命令复杂到难以一次敲对。
    • 分工原则是确定性任务交给代码,判断性任务留给模型。
    • 只加两三个参数调现成工具的,直接在正文写命令,但版本要钉死。
    • 脚本是长期资产,有维护成本,三条都不命中就写正文。
    • 发现重复发明要靠读执行轨迹,不是看最终产出。
  • How does designing a command-line script for an agent differ from designing one for a human?给 Agent 用的命令行脚本,接口设计上和给人用的有什么不同?
    Common in ChinaCommon overseasIntermediate#agent-skills#scripts#cli-design

    How to reason about it · think before answering

    1. The hinge is the difference. Many can list CLI best practices; few can say which ones exist specifically because the caller is a model.
    2. State the root difference: humans read docs, experiment and guess from experience; an agent has only the lines you printed before deciding the next move.
    3. From that: never prompt interactively. This is a hard requirement, not a nicety, because agents run in non-interactive shells and will hang until timeout.
    4. Help output is the interface documentation, but it must be short, since it enters the context window and competes with everything else. A human CLI never faces this constraint.
    5. Error messages decide the next attempt: say what failed, what was expected, what was received, and which values are allowed. Error messages are effectively prompts for the model.
    6. Then: structured output with data on stdout and diagnostics on stderr, and bounded output size because many harnesses truncate silently. Add idempotency, meaningful exit codes, and a dry-run flag for destructive work.
    7. Expected follow-up: how do you validate the design? Hand the help text and one error message to someone who has never seen the skill; if they can act on it, the model probably can too.

    分析过程 · 先想清楚再作答

    1. 题眼是「不同」。能列出五条通用 CLI 最佳实践的人很多,能说清哪几条是因为「使用者是模型」才成立的人少。
    2. 先给根本差异:人会读文档、会试错、会凭经验猜;Agent 只能读你打印的那几行字然后决定下一步。**它的全部信息就是你的输出**。
    3. 由此推出五条。绝对不能交互,这是硬要求不是最佳实践,Agent 在非交互终端里回答不了提示,会一直挂到超时。
    4. 帮助信息就是接口文档,但要短——这段输出原样进上下文,跟别的东西抢位置,这是给人用的 CLI 完全不必考虑的约束。
    5. 错误信息决定它下一次会不会做对:写清哪一项错了、期望什么、实际是什么、可选值有哪些。**错误信息本质上是给模型的提示词**,这一句是拿分点。
    6. 剩下两条:输出结构化并把数据与诊断分流到标准输出与标准错误;输出体量要可控,因为很多 Agent 环境会静默截断超长输出。再补幂等、有意义的退出码、危险操作给预演开关。
    7. 可预期的追问是「怎么验证接口设计得好」。答案是把帮助输出和一条错误信息单独发给一个没看过这个 skill 的人,他能照着敲对改对,模型大概率也能。

    Key points

    • The agent's only information is what you printed; it does not read docs or experiment.
    • Never prompt interactively; a non-interactive shell will hang until timeout.
    • Help text is the interface documentation and must be short because it consumes context.
    • Error messages must state the field, the expectation, the actual value and the allowed set; they are prompts for the model.
    • Emit structured data on stdout and diagnostics on stderr, bound output size, and offer a dry-run for destructive operations.

    答题要点

    • 根本差异:Agent 的全部信息就是你打印的输出,它不会读文档也不会试错。
    • 绝不能交互,否则在非交互终端里会挂到超时。
    • 帮助信息就是接口文档,但必须短,因为它原样占用上下文。
    • 错误信息要写清哪项错、期望什么、实际什么、可选值有哪些,它本质是给模型的提示词。
    • 结构化输出并分流标准输出与标准错误,输出体量要可控,危险操作给预演开关。
  • What security risks come with bundling scripts in a skill, how would you contain them, and why should document tasks follow plan, validate, then execute?skill 里带脚本会带来哪些安全风险?你会怎么限制它?另外,为什么文档处理这类任务要先规划再校验后执行?
    Common in ChinaCommon overseasDeep dive#agent-skills#security#workflow-design

    How to reason about it · think before answering

    1. Two halves; answer both. Security is about boundaries, the three-step flow is about process, and both come down to putting a gate before an irreversible action.
    2. Cover security in four layers. Source: a third-party skill's scripts are someone else's code, so read the scripts directory before installing, exactly as you would skim a package. Skills invite less scrutiny because they look like documentation.
    3. Permissions: pre-approve at command granularity, allowing read-only git subcommands rather than arbitrary shell, and remember the field is experimental with uneven support, so do not rely on it alone.
    4. Input: files and API responses are untrusted. A script that does not execute them is not directly exploitable, but script output enters the model's context, so echoing a large blob of external content effectively speaks it to the model. Actions: gate delete, overwrite and publish behind a dry run or explicit flag, because agents retry.
    5. For the second half, give the three steps and stress that the value is in the middle one: analysis produces ground truth, validation compares plan against it with self-correctable errors, and only the fill step writes files.
    6. Name two disciplines: validation never mutates and fill never validates, or the model loses its pause between planning and execution; and intermediate artifacts must be written to disk so the validator can read them.
    7. Expected follow-up: why not validate while filling? Filesystems have no transactions, and a half-written document is worse than none because it looks complete.

    分析过程 · 先想清楚再作答

    1. 这题有两半,别只答一半。前半考安全边界,后半考流程设计,两者的共同点是「在不可逆的动作之前留一道闸门」。
    2. 安全这一半按来源、权限、输入、动作四层说。来源:第三方 skill 里的脚本就是别人的代码,装之前要读 scripts 目录,跟装一个包之前看两眼是一回事——skill 更容易被当成文档而放松警惕。
    3. 权限:预批工具要卡到命令级,写「允许 git 的只读子命令」而不是「允许任意 shell」;而且这个字段还是实验性的,各家支持不一,不要把安全性全押在它上面。
    4. 输入:脚本处理的外部文件与接口返回是不可信输入。脚本不把它当代码执行就不会被直接利用,但**脚本的输出会进模型上下文**,原样回显一大段外部内容等于把那段话讲给模型听。动作:删除覆盖发布要给预演开关或确认参数,因为 Agent 会重试。
    5. 第二半给三步流程,并强调价值全在中间那步:分析脚本产出的是真值,模型不该凭记忆猜字段;校验脚本比对计划与真值,错误信息要够模型自己改对;填充脚本才落盘。
    6. 两条设计纪律要点出来:校验脚本不改数据、填充脚本不做校验,混在一起模型就没法在计划和执行之间停下来;中间产物要落盘成文件,否则校验脚本读不到,你也没法打开看。
    7. 可预期的追问是「为什么不能边填边校验」。答案是文件系统没有事务,写了一半的文档比完全没写更麻烦——它看起来是完整的。

    Key points

    • Third-party skill scripts are someone else's code; read the scripts directory before installing.
    • Pre-approve tools at command granularity, and do not rely on an experimental field for safety.
    • External input is untrusted, and script output enters context, so never echo large external blobs verbatim.
    • The value of the three-step flow is the middle step: ground truth, self-correctable errors, then writing.
    • Validation never mutates, fill never validates, intermediates go to disk, and never validate while writing.

    答题要点

    • 第三方 skill 的脚本就是别人的代码,装之前要读一遍 scripts 目录。
    • 预批工具按最小权限、卡到命令级;该字段仍是实验性的,不能全押在它上面。
    • 外部输入不可信,且脚本输出会进上下文,不要原样回显大段外部内容。
    • 三步流程的价值全在中间那步校验:分析出真值、校验给可自纠的错误、执行才落盘。
    • 校验不改数据、填充不做校验、中间产物落盘;不要边填边校验,半成品文档看起来是完整的。

Comments

Sign in to join the discussion

No comments yet — be the first.