AI Decision System
Replayable, offline-verifiable records for AI-assisted go/no-go decisions: experiment promotions, typed model answers and human-approved actions.
翻譯準備中
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證The multi-agent workflow engine — compose Claude Code, Codex, and Gemini into graphs with schema-enforced handoffs.
翻譯準備中
取自儲存庫 README
正在載入完整 README。 以下為已儲存的摘錄。
The cloud pipeline for Claude Code, Codex, and Gemini. Compose them into structured workflows with Zod-validated handoff between nodes. Vendor-neutral, JavaScript-first, runs locally or in our cloud.
Each node hands off to a complete agent. The agent does its own tool calls, file edits, and multi-turn reasoning. Your graph defines what agent runs when, what schema it has to return, and what state flows between them.
Mix and match agents per node — Claude for planning, Codex for implementation, Gemini for verification. Or stick with one. Your call:檢視完整 README ↗Deutsch | Español | français | 日本語 | 한국어 | Português | Русский | 中文
📖 Full docs: docs.zibby.app · Get Started · Concepts · Designing agents · Cloud
The cloud pipeline for Claude Code, Codex, and Gemini. Compose them into structured workflows with Zod-validated handoff between nodes. Vendor-neutral, JavaScript-first, runs locally or in our cloud.
┌──────────┐ ┌──────────┐ ┌──────────┐
trigger → │ plan │ → │ implement│ → │ verify │ → result
│ (claude) │ │ (codex) │ │ (gemini) │
└──────────┘ └──────────┘ └──────────┘
│ │ │
Zod out Zod out Zod out
Each node hands off to a complete agent. The agent does its own tool calls, file edits, and multi-turn reasoning. Your graph defines what agent runs when, what schema it has to return, and what state flows between them.
Mix and match agents per node — Claude for planning, Codex for implementation, Gemini for verification. Or stick with one. Your call:
graph
.addNode('plan', { prompt, outputSchema: Plan, agent: 'claude' })
.addNode('implement', { prompt, outputSchema: Diff, agent: 'codex' })
.addNode('verify', { prompt, outputSchema: Result, agent: 'gemini' });
Each agent reads its own credential env var (ANTHROPIC_API_KEY, OPENAI_API_KEY). In Zibby Cloud you can set those per-workflow — different keys per pipeline, no global state — see Per-workflow env vars. Each node runs on the model the run config names for it (config: { models: { node_id: 'claude-opus-4.6', default: '…' } }); a node never borrows another node's model.
npm install @zibby/agent-workflow zod
Save this as index.mjs and run node index.mjs. It uses a stand-in agent with canned answers, so it runs offline with no API key:
import { Graph, AgentStrategy, registerStrategy } from '@zibby/agent-workflow';
import { z } from 'zod';
// 1. Bring your own agent. A real one calls Claude Code, Codex, an API…
// This one returns canned output per node so you can run it offline.
class EchoAgent extends AgentStrategy {
constructor() { super('echo', 'Canned answers for the quickstart'); }
canHandle() { return true; }
async invoke(prompt, { nodeName }) {
const answers = {
plan: { tasks: ['Add a theme setting', 'Add the toggle', 'Test both themes'] },
finish: { summary: `Echo of: ${prompt}` },
};
const structured = answers[nodeName];
return { raw: JSON.stringify(structured), structured };
}
}
registerStrategy(new EchoAgent());
// 2. Declare the graph: each node has a prompt and a Zod output schema.
const Plan = z.object({ tasks: z.array(z.string()) });
const Done = z.object({ summary: z.string() });
const graph = new Graph()
.addNode('plan', { prompt: 'List 3 tasks for: {{goal}}', outputSchema: Plan })
.addNode('finish', {
prompt: (state) => `Summarise: ${state.plan.tasks.join(', ')}`,
outputSchema: Done,
})
.addEdge('plan', 'finish')
.setEntryPoint('plan');
// 3. Run it. Each node's output lands in state under the node's name.
const { state } = await graph.run(null, {
goal: 'add a dark-mode toggle',
agentType: 'echo',
config: { models: { default: 'echo-1' } }, // a model per node id, or one default
});
console.log(state.plan.tasks); // [ 'Add a theme setting', 'Add the toggle', 'Test both themes' ]
console.log(state.finish.summary); // Echo of: Summarise: Add a theme setting, …
To use a real coding agent, replace EchoAgent with an AgentStrategy whose invoke calls it and returns { raw, structured } — see examples/04-custom-agent. Every run writes a session folder under .zibby/output/sessions/<id>/ that you can inspect afterwards.
See examples/ for runnable demos of each pattern.
Run the full Zibby platform — control plane + agents + marketplace — on your own box:
curl -fsSL https://dl.zibby.app/selfhosted/latest/install.sh | bash
Requirements: Docker + ~8 GB RAM. The installer downloads the release bundle, docker loads the images locally (no registry login needed), generates secrets, brings the stack up, and prints your dashboard URL + access token. Free tier: up to 10 deployed agents.
| What it does | Why this is different | |
|---|---|---|
| LangGraph | Python-first graph runtime over LangChain — nodes are LangChain agents or LLM calls, state is shared via the graph. | Our nodes hand off to external coding-agent CLIs (Claude Code, OpenAI Codex, Gemini CLI) — independent processes that own their own tool use, multi-turn loops, and file edits. JS-first, no Python interop, no LangChain assembly. |
| n8n / Zapier | Visual workflow editor — wire SaaS APIs together. | Code-first, no UI. Built around composing coding-agent CLIs against your repo, not connecting SaaS APIs. |
| CrewAI / AutoGen | Multi-agent role-play — agents converse to solve a task. | No agent debate. Each node is a discrete, schema-validated invocation. Deterministic edges, retry-friendly. |
If you want to compose Claude Code + Codex + Gemini into one pipeline with structured handoff between them — JS, no Python, no LangChain — this is that.
| Primitive | What it does |
|---|---|
Graph | The DAG. addNode, addEdge, addConditionalEdges, setEntryPoint. |
| Fan-out | Call addEdge more than once from the same node and every branch runs, each carrying on through its own children. Branches run sequentially in declaration order (depth-first: a branch finishes before the next starts). Where branches converge, the shared node waits for all of them and runs once — see Fan-out below. |
Node | One agent invocation. Config: prompt, outputSchema (Zod), optional agent, retries, skills. |
| Retries | retries: N = N retries on ANY failure (N+1 attempts), no delay — declared per node. On top of that, a failure the engine can POSITIVELY identify as a transient provider failure (a dead stream, a 429, an upstream 5xx) buys up to AGENT_TRANSIENT_RETRIES extra attempts (default 2) with exponential backoff (AGENT_TRANSIENT_BACKOFF_MS, default 5000, 0 = no wait). One loop, one decider — classifyFailure in failure-class.ts. A failure it cannot positively identify is DETERMINISTIC and is never retried, because retrying a bug is an infinite loop that burns money. |
| Sub-graph node | addNode(name, { workflow: 'other-name', ... }) — dispatches another deployed workflow as a child. Sync (poll + merge) or async (async: true, fire-and-forget). See Sub-graphs below. |
AgentStrategy | Abstract base. Implement canHandle(ctx) and invoke(prompt, opts). |
registerStrategy() | Tells the engine what agents are available. Selected by node agent field → config.agents[name] → state.agentType. |
WorkflowState | History-tracked state passed between nodes. / / / . |
State flows automatically: when node plan completes with output { tasks: [...] }, that lands at state.plan.tasks and downstream nodes see it.
One node, several branches, each with its own children:
const graph = new Graph()
.addNode('gather', { prompt: 'Collect the diff', outputSchema: Diff })
.addNode('security', { prompt: 'Security review', outputSchema: Findings })
.addNode('perf', { prompt: 'Performance review', outputSchema: Findings })
.addNode('triage', { prompt: 'Rank the findings', outputSchema: Findings })
.addNode('report', { prompt: 'Write it up', outputSchema: Report })
.addEdge('gather', 'security') // branch 1
.addEdge('gather', 'perf') // branch 2
.addEdge('perf', 'triage') // …with its own child
.addEdge('security', 'report') // both branches converge
.addEdge('triage', 'report')
.setEntryPoint('gather');
The contract:
_currentNodeTools), to the timeline's single current node, and to its stdout interception, so two nodes at once would read each other's tools and interleave each other's logs. Sequential branches need none of that. For genuine parallelism, dispatch each branch as a sub-graph — separate processes, no shared state.state.security, state.triage). It re-arms if a loop drives the fan-out again.addConditionalEdges still picks exactly one path. A join is defined over the unconditional edges a fan-out creates; a conditional arrival schedules its target immediately, as it always has.A sub-graph node dispatches another deployed workflow as a child of the current one. Useful when a step is large enough to deserve its own state schema, its own version, and its own activity-tab history — but you want a parent to call it as part of a larger flow.
One extra field on the existing node config:
g.addNode('audit', { workflow: 'deep-audit' });
That's the entire feature surface. No new imports, no UUID in user code, no separate class. The engine recognizes workflow: and turns the node into a sub-graph dispatcher.
Sync vs async is a single flag:
g.addNode('audit', { workflow: 'deep-audit' }); // sync — parent blocks until child done
g.addNode('notify', { workflow: 'slack-notifier', async: true }); // fire-and-forget
State plumbing — each workflow has its own schema; the parent transforms parent state into child input and (optionally) extracts what it needs back out:
g.addNode('audit', {
workflow: 'deep-audit',
input: (state) => ({ ticketId: state.ticketId }),
output: 'auditResult.score', // dot-path on child finalState
// OR: output: (childState) => ({ score: childState.auditResult.score,
// label: childState.auditResult.label }),
retries: 3, // retry whole dispatch on transient failure
timeoutMs: 5 * 60 * 1000, // give up after 5min (sync mode only)
});
When a custom fan-out node also needs to persist an exact reference to the child execution, the direct dispatcher can return identity with the same projected value:
const { executionId, output } = await dispatchSubgraph('deep-audit', {
input: { ticketId },
output: 'auditResult',
includeExecutionMetadata: true,
});
This is synchronous-only metadata; async dispatch already returns jobId.
Errors are typed so parents can branch:
err.code | When |
|---|---|
SUBGRAPH_INVALID_INPUT | Parent's input: didn't satisfy child's stateSchema — server 400'd before any Fargate spawn |
SUBGRAPH_QUOTA_EXCEEDED | Account over its execution cap; sub-graph runs count separately |
SUBGRAPH_TRIGGER_FAILED | Any other dispatch failure |
Same /trigger endpoint as user-initiated runs. The engine POSTs to /projects/<id>/workflows/<child-name>/trigger with parentExecutionId set. The server's input gate, quota check, and execution accounting all apply identically — a parent that fans out 10 children consumes 11 executions.
Full reference: docs.zibby.app/concepts/sub-graphs
| Shows | |
|---|---|
| 01-hello-world | Smallest possible graph — one node, one fake agent. |
| 02-pipeline | Three nodes with typed handoff — state.plan.tasks flows into the next node. |
| 03-conditional-routing | Branch on state with addConditionalEdges. |
| 04-custom-agent | Bring your own AgentStrategy — calls OpenAI directly. |
| 05-with-skills | Register an MCP-style skill, scope it to a node. |
Run any of them:
cd examples/01-hello-world
npm install
node index.js
Examples 01–03 and 05 use a fake agent — no API key required.
Real coding agents (Claude Code, OpenAI Codex, Gemini CLI) are themselves capable runtimes — they edit files, run shells, call MCP tools, handle multi-turn. But on their own they have no memory across runs and no way to verify their own output.
A graph gives you:
state.A. No prompt-stuffing, no parser bugs.addConditionalEdges for branch-on-state.You're not replacing the agent. You're giving it a job description, a contract, and a place in a pipeline.
| Package | What it adds |
|---|---|
@zibby/skills | Pre-built skills (browser via Playwright MCP, GitHub, Jira, Slack, memory). |
Workflow itself ships zero agent strategies and zero skills — bring your own, or npm install @zibby/skills for pre-built skills.
0.1.x. The public protocol surface is stable and consumed by Zibby Studio + tooling:
WORKFLOW_GRAPH_LOG_MARKER_PREFIX (__WORKFLOW_GRAPH_LOG__)STUDIO_STOP_REQUEST_FILE (.zibby-studio-stop)ZIBBY_RUN_SOURCE=studio env triggerstoppedByStudio: true return key{ phase: 'node_begin' | 'node_end', node: string }The JS API is still pre-1.0 — minor versions may add or rename surface area, breaking changes will be called out in release notes.
MIT
setupdateappendrollback| Skills | Named MCP tool bundles a node can request. registerSkill({ id, serverName, tools, ... }). |
ContextLoader | Walks the spec dir for CONTEXT.md / AGENTS.md and merges them into state. |
compileGraph() | Build a graph from a JSON config (the format Studio writes). |
timeline | CLI progress UX + structured __WORKFLOW_GRAPH_LOG__ markers consumed by Studio. |