agentsbridge 0.1.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.
- agentsbridge-0.1.0/LICENSE +21 -0
- agentsbridge-0.1.0/PKG-INFO +194 -0
- agentsbridge-0.1.0/README.md +166 -0
- agentsbridge-0.1.0/agentsbridge/__init__.py +3 -0
- agentsbridge-0.1.0/agentsbridge/cli.py +174 -0
- agentsbridge-0.1.0/agentsbridge/core.py +204 -0
- agentsbridge-0.1.0/agentsbridge/targets.py +117 -0
- agentsbridge-0.1.0/agentsbridge.egg-info/PKG-INFO +194 -0
- agentsbridge-0.1.0/agentsbridge.egg-info/SOURCES.txt +14 -0
- agentsbridge-0.1.0/agentsbridge.egg-info/dependency_links.txt +1 -0
- agentsbridge-0.1.0/agentsbridge.egg-info/entry_points.txt +2 -0
- agentsbridge-0.1.0/agentsbridge.egg-info/top_level.txt +1 -0
- agentsbridge-0.1.0/pyproject.toml +45 -0
- agentsbridge-0.1.0/setup.cfg +4 -0
- agentsbridge-0.1.0/tests/test_cli.py +78 -0
- agentsbridge-0.1.0/tests/test_core.py +184 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 agentsbridge contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agentsbridge
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Bridge AGENTS.md to every AI coding tool's rules file - one source of truth for Claude Code, Copilot, Cursor, Windsurf, Cline, and Aider.
|
|
5
|
+
Author: agentsbridge contributors
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/DavidStarYu/agentsbridge
|
|
8
|
+
Project-URL: Repository, https://github.com/DavidStarYu/agentsbridge
|
|
9
|
+
Project-URL: Changelog, https://github.com/DavidStarYu/agentsbridge/blob/main/CHANGELOG.md
|
|
10
|
+
Keywords: agents-md,claude,claude-code,cursor,copilot,windsurf,cline,aider,ai,rules,cli,developer-tools
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Software Development
|
|
23
|
+
Classifier: Topic :: Utilities
|
|
24
|
+
Requires-Python: >=3.9
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Dynamic: license-file
|
|
28
|
+
|
|
29
|
+
<div align="center">
|
|
30
|
+
|
|
31
|
+
<img src="assets/banner.svg" alt="agentsbridge" width="640">
|
|
32
|
+
|
|
33
|
+
**One `AGENTS.md`. Every AI coding tool. Zero drift.**
|
|
34
|
+
|
|
35
|
+
[](https://github.com/DavidStarYu/agentsbridge/actions/workflows/ci.yml)
|
|
36
|
+
[](https://pypi.org/project/agentsbridge/)
|
|
37
|
+
[](https://pypi.org/project/agentsbridge/)
|
|
38
|
+
[](LICENSE)
|
|
39
|
+
[](https://github.com/astral-sh/ruff)
|
|
40
|
+
|
|
41
|
+
[Bridge](#why) · [Quick start](#quick-start) · [Supported tools](#supported-tools) · [CI drift check](#ci-drift-check) · [FAQ](#faq)
|
|
42
|
+
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Why
|
|
48
|
+
|
|
49
|
+
Your team uses Claude Code. Your teammate uses Cursor. Someone just switched
|
|
50
|
+
to Codex CLI. And suddenly your coding standards live in **five different
|
|
51
|
+
files** that silently drift apart:
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
AGENTS.md ← Codex, Gemini CLI, Jules, Amp, Zed read this
|
|
55
|
+
CLAUDE.md ← Claude Code reads this (not AGENTS.md)
|
|
56
|
+
.github/copilot-instructions.md ← GitHub Copilot reads this (not AGENTS.md)
|
|
57
|
+
.cursor/rules/*.mdc ← Cursor reads this (not AGENTS.md, older versions)
|
|
58
|
+
.windsurfrules / .clinerules ← Windsurf / Cline read these
|
|
59
|
+
CONVENTIONS.md ← Aider reads this
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
`agentsbridge` fixes this with one command. You maintain **one** `AGENTS.md`
|
|
63
|
+
(the emerging industry standard) — it generates and keeps every tool's file
|
|
64
|
+
in sync. Edit once, sync everywhere, and let CI catch anything that drifts.
|
|
65
|
+
|
|
66
|
+
## Quick start
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
pipx install agentsbridge # or: pip install agentsbridge / uv tool install agentsbridge
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Already have rules somewhere?** Import them:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
agentsbridge import # seeds AGENTS.md from CLAUDE.md, .cursorrules, etc.
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Starting fresh?**
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
agentsbridge init # creates a starter AGENTS.md
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Then — the only command you'll ever need again:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
agentsbridge sync
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
```text
|
|
91
|
+
+ created CLAUDE.md
|
|
92
|
+
+ created .github/copilot-instructions.md
|
|
93
|
+
+ created .cursor/rules/agentsbridge.mdc
|
|
94
|
+
+ created .windsurfrules
|
|
95
|
+
+ created .clinerules
|
|
96
|
+
+ created CONVENTIONS.md
|
|
97
|
+
|
|
98
|
+
wrote 6 file(s)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Edit `AGENTS.md`, run `agentsbridge sync`, commit. That's the whole workflow.
|
|
102
|
+
|
|
103
|
+
## Supported tools
|
|
104
|
+
|
|
105
|
+
| Tool | File generated | Notes |
|
|
106
|
+
|---|---|---|
|
|
107
|
+
| **Claude Code** | `CLAUDE.md` | |
|
|
108
|
+
| **GitHub Copilot** | `.github/copilot-instructions.md` | |
|
|
109
|
+
| **Cursor** | `.cursor/rules/agentsbridge.mdc` | with `alwaysApply` frontmatter |
|
|
110
|
+
| **Windsurf** | `.windsurfrules` | |
|
|
111
|
+
| **Cline** | `.clinerules` | |
|
|
112
|
+
| **Aider** | `CONVENTIONS.md` | |
|
|
113
|
+
| **Codex CLI, Gemini CLI, Jules, Amp, Zed, opencode** | — | read `AGENTS.md` natively, nothing to generate |
|
|
114
|
+
|
|
115
|
+
Missing a tool? [Open an issue](https://github.com/DavidStarYu/agentsbridge/issues) —
|
|
116
|
+
adding a target is ~10 lines.
|
|
117
|
+
|
|
118
|
+
## Safety
|
|
119
|
+
|
|
120
|
+
Generated files are marked:
|
|
121
|
+
|
|
122
|
+
```markdown
|
|
123
|
+
<!-- generated by agentsbridge; do not edit -->
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
If a target file already exists **without** that marker (i.e. you wrote it by
|
|
127
|
+
hand), `sync` skips it instead of clobbering your work. Use `--force` to
|
|
128
|
+
adopt it deliberately.
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
agentsbridge sync --force # adopt existing files
|
|
132
|
+
agentsbridge sync --dry-run # preview changes
|
|
133
|
+
agentsbridge sync -t claude,copilot # subset of targets
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## CI drift check
|
|
137
|
+
|
|
138
|
+
The whole point: rules that drift are rules nobody follows. Add the check to
|
|
139
|
+
your workflow and CI fails whenever someone edits a generated file — or
|
|
140
|
+
forgets to re-sync after editing `AGENTS.md`:
|
|
141
|
+
|
|
142
|
+
```yaml
|
|
143
|
+
# .github/workflows/ci.yml
|
|
144
|
+
name: rules
|
|
145
|
+
on: [push, pull_request]
|
|
146
|
+
jobs:
|
|
147
|
+
agentsbridge:
|
|
148
|
+
runs-on: ubuntu-latest
|
|
149
|
+
steps:
|
|
150
|
+
- uses: actions/checkout@v4
|
|
151
|
+
- uses: DavidStarYu/agentsbridge/action@main
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Or invoke the CLI directly: `agentsbridge check` (exit code 1 on drift).
|
|
155
|
+
|
|
156
|
+
This repository runs the same check on itself — [dogfooding](.github/workflows/rules.yml).
|
|
157
|
+
|
|
158
|
+
## FAQ
|
|
159
|
+
|
|
160
|
+
**Why AGENTS.md as the source, not my own config?**
|
|
161
|
+
AGENTS.md is the emerging standard (adopted by OpenAI Codex, Gemini CLI, Jules,
|
|
162
|
+
Amp, Zed and others — see [agents.md](https://agents.md)). Tools that don't
|
|
163
|
+
read it yet are exactly the ones this bridge targets. You keep zero
|
|
164
|
+
agentsbridge-specific config: the source file is a standard.
|
|
165
|
+
|
|
166
|
+
**Cursor already reads AGENTS.md, why generate an .mdc?**
|
|
167
|
+
Newer Cursor versions read `AGENTS.md` directly; many teams run versions that
|
|
168
|
+
don't, or want explicit rule scoping. The generated `.mdc` is harmless if
|
|
169
|
+
redundant — and you can exclude it: `agentsbridge sync -t claude,copilot,...`.
|
|
170
|
+
|
|
171
|
+
**Does it send my code anywhere?**
|
|
172
|
+
No. No network calls, no telemetry, no API keys. It's a template engine over
|
|
173
|
+
one markdown file. [Zero dependencies](pyproject.toml).
|
|
174
|
+
|
|
175
|
+
**How is this different from X?**
|
|
176
|
+
rulesync (Node.js) covers more features — MCP servers, subagents, commands —
|
|
177
|
+
at the cost of a bigger footprint and a `.rulesync/` directory convention.
|
|
178
|
+
agentsbridge does one thing: keep rule *files* in sync, in pure Python with
|
|
179
|
+
zero dependencies. If you live in `pipx`/`uv` and want the simple thing, this
|
|
180
|
+
is for you.
|
|
181
|
+
|
|
182
|
+
## Development
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
git clone https://github.com/DavidStarYu/agentsbridge
|
|
186
|
+
cd agentsbridge
|
|
187
|
+
pip install -e . pytest ruff
|
|
188
|
+
pytest # 36 tests
|
|
189
|
+
ruff check .
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## License
|
|
193
|
+
|
|
194
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<img src="assets/banner.svg" alt="agentsbridge" width="640">
|
|
4
|
+
|
|
5
|
+
**One `AGENTS.md`. Every AI coding tool. Zero drift.**
|
|
6
|
+
|
|
7
|
+
[](https://github.com/DavidStarYu/agentsbridge/actions/workflows/ci.yml)
|
|
8
|
+
[](https://pypi.org/project/agentsbridge/)
|
|
9
|
+
[](https://pypi.org/project/agentsbridge/)
|
|
10
|
+
[](LICENSE)
|
|
11
|
+
[](https://github.com/astral-sh/ruff)
|
|
12
|
+
|
|
13
|
+
[Bridge](#why) · [Quick start](#quick-start) · [Supported tools](#supported-tools) · [CI drift check](#ci-drift-check) · [FAQ](#faq)
|
|
14
|
+
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Why
|
|
20
|
+
|
|
21
|
+
Your team uses Claude Code. Your teammate uses Cursor. Someone just switched
|
|
22
|
+
to Codex CLI. And suddenly your coding standards live in **five different
|
|
23
|
+
files** that silently drift apart:
|
|
24
|
+
|
|
25
|
+
```text
|
|
26
|
+
AGENTS.md ← Codex, Gemini CLI, Jules, Amp, Zed read this
|
|
27
|
+
CLAUDE.md ← Claude Code reads this (not AGENTS.md)
|
|
28
|
+
.github/copilot-instructions.md ← GitHub Copilot reads this (not AGENTS.md)
|
|
29
|
+
.cursor/rules/*.mdc ← Cursor reads this (not AGENTS.md, older versions)
|
|
30
|
+
.windsurfrules / .clinerules ← Windsurf / Cline read these
|
|
31
|
+
CONVENTIONS.md ← Aider reads this
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`agentsbridge` fixes this with one command. You maintain **one** `AGENTS.md`
|
|
35
|
+
(the emerging industry standard) — it generates and keeps every tool's file
|
|
36
|
+
in sync. Edit once, sync everywhere, and let CI catch anything that drifts.
|
|
37
|
+
|
|
38
|
+
## Quick start
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pipx install agentsbridge # or: pip install agentsbridge / uv tool install agentsbridge
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Already have rules somewhere?** Import them:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
agentsbridge import # seeds AGENTS.md from CLAUDE.md, .cursorrules, etc.
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**Starting fresh?**
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
agentsbridge init # creates a starter AGENTS.md
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Then — the only command you'll ever need again:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
agentsbridge sync
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```text
|
|
63
|
+
+ created CLAUDE.md
|
|
64
|
+
+ created .github/copilot-instructions.md
|
|
65
|
+
+ created .cursor/rules/agentsbridge.mdc
|
|
66
|
+
+ created .windsurfrules
|
|
67
|
+
+ created .clinerules
|
|
68
|
+
+ created CONVENTIONS.md
|
|
69
|
+
|
|
70
|
+
wrote 6 file(s)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Edit `AGENTS.md`, run `agentsbridge sync`, commit. That's the whole workflow.
|
|
74
|
+
|
|
75
|
+
## Supported tools
|
|
76
|
+
|
|
77
|
+
| Tool | File generated | Notes |
|
|
78
|
+
|---|---|---|
|
|
79
|
+
| **Claude Code** | `CLAUDE.md` | |
|
|
80
|
+
| **GitHub Copilot** | `.github/copilot-instructions.md` | |
|
|
81
|
+
| **Cursor** | `.cursor/rules/agentsbridge.mdc` | with `alwaysApply` frontmatter |
|
|
82
|
+
| **Windsurf** | `.windsurfrules` | |
|
|
83
|
+
| **Cline** | `.clinerules` | |
|
|
84
|
+
| **Aider** | `CONVENTIONS.md` | |
|
|
85
|
+
| **Codex CLI, Gemini CLI, Jules, Amp, Zed, opencode** | — | read `AGENTS.md` natively, nothing to generate |
|
|
86
|
+
|
|
87
|
+
Missing a tool? [Open an issue](https://github.com/DavidStarYu/agentsbridge/issues) —
|
|
88
|
+
adding a target is ~10 lines.
|
|
89
|
+
|
|
90
|
+
## Safety
|
|
91
|
+
|
|
92
|
+
Generated files are marked:
|
|
93
|
+
|
|
94
|
+
```markdown
|
|
95
|
+
<!-- generated by agentsbridge; do not edit -->
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
If a target file already exists **without** that marker (i.e. you wrote it by
|
|
99
|
+
hand), `sync` skips it instead of clobbering your work. Use `--force` to
|
|
100
|
+
adopt it deliberately.
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
agentsbridge sync --force # adopt existing files
|
|
104
|
+
agentsbridge sync --dry-run # preview changes
|
|
105
|
+
agentsbridge sync -t claude,copilot # subset of targets
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## CI drift check
|
|
109
|
+
|
|
110
|
+
The whole point: rules that drift are rules nobody follows. Add the check to
|
|
111
|
+
your workflow and CI fails whenever someone edits a generated file — or
|
|
112
|
+
forgets to re-sync after editing `AGENTS.md`:
|
|
113
|
+
|
|
114
|
+
```yaml
|
|
115
|
+
# .github/workflows/ci.yml
|
|
116
|
+
name: rules
|
|
117
|
+
on: [push, pull_request]
|
|
118
|
+
jobs:
|
|
119
|
+
agentsbridge:
|
|
120
|
+
runs-on: ubuntu-latest
|
|
121
|
+
steps:
|
|
122
|
+
- uses: actions/checkout@v4
|
|
123
|
+
- uses: DavidStarYu/agentsbridge/action@main
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Or invoke the CLI directly: `agentsbridge check` (exit code 1 on drift).
|
|
127
|
+
|
|
128
|
+
This repository runs the same check on itself — [dogfooding](.github/workflows/rules.yml).
|
|
129
|
+
|
|
130
|
+
## FAQ
|
|
131
|
+
|
|
132
|
+
**Why AGENTS.md as the source, not my own config?**
|
|
133
|
+
AGENTS.md is the emerging standard (adopted by OpenAI Codex, Gemini CLI, Jules,
|
|
134
|
+
Amp, Zed and others — see [agents.md](https://agents.md)). Tools that don't
|
|
135
|
+
read it yet are exactly the ones this bridge targets. You keep zero
|
|
136
|
+
agentsbridge-specific config: the source file is a standard.
|
|
137
|
+
|
|
138
|
+
**Cursor already reads AGENTS.md, why generate an .mdc?**
|
|
139
|
+
Newer Cursor versions read `AGENTS.md` directly; many teams run versions that
|
|
140
|
+
don't, or want explicit rule scoping. The generated `.mdc` is harmless if
|
|
141
|
+
redundant — and you can exclude it: `agentsbridge sync -t claude,copilot,...`.
|
|
142
|
+
|
|
143
|
+
**Does it send my code anywhere?**
|
|
144
|
+
No. No network calls, no telemetry, no API keys. It's a template engine over
|
|
145
|
+
one markdown file. [Zero dependencies](pyproject.toml).
|
|
146
|
+
|
|
147
|
+
**How is this different from X?**
|
|
148
|
+
rulesync (Node.js) covers more features — MCP servers, subagents, commands —
|
|
149
|
+
at the cost of a bigger footprint and a `.rulesync/` directory convention.
|
|
150
|
+
agentsbridge does one thing: keep rule *files* in sync, in pure Python with
|
|
151
|
+
zero dependencies. If you live in `pipx`/`uv` and want the simple thing, this
|
|
152
|
+
is for you.
|
|
153
|
+
|
|
154
|
+
## Development
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
git clone https://github.com/DavidStarYu/agentsbridge
|
|
158
|
+
cd agentsbridge
|
|
159
|
+
pip install -e . pytest ruff
|
|
160
|
+
pytest # 36 tests
|
|
161
|
+
ruff check .
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## License
|
|
165
|
+
|
|
166
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"""agentsbridge CLI - bridge AGENTS.md to every AI coding tool's rules file."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import sys
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from . import __version__, core
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
13
|
+
parser = argparse.ArgumentParser(
|
|
14
|
+
prog="agentsbridge",
|
|
15
|
+
description=(
|
|
16
|
+
"Bridge AGENTS.md to every AI coding tool's rules file. "
|
|
17
|
+
"Maintain one source of truth; generate CLAUDE.md, "
|
|
18
|
+
"copilot-instructions.md, Cursor rules, and more."
|
|
19
|
+
),
|
|
20
|
+
)
|
|
21
|
+
parser.add_argument("--version", action="version", version=f"%(prog)s {__version__}")
|
|
22
|
+
sub = parser.add_subparsers(dest="command")
|
|
23
|
+
|
|
24
|
+
p_sync = sub.add_parser("sync", help="generate all target rules files from AGENTS.md")
|
|
25
|
+
p_sync.add_argument(
|
|
26
|
+
"-t",
|
|
27
|
+
"--targets",
|
|
28
|
+
default="",
|
|
29
|
+
help="comma-separated subset of targets (default: all)",
|
|
30
|
+
)
|
|
31
|
+
p_sync.add_argument(
|
|
32
|
+
"--force", action="store_true", help="overwrite files not generated by agentsbridge"
|
|
33
|
+
)
|
|
34
|
+
p_sync.add_argument(
|
|
35
|
+
"--dry-run", action="store_true", help="show what would change without writing"
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
p_check = sub.add_parser(
|
|
39
|
+
"check", help="exit non-zero if any generated file drifted from AGENTS.md (for CI)"
|
|
40
|
+
)
|
|
41
|
+
p_check.add_argument(
|
|
42
|
+
"-t",
|
|
43
|
+
"--targets",
|
|
44
|
+
default="",
|
|
45
|
+
help="comma-separated subset of targets (default: all)",
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
p_import = sub.add_parser(
|
|
49
|
+
"import", help="seed AGENTS.md from an existing rules file (CLAUDE.md, .cursorrules, ...)"
|
|
50
|
+
)
|
|
51
|
+
p_import.add_argument("--out", default="AGENTS.md", help="output path (default: AGENTS.md)")
|
|
52
|
+
|
|
53
|
+
p_init = sub.add_parser("init", help="create a starter AGENTS.md")
|
|
54
|
+
p_init.add_argument("--force", action="store_true", help="overwrite existing AGENTS.md")
|
|
55
|
+
|
|
56
|
+
return parser
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _parse_targets(value: str) -> list[str] | None:
|
|
60
|
+
value = value.strip()
|
|
61
|
+
if not value:
|
|
62
|
+
return None
|
|
63
|
+
return [v.strip() for v in value.split(",") if v.strip()]
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _root() -> Path:
|
|
67
|
+
return Path.cwd()
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def cmd_sync(args: argparse.Namespace) -> int:
|
|
71
|
+
root = core.walk_up(_root())
|
|
72
|
+
try:
|
|
73
|
+
results = core.sync(
|
|
74
|
+
root, _parse_targets(args.targets), force=args.force, dry_run=args.dry_run
|
|
75
|
+
)
|
|
76
|
+
except FileNotFoundError as e:
|
|
77
|
+
print(f"error: {e}", file=sys.stderr)
|
|
78
|
+
return 1
|
|
79
|
+
except ValueError as e:
|
|
80
|
+
print(f"error: {e}", file=sys.stderr)
|
|
81
|
+
return 2
|
|
82
|
+
|
|
83
|
+
label = "would create/update" if args.dry_run else "wrote"
|
|
84
|
+
for r in results:
|
|
85
|
+
icon = {
|
|
86
|
+
"created": "+",
|
|
87
|
+
"updated": "~",
|
|
88
|
+
"unchanged": "=",
|
|
89
|
+
"skipped": "!",
|
|
90
|
+
"missing": "?",
|
|
91
|
+
}.get(r.action, " ")
|
|
92
|
+
detail = f" ({r.detail})" if r.detail else ""
|
|
93
|
+
print(f" {icon} {r.action:<9} {r.path}{detail}")
|
|
94
|
+
created = sum(1 for r in results if r.action in ("created", "updated"))
|
|
95
|
+
skipped = sum(1 for r in results if r.action == "skipped")
|
|
96
|
+
print(
|
|
97
|
+
f"\n{label} {created} file(s)"
|
|
98
|
+
+ (f", skipped {skipped}" if skipped else "")
|
|
99
|
+
+ (" (dry run)" if args.dry_run else "")
|
|
100
|
+
)
|
|
101
|
+
return 0
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def cmd_check(args: argparse.Namespace) -> int:
|
|
105
|
+
root = core.walk_up(_root())
|
|
106
|
+
try:
|
|
107
|
+
clean, results = core.check(root, _parse_targets(args.targets))
|
|
108
|
+
except FileNotFoundError as e:
|
|
109
|
+
print(f"error: {e}", file=sys.stderr)
|
|
110
|
+
return 1
|
|
111
|
+
except ValueError as e:
|
|
112
|
+
print(f"error: {e}", file=sys.stderr)
|
|
113
|
+
return 2
|
|
114
|
+
|
|
115
|
+
for r in results:
|
|
116
|
+
icon = {"ok": "=", "drifted": "!", "missing": "?", "skipped": "-"}.get(r.action, " ")
|
|
117
|
+
detail = f" ({r.detail})" if r.detail else ""
|
|
118
|
+
print(f" {icon} {r.action:<9} {r.path}{detail}")
|
|
119
|
+
if clean:
|
|
120
|
+
print("\nall target files are up to date")
|
|
121
|
+
return 0
|
|
122
|
+
print("\ndrift detected: run `agentsbridge sync` to fix", file=sys.stderr)
|
|
123
|
+
return 1
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def cmd_import(args: argparse.Namespace) -> int:
|
|
127
|
+
root = _root()
|
|
128
|
+
try:
|
|
129
|
+
body, src = core.import_source(root)
|
|
130
|
+
except FileNotFoundError as e:
|
|
131
|
+
print(f"error: {e}", file=sys.stderr)
|
|
132
|
+
return 1
|
|
133
|
+
|
|
134
|
+
out_path = root / args.out
|
|
135
|
+
if out_path.exists():
|
|
136
|
+
print(f"error: {out_path} already exists. Delete it first or use --out.", file=sys.stderr)
|
|
137
|
+
return 1
|
|
138
|
+
out_path.write_text(body.rstrip() + "\n", encoding="utf-8")
|
|
139
|
+
print(f"created {out_path} from {src.name}")
|
|
140
|
+
print("review it, then run `agentsbridge sync` to propagate.")
|
|
141
|
+
return 0
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def cmd_init(args: argparse.Namespace) -> int:
|
|
145
|
+
root = _root()
|
|
146
|
+
if (root / core.SOURCE_FILENAME).exists() and not args.force:
|
|
147
|
+
print("AGENTS.md already exists (use --force to overwrite)")
|
|
148
|
+
return 0
|
|
149
|
+
r = core.ensure_agents_md(root, dry_run=False)
|
|
150
|
+
if r.action == "created":
|
|
151
|
+
print(f"created {r.path}")
|
|
152
|
+
print("edit it, then run `agentsbridge sync`")
|
|
153
|
+
return 0
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
COMMANDS = {
|
|
157
|
+
"sync": cmd_sync,
|
|
158
|
+
"check": cmd_check,
|
|
159
|
+
"import": cmd_import,
|
|
160
|
+
"init": cmd_init,
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def main(argv: list[str] | None = None) -> int:
|
|
165
|
+
parser = build_parser()
|
|
166
|
+
args = parser.parse_args(argv)
|
|
167
|
+
if not args.command:
|
|
168
|
+
parser.print_help()
|
|
169
|
+
return 0
|
|
170
|
+
return COMMANDS[args.command](args)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
if __name__ == "__main__":
|
|
174
|
+
sys.exit(main())
|