agentpack-cli 0.3.5__tar.gz → 0.3.8__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 (99) hide show
  1. agentpack_cli-0.3.5/README.md → agentpack_cli-0.3.8/PKG-INFO +84 -2
  2. agentpack_cli-0.3.5/PKG-INFO → agentpack_cli-0.3.8/README.md +45 -41
  3. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/pyproject.toml +2 -2
  4. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/__init__.py +1 -1
  5. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/analysis/ranking.py +6 -4
  6. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/application/pack_service.py +84 -11
  7. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/cli.py +2 -0
  8. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/commands/doctor.py +18 -0
  9. agentpack_cli-0.3.8/src/agentpack/commands/ignore_cmd.py +51 -0
  10. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/commands/init.py +31 -8
  11. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/commands/pack.py +3 -0
  12. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/commands/stats.py +3 -2
  13. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/core/context_pack.py +27 -0
  14. agentpack_cli-0.3.8/src/agentpack/core/ignore.py +448 -0
  15. agentpack_cli-0.3.5/src/agentpack/core/ignore.py +0 -90
  16. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/.gitignore +0 -0
  17. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/LICENSE +0 -0
  18. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/adapters/__init__.py +0 -0
  19. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/adapters/antigravity.py +0 -0
  20. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/adapters/base.py +0 -0
  21. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/adapters/claude.py +0 -0
  22. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/adapters/codex.py +0 -0
  23. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/adapters/cursor.py +0 -0
  24. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/adapters/detect.py +0 -0
  25. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/adapters/generic.py +0 -0
  26. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/adapters/windsurf.py +0 -0
  27. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/analysis/__init__.py +0 -0
  28. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/analysis/dependency_graph.py +0 -0
  29. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/analysis/go_imports.py +0 -0
  30. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/analysis/java_imports.py +0 -0
  31. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/analysis/js_ts_imports.py +0 -0
  32. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/analysis/monorepo.py +0 -0
  33. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/analysis/naming_signals.py +0 -0
  34. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/analysis/python_imports.py +0 -0
  35. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/analysis/repo_map.py +0 -0
  36. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/analysis/role_inference.py +0 -0
  37. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/analysis/rust_imports.py +0 -0
  38. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/analysis/symbols.py +0 -0
  39. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/analysis/task_classifier.py +0 -0
  40. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/analysis/tests.py +0 -0
  41. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/application/__init__.py +0 -0
  42. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/commands/__init__.py +0 -0
  43. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/commands/_shared.py +0 -0
  44. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/commands/benchmark.py +0 -0
  45. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/commands/claude_cmd.py +0 -0
  46. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/commands/diff.py +0 -0
  47. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/commands/explain.py +0 -0
  48. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/commands/guard.py +0 -0
  49. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/commands/hook_cmd.py +0 -0
  50. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/commands/install.py +0 -0
  51. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/commands/mcp_cmd.py +0 -0
  52. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/commands/migrate.py +0 -0
  53. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/commands/monitor.py +0 -0
  54. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/commands/quickstart.py +0 -0
  55. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/commands/repair.py +0 -0
  56. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/commands/scan.py +0 -0
  57. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/commands/status.py +0 -0
  58. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/commands/summarize.py +0 -0
  59. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/commands/tune.py +0 -0
  60. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/commands/watch.py +0 -0
  61. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/core/__init__.py +0 -0
  62. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/core/bootstrap.py +0 -0
  63. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/core/cache.py +0 -0
  64. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/core/config.py +0 -0
  65. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/core/diff.py +0 -0
  66. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/core/git.py +0 -0
  67. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/core/git_hooks.py +0 -0
  68. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/core/global_install.py +0 -0
  69. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/core/merkle.py +0 -0
  70. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/core/models.py +0 -0
  71. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/core/redactor.py +0 -0
  72. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/core/scanner.py +0 -0
  73. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/core/snapshot.py +0 -0
  74. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/core/task_freshness.py +0 -0
  75. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/core/token_estimator.py +0 -0
  76. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/core/vscode_tasks.py +0 -0
  77. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/data/agentpack.md +0 -0
  78. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/installers/__init__.py +0 -0
  79. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/installers/antigravity.py +0 -0
  80. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/installers/claude.py +0 -0
  81. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/installers/codex.py +0 -0
  82. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/installers/cursor.py +0 -0
  83. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/installers/windsurf.py +0 -0
  84. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/integrations/__init__.py +0 -0
  85. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/integrations/agents.py +0 -0
  86. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/integrations/git_hooks.py +0 -0
  87. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/integrations/global_install.py +0 -0
  88. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/integrations/platform.py +0 -0
  89. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/integrations/vscode_tasks.py +0 -0
  90. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/mcp_server.py +0 -0
  91. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/renderers/__init__.py +0 -0
  92. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/renderers/compact.py +0 -0
  93. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/renderers/markdown.py +0 -0
  94. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/renderers/receipts.py +0 -0
  95. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/session/__init__.py +0 -0
  96. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/session/state.py +0 -0
  97. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/summaries/__init__.py +0 -0
  98. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/summaries/base.py +0 -0
  99. {agentpack_cli-0.3.5 → agentpack_cli-0.3.8}/src/agentpack/summaries/offline.py +0 -0
