github-agent 1.2.0__tar.gz → 1.4.1__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.
- {github_agent-1.2.0 → github_agent-1.4.1}/PKG-INFO +4 -3
- {github_agent-1.2.0 → github_agent-1.4.1}/README.md +3 -2
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/agent_server.py +1 -1
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/kg_ingest.py +122 -1
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/mcp_server.py +93 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/ontology/github.ttl +83 -0
- github_agent-1.4.1/github_agent/skills/github-backlog-planner/SKILL.md +113 -0
- github_agent-1.4.1/github_agent/skills/github-backlog-planner/references/addressed-heuristics.md +59 -0
- github_agent-1.4.1/github_agent/skills/github-backlog-planner/scripts/build_plan.py +178 -0
- github_agent-1.4.1/github_agent/skills/github-ci-failure-sweep/SKILL.md +111 -0
- github_agent-1.4.1/github_agent/skills/github-ci-failure-sweep/references/actions-tool-cheatsheet.md +60 -0
- github_agent-1.4.1/github_agent/skills/github-ci-failure-sweep/scripts/summarize_runs.py +156 -0
- github_agent-1.4.1/github_agent/skills/github-org-remediation-loop/SKILL.md +295 -0
- github_agent-1.4.1/github_agent/skills/github-org-remediation-loop/scripts/classify_fix_risk.py +169 -0
- github_agent-1.4.1/github_agent/skills/github-pr-review-sweep/SKILL.md +112 -0
- github_agent-1.4.1/github_agent/skills/github-pr-review-sweep/references/pulls-tool-cheatsheet.md +42 -0
- github_agent-1.4.1/github_agent/skills/github-pr-review-sweep/scripts/summarize_prs.py +171 -0
- github_agent-1.4.1/github_agent/skills/github-project-provisioner/SKILL.md +58 -0
- github_agent-1.4.1/github_agent/skills/github-project-provisioner/scripts/enable_pages.py +53 -0
- github_agent-1.4.1/github_agent/skills/github-tools/SKILL.md +152 -0
- github_agent-1.4.1/github_agent/skills/github-tools/code-reviewer.md +146 -0
- github_agent-1.4.1/github_agent/skills/github-tools/scripts/fetch_comments.py +249 -0
- github_agent-1.4.1/github_agent/skills/github-tools/scripts/inspect_pr_checks.py +532 -0
- github_agent-1.4.1/github_agent/skills/github-triage-resolver/SKILL.md +116 -0
- github_agent-1.4.1/github_agent/skills/github-triage-resolver/references/resolution-rules.md +64 -0
- github_agent-1.4.1/github_agent/skills/github-triage-resolver/scripts/classify_safe.py +212 -0
- github_agent-1.4.1/github_agent/skills/github-triage-resolver/scripts/gh_write.py +131 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent.egg-info/PKG-INFO +4 -3
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent.egg-info/SOURCES.txt +21 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/pyproject.toml +1 -1
- {github_agent-1.2.0 → github_agent-1.4.1}/tests/test_kg_ingest.py +95 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/LICENSE +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/__init__.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/__main__.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/api/__init__.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/api/api_client_base.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/api/api_client_branches.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/api/api_client_commits.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/api/api_client_contents.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/api/api_client_dependabot.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/api/api_client_issues.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/api/api_client_orgs.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/api/api_client_pages.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/api/api_client_pulls.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/api/api_client_releases.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/api/api_client_repos.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/api/api_client_search.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/api/api_client_workflows.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/api_client.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/auth.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/connectors/__init__.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/connectors/mcp_source_presets.json +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/github_gql.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/github_input_models.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/github_response_models.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/mcp/__init__.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/mcp/mcp_action.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/mcp/mcp_branch.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/mcp/mcp_collaborator.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/mcp/mcp_commit.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/mcp/mcp_content.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/mcp/mcp_dependabot.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/mcp/mcp_issue.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/mcp/mcp_org.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/mcp/mcp_pull.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/mcp/mcp_release.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/mcp/mcp_repo.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/mcp/mcp_search.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/mcp_config.json +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/ontology/__init__.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/prompts/__init__.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/prompts/code_collaboration_specialist.json +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/prompts/main_agent.json +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/skills/__init__.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/skills/github-actions-ci-review/SKILL.md +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/skills/github-dependabot-review/SKILL.md +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/skills/github-issue-tracking/SKILL.md +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/skills/github-pull-request-create/SKILL.md +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/skills/github-pull-request-review/SKILL.md +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent/skills/github-repository-management/SKILL.md +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent.egg-info/dependency_links.txt +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent.egg-info/entry_points.txt +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent.egg-info/requires.txt +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/github_agent.egg-info/top_level.txt +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/scripts/security_sanitizer.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/scripts/validate_a2a_agent.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/scripts/verify_api_integration.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/setup.cfg +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/tests/conftest.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/tests/test_action_discovery.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/tests/test_api_client_endpoints.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/tests/test_api_validation.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/tests/test_auth_client_edge_cases.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/tests/test_concept_parity.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/tests/test_github_agent_api_brute_force_coverage.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/tests/test_github_agent_brute_force_coverage.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/tests/test_github_gql.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/tests/test_hardening.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/tests/test_init_dynamics.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/tests/test_mcp_coverage.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/tests/test_model_fields.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/tests/test_org_crud.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/tests/test_pages.py +0 -0
- {github_agent-1.2.0 → github_agent-1.4.1}/tests/test_startup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: github-agent
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.1
|
|
4
4
|
Summary: GitHub Agent for MCP
|
|
5
5
|
Author-email: Audel Rouhi <knucklessg1@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -48,7 +48,7 @@ Dynamic: license-file
|
|
|
48
48
|

