hyperloop 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.
Files changed (56) hide show
  1. hyperloop-0.1.0/.github/workflows/ci.yaml +51 -0
  2. hyperloop-0.1.0/.github/workflows/release.yaml +106 -0
  3. hyperloop-0.1.0/.gitignore +9 -0
  4. hyperloop-0.1.0/.pre-commit-config.yaml +17 -0
  5. hyperloop-0.1.0/.python-version +1 -0
  6. hyperloop-0.1.0/CHANGELOG.md +7 -0
  7. hyperloop-0.1.0/CLAUDE.md +102 -0
  8. hyperloop-0.1.0/PKG-INFO +253 -0
  9. hyperloop-0.1.0/README.md +238 -0
  10. hyperloop-0.1.0/base/implementer.yaml +30 -0
  11. hyperloop-0.1.0/base/pm.yaml +43 -0
  12. hyperloop-0.1.0/base/process-improver.yaml +30 -0
  13. hyperloop-0.1.0/base/process.yaml +11 -0
  14. hyperloop-0.1.0/base/rebase-resolver.yaml +26 -0
  15. hyperloop-0.1.0/base/verifier.yaml +29 -0
  16. hyperloop-0.1.0/pyproject.toml +100 -0
  17. hyperloop-0.1.0/specs/spec.md +569 -0
  18. hyperloop-0.1.0/src/hyperloop/__init__.py +0 -0
  19. hyperloop-0.1.0/src/hyperloop/__main__.py +5 -0
  20. hyperloop-0.1.0/src/hyperloop/adapters/__init__.py +0 -0
  21. hyperloop-0.1.0/src/hyperloop/adapters/git_state.py +254 -0
  22. hyperloop-0.1.0/src/hyperloop/adapters/local.py +273 -0
  23. hyperloop-0.1.0/src/hyperloop/cli.py +166 -0
  24. hyperloop-0.1.0/src/hyperloop/compose.py +126 -0
  25. hyperloop-0.1.0/src/hyperloop/config.py +161 -0
  26. hyperloop-0.1.0/src/hyperloop/domain/__init__.py +0 -0
  27. hyperloop-0.1.0/src/hyperloop/domain/decide.py +104 -0
  28. hyperloop-0.1.0/src/hyperloop/domain/deps.py +66 -0
  29. hyperloop-0.1.0/src/hyperloop/domain/model.py +221 -0
  30. hyperloop-0.1.0/src/hyperloop/domain/pipeline.py +306 -0
  31. hyperloop-0.1.0/src/hyperloop/loop.py +510 -0
  32. hyperloop-0.1.0/src/hyperloop/ports/__init__.py +0 -0
  33. hyperloop-0.1.0/src/hyperloop/ports/pr.py +32 -0
  34. hyperloop-0.1.0/src/hyperloop/ports/runtime.py +37 -0
  35. hyperloop-0.1.0/src/hyperloop/ports/state.py +61 -0
  36. hyperloop-0.1.0/src/hyperloop/pr.py +212 -0
  37. hyperloop-0.1.0/tests/__init__.py +0 -0
  38. hyperloop-0.1.0/tests/fakes/__init__.py +0 -0
  39. hyperloop-0.1.0/tests/fakes/pr.py +150 -0
  40. hyperloop-0.1.0/tests/fakes/runtime.py +97 -0
  41. hyperloop-0.1.0/tests/fakes/state.py +113 -0
  42. hyperloop-0.1.0/tests/test_cli.py +102 -0
  43. hyperloop-0.1.0/tests/test_compose.py +240 -0
  44. hyperloop-0.1.0/tests/test_config.py +237 -0
  45. hyperloop-0.1.0/tests/test_decide.py +296 -0
  46. hyperloop-0.1.0/tests/test_deps.py +96 -0
  47. hyperloop-0.1.0/tests/test_fakes.py +364 -0
  48. hyperloop-0.1.0/tests/test_git_state.py +353 -0
  49. hyperloop-0.1.0/tests/test_local_runtime.py +383 -0
  50. hyperloop-0.1.0/tests/test_loop.py +896 -0
  51. hyperloop-0.1.0/tests/test_model.py +325 -0
  52. hyperloop-0.1.0/tests/test_pipeline.py +289 -0
  53. hyperloop-0.1.0/tests/test_pr.py +139 -0
  54. hyperloop-0.1.0/tests/test_smoke.py +11 -0
  55. hyperloop-0.1.0/tests/test_state_contract.py +326 -0
  56. hyperloop-0.1.0/uv.lock +364 -0
