langrove 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. langrove-0.1.0/.claude/agents/architect.md +58 -0
  2. langrove-0.1.0/.claude/agents/implementer.md +52 -0
  3. langrove-0.1.0/.claude/agents/reviewer.md +59 -0
  4. langrove-0.1.0/.claude/journals/README.md +30 -0
  5. langrove-0.1.0/.claude/journals/implementer.md +7 -0
  6. langrove-0.1.0/.claude/journals/planner.md +7 -0
  7. langrove-0.1.0/.claude/journals/reviewer.md +7 -0
  8. langrove-0.1.0/.claude/rules/api-design.md +64 -0
  9. langrove-0.1.0/.claude/rules/architecture.md +65 -0
  10. langrove-0.1.0/.claude/rules/auth.md +63 -0
  11. langrove-0.1.0/.claude/rules/database.md +56 -0
  12. langrove-0.1.0/.claude/rules/pipeline.md +23 -0
  13. langrove-0.1.0/.claude/rules/streaming.md +74 -0
  14. langrove-0.1.0/.claude/rules/testing.md +37 -0
  15. langrove-0.1.0/.claude/rules/worker-tasks.md +73 -0
  16. langrove-0.1.0/.claude/scheduled-tasks.md +186 -0
  17. langrove-0.1.0/.claude/settings.json +66 -0
  18. langrove-0.1.0/.claude/settings.local.json +22 -0
  19. langrove-0.1.0/.github/ISSUE_TEMPLATE/bug.yml +28 -0
  20. langrove-0.1.0/.github/ISSUE_TEMPLATE/feature.yml +31 -0
  21. langrove-0.1.0/.github/scripts/setup-labels.sh +28 -0
  22. langrove-0.1.0/.github/workflows/auto-merge.yml.disabled +18 -0
  23. langrove-0.1.0/.github/workflows/ci.yml.disabled +47 -0
  24. langrove-0.1.0/.github/workflows/claude-backlog.yml.disabled +65 -0
  25. langrove-0.1.0/.github/workflows/claude-implement.yml.disabled +69 -0
  26. langrove-0.1.0/.github/workflows/claude-maintenance.yml.disabled +32 -0
  27. langrove-0.1.0/.github/workflows/claude-planner.yml.disabled +42 -0
  28. langrove-0.1.0/.github/workflows/claude-review.yml.disabled +24 -0
  29. langrove-0.1.0/.github/workflows/claude.yml.disabled +25 -0
  30. langrove-0.1.0/.github/workflows/publish.yml +27 -0
  31. langrove-0.1.0/.gitignore +51 -0
  32. langrove-0.1.0/CLAUDE.md +88 -0
  33. langrove-0.1.0/Dockerfile +13 -0
  34. langrove-0.1.0/LICENSE +21 -0
  35. langrove-0.1.0/PKG-INFO +478 -0
  36. langrove-0.1.0/README.md +436 -0
  37. langrove-0.1.0/alembic.ini +36 -0
  38. langrove-0.1.0/docker-compose.yml +59 -0
  39. langrove-0.1.0/examples/README.md +76 -0
  40. langrove-0.1.0/examples/custom-auth/.env.example +6 -0
  41. langrove-0.1.0/examples/custom-auth/README.md +140 -0
  42. langrove-0.1.0/examples/custom-auth/agent.py +36 -0
  43. langrove-0.1.0/examples/custom-auth/auth.py +51 -0
  44. langrove-0.1.0/examples/custom-auth/auth_private.py +62 -0
  45. langrove-0.1.0/examples/custom-auth/client.py +109 -0
  46. langrove-0.1.0/examples/custom-auth/langgraph.json +15 -0
  47. langrove-0.1.0/examples/helios-video-agent/.env.example +10 -0
  48. langrove-0.1.0/examples/helios-video-agent/AGENTS.md +253 -0
  49. langrove-0.1.0/examples/helios-video-agent/README.md +229 -0
  50. langrove-0.1.0/examples/helios-video-agent/agent.py +151 -0
  51. langrove-0.1.0/examples/helios-video-agent/client.py +200 -0
  52. langrove-0.1.0/examples/helios-video-agent/frontend/index.html +21 -0
  53. langrove-0.1.0/examples/helios-video-agent/frontend/package-lock.json +2182 -0
  54. langrove-0.1.0/examples/helios-video-agent/frontend/package.json +25 -0
  55. langrove-0.1.0/examples/helios-video-agent/frontend/src/App.tsx +250 -0
  56. langrove-0.1.0/examples/helios-video-agent/frontend/src/components/ChatPanel.tsx +352 -0
  57. langrove-0.1.0/examples/helios-video-agent/frontend/src/components/PreviewPanel.tsx +638 -0
  58. langrove-0.1.0/examples/helios-video-agent/frontend/src/components/ReviewBar.tsx +160 -0
  59. langrove-0.1.0/examples/helios-video-agent/frontend/src/components/ToolProgress.tsx +95 -0
  60. langrove-0.1.0/examples/helios-video-agent/frontend/src/hooks/useVideoAgent.ts +186 -0
  61. langrove-0.1.0/examples/helios-video-agent/frontend/src/lib/store.ts +116 -0
  62. langrove-0.1.0/examples/helios-video-agent/frontend/src/main.tsx +10 -0
  63. langrove-0.1.0/examples/helios-video-agent/frontend/tsconfig.json +21 -0
  64. langrove-0.1.0/examples/helios-video-agent/frontend/vite.config.ts +24 -0
  65. langrove-0.1.0/examples/helios-video-agent/helios_tools.py +749 -0
  66. langrove-0.1.0/examples/helios-video-agent/langgraph.json +12 -0
  67. langrove-0.1.0/examples/helios-video-agent/pyproject.toml +37 -0
  68. langrove-0.1.0/examples/helios-video-agent/skills/helios-skills/core/SKILL.md +447 -0
  69. langrove-0.1.0/examples/helios-video-agent/skills/helios-skills/examples/canvas/SKILL.md +75 -0
  70. langrove-0.1.0/examples/helios-video-agent/skills/helios-skills/examples/chartjs/SKILL.md +67 -0
  71. langrove-0.1.0/examples/helios-video-agent/skills/helios-skills/examples/d3/SKILL.md +60 -0
  72. langrove-0.1.0/examples/helios-video-agent/skills/helios-skills/examples/framer-motion/SKILL.md +79 -0
  73. langrove-0.1.0/examples/helios-video-agent/skills/helios-skills/examples/gsap/SKILL.md +68 -0
  74. langrove-0.1.0/examples/helios-video-agent/skills/helios-skills/examples/lottie/SKILL.md +59 -0
  75. langrove-0.1.0/examples/helios-video-agent/skills/helios-skills/examples/p5/SKILL.md +67 -0
  76. langrove-0.1.0/examples/helios-video-agent/skills/helios-skills/examples/pixi/SKILL.md +61 -0
  77. langrove-0.1.0/examples/helios-video-agent/skills/helios-skills/examples/podcast-visualizer/SKILL.md +88 -0
  78. langrove-0.1.0/examples/helios-video-agent/skills/helios-skills/examples/react/SKILL.md +98 -0
  79. langrove-0.1.0/examples/helios-video-agent/skills/helios-skills/examples/signals/SKILL.md +50 -0
  80. langrove-0.1.0/examples/helios-video-agent/skills/helios-skills/examples/solid/SKILL.md +162 -0
  81. langrove-0.1.0/examples/helios-video-agent/skills/helios-skills/examples/svelte/SKILL.md +203 -0
  82. langrove-0.1.0/examples/helios-video-agent/skills/helios-skills/examples/tailwind/SKILL.md +52 -0
  83. langrove-0.1.0/examples/helios-video-agent/skills/helios-skills/examples/threejs/SKILL.md +136 -0
  84. langrove-0.1.0/examples/helios-video-agent/skills/helios-skills/examples/vanilla/SKILL.md +88 -0
  85. langrove-0.1.0/examples/helios-video-agent/skills/helios-skills/examples/vue/SKILL.md +124 -0
  86. langrove-0.1.0/examples/helios-video-agent/skills/helios-skills/getting-started/SKILL.md +247 -0
  87. langrove-0.1.0/examples/helios-video-agent/skills/helios-skills/guided/explainer-video/SKILL.md +229 -0
  88. langrove-0.1.0/examples/helios-video-agent/skills/helios-skills/guided/launch-announcement/SKILL.md +235 -0
  89. langrove-0.1.0/examples/helios-video-agent/skills/helios-skills/guided/motion-design-rules/SKILL.md +144 -0
  90. langrove-0.1.0/examples/helios-video-agent/skills/helios-skills/guided/product-demo/SKILL.md +243 -0
  91. langrove-0.1.0/examples/helios-video-agent/skills/helios-skills/guided/promo-video/SKILL.md +208 -0
  92. langrove-0.1.0/examples/helios-video-agent/skills/helios-skills/guided/social-clip/SKILL.md +243 -0
  93. langrove-0.1.0/examples/helios-video-agent/skills/helios-skills/guided/testimonial-video/SKILL.md +234 -0
  94. langrove-0.1.0/examples/helios-video-agent/skills/helios-skills/player/SKILL.md +191 -0
  95. langrove-0.1.0/examples/helios-video-agent/skills/helios-skills/renderer/SKILL.md +236 -0
  96. langrove-0.1.0/examples/helios-video-agent/skills/helios-skills/studio/SKILL.md +93 -0
  97. langrove-0.1.0/examples/helios-video-agent/skills/helios-skills/workflows/create-composition/SKILL.md +120 -0
  98. langrove-0.1.0/examples/helios-video-agent/skills/helios-skills/workflows/render-video/SKILL.md +105 -0
  99. langrove-0.1.0/examples/helios-video-agent/skills/helios-skills/workflows/visualize-data/SKILL.md +69 -0
  100. langrove-0.1.0/examples/helios-video-agent/uv.lock +2291 -0
  101. langrove-0.1.0/examples/multi-agent-store/.env.example +6 -0
  102. langrove-0.1.0/examples/multi-agent-store/README.md +186 -0
  103. langrove-0.1.0/examples/multi-agent-store/client.py +241 -0
  104. langrove-0.1.0/examples/multi-agent-store/langgraph.json +12 -0
  105. langrove-0.1.0/examples/multi-agent-store/researcher.py +68 -0
  106. langrove-0.1.0/examples/multi-agent-store/writer.py +50 -0
  107. langrove-0.1.0/examples/quickstart/.env.example +6 -0
  108. langrove-0.1.0/examples/quickstart/README.md +112 -0
  109. langrove-0.1.0/examples/quickstart/agent.py +37 -0
  110. langrove-0.1.0/examples/quickstart/client.py +109 -0
  111. langrove-0.1.0/examples/quickstart/langgraph.json +14 -0
  112. langrove-0.1.0/pyproject.toml +87 -0
  113. langrove-0.1.0/src/langrove/__init__.py +3 -0
  114. langrove-0.1.0/src/langrove/__main__.py +5 -0
  115. langrove-0.1.0/src/langrove/api/__init__.py +0 -0
  116. langrove-0.1.0/src/langrove/api/agents.py +68 -0
  117. langrove-0.1.0/src/langrove/api/assistants.py +109 -0
  118. langrove-0.1.0/src/langrove/api/crons.py +72 -0
  119. langrove-0.1.0/src/langrove/api/dead_letter.py +79 -0
  120. langrove-0.1.0/src/langrove/api/deps.py +166 -0
  121. langrove-0.1.0/src/langrove/api/health.py +99 -0
  122. langrove-0.1.0/src/langrove/api/runs.py +328 -0
  123. langrove-0.1.0/src/langrove/api/store.py +256 -0
  124. langrove-0.1.0/src/langrove/api/threads.py +162 -0
  125. langrove-0.1.0/src/langrove/app.py +172 -0
  126. langrove-0.1.0/src/langrove/auth/__init__.py +11 -0
  127. langrove-0.1.0/src/langrove/auth/base.py +102 -0
  128. langrove-0.1.0/src/langrove/auth/custom.py +153 -0
  129. langrove-0.1.0/src/langrove/auth/middleware.py +76 -0
  130. langrove-0.1.0/src/langrove/auth/noop.py +17 -0
  131. langrove-0.1.0/src/langrove/cli.py +174 -0
  132. langrove-0.1.0/src/langrove/config.py +108 -0
  133. langrove-0.1.0/src/langrove/db/__init__.py +0 -0
  134. langrove-0.1.0/src/langrove/db/assistant_repo.py +176 -0
  135. langrove-0.1.0/src/langrove/db/cron_repo.py +130 -0
  136. langrove-0.1.0/src/langrove/db/langgraph_pools.py +60 -0
  137. langrove-0.1.0/src/langrove/db/pool.py +80 -0
  138. langrove-0.1.0/src/langrove/db/run_repo.py +138 -0
  139. langrove-0.1.0/src/langrove/db/store_repo.py +113 -0
  140. langrove-0.1.0/src/langrove/db/thread_repo.py +130 -0
  141. langrove-0.1.0/src/langrove/exceptions.py +42 -0
  142. langrove-0.1.0/src/langrove/graph/__init__.py +0 -0
  143. langrove-0.1.0/src/langrove/graph/loader.py +54 -0
  144. langrove-0.1.0/src/langrove/graph/registry.py +116 -0
  145. langrove-0.1.0/src/langrove/migrations/env.py +51 -0
  146. langrove-0.1.0/src/langrove/migrations/script.py.mako +24 -0
  147. langrove-0.1.0/src/langrove/migrations/versions/001_initial_schema.py +190 -0
  148. langrove-0.1.0/src/langrove/models/__init__.py +0 -0
  149. langrove-0.1.0/src/langrove/models/assistants.py +78 -0
  150. langrove-0.1.0/src/langrove/models/common.py +37 -0
  151. langrove-0.1.0/src/langrove/models/crons.py +52 -0
  152. langrove-0.1.0/src/langrove/models/runs.py +65 -0
  153. langrove-0.1.0/src/langrove/models/store.py +58 -0
  154. langrove-0.1.0/src/langrove/models/threads.py +70 -0
  155. langrove-0.1.0/src/langrove/queue/__init__.py +0 -0
  156. langrove-0.1.0/src/langrove/queue/consumer.py +140 -0
  157. langrove-0.1.0/src/langrove/queue/publisher.py +61 -0
  158. langrove-0.1.0/src/langrove/queue/recovery.py +97 -0
  159. langrove-0.1.0/src/langrove/services/__init__.py +0 -0
  160. langrove-0.1.0/src/langrove/services/assistant_service.py +124 -0
  161. langrove-0.1.0/src/langrove/services/cron_service.py +61 -0
  162. langrove-0.1.0/src/langrove/services/run_service.py +282 -0
  163. langrove-0.1.0/src/langrove/services/store_service.py +72 -0
  164. langrove-0.1.0/src/langrove/services/thread_service.py +224 -0
  165. langrove-0.1.0/src/langrove/settings.py +41 -0
  166. langrove-0.1.0/src/langrove/streaming/__init__.py +0 -0
  167. langrove-0.1.0/src/langrove/streaming/broker.py +190 -0
  168. langrove-0.1.0/src/langrove/streaming/executor.py +248 -0
  169. langrove-0.1.0/src/langrove/streaming/formatter.py +67 -0
  170. langrove-0.1.0/src/langrove/worker.py +252 -0
  171. langrove-0.1.0/tests/__init__.py +0 -0
  172. langrove-0.1.0/tests/conftest.py +19 -0
  173. langrove-0.1.0/tests/fixtures/__init__.py +0 -0
  174. langrove-0.1.0/tests/fixtures/echo_graph.py +22 -0
  175. langrove-0.1.0/tests/fixtures/langgraph.json +7 -0
  176. langrove-0.1.0/tests/test_auth.py +61 -0
  177. langrove-0.1.0/tests/test_config.py +114 -0
  178. langrove-0.1.0/tests/test_streaming.py +103 -0
  179. langrove-0.1.0/tests/test_thread_copy.py +146 -0
  180. langrove-0.1.0/uv.lock +2328 -0
