Files
openprose__prose/packages/std/controls/guard.md
irl-dan 63c8ce4b23 Migrate std and co into packages/ monorepo layout
Move the standard library (previously `github.com/openprose/std`) and
the company-as-prose library (previously local dir
`/Users/sl/code/openprose/company-as-prose`) into this repository
under `packages/std/` and `packages/co/` respectively.

Motivation: concentrate attention on one repository so stars,
discussions, and issues aggregate. `openprose/std` was a genuinely
useful asset nobody could find because ~50 stars on its own repo
told a much worse story than 1,106 stars on `openprose/prose`
would have. Same logic applies to co.

Layout choice: `packages/{std,co}/` rather than `std/` + `co/` at
the repo root. Root siblings accumulate over time, and a flat
top-level made future libraries (hub, kit, dev, etc.) compete with
spec infrastructure. `packages/` is bounded — new libraries land
there without cluttering root. Matches pnpm/Deno/monorepo tooling
conventions.

Changes:

- New: `packages/std/` (copied from openprose/std, `.git` excluded)
- New: `packages/co/` (copied from company-as-prose, README updated
  for new name and location)
- `packages/std/README.md`: updated shorthand expansion reference
- `packages/co/README.md`: renamed "company-as-prose" to "co" in
  self-references, added std-vs-co split heuristic, updated
  `prose run` examples to use `co/` shorthand
- `skills/open-prose/deps.md`:
  - `std/` shorthand now expands to
    `github.com/openprose/prose/packages/std/`
  - `co/` shorthand added, expands to
    `github.com/openprose/prose/packages/co/`
  - Both shorthands resolve into the same clone of
    `openprose/prose` under `.deps/github.com/openprose/prose/`;
    `packages/std/` and `packages/co/` are sibling subdirectories
  - `prose.lock` format row updated to `host/owner/repo sha`
    (matches the explicit-host resolution that landed in #35)
  - `.deps/` directory structure example redrawn to show the
    `{host}/{owner}/{repo}/packages/{std,co}/...` shape
  - Error message and Interaction tables refreshed accordingly
  - Resolution Algorithm step 1 now documents both shorthands
- `skills/open-prose/forme.md`: Step 2 resolution list updated to
  include co/ shorthand and the host-keyed `.deps/` layout
- `skills/open-prose/help.md`: Q&A "How do dependencies work?"
  rewritten to name both shorthands and the new explicit-host model
- `skills/open-prose/state/filesystem.md`: `.deps/` directory
  tree re-drawn to include the `{host}/` layer with std/co as
  sibling packages inside the clone
- `skills/open-prose/guidance/patterns.md`,
  `skills/open-prose/guidance/antipatterns.md`: examples now use
  the `std/` shorthand or explicit `github.com/...` rather than
  the deprecated bare `openprose/std/` form
- `skills/open-prose/examples/registry-import/index.md`: sample
  service reference switched to `std/evals/inspector`
- `README.md`: Stdlib badge replaced with internal `packages/std/`
  link plus new `packages/co/` link; "Standard Library" section
  rewritten as "Libraries" with both packages described

Out of scope for this PR (deliberately):
- Tooling changes to `prose install` and Forme's `.deps/` writer
  to adopt the `{host}/{owner}/{repo}/` layout in practice — this
  PR is spec-only. Existing tooling continues to work against
  whatever layout it currently implements; the spec now describes
  the target.
- Retiring the `openprose/std` GitHub repo. Delete that repo
  separately after this merges.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 14:14:31 -07:00

2.9 KiB

name, kind
name kind
guard composite

Guard

Check before delegating. Fail-fast pattern.

Metadata

  • version: 0.2.0
  • role: coordinator

Runtime

  • state.reads: &controlState
  • state.writes: &controlState

Slots

  • guard
  • target

Shape

  • self: delegate to guard, if cleared delegate to target, otherwise return guard's reason
  • delegates:
    • guard: evaluate whether the task should proceed
    • target: execute the task if guard approves
  • prohibited: none

Requires

  • &controlState exists at __controlState with: guard: string -- component name for the guard target: string -- component name for the target task_brief: string -- the task (goes to both guard and target)

Ensures

  • Guard receives the brief and returns structured JSON: { proceed: boolean, reason: string }
  • If proceed: target receives the ORIGINAL brief unchanged
  • If blocked: return immediately with the guard's reason — no delegation to target
  • The guard does NOT modify the brief based on output — binary pass/block
  • &controlState.result contains the target's output (if proceeded) or guard's reason (if blocked)
  • &controlState.proceeded is true/false

Delegation

const { guard, target, task_brief } = __controlState;

// Guard decides — expects structured JSON output { proceed, reason }
const guardBrief = `Evaluate whether this task should proceed.\n\nReturn your decision as JSON: { "proceed": true/false, "reason": "..." }\n\n${task_brief}`;
const guardResult = await rlm(guardBrief, null, { use: guard });

// Parse the guard's structured output
let decision;
try {
  const jsonMatch = String(guardResult).match(/\{[\s\S]*"proceed"[\s\S]*\}/);
  decision = JSON.parse(jsonMatch[0]);
} catch {
  // If the guard fails to return structured output, treat as blocked — fail safe
  decision = { proceed: false, reason: `Guard returned unparseable output: ${String(guardResult).slice(0, 200)}` };
}

if (!decision.proceed) {
  __controlState.result = decision.reason;
  __controlState.proceeded = false;
  return(decision.reason);
}

// Target executes
const result = await rlm(task_brief, null, { use: target });
__controlState.result = result;
__controlState.proceeded = true;
return(result);

Notes

The guard does not know it controls access to another component. The target does not know a guard was consulted. The guard is a binary decision point — not a filter that modifies the brief. Useful when delegation is expensive and preconditions should be checked cheaply first.

The guard's contract promises structured JSON output ({ proceed, reason }). The delegation code parses that structure directly. If the guard returns unparseable output, the control fails safe by blocking — a guard that cannot clearly approve is a guard that has not approved.

Different from refine: a guard makes a one-shot binary decision before work begins. Refinement improves work that has already been done.