meredith-agent 0.2.6__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 (69) hide show
  1. meredith_agent-0.2.6/.env.example +23 -0
  2. meredith_agent-0.2.6/.github/workflows/ci.yml +57 -0
  3. meredith_agent-0.2.6/.github/workflows/codeql.yml +22 -0
  4. meredith_agent-0.2.6/.gitignore +65 -0
  5. meredith_agent-0.2.6/.pre-commit-config.yaml +21 -0
  6. meredith_agent-0.2.6/.secrets.baseline +150 -0
  7. meredith_agent-0.2.6/AGENTS.md +108 -0
  8. meredith_agent-0.2.6/LICENSE +182 -0
  9. meredith_agent-0.2.6/Makefile +50 -0
  10. meredith_agent-0.2.6/PKG-INFO +327 -0
  11. meredith_agent-0.2.6/README.md +299 -0
  12. meredith_agent-0.2.6/assets/meredith.svg +90 -0
  13. meredith_agent-0.2.6/config/base.yaml +80 -0
  14. meredith_agent-0.2.6/config/large_model.yaml +35 -0
  15. meredith_agent-0.2.6/config/local_model.yaml +48 -0
  16. meredith_agent-0.2.6/pyproject.toml +59 -0
  17. meredith_agent-0.2.6/skills/code_review/SKILL.md +96 -0
  18. meredith_agent-0.2.6/skills/debugging/SKILL.md +77 -0
  19. meredith_agent-0.2.6/src/coding_agent/__init__.py +38 -0
  20. meredith_agent-0.2.6/src/coding_agent/acp/__init__.py +12 -0
  21. meredith_agent-0.2.6/src/coding_agent/acp/server.py +269 -0
  22. meredith_agent-0.2.6/src/coding_agent/agent/__init__.py +20 -0
  23. meredith_agent-0.2.6/src/coding_agent/agent/core.py +545 -0
  24. meredith_agent-0.2.6/src/coding_agent/agent/planner.py +388 -0
  25. meredith_agent-0.2.6/src/coding_agent/agent/verifier.py +273 -0
  26. meredith_agent-0.2.6/src/coding_agent/config.py +362 -0
  27. meredith_agent-0.2.6/src/coding_agent/context/__init__.py +17 -0
  28. meredith_agent-0.2.6/src/coding_agent/context/budget.py +184 -0
  29. meredith_agent-0.2.6/src/coding_agent/context/compressor.py +323 -0
  30. meredith_agent-0.2.6/src/coding_agent/context/manager.py +327 -0
  31. meredith_agent-0.2.6/src/coding_agent/llm/__init__.py +26 -0
  32. meredith_agent-0.2.6/src/coding_agent/llm/base.py +216 -0
  33. meredith_agent-0.2.6/src/coding_agent/llm/local.py +527 -0
  34. meredith_agent-0.2.6/src/coding_agent/llm/remote.py +304 -0
  35. meredith_agent-0.2.6/src/coding_agent/main.py +212 -0
  36. meredith_agent-0.2.6/src/coding_agent/memory/__init__.py +15 -0
  37. meredith_agent-0.2.6/src/coding_agent/memory/store.py +358 -0
  38. meredith_agent-0.2.6/src/coding_agent/rag/__init__.py +18 -0
  39. meredith_agent-0.2.6/src/coding_agent/rag/chunker.py +484 -0
  40. meredith_agent-0.2.6/src/coding_agent/rag/indexer.py +515 -0
  41. meredith_agent-0.2.6/src/coding_agent/rag/retriever.py +390 -0
  42. meredith_agent-0.2.6/src/coding_agent/recovery/__init__.py +14 -0
  43. meredith_agent-0.2.6/src/coding_agent/recovery/detector.py +303 -0
  44. meredith_agent-0.2.6/src/coding_agent/recovery/strategies.py +288 -0
  45. meredith_agent-0.2.6/src/coding_agent/tools/__init__.py +18 -0
  46. meredith_agent-0.2.6/src/coding_agent/tools/base.py +395 -0
  47. meredith_agent-0.2.6/src/coding_agent/tools/fs.py +419 -0
  48. meredith_agent-0.2.6/src/coding_agent/tools/git.py +201 -0
  49. meredith_agent-0.2.6/src/coding_agent/tools/router.py +248 -0
  50. meredith_agent-0.2.6/src/coding_agent/tools/search.py +487 -0
  51. meredith_agent-0.2.6/src/coding_agent/tools/web.py +419 -0
  52. meredith_agent-0.2.6/src/coding_agent/types.py +430 -0
  53. meredith_agent-0.2.6/tests/__init__.py +0 -0
  54. meredith_agent-0.2.6/tests/conftest.py +89 -0
  55. meredith_agent-0.2.6/tests/test_budget.py +166 -0
  56. meredith_agent-0.2.6/tests/test_compressor.py +148 -0
  57. meredith_agent-0.2.6/tests/test_config.py +298 -0
  58. meredith_agent-0.2.6/tests/test_context_manager.py +118 -0
  59. meredith_agent-0.2.6/tests/test_detector.py +154 -0
  60. meredith_agent-0.2.6/tests/test_import.py +9 -0
  61. meredith_agent-0.2.6/tests/test_llm_base.py +206 -0
  62. meredith_agent-0.2.6/tests/test_memory.py +112 -0
  63. meredith_agent-0.2.6/tests/test_planner.py +108 -0
  64. meredith_agent-0.2.6/tests/test_router.py +155 -0
  65. meredith_agent-0.2.6/tests/test_strategies.py +92 -0
  66. meredith_agent-0.2.6/tests/test_tool_base.py +58 -0
  67. meredith_agent-0.2.6/tests/test_types.py +348 -0
  68. meredith_agent-0.2.6/tests/test_verifier.py +107 -0
  69. meredith_agent-0.2.6/uv.lock +1320 -0
