codeforerunner 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- codeforerunner-0.3.0/LICENSE.md +71 -0
- codeforerunner-0.3.0/PKG-INFO +120 -0
- codeforerunner-0.3.0/README.md +106 -0
- codeforerunner-0.3.0/pyproject.toml +32 -0
- codeforerunner-0.3.0/setup.cfg +4 -0
- codeforerunner-0.3.0/src/codeforerunner/__init__.py +1 -0
- codeforerunner-0.3.0/src/codeforerunner/check.py +156 -0
- codeforerunner-0.3.0/src/codeforerunner/cli.py +236 -0
- codeforerunner-0.3.0/src/codeforerunner/config.py +176 -0
- codeforerunner-0.3.0/src/codeforerunner/doctor.py +321 -0
- codeforerunner-0.3.0/src/codeforerunner/installer.py +304 -0
- codeforerunner-0.3.0/src/codeforerunner/mcp_server.py +177 -0
- codeforerunner-0.3.0/src/codeforerunner/providers/__init__.py +36 -0
- codeforerunner-0.3.0/src/codeforerunner/providers/anthropic.py +61 -0
- codeforerunner-0.3.0/src/codeforerunner/providers/base.py +31 -0
- codeforerunner-0.3.0/src/codeforerunner/providers/google.py +62 -0
- codeforerunner-0.3.0/src/codeforerunner/providers/ollama.py +56 -0
- codeforerunner-0.3.0/src/codeforerunner/providers/openai.py +59 -0
- codeforerunner-0.3.0/src/codeforerunner.egg-info/PKG-INFO +120 -0
- codeforerunner-0.3.0/src/codeforerunner.egg-info/SOURCES.txt +34 -0
- codeforerunner-0.3.0/src/codeforerunner.egg-info/dependency_links.txt +1 -0
- codeforerunner-0.3.0/src/codeforerunner.egg-info/entry_points.txt +2 -0
- codeforerunner-0.3.0/src/codeforerunner.egg-info/requires.txt +1 -0
- codeforerunner-0.3.0/src/codeforerunner.egg-info/top_level.txt +1 -0
- codeforerunner-0.3.0/tests/test_check.py +197 -0
- codeforerunner-0.3.0/tests/test_check_config_integration.py +45 -0
- codeforerunner-0.3.0/tests/test_cli.py +238 -0
- codeforerunner-0.3.0/tests/test_config.py +127 -0
- codeforerunner-0.3.0/tests/test_doctor.py +137 -0
- codeforerunner-0.3.0/tests/test_examples.py +23 -0
- codeforerunner-0.3.0/tests/test_hooks_manifest.py +31 -0
- codeforerunner-0.3.0/tests/test_installer.py +229 -0
- codeforerunner-0.3.0/tests/test_mcp_server.py +216 -0
- codeforerunner-0.3.0/tests/test_providers.py +146 -0
- codeforerunner-0.3.0/tests/test_validate_codex_marketplace.py +105 -0
- codeforerunner-0.3.0/tests/test_workflows_yaml.py +99 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
Codeforerunner Source-Available License v0.1
|
|
2
|
+
===========================================
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2026 Derek Palmer
|
|
5
|
+
|
|
6
|
+
1. Grant of rights
|
|
7
|
+
|
|
8
|
+
Subject to the terms of this license, you are permitted to:
|
|
9
|
+
|
|
10
|
+
1.1 Use this software for personal, educational, and commercial purposes.
|
|
11
|
+
|
|
12
|
+
1.2 Modify this software for your own internal use, including within your
|
|
13
|
+
personal projects, your employer's internal systems, or client work,
|
|
14
|
+
provided that the modified software is not itself sold, licensed,
|
|
15
|
+
hosted as a commercial offering, or otherwise offered as a product or
|
|
16
|
+
service to third parties.
|
|
17
|
+
|
|
18
|
+
1.3 Redistribute unmodified copies of this software, provided that you
|
|
19
|
+
include this license and all copyright notices.
|
|
20
|
+
|
|
21
|
+
2. Restrictions
|
|
22
|
+
|
|
23
|
+
You may NOT, under any circumstance:
|
|
24
|
+
|
|
25
|
+
2.1 Sell, license, sublicense, host, distribute for a fee, or otherwise
|
|
26
|
+
offer this software, or any modified version of it, as a standalone
|
|
27
|
+
product, hosted product, or primary service offering.
|
|
28
|
+
|
|
29
|
+
2.2 Modify, adapt, extend, or integrate this software into another
|
|
30
|
+
product or service and then sell, license, sublicense, host, or
|
|
31
|
+
otherwise commercially offer that product or service where this
|
|
32
|
+
software or any derivative of it provides material functionality.
|
|
33
|
+
|
|
34
|
+
2.3 Rebrand this software, or any modified version of it, as your own
|
|
35
|
+
competing product, or present it in a way that suggests it is your
|
|
36
|
+
original creation.
|
|
37
|
+
|
|
38
|
+
2.4 Remove or alter any attribution, copyright, or license notices
|
|
39
|
+
included with the software, except as necessary to add your own,
|
|
40
|
+
clearly subordinate notices for internal tracking.
|
|
41
|
+
|
|
42
|
+
3. No trademark license
|
|
43
|
+
|
|
44
|
+
The names "codeforerunner", "forerunner", and any associated project
|
|
45
|
+
logos or branding are not licensed for use as your own product or
|
|
46
|
+
service names. You may refer to the software by its name in truthful
|
|
47
|
+
descriptions, such as "powered by codeforerunner", but you may not use
|
|
48
|
+
these names or logos in a way that suggests official endorsement or
|
|
49
|
+
affiliation without prior written permission from the copyright holder.
|
|
50
|
+
|
|
51
|
+
4. No warranty
|
|
52
|
+
|
|
53
|
+
THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
54
|
+
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
55
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
56
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
57
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
58
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
59
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
60
|
+
|
|
61
|
+
5. Termination
|
|
62
|
+
|
|
63
|
+
Any violation of this license automatically terminates your rights under
|
|
64
|
+
it. Upon termination, you must stop using and distributing the software
|
|
65
|
+
and any derivative works, except where otherwise allowed by applicable
|
|
66
|
+
law.
|
|
67
|
+
|
|
68
|
+
6. Miscellaneous
|
|
69
|
+
|
|
70
|
+
If any provision of this license is held to be unenforceable, the
|
|
71
|
+
remaining provisions will remain in full force and effect.
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: codeforerunner
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Model-agnostic repository documentation tooling (prompt-first; thin CLI).
|
|
5
|
+
Author: Derek Palmer
|
|
6
|
+
License-Expression: LicenseRef-Codeforerunner-SAL-0.1
|
|
7
|
+
Project-URL: Repository, https://github.com/derek-palmer/codeforerunner
|
|
8
|
+
Project-URL: Issues, https://github.com/derek-palmer/codeforerunner/issues
|
|
9
|
+
Requires-Python: >=3.11
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE.md
|
|
12
|
+
Requires-Dist: PyYAML>=6.0
|
|
13
|
+
Dynamic: license-file
|
|
14
|
+
|
|
15
|
+