@@ -0,0 +1,51 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ branches: [main]
6
+ push:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ python-version: ["3.12", "3.13"]
15
+
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - name: Install uv
20
+ uses: astral-sh/setup-uv@v4
21
+
22
+ - name: Set up Python ${{ matrix.python-version }}
23
+ run: uv python install ${{ matrix.python-version }}
24
+
25
+ - name: Install dependencies
26
+ run: uv sync --all-extras
27
+
28
+ - name: Lint
29
+ run: uv run ruff check .
30
+
31
+ - name: Format check
32
+ run: uv run ruff format --check .
33
+
34
+ - name: Type check
35
+ run: uv run pyright
36
+
37
+ - name: Test
38
+ run: uv run pytest --tb=short -q
39
+
40
+ gate:
41
+ # Single status check for branch protection rules
42
+ needs: [test]
43
+ runs-on: ubuntu-latest
44
+ if: always()
45
+ steps:
46
+ - name: All checks passed
47
+ run: |
48
+ if [ "${{ needs.test.result }}" != "success" ]; then
49
+ echo "Tests failed"
50
+ exit 1
51
+ fi
@@ -0,0 +1,106 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ release:
12
+ runs-on: ubuntu-latest
13
+ if: github.repository == 'jsell-rh/hyperloop'
14
+
15
+ permissions:
16
+ contents: write
17
+ id-token: write
18
+
19
+ outputs:
20
+ released: ${{ steps.semrel.outputs.released }}
21
+ version: ${{ steps.semrel.outputs.version }}
22
+ tag: ${{ steps.semrel.outputs.tag }}
23
+
24
+ steps:
25
+ - name: Checkout
26
+ uses: actions/checkout@v4
27
+ with:
28
+ fetch-depth: 0
29
+
30
+ - name: Python Semantic Release
31
+ id: semrel
32
+ uses: python-semantic-release/python-semantic-release@v10
33
+ with:
34
+ github_token: ${{ secrets.GITHUB_TOKEN }}
35
+ root_options: "-vv"
36
+
37
+ build:
38
+ needs: release
39
+ if: needs.release.outputs.released == 'true'
40
+ runs-on: ubuntu-latest
41
+
42
+ steps:
43
+ - name: Checkout released tag
44
+ uses: actions/checkout@v4
45
+ with:
46
+ ref: ${{ needs.release.outputs.tag }}
47
+
48
+ - name: Install uv
49
+ uses: astral-sh/setup-uv@v5
50
+
51
+ - name: Set up Python
52
+ run: uv python install 3.12
53
+
54
+ - name: Build package
55
+ run: uv build
56
+
57
+ - name: Upload dist artifacts
58
+ uses: actions/upload-artifact@v4
59
+ with:
60
+ name: dist
61
+ path: dist/
62
+ if-no-files-found: error
63
+
64
+ publish-pypi:
65
+ needs: [release, build]
66
+ if: needs.release.outputs.released == 'true'
67
+ runs-on: ubuntu-latest
68
+
69
+ environment:
70
+ name: pypi
71
+ url: https://pypi.org/project/hyperloop/${{ needs.release.outputs.version }}/
72
+
73
+ permissions:
74
+ id-token: write
75
+
76
+ steps:
77
+ - name: Download dist artifacts
78
+ uses: actions/download-artifact@v4
79
+ with:
80
+ name: dist
81
+ path: dist/
82
+
83
+ - name: Publish to PyPI
84
+ uses: pypa/gh-action-pypi-publish@release/v1
85
+
86
+ publish-github-release:
87
+ needs: [release, build]
88
+ if: needs.release.outputs.released == 'true'
89
+ runs-on: ubuntu-latest
90
+
91
+ permissions:
92
+ contents: write
93
+ id-token: write
94
+
95
+ steps:
96
+ - name: Download dist artifacts
97
+ uses: actions/download-artifact@v4
98
+ with:
99
+ name: dist
100
+ path: dist/
101
+
102
+ - name: Upload to GitHub Release
103
+ uses: python-semantic-release/publish-action@v10
104
+ with:
105
+ github_token: ${{ secrets.GITHUB_TOKEN }}
106
+ tag: ${{ needs.release.outputs.tag }}
@@ -0,0 +1,9 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .pytest_cache/
4
+ .ruff_cache/
5
+ .pyright/
6
+ *.egg-info/
7
+ dist/
8
+ build/
9
+ .venv/
@@ -0,0 +1,17 @@
1
+ repos:
2
+ - repo: https://github.com/astral-sh/ruff-pre-commit
3
+ rev: v0.8.6
4
+ hooks:
5
+ - id: ruff
6
+ args: [--fix]
7
+ - id: ruff-format
8
+
9
+ - repo: local
10
+ hooks:
11
+ - id: pytest
12
+ name: pytest
13
+ entry: uv run pytest
14
+ language: system
15
+ types: [python]
16
+ pass_filenames: false
17
+ always_run: true
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,7 @@
1
+ # CHANGELOG
2
+
3
+ <!-- version list -->
4
+
5
+ ## v0.1.0 (2026-04-15)
6
+
7
+ - Initial Release
@@ -0,0 +1,102 @@
1
+ # hyperloop
2
+
3
+ An orchestrator that walks tasks through composable process pipelines using AI agents.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ uv sync
9
+ uv run pytest # run tests
10
+ uv run ruff check . # lint
11
+ uv run ruff format --check . # format check
12
+ ```
13
+
14
+ ## Architecture
15
+
16
+ Hexagonal (ports & adapters). Domain logic has zero I/O dependencies.
17
+
18
+ ```
19
+ src/hyperloop/
20
+ ├── domain/ ← pure logic, no I/O, no framework imports
21
+ │ ├── model.py ← Task, WorkerResult, Process, Pipeline (value objects/entities)
22
+ │ ├── decide.py ← decide(world) → Action[] (pure function)
23
+ │ └── pipeline.py ← pipeline executor (recursive, handles loops)
24
+ ├── ports/ ← interfaces only (Protocol classes)
25
+ │ ├── state.py ← StateStore protocol
26
+ │ └── runtime.py ← Runtime protocol
27
+ ├── adapters/ ← implementations of ports
28
+ │ ├── git_state.py ← GitStateStore
29
+ │ ├── local.py ← LocalRuntime (worktrees + CLI)
30
+ │ └── ambient.py ← AmbientRuntime (ambient platform API)
31
+ └── loop.py ← main loop, wires ports to domain
32
+ ```
33
+
34
+ The dependency rule: domain/ imports nothing from ports/ or adapters/. Ports/ imports from domain/ (for types). Adapters/ imports from ports/ and domain/. Loop imports everything.
35
+
36
+ ## Development Practices
37
+
38
+ ### TDD — strict, no exceptions
39
+
40
+ Write the failing test first, then implement. Red → green → refactor. Every behavior starts as a test. If you can't write a test for it, reconsider the design.
41
+
42
+ ### No mocks — use fakes
43
+
44
+ Do NOT use `unittest.mock`, `MagicMock`, `patch`, or any mocking library. Instead:
45
+
46
+ - **Fakes**: complete in-memory implementations of port interfaces. They implement the full contract, not just the methods one test needs. Fakes are first-class code — tested, reusable, and shipped alongside the port they implement.
47
+ - **Real objects**: use the actual domain objects. The domain is pure — no I/O, no reason to replace it.
48
+ - **Layered testing**: small tests exercise domain logic with fakes. Integration tests exercise adapters against real systems. Overlap between layers is a feature, not redundancy.
49
+
50
+ Why: mocks couple tests to implementation details. A mock-heavy test says "this function calls that function with these args" — it tests the wiring, not the behavior. When you refactor, mock tests break even if behavior is preserved. Fakes test the contract.
51
+
52
+ Reference: https://www.alechenninger.com/2020/11/the-secret-world-of-testing-without.html
53
+
54
+ ### Fakes live next to their ports
55
+
56
+ ```
57
+ ports/
58
+ ├── state.py ← StateStore protocol
59
+ └── runtime.py ← Runtime protocol
60
+ tests/
61
+ ├── fakes/
62
+ │ ├── state.py ← InMemoryStateStore (full implementation, tested)
63
+ │ └── runtime.py ← InMemoryRuntime (full implementation, tested)
64
+ ├── test_decide.py
65
+ ├── test_pipeline.py
66
+ └── test_loop.py
67
+ ```
68
+
69
+ Every fake must pass the same contract tests as its real adapter. If `InMemoryStateStore` diverges from `GitStateStore` behavior, the contract tests catch it.
70
+
71
+ ### Type hints — full coverage, no Any
72
+
73
+ Every function signature, every variable where the type isn't obvious. Use `Protocol` for interfaces. Use dataclasses or named tuples for value objects. `Any` is banned — if you reach for it, the model is wrong.
74
+
75
+ ### DDD — domain drives the design
76
+
77
+ The domain model (`domain/`) is the heart. It contains:
78
+ - **Value objects**: `TaskStatus`, `Phase`, `Verdict`, `WorkerResult`
79
+ - **Entities**: `Task`, `Process`
80
+ - **Pure functions**: `decide()`, `run_pipeline()`
81
+
82
+ These have no dependencies on frameworks, I/O, or infrastructure. They are tested directly, without fakes, because they are pure.
83
+
84
+ Ports define what the domain needs from the outside world. Adapters fulfill those needs. The domain never knows which adapter is in use.
85
+
86
+ ## Tooling
87
+
88
+ - **Package manager**: `uv` (not pip, not poetry)
89
+ - **Linting + formatting**: `ruff` (configured in pyproject.toml)
90
+ - **Testing**: `pytest`
91
+ - **Pre-commit**: installed and configured for ruff lint, ruff format, and pytest
92
+ - **Type checking**: `pyright` (strict mode)
93
+
94
+ ## Commit Conventions
95
+
96
+ - Conventional commits: `feat:`, `fix:`, `refactor:`, `test:`, `chore:`, `docs:`
97
+ - One logical change per commit
98
+ - Atomic commits — each commit should pass all tests
99
+
100
+ ## Spec
101
+
102
+ The product spec lives at `specs/spec.md`. It is the source of truth for behavior. If code and spec disagree, align the code to the spec.
@@ -0,0 +1,253 @@
1
+ Metadata-Version: 2.4
2
+ Name: hyperloop
3
+ Version: 0.1.0
4
+ Summary: Orchestrator that walks tasks through composable process pipelines using AI agents
5
+ Requires-Python: >=3.12
6
+ Requires-Dist: pyyaml>=6.0.3
7
+ Requires-Dist: rich>=15.0.0
8
+ Requires-Dist: typer>=0.24.1
9
+ Provides-Extra: dev
10
+ Requires-Dist: pre-commit>=4.0; extra == 'dev'
11
+ Requires-Dist: pyright>=1.1; extra == 'dev'
12
+ Requires-Dist: pytest>=8.0; extra == 'dev'
13
+ Requires-Dist: ruff>=0.8; extra == 'dev'
14
+ Description-Content-Type: text/markdown
15
+
16
+ # hyperloop
17
+
18
+ Walks tasks through composable process pipelines using AI agents. You write specs, it creates tasks, implements them, verifies the work, and merges PRs.
19
+
20
+ ## Prerequisites
21
+
22
+ - Python 3.12+
23
+ - [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code) (`claude` on PATH)
24
+ - `gh` CLI (authenticated, for PR management)
25
+ - `git`
26
+
27
+ ## Install
28
+
29
+ From PyPI (once published):
30
+
31
+ ```bash
32
+ pip install hyperloop
33
+ ```
34
+
35
+ From source (for development or testing):
36
+
37
+ ```bash
38
+ git clone git@github.com:jsell-rh/hyperloop.git
39
+ cd hyperloop
40
+ uv sync --all-extras
41
+ ```
42
+
43
+ ## Quickstart
44
+
45
+ 1. Create a repo with a spec:
46
+
47
+ ```bash
48
+ mkdir -p my-project/specs
49
+ cd my-project
50
+ git init && git commit --allow-empty -m "init"
51
+ ```
52
+
53
+ 2. Write a spec. This is what you want built. Be specific about acceptance criteria:
54
+
55
+ ```markdown
56
+ <!-- specs/auth.md -->
57
+ # User Authentication
58
+
59
+ Implement JWT-based authentication for the API.
60
+
61
+ ## Acceptance Criteria
62
+
63
+ - POST /auth/login accepts email + password, returns JWT
64
+ - POST /auth/register creates a new user account
65
+ - GET /auth/me returns the current user (requires valid JWT)
66
+ - Passwords are hashed with bcrypt, never stored in plaintext
67
+ - JWTs expire after 24 hours
68
+ ```
69
+
70
+ 3. Run:
71
+
72
+ ```bash
73
+ # From source:
74
+ uv run hyperloop run --repo owner/repo --branch main
75
+
76
+ # Or if installed:
77
+ hyperloop run --repo owner/repo --branch main
78
+ ```
79
+
80
+ 4. See what it would do without executing:
81
+
82
+ ```bash
83
+ hyperloop run --repo owner/repo --dry-run
84
+ ```
85
+
86
+ The orchestrator reads your specs, has the PM create tasks in `specs/tasks/`, then walks each task through the default pipeline: implement, verify, merge.
87
+
88
+ ## Configuration
89
+
90
+ Create `.hyperloop.yaml` in your repo root:
91
+
92
+ ```yaml
93
+ target:
94
+ base_branch: main
95
+
96
+ runtime:
97
+ max_workers: 4
98
+
99
+ merge:
100
+ auto_merge: true
101
+ strategy: squash
102
+ ```
103
+
104
+ Then just run from the repo directory:
105
+
106
+ ```bash
107
+ hyperloop run
108
+ ```
109
+
110
+ The repo is inferred from your git remote. All settings have sensible defaults.
111
+
112
+ ## Customizing Agent Behavior
113
+
114
+ Hyperloop ships with base agent definitions (implementer, verifier, etc.) that work out of the box. To customize them for your project, overlay with patches.
115
+
116
+ ### In-repo overlay
117
+
118
+ For single-repo projects. Agent patches live in the repo itself:
119
+
120
+ ```yaml
121
+ # .hyperloop.yaml
122
+ overlay: .hyperloop/agents/
123
+ ```
124
+
125
+ ```
126
+ your-repo/
127
+ ├── .hyperloop.yaml
128
+ ├── .hyperloop/
129
+ │ └── agents/
130
+ │ ├── implementer-patch.yaml
131
+ │ └── process-patch.yaml
132
+ └── specs/
133
+ ```
134
+
135
+ An implementer patch injects your project's persona:
136
+
137
+ ```yaml
138
+ # .hyperloop/agents/implementer-patch.yaml
139
+ kind: Agent
140
+ name: implementer
141
+ annotations:
142
+ ambient.io/persona: |
143
+ You work on a Go API service.
144
+ Build: make build. Test: make test. Lint: make lint.
145
+ Follow Clean Architecture. Use dependency injection.
146
+ ```
147
+
148
+ ### Shared overlay via gitops repo
149
+
150
+ For teams with multiple repos sharing agent definitions. The overlay lives in a central gitops repo and references the hyperloop base as a kustomize remote resource:
151
+
152
+ ```yaml
153
+ # .hyperloop.yaml
154
+ overlay: git@github.com:your-org/agent-gitops//overlays/api
155
+ ```
156
+
157
+ ```yaml
158
+ # your-org/agent-gitops/overlays/api/kustomization.yaml
159
+ resources:
160
+ - github.com/org/hyperloop//base?ref=v1.0.0
161
+
162
+ patches:
163
+ - path: implementer-patch.yaml
164
+ target:
165
+ kind: Agent
166
+ name: implementer
167
+ - path: process-patch.yaml
168
+ target:
169
+ kind: Process
170
+ name: default
171
+ ```
172
+
173
+ This pins the base version and lets you upgrade across all repos by bumping the ref.
174
+
175
+ ## Custom Processes
176
+
177
+ The default pipeline is: implement, verify, merge. Override it by patching the process:
178
+
179
+ ```yaml
180
+ # process-patch.yaml
181
+ kind: Process
182
+ name: default
183
+
184
+ pipeline:
185
+ - loop:
186
+ - loop:
187
+ - role: implementer
188
+ - role: verifier
189
+ - role: security-reviewer
190
+ - gate: human-pr-approval
191
+ - action: merge-pr
192
+ ```
193
+
194
+ Four primitives:
195
+
196
+ | Primitive | What it does |
197
+ |---|---|
198
+ | `role: X` | Spawn an agent. Fail restarts the enclosing loop. |
199
+ | `gate: X` | Block until external signal (v1: `lgtm` label on PR). |
200
+ | `loop` | Wrap steps. Retry from top on failure. |
201
+ | `action: X` | Terminal operation (`merge-pr`, `mark-pr-ready`). |
202
+
203
+ Loops nest. Inner loops retry independently of outer loops.
204
+
205
+ ## What it creates in your repo
206
+
207
+ The orchestrator writes to `specs/` in your repo:
208
+
209
+ ```
210
+ specs/
211
+ ├── tasks/ # task files with status, findings, spec references
212
+ ├── reviews/ # review artifacts from verifier (on branches)
213
+ └── prompts/ # process improvements (learned over time)
214
+ ```
215
+
216
+ All task state is tracked in git. Every commit includes `Spec-Ref` and `Task-Ref` trailers for traceability. PRs are created as drafts and labeled by spec and task.
217
+
218
+ ## Configuration Reference
219
+
220
+ ```yaml
221
+ # .hyperloop.yaml
222
+
223
+ overlay: .hyperloop/agents/ # local path or git URL to kustomization dir
224
+
225
+ target:
226
+ repo: owner/repo # GitHub repo (default: inferred from git remote)
227
+ base_branch: main # trunk branch
228
+ specs_dir: specs # where specs live
229
+
230
+ runtime:
231
+ default: local # local (v1) | ambient (planned)
232
+ max_workers: 6 # max parallel task workers
233
+
234
+ merge:
235
+ auto_merge: true # squash-merge on review pass
236
+ strategy: squash # squash | merge
237
+ delete_branch: true # delete worker branch after merge
238
+
239
+ poll_interval: 30 # seconds between orchestrator cycles
240
+ max_rounds: 50 # max retry rounds per task before failure
241
+ max_rebase_attempts: 3 # max rebase retries before full loop retry
242
+ ```
243
+
244
+ ## Development
245
+
246
+ ```bash
247
+ uv sync --all-extras
248
+ uv run pytest # run tests (280 tests)
249
+ uv run ruff check . # lint
250
+ uv run ruff format --check . # format check
251
+ uv run pyright # type check
252
+ uv run hyperloop --help # CLI help
253
+ ```