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.
- hyperloop-0.1.0/.github/workflows/ci.yaml +51 -0
- hyperloop-0.1.0/.github/workflows/release.yaml +106 -0
- hyperloop-0.1.0/.gitignore +9 -0
- hyperloop-0.1.0/.pre-commit-config.yaml +17 -0
- hyperloop-0.1.0/.python-version +1 -0
- hyperloop-0.1.0/CHANGELOG.md +7 -0
- hyperloop-0.1.0/CLAUDE.md +102 -0
- hyperloop-0.1.0/PKG-INFO +253 -0
- hyperloop-0.1.0/README.md +238 -0
- hyperloop-0.1.0/base/implementer.yaml +30 -0
- hyperloop-0.1.0/base/pm.yaml +43 -0
- hyperloop-0.1.0/base/process-improver.yaml +30 -0
- hyperloop-0.1.0/base/process.yaml +11 -0
- hyperloop-0.1.0/base/rebase-resolver.yaml +26 -0
- hyperloop-0.1.0/base/verifier.yaml +29 -0
- hyperloop-0.1.0/pyproject.toml +100 -0
- hyperloop-0.1.0/specs/spec.md +569 -0
- hyperloop-0.1.0/src/hyperloop/__init__.py +0 -0
- hyperloop-0.1.0/src/hyperloop/__main__.py +5 -0
- hyperloop-0.1.0/src/hyperloop/adapters/__init__.py +0 -0
- hyperloop-0.1.0/src/hyperloop/adapters/git_state.py +254 -0
- hyperloop-0.1.0/src/hyperloop/adapters/local.py +273 -0
- hyperloop-0.1.0/src/hyperloop/cli.py +166 -0
- hyperloop-0.1.0/src/hyperloop/compose.py +126 -0
- hyperloop-0.1.0/src/hyperloop/config.py +161 -0
- hyperloop-0.1.0/src/hyperloop/domain/__init__.py +0 -0
- hyperloop-0.1.0/src/hyperloop/domain/decide.py +104 -0
- hyperloop-0.1.0/src/hyperloop/domain/deps.py +66 -0
- hyperloop-0.1.0/src/hyperloop/domain/model.py +221 -0
- hyperloop-0.1.0/src/hyperloop/domain/pipeline.py +306 -0
- hyperloop-0.1.0/src/hyperloop/loop.py +510 -0
- hyperloop-0.1.0/src/hyperloop/ports/__init__.py +0 -0
- hyperloop-0.1.0/src/hyperloop/ports/pr.py +32 -0
- hyperloop-0.1.0/src/hyperloop/ports/runtime.py +37 -0
- hyperloop-0.1.0/src/hyperloop/ports/state.py +61 -0
- hyperloop-0.1.0/src/hyperloop/pr.py +212 -0
- hyperloop-0.1.0/tests/__init__.py +0 -0
- hyperloop-0.1.0/tests/fakes/__init__.py +0 -0
- hyperloop-0.1.0/tests/fakes/pr.py +150 -0
- hyperloop-0.1.0/tests/fakes/runtime.py +97 -0
- hyperloop-0.1.0/tests/fakes/state.py +113 -0
- hyperloop-0.1.0/tests/test_cli.py +102 -0
- hyperloop-0.1.0/tests/test_compose.py +240 -0
- hyperloop-0.1.0/tests/test_config.py +237 -0
- hyperloop-0.1.0/tests/test_decide.py +296 -0
- hyperloop-0.1.0/tests/test_deps.py +96 -0
- hyperloop-0.1.0/tests/test_fakes.py +364 -0
- hyperloop-0.1.0/tests/test_git_state.py +353 -0
- hyperloop-0.1.0/tests/test_local_runtime.py +383 -0
- hyperloop-0.1.0/tests/test_loop.py +896 -0
- hyperloop-0.1.0/tests/test_model.py +325 -0
- hyperloop-0.1.0/tests/test_pipeline.py +289 -0
- hyperloop-0.1.0/tests/test_pr.py +139 -0
- hyperloop-0.1.0/tests/test_smoke.py +11 -0
- hyperloop-0.1.0/tests/test_state_contract.py +326 -0
- 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,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,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.
|
hyperloop-0.1.0/PKG-INFO
ADDED
|
@@ -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
|
+
```
|