@@ -0,0 +1,23 @@
1
+ # ── API Keys ──────────────────────────────────────────
2
+ # Copy this file to .env and fill in your actual keys.
3
+ # NEVER commit .env or any file containing real keys!
4
+
5
+ # LLM provider (any OpenAI-compatible API)
6
+ # Used by: llm/provider = "remote", api_key_env in config YAML
7
+ # Supports OpenAI, Anthropic, Together, Opencode, Fireworks, Azure, etc.
8
+ LLM_API_KEY=sk-your-key-here
9
+
10
+ # Web search backends (pick one)
11
+ # Copy the API key for your chosen backend from config YAML
12
+
13
+ # Brave Search (default for local_model)
14
+ # Get at: https://brave.com/search/api/
15
+ BRAVE_API_KEY=
16
+
17
+ # Tavily Search (default for large_model)
18
+ # Get at: https://tavily.com/api
19
+ TAVILY_API_KEY=
20
+
21
+ # Exa Search (alternative)
22
+ # Get at: https://exa.ai
23
+ EXA_API_KEY=
@@ -0,0 +1,57 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+ release:
9
+ types: [published]
10
+
11
+ jobs:
12
+ lint:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - uses: astral-sh/setup-uv@v3
17
+ with:
18
+ version: "0.6.x"
19
+ - run: uv sync --extra dev
20
+ - run: uv run ruff check src/
21
+
22
+ typecheck:
23
+ runs-on: ubuntu-latest
24
+ steps:
25
+ - uses: actions/checkout@v4
26
+ - uses: astral-sh/setup-uv@v3
27
+ with:
28
+ version: "0.6.x"
29
+ - run: uv sync --extra dev
30
+ - run: uv run mypy src/ --strict
31
+
32
+ test:
33
+ runs-on: ubuntu-latest
34
+ steps:
35
+ - uses: actions/checkout@v4
36
+ - uses: astral-sh/setup-uv@v3
37
+ with:
38
+ version: "0.6.x"
39
+ - run: uv sync --extra dev
40
+ - run: uv run pytest tests/ -v --cov=coding_agent
41
+
42
+ build:
43
+ runs-on: ubuntu-latest
44
+ needs: [lint, typecheck, test]
45
+ if: github.event_name == 'release'
46
+ environment:
47
+ name: pypi
48
+ permissions:
49
+ id-token: write
50
+ contents: read
51
+ steps:
52
+ - uses: actions/checkout@v4
53
+ - uses: astral-sh/setup-uv@v3
54
+ with:
55
+ version: "0.6.x"
56
+ - run: uv build
57
+ - run: uv publish
@@ -0,0 +1,22 @@
1
+ name: CodeQL
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+ schedule:
9
+ - cron: "0 12 * * 1" # Weekly: Monday noon
10
+
11
+ jobs:
12
+ analyze:
13
+ runs-on: ubuntu-latest
14
+ permissions:
15
+ security-events: write
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ - uses: github/codeql-action/init@v3
19
+ with:
20
+ languages: python
21
+ queries: security-and-quality
22
+ - uses: github/codeql-action/analyze@v3
@@ -0,0 +1,65 @@
1
+ # ── Python ──────────────────────────────────────────────
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ *.egg
8
+ .venv/
9
+ venv/
10
+ env/
11
+
12
+ # ── Runtime data ────────────────────────────────────────
13
+ .agent/
14
+ *.db
15
+ *.log
16
+
17
+ # ── IDE / Editor ───────────────────────────────────────
18
+ .vscode/
19
+ .idea/
20
+ *.swp
21
+ *.swo
22
+ *~
23
+ .DS_Store
24
+
25
+ # ── Tooling artifacts ──────────────────────────────────
26
+ .ruff_cache/
27
+ .mypy_cache/
28
+ .pytest_cache/
29
+ htmlcov/
30
+ .coverage
31
+ coverage/
32
+
33
+ # ── Secrets / credentials ─────────────────────────────
34
+ .env
35
+ .env.*
36
+ .env.local
37
+ .env.production
38
+ .env.development
39
+ *.pem
40
+ *.key
41
+ **/secrets/**
42
+ **/credentials/**
43
+ !**/.env.example
44
+
45
+ # ── OS files ───────────────────────────────────────────
46
+ .DS_Store
47
+ Thumbs.db
48
+
49
+ # ── Cloud provider credentials ────────────────────────
50
+ .aws/
51
+ .gcp/
52
+ .azure/
53
+ google-cloud-sdk/
54
+ .gcloud/
55
+
56
+ # ── Local config / identities ─────────────────────────
57
+ .ssh/
58
+ .kube/
59
+ config.json # Docker auth
60
+ .docker/
61
+ .npmrc
62
+ .netrc
63
+ .gitconfig.local
64
+ .git-credentials
65
+ *.local
@@ -0,0 +1,21 @@
1
+ # ── Pre-commit hooks ──────────────────────────────────
2
+ # Install: uv run pre-commit install
3
+ # Run all: uv run pre-commit run --all-files
4
+ # ──────────────────────────────────────────────────────
5
+ repos:
6
+ - repo: https://github.com/pre-commit/pre-commit-hooks
7
+ rev: v5.0.0
8
+ hooks:
9
+ - id: trailing-whitespace
10
+ - id: end-of-file-fixer
11
+ - id: check-yaml
12
+ - id: check-added-large-files
13
+ args: [--maxkb=500]
14
+ - id: detect-private-key
15
+
16
+ - repo: https://github.com/Yelp/detect-secrets
17
+ rev: v1.5.0
18
+ hooks:
19
+ - id: detect-secrets
20
+ args: [--baseline, .secrets.baseline]
21
+ exclude: \.env\.example$
@@ -0,0 +1,150 @@
1
+ {
2
+ "version": "1.5.0",
3
+ "plugins_used": [
4
+ {
5
+ "name": "ArtifactoryDetector"
6
+ },
7
+ {
8
+ "name": "AWSKeyDetector"
9
+ },
10
+ {
11
+ "name": "AzureStorageKeyDetector"
12
+ },
13
+ {
14
+ "name": "Base64HighEntropyString",
15
+ "limit": 4.5
16
+ },
17
+ {
18
+ "name": "BasicAuthDetector"
19
+ },
20
+ {
21
+ "name": "CloudantDetector"
22
+ },
23
+ {
24
+ "name": "DiscordBotTokenDetector"
25
+ },
26
+ {
27
+ "name": "GitHubTokenDetector"
28
+ },
29
+ {
30
+ "name": "GitLabTokenDetector"
31
+ },
32
+ {
33
+ "name": "HexHighEntropyString",
34
+ "limit": 3.0
35
+ },
36
+ {
37
+ "name": "IbmCloudIamDetector"
38
+ },
39
+ {
40
+ "name": "IbmCosHmacDetector"
41
+ },
42
+ {
43
+ "name": "IPPublicDetector"
44
+ },
45
+ {
46
+ "name": "JwtTokenDetector"
47
+ },
48
+ {
49
+ "name": "KeywordDetector",
50
+ "keyword_exclude": ""
51
+ },
52
+ {
53
+ "name": "MailchimpDetector"
54
+ },
55
+ {
56
+ "name": "NpmDetector"
57
+ },
58
+ {
59
+ "name": "OpenAIDetector"
60
+ },
61
+ {
62
+ "name": "PrivateKeyDetector"
63
+ },
64
+ {
65
+ "name": "PypiTokenDetector"
66
+ },
67
+ {
68
+ "name": "SendGridDetector"
69
+ },
70
+ {
71
+ "name": "SlackDetector"
72
+ },
73
+ {
74
+ "name": "SoftlayerDetector"
75
+ },
76
+ {
77
+ "name": "SquareOAuthDetector"
78
+ },
79
+ {
80
+ "name": "StripeDetector"
81
+ },
82
+ {
83
+ "name": "TelegramBotTokenDetector"
84
+ },
85
+ {
86
+ "name": "TwilioKeyDetector"
87
+ }
88
+ ],
89
+ "filters_used": [
90
+ {
91
+ "path": "detect_secrets.filters.allowlist.is_line_allowlisted"
92
+ },
93
+ {
94
+ "path": "detect_secrets.filters.common.is_baseline_file",
95
+ "filename": ".secrets.baseline"
96
+ },
97
+ {
98
+ "path": "detect_secrets.filters.common.is_ignored_due_to_verification_policies",
99
+ "min_level": 2
100
+ },
101
+ {
102
+ "path": "detect_secrets.filters.heuristic.is_indirect_reference"
103
+ },
104
+ {
105
+ "path": "detect_secrets.filters.heuristic.is_likely_id_string"
106
+ },
107
+ {
108
+ "path": "detect_secrets.filters.heuristic.is_lock_file"
109
+ },
110
+ {
111
+ "path": "detect_secrets.filters.heuristic.is_not_alphanumeric_string"
112
+ },
113
+ {
114
+ "path": "detect_secrets.filters.heuristic.is_potential_uuid"
115
+ },
116
+ {
117
+ "path": "detect_secrets.filters.heuristic.is_prefixed_with_dollar_sign"
118
+ },
119
+ {
120
+ "path": "detect_secrets.filters.heuristic.is_sequential_string"
121
+ },
122
+ {
123
+ "path": "detect_secrets.filters.heuristic.is_swagger_file"
124
+ },
125
+ {
126
+ "path": "detect_secrets.filters.heuristic.is_templated_secret"
127
+ }
128
+ ],
129
+ "results": {
130
+ "README.md": [
131
+ {
132
+ "type": "Secret Keyword",
133
+ "filename": "README.md",
134
+ "hashed_secret": "ec3810e10fb78db55ce38b9c18d1c3eb1db739e0",
135
+ "is_verified": false,
136
+ "line_number": 55
137
+ }
138
+ ],
139
+ "config/large_model.yaml": [
140
+ {
141
+ "type": "Secret Keyword",
142
+ "filename": "config/large_model.yaml",
143
+ "hashed_secret": "5376e4b0871e1d739b9157a0b6cbdcf26ec28a97",
144
+ "is_verified": false,
145
+ "line_number": 10
146
+ }
147
+ ]
148
+ },
149
+ "generated_at": "2026-06-27T15:37:32Z"
150
+ }
@@ -0,0 +1,108 @@
1
+ # AGENTS.md — Project Instructions for AI Coding Agents
2
+
3
+ ## Project Overview
4
+
5
+ This is meredith: a modern AI coding agent with RAG,
6
+ ACP (Agent Client Protocol) integration, and smart context
7
+ management. It supports both large remote models via any
8
+ OpenAI-compatible API (Claude, GPT, Opencode, etc.) and
9
+ local models (Ollama on Linux/macOS/Windows, MLX on Apple Silicon).
10
+
11
+ ## Tech Stack
12
+
13
+ - Language: Python 3.13+
14
+ - Package manager: uv
15
+ - Async framework: asyncio
16
+ - HTTP client: httpx
17
+ - Token counting: tiktoken (cl100k_base)
18
+ - Code parsing: tree-sitter-languages (optional, no cp313 wheel)
19
+ - Database: SQLite (via stdlib)
20
+ - Search: ripgrep (preferred) or grep
21
+
22
+ ## Development Environment
23
+
24
+ - Install: uv sync --extra dev
25
+ - Lint: uv run ruff check src/
26
+ - Format: uv run ruff format src/
27
+ - Type check: uv run mypy src/ (if configured)
28
+ - Test: uv run pytest tests/ -v
29
+
30
+ ## Code Style
31
+
32
+ - Use Python 3.13+ syntax: X | Y unions, type statements, slots=True
33
+ - Use from __future__ import annotations in all files
34
+ - All functions and classes must have docstrings (triple double-quotes)
35
+ - Use async/await for all I/O operations
36
+ - Never use pandas — prefer built-in types and stdlib
37
+ - Never hardcode values that users might change — put them in config YAML
38
+
39
+ ## Project Structure
40
+
41
+ - config/ — YAML configuration files (base, large_model, local_model)
42
+ - src/coding_agent/ — Main package
43
+ - agent/ — Core loop, planner, verifier
44
+ - context/ — Context window management
45
+ - tools/ — Tool definitions and executors
46
+ - rag/ — Retrieval-Augmented Generation subsystem
47
+ - recovery/ — Loop detection and escape strategies
48
+ - llm/ — LLM client abstractions (remote, local/MLX)
49
+ - memory/ — Cross-session memory store
50
+ - acp/ — ACP server for editor integration
51
+ - skills/ — SKILL.md files for agent capabilities
52
+ - .agent/ — Runtime data (index, memory DB, logs) — do not edit manually
53
+
54
+ ## Testing Instructions
55
+
56
+ - Run all tests: uv run pytest tests/ -v
57
+ - Run a single test: uv run pytest tests/test_specific.py -v
58
+ - Run with coverage: uv run pytest tests/ --cov=coding_agent
59
+
60
+ ## PR Instructions
61
+
62
+ - Title format: [area] Description (e.g. [rag] Add AST chunker for Go)
63
+ - Run uv run ruff check src/ and uv run pytest tests/ -v before committing
64
+ - Keep PRs focused — one concern per PR
65
+ - Document any new config keys in the appropriate YAML file
66
+
67
+ ## Security Considerations
68
+
69
+ ### Credential Management
70
+ - API keys are read from environment variables (e.g. `LLM_API_KEY`, `BRAVE_API_KEY`), never from source code, config files, or `.env` files within the project tree.
71
+ - The LLM client factory reads `api_key_env` from config and resolves it at runtime from the process environment — keys never appear in logs, dumps, or context windows.
72
+ - Git credentials used by the git tool are inherited from the host environment (git-credential-osxkeychain, etc.), never stored or forwarded by the agent.
73
+ - The memory store (SQLite) does not persist authentication tokens, session keys, or credentials of any kind.
74
+
75
+ ### PII / Sensitive Data Protection
76
+ - Tool outputs (file contents, git diffs, search results, web responses) are **not automatically scrubbed** — the agent may process sensitive data present in the working directory. This is by design (the agent needs file contents to do its job).
77
+ - However, the context compressor may truncate long outputs, which provides a natural volume-based limit on how much raw data enters the LLM context window at once.
78
+ - The cross-session memory store explicitly excludes any content containing email addresses, API keys, tokens, or secrets patterns (`sk-...`, `ghp_...`, `-----BEGIN.*KEY-----`). See `memory/store.py:save_session`.
79
+ - All log files are written to `.agent/agent.log` (gitignored) and are local-only. Logs do not contain environment variable values or full API responses.
80
+
81
+ ### Prompt Injection Mitigation
82
+ - Tool outputs are presented to the LLM as `TOOL`-role messages, which most frontier models treat as system-controlled rather than user-controlled content.
83
+ - The system prompt instructs the agent to treat file contents as data, not instructions. No tool output is ever interpreted as a directive to the agent loop itself.
84
+ - Web-fetched content is stripped of script tags and rendered to plain text before entering the context window.
85
+
86
+ ### File System Safety
87
+ - All file operations (`read_file`, `edit_file`, `write_file`, `list_directory`) are scoped to the configured `working_directory`. Path traversal sequences (`..`) are explicitly rejected.
88
+ - The `write_file` and `edit_file` tools refuse to create symlinks outside the working tree.
89
+ - File writes are validated for encoding (UTF-8) before proceeding; binary files are not written through the agent tools.
90
+ - The `run_command` tool enforces a configurable timeout (default 120s) to prevent runaway processes.
91
+
92
+ ### Subprocess & Shell Safety
93
+ - Shell commands are executed via `asyncio.create_subprocess_shell` with no shell injection surface — the entire command string is user-provided and passed to the shell directly. This is an accepted risk of the `run_command` tool; the agent is trusted within the working directory.
94
+ - The ACP server communicates exclusively over stdio (not TCP), eliminating network-based attack surface for editor integration.
95
+
96
+ ### Data at Rest
97
+ - The RAG index and memory store are SQLite databases stored in `.agent/` (gitignored). They contain file paths, code chunks, and agent observations — not credentials.
98
+ - Users should ensure `.agent/` is excluded from backups that leave their security boundary.
99
+
100
+ ### Supply Chain
101
+ - Dependencies are pinned to minor/major ranges (e.g. `httpx>=0.27,<1`) and managed via `uv.lock` for reproducible builds.
102
+ - The build process uses Hatchling (pure Python, no compiled extensions in the toolchain).
103
+ - CI runs `uv run ruff check`, `uv run mypy --strict`, and `uv run pytest --cov` on every PR to catch regressions.
104
+
105
+ ### Rate Limiting & Resource Protection
106
+ - The `web_fetch` and `web_search` tools have configurable timeouts (default 15s) and result limits.
107
+ - The agent loop has a hard cap at `max_steps` (default 50) to prevent runaway token consumption.
108
+ - The context budget system prevents any single step from consuming more than 10% of the remaining budget.