boring-new-app
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSet up a new app repository, end to end
端到端设置新的 app repository
You act for the maintainer (the person who owns the Factory). The result is a
repository where the expert's agent can start a feature and the Factory takes
it from there. Do every step yourself; ask the person only for the decisions
below and for what needs their browser.
你代表 maintainer(Factory 的所有者)执行操作。最终应得到一个 repository,使 expert 的 agent 可以在其中启动一个 feature,之后由 Factory 接手。所有步骤都要自行完成;仅针对以下决策以及必须由其浏览器处理的事项向对方询问。
0. Decide with the person (one message, all at once)
0. 与对方共同确定(一条消息中一次性确认)
- Repository: (new) — or an existing repository (then go to §6).
OWNER/NAME - Title of the app.
- Runtime: (a container on a host you own; agents run in the app) or
vm(a Worker with D1; its agents are declarative and run by the hub, no agent with code, no job). Defaultcloudflare.vm - Expert: their GitHub login. It must not be the bot's account (GitHub forbids approving your own pull request, and the bot opens contract PRs).
- Bot: the account whose token is (default: the maintainer).
FACTORY_TOKEN
- Repository:(新建)——或使用现有 repository(此时转到 §6)。
OWNER/NAME - Title:app 的标题。
- Runtime:(位于自有 host 上的 container;agents 在 app 中运行),或
vm(使用 D1 的 Worker;其 agents 为 declarative,由 hub 运行,不含带代码的 agent,也没有 job)。默认值为cloudflare。vm - Expert:其 GitHub login。不得使用 bot 的 account(GitHub 禁止 approve 自己的 pull request,而 bot 会开启 contract PR)。
- Bot:token 为 的 account(默认为 maintainer)。
FACTORY_TOKEN
1. Preconditions (check, fix what you can)
1. 前置条件(检查并尽可能修复问题)
bash
gh auth status # signed in as the maintainer, scopes repo + workflow
gh auth setup-git # git (and npx github:…) use gh's credentials
gh api repos/hachej/boring-factory --jq .full_name # read access to the factory
gh api repos/hachej/boring-app --jq .is_template # the app template: must print true
gh api repos/hachej/boring-factory/actions/permissions/access --jq .access_level # must be "user"If the access level is not , other repositories cannot call the
factory's workflows: .
usergh api -X PUT repos/hachej/boring-factory/actions/permissions/access -f access_level=userAsk the person to confirm once (cannot be checked with a token):
- the Claude GitHub App is installed with access to all repositories (https://github.com/apps/claude) — otherwise install it on the new repo;
- for Cursor workers: Cursor's GitHub integration sees the repository and on-demand usage is enabled (https://cursor.com/dashboard).
bash
gh auth status # signed in as the maintainer, scopes repo + workflow
gh auth setup-git # git (and npx github:…) use gh's credentials
gh api repos/hachej/boring-factory --jq .full_name # read access to the factory
gh api repos/hachej/boring-app --jq .is_template # the app template: must print true
gh api repos/hachej/boring-factory/actions/permissions/access --jq .access_level # must be "user"如果 access level 不是 ,其他 repository 就无法调用 Factory 的 workflows:。
usergh api -X PUT repos/hachej/boring-factory/actions/permissions/access -f access_level=user请对方一次性确认以下事项(无法通过 token 检查):
- Claude GitHub App 已安装,并且可访问 all repositories(https://github.com/apps/claude)——否则,需要在新建的 repo 上安装它;
- 对于 Cursor workers:Cursor 的 GitHub integration 能识别该 repo,并且已启用 on-demand usage(https://cursor.com/dashboard)。
2. The three secrets
2. 三个 secrets
Never print a secret; pipe it into .
gh secret set| Secret | Where it comes from |
|---|---|
| The bot's token. When the bot is the signed-in maintainer: |
| The maintainer's Cursor key (from your secret store) |
| Only the person: |
Export what you can before §3 so that sets them:
initbash
export FACTORY_TOKEN="$(gh auth token)"
export CURSOR_API_KEY="…" # read from your secret store, never echoed绝不要打印 secret;应通过管道将其传给 。
gh secret set| Secret | 来源 |
|---|---|
| bot 的 token。当 bot 是已登录的 maintainer 时: |
| maintainer 的 Cursor key(来自你的 secret store) |
| 只能由本人获取:在其机器上运行 |
在 §3 之前 export 可获取的变量,以便 设置它们:
initbash
export FACTORY_TOKEN="$(gh auth token)"
export CURSOR_API_KEY="…" # read from your secret store, never echoed3. Create the repository
3. 创建 repository
Dry run first, read the plan back to the person in three lines, then create:
bash
npx -y github:hachej/boring-factory init OWNER/NAME --expert EXPERT --bot BOT --title "TITLE" --runtime vm
npx -y github:hachej/boring-factory init OWNER/NAME --expert EXPERT --bot BOT --title "TITLE" --runtime vm --yesinitgh repo create --templatescripts/init-app.mjsdeploy/<runtime>/project.mdFACTORY_BOT@mainProduction is set up later, by hand, from in the
app; prints the commands. On Cloudflare the production token lives only
in the GitHub environment (restricted to ), never as a
repository secret, and previews use a separate account's token.
deploy/<runtime>/DEPLOY.mdinitproductionmain先执行 dry run,用三行向对方复述计划,然后再创建:
bash
npx -y github:hachej/boring-factory init OWNER/NAME --expert EXPERT --bot BOT --title "TITLE" --runtime vm
npx -y github:hachej/boring-factory init OWNER/NAME --expert EXPERT --bot BOT --title "TITLE" --runtime vm --yesinithachej/boring-appgh repo create --templatescripts/init-app.mjsdeploy/<runtime>/project.mdFACTORY_BOT@mainProduction 稍后根据 app 中的 手动设置; 会打印相关命令。在 Cloudflare 上,production token 只存放在 GitHub environment 中(限制为 ),绝不作为 repository secret;previews 使用另一个 account 的 token。
deploy/<runtime>/DEPLOY.mdinitproductionmain4. Verify, do not assume
4. 进行验证,不要想当然
bash
gh secret list --repo OWNER/NAME # the three names
gh variable list --repo OWNER/NAME # FACTORY_BOT
gh label list --repo OWNER/NAME --limit 100 | wc -l # 26 or more
gh api repos/OWNER/NAME/invitations --jq '.[].invitee.login'
gh run list --repo OWNER/NAME --limit 5The first run on :
cimain- is red, expected: the customising commit was pushed straight to
paths.main - must be green. If it is red, read
check, fix the cause in the template, hachej/boring-app, first (it will hit every new app), then in the app through a pull request.gh run view <id> --log-failed
bash
gh secret list --repo OWNER/NAME # the three names
gh variable list --repo OWNER/NAME # FACTORY_BOT
gh label list --repo OWNER/NAME --limit 100 | wc -l # 26 or more
gh api repos/OWNER/NAME/invitations --jq '.[].invitee.login'
gh run list --repo OWNER/NAME --limit 5mainci- 为 红色,且符合预期:用于定制的 commit 被直接推送到了
paths。main - 必须为 绿色。如果为红色,读取
check,先在 templategh run view <id> --log-failed中修复原因(该问题会波及每个新 app),再通过 pull request 修复 app 中的问题。hachej/boring-app
5. Hand over to the expert
5. 向 expert 交接
Send the person this, filled in:
Accept the invitation to OWNER/NAME, then on your machine:andnpx skills add hachej/boring-stack --skill boring-pm -g, open your agent (Claude Code, Codex or Cursor) inside the clone and describe what you want.gh repo clone OWNER/NAME
Tell the maintainer what to watch: the factory workflow in the Actions tab
(), triage's one comment per
event, and the checks and on each pull request.
context → ci → triage → checks → gates → buildboring/ciboring/proof向对方发送以下内容,并填入相应信息:
接受 OWNER/NAME 的邀请,然后在自己的机器上:和npx skills add hachej/boring-stack --skill boring-pm -g,在 clone 目录中打开你的 agent(Claude Code、Codex 或 Cursor)并描述你的需求。gh repo clone OWNER/NAME
告诉 maintainer 应关注什么:Actions tab 中的 factory workflow()、triage 针对每个 event 留下的一条 comment,以及每个 pull request 上的 和 checks。
context → ci → triage → checks → gates → buildboring/ciboring/proof6. An existing repository instead
6. 使用现有 repository
bash
npx -y github:hachej/boring-factory sync OWNER/NAME --dry-run
npx -y github:hachej/boring-factory sync OWNER/NAME --yes # labels + the "Adopt the Boring Factory" pull requestThe pull request adds only the files the repository lacks, copied from the
template (the caller, forms, PR template, CODEOWNERS, the ask
rules, ). Fill and in on its branch,
merge it by hand once (the Factory is not active before it lands), then §2, §4,
§5. It is a one-shot adoption: nothing is tracked or bumped afterwards.
factory.ymlproject.mdsetupcheckproject.mdbash
npx -y github:hachej/boring-factory sync OWNER/NAME --dry-run
npx -y github:hachej/boring-factory sync OWNER/NAME --yes # labels + the "Adopt the Boring Factory" pull request该 pull request 只会添加 repository 中缺少的文件,这些文件从 template 复制而来( caller、forms、PR template、CODEOWNERS、ask rules、)。在其 branch 上填写 中的 和 ,手动 merge 一次(在合并落地前 Factory 不会激活),然后执行 §2、§4、§5。这是一次性 adoption:之后不会跟踪任何内容,也不会进行版本升级。
factory.ymlproject.mdproject.mdsetupcheckWhen something fails
出问题时
| Symptom | Cause | Fix |
|---|---|---|
| A factory bug or a token without access | Read the exact path in the log; if the token is fine, fix it in boring-factory's main (apps call it at |
A job says it cannot use | The factory's workflows are not shared | §1, access level |
| A template bug | Fix it in hachej/boring-app, then in the app |
| An agent or chat with | Make the agent declarative, or choose |
| Triage or the claude worker never runs | | §2 |
| The expert cannot approve the contract PR | The expert is the bot's account | Use another account for the expert |
| A Cursor task fails at once | Cursor quota or GitHub integration | Enable on-demand usage; connect the repo; or label the task |
| git has no credentials | |
Fix the cause in boring-factory (the process) or hachej/boring-app (the
template) when it is theirs, so the next app does not hit it; never patch only the app.
| 症状 | 原因 | 修复 |
|---|---|---|
| Factory bug,或 token 没有访问权限 | 读取 log 中的确切路径;如果 token 没问题,则在 boring-factory 的 main 中修复(apps 以 |
Job 表示无法使用 | Factory 的 workflows 未被共享 | §1,access level |
新 app 上的 | Template bug | 先在 |
Cloudflare app 上的 | Agent 或 chat 包含 | 将 agent 改为 declarative,或选择 |
| Triage 或 claude worker 一直不运行 | | §2 |
| Expert 无法 approve contract PR | Expert 是 bot 的 account | 为 expert 使用另一个 account |
| Cursor task 立即失败 | Cursor quota 或 GitHub integration | 启用 on-demand usage;连接 repo;或将 task 标记为 |
| Git 没有 credentials | |
如果原因属于 boring-factory(process)或 hachej/boring-app(template),就在相应位置修复,让下一个 app 不会再次遇到该问题;绝不要只 patch app。