{"id":47922163,"url":"https://github.com/graphrefly/graphrefly-py","last_synced_at":"2026-04-11T07:10:57.187Z","repository":{"id":347488534,"uuid":"1193924530","full_name":"graphrefly/graphrefly-py","owner":"graphrefly","description":"Reactive graph protocol for human + LLM co-operation — Python implementation. Composable nodes, glitch-free diamond resolution, two-phase push, durable streaming. Zero dependencies.","archived":false,"fork":false,"pushed_at":"2026-04-04T06:26:34.000Z","size":2422,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-04T06:31:01.325Z","etag":null,"topics":["ai-agents","asyncio","callbag","diamond-resolution","durable-workflow","graph","llm","observable","orchestration","python","reactive","reactive-programming","signals","state-management","streaming","zero-dependency"],"latest_commit_sha":null,"homepage":"https://py.graphrefly.dev","language":"Python","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":"CONTRIBUTING.md","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-27T18:15:17.000Z","updated_at":"2026-04-04T06:26:38.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/graphrefly/graphrefly-py","commit_stats":null,"previous_names":["graphrefly/graphrefly-py"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/graphrefly/graphrefly-py","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphrefly%2Fgraphrefly-py","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphrefly%2Fgraphrefly-py/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphrefly%2Fgraphrefly-py/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphrefly%2Fgraphrefly-py/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/graphrefly","download_url":"https://codeload.github.com/graphrefly/graphrefly-py/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphrefly%2Fgraphrefly-py/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31533824,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-07T16:28:08.000Z","status":"ssl_error","status_checked_at":"2026-04-07T16:28:06.951Z","response_time":105,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["ai-agents","asyncio","callbag","diamond-resolution","durable-workflow","graph","llm","observable","orchestration","python","reactive","reactive-programming","signals","state-management","streaming","zero-dependency"],"created_at":"2026-04-04T06:16:12.497Z","updated_at":"2026-04-08T00:01:23.539Z","avatar_url":"https://github.com/graphrefly.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# GraphReFly\n\n**Describe what matters. It watches, filters, and explains — persistently.**\n\nYou're buried under emails, alerts, feeds, and messages. You can't process it all. GraphReFly lets you describe automations in plain language, review them visually, run them persistently, and trace every decision back to its source.\n\n[![PyPI](https://img.shields.io/pypi/v/graphrefly?color=blue)](https://pypi.org/project/graphrefly/)\n[![license](https://img.shields.io/github/license/graphrefly/graphrefly-py)](./LICENSE)\n[![Python](https://img.shields.io/pypi/pyversions/graphrefly)](https://pypi.org/project/graphrefly/)\n\n[Docs](https://py.graphrefly.dev) | [Spec](https://py.graphrefly.dev/spec/) | [TypeScript](https://graphrefly.dev) | [API Reference](https://py.graphrefly.dev/api/)\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\npip install graphrefly\n```\n\n```python\nfrom graphrefly import state, derived, effect\n\ncount = state(0)\ndoubled = derived([count], lambda deps, _: deps[0] * 2)\n\neffect([doubled], lambda deps, _: print(\"doubled:\", deps[0]))\n# → doubled: 0\n\ncount.push(3)\n# → doubled: 6\n```\n\n## How it works\n\nYou describe what you need — an LLM composes a reactive graph (like SQL for data flows). The graph runs persistently, checkpoints its state, and traces every decision through a causal chain. Ask \"why?\" at any point and get a human-readable explanation from source to conclusion.\n\n## Why GraphReFly?\n\n|  | Redux / Zustand | RxPY | Pydantic AI | LangGraph | TC39 Signals | **GraphReFly** |\n|--|-----------------|------|-------------|-----------|-------------|---------------|\n| Simple store API | yes | no | no | no | yes | **yes** |\n| Streaming operators | no | yes | no | no | no | **yes** |\n| Diamond resolution | no | n/a | n/a | n/a | partial | **glitch-free** |\n| Graph introspection | no | no | no | checkpoints | no | **describe / observe / diagram** |\n| Causal tracing | no | no | no | no | no | **explain every decision** |\n| Durable checkpoints | no | no | no | yes | no | **file / SQLite / IndexedDB** |\n| LLM orchestration | no | no | partial | yes | no | **agent_loop / chat_stream / tool_registry** |\n| NL → graph composition | no | no | no | no | no | **graph_from_spec / llm_compose** |\n| Async runners | n/a | asyncio | asyncio | asyncio | n/a | **asyncio / trio** |\n| Dependencies | varies | 0 | many | many | n/a | **0** |\n\n## One primitive\n\nEverything is a `node`. Sugar constructors give you the right shape:\n\n```python\nfrom graphrefly import state, derived, producer, effect\nfrom graphrefly.core.messages import DATA\n\n# Writable state\nname = state(\"world\")\n\n# Computed (re-runs when deps change)\ngreeting = derived([name], lambda deps, _: f\"Hello, {deps[0]}!\")\n\n# Push source (timers, events, async streams)\nclock = producer(lambda emit, _: emit([(DATA, time.time())]))\n\n# Side effect\neffect([greeting], lambda deps, _: print(deps[0]))\n```\n\n## Streaming \u0026 operators\n\n70+ operators — transform, combine, buffer, window, rate-limit, retry, circuit-break:\n\n```python\nfrom graphrefly.extra.tier1 import map_op, filter_op, scan\nfrom graphrefly.extra.tier2 import switch_map, debounce_time\nfrom graphrefly.extra.resilience import retry\nfrom graphrefly import pipe\n\nsearch = pipe(\n    user_input,\n    debounce_time(0.3),\n    switch_map(lambda q: from_promise(fetch(f\"/api?q={q}\"))),\n    retry(strategy=\"exponential\", max_attempts=3),\n)\n```\n\n## Graph container\n\nRegister nodes in a `Graph` for introspection, snapshot, and persistence:\n\n```python\nfrom graphrefly import Graph, state, derived\n\ng = Graph(\"pricing\")\nprice = g.register(\"price\", state(100))\ntax   = g.register(\"tax\", derived([price], lambda d, _: d[0] * 0.1))\ntotal = g.register(\"total\", derived([price, tax], lambda d, _: d[0] + d[1]))\n\ng.describe()   # → full graph topology as dict\ng.diagram()    # → Mermaid diagram string\ng.observe(lambda e: print(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```python\nfrom graphrefly.patterns.ai import chat_stream, agent_loop, tool_registry\nfrom graphrefly.patterns.memory import collection, decay\n\n# Streaming chat with tool use\nchat = chat_stream(\"assistant\", model=\"claude-sonnet-4-20250514\",\n                   tools=tool_registry(\"tools\", search=search_fn))\n\n# Full agent loop: observe → think → act → memory\nagent = agent_loop(\"researcher\", llm=chat,\n                   memory=agent_memory(decay=\"openviking\"))\n```\n\n## Async runners\n\nNative asyncio and trio support for async sources and long-running graphs:\n\n```python\nfrom graphrefly.compat.asyncio_runner import AsyncioRunner\nfrom graphrefly.extra.sources import from_async_iter\n\n# Wrap an async generator as a reactive node\nasync def sse_events():\n    async for event in httpx_client.stream(\"GET\", \"/events\"):\n        yield event.data\n\nevents = from_async_iter(sse_events())\n\n# Run the graph in an asyncio event loop\nrunner = AsyncioRunner(graph)\nawait runner.run()\n```\n\n## FastAPI integration\n\nDrop-in integration for reactive backends:\n\n```python\nfrom graphrefly.integrations.fastapi import GraphReflyRouter\n\nrouter = GraphReflyRouter(graph)\napp.include_router(router, prefix=\"/graph\")\n# GET /graph/describe  → graph topology\n# GET /graph/snapshot  → current state\n# WS  /graph/observe   → live change stream\n```\n\n## Resilience \u0026 checkpoints\n\nBuilt-in retry, circuit breakers, rate limiters, and persistent checkpoints:\n\n```python\nfrom graphrefly.extra.resilience import retry, circuit_breaker, rate_limiter\nfrom graphrefly.extra.checkpoint import FileCheckpointAdapter, save_graph_checkpoint\n\n# Retry with exponential backoff\nresilient = pipe(source, retry(strategy=\"exponential\"))\n\n# Circuit breaker\nbreaker = circuit_breaker(threshold=5, reset_timeout=30.0)\n\n# Checkpoint to file system\nadapter = FileCheckpointAdapter(\"./checkpoints\")\nsave_graph_checkpoint(graph, adapter)\n```\n\n## Project layout\n\n| Path | Contents |\n|------|----------|\n| `src/graphrefly/core/` | Message protocol, `node` primitive, batch, sugar constructors |\n| `src/graphrefly/extra/` | Operators, sources, data structures, resilience, checkpoints |\n| `src/graphrefly/graph/` | `Graph` container, describe/observe, snapshot, persistence |\n| `src/graphrefly/patterns/` | Orchestration, messaging, memory, AI, CQRS, reactive layout |\n| `src/graphrefly/compat/` | Async runners (asyncio, trio) |\n| `src/graphrefly/integrations/` | Framework integrations (FastAPI) |\n| `docs/` | Roadmap, guidance, benchmarks |\n| `website/` | Astro + Starlight docs site ([py.graphrefly.dev](https://py.graphrefly.dev)) |\n\n## Scripts\n\n```bash\nuv run pytest              # run tests\nuv run ruff check .        # lint\nuv run mypy src/           # type check\nuv run pytest --benchmark  # benchmarks\n```\n\n## Requirements\n\nPython 3.12 or later. Zero runtime dependencies.\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)** \u0026 **[callbag-recharge-py](https://github.com/Callbag-Recharge/callbag-recharge-py)** — GraphReFly's direct predecessors. The Python port (6 primitives, 18 operators, 100+ tests) established cross-language parity patterns carried forward.\n\n**Reactive design patterns:**\n- **[SolidJS](https://github.com/solidjs/solid)** — two-phase execution (DIRTY propagation + value flow), automatic caching, and effect batching. Closest philosophical neighbor.\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.\n- **[RxJS](https://github.com/ReactiveX/rxjs)** / **[RxPY](https://github.com/ReactiveX/RxPY)** — operator naming conventions 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 `agent_memory()`.\n- **[FadeMem](https://arxiv.org/abs/2501.09399)** (Wei et al., ICASSP 2026) — biologically-inspired dual-layer memory with adaptive exponential decay.\n- **[MAGMA](https://arxiv.org/abs/2501.13920)** (Jiang et al., 2026) — four-parallel-graph model (semantic/temporal/causal/entity) that informed `knowledge_graph()` 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 `agent_memory()` 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.\n- **[CASL](https://github.com/stalniy/casl)** — declarative `allow()`/`deny()` policy builder DX that inspired `policy()`.\n- **[Nanostores](https://github.com/nanostores/nanostores)** — tiny framework-agnostic API with `.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-py","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgraphrefly%2Fgraphrefly-py","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgraphrefly%2Fgraphrefly-py/lists"}