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>
4.3 KiB
name, kind
| name | kind |
|---|---|
| retry-with-learning | composite |
Retry With Learning
Retry a component, passing failure analysis to each subsequent attempt. Each retry differs because it receives the history of all prior failures.
Metadata
version: 0.2.0role: coordinator
Runtime
state.reads: &controlStatestate.writes: &controlState
Slots
target
Shape
self: analyze failures, enrich briefs with failure history, track attemptsdelegates:target: execute the task
prohibited: none
Requires
- &controlState exists at __controlState with: target: string -- component name to retry task_brief: string -- the original task max_retries: number -- (optional, default 3) failure_criteria: string -- (optional) declarative description of what constitutes failure. The coordinator interprets this against the result. e.g., "result contains 'no results found' or is empty" Default: retry on thrown error only.
Ensures
- First attempt: target receives the original brief
- On failure: analyze what went wrong, construct enriched brief with: original task, what was tried, why it failed, what to try differently
- Each retry receives the FULL failure history, not just the last attempt
- Returns on first success
- After max_retries: returns the last result with &controlState.failure_history
- &controlState.result contains the final output
- &controlState.attempts contains the attempt count
- &controlState.failure_history contains analysis of each failed attempt
Delegation Loop
const { target, task_brief, max_retries = 3, failure_criteria } = __controlState;
const failures = [];
for (let attempt = 0; attempt < max_retries; attempt++) {
let brief = task_brief;
if (failures.length > 0) {
brief += `\n\nPrior attempts failed. You MUST try a different approach.\n`;
failures.forEach((f, i) => {
brief += `\nAttempt ${i + 1}: ${f.summary}\nFailure reason: ${f.reason}\n`;
});
}
try {
const result = await rlm(brief, null, { use: target });
// Evaluate failure_criteria declaratively against the result
if (failure_criteria) {
const evalBrief = `Does this result satisfy the failure criteria? Criteria: "${failure_criteria}"\n\nResult:\n${String(result).slice(0, 2000)}\n\nRespond with JSON: { "is_failure": true/false, "reason": "..." }`;
const evalResult = await rlm(evalBrief, null, {});
try {
const jsonMatch = String(evalResult).match(/\{[\s\S]*"is_failure"[\s\S]*\}/);
const evaluation = JSON.parse(jsonMatch[0]);
if (evaluation.is_failure) {
failures.push({ summary: String(result).slice(0, 200), reason: evaluation.reason });
continue;
}
} catch {
// If evaluation is unparseable, treat as success — fail open on ambiguity
}
}
__controlState.result = result;
__controlState.attempts = attempt + 1;
__controlState.failure_history = failures;
return(result);
} catch (e) {
failures.push({ summary: `Error: ${e.message}`, reason: e.message });
}
}
__controlState.result = null;
__controlState.attempts = max_retries;
__controlState.failure_history = failures;
return(null);
Notes
The target component does not know it is being retried. Each invocation looks like a fresh delegation — the failure history appears as context in the brief, not as retry metadata.
The failure_criteria parameter is a declarative string, not a function. The coordinator interprets it against the result using natural language evaluation, consistent with Prose's file-based contract model. Examples: "result contains 'error' or is empty", "result does not include a valid URL", "result has fewer than 3 items".
Different from refine: retry-with-learning recovers from failure — the result is broken, empty, or wrong. Refinement improves mediocrity — the result exists but is not good enough. Retry passes failure analysis. Refinement passes improvement suggestions. A result that throws an error needs retry. A result that scores 0.4 needs refinement.
Different from fallback-chain: retry-with-learning retries the SAME component with enriched context. Fallback-chain tries DIFFERENT components in preference order.