|
|
49
49
|

|
|
50
50
|
|
|
51
|
-
*Version: 1.
|
|
51
|
+
*Version: 1.4.1*
|
|
52
52
|
|
|
53
53
|
> **Documentation** — Installation, deployment, and usage across the MCP, API, and
|
|
54
54
|
> CLI interfaces, including the integrated A2A agent server, are maintained in the
|
|
@@ -101,6 +101,7 @@ _Auto-generated from the live MCP server — do not edit by hand._
|
|
|
101
101
|
| `github_dependabot` | `DEPENDABOTTOOL` | Review and manage GitHub Dependabot vulnerability alerts. |
|
|
102
102
|
| `github_discover_graphql_schema` | `GRAPHQLTOOL` | Discover the live GitHub GraphQL schema (types, fields, and attributes) in real-time. |
|
|
103
103
|
| `github_graphql` | `GRAPHQLTOOL` | Execute raw GraphQL queries and mutations natively on GitHub. |
|
|
104
|
+
| `github_ingest_pipelines` | `INGESTTOOL` | Natively ingest GitHub Actions workflow runs into epistemic-graph. |
|
|
104
105
|
| `github_ingest_repos` | `INGESTTOOL` | Natively ingest GitHub repositories into epistemic-graph as typed :Repository nodes. |
|
|
105
106
|
| `github_issues` | `ISSUETOOL` | Manage GitHub issues. |
|
|
106
107
|
| `github_orgs` | `ORGTOOL` | Manage GitHub organizations. |
|
|
@@ -195,7 +196,7 @@ _Auto-generated from the live MCP server — do not edit by hand._
|
|
|
195
196
|
|
|
196
197
|
</details>
|
|
197
198
|
|
|
198
|
-
|
|
199
|
+
_16 action-routed tool(s) (default) · 76 verbose 1:1 tool(s). Each is enabled unless its `<DOMAIN>TOOL` toggle is set false; `MCP_TOOL_MODE` selects the surface (`condensed` default · `verbose` 1:1 · `both`). Auto-generated — do not edit._
|
|
199
200
|
<!-- MCP-TOOLS-TABLE:END -->
|
|
200
201
|
|
|
201
202
|
Detailed tool schemas, parameter shapes, and validation constraints are preserved in [docs/mcp.md](docs/mcp.md).
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|

|
|
21
21
|