|
|
16
|
+
|
|
17
|
+
# codeForerunner
|
|
18
|
+
|
|
19
|
+
CodeForerunner is a model-agnostic documentation agent that acts as overwatch for your repository, automatically analyzing code and maintaining docs, diagrams, and architecture knowledge as your codebase evolves over time.
|
|
20
|
+
|
|
21
|
+
The current repo is the prompt-first foundation for that agent: it ships prompt assets for understanding a codebase and generating developer docs. A thin Python CLI (including `forerunner mcp-server` and a scoped `forerunner init --full / --agents-only`), an idempotent skill installer, pre-commit + CI hooks, and a PyPI publish workflow now wrap those prompts; the first published PyPI release remains pending.
|
|
22
|
+
|
|
23
|
+
## Current State
|
|
24
|
+
|
|
25
|
+
- Core product: Markdown prompts in `prompts/`.
|
|
26
|
+
- Agent package artifacts: Codex plugin files under `plugins/codeforerunner/` and Claude Code plugin files under `.claude-plugin/` plus `skills/codeforerunner/`.
|
|
27
|
+
- Python package: `pyproject.toml` + `src/codeforerunner/` expose a `forerunner` console script. `forerunner doc <task>` resolves the prompt bundle (base + partials + task) to stdout; `forerunner install <agent>` idempotently writes the canonical skill into agent-specific directories; `forerunner init` resolves the agent-onboarding bundle (with `--full` to prepend a scan or `--agents-only` for the default scope); `forerunner scan` resolves the scan bundle; `forerunner mcp-server` serves prompt bundles as MCP tools over stdio.
|
|
28
|
+
- Hooks: `.pre-commit-hooks.yaml` exposes a `forerunner-check` hook; `.github/workflows/forerunner-check.yml` mirrors it in CI. Both no-op when `forerunner.config.yaml` is absent.
|
|
29
|
+
- Current config: `forerunner.config.yaml.example` documents the schema now parsed by `src/codeforerunner/config.py`; see "Configuration" below.
|
|
30
|
+
- Not currently present: Docker image, Makefile, published PyPI release.
|
|
31
|
+
|
|
32
|
+
## Install
|
|
33
|
+
|
|
34
|
+
After the first PyPI release:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pipx install codeforerunner # recommended; isolated environment
|
|
38
|
+
pip install codeforerunner # alternative
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
From source:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
git clone https://github.com/derek-palmer/codeForerunner
|
|
45
|
+
cd codeForerunner
|
|
46
|
+
python -m pip install -e .
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Then `forerunner --help` should print the subcommand list.
|
|
50
|
+
|
|
51
|
+
## Prompt Layout
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
prompts/
|
|
55
|
+
├── system/
|
|
56
|
+
│ └── base.md
|
|
57
|
+
├── partials/
|
|
58
|
+
│ ├── context-format.md
|
|
59
|
+
│ ├── output-rules.md
|
|
60
|
+
│ └── stack-hints.md
|
|
61
|
+
└── tasks/
|
|
62
|
+
├── scan.md
|
|
63
|
+
├── init-agent-onboarding.md
|
|
64
|
+
├── readme.md
|
|
65
|
+
├── api-docs.md
|
|
66
|
+
├── stack-docs.md
|
|
67
|
+
├── diagrams.md
|
|
68
|
+
├── flows.md
|
|
69
|
+
├── version-audit.md
|
|
70
|
+
├── check.md
|
|
71
|
+
└── review.md
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Quick Start
|
|
75
|
+
|
|
76
|
+
1. Open `prompts/system/base.md` and use it as the agent system or project instruction.
|
|
77
|
+
2. Assemble repo context using the shape in `prompts/partials/context-format.md`.
|
|
78
|
+
3. For documentation generation, run `prompts/tasks/scan.md` first.
|
|
79
|
+
4. For agent onboarding only, run `prompts/tasks/init-agent-onboarding.md` directly.
|
|
80
|
+
5. Pass the scan result into one downstream documentation prompt, such as `prompts/tasks/readme.md` or `prompts/tasks/stack-docs.md`.
|
|
81
|
+
6. Apply generated docs only after checking that every claim is grounded in provided files.
|
|
82
|
+
|
|
83
|
+
## What The Prompts Do
|
|
84
|
+
|
|
85
|
+
| Prompt | Purpose |
|
|
86
|
+
| --- | --- |
|
|
87
|
+
| `prompts/system/base.md` | Defines the codeforerunner role, quality bar, Markdown rules, and accuracy constraints. |
|
|
88
|
+
| `prompts/tasks/scan.md` | Produces the first structured repo scan used by downstream tasks. |
|
|
89
|
+
| `prompts/tasks/init-agent-onboarding.md` | Generates or updates `AGENTS.md` from repo evidence plus files such as `CLAUDE.md`, `.cursor/rules/*`, `.cursorrules`, `.github/copilot-instructions.md`, and `opencode.json`. |
|
|
90
|
+
| `prompts/tasks/readme.md` | Generates or rewrites a top-level README from scan output and selected files. |
|
|
91
|
+
| `prompts/tasks/api-docs.md` | Documents public APIs when endpoints/interfaces are evident. |
|
|
92
|
+
| `prompts/tasks/stack-docs.md` | Documents stack-specific areas of a repo. |
|
|
93
|
+
| `prompts/tasks/diagrams.md` | Generates Mermaid architecture or flow diagrams. |
|
|
94
|
+
| `prompts/tasks/flows.md` | Documents user, request, job, or data flows. |
|
|
95
|
+
| `prompts/tasks/version-audit.md` | Audits pinned versions from manifests, lockfiles, Dockerfiles, workflows, or IaC. |
|
|
96
|
+
| `prompts/tasks/check.md` | Checks existing docs for staleness against a fresh scan. |
|
|
97
|
+
| `prompts/tasks/review.md` | Summarizes documentation impact for review. |
|
|
98
|
+
|
|
99
|
+
## Docs And Spec
|
|
100
|
+
|
|
101
|
+
- `SPEC.md` tracks phases, invariants, and tasks so future PRs can make small status updates instead of broad rewrites.
|
|
102
|
+
- `docs/getting-started.md` explains manual prompt use.
|
|
103
|
+
- `docs/prompt-guide.md` explains how system, partial, and task prompts compose.
|
|
104
|
+
- `docs/editor-agent-setup.md` explains how to adapt prompts to local agents.
|
|
105
|
+
- `docs/roadmap.md` mirrors the `SPEC.md` phase status in human-readable form.
|
|
106
|
+
- `docs/agent-distribution-design.md` records the design that backs the Codex/Claude packages and `forerunner install`.
|
|
107
|
+
|
|
108
|
+
## Configuration
|
|
109
|
+
|
|
110
|
+
`forerunner.config.yaml.example` documents the loaded schema. Copy it to `forerunner.config.yaml` to opt in; without that file, `forerunner check` is a silent no-op. The schema has top-level provider/model fields (`provider`, `model`, `api_key_env`, `output_dir`, `context_max_files`, `context_max_lines_per_file`, `approaching_eol_threshold_months`), `ignore_patterns`, `tasks.version_audit`, and `tasks.check`. `forerunner check` honors `tasks.check.enabled_rules` (allowlist of rule IDs, default all) and `tasks.check.ignore_paths` (fnmatch globs applied to scanned docs). Invalid YAML, unknown providers, unknown `api_key_env` providers, or unknown severities surface as a `ConfigError` and exit non-zero.
|
|
111
|
+
|
|
112
|
+
### MCP Server
|
|
113
|
+
|
|
114
|
+
`forerunner mcp-server` speaks JSON-RPC 2.0 over stdio and exposes one tool per `prompts/tasks/*.md` (tool name = filename stem). Each `tools/call` returns the resolved `base + partials + task` bundle as text. A scan-first gate enforces SPEC V2: any tool other than `scan` or `init-agent-onboarding` returns an error until `scan` has been called in the same session. Point any MCP-compatible client at `forerunner mcp-server` as a stdio server (running from the target repo so `prompts/tasks/` resolves).
|
|
115
|
+
|
|
116
|
+
See `examples/mcp/` for Claude Desktop and mcp-cli wiring examples.
|
|
117
|
+
|
|
118
|
+
## Roadmap
|
|
119
|
+
|
|
120
|
+
See `SPEC.md` for the canonical phase/task tracker and `docs/roadmap.md` for the human-readable roadmap.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
# codeForerunner
|
|
4
|
+
|
|
5
|
+
CodeForerunner is a model-agnostic documentation agent that acts as overwatch for your repository, automatically analyzing code and maintaining docs, diagrams, and architecture knowledge as your codebase evolves over time.
|
|
6
|
+
|
|
7
|
+
The current repo is the prompt-first foundation for that agent: it ships prompt assets for understanding a codebase and generating developer docs. A thin Python CLI (including `forerunner mcp-server` and a scoped `forerunner init --full / --agents-only`), an idempotent skill installer, pre-commit + CI hooks, and a PyPI publish workflow now wrap those prompts; the first published PyPI release remains pending.
|
|
8
|
+
|
|
9
|
+
## Current State
|
|
10
|
+
|
|
11
|
+
- Core product: Markdown prompts in `prompts/`.
|
|
12
|
+
- Agent package artifacts: Codex plugin files under `plugins/codeforerunner/` and Claude Code plugin files under `.claude-plugin/` plus `skills/codeforerunner/`.
|
|
13
|
+
- Python package: `pyproject.toml` + `src/codeforerunner/` expose a `forerunner` console script. `forerunner doc <task>` resolves the prompt bundle (base + partials + task) to stdout; `forerunner install <agent>` idempotently writes the canonical skill into agent-specific directories; `forerunner init` resolves the agent-onboarding bundle (with `--full` to prepend a scan or `--agents-only` for the default scope); `forerunner scan` resolves the scan bundle; `forerunner mcp-server` serves prompt bundles as MCP tools over stdio.
|
|
14
|
+
- Hooks: `.pre-commit-hooks.yaml` exposes a `forerunner-check` hook; `.github/workflows/forerunner-check.yml` mirrors it in CI. Both no-op when `forerunner.config.yaml` is absent.
|
|
15
|
+
- Current config: `forerunner.config.yaml.example` documents the schema now parsed by `src/codeforerunner/config.py`; see "Configuration" below.
|
|
16
|
+
- Not currently present: Docker image, Makefile, published PyPI release.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
After the first PyPI release:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pipx install codeforerunner # recommended; isolated environment
|
|
24
|
+
pip install codeforerunner # alternative
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
From source:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
git clone https://github.com/derek-palmer/codeForerunner
|
|
31
|
+
cd codeForerunner
|
|
32
|
+
python -m pip install -e .
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Then `forerunner --help` should print the subcommand list.
|
|
36
|
+
|
|
37
|
+
## Prompt Layout
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
prompts/
|
|
41
|
+
├── system/
|
|
42
|
+
│ └── base.md
|
|
43
|
+
├── partials/
|
|
44
|
+
│ ├── context-format.md
|
|
45
|
+
│ ├── output-rules.md
|
|
46
|
+
│ └── stack-hints.md
|
|
47
|
+
└── tasks/
|
|
48
|
+
├── scan.md
|
|
49
|
+
├── init-agent-onboarding.md
|
|
50
|
+
├── readme.md
|
|
51
|
+
├── api-docs.md
|
|
52
|
+
├── stack-docs.md
|
|
53
|
+
├── diagrams.md
|
|
54
|
+
├── flows.md
|
|
55
|
+
├── version-audit.md
|
|
56
|
+
├── check.md
|
|
57
|
+
└── review.md
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Quick Start
|
|
61
|
+
|
|
62
|
+
1. Open `prompts/system/base.md` and use it as the agent system or project instruction.
|
|
63
|
+
2. Assemble repo context using the shape in `prompts/partials/context-format.md`.
|
|
64
|
+
3. For documentation generation, run `prompts/tasks/scan.md` first.
|
|
65
|
+
4. For agent onboarding only, run `prompts/tasks/init-agent-onboarding.md` directly.
|
|
66
|
+
5. Pass the scan result into one downstream documentation prompt, such as `prompts/tasks/readme.md` or `prompts/tasks/stack-docs.md`.
|
|
67
|
+
6. Apply generated docs only after checking that every claim is grounded in provided files.
|
|
68
|
+
|
|
69
|
+
## What The Prompts Do
|
|
70
|
+
|
|
71
|
+
| Prompt | Purpose |
|
|
72
|
+
| --- | --- |
|
|
73
|
+
| `prompts/system/base.md` | Defines the codeforerunner role, quality bar, Markdown rules, and accuracy constraints. |
|
|
74
|
+
| `prompts/tasks/scan.md` | Produces the first structured repo scan used by downstream tasks. |
|
|
75
|
+
| `prompts/tasks/init-agent-onboarding.md` | Generates or updates `AGENTS.md` from repo evidence plus files such as `CLAUDE.md`, `.cursor/rules/*`, `.cursorrules`, `.github/copilot-instructions.md`, and `opencode.json`. |
|
|
76
|
+
| `prompts/tasks/readme.md` | Generates or rewrites a top-level README from scan output and selected files. |
|
|
77
|
+
| `prompts/tasks/api-docs.md` | Documents public APIs when endpoints/interfaces are evident. |
|
|
78
|
+
| `prompts/tasks/stack-docs.md` | Documents stack-specific areas of a repo. |
|
|
79
|
+
| `prompts/tasks/diagrams.md` | Generates Mermaid architecture or flow diagrams. |
|
|
80
|
+
| `prompts/tasks/flows.md` | Documents user, request, job, or data flows. |
|
|
81
|
+
| `prompts/tasks/version-audit.md` | Audits pinned versions from manifests, lockfiles, Dockerfiles, workflows, or IaC. |
|
|
82
|
+
| `prompts/tasks/check.md` | Checks existing docs for staleness against a fresh scan. |
|
|
83
|
+
| `prompts/tasks/review.md` | Summarizes documentation impact for review. |
|
|
84
|
+
|
|
85
|
+
## Docs And Spec
|
|
86
|
+
|
|
87
|
+
- `SPEC.md` tracks phases, invariants, and tasks so future PRs can make small status updates instead of broad rewrites.
|
|
88
|
+
- `docs/getting-started.md` explains manual prompt use.
|
|
89
|
+
- `docs/prompt-guide.md` explains how system, partial, and task prompts compose.
|
|
90
|
+
- `docs/editor-agent-setup.md` explains how to adapt prompts to local agents.
|
|
91
|
+
- `docs/roadmap.md` mirrors the `SPEC.md` phase status in human-readable form.
|
|
92
|
+
- `docs/agent-distribution-design.md` records the design that backs the Codex/Claude packages and `forerunner install`.
|
|
93
|
+
|
|
94
|
+
## Configuration
|
|
95
|
+
|
|
96
|
+
`forerunner.config.yaml.example` documents the loaded schema. Copy it to `forerunner.config.yaml` to opt in; without that file, `forerunner check` is a silent no-op. The schema has top-level provider/model fields (`provider`, `model`, `api_key_env`, `output_dir`, `context_max_files`, `context_max_lines_per_file`, `approaching_eol_threshold_months`), `ignore_patterns`, `tasks.version_audit`, and `tasks.check`. `forerunner check` honors `tasks.check.enabled_rules` (allowlist of rule IDs, default all) and `tasks.check.ignore_paths` (fnmatch globs applied to scanned docs). Invalid YAML, unknown providers, unknown `api_key_env` providers, or unknown severities surface as a `ConfigError` and exit non-zero.
|
|
97
|
+
|
|
98
|
+
### MCP Server
|
|
99
|
+
|
|
100
|
+
`forerunner mcp-server` speaks JSON-RPC 2.0 over stdio and exposes one tool per `prompts/tasks/*.md` (tool name = filename stem). Each `tools/call` returns the resolved `base + partials + task` bundle as text. A scan-first gate enforces SPEC V2: any tool other than `scan` or `init-agent-onboarding` returns an error until `scan` has been called in the same session. Point any MCP-compatible client at `forerunner mcp-server` as a stdio server (running from the target repo so `prompts/tasks/` resolves).
|
|
101
|
+
|
|
102
|
+
See `examples/mcp/` for Claude Desktop and mcp-cli wiring examples.
|
|
103
|
+
|
|
104
|
+
## Roadmap
|
|
105
|
+
|
|
106
|
+
See `SPEC.md` for the canonical phase/task tracker and `docs/roadmap.md` for the human-readable roadmap.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "codeforerunner"
|
|
7
|
+
version = "0.3.0"
|
|
8
|
+
description = "Model-agnostic repository documentation tooling (prompt-first; thin CLI)."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
license = "LicenseRef-Codeforerunner-SAL-0.1"
|
|
12
|
+
license-files = ["LICENSE.md"]
|
|
13
|
+
authors = [{ name = "Derek Palmer" }]
|
|
14
|
+
dependencies = [
|
|
15
|
+
"PyYAML>=6.0",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
[project.urls]
|
|
19
|
+
Repository = "https://github.com/derek-palmer/codeforerunner"
|
|
20
|
+
Issues = "https://github.com/derek-palmer/codeforerunner/issues"
|
|
21
|
+
|
|
22
|
+
[project.scripts]
|
|
23
|
+
forerunner = "codeforerunner.cli:main"
|
|
24
|
+
|
|
25
|
+
[tool.setuptools.packages.find]
|
|
26
|
+
where = ["src"]
|
|
27
|
+
|
|
28
|
+
[tool.setuptools.package-data]
|
|
29
|
+
codeforerunner = ["py.typed"]
|
|
30
|
+
|
|
31
|
+
[tool.pytest.ini_options]
|
|
32
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.2.0"
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"""Drift detection for docs that claim files don't exist when they do."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import fnmatch
|
|
5
|
+
import re
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from codeforerunner.config import CheckConfig
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass(frozen=True)
|
|
13
|
+
class Violation:
|
|
14
|
+
path: Path
|
|
15
|
+
line: int
|
|
16
|
+
rule_id: str
|
|
17
|
+
message: str
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
_RULES = [
|
|
21
|
+
(
|
|
22
|
+
"R1-no-cli",
|
|
23
|
+
re.compile(
|
|
24
|
+
r"(?i)no\s+CLI\s+exists"
|
|
25
|
+
r"|CLI\s+does\s+not\s+exist"
|
|
26
|
+
r"|not\s+currently\s+present:[^.]*\bCLI\b"
|
|
27
|
+
r"|Do\s+not\s+run\s+`forerunner`"
|
|
28
|
+
),
|
|
29
|
+
("src/codeforerunner/cli.py",),
|
|
30
|
+
"doc claims no CLI exists, but src/codeforerunner/cli.py is present",
|
|
31
|
+
),
|
|
32
|
+
(
|
|
33
|
+
"R2-no-pre-commit",
|
|
34
|
+
re.compile(r"(?i)no\s+pre[- ]commit(\s+hook)?"),
|
|
35
|
+
(".pre-commit-hooks.yaml",),
|
|
36
|
+
"doc claims no pre-commit hook, but .pre-commit-hooks.yaml is present",
|
|
37
|
+
),
|
|
38
|
+
(
|
|
39
|
+
"R3-no-ci",
|
|
40
|
+
re.compile(r"(?i)no\s+CI(\s+workflow)?"),
|
|
41
|
+
(".github/workflows/*.yml",),
|
|
42
|
+
"doc claims no CI workflow, but .github/workflows/*.yml is present",
|
|
43
|
+
),
|
|
44
|
+
(
|
|
45
|
+
"R4-no-installer",
|
|
46
|
+
re.compile(r"(?i)no\s+installer"),
|
|
47
|
+
("src/codeforerunner/installer.py",),
|
|
48
|
+
"doc claims no installer, but src/codeforerunner/installer.py is present",
|
|
49
|
+
),
|
|
50
|
+
(
|
|
51
|
+
"R5-no-python-package",
|
|
52
|
+
re.compile(r"(?i)no\s+Python\s+package"),
|
|
53
|
+
("pyproject.toml",),
|
|
54
|
+
"doc claims no Python package, but pyproject.toml is present",
|
|
55
|
+
),
|
|
56
|
+
(
|
|
57
|
+
"R6-no-docker",
|
|
58
|
+
re.compile(r"(?i)no\s+Docker(\s+image)?|no\s+Dockerfile"),
|
|
59
|
+
("Dockerfile", "compose.yml", "docker-compose.yml"),
|
|
60
|
+
"doc claims no Docker, but Dockerfile/compose file is present",
|
|
61
|
+
),
|
|
62
|
+
(
|
|
63
|
+
"R6b-no-makefile",
|
|
64
|
+
re.compile(r"(?i)no\s+Makefile"),
|
|
65
|
+
("Makefile",),
|
|
66
|
+
"doc claims no Makefile, but Makefile is present",
|
|
67
|
+
),
|
|
68
|
+
(
|
|
69
|
+
"R7-no-mcp",
|
|
70
|
+
re.compile(r"(?i)no\s+MCP(\s+server)?"),
|
|
71
|
+
("src/codeforerunner/mcp_server.py",),
|
|
72
|
+
"doc claims no MCP server, but src/codeforerunner/mcp_server.py is present",
|
|
73
|
+
),
|
|
74
|
+
(
|
|
75
|
+
"R8-no-marketplace",
|
|
76
|
+
re.compile(r"(?i)no\s+marketplace(\s+manifest)?"),
|
|
77
|
+
("plugins/codex/marketplace.json",),
|
|
78
|
+
"doc claims no marketplace, but plugins/codex/marketplace.json is present",
|
|
79
|
+
),
|
|
80
|
+
]
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _trigger_exists(repo: Path, patterns: tuple[str, ...]) -> bool:
|
|
84
|
+
for pat in patterns:
|
|
85
|
+
if "*" in pat:
|
|
86
|
+
parent = repo / Path(pat).parent
|
|
87
|
+
name = Path(pat).name
|
|
88
|
+
if parent.is_dir() and any(parent.glob(name)):
|
|
89
|
+
return True
|
|
90
|
+
else:
|
|
91
|
+
if (repo / pat).exists():
|
|
92
|
+
return True
|
|
93
|
+
return False
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _scanned_docs(repo: Path) -> list[Path]:
|
|
97
|
+
docs: list[Path] = []
|
|
98
|
+
readme = repo / "README.md"
|
|
99
|
+
if readme.is_file():
|
|
100
|
+
docs.append(readme)
|
|
101
|
+
docs_dir = repo / "docs"
|
|
102
|
+
if docs_dir.is_dir():
|
|
103
|
+
docs.extend(sorted(p for p in docs_dir.rglob("*.md") if p.is_file()))
|
|
104
|
+
return docs
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _path_ignored(repo: Path, doc: Path, ignore_patterns: tuple[str, ...]) -> bool:
|
|
108
|
+
if not ignore_patterns:
|
|
109
|
+
return False
|
|
110
|
+
try:
|
|
111
|
+
rel = doc.relative_to(repo).as_posix()
|
|
112
|
+
except ValueError:
|
|
113
|
+
rel = doc.as_posix()
|
|
114
|
+
return any(fnmatch.fnmatch(rel, pat) for pat in ignore_patterns)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def run(repo: Path, config: CheckConfig | None = None) -> list[Violation]:
|
|
118
|
+
"""Scan repo docs for drift; return list of violations.
|
|
119
|
+
|
|
120
|
+
`config` filters rules via `enabled_rules` and skips docs matching `ignore_paths`.
|
|
121
|
+
`None` config (default) preserves the pre-T25 behavior: all rules, no ignores.
|
|
122
|
+
"""
|
|
123
|
+
repo = Path(repo)
|
|
124
|
+
enabled = set(config.enabled_rules) if (config and config.enabled_rules is not None) else None
|
|
125
|
+
ignore_patterns = config.ignore_paths if config else ()
|
|
126
|
+
|
|
127
|
+
active_rules = [
|
|
128
|
+
(rid, rx, msg)
|
|
129
|
+
for rid, rx, triggers, msg in _RULES
|
|
130
|
+
if _trigger_exists(repo, triggers) and (enabled is None or rid in enabled)
|
|
131
|
+
]
|
|
132
|
+
if not active_rules:
|
|
133
|
+
return []
|
|
134
|
+
|
|
135
|
+
violations: list[Violation] = []
|
|
136
|
+
for doc in _scanned_docs(repo):
|
|
137
|
+
if _path_ignored(repo, doc, ignore_patterns):
|
|
138
|
+
continue
|
|
139
|
+
try:
|
|
140
|
+
text = doc.read_text(encoding="utf-8")
|
|
141
|
+
except (OSError, UnicodeDecodeError):
|
|
142
|
+
continue
|
|
143
|
+
for lineno, line in enumerate(text.splitlines(), start=1):
|
|
144
|
+
for rid, rx, msg in active_rules:
|
|
145
|
+
if rx.search(line):
|
|
146
|
+
violations.append(
|
|
147
|
+
Violation(path=doc, line=lineno, rule_id=rid, message=msg)
|
|
148
|
+
)
|
|
149
|
+
return violations
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def format_violations(vs: list[Violation]) -> str:
|
|
153
|
+
"""Format violations one per line for stderr."""
|
|
154
|
+
return "\n".join(
|
|
155
|
+
f"{v.path}:{v.line}: {v.rule_id}: {v.message}" for v in vs
|
|
156
|
+
)
|