我在日本和韩国负责 GitHub 的市场营销,而活动正是这项工作的核心:面向企业开发者的系列网络研讨会、东京的社区聚会、首尔仅限受邀者参加的高管闭门会。这个市场的开发者当下真正需要什么?哪些话题值得他们花上一小时?谁又该出现在现场?我很乐意整天琢磨这些问题。
决策之后的事情则是另一回事。一旦活动获批,一套固定的流程便随之启动:
- 在我们的活动平台上复制一个落地页。
- 生成一组带 UTM 标记的链接:每个渠道一个,每个都按特定格式排好。
- 起草邀请邮件,并向负责发送的团队提交请求。
- 把活动添加到两个项目看板上。
- 活动开始前每天早上:下载报名者名单,清理数据,为相关方发布一条状态更新。
- 活动结束后:导出参会者名单,重新整理成可上传 CRM 的格式,给相应的记录打上标签,并撰写一份报告。
这些任务单看都不难,但每一个都可能让你贴错链接、漏掉一天,或者拼错一个活动名称——而下游有 15 份报告都依赖它。
事情是这样的:我以前是一名工程师。我的第一份职业是在 Linux 服务器上为企业客户维护数据库的运转。虽然我的编码能力可能已经生疏,但我依然能一眼看出哪条流水线亟待自动化。这正是我用上 GitHub Copilot 的地方,也是你在自己的工作中同样可以用上它的地方。
所以代码不是我写的。我写下了自己的运维手册,交给 GitHub Copilot,然后在对话中逐步把自动化搭建起来。如今,一个我过去需要手工花上几天时间筹备的活动,可以从一个 GitHub Issue 自动完成设置,每天早上自动筛查报名者,并在活动结束后自动清理收尾。
这篇文章将带你了解它是如何运作的,以及为什么我认为,任何工作涉及跨工具重复性劳动、而这些工具又提供某种可脚本化入口(比如 API,甚至只是一个 CLI)的人,都能照做。
一场活动就是一个 Issue
这个基础性的想法不能算我原创。GitHub 的市场营销团队早已养成了每个项目开一个 GitHub Issue 的习惯。这个 Issue 成为计划、讨论和状态共同存在的地方。Issue 本来就是我们的工作单元。我所做的,是让这个 Issue 去干活。
三个 GitHub 基础构件支撑起了整个系统:
- Issue 表单就是申请表。与空白文本框不同,issue 表单呈现的是结构化字段:活动标题、日期、地区、活动名称、目标受众。我们为每种活动类型各设一个表单,比如线上研讨会和线下活动,它们都接入同一套机制。
- 标签就是开关。像
event-setup这样的标签不是标记,而是触发器。每个自动化工作流都以一个条件开头,实际上就是说:“仅当此标签存在时才运行。” - 操作就是机器。GitHub Actions工作流在标签落地时触发,从 issue 正文中解析出表单字段,然后去执行工作。
仓库为开发者提供的一切,也免费为我的营销工作流提供了:历史记录、可见性、审查,以及每个决策对应的 URL。
有一件事让这一切成为可能,而且它与活动本身毫无关系:我们的活动管理平台开放了 API。我们的 CRM 甚至不需要 API;它的官方 CLI 覆盖了我们所做的全部工作,而且我从未为它配置过 API 密钥,因为 CLI 通过浏览器登录,并由此处理身份验证。无论是 API 还是 CLI,要求都是一样的:一种可脚本化的接入方式。如果你的重复性工作流经某个工具,而该工具提供了活动平台、CRM、表单构建器或分析服务中的任意一种,那么本文的模式同样适用于你。
读到这里的开发者可能已经在酝酿那个显而易见的反对意见:这不就是在重复造轮子吗?营销自动化平台已经存在,一款好的平台或许开箱就能覆盖其中一部分需求。但亚太区与其说是一个市场,不如说是一堆截然不同的市场的集合,即便在我自己的团队内部,工作流也会随着每个子区域和每个细分市场而变化。同一场网络研讨会,这个月可能用日语为东京举办,下个月就用韩语为首尔举办,细分市场不同、CRM 中的字段不同、对优质线索的定义也不同。要让一款打包好的工具吸收所有这些差异,意味着定制预算、咨询工时,以及等待别人的路线图。而用现有的工具自己搭建,意味着工作流的改动就是一次 pull request:我描述我想要什么,一位评审者检查它,然后它通过开发者用来修改软件的那套流程合入主分支。
策划一场活动就是一次对话
这条流水线在 Issue 存在之前就已经启动。我打开 GitHub Copilot,大致说:“我想在 11 月举办一场关于 AI 辅助开发的网络研讨会。”
接下来发生的事情,由我们仓库根目录下一个名为 AGENTS.md 的文件所决定。它是我们团队的操作手册,用纯 Markdown 写成,定义了活动如何命名、财季如何对应到日期、每个区域使用哪个时区,以及一封好的邀请邮件长什么样。GitHub Copilot 读取它,然后找到一场类似的过往活动,按照我们的命名规则提出一个活动名称,起草两个版本的邀请邮件,并向我提出操作手册中规定要问的问题。
把对话放在流水线的最前端,这本身就是一个设计决策,它一次性解决了两个问题。如果全部自动化,你就会失去灵活性;哪天你想让某一场活动稍有不同,僵化的流水线根本没有地方去表达这种差异。但如果让人来填写一切,又会出错。对话恰好处于两者之间。GitHub Copilot 遵循模板,因此落到 Issue 里的数据就是格式正确的正确数据。而正因为它是对话,我可以为这一场活动调整细节,而不会破坏下游的机制。
刚开始时,这段对话发生在 GitHub Copilot CLI 里,在终端中进行。对我来说这没什么问题,但“打开终端”对许多我很想拉进这套工作流的人来说是一道门槛。有了 GitHub Copilot 应用,同样的对话现在发生在一个普通的桌面窗口里。入门门槛从“熟悉 shell”降到了“会打字”。
我想把分工说清楚,因为这才是关键所在:GitHub Copilot 起草;我来拍板。每一个活动名称、每一行邮件主题、每一个日期,都要经过我签字确认后才会推进。对话结束时,GitHub Copilot 会带着正确的标签提交 GitHub Issue,从那一刻起,机器就接管了。
一个标签,一场活动,全流程就绪
当 event-setup 标签落到 issue 上的那一刻,一个 GitHub Actions 工作流就会接手,并在几分钟内完成过去要花我大半天才能做完的事:
- 在我们的活动平台上复制一场过往活动,以创建新的落地页
- 生成完整的带 UTM 标记的 URL 集合:每个渠道一个,格式始终一致
- 将邀请邮件生成为 Word 文档并提交到代码仓库
- 向负责发送邮件和跟踪区域营销的团队发起请求 Issue
- 将活动添加到我们的项目看板并填写相关字段
- 在 Issue 上回帖发布一条摘要评论,这样下一个打开它的人就能在一个地方看到所有信息
报名筛选按计划运行,而不是靠标签触发。每天早上,一个由 cron 触发的工作流会获取每个开放活动的最新报名者,并分享整理后的名单。对于仅限邀请的活动,它还会根据我们的标准筛选候补名单(这位报名者是企业客户中的开发者、学生,还是一位非常想参加我们高管简报会的竞争对手?),之后才会批准任何人。
我最引以为傲的设计决策是一个名为 DRY_RUN 的单一开关,它作为一个设置(用 GitHub 的话说,就是一个仓库变量)存储,每个工作流在运行前都会检查它。把它打开,每个工作流都会走一遍流程,但不触碰任何外部系统:不创建落地页,不在其他仓库提交 Issue,不共享列表。当你是一个把自己的工作自动化的营销团队时,你需要一种排练的方式。DRY_RUN 就是排练开关,也正是它让我从不害怕做实验。
活动结束后,一个斜杠命令
活动后的工作过去是最糟糕的部分:导出参会者、为 CRM 上传重新调整列格式、将公司名称与客户记录匹配,以及撰写报告。现在只需两条命令。
/lead-upload 获取参会者名单,将其整理成我们的营销运营团队进行 CRM 上传所需的精确格式,提交请求 Issue,并关闭跟踪 Issue。/event-report 拉取参会指标和调查结果,并将报告作为评论发布在活动的 Issue 上,回到这个活动所有信息所在的那一个 URL。
这些是 GitHub Copilot agent skills,而这是我最想让你听到的部分:一个技能就是一个 Markdown 文件。每一个都是一个 SKILL.md:一份用散文写成的书面流程,告诉 GitHub Copilot 该做什么、按什么顺序做、以及要注意什么。我写的那些读起来就像我以前记在脑子里的操作手册,因为它们本来就是。
如果你能写操作手册,你就能写技能。
技能也是让系统保持灵活的关键。亚太(APAC)地区没有两个市场以完全相同的方式执行后续跟进。受众不同、细分群体不同、本地惯例不同,而硬编码的工作流会迫使每个市场都套用同一种形态。用 Markdown 编写的流程则很灵活:每个市场都能根据自身实际情况调整运行手册,而无需改动底层的机制。正因如此,活动后的步骤才放在 GitHub Copilot 技能中,而不是固定的流水线里。
我们在一个方面把技能当作代码来对待:新技能通过 pull request 提交,并在合并前接受审查,由一个 CODEOWNERS 文件将审查路由给维护者。带审批流程的营销自动化。治理也随平台一并免费获得了。
内置的护栏让我可以放手试验
我自动化了一个涉及客户数据和 API 凭证的工作流,放在全团队都能看到的仓库里,而我自己几乎没怎么写代码。六个月前我会说这种组合太鲁莽。让我改变想法的是,我意识到在我介入之前,已经有那么多护栏就位了。
我搭建的一些护栏:DRY_RUN 开关、每次 pull request 都会运行的测试套件,以及对每项变更的代码审查。标准的开发者习惯。事实证明,它们对营销工作的保护和对软件的保护一样有效。
但最重要的护栏是随平台而来的:
- 带推送保护的密钥扫描。对我这个岗位的人来说,最可怕的场景莫过于不小心提交了 API token。GitHub 的推送保护会在密钥进入仓库之前就拦截这次推送,而对于 GitHub 自家的 token,即便真有漏网的,也会被自动吊销。
- GitHub Copilot 的数据政策。注册人名单属于业务数据,固定脚本会以固定方式处理它们。但真正的工作从来不是完全固定的;有些时候我需要一份没有任何脚本能预料到的一次性数据切分。由于 GitHub Copilot 的商业版方案不会保留提示词,也不会用它们来训练模型,我可以直接请求做那次一次性分析,而不必像业界许多人私下做的那样:把业务数据粘贴到旁边标签页里开着的随便哪个消费级聊天机器人里。模型本身也是如此:我究竟能用哪些模型,是由组织政策决定的,而不是交给我个人判断,所以即便是一次性实验,也是在公司已经划定的边界内进行。安全的路和便捷的路,这一次难得是同一条路。
技能还带来了另一个好处,几乎算是顺带产生的:由于每个流程现在都是一个有名字、固定的工作单元,我可以把模型和任务匹配起来,从我们组织已批准的阵容中挑选。一个快速、便宜的模型负责日常的名单清理;一个更强的模型负责起草营销文案。
还有一个真实的失败案例,希望你不要重蹈覆辙:那个早晨筛选工作流曾经悄无声息地失败了五天,才有人注意到列表已经过期了。你不监控的自动化,更像是一颗带延迟的定时炸弹。给每一个定时工作流都配上一种能大声报错的方式,这样你就不会错过它了。
从一个任务开始
以下是我的建议,来自一个正在康复的手工劳动者,写给另一个。
挑选你每周重复次数最多的一项任务。然后检查它所涉及的工具是否提供 API 或 CLI。你可能会惊讶地发现,很多工具都有。
然后构建尽可能最小的版本:一个捕获输入的问题表单、一个表示“开始”的标签,以及一个只完成其中一步工作的 Action。或者直接跳过这些,把你的操作手册写成一份 SKILL.md,让 GitHub Copilot 来执行它。用 dry-run 开关运行,直到你信任它为止。再在此基础上逐步扩展。
我没有写代码。我只是把已经知道的东西(工作是如何完成的)写了下来,剩下的就交给平台了。无论你那个版本的早晨登记名单是什么,它距离自动完成,大概只差一份写下来的操作手册。
开始使用:
- issue 表单的语法
- GitHub Actions 文档
- GitHub Copilot 文档
- 以及那篇让我相信这确实可行的博客文章:我把自己的工作自动化了(而这让我成为了更好的领导者)
I run marketing for GitHub in Japan and Korea, and events are the heartbeat of it: a recurring webinar series for enterprise developers, community meetups in Tokyo, invite-only executive sessions in Seoul. What does a developer in this market actually need right now? Which topics are worth an hour of their time, and who should be in the room? I’d happily spend all day on those questions.
What follows the decisions is another matter. Once an event is greenlit, a fixed sequence begins:
- Duplicate a landing page on our event platform.
- Generate a set of UTM-tagged links: one for each channel, each formatted just so.
- Draft the invitation email and file a request with the team that sends it.
- Add the event to two project boards.
- Every morning until the event: download the registrant list, clean it up, post a status update for stakeholders.
- After the event: export the attendees, reshape the list for a CRM upload, tag the right records, and write a report.
While none of these tasks are hard on their own, they’re an opportunity to paste the wrong link, skip a day, or misspell a campaign name that 15 downstream reports depend on.
Here’s the thing: I used to be an engineer. My first career was keeping databases alive on Linux servers for enterprise customers. While my coding may be rusty, I can still see a pipeline begging to be automated. This is where I put GitHub Copilot to use and where you could too in your own work.
So I didn’t write the code. I wrote down my runbooks, handed them to GitHub Copilot, and grew the automation in conversation. Today, an event I used to assemble by hand over a couple of days sets itself up from a single GitHub Issue, screens its own registrants every morning, and cleans up after itself when it’s over.
This post walks through how that works, and why I think anyone whose job involves repetitive work across tools that offer any scriptable way in (an API, or even just a CLI) can do the same.
An event is an issue
I can’t claim the foundational idea as my own. Marketing teams at GitHub already had a habit of opening one GitHub Issue per project. This becomes the place where the plan, the discussion, and the status live together. The issue was already our unit of work. What I did was make the issue do the work.
Three GitHub primitives carry the whole system:
- Issue forms are the application form. Instead of a blank text box, an issue form presents structured fields: event title, date, region, campaign name, target audience. We have one form per event type, such as webinars and in-person events, and they feed the same machinery.
- Labels are the switches. A label like
event-setupisn’t a tag, it’s a trigger. Each automation workflow starts with a condition that says, in effect, “only run when this label is present.” - Actions are the machinery. GitHub Actions workflows fire when labels land, parse the form fields out of the issue body, and go do the work.
Everything a repository gives developers, it gave my marketing workflow for free: history, visibility, review, and a URL for every decision.
One thing made this possible, and it has nothing to do with events specifically: our event management platform exposes an API. Our CRM doesn’t even need one; its official CLI covers everything we do, and I never configured an API key for it, because the CLI signs in through the browser and handles authentication from there. API or CLI, the requirement is the same: a scriptable way in. If your repetitive work runs through a tool that offers either an event platform, a CRM, a form builder, an analytics service, the pattern in this post applies to you.
A developer reading this may already be composing the obvious objection: isn’t this reinventing the wheel? Marketing automation platforms exist, and a good one might have covered some of this out of the box. But APAC is less one market than a collection of very different ones, and even within my own team, workflows shift with each sub-region and each segment. The same webinar might run in Japanese for Tokyo one month and in Korean for Seoul the next, with different segments, different fields in the CRM, and a different definition of a good lead. Getting a packaged tool to absorb all of those variations means customization budgets, consulting hours, and waiting on someone else’s roadmap. Building it ourselves, from the tools already at hand, means a workflow change is a pull request: I describe what I want, a reviewer checks it, and it lands on the main branch through exactly the process developers use to change software.
Planning an event is a conversation
The pipeline starts before the Issue exists. I open GitHub Copilot and say, roughly: “I want to run a webinar about AI-assisted development in November.”
What happens next is shaped by a file called AGENTS.md at the root of our repository. It’s our team runbook, written in plain Markdown, that defines how we name campaigns, how fiscal quarters map to dates, which time zone each region uses, and what a good invitation email looks like. GitHub Copilot reads it, and then, it finds a similar past event, proposes a campaign name that follows our naming rules, drafts two versions of the invitation email, and asks me the questions the runbook says to ask.
Putting a conversation at the front of the pipeline was itself a design decision, and it solved two problems at once. Automate everything, and you lose flexibility; the day you want this one event to be slightly different, a rigid pipeline has no place to say so. But if you let humans fill in everything, you get mistakes. The conversation sits exactly between the two. GitHub Copilot follows the template, so the data that lands in the Issue is the right data in the right format. And because it’s a conversation, I can bend the details for this one event without breaking the machinery downstream.
When we started, this conversation happened in GitHub Copilot CLI, in a terminal. That was fine for me, but “open a terminal” is a barrier for many people I’d love to bring into this workflow. With the GitHub Copilot app, the same conversation now happens in a regular desktop window. The barrier to entry dropped from “comfortable with a shell” to “can type.”
I want to be precise about the division of labor, because it’s the whole point: GitHub Copilot drafts; I decide. Every campaign name, every email subject line, every date gets my sign-off before anything moves. At the end of the conversation, GitHub Copilot files the GitHub Issue with the right labels, and that’s when the machines take over.
One label, one event, fully staged
The moment the event-setup label lands on the issue, a GitHub Actions workflow picks it up and does, in a few minutes, what used to take me the better part of a day:
- Duplicates a past event on our event platform to create the new landing page
- Generates the full set of UTM-tagged URLs: one per channel, consistently formatted, every time
- Produces the invitation email as a Word document and commits it to the repository
- Opens request Issues with the teams that send emails and track regional marketing
- Adds the event to our project boards and fills in the fields
- Posts a summary comment back on the Issue, so the next human who opens it sees everything in one place
Registration screening runs on a schedule instead of a label. Every morning, a cron-triggered workflow fetches the latest registrants for every open event and shares the cleaned-up list. For invite-only events, it also screens the waitlist against our criteria (is this registrant a developer at an enterprise account, a student, or a competitor who would very much like to attend our executive briefing?) before anyone gets approved.
The design decision I’m most proud of is a single on/off switch called DRY_RUN, stored as a setting (in GitHub terms, a repository variable) that every workflow checks before it runs. Flip it on, and every workflow goes through the motions without touching any external system: no landing pages created, no issues filed in other repositories, no lists shared. When you’re a team of marketers automating your own job, you need a way to rehearse. DRY_RUN is the rehearsal switch, and it’s the reason I was never afraid to experiment.
After the event, a slash command
Post-event work used to be the worst part: exporting attendees, reformatting columns for the CRM upload, matching company names against account records, and writing the report. Now it’s two commands.
/lead-upload fetches the attendee list, shapes it into the exact format our marketing operations team needs for a CRM upload, files the request Issue, and closes out the tracking issues. /event-report pulls attendance metrics and survey results and posts a report as a comment on the event’s Issue, back to the one URL where everything about this event lives.
These are GitHub Copilot agent skills, and here is the part I most want you to hear: a skill is a Markdown file. Each one is a SKILL.md: a written procedure, in prose, that tells GitHub Copilot what to do, in what order, and what to watch out for. Mine read like the runbooks I used to keep in my head, because that’s what they are.
If you can write a runbook, you can write a skill.
Skills are also what keeps the system flexible. No two markets in the Asia/Pacific (APAC) region run their follow-up identically. Audiences differ, segments differ, local conventions differ, and a hard-coded workflow would force every market into one shape. A procedure written in Markdown is flexible: each market can adapt the runbook to its own reality without touching the machinery underneath. That is precisely why the post-event steps live in GitHub Copilot skills rather than in fixed pipelines.
We treat skills like code in one respect: new ones arrive by pull request and get reviewed before they’re merged, with a CODEOWNERS file routing the review to a maintainer. Marketing automation with an approval process. The governance came free with the platform, too.
Built-in guardrails let me experiment
I automated a workflow that touches customer data and API credentials, in a repository my whole team can see, while barely writing code myself. Six months ago I would have said that combination was reckless. What changed my mind was realizing how many guardrails were already in place before I showed up.
Some guardrails I built: the DRY_RUN switch, a test suite that runs on every pull request, and code review for every change. Standard developer habits. It turns out they protect marketing work just as well as they protect software.
But the guardrails that mattered most came with the platform:
- Secret scanning with push protection. The nightmare scenario for someone in my position is committing an API token by accident. GitHub’s push protection blocks the push before the secret ever lands in the repository, and for GitHub’s own tokens, even one that does slip through gets revoked automatically.
- GitHub Copilot’s data policies. Registrant lists are business data, and the fixed scripts handle them in fixed ways. But real work is never entirely fixed; some days I need a one-off cut of the data that no script anticipates. Because GitHub Copilot’s business plans don’t retain prompts or use them to train models, I could ask for that one-off analysis directly, instead of doing what people all over the industry quietly do: pasting business data into whatever consumer chatbot is open in the next tab. The same goes for the models themselves: which ones I can use at all is set by organization policy, not left to my personal judgment, so even a one-off experiment runs inside boundaries the company has already decided. The safe path and the easy path were, for once, the same path.
One more thing the skills made possible, almost as a side effect: because each procedure is now a named, fixed unit of work, I can match the model to the job, choosing from the lineup our organization has approved. A fast, inexpensive model handles the daily list-cleaning; a stronger one drafts campaign copy.
And one honest failure, so you don’t repeat it: the morning screening workflow once failed silently for five days before anyone noticed the lists had gone stale. Automation you don’t monitor is more of a time bomb with a delay. Give every scheduled workflow a way to complain loudly so you don’t miss it.
Start with one task
Here’s what I’d suggest, from one recovering manual-worker to another.
Pick the single most repetitive task in your week. Then check whether the tools it touches have an API or a CLI. You may be surprised how many do.
Then build the smallest possible version: an issue form that captures the inputs, a label that means “go,” and an Action that does one step of the work. Or skip straight to writing your runbook down as a SKILL.md and let GitHub Copilot execute it. Run it with a dry-run switch until you trust it. Grow it from there.
I didn’t write the code. I wrote down what I already knew (how the work gets done) and the platform did the rest. Whatever your version of the morning registrant list is, it’s probably one written-down runbook away from doing itself.
Get started:
- Syntax for issue forms
- GitHub Actions documentation
- GitHub Copilot documentation
- And the blog post that convinced me this works: I automated my job (and it made me a better leader)