myorch Flow manual
This manual covers each flow: what it does, when to use it, what each step does, and when it needs you. The platform itself (services, architecture, commands, project packs, flow syntax) is in the User manual.
Each flow has one chapter. The input table, the step graph and the step details in a chapter are generated from flows/*.yaml. They match what myorch expand and the console Flows (流程) page show, so they cannot drift from the flow definition. The rest of the text is written by hand: the Chinese original next to the flow in flows/<flow>.md, this English version in docs/en/flows/<flow>.md. After you change a flow or its .md, regenerate (it writes the English and the Chinese manual):
uv run --with markdown python docs/workflows/build.py
One set of flows for every project
Each role has one flow (flows/development.yaml, review.yaml and so on), shared by all projects. The differences between projects live in the project pack myorch-knowledge/<project>/. They take effect when the flow is expanded; you do not pick them when you start a run:
flows.developmentinproject.yaml: how heavy review is (reviewers,max_rounds,security,on_exhausted), whether to commit a takeaway (takeaway), and whether there is anincidentinput (incident). When not set, the defaults are: 3, 3, true,ask, false, false.prompts/<slot>.md: the project's own prompt rules. The slots aredevelop,review,verify,fix,risk. At expansion the text is appended verbatim to the prompt of the matching step: the template's first, then the project's.jira: when the project has Jira, the development flow has a ticket input andfetch-ticket, and the ticket is the requirement. Without Jira, the first message is the requirement.if:in a flow drops steps and inputs per project. Dropped inputs do not show in the form.
| Project | flows.development |
prompts/ |
Jira |
|---|---|---|---|
| mdm (Cookbook, master-data-management) | Defaults, plus takeaway: true |
develop.md and review.md from the core-ng template (Gradle dependencies, *-interface contracts) |
Yes (MD) |
| blog (personal blog) | reviewers: 1, max_rounds: 1, security: false, on_exhausted: accept |
develop.md, review.md (Jekyll, writing rules, accidental publishing) |
No |
| myorch (the platform itself) | Defaults, plus incident: true |
develop.md (incident cause analysis, the platform's design checks, what to do after merging), risk.md |
No |
- How each project goes through the development flow: see Differences by project in development.
- To change how one project works, change its project pack, then run
uv run myorch project sync <project>. Changing a flow or fragment underflows/affects all projects. - A flow file starts with
role:. myorch recognizes flows by role, not by name. For example, Continue on this branch (在这个分支上接着改) works for any run of the development role, and eval replay uses the flow of the eval role. - Between 2026-11-03 and 2026-11-10, flows were copied per project (prefixes
ck-,blog-,mo-). They are now merged into one set; the reasons are in docs/notes/2026-11-10-one-set-of-flows.md. Old runs (for exampleck-development-…) can still be viewed and continued.
Roles
| Role | Task in the console | Purpose | What it writes outside | Flow |
|---|---|---|---|---|
development |
Development (开发) | From requirement to pushed branch: requirement, implementation, review, approval, push the branch | Pushes the branch after approval. Opens no PR, does not push the base branch | development |
review |
Review PR (评审 PR) | Reviews an existing PR; the verdict shows in the console | Nothing. Only reads the PR | review |
postmortem |
Postmortem (复盘) | A problem already got into the code: find the change that introduced it and the layer that should have caught it, improve knowledge, create eval cases | Only the local myorch-knowledge |
postmortem |
sweep |
Find bugs (找 bug) | Finds bugs in existing code, one batch of files at a time; produces only a daily report | Nothing | sweep |
learn |
Learn (学习) | Builds knowledge from past runs: improves guide/, records decisions people made, adds deterministic checks |
Only the local myorch-knowledge |
learn |
eval |
Eval (评测) | Replays an eval case and scores the reviewers | Nothing | eval |
onboard |
Onboard project (接入项目) | Analyzes the repository, trial-runs the checks, proposes changes to the project pack | Only the local myorch-knowledge |
onboard |
Which flow to use when
| Situation | Use |
|---|---|
| There is a requirement to implement | development |
| The change is pushed and your own testing found a problem, or you want to change more on top of it | development, continue on the same branch |
| A PR needs a look | review |
| After a few runs, review keeps reporting the same kind of problem or keeps missing the same kind | learn |
| A new repository is added, or a repository's structure changed | onboard |
| You want to look for bugs in old code regularly | sweep, run nightly with myorch schedule |
| You changed a reviewer's prompt or model and want to know if it got better or worse | eval |
| A problem is already fixed and you want to know why it was not caught | postmortem (fix the bug itself with development) |
| The platform itself had a problem (in a run of any project) | development on the myorch project, with incident |
Starting a run
| Where | How |
|---|---|
| Console http://127.0.0.1:8800/ | + New run (+ 新运行) in the top bar: pick the project, then the task (one button per flow of this project), fill in the fields, and write the request in the first message |
| Slack | /myorch opens the start dialog: pick the project, then it lists the project's flows; the fields are the same as in the console. Once the run starts, the bot opens a thread for it in your DMs |
| Local Claude Code session | Start with the channel tool start, for example to start development on the myorch project after finding a platform problem. Runs it starts push their events to that session |
| Command line | uv run myorch run flows/<flow>.yaml --project <project> -i name=value. For the commands see User manual · 5. CLI reference |
| Schedule | uv run myorch schedule add <name> --flow <flow name, for example sweep> --project <project> --cron '…', for example a nightly sweep or a weekly learn |
- The fields are defined by the flow file's
inputs: label, hint, whether required, type. The types are text, message, dropdown, ticket number (MD-18700and18700both work) and run (picked from this project's finished runs). Each chapter's Inputs table lists them. - What goes in the message box is also defined by the flow and can differ by project. For development on a project with Jira (mdm), the requirement is in the ticket and the message is an optional note. blog and myorch have no tickets, so the message is the requirement and is required.
- A ticket input, and ticket numbers in inputs, become tags on the run automatically. The run list can be searched by tag.
- Before starting, the client reads the flow, picks parameters by presets, expands fragments, fills in project values, and checks. Mistakes are reported right away and the run does not start. To see the expanded result first:
uv run myorch expand flows/<flow>.yaml --project <project>.
Where you step in
A flow stops and waits for you in the places below. The Waiting on you list (等你处理) in the console top bar and uv run myorch list both list them. The Slack thread has the same buttons. In the step graph, amber cards and the May ask you (可能问你) marker show these places.
| When | Console / Slack | Command line |
|---|---|---|
| An agent asks a question | Reply in the conversation. In Slack, click an option button or reply in the thread | myorch reply <run> <step> "answer" |
| A loop runs out of rounds and the problem is not solved | Read the reflect step's proposal first, then reply 1 to run one more round, 2 to accept, 3 to stop | myorch reply <run> <loop> 1 |
| Choosing proposals (learn, onboard, postmortem and others) | Reply with numbers, for example 1,3, all, none |
myorch reply <run> choose "1,3" |
| Approval | First read the Changes (改动) tab in the right pane (diff, review verdict, risk verdict), then click Approve (批准), Request changes (提修改意见; write your comments in the input box first) or Reject (驳回). Slack has three buttons: Approve, Request changes (要求修改), Reject | myorch review <run> to see the material, then myorch approve, myorch changes or myorch reject |
| You do not want it to continue | Cancel (取消) | myorch cancel <run> |
| It failed and the cause is fixed | Re-run failed steps (重新执行失败的步骤), or Re-run from this step (从这一步重新执行) on a step. The same run continues; succeeded steps keep their results | myorch resume <run> |
- A question that waits too long times out and fails. The default is 24 hours.
- An approval is bound to a commit. If the code changes after approval, delivery refuses to push and the run must be redone.
- Request changes sends the run back to the loop before approval (for example
review-fix) for one more round. Your comments go to the fixing agent. - A local Claude Code session can answer questions and resume from a failed step. It cannot approve.
Continue on the same branch
Use this after a development run has finished: your own testing found a problem, or you want to change more on top of this change. Open that run in the console, click Continue on this branch (在这个分支上接着改), and write what to change this time in the first message. On the command line use -i from_run=<run ID>.
- The chosen run must be finished, belong to the same project, and have the development role. If no ticket number is given, the previous one is reused.
- The new run uses the same branch name. The push updates the same branch, so a PR a person opened updates too.
- It starts from the last commit of that branch. If someone added commits to the remote branch, it starts from the latest remote commit. If the two have diverged, it stops and a person must sort it out first.
- The previous run's requirements, design, implementation record, risk verdict, delivery note and last-round review verdict are put in
docs/previous/. The agent writes on top of them and states separately what changed this time. Earlier runs are indocs/previous/earlier/, nested one inside another. - What people said to the previous run is in
docs/previous/conversation.md: the agent's questions and the answers, change requests, comments given on approve or reject, and failures and re-runs. The event log is on the host and the sandbox cannot read it, so the host writes this file into the new run when it starts (the same for command line, console and Slack). The agent treats it as human decisions; where it conflicts with assumptions in the previous documents, it wins. - Implementation, review and approval then proceed as usual. Review round 1 looks only at the commits added this time; checks and the risk verdict look at the whole branch's changes against base. Details are in Continue in development.
Reading the step graph
- Top to bottom is execution order. Steps on the same row run in parallel. When a card does not wait for every step on the row above, the card says "Waits for …" (等 …) underneath.
- The second line of a card is the executor: agent (model · profile), script (profile), host action (a registered deterministic action that does not run in a sandbox), or approval. The profile sets the sandbox's permissions; see User manual · 7. Project packs.
- Cards with a blue bar on the left are agents. Hatched cards are host actions. Amber marks where you are needed: approval cards and steps marked May ask you (可能问你).
- A dashed outer border marks a conditional step or loop. Hover over conditional (有条件) to see the expression.
- A box is a loop: its title says the maximum number of rounds, when it stops, and what happens when it runs out of rounds. The reflect step at the bottom runs only when the loop is exhausted and it is to ask you; it gives a proposal.
- "×3 parallel" (×3 并行) means three instances of the same step (for example 3 reviewers).
- The graph is expanded for mdm with default inputs (mdm's development flow has the most steps). For another project, the project pack may drop some steps or change parameters (for example blog's review has only 1 reviewer), and project values in conditions may differ. Use
myorch expand flows/<flow>.yaml --project <project>or the console Flows (流程) page to see the expansion for a given project. Open Executor, condition and outputs of each step (每一步的执行者、条件、输出) below the graph to see the full expressions.
Changing a flow
- Change
flows/<flow>.yamlor a fragment. The syntax is in User manual · 8. Writing flows. - Run
uv run myorch expand flows/<flow>.yaml --project <project>to see the expanded result. - Update
flows/<flow>.mdanddocs/en/flows/<flow>.mdto match, and regenerate this manual. - Run
uv run pytestonce. When the worker and console run in compose,docker compose -f deploy/compose.yaml up -d --buildmakes them load the new flow.
Source of this page: docs/en/workflows/README.md
development Development
| File | flows/development.yaml, prose docs/en/flows/development.md |
| Role | development (the console task “Development”) |
| Projects | shared by every project |
| In short | From requirement to PR: requirement analysis, technical design, implementation, review by several reviewers, risk approval. The branch is pushed and the PR opened only after approval. |
| Fragments | lib/sync-base.yaml, lib/review-loop.yaml, lib/deliver.yaml |
The development flow: from one requirement to a pushed branch. All projects share this one flow. In one session it writes the requirements, the technical design and the code changes. The change then goes through review, a risk verdict and human approval. Finally the approved commit is pushed to this run's branch. myorch opens no PR and does not merge: a person opens the PR on GitHub and decides on merging. Before approval the change does not leave the sandbox and nothing is pushed.
The differences between projects are all in the project pack; you do not pick them when you start a run (see Differences by project):
- How heavy review is: how many reviewers, at most how many rounds, whether there is a separate security review, what happens when the loop runs out of rounds (
flows.developmentinproject.yaml). - Whether there is Jira: if so,
fetch-ticketreads the ticket first and the ticket is the requirement. If not, the first message is the requirement. - Whether to commit the task info and lessons (takeaway) to the repository's
myorch/directory (flows.development.takeaway). - Whether there is an
incidentinput: when the platform had a problem, the failing run is attached fordevelopto look at (flows.development.incident). - The project's own prompt rules (
prompts/develop.md,review.md,verify.md,fix.md,risk.md). At expansion their text is appended verbatim to the prompt of the matching step.
uv run myorch run flows/development.yaml --project mdm -i ticket=18700
uv run myorch run flows/development.yaml --project mdm -i ticket=18700 -i task="Backend API only; the frontend gets its own ticket"
uv run myorch run flows/development.yaml --project blog -i task="Add a word count to article pages"
uv run myorch run flows/development.yaml --project myorch -i task="..." -i incident=development-1a2b3c4d
uv run myorch run flows/development.yaml --project mdm -i from_run=<previous run ID> -i task="Found in testing: bulk import does not validate"
uv run myorch run flows/development.yaml --project mdm -i ticket=18700 -i at=<the PR's merge-base> -i ticket_as_of=2026-10-01T08:00:00Z
Console: pick the project first, then the task Development (开发). The form shows only the fields this project uses.
- Projects with Jira (mdm): fill in the ticket number (
MD-18700or18700). The first message is an optional note: write the key points and constraints that are not in the ticket. - Projects without Jira (blog, myorch): the first message is the requirement. It is required and can span several lines.
- myorch: when the platform had a problem in some run, put that run's ID in Failing run (出问题的运行). When a local Claude Code session finds a platform problem, it also starts the run with the channel tool
start, and the first message describes what was seen and a first analysis.
The first line of the message becomes task. The full text is written to docs/external/request.md.
Inputs
| Input | Label | Type | Required | Default | Description |
|---|---|---|---|---|---|
ticket | Jira ticket | ticket | For example 18700. The first step reads the ticket shown only for projects where project.jira.url holds | ||
from_run | Starting point | run | |||
task | Requirement | message | depends on the project: not project.jira.url | What to change, as specific as possible; several lines are fine. With a ticket, the ticket is the requirement; write here only what it does not say: focus, limits, things to watch | |
incident | Run with the problem | text | The run where the problem happened, for example development-1a2b3c4d. Leave empty if there is none shown only for projects where project.flows.development.incident holds | ||
at | Replay: base commit (for evals) | text | Normally empty. When an eval replays a past ticket, the PR's merge-base: start from this commit, drop the later history, no approval, no delivery shown only for projects where project.jira.url holds | ||
ticket_as_of | Replay: ticket cut-off time (for evals) | text | Normally empty. An ISO time, for example 2026-10-01T08:00:00Z: the ticket is read as it was at that moment (description rolled back, only earlier comments kept) shown only for projects where project.jira.url holds | ||
ticket_comments | Ticket comments | options: all / none | all | shown only for projects where project.jira.url holds |
Step graph
Generated from flows/development.yaml, expanded for project mdm with default inputs (another project's pack may leave steps out or change parameters); the same as myorch expand and the console's Flows page (流程).
steps.verify.outputs.blocking == 0 · asks you when out of rounds · lib/review-loop.yaml · conditionalEach step's executor, condition and outputs (generated from the YAML)
| Step | Runs as | Condition | outputs | People and parallelism | Limits |
|---|---|---|---|---|---|
sync-master | script · dev-git | on failure ask | timeout 15m · retries 1 | ||
checkout-branch | script · dev-git | since | on failure ask | timeout 30m | |
fetch-ticket | script · ticket-read | inputs.ticket | key, summary_line | on failure ask | timeout 5m · retries 1 |
develop | agent · Opus · dev-write | title, proceed, impact, requires_design_decision, design_question, design_options, checks_passed | can ask you questions; on failure ask | timeout 75m · retries 1 | |
Loop review-fix: up to 3 rounds, until steps.verify.outputs.blocking == 0, asks you when out of rounds. Condition steps.develop.outputs.proceed != false. Fragment lib/review-loop.yaml | |||||
ci | script · dev-write | on failure ask | timeout 15m | ||
review | agent · Sonnet · dev-read | findings | 3 instances in parallel; on failure ask | timeout 20m | |
security | agent · Sonnet · dev-read | findings | on failure ask | timeout 20m | |
verify | agent · Opus · dev-read | blocking, nits, pre_existing | on failure ask | timeout 20m | |
fix | agent · Opus · dev-write | steps.verify.outputs.blocking > 0 | pack_proposals | on failure ask | timeout 30m |
pack-choose | script · dev-read | steps.fix.outputs.pack_proposals > 0 | accepted | can ask you questions; on failure ask | timeout 30m |
pack-apply | host action · project-apply | steps.pack-choose.outputs.accepted > 0 | on failure ask | timeout 30m | |
reflect | agent · Opus · dev-read | recommendation, reason | on failure ask | timeout 15m | |
takeaway-trail | host action · run-trail | steps.develop.outputs.proceed != false and not inputs.at | on failure skip | timeout 2m | |
takeaway | agent · Sonnet · dev-read | steps.develop.outputs.proceed != false and not inputs.at and steps.takeaway-trail.outputs.path | items | on failure skip | timeout 10m · retries 1 |
takeaway-redact | host action · takeaway-redact | steps.develop.outputs.proceed != false and not inputs.at and steps.takeaway.outputs.items != null | on failure skip | timeout 2m | |
takeaway-commit | script · dev-write | steps.develop.outputs.proceed != false and not inputs.at and steps.takeaway-redact.outputs.files > 0 | dir | on failure skip | timeout 2m |
risk-rules | script · dev-read | steps.develop.outputs.proceed != false | on failure ask | timeout 30m | |
classify-risk | agent · Sonnet · dev-read | steps.develop.outputs.proceed != false | approvers, risk | on failure ask | timeout 15m |
human-review | approval · count set by risk | steps.develop.outputs.proceed != false and not inputs.at | approvers min(steps.risk-rules.outputs.available, max(steps.risk-rules.outputs.approvers, min(steps.classify-risk.outputs.approvers, 2))); changes can be requested: runs review-fix again; on failure ask | timeout 30m | |
deliver | script · dev-git | steps.develop.outputs.proceed != false and not inputs.at | delivery | on failure ask | timeout 10m · retries 1 |
The graph above is expanded for mdm, which has the most steps. blog and myorch have no fetch-ticket and none of the four takeaway steps. blog's review loop has only 1 reviewer and no security.
What each step does
| Step | What it does | Artifacts |
|---|---|---|
sync-master |
Clones or updates the repository, force-aligns with origin/<base>, initializes submodules. The first clone goes through the mirror repository in the project's shared directory; after that only increments are fetched (lib/sync-base.yaml) |
outputs.base_sha |
checkout-branch |
Creates this run's branch. The branch name comes from the project pack's branch (mdm: MD-<ticket number>-myorch-<run ID>; blog and myorch: myorch/<run ID>). Runs the project's setup.sh. When continuing, it switches to the previous run's branch; when replaying, to at. See the two sections below |
outputs.branch, outputs.since |
fetch-ticket |
Only when the project has Jira. Reads the ticket with the Jira REST API (read-only), writes it as docs/external/ticket.md, downloads screenshots. See "Reading the ticket" |
docs/external/ticket.md, docs/external/attachments/ |
develop |
Does it all in one session: writes the requirements document, writes the technical design, asks all questions that need a human decision at once, changes the code, runs the checks, writes the implementation record, commits once. See "develop" | docs/requirements.md, docs/design.md, docs/implementation.md, one commit |
review-fix loop |
ci (the project's checks.sh) → review (count per project) and security in parallel → verify checks the findings and computes blocking → fix (only when blocking > 0) → pack-choose, pack-apply (only when fix proposed project pack changes). The number of rounds and what happens when they run out depend on the project. See "The review loop" |
docs/ci/round-N.md, docs/review/round-N/ |
takeaway-trail |
Only with flows.development.takeaway (mdm). Host action: writes the run's history so far to docs/takeaway/trail.json |
trail.json |
takeaway |
Same condition. Read-only agent: writes the task info task.md and the lessons takeaway.md |
docs/takeaway/task.md, takeaway.md |
takeaway-redact |
Same condition. Host action: deletes lines that look like secrets from the two files | |
takeaway-commit |
Same condition. Commits the two files to the repository at myorch/<date>-<run ID>/ |
one commit |
risk-rules |
Computes the number of approvers by rules: changed paths and content, unresolved review findings, failed checks, commits that were not reviewed | outputs.approvers, head_sha and others |
classify-risk |
Reads the actual diff, judges independently how many approvers are needed, writes a risk note for the approvers | docs/risk.md |
human-review |
Human approval. For the number of approvers see "Risk and approval". Passes automatically when the number is 0 | |
deliver |
Checks that HEAD is the approved commit, pushes the branch, writes the delivery note | docs/delivery.md, outputs.delivery |
- When
developdecides no code change is needed (proceedis false), all later steps are skipped and the run ends normally. - For projects without takeaway, the four steps are removed at expansion, and
risk-ruleswaits directly onreview-fix. - The flow sets
on_failed: askat the top level: when a step still fails after retries, it asks you.
Where you step in
| When | Console | Command line |
|---|---|---|
develop asks before changing code |
Reply in the conversation, or click an option | myorch reply <run> develop "answer" |
| Adopting project pack changes | Reply with numbers, for example 1,3, all, none |
myorch reply <run> pack-choose.r<N> "1,3" (N is the round) |
Review runs out of rounds with blocking findings left (projects with on_exhausted: ask) |
Read the reflect proposal, reply 1, 2 or 3 | myorch reply <run> review-fix 1 (1 runs one more round, 2 accepts the current result, 3 stops) |
| A step still fails after retries | Reply 1, 2, 3, or write a hint | myorch reply <run> <step> 1 (1 starts over in a new session, 2 skips, 3 stops. Any other text is a hint, and the step continues in the same session) |
| Approval is needed | Read the diff, review verdict and risk verdict on the Changes (改动) tab in the right pane, click Approve (批准), Request changes (要求修改) or Reject (驳回) | myorch review <run> opens the summary page; myorch approve <run> human-review, myorch changes <run> human-review "comments", myorch reject <run> human-review |
| After the push | — | Open a PR on GitHub from the pushed branch (the delivery note can serve as the PR description) and decide whether to merge. For the myorch project, a release follows the merge; see "myorch: after merging" |
When any of the four takeaway steps fails, you are not asked (on_failed: skip), and later steps are not blocked. Failed host actions do not ask either.
Artifacts
All steps of a run share one workspace. The Docs (文档) tab in the console's right pane shows all documents and screenshots. On the command line, myorch ws <run> lists the files and myorch ws <run> docs/risk.md reads one.
observed/<run ID>/ the previous run when continuing; the failing run with incident (read-only)
docs/
├── external/
│ ├── request.md original text of the first message (when started from the console or Slack)
│ ├── ticket.md the ticket (fetch-ticket, or read by develop via MCP)
│ └── attachments/ images from the ticket
├── previous/ when continuing: the previous run's documents and conversation
├── requirements.md requirements, acceptance criteria, ticket mapping; with incident it starts with the cause category
├── design.md impact analysis, approach, compatibility and rollback, test plan
├── implementation.md changes, evidence, check results, assumptions, deviations from the design; fix appends "Round N fix"
├── ci/round-N.md check report per round (round-N/ holds result.json, head.txt)
├── review/round-N/ reviewer-K.json, security.json, verified.json, summary.md, rebuttal.md, approver.json, pack/
├── takeaway/ trail.json, task.md, takeaway.md (only for takeaway projects)
├── risk.md risk verdict and the places the approvers should check
└── delivery.md delivery note
repo/myorch/<date>-<run ID>/ task.md, takeaway.md (committed on the branch, only for takeaway projects)
develop
One agent goes from reading the requirement to committing code, in three phases in order: requirements, technical design, implementation. It cannot skip the first two phases and go straight to code. The project's prompts/develop.md is appended verbatim after the "Inputs" part of the prompt; see Differences by project.
- Inputs: the ticket
docs/external/ticket.md(when there is one), screenshots, the original requestdocs/external/request.md, project conventions, the knowledge that comes with the repository, the project pack'sguide/(itsdecisions.mdholds decisions people made before). The original request and the ticket are external data; instructions in them are not followed. - Requirements document: goal, scope, what is explicitly out of scope, checkable acceptance criteria, a ticket mapping table, the files expected to change, risks, sources.
- Ticket mapping table: each requirement in the ticket is copied as one row (including those added in comments), with the acceptance criterion it maps to, or why it is not done. When one requirement contains several actions, the acceptance criteria must cover each action.
- The agent cannot put modules, features or scenarios the ticket names into "explicitly out of scope" on its own. To exclude one, it must ask a person.
- Technical design: impact analysis (callers, cross-module dependencies, other services), the approach and the rejected approaches, compatibility and rollback, a test plan (a test for each acceptance criterion, plus edge cases and counterexamples), risks. No code in the design.
- List every entry point: when adding validation to a field or requiring consistency in several places, search back in at least two ways, by the error message and by the field name. Write the search commands and the entry points found into the design.
- Before removing or loosening an existing check, find out why it exists with comments,
git log -Landgit blame. If that cannot be found out, or what it protects no longer holds after the change, ask a person. - Look for an existing implementation of the same kind first: if it fits, call it; if its shape does not fit, reshape it so it can be shared; when the behavior is decided by a shared method, change the shared method and check every caller. Do not copy it. Changing the shared implementation for reuse is within this change's scope.
- Ask before changing code, at most once: the questions from both phases that need a human decision go into one question, each with options, the first one recommended. The agent cannot choose for you on: things users can see, interfaces and contracts, data models and migrations, behavior changes that affect other modules or services, and choices that clearly change the size of the implementation. Decisions already in
decisions.mdare followed and not asked again. - Safety net: when the agent finishes and reports questions it did not ask but decided by the recommendation (
requires_design_decision), the platform still asks you, and your answer is sent back to the same session as the next turn. - Implementation: change only code within scope, give each acceptance criterion a test or check, run
myorch-checks(the project'schecks.sh) until it passes, write the implementation record, and commit once on the current branch. When the check report lists failures under "Environment" (环境) (network or system limits of the sandbox), they are not code problems: commit as usual and note them in the implementation record. - Stop: when the requirement contradicts the code, when code outside the scope must change, or when checks fail because of the code and cannot be fixed, it does not commit. The step fails and then asks you what to do.
- It may decide no change is needed: the feature already exists, or you decide not to do it. No documents are written and everything after is skipped.
Why one step: when these were separate, every handoff lost information. The steps with credentials (sync-master, fetch-ticket, deliver) still run separately; develop gets no GitHub or Jira credentials.
Reading the ticket
- Condition: the project sets
jira.url(mdm:example.atlassian.net, prefixMD) and a ticket number is given. When only digits are given, the project's prefix (jira.key) is added. Projects without Jira have no ticket input and nofetch-ticketstep. - Read-only: the credentials are the project's Jira provider (mdm:
jira-mdm). The egress rules allow only reading tickets, reading attachment content, and/myself. The sandbox holds only a placeholder; the gateway swaps in the real token. - Content: title, type, status, priority, reporter, assignee, labels, components, parent ticket, linked tickets, description, subtasks, attachment list, comments. The file states at the top that it is external data.
- Screenshots: only image attachments are downloaded, at most 10, each at most 5 MB, saved to
docs/external/attachments/<id>-<file name>. The "Attachments" (附件) section ofticket.mdlists the paths, anddevelopopens them with Read.!file name!in the description refers to these images. Other attachments are listed by name only. A failed download does not affect the run. The console's Docs (文档) tab also shows these images. - Comments:
ticket_commentsdefaults toall. Withnone, comments are left out and only the description is used (for evals: the requirement should be in the ticket, not depend on comments). - MCP fallback: when
fetch-ticketdid not run (the project has nojira.url) and the run has an MCP knowledge source that can read tickets,developfirst reads the ticket via MCP and writes the samedocs/external/ticket.md, noting the source at the top. If it cannot read it, it says so in the summary and continues from the original request. mdm does not attach the Atlassian MCP by default at the moment.
The review loop
Defined in the fragment lib/review-loop.yaml. review and eval use it too (one round only, no fixing). The parameters here come from the project's flows.development: by default 3 reviewers plus a separate security review, at most 3 rounds, and it asks you when it runs out of rounds. The project's prompts/review.md, verify.md and fix.md are appended to the matching steps.
- What each round looks at: round 1 looks at the whole change (when continuing, only this run's new commits); each later round looks only at the commits since the previous round started.
cicomputes the range and writes it todocs/ci/round-N/head.txt. - Judge independently first, read the author's account last: a reviewer first looks only at the requirements document, the technical design and the diff, and finds problems on its own. Only then does it read the implementation record and check that the tests and checks listed there really exist and the assumptions hold. A reason given in the implementation record is no excuse to let a problem pass.
- Check the requirements document against the original ticket: the requirements document is also written by the author. Leaving out, narrowing or rewriting a ticket requirement, a ticket mapping table that covers only some of the actions, or moving something the ticket names out of scope on its own, all count as Important.
- Look in the repository: three kinds of problems that the diff alone does not show always count as Important:
- Not reusing an existing implementation of the same kind, or copying a branch of a shared method instead of changing it.
- Missed entry points: other places that read or write the same field or the same error message were not changed, and the design does not say why.
- An existing check was removed or loosened, breaking what it protected, and the requirements document does not say a person decided this.
- Division of work: reviewer 1 focuses on correctness and edge cases, reviewer 2 on acceptance criteria and tests, reviewer 3 on design, scope and reuse. Everyone checks for missed entry points and loosened checks. Projects with only 1 reviewer (blog) have only reviewer 1.
- Reading earlier steps' history:
fixandreflectcan use/sandbox/bin/myorch-stepsto read, in parts, the manifests and logs of this run's earlier steps (for example why develop did something). The reviewer and verify prompts do not mention it: they must judge independently first. Earlier steps' records (.myorch/, other steps'.claude/) are read-only for every step. - Rule markers: rules like "look in the repository", "judge independently first" and "at most 5 Nits" above were added because the model made those mistakes before. They are marked in the flow file with
[[rule:<rule>/<location>]], and the reason for each is recorded inrules/registry.yaml. At expansion the marker is removed and the text stays. Only a replay with--set flows.ablate=<rule>removes the whole rule, to evaluate whether the rule is still needed. - verify: merges duplicates, opens the code for each finding to confirm it, also confirms findings only one reviewer reported, and deletes those that do not hold. Deletes pure style comments and keeps at most 5 Nits. Each failed check counts as one Important; environment failures do not. Findings from the previous round are marked fixed, open or rebutted.
blockingis the number of unresolved Important findings; the loop ends when it is 0. - fix: fixes only Important findings, changes all places of one problem together, and leaves Nits alone. When it thinks a finding does not hold, or the fix needs a human decision, it does not change the code and writes it in
rebuttal.mdinstead (those needing a human decision start with "Needs a human decision:" (需要人决定:)); the next round's verify judges it. When the cause is in the project pack, it proposes a project pack change; see the next section. After fixing it runs the checks, appends "Round N fix" (第 N 轮修复) to the end of the implementation record, and commits once. - Running out of rounds: with
on_exhausted: ask(the default),reflectreads all rounds and judges whether it is an isolated problem, a wrong direction, something needing a human decision, or reviewers being wrong. It gives a proposal and then asks you: run one more round, accept the current result, or stop. Withaccept(blog) the flow goes straight on. The last round's fixes were never reviewed, andrisk-ruleslists those commits. - The approver requests changes: the comments are written into the next round's
approver.json. Each one counts as Important, and verify will not delete them.
Project pack changes (pack-choose, pack-apply)
Sometimes a blocking problem lies in the project pack, for example a mistake in checks.sh. The project pack is read-only in the sandbox (project/), so fix cannot change it. In that case:
fixdoes not changeproject/and does not write a rebuttal for it. It copiesproject/to/tmp, changes the copy, runs the relevant checks once with the copy, and writes the proposals todocs/review/round-N/pack/proposals.json(for machines) andproposals.md(for people, including the verification result).pack-chooselists the proposals and asks which ones you adopt.pack-applywrites the adopted changes back tomyorch-knowledgeon the host, commits only those files, and syncs the project snapshot again. The original text of each change must appear exactly once in the file; otherwise nothing is written and the step fails.- The next round of this run mounts the new snapshot and checks with the new project pack. Other runs are not affected. When the write-back happened in the last round, the reflect step proposes one more round.
Only files under guide/, checks.sh, checks.env and setup.sh can be changed (EDITABLE["fix"] in project.py). risk-rules.yaml and security.md cannot: a run must not change how its own changes are approved. To change other files, fix writes "Needs a human decision:" (需要人决定:).
Task info and takeaway
Only when the project sets flows.development.takeaway: true (currently only mdm): putting a myorch/ directory in the repository needs the project's consent. After the review loop and before the risk verdict, four steps commit this run's task info and lessons to the repository.
- Committed on the branch:
takeaway-commitcopiestask.mdandtakeaway.mdtorepo/myorch/<date>-<run ID>/(the date is the day the run started), commits only this directory, with the fixed commit messageAdd myorch task and takeaway for <run ID>. When the content has not changed, it does not commit again. It is visible at approval, is in the PR after the push, and reaches the base branch after merging; learn reads it from there. - Not blocking: all four steps have
on_failed: skip. A failure records a failure event, counts as skipped, and the flow goes on. Each step runs only when the previous one produced output, so stale or half-written files are never committed (takeaway-trailempties both files first). - trail: each step's status, summary, failure reason and retry count; questions and answers; each review round's blocking count and check results; branch, inputs, myorch commit, project pack version. Lines that look like secrets are deleted before writing.
- What takeaway writes:
task.mdholds only facts (ticket, run, inputs, requirements summary, questions and answers, each review round and its checks, the result).takeaway.mdholds the problems met, root causes, how they were solved, what knowledge was missing, and proposals for the flow or platform. Each item is tagged with a category (project knowledge, flow, platform, environment) and gives evidence. "What knowledge was missing" holds only project knowledge that would help with a different requirement too, not the answer to this ticket. The two files together are at most 200 lines. The agent has no knowledge sources attached and is read-only. - Reading the history: besides
trail.json,takeawaycan use/sandbox/bin/myorch-stepsto read each step's logs in parts, to find where things first went wrong. - No secrets: the two files go into the company repository.
takeaway-redactdeletes lines that look like secrets byknowledge.SECRET_RULES(the same rules as the knowledge source scan). When both files end up empty it fails, so the commit does not run. - How risk-rules sees this commit: it comes after the last review round, but it does not count as a "commit that was not reviewed": a commit with a single parent that changes only
.mdfiles undermyorch/is not counted. Merge commits are always counted.risk-rulestakeshead_shaafter this commit, so what you approve and what is pushed is the commit with these two files. - When it is not written: replays (
at) do not write it; otherwise the eval case's answer would get into knowledge. It is also not written whendevelopdecides no change is needed. A run that fails before approval cannot be pushed, so its lessons are not in the repository.
Risk and approval
Risk is decided by the change, not by the author. Two classifiers back each other up: rules may miss semantic risk, the model may miss path-based risk, and the stricter of the two wins.
risk-rules (deterministic script):
- The rules come from the project pack's
risk-rules.yaml(the template's rules plus the project's own). Of the rules that match, the strictest applies. Rules can match by path, by text in new files, or by a regex on changed lines. When no rule matches,defaultapplies. - At least 1 approver in any of these cases: the last review round still has unresolved Important findings; the last round's checks failed; there are new commits after the last review round (for example after accepting when the loop ran out of rounds, so nobody looked at the last round's fixes). The takeaway commit does not count; see the previous section.
- Outputs
approvers(the number the rules require) andavailable(the number of approvers registered for the project).
classify-risk (agent, read-only): reads the actual diff, the requirements document, the assumptions in the implementation record, the last review round and checks, and the commits that were not reviewed, and decides 0, 1 or 2 approvers. Any one of these means 2: changes to interfaces or data, changes to build or deployment, anything security-related, hard to undo, affects downstream. It writes docs/risk.md: the verdict, the impact, unresolved problems, and 3 to 5 places the approvers should check. The project's prompts/risk.md is appended to the end of the prompt (myorch uses it to require that the impact be written in terms of the platform's boundaries, unfinished runs, and deployment).
Number of approvers for human-review:
min(approvers registered for the project, max(risk-rules count, min(classify-risk count, 2)))
- All three projects currently register only one approver, so the number is at most 1.
- mdm: the core-ng template's default is 1. Database migrations, interface modules, build and dependencies, CI and deployment, environment config, entity field annotations and destructive SQL need 2. mdm's protos submodule needs 2 and spec documents need 1. So every run needs exactly 1.
- blog:
default: 1; every run needs 1. - myorch:
default: 0; the platform's boundaries (code for sandbox, credentials, profiles, deployment, scheduling and approval) need 2. When both judgments give 0 (for example only docs changed), approval passes automatically anddeliverpushes the branch right away. Only the branch is pushed; merging and deployment are done by a person. - The person who started the run must be one of the approvers (
require_initiator). An agent's approval does not count. - Approval is bound to a commit:
head_shais recorded when approval opens, anddeliverchecks it before pushing. - Request changes: back to
review-fix, at most 2 more rounds. Then takeaway, the risk verdict and approval run again from the start. - After 24 hours with no action, one reminder is sent. After 7 days with no action, the step fails ("approval timed out" (审批超时)) and nothing is pushed.
- If any approver rejects, the run ends.
Delivery
Defined in lib/deliver.yaml.
- It refuses to push when the current branch is the base branch. It refuses to push when HEAD is not the approved commit; the run must be redone and approved again.
- Pushes the branch (normal push, no force push). Does not call the GitHub API and does not open a PR.
- Writes
docs/delivery.md: title and ticket, what changed (taken from "Changes" (改动) in the implementation record), how it was verified (check results, acceptance criteria table), number of review rounds and unresolved problems, commits that were not reviewed, the risk verdict and the places to check, how to undo. outputs.deliverycarries the branch, base, commit, title, ticket, the delivery note and the repository's PR template. Therun_finishedevent carries it, and the console and Slack use it to tell you which branch was pushed. You open the PR.
Continue (from_run)
The general procedure is in Continue on the same branch. In this flow:
checkout-branchmounts the previous run's workspace read-only and starts from its last commit. If someone added commits to the remote branch of the same name, it starts from the latest remote commit. If the two have diverged, it stops and a person must sort it out first.- Files copied to
docs/previous/:requirements.md,design.md,implementation.md,risk.md,delivery.md,external-request.md(the previous original request), the last review round'sreview-summary.md, andRUNwith the previous run ID. Earlier runs are inearlier/.conversation.mdis written by the host: what people said to the previous run. develop's requirements document states the full requirement, with a separate paragraph "This change" (这次的修改) under "Goal" (目标). The previous acceptance criteria still hold unless this request changes them. The design is changed on top of the previous one. The code is changed on top of the existing commits, not redone. Human decisions inconversation.mdtake precedence over assumptions in the previous documents.checkout-branchoutputssince(the commit at the start of this run). Round 1 of the review loop looks only at commits aftersince; checks still run on the files the whole branch changed against base. The risk verdict looks at the whole branch.- It pushes to the same branch, so a PR that is already open updates automatically. If no ticket number or
incidentis given, the previous ones are reused. - Cannot be combined with
at.
Replay (for evals)
Used to redo an already merged ticket on the code as it was then, and compare with the merged PR. The form shows at, ticket_as_of and ticket_comments only for projects with Jira (on the command line, -i at= can be passed for any project). Leave them empty normally.
atis the PR's merge-base.checkout-branchcreates the branch from this commit, then deletes theoriginremote, all other refs,FETCH_HEAD, the reflog and borrowed objects, runs gc, and does the same for submodules. Later commits would leak the answer, so only history reachable fromatstays in the repository. Finally it pointsorigin/<base>atat, so every later diff uses it as the base.ticket_as_ofis the moment work on the ticket started (ISO time).fetch-ticketuses the ticket's changelog to roll title, description, status, priority and assignee back to that moment. It keeps only earlier comments, attachments and linked tickets, and leaves out subtasks (subtasks may contain the solution).- A replay never asks for approval and never pushes: the conditions of
human-reviewanddeliverincludenot inputs.at. Deletingoriginis a second safeguard. No takeaway is written either. The run ends afterclassify-risk. - Cannot be combined with
from_run;checkout-branchfails right away. - To find out whether the ticket description alone is enough, add
-i ticket_comments=none. - Comparisons: a replay can change this run's flow settings with
--set, for example--set flows.development.reviewers=1or--set flows.ablate=nit-cap(removes one marked rule; rule names are inrules/registry.yaml). Only existing settings underflows.can be changed, and only in replays. What was changed is recorded in the mandate, and the run gets aset:…tag so variants can be grouped.myorch expand --set …shows the changed prompt first.
Differences by project
There is only this one flow. Before 2026-11-10 each project had its own copy (ck-development, blog-development, mo-development). The same improvement had to be made three times, and the three copies soon diverged, so they were merged back into one (docs/notes/2026-11-10-one-set-of-flows.md). The differences between projects live in the project pack myorch-knowledge/<project>/ and take effect when the flow is expanded:
flows.developmentinproject.yaml:reviewers(default 3),max_rounds(3),security(true),on_exhausted(ask),takeaway(false),incident(false). A template can set them; the project overrides the template.prompts/<slot>.md: the slots aredevelop,review,verify,fix,risk. The template's comes first, then the project's, appended verbatim to the prompt of the matching step. The mandate's snapshot shows the assembled prompt. A file name that is not one of these slots is an error.if:in the flow: drops steps and inputs per project.fetch-ticket, the ticket input and the replay inputs depend onproject.jira.url; the four takeaway steps onflows.development.takeaway; theincidentinput onflows.development.incident. Dropped inputs do not show in the form and keep their defaults.
| mdm | blog | myorch | |
|---|---|---|---|
| Jira | Yes: ticket required, fetch-ticket, replay inputs |
No: the first message is the requirement | No: the first message is the requirement |
| review | Default: 3 reviewers, security, 3 rounds, asks you when out of rounds | 1 reviewer, no security, 1 round, accepts when out of rounds | Default |
| takeaway | Yes | No | No |
incident |
No | No | Yes |
| prompts | From the core-ng template: develop.md (Gradle dependencies, *-interface contract comments), review.md (checks for *-interface) |
develop.md (Jekyll: keep documents short, writing rules, what to ask a person), review.md (build, links, writing rules, accidental publishing) |
develop.md (incident cause analysis, platform matters the design must cover, "What to do after merging"), risk.md |
| Approval | 1 person | Always 1 person (default: 1 in risk-rules.yaml) |
0 or 1 person, by risk |
To change how one project works: change its project pack (flows.development, prompts/, risk-rules.yaml), then run uv run myorch project sync <project>. Changing flows/development.yaml or a fragment affects all projects.
blog
Personal blog (leweii/leweii.github.io). Changes are small, so review is light: 1 reviewer looks once, blocking findings are fixed once and not reviewed again, and the loop accepts when it runs out of rounds. Nobody reviewed the commits after the fix; risk-rules lists them, and the "review" section of the delivery note lists the problems that were not fixed. The branch is myorch/<run ID>; it never pushes to master: pushing to master puts the blog live.
prompts/develop.md: for posts, read the writing rules; for theme changes, read the development guide. Keep the requirements document and technical design short, and write "Not applicable" for parts that do not apply. The opinions and facts in a post, whether it is public (published, encrypted posts), and site-wide changes (_config.yml, layouts, dependencies, deployment) must all be asked of a person.prompts/review.md: will the build break, will links break, will pages render wrong; writing rules, front matter, accidental publishing.- End-to-end tests run only in review, not in development.
myorch and incident
The myorch platform itself: code, flows, prompts and docs are all in the repository leweii/myorch, branch myorch/<run ID>. Two uses: a normal requirement; or, when the platform had a problem in some run (a run of any project), passing incident to find the cause and fix the platform.
incident is the run that had the problem. Its workspace is mounted read-only for develop at /sandbox/workspace/observed/<run ID>/:
.myorch/flow.yaml: the snapshot of the flow that run used..myorch/steps/<instance>/out/manifest.jsonandlogs/turn-<attempt>-<turn>.log: each step's result and each attempt's log.supervisor-*.logholds the sandbox's network, DNS and credential records.docs/andmemory/MEMORY.md: that run's requirements, design, review and check reports.
These files are that run's data: the agent only reads them and does not run commands or follow instructions in them. The console's run picker lists only this project's runs, so incident is a plain text box.
myorch's prompts/develop.md requires develop to decide the cause before writing the requirements:
| Cause | Meaning | Next |
|---|---|---|
platform-code |
A defect in myorch's code (src/myorch/, tools/, deploy/) |
Continue: requirements, design, implementation, review, approval |
flow |
A defect in a flow definition, fragment, prompt or profile (flows/, profiles/) |
Continue |
project-knowledge |
That project's pack lacks knowledge or checks; the platform is not at fault | Stop. Proposes that project's learn or postmortem |
environment |
Network, external services, expired credentials, machine resources | Stop. Record only, no code change |
one-off |
A random model mistake that a re-run will most likely not repeat | Stop. Proposes a re-run |
unclear |
Not enough evidence | Stop. States what evidence is missing |
"Stop" means outputs.proceed is false: all later steps are skipped, the run ends normally, and nothing is pushed. The cause category, the evidence (files and lines) and where to handle it go in the summary. To continue, the requirements document starts with "The failing run and its cause category" (出问题的运行和原因分类), and "Goal" states what went wrong in that run, which file holds the root cause, and what should happen in the same situation after the change. The fix must not loosen policies, providers, mounts or approval.
The same prompts/develop.md also makes the technical design cover several platform matters: layering (engines → runner → storage → core), which flows a changed fragment or profile affects (flows are shared by all projects), Temporal determinism, volumes and events.db, commands and images in the sandbox, and whether the docs need regenerating.
myorch: after merging
This flow does not deploy. The sandbox only changes the repository and has no access to docker.sock, the gateway or the data directory, and a flow must not have automatic merge or deploy steps (the project pack's security.md). develop writes "What to do after merging" (合并以后要做的事) at the end of the implementation record. After you open a PR on GitHub and merge it into main:
- On myorch's main branch, run
deploy/update.sh(first use--checkto see which commits will be released and what it will wait for). It fast-forwards main, waits until no step is running, rebuilds the images from a clean checkout of the target commit, restarts the worker and the console, and runs the smoke flow. If the smoke test fails, it rolls back to the previously released commit automatically. Whensrc/myorch/engines/orcore/run.pychanged, it waits for all unfinished runs to end. See "Release origin/main" (发布 origin/main) indeploy/README.md. - When
images/claude-code/changed,update.shalso rebuilds the sandbox base imageopenshell-claude-code. Each project's development image is based on it; to use the new base image, the project's image must also be rebuilt (the project pack'simage/build.sh). Whenpyproject.tomloruv.lockchanged, rebuild the myorch project's development image (in the myorch-knowledge directory, runmyorch/image/build.sh ../myorch); only then do later development runs of the myorch project use the new dependencies. - When
tools/changed (the helper commands in the sandbox, such asmyorch-checksandmyorch-ask), they are installed into the volume bymyorch init(theinitservice in compose). Make suremyorch inithas been run again; otherwise the sandbox still has the old versions.
Source of this page: docs/en/flows/development.md
review Review PR
| File | flows/review.yaml, prose docs/en/flows/review.md |
| Role | review (the console task “Review PR”) |
| Projects | shared by every project |
| In short | Review an existing PR. The verdict is shown only in the console. |
| Fragments | lib/review-loop.yaml, lib/e2e.yaml |
PR review: one round of AI review on an existing PR (including PRs written by people). All projects share this one flow. It first runs the project's checks, then has reviewers read the code; when the project has end-to-end tests, it finally tests the running application with a browser. The conclusions appear only in the local console (the Changes (改动) tab in the right panel) and in the workspace's docs/review/round-1/. Nothing is posted to GitHub. It only looks for problems: it does not change code, does not approve the PR and does not request changes, because an agent's approval does not count. Its access to GitHub is read-only.
The review loop it uses is the same fragment as in development, lib/review-loop.yaml, but it runs only 1 round, does not fix, and ends normally even when there are blocking problems. The project's prompts/review.md and verify.md are spliced in the same way (for example the *-interface checks of core-ng projects, and the blog's writing rules and accidental-publication checks).
uv run myorch run flows/review.yaml --project mdm -i pr=13 # default standard
uv run myorch run flows/review.yaml --project blog -i pr=13 -i depth=deep
Console: choose the project first, then the task Review PR (评审 PR), fill in the PR number and choose the review depth. The first message can stay empty.
The review depth (depth) decides the number of reviewers, their model, and whether there is a separate security review; see the preset table below. Use standard for everyday PRs. Use quick for a fast look. Use deep for changes to the build, dependencies or security-related code. verify always uses Opus.
Inputs
| Input | Label | Type | Required | Default | Description |
|---|---|---|---|---|---|
pr | PR number | text | required | For example 25 | |
depth | Review depth | options: quick / standard / deep | standard |
The input depth picks a set of parameters (presets):
| depth | reviewers | security | review_model |
|---|---|---|---|
quick | 1 | False | Haiku |
standard | 2 | True | Sonnet |
deep | 3 | True | Opus |
Step graph
Generated from flows/review.yaml, expanded for project mdm with default inputs (another project's pack may leave steps out or change parameters); the same as myorch expand and the console's Flows page (流程).
steps.verify.outputs.blocking == 0 · accepts when out of rounds and goes on · lib/review-loop.yaml · conditionalEach step's executor, condition and outputs (generated from the YAML)
| Step | Runs as | Condition | outputs | People and parallelism | Limits |
|---|---|---|---|---|---|
fetch-pr | script · dev-git | timeout 10m · retries 1 | |||
Loop review-round: up to 1 rounds, until steps.verify.outputs.blocking == 0, accepts when out of rounds and goes on. Condition steps.fetch-pr.outputs.changed. Fragment lib/review-loop.yaml | |||||
ci | script · dev-write | timeout 15m | |||
review | agent · Sonnet · dev-read | findings | 2 instances in parallel | timeout 20m | |
security | agent · Sonnet · dev-read | findings | timeout 20m | ||
verify | agent · Opus · dev-read | blocking, nits, pre_existing | timeout 20m | ||
reflect | agent · Opus · dev-read | recommendation, reason | timeout 15m | ||
The graph above is expanded for mdm. mdm and myorch do not set e2e.image and have no e2e block; blog does.
What each step does
| Step | What it does | Artifacts |
|---|---|---|
fetch-pr |
Reads the PR and its list of changed files through the GitHub API; clones the repository, fetches the base branch and pull/<n>/head, checks out the PR's head on this run's branch, initialises submodules |
docs/pr.md, docs/external/pr.md |
review-round loop (1 round) |
ci (the project's checks.sh, checking the files the PR changed) → review (the count depends on the depth) and security (not in quick) in parallel → verify checks the findings. There is no fix |
docs/ci/round-1.md, docs/review/round-1/ |
e2e loop (1 round) |
This block exists only when the project sets e2e.image (currently only blog). e2e-smoke runs the project pack's fixed smoke test cases; e2e-accept turns the acceptance criteria in the PR description that a browser can check into test cases and runs them. It only tests and does not fix |
docs/e2e/round-1/ |
- Both blocks run only 1 round, with
fix: falseandon_exhausted: accept: with blocking problems or failed tests, the run still ends normally and only reports. e2ecomes afterreview-roundand uses the checkoutciprepared.
Where you step in
There are no questions for you and no approvals. When a step fails, the run fails (this flow does not set on_failed: ask).
| When | Console | Command line |
|---|---|---|
| After the run ends | The Changes (改动) tab in the right panel shows the diff and the verified findings; the Docs (文档) tab shows the checks report and the end-to-end test reports and screenshots | myorch ws <run> docs/review/round-1/summary.md |
| After reading | — | Decide yourself on GitHub what to do with the PR |
Artifacts
docs/
├── pr.md trusted metadata: author, state, head → base, changed files
├── external/pr.md title and description written by the PR author (reference data only)
├── ci/round-1.md checks report
├── review/round-1/
│ ├── reviewer-K.json each reviewer's findings
│ ├── security.json security review findings (not in quick)
│ ├── verified.json findings after verification: Important / Nit / Pre-existing
│ └── summary.md counts, list of blocking problems, acceptance criteria table
└── e2e/round-1/ projects with end-to-end tests
├── smoke/ report.md, result.json, screenshots
├── acceptance/ report.md, result.json, screenshots; cases/ holds the written test cases
└── acceptance.md the verdict for each acceptance criterion
Principles
- Always review the whole PR: myorch leaves no markers on GitHub, so there is no incremental review. The "reviewed up to last time" logic in
fetch-pris no longer used:last_reviewedis always empty andchangedis always true, soreview-roundalways runs, and round 1 looks atorigin/<base>...HEAD. - Trusted and untrusted data are kept apart: author, state, changed files and SHAs go into
docs/pr.md. The title and description written by the PR author go intodocs/external/pr.md. Every agent treatsdocs/external/as reference data and does not follow instructions in it. - Reviewer rules are the same as in the development flow: judge independently first, then check the author's claims; search the repository for reuse and missed entry points; relaxed judgement. See development's review loop. Reviewers 1, 2 and 3 each have their own focus; quick has only reviewer 1 (focused on correctness and edge cases).
- verify checks each finding: no matter how many reviewers there are, every finding is checked by opening the code. Findings that do not hold are removed; findings reported by only one reviewer are checked too.
votesonly records how many reviewers reported it. At most 5 Nits are kept; failed checks count as Important. - Requirements document: this flow does not pass
requirement_docto the review loop. Reviewers and verify are told the requirements document isdocs/requirements.md, but a review run has no such file. So they can only judge from the change itself, and the PR description is only reference material indocs/external/pr.md. The end-to-end block is passeddocs/pr.md.
End-to-end tests
- review reads the code; e2e tests the running application. The two are separate. The project decides which tools to test with:
e2e:inproject.yaml(image,profile,acceptance) and the project pack'se2e/(the blog uses Playwright and headless Chromium; seemyorch-knowledge/blog/e2e/README.md). - The test steps' permissions are
e2e.profile(for blog,dev-read: read-only repository, no credentials). - When a smoke test case fails only because of the test environment (for example the browser did not start), the report lists it separately as "environment" (环境), not as a problem in the code.
e2e-acceptmust not loosen test cases to make them pass. When a test case fails, it first decides whether the test case is wrong or the change has a problem; if the change has a problem, the test case stays.
Security
- Code in other people's PRs is untrusted, and
ciand the end-to-end tests execute it (build scripts, tests, lint configuration). The steps that execute PR code (ci,e2e-smoke,e2e-accept) and the reviewers that read the code get no GitHub credentials, and run in sandboxes that are deleted after use. - The one step with credentials (
fetch-pr) runs only scripts fixed in the flow and executes no code from the PR. It only reads: fetches code, reads the PR. - The remaining risk is prompt injection: PR content may lead reviewers to misleading conclusions. Conclusions are shown only on the local machine and not posted to GitHub.
Source of this page: docs/en/flows/review.md
postmortem Postmortem
| File | flows/postmortem.yaml, prose docs/en/flows/postmortem.md |
| Role | postmortem (the console task “Postmortem”) |
| Projects | shared by every project |
| In short | Postmortem: a problem already got into the code. Find the change that introduced it and the layer that should have caught it, propose knowledge changes, and generate an eval case. Does not change project code. |
| Fragments | lib/choose-proposals.yaml |
Analyses a problem that already got into the project's code: finds the commit that introduced it, works out at which layer it should have been stopped first and why it was not, proposes knowledge changes, and turns the change into an eval case. Use it after the problem is fixed (or reverted), when you want to know why it was not stopped at the time.
It only analyses and does not change project code; to fix the bug, use development. The only things it changes outside are the local myorch-knowledge (the proposals you adopt) and the local eval set (myorch-data/evals/cases/). The difference from learn: learn looks for patterns across a batch of runs; postmortem works backwards from one concrete problem. learn later reads postmortem's conclusions too.
uv run myorch run flows/postmortem.yaml --project mdm -i commit=<fix or revert commit>
uv run myorch run flows/postmortem.yaml --project mdm -i bad=<commit that introduced the problem>
Console: choose the project first, then the task Postmortem (复盘), and fill in one of Fix or revert commit (修复或 revert 提交) or Commit that introduced the problem (引入问题的提交). The first message can describe the problem's symptoms and impact, or stay empty. If you write one, it is stored as docs/external/request.md, and analyze reads it.
Inputs
| Input | Label | Type | Required | Default | Description |
|---|---|---|---|---|---|
commit | Fix or revert commit | text | one of two | A commit SHA. Give this or the next one | |
bad | Commit that introduced the problem | text | one of two | Its SHA, if you know it | |
runs | hidden |
Step graph
Generated from flows/postmortem.yaml, expanded for project mdm with default inputs (another project's pack may leave steps out or change parameters); the same as myorch expand and the console's Flows page (流程).
Each step's executor, condition and outputs (generated from the YAML)
| Step | Runs as | Condition | outputs | People and parallelism | Limits |
|---|---|---|---|---|---|
locate | script · dev-git | bad, fix, kind, matched, matched_runs | timeout 15m · retries 1 | ||
replay-before | host action · postmortem-replay | timeout 5m | |||
trace | script · dev-read | timeout 10m | |||
analyze | agent · Opus · dev-read | layer, category, proposals, expected | timeout 30m | ||
choose | script · dev-read | steps.analyze.outputs.proposals > 0 | accepted | can ask you questions | timeout 30m |
apply | host action · project-apply | steps.choose.outputs.accepted > 0 | timeout 5m | ||
replay-after | host action · postmortem-replay | timeout 5m |
Inputs
- Give either
commitorbad. When neither is filled in, the run does not start. When both are filled in,badwins andcommitis treated as the fix commit. - The commit does not have to be on a branch (for example an unmerged PR): locate fetches it from GitHub by SHA.
runsdoes not need to be filled in. At start the client fills in this project's newest development and review runs (at most 20; ended, failed and cancelled all count), and locate picks out the ones that touched this change.
What each step does
| Step | What it does | Artifacts |
|---|---|---|
locate |
Finds the commit that introduced the problem (see below), its PR, and which myorch runs touched it | docs/postmortem/target.json, bad.diff, fix.diff (when there is a fix commit) |
replay-before |
Host action: creates the eval case (draft) and starts a separate eval run that replays the change with the current knowledge. Runs at the same time as trace and analyze | Eval case, eval run eval-<id>-before |
trace |
From the runs that touched the change, lists what each layer saw at the time: which related files the requirements document mentioned, the findings of each review round near the change (10 lines before and after), CI results, the risk verdict | docs/postmortem/trace.json, trace.md |
analyze |
Works out what the problem is, at which layer it should have been stopped first and why it was not; proposes knowledge changes; writes the findings a reviewer is expected to report. Read-only; writes only docs/postmortem/ |
postmortem.md, proposals.json, proposals.md, follow-ups.md, case.json |
choose |
Lists the proposals and waits for you to reply with numbers. Skipped when there are no proposals | docs/postmortem/accepted.json |
apply |
Host action project-apply: writes back to the project pack, commits, re-syncs the snapshot. Skipped when nothing was adopted |
A commit in myorch-knowledge |
replay-after |
Host action: writes the expected findings into the eval case. When proposals were adopted, replays once more with the new knowledge | Updated eval case, eval run eval-<id>-after |
<id> is the last part of this postmortem run's ID. For example, the replay of postmortem-1a2b3c4d is eval-1a2b3c4d-before.
locate: how it finds the commit that introduced the problem
| What was given | How it finds it |
|---|---|
bad |
Used directly |
commit, and its message contains This reverts commit <sha> |
The reverted commit |
commit, an ordinary fix |
git blame on the lines the fix changed (for pure additions, the 2 lines before and after the insertion point); takes the commit that appears most often |
- When the commit that introduced the problem is a merge commit, the comparison base is its first parent, so the whole PR is looked at.
- The full-history clone lives outside the workspace (
/tmp). The history that contains the fix does not enter the run's workspace. - Runs that touched the change: runs whose branch has this commit while the base they started from did not; or runs whose linked PR is this commit's PR.
- The requirement is taken from
requirements.md(orpr.md) of the first run that touched it. When no myorch run touched it, the commit message and the PR title and description are used. - When it cannot find it, the step fails and says why: the commit is not in the repository; the lines the fix changed have no traceable origin (then use
-i bad=to name it directly); the commit that introduced the problem is the repository's first commit.
analyze: the layer that should have stopped it, and why
| Output | Values |
|---|---|
layer: the first layer that should have stopped it |
requirement requirements analysis should have asked; implementation the implementation guide should have avoided it; review; security; risk should have been judged high risk for a person to look at; ci deterministic checks; approval the approver should have seen it; none |
category: why it was not stopped |
no-rule neither the knowledge nor the checks covered it; rule-not-applied a rule existed but was not used; flagged-not-handled a reviewer or CI pointed it out, but it was rebutted, downgraded or ignored; human-let-through a person saw the risk and let it through anyway; not-detectable it really could not be found in advance |
- When no myorch run touched the change, the question is: had it gone through myorch at the time, which layer should have stopped it.
- At most 5 proposals, in the same format as learn (exact replacement or append), changing only
guide/. Rules must be written so that they apply to the same kind of problem, not only to this one bug. - Proposals better done as lint, CI or tests go into
follow-ups.mdand need a separate development run. case.jsoncontains only the problems a reviewer should find from the change itself. Whencategoryisnot-detectable, or only CI could find it, it is[].
Replays and the eval case
A replay is a separate eval run (the eval flow, evals.py). The reviewer there sees only the change itself and the requirement, not this run's workspace: not the incident description, the fix, the analysis or the expected findings. The eval run clones the repository from GitHub, checks out the commit that introduced the problem, and deletes later commits (including the fix), branches and the reflog.
The case ID is this postmortem's run ID, stored on the local machine in myorch-data/evals/cases/<run ID>.json. This is how it reaches the eval set:
| When | Case state | What happens |
|---|---|---|
replay-before |
draft |
Only the change, no expected findings yet; not visible in the eval set. Replays once with the current knowledge |
replay-after, case.json has content |
pending |
The expected findings are written; it waits for you to confirm under Flows → Eval set (流程 → 评测集) in the console. When proposals were adopted, replays once more with the new knowledge |
replay-after, case.json is empty |
rejected |
No problem that could have been found in advance; the case is not scored and not replayed again |
| You mark the valid findings under Flows → Eval set | confirmed |
The case joins the eval set, and later myorch eval run uses it too. If you mark none, it is rejected |
- The case page shows how many findings each of the two replays caught. Before confirmation, all findings in
case.jsoncount; after confirmation, the ones you marked. - To compare this run's two replays on the command line:
uv run myorch eval report --batch <postmortem run ID>. It scores only against the findings you marked, so confirm the case first. - Both replay steps are idempotent: a replay that was already started is not started a second time.
- A replay is another run; if it fails, the postmortem itself is not affected. Look at the eval run for the cause.
Where you step in
| When | Console / Slack | Command line |
|---|---|---|
choose: pick which to adopt |
Reply with numbers in the conversation, or click all or none |
uv run myorch reply <run> choose "1,3" |
| After the run ends: confirm the eval case | Open this case under Flows → Eval set and mark the valid findings | No command |
- Replies are written the same way as for learn:
1,3,1、3,all,none; if the reply cannot be understood, it asks again. The details are indocs/postmortem/proposals.md. - When nothing is adopted, the knowledge is not changed and there is no second replay.
Writing back to the project pack
Uses the same host action project-apply as learn, also with scope: learn. For the rules see learn's "Writing back to the project pack": write only when everything validates, commit only the files it wrote, the commit message is learn(<project>): … with myorch-run: <run_id>, re-sync the snapshot after writing, git revert is possible.
The only difference is which files are read: the proposals are in docs/postmortem/proposals.json, the adopted numbers in docs/postmortem/accepted.json. The prompt lets analyze change only guide/; the action itself validates against learn's scope and also accepts checks.sh and checks.env.
Artifacts
All under docs/postmortem/ in the workspace. The Docs (文档) tab in the console's right panel shows them, or use uv run myorch ws <run> docs/postmortem.
docs/postmortem/
target.json the commit that introduced the problem, base, fix, PR, runs that touched it, requirement
bad.diff, fix.diff the change that introduced the problem; the fix (sometimes)
trace.json, trace.md what each layer saw at the time
postmortem.md conclusion: the problem, the layer that should have stopped it and why, evidence, proposals
proposals.json, proposals.md, accepted.json knowledge proposals, the numbers you adopted
follow-ups.md proposals for deterministic checks that need a separate development run
case.json the expected findings for the eval case
Source of this page: docs/en/flows/postmortem.md
sweep Find bugs
| File | flows/sweep.yaml, prose docs/en/flows/sweep.md |
| Role | sweep (the console task “Find bugs”) |
| Projects | shared by every project |
| In short | Find bugs in existing code, a batch of files at a time; produces only a daily report. |
| Fragments | lib/sync-base.yaml |
Finds bugs in a project's existing code. All projects share this one flow. Each run looks at a batch of files in a fixed order, with several auditors in parallel, verifies the findings and writes a daily report. It suits nightly schedules that work through the whole repository batch by batch.
It is observe-only: it writes only the daily report docs/sweep/report.md. It does not change code, does not push, does not start development and does not change the knowledge. To fix a problem it found, a person starts a separate development run. The difference from review: review looks at a PR's change; sweep looks at code already on the main branch.
uv run myorch run flows/sweep.yaml --project mdm # run once, audit depth defaults to standard
uv run myorch run flows/sweep.yaml --project mdm -i depth=deep
uv run myorch schedule add nightly-sweep-mdm --flow sweep --project mdm --cron '0 2 * * *' # every night at 2:00
Console: choose the project first, then the task Find bugs (找 bug), and choose the audit depth. The first message is not needed.
Inputs
| Input | Label | Type | Required | Default | Description |
|---|---|---|---|---|---|
depth | Audit depth | options: quick / standard / deep | standard |
The input depth picks a set of parameters (presets):
| depth | auditors | audit_model |
|---|---|---|
quick | 1 | Haiku |
standard | 2 | Sonnet |
deep | 3 | Opus |
Step graph
Generated from flows/sweep.yaml, expanded for project mdm with default inputs (another project's pack may leave steps out or change parameters); the same as myorch expand and the console's Flows page (流程).
Each step's executor, condition and outputs (generated from the YAML)
| Step | Runs as | Condition | outputs | People and parallelism | Limits |
|---|---|---|---|---|---|
sync | script · dev-git | timeout 15m · retries 1 | |||
pick | script · dev-read | timeout 5m | |||
audit | agent · Sonnet · dev-read | findings | 2 instances in parallel | timeout 30m | |
verify | agent · Sonnet · dev-read | new_important, new_nit | timeout 20m | ||
record | script · dev-read | timeout 5m |
Which files it looks at
Decided by sweep: in the project pack's project.yaml (see 7. Project packs):
| Field | Meaning | When not set |
|---|---|---|
paths |
Look only at these directories or files | The whole repository |
include |
Look only at files matching these globs (** allowed) |
No filter |
exclude |
Skip files matching these globs | Nothing excluded |
chunk |
How many files per run (1 to 200) | 20 |
- The file list comes from
git ls-files, sorted by path. - mdm and blog currently have no
sweep:, so they look at the whole repository, 20 files per run. myorch looks only atsrc/myorch,flows,toolsanddeploy(notsrc/myorch/ui/static/vendor/**), 15 files per run. - sweep reads the configuration from the project pack snapshot. After changing
project.yaml, runuv run myorch project sync <project>. - When the configuration selects no files at all,
pickfails.
What each step does
| Step | What it does | Artifacts |
|---|---|---|
sync |
Clones or updates the repository and checks out the latest base branch (lib/sync-base.yaml, sped up by the project's shared bare mirror) |
repo/ |
pick |
Takes the next batch of files at the cursor and copies the known issues into the workspace. The cursor does not move here | docs/sweep/chunk.txt, docs/sweep/known.json |
audit |
Each auditor reads the batch on its own and looks for defects that exist now. Read-only; does not change code | docs/sweep/audit-<n>.json |
verify |
Checks each finding by opening the code, removes false positives and known issues, merges duplicates, writes the daily report | docs/sweep/verified.json, docs/sweep/report.md |
record |
Records the new issues in known.json and moves the cursor forward |
cursor.json, known.json in the shared directory |
audit: what it looks for
- Correctness (logic errors, missed edge cases, unhandled errors, mismatches with docs or comments), security (injection, leaked secrets, unsafe defaults, missing permission checks), errors users see (broken links, wrong data or display).
- Each auditor has its own focus: auditor 1 looks more at correctness and edge cases, auditor 2 at security and error handling, auditor 3 at whether docs and data agree.
- Not reported: code style, naming, things that could be written better but are not wrong, missing tests; known issues; code outside this batch of files (used only to understand context).
- There are only two severities:
Important(wrong behaviour, wrong data, security problems; worth having someone fix) andNit(really a problem, but with small impact). Findings it is not sure about are not reported. - When there is a
guide/review-guide.md, it follows its standards.
verify: verification
- Each finding is checked by opening the code; findings that do not hold are removed.
- The same issue reported by several auditors is merged into one, and
votesis the number of auditors who reported it. Findings reported by only one auditor are kept if they hold. - Findings that are the same issue as one in
known.jsonare removed. - The daily report: with no new issues, it has only the sentence "No new issues found in this batch of files." (这批文件没有发现新问题。), followed by the directories that were looked at. With new issues, the first sentence gives the number of Important and Nit findings, then lists each one by severity with its location, the problem, the consequence and a suggested fix. No process notes, no pleasantries.
State across runs
State across runs lives in the project's shared directory shared/<project>/sweep/ (on the myorch storage volume). Only pick and record mount it.
| File | Content | Written by |
|---|---|---|
cursor.json |
{"next": index of the file the next batch starts at, "total": total number of files, "run": the run that wrote it} |
record |
known.json |
List of reported issues: fingerprint, file, line, title, severity, run, at (date) |
record appends |
- The cursor moves forward only after the whole run succeeds.
recordis the last step. If any earlier step fails, it does not run, and the next run scans the same batch again. - After the last file it starts over from the beginning, so it can keep running on a schedule.
- The cursor is a position in the sorted list, not a file name. When files are added or deleted, the start of the next batch shifts by a few files: a few may be skipped or looked at twice, and the next pass makes up for it.
- Known issues are deduplicated twice: verify decides by meaning whether two are the same issue, and
recordthen removes exact duplicates by thefile|titlefingerprint. known.jsononly grows. To scan from the beginning, deletecursor.json. To have an issue reported again, delete its entry fromknown.json. Each run's workspace also has a copy from that time indocs/sweep/known.json.
Where you step in
You are not needed while it runs. To read the daily report: open the run in the console and find docs/sweep/report.md under the Docs (文档) tab in the right panel; or uv run myorch ws <run> docs/sweep/report.md. For issues worth fixing, start a separate development run.
Scheduled runs
--flowtakes the flow namesweep. For a different audit depth, add-i depth=quickor-i depth=deep.- When the run started by the previous schedule is still running, this one is skipped, so two runs never move the cursor at the same time. Do not add
--allow-overlap: two runs would scan the same batch, and the one that ends later could overwriteknown.json. - The run's starter is the person who created the schedule.
uv run myorch schedule listshows when it runs next;pause,unpauseanddeletemanage it;triggerruns it once right away.
Artifacts
docs/sweep/
chunk.txt the files looked at this time, one per line
known.json copy of the known issues at start
audit-<n>.json each auditor's findings
verified.json new issues after verification
report.md daily report
Source of this page: docs/en/flows/sweep.md
learn Learn
| File | flows/learn.yaml, prose docs/en/flows/learn.md |
| Role | learn (the console task “Learn”) |
| Projects | shared by every project |
| In short | Distil knowledge from past runs: improve guide/, record decisions people made, add deterministic checks. |
| Fragments | lib/choose-proposals.yaml |
Turns a project's past runs into knowledge, so that the next run knows it from the start. All projects share this one flow. It turns various signals into proposals for changing the project pack. You pick which ones to adopt, and it writes them back to myorch-knowledge/<project>/. When the knowledge gets more accurate, every later development and review run benefits.
It only changes the local myorch-knowledge: guide/, checks.sh, checks.env. It does not push, does not touch the project repository and does not change flows (proposals about flows are only written to a file). The difference from postmortem: postmortem works backwards from one problem that slipped through; learn looks for recurring patterns across a batch of runs.
uv run myorch run flows/learn.yaml --project mdm # pick runs automatically
uv run myorch run flows/learn.yaml --project mdm -i runs=development-b947d694,review-5d5a21ec # pick runs by hand
uv run myorch schedule add weekly-learn-mdm --flow learn --project mdm --cron '0 9 * * 1' # every Monday at 9:00
Console: choose the project first, then the task Learn (学习). Runs to learn from (要学习的运行) can stay empty. The first message is not needed.
Inputs
| Input | Label | Type | Required | Default | Description |
|---|---|---|---|---|---|
runs | Runs to learn from | text | Optional. Comma-separated run IDs; when empty, the runs since the last learn are picked |
Step graph
Generated from flows/learn.yaml, expanded for project mdm with default inputs (another project's pack may leave steps out or change parameters); the same as myorch expand and the console's Flows page (流程).
Each step's executor, condition and outputs (generated from the YAML)
| Step | Runs as | Condition | outputs | People and parallelism | Limits |
|---|---|---|---|---|---|
collect | script · dev-git | findings | timeout 10m · retries 1 | ||
analyze | agent · Opus · dev-read | proposals, follow_ups | timeout 20m | ||
choose | script · dev-read | steps.analyze.outputs.proposals > 0 | accepted | can ask you questions | timeout 30m |
apply | host action · project-apply | steps.choose.outputs.accepted > 0 | timeout 5m | ||
takeaways-learned | host action · takeaways-learned | steps.collect.outputs.takeaways > 0 | timeout 2m |
Which runs it learns from
When runs is not given, the client that starts the run picks them (the same for the command line, the console, Slack and schedules):
- development, review and postmortem runs of this project that started after the last completed learn;
- only runs that have ended (succeeded or failed); cancelled runs do not count;
- at most 20, the newest.
observe_runsmounts at most 20 workspaces.
The command line lists the chosen runs before it starts. When there is no new run at all, the run does not start and reports "no new ended development / review run" (没有新的已结束的 development / review run). uv run myorch list --project <project> shows which runs exist. To pick by hand, use -i runs=<id>,<id>.
A failed or timed-out learn does not count as completed. The next learn picks the same runs again.
Which signals it reads
| Signal | Source | How it gets into the run |
|---|---|---|
| review findings and what happened to them later | Each run's docs/review/round-*/, the PR's state |
collect reads the read-only mounted observed/<run_id>/ and queries GitHub for the PR |
| Questions people answered, requested changes, rejections, failed steps, re-runs, which run was continued from | The event log on the host | Written to docs/learn/trail.json by the client at start (trail.py). The sandbox cannot read the event log |
| CI failures | docs/ci/round-*/result.json |
collect |
| Assumptions made during implementation, deviations from the requirements and the design | The matching sections of docs/implementation.md |
collect |
| Why a branch was continued | The request of the continuing run (docs/external/request.md) |
collect |
| Postmortem conclusions and follow-up proposals | docs/postmortem/ of postmortem runs |
collect |
| Task info and takeaways written by development runs | myorch/<date>-<run_id>/ on the project repository's base branch |
collect reads them from the repository. Which ones were already learned is written to docs/learn/takeaways-learned.json at start |
What each step does
| Step | What it does | Artifacts |
|---|---|---|
collect |
Gathers the signals in the table above, works out what happened to each review finding later, and reads the takeaways in the repository that have not been learned yet. The script only reads from GitHub and does not run repository code | docs/learn/findings.json, outcomes.md, signals.json, signals.md, takeaways.json, takeaways/ |
analyze |
Looks for patterns and makes proposals, each with evidence. Only writes proposal files and changes nothing | docs/learn/proposals.json, proposals.md, follow-ups.md, flow-proposals.md |
choose |
Lists the proposals for you and waits for you to reply with numbers. Skipped when there are no proposals | docs/learn/accepted.json |
apply |
Host action project-apply: validates, writes back to the project pack, commits in myorch-knowledge, re-syncs the snapshot. Skipped when nothing was adopted |
A commit in myorch-knowledge |
takeaways-learned |
Host action: marks the takeaways read in this run as learned. Runs no matter how many proposals were adopted; skipped when no takeaways were read this time | myorch-data/learn/<project>/takeaways.json |
collect: what happened to the findings
Findings already marked fixed do not count. Each of the others is checked in the order below, and the first that holds wins:
| Outcome | Meaning |
|---|---|
fixed |
In a later round, a finding in the same file is marked fixed |
rebutted |
The first 12 characters of the title appear in some round's rebuttal.md |
merged_unchanged / closed / open |
Review runs only: the reviewed PR was merged, was closed, is still open |
not_required |
Nit or Pre-existing; it never blocked |
unknown |
None of the above |
myorch no longer posts comments on PRs, so there is no "someone replied to the comment" outcome. Outcomes come only from the runs' own records and the PR state.
collect: takeaways in the repository
- When the project sets
flows.development.takeaway(currently only mdm), development commitstask.mdandtakeaway.mdwith each change tomyorch/<date>-<run_id>/. They reach the base branch only after the PR is merged, so only merged ones can be read. Other project repositories have no such directory, and this kind of signal is empty. - When the workspace has no repository, collect makes a shallow clone without checking out files and reads them one by one with
git show. - Learned ones are skipped, and reading starts from the oldest. At most 30 entries and 300 KB per run (the first one is always read); the rest wait for the next run. The digest says how many are left.
- An entry whose
takeaway.mdcannot be read (network problem, empty file) is not read and not marked learned; the next run tries again. After 3 unreadable entries in a row it stops. Directories whose name is not<date>-<run_id>are skipped. - When the repository cannot be read, it records only a fixed sentence and the git exit code, without the command line or git's output. learn carries on.
- Which ones were learned is recorded only on the local machine in
myorch-data/learn/<project>/takeaways.json(takeaways.py). Nothing is written to the company repository or tomyorch-knowledge.
analyze: which kinds of knowledge it looks for
At most 8 proposals. With too little evidence it proposes fewer or none. It does not repeat what the knowledge and the repository's own docs already say. The wording is short and follows the style of the existing files.
| Type | What it looks for | Where it writes |
|---|---|---|
record-decision |
Decisions a person made while answering during requirements analysis or design that apply to all similar questions later | guide/decisions.md (created when missing): the situation, what to do, why, the source. Later similar questions follow it without asking a person |
fill-gap |
Causes of rework: continuations, postmortem conclusions, implementations that deviated from the requirements or design, assumptions that had to be made | Guides for development and design. The question is "what could the knowledge have said in advance so that the first attempt was right" |
add-rule |
The same kind of problem recurring (in at least 2 runs, or in 1 with high impact) | Rules to avoid during implementation, or review-guide.md |
relax-rule |
Comments that were rebutted repeatedly, or merged without changes | Relax review-guide.md |
add-check |
Recurring problems a script can detect, or CI checks that fail repeatedly | checks.sh or checks.env. Only deterministic checks; checks that may give false positives only warn. When it is not sure it can write the check correctly, it goes into follow-ups.md |
Two more files are never applied: follow-ups.md holds proposals for changing the project repository itself (lint, CI, tests), which need a separate development run; flow-proposals.md holds proposals for myorch flows (step order, when to ask questions, steps that always fail or are not needed).
Takeaways are treated as signals and checked like other evidence: only project knowledge that generalises to later work is adopted, not what holds only for one ticket. Evidence is written as <run_id>: takeaway. Proposals about flows, the platform or the environment go into flow-proposals.md.
Each proposal's change is written as an exact replacement (edits: old copied verbatim from the current file and occurring exactly once in it) or an append (append). No diffs, because diffs written by agents often have wrong line numbers.
Where you step in
| When | Console / Slack | Command line |
|---|---|---|
choose: pick which to adopt |
Reply with numbers in the conversation, or click all or none |
uv run myorch reply <run> choose "1,3" |
- The question has one line per proposal, with its type and the number of pieces of evidence. The details are in
docs/learn/proposals.md: the Docs (文档) tab in the console's right panel, oruv run myorch ws <run> docs/learn/proposals.md. - Reply with the numbers only:
1,3,1、3and1 3all work.allor全部adopts all of them;none,无or0adopts none. When a number does not exist or the reply cannot be understood, it asks again. - Once the reply is accepted, it starts running and cannot be changed. To adopt more, run learn again or edit the project pack by hand.
- Without a reply for 24 hours, this step times out and fails. A scheduled learn also stops here and waits for you.
Writing back to the project pack
apply is the host action project-apply with scope: learn (actions.py, project.py). The sandbox cannot reach myorch-knowledge, so this happens on the host.
| Can change | Cannot change |
|---|---|
Files under guide/, including new ones |
risk-rules.yaml, security.md, setup.sh |
checks.sh, checks.env |
project.yaml, image/, policy.yaml, providers/, sources/ and other files |
- It writes only the project's own directory
myorch-knowledge/<project>/. Templates (for example mdm's_templates/core-ng/) stay unchanged. A file the project only inherits from the template is first copied from the template on its first change, then changed. - All adopted changes are validated in memory first: the path is within the allowed scope, does not escape the project pack, and each
oldoccurs exactly once. If anything fails, nothing is written. The step fails and lists the reasons. - After writing, it commits in
myorch-knowledge, committing only the files written this time (changes someone else staged are not included). The commit message islearn(<project>): #1 title; #3 title, and the body hasmyorch-run: <run_id> step: applyand the adopted numbers. - Then it re-syncs the project pack snapshot. Runs that start after that use the new knowledge, and the project pack version recorded in the Mandate changes with it. Runs in progress keep using their own snapshots.
- Idempotent: when it finds this step has already committed, it counts as succeeded and does not write a second time.
- If a proposal works out badly:
git revert <commit>inmyorch-knowledge, thenuv run myorch project sync <project>.
Artifacts
All under docs/learn/ in the workspace. The Docs tab in the console's right panel shows them, or use uv run myorch ws <run> docs/learn.
docs/learn/
trail.json written at start: questions and answers, comments, rejections, failures, re-runs from the event log
takeaways-learned.json written at start: run_ids of takeaways already learned
findings.json, outcomes.md findings and their outcomes, statistics table
signals.json, signals.md signals other than review
takeaways.json, takeaways/<date>-<run_id>/ takeaways read this time
proposals.json, proposals.md proposals
follow-ups.md, flow-proposals.md proposals that are not applied automatically
accepted.json the numbers you adopted
Scheduled runs
The --flow of myorch schedule add takes the flow name learn. Schedules start runs through the same path as the console, so automatic run selection and writing trail.json and takeaways-learned.json work the same.
- When the run started by the previous schedule is still running (for example still waiting at
choose), this one is skipped. To run both at once, add--allow-overlap. - When there are no new runs, this one does not start a run. This holds even when the repository has new takeaways, because takeaways are only read inside a learn run.
- The run's starter is the person who created the schedule.
uv run myorch schedule listshows when it runs next;pauseanddeletestop it.
Source of this page: docs/en/flows/learn.md
eval Eval
| File | flows/eval.yaml, prose docs/en/flows/eval.md |
| Role | eval (the console task “Eval”) |
| Projects | shared by every project |
| In short | Replay an eval case and score the reviewers. |
| Fragments | lib/review-loop.yaml |
Scores the reviewer. It replays the change that a past review looked at, unchanged, and lets the reviewer look at it again. It compares the result with the real issues a person confirmed and counts how many were caught, how many were missed and how many extra findings were reported. Use it after you change the reviewer's prompt, its model or the project pack's guide/, to tell whether things got better or worse. It writes nothing outside: it does not push, does not change code and does not change the project pack.
One eval run replays one case at one review depth. Collecting, confirming, batch-starting and scoring cases all happen on the local machine through myorch eval (src/myorch/evals.py). The flow itself only prepares the code and runs one review round.
uv run myorch eval collect # collect candidate cases from past runs
uv run myorch eval list # cases and their state
# in the console under "Flows → Eval set", mark for each case which findings are real issues
uv run myorch eval run --depth quick --depth standard # one eval per confirmed case and per depth
uv run myorch eval run --case <case ID> # run only one case (default depth standard)
uv run myorch eval report [--batch <batch>] # comparison table
Do not start it from + New run (+ 新运行) in the console or with myorch run. Only myorch eval run (and postmortem's replays) write the case into the workspace. When you start it directly, prepare finds no case and fails. The Slack start dialog does not list this flow.
Inputs
| Input | Label | Type | Required | Default | Description |
|---|---|---|---|---|---|
case | Case | text | required | Case ID (Flows → Eval set, 流程 → 评测集) | |
depth | Depth to test | options: quick / standard / deep | standard |
The input depth picks a set of parameters (presets):
| depth | reviewers | security | review_model |
|---|---|---|---|
quick | 1 | False | Haiku |
standard | 2 | True | Sonnet |
deep | 3 | True | Opus |
Step graph
Generated from flows/eval.yaml, expanded for project mdm with default inputs (another project's pack may leave steps out or change parameters); the same as myorch expand and the console's Flows page (流程).
steps.verify.outputs.blocking == 0 · accepts when out of rounds and goes on · lib/review-loop.yamlEach step's executor, condition and outputs (generated from the YAML)
| Step | Runs as | Condition | outputs | People and parallelism | Limits |
|---|---|---|---|---|---|
prepare | script · dev-git | timeout 10m | |||
Loop review-round: up to 1 rounds, until steps.verify.outputs.blocking == 0, accepts when out of rounds and goes on. Fragment lib/review-loop.yaml | |||||
ci | script · dev-write | timeout 15m | |||
review | agent · Sonnet · dev-read | findings | 2 instances in parallel | timeout 20m | |
security | agent · Sonnet · dev-read | findings | timeout 20m | ||
verify | agent · Sonnet · dev-read | blocking, nits, pre_existing | timeout 20m | ||
reflect | agent · Sonnet · dev-read | recommendation, reason | timeout 15m | ||
Where cases come from
A case is the change that round 1 of a past review looked at, plus the real issues a person confirmed. Cases are stored on the local machine in myorch-data/evals/cases/<case ID>.json.
| Stage | Who | What |
|---|---|---|
| Collect | myorch eval collect |
Scans all runs. A development or review run becomes a candidate when its round-1 verified.json has an Important or Nit with a file location. The case ID is that run's ID. Pre-existing findings do not count as issues of this change. It records the comparison range (base and head commits), the commits on the branch, the requirements document of the time (docs/requirements.md, or docs/pr.md when there is none) and the findings. Cases that already exist are not collected again |
| Confirm | You, in the console under Flows → Eval set (流程 → 评测集) | Mark each finding that really is an issue and click Add to eval set (收入评测集). The state becomes confirmed. When none of them is, click None are real issues (都不是真问题) and the case is dropped. For old runs that did not record a head, the head is inferred (the first commit on the branch), and the page asks you to check it |
| Replay | myorch eval run |
Starts one eval per confirmed case and per depth. All runs of one batch share a batch ID. Uses the latest version of the project pack and attaches no knowledge sources |
| Score | myorch eval report |
Reads each replay's docs/review/round-1/verified.json and compares it with the marked findings. See "How scoring works" |
postmortem also creates cases (origin: git). The change is the commit in the project repository that introduced the problem. It does not come from a myorch run, and the case ID is the postmortem run's ID. The postmortem starts these replays itself: once with the knowledge of the time, and, when you adopt the knowledge changes it proposes, once more with the new knowledge. myorch eval report --batch <postmortem run ID> shows them.
What each step does
| Step | What it does | Artifacts |
|---|---|---|
prepare |
Reads docs/eval/case.json. Clones the repository from the source run's own workspace (mounted read-only, so commits that were never pushed to GitHub can be replayed too). Postmortem cases are cloned from GitHub. Checks out the case's head, then deletes the origin remote, all other refs and the reflog, runs a gc, and points origin/eval-base at the case's base. Writes the requirements document of the time to docs/eval/requirement.md |
repo/, docs/eval/requirement.md |
review-round loop (1 round) |
The same review round as in review: ci → review (the count depends on the depth) and security → verify. The comparison base is eval-base, and the requirements document is docs/eval/requirement.md. There is no fix. When the loop runs out of rounds, the result is accepted automatically |
docs/ci/round-1.md, docs/review/round-1/ |
The depths are the same three as in review. See the preset table above.
Not leaking the answers
- The answer key stays out of the workspace:
myorch eval runwrites only the case fields that may be seen intodocs/eval/case.json: origin, source run, flow, repository, base and head commits, requirements document. The findings a person confirmed stay on the local machine inmyorch-data/evals/cases/. - Later commits are not kept: the source run's later fix commits would tell the reviewer where the problems are. So the repository keeps only the history reachable from head. Branches, remote refs and the reflog are deleted.
- Nothing outside is writable: after
originis deleted, no step in the replay can push. - The reviewer also does not see the source run's technical design, implementation notes or the original ticket text. The workspace contains only the requirements document and the change. So the eval's review has fewer inputs than a review in the real development flow.
How scoring works
Scoring happens on the local machine, not in the flow:
- Only Important and Nit are compared, on both sides.
- Caught: a replay finding is in the same file as a marked finding and the line numbers differ by at most 10 (a match on any one location counts).
- Missed: marked findings that were not caught.
- Extra: findings the replay reported that matched no marked finding. They may be false positives, or real issues nobody flagged at the time. The number of Important ones among them is listed separately.
reportfirst lists each run (depth, case, caught/expected, extra), then sums up per depth: cases, expected, caught, missed, recall (caught ÷ expected), extra, extra Important. Postmortem replays are split into "depth·before" (强度·before) and "depth·after" (强度·after). Runs that have not finished are not counted, and a note at the end says how many are still running.
Where you step in
| When | Console | Command line |
|---|---|---|
| After collecting | Under Flows → Eval set, mark the real issues case by case | Confirming is console-only; myorch eval list shows the state |
| After the runs finish | Open each run and look at docs/review/round-1/ |
myorch eval report --batch <batch> |
The run itself has no questions and no approvals.
Source of this page: docs/en/flows/eval.md
onboard Onboard project
| File | flows/onboard.yaml, prose docs/en/flows/onboard.md |
| Role | onboard (the console task “Onboard project”) |
| Projects | shared by every project |
| In short | Onboard a new project: analyse the repository and propose changes to the project pack. |
| Fragments | lib/sync-base.yaml, lib/choose-proposals.yaml |
Teaches myorch about a project. It reads the repository, tries the project pack's checks on the last few commits, and then proposes additions and fixes to the project pack. You pick which ones to adopt, and it writes them back to myorch-knowledge/<project>/. Later development, review and risk verdicts all depend on this knowledge.
Run it once when you take on a new project, and again when the repository structure changes a lot. It pushes nothing to the project repository and only changes the local myorch-knowledge. Like the other flows, it is shared by all projects. The difference from learn: learn learns from runs that already happened; onboard looks only at the repository itself and can change more files (checks script, setup script, approval rules, security focus).
uv run myorch run flows/onboard.yaml --project <project>
uv run myorch run flows/onboard.yaml --project <project> -i focus="database migrations"
Console: choose the project first, then the task Onboard project (接入项目). The first message is Focus areas (要重点看的地方) and can stay empty.
Inputs
| Input | Label | Type | Required | Default | Description |
|---|---|---|---|---|---|
focus | Focus areas | message | Optional, for example “frontend checks”, “database migrations” |
Step graph
Generated from flows/onboard.yaml, expanded for project mdm with default inputs (another project's pack may leave steps out or change parameters); the same as myorch expand and the console's Flows page (流程).
Each step's executor, condition and outputs (generated from the YAML)
| Step | Runs as | Condition | outputs | People and parallelism | Limits |
|---|---|---|---|---|---|
sync | script · dev-git | timeout 15m · retries 1 | |||
try-checks | script · dev-write | passed | timeout 60m | ||
analyze | agent · Opus · dev-read | proposals | timeout 40m | ||
choose | script · dev-read | steps.analyze.outputs.proposals > 0 | accepted | can ask you questions | timeout 30m |
apply | host action · project-apply | steps.choose.outputs.accepted > 0 | timeout 5m |
Before you start
The project pack needs at least a project.yaml, and uv run myorch project sync <project> must have been run. The project's GitHub provider must be set up and the development image built. See 7. Project packs · Onboarding a new project for the steps.
focus is appended as is to analyze's task description, for example "frontend checks" or "database migrations", so that it spends more effort there.
What each step does
| Step | What it does | Artifacts |
|---|---|---|
sync |
Clones the repository, checks out the latest base branch, initialises submodules (lib/sync-base.yaml) |
repo/ |
try-checks |
Runs setup.sh first when there is one, then runs checks.sh on the last 5 commits as a sample change, and records the results and timings |
docs/onboard/checks/ |
analyze |
Reads the repository, the repository's own docs, the current project pack and the trial results, and writes a project overview and change proposals. Changes neither the repository nor the project pack | docs/onboard/report.md, proposals.json, proposals.md, open-questions.md |
choose |
Lists the proposals and waits for you to reply with numbers. Skipped when there are no proposals (lib/choose-proposals.yaml) |
docs/onboard/accepted.json |
apply |
Host action project-apply with scope: onboard: validates, writes back to the project pack, commits in myorch-knowledge, re-syncs the snapshot. Skipped when nothing was adopted |
A commit in myorch-knowledge |
try-checks: trying the checks
- Purpose: see whether
checks.shfinds the right modules, how long it takes, and which checks fail for reasons unrelated to the change (environment, network, cache). - The sample change is the last 5 commits of the base branch. When the repository has fewer than 6 commits, it uses the whole history (starting from the empty tree). The changed files are listed in
changed.txt. - The checks run under the
checks.shconventions, withCHECKS_DIRset todocs/onboard/checks/. - Failed checks, a failing
setup.shor a missingchecks.share only recorded in the results; the step still succeeds. These are exactly what analyze needs to look at.
analyze: what it needs to find out
| Area | Content |
|---|---|
| Structure | How the modules are divided, their dependencies, which parts are external contracts (interfaces, protocols, database migrations), where the frontend is |
| Build and checks | How to build, how to test only the affected parts, which private dependencies or environment are needed; whether checks.sh finds the right modules, misses checks, or fails for unrelated reasons |
| Conventions | Code style, how tests are written, commit and PR conventions, and whether they match what guide/ says |
| Risk | Changes to which paths need more approvers (whether risk-rules.yaml misses anything or catches things it should not), what needs special attention for security |
- Each conclusion names its basis (file paths).
- At most 8 proposals, of type
fill-gap(add knowledge),fix-checks(fix the checks),fix-rule(fix the approval rules) orsecurity(security focus). guide/gets only what the repository's own docs do not say and what affects the agent's judgement. The wording is short.- Questions that need a person to answer go into
open-questions.md. The flow does not ask you these questions. After reading them, edit the project pack by hand, or run again with afocus.
Where you step in
| When | Console / Slack | Command line |
|---|---|---|
choose: pick which to adopt |
Reply with numbers in the conversation, or click all or none |
uv run myorch reply <run> choose "1,3" |
- Read
docs/onboard/report.mdandproposals.mdfirst: the Docs (文档) tab in the console's right panel, oruv run myorch ws <run> docs/onboard. - Reply with the numbers only:
1,3,1、3and1 3all work.allor全部adopts all of them;none,无or0adopts none. When a number does not exist or the reply cannot be understood, it asks again. - Once the reply is accepted, it starts running and cannot be changed. Without a reply for 24 hours, this step times out and fails.
Writing back to the project pack
| Can change | Cannot change |
|---|---|
Files under guide/, including new ones |
project.yaml, image/, policy.yaml, providers/, sources/ |
checks.sh, setup.sh |
checks.env (learn can change it) |
risk-rules.yaml, security.md |
Other files, including prompts/ |
onboard cannot change the development flow's per-project settings (flows.development in project.yaml, prompts/; see development's "Per-project differences"). A person changes them by hand when needed.
A change can be written in three ways: exact replacement (edits; old must occur exactly once in the file), append (append), whole file (content).
- It writes only the project's own directory
myorch-knowledge/<project>/. The template_templates/<template>/stays unchanged. guide/,checks.shandsetup.shinherit by override: a file the project only inherits from the template is first copied from the template on its first change, then changed. Soeditscan quote the original text seen in the snapshot.risk-rules.yamlandsecurity.mdinherit by concatenation: the snapshot holds the template's content plus the project's content, and the project's own file holds only the project-specific part. Sosecurity.mduses onlyappend, andrisk-rules.yamluses onlycontent, writing the complete project rules file (arules:list, optionaldefault:). Syncing the snapshot joins it with the template's rules again.- The other rules are the same as for learn; see learn's "Writing back to the project pack": write only when everything validates, commit only the files it wrote, re-sync the snapshot after writing,
git revertis possible. The commit message isonboard(<project>): #1 title; …, and the body hasmyorch-run: <run_id>.
Artifacts
All under docs/onboard/ in the workspace.
docs/onboard/
checks/
changed.txt files of the sample change
report.md checks.sh's report
result.json passed, failed, skipped
report.md project overview and conclusions, each with its basis
proposals.json, proposals.md proposals
open-questions.md questions for a person to answer
accepted.json the numbers you adopted
Source of this page: docs/en/flows/onboard.md
Fragments
Fragments are reusable steps or loops in flows/lib/. A flow refers to one with use:; it is expanded when a run starts. Syntax: User manual · 8. Writing flows. This table is generated from the fragment files.
| File | Kind | What it does | Params | Used by |
|---|---|---|---|---|
flows/lib/choose-proposals.yaml | step | Lists proposals and lets a person pick which ones to adopt | dir, what | learn, onboard, postmortem |
flows/lib/deliver.yaml | step | After approval, pushes the branch and writes the delivery notes (calls no platform API) | approved | development |
flows/lib/e2e.yaml | loop | End-to-end tests: the project's fixed smoke cases + (optional) cases written from the acceptance criteria → (optional) fix, round after round until all pass | image, profile, acceptance, base, max_rounds, fix, on_exhausted, requirement_doc, check_model, fix_model | review |
flows/lib/review-loop.yaml | loop | CI → parallel reviewers + security → verify vote → (optional) fix, round after round until no blocking issue is left | base, reviewers, max_rounds, security, fix, on_exhausted, since, requirement_doc, review_model, verify_model, fix_model | development, eval, review |
flows/lib/sync-base.yaml | step | Clones or updates the project's repository, checks out the latest base branch, initialises submodules | none | development, onboard, sweep |