@@ -0,0 +1,58 @@
1
+ ---
2
+ name: architect
3
+ description: Plans implementation approach for complex features
4
+ model: claude-opus-4-6
5
+ tools: ["Read", "Glob", "Grep", "WebSearch"]
6
+ ---
7
+ You are the Langrove architect agent. Your job is to analyze
8
+ requirements and create a detailed implementation plan. You do NOT
9
+ write code — only plans. Follow CLAUDE.md principles strictly.
10
+
11
+ ## Before Planning
12
+ 1. Read `.claude/rules/` files relevant to the area you're planning for
13
+ 2. Read CLAUDE.md for project principles and structure
14
+ 3. Read the issue description and acceptance criteria carefully
15
+ 4. Identify ALL files that need to change — read them to understand current state
16
+
17
+ ## Plan Format
18
+ Post the plan as a **GitHub issue comment** using this exact structure:
19
+
20
+ ```
21
+ ## Implementation Plan
22
+
23
+ ### Approach
24
+ (1-3 sentences describing the strategy)
25
+
26
+ ### Files to Modify
27
+ - `path/to/file.py` — what changes and why
28
+
29
+ ### Files to Create
30
+ - `path/to/new.py` — purpose and responsibility
31
+
32
+ ### Test Plan
33
+ - What scenarios to test
34
+ - Which existing tests may need updates
35
+
36
+ ### Estimated Diff Size
37
+ - Lines added/removed estimate
38
+ - Complexity assessment
39
+
40
+ ### Risk Assessment
41
+ - low / medium / high — and why
42
+ - Any areas requiring extra caution
43
+ ```
44
+
45
+ ## Complexity Estimation
46
+ - **small** (<100 lines diff, single file or module)
47
+ - **medium** (100-300 lines, multiple files in same module)
48
+ - **large** (>300 lines, cross-module changes)
49
+
50
+ If estimated as large: add labels `complexity:large` + `blocked` instead of `planned`.
51
+ Only proceed with `planned` label for small/medium issues.
52
+
53
+ ## After Planning
54
+ - Remove `triage` label, add `planned` + appropriate `complexity:*` label
55
+ - Append new learnings to the most relevant `.claude/rules/` file:
56
+ - Date prefix: `- YYYY-MM-DD: <concise learning>`
57
+ - Only add genuinely new insights, not duplicates of existing entries
58
+ - **Do NOT commit or push** — you only read files and post issue comments
@@ -0,0 +1,52 @@
1
+ ---
2
+ name: implementer
3
+ description: Implements features following the architect's plan
4
+ model: claude-opus-4-6
5
+ tools: ["Read", "Write", "Edit", "Bash", "Glob", "Grep"]
6
+ ---
7
+ You are the Langrove implementation agent. You receive a plan
8
+ from the architect and implement it precisely. Follow CLAUDE.md strictly.
9
+
10
+ ## Before Implementing
11
+ 1. Read `.claude/rules/` files relevant to the files you'll touch
12
+ 2. Read CLAUDE.md for project principles and structure
13
+ 3. Read the **Implementation Plan** comment on the issue (posted by architect)
14
+ 4. Follow the plan exactly unless you find a technical reason not to
15
+
16
+ ## Implementation Process
17
+ 1. **Never commit or push directly to `main`.**
18
+ 2. Create a new branch from `main`: `git checkout main && git pull && git checkout -b claude/{issue-number}-{short-slug}`
19
+ 3. Implement changes following the architect's plan
20
+ 4. Write tests for all new/changed functionality
21
+ 5. Run the full quality check:
22
+ ```bash
23
+ uv run ruff check . && uv run ruff format . && uv run pytest
24
+ ```
25
+ 6. Fix any failures (up to 3 retry cycles)
26
+ 7. Commit all changes on the branch with a message referencing the issue
27
+
28
+ ## Diff Size Guard
29
+ - If your changes exceed **500 lines**, STOP
30
+ - Add labels `blocked` + `human-review-required` to the issue
31
+ - Post a comment explaining why the diff is larger than expected
32
+ - Do NOT open a PR
33
+
34
+ ## PR Convention
35
+ - Branch: `claude/{issue-number}-{short-slug}` — always branched off `main`, never commit to `main` directly
36
+ - Push the branch and open a PR targeting `main`
37
+ - PR description must include: `Closes #{issue-number}`
38
+ - If you deviated from the architect's plan, explain why in the PR description
39
+ - Labels: remove `in-progress`, add `review`
40
+
41
+ ## Code Standards (from CLAUDE.md)
42
+ - KISS, YAGNI, SOLID, OOP
43
+ - Raw asyncpg SQL — no ORM
44
+ - Services receive dependencies via constructor injection
45
+ - API handlers are thin — delegate to services
46
+ - No speculative abstractions
47
+
48
+ ## After Implementing
49
+ - Append new learnings to the most relevant `.claude/rules/` file:
50
+ - Date prefix: `- YYYY-MM-DD: <concise learning>`
51
+ - Only genuinely new insights (implementation gotchas, patterns discovered)
52
+ - Commit rules/ updates alongside implementation changes
@@ -0,0 +1,59 @@
1
+ ---
2
+ name: reviewer
3
+ description: Reviews code for quality, security, and correctness
4
+ model: claude-opus-4-6
5
+ tools: ["Read", "Glob", "Grep", "Bash"]
6
+ ---
7
+ You are the Langrove code review agent. Review code changes thoroughly
8
+ but concisely. Follow CLAUDE.md principles as the quality bar.
9
+
10
+ ## Before Reviewing
11
+ 1. Read `.claude/rules/` files relevant to the changed files
12
+ 2. Read CLAUDE.md for project principles
13
+
14
+ ## Review Checklist
15
+ For every PR, check:
16
+
17
+ ### Security
18
+ - [ ] All SQL queries use `$N` parameterized syntax — no f-strings or string interpolation
19
+ - [ ] No hardcoded secrets or credentials
20
+ - [ ] Auth bypass not possible via missing middleware checks
21
+ - [ ] JSONB inputs properly cast with `::jsonb`
22
+
23
+ ### Async Correctness
24
+ - [ ] All I/O operations properly awaited
25
+ - [ ] No blocking calls in async context (no `time.sleep`, `requests.get`)
26
+ - [ ] Connection pools properly acquired/released (context managers)
27
+ - [ ] `asyncio.aclosing()` used for astream() generators
28
+
29
+ ### CLAUDE.md Adherence
30
+ - [ ] KISS — no unnecessary complexity
31
+ - [ ] YAGNI — no speculative features or abstractions
32
+ - [ ] SOLID — single responsibility, dependency injection
33
+ - [ ] Raw asyncpg — no ORM usage
34
+ - [ ] Thin API handlers — logic in services, not routes
35
+
36
+ ### Test Coverage
37
+ - [ ] New code paths have corresponding tests
38
+ - [ ] Edge cases considered (None, empty, error states)
39
+ - [ ] Tests actually assert meaningful behavior
40
+
41
+ ### SSE Format (if streaming changes)
42
+ - [ ] Wire format compliance: `event: {name}\ndata: {json}\n\n`
43
+ - [ ] Event sequence: metadata first, end last
44
+ - [ ] Subgraph namespace uses pipe delimiter
45
+
46
+ ## Decision Tree
47
+ - **APPROVE** if: tests pass, no security issues, follows CLAUDE.md, reasonable coverage
48
+ - **REQUEST_CHANGES** if: security vulnerability, missing tests for critical paths, CLAUDE.md violations, broken async patterns
49
+
50
+ ## Review Cycle Limit
51
+ - Track how many review cycles have occurred (check existing review comments)
52
+ - After **2 review cycles** with unresolved issues: add `human-review-required` label and stop
53
+
54
+ ## After Reviewing
55
+ - On approve: remove `review` label, add `done`
56
+ - On request changes: remove `review` label, add `in-progress`
57
+ - Append new learnings to the most relevant `.claude/rules/` file:
58
+ - Date prefix: `- YYYY-MM-DD: <concise learning>`
59
+ - Focus on recurring patterns (what keeps coming up in reviews)
@@ -0,0 +1,30 @@
1
+ # Agent Journals
2
+
3
+ This directory previously contained per-role journal files (planner.md, implementer.md, reviewer.md).
4
+
5
+ ## Migration to `.claude/rules/`
6
+
7
+ Agent learnings are now stored in **topic-based `.claude/rules/` files** instead of per-role journals.
8
+ This follows the industry-standard pattern (Lore Protocol, Letta Context Repositories, Cline Memory Bank)
9
+ and uses Claude Code's native path-scoped rules for automatic context loading.
10
+
11
+ ### How it works now
12
+
13
+ - Knowledge organized by domain: `database.md`, `streaming.md`, `auth.md`, etc.
14
+ - Files have `globs:` frontmatter — Claude auto-loads relevant rules when editing matching files
15
+ - All agents share all knowledge (no role silos)
16
+ - Agents append new learnings to the most relevant rules/ file after completing work
17
+ - Weekly maintenance consolidates and deduplicates entries
18
+
19
+ ### Rules files
20
+
21
+ | File | Scope |
22
+ |------|-------|
23
+ | `rules/database.md` | asyncpg, JSONB, pools, migrations |
24
+ | `rules/streaming.md` | SSE format, pub/sub, event replay |
25
+ | `rules/worker-tasks.md` | Redis Streams, consumer groups, recovery |
26
+ | `rules/auth.md` | middleware, authorization, AuthUser |
27
+ | `rules/api-design.md` | FastAPI patterns, services, error handling |
28
+ | `rules/testing.md` | pytest conventions, fixtures, CI |
29
+ | `rules/architecture.md` | system design, graph loading, lifecycle |
30
+ | `rules/pipeline.md` | automation meta-learnings |
@@ -0,0 +1,7 @@
1
+ # Implementer Agent Journal
2
+
3
+ > **Migrated to `.claude/rules/`** — Agent learnings are now stored by topic
4
+ > (database.md, streaming.md, etc.) instead of by role. See `.claude/rules/` for all knowledge.
5
+ >
6
+ > This file is kept for backwards compatibility. New learnings go into the
7
+ > most relevant `.claude/rules/` file.
@@ -0,0 +1,7 @@
1
+ # Planner Agent Journal
2
+
3
+ > **Migrated to `.claude/rules/`** — Agent learnings are now stored by topic
4
+ > (database.md, streaming.md, etc.) instead of by role. See `.claude/rules/` for all knowledge.
5
+ >
6
+ > This file is kept for backwards compatibility. New learnings go into the
7
+ > most relevant `.claude/rules/` file.
@@ -0,0 +1,7 @@
1
+ # Reviewer Agent Journal
2
+
3
+ > **Migrated to `.claude/rules/`** — Agent learnings are now stored by topic
4
+ > (database.md, streaming.md, etc.) instead of by role. See `.claude/rules/` for all knowledge.
5
+ >
6
+ > This file is kept for backwards compatibility. New learnings go into the
7
+ > most relevant `.claude/rules/` file.
@@ -0,0 +1,64 @@
1
+ ---
2
+ description: FastAPI route patterns, dependency injection, service layer, error handling, and request/response models
3
+ globs:
4
+ - "src/langrove/api/**/*.py"
5
+ - "src/langrove/models/**/*.py"
6
+ - "src/langrove/services/**/*.py"
7
+ - "src/langrove/exceptions.py"
8
+ ---
9
+
10
+ # API Design
11
+
12
+ ## Route Handler Pattern
13
+ - **Thin handlers** — delegate ALL business logic to services
14
+ - Handlers only: parse request, inject dependencies, call service, return response
15
+ - One router per resource: agents, assistants, threads, runs, store, crons, health, dead_letter
16
+
17
+ ## Dependency Injection
18
+ - FastAPI `Depends()` functions in `api/deps.py`
19
+ - App-level resources: `request.app.state.{db_pool, redis, graph_registry, checkpointer, store}`
20
+ - Request-scoped: `request.state.{user, auth}`
21
+ - Service factory pattern:
22
+ ```python
23
+ def _get_service(db=Depends(get_db), registry=Depends(get_graph_registry)):
24
+ return ServiceClass(Repository(db), registry)
25
+ ```
26
+
27
+ ## Service Layer
28
+ - Services instantiated fresh per-request (not cached)
29
+ - Constructor injection: `__init__(self, repo, registry, ...)`
30
+ - Repositories are lightweight, stateless data-access objects
31
+ - One service per domain: AssistantService, RunService, ThreadService, StoreService, CronService
32
+
33
+ ## Error Hierarchy
34
+ ```
35
+ LangroveError (base)
36
+ ├── NotFoundError(resource: str, resource_id: str) → 404
37
+ ├── ConflictError(message: str) → 409
38
+ ├── AuthError(message: str) → 401
39
+ └── ForbiddenError(message: str) → 403
40
+ ```
41
+ - Response format: `JSONResponse({"code": "error_type", "message": "..."})`
42
+ - Exception handlers registered in `app.py`
43
+
44
+ ## Request/Response Models
45
+ - Response models: Pydantic `BaseModel` with UUID + datetime fields
46
+ - Create models: optional `if_exists` field ("raise" | "do_nothing")
47
+ - Search models: optional filters + `limit`/`offset` pagination
48
+ - Patch/Update: all fields optional, `model_dump(exclude_none=True)` for partial updates
49
+
50
+ ## Key Patterns
51
+ - `if_exists="do_nothing"` returns existing record instead of ConflictError
52
+ - Thread state is dual-sourced: record (metadata, status) from repo + state (values, next, tasks) from checkpointer
53
+ - Ephemeral threads: auto-deleted after stream completes if `on_completion="delete"`
54
+ - Run cancellation: DB status → "interrupted" + Redis cancel key + thread reset to "idle"
55
+
56
+ ## Three Run Execution Modes
57
+ 1. `stream_run()` — foreground SSE streaming (same process, asyncio.Queue)
58
+ 2. `wait_run()` — foreground blocking, returns final state
59
+ 3. `background_run()` — dispatches to Redis Streams queue, returns Run immediately
60
+
61
+ ## Gotchas
62
+ - Services are NOT singletons — new instance per request
63
+ - `metadata_` → `metadata` rename happens in repository layer, not service/API layer
64
+ - Auth user injected into graph config as `langgraph_auth_user` key in configurable dict
@@ -0,0 +1,65 @@
1
+ ---
2
+ description: System architecture, graph loading, app lifecycle, and cross-cutting patterns
3
+ globs:
4
+ - "src/langrove/**/*.py"
5
+ ---
6
+
7
+ # Architecture
8
+
9
+ ## Graph Instance Per Request
10
+ - Base graphs loaded at startup into `GraphRegistry` — cached without checkpointer (immutable, shared)
11
+ - Per-request: `graph.copy(update={...})` injects checkpointer + store
12
+ - Config deep-copied per request via `deepcopy(config)` to prevent concurrent mutations
13
+ - Fallback to shallow copy if deepcopy fails (e.g., non-serializable objects like LangfuseResourceManager)
14
+
15
+ ## Graph Loading (graph/loader.py)
16
+ - Dynamic module loading: `importlib.util.spec_from_file_location()` from `"./path/to/module.py:attribute"` specs
17
+ - Parent directory auto-added to `sys.path` for transitive imports
18
+ - Relative paths resolve against config file directory, NOT cwd
19
+
20
+ ## App Factory (app.py)
21
+ - `create_app()` with `@asynccontextmanager` for async lifespan
22
+ - **Startup order:** load .env → asyncpg pool → Redis → load graphs → setup checkpointer (psycopg) → setup store (psycopg) → auto-create assistants
23
+ - **Shutdown:** close all pools (checkpointer, store, db, redis)
24
+ - State on `app.state`: `db_pool`, `redis`, `graph_registry`, `checkpointer`, `store`, `settings`, `config`
25
+
26
+ ## Middleware Stack
27
+ 1. CORS (configured from `config.http.cors`)
28
+ 2. Auth (if `config.auth.path` set) — see `.claude/rules/auth.md`
29
+
30
+ ## Two Database Pool Types
31
+ - **asyncpg** (`db/pool.py`): app-level queries (threads, runs, assistants, store, crons)
32
+ - **psycopg** (`db/langgraph_pools.py`): LangGraph checkpointer + store (separate pools, autocommit=True)
33
+
34
+ ## Streaming Architecture
35
+ - **Foreground:** `asyncio.Queue` per run_id — publish/subscribe within same process
36
+ - **Background:** Redis pub/sub (live events) + Redis Streams (replay/reconnection)
37
+ - See `.claude/rules/streaming.md` for details
38
+
39
+ ## Thread State Lifecycle
40
+ - Status: `idle` → `busy` → `success|error` → `idle`
41
+ - Thread `values` and `interrupts` are NOT stored in threads table — derived from LangGraph checkpointer at read time
42
+
43
+ ## Ephemeral Threads
44
+ - Created when no `thread_id` provided and `on_completion="delete"`
45
+ - Auto-deleted in generator `finally` block after stream completes
46
+
47
+ ## Config File (langgraph.json)
48
+ - Parsed by `config.py` with Pydantic models
49
+ - Fallback loading: `langgraph.json` → `aegra.json` → defaults
50
+ - `.env` path in config resolves relative to config file directory
51
+ - Graphs: `{"graph_id": "./path/to/module.py:attribute"}`
52
+
53
+ ## CLI Commands (cli.py)
54
+ - `langrove serve` — FastAPI via uvicorn (default port 8123)
55
+ - `langrove worker` — Redis Streams consumer + recovery monitor
56
+ - `langrove init` — scaffold langgraph.json + agent.py
57
+
58
+ ## Settings (settings.py)
59
+ - Pydantic BaseSettings with `env_prefix="LANGROVE_"` and `.env` file support
60
+ - Key defaults: DB pool 2-10, checkpointer pool 5, store pool 5, worker concurrency 5, task timeout 900s, event TTL 86400s (24h)
61
+
62
+ ## Gotchas
63
+ - Multiple workers each spawn all pools — can exhaust PostgreSQL max_connections quickly
64
+ - Auth user injected into graph configurable as `langgraph_auth_user` key
65
+ - `asyncio.aclosing()` required for astream() generator cleanup (releases checkpoint locks)
@@ -0,0 +1,63 @@
1
+ ---
2
+ description: Authentication middleware, authorization handlers, AuthUser protocol, and custom auth loading
3
+ globs:
4
+ - "src/langrove/auth/**/*.py"
5
+ ---
6
+
7
+ # Authentication & Authorization
8
+
9
+ ## Two-Stage Auth
10
+ 1. **Authenticate** (request-level via middleware): validates credentials → returns AuthUser
11
+ 2. **Authorize** (per-operation via deps.py): checks if user can perform action on resource
12
+
13
+ ## Auth Handler Resolution (Priority Order)
14
+ 1. Exact match: `(resource, action)` — e.g., `("assistants", "create")`
15
+ 2. Resource-level: `(resource, *)` — e.g., `("assistants", "*")`
16
+ 3. Global: catches all
17
+
18
+ ## AuthUser Protocol
19
+ - Implements `langgraph_sdk.auth.types.BaseUser`
20
+ - Properties: `identity`, `display_name`, `permissions`, `is_authenticated`
21
+ - Dict-like access: `user[key]`, `key in user`, `iter(user)`
22
+ - `to_dict()` serializes for graph configurable injection as `langgraph_auth_user`
23
+ - Uses `__slots__` for memory efficiency
24
+
25
+ ## CustomAuthHandler (auth/custom.py)
26
+ - Loads from `module.py:handler` spec in `langgraph.json` auth config
27
+ - Supports two modes:
28
+ - Plain async function: `async def handler(headers) -> dict`
29
+ - `langgraph_sdk.Auth` instance with `@auth.authenticate` decorator
30
+
31
+ ### Parameter Injection (signature-based)
32
+ Handler parameters are inspected and injected:
33
+ - `headers` → full headers dict
34
+ - `authorization` → extracted from `headers["authorization"]`
35
+ - `method` → HTTP method string
36
+ - `path` → request path string
37
+ - Unknown params → falls back to headers as first positional arg
38
+
39
+ ### Return Type Handling
40
+ - `None` → 401 (reject)
41
+ - `str` → `AuthUser(identity=string)`
42
+ - `dict` → must have `identity` key, optional `display_name`, `permissions`
43
+ - Object with `.identity` → extracted as MinimalUser protocol
44
+
45
+ ## AuthMiddleware (auth/middleware.py)
46
+ - Extends `BaseHTTPMiddleware`
47
+ - Skip paths: `/ok`, `/health`, `/info`, `/docs`, `/openapi.json`, `/redoc`
48
+ - Skips OPTIONS (CORS preflight)
49
+ - Stores result: `request.state.user` (AuthUser) + `request.state.auth` (langgraph_sdk.Auth or None)
50
+
51
+ ## Authorization in API Endpoints (deps.py)
52
+ - `authorize(request, resource, action, value_dict)` — for write operations
53
+ - Handler can return `False` (reject → 403), `True/None` (accept), or modified dict (rewrite values)
54
+ - `authorize_read(request, resource, metadata)` — for read operations
55
+ - Validates fetched resource against filter operators: `$eq`, `$contains`
56
+
57
+ ## NoopAuthHandler (auth/noop.py)
58
+ - Development mode: always returns `AuthUser(identity="anonymous", permissions=("authenticated",))`
59
+
60
+ ## Gotchas
61
+ - Auth is null-safe: no `request.state.auth` = no-op passthrough
62
+ - `request.state.auth` is the `langgraph_sdk.Auth` instance (for authorization rules), not the AuthUser
63
+ - Store namespace can be rewritten by auth handler via authorization result
@@ -0,0 +1,56 @@
1
+ ---
2
+ description: asyncpg query patterns, JSONB handling, connection pools, and migration conventions
3
+ globs:
4
+ - "src/langrove/db/**/*.py"
5
+ - "migrations/**/*.py"
6
+ ---
7
+
8
+ # Database
9
+
10
+ ## asyncpg JSONB Handling
11
+ - asyncpg returns JSONB as JSON-encoded strings. The custom codec in `db/pool.py` uses `orjson.loads()` which may need two passes (first unwraps outer quotes, second extracts the object)
12
+ - Encoder: `orjson.dumps(v).decode()` — must decode bytes to string for PostgreSQL
13
+ - Codec registration uses "text" format (not "binary") via `init` callback on pool creation
14
+
15
+ ## Query Patterns
16
+ - ALL queries use `$N` positional parameters — never f-strings or string interpolation (SQL injection prevention)
17
+ - JSONB inserts require explicit `::jsonb` cast: `VALUES ($1::jsonb)`
18
+ - Dynamic WHERE building: track `idx` counter, append conditions + args in lockstep
19
+ ```python
20
+ conditions.append(f"{key} = ${idx}")
21
+ args.append(value)
22
+ idx += 1
23
+ ```
24
+ - JSONB containment operator: `metadata_ @> $N::jsonb` with `orjson.dumps(dict).decode()`
25
+ - Only interpolate known field names into SQL — parameters always use $N placeholders
26
+
27
+ ## Field Naming
28
+ - DB column `metadata_` (reserved word escape) → normalized to `metadata` in Python dicts
29
+ - All repositories call `_normalize()` to handle this rename
30
+ - Config/JSON columns use `::jsonb` cast on INSERT/UPDATE
31
+
32
+ ## Store Namespace
33
+ - PostgreSQL `ARRAY(TEXT)` type for hierarchical keys
34
+ - Queried via array slice: `namespace[1:{len(prefix)}]` — positional, not semantic
35
+ - Composite PK: `(namespace, key)`
36
+
37
+ ## Connection Pools
38
+ - asyncpg: min=2, max=10 (app-level queries via `db/pool.py`)
39
+ - psycopg: max=5 each (LangGraph checkpointer + store via `db/langgraph_pools.py`)
40
+ - Total up to 20 connections per server instance — watch for PostgreSQL `max_connections` exhaustion with multiple workers
41
+ - psycopg pools use `autocommit=True, prepare_threshold=0`
42
+
43
+ ## Transactions & Atomicity
44
+ - No explicit transactions in repositories — each method is a single atomic query
45
+ - Multi-step operations (create run + update status) are NOT transactional
46
+
47
+ ## Version Snapshots
48
+ - `ON CONFLICT (assistant_id, version) DO NOTHING` for idempotent history writes
49
+ - Version auto-incremented on UPDATE before INSERT into versions table
50
+
51
+ ## Gotchas
52
+ - `orjson.dumps(None)` produces `"null"` string — correct for PostgreSQL NULL JSONB
53
+ - Store items have no indices beyond PK — could bottleneck on large stores
54
+ - Pool acquisition: `async with self.pool.acquire() as conn` — single connection per query
55
+ - All `fetch_*` methods return dicts via `dict(row)` conversion from asyncpg.Record
56
+ - 2026-04-07: Checkpointer pool is psycopg (not asyncpg) — uses `%s` placeholders, acquired via `async with checkpointer.conn.connection() as conn`. The `$N` asyncpg convention applies only to the app-level `DatabasePool`, not the checkpointer/store psycopg pools.
@@ -0,0 +1,23 @@
1
+ ---
2
+ description: Automated pipeline meta-learnings and coordination knowledge
3
+ ---
4
+
5
+ # Pipeline Automation
6
+
7
+ ## Label State Machine
8
+ ```
9
+ New Issue → [triage] → [planned] → [in-progress] → [review] → [done]
10
+ ↑ |
11
+ +-- (REQUEST_CHANGES) --+
12
+
13
+ blocked / human-review-required: applied on top of any state, pause automation
14
+ ```
15
+
16
+ ## Coordination Rules
17
+ - Only ONE issue may be `in-progress` at a time
18
+ - `complexity:large` issues skipped unless `force-auto` label present
19
+ - Max 2 review cycles before `human-review-required`
20
+ - 500-line diff limit on PRs
21
+
22
+ ## Learnings
23
+ <!-- Pipeline agents append new learnings below this line -->
@@ -0,0 +1,74 @@
1
+ ---
2
+ description: SSE wire format, event types, stream modes, pub/sub broker, and event replay
3
+ globs:
4
+ - "src/langrove/streaming/**/*.py"
5
+ ---
6
+
7
+ # Streaming
8
+
9
+ ## SSE Wire Format (useStream / LangGraph SDK compatible)
10
+ - Format: `event: {name}\ndata: {json}\n\n` — double newline terminates each event
11
+ - Content-Type: `text/event-stream`
12
+ - Optional reconnection: `id: {event_id}` line before data line
13
+
14
+ ## Event Sequence
15
+ 1. `metadata` — always first: `{"run_id": "..."}`
16
+ 2. `values` / `updates` / `messages` — graph execution events
17
+ 3. `end` — always last: `data: null` (literal null, not omitted)
18
+ 4. `error` — terminal on exception: `{"error": "...", "message": "ExceptionType"}`
19
+
20
+ ## Stream Modes
21
+ - Input can be string or list: `stream_mode: str | list[str]`
22
+ - Langrove internally adds "updates" (always) for interrupt detection
23
+ - "messages" mode also adds "messages-tuple" internally (SDK convenience)
24
+ - SDK-internal modes ("events", "messages-tuple") stripped before processing chunks
25
+
26
+ ## Chunk Processing (executor.py)
27
+ LangGraph `astream()` output varies by configuration:
28
+ - Single mode, no subgraphs: bare `chunk`
29
+ - Multi-mode, no subgraphs: `(mode, chunk)` tuple
30
+ - Single mode, subgraphs=True: `(namespace_tuple, chunk)`
31
+ - Multi-mode, subgraphs=True: `(namespace_tuple, mode, chunk)`
32
+
33
+ ## Subgraph Namespace
34
+ - Pipe-delimited event names: `updates|parent|child`
35
+ - SDK parses pipes to route subagent messages to correct handler
36
+ - Supports arbitrary nesting depth
37
+
38
+ ## Messages Mode
39
+ - Chunks are `(BaseMessageChunk, metadata_dict)` tuples
40
+ - Serialized via `model_dump()` (Pydantic v2) or `dict()` (Pydantic v1)
41
+ - If message is already a dict (not Pydantic), use as-is
42
+
43
+ ## Updates Mode
44
+ - Contains interrupts as `__interrupt__` key: `{"__interrupt__": [...]}`
45
+ - Only forwarded as SSE if explicitly requested OR contains interrupt data
46
+ - Prevents duplicate state broadcasts
47
+
48
+ ## JSON Serialization
49
+ - `_default(obj)` fallback: tries `obj.model_dump()` → `obj.dict()` → TypeError
50
+ - Handles LangChain message objects, UUIDs, datetimes (orjson native)
51
+
52
+ ## Event IDs
53
+ - Format: `{run_id}_event_{counter}` — monotonically increasing
54
+ - Must be sortable for Redis XRANGE replay
55
+ - Client sends `Last-Event-ID` header on reconnect
56
+
57
+ ## Event Broker Architecture
58
+ - **Foreground runs (same process):** `asyncio.Queue` per run_id in `_local_queues` dict
59
+ - **Background runs (cross-process):** Redis pub/sub channel `langrove:runs:{run_id}:stream`
60
+ - **Event storage:** Redis Streams `langrove:runs:{run_id}:events` (TTL configurable, default 24h)
61
+
62
+ ## Event Replay (subscribe-first pattern)
63
+ 1. Subscribe to pub/sub FIRST (captures events during replay gap)
64
+ 2. Replay stored events via XRANGE from "-" to "+"
65
+ 3. Skip events until `last_event_id` found
66
+ 4. Yield stored events, tracking seen IDs in `seen_ids` set
67
+ 5. Drain live pub/sub, deduplicating by ID
68
+ 6. Stop on "end" or "error" event
69
+
70
+ ## Gotchas
71
+ - Redis pub/sub doesn't persist — messages lost if no subscribers present
72
+ - `end` event data is `null`, not omitted: `data: null\n`
73
+ - `asyncio.aclosing()` required for astream() generator cleanup (releases checkpoint locks)
74
+ - Implicitly added `values` mode is suppressed if not in user's original request
@@ -0,0 +1,37 @@
1
+ ---
2
+ description: pytest conventions, fixtures, test patterns, and CI commands
3
+ globs:
4
+ - "tests/**/*.py"
5
+ ---
6
+
7
+ # Testing
8
+
9
+ ## Framework
10
+ - `pytest` + `pytest-asyncio` for all async tests
11
+ - Dev dependencies: `httpx` (test client), `testcontainers[postgres,redis]`
12
+
13
+ ## Fixtures (conftest.py)
14
+ - `fixtures_dir` → `Path(__file__).parent / "fixtures"` — test data directory
15
+ - `test_config_path` → path to test `langgraph.json`
16
+ - Path objects from fixtures — convert with `str()` when passing to functions expecting strings
17
+
18
+ ## Test Patterns
19
+ - **Auth tests:** create temp handler files with `tmp_path.write_text()`, test module loading
20
+ - **SSE formatter tests:** verify exact wire format (event names, JSON encoding, blank line separators, null data)
21
+ - **Config tests:** valid/invalid JSON, missing files (returns defaults), type validation, CORS parsing
22
+ - **Graph registry tests:** loading from config, NotFoundError for missing graphs, schema extraction
23
+
24
+ ## Conventions
25
+ - No mocking of database when possible — use real postgres via testcontainers
26
+ - Full stream sequence tests: metadata → events → end
27
+ - Test both success and error paths for every endpoint
28
+
29
+ ## Commands
30
+ ```bash
31
+ uv run pytest --tb=short -q # Quick feedback
32
+ uv run pytest tests/test_runs.py # Specific file
33
+ uv run pytest -x -v # Stop on first failure, verbose
34
+ uv run ruff check . # Lint
35
+ uv run ruff format . # Format
36
+ uv run ruff check . && uv run ruff format . && uv run pytest # Full pre-commit check
37
+ ```