Set Up Scheduled Verification
Scheduled verification is where Orcho becomes specific to your repository. You declare the commands the project already trusts; Orcho decides which ones apply to a run, gives them a lifecycle identity, executes the eligible gates, and records immutable proof.
inspect the project → declare environments and commands → classify cost from evidence → group, select, and schedule → choose policy and failure action → inspect the effective contract → read receiptsDo not start by copying a Python, JavaScript, or PHP example. Start with the repository’s own instructions, manifests, package scripts, CI workflows, and developer documentation.
If those checks already run in CI, that is evidence for their command and importance, not a reason to skip the contract. Keep CI as the independent repository gate. Declare the same project-native proof in Orcho when you need it selected, scheduled, repaired, handed off, and recorded before delivery. The contract adds lifecycle ownership and receipts; it should not fork the project’s quality system.
One small, complete contract
Section titled “One small, complete contract”Create the project plugin at:
your-project/.orcho/multiagent/plugin.pyThen declare a contract using commands that are real for that project:
PLUGIN = { "name": "Checkout API", "language": "Python 3.12", "verification_envs": { "project": {"python": "python"}, }, "work_mode": "pro", "verification": { "default_env": "project", "commands": { "lint": { "run": ["python", "-m", "ruff", "check", "."], "cost": "fast", }, "unit": { "run": ["python", "-m", "pytest", "-q", "tests/unit"], "cost": "moderate", }, }, "gate_sets": { "hygiene": { "commands": ["lint"], "default_policy": "require", }, "tests": { "commands": ["unit"], "default_policy": "require", }, }, "selection": [ {"always": ["hygiene"]}, { "paths": ["app/**", "tests/**"], "include": ["tests"], }, ], "schedule": [ { "after_phase": "implement", "gate_sets": ["hygiene"], "action": "repair_loop", }, { "after_phase": "implement", "gate_sets": ["tests"], "action": "repair_loop", }, ], },}The example is intentionally asymmetric. lint is proven, fast, required,
repairable, and universal, so it is selected always. The unit suite is
moderate, required, and repairable, but only selected when application or test
paths change. Do not default everything to warn: use require for a proven
load-bearing check, warn for a genuinely advisory diagnostic, and operator
selection for checks whose environment or consequence is still uncertain.
Cost has four values
Section titled “Cost has four values”Cost describes expected execution effort. It does not decide whether a gate is selected, who executes it, or whether failure blocks delivery.
| Cost | Use it when |
|---|---|
fast | The check is bounded, deterministic, local, and cheap enough for the normal implementation loop. |
moderate | The check needs materially more setup or time than immediate feedback, but remains routine during ordinary development. |
slow | The proof is broad, expensive, service-heavy, serial, or long-running enough to shape run latency. |
unknown | There is not enough reliable evidence, or behavior is too variable to predict. |
Classify from observation, not from the command’s name. A focused test can be
fast while a repository-wide formatter can be slow. If several commands in a
gate set share a cost, declare default_cost on the gate set; a command-level
cost overrides it.
Quality gate strategy owns the practical p90 bands and full-boundary measurement method.
Granularity is per executable proof
Section titled “Granularity is per executable proof”The useful unit of cost is the smallest independently selectable and
schedulable command receipt. Do not describe a mixed bundle such as
make qa as moderate when it hides a 5-second linter, a 90-second unit suite,
and a 12-minute integration suite. Declare those commands separately, then
place them in gate sets that share the same semantic selection and lifecycle:
"commands": { "lint": { "run": ["make", "lint"], "cost": "fast", }, "unit": { "run": ["make", "test-unit"], "cost": "moderate", }, "integration": { "run": ["make", "test-integration"], "cost": "slow", },},"gate_sets": { "hygiene": { "commands": ["lint"], "default_policy": "require", }, "application-tests": { "commands": ["unit"], "default_policy": "require", }, "integration-proof": { "commands": ["integration"], "default_policy": "require", },},This is what cost granularity buys: lint can run after every implementation,
unit can be path-selected and repairable, and integration can run only for
relevant changes at the delivery boundary. Each result gets its own immutable
receipt and can be reused as fresh evidence without rerunning unrelated work.
Keep one native command when it is genuinely atomic. Split a wrapper only when
its components are stable public commands with meaningful independent
outcomes; do not reproduce private setup logic in plugin.py.
Keep these axes independent:
cost ≠ selection ≠ schedule ≠ executor ≠ policy ≠ actionChanging slow to moderate must not silently make a check required, move it
to another hook, or transfer ownership to an implementation agent.
Turn cost into a scheduling decision
Section titled “Turn cost into a scheduling decision”Cost does not execute policy, but it is not decorative. The contract author uses measured cost together with four other questions:
- Is this proof universal, path-specific, task-specific, or rare?
- Is failure normally repairable in source code?
- Must the proof exist before delivery, or is independent post-push CI enough?
- Does the command need services, credentials, destructive setup, or serial infrastructure?
Answer those questions first, then choose selection, schedule, policy, and
action explicitly. Do not build a hidden rule such as “slow means warn” or
“fast means always.” A slow security proof may be release-blocking; a fast
diagnostic may still be merely advisory.
Practical cost-to-schedule matrix
Section titled “Practical cost-to-schedule matrix”| Observed cost | Good default design | Escalate when | Avoid |
|---|---|---|---|
fast | Select always only for universal checks; otherwise use paths. Schedule repairable checks at after_phase(implement). A proven load-bearing check can be require + repair_loop. | Use before_delivery when the check is meaningful only at the final boundary or failure is not safely repairable. | Repeating the same command at multiple hooks without a distinct proof requirement. |
moderate | Prefer paths or an explicit task_kind. Use after_phase(implement) when routine failure should enter repair. | Use before_delivery + handoff for integration proof that must block but should not start a repair loop. | Selecting every moderate suite always merely because CI already runs it. |
slow | Narrow with paths, task_kind, or explicit operator opt-in. Put final release proof at before_delivery; use manual_only when it is rare or operational. | A slow after_phase(implement) + repair_loop is valid when the proof is load-bearing, reliably repairable, and its retry budget is worth the time. | Automatic broad execution on every task, or using warn only to hide the cost. |
unknown | Keep it manual_only or behind operator selection while measuring exact argv, cwd, services, credentials, duration, and failure shape. | Promote to fast, moderate, or slow only after observed evidence supports predictable execution. | Auto-running it to “finish configuration,” or assigning a guessed cost from the tool name. |
These are authoring defaults, not runtime transformations. Orcho will execute the contract you declare; it will not move a gate because its cost changes.
Choose the selection rule before the hook
Section titled “Choose the selection rule before the hook”| Selection | Use it for |
|---|---|
always | A universal repository invariant whose proof is relevant to every change. |
paths | Subsystem tests, generated-code checks, schema validation, or builds relevant only when matching files changed. |
task_kind | A check tied to an explicitly declared work class such as migration or release work. Task kind is not guessed automatically when the run has no declared value. |
operator | Rare, expensive, credentialed, destructive, or deliberately requested proof. With no opt-in, the set is not selected. |
Selection reduces irrelevant work. It must express semantic relevance, not only
runtime duration: do not use paths to suppress a slow check that is actually a
universal release invariant.
Choose the hook from the desired transition
Section titled “Choose the hook from the desired transition”The authorable hooks are before_phase, after_phase, before_delivery,
on_resume, and manual_only.
| Hook | Best use | Failure design |
|---|---|---|
before_phase(<phase>) | A prerequisite that must hold before entering that phase. | Prefer handoff or explicit abort when repair has not started yet. |
after_phase(implement) | Code checks that should give early, actionable feedback. | repair_loop is a real implement → repair transition here when the profile has repair_changes. |
before_delivery | Final integration, packaging, compatibility, or release proof that must be current at the delivery boundary. | A required failure normally hands off for an operator decision; use explicit abort only for a deliberate terminal policy. |
on_resume | Reassert assumptions that may have changed while a run was paused. | Treat failure as a resume decision, not an ordinary code-repair loop. |
manual_only | Credentialed, destructive, rare, or still-unproven commands. | manual or suggest; the engine does not auto-run it. |
repair_loop is executable repair only at after_phase(implement). At other
hooks it degrades visibly to handoff, because there is no valid
implement → repair transition to drive.
pre-final is not a hook you write in plugin.py. It is the derived
operator-facing stage used for eligible non-required gates when a profile has a
final phase. Author the real hook and policy; inspect the effective when
column with orcho quality-gates --profile <work-kind>.
Three patterns worth copying
Section titled “Three patterns worth copying”Fast universal hygiene
"commands": { "lint": {"run": ["make", "lint"], "cost": "fast"},},"gate_sets": { "hygiene": { "commands": ["lint"], "default_policy": "require", },},"selection": [{"always": ["hygiene"]}],"schedule": [{ "after_phase": "implement", "gate_sets": ["hygiene"], "action": "repair_loop",}],Slow subsystem proof at delivery
"commands": { "payments-integration": { "run": ["make", "test-payments-integration"], "cost": "slow", },},"gate_sets": { "payments": { "commands": ["payments-integration"], "default_policy": "require", },},"selection": [{ "paths": ["src/payments/**", "tests/integration/payments/**"], "include": ["payments"],}],"schedule": [{ "before_delivery": True, "gate_sets": ["payments"], "action": "handoff",}],Unknown external proof kept operator-owned
"commands": { "staging-smoke": { "run": ["./scripts/staging-smoke"], "cost": "unknown", },},"gate_sets": { "external": { "commands": ["staging-smoke"], "default_policy": "suggest", },},"selection": [{"operator": ["external"]}],"schedule": [{ "manual_only": True, "gate_sets": ["external"], "policy": "suggest",}],Decide who owns execution
Section titled “Decide who owns execution”require and warn scheduled identities are engine-owned. The engine invokes
the native command, writes the authoritative receipt, and applies the declared
consequence.
manual and suggest identities remain operator-owned. Use them when a check
needs credentials, external services, destructive setup, or a deliberate
human decision.
Implementation agents may still run focused tests, lint changed files, or use another bounded command while debugging. What they should not do is duplicate the broad scheduled proof as an implementation subtask. Official readiness comes from the engine receipt.
Inspect before running
Section titled “Inspect before running”Resolve the project contract without executing its commands:
orcho quality-gates --project .Review:
- the selected gate sets;
- the resolved schedule hook and phase;
- executor and policy;
- failure action;
- command cost;
- validation errors or unreachable gate sets.
Fix every contract validation error. Execute only bounded candidate commands needed to confirm their exact arguments and working directory. Do not launch a broad, destructive, or credential-dependent suite merely to finish setup.
Let project instructions teach future agents
Section titled “Let project instructions teach future agents”orcho workspace init creates a language-neutral plugin template and adjacent
agent guidance. When adopting the plugin in a repository:
- copy the template to
.orcho/multiagent/plugin.py; - merge the adjacent agent rules into the repository’s root
AGENTS.md; - keep a root
CLAUDE.mdshim pointing toAGENTS.md; - preserve existing project instructions while adding verification ownership and task-authoring rules.
Those instructions matter whether work arrives through --task, a task file,
an edited plan, or a follow-up. They teach agents to inspect the effective
contract before putting broad commands into acceptance criteria.
For a faster first draft, run the read-only marker inspection:
orcho workspace fine-tune --dry-runThen let a coding agent use the generated rules to inspect the actual
repository and prepare the plugin. Treat both outputs as proposals. An engineer
must approve the exact command, environment, selection, schedule, policy, and
failure action before the gate becomes authoritative. Finish by reviewing
orcho quality-gates; do not accept a contract merely because it validates
syntactically.
Read the result as proof
Section titled “Read the result as proof”The lifecycle is:
declaration → selection → scheduled identity → execution → immutable receipt → readiness consequenceA missing receipt is not a failed test. A stale receipt is not a current pass. The scheduled-gate ledger preserves why each identity ran, did not run, or needs attention. Final acceptance consumes that evidence rather than trusting the worker’s summary.
Deep reference
Section titled “Deep reference”The canonical engineering docs live with the code:
- Scheduled verification guide
- plugin.py field reference
- Task-file authoring and verification ownership
- Quality gate strategy compares concrete Python, PHP/Docker, and TypeScript/browser gate portfolios.
- Project tuning and plugins explains the surrounding project context.
- Gates and verification explains the trust-boundary design.
- Verification receipts shows the durable proof written by the engine.