Two minors in one note. v1.16 and v1.17 are a single arc told in two halves: first the runtime grows the primitives a workflow needs to build on its own output, then the family settles them into place: a breaking config consolidation, a declarative skill-swap seam, a tighter developer checkpoint, and two new search providers. If you skipped straight from the v1.15.0 notes, this is everything since.
Upgrade notes, both at once.
- v1.17 moves workflow config. Project workflow files relocate from
.rpiv-workflow/to a unified.rpiv/workflows/tree. There is no legacy fallback; the new paths are the only ones read. Themvcommands are below, and a load-time warning points at them if you forget.- Refresh the bundled agents. v1.17.1 narrows the
web-search-researcheragent’s tool grant. Run/rpiv-update-agentsinside a Pi session to pick it up.- Still on the pre-1.14 layout? If
/wfreports a missing@juicesharp/rpiv-workflowsibling, run/rpiv-setup.
v1.16: the two primitives a chain needs to build on itself
The workflow runtime that shipped in v1.14 could chain skills, branch on typed output, and loop on a gate. What it couldn’t do was let a stage build on its own prior output within one run. v1.16 adds the two primitives that close that gap, and a bundled workflow that needs both.
iterate: sequential accumulation, the dual of fanout. A
fanout stage computes every unit up front and runs them blind to
one another, the right shape when the units are independent (one Pi
session per ## Phase N: heading of a plan, say). iterate is the
other half: the runner calls your IterateFn one unit at a time and
feeds each call the validated outputs of every prior unit in the same
stage. Return the next unit, or null to terminate. Each unit runs
the stage’s outcome collector exactly like a one-shot produces
pass, so every unit publishes into the same named slot and the next
unit can read it.
import type { IterateFn } from "@juicesharp/rpiv-workflow";
// one pass per review phase, each seeing the plans
// the earlier passes already wrote
const perPhase: IterateFn = ({
artifact,
accumulated,
index,
cwd,
}) => {
if (artifact?.handle.kind !== "fs") return null;
const phases = readPhases(artifact.handle.path, cwd);
if (index >= phases.length) return null; // terminator
const prior = accumulated
.flatMap((o) => o.artifacts)
.map(pathOf);
return {
prompt:
`${artifact.handle.path} Phase ${phases[index].n}` +
(prior.length
? `\nPrior plans: ${prior.join(", ")}`
: ""),
label: `phase ${index + 1}/${phases.length}`,
id: `phase-${phases[index].n}`, // stable audit key
};
};
produces({
outcome: rpivBucketOutcome("plans"),
iterate: perPhase,
});
iterate requires kind: "produces" and an outcome with a name;
every unit accumulates into one slot. It’s mutually exclusive with
fanout and script run, incompatible with
sessionPolicy: "continue" (each unit needs its own clean session),
and backstopped by a run-wide maxIterations cap (default 32).
prompt: raw text straight to the model. Alongside the two
existing dispatches, a skill (/skill:<name>) and a script (run:),
a stage can now carry prompt: string | PromptFn, sending
author-owned text as the user message with no skill body and no
skill-registry check. Prefer the typed builders produces.prompt({…})
/ acts.prompt({…}): they structurally omit skill/run/fanout/
iterate/reads, so an invalid combo fails to compile rather than
only failing load validation.
The sharp use is the continue follow-up: a prompt stage that sends
a turn into a session a prior stage already populated, without
re-invoking a skill. It’s the only honest way to build on a stage
whose output is conversation-only (a frontend-design pass that
emits no artifact, for instance) where the downstream step leans on
the shared context.
When not to. Prompt text in a workflow definition isn’t versioned, localized, or independently testable the way a
SKILL.mdis. Keep prompt stages short and glue-like; anything reusable belongs in a skill.
polish: the workflow that needs both. rpiv-pi 1.16.0 ships a
new bundled chain for a large architecture review that can’t be
planned in one pass:
architecture-review → blueprint (iterate) → implement (fanout) → validate → code-review → commit. Three moves make it work, and each
leans on a v1.16 primitive:
blueprintiterates over the review’s phases. Phase 3’s plan sees phases 1 and 2. Wherefanoutwould plan every phase blind,iteratehands each pass the plans the earlier passes wrote, with the instruction to build on them rather than duplicate.implementfans out over every plan the blueprint pass accumulated: push decomposition, because implementing one phase doesn’t depend on another.validateis apromptstage, and it has to be. A plain positional arg would handvalidateonly the last plan, leaving the earlier phases unvalidated. The prompt stage owns its whole message, so it reaches into the accumulation and builds a/skill:validate <p1> <p2> …call over every plan from the latest blueprint pass.
The review loop routes on the same { blockers_count } schema as
build, but the backward edge returns to blueprint: a corrective
pass re-plans every phase with the blockers folded in, under the same
maxBackwardJumps bound. The new
Compose skills as skills
guide walks the whole thing as the iterate-plus-prompt capstone,
including the four-questions authoring protocol.
v1.16.1 is the install-hardening patch that always tails a new
file: iterate.ts was git-tracked but missing from the published
files allowlist, so an npm install shipped stage-lifecycle.ts
without the ../iterate.js it imports. Source builds and CI passed
because the file was on disk, which is exactly why it slipped
through. Fixed.
v1.17: settling the primitives into place
With the primitives landed, v1.17 is about making them livable: where the config lives, how you reuse a bundled chain without forking it, and how the design loop decides what to ask you.
The workflow config tree moved (breaking)
Project workflow config consolidates from .rpiv-workflow/ into the
unified .rpiv/workflows/ tree, with the three concerns each in their
own subfolder:
mkdir -p .rpiv/workflows
mv .rpiv-workflow/workflows.config.ts \
.rpiv/workflows/config.ts
mv .rpiv-workflow/workflows .rpiv/workflows/packs
# run state moves too:
# .rpiv/workflows/<run-id>.jsonl
# → .rpiv/workflows/runs/<id>.jsonl
The user layer aligns for symmetry:
~/.config/rpiv-workflow/{config.ts, packs/}. These are the only
locations read; no legacy fallback. Load-time warnings (advisory,
never blocking) fire on a stale project .rpiv-workflow/ directory,
orphaned top-level *.jsonl run files, or a legacy
~/.config/rpiv-workflow/workflows.config.ts, each pointing at its
mv.
The gitignore gotcha.
.rpiv/workflows/is commonly gitignored because it holds ephemeral run state, which means the movedconfig.tsandpacks/may be silently uncommittable.git add .rpiv/workflows/config.tsbecomes a no-op with no error. If you version-control your workflow config, un-ignore the config surface, e.g. add!.rpiv/workflows/config.tsand!.rpiv/workflows/packs/to.gitignore. The overlay warning now carries this advisory inline.
One API rename rides along: the public workflowsDir export is now
runsDir and points at .rpiv/workflows/runs (was
.rpiv/workflows). Update any direct importers.
skillAliases: reuse a bundled chain, swap one skill
You often want a bundled chain (ship, build, arch, vet,
polish) exactly as shipped, but with one skill swapped for your
own. The canonical case is model attribution on commits: a team
authors an attributed-commit skill and wants every chain to use
it. Forking five workflow definitions to change one stage is the
wrong move; they’d drift on the next upgrade.
skillAliases is the seam. One declarative entry in config.ts
remaps a skill name across every loaded workflow (built-in,
user, and project) at load time:
// .rpiv/workflows/config.ts
export default {
skillAliases: { commit: "attributed-commit" },
};
Now every stage that would dispatch /skill:commit dispatches
/skill:attributed-commit, and the bundled definitions stay
byte-for-byte untouched and upgrade-safe. It keys on the skill name
(stage.skill ?? <stage key>), so it catches both implicit and
explicit-skill: stages; it’s one hop only (no transitive chains);
run/prompt stages are skipped; project overrides user per key.
It’s visible, not magic: /wf previews a
Skill aliases in effect: commit → attributed-commit banner, and an
alias key matching no dispatched skill anywhere surfaces a load-time
warning. An alias-only config.ts with no workflows block is now
valid; packs still reject the envelope, keeping default and aliases
one-source-of-truth-per-layer.
A sharper design/blueprint checkpoint
rpiv-pi 1.17.0 splits the developer checkpoint in design and
blueprint into two tiers. Directional decisions
(extend-vs-replace, propagate-a-pattern, spread-a-convention) now get
a single batched confirm at Step 4, separate from genuine
ambiguities. “Follow the pattern” is offered without a Recommended
badge; choosing “move off” promotes the finding to a one-at-a-time
genuine question. And every slice now renders a mandatory Fit
line at Step 6.3 (reused / new surface / convention)
regardless of the omit list, so you always see how a slice relates to
what’s already there.
Two new search providers
rpiv-web-tools 1.17.1 adds two:
- You.com: a
FullProviderbacked by You.com’s Search API (POST /v1/search) and Contents API (POST /v1/contents), returning native markdown (contentType: "text/markdown").web_fetchuses the Contents API for clean extraction, the same path as Jina/Firecrawl. Configure viaYOUCOM_API_KEYorapiKeys.youcom. - Perplexity: a search-only
SearchProviderposting toPOST https://api.perplexity.ai/search.web_fetchfalls through to the shared raw-HTTP + htmlToText pipeline (the Brave/Serper/ SearXNG path). Configure viaPERPLEXITY_API_KEYor paste the key through/web-tools. $5/1K requests, 50 RPS.
Fixes worth calling out
- Clean
npm install @juicesharp/rpiv-pino longer crashes when the@juicesharp/rpiv-workflowpeer is absent. Built-in workflow registration is now deferred behind a guarded dynamic import, so/rpiv-setupand the missing-siblings banner always load and can offer to install the sibling. (1.17.0) web-search-researcheragent tool-gating. Underpi-subagents0.10 the bundled agent now selects onlyweb_searchandweb_fetchinstead of exposing the fullrpiv-web-toolssurface. Run/rpiv-update-agentsto refresh. (1.17.1)- Slice verification skips cross-slice walks for slices that share
no files or symbols, cutting verification time on large
blueprint/designplans. (1.17.1) - rpiv-workflow loader hardening: a present-but-non-array
workflowsfield is now a load error instead of aTypeError, restoring the “loader never throws” contract; and the in-product legacy-migration shell now creates the destination directory and globspacks/*.tscorrectly. (1.17.0)
On the site
rpiv-site 1.17.0 shipped the
Compose skills as skills
authoring guide, the producer’s tour to match the consumer’s
Run a workflow, documenting the
four-questions protocol, the three dispatch modes, and the
fanout/iterate split through the polish walkthrough. Docs now
reference the unified .rpiv/workflows/ paths and skillAliases,
the blogroll rows are fully clickable, and the agent carousel got
working drag and keyboard navigation.
Anything else?
Every other package in the @juicesharp/rpiv-* family rode the
lockstep bump to 1.17.1 with no user-visible changes. rpiv-advisor
gained fuzzy type-to-filter in its model and reasoning-level pickers
(1.16.0), and rpiv-warp fixed a stale “Waiting for your answer”
badge left behind when ESC refuses a blocking prompt (1.16.0).
Grab the new version the usual way:
npm install @juicesharp/rpiv-pi@1.17.1
Or let your normal upgrade flow pick it up, then run
/rpiv-update-agents once for the agent tool-gating fix, and migrate
your workflow config if you keep one. The full per-package changelog
lives in each package’s CHANGELOG.md in the
monorepo.
See you at v1.18.0.