@ob1-sg/horizon 0.1.11 → 0.2.0

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.
package/README.md CHANGED
@@ -1,6 +1,13 @@
1
- # Horizon - Autonomous Product Development Agent
1
+ # Horizon - Turn Linear Tickets into Pull Requests with Parallel Agents
2
2
 
3
- Horizon is an AI-powered autonomous development system that works on Linear tickets without human intervention. It orchestrates multiple AI agents to research, plan, implement, and validate code changes, all while keeping Linear updated with progress.
3
+ Horizon turns Linear tickets into pull requests with code changes. You write tickets, Horizon runs a loop of researching, planning, implementing, and validating changes on its own. Multiple Horizon agents can work in parallel so you can focus on reviewing high-quality PRs. The validation pipeline ensures the pull requests are tested, easy to review, and ready to merge.
4
+
5
+ ## Prerequisites
6
+
7
+ - Node v24.12.0 (only version tested so far)
8
+ - [Claude Code (recommended)](https://code.claude.com/docs/en/setup#installation) or OpenAI Codex CLI installed
9
+ - A Linear account with API access
10
+ - Git repository initialized
4
11
 
5
12
  ## Installation
6
13
 
@@ -20,57 +27,27 @@ npm install --save-dev @ob1-sg/horizon
20
27
 
21
28
  1. **Install Horizon** (see above)
22
29
 
23
- 2. **Run Horizon**:
30
+ 2. **Run Horizon** in your project:
24
31
  ```bash
25
- cd your-project
32
+ cd your-project-with-git-initialized
26
33
  horizon # Global install
27
34
  npx horizon # Local install
28
35
  ```
29
36
 
30
- 3. **First-run setup** - On first run, Horizon will:
31
- - Prompt for your Linear API key
32
- - Auto-detect your Linear team
33
- - Create necessary directories and configuration
34
- - Start the development loop
37
+ 3. **First-run wizard** Horizon walks you through setup:
38
+ - Enter your Linear API key
39
+ - Auto-detects your Linear team (or lets you pick)
40
+ - Auto-selects AI provider (Claude Code or OpenAI Codex) based on what's installed, defaulting to Claude Code
41
+ - Choose merge mode: `auto` (recommended), `merge`, or `pr`
42
+ - Creates `.horizon/` config directory
43
+ - Sets up Horizon Agent's `∞` workflow statuses in your Linear team
35
44
 
36
- 4. **Create tickets** in Linear and Horizon will work on them autonomously
45
+ 4. **Create tickets** in Linear and Horizon works on them autonomously
37
46
 
38
- For advanced configuration, run `horizon config` to change settings like provider, model, and iteration limits.
47
+ Run `horizon config` to change settings like provider, model, and iteration limits.
39
48
 
40
49
  ## How It Works
41
50
 
42
- Horizon uses three core concepts: **Pods**, **Loops**, and **Agents**.
43
-
44
- ### Pods, Loops, and Agents
45
-
46
- ```
47
- ┌─────────────────────────────────────────────────────────────────────────┐
48
- │ Pod (swift-wyvern) │
49
- ├─────────────────────────────────────────────────────────────────────────┤
50
- │ │
51
- │ Loop 1: Ticket RSK-42 │
52
- │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
53
- │ │ Agent 1 │ │ Agent 2 │ │ Agent 3 │ │
54
- │ │ Linear │────▶│ Worker │────▶│ Linear │ │
55
- │ │ Reader │ │ │ │ Writer │ │
56
- │ └──────────────┘ └──────────────┘ └──────────────┘ │
57
- │ │
58
- │ Loop 2: Ticket RSK-43 │
59
- │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
60
- │ │ Agent 1 │────▶│ Agent 2 │────▶│ Agent 3 │ │
61
- │ └──────────────┘ └──────────────┘ └──────────────┘ │
62
- │ │
63
- │ Loop 3: ... │
64
- │ │
65
- └─────────────────────────────────────────────────────────────────────────┘
66
- ```
67
-
68
- - **Pod**: A running instance of Horizon. Each pod gets a unique name (e.g., "swift-wyvern") and continuously processes tickets until stopped. You can run multiple pods in parallel.
69
-
70
- - **Loop**: One complete cycle of work. Each loop claims a ticket, works on it, and updates Linear. A pod runs loops continuously until there's no more work.
71
-
72
- - **Agent**: An AI worker that handles one part of the loop. Three agents work in sequence to complete each loop.
73
-
74
51
  ### The Agent Pipeline
75
52
 
76
53
  1. **Agent 1 (Linear Reader)**: Scans Linear for available tickets, prioritizes by urgency, **claims** the highest-priority ticket, and gathers context.
@@ -79,48 +56,52 @@ Horizon uses three core concepts: **Pods**, **Loops**, and **Agents**.
79
56
 
80
57
  3. **Agent 3 (Linear Writer)**: Updates Linear with results - posts comments, updates status, and links commits.
81
58
 
82
- ### Parallel Execution
83
59
 
84
- Multiple pods can work on the same codebase simultaneously. Horizon prevents conflicts through **ticket claiming**:
60
+ ### The Agent Loop
85
61
 
86
- 1. When Agent 1 finds a ticket to work on, it immediately changes the status to "In Progress"
87
- 2. Other pods see this status and skip the ticket
88
- 3. Each pod works on different tickets, avoiding collisions
62
+ ```
63
+ +-----------------------------------------------------------------------+
64
+ | Instance (yellow-giraffe) |
65
+ +-----------------------------------------------------------------------+
66
+ | |
67
+ | Loop 1: Ticket PROJ-12 |
68
+ | +------------+ +------------+ +------------+ |
69
+ | | Agent 1 | | Agent 2 | | Agent 3 | |
70
+ | | Linear |---->| Worker |---->| Linear | |
71
+ | | Reader | | | | Writer | |
72
+ | +------------+ +------------+ +------------+ |
73
+ | |
74
+ | Loop 2: Ticket PROJ-13 |
75
+ | +------------+ +------------+ +------------+ |
76
+ | | Agent 1 |---->| Agent 2 |---->| Agent 3 | |
77
+ | +------------+ +------------+ +------------+ |
78
+ | |
79
+ | Loop 3: ... |
80
+ | |
81
+ +-----------------------------------------------------------------------+
82
+ ```
89
83
 
90
- This lets you scale development by running multiple Horizon pods in parallel - on different machines, in CI, or as background processes.
84
+ 1. Create a ticket in Linear and set its status to `Backlog (default)` (or any `Needs ...` status)
85
+ 2. Horizon claims it, does the work, and advances to the next stage
86
+ 3. This repeats automatically until the ticket reaches `∞ Done`
87
+ 4. Retry any stage by moving the ticket back to `Backlog` (or any `Needs ...` status)
88
+ 5. Queue multiple tickets — Horizon processes them by priority, which you can configure in Linear. Provide feedback or unblock the agent when human intervention is needed
91
89
 
92
- ### Linear as State Machine
90
+ ### Parallel Execution
93
91
 
94
- Horizon uses Linear as its state machine. You don't need to configure Horizon or tell it what to work on - just add tickets to Linear and Horizon handles the rest.
92
+ Run `horizon` in a separate terminal window for each parallel agent. Agents coordinate through Linear: when one agent claims a ticket, it changes the status to "In Progress" so other agents skip it. Agent 1 (the orchestrator) understands ticket hierarchy and dependencies, so it picks the right work in the right order. Each instance runs loops continuously until there's no more work.
95
93
 
96
- ```
97
- ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
98
- │ ∞ Needs │────▶│ ∞ Needs │────▶│ ∞ Needs │────▶│ ∞ Needs │────▶│ ∞ Needs │
99
- │ Research │ │ Spec* │ │ Plan │ │ Implement │ │ Validate │
100
- └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
101
- │ │ │ │ │
102
- ▼ ▼ ▼ ▼ ▼
103
- ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
104
- │ ∞ Research │ │ ∞ Spec In │ │ ∞ Plan In │ │∞ Implement │ │ ∞ Validate │
105
- │ In Progress │ │ Progress* │ │ Progress │ │ In Progress │ │ In Progress │
106
- └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
107
-
108
- * Specification is optional - only when ▼
109
- research determines UX decisions are needed ┌─────────────┐
110
- │ ∞ Done │
111
- └─────────────┘
112
- ```
94
+ ### Git Worktree Isolation
113
95
 
114
- **How it works:**
96
+ Each Agent 2 (Worker) runs in its own [git worktree](https://git-scm.com/docs/git-worktree), so multiple agents can work on different tickets in parallel without conflicts. When a ticket is claimed:
115
97
 
116
- 1. **You create a ticket** in Linear and set its status to `∞ Needs Research` (or any "Needs" status)
117
- 2. **Horizon picks it up** - Agent 1 scans for tickets in "Needs" statuses
118
- 3. **Horizon claims it** - Changes status to "In Progress" so other pods skip it
119
- 4. **Horizon works on it** - Agent 2 does the actual development work
120
- 5. **Horizon advances it** - Agent 3 moves the ticket to the next status
121
- 6. **Repeat** until the ticket reaches `∞ Done`
98
+ 1. Horizon creates a worktree at `.horizon/worktrees/{issue-identifier}/`
99
+ 2. The worktree checks out a dedicated branch: `horizon/{issue-identifier}`
100
+ 3. Dependencies are installed in the worktree automatically
101
+ 4. Agent 2 runs entirely within the worktree
102
+ 5. After completion, the worktree is cleaned up
122
103
 
123
- This means you can queue up work by creating tickets, and Horizon will process them in priority order. You can also intervene at any point - move a ticket back to a "Needs" status and Horizon will re-do that step.
104
+ This means you can run multiple `horizon` instances simultaneously each one gets an isolated copy of the repo with its own branch, so there are no working directory conflicts between agents.
124
105
 
125
106
  ## Directory Structure
126
107
 
@@ -131,15 +112,25 @@ your-project/
131
112
  ├── .horizon/ # Runtime data (gitignored)
132
113
  │ ├── env # Configuration and credentials
133
114
  │ ├── mcp.json # MCP configuration for Claude Code
115
+ │ ├── prompts/ # Agent prompt templates (synced from package)
134
116
  │ ├── output/ # Runtime logs
117
+ │ ├── worktrees/ # Git worktrees for parallel agents
135
118
  │ └── attachments/ # Downloaded issue attachments
136
119
  ├── horizon-docs/ # Work artifacts (committed)
137
120
  │ ├── research/ # Research documents
138
121
  │ ├── plans/ # Implementation plans
139
- └── validation/ # Validation reports
122
+ ├── validation/ # Validation reports
123
+ │ ├── oneshot/ # Oneshot completions
124
+ │ ├── specifications/ # Feature specifications
140
125
  └── CLAUDE.md # Your project's Claude instructions
141
126
  ```
142
127
 
128
+ ### Horizon Documentation Folder
129
+
130
+ The `horizon-docs/` folder contains the work artifacts for Horizon. You can use this folder to track the work that Horizon has done.
131
+
132
+ However, the main purpose of this folder is for the agent to document its work and historical changes, which are valuable for understanding the codebase evolution and development of future features.
133
+
143
134
  ## Configuration
144
135
 
145
136
  ### Environment Variables
@@ -153,19 +144,25 @@ Set these in `.horizon/env` or export them:
153
144
  | `HORIZON_PROVIDER` | AI provider: "claude" or "codex" | "claude" |
154
145
  | `HORIZON_CLAUDE_MODEL` | Claude model: "opus", "sonnet", "haiku" | "opus" |
155
146
  | `HORIZON_MAX_ITERATIONS` | Stop after N iterations (0 = unlimited) | 0 |
156
- | `HORIZON_MERGE_MODE` | Merge mode: "merge" or "pr" | "merge" |
147
+ | `HORIZON_MERGE_MODE` | Merge mode: "auto", "merge", or "pr" | "auto" |
157
148
 
158
149
  ### Merge Modes
159
150
 
160
- Horizon supports two modes for completing work:
151
+ Horizon supports three modes for completing work:
161
152
 
162
- **Direct Merge (default)**
153
+ **Auto (default)**
154
+ ```bash
155
+ export HORIZON_MERGE_MODE=auto
156
+ ```
157
+ The agent decides the safest path — merge directly for small changes, create a PR for larger ones.
158
+
159
+ **Direct Merge**
163
160
  ```bash
164
161
  export HORIZON_MERGE_MODE=merge
165
162
  ```
166
163
  Horizon merges completed work directly to main. Best for trusted autonomous operation.
167
164
 
168
- **Pull Request Mode**
165
+ **Pull Request**
169
166
  ```bash
170
167
  export HORIZON_MERGE_MODE=pr
171
168
  ```
@@ -204,69 +201,26 @@ Update with:
204
201
  npm install -g @ob1-sg/horizon@latest
205
202
  ```
206
203
 
207
- ## Releasing (Maintainers)
208
-
209
- Releases are performed via GitHub Actions.
210
-
211
- ### Preflight
212
-
213
- 1. Confirm GitHub repo secrets:
214
- - `NPM_TOKEN` (required): npm publish token with access to publish `@ob1-sg/horizon`.
215
- - `RELEASE_TOKEN` (optional): GitHub token/PAT with `contents: write` in case `github.token` can’t push to `main` due to branch protections (also used to create the GitHub Release).
216
- 2. Confirm no other release run is in progress (the workflow uses `concurrency: release`).
217
-
218
- ### Optional: dry run (CI gates only)
219
-
220
- 1. GitHub → Actions → `Release` → Run workflow (branch: `main`)
221
- 2. Inputs:
222
- - `release_type`: `patch`
223
- - `npm_tag`: `latest`
224
- - `dry_run`: `true`
225
- 3. Expectation: build/typecheck/tests run and pass; **no** version bump commit, tag, GitHub Release, or npm publish is created.
226
-
227
- ### Patch release
228
-
229
- 1. GitHub → Actions → `Release` → Run workflow (branch: `main`)
230
- 2. Inputs:
231
- - `release_type`: `patch` (or `minor` / `major`)
232
- - `npm_tag`: `latest` (or another intended dist-tag)
233
- - `dry_run`: `false`
234
- 3. Expected outputs:
235
- - A commit on `main` with message like `chore(release): vX.Y.Z`
236
- - A git tag `vX.Y.Z` pushed to the repo
237
- - A GitHub Release created for `vX.Y.Z` (auto-generated notes)
238
- - `@ob1-sg/horizon@X.Y.Z` published to npm under the chosen dist-tag
239
-
240
- ### Recovery (partial failures)
241
-
242
- - **Tag exists but npm publish failed**: GitHub → Actions → `Publish existing ref to npm`
243
- - `ref`: the tag (e.g. `vX.Y.Z`)
244
- - `npm_tag`: the intended dist-tag (default `latest`)
245
- - **npm publish succeeded but GitHub Release creation failed**: create a GitHub Release from the existing tag (UI or `gh release create vX.Y.Z --generate-notes`).
246
-
247
- ### Rollback (only if necessary)
248
-
249
- If a tag was created but should not exist (and npm publish did not occur):
250
-
251
- ```bash
252
- git tag -d vX.Y.Z && git push origin :refs/tags/vX.Y.Z
253
- ```
204
+ ## Writing Good Tickets
254
205
 
255
- Delete the GitHub Release for that tag in the UI if one was created.
206
+ Horizon works best with clear, specific tickets:
256
207
 
257
- ### Local parity checks (optional)
208
+ **Good ticket**:
209
+ > Add a dark mode toggle to the settings page. Should save preference to localStorage and apply a .dark-theme class to the body.
258
210
 
259
- ```bash
260
- npm ci
261
- npm run build
262
- npm run typecheck
263
- npm test
264
- ```
211
+ **Tips**:
212
+ - Include **acceptance criteria** when possible
213
+ - Reference existing code patterns to follow
214
+ - Specify any constraints or requirements
215
+ - Link related issues if dependencies exist
265
216
 
266
217
  ## Linear Workflow Statuses
267
218
 
268
219
  Horizon creates these statuses in Linear:
269
220
 
221
+ **Backlog**:
222
+ - `Backlog (default)`
223
+
270
224
  **Ready statuses** (waiting for Horizon):
271
225
  - `∞ Needs Research`
272
226
  - `∞ Needs Specification` (optional - when UX decisions are needed)
@@ -280,6 +234,7 @@ Horizon creates these statuses in Linear:
280
234
  - `∞ Plan In Progress`
281
235
  - `∞ Implement In Progress`
282
236
  - `∞ Validate In Progress`
237
+ - `∞ Oneshot In Progress`
283
238
 
284
239
  **Intervention statuses** (requires human action):
285
240
  - `∞ Blocked` - Agent needs clarification or decision before proceeding
@@ -289,55 +244,21 @@ Horizon creates these statuses in Linear:
289
244
  - `∞ Done`
290
245
  - `∞ Canceled`
291
246
 
292
- ## Writing Good Tickets
293
-
294
- Horizon works best with clear, specific tickets:
295
-
296
- **Good ticket**:
297
- > Add a dark mode toggle to the settings page. Should save preference to localStorage and apply a .dark-theme class to the body.
298
-
299
- **Tips**:
300
- - Include acceptance criteria when possible
301
- - Reference existing code patterns to follow
302
- - Specify any constraints or requirements
303
- - Link related issues if dependencies exist
304
-
305
247
  ## Developing Horizon
306
248
 
307
249
  If you want to contribute or modify Horizon:
308
250
 
309
- ```bash
310
- # Clone the repo
311
- git clone https://github.com/ob1-sg/horizon
312
- cd horizon
313
-
314
- # Install dependencies
315
- npm install
316
-
317
- # Build
318
- npm run build
319
-
320
- # Run from source
321
- npm start
322
-
323
- # Type check
324
- npm run typecheck
325
- ```
326
-
327
- ## Prerequisites
328
-
329
- - Node.js 18+
330
- - [Claude Code](https://claude.ai/claude-code) or Codex CLI installed
331
- - A Linear account with API access
332
- - Git repository initialized
251
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for release process and maintainer guidelines.
333
252
 
334
253
  ## Acknowledgments
335
254
 
336
255
  Horizon builds on ideas and techniques from the AI engineering community:
337
256
 
257
+ - **[Ramp Inspect](https://builders.ramp.com/post/why-we-built-our-background-agent)** - For agent UIUX, infrastructure and tooling inspiration.
258
+ - **[Stripe Minions](https://stripe.dev/blog/minions-stripes-one-shot-end-to-end-coding-agents)** - For the architecture and design of multiple agents working in parallel.
338
259
  - **[Dex Horthy](https://github.com/humanlayer/advanced-context-engineering-for-coding-agents/blob/main/ace-fca.md)** - For the research/plan/implement pattern that structures how Horizon approaches work
339
260
  - **[Geoff Huntley](https://ghuntley.com/ralph/)** - For the Ralph Wiggum technique that inspires Horizon's autonomous agent approach
340
- - **[Vaibhav @ BoundaryML](https://boundaryml.com/podcast)** - For BAML and the "AI That Works" podcast series on building reliable AI systems
261
+ - **[Vaibhav's BoundaryML Podcast](https://boundaryml.com/podcast)** - For "AI That Works" podcast series on building reliable AI systems
341
262
 
342
263
  ## License
343
264
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAyCA,OAAO,iBAAiB,CAAC;AACzB,OAAO,gBAAgB,CAAC;AAwjBxB,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAiI1C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA8CA,OAAO,iBAAiB,CAAC;AACzB,OAAO,gBAAgB,CAAC;AAgpBxB,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAqI1C"}