{"id":50691645,"url":"https://github.com/fundamental-research-labs/langdag","last_synced_at":"2026-06-09T03:11:38.229Z","repository":{"id":336365988,"uuid":"1149365563","full_name":"fundamental-research-labs/langdag","owner":"fundamental-research-labs","description":"High-performance tool for managing LLM conversations and workflows as DAGs.","archived":false,"fork":false,"pushed_at":"2026-05-25T01:23:13.000Z","size":5605,"stargazers_count":24,"open_issues_count":1,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-05-25T03:22:19.765Z","etag":null,"topics":["ai","cli","conversation","dag","langchain","langfuse","llm","prompt-engineering","prompt-management","self-hosted"],"latest_commit_sha":null,"homepage":"https://langdag.com","language":"Go","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/fundamental-research-labs.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":null,"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-02-04T03:04:38.000Z","updated_at":"2026-05-21T17:50:27.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/fundamental-research-labs/langdag","commit_stats":null,"previous_names":["aduermael/langdag","fundamental-research-labs/langdag"],"tags_count":27,"template":false,"template_full_name":null,"purl":"pkg:github/fundamental-research-labs/langdag","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fundamental-research-labs%2Flangdag","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fundamental-research-labs%2Flangdag/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fundamental-research-labs%2Flangdag/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fundamental-research-labs%2Flangdag/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fundamental-research-labs","download_url":"https://codeload.github.com/fundamental-research-labs/langdag/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fundamental-research-labs%2Flangdag/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34089657,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-09T02:00:06.510Z","response_time":63,"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":["ai","cli","conversation","dag","langchain","langfuse","llm","prompt-engineering","prompt-management","self-hosted"],"created_at":"2026-06-09T03:11:37.360Z","updated_at":"2026-06-09T03:11:38.215Z","avatar_url":"https://github.com/fundamental-research-labs.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/assets/langdag-banner.svg\" width=\"600\" alt=\"LangDAG\"\u003e\n\u003c/p\u003e\n\n\u003ch3 align=\"center\"\u003e\u003cem\u003eLLM Conversations as Directed Acyclic Graphs\u003c/em\u003e\u003c/h3\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/aduermael/langdag/actions/workflows/test-go.yml\"\u003e\u003cimg src=\"https://img.shields.io/github/actions/workflow/status/aduermael/langdag/test-go.yml?style=flat-square\u0026label=Go%20SDK\" alt=\"Go SDK Tests\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/aduermael/langdag/actions/workflows/test-python.yml\"\u003e\u003cimg src=\"https://img.shields.io/github/actions/workflow/status/aduermael/langdag/test-python.yml?style=flat-square\u0026label=Python%20SDK\" alt=\"Python SDK Tests\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/aduermael/langdag/actions/workflows/test-typescript.yml\"\u003e\u003cimg src=\"https://img.shields.io/github/actions/workflow/status/aduermael/langdag/test-typescript.yml?style=flat-square\u0026label=TypeScript%20SDK\" alt=\"TypeScript SDK Tests\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/aduermael/langdag/actions/workflows/test.yml\"\u003e\u003cimg src=\"https://img.shields.io/github/actions/workflow/status/aduermael/langdag/test.yml?style=flat-square\u0026label=E2E\" alt=\"E2E Tests\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/aduermael/langdag/tags\"\u003e\u003cimg src=\"https://img.shields.io/github/v/tag/aduermael/langdag?style=flat-square\u0026label=version\u0026color=00ADD8\" alt=\"Version\"\u003e\u003c/a\u003e\n  \u003ca href=\"LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-MIT-blue?style=flat-square\" alt=\"License\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://golang.org/\"\u003e\u003cimg src=\"https://img.shields.io/badge/Go-1.23+-00ADD8?style=flat-square\u0026logo=go\u0026logoColor=white\" alt=\"Go\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"#features\"\u003eFeatures\u003c/a\u003e •\n  \u003ca href=\"#use-as-a-go-library\"\u003eGo Library\u003c/a\u003e •\n  \u003ca href=\"#installation\"\u003eInstallation\u003c/a\u003e •\n  \u003ca href=\"#cli\"\u003eCLI\u003c/a\u003e •\n  \u003ca href=\"#api--sdks\"\u003eAPI \u0026 SDKs\u003c/a\u003e •\n  \u003ca href=\"#roadmap\"\u003eRoadmap\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## Why LangDAG?\n\nLangDAG is a **high-performance Go tool** that persists LLM conversations as directed acyclic graphs. Branch from any point, explore alternative paths, and maintain full conversation history.\n\n```\n┌─────────┐     ┌─────────┐     ┌─────────┐     ┌─────────┐\n│  User   │────▶│   LLM   │────▶│  Tool   │────▶│   LLM   │\n└─────────┘     └─────────┘     └─────────┘     └─────────┘\n                    │                               │\n                    └──────── conversation ─────────┘\n                                 = DAG\n```\n\n**Key insight:** A conversation *is* a DAG—it just grows incrementally.\n\n---\n\n## Features\n\n| Feature | Description |\n|---------|-------------|\n| ⚡ **Performance** | Pure Go, ~1ms overhead, single static binary, zero runtime deps |\n| 🌊 **Native Streaming** | SSE streaming with real-time token delivery |\n| 🌳 **Conversation Forking** | Branch from any node, explore alternative paths |\n| 🏷️ **Node Aliases** | Human-readable names for any node |\n| 🔄 **Auto Retry** | Exponential backoff for transient LLM failures |\n| 💾 **Persistent Storage** | SQLite with WAL mode, full history replay |\n| 🔧 **Tool Use** | First-class tool definitions with tool_use/tool_result flows |\n| 🌐 **Multi-Provider** | Canonical model routing across Anthropic, OpenAI, Gemini, Grok, OpenRouter, Ollama, Azure, Vertex AI, and Bedrock deployments |\n\n---\n\n## Use as a Go Library\n\nLangDAG is available as an importable Go package for building AI agent applications with persistent conversation storage.\n\n```bash\ngo get langdag.com/langdag\n```\n\n### Basic Usage\n\n```go\nimport \"langdag.com/langdag\"\n\nclient, err := langdag.New(langdag.Config{\n    StoragePath: \"./agent.db\",\n    APIKeys: map[string]string{\n        \"anthropic\": os.Getenv(\"ANTHROPIC_API_KEY\"),\n    },\n})\nif err != nil {\n    log.Fatal(err)\n}\ndefer client.Close()\n\n// Start a new conversation\nresult, err := client.Prompt(ctx, \"What is LangDAG?\",\n    langdag.WithModel(\"claude-opus-4-6\"),\n)\n// Stream the response\nfor chunk := range result.Stream {\n    if chunk.Done {\n        fmt.Printf(\"\\n[saved as node %s]\\n\", chunk.NodeID)\n    } else {\n        fmt.Print(chunk.Content)\n    }\n}\n\n// Continue the conversation from a specific node\nresult2, err := client.PromptFrom(ctx, result.NodeID, \"Tell me more\")\n```\n\n### Deployment-Aware Routing\n\n```go\nclient, err := langdag.New(langdag.Config{\n    Deployments: map[string]langdag.DeploymentConfig{\n        \"openai-direct\": {APIKey: os.Getenv(\"OPENAI_API_KEY\")},\n        \"openrouter\":    {APIKey: os.Getenv(\"OPENROUTER_API_KEY\")},\n    },\n    RoutingPolicy: \u0026langdag.RoutingPolicy{\n        Providers: map[string][]langdag.RoutingStage{\n            \"openai\": {{\n                Deployments: []langdag.DeploymentChoice{\n                    {DeploymentID: \"openai-direct\", Weight: 80},\n                    {DeploymentID: \"openrouter\", Weight: 20},\n                },\n                Retries: 1,\n            }},\n        },\n    },\n})\n\nresult, err := client.Prompt(ctx, \"Review this change\",\n    langdag.WithModel(\"openai/gpt-4.1-2025-04-14\"),\n)\n```\n\nThe request targets a canonical model ID. LangDAG resolves it to an eligible\ndeployment offering, passes the deployment's native model ID to the adapter, and\nrecords served identity, normalized usage, pricing snapshot, and provider exact\ncost metadata when available.\nProvider and model routing rules are scoped, so unrelated models continue to\nuse automatic eligible deployment resolution. Set `RoutingPolicy.Default` only\nwhen you intentionally want an advanced global baseline for every unmatched\nmodel.\n\n### Config Options\n\n| Field | Description |\n|-------|-------------|\n| `StoragePath` | Path to SQLite database file |\n| `APIKeys` | Map of provider name to API key (`\"anthropic\"`, `\"openai\"`, `\"gemini\"`, `\"grok\"`) |\n| `Provider` | Default provider name (anthropic, openai, gemini, grok) |\n| `ModelCatalog` | Deployment-aware catalog used for canonical model resolution |\n| `RemoteModelCatalog` | Explicit opt-in to fetch the latest published catalog at startup |\n| `Deployments` | Routeable deployment credentials, base URLs, cloud settings, and Azure model mappings |\n| `RoutingPolicy` | Weighted deployment stages by default, provider, or exact canonical model |\n| `Routing` | Deprecated provider-keyed routing rules |\n| `FallbackOrder` | Deprecated provider fallback order |\n| `RetryConfig` | Retry settings (max retries, base/max delay) |\n\n### Available Methods\n\n- `client.Prompt(ctx, message, opts...)` — Start a new conversation\n- `client.PromptFrom(ctx, nodeID, message, opts...)` — Continue from an existing node\n- `client.ListConversations(ctx)` — List all root conversation nodes\n- `client.GetNode(ctx, nodeID)` — Get a single node by ID\n- `client.GetSubtree(ctx, nodeID)` — Get full subtree rooted at a node\n- `client.GetAncestors(ctx, nodeID)` — Get ancestor chain up to root\n- `client.DeleteNode(ctx, nodeID)` — Delete a node and its subtree\n\n### Testing with `NewWithDeps`\n\nUse `NewWithDeps` to inject custom storage and provider implementations — no API keys required in tests:\n\n```go\nclient := langdag.NewWithDeps(tempStorage, mockProvider)\n```\n\n## Model Catalog Refresh\n\nLangDAG ships an embedded catalog generated from the published\n`origin/model-catalog` branch. The generated `internal/models/catalog.json`\nfile is committed so Go module release tags include the data used by\n`go:embed`. Maintainers can update it manually with\n`./scripts/sync-model-catalog.sh`.\n\nPrompt/runtime routing uses the embedded catalog by default. It does not read\n`~/.config/langdag/model_catalog.json` implicitly, so a stale user cache cannot\noverride the published catalog snapshot. Apps that want the freshest catalog at\nstartup can set `RemoteModelCatalog`; apps that want a one-shot fetch can call\n`LoadRemoteModelCatalog` or `RefreshModelCatalogCache` with no cache path and\npass the returned catalog via `Config.ModelCatalog`. `langdag models --update`\ncan fetch `https://langdag.com/model-catalog/v1/catalog.json` for the current\ncommand. `LANGDAG_MODEL_CATALOG_URL` / `LANGDAG_MODEL_CATALOG_TIMEOUT` can\noverride CLI fetches.\n\n---\n\n## Installation\n\n### From Source\n\n```bash\ngit clone https://github.com/aduermael/langdag.git\ncd langdag\ngo build -o langdag ./cmd/langdag\n```\n\n### Go Install\n\n```bash\ngo install github.com/aduermael/langdag/cmd/langdag@latest\n```\n\n---\n\n## CLI\n\n```bash\n# Set your API key\nexport ANTHROPIC_API_KEY=\"your-api-key\"\n\n# Start a new conversation\nlangdag prompt \"What is a DAG?\"\n\n# Interactive mode\nlangdag prompt\n\n# List all conversations (root nodes)\nlangdag ls\n\n# View a conversation tree\nlangdag show a1b2\n\n# Continue from a specific node\nlangdag prompt a1b2 \"Tell me more\"\n\n# Delete a conversation\nlangdag rm a1b2\n```\n\nEvery conversation is a DAG that grows as you chat—and you can branch from any point:\n\n```\nNode history:\n├─ 1a2b [human]: What is a DAG?\n│  ├─ 5e6f [assistant]: A DAG is a directed graph with no cycles...\n│  │  └─ 9c0d [human]: Can you give me an example?\n│  │     └─ 2f34 [assistant]: Sure! Think of a family tree...\n│  └─ 7a8b [assistant]: Let me explain with a diagram...\n│     └─ 4e5f [human]: That's clearer, thanks!\n└─ ...\n```\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eCLI Reference\u003c/strong\u003e\u003c/summary\u003e\n\n```bash\n# Prompt commands\nlangdag prompt \"message\"               # Start new conversation\nlangdag prompt -m \u003cmodel\u003e \"message\"    # Use a specific model\nlangdag prompt -s \"system\" \"message\"   # With system prompt\nlangdag prompt \u003cnode-id\u003e \"message\"     # Continue from node\nlangdag prompt                         # Interactive mode (new tree)\nlangdag prompt \u003cnode-id\u003e               # Interactive mode from node\n\n# Node management\nlangdag ls                             # List root nodes\nlangdag show \u003cid\u003e                      # Show node tree\nlangdag rm \u003cid\u003e                        # Delete node and subtree\n```\n\n\u003c/details\u003e\n\n---\n\n## API \u0026 SDKs\n\nLangDAG can run as a REST API server:\n\n```bash\nlangdag serve --port 8080\n```\n\n**Endpoints:**\n- `POST /prompt` — Start new conversation tree\n- `POST /nodes/{id}/prompt` — Continue from existing node\n- `GET /nodes` — List root nodes\n- `GET /nodes/{id}` — Get a single node\n- `GET /nodes/{id}/tree` — Get full tree from node\n- `DELETE /nodes/{id}` — Delete node and subtree\n- `PUT /nodes/{id}/aliases/{alias}` — Create node alias\n- `GET /nodes/{id}/aliases` — List node aliases\n- `DELETE /aliases/{alias}` — Delete alias\n\nSee the [OpenAPI specification](api/openapi.yaml) for full API documentation.\n\n### Python\n\n```bash\npip install langdag\n```\n\n```python\nfrom langdag import LangDAGClient\n\nclient = LangDAGClient()\n\n# Start a conversation\nnode = client.prompt(\"What is a DAG?\")\nprint(node.content)\n\n# Continue from any node\nnode2 = node.prompt(\"Tell me more\")\n\n# Stream responses\nfor event in client.prompt(\"Explain graphs\", stream=True):\n    if event.content:\n        print(event.content, end=\"\")\n```\n\n### Go\n\n```bash\ngo get github.com/langdag/langdag-go\n```\n\n```go\nclient := langdag.NewClient(\"http://localhost:8080\")\n\n// Start a conversation\nnode, _ := client.Prompt(ctx, \"What is a DAG?\")\nfmt.Println(node.Content)\n\n// Continue from any node\nnode2, _ := node.Prompt(ctx, \"Tell me more\")\n\n// Stream responses\nstream, _ := client.PromptStream(ctx, \"Explain graphs\")\nfor event := range stream.Events() {\n    fmt.Print(event.Content)\n}\nresult, _ := stream.Node()\n```\n\n### TypeScript\n\n```bash\nnpm install langdag\n```\n\n```typescript\nimport { LangDAGClient } from 'langdag';\n\nconst client = new LangDAGClient();\n\n// Start a conversation\nconst node = await client.prompt('What is a DAG?');\nconsole.log(node.content);\n\n// Continue from any node\nconst node2 = await node.prompt('Tell me more');\n\n// Stream responses\nconst stream = await client.promptStream('Explain graphs');\nfor await (const event of stream.events()) {\n  process.stdout.write(event.content);\n}\nconst result = await stream.node();\n```\n\nSee the [SDK source code](sdks/) and [example projects](examples/) for more details.\n\n---\n\n## Architecture\n\n```\n┌──────────────────────────────────────────────────────────┐\n│                      CLI / API                           │\n├──────────────────────────────────────────────────────────┤\n│                 Conversation Manager                     │\n├──────────────────────────────────────────────────────────┤\n│                      Provider Layer                      │\n│   ┌───────────┐  ┌───────────┐  ┌───────────┐  ┌──────┐ │\n│   │ Anthropic │  │  OpenAI   │  │  Gemini   │  │ Grok │ │\n│   └───────────┘  └───────────┘  └───────────┘  └──────┘ │\n├──────────────────────────────────────────────────────────┤\n│                   Storage Layer                          │\n│   ┌───────────┐                                          │\n│   │  SQLite   │                                          │\n│   └───────────┘                                          │\n└──────────────────────────────────────────────────────────┘\n```\n\n---\n\n## Documentation\n\n- **[Design Document](docs/DESIGN.md)** — Deep dive into architecture\n- **[API Reference](https://aduermael.github.io/langdag/api)** — REST \u0026 WebSocket APIs\n- **[Examples](examples/)** — Sample workflows\n- **[Migrate from LangGraph](docs/migrate-from-langgraph.md)** — Import your existing LangGraph conversations into LangDAG\n\n---\n\n## Roadmap\n\n- [x] SQLite storage with WAL mode\n- [x] Anthropic, OpenAI, Gemini providers with streaming\n- [x] Node-centric API (prompt, branch, tree)\n- [x] Tree visualization\n- [x] REST API with SSE streaming\n- [x] Python, Go, TypeScript SDKs\n- [x] Node aliases\n- [x] Automatic retry with exponential backoff\n- [x] Tool use (WithTools, tool_use/tool_result flows)\n- [x] Grok (xAI) provider\n- [x] Model catalog with pricing and context windows\n- [x] LangGraph migration tooling (JSON + SQLite import)\n- [x] Prompt caching (Anthropic)\n- [ ] Web UI\n\n---\n\n## Comparison\n\n| | LangDAG | LangGraph | Langfuse |\n|---|---------|-----------|----------|\n| **Focus** | Conversation tree store | State machine orchestration | Observability |\n| **Language** | Go | Python | TypeScript |\n| **Performance** | ~1ms overhead | Higher latency | N/A |\n| **Conversation model** | Native DAG | Manual | Trace-based |\n| **Deployment** | Single binary | Python runtime | SaaS/Self-host |\n\n---\n\n## Contributing\n\nContributions are welcome! Please read the [Contributing Guide](CONTRIBUTING.md) first.\n\n```bash\n# Run tests\ngo test ./...\n\n# Build\ngo build -o langdag ./cmd/langdag\n```\n\n---\n\n## License\n\nMIT License - see [LICENSE](LICENSE) for details.\n\n---\n\n\u003cp align=\"center\"\u003e\n  \u003csub\u003eBuilt with ❤️ in Go\u003c/sub\u003e\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffundamental-research-labs%2Flangdag","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffundamental-research-labs%2Flangdag","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffundamental-research-labs%2Flangdag/lists"}