← Projects

Projectv0.8.2

Prism

Write agent workflows as programs. Run them anywhere. Run them again.

Prism runs Claude Code, Codex, Grok, and ten more agent CLIs from workflows you write in TypeScript with Effect. Mix models in one program, fan out across a whole codebase, let Jev make the calls between steps, and run it again for free: finished work comes back from cache.

npm install -g @skastr0/prism

01

Many agents. One program.

You have Claude Code, Codex, Grok, and more models than you can keep track of. Using them together by hand doesn't scale. Scripting them is painful: every CLI has its own flags, models, and permission modes. Runs go on for minutes or hours, crash halfway, and take their output with them.

Prism turns that into a program. You write a workflow in TypeScript with Effect. Prism runs the agents you already have, on the models you pick, and keeps every result.

  1. 01Write itTasks, agents, and the answers you want back, in one TypeScript file.
  2. 02Run itEvery agent in parallel, on your machine or somewhere else.
  3. 03Run it againFinished work comes back from cache. Change one task and only that task reruns.

02

Write it. Run it. Run it again.

A task is a prompt, the agent that runs it, and the shape of the answer you want back. A workflow is ordinary Effect code around those tasks.

Here Codex and Claude review the same commit at the same time. Both answers come back in one shape, so the next step can use them. Run it again and nothing reruns: both answers come back from cache.

review.workflow.ts
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
import { Effect, Schema } from "effect"; import { defineTask, defineWorkflow, type WorkflowTaskWorkerOptions } from "prism"; const Review = Schema.Struct({ verdict: Schema.Literals(["ship", "revise", "block"]), findings: Schema.Array(Schema.String), }); const review = (id: string, worker: WorkflowTaskWorkerOptions) => defineTask({ id, prompt: "Review the last commit (git show HEAD). Is it safe to ship?", output: Review, cacheKey: "review-head", worker, }); export default defineWorkflow({ name: "review-commit", run: (wf) => Effect.all( [ wf.runTask(review("codex", { worker: "codex-cli" })), wf.runTask(review("claude", { worker: "claude-code", model: "sonnet" })), ], { concurrency: "unbounded" }, ), });
terminalfirst run

$

codexcodex-cliqueued
verdict: "revise"README.md:117 promises a backup on every repair; source repairs skip it
claudeclaude-code · sonnetqueued
verdict: "ship"docs-only change, nothing to block
agents run–
time–
cost–

A real run: Codex and Claude reviewed one commit in 57 seconds for $0.24. The second run cost nothing.

03

Orchestrate at scale.

A workflow is a program, so it can do what programs do: fan out across a codebase, run one phase after another, branch, retry, loop.

Give every file its own agent, as many at once as your machine allows. If the run dies, resume it: finished files replay from cache and the rest carry on.

migrate.workflow.ts
const patches = yield* Effect.all(
files.map((file) => wf.runTask(migrate(file))),
{ concurrency: "unbounded" },
);
const risk = yield* wf.runTask(
jev({
id: "risk",
state: { patches },
questions: Object.fromEntries(
patches.map((p, i) => [
`p${i}`,
{ type: "choice", instructions: `About patch ${i}`, criteria: route },
]),
),
}),
);
const risky = patches.filter((_, i) => risk.answers[`p${i}`]?.choice === "review");
return yield* Effect.all(risky.map((p) => wf.runTask(review(p))), {
concurrency: 4,
});
const patches = yield* Effect.all( files.map((file) => wf.runTask(migrate(file))), { concurrency: "unbounded" }, ); const risk = yield* wf.runTask( jev({ id: "risk", state: { patches }, questions: Object.fromEntries( patches.map((p, i) => [ `p${i}`, { type: "choice", instructions: `About patch ${i}`, criteria: route }, ]), ), }), ); const risky = patches.filter((_, i) => risk.answers[`p${i}`]?.choice === "review"); return yield* Effect.all(risky.map((p) => wf.runTask(review(p))), { concurrency: 4, });
runOne agent per file
users.ts
orders.ts
billing.ts
session.ts
invoices.ts
refunds.ts
search.ts
carts.ts
coupons.ts
tax.ts
webhooks.ts
exports.ts
teams.ts
roles.ts
audit.ts
emails.ts
uploads.ts
reports.ts
plans.ts
trials.ts
limits.ts
keys.ts
sso.ts
health.ts