|
|
22
22
|
|
|
23
|
-
*Version: 1.
|
|
23
|
+
*Version: 1.4.1*
|
|
24
24
|
|
|
25
25
|
> **Documentation** — Installation, deployment, and usage across the MCP, API, and
|
|
26
26
|
> CLI interfaces, including the integrated A2A agent server, are maintained in the
|
|
@@ -73,6 +73,7 @@ _Auto-generated from the live MCP server — do not edit by hand._
|
|
|
73
73
|
| `github_dependabot` | `DEPENDABOTTOOL` | Review and manage GitHub Dependabot vulnerability alerts. |
|
|
74
74
|
| `github_discover_graphql_schema` | `GRAPHQLTOOL` | Discover the live GitHub GraphQL schema (types, fields, and attributes) in real-time. |
|
|
75
75
|
| `github_graphql` | `GRAPHQLTOOL` | Execute raw GraphQL queries and mutations natively on GitHub. |
|
|
76
|
+
| `github_ingest_pipelines` | `INGESTTOOL` | Natively ingest GitHub Actions workflow runs into epistemic-graph. |
|
|
76
77
|
| `github_ingest_repos` | `INGESTTOOL` | Natively ingest GitHub repositories into epistemic-graph as typed :Repository nodes. |
|
|
77
78
|
| `github_issues` | `ISSUETOOL` | Manage GitHub issues. |
|
|
78
79
|
| `github_orgs` | `ORGTOOL` | Manage GitHub organizations. |
|
|
@@ -167,7 +168,7 @@ _Auto-generated from the live MCP server — do not edit by hand._
|
|
|
167
168
|
|
|
168
169
|
</details>
|
|
169
170
|
|
|
170
|
-
|
|
171
|
+
_16 action-routed tool(s) (default) · 76 verbose 1:1 tool(s). Each is enabled unless its `<DOMAIN>TOOL` toggle is set false; `MCP_TOOL_MODE` selects the surface (`condensed` default · `verbose` 1:1 · `both`). Auto-generated — do not edit._
|
|
171
172
|
<!-- MCP-TOOLS-TABLE:END -->
|
|
172
173
|
|
|
173
174
|
Detailed tool schemas, parameter shapes, and validation constraints are preserved in [docs/mcp.md](docs/mcp.md).
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
CONCEPT:AU-KG.ingest.enterprise-source-extractor. The github-agent connector natively
|
|
4
4
|
pushes its data into the ONE epistemic-graph knowledge graph as **typed OWL nodes**
|
|
5
5
|
(``:Repository``, ``:PullRequest``, ``:Issue``, ``:Release``, ``:Organization``,
|
|
6
|
-
``:Person``) plus links, and release notes as
|
|
6
|
+
``:Person``, ``:PipelineRun``, ``:CheckRun``) plus links, and release notes as
|
|
7
|
+
**:Document** nodes for semantic search —
|
|
7
8
|
using the lightweight engine client (``GraphComputeEngine()._client`` + ``txn``), the
|
|
8
9
|
same fast client the blob ``MediaStore`` uses, NOT the heavy in-process ingestion engine.
|
|
9
10
|
|
|
@@ -355,3 +356,123 @@ def ingest_release_notes(
|
|
|
355
356
|
}
|
|
356
357
|
)
|
|
357
358
|
return ingest_documents(docs, client=client, graph=graph)
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
def _duration_seconds(start: Any, end: Any) -> int | None:
|
|
362
|
+
"""Whole-second wall-clock duration between two ISO-8601 timestamps, or ``None``."""
|
|
363
|
+
if not start or not end:
|
|
364
|
+
return None
|
|
365
|
+
try:
|
|
366
|
+
import datetime as _dt
|
|
367
|
+
|
|
368
|
+
started = _dt.datetime.fromisoformat(str(start).replace("Z", "+00:00"))
|
|
369
|
+
ended = _dt.datetime.fromisoformat(str(end).replace("Z", "+00:00"))
|
|
370
|
+
return max(0, int((ended - started).total_seconds()))
|
|
371
|
+
except (ValueError, TypeError):
|
|
372
|
+
return None
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
def ingest_pipeline_runs(
|
|
376
|
+
runs: list[dict[str, Any]],
|
|
377
|
+
*,
|
|
378
|
+
repo_full_name: str | None = None,
|
|
379
|
+
repo_node_id: str | None = None,
|
|
380
|
+
jobs_by_run: dict[int, list[dict[str, Any]]] | None = None,
|
|
381
|
+
client: Any | None = None,
|
|
382
|
+
graph: str | None = None,
|
|
383
|
+
) -> dict[str, int] | None:
|
|
384
|
+
"""Map GitHub Actions workflow runs (+ jobs/check-runs) → ``:PipelineRun``/``:CheckRun``.
|
|
385
|
+
|
|
386
|
+
``runs``: raw ``WorkflowRun`` records (``client.get_workflow_runs`` /
|
|
387
|
+
``.get_workflow_run`` ``model_dump()``). ``jobs_by_run``: optional ``{run_id:
|
|
388
|
+
[job_or_check_run, ...]}`` from ``client.get_workflow_run_jobs`` (or the Checks
|
|
389
|
+
API) — each becomes a child ``:CheckRun`` linked via ``hasJob``.
|
|
390
|
+
|
|
391
|
+
Uses the SAME ``:PipelineRun``/``:CheckRun`` classes and ``ranFor``/``hasJob``
|
|
392
|
+
edge names as gitlab-api's ingestion so GitHub Actions and GitLab CI/CD unify
|
|
393
|
+
under one CI node shape in the knowledge graph. ``ranFor`` is emitted once per
|
|
394
|
+
known target — the repo, the head commit, and (if the run lists it) the PR.
|
|
395
|
+
Stable ids: ``github:pipelinerun:<repo>:<id>`` / ``github:checkrun:<repo>:<id>``.
|
|
396
|
+
"""
|
|
397
|
+
entities: list[dict[str, Any]] = []
|
|
398
|
+
relationships: list[dict[str, Any]] = []
|
|
399
|
+
jobs_by_run = jobs_by_run or {}
|
|
400
|
+
for run in runs or []:
|
|
401
|
+
run_id = run.get("id")
|
|
402
|
+
if run_id is None:
|
|
403
|
+
continue
|
|
404
|
+
repo = repo_full_name or (run.get("repository") or {}).get("full_name")
|
|
405
|
+
node_id = f"github:pipelinerun:{repo}:{run_id}"
|
|
406
|
+
run_started = run.get("run_started_at")
|
|
407
|
+
run_updated = run.get("updated_at")
|
|
408
|
+
entities.append(
|
|
409
|
+
{
|
|
410
|
+
"id": node_id,
|
|
411
|
+
"type": "PipelineRun",
|
|
412
|
+
"status": run.get("status"),
|
|
413
|
+
"conclusion": run.get("conclusion"),
|
|
414
|
+
"headSha": run.get("head_sha"),
|
|
415
|
+
"headBranch": run.get("head_branch"),
|
|
416
|
+
"event": run.get("event"),
|
|
417
|
+
"htmlUrl": _str(run.get("html_url")),
|
|
418
|
+
"runStartedAt": run_started,
|
|
419
|
+
"runUpdatedAt": run_updated,
|
|
420
|
+
"durationSeconds": _duration_seconds(run_started, run_updated),
|
|
421
|
+
"externalToolId": str(run_id),
|
|
422
|
+
}
|
|
423
|
+
)
|
|
424
|
+
|
|
425
|
+
if repo_node_id:
|
|
426
|
+
relationships.append(
|
|
427
|
+
{"source": node_id, "target": repo_node_id, "type": "ranFor"}
|
|
428
|
+
)
|
|
429
|
+
|
|
430
|
+
head_sha = run.get("head_sha")
|
|
431
|
+
if repo and head_sha:
|
|
432
|
+
commit_id = f"github:commit:{repo}:{head_sha}"
|
|
433
|
+
entities.append(
|
|
434
|
+
{
|
|
435
|
+
"id": commit_id,
|
|
436
|
+
"type": "Commit",
|
|
437
|
+
"sha": head_sha,
|
|
438
|
+
"externalToolId": head_sha,
|
|
439
|
+
}
|
|
440
|
+
)
|
|
441
|
+
relationships.append(
|
|
442
|
+
{"source": node_id, "target": commit_id, "type": "ranFor"}
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
for pr in run.get("pull_requests") or []:
|
|
446
|
+
pr_id = pr.get("id")
|
|
447
|
+
if pr_id is None:
|
|
448
|
+
continue
|
|
449
|
+
relationships.append(
|
|
450
|
+
{
|
|
451
|
+
"source": node_id,
|
|
452
|
+
"target": f"github:pullrequest:{pr_id}",
|
|
453
|
+
"type": "ranFor",
|
|
454
|
+
}
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
for job in jobs_by_run.get(run_id) or []:
|
|
458
|
+
job_id = job.get("id")
|
|
459
|
+
if job_id is None:
|
|
460
|
+
continue
|
|
461
|
+
job_node_id = f"github:checkrun:{repo}:{job_id}"
|
|
462
|
+
entities.append(
|
|
463
|
+
{
|
|
464
|
+
"id": job_node_id,
|
|
465
|
+
"type": "CheckRun",
|
|
466
|
+
"name": job.get("name"),
|
|
467
|
+
"status": job.get("status"),
|
|
468
|
+
"conclusion": job.get("conclusion"),
|
|
469
|
+
"startedAt": job.get("started_at"),
|
|
470
|
+
"completedAt": job.get("completed_at"),
|
|
471
|
+
"htmlUrl": _str(job.get("html_url")),
|
|
472
|
+
"externalToolId": str(job_id),
|
|
473
|
+
}
|
|
474
|
+
)
|
|
475
|
+
relationships.append(
|
|
476
|
+
{"source": node_id, "target": job_node_id, "type": "hasJob"}
|
|
477
|
+
)
|
|
478
|
+
return ingest_entities(entities, relationships, client=client, graph=graph)
|
|
@@ -2317,6 +2317,99 @@ def register_ingest_tools(mcp: FastMCP):
|
|
|
2317
2317
|
result = ingest_repositories(records)
|
|
2318
2318
|
return {"listed": len(records), "ingested": result}
|
|
2319
2319
|
|
|
2320
|
+
@mcp.tool(tags={"kg"})
|
|
2321
|
+
async def github_ingest_pipelines(
|
|
2322
|
+
params_json: str = Field(
|
|
2323
|
+
default="{}",
|
|
2324
|
+
description="JSON string with required 'owner'/'repo' and optional "
|
|
2325
|
+
"github_actions 'list_runs' filters (status, branch, per_page, "
|
|
2326
|
+
"max_pages), plus 'include_jobs' (default true — fetch each run's "
|
|
2327
|
+
"jobs as :CheckRun children) and 'repo_node_id' (the :Repository "
|
|
2328
|
+
"node id to link runs to via ranFor).",
|
|
2329
|
+
),
|
|
2330
|
+
client=Depends(get_client),
|
|
2331
|
+
ctx: Context | None = Field(
|
|
2332
|
+
default=None, description="MCP context for progress reporting"
|
|
2333
|
+
),
|
|
2334
|
+
) -> Any:
|
|
2335
|
+
"""Natively ingest GitHub Actions workflow runs into epistemic-graph.
|
|
2336
|
+
|
|
2337
|
+
Lists recent workflow runs for a repository (+ each run's jobs, unless
|
|
2338
|
+
``include_jobs=false``) via the GitHub API and pushes them as typed
|
|
2339
|
+
:PipelineRun nodes (with child :CheckRun jobs linked via hasJob, and
|
|
2340
|
+
ranFor links to the repo/head-commit/PR) into the knowledge graph via
|
|
2341
|
+
the fast engine client. Uses the SAME :PipelineRun/:CheckRun classes as
|
|
2342
|
+
gitlab-api's CI ingestion so GitHub Actions and GitLab CI/CD unify under
|
|
2343
|
+
one node shape. Best-effort: returns ``{"ingested": None}`` when no
|
|
2344
|
+
engine is reachable. CONCEPT:AU-KG.ingest.enterprise-source-extractor.
|
|
2345
|
+
"""
|
|
2346
|
+
if ctx:
|
|
2347
|
+
await ctx.info(
|
|
2348
|
+
"Ingesting GitHub Actions pipeline runs into the knowledge graph..."
|
|
2349
|
+
)
|
|
2350
|
+
import json
|
|
2351
|
+
|
|
2352
|
+
from github_agent.kg_ingest import ingest_pipeline_runs
|
|
2353
|
+
|
|
2354
|
+
try:
|
|
2355
|
+
kwargs = json.loads(params_json) if params_json else {}
|
|
2356
|
+
except Exception as e:
|
|
2357
|
+
return {"status": 400, "error": f"Invalid params_json: {e}", "data": None}
|
|
2358
|
+
|
|
2359
|
+
owner = kwargs.get("owner")
|
|
2360
|
+
repo = kwargs.get("repo")
|
|
2361
|
+
if not owner or not repo:
|
|
2362
|
+
return {
|
|
2363
|
+
"status": 400,
|
|
2364
|
+
"error": "Missing required 'owner' or 'repo' parameter",
|
|
2365
|
+
"data": None,
|
|
2366
|
+
}
|
|
2367
|
+
|
|
2368
|
+
include_jobs = kwargs.get("include_jobs", True)
|
|
2369
|
+
repo_node_id = kwargs.get("repo_node_id")
|
|
2370
|
+
list_kwargs = {
|
|
2371
|
+
k: v
|
|
2372
|
+
for k, v in kwargs.items()
|
|
2373
|
+
if k in ("owner", "repo", "status", "branch", "per_page", "max_pages")
|
|
2374
|
+
and v is not None
|
|
2375
|
+
}
|
|
2376
|
+
|
|
2377
|
+
response = await run_blocking(client.get_workflow_runs, **list_kwargs)
|
|
2378
|
+
runs = [
|
|
2379
|
+
run.model_dump() if hasattr(run, "model_dump") else run
|
|
2380
|
+
for run in response.data
|
|
2381
|
+
if run is not None
|
|
2382
|
+
]
|
|
2383
|
+
|
|
2384
|
+
jobs_by_run: dict[int, Any] = {}
|
|
2385
|
+
if include_jobs:
|
|
2386
|
+
for run in runs:
|
|
2387
|
+
run_id = run.get("id")
|
|
2388
|
+
if run_id is None:
|
|
2389
|
+
continue
|
|
2390
|
+
try:
|
|
2391
|
+
jobs_response = await run_blocking(
|
|
2392
|
+
client.get_workflow_run_jobs,
|
|
2393
|
+
owner=owner,
|
|
2394
|
+
repo=repo,
|
|
2395
|
+
run_id=run_id,
|
|
2396
|
+
)
|
|
2397
|
+
jobs_by_run[run_id] = jobs_response.data
|
|
2398
|
+
except Exception as e:
|
|
2399
|
+
logger.debug(
|
|
2400
|
+
"github_ingest_pipelines: jobs fetch failed for run %s: %s",
|
|
2401
|
+
run_id,
|
|
2402
|
+
e,
|
|
2403
|
+
)
|
|
2404
|
+
|
|
2405
|
+
result = ingest_pipeline_runs(
|
|
2406
|
+
runs,
|
|
2407
|
+
repo_full_name=f"{owner}/{repo}",
|
|
2408
|
+
repo_node_id=repo_node_id,
|
|
2409
|
+
jobs_by_run=jobs_by_run,
|
|
2410
|
+
)
|
|
2411
|
+
return {"listed": len(runs), "ingested": result}
|
|
2412
|
+
|
|
2320
2413
|
|
|
2321
2414
|
def register_graphql_tools(mcp: FastMCP):
|
|
2322
2415
|
from github_agent.auth import get_graphql_client
|
|
@@ -49,6 +49,17 @@
|
|
|
49
49
|
rdfs:label "Workflow Run" ;
|
|
50
50
|
rdfs:comment "A single execution of a GitHub Actions workflow for a ref/commit (github_actions)." .
|
|
51
51
|
|
|
52
|
+
:PipelineRun a owl:Class ;
|
|
53
|
+
rdfs:label "Pipeline Run" ;
|
|
54
|
+
rdfs:comment """A single CI/CD execution for a ref/commit (github_actions workflow run).
|
|
55
|
+
Shares its class name with the twin gitlab-api producer so GitHub Actions and GitLab
|
|
56
|
+
CI/CD unify under one node shape in the knowledge graph.""" .
|
|
57
|
+
|
|
58
|
+
:CheckRun a owl:Class ;
|
|
59
|
+
rdfs:label "Check Run" ;
|
|
60
|
+
rdfs:comment """A single job/check within a PipelineRun (github_actions workflow-run job or
|
|
61
|
+
GitHub Checks-API check run). Shares its class name with the twin gitlab-api producer.""" .
|
|
62
|
+
|
|
52
63
|
# --- links (owl:ObjectProperty) ---
|
|
53
64
|
|
|
54
65
|
:belongsToRepository a owl:ObjectProperty ;
|
|
@@ -90,6 +101,20 @@
|
|
|
90
101
|
rdfs:domain :Workflow ;
|
|
91
102
|
rdfs:range :WorkflowRun .
|
|
92
103
|
|
|
104
|
+
:ranFor a owl:ObjectProperty ;
|
|
105
|
+
rdfs:label "ran for" ;
|
|
106
|
+
rdfs:comment """Links a PipelineRun to what it ran for — its Repository, the Commit it
|
|
107
|
+
built, and/or the PullRequest it validated. Same predicate name as the twin gitlab-api
|
|
108
|
+
producer (Pipeline ranFor Project/Commit/MergeRequest).""" ;
|
|
109
|
+
rdfs:domain :PipelineRun .
|
|
110
|
+
|
|
111
|
+
:hasJob a owl:ObjectProperty ;
|
|
112
|
+
rdfs:label "has job" ;
|
|
113
|
+
rdfs:comment """Links a PipelineRun to a CheckRun (job/check) it contains. Same predicate
|
|
114
|
+
name as the twin gitlab-api producer (Pipeline hasJob Job).""" ;
|
|
115
|
+
rdfs:domain :PipelineRun ;
|
|
116
|
+
rdfs:range :CheckRun .
|
|
117
|
+
|
|
93
118
|
:documentsRelease a owl:ObjectProperty ;
|
|
94
119
|
rdfs:label "documents release" ;
|
|
95
120
|
rdfs:comment "Links a Release to the :Document carrying its release-notes body." ;
|
|
@@ -151,6 +176,64 @@
|
|
|
151
176
|
rdfs:comment "Result/conclusion of a WorkflowRun (success, failure, in_progress, cancelled)." ;
|
|
152
177
|
rdfs:range xsd:string .
|
|
153
178
|
|
|
179
|
+
:status a owl:DatatypeProperty ;
|
|
180
|
+
rdfs:label "status" ;
|
|
181
|
+
rdfs:comment "Lifecycle status of a PipelineRun or CheckRun (queued, in_progress, completed)." ;
|
|
182
|
+
rdfs:range xsd:string .
|
|
183
|
+
|
|
184
|
+
:conclusion a owl:DatatypeProperty ;
|
|
185
|
+
rdfs:label "conclusion" ;
|
|
186
|
+
rdfs:comment "Terminal result of a PipelineRun or CheckRun (success, failure, cancelled, skipped)." ;
|
|
187
|
+
rdfs:range xsd:string .
|
|
188
|
+
|
|
189
|
+
:headSha a owl:DatatypeProperty ;
|
|
190
|
+
rdfs:label "head sha" ;
|
|
191
|
+
rdfs:comment "Full git commit SHA a PipelineRun ran against." ;
|
|
192
|
+
rdfs:domain :PipelineRun ;
|
|
193
|
+
rdfs:range xsd:string .
|
|
194
|
+
|
|
195
|
+
:headBranch a owl:DatatypeProperty ;
|
|
196
|
+
rdfs:label "head branch" ;
|
|
197
|
+
rdfs:comment "Branch name a PipelineRun ran against." ;
|
|
198
|
+
rdfs:domain :PipelineRun ;
|
|
199
|
+
rdfs:range xsd:string .
|
|
200
|
+
|
|
201
|
+
:event a owl:DatatypeProperty ;
|
|
202
|
+
rdfs:label "event" ;
|
|
203
|
+
rdfs:comment "Triggering event of a PipelineRun (push, pull_request, schedule, workflow_dispatch)." ;
|
|
204
|
+
rdfs:domain :PipelineRun ;
|
|
205
|
+
rdfs:range xsd:string .
|
|
206
|
+
|
|
207
|
+
:runStartedAt a owl:DatatypeProperty ;
|
|
208
|
+
rdfs:label "run started at" ;
|
|
209
|
+
rdfs:comment "Timestamp a PipelineRun started executing." ;
|
|
210
|
+
rdfs:domain :PipelineRun ;
|
|
211
|
+
rdfs:range xsd:dateTime .
|
|
212
|
+
|
|
213
|
+
:runUpdatedAt a owl:DatatypeProperty ;
|
|
214
|
+
rdfs:label "run updated at" ;
|
|
215
|
+
rdfs:comment "Timestamp a PipelineRun was last updated." ;
|
|
216
|
+
rdfs:domain :PipelineRun ;
|
|
217
|
+
rdfs:range xsd:dateTime .
|
|
218
|
+
|
|
219
|
+
:durationSeconds a owl:DatatypeProperty ;
|
|
220
|
+
rdfs:label "duration seconds" ;
|
|
221
|
+
rdfs:comment "Wall-clock duration in seconds of a PipelineRun (runUpdatedAt - runStartedAt)." ;
|
|
222
|
+
rdfs:domain :PipelineRun ;
|
|
223
|
+
rdfs:range xsd:integer .
|
|
224
|
+
|
|
225
|
+
:startedAt a owl:DatatypeProperty ;
|
|
226
|
+
rdfs:label "started at" ;
|
|
227
|
+
rdfs:comment "Timestamp a CheckRun started executing." ;
|
|
228
|
+
rdfs:domain :CheckRun ;
|
|
229
|
+
rdfs:range xsd:dateTime .
|
|
230
|
+
|
|
231
|
+
:completedAt a owl:DatatypeProperty ;
|
|
232
|
+
rdfs:label "completed at" ;
|
|
233
|
+
rdfs:comment "Timestamp a CheckRun finished executing." ;
|
|
234
|
+
rdfs:domain :CheckRun ;
|
|
235
|
+
rdfs:range xsd:dateTime .
|
|
236
|
+
|
|
154
237
|
<http://knuckles.team/kg/github> a owl:Ontology ;
|
|
155
238
|
rdfs:label "GitHub Ontology" ;
|
|
156
239
|
rdfs:comment """GitHub source-control, code-review and CI/CD model — organizations,
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: github-backlog-planner
|
|
3
|
+
skill_type: skill
|
|
4
|
+
description: >-
|
|
5
|
+
Sweeps every open issue and pull request across one or more GitHub accounts
|
|
6
|
+
(a user and/or an organization, all repositories), deeply verifies which items
|
|
7
|
+
are already addressed, and emits a prioritized Markdown remediation plan. Use
|
|
8
|
+
when asked to "go through all issues and PRs", triage a whole backlog, plan
|
|
9
|
+
what to work on next across repos, or audit open work for a user/org. Defaults
|
|
10
|
+
to read-only analysis; write actions (close, comment, open tracking issue) are
|
|
11
|
+
opt-in and run only on explicit confirmation. Do NOT use for a single PR's
|
|
12
|
+
review comments (use github-tools) or interactive one-tracker triage (use
|
|
13
|
+
issue-triage).
|
|
14
|
+
license: MIT
|
|
15
|
+
tags: [github, issues, pull-requests, backlog, triage, planning, ops]
|
|
16
|
+
metadata:
|
|
17
|
+
author: Genius
|
|
18
|
+
version: '1.0.3'
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
# GitHub Backlog Planner
|
|
22
|
+
|
|
23
|
+
## Overview
|
|
24
|
+
|
|
25
|
+
Account-wide backlog sweep. Discovers all open issues and PRs across the target
|
|
26
|
+
accounts (e.g. the `Knucklessg1` user **and** the `Knuckles-Team` org), determines
|
|
27
|
+
which are **already addressed** (deep verification, not just labels), and produces a
|
|
28
|
+
single prioritized Markdown plan grouped by account → repo. Read-only by default;
|
|
29
|
+
any change to GitHub is opt-in.
|
|
30
|
+
|
|
31
|
+
Drives the **github-agent** MCP server. No `gh` CLI or local `GITHUB_*` token is
|
|
32
|
+
required — the MCP server holds its own auth.
|
|
33
|
+
|
|
34
|
+
## Tool access (works under delegation AND the multiplexer)
|
|
35
|
+
|
|
36
|
+
The tools are `github_issues`, `github_pulls`, `github_search`, `github_repos`,
|
|
37
|
+
`github_orgs`, `github_commits`, `github_contents` — each takes `action` + a
|
|
38
|
+
`params_json` **JSON string**.
|
|
39
|
+
|
|
40
|
+
- **Under direct delegation** to `github-agent` (`execute_agent server=github-agent`,
|
|
41
|
+
or the `mcp-client` skill) the tools are already bound by their **native** names
|
|
42
|
+
— call them directly. This is the path this skill is written for.
|
|
43
|
+
- **In the multiplexer / orchestrator** context the same tools carry the `gith__`
|
|
44
|
+
prefix (`gith__issues`, …); mount them first with
|
|
45
|
+
`load_tools(servers=["github-agent"])`.
|
|
46
|
+
|
|
47
|
+
Confirmed action shapes: `github_issues`/`github_pulls` → `list|get|create|update`;
|
|
48
|
+
`github_search` → `repositories|issues|code`; `github_repos` → `list|get`;
|
|
49
|
+
`github_orgs` → `repos|get`.
|
|
50
|
+
|
|
51
|
+
## Inputs
|
|
52
|
+
|
|
53
|
+
- **accounts**: list of `{login, type}` where type is `user` or `org`. Default:
|
|
54
|
+
`[{login: "Knucklessg1", type: "user"}, {login: "Knuckles-Team", type: "org"}]`.
|
|
55
|
+
- **include_prs**: default true. **include_issues**: default true.
|
|
56
|
+
|
|
57
|
+
## Workflow
|
|
58
|
+
|
|
59
|
+
### Step 1 — Discover repositories
|
|
60
|
+
- User: `github_repos action=list` (authenticated user) — keep repos owned by the target login.
|
|
61
|
+
- Org: `github_orgs action=repos {"org": "<login>"}`.
|
|
62
|
+
- Record each repo's `default_branch`, `open_issues_count`, and archived flag. Skip archived repos.
|
|
63
|
+
|
|
64
|
+
### Step 2 — Bulk-discover open items (efficient path)
|
|
65
|
+
Use search, which returns issues AND PRs compactly account-wide:
|
|
66
|
+
- `github_search action=issues {"q": "user:Knucklessg1 is:open is:issue"}`
|
|
67
|
+
- `github_search action=issues {"q": "user:Knucklessg1 is:open is:pr"}`
|
|
68
|
+
- `github_search action=issues {"q": "org:Knuckles-Team is:open is:issue"}`
|
|
69
|
+
- `github_search action=issues {"q": "org:Knuckles-Team is:open is:pr"}`
|
|
70
|
+
|
|
71
|
+
Paginate (`per_page`, `page`) until exhausted. If search results look incomplete for a
|
|
72
|
+
repo, fall back to per-repo `github_issues action=list {owner, repo, state:"open"}` and
|
|
73
|
+
`github_pulls action=list {owner, repo, state:"open"}`. Remember: the GitHub search/issues
|
|
74
|
+
APIs return PRs in the issues list — distinguish them by the `pull_request` field.
|
|
75
|
+
|
|
76
|
+
### Step 3 — Heuristic triage (Pass 1)
|
|
77
|
+
Bucket every item using `references/addressed-heuristics.md` (Pass 1 table) into
|
|
78
|
+
`needs-action`, `in-progress`, or *maybe addressed*. This is cheap and uses only the
|
|
79
|
+
data already fetched.
|
|
80
|
+
|
|
81
|
+
### Step 4 — Deep verification (Pass 2)
|
|
82
|
+
For each *maybe addressed* item, follow Pass 2 in `references/addressed-heuristics.md`:
|
|
83
|
+
`github_issues/pulls action=get` for linked PRs/commits, then `github_commits action=get`
|
|
84
|
+
and/or `github_contents action=get` to **confirm the fix actually landed on the default
|
|
85
|
+
branch** before marking it `addressed`. For items that still need a plan, read the
|
|
86
|
+
relevant source to write a one-line root-cause note and a concrete recommendation.
|
|
87
|
+
|
|
88
|
+
### Step 5 — Build the plan
|
|
89
|
+
Normalize each item to the JSON schema in `scripts/build_plan.py` (account, repo, kind,
|
|
90
|
+
number, title, url, state, status, evidence, recommendation, priority, labels), then:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
python scripts/build_plan.py --input items.json --title "GitHub Backlog Plan (<date>)"
|
|
94
|
+
# or: cat items.json | python scripts/build_plan.py
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
This renders: a summary line, a "verified addressed — safe to close" section, and a
|
|
98
|
+
per-account/per-repo action table sorted by status then priority. Present it to the user.
|
|
99
|
+
|
|
100
|
+
### Step 6 — Opt-in actions (only on explicit confirmation)
|
|
101
|
+
Never write to GitHub without the user confirming. When asked:
|
|
102
|
+
- Close a verified-addressed issue: `github_issues action=update {owner, repo, number, state:"closed"}`.
|
|
103
|
+
- Post a triage comment: there is **no native comment action or tool** (`github_issues`
|
|
104
|
+
has no `comment` action, and no dedicated comment tool exists). Hand off to
|
|
105
|
+
`github-triage-resolver`, which performs gated writes, to leave the
|
|
106
|
+
`> *This was generated by AI during triage.*` note (mirrors the `issue-triage` convention).
|
|
107
|
+
- Open a tracking issue for orphaned work: `github_issues action=create`.
|
|
108
|
+
|
|
109
|
+
## Related skills
|
|
110
|
+
- `github-ci-failure-sweep` — cross-link when a PR is blocked by failing CI.
|
|
111
|
+
- `github-tools` — single-PR comments/CI inspection (do not duplicate here).
|
|
112
|
+
- `issue-triage` — interactive, single-tracker state-machine triage.
|
|
113
|
+
- `github-triage-resolver` — performs gated writes (comments, closes) this skill only recommends.
|
github_agent-1.4.1/github_agent/skills/github-backlog-planner/references/addressed-heuristics.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# "Already addressed?" — triage + deep-verify decision table
|
|
2
|
+
|
|
3
|
+
Two-pass classification. **Pass 1** is a cheap heuristic that buckets every open item.
|
|
4
|
+
**Pass 2** is a deep, per-item investigation that is run only on the items Pass 1 marks
|
|
5
|
+
as *maybe addressed*, to confirm a fix actually landed before recommending a close.
|
|
6
|
+
|
|
7
|
+
## Pass 1 — heuristic triage (cheap, from list/search data)
|
|
8
|
+
|
|
9
|
+
### Issues
|
|
10
|
+
| Signal | Bucket | Status |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| Has a **linked open PR** (or `linked_pull_requests`, or a PR whose body says `fixes #N`) | in progress | `in-progress` |
|
|
13
|
+
| Has a **merged/closed PR** referencing it, but the issue is still open | maybe addressed → Pass 2 | (`addressed` if confirmed) |
|
|
14
|
+
| Referenced by a recent **commit** on the default branch | maybe addressed → Pass 2 | (`addressed` if confirmed) |
|
|
15
|
+
| Last activity is **stale** and no linked work | needs plan | `needs-action` |
|
|
16
|
+
| Fresh, no linked work | needs plan | `needs-action` |
|
|
17
|
+
|
|
18
|
+
### Pull requests
|
|
19
|
+
| Signal | Status | Notes |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| Open, `draft: true` | `in-progress` | Recommend: finish + mark ready. |
|
|
22
|
+
| Open, `mergeable_state: clean`, approved | `needs-action` | Recommend: merge. |
|
|
23
|
+
| Open, failing checks / `mergeable_state: dirty`/`blocked` | `needs-action` | Recommend: fix CI or rebase (cross-link the CI sweep skill). |
|
|
24
|
+
| Open, awaiting review | `needs-action` | Recommend: request/perform review. |
|
|
25
|
+
| Open, conflicts with base | `needs-action` | Recommend: rebase/resolve. |
|
|
26
|
+
|
|
27
|
+
## Pass 2 — deep verification (only for "maybe addressed")
|
|
28
|
+
|
|
29
|
+
For each candidate, gather enough evidence to either confirm `addressed` (safe to close)
|
|
30
|
+
or downgrade to `needs-action`:
|
|
31
|
+
|
|
32
|
+
1. `github_issues action=get {owner, repo, number}` — read body + timeline; collect every
|
|
33
|
+
referenced PR number and commit SHA (look for `fixes/closes/resolves #N`, cross-refs).
|
|
34
|
+
2. For each referenced PR: `github_pulls action=get {owner, repo, number}` — confirm
|
|
35
|
+
`merged: true` and which files it touched (`changed_files`, or list the PR's files).
|
|
36
|
+
3. Open the **referencing commit / changed file** to verify the fix is real, not a no-op:
|
|
37
|
+
- `github_commits action=get {owner, repo, sha}` for the diff, and/or
|
|
38
|
+
- `github_contents action=get {owner, repo, path, ref}` to read the current source on the
|
|
39
|
+
default branch and confirm the described change is present.
|
|
40
|
+
4. Verdict:
|
|
41
|
+
- Fix present on default branch + PR merged → `status: addressed`,
|
|
42
|
+
`evidence: "merged PR #N landed <change> in <file>"`, `recommendation: "Close #M"`.
|
|
43
|
+
- Referenced work reverted, or change absent, or PR closed-unmerged → `status: needs-action`,
|
|
44
|
+
`evidence: "PR #N closed without merging / change not on main"`.
|
|
45
|
+
|
|
46
|
+
## For items that still need a plan
|
|
47
|
+
|
|
48
|
+
Read the relevant source (`github_contents`) around the reported problem to write a
|
|
49
|
+
**one-line root-cause note** and a **concrete recommended next step** (the `recommendation`
|
|
50
|
+
field). Keep it actionable: name the file/function and the change, not "investigate".
|
|
51
|
+
|
|
52
|
+
## Priority assignment
|
|
53
|
+
- `high` (P1): PRs ready to merge, regressions/bugs blocking users, failing CI on default branch.
|
|
54
|
+
- `medium` (P2): normal bugs, enhancements with a clear path.
|
|
55
|
+
- `low` (P3): nice-to-have enhancements, stale/low-signal items.
|
|
56
|
+
|
|
57
|
+
## Output contract
|
|
58
|
+
Emit one normalized JSON object per item (see `scripts/build_plan.py` docstring for the schema)
|
|
59
|
+
and pipe the list through `build_plan.py` to render the final Markdown plan.
|