emdash-core 0.1.7__py3-none-any.whl
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.
- emdash_core/__init__.py +3 -0
- emdash_core/agent/__init__.py +37 -0
- emdash_core/agent/agents.py +225 -0
- emdash_core/agent/code_reviewer.py +476 -0
- emdash_core/agent/compaction.py +143 -0
- emdash_core/agent/context_manager.py +140 -0
- emdash_core/agent/events.py +338 -0
- emdash_core/agent/handlers.py +224 -0
- emdash_core/agent/inprocess_subagent.py +377 -0
- emdash_core/agent/mcp/__init__.py +50 -0
- emdash_core/agent/mcp/client.py +346 -0
- emdash_core/agent/mcp/config.py +302 -0
- emdash_core/agent/mcp/manager.py +496 -0
- emdash_core/agent/mcp/tool_factory.py +213 -0
- emdash_core/agent/prompts/__init__.py +38 -0
- emdash_core/agent/prompts/main_agent.py +104 -0
- emdash_core/agent/prompts/subagents.py +131 -0
- emdash_core/agent/prompts/workflow.py +136 -0
- emdash_core/agent/providers/__init__.py +34 -0
- emdash_core/agent/providers/base.py +143 -0
- emdash_core/agent/providers/factory.py +80 -0
- emdash_core/agent/providers/models.py +220 -0
- emdash_core/agent/providers/openai_provider.py +463 -0
- emdash_core/agent/providers/transformers_provider.py +217 -0
- emdash_core/agent/research/__init__.py +81 -0
- emdash_core/agent/research/agent.py +143 -0
- emdash_core/agent/research/controller.py +254 -0
- emdash_core/agent/research/critic.py +428 -0
- emdash_core/agent/research/macros.py +469 -0
- emdash_core/agent/research/planner.py +449 -0
- emdash_core/agent/research/researcher.py +436 -0
- emdash_core/agent/research/state.py +523 -0
- emdash_core/agent/research/synthesizer.py +594 -0
- emdash_core/agent/reviewer_profile.py +475 -0
- emdash_core/agent/rules.py +123 -0
- emdash_core/agent/runner.py +601 -0
- emdash_core/agent/session.py +262 -0
- emdash_core/agent/spec_schema.py +66 -0
- emdash_core/agent/specification.py +479 -0
- emdash_core/agent/subagent.py +397 -0
- emdash_core/agent/subagent_prompts.py +13 -0
- emdash_core/agent/toolkit.py +482 -0
- emdash_core/agent/toolkits/__init__.py +64 -0
- emdash_core/agent/toolkits/base.py +96 -0
- emdash_core/agent/toolkits/explore.py +47 -0
- emdash_core/agent/toolkits/plan.py +55 -0
- emdash_core/agent/tools/__init__.py +141 -0
- emdash_core/agent/tools/analytics.py +436 -0
- emdash_core/agent/tools/base.py +131 -0
- emdash_core/agent/tools/coding.py +484 -0
- emdash_core/agent/tools/github_mcp.py +592 -0
- emdash_core/agent/tools/history.py +13 -0
- emdash_core/agent/tools/modes.py +153 -0
- emdash_core/agent/tools/plan.py +206 -0
- emdash_core/agent/tools/plan_write.py +135 -0
- emdash_core/agent/tools/search.py +412 -0
- emdash_core/agent/tools/spec.py +341 -0
- emdash_core/agent/tools/task.py +262 -0
- emdash_core/agent/tools/task_output.py +204 -0
- emdash_core/agent/tools/tasks.py +454 -0
- emdash_core/agent/tools/traversal.py +588 -0
- emdash_core/agent/tools/web.py +179 -0
- emdash_core/analytics/__init__.py +5 -0
- emdash_core/analytics/engine.py +1286 -0
- emdash_core/api/__init__.py +5 -0
- emdash_core/api/agent.py +308 -0
- emdash_core/api/agents.py +154 -0
- emdash_core/api/analyze.py +264 -0
- emdash_core/api/auth.py +173 -0
- emdash_core/api/context.py +77 -0
- emdash_core/api/db.py +121 -0
- emdash_core/api/embed.py +131 -0
- emdash_core/api/feature.py +143 -0
- emdash_core/api/health.py +93 -0
- emdash_core/api/index.py +162 -0
- emdash_core/api/plan.py +110 -0
- emdash_core/api/projectmd.py +210 -0
- emdash_core/api/query.py +320 -0
- emdash_core/api/research.py +122 -0
- emdash_core/api/review.py +161 -0
- emdash_core/api/router.py +76 -0
- emdash_core/api/rules.py +116 -0
- emdash_core/api/search.py +119 -0
- emdash_core/api/spec.py +99 -0
- emdash_core/api/swarm.py +223 -0
- emdash_core/api/tasks.py +109 -0
- emdash_core/api/team.py +120 -0
- emdash_core/auth/__init__.py +17 -0
- emdash_core/auth/github.py +389 -0
- emdash_core/config.py +74 -0
- emdash_core/context/__init__.py +52 -0
- emdash_core/context/models.py +50 -0
- emdash_core/context/providers/__init__.py +11 -0
- emdash_core/context/providers/base.py +74 -0
- emdash_core/context/providers/explored_areas.py +183 -0
- emdash_core/context/providers/touched_areas.py +360 -0
- emdash_core/context/registry.py +73 -0
- emdash_core/context/reranker.py +199 -0
- emdash_core/context/service.py +260 -0
- emdash_core/context/session.py +352 -0
- emdash_core/core/__init__.py +104 -0
- emdash_core/core/config.py +454 -0
- emdash_core/core/exceptions.py +55 -0
- emdash_core/core/models.py +265 -0
- emdash_core/core/review_config.py +57 -0
- emdash_core/db/__init__.py +67 -0
- emdash_core/db/auth.py +134 -0
- emdash_core/db/models.py +91 -0
- emdash_core/db/provider.py +222 -0
- emdash_core/db/providers/__init__.py +5 -0
- emdash_core/db/providers/supabase.py +452 -0
- emdash_core/embeddings/__init__.py +24 -0
- emdash_core/embeddings/indexer.py +534 -0
- emdash_core/embeddings/models.py +192 -0
- emdash_core/embeddings/providers/__init__.py +7 -0
- emdash_core/embeddings/providers/base.py +112 -0
- emdash_core/embeddings/providers/fireworks.py +141 -0
- emdash_core/embeddings/providers/openai.py +104 -0
- emdash_core/embeddings/registry.py +146 -0
- emdash_core/embeddings/service.py +215 -0
- emdash_core/graph/__init__.py +26 -0
- emdash_core/graph/builder.py +134 -0
- emdash_core/graph/connection.py +692 -0
- emdash_core/graph/schema.py +416 -0
- emdash_core/graph/writer.py +667 -0
- emdash_core/ingestion/__init__.py +7 -0
- emdash_core/ingestion/change_detector.py +150 -0
- emdash_core/ingestion/git/__init__.py +5 -0
- emdash_core/ingestion/git/commit_analyzer.py +196 -0
- emdash_core/ingestion/github/__init__.py +6 -0
- emdash_core/ingestion/github/pr_fetcher.py +296 -0
- emdash_core/ingestion/github/task_extractor.py +100 -0
- emdash_core/ingestion/orchestrator.py +540 -0
- emdash_core/ingestion/parsers/__init__.py +10 -0
- emdash_core/ingestion/parsers/base_parser.py +66 -0
- emdash_core/ingestion/parsers/call_graph_builder.py +121 -0
- emdash_core/ingestion/parsers/class_extractor.py +154 -0
- emdash_core/ingestion/parsers/function_extractor.py +202 -0
- emdash_core/ingestion/parsers/import_analyzer.py +119 -0
- emdash_core/ingestion/parsers/python_parser.py +123 -0
- emdash_core/ingestion/parsers/registry.py +72 -0
- emdash_core/ingestion/parsers/ts_ast_parser.js +313 -0
- emdash_core/ingestion/parsers/typescript_parser.py +278 -0
- emdash_core/ingestion/repository.py +346 -0
- emdash_core/models/__init__.py +38 -0
- emdash_core/models/agent.py +68 -0
- emdash_core/models/index.py +77 -0
- emdash_core/models/query.py +113 -0
- emdash_core/planning/__init__.py +7 -0
- emdash_core/planning/agent_api.py +413 -0
- emdash_core/planning/context_builder.py +265 -0
- emdash_core/planning/feature_context.py +232 -0
- emdash_core/planning/feature_expander.py +646 -0
- emdash_core/planning/llm_explainer.py +198 -0
- emdash_core/planning/similarity.py +509 -0
- emdash_core/planning/team_focus.py +821 -0
- emdash_core/server.py +153 -0
- emdash_core/sse/__init__.py +5 -0
- emdash_core/sse/stream.py +196 -0
- emdash_core/swarm/__init__.py +17 -0
- emdash_core/swarm/merge_agent.py +383 -0
- emdash_core/swarm/session_manager.py +274 -0
- emdash_core/swarm/swarm_runner.py +226 -0
- emdash_core/swarm/task_definition.py +137 -0
- emdash_core/swarm/worker_spawner.py +319 -0
- emdash_core/swarm/worktree_manager.py +278 -0
- emdash_core/templates/__init__.py +10 -0
- emdash_core/templates/defaults/agent-builder.md.template +82 -0
- emdash_core/templates/defaults/focus.md.template +115 -0
- emdash_core/templates/defaults/pr-review-enhanced.md.template +309 -0
- emdash_core/templates/defaults/pr-review.md.template +80 -0
- emdash_core/templates/defaults/project.md.template +85 -0
- emdash_core/templates/defaults/research_critic.md.template +112 -0
- emdash_core/templates/defaults/research_planner.md.template +85 -0
- emdash_core/templates/defaults/research_synthesizer.md.template +128 -0
- emdash_core/templates/defaults/reviewer.md.template +81 -0
- emdash_core/templates/defaults/spec.md.template +41 -0
- emdash_core/templates/defaults/tasks.md.template +78 -0
- emdash_core/templates/loader.py +296 -0
- emdash_core/utils/__init__.py +45 -0
- emdash_core/utils/git.py +84 -0
- emdash_core/utils/image.py +502 -0
- emdash_core/utils/logger.py +51 -0
- emdash_core-0.1.7.dist-info/METADATA +35 -0
- emdash_core-0.1.7.dist-info/RECORD +187 -0
- emdash_core-0.1.7.dist-info/WHEEL +4 -0
- emdash_core-0.1.7.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
"""Git worktree management for parallel agent execution."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
import shutil
|
|
5
|
+
import subprocess
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Optional
|
|
10
|
+
|
|
11
|
+
from git import Repo
|
|
12
|
+
|
|
13
|
+
from ..utils.logger import log
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class WorktreeInfo:
|
|
18
|
+
"""Information about a created worktree."""
|
|
19
|
+
path: Path
|
|
20
|
+
branch: str
|
|
21
|
+
base_branch: str
|
|
22
|
+
task_slug: str
|
|
23
|
+
created_at: str
|
|
24
|
+
status: str # pending, active, completed, failed
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class WorktreeError(Exception):
|
|
28
|
+
"""Error during worktree operations."""
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class WorktreeManager:
|
|
33
|
+
"""Manages Git worktrees for parallel agent execution.
|
|
34
|
+
|
|
35
|
+
Creates isolated worktrees under .emdash-worktrees/{task-slug}/
|
|
36
|
+
with unique branches for each parallel task.
|
|
37
|
+
|
|
38
|
+
Example:
|
|
39
|
+
manager = WorktreeManager(repo_root=Path("."))
|
|
40
|
+
|
|
41
|
+
# Create worktree for a task
|
|
42
|
+
info = manager.create_worktree("add-user-auth", base_branch="main")
|
|
43
|
+
# -> .emdash-worktrees/add-user-auth/
|
|
44
|
+
# -> branch: emdash/task-add-user-auth
|
|
45
|
+
|
|
46
|
+
# Clean up when done
|
|
47
|
+
manager.remove_worktree("add-user-auth")
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
WORKTREE_DIR = ".emdash-worktrees"
|
|
51
|
+
BRANCH_PREFIX = "emdash/task-"
|
|
52
|
+
|
|
53
|
+
def __init__(self, repo_root: Path):
|
|
54
|
+
"""Initialize worktree manager.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
repo_root: Root of the main git repository
|
|
58
|
+
"""
|
|
59
|
+
self.repo_root = repo_root.resolve()
|
|
60
|
+
self.repo = Repo(self.repo_root)
|
|
61
|
+
self.worktrees_base = self.repo_root / self.WORKTREE_DIR
|
|
62
|
+
|
|
63
|
+
def slugify(self, text: str) -> str:
|
|
64
|
+
"""Convert text to URL-safe slug."""
|
|
65
|
+
text = text.lower().strip()
|
|
66
|
+
text = re.sub(r"[^\w\s-]", "", text)
|
|
67
|
+
text = re.sub(r"[-\s]+", "-", text)
|
|
68
|
+
return text[:50]
|
|
69
|
+
|
|
70
|
+
def _get_default_branch(self) -> str:
|
|
71
|
+
"""Get the default branch name for this repo.
|
|
72
|
+
|
|
73
|
+
Tries HEAD, then common names (main, master), then first available branch.
|
|
74
|
+
"""
|
|
75
|
+
# Try current HEAD branch
|
|
76
|
+
try:
|
|
77
|
+
if not self.repo.head.is_detached:
|
|
78
|
+
return self.repo.active_branch.name
|
|
79
|
+
except Exception:
|
|
80
|
+
pass
|
|
81
|
+
|
|
82
|
+
# Try common branch names
|
|
83
|
+
branch_names = [h.name for h in self.repo.heads]
|
|
84
|
+
for name in ["main", "master", "develop"]:
|
|
85
|
+
if name in branch_names:
|
|
86
|
+
return name
|
|
87
|
+
|
|
88
|
+
# Use first available branch
|
|
89
|
+
if branch_names:
|
|
90
|
+
return branch_names[0]
|
|
91
|
+
|
|
92
|
+
# Fallback to HEAD
|
|
93
|
+
return "HEAD"
|
|
94
|
+
|
|
95
|
+
def create_worktree(
|
|
96
|
+
self,
|
|
97
|
+
task_name: str,
|
|
98
|
+
base_branch: str | None = None,
|
|
99
|
+
force: bool = False,
|
|
100
|
+
) -> WorktreeInfo:
|
|
101
|
+
"""Create a new worktree for a task.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
task_name: Human-readable task name or slug
|
|
105
|
+
base_branch: Branch to base the worktree on (auto-detected if None)
|
|
106
|
+
force: If True, remove existing worktree first
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
WorktreeInfo with worktree details
|
|
110
|
+
|
|
111
|
+
Raises:
|
|
112
|
+
WorktreeError: If worktree creation fails
|
|
113
|
+
"""
|
|
114
|
+
slug = self.slugify(task_name)
|
|
115
|
+
worktree_path = self.worktrees_base / slug
|
|
116
|
+
branch_name = f"{self.BRANCH_PREFIX}{slug}"
|
|
117
|
+
|
|
118
|
+
# Auto-detect base branch if not provided
|
|
119
|
+
if base_branch is None:
|
|
120
|
+
base_branch = self._get_default_branch()
|
|
121
|
+
log.debug(f"Using base branch: {base_branch}")
|
|
122
|
+
|
|
123
|
+
# Handle existing worktree
|
|
124
|
+
if worktree_path.exists():
|
|
125
|
+
if force:
|
|
126
|
+
self.remove_worktree(slug)
|
|
127
|
+
else:
|
|
128
|
+
raise WorktreeError(f"Worktree already exists: {worktree_path}")
|
|
129
|
+
|
|
130
|
+
# Ensure base directory exists
|
|
131
|
+
self.worktrees_base.mkdir(parents=True, exist_ok=True)
|
|
132
|
+
|
|
133
|
+
# Fetch latest if remote exists
|
|
134
|
+
try:
|
|
135
|
+
if self.repo.remotes:
|
|
136
|
+
self.repo.remotes.origin.fetch()
|
|
137
|
+
except Exception:
|
|
138
|
+
pass # No remote or fetch failed, continue with local
|
|
139
|
+
|
|
140
|
+
# Delete branch if it exists (from previous run)
|
|
141
|
+
if branch_name in [h.name for h in self.repo.heads]:
|
|
142
|
+
self.repo.delete_head(branch_name, force=True)
|
|
143
|
+
|
|
144
|
+
# Create worktree with new branch using git command
|
|
145
|
+
cmd = [
|
|
146
|
+
"git", "worktree", "add",
|
|
147
|
+
"-b", branch_name,
|
|
148
|
+
str(worktree_path),
|
|
149
|
+
base_branch,
|
|
150
|
+
]
|
|
151
|
+
result = subprocess.run(
|
|
152
|
+
cmd,
|
|
153
|
+
cwd=str(self.repo_root),
|
|
154
|
+
capture_output=True,
|
|
155
|
+
text=True,
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
if result.returncode != 0:
|
|
159
|
+
raise WorktreeError(f"Failed to create worktree: {result.stderr}")
|
|
160
|
+
|
|
161
|
+
log.info(f"Created worktree at {worktree_path} on branch {branch_name}")
|
|
162
|
+
|
|
163
|
+
return WorktreeInfo(
|
|
164
|
+
path=worktree_path,
|
|
165
|
+
branch=branch_name,
|
|
166
|
+
base_branch=base_branch,
|
|
167
|
+
task_slug=slug,
|
|
168
|
+
created_at=datetime.now().isoformat(),
|
|
169
|
+
status="pending",
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
def remove_worktree(self, slug_or_path: str | Path) -> bool:
|
|
173
|
+
"""Remove a worktree and optionally its branch.
|
|
174
|
+
|
|
175
|
+
Args:
|
|
176
|
+
slug_or_path: Task slug or full worktree path
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
True if removed successfully
|
|
180
|
+
"""
|
|
181
|
+
if isinstance(slug_or_path, Path):
|
|
182
|
+
worktree_path = slug_or_path
|
|
183
|
+
slug = worktree_path.name
|
|
184
|
+
else:
|
|
185
|
+
slug = slug_or_path
|
|
186
|
+
worktree_path = self.worktrees_base / slug
|
|
187
|
+
|
|
188
|
+
branch_name = f"{self.BRANCH_PREFIX}{slug}"
|
|
189
|
+
|
|
190
|
+
# Remove worktree
|
|
191
|
+
if worktree_path.exists():
|
|
192
|
+
cmd = ["git", "worktree", "remove", str(worktree_path), "--force"]
|
|
193
|
+
subprocess.run(cmd, cwd=str(self.repo_root), capture_output=True)
|
|
194
|
+
|
|
195
|
+
# If git worktree remove fails, force delete
|
|
196
|
+
if worktree_path.exists():
|
|
197
|
+
shutil.rmtree(worktree_path)
|
|
198
|
+
|
|
199
|
+
# Prune worktree metadata
|
|
200
|
+
subprocess.run(
|
|
201
|
+
["git", "worktree", "prune"],
|
|
202
|
+
cwd=str(self.repo_root),
|
|
203
|
+
capture_output=True,
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
# Delete the branch
|
|
207
|
+
try:
|
|
208
|
+
if branch_name in [h.name for h in self.repo.heads]:
|
|
209
|
+
self.repo.delete_head(branch_name, force=True)
|
|
210
|
+
except Exception:
|
|
211
|
+
pass # Branch may not exist
|
|
212
|
+
|
|
213
|
+
log.info(f"Removed worktree {slug}")
|
|
214
|
+
return True
|
|
215
|
+
|
|
216
|
+
def list_worktrees(self) -> list[WorktreeInfo]:
|
|
217
|
+
"""List all active emdash worktrees."""
|
|
218
|
+
result = subprocess.run(
|
|
219
|
+
["git", "worktree", "list", "--porcelain"],
|
|
220
|
+
cwd=str(self.repo_root),
|
|
221
|
+
capture_output=True,
|
|
222
|
+
text=True,
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
worktrees = []
|
|
226
|
+
current: dict = {}
|
|
227
|
+
|
|
228
|
+
for line in result.stdout.strip().split("\n"):
|
|
229
|
+
if line.startswith("worktree "):
|
|
230
|
+
current["path"] = Path(line[9:])
|
|
231
|
+
elif line.startswith("branch refs/heads/"):
|
|
232
|
+
current["branch"] = line[18:]
|
|
233
|
+
elif line == "":
|
|
234
|
+
path = current.get("path")
|
|
235
|
+
if path and str(self.worktrees_base) in str(path):
|
|
236
|
+
worktrees.append(WorktreeInfo(
|
|
237
|
+
path=path,
|
|
238
|
+
branch=current.get("branch", ""),
|
|
239
|
+
base_branch="main",
|
|
240
|
+
task_slug=path.name,
|
|
241
|
+
created_at="",
|
|
242
|
+
status="active",
|
|
243
|
+
))
|
|
244
|
+
current = {}
|
|
245
|
+
|
|
246
|
+
return worktrees
|
|
247
|
+
|
|
248
|
+
def cleanup_all(self) -> int:
|
|
249
|
+
"""Remove all emdash worktrees.
|
|
250
|
+
|
|
251
|
+
Returns:
|
|
252
|
+
Number of worktrees removed
|
|
253
|
+
"""
|
|
254
|
+
worktrees = self.list_worktrees()
|
|
255
|
+
for wt in worktrees:
|
|
256
|
+
self.remove_worktree(wt.task_slug)
|
|
257
|
+
|
|
258
|
+
# Also clean up the base directory
|
|
259
|
+
if self.worktrees_base.exists():
|
|
260
|
+
shutil.rmtree(self.worktrees_base)
|
|
261
|
+
|
|
262
|
+
return len(worktrees)
|
|
263
|
+
|
|
264
|
+
def get_worktree(self, slug: str) -> Optional[WorktreeInfo]:
|
|
265
|
+
"""Get info for a specific worktree by slug."""
|
|
266
|
+
worktree_path = self.worktrees_base / slug
|
|
267
|
+
if not worktree_path.exists():
|
|
268
|
+
return None
|
|
269
|
+
|
|
270
|
+
branch_name = f"{self.BRANCH_PREFIX}{slug}"
|
|
271
|
+
return WorktreeInfo(
|
|
272
|
+
path=worktree_path,
|
|
273
|
+
branch=branch_name,
|
|
274
|
+
base_branch="main",
|
|
275
|
+
task_slug=slug,
|
|
276
|
+
created_at="",
|
|
277
|
+
status="active",
|
|
278
|
+
)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Agent Builder Rules
|
|
2
|
+
|
|
3
|
+
> How we create specialized AI agents for this codebase.
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
The agent-builder creates custom AGENTS.md profiles by analyzing the codebase, PRs, and review patterns to capture institutional knowledge.
|
|
8
|
+
|
|
9
|
+
## What to Gather
|
|
10
|
+
|
|
11
|
+
1. **Related PRs** - Find PRs related to the agent's purpose using keyword search
|
|
12
|
+
2. **Review Patterns** - What reviewers consistently care about (from APPROVED reviews)
|
|
13
|
+
3. **Anti-Patterns** - Things from REQUEST_CHANGES reviews that should be avoided
|
|
14
|
+
4. **Domain Experts** - Authors and reviewers with most activity in the area
|
|
15
|
+
5. **Code Communities** - Clustered areas of related code in the graph
|
|
16
|
+
6. **Entry Points** - Key files and functions relevant to the purpose
|
|
17
|
+
|
|
18
|
+
## AGENTS.md Format
|
|
19
|
+
|
|
20
|
+
The output should be Claude Code CLAUDE.md compatible:
|
|
21
|
+
|
|
22
|
+
```markdown
|
|
23
|
+
# <agent-name>
|
|
24
|
+
|
|
25
|
+
## Purpose
|
|
26
|
+
Single paragraph defining what this agent does and specializes in.
|
|
27
|
+
|
|
28
|
+
## Knowledge Context
|
|
29
|
+
### Code Areas
|
|
30
|
+
- Community descriptions from graph analysis
|
|
31
|
+
|
|
32
|
+
### Key Files
|
|
33
|
+
- List of relevant file paths
|
|
34
|
+
|
|
35
|
+
## Hints
|
|
36
|
+
1. Best practice from approved reviews
|
|
37
|
+
2. Specific, actionable advice (not generic)
|
|
38
|
+
...
|
|
39
|
+
|
|
40
|
+
## Things to Avoid
|
|
41
|
+
- (PR #N, @reviewer) Feedback from CHANGES_REQUESTED reviews
|
|
42
|
+
...
|
|
43
|
+
|
|
44
|
+
## Related PRs
|
|
45
|
+
- **PR #N**: Title (by @author)
|
|
46
|
+
...
|
|
47
|
+
|
|
48
|
+
## Domain Experts
|
|
49
|
+
- @username (N PRs in this area)
|
|
50
|
+
...
|
|
51
|
+
|
|
52
|
+
## MCP Tools
|
|
53
|
+
Reference to mcp.json tools.
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Exploration Strategy
|
|
57
|
+
|
|
58
|
+
1. Start with semantic search for the agent's purpose
|
|
59
|
+
2. Use github_search_prs to find related PRs
|
|
60
|
+
3. For top PRs, extract review comments with github_pr_details
|
|
61
|
+
4. Find communities that contain the relevant code
|
|
62
|
+
5. Identify top contributors from PR authors
|
|
63
|
+
|
|
64
|
+
## Hint Quality Guidelines
|
|
65
|
+
|
|
66
|
+
Good hints are:
|
|
67
|
+
- Specific to this codebase (reference actual patterns)
|
|
68
|
+
- Actionable (tell the agent what TO DO)
|
|
69
|
+
- Derived from real review feedback
|
|
70
|
+
- Concise (1-2 sentences each)
|
|
71
|
+
|
|
72
|
+
Bad hints:
|
|
73
|
+
- Generic advice ("write good tests")
|
|
74
|
+
- Vague guidance ("follow best practices")
|
|
75
|
+
- Not backed by PR evidence
|
|
76
|
+
|
|
77
|
+
## Things to Avoid
|
|
78
|
+
|
|
79
|
+
- Generic hints that apply to any project
|
|
80
|
+
- Listing every file touched (focus on patterns)
|
|
81
|
+
- Ignoring negative feedback (REQUEST_CHANGES are valuable)
|
|
82
|
+
- Creating duplicate entries
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Team Focus Analysis Template
|
|
2
|
+
|
|
3
|
+
> How we summarize team activity and work-in-progress for stakeholders.
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
The Team Focus report gives engineering managers and leads a quick understanding of:
|
|
8
|
+
- What the team is actively building
|
|
9
|
+
- Where technical effort is concentrated
|
|
10
|
+
- Who is working on what
|
|
11
|
+
- Patterns and risks worth attention
|
|
12
|
+
|
|
13
|
+
## Required Sections
|
|
14
|
+
|
|
15
|
+
### 1. Executive Summary
|
|
16
|
+
|
|
17
|
+
2-3 sentences capturing the main thrust of team activity. Should answer:
|
|
18
|
+
- What is the primary focus area?
|
|
19
|
+
- What secondary work is happening?
|
|
20
|
+
- What's the overall picture?
|
|
21
|
+
|
|
22
|
+
**Example:**
|
|
23
|
+
> The team is focused on **AI-driven code generation improvements**, with primary efforts in prompt engineering and content handling. Secondary work involves test infrastructure modernization and bug fixes.
|
|
24
|
+
|
|
25
|
+
### 2. Work Streams
|
|
26
|
+
|
|
27
|
+
Group related work by theme. For each stream:
|
|
28
|
+
- **Name the stream** with activity percentage
|
|
29
|
+
- **List hot files** being modified
|
|
30
|
+
- **Explain what's being built** using function/class names
|
|
31
|
+
- **Why it matters** (business/technical impact)
|
|
32
|
+
- **How it fits together** (show call flow if available)
|
|
33
|
+
|
|
34
|
+
Use code blocks for call graphs:
|
|
35
|
+
```
|
|
36
|
+
FunctionA()
|
|
37
|
+
→ calls FunctionB()
|
|
38
|
+
→ returns to FunctionC()
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 3. PR Analysis
|
|
42
|
+
|
|
43
|
+
A table showing recent PRs with technical context:
|
|
44
|
+
|
|
45
|
+
| PR | Author | Code Changes | What It Does |
|
|
46
|
+
|----|--------|--------------|--------------|
|
|
47
|
+
| [PR #123](link) | [@author](link) | `file.ts` | Description of change |
|
|
48
|
+
|
|
49
|
+
**Requirements:**
|
|
50
|
+
- PRs MUST be linked: `[PR #123](https://github.com/owner/repo/pull/123)`
|
|
51
|
+
- Authors MUST be linked: `[@username](https://github.com/username)`
|
|
52
|
+
- Describe WHAT the code does, not just which files changed
|
|
53
|
+
|
|
54
|
+
### 4. Key Contributors
|
|
55
|
+
|
|
56
|
+
A table showing who is working on what:
|
|
57
|
+
|
|
58
|
+
| Contributor | Commits | Technical Focus | Key PRs |
|
|
59
|
+
|-------------|---------|-----------------|---------|
|
|
60
|
+
| [@name](link) | N | Description of focus area | #PR1, #PR2 |
|
|
61
|
+
|
|
62
|
+
**Requirements:**
|
|
63
|
+
- Contributors MUST be linked to their GitHub profile
|
|
64
|
+
- Describe their technical focus area, not just file paths
|
|
65
|
+
|
|
66
|
+
### 5. Technical Insights
|
|
67
|
+
|
|
68
|
+
Split into positive patterns and areas of attention:
|
|
69
|
+
|
|
70
|
+
#### Positive Patterns
|
|
71
|
+
- What's working well?
|
|
72
|
+
- Good architectural decisions?
|
|
73
|
+
- Effective patterns emerging?
|
|
74
|
+
|
|
75
|
+
#### Areas of Attention
|
|
76
|
+
- Risks or concerns?
|
|
77
|
+
- Large changes with missing context?
|
|
78
|
+
- Churn or instability patterns?
|
|
79
|
+
|
|
80
|
+
#### Recommendations
|
|
81
|
+
- Specific, actionable suggestions
|
|
82
|
+
- Reference specific PRs or patterns
|
|
83
|
+
|
|
84
|
+
## Link Formatting (REQUIRED)
|
|
85
|
+
|
|
86
|
+
**All PRs and contributors must be clickable links:**
|
|
87
|
+
|
|
88
|
+
- PRs: `[PR #123](https://github.com/owner/repo/pull/123)`
|
|
89
|
+
- Contributors: `[@username](https://github.com/username)`
|
|
90
|
+
|
|
91
|
+
The GitHub repository URL will be provided in the data. Use it to construct proper links.
|
|
92
|
+
|
|
93
|
+
## Writing Style
|
|
94
|
+
|
|
95
|
+
- Be specific: name functions, classes, and files
|
|
96
|
+
- Explain WHAT is being built, not just WHERE files are changing
|
|
97
|
+
- Use docstrings and code context to understand purpose
|
|
98
|
+
- Write for an engineering manager audience
|
|
99
|
+
- No vague statements like "improvements to X directory"
|
|
100
|
+
- Use tables for structured data (PRs, contributors)
|
|
101
|
+
- Use code blocks for call graphs and technical flows
|
|
102
|
+
|
|
103
|
+
## What to Avoid
|
|
104
|
+
|
|
105
|
+
- Generic descriptions ("working on the codebase")
|
|
106
|
+
- Directory-only references without file specifics
|
|
107
|
+
- Missing links for PRs and contributors
|
|
108
|
+
- Unexplained technical terms
|
|
109
|
+
- Skipping the insights section
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
|