mergetrain 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.
- mergetrain-0.1.0/.gitignore +34 -0
- mergetrain-0.1.0/AGENTS.md +32 -0
- mergetrain-0.1.0/CHANGELOG.md +27 -0
- mergetrain-0.1.0/LICENSE +21 -0
- mergetrain-0.1.0/PKG-INFO +207 -0
- mergetrain-0.1.0/README.md +172 -0
- mergetrain-0.1.0/dashboard/AGENTS.md +15 -0
- mergetrain-0.1.0/dashboard/index.html +15 -0
- mergetrain-0.1.0/dashboard/package-lock.json +1740 -0
- mergetrain-0.1.0/dashboard/package.json +20 -0
- mergetrain-0.1.0/dashboard/public/favicon.svg +1 -0
- mergetrain-0.1.0/dashboard/scripts/generate-favicon.mjs +15 -0
- mergetrain-0.1.0/dashboard/src/App.jsx +486 -0
- mergetrain-0.1.0/dashboard/src/main.jsx +12 -0
- mergetrain-0.1.0/dashboard/src/styles.css +408 -0
- mergetrain-0.1.0/dashboard/vite.config.mjs +22 -0
- mergetrain-0.1.0/docs/adapter-pattern.md +20 -0
- mergetrain-0.1.0/docs/agent-contract.md +43 -0
- mergetrain-0.1.0/docs/cli.md +218 -0
- mergetrain-0.1.0/docs/config.md +143 -0
- mergetrain-0.1.0/docs/daemon.md +39 -0
- mergetrain-0.1.0/docs/design.md +259 -0
- mergetrain-0.1.0/docs/development.md +93 -0
- mergetrain-0.1.0/docs/failure-modes.md +103 -0
- mergetrain-0.1.0/docs/install.md +39 -0
- mergetrain-0.1.0/docs/mobile.md +74 -0
- mergetrain-0.1.0/docs/quickstart.md +65 -0
- mergetrain-0.1.0/docs/release.md +121 -0
- mergetrain-0.1.0/docs/security.md +40 -0
- mergetrain-0.1.0/examples/example.mergetrain.yaml +31 -0
- mergetrain-0.1.0/examples/mergetrain.agent.yaml +14 -0
- mergetrain-0.1.0/llms-full.txt +54 -0
- mergetrain-0.1.0/llms.txt +21 -0
- mergetrain-0.1.0/pyproject.toml +62 -0
- mergetrain-0.1.0/src/mergetrain/__init__.py +5 -0
- mergetrain-0.1.0/src/mergetrain/__main__.py +4 -0
- mergetrain-0.1.0/src/mergetrain/cli.py +628 -0
- mergetrain-0.1.0/src/mergetrain/config.py +438 -0
- mergetrain-0.1.0/src/mergetrain/daemon.py +80 -0
- mergetrain-0.1.0/src/mergetrain/dashboard.py +188 -0
- mergetrain-0.1.0/src/mergetrain/dashboard_dist/assets/index-BKsW0WDL.js +49 -0
- mergetrain-0.1.0/src/mergetrain/dashboard_dist/assets/index-dvMrfMz1.css +1 -0
- mergetrain-0.1.0/src/mergetrain/dashboard_dist/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- mergetrain-0.1.0/src/mergetrain/dashboard_dist/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- mergetrain-0.1.0/src/mergetrain/dashboard_dist/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- mergetrain-0.1.0/src/mergetrain/dashboard_dist/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- mergetrain-0.1.0/src/mergetrain/dashboard_dist/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- mergetrain-0.1.0/src/mergetrain/dashboard_dist/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- mergetrain-0.1.0/src/mergetrain/dashboard_dist/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- mergetrain-0.1.0/src/mergetrain/dashboard_dist/assets/jetbrains-mono-cyrillic-ext-wght-normal-EocZY2iu.woff2 +0 -0
- mergetrain-0.1.0/src/mergetrain/dashboard_dist/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
- mergetrain-0.1.0/src/mergetrain/dashboard_dist/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
- mergetrain-0.1.0/src/mergetrain/dashboard_dist/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
- mergetrain-0.1.0/src/mergetrain/dashboard_dist/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
- mergetrain-0.1.0/src/mergetrain/dashboard_dist/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
- mergetrain-0.1.0/src/mergetrain/dashboard_dist/favicon.svg +1 -0
- mergetrain-0.1.0/src/mergetrain/dashboard_dist/index.html +16 -0
- mergetrain-0.1.0/src/mergetrain/errors.py +56 -0
- mergetrain-0.1.0/src/mergetrain/git_runner.py +1183 -0
- mergetrain-0.1.0/src/mergetrain/models.py +133 -0
- mergetrain-0.1.0/src/mergetrain/snapshot.py +241 -0
- mergetrain-0.1.0/src/mergetrain/store.py +893 -0
- mergetrain-0.1.0/tests/test_cli.py +100 -0
- mergetrain-0.1.0/tests/test_config.py +75 -0
- mergetrain-0.1.0/tests/test_daemon.py +43 -0
- mergetrain-0.1.0/tests/test_dashboard.py +148 -0
- mergetrain-0.1.0/tests/test_git_runner.py +273 -0
- mergetrain-0.1.0/tests/test_store.py +294 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# mergetrain runtime state (queue DB, logs, temporary worktrees)
|
|
2
|
+
.mergetrain/
|
|
3
|
+
|
|
4
|
+
# Python
|
|
5
|
+
__pycache__/
|
|
6
|
+
*.py[cod]
|
|
7
|
+
*.egg
|
|
8
|
+
*.egg-info/
|
|
9
|
+
.eggs/
|
|
10
|
+
build/
|
|
11
|
+
dist/
|
|
12
|
+
|
|
13
|
+
# Virtual environments
|
|
14
|
+
.venv/
|
|
15
|
+
venv/
|
|
16
|
+
env/
|
|
17
|
+
|
|
18
|
+
# Test / type / lint caches
|
|
19
|
+
.pytest_cache/
|
|
20
|
+
.mypy_cache/
|
|
21
|
+
.ruff_cache/
|
|
22
|
+
.coverage
|
|
23
|
+
htmlcov/
|
|
24
|
+
|
|
25
|
+
# Dashboard authoring dependencies and cache
|
|
26
|
+
dashboard/node_modules/
|
|
27
|
+
dashboard/.npm-cache/
|
|
28
|
+
|
|
29
|
+
# IDE / editor
|
|
30
|
+
.idea/
|
|
31
|
+
.vscode/
|
|
32
|
+
|
|
33
|
+
# OS
|
|
34
|
+
.DS_Store
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
This repository contains `mergetrain`, a local deploy train for coding-agent
|
|
4
|
+
worktrees.
|
|
5
|
+
|
|
6
|
+
## Agent operating rules
|
|
7
|
+
|
|
8
|
+
1. Work on a task-specific branch and worktree.
|
|
9
|
+
2. Commit all changes before enqueueing.
|
|
10
|
+
3. Do not push deploy refs directly.
|
|
11
|
+
4. Read `mergetrain doctor --json` or `mergetrain status --json` before deciding
|
|
12
|
+
the next action.
|
|
13
|
+
5. Use `--auto` only after explicit unattended-deploy approval.
|
|
14
|
+
6. Let one runner or daemon own merge, test, push, and verify.
|
|
15
|
+
7. Fix blocked or failed work in the owning branch, commit a clean result, then
|
|
16
|
+
enqueue a new job.
|
|
17
|
+
|
|
18
|
+
## Useful commands
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
PYTHONPATH=src python -m unittest discover -s tests
|
|
22
|
+
PYTHONPATH=src python -m mergetrain agent-contract --json
|
|
23
|
+
PYTHONPATH=src python -m mergetrain init --project demo
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Boundaries
|
|
27
|
+
|
|
28
|
+
- Never add provider-specific credentials to examples or tests.
|
|
29
|
+
- Keep core provider-neutral; adapters belong under `integrations/` or in a
|
|
30
|
+
separate service repository.
|
|
31
|
+
- Gate and verify commands run through `/bin/sh`; document new shell execution
|
|
32
|
+
behavior clearly.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
## 0.1.0 - 2026-07-17
|
|
6
|
+
|
|
7
|
+
First public alpha release.
|
|
8
|
+
|
|
9
|
+
- Preserve exact validated train identity for a later approval-gated deploy.
|
|
10
|
+
- Rebuild validated trains on the current integration ref and reject changed task HEADs.
|
|
11
|
+
- Exclude validated-but-not-deployed branches from destructive GC.
|
|
12
|
+
- Fence batch claims and state transitions with unique lease tokens.
|
|
13
|
+
- Heartbeat, cancel, and time out long-running Git and shell subprocesses.
|
|
14
|
+
- Reject explicitly empty deploy refs and invalid queue timing at config load.
|
|
15
|
+
- Return truthful JSON outcomes and non-zero exit codes for blocked/failed jobs.
|
|
16
|
+
- Version SQLite migrations with `PRAGMA user_version`.
|
|
17
|
+
- Add a loopback-first, read-only live dashboard with SSE and polling fallback.
|
|
18
|
+
- Distinguish browser connectivity from runner activity and explain the current gate, command, scope, and Activity milestones.
|
|
19
|
+
- Record structured runner phases and explicit lock heartbeat timestamps.
|
|
20
|
+
- Redact lease tokens and local filesystem paths from dashboard payloads.
|
|
21
|
+
- SQLite-backed local deploy queue.
|
|
22
|
+
- Runner lock with PID liveness checks.
|
|
23
|
+
- Git worktree merge train execution.
|
|
24
|
+
- Configurable pre-push gates and post-push verify hooks.
|
|
25
|
+
- Atomic push refs.
|
|
26
|
+
- Auto-only daemon boundary.
|
|
27
|
+
- JSON-first agent contract, status, doctor, and GC output.
|
mergetrain-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 mergetrain 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,207 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mergetrain
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A local-first merge-and-deploy queue for coding-agent worktrees
|
|
5
|
+
Project-URL: Homepage, https://github.com/yongjip/mergetrain
|
|
6
|
+
Project-URL: Documentation, https://github.com/yongjip/mergetrain/tree/main/docs
|
|
7
|
+
Project-URL: Issues, https://github.com/yongjip/mergetrain/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/yongjip/mergetrain/blob/main/CHANGELOG.md
|
|
9
|
+
Author: mergetrain contributors
|
|
10
|
+
License: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: ai-agent,deploy,git,llm,merge-train,sqlite,worktree
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
24
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
25
|
+
Classifier: Topic :: Software Development :: Version Control :: Git
|
|
26
|
+
Requires-Python: >=3.10
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: build>=1.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: hatchling>=1.21; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest>=7; extra == 'dev'
|
|
31
|
+
Requires-Dist: pyyaml>=6.0; extra == 'dev'
|
|
32
|
+
Provides-Extra: yaml
|
|
33
|
+
Requires-Dist: pyyaml>=6.0; extra == 'yaml'
|
|
34
|
+
Description-Content-Type: text/markdown
|
|
35
|
+
|
|
36
|
+
# mergetrain
|
|
37
|
+
|
|
38
|
+
**A local-first merge-and-deploy queue for coding-agent worktrees.**
|
|
39
|
+
|
|
40
|
+
mergetrain keeps its queue, coordination, merge assembly, and gate execution on
|
|
41
|
+
your machine. Coding agents commit in separate worktrees; one local runner
|
|
42
|
+
serializes their branches, validates the exact train, and pushes only after
|
|
43
|
+
explicit approval. No hosted merge-queue service or CI provider is required.
|
|
44
|
+
|
|
45
|
+
> **Local-first, not local-only.** Queue state, locking, train assembly, and
|
|
46
|
+
> gates stay local. Configured Git remotes and post-deploy verification may
|
|
47
|
+
> still use external services.
|
|
48
|
+
|
|
49
|
+
> Status: alpha (`v0.1.0`). The core is implemented and tested; interfaces may still change. Built to scratch my own itch first — published in case it scratches yours too.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## The problem
|
|
54
|
+
|
|
55
|
+
When several Codex/Claude/LLM sessions work on the same repo at the same time, each in its own worktree and branch, a few things break down:
|
|
56
|
+
|
|
57
|
+
- It's unclear what order branches should land on the deploy branch.
|
|
58
|
+
- If an agent runs `git push` itself, sessions overwrite each other or ship unverified combinations.
|
|
59
|
+
- Each branch passes its own tests, but the *merge of several branches in sequence* can still be broken.
|
|
60
|
+
- Conflicts, stale locks, duplicate enqueues, and "is the daemon allowed to deploy this?" all become judgment calls — and you do not want an LLM guessing at those.
|
|
61
|
+
|
|
62
|
+
Hosted merge queues (GitHub Merge Queue, GitLab Merge Trains, Mergify, Aviator, bors) solve a related problem, but they are PR-first, remote-CI-first, and platform-first. mergetrain is for the other workflow: **local-agent, worktree-first, deploy-branch-first.**
|
|
63
|
+
|
|
64
|
+
## How it works
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
agent A ─┐
|
|
68
|
+
agent B ─┼─▶ mergetrain queue (SQLite) ─▶ one runner (lock)
|
|
69
|
+
agent C ─┘ │
|
|
70
|
+
▼
|
|
71
|
+
fresh integration worktree @ origin/main
|
|
72
|
+
merge A → B → C (the train)
|
|
73
|
+
│
|
|
74
|
+
gates (diff-check, tests, scans…)
|
|
75
|
+
│
|
|
76
|
+
git push --atomic → deploy refs
|
|
77
|
+
│
|
|
78
|
+
post-push verify hooks
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Agents commit their work and **enqueue** a branch. They never push deploy refs themselves. A single **runner** (or unattended **daemon**) claims the queue, builds a throwaway integration worktree on top of your integration branch, merges the queued branches in FIFO order, runs your gates once over the whole train, and only then pushes — atomically — to your deploy refs. Every important state is readable as JSON so an agent can follow the result instead of inferring it.
|
|
82
|
+
|
|
83
|
+
## Quickstart
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
# Install the public alpha
|
|
87
|
+
python -m pip install mergetrain
|
|
88
|
+
|
|
89
|
+
# 1. Scaffold config + agent docs in your repo
|
|
90
|
+
mergetrain init --project my-app --write
|
|
91
|
+
|
|
92
|
+
# 2. An agent finishes work, commits, and enqueues its branch
|
|
93
|
+
mergetrain enqueue --task "add health check" --branch agent/health --capture-sha
|
|
94
|
+
|
|
95
|
+
# 3. See the queue and lock state (machine-readable)
|
|
96
|
+
mergetrain status --json
|
|
97
|
+
|
|
98
|
+
# 4. Watch the queue and runner locally (read-only)
|
|
99
|
+
mergetrain dashboard
|
|
100
|
+
|
|
101
|
+
# 5. Validate the whole train without shipping
|
|
102
|
+
mergetrain run-batch --validate-only
|
|
103
|
+
|
|
104
|
+
# 6. Ship — explicit, never implicit
|
|
105
|
+
mergetrain run-batch --deploy
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
For an unreleased source checkout, use `python -m pip install -e .` instead.
|
|
109
|
+
|
|
110
|
+
The dashboard is served at `http://127.0.0.1:8765/`. It streams structured
|
|
111
|
+
runner phases, heartbeat freshness, job order, blocked reasons, recent activity,
|
|
112
|
+
the exact current gate and command template, and the next safe action. `CONNECTED`
|
|
113
|
+
describes the browser's data stream; `RUNNER ACTIVE` separately describes the
|
|
114
|
+
process that owns the train. It has no mutation endpoints or deploy controls.
|
|
115
|
+
|
|
116
|
+
Validation records an exact train identity, including every task HEAD and the
|
|
117
|
+
integration base used for the check. The later deploy reassembles that same
|
|
118
|
+
train on the current integration ref, reruns all gates, and refuses changed
|
|
119
|
+
task branches. Newly queued work is not silently added to the approved train.
|
|
120
|
+
|
|
121
|
+
Every agent-facing command is non-interactive and requires explicit intent: `--validate-only` or `--deploy`, never a bare `run-batch`.
|
|
122
|
+
|
|
123
|
+
## Core concepts
|
|
124
|
+
|
|
125
|
+
- **Job** — one task branch waiting in the queue, with the SHAs captured at enqueue time.
|
|
126
|
+
- **Validated train** — an exact, deployable group of jobs that passed gates together and is waiting for explicit deploy approval.
|
|
127
|
+
- **Runner lock** — gives every claim a unique lease token, heartbeats through long-running commands, and prevents a stale runner from overwriting a newer owner.
|
|
128
|
+
- **Integration worktree** — a disposable, detached Git worktree built on your integration ref. The runner merges here, so agents never checkout or push the deploy branch.
|
|
129
|
+
- **Gate** — a verification command (diff-check, tests, secret-scan…) run once over the assembled train *before* push. A gate failure means nothing ships.
|
|
130
|
+
- **Verify hook** — a command run *after* push to confirm the deploy is live.
|
|
131
|
+
- **Auto job** — a job enqueued with `--auto`, the only kind the unattended daemon will touch. Manual jobs are left for a human-initiated runner.
|
|
132
|
+
|
|
133
|
+
Full reference in [docs/design.md](./docs/design.md) and the [CLI reference](./docs/cli.md).
|
|
134
|
+
|
|
135
|
+
## When to use mergetrain
|
|
136
|
+
|
|
137
|
+
| Your workflow is… | Use |
|
|
138
|
+
|---|---|
|
|
139
|
+
| PR-first, remote-CI-first, hosted platform | GitHub / GitLab merge queue, Mergify, Aviator |
|
|
140
|
+
| Local agents in worktrees shipping to a deploy branch | **mergetrain** |
|
|
141
|
+
|
|
142
|
+
mergetrain is **not** a general-purpose job queue (it won't replace Celery/RQ/Sidekiq), a CI provider, or a deploy provider. The core is provider-neutral: your push targets, test commands, and deploy checks live in config, not in mergetrain.
|
|
143
|
+
|
|
144
|
+
## Configuration
|
|
145
|
+
|
|
146
|
+
A single `.mergetrain.yaml` at your repo root holds all policy. The core stays neutral; you bring the commands.
|
|
147
|
+
|
|
148
|
+
```yaml
|
|
149
|
+
project:
|
|
150
|
+
name: my-app
|
|
151
|
+
|
|
152
|
+
git:
|
|
153
|
+
remote: origin
|
|
154
|
+
integration_branch: main
|
|
155
|
+
push_refs: [main] # atomic push targets on deploy
|
|
156
|
+
|
|
157
|
+
queue:
|
|
158
|
+
lock_ttl_minutes: 30
|
|
159
|
+
heartbeat_interval_seconds: 10
|
|
160
|
+
command_timeout_seconds: 3600
|
|
161
|
+
|
|
162
|
+
gates:
|
|
163
|
+
- name: diff-check
|
|
164
|
+
run: git diff --check ${integration_ref}..HEAD
|
|
165
|
+
- name: tests
|
|
166
|
+
run: python -m pytest
|
|
167
|
+
|
|
168
|
+
deploy:
|
|
169
|
+
verify:
|
|
170
|
+
- name: live-health
|
|
171
|
+
run: curl -fsS https://example.invalid/health
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
See the [config reference](./docs/config.md) for the full schema, placeholders, and environment variables.
|
|
175
|
+
|
|
176
|
+
## For AI agents
|
|
177
|
+
|
|
178
|
+
mergetrain is designed so an agent can operate it from a short contract and JSON output, without guessing:
|
|
179
|
+
|
|
180
|
+
1. Work on a task-specific branch in its own worktree.
|
|
181
|
+
2. Commit before enqueuing.
|
|
182
|
+
3. Never push deploy refs directly.
|
|
183
|
+
4. Read `mergetrain doctor --json` / `status --json` before acting.
|
|
184
|
+
5. Use `--auto` only after explicit human approval for unattended deploys.
|
|
185
|
+
6. Let one runner or daemon own merge → test → push → verify.
|
|
186
|
+
7. Fix `blocked`/`failed` work on the owning branch and enqueue a fresh clean job.
|
|
187
|
+
|
|
188
|
+
`mergetrain init` writes `AGENTS.mergetrain.md` / `CLAUDE.mergetrain.md` so your agents pick this up automatically.
|
|
189
|
+
|
|
190
|
+
## Documentation
|
|
191
|
+
|
|
192
|
+
- [Quickstart](./docs/quickstart.md) · [Install](./docs/install.md)
|
|
193
|
+
- [CLI reference](./docs/cli.md) — every command and flag
|
|
194
|
+
- [Config reference](./docs/config.md) — `.mergetrain.yaml` schema, placeholders, env vars
|
|
195
|
+
- [Design & architecture](./docs/design.md) — the model, data model, and safety guarantees
|
|
196
|
+
- [Daemon](./docs/daemon.md) · [Failure modes](./docs/failure-modes.md) — operating it day to day
|
|
197
|
+
- [Manage from your phone](./docs/mobile.md) — drive mergetrain via Cowork Dispatch
|
|
198
|
+
- [Agent contract](./docs/agent-contract.md) — the rules agents follow
|
|
199
|
+
- [Security](./docs/security.md) · [Adapter pattern](./docs/adapter-pattern.md) · [Development](./docs/development.md) · [Release](./docs/release.md)
|
|
200
|
+
|
|
201
|
+
## Status
|
|
202
|
+
|
|
203
|
+
`v0.1.0`, alpha. The core — queue, runner lock, merge train, gates, atomic push, auto-only daemon, JSON `doctor`/`status`, and the local read-only dashboard — is implemented with a passing test suite. Built for my own multi-agent workflow first; issues and ideas welcome. Review your config trust boundary, gate commands, and secret handling before enabling unattended deploys — see [security](./docs/security.md).
|
|
204
|
+
|
|
205
|
+
## License
|
|
206
|
+
|
|
207
|
+
Released under the [MIT License](./LICENSE).
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# mergetrain
|
|
2
|
+
|
|
3
|
+
**A local-first merge-and-deploy queue for coding-agent worktrees.**
|
|
4
|
+
|
|
5
|
+
mergetrain keeps its queue, coordination, merge assembly, and gate execution on
|
|
6
|
+
your machine. Coding agents commit in separate worktrees; one local runner
|
|
7
|
+
serializes their branches, validates the exact train, and pushes only after
|
|
8
|
+
explicit approval. No hosted merge-queue service or CI provider is required.
|
|
9
|
+
|
|
10
|
+
> **Local-first, not local-only.** Queue state, locking, train assembly, and
|
|
11
|
+
> gates stay local. Configured Git remotes and post-deploy verification may
|
|
12
|
+
> still use external services.
|
|
13
|
+
|
|
14
|
+
> Status: alpha (`v0.1.0`). The core is implemented and tested; interfaces may still change. Built to scratch my own itch first — published in case it scratches yours too.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## The problem
|
|
19
|
+
|
|
20
|
+
When several Codex/Claude/LLM sessions work on the same repo at the same time, each in its own worktree and branch, a few things break down:
|
|
21
|
+
|
|
22
|
+
- It's unclear what order branches should land on the deploy branch.
|
|
23
|
+
- If an agent runs `git push` itself, sessions overwrite each other or ship unverified combinations.
|
|
24
|
+
- Each branch passes its own tests, but the *merge of several branches in sequence* can still be broken.
|
|
25
|
+
- Conflicts, stale locks, duplicate enqueues, and "is the daemon allowed to deploy this?" all become judgment calls — and you do not want an LLM guessing at those.
|
|
26
|
+
|
|
27
|
+
Hosted merge queues (GitHub Merge Queue, GitLab Merge Trains, Mergify, Aviator, bors) solve a related problem, but they are PR-first, remote-CI-first, and platform-first. mergetrain is for the other workflow: **local-agent, worktree-first, deploy-branch-first.**
|
|
28
|
+
|
|
29
|
+
## How it works
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
agent A ─┐
|
|
33
|
+
agent B ─┼─▶ mergetrain queue (SQLite) ─▶ one runner (lock)
|
|
34
|
+
agent C ─┘ │
|
|
35
|
+
▼
|
|
36
|
+
fresh integration worktree @ origin/main
|
|
37
|
+
merge A → B → C (the train)
|
|
38
|
+
│
|
|
39
|
+
gates (diff-check, tests, scans…)
|
|
40
|
+
│
|
|
41
|
+
git push --atomic → deploy refs
|
|
42
|
+
│
|
|
43
|
+
post-push verify hooks
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Agents commit their work and **enqueue** a branch. They never push deploy refs themselves. A single **runner** (or unattended **daemon**) claims the queue, builds a throwaway integration worktree on top of your integration branch, merges the queued branches in FIFO order, runs your gates once over the whole train, and only then pushes — atomically — to your deploy refs. Every important state is readable as JSON so an agent can follow the result instead of inferring it.
|
|
47
|
+
|
|
48
|
+
## Quickstart
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Install the public alpha
|
|
52
|
+
python -m pip install mergetrain
|
|
53
|
+
|
|
54
|
+
# 1. Scaffold config + agent docs in your repo
|
|
55
|
+
mergetrain init --project my-app --write
|
|
56
|
+
|
|
57
|
+
# 2. An agent finishes work, commits, and enqueues its branch
|
|
58
|
+
mergetrain enqueue --task "add health check" --branch agent/health --capture-sha
|
|
59
|
+
|
|
60
|
+
# 3. See the queue and lock state (machine-readable)
|
|
61
|
+
mergetrain status --json
|
|
62
|
+
|
|
63
|
+
# 4. Watch the queue and runner locally (read-only)
|
|
64
|
+
mergetrain dashboard
|
|
65
|
+
|
|
66
|
+
# 5. Validate the whole train without shipping
|
|
67
|
+
mergetrain run-batch --validate-only
|
|
68
|
+
|
|
69
|
+
# 6. Ship — explicit, never implicit
|
|
70
|
+
mergetrain run-batch --deploy
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
For an unreleased source checkout, use `python -m pip install -e .` instead.
|
|
74
|
+
|
|
75
|
+
The dashboard is served at `http://127.0.0.1:8765/`. It streams structured
|
|
76
|
+
runner phases, heartbeat freshness, job order, blocked reasons, recent activity,
|
|
77
|
+
the exact current gate and command template, and the next safe action. `CONNECTED`
|
|
78
|
+
describes the browser's data stream; `RUNNER ACTIVE` separately describes the
|
|
79
|
+
process that owns the train. It has no mutation endpoints or deploy controls.
|
|
80
|
+
|
|
81
|
+
Validation records an exact train identity, including every task HEAD and the
|
|
82
|
+
integration base used for the check. The later deploy reassembles that same
|
|
83
|
+
train on the current integration ref, reruns all gates, and refuses changed
|
|
84
|
+
task branches. Newly queued work is not silently added to the approved train.
|
|
85
|
+
|
|
86
|
+
Every agent-facing command is non-interactive and requires explicit intent: `--validate-only` or `--deploy`, never a bare `run-batch`.
|
|
87
|
+
|
|
88
|
+
## Core concepts
|
|
89
|
+
|
|
90
|
+
- **Job** — one task branch waiting in the queue, with the SHAs captured at enqueue time.
|
|
91
|
+
- **Validated train** — an exact, deployable group of jobs that passed gates together and is waiting for explicit deploy approval.
|
|
92
|
+
- **Runner lock** — gives every claim a unique lease token, heartbeats through long-running commands, and prevents a stale runner from overwriting a newer owner.
|
|
93
|
+
- **Integration worktree** — a disposable, detached Git worktree built on your integration ref. The runner merges here, so agents never checkout or push the deploy branch.
|
|
94
|
+
- **Gate** — a verification command (diff-check, tests, secret-scan…) run once over the assembled train *before* push. A gate failure means nothing ships.
|
|
95
|
+
- **Verify hook** — a command run *after* push to confirm the deploy is live.
|
|
96
|
+
- **Auto job** — a job enqueued with `--auto`, the only kind the unattended daemon will touch. Manual jobs are left for a human-initiated runner.
|
|
97
|
+
|
|
98
|
+
Full reference in [docs/design.md](./docs/design.md) and the [CLI reference](./docs/cli.md).
|
|
99
|
+
|
|
100
|
+
## When to use mergetrain
|
|
101
|
+
|
|
102
|
+
| Your workflow is… | Use |
|
|
103
|
+
|---|---|
|
|
104
|
+
| PR-first, remote-CI-first, hosted platform | GitHub / GitLab merge queue, Mergify, Aviator |
|
|
105
|
+
| Local agents in worktrees shipping to a deploy branch | **mergetrain** |
|
|
106
|
+
|
|
107
|
+
mergetrain is **not** a general-purpose job queue (it won't replace Celery/RQ/Sidekiq), a CI provider, or a deploy provider. The core is provider-neutral: your push targets, test commands, and deploy checks live in config, not in mergetrain.
|
|
108
|
+
|
|
109
|
+
## Configuration
|
|
110
|
+
|
|
111
|
+
A single `.mergetrain.yaml` at your repo root holds all policy. The core stays neutral; you bring the commands.
|
|
112
|
+
|
|
113
|
+
```yaml
|
|
114
|
+
project:
|
|
115
|
+
name: my-app
|
|
116
|
+
|
|
117
|
+
git:
|
|
118
|
+
remote: origin
|
|
119
|
+
integration_branch: main
|
|
120
|
+
push_refs: [main] # atomic push targets on deploy
|
|
121
|
+
|
|
122
|
+
queue:
|
|
123
|
+
lock_ttl_minutes: 30
|
|
124
|
+
heartbeat_interval_seconds: 10
|
|
125
|
+
command_timeout_seconds: 3600
|
|
126
|
+
|
|
127
|
+
gates:
|
|
128
|
+
- name: diff-check
|
|
129
|
+
run: git diff --check ${integration_ref}..HEAD
|
|
130
|
+
- name: tests
|
|
131
|
+
run: python -m pytest
|
|
132
|
+
|
|
133
|
+
deploy:
|
|
134
|
+
verify:
|
|
135
|
+
- name: live-health
|
|
136
|
+
run: curl -fsS https://example.invalid/health
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
See the [config reference](./docs/config.md) for the full schema, placeholders, and environment variables.
|
|
140
|
+
|
|
141
|
+
## For AI agents
|
|
142
|
+
|
|
143
|
+
mergetrain is designed so an agent can operate it from a short contract and JSON output, without guessing:
|
|
144
|
+
|
|
145
|
+
1. Work on a task-specific branch in its own worktree.
|
|
146
|
+
2. Commit before enqueuing.
|
|
147
|
+
3. Never push deploy refs directly.
|
|
148
|
+
4. Read `mergetrain doctor --json` / `status --json` before acting.
|
|
149
|
+
5. Use `--auto` only after explicit human approval for unattended deploys.
|
|
150
|
+
6. Let one runner or daemon own merge → test → push → verify.
|
|
151
|
+
7. Fix `blocked`/`failed` work on the owning branch and enqueue a fresh clean job.
|
|
152
|
+
|
|
153
|
+
`mergetrain init` writes `AGENTS.mergetrain.md` / `CLAUDE.mergetrain.md` so your agents pick this up automatically.
|
|
154
|
+
|
|
155
|
+
## Documentation
|
|
156
|
+
|
|
157
|
+
- [Quickstart](./docs/quickstart.md) · [Install](./docs/install.md)
|
|
158
|
+
- [CLI reference](./docs/cli.md) — every command and flag
|
|
159
|
+
- [Config reference](./docs/config.md) — `.mergetrain.yaml` schema, placeholders, env vars
|
|
160
|
+
- [Design & architecture](./docs/design.md) — the model, data model, and safety guarantees
|
|
161
|
+
- [Daemon](./docs/daemon.md) · [Failure modes](./docs/failure-modes.md) — operating it day to day
|
|
162
|
+
- [Manage from your phone](./docs/mobile.md) — drive mergetrain via Cowork Dispatch
|
|
163
|
+
- [Agent contract](./docs/agent-contract.md) — the rules agents follow
|
|
164
|
+
- [Security](./docs/security.md) · [Adapter pattern](./docs/adapter-pattern.md) · [Development](./docs/development.md) · [Release](./docs/release.md)
|
|
165
|
+
|
|
166
|
+
## Status
|
|
167
|
+
|
|
168
|
+
`v0.1.0`, alpha. The core — queue, runner lock, merge train, gates, atomic push, auto-only daemon, JSON `doctor`/`status`, and the local read-only dashboard — is implemented with a passing test suite. Built for my own multi-agent workflow first; issues and ideas welcome. Review your config trust boundary, gate commands, and secret handling before enabling unattended deploys — see [security](./docs/security.md).
|
|
169
|
+
|
|
170
|
+
## License
|
|
171
|
+
|
|
172
|
+
Released under the [MIT License](./LICENSE).
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Prototype Instructions
|
|
2
|
+
|
|
3
|
+
Run the local server yourself and open the preview in the browser available to this environment. Do not give the user server-start instructions when you can run it.
|
|
4
|
+
|
|
5
|
+
Before making substantial visual changes, use the Product Design plugin's `get-context` skill when the visual source is unclear or no longer matches the current goal. When the user gives durable prototype-specific design feedback, preferences, or decisions, record them in `AGENTS.md`.
|
|
6
|
+
|
|
7
|
+
When implementing from a selected generated mock, treat that image as the source of truth for layout, component anatomy, density, spacing, color, typography, visible content, and hierarchy.
|
|
8
|
+
|
|
9
|
+
## Selected direction
|
|
10
|
+
|
|
11
|
+
- Use the approved hybrid: Live Track hierarchy (direction 3) with Signal Board clarity (direction 1).
|
|
12
|
+
- Keep the interface read-only, single-repository, desktop-first, and local-only for v0.1.
|
|
13
|
+
- Show actual runner phases, heartbeat freshness, blocked reason, activity, and the next safe action.
|
|
14
|
+
- Use a warm off-white canvas, dark ink, blue active state, green success, amber attention, red failure, thin borders, and restrained radii.
|
|
15
|
+
- Avoid literal train illustrations and action controls; the track is an information model, not decoration.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<meta name="theme-color" content="#fbfaf7" />
|
|
7
|
+
<meta name="description" content="Live, read-only local mergetrain status" />
|
|
8
|
+
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
|
9
|
+
<title>mergetrain · live local status</title>
|
|
10
|
+
</head>
|
|
11
|
+
<body>
|
|
12
|
+
<div id="root"></div>
|
|
13
|
+
<script type="module" src="/src/main.jsx"></script>
|
|
14
|
+
</body>
|
|
15
|
+
</html>
|