@projectpac/flow-template
v0.6.0
Published
Part of PAC: @projectpac/flow-template.
Downloads
132
Readme
@projectpac/flow-template
The smallest complete flow, doing the smallest complete network thing: it advertises itself, finds a peer through discovery, opens a session, sends one message, and echoes the same message back when a peer sends it. Locally it answers at once, or asks its own model what to say when configured to.
It exists to keep the sdk honest. Everything it touches -- the host events, the
caller-aware components, the manifest -- comes from @projectpac/sdk and cordis
alone, so if the template compiles and runs, a flow nobody here wrote needs
no core package either. Two things sit beyond them. The router's contract, and
only its types: what a flow declares to ctx.router is the router's shape to
define, so the router is a devDependency imported for the declaration alone, and
nothing of it is loaded at runtime. And @projectpac/prompting, which is
functions rather than a plugin: the kernel hands a turn's text back verbatim and
composes no prompt, so a flow that asks its model anything composes the prompt
and reads the answer itself, and these are the helpers every such flow shares.
That is why the loader smoke suite and the two-node tests reach for the
template: a failure in it is a failure in the seam, not in a workload.
It is also what the name says: the smallest thing to copy when starting a flow of your own.
A seam test and a thing to copy, not a workload. It declares the fallback intent to the router, from an optional scope, so on a node whose router has nothing better it answers -- by echoing; a node with no router runs it all the same. Install it to prove the machinery; uninstall it before it answers for something real.
Nothing is done for it. The flow tells the network this node runs it
(ctx.network.route), or an envelope naming it is rejected; it advertises
itself under kind: "flow" -- version, package, payload types -- which is how a
router learns which peers a flow can be started with; and it runs its own
timers, as effects of its own scope. The host fires no schedule and advertises
nothing on a flow's behalf, so what you copy is the whole of what a flow does.
| | |
| ---------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| routes | POST /echo -- locally, or across the wire with peer (from GET /board) or anyone; GET /echoes is where replies land |
| payloads | echo.request, echo.reply |
| advertises | itself under kind: "flow" (version, package, payload types), and its echo under kind: "echo", which is what the board shows |
| background | two intervals of its own: advertise every 60s until both advertisements stick, sweep every 60s (a pending echo ends unanswered) |
| needs | nothing: no sources, no operations, no tools |
| intent | echo, declared to ctx.router from an optional scope and fallback, so a router has something to pick when nothing else fits |
| results | one echo per echo sent, declared to ctx.results from an optional scope: GET /flows/results/results reads them beside every flow's |
Running it
pnpm check # includes tests/template.spec.ts: two whole nodes, one echo across the wire
just demo # headless: a directory, two seeded nodes, one echo over iroh, down
just dev # the same, lived in: panes, both pages, driven by handWith the environment up: just a1 api GET /flows/template/board says who is
offering, just echo "anything" sends it across and waits for the reply, and
just a1 api POST /flows/template/echo --body '{"text":"hi"}' is the local
case.
A real model
The lane needs none: the scripted executor answers, and the echo across the
wire is a plain echo either way. MODEL= swaps in a real one, the way the
other flow lanes take it -- the command is spawned rather than shelled and
gets the prompt on stdin, so its flags ride MODEL_ARG, space-separated:
MODEL=pi MODEL_ARG="-p --model anthropic/claude-sonnet-4-5" just devCheck the command works headless first (echo hi | pi -p): it authenticates
from your home directory, which the executor passes through. With MODEL set
the flow is installed with reasonAboutReplies, so the local POST /echo
starts a run rather than answering itself and comes back 202 with a run id --
the page's runs pane is where that answer lands. The wire path is unchanged: a
peer answering an echo.request still echoes it. The executor is chosen when a
node is set up, so switching MODEL, or going back to the scripted one, takes
a just reset first.
The sibling layout
Cross-repo dependencies are link: paths into checkouts beside this one --
nothing of PAC's is fetched from a registry. Clone the repos this one links
into the same parent directory, run pnpm install in each, and everything
resolves from source. The flow's whole-node suite lives in tests/, standing
up real nodes from the sibling pac-node. Copy this repository to start a
flow of your own.