@@ -1,3 +1,42 @@
1
+ Metadata-Version: 2.4
2
+ Name: agentpack-cli
3
+ Version: 0.3.8
4
+ Summary: Local context engine for AI coding agents that ranks relevant files and builds task-focused context packs.
5
+ License: MIT
6
+ License-File: LICENSE
7
+ Keywords: ai,ai-coding-agents,antigravity,ci,codex,context,context-engine,context-packing,cursor,developer-tools,llm,mcp,packing,prompt-context,repo-analysis,windsurf
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Topic :: Software Development :: Build Tools
16
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
17
+ Requires-Python: >=3.10
18
+ Requires-Dist: pathspec>=0.12.1
19
+ Requires-Dist: pydantic>=2.0.0
20
+ Requires-Dist: rich>=13.0.0
21
+ Requires-Dist: tiktoken>=0.7.0
22
+ Requires-Dist: tomli-w>=1.0.0
23
+ Requires-Dist: tomli>=2.0.0; python_version < '3.11'
24
+ Requires-Dist: typer>=0.12.0
25
+ Provides-Extra: all
26
+ Requires-Dist: mcp>=1.0.0; extra == 'all'
27
+ Requires-Dist: watchdog>=4.0.0; extra == 'all'
28
+ Provides-Extra: dev
29
+ Requires-Dist: mypy; extra == 'dev'
30
+ Requires-Dist: pytest; extra == 'dev'
31
+ Requires-Dist: pytest-cov; extra == 'dev'
32
+ Requires-Dist: ruff; extra == 'dev'
33
+ Requires-Dist: tomli>=2.0.0; (python_version < '3.11') and extra == 'dev'
34
+ Provides-Extra: mcp
35
+ Requires-Dist: mcp>=1.0.0; extra == 'mcp'
36
+ Provides-Extra: watch
37
+ Requires-Dist: watchdog>=4.0.0; extra == 'watch'
38
+ Description-Content-Type: text/markdown
39
+
1
40
  # AgentPack
2
41
 
