Owner gate

SkillDev tools

Raise a factory gate as a durable Inbox Human Intention and block on the owner's decision.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Owner gate skill

What this skill tells your AI

The instructions your AI receives, as published by hachej/boring-ui in .agents/skills/owner-gate/SKILL.md and read by ahel’s review.

A factory gate is a point where the owner decides and the seat must not proceed. There is exactly one transport: the ask_user tool, which raises an Inbox Human Intention and blocks your turn until the owner answers. docs/procedures/owner-review-card.md says WHAT to put in front of the owner; this says HOW it reaches them.

Never substitute a chat message, a bead comment, or a "let me know" for a gate. A gate that did not become an inbox item did not happen.

Everything below is a default. The host and the owner decide. A host notice, a host tool result, or an owner instruction relayed in a prompt overrides any default in this skill; comply in the same turn and record the override in the gate card or handoff (AGENTS.md hard rule 1). Owner-owned Beads (assignee owner) never block a gate.

Titles follow docs/procedures/naming-conventions.md: [Feature Name] Plan approval / [Feature Name] Merge approval — never lead with a bead id.

The two gates

The visual is expected at both gates — read ../show-me/SKILL.md for its view-selection table before producing either artifact below.

  • Gate 1 — plan approval (Orchestrator). Raised after the Bead graph is materialized and the (at most one) adversarial plan review is done, or when the host's plan budget is reached, or when the epic is review-only/docs-only. Links the plan doc. Also write docs/issues/<issue>/show-me-plan.md with at most three views selected from show-me's table: the structure view (a shallow file tree or component tree of what the epic touches), the behavior view (a call tree or mermaid sequence of the new flow), and a diff-shaped view of what changes in the existing shape. Pass it as an artifacts[] entry:

    {
      "id": "show-me-plan",
      "surfaceKind": "workspace.open.path",
      "target": "docs/issues/<issue>/show-me-plan.md",
      "title": "[Feature Name] Plan, visually"
    }
    

    context still starts with the one-sentence line; the show-me artifact adds to it, never replaces it.

  • Gate 2 — merge approval (Orchestrator). Raised once every epic Bead is handed off (per factory_status or its equivalent): open or update the epic PR (title [Feature Name] <what changed>, body = the Owner Review card from docs/procedures/owner-review-card.md, then a ## Show me section, then ## Handover), start a demo_sandbox at the exact SHA when that tool is available, and put its URL on the card's Artifact: line and again in context with its expiry. When demo_sandbox returns an error after its fallback, raise the gate anyway and put the exact error under Demo:. Must name the exact SHA and the expected target head; a docs-only commit of the show-me/presentation artifacts after the reviewed SHA does not void the review — cite both SHAs. The ## Show me section carries diff-shaped views (component/call/file tree diff) plus one sequence diagram of the shipped flow, derived from the actual commits — never from memory of the plan. Write the same views to docs/issues/<issue>/show-me-<short sha>.md and pass it as an artifact next to the present-pr artifact when one exists:

    {
      "id": "show-me-pr",
      "surfaceKind": "workspace.open.path",
      "target": "docs/issues/<issue>/show-me-<short sha>.md",
      "title": "[Feature Name] What changed, visually"
    }
    

    A seat may never approve its own request — you raise it, the owner answers it.

The call

ask_user takes title, context, artifacts, and a form schema:

{
  "title": "[Farewell API] Merge approval",
  "context": "The farewell export is ready to merge.\nPR #1234 · head abc1234 · target main\nDemo: https://demo.example/abc1234 (expires in 30m)\nProof: 41 tests green, thermo clean.\nRisk: read-only view, revert = revert the commit.\nPlease test: open Tasks -> Epics, expand br-1100, toggle 'Show closed'.",
  "artifacts": [
    {
      "id": "plan-note",
      "surfaceKind": "workspace.open.path",
      "target": "docs/issues/1187/plan.md",
      "title": "Plan note",
      "description": "Short plan note for this epic"
    }
  ],
  "schema": {
    "wireVersion": 1,
    "submitLabel": "Record decision",
    "fields": [
      {
        "type": "radio",
        "name": "decision",
        "label": "Decision",
        "required": true,
        "options": [
          { "value": "approve", "label": "Approve — merge at this SHA" },
          { "value": "changes", "label": "Request changes" },
          { "value": "defer", "label": "Defer" },
          { "value": "reject", "label": "Reject" }
        ]
      },
      { "type": "textarea", "name": "notes", "label": "Notes", "required": false }
    ]
  }
}

Rules that make the item usable rather than merely present:

  • title follows docs/procedures/naming-conventions.md: [Feature Name] Plan approval or [Feature Name] Merge approval — never a bead id. The feature name, not the id, is the thing the owner recognizes at a glance.
  • The first line of context is one plain sentence about what this is — no ids in it. Ids (bead id, PR number, SHA, demo URL) come after that line.
  • artifacts[].surfaceKind must be a surface kind the workspace can open. workspace.open.path with a workspace-relative target opens a file in a pane — that is how a plan note or proof file reaches the owner. A surface kind nothing resolves is a dead row in the Inbox.
  • URLs are not artifacts. There is no external-URL surface. PR links, CI links, demo URLs, and SHAs go in context as plain text (and, at Gate 2, on the card's Artifact: line too).
  • Everything the owner needs to decide is in context. They should not have to open a session transcript. State what changed, the risk and rollback, the proof, and the exact test steps.
  • Ask a decision, not an essay. A radio/select decision field plus an optional notes textarea. Max 8 fields.

After the answer

The tool returns the owner's values to you, and the same exchange is durable in the workspace — it, not chat, is the decision record.

  • approve at Gate 1 → arm durable supervision and dispatch Workers.
  • approve at Gate 2 → comment on the PR that the owner approved at that SHA and report; the agent never merges — the owner merges.
  • changes/defer/reject at Gate 2 → open follow-up Beads labelled epic:<key> and dispatch a Worker; never overwrite prior review evidence, never merge.
  • changes/defer/reject at Gate 1 → revise the plan and re-raise, or stop and report.
  • In every case, only at the SHA/plan you named. If the head moved with code, the approval is void; re-raise. Docs-only artifact commits are cited, not re-gated.

If the tool errors or is unavailable, fall back to a GitHub comment on the PR carrying the same card, and say in your handoff that the fallback was used.

Failure modes

  • Restart loses the question. A pending intention whose server restarted is marked abandoned, not answered. Treat an abandoned gate as unanswered and re-raise it; never read it as consent.
  • A cancelled ask returns an error, not a decision. Same rule: unanswered.
  • Rate limits are 6 asks per session per minute. Gates are rare; if you are hitting that, you are asking questions that belong in the work, not at a gate.

Return: the intention's title, the artifacts it carried, the owner's decision verbatim, and the action you took because of it.

Signals

GitHub stars
46
Forks
2
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
owner-gate
Source
github.com/hachej/boring-ui