{"id":47908832,"url":"https://github.com/graphrefly/graphrefly-ts","last_synced_at":"2026-05-26T06:06:44.976Z","repository":{"id":348057089,"uuid":"1195401492","full_name":"graphrefly/graphrefly-ts","owner":"graphrefly","description":"Reactive harness layer for agent workflows. Describe automations in plain language, trace every decision, enforce policies, persist checkpoints. TypeScript. Zero dependencies.","archived":false,"fork":false,"pushed_at":"2026-05-17T03:43:54.000Z","size":8426,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-17T05:44:17.184Z","etag":null,"topics":["agent-harness","ai-agents","automation","causal-trace","causal-tracing","graph","harness-engineering","human-in-the-loop","llm","natural-language","nestjs","orchestration","react","reactive","svelte","typescript","vue","workflow","zero-dependency"],"latest_commit_sha":null,"homepage":"https://graphrefly.dev","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/graphrefly.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":"docs/roadmap.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-29T16:21:24.000Z","updated_at":"2026-05-17T03:41:31.000Z","dependencies_parsed_at":null,"dependency_job_id":"127fe6f3-5dc2-4c44-ac01-6aa5b94f0d9d","html_url":"https://github.com/graphrefly/graphrefly-ts","commit_stats":null,"previous_names":["graphrefly/graphrefly-ts"],"tags_count":56,"template":false,"template_full_name":null,"purl":"pkg:github/graphrefly/graphrefly-ts","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphrefly%2Fgraphrefly-ts","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphrefly%2Fgraphrefly-ts/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphrefly%2Fgraphrefly-ts/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphrefly%2Fgraphrefly-ts/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/graphrefly","download_url":"https://codeload.github.com/graphrefly/graphrefly-ts/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphrefly%2Fgraphrefly-ts/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33379722,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-23T01:21:08.577Z","status":"online","status_checked_at":"2026-05-23T02:00:05.530Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent-harness","ai-agents","automation","causal-trace","causal-tracing","graph","harness-engineering","human-in-the-loop","llm","natural-language","nestjs","orchestration","react","reactive","svelte","typescript","vue","workflow","zero-dependency"],"created_at":"2026-04-04T05:06:19.931Z","updated_at":"2026-05-23T02:13:26.103Z","avatar_url":"https://github.com/graphrefly.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# GraphReFly\n\n**The reactive graph your code, your agents, and your humans share as a blueprint.** Compose in code, review the projected spec, co-edit across agents without colliding, trace every decision.\n\nGraphReFly is a reactive graph protocol for human + LLM co-operation. Code is the source of truth — `factoryTag`-stamped factories project automatically into a `GraphSpec` blueprint that humans and agents read, diff, and review together. Multi-agent worktrees claim subgraph ownership through a structural protocol (TTL → heartbeat → supervisor) so concurrent edits don't corrupt shared topology. Every decision has a causal chain — `graph.explain()` walks back through dependencies and tells you exactly why a value is what it is.\n\n[![npm](https://img.shields.io/npm/v/@graphrefly/graphrefly?color=blue)](https://www.npmjs.com/package/@graphrefly/graphrefly)\n[![license](https://img.shields.io/github/license/graphrefly/graphrefly-ts)](./LICENSE)\n\n[Docs](https://graphrefly.dev) | [Spec](https://graphrefly.dev/spec/) | [Python API](https://graphrefly.dev/py/api/) | [TS API Reference](https://graphrefly.dev/api/node/)\n\n## Packages\n\n| Package | What it is |\n|---|---|\n| [`@graphrefly/graphrefly`](https://www.npmjs.com/package/@graphrefly/graphrefly) | The library — reactive graph primitives, operators, `Graph` container, framework adapters. |\n| [`@graphrefly/cli`](./packages/cli) | Stateless command-line shell — `describe`, `explain`, `observe`, `reduce`, `snapshot` from your terminal or CI. |\n\n---\n\n\u003c!-- TODO: Demo 0 GIF/video — NL → flow view → running → \"why was this flagged?\" --\u003e\n\n## What can you do with it?\n\n**Email triage** — \"Watch my inbox. Urgent emails from my team go to a priority list. Newsletters get summarized weekly. Everything else, count by sender.\" It watches, classifies, and alerts — and when you ask \"why was this flagged?\", it walks you through the reasoning.\n\n**Spending alerts** — Connect bank transactions to budget categories. Get a push notification when monthly dining exceeds your target. No polling, no manual checks — changes propagate the moment data arrives.\n\n**Knowledge management** — Notes, bookmarks, highlights flow in. Contradictions surface automatically. Related ideas link themselves. Your second brain stays current without you maintaining it.\n\n---\n\n## Quick start\n\n```bash\nnpm install @graphrefly/graphrefly\n```\n\n```ts\nimport { state, derived, effect } from \"@graphrefly/graphrefly\";\n\nconst count = state(0);\nconst doubled = derived([count], ([c]) =\u003e c * 2);\n\neffect([doubled], ([d]) =\u003e console.log(\"doubled:\", d));\n// → doubled: 0\n\ncount.set(3);\n// → doubled: 6\n```\n\n## How it works\n\nCode is the source of truth. You compose a reactive graph using primitives (`state`, `derived`, `effect`, `producer`) and factories (`agentLoop`, `harnessLoop`, `agentMemory`, …). `factoryTag`-stamped factories carry self-description into the live graph. `graph.describe({ detail: \"spec\" })` projects the topology into a JSON `GraphSpec` blueprint — the same shape the original spec was written from, but always in sync with what's actually running. Spec is what your agents read to understand the topology. Code is what they (and you) actually edit.\n\nThe graph runs persistently, checkpoints state on `messageTier ≥ 3` and topology on `_topologyVersion` bump, and traces every decision through a causal chain. Ask \"why?\" at any point — `graph.explain(from, to)` walks backward through dependencies and returns a structured chain that's both human-readable and LLM-parseable.\n\n## Substrate coverage\n\nThe eight requirements of a production agent system cluster into a handful of composed blocks that sit on top of the reactive graph primitives:\n\n| Need | GraphReFly |\n|---|---|\n| Context \u0026 state | `persistentState()` — `autoCheckpoint` + `snapshot` / `restore` + incremental diff |\n| Agent memory | `agentMemory()` — `distill` + vectors + knowledge graph + tiers, OpenViking decay |\n| Control flow \u0026 resilience | `resilientPipeline()` — `rateLimiter → breaker → retry → timeout → fallback`, correct ordering built in |\n| Execution \u0026 policy | `guardedExecution()` — Actor / Guard ABAC + `policy()` + `budgetGate` + scoped describe |\n| Observability \u0026 causality | `graphLens()` — reactive topology, health, flow, and `why(node)` causal chains as structured data |\n| Human governance | `gate` — reactive `pending` / `isOpen` with `approve` / `reject` / `modify(fn, n)` |\n| Verification | Multi-model eval harness with regression gates |\n| Continuous improvement | Strategy model: `rootCause × intervention → successRate` |\n| Multi-agent coordination | `ownershipController()` — L0 static / L1 TTL / L2 heartbeat / L3 supervisor staircase; `Actor / Guard ABAC` enforces claims at write time; `validateOwnership` lints PR diffs |\n\nThe library computes structured facts reactively; LLMs and UIs render them. Natural language is never the library's job — which keeps the whole stack model-agnostic and testable.\n\n## Why GraphReFly?\n\n|  | Zustand / Jotai | RxJS | XState | LangGraph | Archon | Hermes | **GraphReFly** |\n|--|-----------------|------|--------|-----------|--------|--------|---------------|\n| Simple store API | yes | no | no | no | n/a | n/a | **yes** |\n| Streaming operators | no | yes | no | no | no | no | **yes** |\n| Diamond resolution | no | n/a | n/a | n/a | n/a | n/a | **glitch-free** |\n| Graph introspection | no | no | visual | checkpoints | YAML view | no | **describe / observe / diagram** |\n| Causal tracing | no | no | no | no | no | no (black-box) | **explain every decision** |\n| Durable checkpoints | no | no | persistence | yes | sqlite | yes | **file / SQLite / IndexedDB** |\n| LLM orchestration | no | no | no | yes | yes (workflow) | yes (skills) | **agentLoop / chatStream / toolRegistry** |\n| Auto-projection: code → spec | no | no | no | no | no (manual YAML) | partial (skill emit) | **factoryTag round-trip** |\n| Multi-agent on shared topology | no | no | no | no | no (worktree-isolated) | no (skill-isolated) | **L0–L3 ownership protocol** |\n| Framework adapters | React | Angular | React / Vue | n/a | n/a | n/a | **React / Vue / Svelte / Solid / NestJS** |\n| Dependencies | 0 | 0 | 0 | many | many | many | **0** |\n\n## One primitive\n\nEverything is a `node`. Sugar constructors give you the right shape:\n\n```ts\nimport { state, derived, producer, effect, pipe } from \"@graphrefly/graphrefly\";\n\n// Writable state\nconst name = state(\"world\");\n\n// Computed (re-runs when deps change)\nconst greeting = derived([name], ([n]) =\u003e `Hello, ${n}!`);\n\n// Push source (timers, events, async streams)\nconst clock = producer((emit) =\u003e {\n  const id = setInterval(() =\u003e emit([[DATA, Date.now()]]), 1000);\n  return () =\u003e clearInterval(id);\n});\n\n// Side effect\neffect([greeting], ([g]) =\u003e document.title = g);\n\n// Operator pipeline\nconst delayed = pipe(clock, delay(500), map(([, ts]) =\u003e new Date(ts)));\n```\n\n## Streaming \u0026 operators\n\n70+ operators — transform, combine, buffer, window, rate-limit, retry, circuit-break:\n\n```ts\nimport { pipe, merge, switchMap, debounceTime, retry } from \"@graphrefly/graphrefly\";\n\nconst search = pipe(\n  input,\n  debounceTime(300),\n  switchMap((query) =\u003e fromPromise(fetch(`/api?q=${query}`))),\n  retry({ strategy: \"exponential\", maxAttempts: 3 }),\n);\n```\n\n## Graph container\n\nRegister nodes in a `Graph` for introspection, snapshot, and persistence:\n\n```ts\nimport { Graph, state, derived } from \"@graphrefly/graphrefly\";\n\nconst g = new Graph(\"pricing\");\nconst price = g.register(\"price\", state(100));\nconst tax   = g.register(\"tax\", derived([price], ([p]) =\u003e p * 0.1));\nconst total = g.register(\"total\", derived([price, tax], ([p, t]) =\u003e p + t));\n\ng.describe();   // → full graph topology as JSON\ng.diagram();    // → Mermaid diagram string\ng.observe((e) =\u003e console.log(e));  // → live change stream\n```\n\n## AI \u0026 orchestration\n\nFirst-class patterns for LLM streaming, agent loops, and human-in-the-loop workflows:\n\n```ts\nimport { chatStream, agentLoop, toolRegistry } from \"@graphrefly/graphrefly\";\n\n// Streaming chat with tool use\nconst chat = chatStream(\"assistant\", {\n  model: \"claude-sonnet-4-20250514\",\n  tools: toolRegistry(\"tools\", { search, calculate }),\n});\n\n// Full agent loop: observe → think → act → memory\nconst agent = agentLoop(\"researcher\", {\n  llm: chat,\n  memory: agentMemory({ decay: \"openviking\" }),\n});\n```\n\n## Framework adapters\n\nDrop-in bindings — your framework, your way:\n\n```tsx\n// React\nimport { useNode } from \"@graphrefly/graphrefly/compat/react\";\nconst [value, setValue] = useNode(count);\n\n// Vue\nimport { useNode } from \"@graphrefly/graphrefly/compat/vue\";\nconst value = useNode(count);  // → Ref\u003cnumber\u003e\n\n// Svelte\nimport { toStore } from \"@graphrefly/graphrefly/compat/svelte\";\nconst value = toStore(count);  // → Svelte store\n\n// Solid\nimport { useNode } from \"@graphrefly/graphrefly/compat/solid\";\nconst value = useNode(count);  // → Signal\u003cnumber\u003e\n\n// NestJS\nimport { GraphReflyModule } from \"@graphrefly/graphrefly/compat/nestjs\";\n@Module({ imports: [GraphReflyModule.forRoot()] })\n```\n\n## Tree-shaking imports\n\nPrefer subpath imports for minimal bundle:\n\n```ts\nimport { node, batch, DATA } from \"@graphrefly/graphrefly/core\";\nimport { map, switchMap } from \"@graphrefly/graphrefly/extra\";\nimport { Graph } from \"@graphrefly/graphrefly/graph\";\n```\n\nThe root entry re-exports everything:\n\n```ts\nimport { node, map, Graph } from \"@graphrefly/graphrefly\";\n```\n\n## Resilience \u0026 checkpoints\n\nBuilt-in retry, circuit breakers, rate limiters, and persistent storage:\n\n```ts\nimport { retry, circuitBreaker, fileStorage, memoryStorage } from \"@graphrefly/graphrefly\";\n\n// Retry with exponential backoff\nconst resilient = pipe(source, retry({ strategy: \"exponential\" }));\n\n// Circuit breaker\nconst breaker = circuitBreaker({ threshold: 5, resetTimeout: 30_000 });\n\n// Multi-tier storage with auto-restore: hot in-memory + warm on disk.\ngraph.attachStorage(\n  [memoryStorage(), fileStorage(\"./checkpoints\")],\n  { autoRestore: true },\n);\n```\n\n## Project layout\n\n| Path | Contents |\n|------|----------|\n| `src/core/` | Message protocol, `node` primitive, batch, sugar constructors |\n| `src/extra/` | Operators, sources, data structures, resilience, checkpoints |\n| `src/graph/` | `Graph` container, describe/observe, snapshot, persistence |\n| `src/patterns/` | Orchestration, messaging, memory, AI, CQRS, reactive layout |\n| `src/compat/` | Framework adapters (React, Vue, Svelte, Solid, NestJS) |\n| `docs/` | Roadmap, guidance, benchmarks |\n| `website/` | Astro + Starlight docs site ([graphrefly.dev](https://graphrefly.dev)) |\n\n## Scripts\n\n```bash\npnpm test          # vitest run\npnpm run lint      # biome check\npnpm run build     # tsup (ESM + CJS + .d.ts)\npnpm bench         # vitest bench\n```\n\n## Acknowledgments\n\nGraphReFly builds on ideas from many projects and papers:\n\n**Protocol \u0026 predecessor:**\n- **[Callbag](https://github.com/callbag/callbag)** (Andre Staltz) — the original reactive protocol spec. GraphReFly's message-based node communication descends from callbag's function-calling-function model.\n- **[callbag-recharge](https://github.com/Callbag-Recharge/callbag-recharge)** — GraphReFly's direct predecessor. 170+ modules, 4 architecture iterations, and 30 engineering blog posts that shaped every design decision.\n\n**Reactive design patterns:**\n- **[SolidJS](https://github.com/solidjs/solid)** — two-phase execution (DIRTY propagation + value flow), automatic caching, and effect batching. Identified as the closest philosophical neighbor during design research.\n- **[Preact Signals](https://github.com/preactjs/signals)** — fine-grained reactivity and cached-flag optimization patterns that informed RESOLVED signal design.\n- **[TC39 Signals Proposal](https://github.com/tc39/proposal-signals)** — the `.get()/.set()` contract and the push toward language-level reactivity that clarified where signals end and graphs begin.\n- **[RxJS](https://github.com/ReactiveX/rxjs)** — operator naming conventions (aliases like `combineLatest`, `mergeMap`, `catchError`) and the DevTools observability philosophy that inspired the Inspector pattern.\n\n**AI \u0026 memory:**\n- **[OpenViking](https://github.com/volcengine/openviking)** (Volcengine) — the memory decay formula (`sigmoid(log1p(count)) * exp_decay(age, 7d)`) and L0/L1/L2 progressive loading strategy used in `agentMemory()`.\n- **[FadeMem](https://arxiv.org/abs/2501.09399)** (Wei et al., ICASSP 2026) — biologically-inspired dual-layer memory with adaptive exponential decay, validating the decay approach independently.\n- **[MAGMA](https://arxiv.org/abs/2501.13920)** (Jiang et al., 2026) — four-parallel-graph model (semantic/temporal/causal/entity) that informed `knowledgeGraph()` design.\n- **[Letta/MemGPT](https://github.com/letta-ai/letta)**, **[Mem0](https://github.com/mem0ai/mem0)**, **[Zep/Graphiti](https://github.com/getzep/graphiti)**, **[Cognee](https://github.com/topoteretes/cognee)** — production memory architectures surveyed during `agentMemory()` design.\n\n**Layout \u0026 other:**\n- **[Pretext](https://github.com/chenglou/pretext)** (Cheng Lou) — inspired the reactive layout engine's DOM-free text measurement pipeline, rebuilt as a `state -\u003e derived` graph.\n- **[CASL](https://github.com/stalniy/casl)** — declarative `allow()`/`deny()` policy builder DX that inspired `policy()`, though CASL itself was rejected as a dependency.\n- **[Nanostores](https://github.com/nanostores/nanostores)** — tiny framework-agnostic API with near 1:1 `.get()/.set()/.subscribe()` mapping that validated the store ergonomics.\n\n## License\n\n[MIT](./LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgraphrefly%2Fgraphrefly-ts","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgraphrefly%2Fgraphrefly-ts","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgraphrefly%2Fgraphrefly-ts/lists"}