3
42
  [![PyPI version](https://img.shields.io/pypi/v/agentpack-cli.svg)](https://pypi.org/project/agentpack-cli/)
@@ -7,7 +46,7 @@
7
46
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
47
  [![CI](https://github.com/vishal2612200/agentpack/actions/workflows/ci.yml/badge.svg)](https://github.com/vishal2612200/agentpack/actions/workflows/ci.yml)
9
48
 
10
- > **Status: alpha (v0.3.5).** Works, tested, used in real sessions. Python and JavaScript/TypeScript are the best-supported languages. Public benchmark proof exists for the current suite, but broader repo coverage is still growing. API may change before 1.0.
49
+ > **Status: alpha (v0.3.8).** Works, tested, used in real sessions. Python and JavaScript/TypeScript are the best-supported languages. Public benchmark proof exists for the current suite, but broader repo coverage is still growing. API may change before 1.0.
11
50
  >
12
51
  > **Platform note:** macOS, Linux, and Windows are supported. Windows support targets PowerShell plus Git for Windows. `cmd.exe` and bare Git setups are not a supported path yet.
13
52
 
@@ -109,7 +148,19 @@ printf '%s\n' "fix auth token expiry" > .agentpack/task.md
109
148
  agentpack pack
110
149
  ```
111
150
 
112
- This creates `.agentpack/` state, installs the requested agent integration, generates a ranked context pack, and writes the adapter output for that agent. For active local work, keep context fresh with:
151
+ This creates `.agentpack/` state, installs the requested agent integration, seeds `.agentignore` with safe defaults, imports obvious generated/noisy rules from git ignore sources, generates a ranked context pack, and writes the adapter output for that agent.
152
+
153
+ Task text matters. Good task text names the concrete feature, route, service, or file you are about to change. Bad task text uses repo-meta words like `improve context`, `pack quality`, `stats`, or `ignore`, which can pull README or tool internals by keyword.
154
+
155
+ ```bash
156
+ # good
157
+ printf '%s\n' "fix billing webhook retry handling in app/api/billing/route.ts" > .agentpack/task.md
158
+
159
+ # too broad
160
+ printf '%s\n' "improve context pack quality from stats" > .agentpack/task.md
161
+ ```
162
+
163
+ For active local work, keep context fresh with:
113
164
 
114
165
  ```bash
115
166
  agentpack watch
@@ -202,6 +253,23 @@ agentpack explain --task "fix billing webhook" --budget-plan
202
253
 
203
254
  This is the core reliability loop: pack, measure recall, inspect misses, then tune task wording, `.agentignore`, or scoring weights.
204
255
 
256
+ If top includes look noisy:
257
+
258
+ 1. Rewrite `.agentpack/task.md` with concrete domain nouns, entrypoints, or filenames.
259
+ 2. Re-pack and re-check `agentpack stats`.
260
+ 3. If generated output still dominates, add that path to `.agentignore` or run `agentpack ignore sync`.
261
+ 4. Use `agentpack explain --file <path>` on repeat offenders before changing scoring.
262
+
263
+ `.agentignore` is for AgentPack ranking noise, not general git hygiene. `agentpack init` seeds it with safe defaults and imports obvious generated/noisy entries from the root `.gitignore`, nested `.gitignore` files, `.git/info/exclude`, and your global git ignore when they look safe to carry over. You should still add repo-specific outputs such as deploy artifacts, exports, or generated SDK folders when they are not useful context.
264
+
265
+ When ignore sources change later, re-sync with:
266
+
267
+ ```bash
268
+ agentpack ignore sync
269
+ agentpack ignore sync --dry-run
270
+ agentpack ignore sync --check
271
+ ```
272
+
205
273
  ## MCP-First Workflow
206
274
 
207
275
  For MCP-capable agents, the preferred workflow is pull-based:
@@ -817,6 +885,20 @@ agentpack quickstart --task "fix auth token expiry" --write
817
885
 
818
886
  ---
819
887
 
888
+ ### `agentpack ignore sync`
889
+
890
+ Refresh imported generated/noisy rules inside `.agentignore` without touching your manual entries.
891
+
892
+ ```bash
893
+ agentpack ignore sync
894
+ agentpack ignore sync --dry-run
895
+ agentpack ignore sync --check
896
+ ```
897
+
898
+ Use this after editing `.gitignore`, nested workspace ignores, or `.git/info/exclude`. `doctor` also warns when the imported `.agentignore` block is stale.
899
+
900
+ ---
901
+
820
902
  ### `agentpack watch`
821
903
 
822
904
  Watch for file and task changes, refresh context automatically.
@@ -1,42 +1,3 @@
1
- Metadata-Version: 2.4
2
- Name: agentpack-cli
3
- Version: 0.3.5
4
- Summary: Local context engine for AI coding agents that ranks relevant files and builds task-focused context packs.
5
- License: MIT
6
- License-File: LICENSE
7
- Keywords: ai,ai-coding-agents,antigravity,ci,claude,claude-code,codex,context,context-engine,context-packing,cursor,developer-tools,llm,mcp,packing,prompt-context,repo-analysis,windsurf
8
- Classifier: Development Status :: 3 - Alpha
9
- Classifier: Intended Audience :: Developers
10
- Classifier: License :: OSI Approved :: MIT License
11
- Classifier: Programming Language :: Python :: 3.10
12
- Classifier: Programming Language :: Python :: 3.11
13
- Classifier: Programming Language :: Python :: 3.12
14
- Classifier: Programming Language :: Python :: 3.13
15
- Classifier: Topic :: Software Development :: Build Tools
16
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
17
- Requires-Python: >=3.10
18
- Requires-Dist: pathspec>=0.12.1
19
- Requires-Dist: pydantic>=2.0.0
20
- Requires-Dist: rich>=13.0.0
21
- Requires-Dist: tiktoken>=0.7.0
22
- Requires-Dist: tomli-w>=1.0.0
23
- Requires-Dist: tomli>=2.0.0; python_version < '3.11'
24
- Requires-Dist: typer>=0.12.0
25
- Provides-Extra: all
26
- Requires-Dist: mcp>=1.0.0; extra == 'all'
27
- Requires-Dist: watchdog>=4.0.0; extra == 'all'
28
- Provides-Extra: dev
29
- Requires-Dist: mypy; extra == 'dev'
30
- Requires-Dist: pytest; extra == 'dev'
31
- Requires-Dist: pytest-cov; extra == 'dev'
32
- Requires-Dist: ruff; extra == 'dev'
33
- Requires-Dist: tomli>=2.0.0; (python_version < '3.11') and extra == 'dev'
34
- Provides-Extra: mcp
35
- Requires-Dist: mcp>=1.0.0; extra == 'mcp'
36
- Provides-Extra: watch
37
- Requires-Dist: watchdog>=4.0.0; extra == 'watch'
38
- Description-Content-Type: text/markdown
39
-
40
1
  # AgentPack
41
2
 
42
3
  [![PyPI version](https://img.shields.io/pypi/v/agentpack-cli.svg)](https://pypi.org/project/agentpack-cli/)
@@ -46,7 +7,7 @@ Description-Content-Type: text/markdown
46
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
47
8
  [![CI](https://github.com/vishal2612200/agentpack/actions/workflows/ci.yml/badge.svg)](https://github.com/vishal2612200/agentpack/actions/workflows/ci.yml)
48
9
 
49
- > **Status: alpha (v0.3.5).** Works, tested, used in real sessions. Python and JavaScript/TypeScript are the best-supported languages. Public benchmark proof exists for the current suite, but broader repo coverage is still growing. API may change before 1.0.
10
+ > **Status: alpha (v0.3.8).** Works, tested, used in real sessions. Python and JavaScript/TypeScript are the best-supported languages. Public benchmark proof exists for the current suite, but broader repo coverage is still growing. API may change before 1.0.
50
11
  >
51
12
  > **Platform note:** macOS, Linux, and Windows are supported. Windows support targets PowerShell plus Git for Windows. `cmd.exe` and bare Git setups are not a supported path yet.
52
13
 
@@ -148,7 +109,19 @@ printf '%s\n' "fix auth token expiry" > .agentpack/task.md
148
109
  agentpack pack
149
110
  ```
150
111
 
151
- This creates `.agentpack/` state, installs the requested agent integration, generates a ranked context pack, and writes the adapter output for that agent. For active local work, keep context fresh with:
112
+ This creates `.agentpack/` state, installs the requested agent integration, seeds `.agentignore` with safe defaults, imports obvious generated/noisy rules from git ignore sources, generates a ranked context pack, and writes the adapter output for that agent.
113
+
114
+ Task text matters. Good task text names the concrete feature, route, service, or file you are about to change. Bad task text uses repo-meta words like `improve context`, `pack quality`, `stats`, or `ignore`, which can pull README or tool internals by keyword.
115
+
116
+ ```bash
117
+ # good
118
+ printf '%s\n' "fix billing webhook retry handling in app/api/billing/route.ts" > .agentpack/task.md
119
+
120
+ # too broad
121
+ printf '%s\n' "improve context pack quality from stats" > .agentpack/task.md
122
+ ```
123
+
124
+ For active local work, keep context fresh with:
152
125
 
153
126
  ```bash
154
127
  agentpack watch
@@ -241,6 +214,23 @@ agentpack explain --task "fix billing webhook" --budget-plan
241
214
 
242
215
  This is the core reliability loop: pack, measure recall, inspect misses, then tune task wording, `.agentignore`, or scoring weights.
243
216
 
217
+ If top includes look noisy:
218
+
219
+ 1. Rewrite `.agentpack/task.md` with concrete domain nouns, entrypoints, or filenames.
220
+ 2. Re-pack and re-check `agentpack stats`.
221
+ 3. If generated output still dominates, add that path to `.agentignore` or run `agentpack ignore sync`.
222
+ 4. Use `agentpack explain --file <path>` on repeat offenders before changing scoring.
223
+
224
+ `.agentignore` is for AgentPack ranking noise, not general git hygiene. `agentpack init` seeds it with safe defaults and imports obvious generated/noisy entries from the root `.gitignore`, nested `.gitignore` files, `.git/info/exclude`, and your global git ignore when they look safe to carry over. You should still add repo-specific outputs such as deploy artifacts, exports, or generated SDK folders when they are not useful context.
225
+
226
+ When ignore sources change later, re-sync with:
227
+
228
+ ```bash
229
+ agentpack ignore sync
230
+ agentpack ignore sync --dry-run
231
+ agentpack ignore sync --check
232
+ ```
233
+
244
234
  ## MCP-First Workflow
245
235
 
246
236
  For MCP-capable agents, the preferred workflow is pull-based:
@@ -856,6 +846,20 @@ agentpack quickstart --task "fix auth token expiry" --write
856
846
 
857
847
  ---
858
848
 
849
+ ### `agentpack ignore sync`
850
+
851
+ Refresh imported generated/noisy rules inside `.agentignore` without touching your manual entries.
852
+
853
+ ```bash
854
+ agentpack ignore sync
855
+ agentpack ignore sync --dry-run
856
+ agentpack ignore sync --check
857
+ ```
858
+
859
+ Use this after editing `.gitignore`, nested workspace ignores, or `.git/info/exclude`. `doctor` also warns when the imported `.agentignore` block is stale.
860
+
861
+ ---
862
+
859
863
  ### `agentpack watch`
860
864
 
861
865
  Watch for file and task changes, refresh context automatically.
@@ -1,11 +1,11 @@
1
1
  [project]
2
2
  name = "agentpack-cli"
3
- version = "0.3.5"
3
+ version = "0.3.8"
4
4
  description = "Local context engine for AI coding agents that ranks relevant files and builds task-focused context packs."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
7
7
  license = {text = "MIT"}
8
- keywords = ["ai-coding-agents", "developer-tools", "repo-analysis", "context-engine", "context-packing", "prompt-context", "mcp", "ci", "claude-code", "codex", "cursor", "windsurf", "antigravity", "ai", "llm", "context", "packing", "claude"]
8
+ keywords = ["ai-coding-agents", "developer-tools", "repo-analysis", "context-engine", "context-packing", "prompt-context", "mcp", "ci", "codex", "cursor", "windsurf", "antigravity", "ai", "llm", "context", "packing"]
9
9
  classifiers = [
10
10
  "Development Status :: 3 - Alpha",
11
11
  "Intended Audience :: Developers",
@@ -1,3 +1,3 @@
1
1
  """AgentPack — task-aware context packing for AI coding agents."""
2
2
 
3
- __version__ = "0.3.5"
3
+ __version__ = "0.3.8"
@@ -21,10 +21,12 @@ _GENERIC_TASK_TERMS = {
21
21
  "add", "added", "change", "changed", "changes", "clean", "cleanup",
22
22
  "code", "commit", "context", "debug", "dev", "development", "doc",
23
23
  "docs", "eval", "evals", "feature", "fix", "freshness", "general",
24
- "impl", "implement", "implementation", "improve", "issue", "metric", "metrics",
25
- "noise", "noisy", "package", "pack", "packs", "release", "repo",
26
- "source", "sync", "task", "tasks", "test", "tests", "update", "use",
27
- "useful", "usefulness", "version", "workflow", "workflows",
24
+ "gap", "gaps", "generic", "impl", "implement", "implementation", "improve",
25
+ "issue", "metric", "metrics", "noise", "noisy", "package", "pack", "packs",
26
+ "quality", "release", "remaining", "repo", "root", "rule", "rules",
27
+ "source", "stat", "stats", "sync", "task", "tasks", "test", "tests",
28
+ "text", "update", "use", "useful", "usefulness", "version", "visibility",
29
+ "workflow", "workflows", "wording",
28
30
  }
29
31
 
30
32
  _CONCEPT_MAP: dict[str, frozenset[str]] = {
@@ -223,7 +223,12 @@ class FileRanker:
223
223
  scored = boost_cross_layer_related(scored, keyword_weights, weights=cfg.scoring)
224
224
  scored = boost_paired_tests(scored, weights=cfg.scoring)
225
225
  if root is not None:
226
- scored = _apply_history_penalties(root, scored, changes.all_changed)
226
+ scored = _apply_history_penalties(
227
+ root,
228
+ scored,
229
+ changes.all_changed,
230
+ generic_ratio=generic_ratio,
231
+ )
227
232
  return RankResult(
228
233
  keywords=keywords,
229
234
  generic_ratio=generic_ratio,
@@ -324,6 +329,13 @@ class PackPlanner:
324
329
  no_live_changes=not changes.all_changed,
325
330
  effective_budget=effective_budget,
326
331
  ),
332
+ max_weak_signal_files=_guarded_weak_signal_cap(
333
+ root,
334
+ request.mode,
335
+ rank_result.generic_ratio,
336
+ no_live_changes=not changes.all_changed,
337
+ effective_budget=effective_budget,
338
+ ),
327
339
  )
328
340
  phase_times["select"] = time.perf_counter() - t0
329
341
 
@@ -581,6 +593,7 @@ def _apply_history_penalties(
581
593
  scored: list[tuple[Any, float, list[str]]],
582
594
  changed_paths: set[str],
583
595
  *,
596
+ generic_ratio: float = 0.0,
584
597
  window: int = 20,
585
598
  ) -> list[tuple[Any, float, list[str]]]:
586
599
  """Downrank paths that recent packs proved noisy for later edits."""
@@ -597,7 +610,11 @@ def _apply_history_penalties(
597
610
  if count <= 0:
598
611
  adjusted.append((fi, score, reasons))
599
612
  continue
600
- penalty = min(25.0, count * 4.0)
613
+ has_strong = any(reason.startswith(_NO_LIVE_STRONG_SIGNALS) for reason in reasons)
614
+ if generic_ratio >= 0.35 and count >= 4 and not has_strong:
615
+ adjusted.append((fi, 0.0, [*reasons, "repeat noise path suppressed"]))
616
+ continue
617
+ penalty = min(45.0, count * 6.0 + max(0, count - 2) * 4.0)
601
618
  adjusted.append((fi, max(0.0, score - penalty), [*reasons, f"history noise penalty -{penalty:.0f}"]))
602
619
  return adjusted
603
620
 
@@ -649,10 +666,7 @@ _NO_LIVE_STRONG_SIGNALS = (
649
666
  "content keyword match",
650
667
  "matched entrypoint",
651
668
  "matched external system",
652
- "matched role keyword",
653
669
  "matched domain",
654
- "matched ranking keyword",
655
- "matched define",
656
670
  "matched env read",
657
671
  "matched side effect",
658
672
  "direct dependency",
@@ -663,6 +677,11 @@ _NO_LIVE_STRONG_SIGNALS = (
663
677
  "knowledge/architecture doc",
664
678
  "historically co-changed",
665
679
  )
680
+ _NO_LIVE_META_ONLY_SIGNALS = (
681
+ "matched role keyword",
682
+ "matched ranking keyword",
683
+ "matched define",
684
+ )
666
685
 
667
686
 
668
687
  def _apply_no_live_precision_guard(
@@ -676,19 +695,22 @@ def _apply_no_live_precision_guard(
676
695
  filename-only hits, and avoid letting broad task words fan out across repo.
677
696
  """
678
697
  adjusted: list[tuple[Any, float, list[str]]] = []
679
- broad_task = generic_ratio >= 0.35
698
+ broad_task = generic_ratio >= 0.3
680
699
  for fi, score, reasons in scored:
681
700
  has_filename = any(reason.startswith("filename keyword match") for reason in reasons)
682
701
  has_strong = any(reason.startswith(_NO_LIVE_STRONG_SIGNALS) for reason in reasons)
702
+ has_meta_only = any(reason.startswith(_NO_LIVE_META_ONLY_SIGNALS) for reason in reasons)
703
+ if broad_task and has_filename and not has_strong:
704
+ damped = min(score, max(0.0, score * 0.2))
705
+ adjusted.append((fi, damped, [*reasons, "broad-task weak-signal dampening"]))
706
+ continue
683
707
  if has_filename and not has_strong:
684
708
  damped = min(score, max(0.0, score * 0.35))
685
709
  adjusted.append((fi, damped, [*reasons, "no-live filename-only dampening"]))
686
710
  continue
687
- if broad_task and has_filename and not any(
688
- reason.startswith(("symbol keyword match", "content keyword match", "historically co-changed"))
689
- for reason in reasons
690
- ):
691
- adjusted.append((fi, max(0.0, score - 30), [*reasons, "broad-task filename dampening"]))
711
+ if broad_task and has_meta_only and not has_strong:
712
+ damped = max(0.0, score * 0.45 - 15)
713
+ adjusted.append((fi, damped, [*reasons, "broad-task meta-summary dampening"]))
692
714
  continue
693
715
  adjusted.append((fi, score, reasons))
694
716
  return adjusted
@@ -813,6 +835,57 @@ def _guarded_summary_cap(
813
835
  return min(cap, strict_cap)
814
836
 
815
837
 
838
+ def _recent_token_precision(root: Path, window: int = 10) -> tuple[float, int]:
839
+ metrics_path = root / ".agentpack" / "metrics.jsonl"
840
+ if not metrics_path.exists():
841
+ return 1.0, 0
842
+ values: list[float] = []
843
+ try:
844
+ lines = metrics_path.read_text(encoding="utf-8").splitlines()
845
+ except OSError:
846
+ return 1.0, 0
847
+ for line in reversed(lines):
848
+ try:
849
+ rec = json.loads(line)
850
+ except json.JSONDecodeError:
851
+ continue
852
+ value = rec.get("selection_token_precision")
853
+ if isinstance(value, int | float):
854
+ values.append(float(value))
855
+ if len(values) >= window:
856
+ break
857
+ if not values:
858
+ return 1.0, 0
859
+ return sum(values) / len(values), len(values)
860
+
861
+
862
+ def _guarded_weak_signal_cap(
863
+ root: Path,
864
+ mode: str,
865
+ generic_ratio: float,
866
+ *,
867
+ no_live_changes: bool = False,
868
+ effective_budget: int = 0,
869
+ ) -> int:
870
+ if not no_live_changes:
871
+ return 0
872
+ if generic_ratio >= 0.5:
873
+ base = {"minimal": 0, "balanced": 1, "deep": 2}.get(mode, 1)
874
+ elif generic_ratio >= 0.35:
875
+ base = {"minimal": 1, "balanced": 2, "deep": 3}.get(mode, 2)
876
+ else:
877
+ base = {"minimal": 2, "balanced": 4, "deep": 6}.get(mode, 3)
878
+ avg_precision, rows = _recent_token_precision(root)
879
+ if rows >= 3:
880
+ if avg_precision <= 0.1:
881
+ base = min(base, 0 if mode == "minimal" else 1)
882
+ elif avg_precision <= 0.2:
883
+ base = min(base, 1 if mode != "deep" else 2)
884
+ if effective_budget and effective_budget <= 2500:
885
+ base = min(base, 1)
886
+ return max(0, base)
887
+
888
+
816
889
  def _recent_summary_token_precision(root: Path, window: int = 10) -> tuple[float, int]:
817
890
  metrics_path = root / ".agentpack" / "metrics.jsonl"
818
891
  if not metrics_path.exists():
@@ -9,6 +9,7 @@ from agentpack.commands import (
9
9
  explain,
10
10
  guard,
11
11
  hook_cmd,
12
+ ignore_cmd,
12
13
  init,
13
14
  install,
14
15
  mcp_cmd,
@@ -45,6 +46,7 @@ def _main(
45
46
 
46
47
  for mod in [
47
48
  init,
49
+ ignore_cmd,
48
50
  scan,
49
51
  diff,
50
52
  status,
@@ -18,6 +18,7 @@ from agentpack.integrations.global_install import (
18
18
  )
19
19
  from agentpack.commands._shared import console, _root
20
20
  from agentpack.core.context_pack import load_pack_metadata
21
+ from agentpack.core.ignore import agentignore_sync_status, format_import_summary
21
22
  from agentpack.core.task_freshness import task_freshness
22
23
  from agentpack.integrations.agents import SUPPORTED_AGENTS, check_agent_integration, expand_agents
23
24
 
@@ -121,6 +122,12 @@ def register(app: typer.Typer) -> None:
121
122
  console.print(f" [yellow]![/] Not initialized in {root} — run: agentpack init")
122
123
  else:
123
124
  console.print(" [green]✓[/] .agentpack/config.toml present")
125
+ for finding in _agentignore_sync_findings(root):
126
+ if finding.startswith("synced:"):
127
+ console.print(f" [green]✓[/] {finding.split(':', 1)[1].strip()}")
128
+ else:
129
+ console.print(f" [yellow]![/] {finding}")
130
+ ok = False
124
131
  context_path = _latest_context_path(root)
125
132
  if context_path.exists():
126
133
  import time
@@ -405,6 +412,17 @@ def _publish_secret_findings(root: Path, env: Mapping[str, str] | None = None) -
405
412
  return findings
406
413
 
407
414
 
415
+ def _agentignore_sync_findings(root: Path) -> list[str]:
416
+ status = agentignore_sync_status(root)
417
+ if status.action == "create":
418
+ return ["missing .agentignore; run `agentpack init` or `agentpack ignore sync`."]
419
+ if status.is_stale:
420
+ return ["imported .agentignore rules are stale; run `agentpack ignore sync`."]
421
+ if status.imported_rules:
422
+ return [f"synced: {format_import_summary(status)}"]
423
+ return ["synced: .agentignore present; no imported generated/noisy rules detected."]
424
+
425
+
408
426
  def _print_summary(ok: bool) -> None:
409
427
  console.print("")
410
428
  if ok:
@@ -0,0 +1,51 @@
1
+ from __future__ import annotations
2
+
3
+ import typer
4
+
5
+ from agentpack.commands._shared import console, _root
6
+ from agentpack.core.ignore import agentignore_sync_status, format_import_summary
7
+
8
+
9
+ def register(app: typer.Typer) -> None:
10
+ ignore_app = typer.Typer(help="Inspect and sync AgentPack ignore rules.")
11
+
12
+ @ignore_app.command("sync")
13
+ def sync(
14
+ dry_run: bool = typer.Option(False, "--dry-run", help="Show the planned .agentignore update without writing."),
15
+ check: bool = typer.Option(False, "--check", help="Exit non-zero when .agentignore is stale."),
16
+ ) -> None:
17
+ """Sync imported generated/noisy rules into .agentignore."""
18
+ root = _root()
19
+ status = agentignore_sync_status(root)
20
+
21
+ if dry_run:
22
+ console.print(f"[bold]Action:[/] {status.action}")
23
+ if status.imported_rules:
24
+ console.print(f"[dim]{format_import_summary(status)}[/]")
25
+ else:
26
+ console.print("[dim]Imported 0 generated/noisy rules.[/]")
27
+ raise typer.Exit(0)
28
+
29
+ if check:
30
+ if status.action == "unchanged":
31
+ console.print("[green].agentignore is in sync.[/]")
32
+ raise typer.Exit(0)
33
+ console.print("[yellow].agentignore is stale; run `agentpack ignore sync`.[/]")
34
+ raise typer.Exit(1)
35
+
36
+ previous_action = status.action
37
+ if previous_action != "unchanged":
38
+ status.path.parent.mkdir(parents=True, exist_ok=True)
39
+ status.path.write_text(status.desired_content, encoding="utf-8")
40
+ status = agentignore_sync_status(root)
41
+
42
+ if previous_action == "create":
43
+ console.print("[green]Created .agentignore.[/]")
44
+ elif previous_action == "update":
45
+ console.print("[green]Updated .agentignore.[/]")
46
+ else:
47
+ console.print("[green].agentignore already in sync.[/]")
48
+ if status.imported_rules:
49
+ console.print(f"[dim]{format_import_summary(status)}[/]")
50
+
51
+ app.add_typer(ignore_app, name="ignore")
@@ -8,7 +8,11 @@ from typing import Optional
8
8
  import typer
9
9
 
10
10
  from agentpack.core.config import DEFAULT_CONFIG, CONFIG_TEMPLATE
11
- from agentpack.core.ignore import DEFAULT_AGENTIGNORE
11
+ from agentpack.core.ignore import (
12
+ AgentIgnoreSyncStatus,
13
+ agentignore_sync_status,
14
+ format_import_summary,
15
+ )
12
16
  from agentpack.commands._shared import console, _root
13
17
  from agentpack.integrations.agents import check_agent_integration, install_agent_integration
14
18
  from agentpack.session.state import load_session, create_session, SESSION_FILE, TASK_FILE
@@ -147,6 +151,24 @@ def _patch_repo_gitignore(root: Path, share_cache: bool = False, agent: str = "g
147
151
  return "updated"
148
152
 
149
153
 
154
+ def _patch_agentignore(
155
+ root: Path,
156
+ *,
157
+ force: bool = False,
158
+ backups: list[InitResult] | None = None,
159
+ ) -> tuple[str, AgentIgnoreSyncStatus]:
160
+ status = agentignore_sync_status(root)
161
+ if force and status.path.exists() and backups is not None:
162
+ backup = _backup_file(status.path)
163
+ backups.append(InitResult(str(backup.relative_to(root)), "created"))
164
+ if status.action == "unchanged":
165
+ return "unchanged", status
166
+ status.path.parent.mkdir(parents=True, exist_ok=True)
167
+ status.path.write_text(status.desired_content, encoding="utf-8")
168
+ action = "created" if status.action == "create" else "updated"
169
+ return action, agentignore_sync_status(root)
170
+
171
+
150
172
  def _install_agent_integration(root, agent: str) -> dict[str, str]:
151
173
  """Install repo-local agent integration files after `agentpack init`."""
152
174
  return install_agent_integration(root, agent)
@@ -222,6 +244,7 @@ def _planned_action(path: Path, expected: str | None = None) -> str:
222
244
 
223
245
  def _print_dry_run(root: Path, agent: str, share_cache: bool, mode: str | None, budget: int) -> None:
224
246
  console.print("[bold yellow]Dry run — no files will be changed.[/]\n")
247
+ ignore_status = agentignore_sync_status(root)
225
248
  items = [
226
249
  InitResult(".agentpack/", "ensure"),
227
250
  InitResult(".agentpack/snapshots/", "ensure"),
@@ -229,7 +252,7 @@ def _print_dry_run(root: Path, agent: str, share_cache: bool, mode: str | None,
229
252
  InitResult(".agentpack/.gitignore", _planned_action(root / ".agentpack" / ".gitignore")),
230
253
  InitResult(".gitignore", _planned_action(root / ".gitignore")),
231
254
  InitResult(".agentpack/config.toml", _planned_action(root / ".agentpack" / "config.toml")),
232
- InitResult(".agentignore", _planned_action(root / ".agentignore", DEFAULT_AGENTIGNORE)),
255
+ InitResult(".agentignore", ignore_status.action),
233
256
  InitResult(SESSION_FILE, _planned_action(root / SESSION_FILE)),
234
257
  InitResult(TASK_FILE, _planned_action(root / TASK_FILE)),
235
258
  ]
@@ -240,6 +263,8 @@ def _print_dry_run(root: Path, agent: str, share_cache: bool, mode: str | None,
240
263
  console.print(f" Mode: {mode or DEFAULT_CONFIG.context.default_mode}")
241
264
  console.print(f" Budget: {budget or DEFAULT_CONFIG.context.default_budget:,}")
242
265
  console.print(f" Share cache: {'yes' if share_cache else 'no'}")
266
+ if ignore_status.imported_rules:
267
+ console.print(f" {format_import_summary(ignore_status)}")
243
268
 
244
269
 
245
270
  def _print_init_summary(title: str, results: list[InitResult]) -> None:
@@ -369,12 +394,8 @@ def register(app: typer.Typer) -> None:
369
394
  else:
370
395
  results.append(InitResult(".agentpack/config.toml", "unchanged"))
371
396
 
372
- ignore_path = root / ".agentignore"
373
- if not ignore_path.exists() or force:
374
- action = _write_text(root, ignore_path, DEFAULT_AGENTIGNORE, force=force, backups=backups)
375
- results.append(InitResult(".agentignore", action))
376
- else:
377
- results.append(InitResult(".agentignore", "unchanged"))
397
+ ignore_action, ignore_status = _patch_agentignore(root, force=force, backups=backups)
398
+ results.append(InitResult(".agentignore", ignore_action))
378
399
 
379
400
  # Bootstrap session so `agentpack watch` works immediately — no separate `session start` needed
380
401
  from agentpack.core.config import load_config
@@ -402,6 +423,8 @@ def register(app: typer.Typer) -> None:
402
423
  if backups:
403
424
  _print_init_summary("Backups", backups)
404
425
  _print_init_summary("Init Summary", results)
426
+ if ignore_status.imported_rules:
427
+ console.print(f" [dim]{format_import_summary(ignore_status)}[/]")
405
428
  if health_check:
406
429
  _print_health(root, resolved_agent)
407
430
  console.print(f"\n[bold green]AgentPack initialized.[/] [dim]agent={resolved_agent} mode={resolved_mode}[/]")
@@ -233,8 +233,11 @@ def _pack_diagnostics(result: PackResult) -> list[str]:
233
233
  part for part in result.pack.task.replace("_", " ").replace("-", " ").split()
234
234
  if len(part) >= 3
235
235
  ]
236
+ generic_ratio = float((result.pack.freshness or {}).get("generic_task_ratio") or 0.0)
236
237
  if len(task_words) <= 3:
237
238
  diagnostics.append("Task is very short; add subsystem, file, or symptom words for better precision.")
239
+ if generic_ratio >= 0.5:
240
+ diagnostics.append("Task terms are broad/generic; name concrete file, route, service, or symptom words.")
238
241
  if not result.changed_files:
239
242
  diagnostics.append("No changed files detected; pack relies mostly on task keywords and cached summaries.")
240
243
  if selected and not strong_live_signal and filename_matches / len(selected) >= 0.6:
@@ -346,6 +346,7 @@ def _noise_diagnostics(
346
346
  diagnostics.append("Latest pack is mostly summaries; use minimal mode or a narrower task for edit work.")
347
347
  if filename_matches / len(visible_top) >= 0.6:
348
348
  diagnostics.append("Top files mostly matched by filename; task terms may be broad.")
349
+ diagnostics.append("Rewrite `.agentpack/task.md` with concrete file, route, service, or symptom words.")
349
350
 
350
351
  if accuracy_rows:
351
352
  avg_precision = sum(r["selection_precision"] for r in accuracy_rows) / len(accuracy_rows)
@@ -380,9 +381,9 @@ def _noise_diagnostics(
380
381
  first_path = noisy[0][0]
381
382
  diagnostics.append(
382
383
  f"Inspect top noisy path: `agentpack explain --file {first_path} --task auto`; "
383
- "add generated/vendor paths to `.agentignore` or tighten task wording if it is not useful."
384
+ "add generated/vendor paths to `.agentignore`, run `agentpack ignore sync`, or tighten task wording if it is not useful."
384
385
  )
385
- return diagnostics[:8]
386
+ return diagnostics[:9]
386
387
 
387
388
 
388
389
  def _top_files_from_metadata(meta: dict) -> list[tuple[str, str, str]]: