laneguard 0.2.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.
@@ -0,0 +1,239 @@
1
+ Metadata-Version: 2.4
2
+ Name: laneguard
3
+ Version: 0.2.0
4
+ Summary: Coordinate parallel coding agents: disjoint backlogs and conflict prediction for in-flight branches.
5
+ License: MIT
6
+ Requires-Python: >=3.12
7
+ Description-Content-Type: text/markdown
8
+ Provides-Extra: dev
9
+ Requires-Dist: pytest>=8; extra == "dev"
10
+ Requires-Dist: ruff>=0.6; extra == "dev"
11
+
12
+ # laneguard
13
+
14
+ Keep parallel coding agents in their lanes.
15
+
16
+ - `laneguard plan TASKS_DIR` checks a backlog of task files for disjoint file ownership **before** work starts.
17
+ - `laneguard scan REPO` compares in-flight branches and predicts merge conflicts **before** integration.
18
+ - `laneguard mcp` exposes both to coding agents as MCP tools.
19
+
20
+ Standard library only. Git is used read-only. Output is deterministic and compact; `--json` is the contract.
21
+
22
+ **Status:** v0.2 includes the claims ledger, schema command, and packaging. See [docs/spec.md](docs/spec.md) for the specification and [AGENTS.md](AGENTS.md) if you are an agent working on this repository.
23
+
24
+ ## Install
25
+
26
+ Install from GitHub now:
27
+
28
+ ```bash
29
+ pip install "laneguard @ git+https://github.com/55kov/laneguard.git"
30
+ ```
31
+
32
+ Once published to PyPI:
33
+
34
+ ```bash
35
+ pip install laneguard
36
+ ```
37
+
38
+ ## Usage
39
+
40
+ Run these Bash examples from the repository root with Python 3.12+ available
41
+ as `python3` and Git installed. Setup creates only disposable files under `/tmp`;
42
+ `laneguard` itself uses Git read-only. Run the blocks in order. Each output block
43
+ contains actual stdout, including the exit status printed by `printf`.
44
+
45
+ ### Plan: explicit task ownership
46
+
47
+ Create two disjoint tasks, including one file that does not exist yet:
48
+
49
+ ```bash
50
+ example_dir=$(mktemp -d)
51
+ mkdir "$example_dir/tasks"
52
+ printf 'Files: README.md\n' > "$example_dir/tasks/docs.md"
53
+ printf 'Files: future.py\n' > "$example_dir/tasks/feature.md"
54
+ python3 -m laneguard plan "$example_dir/tasks"
55
+ printf 'exit: %s\n' "$?"
56
+ ```
57
+
58
+ ```text
59
+ plan: disjoint
60
+ exit: 0
61
+ ```
62
+
63
+ The default text is concise. Use `--repo .` to classify claims against Git's
64
+ tracked files, and `--json` for the structured `exists`/`new` arrays (`--repo`
65
+ also prints classifications in text mode). New files are allowed:
66
+
67
+ ```bash
68
+ python3 -m laneguard plan "$example_dir/tasks" --repo . --json
69
+ printf 'exit: %s\n' "$?"
70
+ ```
71
+
72
+ ```json
73
+ {"kind":"plan","version":1,"tasks":[{"id":"docs","files":["README.md"],"exists":["README.md"],"new":[]},{"id":"feature","files":["future.py"],"exists":[],"new":["future.py"]}],"overlaps":[],"warnings":[]}
74
+ ```
75
+
76
+ ```text
77
+ exit: 0
78
+ ```
79
+
80
+ Add a competing claim to see an overlap:
81
+
82
+ ```bash
83
+ printf 'Files: README.md\n' > "$example_dir/tasks/other.md"
84
+ python3 -m laneguard plan "$example_dir/tasks"
85
+ printf 'exit: %s\n' "$?"
86
+ ```
87
+
88
+ ```text
89
+ overlap docs other: README.md
90
+ exit: 2
91
+ ```
92
+
93
+ ### Scan: a fully specified clean fixture
94
+
95
+ This creates a temporary bare repository with an empty base commit and two local
96
+ task branches pointing to it. Neither branch has changes. The fixture setup
97
+ writes only to the temporary repository, never the project repository:
98
+
99
+ ```bash
100
+ git init --bare --quiet "$example_dir/repo.git"
101
+ git -C "$example_dir/repo.git" fast-import --quiet <<'GIT'
102
+ commit refs/heads/main
103
+ mark :1
104
+ committer Example <example@example.com> 0 +0000
105
+ data 7
106
+ fixture
107
+
108
+ reset refs/heads/task/one
109
+ from :1
110
+
111
+ reset refs/heads/task/two
112
+ from :1
113
+
114
+ GIT
115
+ python3 -m laneguard scan "$example_dir/repo.git" --base main --branches 'task/*' --detail
116
+ printf 'exit: %s\n' "$?"
117
+ ```
118
+
119
+ ```text
120
+ scan: no likely conflicts
121
+ task/one: (no changes)
122
+ task/two: (no changes)
123
+ exit: 0
124
+ ```
125
+
126
+ `--detail` lists each selected branch's changed files; omit it for compact
127
+ findings only. Use `--json` for structured hunk ranges and merge-base hashes.
128
+ Branches editing the same file in separate regions receive an informational
129
+ `shared-file` verdict, which does not cause exit 2. Overlapping ranges or ranges
130
+ within `--near` lines (default 3), and delete/rename versus modify cases, can
131
+ produce `likely-conflict` and exit 2.
132
+
133
+ For both `plan` and `scan`, exit **0** means no overlaps or likely conflicts,
134
+ **2** means overlaps or likely conflicts were found, and **1** means a usage,
135
+ input, or Git error. Exit 2 is a finding, not a command failure.
136
+
137
+ ### MCP: a finite stdio round trip
138
+
139
+ MCP uses newline-delimited JSON-RPC 2.0. Pipe a concrete `ping` request; closing
140
+ stdin terminates the server at EOF:
141
+
142
+ ```bash
143
+ printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"ping"}' | python3 -m laneguard mcp
144
+ printf 'exit: %s\n' "$?"
145
+ ```
146
+
147
+ ```text
148
+ {"jsonrpc":"2.0","id":1,"result":{}}
149
+ exit: 0
150
+ ```
151
+
152
+ The server also supports `initialize`, `tools/list`, and `tools/call` for
153
+ `laneguard_plan` and `laneguard_scan`. Tool arguments mirror the CLI inputs (for example,
154
+ `tasks_dir` for plan and `repo`, `base`, `branches`, `near`, `detail` for scan).
155
+ Tool results already include JSON, so no `json` argument is needed. CLI finding
156
+ exit codes apply to CLI invocations; MCP returns findings and tool errors in
157
+ JSON-RPC responses.
158
+
159
+ ### Claims
160
+
161
+ Claim your task's files in a shared ledger before starting work.
162
+ If another owner holds an overlapping path, wait for their release before claiming
163
+ it and making changes.
164
+ Concurrent writers are serialized by an exclusive `FILE.lock` (retrying for up to
165
+ 10 seconds, reclaiming locks older than 60 seconds), and writes atomically replace
166
+ the ledger using a temporary file in the same directory.
167
+
168
+ ```bash
169
+ python3 -m laneguard claim --ledger "$example_dir/claims.json" --owner docs README.md
170
+ printf 'exit: %s\n' "$?"
171
+ python3 -m laneguard claim --ledger "$example_dir/claims.json" --owner feature README.md
172
+ printf 'exit: %s\n' "$?"
173
+ python3 -m laneguard release --ledger "$example_dir/claims.json" --owner docs README.md
174
+ printf 'exit: %s\n' "$?"
175
+ ```
176
+
177
+ ```text
178
+ claimed docs: README.md
179
+ exit: 0
180
+ refused feature README.md: held by docs (README.md)
181
+ exit: 2
182
+ released docs: README.md
183
+ exit: 0
184
+ ```
185
+
186
+ List the live claims as JSON, trimming the temporary ledger path from the output:
187
+
188
+ ```bash
189
+ python3 -m laneguard claims --ledger "$example_dir/claims.json" --json | python3 -c 'import json, sys; d = json.load(sys.stdin); del d["ledger"]; print(json.dumps(d, separators=(",", ":")))'
190
+ printf 'exit: %s\n' "$?"
191
+ ```
192
+
193
+ ```json
194
+ {"kind":"claims","version":1,"claims":[],"refused":[],"released":[],"warnings":[]}
195
+ ```
196
+
197
+ ```text
198
+ exit: 0
199
+ ```
200
+
201
+ ### Schemas
202
+
203
+ Print the packaged JSON Schema for `plan`, `scan`, or `claims`; here are the first
204
+ ten lines for `plan`:
205
+
206
+ ```bash
207
+ python3 -m laneguard schema plan | head -n 10
208
+ printf 'exit: %s\n' "$?"
209
+ ```
210
+
211
+ ```text
212
+ {
213
+ "$id": "https://laneguard.dev/schemas/plan.schema.json",
214
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
215
+ "additionalProperties": false,
216
+ "properties": {
217
+ "kind": {
218
+ "const": "plan",
219
+ "type": "string"
220
+ },
221
+ "overlaps": {
222
+ exit: 0
223
+ ```
224
+
225
+ In CI, save the full `laneguard schema <kind>` output and validate the corresponding
226
+ `--json` output with a JSON Schema draft 2020-12 validator.
227
+
228
+ Remove the disposable fixtures when finished:
229
+
230
+ ```bash
231
+ rm -rf "$example_dir"
232
+ ```
233
+
234
+ ## Development
235
+
236
+ ```bash
237
+ python -m venv .venv && .venv/bin/pip install -e '.[dev]'
238
+ PY=.venv/bin/python sh check.sh
239
+ ```
@@ -0,0 +1,228 @@
1
+ # laneguard
2
+
3
+ Keep parallel coding agents in their lanes.
4
+
5
+ - `laneguard plan TASKS_DIR` checks a backlog of task files for disjoint file ownership **before** work starts.
6
+ - `laneguard scan REPO` compares in-flight branches and predicts merge conflicts **before** integration.
7
+ - `laneguard mcp` exposes both to coding agents as MCP tools.
8
+
9
+ Standard library only. Git is used read-only. Output is deterministic and compact; `--json` is the contract.
10
+
11
+ **Status:** v0.2 includes the claims ledger, schema command, and packaging. See [docs/spec.md](docs/spec.md) for the specification and [AGENTS.md](AGENTS.md) if you are an agent working on this repository.
12
+
13
+ ## Install
14
+
15
+ Install from GitHub now:
16
+
17
+ ```bash
18
+ pip install "laneguard @ git+https://github.com/55kov/laneguard.git"
19
+ ```
20
+
21
+ Once published to PyPI:
22
+
23
+ ```bash
24
+ pip install laneguard
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ Run these Bash examples from the repository root with Python 3.12+ available
30
+ as `python3` and Git installed. Setup creates only disposable files under `/tmp`;
31
+ `laneguard` itself uses Git read-only. Run the blocks in order. Each output block
32
+ contains actual stdout, including the exit status printed by `printf`.
33
+
34
+ ### Plan: explicit task ownership
35
+
36
+ Create two disjoint tasks, including one file that does not exist yet:
37
+
38
+ ```bash
39
+ example_dir=$(mktemp -d)
40
+ mkdir "$example_dir/tasks"
41
+ printf 'Files: README.md\n' > "$example_dir/tasks/docs.md"
42
+ printf 'Files: future.py\n' > "$example_dir/tasks/feature.md"
43
+ python3 -m laneguard plan "$example_dir/tasks"
44
+ printf 'exit: %s\n' "$?"
45
+ ```
46
+
47
+ ```text
48
+ plan: disjoint
49
+ exit: 0
50
+ ```
51
+
52
+ The default text is concise. Use `--repo .` to classify claims against Git's
53
+ tracked files, and `--json` for the structured `exists`/`new` arrays (`--repo`
54
+ also prints classifications in text mode). New files are allowed:
55
+
56
+ ```bash
57
+ python3 -m laneguard plan "$example_dir/tasks" --repo . --json
58
+ printf 'exit: %s\n' "$?"
59
+ ```
60
+
61
+ ```json
62
+ {"kind":"plan","version":1,"tasks":[{"id":"docs","files":["README.md"],"exists":["README.md"],"new":[]},{"id":"feature","files":["future.py"],"exists":[],"new":["future.py"]}],"overlaps":[],"warnings":[]}
63
+ ```
64
+
65
+ ```text
66
+ exit: 0
67
+ ```
68
+
69
+ Add a competing claim to see an overlap:
70
+
71
+ ```bash
72
+ printf 'Files: README.md\n' > "$example_dir/tasks/other.md"
73
+ python3 -m laneguard plan "$example_dir/tasks"
74
+ printf 'exit: %s\n' "$?"
75
+ ```
76
+
77
+ ```text
78
+ overlap docs other: README.md
79
+ exit: 2
80
+ ```
81
+
82
+ ### Scan: a fully specified clean fixture
83
+
84
+ This creates a temporary bare repository with an empty base commit and two local
85
+ task branches pointing to it. Neither branch has changes. The fixture setup
86
+ writes only to the temporary repository, never the project repository:
87
+
88
+ ```bash
89
+ git init --bare --quiet "$example_dir/repo.git"
90
+ git -C "$example_dir/repo.git" fast-import --quiet <<'GIT'
91
+ commit refs/heads/main
92
+ mark :1
93
+ committer Example <example@example.com> 0 +0000
94
+ data 7
95
+ fixture
96
+
97
+ reset refs/heads/task/one
98
+ from :1
99
+
100
+ reset refs/heads/task/two
101
+ from :1
102
+
103
+ GIT
104
+ python3 -m laneguard scan "$example_dir/repo.git" --base main --branches 'task/*' --detail
105
+ printf 'exit: %s\n' "$?"
106
+ ```
107
+
108
+ ```text
109
+ scan: no likely conflicts
110
+ task/one: (no changes)
111
+ task/two: (no changes)
112
+ exit: 0
113
+ ```
114
+
115
+ `--detail` lists each selected branch's changed files; omit it for compact
116
+ findings only. Use `--json` for structured hunk ranges and merge-base hashes.
117
+ Branches editing the same file in separate regions receive an informational
118
+ `shared-file` verdict, which does not cause exit 2. Overlapping ranges or ranges
119
+ within `--near` lines (default 3), and delete/rename versus modify cases, can
120
+ produce `likely-conflict` and exit 2.
121
+
122
+ For both `plan` and `scan`, exit **0** means no overlaps or likely conflicts,
123
+ **2** means overlaps or likely conflicts were found, and **1** means a usage,
124
+ input, or Git error. Exit 2 is a finding, not a command failure.
125
+
126
+ ### MCP: a finite stdio round trip
127
+
128
+ MCP uses newline-delimited JSON-RPC 2.0. Pipe a concrete `ping` request; closing
129
+ stdin terminates the server at EOF:
130
+
131
+ ```bash
132
+ printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"ping"}' | python3 -m laneguard mcp
133
+ printf 'exit: %s\n' "$?"
134
+ ```
135
+
136
+ ```text
137
+ {"jsonrpc":"2.0","id":1,"result":{}}
138
+ exit: 0
139
+ ```
140
+
141
+ The server also supports `initialize`, `tools/list`, and `tools/call` for
142
+ `laneguard_plan` and `laneguard_scan`. Tool arguments mirror the CLI inputs (for example,
143
+ `tasks_dir` for plan and `repo`, `base`, `branches`, `near`, `detail` for scan).
144
+ Tool results already include JSON, so no `json` argument is needed. CLI finding
145
+ exit codes apply to CLI invocations; MCP returns findings and tool errors in
146
+ JSON-RPC responses.
147
+
148
+ ### Claims
149
+
150
+ Claim your task's files in a shared ledger before starting work.
151
+ If another owner holds an overlapping path, wait for their release before claiming
152
+ it and making changes.
153
+ Concurrent writers are serialized by an exclusive `FILE.lock` (retrying for up to
154
+ 10 seconds, reclaiming locks older than 60 seconds), and writes atomically replace
155
+ the ledger using a temporary file in the same directory.
156
+
157
+ ```bash
158
+ python3 -m laneguard claim --ledger "$example_dir/claims.json" --owner docs README.md
159
+ printf 'exit: %s\n' "$?"
160
+ python3 -m laneguard claim --ledger "$example_dir/claims.json" --owner feature README.md
161
+ printf 'exit: %s\n' "$?"
162
+ python3 -m laneguard release --ledger "$example_dir/claims.json" --owner docs README.md
163
+ printf 'exit: %s\n' "$?"
164
+ ```
165
+
166
+ ```text
167
+ claimed docs: README.md
168
+ exit: 0
169
+ refused feature README.md: held by docs (README.md)
170
+ exit: 2
171
+ released docs: README.md
172
+ exit: 0
173
+ ```
174
+
175
+ List the live claims as JSON, trimming the temporary ledger path from the output:
176
+
177
+ ```bash
178
+ python3 -m laneguard claims --ledger "$example_dir/claims.json" --json | python3 -c 'import json, sys; d = json.load(sys.stdin); del d["ledger"]; print(json.dumps(d, separators=(",", ":")))'
179
+ printf 'exit: %s\n' "$?"
180
+ ```
181
+
182
+ ```json
183
+ {"kind":"claims","version":1,"claims":[],"refused":[],"released":[],"warnings":[]}
184
+ ```
185
+
186
+ ```text
187
+ exit: 0
188
+ ```
189
+
190
+ ### Schemas
191
+
192
+ Print the packaged JSON Schema for `plan`, `scan`, or `claims`; here are the first
193
+ ten lines for `plan`:
194
+
195
+ ```bash
196
+ python3 -m laneguard schema plan | head -n 10
197
+ printf 'exit: %s\n' "$?"
198
+ ```
199
+
200
+ ```text
201
+ {
202
+ "$id": "https://laneguard.dev/schemas/plan.schema.json",
203
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
204
+ "additionalProperties": false,
205
+ "properties": {
206
+ "kind": {
207
+ "const": "plan",
208
+ "type": "string"
209
+ },
210
+ "overlaps": {
211
+ exit: 0
212
+ ```
213
+
214
+ In CI, save the full `laneguard schema <kind>` output and validate the corresponding
215
+ `--json` output with a JSON Schema draft 2020-12 validator.
216
+
217
+ Remove the disposable fixtures when finished:
218
+
219
+ ```bash
220
+ rm -rf "$example_dir"
221
+ ```
222
+
223
+ ## Development
224
+
225
+ ```bash
226
+ python -m venv .venv && .venv/bin/pip install -e '.[dev]'
227
+ PY=.venv/bin/python sh check.sh
228
+ ```
@@ -0,0 +1,3 @@
1
+ """laneguard: coordinate parallel coding agents."""
2
+
3
+ __version__ = "0.2.0"
@@ -0,0 +1,3 @@
1
+ from .cli import main
2
+
3
+ raise SystemExit(main())