codex-cli · one agent per file

04

Agents and Jev, woven together.

Jev makes decisions. Hand it an array (issues, files, findings, tabs, anything) with a question for each item. One request brings back a typed answer per item: the choice, how sure it is, and the full probabilities.

Your agents take it from there. Jev decides which work matters and who should do it. The agents do the work.

work-the-backlog.workflow.ts
const effort = {
quick: "a one-file fix a fast model can do",
deep: "needs reasoning across the codebase",
human: "needs a product decision first",
} as const;
const plan = yield* wf.runTask(
jev({
id: "plan",
state: { issues },
questions: Object.fromEntries(
issues.map((i) => [
i.id,
{ type: "choice", instructions: `About issue #${i.id}`, criteria: effort },
]),
),
}),
);
yield* Effect.all(
issues
.filter((i) => plan.answers[i.id]?.choice !== "human")
.map((i) => wf.runTask(fix(i, plan.answers[i.id]?.choice === "deep"))),
{ concurrency: 8 },
);
const effort = { quick: "a one-file fix a fast model can do", deep: "needs reasoning across the codebase", human: "needs a product decision first", } as const; const plan = yield* wf.runTask( jev({ id: "plan", state: { issues }, questions: Object.fromEntries( issues.map((i) => [ i.id, { type: "choice", instructions: `About issue #${i.id}`, criteria: effort }, ]), ), }), ); yield* Effect.all( issues .filter((i) => plan.answers[i.id]?.choice !== "human") .map((i) => wf.runTask(fix(i, plan.answers[i.id]?.choice === "deep"))), { concurrency: 8 }, );
decisions
#412 Typo in the signup emailquickdeephumancodex-cli
#415 Checkout double-charges when the user retriesquickdeephumanclaude-code · opus
#418 Dark mode toggle ignores system settingquickdeephumancodex-cli
#421 Should free accounts keep export after the trial ends?quickdeephumanyour inbox
#423 Search drops items when two filters are combinedquickdeephumanclaude-code · opus(unsure)
#427 Rename 'Workspace' to 'Team' in settingsquickdeephumancodex-cli
decisions–
requests–
time–

A real request: six issues, one call, 1.0 second. #423 came back unsure (0.29), and the workflow can see that and treat it differently.

RouteSend each task to the model it needs: a fast one where it's easy, a strong one where it's hard, you where it needs a decision.
GateScore what the agents produced against your own rubric. Keep the strong results and send the weak ones back.
TriageTwo hundred failing tests in, grouped by cause, one agent per cause.
SortTabs, inbox, backlog: keep, park, or close, each with a confidence you can set a threshold on.

05

Run it anywhere.

A workflow runs wherever Prism and your agents are installed, and each agent uses its own login. Start it in your terminal, leave it running in the background, put it on a schedule, or send a task to another machine.

In your terminal
$ prism workflow run review.workflow.ts
In the background, resumable
$ prism workflow run migrate.workflow.ts --detach
$ prism workflow runs resume <run> migrate.workflow.ts
On a schedule
export default defineWorkflow({
name: "morning-triage",
schedule: { cron: "0 7 * * 1-5", timezone: "America/Sao_Paulo", overlap: "skip", missedRuns: "skip" },
run: (wf) => wf.runTask(triage),
});
$ prism workflow schedule install morning-triage.workflow.ts
On another machine
worker: { worker: "amp-runner", runnerId: "macbook" }

A task can run on a registered runner machine or in a hosted Amp orb.

With the agents you already use

  • Claude Code
  • Codex
  • Grok
  • Amp
  • Amp Orb
  • Amp Runner
  • Cursor
  • OpenCode
  • Kimi Code
  • Devin
  • Antigravity
  • Hermes
  • Oh My Pi

Prism also installs one set of skills, agents, and hooks into every one of them, in each one's own format.

06

Install

Version
0.8.2
Runs on
macOS and Linux, arm64 and x64
Install
npm install -g @skastr0/prismRuns the agent CLIs you have logged in. Run Codex tasks from inside a Git repository.